source-server

This commit is contained in:
metin2clean 2024-06-01 15:59:51 -05:00
parent a00b9a88eb
commit 9ead72db4a
597 changed files with 224577 additions and 0 deletions

22
source-server/.gitattributes vendored Normal file
View File

@ -0,0 +1,22 @@
### default behavior
* text=auto eol=lf
## note: eol in text auto is fixed since git 2.10 (31 aug 2016)
### windows (always crlf)
*.bat eol=crlf
*.sln eol=crlf
*.filters eol=crlf
*.users eol=crlf
*.vcxproj eol=crlf
*.vssscc eol=crlf
### unix (always lf)
*.sh eol=lf
*.bash eol=lf
*.py eol=lf
### binaries
*.suo binary
### others
*.txt eol=crlf

69
source-server/.gitignore vendored Normal file
View File

@ -0,0 +1,69 @@
Extern
__test
__trash
.vs
*.ncb
*.opensdf
*.sdf
#+easy with .suo
#*.suo
*.bsc
*.exe
*.ilk
*.map
*.pdb
*.idb
obj
ipch
Debug
Release
MfcRelease
*___Win32_MfcRelease
MfcDebug
*___Win32_MfcDebug
Distribute
bin
OBJDIR
.obj
Depend
Depend.bak
*.a
*.dll
*.lib
*.o
*.so
*.iobj
*.ipdb
db_r*
game_r*
db_symlink
game_symlink
pre_qc
*.pyc
*.bak
/.project
### archives
*.rar
*.7z
*.zip
!server-Extern.zip
*.gz
*.bz
*.xz
*.tar
*.tgz
*.tbz
*.txz

View File

@ -0,0 +1,448 @@
# README #
### What is this repository for? ###
* Quick summary
* Version
* [Learn Markdown](https://bitbucket.org/tutorials/markdowndemo)
####
# git config --global http.sslVerify false
# git config --global credential.helper "cache --timeout=3600"
###
# git add -A
# git commit -m "base added"
### or
# git commit -am "files updated"
###
# git push
###
# git pull
####
### How do I get set up? ###
* Summary of set up
// mysql dep
# cd /usr/ports/databases/mysql56-client
# make WITH_XCHARSET=all install clean
## OR
# pkg install mysql56-client
// extern extract
# cd ./Srcs
# tar -xzf Extern.tgz
// cryptopp dep
# cd ./Srcs/Extern/cryptopp
# gmake libcryptopp.a -j4
//how to compile all-the-server (db+game+dep)
# cd ./Srcs/Server
# gmake all -j4
//how to compile just game (not necessary)
# cd ./Srcs/Server/game/src
# gmake -j4
//how to compile just db (not necessary)
# cd ./Srcs/Server/db/src
# gmake -j4
* Configuration
@#GENERAL MACROS
#define __OBSOLETE__ //useless and pointless code removed
#define __UNIMPLEMENTED__ //drafts of new things to be implemented
@/Src/Server/common/CommonDefines.h
>>default
#define _IMPROVED_PACKET_ENCRYPTION_ //enable cryptopp mixed encryption for client<>server comunication
#define USE_IMPROVED_PACKET_DECRYPTED_BUFFER //enable a buffer for decrypting incoming packets sent at different times (for IMPROVED_PACKET_ENCRYPTION only)
#define __UDP_BLOCK__
#define ENABLE_QUEST_CATEGORY //enable quest category+new packet types (unimplemented)
>>systems
#define ENABLE_D_NJGUILD //enable d.new_jump_all_guild+cpp relative functions (untested)
#define ENABLE_NEWSTUFF //enable new stuff (new lua funcs, new CONFIG options, ecc)
#define ENABLE_FULL_NOTICE //enable new big notice features
#define ENABLE_PORT_SECURITY // block db_port, p2p_port, and remote adminpage exploits
#define ENABLE_BELT_INVENTORY_EX // move the belt items into the BELT_INVENTORY window and prevents unknown belt positions if you de/increase wear/inventory slots
#define ENABLE_CMD_WARP_IN_DUNGEON // /warp <player> will warp successfully even if the player is inside a dungeon (be sure a .quest login event won't still warp you out)
#define ENABLE_USE_COSTUME_ATTR // enable the items reset costume and enchant costume
#define ENABLE_ITEM_ATTR_COSTUME // enable costume_hair, costume_body, costume_weapon item_attr/_rare parts
#define ENABLE_SEQUENCE_SYSTEM // enable sequence system
#define MAP_ALLOW_LIMIT <int> // define how many maps are allowed per game core (default 32)
#define ENABLE_PLAYER_PER_ACCOUNT5 // enable 5 characters (per account) in the select phase (instead of 4)
#define ENABLE_DICE_SYSTEM // enable dice system: if the mob is king or boss and you're in party, the dropped item is randomly rolled
#define ENABLE_EXTEND_INVEN_SYSTEM //enable 4 inventory pages
#define ENABLE_MOUNT_COSTUME_SYSTEM // enable mount costume slot
#define ENABLE_WEAPON_COSTUME_SYSTEM //enable weapon costume slot
#define ENABLE_PET_SYSTEM_EX // enable item pet without quest [@warme666]
#define ENABLE_SKILL_FLAG_PARTY //enable skill flag party (separated from lycan define)
#define ENABLE_NO_DSS_QUALIFICATION //disable dragon soul qualification [@warme666]
#define ENABLE_NO_SELL_PRICE_DIVIDED_BY_5 // disable dividing the sell price by 5 [@warme666]
#define ENABLE_CHECK_SELL_PRICE // it checks if the sell price is higher than the buy price; if yes, sell price will be equal to the buy price
#define ENABLE_GOTO_LAG_FIX // it force-clears the entities when switching sectree
#define ENABLE_MOUNT_COSTUME_EX_SYSTEM //mount load via item_proto with APPLY_MOUNT (118) bonus like official
#define ENABLE_PENDANT_SYSTEM // pendant equip implementation
#define ENABLE_GLOVE_SYSTEM // glove equip implementation
#define ENABLE_MOVE_CHANNEL // enable channel switch
#define ENABLE_REDUCED_ENTITY_VIEW // it reduces the complexity of the entity view
>>lycan
#define ENABLE_WOLFMAN_CHARACTER // enable wolfman character and the relative new features (claws, bleeding and so on) [@warme666]
#define DISABLE_WOLFMAN_ON_CREATE // disable wolfman on create phase [@warme666]
#define USE_MOB_BLEEDING_AS_POISON // if enabled, the mob_proto structure won't change and the bleeding % will be get from the poison field
#define USE_MOB_CLAW_AS_DAGGER // if enabled, the mob_proto structure won't change and the claw % will be get from the dagger field
#define USE_ITEM_BLEEDING_AS_POISON // if enabled, the poison reduce bonus can also reduce the bleeding damage as if it's bleeding reduce itself
#define USE_ITEM_CLAW_AS_DAGGER // if enabled, the resist dagger bonus can also reduce the claw damage as if it's resist claw itself
#define USE_WOLFMAN_STONES // if enabled, lycan stones can be dropped from the metin stones
#define USE_WOLFMAN_BOOKS // if enabled, lycan skill books can be dropped
>>magic reduction stone
#define ENABLE_MAGIC_REDUCTION_SYSTEM // enable resist magic reduction bonus
#define USE_MAGIC_REDUCTION_STONES // enable resist magic reduction stone drops from metins
>>pet system
#define __PET_SYSTEM__ // enable traditional pet system
#define USE_ACTIVE_PET_SEAL_EFFECT // it will activate the pet slot if it's active
#define USE_PET_SEAL_ON_LOGIN // it will automatically spawn the pet after a rewarp
@/Src/Server/db/src/ClientManager.h
#define ENABLE_PROTO_FROM_DB //read protos from db if "PROTO_FROM_DB = 1" is specified inside conf.txt
//mirror protos to db if "MIRROR2DB = 1" is specified inside conf.txt
@/Src/Server/db/src/ClientManager.cpp
#define ENABLE_DEFAULT_PRIV //enable default priv loading from common.priv_settings
#define ENABLE_ITEMAWARD_REFRESH //enable a select query every 5 seconds into player.item_award
@/Src/Server/db/src/ClientManagerBoot.cpp
#define ENABLE_AUTODETECT_VNUMRANGE //if protos are loaded from db, it will automatically detect the vnum range for ds items
@/Src/Server/db/src/ProtoReader.cpp
#define ENABLE_NUMERIC_FIELD //txt protos now can read numbers instead of tags as well
@/Srcs/Server/game/src/stdafx.h
>moved to CommonDefines.h
@/Srcs/Server/game/src/stdafx.h
#define ENABLE_LIMIT_TIME //enable game timestamp expiration
@/Srcs/Server/game/src/guild.h
#define ENABLE_NEWGUILDMAKE //enable pc.make_guild0 and disable CInputMain::AnswerMakeGuild
@/Srcs/Server/game/src/horse_rider.h
#define ENABLE_INFINITE_HORSE_HEALTH_STAMINA // full horse health and stamina all the times
@/Srcs/Server/game/src/quest.h
#define ENABLE_QUEST_DIE_EVENT //add quest event "die"
#define ENABLE_QUEST_BOOT_EVENT //add quest event "boot"
#define ENABLE_QUEST_DND_EVENT //add quest event "dnd"
@/Srcs/Server/game/src/config.cpp
#define ENABLE_CMD_PLAYER //enable PLAYER grade inside CMD
#define ENABLE_EXPTABLE_FROMDB //read the exp table from the db
#define ENABLE_AUTODETECT_INTERNAL_IP //autodetect internal ip if the public one is missing
#define ENABLE_GENERAL_CMD //if enabled, it reads a general CMD from "locale/%s/conf/GENERAL_CMD", "locale/%s/conf/GENERAL_CMD_CHANNEL_%d", and/or "locale/%s/conf/GENERAL_CMD_CHANNEL_%d_HOSTNAME_%s"
#define ENABLE_GENERAL_CONFIG //if enabled, it reads a general CONFIG from "locale/%s/conf/GENERAL_CONFIG", "locale/%s/conf/GENERAL_CONFIG_CHANNEL_%d", and/or "locale/%s/conf/GENERAL_CONFIG_CHANNEL_%d_HOSTNAME_%s"
//in the GENERAL_CONFIG, all the options are valid except: HOSTNAME, CHANNEL, PLAYER_SQL, COMMON_SQL, LOG_SQL, PORT, P2P_PORT, MAP_ALLOW, AUTH_SERVER, TEEN_ADDR, TEEN_PORT
@/Srcs/Server/game/src/char_resist.cpp
#define ENABLE_IMMUNE_PERC //enable 90% of success instead of 100% regarding immunes (antistun/slow/fall)
@/Srcs/Server/game/src/item.cpp
#define ENABLE_IMMUNE_FIX //fix immune bug where you need to equip shield at last (or refresh compute e.g. un/riding horse)
@/Srcs/Server/game/src/item_manager.h
#define ENABLE_ITEM_PROTO_MAP //improves GetTable load by O(1)
@/Srcs/Server/game/src/db.cpp
#define ENABLE_SPAMDB_REFRESH //enable a select query every 10 minutes into common.spam_db
@/Srcs/Server/game/src/questlua.cpp
#define ENABLE_TRANSLATE_LUA //enable translate.lua loading
#define ENABLE_QUESTLIB_EXTRA_LUA //enable questlib_extra.lua loading
@/Srcs/Server/game/src/questlua_dungeon.cpp
#define D_JOIN_AS_JUMP_PARTY //d.join will internally work as d.new_jump_party
@/Srcs/Server/game/src/questlua_pc.cpp
#define ENABLE_LOCALECHECK_CHANGENAME //enable check that unable change name on Europe Locales
#define ENABLE_PC_OPENSHOP //enable pc.open_shop0(idshop) but buy/sell not work yet
@/Srcs/Server/game/src/shop.cpp
#define ENABLE_SHOP_BLACKLIST //enable ignore 70024 (Blessing Marble) and 70035 (Magic Copper Ore)
@/Srcs/Server/game/src/cmd.cpp
#define ENABLE_BLOCK_CMD_SHORTCUT //if enabled, people won't be able to shorten commands
@/Srcs/Server/game/src/cmd_gm.cpp
#define ENABLE_STATPLUS_NOLIMIT //disable only 90 points for con+/int+/str+/dex+ commands
#define ENABLE_SET_STATE_WITH_TARGET // enable set_state target as 3rd arg
#define ENABLE_CMD_IPURGE_EX // /ipurge 2nd arg can remove items from a specific window (inv/equip/ds/belt/all)
@/Srcs/Server/game/src/char_skill.cpp
#define ENABLE_FORCE2MASTERSKILL //skill always pass to m1 when b17 instead of b(number(17-20))
#define ENABLE_NO_MOUNT_CHECK //check whether horse mount vnum should be checked when skilling
#define ENABLE_NULLIFYAFFECT_LIMIT //sura skill 66 won't nullify players with level < or > of yours by 9
#define ENABLE_MASTER_SKILLBOOK_NO_STEPS //if enabled, you will only need a book to increase a master skill, and not as many as the level-20
@/Srcs/Server/game/src/char_item.cpp
#define ENABLE_FIREWORK_STUN //enable stun affect when using firework items
#define ENABLE_ADDSTONE_FAILURE //enable add stone failure
#define ENABLE_EFFECT_EXTRAPOT //enable extrapot effects when using green/purple potions
#define ENABLE_BOOKS_STACKFIX //enable stackable books instead of remove all the pile
#define ENABLE_ITEM_RARE_ATTR_LEVEL_PCT //enable 1-5 level pct for item rare attr add/change
#define ENABLE_UNIQUE_ITEM_AUTOSPLIT //enable autosplit when equipping stacked unique items
@/Srcs/Server/game/src/char_battle.cpp
#define ENABLE_NEWEXP_CALCULATION //recalculate exp rate so you won't get random negative exp/marriage points
#define ENABLE_EFFECT_PENETRATE //enable penetrate effect when performing a penetration
#define ENABLE_NO_DAMAGE_QUEST_RUNNING //if enabled, no damage will be dealt to monsters while running quests (otherwise the quest kill event wouldn't be triggered)
@/Srcs/Server/game/src/char.h
#define NEW_ICEDAMAGE_SYSTEM //add new system for nemere dungeon and so on
#define ENABLE_ANTI_CMD_FLOOD //limit player's command execution to 10 commands per second, otherwise it'll be disconnected!
#define ENABLE_OPEN_SHOP_WITH_ARMOR //if enabled, people can open a personal shop with the armor equipped
#define ENABLE_SKILL_COOLDOWN_CHECK //if enabled, it will add a check on the skill usage to prevent some damage hacks
@/Srcs/Server/game/src/char.cpp
#define ENABLE_SHOWNPCLEVEL //show Lv %d level even for NPCs (not applicable on mob/stone/warp)
#define ENABLE_GOHOME_IF_MAP_NOT_ALLOWED //you'll go back to your village if you're not allowed to go in that map
#define ENABLE_GM_FLAG_IF_TEST_SERVER //show the gm flag if it's on test server mode
#define ENABLE_GM_FLAG_FOR_LOW_WIZARD //show the gm flag for low wizard too
#define ENABLE_MOUNT_ENTITY_REFRESH //it will refresh entities when riding/unriding (it's also a quick work-around when the client desyncs)
@/Srcs/Server/game/src/input_db.cpp
#define ENABLE_GOHOME_IF_MAP_NOT_EXIST //you'll go back to your village if the map doesn't exist
@/Srcs/Server/game/src/guild.cpp
#define ENABLE_GUILD_COMMENT_ANTIFLOOD //prevent flood in guild comments
@/Srcs/Server/game/src/mining.cpp
#define ENABLE_PICKAXE_RENEWAL //if the upgrading of the pickaxe will fail, it won't turn back of 1 grade, but just lose 10% mastering points.
@/Srcs/Server/game/src/fishing.cpp
#define ENABLE_FISHINGROD_RENEWAL //if the upgrading of the fishing rod will fail, it won't turn back of 1 grade, but just lose 10% mastering points.
@/Srcs/Server/game/src/questmanager.cpp
#define ENABLE_PARTYKILL //re-enable PartyKill
@/Srcs/Server/game/src/input_auth.cpp
#define ENABLE_ACCOUNT_W_SPECIALCHARS //enable special characters in account names (account.account.login)
@/Srcs/Server/game/src/input_main.cpp
#define ENABLE_CHAT_COLOR_SYSTEM //enable chat colors based on IsGm or GetEmpire (+colored empire name)
#define ENABLE_CHAT_SPAMLIMIT //limit chat spam to 4 messages for 5 seconds, if you spam it for 10 times, you'll be disconnected!
#define ENABLE_WHISPER_CHAT_SPAMLIMIT //limit whisper chat to 10 messages per 5 seconds, otherwise you'll be disconnected!
#define ENABLE_CHAT_LOGGING //enable chat logging (which saves all the gm chats)
#define ENABLE_CHECK_GHOSTMODE //enable check that blocks the movements if the character is dead
#define ENABLE_TP_SPEED_CHECK //enable speed check teleport back
@/Srcs/Server/game/src/input_login.cpp
#define USE_LYCAN_CREATE_POSITION // if enabled, the lycan will be warped to his own village at character creation
@/Src/Server/game/src/quest/qc.cc
#define ENABLE_WHEN_PARENTHESIS //it enables () [] usage in the when cause for the quest file
* Dependencies
@/Srcs/Extern/include/boost
@/Srcs/Extern/include/cryptopp
@/Srcs/Extern/include/IL
@/Srcs/Extern/lib:
libIL.a //from DevIL
libcryptopp.a //from cryptopp
libjasper.a
libpng.a
libtiff.a
libjbig.a
libmng.a
liblcms.a
libjpeg.a
@/usr/lib/liblzma.a //or lib32
* Database configuration
* How to run tests
* Deployment instructions
### Contribution guidelines ###
* Writing tests
* Code review
#@general
@warme001: be aware about PLAYER_MAX_LEVEL_CONST (common/length.h) and gPlayerMaxLevel (game/config.h)
@warme002: be aware about ITEM_MAX_COUNT (common/item_length.h) and g_bItemCountLimit (game/config.h)
@warme003: do_click_safebox can be used by PLAYER in every map!
@warme004: `when vnum.kill begin` and `when kill begin` are both triggered
@warme005: different locale stuff
@warme006: not implemented stuff from another locale
@warme007: on db/src/ClientManager.cpp; commented locale set from common.locale due to its uselessness and bugginess (./close && ./start)
it processes a NULL mysql connection (dat ymir threading) if there was a bit of overload before starting the process up again
@warme008: on char_item.cpp; now 27996 (poison bottle) can inflict poison
@warme009: on char_resist.cpp; if bleeding is used as poison, the bleeding enchantment is poison enchantment/50 (so mobs can bleed players)
@warme010: on char_state.cpp; test_server is used as "BOOL g_test_server"
@warme011: on dungeon.cpp; you should never use d.join instead of d.new_jump_party since it causes random crashes due to a wrong implementation of the party hash check
@warme012: trivial errors are now considered as simple logs
@warme013: unneccessary errors are now simply commented
@warme014: wrong lua return arguments number
@warme015: increased buffer size for prevention
@warme016: improved info in the relative print
#@common
@fixme400: on tables.h; TPlayerTable hp/mp from short to int (hp/mp >32767 should be fixed)
#@db/src
@fixme201: on ProtoReader.cpp; changed 'SAMLL' into 'SMALL'
@fixme202: on ClientManagerGuild.cpp; fixed the guild remove member time issue if the player was offline
(withdraw_time -> new_withdraw_time)
@fixme203: on ClientManagerPlayer.cpp; dandling pointer for "command"
@fixme204: on Cache.cpp; myshop_pricelist primary key duplication error if there are many items of the same vnum in the personal shop
@fixme205: on Cache.cpp, ClientManager.cpp; "replace into item" was deleting any foreign keys pointed to player.item
#@game/src
@fixme101: on log.cpp; fixed '%s' for invalid_server_log
@fixme102: on cmd_general.cpp; inside ACMD(do_war) fixed the unsigned bug
@fixme103: on config, input_login, input_main.cpp; fixed clientcheckversion (version > date) to (version != date) and delay from 10 to 0
@fixme104: on char.cpp, questlua_pc.cpp; fixed get status point after lv90 changing 90 with gPlayerMaxLevel
@fixme105: on cmd.cpp; disabled every korean command
@fixme106: on input_main.cpp; if a full-speeded player is on a mount (es. lion), he'll be brought back due to the distance range
@fixme107: on char_battle.cpp; if character (player|mob) has negative hp on dead, sura&co will absorb hp/mp losing 'em themselves
@fixme108: on char.cpp; if you change a mount but the previous is not 0, all the entities (npcs&co) in the player client
(not others) are vanished until another refresh (not exists mounts still bug you after second mount call)
@fixme109: on questmanager.cpp; if you kill a player (war m), `when kill begin` will be triggered twice
@fixme110: on char_affect.cpp; if you attack when semi-transparent (revived or ninja skill or white flag) you'll still be transparent
@fixme111: on test.cpp; ConvertAttribute2 has x and y inverted (before y->x after x->y)
@fixme112: on char_item.cpp; you can change bonuses in equipped items too (until re-login)
bonus values will not be refreshed by ChangePoint and unequipping it will remove back only the new bonuses set on
e.g. you had a 2500hp bonus shoes, you changed it to 50mp when equipped and you'll unequipped
what will it happen? instead of remove 2500hp, you won't receive 50mp and you also lose 50mp when unequipped
@fixme113: on char_item.cpp; same thing of #112
you can remove stones from equipped items w/o losing bonuses
e.g. have an item with antiwar+4 equipped:
1) remove all the stones 2) unequip it 3) re-add stone 4) re-equip it 5) repeat it thrice
result? an item with no stones but you'll have 75% of antiwar
@fixme114: on char_item.cpp; gathering of #111, #112 and few others.
@fixme115: on char_item.cpp; you can retrieve all the item on the ground if you're in a party and the owner is not in yours.
@fixme116: on char_skill.cpp; normal horse mount skills cannot inflict damage
@fixme117: on char_item.cpp; you can't swap equipment from inventory if full, and also prevent unmotivated belt swap if its inventory is not empty
@fixme118: on char.cpp; when ComputePoints is called:
you'll gain as many hp/mp as many you have in your equipment bonuses
affect hp/mp will be lost when login or updating
@fixme119: on input_main.cpp; you can put items from safebox/mall to belt inventory w/o checking the type (items with size>1 are not placeable anyway)
@fixme120: on input_login.cpp; few packet IDs not checked
@fixme121: on char_item.cpp; the refine scroll item value 1 from the magic stone was generating useless syserrs
@fixme122: on arena.cpp; few other potions were not checked on arena map
@fixme123: on char_item.cpp; USE_CHANGE_ATTRIBUTE2 (24) sub type check bug (the condition could never be true)
@fixme124: on char_item.cpp; no check on 6-7 add/change items about costume stuff
@fixme125: on char.cpp; dungeon regen pointing to a dangling pointer (not required -> removed)
@fixme126: on marriage.cpp; fix lovepoints overflow
@fixme127: on cube.cpp; /cube r_info exploit fix; it can cause a crash due to an unchecked cube npc masters vnums
e.g. 1) you open the Baek-Go cube's console 2) click on an npc/kill a mob without close the cube console
3) digit /cube r_info 4) crash core
@fixme128: on char.cpp; mining hack fix; you can mine a vein anywhere in the map because there's no check on the character
which means, you can stay at 0x0y and mining a vein in 666x999y and get the stuff beside him or in the pc's inventory
@fixme129: on PetSystem.cpp; the azrael pets (53005->34004 normal/53006->34009 gold) don't give the buff if not in dungeon at summon up and remove them anyway when unsummoned
@fixme130: on messenger_manager.cpp; and cmd_general.cpp if you do /messenger_auth n XXX, the player with the name XXX will receive a "refused friend invite" print from you
which means, if you flood this packet, the "victim" will be disconnected or at maximum could get lag
@fixme131: on char.cpp; fix annoying sync packets sendable even on unfightable pc/npc entities
e.g. wallhack against players' shops inside the village's squares (where the NOPK attr is set) to move them out and kill them
@fixme132: on shop.cpp; if two people buy the same item at the same time from a pc's shop, the slower one will receive a wrong return packet (crash client)
@fixme133: on input_main.cpp; banword check and hyper text feature were processing the final chat string instead of the raw one
@fixme134: on questlua_pc.cpp; the pc.mount_bonus was addable even if the mount wasn't spawn (only /unmount pc.unmount can remove it)
@fixme135: on char.cpp; if the Sync is made before a move packet and the sectree differs of few x/y coordinates, the sectree will be changed without update (crash character) (troublesome -> removed)
@fixme136: on char.cpp; there are no checks about the zero division exception: e.g. if you set a mob's max hp to 0 in the mob proto, you'll get random crashes.
@fixme137: on char_battle.cpp; when a player dies, the HP could have a negative value. Now it's 0 like the official.
@fixme138: on db.cpp, input_auth.cpp; the account's password was shown in the mysql history queries as clear text at every login attempt (mysql full granted user required -> now hashed)
@fixme139: on shop.h; CShop class destructor wasn't virtual. If a derived class like CShopEx was deleted, a memory leak would have been generated.
@fixme140: on input_main.cpp; the belt could be put into the safebox even though the belt inventory isn't empty.
@fixme141: on char_item.cpp; the items in the belt inventory could be used even if their slot were not available
@fixme142: on messenger_manager.cpp; sql injection fix about net.SendMessengerRemovePacket
@fixme143: on guild_manager.cpp; sql injection fix about net.SendAnswerMakeGuildPacket
@fixme144: on sectree_manager.cpp; if map/index doesn't end with a newline, the game will crash (before refactory)
@fixme145: on input_main.cpp; guild_add_member can add any vid as guild's member even if it's a mob or an npc
@fixme147: on char_item.cpp; ramadan candy item can be used even if the relative affect is still up
@fixme148: on item_manager_read_tables.cpp; type quest, special, attr not handled in ConvSpecialDropItemFile
@fixme149: on char.cpp; refine material skip exploit if items are swapped
@fixme150: on exchange.cpp; char_item.cpp; prevent item module swapping if the quest is suspended
@fixme152: on questlua_pc.cpp; pc.get_special_ride_vnum was checking socket2 instead of socket0
@fixme153: on threeway_war.cpp; kills made of people over lvl99 weren't counted
@fixme154: on cmd_gm.cpp; the /all_skill_master command will now set the right amount of points to the sub skills
@fixme156: on char_affect.cpp; prevent doubling the affect values before they are loaded (such as pc.mount_bonus at login; because the quest is loaded before the quests)
@fixme157: on OxEvent.cpp; the attender list wasn't cleared after stopping the ox event
@fixme158: on input_main.cpp; the deviltower refiner won't set the flag to 0 anymore if you have no money, and it will decrease it by 1 for allowing multiple refine attempts
@fixme159: on exchange.cpp; when exchanging, a wrong check in the ds items was not allowing the exchange due to "not enough space in ds inventory" if the first sub ds inventory slot was not empty
@fixme160: on DragonSoul.cpp; when removing a ds stone, if the destination slot wasn't empty, the ds item in there would have been replaced and lost
@fixme168: on questevent.cpp; if the quest info name is already null, the std::string constructor will throw an exception
@fixme169: on char_item.cpp; missing checks for mythical peach like a second vnum and nullptr
@fixme170: on item.cpp; missing condition on special mineral slots for just 2 bonuses
@fixme171: on dungeon.cpp; FCountMonster was also counting horses and pets
@fixme172: on dungeon.cpp; FNotice was sending ChatPackets to even non-player characters
@fixme173: on item.cpp; by pressing \\z to pick up items, sometimes, it would fail due to far distance
@fixme174: on questmanager.cpp; in case of quest error in server_timer, it would try to print the error to the current player causing a core crash
@fixme177: on cmd_gm.cpp; /priv_guild snprintf had an empty format
@fixme179: on ClientManagerBoot.cpp, ProtoReader.cpp; the item size with 0 length will cause game cores
@fixme180: on cmd_general.cpp; /costume will cause game core crashes if the relative costume bonus ids aren't present inside fn_string or have no %d
@fixme182: on input_login.cpp; you'd get no horse level if you relogged in with no job set
@fixme183: on input_main.cpp, messenger_manager.cpp; player rename wasn't clearing the previous nickname from the friendlist
@fixme184: on length.h; some slots of the dragon soul inventory weren't working properly
@fixme185: on ClientManagerBoot.cpp; the material count var isn't initialized and cause crashes on certain circumstances
@fixme186: on item.cpp; the ClearMountAttributeAndAffect without owner would trigger a core crash
@fixme187: on input.cpp; the input buffer will keep increasing until it saturates the ram if people keep sending broken packets
@fixme188: on char.h, questlua_npc|dungeon|global.cpp, dungeon.cpp; the scripted npc->Dead() was triggering player rewards if the mob was previously damaged
@fixme189: on item_manager.cpp; the Stones array had an out of range error
@fixme190: on input_login.cpp; exploit by accessing non-existing players
@fixme191: on safebox.cpp; switching safebox size level was causing a memory leak
@fixme192: on char_battle.cpp; the deathblow wasn't affecting warrior and wolfman races
@fixme193: on guild_manager.cpp; observer players can be killed to increment the guild war kills
@fixme194: on char_battle.cpp; mobs killed in non attackable zones weren't dropping yangs/items
@fixme195: on regen.cpp; missing 'ma' 'ra' 'sa' handling regen type
@fixme196: on char_item.cpp; possible item duplication bug while moving splitted items onto the same slot
@fixme197: on cmd_general.cpp; stucked connections while fully quitting from game would leave the character online
@fixme198: on char_battle.cpp; karma drop duplication bug: the dropped item gets duplicated after warping to another game core
@fixme199: on char.h, char.cpp, char_item.cpp, char_quickslot.cpp; the mobs were allocating unused memory
@fixme300: on cmd_gm.cpp; /full and /ipurge were causing a glitch in the status page by having negative status
@fixme301: on input_main.cpp, char.cpp; leaders and party members can leave the party while being on other channels
@fixme302: on questpc.cpp; HEADER_GC_QUEST_INFO had a wrong calculated size
@fixme303: on item_manager_read_tables.cpp; the load of items had O(n) complexity for each vnum of any Group
@fixme304: on char.h, char.cpp; yielded quest states were pointing to dangling item pointers
@fixme305: on char_skill.cpp; skill affects were not cleared after a skill reset
@fixme306: on char.cpp; real time items were not expired if inside the safebox
@fixme307: on cmd_general.cpp; crash core if the item for feeding the horse didn't exist in the item proto
@fixme308: on sectree_manager.cpp; when loading map/index, if the map is already loaded, the regen will duplicate
@fixme309: on questlua_pc.cpp; flushing the cache after changing the player name was causing item duplication
@fixme310: on ClientManager.cpp; only the first 3 players of the account had a full empire select check
@fixme311: on questmanager.cpp; CancelServerTimers not properly erasing the element from the container
@fixme312: on char_skill.cpp; mobs could ran away on death instead of playing the death animation
@fixme313: on char.cpp; very fast mounts would reach coordinates like -2147483648 and being unable to sync
@fixme314: on char_item.cpp; unique items can now be be stackable without issues
@fixme315: on building.cpp; skip guild land load from other maps
@fixme316: on char_item.cpp; items with sockets set at runtime weren't automatically stacked properly
#@/Server (general)
@fixme401: fixed the guild disband time issue
on db/src/ClientManagerGuild.cpp
(withdraw_time -> new_disband_time)
on game/src/guild.cpp
(new_withdraw_time -> new_disband_time)
@fixme402: fixed the usage of the affect system before its loading
on game/src/char_item.cpp
added an IsAffectLoaded check when using an item
@fixme403: fixed player.myshop_pricelist corrupted data
on db/src/ClientManager.cpp; db/src/ClientManager.h; game/src/char.cpp
TPacketMyshopPricelistHeader to TItemPriceListTable
#@/General
@fixme501: on game/src/char.h, game/src/char.cpp, game/src/packet.h; mob race word to dword
@fixme502: on common/tables.h, game/src/packet.h; character part word to dword
* Other guidelines
## Trick to replace ALUA macro (notepad++) for all questlua*.cpp files (CTRL+F)
# Find (Search Type -> Regular Expression)
int[ \t]*([A-Za-z0-9\_]+)[ \t]*\([ \t]*lua_State[ \t]*\*[ \t]*[\/\*]*L[\*\/]*[ \t]*\)
# Replace with (File -> Save all) [26 files, 621 replaces]
ALUA\($1\)
### Who do I talk to? ###
* Repo owner or admin
martysama0134

View File

@ -0,0 +1,149 @@
CC = clang
CXX = clang++
PLATFORM = $(shell file /bin/ls | cut -d' ' -f3 | cut -d'-' -f1)
BSD_VERSION = $(shell uname -v 2>&1 | cut -d' ' -f2 | cut -d'.' -f1)
SVR_VERSION = $(shell cat __REVISION__)
.PHONY: liblua libsql libgame libpoly libthecore game db
default: liblua libsql libgame libpoly libthecore game db
@echo "--------------------------------------"
@echo "Build Done"
@echo "--------------------------------------"
quick: .
$(MAKE) -C liblua/5.0
$(MAKE) -C libsql
$(MAKE) -C libgame/src
$(MAKE) -C libpoly
$(MAKE) -C libthecore/src
touch game/src/main.cpp
$(MAKE) -C game/src
$(MAKE) -C game/src symlink
touch db/src/Main.cpp
$(MAKE) -C db/src
$(MAKE) -C db/src symlink
liblua: .
$(MAKE) -C $@/5.0 clean
$(MAKE) -C $@/5.0
libsql: .
@touch $@/Depend
$(MAKE) -C $@ dep
$(MAKE) -C $@ clean
$(MAKE) -C $@
libgame: .
@touch $@/src/Depend
$(MAKE) -C $@/src dep
$(MAKE) -C $@/src clean
$(MAKE) -C $@/src
libpoly: .
@touch $@/Depend
$(MAKE) -C $@ dep
$(MAKE) -C $@ clean
$(MAKE) -C $@
libthecore: .
@touch $@/src/Depend
$(MAKE) -C $@/src dep
$(MAKE) -C $@/src clean
$(MAKE) -C $@/src
game: .
@touch $@/src/Depend
$(MAKE) -C $@/src dep
$(MAKE) -C $@/src clean
# $(MAKE) -C $@/src limit_time
$(MAKE) -C $@/src
$(MAKE) -C $@/src symlink
db: .
@touch $@/src/Depend
$(MAKE) -C $@/src dep
$(MAKE) -C $@/src clean
$(MAKE) -C $@/src
$(MAKE) -C $@/src symlink
ver:
@$(CC) -v
ver2:
@$(CC) -v
$(MAKE) -C game/src ver
symlink:
$(MAKE) -C game/src symlink
$(MAKE) -C db/src symlink
strip:
$(MAKE) -C game/src strip
$(MAKE) -C db/src strip
clean:
$(MAKE) -C liblua/5.0 clean
$(MAKE) -C libsql clean
$(MAKE) -C libgame/src clean
$(MAKE) -C libpoly clean
$(MAKE) -C libthecore/src clean
$(MAKE) -C game/src clean
$(MAKE) -C db/src clean
all:
@echo "--------------------------------------"
@echo "Update Revision"
@echo "--------------------------------------"
@expr $(SVR_VERSION) + 1 > __REVISION__
@cat __REVISION__
@echo "--------------------------------------"
@echo "Full Build Start"
@echo "--------------------------------------"
$(MAKE) -C liblua/5.0 clean
$(MAKE) -C liblua/5.0
# $(MAKE) -C liblua/5.2 clean
# $(MAKE) -C liblua/5.2 freebsd
# $(MAKE) -C liblua/5.2 local
@touch libsql/Depend
$(MAKE) -C libsql dep
$(MAKE) -C libsql clean
$(MAKE) -C libsql
@touch libgame/src/Depend
$(MAKE) -C libgame/src dep
$(MAKE) -C libgame/src clean
$(MAKE) -C libgame/src
@touch libpoly/Depend
$(MAKE) -C libpoly dep
$(MAKE) -C libpoly clean
$(MAKE) -C libpoly
@touch libthecore/src/Depend
$(MAKE) -C libthecore/src dep
$(MAKE) -C libthecore/src clean
$(MAKE) -C libthecore/src
@touch game/src/Depend
$(MAKE) -C game/src dep
$(MAKE) -C game/src clean
# $(MAKE) -C game/src limit_time
$(MAKE) -C game/src
$(MAKE) -C game/src symlink
# $(MAKE) -C game/src strip
@touch db/src/Depend
$(MAKE) -C db/src dep
$(MAKE) -C db/src clean
$(MAKE) -C db/src
$(MAKE) -C db/src symlink
# $(MAKE) -C db/src strip
@echo "--------------------------------------"
@echo "Full Build End"
@echo "--------------------------------------"

View File

@ -0,0 +1 @@
41023

View File

@ -0,0 +1,105 @@
#ifndef __INC_METIN2_COMMON_DEFINES_H__
#define __INC_METIN2_COMMON_DEFINES_H__
#pragma once
//////////////////////////////////////////////////////////////////////////
// ### Standard Features ###
#define _IMPROVED_PACKET_ENCRYPTION_
#ifdef _IMPROVED_PACKET_ENCRYPTION_
#define USE_IMPROVED_PACKET_DECRYPTED_BUFFER
#endif
#define __UDP_BLOCK__
//#define ENABLE_QUEST_CATEGORY
// ### END Standard Features ###
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// ### New Features ###
#define ENABLE_NO_MOUNT_CHECK
#define ENABLE_D_NJGUILD
#define ENABLE_FULL_NOTICE
#define ENABLE_NEWSTUFF
#define ENABLE_PORT_SECURITY
#define ENABLE_BELT_INVENTORY_EX
#define ENABLE_CMD_WARP_IN_DUNGEON
// #define ENABLE_ITEM_ATTR_COSTUME
// #define ENABLE_SEQUENCE_SYSTEM
#define ENABLE_PLAYER_PER_ACCOUNT5
#define ENABLE_DICE_SYSTEM
#define ENABLE_EXTEND_INVEN_SYSTEM
#define ENABLE_MOUNT_COSTUME_SYSTEM
#define ENABLE_WEAPON_COSTUME_SYSTEM
#define ENABLE_QUEST_DIE_EVENT
#define ENABLE_QUEST_BOOT_EVENT
#define ENABLE_QUEST_DND_EVENT
#define ENABLE_PET_SYSTEM_EX
#define ENABLE_SKILL_FLAG_PARTY
#define ENABLE_NO_DSS_QUALIFICATION
// #define ENABLE_NO_SELL_PRICE_DIVIDED_BY_5
#define ENABLE_CHECK_SELL_PRICE
#define ENABLE_GOTO_LAG_FIX
#define ENABLE_MOUNT_COSTUME_EX_SYSTEM
#define ENABLE_PENDANT_SYSTEM
#define ENABLE_GLOVE_SYSTEM
#define ENABLE_MOVE_CHANNEL
#define ENABLE_QUIVER_SYSTEM
#define ENABLE_REDUCED_ENTITY_VIEW
#define ENABLE_GUILD_TOKEN_AUTH
#define ENABLE_DS_GRADE_MYTH
#define ENABLE_DB_SQL_LOG
#define __PET_SYSTEM__
#ifdef __PET_SYSTEM__
#define USE_ACTIVE_PET_SEAL_EFFECT
#define PET_SEAL_ACTIVE_SOCKET_IDX 2
#define USE_PET_SEAL_ON_LOGIN
#endif
enum eCommonDefines {
MAP_ALLOW_LIMIT = 32, // 32 default
};
#define ENABLE_WOLFMAN_CHARACTER
#ifdef ENABLE_WOLFMAN_CHARACTER
// #define DISABLE_WOLFMAN_ON_CREATE
#define USE_MOB_BLEEDING_AS_POISON
#define USE_MOB_CLAW_AS_DAGGER
// #define USE_ITEM_BLEEDING_AS_POISON
// #define USE_ITEM_CLAW_AS_DAGGER
#define USE_WOLFMAN_STONES
#define USE_WOLFMAN_BOOKS
#endif
// #define ENABLE_MAGIC_REDUCTION_SYSTEM
#ifdef ENABLE_MAGIC_REDUCTION_SYSTEM
// #define USE_MAGIC_REDUCTION_STONES
#endif
// ### END New Features ###
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// ### Ex Features ###
#define DISABLE_STOP_RIDING_WHEN_DIE // if DISABLE_TOP_RIDING_WHEN_DIE is defined, the player doesn't lose the horse after dying
#define ENABLE_ACCE_COSTUME_SYSTEM //fixed version
// #define USE_ACCE_ABSORB_WITH_NO_NEGATIVE_BONUS //enable only positive bonus in acce absorb
#define ENABLE_HIGHLIGHT_NEW_ITEM //if you want to see highlighted a new item when dropped or when exchanged
#define ENABLE_KILL_EVENT_FIX //if you want to fix the 0 exp problem about the when kill lua event (recommended)
// #define ENABLE_SYSLOG_PACKET_SENT // debug purposes
#define ENABLE_EXTEND_ITEM_AWARD //slight adjustement
#ifdef ENABLE_EXTEND_ITEM_AWARD
// #define USE_ITEM_AWARD_CHECK_ATTRIBUTES //it prevents bonuses higher than item_attr lvl1-lvl5 min-max range limit
#endif
#define ENABLE_CHEQUE_SYSTEM
#ifdef ENABLE_CHEQUE_SYSTEM
#define ENABLE_SHOP_USE_CHEQUE
#define DISABLE_CHEQUE_DROP
#define ENABLE_WON_EXCHANGE_WINDOW
#endif
// ### END Ex Features ###
//////////////////////////////////////////////////////////////////////////
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,266 @@
// martysama0134's PulseManager class for quick anti-flood code implementation
#ifndef __COMMON__PULSEMANAGER_H__
#define __COMMON__PULSEMANAGER_H__
#pragma once
#include <cstdint>
#include <ctime>
#include <unordered_map>
#include <chrono>
enum class ePulse {
GuildComment,
CommandRequest,
ItemDrop,
BoxOpening,
BuySell,
SafeboxMove,
ChannelStatus,
RideMount,
SharedRequest,
};
// #define __PULSEMANAGER__SECOND_SUPPORT__
#define __PULSEMANAGER__CLOCK_SUPPORT__
// #define __PULSEMANAGER__M2_SUPPORT__
#ifdef __PULSEMANAGER__M2_SUPPORT__
#include "../libthecore/include/stdafx.h"
#endif
#define PULSEMANAGER_CLOCK_TO_SEC(diff) (std::chrono::duration_cast<std::chrono::milliseconds>(diff).count()/1000.0)
#define PULSEMANAGER_CLOCK_TO_SEC2(key1, key2) (PULSEMANAGER_CLOCK_TO_SEC(PulseManager::Instance().DiffClock(key1, key2)))
class PulseManager
{
public:
using SubKeyT = ePulse;
using MainKeyT = uint32_t;
#ifdef __PULSEMANAGER__M2_SUPPORT__
using PulseT = int;
using PulseMapT = std::unordered_map<SubKeyT, PulseT>;
using MainPulseMapT = std::unordered_map<MainKeyT, PulseMapT>;
PulseT passesPerSec{ 25 };
MainPulseMapT pulseMap;
#endif
#ifdef __PULSEMANAGER__SECOND_SUPPORT__
using SecondT = time_t;//uint32_t;
using SecondMapT = std::unordered_map<SubKeyT, SecondT>;
using MainSecondMapT = std::unordered_map<MainKeyT, SecondMapT>;
MainSecondMapT secondMap;
#endif
#ifdef __PULSEMANAGER__CLOCK_SUPPORT__
using TypeClock = std::chrono::high_resolution_clock;
using ClockT = TypeClock::time_point;
using DurationT = TypeClock::duration;
using CountT = int64_t;
using PairValueT = std::pair<DurationT, CountT>;
using ClockMapT = std::unordered_map<SubKeyT, PairValueT>;
using MainClockMapT = std::unordered_map<MainKeyT, ClockMapT>;
MainClockMapT clockMap;
#endif
static PulseManager& Instance() {
thread_local PulseManager _this;
return _this;
}
#ifdef __PULSEMANAGER__SECOND_SUPPORT__
inline static SecondT GetTime() {
return time(0); //get_global_time();//get_dword_time();
}
/* SECOND BLOCK */
SecondT GetSecond(MainKeyT key1, SubKeyT key2) {
auto it1 = secondMap.find(key1);
if (it1 == secondMap.end())
return 0;
auto it2 = it1->second.find(key2);
if (it2 == it1->second.end())
return 0;
return it2->second;
}
void SetSecond(MainKeyT key1, SubKeyT key2, SecondT value, bool appendCurrent = true) {
if (appendCurrent)
value += GetTime();
secondMap[key1][key2] = value;
}
bool CheckSecond(MainKeyT key1, SubKeyT key2, SecondT nextLapse) {
if (GetSecond(key1, key2) > GetTime())
return false;
SetSecond(key1, key2, nextLapse, true);
return true;
}
#endif
#ifdef __PULSEMANAGER__CLOCK_SUPPORT__
inline static DurationT GetChrono() {
return std::chrono::high_resolution_clock::now().time_since_epoch();
}
/* CLOCK BLOCK */
PairValueT GetPair(MainKeyT key1, SubKeyT key2) const {
const auto it1 = clockMap.find(key1);
if (it1 == clockMap.end())
return {TypeClock::duration::zero(), 0};
const auto it2 = it1->second.find(key2);
if (it2 == it1->second.end())
return {TypeClock::duration::zero(), 0};
return it2->second;
}
DurationT GetClock(MainKeyT key1, SubKeyT key2) const {
return GetPair(key1, key2).first;
}
CountT GetCount(MainKeyT key1, SubKeyT key2) const {
return GetPair(key1, key2).second;
}
void SetPair(MainKeyT key1, SubKeyT key2, PairValueT pair, bool appendCurrent = true) {
if (appendCurrent)
pair.first += GetChrono();
clockMap[key1][key2] = pair;
}
void SetClock(MainKeyT key1, SubKeyT key2, DurationT value, bool appendCurrent = true) {
if (appendCurrent)
value += GetChrono();
clockMap[key1][key2].first = value;
}
void SetCount(MainKeyT key1, SubKeyT key2, CountT count, bool decreaseValue = true) {
if (decreaseValue)
clockMap[key1][key2].second -= count;
else
clockMap[key1][key2].second = count;
}
bool CheckClock(MainKeyT key1, SubKeyT key2) {
if (GetClock(key1, key2) > GetChrono())
return false;
return true;
}
bool IncreaseClock(MainKeyT key1, SubKeyT key2, DurationT nextLapse) {
if (!CheckClock(key1, key2))
return false;
SetClock(key1, key2, nextLapse, true);
return true;
}
bool CheckCount(MainKeyT key1, SubKeyT key2) {
//std::cout << "CHECK COUNT " << GetCount(key1, key2) << std::endl;
SetCount(key1, key2, 1, true);
if (GetCount(key1, key2) <= 0)
return false;
return true;
}
bool IncreaseCount(MainKeyT key1, SubKeyT key2, DurationT nextLapse, CountT maxCount) {
if (!CheckClock(key1, key2)) { // if clock fails, check if max count is reached
if (!CheckCount(key1, key2))
return false;
return true;
}
SetPair(key1, key2, { nextLapse, maxCount }, true);
return true;
}
DurationT DiffClock(MainKeyT key1, SubKeyT key2) {
return GetClock(key1, key2) - GetChrono();
}
void ClearClock(MainKeyT key1) {
auto it1 = clockMap.find(key1);
if (it1 == clockMap.end())
return;
clockMap.erase(it1);
}
void ClearClock(MainKeyT key1, SubKeyT key2) {
auto it1 = clockMap.find(key1);
if (it1 == clockMap.end())
return;
auto it2 = it1->second.find(key2);
if (it2 == it1->second.end())
return;
it1->second.erase(it2);
}
#endif
#ifdef __PULSEMANAGER__M2_SUPPORT__
void SetPassesPerSec(PulseT v) {
passesPerSec = v;
}
PulseT Sec2Pulse(SecondT v) {
return v * passesPerSec;
}
SecondT Pulse2Sec(PulseT v) {
return v / passesPerSec;
}
inline static PulseT GetCorePulse() {
return thecore_pulse();
}
/* CLOCK BLOCK */
bool HasPulse(MainKeyT key1, SubKeyT key2) {
auto it1 = pulseMap.find(key1);
if (it1 == pulseMap.end())
return false;
auto it2 = it1->second.find(key2);
if (it2 == it1->second.end())
return false;
return true;
}
PulseT GetPulse(MainKeyT key1, SubKeyT key2) {
auto it1 = pulseMap.find(key1);
if (it1 == pulseMap.end())
return 0;
auto it2 = it1->second.find(key2);
if (it2 == it1->second.end())
return 0;
return it2->second;
}
void SetPulse(MainKeyT key1, SubKeyT key2, PulseT value, bool appendCurrent = true) {
if (appendCurrent)
value += GetCorePulse();
pulseMap[key1][key2] = value;
}
bool CheckPulse(MainKeyT key1, SubKeyT key2, PulseT nextLapse) {
if (GetPulse(key1, key2) > GetCorePulse())
return false;
SetPulse(key1, key2, nextLapse, true);
return true;
}
SecondT GetPSecond(MainKeyT key1, SubKeyT key2) {
auto v = GetPulse(key1, key2);
return Pulse2Sec(v);
}
void SetPSecond(MainKeyT key1, SubKeyT key2, SecondT value, bool appendCurrent = true) {
auto pulses = Sec2Pulse(value);
// if (appendCurrent)
// pulses += GetTime();
SetPulse(key1, key2, pulses, true);
}
#endif
};
#endif // __COMMON__PULSEMANAGER_H__
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,38 @@
#ifndef __HEADER_VNUM_HELPER__
#define __HEADER_VNUM_HELPER__
class CItemVnumHelper
{
public:
static const bool IsPhoenix(DWORD vnum) { return 53001 == vnum; }
static const bool IsRamadanMoonRing(DWORD vnum) { return 71135 == vnum; }
static const bool IsHalloweenCandy(DWORD vnum) { return 71136 == vnum; }
static const bool IsHappinessRing(DWORD vnum) { return 71143 == vnum; }
static const bool IsLovePendant(DWORD vnum) { return 71145 == vnum; }
};
class CMobVnumHelper
{
public:
static bool IsPhoenix(DWORD vnum) { return 34001 == vnum; }
static bool IsIcePhoenix(DWORD vnum) { return 34003 == vnum; }
static bool IsPetUsingPetSystem(DWORD vnum) { return (IsPhoenix(vnum) || IsReindeerYoung(vnum)) || IsIcePhoenix(vnum); }
static bool IsReindeerYoung(DWORD vnum) { return 34002 == vnum; }
static bool IsRamadanBlackHorse(DWORD vnum) { return 20119 == vnum || 20219 == vnum || 22022 == vnum; }
};
class CVnumHelper
{
};
#endif //__HEADER_VNUM_HELPER__
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,16 @@
#ifndef __INC_METIN_II_COMMON_BILLING_H__
#define __INC_METIN_II_COMMON_BILLING_H__
enum EBillingTypes
{
BILLING_NONE,
BILLING_IP_FREE,
BILLING_FREE,
BILLING_IP_TIME,
BILLING_IP_DAY,
BILLING_TIME,
BILLING_DAY,
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,64 @@
#ifndef __METIN_II_COMMON_BUILDING_H__
#define __METIN_II_COMMON_BUILDING_H__
namespace building
{
enum
{
OBJECT_MATERIAL_MAX_NUM = 5,
};
typedef struct SLand
{
DWORD dwID;
long lMapIndex;
long x, y;
long width, height;
DWORD dwGuildID;
BYTE bGuildLevelLimit;
DWORD dwPrice;
} TLand;
typedef struct SObjectMaterial
{
DWORD dwItemVnum;
DWORD dwCount;
} TObjectMaterial;
typedef struct SObjectProto
{
DWORD dwVnum;
DWORD dwPrice;
TObjectMaterial kMaterials[OBJECT_MATERIAL_MAX_NUM];
DWORD dwUpgradeVnum;
DWORD dwUpgradeLimitTime;
long lLife;
long lRegion[4];
DWORD dwNPCVnum;
long lNPCX;
long lNPCY;
DWORD dwGroupVnum;
DWORD dwDependOnGroupVnum;
} TObjectProto;
typedef struct SObject
{
DWORD dwID;
DWORD dwLandID;
DWORD dwVnum;
long lMapIndex;
long x, y;
float xRot;
float yRot;
float zRot;
long lLife;
} TObject;
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,69 @@
#ifndef __INC_COMMON_CACHE_H__
#define __INC_COMMON_CACHE_H__
template <typename T> class cache
{
public:
cache()
: m_bNeedQuery(false), m_expireTime(600), m_lastUpdateTime(0)
{
m_lastFlushTime = time(0);
memset( &m_data, 0, sizeof(m_data) );
}
T * Get(bool bUpdateTime = true)
{
if (bUpdateTime)
m_lastUpdateTime = time(0);
return &m_data;
}
void Put(T * pNew, bool bSkipQuery = false)
{
thecore_memcpy(&m_data, pNew, sizeof(T));
m_lastUpdateTime = time(0);
if (!bSkipQuery)
m_bNeedQuery = true;
}
bool CheckFlushTimeout()
{
if (m_bNeedQuery && time(0) - m_lastFlushTime > m_expireTime)
return true;
return false;
}
bool CheckTimeout()
{
if (time(0) - m_lastUpdateTime > m_expireTime)
return true;
return false;
}
void Flush()
{
if (!m_bNeedQuery)
return;
OnFlush();
m_bNeedQuery = false;
m_lastFlushTime = time(0);
}
virtual void OnFlush() = 0;
protected:
T m_data;
bool m_bNeedQuery;
time_t m_expireTime;
time_t m_lastUpdateTime;
time_t m_lastFlushTime;
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,40 @@
#ifndef __INC_METIN_II_D3DTYPE_H__
#define __INC_METIN_II_D3DTYPE_H__
typedef struct D3DXVECTOR2
{
float x, y;
} D3DXVECTOR2, *LPD3DXVECTOR2;
typedef struct D3DXVECTOR3
{
float x, y, z;
} D3DXVECTOR3, *LPD3DXVECTOR3;
typedef struct D3DXVECTOR4
{
float x, y, z, w;
} D3DXVECTOR4, *LPD3DXVECTOR4;
typedef struct D3DXQUATERNION
{
float x, y, z, w;
} D3DXQUATERNION, *LPD3DXQUATERNION;
typedef struct D3DXCOLOR
{
float r, g, b, a;
} D3DXCOLOR, *LPD3DXCOLOR;
typedef struct _D3DCOLORVALUE
{
float r;
float g;
float b;
float a;
} D3DCOLORVALUE;
typedef D3DXVECTOR3 D3DVECTOR;
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,447 @@
#ifndef __INC_METIN2_ITEM_LENGTH_H__
#define __INC_METIN2_ITEM_LENGTH_H__
#include "CommonDefines.h"
enum EItemMisc
{
ITEM_NAME_MAX_LEN = 24,
ITEM_VALUES_MAX_NUM = 6,
ITEM_SMALL_DESCR_MAX_LEN = 256,
ITEM_LIMIT_MAX_NUM = 2,
ITEM_APPLY_MAX_NUM = 3,
ITEM_SOCKET_MAX_NUM = 3,
ITEM_MAX_COUNT = 200,
ITEM_ATTRIBUTE_NORM_NUM = 5,
ITEM_ATTRIBUTE_RARE_NUM = 2,
ITEM_ATTRIBUTE_NORM_START = 0,
ITEM_ATTRIBUTE_NORM_END = ITEM_ATTRIBUTE_NORM_START + ITEM_ATTRIBUTE_NORM_NUM,
ITEM_ATTRIBUTE_RARE_START = ITEM_ATTRIBUTE_NORM_END,
ITEM_ATTRIBUTE_RARE_END = ITEM_ATTRIBUTE_RARE_START + ITEM_ATTRIBUTE_RARE_NUM,
ITEM_ATTRIBUTE_MAX_NUM = ITEM_ATTRIBUTE_RARE_END, // 7
ITEM_ATTRIBUTE_MAX_LEVEL = 5,
ITEM_AWARD_WHY_MAX_LEN = 50,
REFINE_MATERIAL_MAX_NUM = 5,
ITEM_ELK_VNUM = 50026,
};
const BYTE ITEM_SOCKET_REMAIN_SEC = 0;
enum EItemValueIdice
{
ITEM_VALUE_DRAGON_SOUL_POLL_OUT_BONUS_IDX = 0,
ITEM_VALUE_CHARGING_AMOUNT_IDX = 0,
ITEM_VALUE_SECONDARY_COIN_UNIT_IDX = 0,
};
enum EItemDragonSoulSockets
{
ITEM_SOCKET_DRAGON_SOUL_ACTIVE_IDX = 2,
ITEM_SOCKET_CHARGING_AMOUNT_IDX = 2,
};
enum EItemUniqueSockets
{
ITEM_SOCKET_UNIQUE_SAVE_TIME = ITEM_SOCKET_MAX_NUM - 2,
ITEM_SOCKET_UNIQUE_REMAIN_TIME = ITEM_SOCKET_MAX_NUM - 1
};
enum EItemTypes
{
ITEM_NONE, //0
ITEM_WEAPON,
ITEM_ARMOR,
ITEM_USE,
ITEM_AUTOUSE, //4
ITEM_MATERIAL, //5
ITEM_SPECIAL,
ITEM_TOOL, //7
ITEM_LOTTERY,
ITEM_ELK,
ITEM_METIN, //10
ITEM_CONTAINER, //11
ITEM_FISH,
ITEM_ROD, //13
ITEM_RESOURCE, //14
ITEM_CAMPFIRE, //15
ITEM_UNIQUE, //16
ITEM_SKILLBOOK, //17
ITEM_QUEST, //18
ITEM_POLYMORPH, //19
ITEM_TREASURE_BOX,
ITEM_TREASURE_KEY,
ITEM_SKILLFORGET, //22
ITEM_GIFTBOX, //23
ITEM_PICK, //24
ITEM_HAIR,
ITEM_TOTEM,
ITEM_BLEND,
ITEM_COSTUME,
ITEM_DS,
ITEM_SPECIAL_DS,
ITEM_EXTRACT,
ITEM_SECONDARY_COIN,
ITEM_RING,
ITEM_BELT,
ITEM_PET,
};
enum EMetinSubTypes
{
METIN_NORMAL,
METIN_GOLD,
};
enum EWeaponSubTypes
{
WEAPON_SWORD,
WEAPON_DAGGER,
WEAPON_BOW,
WEAPON_TWO_HANDED,
WEAPON_BELL,
WEAPON_FAN,
WEAPON_ARROW,
WEAPON_MOUNT_SPEAR,
#ifdef ENABLE_WOLFMAN_CHARACTER
WEAPON_CLAW = 8,
#endif
#ifdef ENABLE_QUIVER_SYSTEM
WEAPON_QUIVER = 9,
#endif
WEAPON_NUM_TYPES,
};
enum EArmorSubTypes
{
ARMOR_BODY,
ARMOR_HEAD,
ARMOR_SHIELD,
ARMOR_WRIST,
ARMOR_FOOTS,
ARMOR_NECK,
ARMOR_EAR,
ARMOR_PENDANT, //7
ARMOR_GLOVE, //8
ARMOR_NUM_TYPES
};
enum ECostumeSubTypes
{
COSTUME_BODY = ARMOR_BODY,
COSTUME_HAIR = ARMOR_HEAD,
#ifdef ENABLE_MOUNT_COSTUME_SYSTEM
COSTUME_MOUNT = 2,
#endif
#ifdef ENABLE_ACCE_COSTUME_SYSTEM
COSTUME_ACCE = 3,
#endif
#ifdef ENABLE_WEAPON_COSTUME_SYSTEM
COSTUME_WEAPON = 4,
#endif
COSTUME_NUM_TYPES,
};
#ifdef ENABLE_ACCE_COSTUME_SYSTEM
enum EAcceInfo
{
ACCE_GRADE_VALUE_FIELD = 0,
ACCE_ABSORPTION_SOCKET = 0,
ACCE_ABSORBED_SOCKET = 1,
ACCE_GRADE_1_ABS = 1,
ACCE_GRADE_2_ABS = 5,
ACCE_GRADE_3_ABS = 10,
ACCE_GRADE_4_ABS_MIN = 11,
ACCE_GRADE_4_ABS_MAX = 25,
ACCE_GRADE_4_ABS_MAX_COMB = 19,
ACCE_GRADE_4_ABS_RANGE = 5,
ACCE_EFFECT_FROM_ABS = 19,
ACCE_CLEAN_ATTR_VALUE0 = 7,
ACCE_WINDOW_MAX_MATERIALS = 2,
ACCE_GRADE_1_PRICE = 100000,
ACCE_GRADE_2_PRICE = 200000,
ACCE_GRADE_3_PRICE = 300000,
ACCE_GRADE_4_PRICE = 500000,
ACCE_COMBINE_GRADE_1 = 80,
ACCE_COMBINE_GRADE_2 = 70,
ACCE_COMBINE_GRADE_3 = 50,
ACCE_COMBINE_GRADE_4 = 30,
ACCE_REVERSAL_VNUM_1 = 39046,
ACCE_REVERSAL_VNUM_2 = 90000,
ACCE_BASE_VNUM = 85000,
ACCE_EFFECT_VNUM = 500,
};
#endif
enum EDragonSoulSubType
{
DS_SLOT1,
DS_SLOT2,
DS_SLOT3,
DS_SLOT4,
DS_SLOT5,
DS_SLOT6,
DS_SLOT_MAX,
};
enum EDragonSoulGradeTypes
{
DRAGON_SOUL_GRADE_NORMAL,
DRAGON_SOUL_GRADE_BRILLIANT,
DRAGON_SOUL_GRADE_RARE,
DRAGON_SOUL_GRADE_ANCIENT,
DRAGON_SOUL_GRADE_LEGENDARY,
#ifdef ENABLE_DS_GRADE_MYTH
DRAGON_SOUL_GRADE_MYTH,
#endif
DRAGON_SOUL_GRADE_MAX,
};
enum EDragonSoulStepTypes
{
DRAGON_SOUL_STEP_LOWEST,
DRAGON_SOUL_STEP_LOW,
DRAGON_SOUL_STEP_MID,
DRAGON_SOUL_STEP_HIGH,
DRAGON_SOUL_STEP_HIGHEST,
DRAGON_SOUL_STEP_MAX,
};
#define DRAGON_SOUL_STRENGTH_MAX 7
enum EDSInventoryMaxNum
{
DRAGON_SOUL_INVENTORY_MAX_NUM = DS_SLOT_MAX * DRAGON_SOUL_GRADE_MAX * DRAGON_SOUL_BOX_SIZE,
};
enum EFishSubTypes
{
FISH_ALIVE,
FISH_DEAD,
};
enum EResourceSubTypes
{
RESOURCE_FISHBONE,
RESOURCE_WATERSTONEPIECE,
RESOURCE_WATERSTONE,
RESOURCE_BLOOD_PEARL,
RESOURCE_BLUE_PEARL,
RESOURCE_WHITE_PEARL,
RESOURCE_BUCKET,
RESOURCE_CRYSTAL,
RESOURCE_GEM,
RESOURCE_STONE,
RESOURCE_METIN,
RESOURCE_ORE,
};
enum EUniqueSubTypes
{
UNIQUE_NONE,
UNIQUE_BOOK,
UNIQUE_SPECIAL_RIDE,
UNIQUE_SPECIAL_MOUNT_RIDE,
};
enum EUseSubTypes
{
USE_POTION, // 0
USE_TALISMAN,
USE_TUNING,
USE_MOVE,
USE_TREASURE_BOX,
USE_MONEYBAG,
USE_BAIT,
USE_ABILITY_UP,
USE_AFFECT,
USE_CREATE_STONE,
USE_SPECIAL, // 10
USE_POTION_NODELAY,
USE_CLEAR,
USE_INVISIBILITY,
USE_DETACHMENT,
USE_BUCKET,
USE_POTION_CONTINUE,
USE_CLEAN_SOCKET,
USE_CHANGE_ATTRIBUTE,
USE_ADD_ATTRIBUTE,
USE_ADD_ACCESSORY_SOCKET, // 20
USE_PUT_INTO_ACCESSORY_SOCKET,
USE_ADD_ATTRIBUTE2,
USE_RECIPE,
USE_CHANGE_ATTRIBUTE2,
USE_BIND,
USE_UNBIND,
USE_TIME_CHARGE_PER,
USE_TIME_CHARGE_FIX, // 28
USE_PUT_INTO_BELT_SOCKET,
USE_PUT_INTO_RING_SOCKET,
USE_CHANGE_COSTUME_ATTR, // 31
USE_RESET_COSTUME_ATTR, // 32
};
enum EExtractSubTypes
{
EXTRACT_DRAGON_SOUL,
EXTRACT_DRAGON_HEART,
};
enum EAutoUseSubTypes
{
AUTOUSE_POTION,
AUTOUSE_ABILITY_UP,
AUTOUSE_BOMB,
AUTOUSE_GOLD,
AUTOUSE_MONEYBAG,
AUTOUSE_TREASURE_BOX
};
enum EMaterialSubTypes
{
MATERIAL_LEATHER,
MATERIAL_BLOOD,
MATERIAL_ROOT,
MATERIAL_NEEDLE,
MATERIAL_JEWEL,
MATERIAL_DS_REFINE_NORMAL,
MATERIAL_DS_REFINE_BLESSED,
MATERIAL_DS_REFINE_HOLLY,
};
enum ESpecialSubTypes
{
SPECIAL_MAP,
SPECIAL_KEY,
SPECIAL_DOC,
SPECIAL_SPIRIT,
};
enum EToolSubTypes
{
TOOL_FISHING_ROD
};
enum ELotterySubTypes
{
LOTTERY_TICKET,
LOTTERY_INSTANT
};
enum EItemFlag
{
ITEM_FLAG_REFINEABLE = (1 << 0),
ITEM_FLAG_SAVE = (1 << 1),
ITEM_FLAG_STACKABLE = (1 << 2),
ITEM_FLAG_COUNT_PER_1GOLD = (1 << 3),
ITEM_FLAG_SLOW_QUERY = (1 << 4),
ITEM_FLAG_UNUSED01 = (1 << 5), // UNUSED
ITEM_FLAG_UNIQUE = (1 << 6),
ITEM_FLAG_MAKECOUNT = (1 << 7),
ITEM_FLAG_IRREMOVABLE = (1 << 8),
ITEM_FLAG_CONFIRM_WHEN_USE = (1 << 9),
ITEM_FLAG_QUEST_USE = (1 << 10),
ITEM_FLAG_QUEST_USE_MULTIPLE = (1 << 11),
ITEM_FLAG_QUEST_GIVE = (1 << 12),
ITEM_FLAG_LOG = (1 << 13),
ITEM_FLAG_APPLICABLE = (1 << 14),
};
enum EItemAntiFlag
{
ITEM_ANTIFLAG_FEMALE = (1 << 0),
ITEM_ANTIFLAG_MALE = (1 << 1),
ITEM_ANTIFLAG_WARRIOR = (1 << 2),
ITEM_ANTIFLAG_ASSASSIN = (1 << 3),
ITEM_ANTIFLAG_SURA = (1 << 4),
ITEM_ANTIFLAG_SHAMAN = (1 << 5),
ITEM_ANTIFLAG_GET = (1 << 6),
ITEM_ANTIFLAG_DROP = (1 << 7),
ITEM_ANTIFLAG_SELL = (1 << 8),
ITEM_ANTIFLAG_EMPIRE_A = (1 << 9),
ITEM_ANTIFLAG_EMPIRE_B = (1 << 10),
ITEM_ANTIFLAG_EMPIRE_C = (1 << 11),
ITEM_ANTIFLAG_SAVE = (1 << 12),
ITEM_ANTIFLAG_GIVE = (1 << 13),
ITEM_ANTIFLAG_PKDROP = (1 << 14),
ITEM_ANTIFLAG_STACK = (1 << 15),
ITEM_ANTIFLAG_MYSHOP = (1 << 16),
ITEM_ANTIFLAG_SAFEBOX = (1 << 17),
#ifdef ENABLE_WOLFMAN_CHARACTER
ITEM_ANTIFLAG_WOLFMAN = (1 << 18),
#endif
};
enum EItemWearableFlag
{
WEARABLE_BODY = (1 << 0),
WEARABLE_HEAD = (1 << 1),
WEARABLE_FOOTS = (1 << 2),
WEARABLE_WRIST = (1 << 3),
WEARABLE_WEAPON = (1 << 4),
WEARABLE_NECK = (1 << 5),
WEARABLE_EAR = (1 << 6),
WEARABLE_UNIQUE = (1 << 7),
WEARABLE_SHIELD = (1 << 8),
WEARABLE_ARROW = (1 << 9),
WEARABLE_HAIR = (1 << 10),
WEARABLE_ABILITY = (1 << 11),
WEARABLE_PENDANT = (1 << 12),
WEARABLE_GLOVE = (1 << 13),
};
enum ELimitTypes
{
LIMIT_NONE,
LIMIT_LEVEL,
LIMIT_STR,
LIMIT_DEX,
LIMIT_INT,
LIMIT_CON,
LIMIT_PCBANG, //reserved for backwards compatibility
LIMIT_REAL_TIME,
LIMIT_REAL_TIME_START_FIRST_USE,
LIMIT_TIMER_BASED_ON_WEAR,
LIMIT_MAX_NUM,
};
enum EAttrAddonTypes
{
ATTR_ADDON_NONE,
// positive values are reserved for set
ATTR_DAMAGE_ADDON = -1,
};
enum ERefineType
{
REFINE_TYPE_NORMAL,
REFINE_TYPE_NOT_USED1,
REFINE_TYPE_SCROLL,
REFINE_TYPE_HYUNIRON,
REFINE_TYPE_MONEY_ONLY,
REFINE_TYPE_MUSIN,
REFINE_TYPE_BDRAGON,
};
enum EPetType
{
PET_EGG, //0
PET_UPBRINGING, //1
PET_BAG, //2
PET_FEEDSTUFF, //3
PET_SKILL, //4
PET_SKILL_DEL_BOOK, //5
PET_NAME_CHANGE, //6
PET_EXPFOOD, //7
PET_SKILL_ALL_DEL_BOOK, //8
PET_EXPFOOD_PER, //9
PET_ATTR_DETERMINE, //10
PET_ATTR_CHANGE, //11
PET_PAY, //12
PET_PRIMIUM_FEEDSTUFF, //13
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,873 @@
#ifndef __INC_METIN_II_LENGTH_H__
#define __INC_METIN_II_LENGTH_H__
#include "CommonDefines.h"
#define WORD_MAX 0xffff
enum EMisc
{
MAX_HOST_LENGTH = 15,
IP_ADDRESS_LENGTH = 15,
LOGIN_MAX_LEN = 30,
PASSWD_MAX_LEN = 16,
#ifdef ENABLE_PLAYER_PER_ACCOUNT5
PLAYER_PER_ACCOUNT = 5,
#else
PLAYER_PER_ACCOUNT = 4,
#endif
ACCOUNT_STATUS_MAX_LEN = 8,
CHARACTER_NAME_MAX_LEN = 24,
SHOP_SIGN_MAX_LEN = 32,
INVENTORY_PAGE_COLUMN = 5, // 5 (default)
INVENTORY_PAGE_ROW = 9, // 9 (default)
INVENTORY_PAGE_SIZE = INVENTORY_PAGE_COLUMN*INVENTORY_PAGE_ROW,
#ifdef ENABLE_EXTEND_INVEN_SYSTEM
INVENTORY_PAGE_COUNT = 4, // 2 (default)
#else
INVENTORY_PAGE_COUNT = 2, // 2 (default)
#endif
INVENTORY_MAX_NUM = INVENTORY_PAGE_SIZE*INVENTORY_PAGE_COUNT, // 90 (default)
ABILITY_MAX_NUM = 50,
EMPIRE_MAX_NUM = 4,
BANWORD_MAX_LEN = 24,
SOCIAL_ID_MAX_LEN = 18,
GUILD_NAME_MAX_LEN = 12,
SHOP_HOST_ITEM_MAX_NUM = 40,
SHOP_GUEST_ITEM_MAX_NUM = 18,
SHOP_PRICELIST_MAX_NUM = 40,
CHAT_MAX_LEN = 512,
QUICKSLOT_MAX_NUM = 36,
JOURNAL_MAX_NUM = 2,
QUERY_MAX_LEN = 8192,
FILE_MAX_LEN = 128,
PLAYER_EXP_TABLE_MAX = 120,
PLAYER_MAX_LEVEL_CONST = 250,
GUILD_MAX_LEVEL = 20,
MOB_MAX_LEVEL = 100,
ATTRIBUTE_MAX_VALUE = 20,
CHARACTER_PATH_MAX_NUM = 64,
SKILL_MAX_NUM = 255,
SKILLBOOK_DELAY_MIN = 64800,
SKILLBOOK_DELAY_MAX = 108000,
SKILL_MAX_LEVEL = 40,
APPLY_NAME_MAX_LEN = 32,
EVENT_FLAG_NAME_MAX_LEN = 32,
MOB_SKILL_MAX_NUM = 5,
POINT_MAX_NUM = 255,
DRAGON_SOUL_BOX_SIZE = 32,
DRAGON_SOUL_BOX_COLUMN_NUM = 8,
DRAGON_SOUL_BOX_ROW_NUM = DRAGON_SOUL_BOX_SIZE / DRAGON_SOUL_BOX_COLUMN_NUM,
DRAGON_SOUL_REFINE_GRID_SIZE = 15,
MAX_AMOUNT_OF_MALL_BONUS = 20,
WEAR_MAX_NUM = 32,
//LIMIT_GOLD
GOLD_MAX = 2000000000,
#ifdef ENABLE_CHEQUE_SYSTEM
CHEQUE_MAX = 1000,
CHEQUE_VNUM = 2,
#ifndef ENABLE_IKASHOP_RENEWAL
YANG_PER_CHEQUE = 100000000,
#endif
#endif
//END_LIMIT_GOLD
SHOP_TAB_NAME_MAX = 32,
SHOP_TAB_COUNT_MAX = 3,
BELT_INVENTORY_SLOT_WIDTH = 4,
BELT_INVENTORY_SLOT_HEIGHT= 4,
BELT_INVENTORY_SLOT_COUNT = BELT_INVENTORY_SLOT_WIDTH * BELT_INVENTORY_SLOT_HEIGHT,
};
enum EWearPositions
{
WEAR_BODY, // 0
WEAR_HEAD, // 1
WEAR_FOOTS, // 2
WEAR_WRIST, // 3
WEAR_WEAPON, // 4
WEAR_NECK, // 5
WEAR_EAR, // 6
WEAR_UNIQUE1, // 7
WEAR_UNIQUE2, // 8
WEAR_ARROW, // 9
WEAR_SHIELD, // 10
WEAR_ABILITY1, // 11
WEAR_ABILITY2, // 12
WEAR_ABILITY3, // 13
WEAR_ABILITY4, // 14
WEAR_ABILITY5, // 15
WEAR_ABILITY6, // 16
WEAR_ABILITY7, // 17
WEAR_ABILITY8, // 18
WEAR_COSTUME_BODY, // 19
WEAR_COSTUME_HAIR, // 20
#ifdef ENABLE_MOUNT_COSTUME_SYSTEM
WEAR_COSTUME_MOUNT, // 21
#endif
#ifdef ENABLE_ACCE_COSTUME_SYSTEM
WEAR_COSTUME_ACCE, // 22
#endif
WEAR_BELT, // 23
#ifdef ENABLE_WEAPON_COSTUME_SYSTEM
WEAR_COSTUME_WEAPON,// 24
#endif
WEAR_PENDANT, // 25
WEAR_GLOVE, // 26
WEAR_MAX = 32
};
enum EDragonSoulDeckType
{
DRAGON_SOUL_DECK_0,
DRAGON_SOUL_DECK_1,
DRAGON_SOUL_DECK_MAX_NUM = 2,
DRAGON_SOUL_DECK_RESERVED_MAX_NUM = 3,
};
enum ESex
{
SEX_MALE,
SEX_FEMALE
};
enum EDirection
{
DIR_NORTH,
DIR_NORTHEAST,
DIR_EAST,
DIR_SOUTHEAST,
DIR_SOUTH,
DIR_SOUTHWEST,
DIR_WEST,
DIR_NORTHWEST,
DIR_MAX_NUM
};
#define ABILITY_MAX_LEVEL 10
enum EAbilityDifficulty
{
DIFFICULTY_EASY,
DIFFICULTY_NORMAL,
DIFFICULTY_HARD,
DIFFICULTY_VERY_HARD,
DIFFICULTY_NUM_TYPES
};
enum EAbilityCategory
{
CATEGORY_PHYSICAL,
CATEGORY_MENTAL,
CATEGORY_ATTRIBUTE,
CATEGORY_NUM_TYPES
};
enum EJobs
{
JOB_WARRIOR,
JOB_ASSASSIN,
JOB_SURA,
JOB_SHAMAN,
#ifdef ENABLE_WOLFMAN_CHARACTER
JOB_WOLFMAN,
#endif
JOB_MAX_NUM
};
enum ESkillGroups
{
SKILL_GROUP_MAX_NUM = 2,
};
enum ERaceFlags
{
RACE_FLAG_ANIMAL = (1 << 0),
RACE_FLAG_UNDEAD = (1 << 1),
RACE_FLAG_DEVIL = (1 << 2),
RACE_FLAG_HUMAN = (1 << 3),
RACE_FLAG_ORC = (1 << 4),
RACE_FLAG_MILGYO = (1 << 5),
RACE_FLAG_INSECT = (1 << 6),
RACE_FLAG_FIRE = (1 << 7),
RACE_FLAG_ICE = (1 << 8),
RACE_FLAG_DESERT = (1 << 9),
RACE_FLAG_TREE = (1 << 10),
RACE_FLAG_ATT_ELEC = (1 << 11),
RACE_FLAG_ATT_FIRE = (1 << 12),
RACE_FLAG_ATT_ICE = (1 << 13),
RACE_FLAG_ATT_WIND = (1 << 14),
RACE_FLAG_ATT_EARTH = (1 << 15),
RACE_FLAG_ATT_DARK = (1 << 16),
RACE_FLAG_CZ = (1 << 17), // 1<<11 official
};
enum ELoads
{
LOAD_NONE,
LOAD_LIGHT,
LOAD_NORMAL,
LOAD_HEAVY,
LOAD_MASSIVE
};
enum
{
QUICKSLOT_TYPE_NONE,
QUICKSLOT_TYPE_ITEM,
QUICKSLOT_TYPE_SKILL,
QUICKSLOT_TYPE_COMMAND,
QUICKSLOT_TYPE_MAX_NUM,
};
enum EParts
{
PART_MAIN,
PART_WEAPON,
PART_HEAD,
PART_HAIR,
#ifdef ENABLE_ACCE_COSTUME_SYSTEM
PART_ACCE,
#endif
PART_MAX_NUM,
PART_WEAPON_SUB,
};
enum EChatType
{
CHAT_TYPE_TALKING,
CHAT_TYPE_INFO,
CHAT_TYPE_NOTICE,
CHAT_TYPE_PARTY,
CHAT_TYPE_GUILD,
CHAT_TYPE_COMMAND,
CHAT_TYPE_SHOUT,
CHAT_TYPE_WHISPER,
CHAT_TYPE_BIG_NOTICE,
CHAT_TYPE_MONARCH_NOTICE,
#ifdef ENABLE_DICE_SYSTEM
CHAT_TYPE_DICE_INFO, //11
#endif
CHAT_TYPE_MAX_NUM
};
enum EWhisperType
{
WHISPER_TYPE_NORMAL = 0,
WHISPER_TYPE_NOT_EXIST = 1,
WHISPER_TYPE_TARGET_BLOCKED = 2,
WHISPER_TYPE_SENDER_BLOCKED = 3,
WHISPER_TYPE_ERROR = 4,
WHISPER_TYPE_GM = 5,
WHISPER_TYPE_SYSTEM = 0xFF
};
enum ECharacterPosition
{
POSITION_GENERAL,
POSITION_BATTLE,
POSITION_DYING,
POSITION_SITTING_CHAIR,
POSITION_SITTING_GROUND,
POSITION_INTRO,
POSITION_MAX_NUM
};
enum EGMLevels
{
GM_PLAYER,
GM_LOW_WIZARD,
GM_WIZARD,
GM_HIGH_WIZARD,
GM_GOD,
GM_IMPLEMENTOR,
GM_DISABLE,
};
enum EMobRank
{
MOB_RANK_PAWN,
MOB_RANK_S_PAWN,
MOB_RANK_KNIGHT,
MOB_RANK_S_KNIGHT,
MOB_RANK_BOSS,
MOB_RANK_KING,
MOB_RANK_MAX_NUM
};
enum ECharType
{
CHAR_TYPE_MONSTER,
CHAR_TYPE_NPC,
CHAR_TYPE_STONE,
CHAR_TYPE_WARP,
CHAR_TYPE_DOOR,
CHAR_TYPE_BUILDING,
CHAR_TYPE_PC,
CHAR_TYPE_POLYMORPH_PC,
CHAR_TYPE_HORSE,
CHAR_TYPE_GOTO
};
enum EBattleType
{
BATTLE_TYPE_MELEE,
BATTLE_TYPE_RANGE,
BATTLE_TYPE_MAGIC,
BATTLE_TYPE_SPECIAL,
BATTLE_TYPE_POWER,
BATTLE_TYPE_TANKER,
BATTLE_TYPE_SUPER_POWER,
BATTLE_TYPE_SUPER_TANKER,
BATTLE_TYPE_MAX_NUM
};
enum EApplyTypes
{
APPLY_NONE, // 0
APPLY_MAX_HP, // 1
APPLY_MAX_SP, // 2
APPLY_CON, // 3
APPLY_INT, // 4
APPLY_STR, // 5
APPLY_DEX, // 6
APPLY_ATT_SPEED, // 7
APPLY_MOV_SPEED, // 8
APPLY_CAST_SPEED, // 9
APPLY_HP_REGEN, // 10
APPLY_SP_REGEN, // 11
APPLY_POISON_PCT, // 12
APPLY_STUN_PCT, // 13
APPLY_SLOW_PCT, // 14
APPLY_CRITICAL_PCT, // 15
APPLY_PENETRATE_PCT, // 16
APPLY_ATTBONUS_HUMAN, // 17
APPLY_ATTBONUS_ANIMAL, // 18
APPLY_ATTBONUS_ORC, // 19
APPLY_ATTBONUS_MILGYO, // 20
APPLY_ATTBONUS_UNDEAD, // 21
APPLY_ATTBONUS_DEVIL, // 22
APPLY_STEAL_HP, // 23
APPLY_STEAL_SP, // 24
APPLY_MANA_BURN_PCT, // 25
APPLY_DAMAGE_SP_RECOVER, // 26
APPLY_BLOCK, // 27
APPLY_DODGE, // 28
APPLY_RESIST_SWORD, // 29
APPLY_RESIST_TWOHAND, // 30
APPLY_RESIST_DAGGER, // 31
APPLY_RESIST_BELL, // 32
APPLY_RESIST_FAN, // 33
APPLY_RESIST_BOW, // 34
APPLY_RESIST_FIRE, // 35
APPLY_RESIST_ELEC, // 36
APPLY_RESIST_MAGIC, // 37
APPLY_RESIST_WIND, // 38
APPLY_REFLECT_MELEE, // 39
APPLY_REFLECT_CURSE, // 40
APPLY_POISON_REDUCE, // 41
APPLY_KILL_SP_RECOVER, // 42
APPLY_EXP_DOUBLE_BONUS, // 43
APPLY_GOLD_DOUBLE_BONUS, // 44
APPLY_ITEM_DROP_BONUS, // 45
APPLY_POTION_BONUS, // 46
APPLY_KILL_HP_RECOVER, // 47
APPLY_IMMUNE_STUN, // 48
APPLY_IMMUNE_SLOW, // 49
APPLY_IMMUNE_FALL, // 50
APPLY_SKILL, // 51
APPLY_BOW_DISTANCE, // 52
APPLY_ATT_GRADE_BONUS, // 53
APPLY_DEF_GRADE_BONUS, // 54
APPLY_MAGIC_ATT_GRADE, // 55
APPLY_MAGIC_DEF_GRADE, // 56
APPLY_CURSE_PCT, // 57
APPLY_MAX_STAMINA, // 58
APPLY_ATTBONUS_WARRIOR, // 59
APPLY_ATTBONUS_ASSASSIN, // 60
APPLY_ATTBONUS_SURA, // 61
APPLY_ATTBONUS_SHAMAN, // 62
APPLY_ATTBONUS_MONSTER, // 63
APPLY_MALL_ATTBONUS,
APPLY_MALL_DEFBONUS,
APPLY_MALL_EXPBONUS,
APPLY_MALL_ITEMBONUS,
APPLY_MALL_GOLDBONUS,
APPLY_MAX_HP_PCT,
APPLY_MAX_SP_PCT,
APPLY_SKILL_DAMAGE_BONUS,
APPLY_NORMAL_HIT_DAMAGE_BONUS,
APPLY_SKILL_DEFEND_BONUS,
APPLY_NORMAL_HIT_DEFEND_BONUS,
APPLY_PC_BANG_EXP_BONUS, //reserved for backwards compatibility
APPLY_PC_BANG_DROP_BONUS, //reserved for backwards compatibility
APPLY_EXTRACT_HP_PCT,
APPLY_RESIST_WARRIOR,
APPLY_RESIST_ASSASSIN,
APPLY_RESIST_SURA,
APPLY_RESIST_SHAMAN,
APPLY_ENERGY,
APPLY_DEF_GRADE,
APPLY_COSTUME_ATTR_BONUS,
APPLY_MAGIC_ATTBONUS_PER,
APPLY_MELEE_MAGIC_ATTBONUS_PER,
APPLY_RESIST_ICE,
APPLY_RESIST_EARTH,
APPLY_RESIST_DARK,
APPLY_ANTI_CRITICAL_PCT,
APPLY_ANTI_PENETRATE_PCT,
#ifdef ENABLE_WOLFMAN_CHARACTER
APPLY_BLEEDING_REDUCE = 92, //92
APPLY_BLEEDING_PCT = 93, //93
APPLY_ATTBONUS_WOLFMAN = 94,
APPLY_RESIST_WOLFMAN = 95,
APPLY_RESIST_CLAW = 96,
#endif
#ifdef ENABLE_ACCE_COSTUME_SYSTEM
APPLY_ACCEDRAIN_RATE = 97, //97
#endif
#ifdef ENABLE_MAGIC_REDUCTION_SYSTEM
APPLY_RESIST_MAGIC_REDUCTION = 98, //98
#endif
APPLY_ENCHANT_ELECT = 99,
APPLY_ENCHANT_FIRE = 100,
APPLY_ENCHANT_ICE = 101,
APPLY_ENCHANT_WIND = 102,
APPLY_ENCHANT_EARTH = 103,
APPLY_ENCHANT_DARK = 104,
APPLY_ATTBONUS_CZ = 105,
APPLY_ATTBONUS_INSECT = 106,
APPLY_ATTBONUS_DESERT = 107,
APPLY_ATTBONUS_SWORD = 108,
APPLY_ATTBONUS_TWOHAND = 109,
APPLY_ATTBONUS_DAGGER = 110,
APPLY_ATTBONUS_BELL = 111,
APPLY_ATTBONUS_FAN = 112,
APPLY_ATTBONUS_BOW = 113,
#ifdef ENABLE_WOLFMAN_CHARACTER
APPLY_ATTBONUS_CLAW = 114,
#endif
APPLY_RESIST_HUMAN = 115,
APPLY_RESIST_MOUNT_FALL = 116,
APPLY_MOUNT = 118,
MAX_APPLY_NUM = 127,
};
enum EOnClickEvents
{
ON_CLICK_NONE,
ON_CLICK_SHOP,
ON_CLICK_TALK,
ON_CLICK_MAX_NUM
};
enum EOnIdleEvents
{
ON_IDLE_NONE,
ON_IDLE_GENERAL,
ON_IDLE_MAX_NUM
};
enum EWindows
{
RESERVED_WINDOW,
INVENTORY,
EQUIPMENT,
SAFEBOX,
MALL,
DRAGON_SOUL_INVENTORY,
BELT_INVENTORY,
GROUND,
WINDOW_TYPE_MAX,
};
enum EMobSizes
{
MOBSIZE_RESERVED,
MOBSIZE_SMALL,
MOBSIZE_MEDIUM,
MOBSIZE_BIG
};
enum EAIFlags
{
AIFLAG_AGGRESSIVE = (1 << 0),
AIFLAG_NOMOVE = (1 << 1),
AIFLAG_COWARD = (1 << 2),
AIFLAG_NOATTACKSHINSU = (1 << 3),
AIFLAG_NOATTACKJINNO = (1 << 4),
AIFLAG_NOATTACKCHUNJO = (1 << 5),
AIFLAG_ATTACKMOB = (1 << 6),
AIFLAG_BERSERK = (1 << 7),
AIFLAG_STONESKIN = (1 << 8),
AIFLAG_GODSPEED = (1 << 9),
AIFLAG_DEATHBLOW = (1 << 10),
AIFLAG_REVIVE = (1 << 11),
AIFLAG_HEALER = (1 << 12),
AIFLAG_COUNT = (1 << 13),
AIFLAG_NORECOVERY = (1 << 14),
AIFLAG_REFLECT = (1 << 15),
AIFLAG_FALL = (1 << 16),
AIFLAG_VIT = (1 << 17),
AIFLAG_RATTSPEED = (1 << 18),
AIFLAG_RCASTSPEED = (1 << 19),
AIFLAG_RHP_REGEN = (1 << 20),
AIFLAG_TIMEVIT = (1 << 21),
};
enum EMobStatType
{
MOB_STATTYPE_POWER,
MOB_STATTYPE_TANKER,
MOB_STATTYPE_SUPER_POWER,
MOB_STATTYPE_SUPER_TANKER,
MOB_STATTYPE_RANGE,
MOB_STATTYPE_MAGIC,
MOB_STATTYPE_MAX_NUM
};
enum EImmuneFlags
{
IMMUNE_STUN = (1 << 0),
IMMUNE_SLOW = (1 << 1),
IMMUNE_FALL = (1 << 2),
IMMUNE_CURSE = (1 << 3),
IMMUNE_POISON = (1 << 4),
IMMUNE_TERROR = (1 << 5),
IMMUNE_REFLECT = (1 << 6),
};
enum EMobEnchants
{
MOB_ENCHANT_CURSE,
MOB_ENCHANT_SLOW,
MOB_ENCHANT_POISON,
MOB_ENCHANT_STUN,
MOB_ENCHANT_CRITICAL,
MOB_ENCHANT_PENETRATE,
#if defined(ENABLE_WOLFMAN_CHARACTER) && !defined(USE_MOB_BLEEDING_AS_POISON)
MOB_ENCHANT_BLEEDING,
#endif
MOB_ENCHANTS_MAX_NUM
};
enum EMobResists
{
MOB_RESIST_SWORD,
MOB_RESIST_TWOHAND,
MOB_RESIST_DAGGER,
MOB_RESIST_BELL,
MOB_RESIST_FAN,
MOB_RESIST_BOW,
MOB_RESIST_FIRE,
MOB_RESIST_ELECT,
MOB_RESIST_MAGIC,
MOB_RESIST_WIND,
MOB_RESIST_POISON,
#if defined(ENABLE_WOLFMAN_CHARACTER) && !defined(USE_MOB_CLAW_AS_DAGGER)
MOB_RESIST_CLAW,
#endif
#if defined(ENABLE_WOLFMAN_CHARACTER) && !defined(USE_MOB_BLEEDING_AS_POISON)
MOB_RESIST_BLEEDING,
#endif
MOB_RESISTS_MAX_NUM
};
enum
{
SKILL_ATTR_TYPE_NORMAL = 1,
SKILL_ATTR_TYPE_MELEE,
SKILL_ATTR_TYPE_RANGE,
SKILL_ATTR_TYPE_MAGIC
/*
SKILL_ATTR_TYPE_FIRE,
SKILL_ATTR_TYPE_ICE,
SKILL_ATTR_TYPE_ELEC,
SKILL_ATTR_TYPE_DARK,
*/
};
enum
{
SKILL_NORMAL,
SKILL_MASTER,
SKILL_GRAND_MASTER,
SKILL_PERFECT_MASTER,
};
enum EGuildWarType
{
GUILD_WAR_TYPE_FIELD,
GUILD_WAR_TYPE_BATTLE,
GUILD_WAR_TYPE_FLAG,
GUILD_WAR_TYPE_MAX_NUM
};
enum EGuildWarState
{
GUILD_WAR_NONE,
GUILD_WAR_SEND_DECLARE,
GUILD_WAR_REFUSE,
GUILD_WAR_RECV_DECLARE,
GUILD_WAR_WAIT_START,
GUILD_WAR_CANCEL,
GUILD_WAR_ON_WAR,
GUILD_WAR_END,
GUILD_WAR_OVER,
GUILD_WAR_RESERVE,
GUILD_WAR_DURATION = 30*60,
GUILD_WAR_WIN_POINT = 1000,
GUILD_WAR_LADDER_HALF_PENALTY_TIME = 12*60*60,
};
enum EAttributeSet
{
ATTRIBUTE_SET_WEAPON,
ATTRIBUTE_SET_BODY,
ATTRIBUTE_SET_WRIST,
ATTRIBUTE_SET_FOOTS,
ATTRIBUTE_SET_NECK,
ATTRIBUTE_SET_HEAD,
ATTRIBUTE_SET_SHIELD,
ATTRIBUTE_SET_EAR,
#ifdef ENABLE_ITEM_ATTR_COSTUME
ATTRIBUTE_SET_COSTUME_BODY,
ATTRIBUTE_SET_COSTUME_HAIR,
#if defined(ENABLE_ITEM_ATTR_COSTUME) && defined(ENABLE_WEAPON_COSTUME_SYSTEM)
ATTRIBUTE_SET_COSTUME_WEAPON,
#endif
#endif
#ifdef ENABLE_PENDANT_SYSTEM
ATTRIBUTE_SET_PENDANT,
#endif
#ifdef ENABLE_GLOVE_SYSTEM
ATTRIBUTE_SET_GLOVE,
#endif
ATTRIBUTE_SET_MAX_NUM
};
enum EPrivType
{
PRIV_NONE,
PRIV_ITEM_DROP,
PRIV_GOLD_DROP,
PRIV_GOLD10_DROP,
PRIV_EXP_PCT,
MAX_PRIV_NUM,
};
enum EMoneyLogType
{
MONEY_LOG_RESERVED,
MONEY_LOG_MONSTER,
MONEY_LOG_SHOP,
MONEY_LOG_REFINE,
MONEY_LOG_QUEST,
MONEY_LOG_GUILD,
MONEY_LOG_MISC,
MONEY_LOG_MONSTER_KILL,
MONEY_LOG_DROP,
MONEY_LOG_TYPE_MAX_NUM,
};
enum EPremiumTypes
{
PREMIUM_EXP,
PREMIUM_ITEM,
PREMIUM_SAFEBOX,
PREMIUM_AUTOLOOT,
PREMIUM_FISH_MIND,
PREMIUM_MARRIAGE_FAST,
PREMIUM_GOLD,
PREMIUM_MAX_NUM = 9
};
enum SPECIAL_EFFECT
{
SE_NONE,
SE_HPUP_RED,
SE_SPUP_BLUE,
SE_SPEEDUP_GREEN,
SE_DXUP_PURPLE,
SE_CRITICAL,
SE_PENETRATE,
SE_BLOCK,
SE_DODGE,
SE_CHINA_FIREWORK,
SE_SPIN_TOP,
SE_SUCCESS,
SE_FAIL,
SE_FR_SUCCESS,
SE_LEVELUP_ON_14_FOR_GERMANY,
SE_LEVELUP_UNDER_15_FOR_GERMANY,
SE_PERCENT_DAMAGE1,
SE_PERCENT_DAMAGE2,
SE_PERCENT_DAMAGE3,
SE_AUTO_HPUP,
SE_AUTO_SPUP,
SE_EQUIP_RAMADAN_RING,
SE_EQUIP_HALLOWEEN_CANDY,
SE_EQUIP_HAPPINESS_RING,
SE_EQUIP_LOVE_PENDANT,
#ifdef ENABLE_ACCE_COSTUME_SYSTEM
SE_EFFECT_ACCE_SUCESS_ABSORB,
SE_EFFECT_ACCE_EQUIP,
#endif
};
#include "item_length.h"
enum EDragonSoulRefineWindowSize
{
DRAGON_SOUL_REFINE_GRID_MAX = 15,
};
enum EMisc2
{
DRAGON_SOUL_EQUIP_SLOT_START = INVENTORY_MAX_NUM + WEAR_MAX_NUM,
DRAGON_SOUL_EQUIP_SLOT_END = DRAGON_SOUL_EQUIP_SLOT_START + (DS_SLOT_MAX * DRAGON_SOUL_DECK_MAX_NUM),
DRAGON_SOUL_EQUIP_RESERVED_SLOT_END = DRAGON_SOUL_EQUIP_SLOT_END + (DS_SLOT_MAX * DRAGON_SOUL_DECK_RESERVED_MAX_NUM),
BELT_INVENTORY_SLOT_START = DRAGON_SOUL_EQUIP_RESERVED_SLOT_END,
BELT_INVENTORY_SLOT_END = BELT_INVENTORY_SLOT_START + BELT_INVENTORY_SLOT_COUNT,
INVENTORY_AND_EQUIP_SLOT_MAX = BELT_INVENTORY_SLOT_END,
};
#pragma pack(push, 1)
typedef struct SItemPos
{
BYTE window_type;
WORD cell;
SItemPos ()
{
window_type = INVENTORY;
cell = WORD_MAX;
}
SItemPos (BYTE _window_type, WORD _cell)
{
window_type = _window_type;
cell = _cell;
}
bool IsValidItemPosition() const
{
switch (window_type)
{
case RESERVED_WINDOW:
return false;
case INVENTORY:
case EQUIPMENT:
case BELT_INVENTORY:
return cell < INVENTORY_AND_EQUIP_SLOT_MAX;
case DRAGON_SOUL_INVENTORY:
return cell < (DRAGON_SOUL_INVENTORY_MAX_NUM);
case SAFEBOX:
case MALL:
return false;
default:
return false;
}
return false;
}
bool IsSamePosition(const SItemPos & other) const
{
return *this==other
|| ((INVENTORY == window_type || EQUIPMENT == window_type)
&& (INVENTORY == other.window_type || EQUIPMENT == other.window_type)
&& cell == other.cell);
}
bool IsEquipPosition() const
{
return ((INVENTORY == window_type || EQUIPMENT == window_type) && cell >= INVENTORY_MAX_NUM && cell < INVENTORY_MAX_NUM + WEAR_MAX_NUM)
|| IsDragonSoulEquipPosition();
}
bool IsDragonSoulEquipPosition() const
{
return (window_type == INVENTORY) && (DRAGON_SOUL_EQUIP_SLOT_START <= cell) && (DRAGON_SOUL_EQUIP_SLOT_END > cell); // @fixme184
}
bool IsBeltInventoryPosition() const // @fixme324 (INVENTORY n EQUIPMENT)
{
return (window_type == INVENTORY || window_type == EQUIPMENT) && (BELT_INVENTORY_SLOT_START <= cell) && (BELT_INVENTORY_SLOT_END > cell);
}
bool IsDefaultInventoryPosition() const
{
return INVENTORY == window_type && cell < INVENTORY_MAX_NUM;
}
bool operator==(const struct SItemPos& rhs) const
{
return (window_type == rhs.window_type) && (cell == rhs.cell);
}
bool operator<(const struct SItemPos& rhs) const
{
return (window_type < rhs.window_type) || ((window_type == rhs.window_type) && (cell < rhs.cell));
}
} TItemPos;
const TItemPos NPOS (RESERVED_WINDOW, WORD_MAX);
typedef struct SItemPosEx
{
TItemPos pos;
int id{ 0 };
} TItemPosEx;
typedef enum
{
SHOP_COIN_TYPE_GOLD, // DEFAULT VALUE
SHOP_COIN_TYPE_SECONDARY_COIN,
} EShopCoinType;
#pragma pack(pop)
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,16 @@
#ifndef INC_METIN_II_COMMON_NONCOPYABLE_TEMPLATE
#define INC_METIN_II_COMMON_NONCOPYABLE_TEMPLATE
class noncopyable
{
protected:
noncopyable() {}
~noncopyable() {}
private:
noncopyable(const noncopyable &);
noncopyable& operator = (const noncopyable &);
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,186 @@
#ifndef __INC_METIN_II_COMMON_POOL_H__
#define __INC_METIN_II_COMMON_POOL_H__
#include <assert.h>
#include <string>
template<typename T>
class CPoolNode : public T
{
public:
CPoolNode()
{
m_pNext = NULL;
m_pPrev = NULL;
}
virtual ~CPoolNode()
{
}
public:
CPoolNode<T> * m_pNext;
CPoolNode<T> * m_pPrev;
};
template<typename T>
class CDynamicPool
{
public:
typedef CPoolNode<T> TNode;
public:
CDynamicPool()
{
Initialize();
}
virtual ~CDynamicPool()
{
assert(m_pFreeList==NULL && "CDynamicPool::~CDynamicPool() - NOT Clear");
assert(m_pUsedList==NULL && "CDynamicPool::~CDynamicPool() - NOT Clear");
Clear();
}
void Initialize()
{
m_nodes = NULL;
m_nodeCount = 0;
m_pFreeList = NULL;
m_pUsedList = NULL;
}
void SetName(const char* c_szName)
{
m_stName = c_szName;
}
DWORD GetCapacity()
{
return m_nodeCount;
}
T* Alloc()
{
TNode* pnewNode;
if (m_pFreeList)
{
pnewNode = m_pFreeList;
m_pFreeList = m_pFreeList->m_pNext;
}
else
{
pnewNode = AllocNode();
}
if (!pnewNode)
return NULL;
if (!m_pUsedList)
{
m_pUsedList = pnewNode;
m_pUsedList->m_pPrev = m_pUsedList->m_pNext = NULL;
}
else
{
m_pUsedList->m_pPrev = pnewNode;
pnewNode->m_pNext = m_pUsedList;
pnewNode->m_pPrev = NULL;
m_pUsedList = pnewNode;
}
//Tracef("%s Pool Alloc %p\n", m_stName.c_str(), pnewNode);
return (T*) pnewNode;
}
void Free(T * pdata)
{
TNode* pfreeNode = (TNode*) pdata;
if (pfreeNode == m_pUsedList)
{
if (NULL != (m_pUsedList = m_pUsedList->m_pNext))
m_pUsedList->m_pPrev = NULL;
}
else
{
if (pfreeNode->m_pNext)
pfreeNode->m_pNext->m_pPrev = pfreeNode->m_pPrev;
if (pfreeNode->m_pPrev)
pfreeNode->m_pPrev->m_pNext = pfreeNode->m_pNext;
}
pfreeNode->m_pPrev = NULL;
pfreeNode->m_pNext = m_pFreeList;
m_pFreeList = pfreeNode;
//Tracef("%s Pool Free\n", m_stName.c_str());
}
void FreeAll()
{
TNode * pcurNode;
TNode * pnextNode;
pcurNode = m_pUsedList;
while (pcurNode)
{
pnextNode = pcurNode->m_pNext;
Free(pcurNode);
pcurNode = pnextNode;
}
}
void Clear()
{
TNode* pcurNode;
TNode* pnextNode;
[[maybe_unused]] DWORD count = 0;
pcurNode = m_pFreeList;
while (pcurNode)
{
pnextNode = pcurNode->m_pNext;
delete pcurNode;
pcurNode = pnextNode;
++count;
}
m_pFreeList = NULL;
pcurNode = m_pUsedList;
while (pcurNode)
{
pnextNode = pcurNode->m_pNext;
delete pcurNode;
pcurNode = pnextNode;
++count;
}
m_pUsedList = NULL;
assert(count==m_nodeCount && "CDynamicPool::Clear()");
m_nodeCount=0;
}
protected:
TNode* AllocNode()
{
++m_nodeCount;
return new TNode;
}
protected:
TNode * m_nodes;
TNode * m_pFreeList;
TNode * m_pUsedList;
DWORD m_nodeCount;
std::string m_stName;
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,6 @@
#ifndef __INC_SERVICE_H__
#define __INC_SERVICE_H__
#pragma once
#include "CommonDefines.h"
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,45 @@
#ifndef __INC_SINGLETON_H__
#define __INC_SINGLETON_H__
#include <assert.h>
template <typename T> class singleton
{
public:
static T * ms_singleton;
singleton()
{
assert(!ms_singleton);
long offset = (long) (T*) 1 - (long) (singleton <T>*) (T*) 1;
ms_singleton = (T*) ((long) this + offset);
}
virtual ~singleton()
{
assert(ms_singleton);
ms_singleton = 0;
}
static T & instance()
{
assert(ms_singleton);
return (*ms_singleton);
}
static T & Instance()
{
assert(ms_singleton);
return (*ms_singleton);
}
static T * instance_ptr()
{
return (ms_singleton);
}
};
template <typename T> T * singleton <T>::ms_singleton = NULL;
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,237 @@
#ifndef __INC_METIN_II_STL_H__
#define __INC_METIN_II_STL_H__
#include <vector>
#include <string>
#include <algorithm>
#include <random>
#include <map>
#include <list>
#include <functional>
#include <stack>
#include <set>
#ifdef __GNUC__
#ifndef __clang__
#include <ext/functional>
#else
#include <functional>
#endif
#endif
#ifndef itertype
#define itertype(v) typeof((v).begin())
#endif
inline void stl_lowers(std::string& rstRet)
{
for (size_t i = 0; i < rstRet.length(); ++i)
rstRet[i] = tolower(rstRet[i]);
}
struct stringhash
{
size_t operator () (const std::string & str) const
{
const unsigned char * s = (const unsigned char*) str.c_str();
const unsigned char * end = s + str.size();
size_t h = 0;
while (s < end)
{
h *= 16777619;
h ^= *(s++);
}
return h;
}
};
// code from tr1/functional_hash.h
template<typename T>
struct hash;
template<typename _Tp>
struct hash<_Tp*>
{
std::size_t
operator()(_Tp* __p) const
{ return reinterpret_cast<std::size_t>(__p); }
};
namespace utils
{
template <typename T> struct IsContiguous {
static bool constexpr value = false;
};
template <typename... Args>
struct IsContiguous<std::vector<Args...>> {
static bool constexpr value = true;
};
template <>
struct IsContiguous<std::string> {
static bool constexpr value = true;
};
template <typename... Args>
struct IsContiguous<std::array<Args...>> {
static bool constexpr value = true;
};
template<typename T>
constexpr bool IsContiguousV = IsContiguous<T>::value;
/////////////////////
template<typename T>
constexpr bool IsRawV = !std::is_pointer_v<T> && std::is_trivially_copyable_v<T> && !IsContiguousV<T>;
};
namespace msl
{
template< class F, class... Args >
constexpr decltype(auto) bind1st( F&& f, Args&&... args )
{
return std::bind(f, args..., std::placeholders::_1);
}
template< class F, class... Args >
constexpr decltype(auto) bind2nd( F&& f, Args&&... args )
{
return std::bind(f, std::placeholders::_1, args...);
}
template <class T>
void random_shuffle(T first, T last)
{
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(first, last, g);
}
};
namespace std
{
template <class container, class Pred>
void erase_if (container & a, typename container::iterator first, typename container::iterator past, Pred pred)
{
while (first != past)
if (pred(*first))
a.erase(first++);
else
++first;
}
template <class container>
void wipe(container & a)
{
typename container::iterator first, past;
first = a.begin();
past = a.end();
while (first != past)
delete *(first++);
a.clear();
}
template <class container>
void wipe_second(container & a)
{
typename container::iterator first, past;
first = a.begin();
past = a.end();
while (first != past)
{
delete first->second;
++first;
}
a.clear();
}
template <typename T> T MINMAX(T min, T value, T max)
{
T tv;
tv = (min > value ? min : value);
return (max < tv) ? max : tv;
}
template <class _Ty>
class void_mem_fun_t
{
public:
explicit void_mem_fun_t(void (_Ty::*_Pm)()) : _Ptr(_Pm)
{
}
void operator()(_Ty* p) const
{
((p->*_Ptr)());
}
private:
void (_Ty::*_Ptr)();
};
template<class _Ty> inline
void_mem_fun_t<_Ty> void_mem_fun(void (_Ty::*_Pm)())
{ return (void_mem_fun_t<_Ty>(_Pm)); }
template<class _Ty>
class void_mem_fun_ref_t
{
public:
explicit void_mem_fun_ref_t(void (_Ty::*_Pm)()) : _Ptr(_Pm) {}
void operator()(_Ty& x) const
{ return ((x.*_Ptr)()); }
private:
void (_Ty::*_Ptr)();
};
template<class _Ty> inline
void_mem_fun_ref_t<_Ty> void_mem_fun_ref(void (_Ty::*_Pm)())
{ return (void_mem_fun_ref_t< _Ty>(_Pm)); }
};
inline std::string FormatNumberWithDots(long long number) {
std::string result;
bool isNegative = false;
// Handle the case for negative numbers
if (number < 0) {
isNegative = true;
number = -number; // Make it positive for processing
}
// Convert the number to a string
std::string numStr = std::to_string(number);
// Insert dots from the right every three digits
int count = 0;
for (int i = numStr.size() - 1; i >= 0; --i) {
result.push_back(numStr[i]);
if (++count == 3 && i > 0) {
result.push_back('.');
count = 0;
}
}
// Reverse the result string to get the correct order
std::reverse(result.begin(), result.end());
// Add the negative sign if necessary
if (isNegative) {
result.insert(result.begin(), '-');
}
return result;
}
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,122 @@
#ifndef _INCLUDE_HEADER_COMMON_UTILS_
#define _INCLUDE_HEADER_COMMON_UTILS_
#include <msl/utils.h>
/*----- atoi function -----*/
inline bool str_to_number (bool& out, const char *in)
{
if (0==in || 0==in[0]) return false;
out = (strtol(in, NULL, 10) != 0);
return true;
}
inline bool str_to_number (char& out, const char *in)
{
if (0==in || 0==in[0]) return false;
out = (char) strtol(in, NULL, 10);
return true;
}
inline bool str_to_number (unsigned char& out, const char *in)
{
if (0==in || 0==in[0]) return false;
out = (unsigned char) strtoul(in, NULL, 10);
return true;
}
inline bool str_to_number (short& out, const char *in)
{
if (0==in || 0==in[0]) return false;
out = (short) strtol(in, NULL, 10);
return true;
}
inline bool str_to_number (unsigned short& out, const char *in)
{
if (0==in || 0==in[0]) return false;
out = (unsigned short) strtoul(in, NULL, 10);
return true;
}
inline bool str_to_number (int& out, const char *in)
{
if (0==in || 0==in[0]) return false;
out = (int) strtol(in, NULL, 10);
return true;
}
inline bool str_to_number (unsigned int& out, const char *in)
{
if (0==in || 0==in[0]) return false;
out = (unsigned int) strtoul(in, NULL, 10);
return true;
}
inline bool str_to_number (long& out, const char *in)
{
if (0==in || 0==in[0]) return false;
out = (long) strtol(in, NULL, 10);
return true;
}
inline bool str_to_number (unsigned long& out, const char *in)
{
if (0==in || 0==in[0]) return false;
out = (unsigned long) strtoul(in, NULL, 10);
return true;
}
inline bool str_to_number (long long& out, const char *in)
{
if (0==in || 0==in[0]) return false;
out = (long long) strtoull(in, NULL, 10);
return true;
}
inline bool str_to_number (unsigned long long& out, const char *in)
{
if (0==in || 0==in[0]) return false;
out = (unsigned long long) strtoull(in, NULL, 10);
return true;
}
inline bool str_to_number (float& out, const char *in)
{
if (0==in || 0==in[0]) return false;
out = (float) strtof(in, NULL);
return true;
}
inline bool str_to_number (double& out, const char *in)
{
if (0==in || 0==in[0]) return false;
out = (double) strtod(in, NULL);
return true;
}
#ifdef __FreeBSD__
inline bool str_to_number (long double& out, const char *in)
{
if (0==in || 0==in[0]) return false;
out = (long double) strtold(in, NULL);
return true;
}
#endif
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,204 @@
#include "stdafx.h"
#include "Cache.h"
#include "QID.h"
#include "ClientManager.h"
#include "Main.h"
#include <fmt/fmt.h>
extern CPacketInfo g_item_info;
extern int g_iPlayerCacheFlushSeconds;
extern int g_iItemCacheFlushSeconds;
extern int g_test_server;
// MYSHOP_PRICE_LIST
extern int g_iItemPriceListTableCacheFlushSeconds;
// END_OF_MYSHOP_PRICE_LIST
//
extern int g_item_count;
CItemCache::CItemCache()
{
m_expireTime = MIN(1800, g_iItemCacheFlushSeconds);
}
CItemCache::~CItemCache()
{
}
void CItemCache::Delete()
{
if (m_data.vnum == 0)
return;
if (g_test_server)
sys_log(0, "ItemCache::Delete : DELETE %u", m_data.id);
m_data.vnum = 0;
m_bNeedQuery = true;
m_lastUpdateTime = time(0);
OnFlush();
}
void CItemCache::OnFlush()
{
if (m_data.vnum == 0)
{
char szQuery[QUERY_MAX_LEN];
snprintf(szQuery, sizeof(szQuery), "DELETE FROM item%s WHERE id=%u", GetTablePostfix(), m_data.id);
CDBManager::instance().ReturnQuery(szQuery, QID_ITEM_DESTROY, 0, NULL);
if (g_test_server)
sys_log(0, "ItemCache::Flush : DELETE %u %s", m_data.id, szQuery);
}
else
{
TPlayerItem *p = &m_data;
const auto setQuery = fmt::format(FMT_COMPILE("id={}, owner_id={}, `window`={}, pos={}, count={}, vnum={}, socket0={}, socket1={}, socket2={}, "
"attrtype0={}, attrvalue0={}, "
"attrtype1={}, attrvalue1={}, "
"attrtype2={}, attrvalue2={}, "
"attrtype3={}, attrvalue3={}, "
"attrtype4={}, attrvalue4={}, "
"attrtype5={}, attrvalue5={}, "
"attrtype6={}, attrvalue6={} ")
, p->id,
p->owner,
p->window,
p->pos,
p->count,
p->vnum,
p->alSockets[0],
p->alSockets[1],
p->alSockets[2],
p->aAttr[0].bType, p->aAttr[0].sValue,
p->aAttr[1].bType, p->aAttr[1].sValue,
p->aAttr[2].bType, p->aAttr[2].sValue,
p->aAttr[3].bType, p->aAttr[3].sValue,
p->aAttr[4].bType, p->aAttr[4].sValue,
p->aAttr[5].bType, p->aAttr[5].sValue,
p->aAttr[6].bType, p->aAttr[6].sValue
); // @fixme205
const auto itemQuery = fmt::format(FMT_COMPILE("INSERT INTO item{} SET {} ON DUPLICATE KEY UPDATE {}"),
GetTablePostfix(), setQuery, setQuery);
if (g_test_server)
sys_log(0, "ItemCache::Flush :REPLACE (%s)", itemQuery.c_str());
CDBManager::instance().ReturnQuery(itemQuery.c_str(), QID_ITEM_SAVE, 0, NULL);
++g_item_count;
}
m_bNeedQuery = false;
}
//
// CPlayerTableCache
//
CPlayerTableCache::CPlayerTableCache()
{
m_expireTime = MIN(1800, g_iPlayerCacheFlushSeconds);
}
CPlayerTableCache::~CPlayerTableCache()
{
}
void CPlayerTableCache::OnFlush()
{
if (g_test_server)
sys_log(0, "PlayerTableCache::Flush : %s", m_data.name);
char szQuery[QUERY_MAX_LEN];
CreatePlayerSaveQuery(szQuery, sizeof(szQuery), &m_data);
CDBManager::instance().ReturnQuery(szQuery, QID_PLAYER_SAVE, 0, NULL);
}
// MYSHOP_PRICE_LIST
//
// CItemPriceListTableCache class implementation
//
const int CItemPriceListTableCache::s_nMinFlushSec = 1800;
CItemPriceListTableCache::CItemPriceListTableCache()
{
m_expireTime = MIN(s_nMinFlushSec, g_iItemPriceListTableCacheFlushSeconds);
}
void CItemPriceListTableCache::UpdateList(const TItemPriceListTable* pUpdateList)
{
std::vector<TItemPriceInfo> tmpvec;
for (uint idx = 0; idx < m_data.byCount; ++idx)
{
const TItemPriceInfo* pos = pUpdateList->aPriceInfo;
for (; pos != pUpdateList->aPriceInfo + pUpdateList->byCount && m_data.aPriceInfo[idx].dwVnum != pos->dwVnum; ++pos)
;
if (pos == pUpdateList->aPriceInfo + pUpdateList->byCount)
tmpvec.emplace_back(m_data.aPriceInfo[idx]);
}
if (pUpdateList->byCount > SHOP_PRICELIST_MAX_NUM)
{
sys_err("Count overflow!");
return;
}
m_data.byCount = pUpdateList->byCount;
thecore_memcpy(m_data.aPriceInfo, pUpdateList->aPriceInfo, sizeof(TItemPriceInfo) * pUpdateList->byCount);
int nDeletedNum;
if (pUpdateList->byCount < SHOP_PRICELIST_MAX_NUM)
{
size_t sizeAddOldDataSize = SHOP_PRICELIST_MAX_NUM - pUpdateList->byCount;
if (tmpvec.size() < sizeAddOldDataSize)
sizeAddOldDataSize = tmpvec.size();
if (tmpvec.size() != 0)
{
thecore_memcpy(m_data.aPriceInfo + pUpdateList->byCount, &tmpvec[0], sizeof(TItemPriceInfo) * sizeAddOldDataSize);
m_data.byCount += sizeAddOldDataSize;
}
nDeletedNum = tmpvec.size() - sizeAddOldDataSize;
}
else
nDeletedNum = tmpvec.size();
m_bNeedQuery = true;
sys_log(0,
"ItemPriceListTableCache::UpdateList : OwnerID[%u] Update [%u] Items, Delete [%u] Items, Total [%u] Items",
m_data.dwOwnerID, pUpdateList->byCount, nDeletedNum, m_data.byCount);
}
void CItemPriceListTableCache::OnFlush()
{
char szQuery[QUERY_MAX_LEN];
snprintf(szQuery, sizeof(szQuery), "DELETE FROM myshop_pricelist%s WHERE owner_id = %u", GetTablePostfix(), m_data.dwOwnerID);
CDBManager::instance().ReturnQuery(szQuery, QID_ITEMPRICE_DESTROY, 0, NULL);
for (int idx = 0; idx < m_data.byCount; ++idx)
{
snprintf(szQuery, sizeof(szQuery),
"REPLACE myshop_pricelist%s(owner_id, item_vnum, price) VALUES(%u, %u, %u)", // @fixme204 (INSERT INTO -> REPLACE)
GetTablePostfix(), m_data.dwOwnerID, m_data.aPriceInfo[idx].dwVnum, m_data.aPriceInfo[idx].dwPrice);
CDBManager::instance().ReturnQuery(szQuery, QID_ITEMPRICE_SAVE, 0, NULL);
}
sys_log(0, "ItemPriceListTableCache::Flush : OwnerID[%u] Update [%u]Items", m_data.dwOwnerID, m_data.byCount);
m_bNeedQuery = false;
}
CItemPriceListTableCache::~CItemPriceListTableCache()
{
}
// END_OF_MYSHOP_PRICE_LIST
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,49 @@
// vim:ts=8 sw=4
#ifndef __INC_DB_CACHE_H__
#define __INC_DB_CACHE_H__
#include "../../common/cache.h"
class CItemCache : public cache<TPlayerItem>
{
public:
CItemCache();
virtual ~CItemCache();
void Delete();
virtual void OnFlush();
};
class CPlayerTableCache : public cache<TPlayerTable>
{
public:
CPlayerTableCache();
virtual ~CPlayerTableCache();
virtual void OnFlush();
DWORD GetLastUpdateTime() { return m_lastUpdateTime; }
};
// MYSHOP_PRICE_LIST
class CItemPriceListTableCache : public cache< TItemPriceListTable >
{
public:
/// Constructor
CItemPriceListTableCache(void);
virtual ~CItemPriceListTableCache();
void UpdateList(const TItemPriceListTable* pUpdateList);
virtual void OnFlush(void);
private:
static const int s_nMinFlushSec; ///< Minimum cache expire time
};
// END_OF_MYSHOP_PRICE_LIST
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,513 @@
#ifndef __INC_CLIENTMANAGER_H__
#define __INC_CLIENTMANAGER_H__
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include "../../common/stl.h"
#include "../../common/building.h"
#include "Peer.h"
#include "DBManager.h"
#include "LoginData.h"
#define ENABLE_PROTO_FROM_DB
class CPlayerTableCache;
class CItemCache;
class CItemPriceListTableCache;
class CPacketInfo
{
public:
void Add(int header);
void Reset();
std::map<int, int> m_map_info;
};
size_t CreatePlayerSaveQuery(char * pszQuery, size_t querySize, TPlayerTable * pkTab);
class CClientManager : public CNetBase, public singleton<CClientManager>
{
public:
typedef std::list<CPeer *> TPeerList;
typedef boost::unordered_map<DWORD, CPlayerTableCache *> TPlayerTableCacheMap;
typedef boost::unordered_map<DWORD, CItemCache *> TItemCacheMap;
typedef boost::unordered_set<CItemCache *, boost::hash<CItemCache*> > TItemCacheSet;
typedef boost::unordered_map<DWORD, TItemCacheSet *> TItemCacheSetPtrMap;
typedef boost::unordered_map<DWORD, CItemPriceListTableCache*> TItemPriceListCacheMap;
typedef boost::unordered_map<short, BYTE> TChannelStatusMap;
// MYSHOP_PRICE_LIST
typedef std::pair< DWORD, DWORD > TItemPricelistReqInfo;
// END_OF_MYSHOP_PRICE_LIST
class ClientHandleInfo
{
public:
DWORD dwHandle;
DWORD account_id;
DWORD player_id;
BYTE account_index;
char login[LOGIN_MAX_LEN + 1];
char safebox_password[SAFEBOX_PASSWORD_MAX_LEN + 1];
char ip[MAX_HOST_LENGTH + 1];
TAccountTable * pAccountTable;
TSafeboxTable * pSafebox;
ClientHandleInfo(DWORD argHandle, DWORD dwPID = 0)
{
dwHandle = argHandle;
pSafebox = NULL;
pAccountTable = NULL;
player_id = dwPID;
};
ClientHandleInfo(DWORD argHandle, DWORD dwPID, DWORD accountId)
{
dwHandle = argHandle;
pSafebox = NULL;
pAccountTable = NULL;
player_id = dwPID;
account_id = accountId;
};
~ClientHandleInfo()
{
if (pSafebox)
{
delete pSafebox;
pSafebox = NULL;
}
}
};
public:
CClientManager();
~CClientManager();
bool Initialize();
time_t GetCurrentTime();
void MainLoop();
void Quit();
void GetPeerP2PHostNames(std::string& peerHostNames);
void SetTablePostfix(const char* c_pszTablePostfix);
void SetPlayerIDStart(int iIDStart);
int GetPlayerIDStart() { return m_iPlayerIDStart; }
int GetPlayerDeleteLevelLimit() { return m_iPlayerDeleteLevelLimit; }
void SetChinaEventServer(bool flag) { m_bChinaEventServer = flag; }
bool IsChinaEventServer() { return m_bChinaEventServer; }
DWORD GetUserCount();
void SendAllGuildSkillRechargePacket();
void SendTime();
CPlayerTableCache * GetPlayerCache(DWORD id);
void PutPlayerCache(TPlayerTable * pNew);
void CreateItemCacheSet(DWORD dwID);
TItemCacheSet * GetItemCacheSet(DWORD dwID);
void FlushItemCacheSet(DWORD dwID);
CItemCache * GetItemCache(DWORD id);
void PutItemCache(TPlayerItem * pNew, bool bSkipQuery = false);
bool DeleteItemCache(DWORD id);
void UpdatePlayerCache();
void UpdateItemCache();
// MYSHOP_PRICE_LIST
CItemPriceListTableCache* GetItemPriceListCache(DWORD dwID);
void PutItemPriceListCache(const TItemPriceListTable* pItemPriceList);
void UpdateItemPriceListCache(void);
// END_OF_MYSHOP_PRICE_LIST
void SendGuildSkillUsable(DWORD guild_id, DWORD dwSkillVnum, bool bUsable);
void SetCacheFlushCountLimit(int iLimit);
template <class Func>
Func for_each_peer(Func f);
CPeer * GetAnyPeer();
void ForwardPacket(BYTE header, const void* data, int size, BYTE bChannel = 0, CPeer * except = NULL);
void SendNotice(const char * c_pszFormat, ...);
// @fixme203 directly GetCommand instead of strcpy
char* GetCommand(char* str, char* command);
void ItemAward(CPeer * peer, char* login);
protected:
void Destroy();
private:
bool InitializeTables();
bool InitializeShopTable();
bool InitializeMobTable();
bool InitializeItemTable();
bool InitializeQuestItemTable();
bool InitializeSkillTable();
bool InitializeRefineTable();
bool InitializeBanwordTable();
bool InitializeItemAttrTable();
bool InitializeItemRareTable();
bool InitializeLandTable();
bool InitializeObjectProto();
bool InitializeObjectTable();
bool InitializeMonarch();
bool MirrorMobTableIntoDB();
bool MirrorItemTableIntoDB();
void AddPeer(socket_t fd);
void RemovePeer(CPeer * pPeer);
CPeer * GetPeer(IDENT ident);
int AnalyzeQueryResult(SQLMsg * msg);
int AnalyzeErrorMsg(CPeer * peer, SQLMsg * msg);
int Process();
void ProcessPackets(CPeer * peer);
CLoginData * GetLoginData(DWORD dwKey);
CLoginData * GetLoginDataByLogin(const char * c_pszLogin);
CLoginData * GetLoginDataByAID(DWORD dwAID);
void InsertLoginData(CLoginData * pkLD);
void DeleteLoginData(CLoginData * pkLD);
bool InsertLogonAccount(const char * c_pszLogin, DWORD dwHandle, const char * c_pszIP);
bool DeleteLogonAccount(const char * c_pszLogin, DWORD dwHandle);
bool FindLogonAccount(const char * c_pszLogin);
void GuildCreate(CPeer * peer, DWORD dwGuildID);
void GuildSkillUpdate(CPeer * peer, TPacketGuildSkillUpdate* p);
void GuildExpUpdate(CPeer * peer, TPacketGuildExpUpdate* p);
void GuildAddMember(CPeer * peer, TPacketGDGuildAddMember* p);
void GuildChangeGrade(CPeer * peer, TPacketGuild* p);
void GuildRemoveMember(CPeer * peer, TPacketGuild* p);
void GuildChangeMemberData(CPeer * peer, TPacketGuildChangeMemberData* p);
void GuildDisband(CPeer * peer, TPacketGuild * p);
void GuildWar(CPeer * peer, TPacketGuildWar * p);
void GuildWarScore(CPeer * peer, TPacketGuildWarScore * p);
void GuildChangeLadderPoint(TPacketGuildLadderPoint* p);
void GuildUseSkill(TPacketGuildUseSkill* p);
void GuildDepositMoney(TPacketGDGuildMoney* p);
void GuildWithdrawMoney(CPeer* peer, TPacketGDGuildMoney* p);
void GuildWithdrawMoneyGiveReply(TPacketGDGuildMoneyWithdrawGiveReply* p);
void GuildWarBet(TPacketGDGuildWarBet * p);
void GuildChangeMaster(TPacketChangeGuildMaster* p);
void SetGuildWarEndTime(DWORD guild_id1, DWORD guild_id2, time_t tEndTime);
void QUERY_BOOT(CPeer * peer, TPacketGDBoot * p);
void QUERY_LOGIN(CPeer * peer, DWORD dwHandle, SLoginPacket* data);
void QUERY_LOGOUT(CPeer * peer, DWORD dwHandle, const char *);
void RESULT_LOGIN(CPeer * peer, SQLMsg *msg);
void QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoadPacket*);
void RESULT_COMPOSITE_PLAYER(CPeer * peer, SQLMsg * pMsg, DWORD dwQID);
void RESULT_PLAYER_LOAD(CPeer * peer, MYSQL_RES * pRes, ClientHandleInfo * pkInfo);
void RESULT_ITEM_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dwHandle, DWORD dwPID);
void RESULT_QUEST_LOAD(CPeer * pkPeer, MYSQL_RES * pRes, DWORD dwHandle, DWORD dwPID);
// @fixme402 (RESULT_AFFECT_LOAD +dwRealPID)
void RESULT_AFFECT_LOAD(CPeer * pkPeer, MYSQL_RES * pRes, DWORD dwHandle, DWORD dwRealPID);
// PLAYER_INDEX_CREATE_BUG_FIX
void RESULT_PLAYER_INDEX_CREATE(CPeer *pkPeer, SQLMsg *msg);
// END_PLAYER_INDEX_CREATE_BUG_FIX
// MYSHOP_PRICE_LIST
void RESULT_PRICELIST_LOAD(CPeer* peer, SQLMsg* pMsg);
void RESULT_PRICELIST_LOAD_FOR_UPDATE(SQLMsg* pMsg);
// END_OF_MYSHOP_PRICE_LIST
void QUERY_PLAYER_SAVE(CPeer * peer, DWORD dwHandle, TPlayerTable*);
void __QUERY_PLAYER_CREATE(CPeer * peer, DWORD dwHandle, TPlayerCreatePacket *);
void __QUERY_PLAYER_DELETE(CPeer * peer, DWORD dwHandle, TPlayerDeletePacket *);
void __RESULT_PLAYER_DELETE(CPeer * peer, SQLMsg* msg);
void QUERY_PLAYER_COUNT(CPeer * pkPeer, TPlayerCountPacket *);
void QUERY_ITEM_SAVE(CPeer * pkPeer, const char * c_pData);
void QUERY_ITEM_DESTROY(CPeer * pkPeer, const char * c_pData);
void QUERY_ITEM_FLUSH(CPeer * pkPeer, const char * c_pData);
void QUERY_QUEST_SAVE(CPeer * pkPeer, TQuestTable *, DWORD dwLen);
void QUERY_ADD_AFFECT(CPeer * pkPeer, TPacketGDAddAffect * p);
void QUERY_REMOVE_AFFECT(CPeer * pkPeer, TPacketGDRemoveAffect * p);
void QUERY_SAFEBOX_LOAD(CPeer * pkPeer, DWORD dwHandle, TSafeboxLoadPacket *, bool bMall);
void QUERY_SAFEBOX_SAVE(CPeer * pkPeer, TSafeboxTable * pTable);
void QUERY_SAFEBOX_CHANGE_SIZE(CPeer * pkPeer, DWORD dwHandle, TSafeboxChangeSizePacket * p);
void QUERY_SAFEBOX_CHANGE_PASSWORD(CPeer * pkPeer, DWORD dwHandle, TSafeboxChangePasswordPacket * p);
void RESULT_SAFEBOX_LOAD(CPeer * pkPeer, SQLMsg * msg);
void RESULT_SAFEBOX_CHANGE_SIZE(CPeer * pkPeer, SQLMsg * msg);
void RESULT_SAFEBOX_CHANGE_PASSWORD(CPeer * pkPeer, SQLMsg * msg);
void RESULT_SAFEBOX_CHANGE_PASSWORD_SECOND(CPeer * pkPeer, SQLMsg * msg);
void QUERY_EMPIRE_SELECT(CPeer * pkPeer, DWORD dwHandle, TEmpireSelectPacket * p);
void QUERY_SETUP(CPeer * pkPeer, DWORD dwHandle, const char * c_pData);
void SendPartyOnSetup(CPeer * peer);
void QUERY_FLUSH_CACHE(CPeer * pkPeer, const char * c_pData);
void QUERY_PARTY_CREATE(CPeer * peer, TPacketPartyCreate* p);
void QUERY_PARTY_DELETE(CPeer * peer, TPacketPartyDelete* p);
void QUERY_PARTY_ADD(CPeer * peer, TPacketPartyAdd* p);
void QUERY_PARTY_REMOVE(CPeer * peer, TPacketPartyRemove* p);
void QUERY_PARTY_STATE_CHANGE(CPeer * peer, TPacketPartyStateChange* p);
void QUERY_PARTY_SET_MEMBER_LEVEL(CPeer * peer, TPacketPartySetMemberLevel* p);
void QUERY_RELOAD_PROTO();
void QUERY_CHANGE_NAME(CPeer * peer, DWORD dwHandle, TPacketGDChangeName * p);
void GetPlayerFromRes(TPlayerTable * player_table, MYSQL_RES* res);
void QUERY_LOGIN_KEY(CPeer * pkPeer, TPacketGDLoginKey * p);
void AddGuildPriv(TPacketGiveGuildPriv* p);
void AddEmpirePriv(TPacketGiveEmpirePriv* p);
void AddCharacterPriv(TPacketGiveCharacterPriv* p);
void MoneyLog(TPacketMoneyLog* p);
void QUERY_AUTH_LOGIN(CPeer * pkPeer, DWORD dwHandle, TPacketGDAuthLogin * p);
void QUERY_LOGIN_BY_KEY(CPeer * pkPeer, DWORD dwHandle, TPacketGDLoginByKey * p);
void RESULT_LOGIN_BY_KEY(CPeer * peer, SQLMsg * msg);
void ChargeCash(const TRequestChargeCash * p);
void LoadEventFlag();
void SetEventFlag(TPacketSetEventFlag* p);
void SendEventFlagsOnSetup(CPeer* peer);
void BillingExpire(TPacketBillingExpire * p);
void BillingCheck(const char * data);
void SendAllLoginToBilling();
void SendLoginToBilling(CLoginData * pkLD, bool bLogin);
void MarriageAdd(TPacketMarriageAdd * p);
void MarriageUpdate(TPacketMarriageUpdate * p);
void MarriageRemove(TPacketMarriageRemove * p);
void WeddingRequest(TPacketWeddingRequest * p);
void WeddingReady(TPacketWeddingReady * p);
void WeddingEnd(TPacketWeddingEnd * p);
// MYSHOP_PRICE_LIST
void MyshopPricelistUpdate(const TItemPriceListTable* pPacket); // @fixme403 (TPacketMyshopPricelistHeader to TItemPriceListTable)
void MyshopPricelistRequest(CPeer* peer, DWORD dwHandle, DWORD dwPlayerID);
// END_OF_MYSHOP_PRICE_LIST
// Building
void CreateObject(TPacketGDCreateObject * p);
void DeleteObject(DWORD dwID);
void UpdateLand(DWORD * pdw);
// BLOCK_CHAT
void BlockChat(TPacketBlockChat * p);
// END_OF_BLOCK_CHAT
private:
int m_looping;
socket_t m_fdAccept;
TPeerList m_peerList;
CPeer * m_pkAuthPeer;
// LoginKey, LoginData pair
typedef boost::unordered_map<DWORD, CLoginData *> TLoginDataByLoginKey;
TLoginDataByLoginKey m_map_pkLoginData;
// Login LoginData pair
typedef boost::unordered_map<std::string, CLoginData *> TLoginDataByLogin;
TLoginDataByLogin m_map_pkLoginDataByLogin;
// AccountID LoginData pair
typedef boost::unordered_map<DWORD, CLoginData *> TLoginDataByAID;
TLoginDataByAID m_map_pkLoginDataByAID;
typedef boost::unordered_map<std::string, CLoginData *> TLogonAccountMap;
TLogonAccountMap m_map_kLogonAccount;
int m_iPlayerIDStart;
int m_iPlayerDeleteLevelLimit;
int m_iPlayerDeleteLevelLimitLower;
bool m_bChinaEventServer;
std::vector<TMobTable> m_vec_mobTable;
std::vector<TItemTable> m_vec_itemTable;
std::map<DWORD, TItemTable *> m_map_itemTableByVnum;
int m_iShopTableSize;
TShopTable * m_pShopTable;
int m_iRefineTableSize;
TRefineTable* m_pRefineTable;
std::vector<TSkillTable> m_vec_skillTable;
std::vector<TBanwordTable> m_vec_banwordTable;
std::vector<TItemAttrTable> m_vec_itemAttrTable;
std::vector<TItemAttrTable> m_vec_itemRareTable;
std::vector<building::TLand> m_vec_kLandTable;
std::vector<building::TObjectProto> m_vec_kObjectProto;
std::map<DWORD, building::TObject *> m_map_pkObjectTable;
bool m_bShutdowned;
TPlayerTableCacheMap m_map_playerCache;
TItemCacheMap m_map_itemCache;
TItemCacheSetPtrMap m_map_pkItemCacheSetPtr;
// MYSHOP_PRICE_LIST
TItemPriceListCacheMap m_mapItemPriceListCache;
// END_OF_MYSHOP_PRICE_LIST
TChannelStatusMap m_mChannelStatus;
struct TPartyInfo
{
BYTE bRole;
BYTE bLevel;
TPartyInfo() :bRole(0), bLevel(0)
{
}
};
typedef std::map<DWORD, TPartyInfo> TPartyMember;
typedef std::map<DWORD, TPartyMember> TPartyMap;
typedef std::map<BYTE, TPartyMap> TPartyChannelMap;
TPartyChannelMap m_map_pkChannelParty;
typedef std::map<std::string, long> TEventFlagMap;
TEventFlagMap m_map_lEventFlag;
BYTE m_bLastHeader;
int m_iCacheFlushCount;
int m_iCacheFlushCountLimit;
private :
TItemIDRangeTable m_itemRange;
public :
bool InitializeNowItemID();
DWORD GetItemID();
DWORD GainItemID();
TItemIDRangeTable GetItemRange() { return m_itemRange; }
//BOOT_LOCALIZATION
public:
bool InitializeLocalization();
private:
std::vector<tLocale> m_vec_Locale;
//END_BOOT_LOCALIZATION
//ADMIN_MANAGER
bool __GetAdminInfo(const char *szIP, std::vector<tAdminInfo> & rAdminVec);
bool __GetHostInfo(std::vector<std::string> & rIPVec);
//END_ADMIN_MANAGER
//RELOAD_ADMIN
void ReloadAdmin(CPeer * peer, TPacketReloadAdmin * p);
//END_RELOAD_ADMIN
void BreakMarriage(CPeer * peer, const char * data);
struct TLogoutPlayer
{
DWORD pid;
time_t time;
bool operator < (const TLogoutPlayer & r)
{
return (pid < r.pid);
}
};
typedef boost::unordered_map<DWORD, TLogoutPlayer*> TLogoutPlayerMap;
TLogoutPlayerMap m_map_logout;
void InsertLogoutPlayer(DWORD pid);
void DeleteLogoutPlayer(DWORD pid);
void UpdateLogoutPlayer();
void UpdateItemCacheSet(DWORD pid);
void FlushPlayerCacheSet(DWORD pid);
//MONARCH
void Election(CPeer * peer, DWORD dwHandle, const char * p);
void Candidacy(CPeer * peer, DWORD dwHandle, const char * p);
void AddMonarchMoney(CPeer * peer, DWORD dwHandle, const char * p);
void TakeMonarchMoney(CPeer * peer, DWORD dwHandle, const char * p);
void ComeToVote(CPeer * peer, DWORD dwHandle, const char * p);
void RMCandidacy(CPeer * peer, DWORD dwHandle, const char * p);
void SetMonarch(CPeer * peer, DWORD dwHandle, const char * p);
void RMMonarch(CPeer * peer, DWORD dwHandle, const char * p);
void DecMonarchMoney(CPeer * peer, DWORD dwHandle, const char * p);
//END_MONARCH
void ChangeMonarchLord(CPeer* peer, DWORD dwHandle, TPacketChangeMonarchLord* info);
void SendSpareItemIDRange(CPeer* peer);
void UpdateHorseName(TPacketUpdateHorseName* data, CPeer* peer);
void AckHorseName(DWORD dwPID, CPeer* peer);
void DeleteLoginKey(TPacketDC *data);
void ResetLastPlayerID(const TPacketNeedLoginLogInfo* data);
//delete gift notify icon
void DeleteAwardId(TPacketDeleteAwardID* data);
void UpdateChannelStatus(TChannelStatus* pData);
void RequestChannelStatus(CPeer* peer, DWORD dwHandle);
#ifdef ENABLE_PROTO_FROM_DB
public:
bool InitializeMobTableFromDB();
bool InitializeItemTableFromDB();
protected:
bool bIsProtoReadFromDB;
#endif
};
template<class Func>
Func CClientManager::for_each_peer(Func f)
{
TPeerList::iterator it;
for (it = m_peerList.begin(); it!=m_peerList.end();++it)
{
f(*it);
}
return f;
}
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,77 @@
// vim:ts=4 sw=4
#include "stdafx.h"
#include "ClientManager.h"
#include "Main.h"
#include "Config.h"
#include "DBManager.h"
#include "QID.h"
void CClientManager::LoadEventFlag()
{
char szQuery[1024];
snprintf(szQuery, sizeof(szQuery), "SELECT szName, lValue FROM quest%s WHERE dwPID = 0", GetTablePostfix());
auto pmsg(CDBManager::instance().DirectQuery(szQuery));
SQLResult* pRes = pmsg->Get();
if (pRes->uiNumRows)
{
MYSQL_ROW row;
while ((row = mysql_fetch_row(pRes->pSQLResult)))
{
TPacketSetEventFlag p;
strlcpy(p.szFlagName, row[0], sizeof(p.szFlagName));
str_to_number(p.lValue, row[1]);
sys_log(0, "EventFlag Load %s %d", p.szFlagName, p.lValue);
m_map_lEventFlag.emplace(p.szFlagName, p.lValue);
ForwardPacket(HEADER_DG_SET_EVENT_FLAG, &p, sizeof(TPacketSetEventFlag));
}
}
}
void CClientManager::SetEventFlag(TPacketSetEventFlag* p)
{
ForwardPacket(HEADER_DG_SET_EVENT_FLAG, p, sizeof(TPacketSetEventFlag));
bool bChanged = false;
typeof(m_map_lEventFlag.begin()) it = m_map_lEventFlag.find(p->szFlagName);
if (it == m_map_lEventFlag.end())
{
bChanged = true;
m_map_lEventFlag.emplace(p->szFlagName, p->lValue);
}
else if (it->second != p->lValue)
{
bChanged = true;
it->second = p->lValue;
}
if (bChanged)
{
char szQuery[1024];
snprintf(szQuery, sizeof(szQuery),
"REPLACE INTO quest%s (dwPID, szName, szState, lValue) VALUES(0, '%s', '', %ld)",
GetTablePostfix(), p->szFlagName, p->lValue);
szQuery[1023] = '\0';
//CDBManager::instance().ReturnQuery(szQuery, QID_QUEST_SAVE, 0, NULL);
CDBManager::instance().AsyncQuery(szQuery);
sys_log(0, "HEADER_GD_SET_EVENT_FLAG : Changed CClientmanager::SetEventFlag(%s %d) ", p->szFlagName, p->lValue);
return;
}
sys_log(0, "HEADER_GD_SET_EVENT_FLAG : No Changed CClientmanager::SetEventFlag(%s %d) ", p->szFlagName, p->lValue);
}
void CClientManager::SendEventFlagsOnSetup(CPeer* peer)
{
typeof(m_map_lEventFlag.begin()) it;
for (it = m_map_lEventFlag.begin(); it != m_map_lEventFlag.end(); ++it)
{
TPacketSetEventFlag p;
strlcpy(p.szFlagName, it->first.c_str(), sizeof(p.szFlagName));
p.lValue = it->second;
peer->EncodeHeader(HEADER_DG_SET_EVENT_FLAG, 0, sizeof(TPacketSetEventFlag));
peer->Encode(&p, sizeof(TPacketSetEventFlag));
}
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,244 @@
// vim:ts=4 sw=4
#include "stdafx.h"
#include "ClientManager.h"
#include "Main.h"
#include "Config.h"
#include "DBManager.h"
#include "QID.h"
#include "GuildManager.h"
void CClientManager::GuildCreate(CPeer * peer, DWORD dwGuildID)
{
sys_log(0, "GuildCreate %u", dwGuildID);
ForwardPacket(HEADER_DG_GUILD_LOAD, &dwGuildID, sizeof(DWORD));
CGuildManager::instance().Load(dwGuildID);
}
void CClientManager::GuildChangeGrade(CPeer* peer, TPacketGuild* p)
{
sys_log(0, "GuildChangeGrade %u %u", p->dwGuild, p->dwInfo);
ForwardPacket(HEADER_DG_GUILD_CHANGE_GRADE, p, sizeof(TPacketGuild));
}
void CClientManager::GuildAddMember(CPeer* peer, TPacketGDGuildAddMember * p)
{
CGuildManager::instance().TouchGuild(p->dwGuild);
sys_log(0, "GuildAddMember %u %u", p->dwGuild, p->dwPID);
char szQuery[512];
snprintf(szQuery, sizeof(szQuery),
"INSERT INTO guild_member%s VALUES(%u, %u, %d, 0, 0)",
GetTablePostfix(), p->dwPID, p->dwGuild, p->bGrade);
auto pmsg_insert(CDBManager::instance().DirectQuery(szQuery));
snprintf(szQuery, sizeof(szQuery),
"SELECT pid, grade, is_general, offer, level, job, name FROM guild_member%s, player%s WHERE guild_id = %u and pid = id and pid = %u", GetTablePostfix(), GetTablePostfix(), p->dwGuild, p->dwPID);
auto pmsg(CDBManager::instance().DirectQuery(szQuery));
if (pmsg->Get()->uiNumRows == 0)
{
sys_err("Query failed when getting guild member data %s", pmsg->stQuery.c_str());
return;
}
MYSQL_ROW row = mysql_fetch_row(pmsg->Get()->pSQLResult);
if (!row[0] || !row[1])
return;
TPacketDGGuildMember dg;
dg.dwGuild = p->dwGuild;
str_to_number(dg.dwPID, row[0]);
str_to_number(dg.bGrade, row[1]);
str_to_number(dg.isGeneral, row[2]);
str_to_number(dg.dwOffer, row[3]);
str_to_number(dg.bLevel, row[4]);
str_to_number(dg.bJob, row[5]);
strlcpy(dg.szName, row[6], sizeof(dg.szName));
ForwardPacket(HEADER_DG_GUILD_ADD_MEMBER, &dg, sizeof(TPacketDGGuildMember));
}
void CClientManager::GuildRemoveMember(CPeer* peer, TPacketGuild* p)
{
sys_log(0, "GuildRemoveMember %u %u", p->dwGuild, p->dwInfo);
char szQuery[512];
snprintf(szQuery, sizeof(szQuery), "DELETE FROM guild_member%s WHERE pid=%u and guild_id=%u", GetTablePostfix(), p->dwInfo, p->dwGuild);
CDBManager::instance().AsyncQuery(szQuery);
// @fixme202 new_+withdraw_time
snprintf(szQuery, sizeof(szQuery), "REPLACE INTO quest%s (dwPID, szName, szState, lValue) VALUES(%u, 'guild_manage', 'new_withdraw_time', %u)", GetTablePostfix(), p->dwInfo, (DWORD) GetCurrentTime());
CDBManager::instance().AsyncQuery(szQuery);
ForwardPacket(HEADER_DG_GUILD_REMOVE_MEMBER, p, sizeof(TPacketGuild));
}
void CClientManager::GuildSkillUpdate(CPeer* peer, TPacketGuildSkillUpdate* p)
{
sys_log(0, "GuildSkillUpdate %d", p->amount);
ForwardPacket(HEADER_DG_GUILD_SKILL_UPDATE, p, sizeof(TPacketGuildSkillUpdate));
}
void CClientManager::GuildExpUpdate(CPeer* peer, TPacketGuildExpUpdate* p)
{
sys_log(0, "GuildExpUpdate %d", p->amount);
ForwardPacket(HEADER_DG_GUILD_EXP_UPDATE, p, sizeof(TPacketGuildExpUpdate), 0, peer);
}
void CClientManager::GuildChangeMemberData(CPeer* peer, TPacketGuildChangeMemberData* p)
{
sys_log(0, "GuildChangeMemberData %u %u %d %d", p->pid, p->offer, p->level, p->grade);
ForwardPacket(HEADER_DG_GUILD_CHANGE_MEMBER_DATA, p, sizeof(TPacketGuildChangeMemberData), 0, peer);
}
void CClientManager::GuildDisband(CPeer* peer, TPacketGuild* p)
{
sys_log(0, "GuildDisband %u", p->dwGuild);
char szQuery[512];
snprintf(szQuery, sizeof(szQuery), "DELETE FROM guild%s WHERE id=%u", GetTablePostfix(), p->dwGuild);
CDBManager::instance().AsyncQuery(szQuery);
snprintf(szQuery, sizeof(szQuery), "DELETE FROM guild_grade%s WHERE guild_id=%u", GetTablePostfix(), p->dwGuild);
CDBManager::instance().AsyncQuery(szQuery);
// @fixme401 (withdraw -> new_disband)_time
snprintf(szQuery, sizeof(szQuery), "REPLACE INTO quest%s (dwPID, szName, szState, lValue) SELECT pid, 'guild_manage', 'new_disband_time', %u FROM guild_member%s WHERE guild_id = %u", GetTablePostfix(), (DWORD) GetCurrentTime(), GetTablePostfix(), p->dwGuild);
CDBManager::instance().AsyncQuery(szQuery);
snprintf(szQuery, sizeof(szQuery), "DELETE FROM guild_member%s WHERE guild_id=%u", GetTablePostfix(), p->dwGuild);
CDBManager::instance().AsyncQuery(szQuery);
snprintf(szQuery, sizeof(szQuery), "DELETE FROM guild_comment%s WHERE guild_id=%u", GetTablePostfix(), p->dwGuild);
CDBManager::instance().AsyncQuery(szQuery);
ForwardPacket(HEADER_DG_GUILD_DISBAND, p, sizeof(TPacketGuild));
}
const char* __GetWarType(int n)
{
switch (n)
{
case 0 :
return "Field";
case 1 :
return "Theater";
case 2 :
return "CTF"; //Capture The Flag
default :
return "Wrong number";
}
}
void CClientManager::GuildWar(CPeer* peer, TPacketGuildWar* p)
{
switch (p->bWar)
{
case GUILD_WAR_SEND_DECLARE:
sys_log(0, "GuildWar: GUILD_WAR_SEND_DECLARE type(%s) guild(%d - %d)", __GetWarType(p->bType), p->dwGuildFrom, p->dwGuildTo);
CGuildManager::instance().AddDeclare(p->bType, p->dwGuildFrom, p->dwGuildTo);
break;
case GUILD_WAR_REFUSE:
sys_log(0, "GuildWar: GUILD_WAR_REFUSE type(%s) guild(%d - %d)", __GetWarType(p->bType), p->dwGuildFrom, p->dwGuildTo);
CGuildManager::instance().RemoveDeclare(p->dwGuildFrom, p->dwGuildTo);
break;
/*
case GUILD_WAR_WAIT_START:
CGuildManager::instance().RemoveDeclare(p->dwGuildFrom, p->dwGuildTo);
if (!CGuildManager::instance().WaitStart(p))
p->bWar = GUILD_WAR_CANCEL;
break;
*/
case GUILD_WAR_WAIT_START:
sys_log(0, "GuildWar: GUILD_WAR_WAIT_START type(%s) guild(%d - %d)", __GetWarType(p->bType), p->dwGuildFrom, p->dwGuildTo);
case GUILD_WAR_RESERVE:
if (p->bWar != GUILD_WAR_WAIT_START)
sys_log(0, "GuildWar: GUILD_WAR_RESERVE type(%s) guild(%d - %d)", __GetWarType(p->bType), p->dwGuildFrom, p->dwGuildTo);
CGuildManager::instance().RemoveDeclare(p->dwGuildFrom, p->dwGuildTo);
if (!CGuildManager::instance().ReserveWar(p))
p->bWar = GUILD_WAR_CANCEL;
else
p->bWar = GUILD_WAR_RESERVE;
break;
case GUILD_WAR_ON_WAR:
sys_log(0, "GuildWar: GUILD_WAR_ON_WAR type(%s) guild(%d - %d)", __GetWarType(p->bType), p->dwGuildFrom, p->dwGuildTo);
CGuildManager::instance().RemoveDeclare(p->dwGuildFrom, p->dwGuildTo);
CGuildManager::instance().StartWar(p->bType, p->dwGuildFrom, p->dwGuildTo);
break;
case GUILD_WAR_OVER:
sys_log(0, "GuildWar: GUILD_WAR_OVER type(%s) guild(%d - %d)", __GetWarType(p->bType), p->dwGuildFrom, p->dwGuildTo);
CGuildManager::instance().RecvWarOver(p->dwGuildFrom, p->dwGuildTo, p->bType, p->lWarPrice);
break;
case GUILD_WAR_END:
sys_log(0, "GuildWar: GUILD_WAR_END type(%s) guild(%d - %d)", __GetWarType(p->bType), p->dwGuildFrom, p->dwGuildTo);
CGuildManager::instance().RecvWarEnd(p->dwGuildFrom, p->dwGuildTo);
return;
case GUILD_WAR_CANCEL :
sys_log(0, "GuildWar: GUILD_WAR_CANCEL type(%s) guild(%d - %d)", __GetWarType(p->bType), p->dwGuildFrom, p->dwGuildTo);
CGuildManager::instance().CancelWar(p->dwGuildFrom, p->dwGuildTo);
break;
}
ForwardPacket(HEADER_DG_GUILD_WAR, p, sizeof(TPacketGuildWar));
}
void CClientManager::GuildWarScore(CPeer* peer, TPacketGuildWarScore * p)
{
CGuildManager::instance().UpdateScore(p->dwGuildGainPoint, p->dwGuildOpponent, p->lScore, p->lBetScore);
}
void CClientManager::GuildChangeLadderPoint(TPacketGuildLadderPoint* p)
{
sys_log(0, "GuildChangeLadderPoint Recv %u %d", p->dwGuild, p->lChange);
CGuildManager::instance().ChangeLadderPoint(p->dwGuild, p->lChange);
}
void CClientManager::GuildUseSkill(TPacketGuildUseSkill* p)
{
sys_log(0, "GuildUseSkill Recv %u %d", p->dwGuild, p->dwSkillVnum);
CGuildManager::instance().UseSkill(p->dwGuild, p->dwSkillVnum, p->dwCooltime);
SendGuildSkillUsable(p->dwGuild, p->dwSkillVnum, false);
}
void CClientManager::SendGuildSkillUsable(DWORD guild_id, DWORD dwSkillVnum, bool bUsable)
{
sys_log(0, "SendGuildSkillUsable Send %u %d %s", guild_id, dwSkillVnum, bUsable?"true":"false");
TPacketGuildSkillUsableChange p;
p.dwGuild = guild_id;
p.dwSkillVnum = dwSkillVnum;
p.bUsable = bUsable;
ForwardPacket(HEADER_DG_GUILD_SKILL_USABLE_CHANGE, &p, sizeof(TPacketGuildSkillUsableChange));
}
void CClientManager::GuildChangeMaster(TPacketChangeGuildMaster* p)
{
if (CGuildManager::instance().ChangeMaster(p->dwGuildID, p->idFrom, p->idTo) == true)
{
TPacketChangeGuildMaster packet;
packet.dwGuildID = p->dwGuildID;
packet.idFrom = 0;
packet.idTo = 0;
ForwardPacket(HEADER_DG_ACK_CHANGE_GUILD_MASTER, &packet, sizeof(packet));
}
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,39 @@
// vim:ts=4 sw=4
#include "stdafx.h"
#include "ClientManager.h"
void CClientManager::UpdateHorseName(TPacketUpdateHorseName* data, CPeer* peer)
{
char szQuery[512];
snprintf(szQuery, sizeof(szQuery), "REPLACE INTO horse_name VALUES(%u, '%s')", data->dwPlayerID, data->szHorseName);
auto pmsg_insert(CDBManager::instance().DirectQuery(szQuery));
ForwardPacket(HEADER_DG_UPDATE_HORSE_NAME, data, sizeof(TPacketUpdateHorseName), 0, peer);
}
void CClientManager::AckHorseName(DWORD dwPID, CPeer* peer)
{
char szQuery[512];
snprintf(szQuery, sizeof(szQuery), "SELECT name FROM horse_name WHERE id = %u", dwPID);
auto pmsg(CDBManager::instance().DirectQuery(szQuery));
TPacketUpdateHorseName packet;
packet.dwPlayerID = dwPID;
if (pmsg->Get()->uiNumRows == 0)
{
memset(packet.szHorseName, 0, sizeof (packet.szHorseName));
}
else
{
MYSQL_ROW row = mysql_fetch_row(pmsg->Get()->pSQLResult);
strlcpy(packet.szHorseName, row[0], sizeof(packet.szHorseName));
}
peer->EncodeHeader(HEADER_DG_ACK_HORSE_NAME, 0, sizeof(TPacketUpdateHorseName));
peer->Encode(&packet, sizeof(TPacketUpdateHorseName));
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,538 @@
#include "stdafx.h"
#include "../../common/CommonDefines.h"
#include "ClientManager.h"
#include "Main.h"
#include "Config.h"
#include "QID.h"
#include "Cache.h"
extern std::string g_stLocale;
extern bool CreatePlayerTableFromRes(MYSQL_RES * res, TPlayerTable * pkTab);
extern int g_test_server;
extern int g_log;
bool CClientManager::InsertLogonAccount(const char * c_pszLogin, DWORD dwHandle, const char * c_pszIP)
{
char szLogin[LOGIN_MAX_LEN + 1];
trim_and_lower(c_pszLogin, szLogin, sizeof(szLogin));
itertype(m_map_kLogonAccount) it = m_map_kLogonAccount.find(szLogin);
if (m_map_kLogonAccount.end() != it)
return false;
CLoginData * pkLD = GetLoginDataByLogin(c_pszLogin);
if (!pkLD)
return false;
pkLD->SetConnectedPeerHandle(dwHandle);
pkLD->SetIP(c_pszIP);
m_map_kLogonAccount.emplace(szLogin, pkLD);
return true;
}
bool CClientManager::DeleteLogonAccount(const char * c_pszLogin, DWORD dwHandle)
{
char szLogin[LOGIN_MAX_LEN + 1];
trim_and_lower(c_pszLogin, szLogin, sizeof(szLogin));
itertype(m_map_kLogonAccount) it = m_map_kLogonAccount.find(szLogin);
if (it == m_map_kLogonAccount.end())
return false;
CLoginData * pkLD = it->second;
if (pkLD->GetConnectedPeerHandle() != dwHandle)
{
sys_err("%s tried to logout in other peer handle %lu, current handle %lu", szLogin, dwHandle, pkLD->GetConnectedPeerHandle());
return false;
}
if (pkLD->IsPlay())
{
pkLD->SetPlay(false);
SendLoginToBilling(pkLD, false);
}
if (pkLD->IsDeleted())
{
delete pkLD;
}
m_map_kLogonAccount.erase(it);
return true;
}
bool CClientManager::FindLogonAccount(const char * c_pszLogin)
{
char szLogin[LOGIN_MAX_LEN + 1];
trim_and_lower(c_pszLogin, szLogin, sizeof(szLogin));
if (m_map_kLogonAccount.end() == m_map_kLogonAccount.find(szLogin))
return false;
return true;
}
void CClientManager::QUERY_LOGIN_BY_KEY(CPeer * pkPeer, DWORD dwHandle, TPacketGDLoginByKey * p)
{
#ifdef ENABLE_LIMIT_TIME
static int s_updateCount = 0;
static int s_curTime = time(0);
if (s_updateCount > 100)
{
s_curTime = time(0);
s_updateCount = 0;
}
++s_updateCount;
if (s_curTime >= GLOBAL_LIMIT_TIME)
{
sys_err("Server life time expired.");
exit(0);
return;
}
#endif
CLoginData * pkLoginData = GetLoginData(p->dwLoginKey);
char szLogin[LOGIN_MAX_LEN + 1];
trim_and_lower(p->szLogin, szLogin, sizeof(szLogin));
if (!pkLoginData)
{
sys_log(0, "LOGIN_BY_KEY key not exist %s %lu", szLogin, p->dwLoginKey);
pkPeer->EncodeReturn(HEADER_DG_LOGIN_NOT_EXIST, dwHandle);
return;
}
TAccountTable & r = pkLoginData->GetAccountRef();
if (FindLogonAccount(r.login))
{
sys_log(0, "LOGIN_BY_KEY already login %s %lu", r.login, p->dwLoginKey);
TPacketDGLoginAlready ptog;
strlcpy(ptog.szLogin, szLogin, sizeof(ptog.szLogin));
pkPeer->EncodeHeader(HEADER_DG_LOGIN_ALREADY, dwHandle, sizeof(TPacketDGLoginAlready));
pkPeer->Encode(&ptog, sizeof(TPacketDGLoginAlready));
return;
}
if (strcasecmp(r.login, szLogin))
{
sys_log(0, "LOGIN_BY_KEY login differ %s %lu input %s", r.login, p->dwLoginKey, szLogin);
pkPeer->EncodeReturn(HEADER_DG_LOGIN_NOT_EXIST, dwHandle);
return;
}
if (memcmp(pkLoginData->GetClientKey(), p->adwClientKey, sizeof(DWORD) * 4))
{
const DWORD * pdwClientKey = pkLoginData->GetClientKey();
sys_log(0, "LOGIN_BY_KEY client key differ %s %lu %lu %lu %lu, %lu %lu %lu %lu",
r.login,
p->adwClientKey[0], p->adwClientKey[1], p->adwClientKey[2], p->adwClientKey[3],
pdwClientKey[0], pdwClientKey[1], pdwClientKey[2], pdwClientKey[3]);
pkPeer->EncodeReturn(HEADER_DG_LOGIN_NOT_EXIST, dwHandle);
return;
}
TAccountTable * pkTab = new TAccountTable;
memset(pkTab, 0, sizeof(TAccountTable));
pkTab->id = r.id;
trim_and_lower(r.login, pkTab->login, sizeof(pkTab->login));
strlcpy(pkTab->passwd, r.passwd, sizeof(pkTab->passwd));
strlcpy(pkTab->social_id, r.social_id, sizeof(pkTab->social_id));
strlcpy(pkTab->status, "OK", sizeof(pkTab->status));
ClientHandleInfo * info = new ClientHandleInfo(dwHandle);
info->pAccountTable = pkTab;
strlcpy(info->ip, p->szIP, sizeof(info->ip));
sys_log(0, "LOGIN_BY_KEY success %s %lu %s", r.login, p->dwLoginKey, info->ip);
char szQuery[QUERY_MAX_LEN];
#ifdef ENABLE_PLAYER_PER_ACCOUNT5
snprintf(szQuery, sizeof(szQuery), "SELECT pid1, pid2, pid3, pid4, pid5, empire FROM player_index%s WHERE id=%u", GetTablePostfix(), r.id);
#else
snprintf(szQuery, sizeof(szQuery), "SELECT pid1, pid2, pid3, pid4, empire FROM player_index%s WHERE id=%u", GetTablePostfix(), r.id);
#endif
CDBManager::instance().ReturnQuery(szQuery, QID_LOGIN_BY_KEY, pkPeer->GetHandle(), info);
}
void CClientManager::RESULT_LOGIN_BY_KEY(CPeer * peer, SQLMsg * msg)
{
CQueryInfo * qi = (CQueryInfo *) msg->pvUserData;
ClientHandleInfo * info = (ClientHandleInfo *) qi->pvData;
if (msg->uiSQLErrno != 0)
{
peer->EncodeReturn(HEADER_DG_LOGIN_NOT_EXIST, info->dwHandle);
delete info;
return;
}
char szQuery[QUERY_MAX_LEN];
if (msg->Get()->uiNumRows == 0)
{
DWORD account_id = info->pAccountTable->id;
char szQuery[QUERY_MAX_LEN];
snprintf(szQuery, sizeof(szQuery),
"SELECT pid1, pid2, pid3, pid4,"
#ifdef ENABLE_PLAYER_PER_ACCOUNT5
" pid5,"
#endif
" empire FROM player_index%s WHERE id=%u", GetTablePostfix(), account_id);
auto pMsg(CDBManager::instance().DirectQuery(szQuery, SQL_PLAYER));
sys_log(0, "RESULT_LOGIN_BY_KEY FAIL player_index's NULL : ID:%d", account_id);
if (pMsg->Get()->uiNumRows == 0)
{
sys_log(0, "RESULT_LOGIN_BY_KEY FAIL player_index's NULL : ID:%d", account_id);
// PLAYER_INDEX_CREATE_BUG_FIX
//snprintf(szQuery, sizeof(szQuery), "INSERT IGNORE INTO player_index%s (id) VALUES(%lu)", GetTablePostfix(), info->pAccountTable->id);
snprintf(szQuery, sizeof(szQuery), "INSERT INTO player_index%s (id) VALUES(%u)", GetTablePostfix(), info->pAccountTable->id);
CDBManager::instance().ReturnQuery(szQuery, QID_PLAYER_INDEX_CREATE, peer->GetHandle(), info);
// END_PLAYER_INDEX_CREATE_BUF_FIX
}
return;
}
MYSQL_ROW row = mysql_fetch_row(msg->Get()->pSQLResult);
int col = 0;
for (; col < PLAYER_PER_ACCOUNT; ++col)
str_to_number(info->pAccountTable->players[col].dwID, row[col]);
str_to_number(info->pAccountTable->bEmpire, row[col++]);
info->account_index = 1;
snprintf(szQuery, sizeof(szQuery),
"SELECT id, name, job, level, playtime, st, ht, dx, iq, part_main, part_hair,"
#ifdef ENABLE_ACCE_COSTUME_SYSTEM
"part_acce,"
#endif
" x, y, skill_group, change_name FROM player%s WHERE account_id=%u",
GetTablePostfix(), info->pAccountTable->id);
CDBManager::instance().ReturnQuery(szQuery, QID_LOGIN, peer->GetHandle(), info);
}
// PLAYER_INDEX_CREATE_BUG_FIX
void CClientManager::RESULT_PLAYER_INDEX_CREATE(CPeer * pkPeer, SQLMsg * msg)
{
CQueryInfo * qi = (CQueryInfo *) msg->pvUserData;
ClientHandleInfo * info = (ClientHandleInfo *) qi->pvData;
char szQuery[QUERY_MAX_LEN];
#ifdef ENABLE_PLAYER_PER_ACCOUNT5
snprintf(szQuery, sizeof(szQuery), "SELECT pid1, pid2, pid3, pid4, pid5, empire FROM player_index%s WHERE id=%u", GetTablePostfix(),
info->pAccountTable->id);
#else
snprintf(szQuery, sizeof(szQuery), "SELECT pid1, pid2, pid3, pid4, empire FROM player_index%s WHERE id=%u", GetTablePostfix(),
info->pAccountTable->id);
#endif
CDBManager::instance().ReturnQuery(szQuery, QID_LOGIN_BY_KEY, pkPeer->GetHandle(), info);
}
// END_PLAYER_INDEX_CREATE_BUG_FIX
TAccountTable * CreateAccountTableFromRes(MYSQL_RES * res)
{
char input_pwd[PASSWD_MAX_LEN + 1];
MYSQL_ROW row = NULL;
DWORD col;
row = mysql_fetch_row(res);
col = 0;
TAccountTable * pkTab = new TAccountTable;
memset(pkTab, 0, sizeof(TAccountTable));
strlcpy(input_pwd, row[col++], sizeof(input_pwd));
str_to_number(pkTab->id, row[col++]);
strlcpy(pkTab->login, row[col++], sizeof(pkTab->login));
strlcpy(pkTab->passwd, row[col++], sizeof(pkTab->passwd));
strlcpy(pkTab->social_id, row[col++], sizeof(pkTab->social_id));
str_to_number(pkTab->bEmpire, row[col++]);
for (int j = 0; j < PLAYER_PER_ACCOUNT; ++j)
str_to_number(pkTab->players[j].dwID, row[col++]);
strlcpy(pkTab->status, row[col++], sizeof(pkTab->status));
if (strcmp(pkTab->passwd, input_pwd))
{
delete pkTab;
return NULL;
}
return pkTab;
}
void CreateAccountPlayerDataFromRes(MYSQL_RES * pRes, TAccountTable * pkTab)
{
if (!pRes)
return;
for (DWORD i = 0; i < mysql_num_rows(pRes); ++i)
{
MYSQL_ROW row = mysql_fetch_row(pRes);
int col = 0;
DWORD player_id = 0;
!row[col++] ? 0 : str_to_number(player_id, row[col - 1]);
if (!player_id)
continue;
int j;
for (j = 0; j < PLAYER_PER_ACCOUNT; ++j)
{
if (pkTab->players[j].dwID == player_id)
{
CPlayerTableCache * pc = CClientManager::instance().GetPlayerCache(player_id);
TPlayerTable * pt = pc ? pc->Get(false) : NULL;
if (pt)
{
strlcpy(pkTab->players[j].szName, pt->name, sizeof(pkTab->players[j].szName));
pkTab->players[j].byJob = pt->job;
pkTab->players[j].byLevel = pt->level;
pkTab->players[j].dwPlayMinutes = pt->playtime;
pkTab->players[j].byST = pt->st;
pkTab->players[j].byHT = pt->ht;
pkTab->players[j].byDX = pt->dx;
pkTab->players[j].byIQ = pt->iq;
pkTab->players[j].wMainPart = pt->parts[PART_MAIN];
pkTab->players[j].wHairPart = pt->parts[PART_HAIR];
#ifdef ENABLE_ACCE_COSTUME_SYSTEM
pkTab->players[j].wAccePart = pt->parts[PART_ACCE];
#endif
pkTab->players[j].x = pt->x;
pkTab->players[j].y = pt->y;
pkTab->players[j].skill_group = pt->skill_group;
pkTab->players[j].bChangeName = 0;
}
else
{
if (!row[col++])
*pkTab->players[j].szName = '\0';
else
strlcpy(pkTab->players[j].szName, row[col - 1], sizeof(pkTab->players[j].szName));
pkTab->players[j].byJob = 0;
pkTab->players[j].byLevel = 0;
pkTab->players[j].dwPlayMinutes = 0;
pkTab->players[j].byST = 0;
pkTab->players[j].byHT = 0;
pkTab->players[j].byDX = 0;
pkTab->players[j].byIQ = 0;
pkTab->players[j].wMainPart = 0;
pkTab->players[j].wHairPart = 0;
#ifdef ENABLE_ACCE_COSTUME_SYSTEM
pkTab->players[j].wAccePart = 0;
#endif
pkTab->players[j].x = 0;
pkTab->players[j].y = 0;
pkTab->players[j].skill_group = 0;
pkTab->players[j].bChangeName = 0;
str_to_number(pkTab->players[j].byJob, row[col++]);
str_to_number(pkTab->players[j].byLevel, row[col++]);
str_to_number(pkTab->players[j].dwPlayMinutes, row[col++]);
str_to_number(pkTab->players[j].byST, row[col++]);
str_to_number(pkTab->players[j].byHT, row[col++]);
str_to_number(pkTab->players[j].byDX, row[col++]);
str_to_number(pkTab->players[j].byIQ, row[col++]);
str_to_number(pkTab->players[j].wMainPart, row[col++]);
str_to_number(pkTab->players[j].wHairPart, row[col++]);
#ifdef ENABLE_ACCE_COSTUME_SYSTEM
str_to_number(pkTab->players[j].wAccePart, row[col++]);
#endif
str_to_number(pkTab->players[j].x, row[col++]);
str_to_number(pkTab->players[j].y, row[col++]);
str_to_number(pkTab->players[j].skill_group, row[col++]);
str_to_number(pkTab->players[j].bChangeName, row[col++]);
}
sys_log(0, "%s %lu %lu hair %u",
pkTab->players[j].szName, pkTab->players[j].x, pkTab->players[j].y, pkTab->players[j].wHairPart);
break;
}
}
}
}
void CClientManager::RESULT_LOGIN(CPeer * peer, SQLMsg * msg)
{
CQueryInfo * qi = (CQueryInfo *) msg->pvUserData;
ClientHandleInfo * info = (ClientHandleInfo *) qi->pvData;
if (info->account_index == 0)
{
if (msg->Get()->uiNumRows == 0)
{
sys_log(0, "RESULT_LOGIN: no account");
peer->EncodeHeader(HEADER_DG_LOGIN_NOT_EXIST, info->dwHandle, 0);
delete info;
return;
}
info->pAccountTable = CreateAccountTableFromRes(msg->Get()->pSQLResult);
if (!info->pAccountTable)
{
sys_log(0, "RESULT_LOGIN: no account : WRONG_PASSWD");
peer->EncodeReturn(HEADER_DG_LOGIN_WRONG_PASSWD, info->dwHandle);
delete info;
}
else
{
++info->account_index;
char queryStr[512];
snprintf(queryStr, sizeof(queryStr),
"SELECT id, name, job, level, playtime, st, ht, dx, iq, part_main, part_hair,"
#ifdef ENABLE_ACCE_COSTUME_SYSTEM
"part_acce, "
#endif
" x, y, skill_group, change_name FROM player%s WHERE account_id=%u",
GetTablePostfix(), info->pAccountTable->id);
CDBManager::instance().ReturnQuery(queryStr, QID_LOGIN, peer->GetHandle(), info);
}
return;
}
else
{
if (!info->pAccountTable)
{
peer->EncodeReturn(HEADER_DG_LOGIN_WRONG_PASSWD, info->dwHandle);
delete info;
return;
}
if (!InsertLogonAccount(info->pAccountTable->login, peer->GetHandle(), info->ip))
{
sys_log(0, "RESULT_LOGIN: already logon %s", info->pAccountTable->login);
TPacketDGLoginAlready p;
strlcpy(p.szLogin, info->pAccountTable->login, sizeof(p.szLogin));
peer->EncodeHeader(HEADER_DG_LOGIN_ALREADY, info->dwHandle, sizeof(TPacketDGLoginAlready));
peer->Encode(&p, sizeof(p));
}
else
{
sys_log(0, "RESULT_LOGIN: login success %s rows: %lu", info->pAccountTable->login, msg->Get()->uiNumRows);
if (msg->Get()->uiNumRows > 0)
CreateAccountPlayerDataFromRes(msg->Get()->pSQLResult, info->pAccountTable);
//PREVENT_COPY_ITEM
CLoginData * p = GetLoginDataByLogin(info->pAccountTable->login);
memcpy(&p->GetAccountRef(), info->pAccountTable, sizeof(TAccountTable));
//END_PREVENT_COPY_ITEM
peer->EncodeHeader(HEADER_DG_LOGIN_SUCCESS, info->dwHandle, sizeof(TAccountTable));
peer->Encode(info->pAccountTable, sizeof(TAccountTable));
}
delete info->pAccountTable;
info->pAccountTable = NULL;
delete info;
}
}
void CClientManager::QUERY_LOGOUT(CPeer * peer, DWORD dwHandle,const char * data)
{
TLogoutPacket* packet = (TLogoutPacket*)data;
if (!*packet->login)
return;
CLoginData * pLoginData = GetLoginDataByLogin(packet->login);
if (pLoginData == NULL)
return;
int pid[PLAYER_PER_ACCOUNT];
for (int n = 0; n < PLAYER_PER_ACCOUNT; ++n)
{
if (pLoginData->GetAccountRef().players[n].dwID == 0)
{
if (g_test_server)
sys_log(0, "LOGOUT %s %d", packet->login, pLoginData->GetAccountRef().players[n].dwID);
continue;
}
pid[n] = pLoginData->GetAccountRef().players[n].dwID;
if (g_log)
sys_log(0, "LOGOUT InsertLogoutPlayer %s %d", packet->login, pid[n]);
InsertLogoutPlayer(pid[n]);
}
if (DeleteLogonAccount(packet->login, peer->GetHandle()))
{
if (g_log)
sys_log(0, "LOGOUT %s ", packet->login);
}
}
void CClientManager::QUERY_CHANGE_NAME(CPeer * peer, DWORD dwHandle, TPacketGDChangeName * p)
{
char queryStr[QUERY_MAX_LEN];
snprintf(queryStr, sizeof(queryStr),
"SELECT COUNT(*) as count FROM player%s WHERE name='%s' AND id <> %u", GetTablePostfix(), p->name, p->pid);
auto pMsg(CDBManager::instance().DirectQuery(queryStr, SQL_PLAYER));
if (pMsg->Get()->uiNumRows)
{
if (!pMsg->Get()->pSQLResult)
{
peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
return;
}
MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult);
if (*row[0] != '0')
{
peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_ALREADY, dwHandle, 0);
return;
}
}
else
{
peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0);
return;
}
snprintf(queryStr, sizeof(queryStr),
"UPDATE player%s SET name='%s',change_name=0 WHERE id=%u", GetTablePostfix(), p->name, p->pid);
auto pMsg0(CDBManager::instance().DirectQuery(queryStr, SQL_PLAYER));
TPacketDGChangeName pdg;
peer->EncodeHeader(HEADER_DG_CHANGE_NAME, dwHandle, sizeof(TPacketDGChangeName));
pdg.pid = p->pid;
strlcpy(pdg.name, p->name, sizeof(pdg.name));
peer->Encode(&pdg, sizeof(TPacketDGChangeName));
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,136 @@
// vim:ts=4 sw=4
#include "stdafx.h"
#include "ClientManager.h"
#include "Config.h"
#include "DBManager.h"
#include "QID.h"
void CClientManager::QUERY_PARTY_CREATE(CPeer* peer, TPacketPartyCreate* p)
{
TPartyMap & pm = m_map_pkChannelParty[peer->GetChannel()];
if (pm.find(p->dwLeaderPID) == pm.end())
{
pm.emplace(p->dwLeaderPID, TPartyMember());
ForwardPacket(HEADER_DG_PARTY_CREATE, p, sizeof(TPacketPartyCreate), peer->GetChannel(), peer);
sys_log(0, "PARTY Create [%lu]", p->dwLeaderPID);
}
else
{
sys_err("PARTY Create - Already exists [%lu]", p->dwLeaderPID);
}
}
void CClientManager::QUERY_PARTY_DELETE(CPeer* peer, TPacketPartyDelete* p)
{
TPartyMap& pm = m_map_pkChannelParty[peer->GetChannel()];
itertype(pm) it = pm.find(p->dwLeaderPID);
if (it == pm.end())
{
sys_err("PARTY Delete - Non exists [%lu]", p->dwLeaderPID);
return;
}
pm.erase(it);
ForwardPacket(HEADER_DG_PARTY_DELETE, p, sizeof(TPacketPartyDelete), peer->GetChannel(), peer);
sys_log(0, "PARTY Delete [%lu]", p->dwLeaderPID);
}
void CClientManager::QUERY_PARTY_ADD(CPeer* peer, TPacketPartyAdd* p)
{
TPartyMap & pm = m_map_pkChannelParty[peer->GetChannel()];
itertype(pm) it = pm.find(p->dwLeaderPID);
if (it == pm.end())
{
sys_err("PARTY Add - Non exists [%lu]", p->dwLeaderPID);
return;
}
if (it->second.find(p->dwPID) == it->second.end())
{
it->second.emplace(p->dwPID, TPartyInfo());
ForwardPacket(HEADER_DG_PARTY_ADD, p, sizeof(TPacketPartyAdd), peer->GetChannel(), peer);
sys_log(0, "PARTY Add [%lu] to [%lu]", p->dwPID, p->dwLeaderPID);
}
else
sys_err("PARTY Add - Already [%lu] in party [%lu]", p->dwPID, p->dwLeaderPID);
}
void CClientManager::QUERY_PARTY_REMOVE(CPeer* peer, TPacketPartyRemove* p)
{
TPartyMap & pm = m_map_pkChannelParty[peer->GetChannel()];
itertype(pm) it = pm.find(p->dwLeaderPID);
if (it == pm.end())
{
sys_err("PARTY Remove - Non exists [%lu] cannot remove [%lu]",p->dwLeaderPID, p->dwPID);
return;
}
itertype(it->second) pit = it->second.find(p->dwPID);
if (pit != it->second.end())
{
it->second.erase(pit);
ForwardPacket(HEADER_DG_PARTY_REMOVE, p, sizeof(TPacketPartyRemove), peer->GetChannel(), peer);
sys_log(0, "PARTY Remove [%lu] to [%lu]", p->dwPID, p->dwLeaderPID);
}
else
sys_err("PARTY Remove - Cannot find [%lu] in party [%lu]", p->dwPID, p->dwLeaderPID);
}
void CClientManager::QUERY_PARTY_STATE_CHANGE(CPeer* peer, TPacketPartyStateChange* p)
{
TPartyMap & pm = m_map_pkChannelParty[peer->GetChannel()];
itertype(pm) it = pm.find(p->dwLeaderPID);
if (it == pm.end())
{
sys_err("PARTY StateChange - Non exists [%lu] cannot state change [%lu]",p->dwLeaderPID, p->dwPID);
return;
}
itertype(it->second) pit = it->second.find(p->dwPID);
if (pit == it->second.end())
{
sys_err("PARTY StateChange - Cannot find [%lu] in party [%lu]", p->dwPID, p->dwLeaderPID);
return;
}
if (p->bFlag)
pit->second.bRole = p->bRole;
else
pit->second.bRole = 0;
ForwardPacket(HEADER_DG_PARTY_STATE_CHANGE, p, sizeof(TPacketPartyStateChange), peer->GetChannel(), peer);
sys_log(0, "PARTY StateChange [%lu] at [%lu] from %d %d",p->dwPID, p->dwLeaderPID, p->bRole, p->bFlag);
}
void CClientManager::QUERY_PARTY_SET_MEMBER_LEVEL(CPeer* peer, TPacketPartySetMemberLevel* p)
{
TPartyMap & pm = m_map_pkChannelParty[peer->GetChannel()];
itertype(pm) it = pm.find(p->dwLeaderPID);
if (it == pm.end())
{
sys_err("PARTY SetMemberLevel - Non exists [%lu] cannot level change [%lu]",p->dwLeaderPID, p->dwPID);
return;
}
itertype(it->second) pit = it->second.find(p->dwPID);
if (pit == it->second.end())
{
sys_err("PARTY SetMemberLevel - Cannot find [%lu] in party [%lu]", p->dwPID, p->dwLeaderPID);
return;
}
pit->second.bLevel = p->bLevel;
ForwardPacket(HEADER_DG_PARTY_SET_MEMBER_LEVEL, p, sizeof(TPacketPartySetMemberLevel), peer->GetChannel());
sys_log(0, "PARTY SetMemberLevel pid [%lu] level %d",p->dwPID, p->bLevel);
}
//martysama0134's 623a0779c74cb7565145d45548376308

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,246 @@
#include "stdafx.h"
#include "Config.h"
CConfig::CConfig()
{
}
CConfig::~CConfig()
{
Destroy();
}
void CConfig::Destroy()
{
m_valueMap.clear();
}
void CConfig::NextLine(FILE *fp)
{
int c;
while ((c = fgetc(fp)) != EOF)
{
if (c == '\n')
return;
}
}
bool CConfig::GetWord(FILE *fp, char *tar)
{
int i = 0;
int c;
int semicolon_mode = 0;
while ((c = fgetc(fp)) != EOF)
{
if (c == 13)
continue;
if (semicolon_mode)
{
if (c == '"')
{
tar[i] = '\0';
return true;
}
tar[i++] = c;
continue;
}
else
{
if (i == 0)
{
if (c == '"')
{
semicolon_mode = 1;
continue;
}
if (c == ' ' || c == '\t' || c == '\n')
{
continue;
}
}
if ((c == ' ' || c == '\t' || c == '\n'))
{
tar[i] = '\0';
return true;
}
tar[i] = c;
++i;
}
}
return (i != 0);
}
bool CConfig::GetLine(FILE* fp, char*dest)
{
int c;
int i = 0;
while ((c = fgetc(fp)) != EOF)
{
if (c == '\n')
return true;
dest[i] = c;
++i;
}
return true;
}
bool CConfig::LoadFile(const char* filename)
{
char szTmp[256];
char comment[256];
FILE * fp = fopen(filename, "rb");
if (fp == NULL)
return false;
int mode = 0;
while (GetWord(fp, szTmp))
{
if (strcmp(szTmp, "//") == 0)
{
NextLine(fp);
continue;
}
switch (mode)
{
case 0:
strlcpy(comment, szTmp, sizeof(comment));
++mode;
break;
case 1:
if (*szTmp == '=')
++mode;
break;
case 2:
mode = 0;
m_valueMap.emplace(comment, szTmp);
break;
}
// ITEM_ID_RANGE
if (mode == 2 && strcmp(comment, "ITEM_ID_RANGE") == 0)
{
GetLine(fp, szTmp);
m_valueMap.emplace(comment, szTmp);
mode = 0;
}
// ITEM_ID_RANGE_END
}
fclose(fp);
return true;
}
std::string * CConfig::Search(const char* key)
{
itertype(m_valueMap) i = m_valueMap.find(key);
if (i == m_valueMap.end())
return NULL;
else
return (&i->second);
}
bool CConfig::GetParam(const char*key, int index, DWORD *Param)
{
std::string * pstStr = Search(key);
if (!pstStr)
return false;
char szParam[5][32];
sscanf(pstStr->c_str(), "%s %s %s %s %s", szParam[0],szParam[1],szParam[2],szParam[3],szParam[4]);
str_to_number(*Param, szParam[index]);
sys_log(0, "GetParam %d", *Param);
return true;
}
const char * CConfig::Get(const char* key)
{
std::string * pstStr = Search(key);
if (!pstStr)
{
static std::string stTemp = "";
return stTemp.c_str();
}
return pstStr->c_str();
}
bool CConfig::GetValue(const char * key, int* dest)
{
if (!Search(key))
return false;
str_to_number(*dest, Get(key));
return true;
}
bool CConfig::GetValue(const char * key, float *dest)
{
if (!Search(key))
return false;
str_to_number(*dest, Get(key));
return true;
}
bool CConfig::GetValue(const char * key, DWORD *dest)
{
if (!Search(key))
return false;
str_to_number(*dest, Get(key));
return true;
}
bool CConfig::GetValue(const char * key, BYTE *dest)
{
if (!Search(key))
return false;
*dest = *(BYTE *) Get(key);
return true;
}
bool CConfig::GetValue(const char * key, char *dest, size_t destSize)
{
if (!Search(key))
return false;
strlcpy(dest, Get(key), destSize);
if (!*dest)
return false;
return true;
}
bool CConfig::GetTwoValue(const char* key, DWORD * dest1, DWORD *dest2)
{
if (!GetParam(key, 0, dest1))
return false;
if (!GetParam(key, 1, dest2))
return false;
return true;
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,35 @@
#ifndef __INC_CONFIG_H__
#define __INC_CONFIG_H__
typedef std::map<std::string, std::string> TValueMap;
class CConfig : public singleton<CConfig>
{
public:
CConfig();
~CConfig();
bool LoadFile(const char* filename);
bool GetValue(const char* key, int* dest);
bool GetValue(const char* key, float* dest);
bool GetValue(const char* key, DWORD* dest);
bool GetValue(const char* key, BYTE* dest);
bool GetValue(const char* key, char* dest, size_t destSize);
bool GetWord(FILE* fp, char* dest);
bool GetLine(FILE* fp, char* dest);
bool GetTwoValue(const char* key, DWORD * dest1, DWORD *dest2);
void NextLine(FILE* fp);
private:
void Destroy();
bool GetParam(const char*key,int index, DWORD *Param);
const char * Get(const char* key);
std::string * Search(const char* key);
private:
TValueMap m_valueMap;
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,372 @@
#include "stdafx.h"
#include "CsvReader.h"
#include <fstream>
#include <algorithm>
#ifndef Assert
#include <assert.h>
#define Assert assert
#define LogToFile (void)(0);
#endif
namespace
{
enum ParseState
{
STATE_NORMAL = 0,
STATE_QUOTE
};
std::string Trim(std::string str)
{
str = str.erase(str.find_last_not_of(" \t\r\n") + 1);
str = str.erase(0, str.find_first_not_of(" \t\r\n"));
return str;
}
std::string Lower(std::string original)
{
std::transform(original.begin(), original.end(), original.begin(), tolower);
return original;
}
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void cCsvAlias::AddAlias(const char* name, size_t index)
{
std::string converted(Lower(name));
Assert(m_Name2Index.find(converted) == m_Name2Index.end());
Assert(m_Index2Name.find(index) == m_Index2Name.end());
m_Name2Index.emplace(converted, index);
m_Index2Name.emplace(index, name);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void cCsvAlias::Destroy()
{
m_Name2Index.clear();
m_Index2Name.clear();
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
const char* cCsvAlias::operator [] (size_t index) const
{
INDEX2NAME_MAP::const_iterator itr(m_Index2Name.find(index));
if (itr == m_Index2Name.end())
{
//LogToFile(NULL, "cannot find suitable conversion for %d", index);
Assert(false && "cannot find suitable conversion");
return NULL;
}
return itr->second.c_str();
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
size_t cCsvAlias::operator [] (const char* name) const
{
NAME2INDEX_MAP::const_iterator itr(m_Name2Index.find(Lower(name)));
if (itr == m_Name2Index.end())
{
//LogToFile(NULL, "cannot find suitable conversion for %s", name);
Assert(false && "cannot find suitable conversion");
return 0;
}
return itr->second;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
bool cCsvFile::Load(const char* fileName, const char seperator, const char quote)
{
Assert(seperator != quote);
std::ifstream file(fileName, std::ios::in);
if (!file) return false;
Destroy();
cCsvRow* row = NULL;
ParseState state = STATE_NORMAL;
std::string token = "";
char buf[2048+1] = {0,};
while (file.good())
{
file.getline(buf, 2048);
buf[sizeof(buf)-1] = 0;
std::string line(Trim(buf));
if (line.empty() || (state == STATE_NORMAL && line[0] == '#')) continue;
std::string text = std::string(line) + " ";
size_t cur = 0;
while (cur < text.size())
{
if (state == STATE_QUOTE)
{
if (text[cur] == quote)
{
if (text[cur+1] == quote)
{
token += quote;
++cur;
}
else
{
state = STATE_NORMAL;
}
}
else
{
token += text[cur];
}
}
else if (state == STATE_NORMAL)
{
if (row == NULL)
row = new cCsvRow();
if (text[cur] == seperator)
{
row->emplace_back(token);
token.clear();
}
else if (text[cur] == quote)
{
state = STATE_QUOTE;
}
else
{
token += text[cur];
}
}
++cur;
}
if (state == STATE_NORMAL)
{
Assert(row != NULL);
row->emplace_back(token.substr(0, token.size()-2));
m_Rows.emplace_back(row);
token.clear();
row = NULL;
}
else
{
token = token.substr(0, token.size()-2) + "\r\n";
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
bool cCsvFile::Save(const char* fileName, bool append, char seperator, char quote) const
{
Assert(seperator != quote);
std::ofstream file;
if (append) { file.open(fileName, std::ios::out | std::ios::app); }
else { file.open(fileName, std::ios::out | std::ios::trunc); }
if (!file) return false;
char special_chars[5] = { seperator, quote, '\r', '\n', 0 };
char quote_escape_string[3] = { quote, quote, 0 };
for (size_t i=0; i<m_Rows.size(); i++)
{
const cCsvRow& row = *((*this)[i]);
std::string line;
for (size_t j=0; j<row.size(); j++)
{
const std::string& token = row[j];
if (token.find_first_of(special_chars) == std::string::npos)
{
line += token;
}
else
{
line += quote;
for (size_t k=0; k<token.size(); k++)
{
if (token[k] == quote) line += quote_escape_string;
else line += token[k];
}
line += quote;
}
if (j != row.size() - 1) { line += seperator; }
}
file << line << std::endl;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void cCsvFile::Destroy()
{
for (ROWS::iterator itr(m_Rows.begin()); itr != m_Rows.end(); ++itr)
delete *itr;
m_Rows.clear();
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
cCsvRow* cCsvFile::operator [] (size_t index)
{
Assert(index < m_Rows.size());
return m_Rows[index];
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
const cCsvRow* cCsvFile::operator [] (size_t index) const
{
Assert(index < m_Rows.size());
return m_Rows[index];
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
cCsvTable::cCsvTable()
: m_CurRow(-1)
{
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
cCsvTable::~cCsvTable()
{
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
bool cCsvTable::Load(const char* fileName, const char seperator, const char quote)
{
Destroy();
m_fileName = fileName;
return m_File.Load(fileName, seperator, quote);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
bool cCsvTable::Next()
{
return ++m_CurRow < (int)m_File.GetRowCount() ? true : false;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
size_t cCsvTable::ColCount() const
{
return CurRow()->size();
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
int cCsvTable::AsInt(size_t index) const
{
const cCsvRow* const row = CurRow();
Assert(row);
if (index >= row->size())
sys_err("file %s index %d >= row size %d of row %s", m_fileName.c_str(), index, row->size(), row->AsString(0));
Assert(index < row->size());
return row->AsInt(index);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
double cCsvTable::AsDouble(size_t index) const
{
const cCsvRow* const row = CurRow();
Assert(row);
if (index >= row->size())
sys_err("file %s index %d >= row size %d of row %s", m_fileName.c_str(), index, row->size(), row->AsString(0));
Assert(index < row->size());
return row->AsDouble(index);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
const char* cCsvTable::AsStringByIndex(size_t index) const
{
const cCsvRow* const row = CurRow();
Assert(row);
if (index >= row->size())
sys_err("file %s index %d >= row size %d of row %s", m_fileName.c_str(), index, row->size(), row->AsString(0));
Assert(index < row->size());
return row->AsString(index);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void cCsvTable::Destroy()
{
m_File.Destroy();
m_Alias.Destroy();
m_CurRow = -1;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
const cCsvRow* const cCsvTable::CurRow() const
{
if (m_CurRow < 0)
{
Assert(false && "call Next() first!");
return NULL;
}
else if (m_CurRow >= (int)m_File.GetRowCount())
{
Assert(false && "no more rows!");
return NULL;
}
return m_File[m_CurRow];
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,253 @@
#ifndef __CSVFILE_H__
#define __CSVFILE_H__
#include <string>
#include <vector>
////////////////////////////////////////////////////////////////////////////////
/// \class cCsvAlias
///
///
/// <pre>
/// int a = row.AsInt(0);
/// int b = row.AsInt(1);
/// </pre>
///
///
/// <pre>
/// int a = row.AsInt(0);
/// int c = row.AsInt(1);
/// </pre>
///
////////////////////////////////////////////////////////////////////////////////
class cCsvAlias
{
private:
typedef std::map<std::string, size_t> NAME2INDEX_MAP;
typedef std::map<size_t, std::string> INDEX2NAME_MAP;
NAME2INDEX_MAP m_Name2Index;
INDEX2NAME_MAP m_Index2Name;
public:
cCsvAlias() {}
virtual ~cCsvAlias() {}
public:
void AddAlias(const char* name, size_t index);
void Destroy();
const char* operator [] (size_t index) const;
size_t operator [] (const char* name) const;
private:
cCsvAlias(const cCsvAlias&) {}
const cCsvAlias& operator = (const cCsvAlias&) { return *this; }
};
////////////////////////////////////////////////////////////////////////////////
/// \class cCsvRow
///
///
/// <pre>
/// ---------------------+----------------------------------------------------
/// ItemPrice | ItemPrice
/// Item,Price | "Item,Price"
/// Item"Price | "Item""Price"
/// "ItemPrice" | """ItemPrice"""
/// "Item,Price" | """Item,Price"""
/// Item",Price | "Item"",Price"
/// </pre>
///
///
/// \sa cCsvFile
////////////////////////////////////////////////////////////////////////////////
class cCsvRow : public std::vector<std::string>
{
public:
cCsvRow() {}
~cCsvRow() {}
public:
int AsInt(size_t index) const { return atoi(at(index).c_str()); }
double AsDouble(size_t index) const { return atof(at(index).c_str()); }
const char* AsString(size_t index) const { return at(index).c_str(); }
int AsInt(const char* name, const cCsvAlias& alias) const {
return atoi( at(alias[name]).c_str() );
}
double AsDouble(const char* name, const cCsvAlias& alias) const {
return atof( at(alias[name]).c_str() );
}
const char* AsString(const char* name, const cCsvAlias& alias) const {
return at(alias[name]).c_str();
}
cCsvRow(const cCsvRow&) {}
private:
const cCsvRow& operator = (const cCsvRow&) { return *this; }
};
////////////////////////////////////////////////////////////////////////////////
/// \class cCsvFile
///
/// <b>sample</b>
/// <pre>
/// cCsvFile file;
///
/// cCsvRow row1, row2, row3;
/// row1.emplace_back("ItemPrice");
/// row1.emplace_back("Item,Price");
/// row1.emplace_back("Item\"Price");
///
/// row2.reserve(3);
/// row2[0] = "\"ItemPrice\"";
/// row2[1] = "\"Item,Price\"";
/// row2[2] = "Item\",Price\"";
///
/// row3 = "\"ItemPrice\"\"Item,Price\"Item\",Price\"";
///
/// file.add(row1);
/// file.add(row2);
/// file.add(row3);
/// file.save("test.csv", false);
/// </pre>
///
////////////////////////////////////////////////////////////////////////////////
class cCsvFile
{
private:
typedef std::vector<cCsvRow*> ROWS;
ROWS m_Rows;
public:
cCsvFile() {}
virtual ~cCsvFile() { Destroy(); }
public:
bool Load(const char* fileName, const char seperator=',', const char quote='"');
bool Save(const char* fileName, bool append=false, char seperator=',', char quote='"') const;
void Destroy();
cCsvRow* operator [] (size_t index);
const cCsvRow* operator [] (size_t index) const;
size_t GetRowCount() const { return m_Rows.size(); }
private:
cCsvFile(const cCsvFile&) {}
const cCsvFile& operator = (const cCsvFile&) { return *this; }
};
////////////////////////////////////////////////////////////////////////////////
/// \class cCsvTable
///
///
/// <b>sample</b>
/// <pre>
/// cCsvTable table;
///
/// table.alias(0, "ItemClass");
/// table.alias(1, "ItemType");
///
/// if (table.load("test.csv"))
/// {
/// while (table.next())
/// {
/// std::string item_class = table.AsString("ItemClass");
/// int item_type = table.AsInt("ItemType");
/// }
/// }
/// </pre>
////////////////////////////////////////////////////////////////////////////////
class cCsvTable
{
public :
cCsvFile m_File;
std::string m_fileName;
private:
cCsvAlias m_Alias;
int m_CurRow;
public:
cCsvTable();
virtual ~cCsvTable();
public:
bool Load(const char* fileName, const char seperator=',', const char quote='"');
void AddAlias(const char* name, size_t index) { m_Alias.AddAlias(name, index); }
bool Next();
size_t ColCount() const;
int AsInt(size_t index) const;
double AsDouble(size_t index) const;
const char* AsStringByIndex(size_t index) const;
int AsInt(const char* name) const { return AsInt(m_Alias[name]); }
double AsDouble(const char* name) const { return AsDouble(m_Alias[name]); }
const char* AsString(const char* name) const { return AsStringByIndex(m_Alias[name]); }
void Destroy();
private:
const cCsvRow* const CurRow() const;
cCsvTable(const cCsvTable&) {}
const cCsvTable& operator = (const cCsvTable&) { return *this; }
};
#endif //__CSVFILE_H__
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,173 @@
#include "stdafx.h"
#include "DBManager.h"
#include "ClientManager.h"
extern std::string g_stLocale;
CDBManager::CDBManager()
{
Initialize();
}
CDBManager::~CDBManager()
{
Destroy();
}
void CDBManager::Initialize()
{
for (int i = 0; i < SQL_MAX_NUM; ++i)
{
m_mainSQL[i].release();
m_directSQL[i].release();
m_asyncSQL[i].release();
}
}
void CDBManager::Destroy()
{
Clear();
}
void CDBManager::Clear()
{
for (int i = 0; i < SQL_MAX_NUM; ++i)
{
m_mainSQL[i].release();
m_directSQL[i].release();
m_asyncSQL[i].release();
}
Initialize();
}
void CDBManager::Quit()
{
for (int i = 0; i < SQL_MAX_NUM; ++i)
{
if (m_mainSQL[i])
m_mainSQL[i]->Quit();
if (m_asyncSQL[i])
m_asyncSQL[i]->Quit();
if (m_directSQL[i])
m_directSQL[i]->Quit();
}
}
SQLMsg * CDBManager::PopResult()
{
SQLMsg * p;
for (int i = 0; i < SQL_MAX_NUM; ++i)
if (m_mainSQL[i] && m_mainSQL[i]->PopResult(&p))
return p;
return NULL;
}
SQLMsg * CDBManager::PopResult(eSQL_SLOT slot)
{
SQLMsg * p;
if (m_mainSQL[slot] && m_mainSQL[slot]->PopResult(&p))
return p;
return NULL;
}
int CDBManager::Connect(int iSlot, const char * db_address, const int db_port, const char * db_name, const char * user, const char * pwd)
{
if (db_address == NULL || db_name == NULL)
return false;
if (iSlot < 0 || iSlot >= SQL_MAX_NUM)
return false;
sys_log(0, "CREATING DIRECT_SQL");
m_directSQL[iSlot] = std::make_unique<CAsyncSQL2>();
if (!m_directSQL[iSlot]->Setup(db_address, user, pwd, db_name, g_stLocale.c_str(), true, db_port))
{
Clear();
return false;
}
sys_log(0, "CREATING MAIN_SQL");
m_mainSQL[iSlot] = std::make_unique<CAsyncSQL2>();
if (!m_mainSQL[iSlot]->Setup(db_address, user, pwd, db_name, g_stLocale.c_str(), false, db_port))
{
Clear();
return false;
}
sys_log(0, "CREATING ASYNC_SQL");
m_asyncSQL[iSlot] = std::make_unique<CAsyncSQL2>();
if (!m_asyncSQL[iSlot]->Setup(db_address, user, pwd, db_name, g_stLocale.c_str(), false, db_port))
{
Clear();
return false;
}
return true;
}
std::unique_ptr<SQLMsg> CDBManager::DirectQuery(const char * c_pszQuery, int iSlot)
{
return m_directSQL[iSlot]->DirectQuery(c_pszQuery);
}
extern CPacketInfo g_query_info;
extern int g_query_count[2];
void CDBManager::ReturnQuery(const char * c_pszQuery, int iType, IDENT dwIdent, void * udata, int iSlot)
{
assert(iSlot < SQL_MAX_NUM);
//sys_log(0, "ReturnQuery %s", c_pszQuery);
CQueryInfo * p = new CQueryInfo;
p->iType = iType;
p->dwIdent = dwIdent;
p->pvData = udata;
m_mainSQL[iSlot]->ReturnQuery(c_pszQuery, p);
//g_query_info.Add(iType);
++g_query_count[0];
}
void CDBManager::AsyncQuery(const char * c_pszQuery, int iSlot)
{
assert(iSlot < SQL_MAX_NUM);
m_asyncSQL[iSlot]->AsyncQuery(c_pszQuery);
++g_query_count[1];
}
unsigned long CDBManager::EscapeString(void *to, const void *from, unsigned long length, int iSlot)
{
assert(iSlot < SQL_MAX_NUM);
return mysql_real_escape_string(m_directSQL[iSlot]->GetSQLHandle(), (char *) to, (const char *) from, length);
}
void CDBManager::SetLocale(const char * szLocale)
{
const std::string stLocale(szLocale);
sys_log(0, "SetLocale start %s", szLocale);
for (int n = 0; n < SQL_MAX_NUM; ++n)
{
m_mainSQL[n]->SetLocale(stLocale);
m_directSQL[n]->SetLocale(stLocale);
m_asyncSQL[n]->SetLocale(stLocale);
}
sys_log(0, "SetLocale end %s", szLocale);
}
void CDBManager::QueryLocaleSet()
{
for (int n = 0; n < SQL_MAX_NUM; ++n)
{
m_mainSQL[n]->QueryLocaleSet();
m_directSQL[n]->QueryLocaleSet();
m_asyncSQL[n]->QueryLocaleSet();
}
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,100 @@
// vim:ts=8 sw=4
#ifndef __INC_METIN2_DB_DBMANAGER_H__
#define __INC_METIN2_DB_DBMANAGER_H__
#include <mysql/mysql.h>
#include "../../libsql/AsyncSQL.h"
#include <memory>
#define SQL_SAFE_LENGTH(size) (size * 2 + 1)
#define QUERY_SAFE_LENGTH(size) (1024 + SQL_SAFE_LENGTH(size))
class CQueryInfo
{
public:
int iType;
DWORD dwIdent;
void * pvData;
};
enum eSQL_SLOT
{
SQL_PLAYER,
SQL_ACCOUNT,
SQL_COMMON,
SQL_HOTBACKUP,
#ifdef ENABLE_DB_SQL_LOG
SQL_LOG,
#endif
SQL_MAX_NUM,
};
class CDBManager : public singleton<CDBManager>
{
protected:
void Initialize();
void Destroy();
public:
CDBManager();
virtual ~CDBManager();
void Clear();
void Quit();
int Connect(int iSlot, const char * host, int port, const char* dbname, const char* user, const char* pass);
void ReturnQuery(const char * c_pszQuery, int iType, DWORD dwIdent, void * pvData, int iSlot = SQL_PLAYER);
void AsyncQuery(const char * c_pszQuery, int iSlot = SQL_PLAYER);
std::unique_ptr<SQLMsg> DirectQuery(const char * c_pszQuery, int iSlot = SQL_PLAYER);
SQLMsg * PopResult();
SQLMsg * PopResult(eSQL_SLOT slot );
unsigned long EscapeString(void * to, const void * from, unsigned long length, int iSlot = SQL_PLAYER);
DWORD CountReturnQuery(int i) { return m_mainSQL[i] ? m_mainSQL[i]->CountQuery() : 0; }
DWORD CountReturnResult(int i) { return m_mainSQL[i] ? m_mainSQL[i]->CountResult() : 0; }
DWORD CountReturnQueryFinished(int i) { return m_mainSQL[i] ? m_mainSQL[i]->CountQueryFinished() : 0; }
DWORD CountReturnCopiedQuery(int i) { return m_mainSQL[i] ? m_mainSQL[i]->GetCopiedQueryCount() : 0; }
DWORD CountAsyncQuery(int i) { return m_asyncSQL[i] ? m_asyncSQL[i]->CountQuery() : 0; }
DWORD CountAsyncResult(int i) { return m_asyncSQL[i] ? m_asyncSQL[i]->CountResult() : 0; }
DWORD CountAsyncQueryFinished(int i) { return m_asyncSQL[i] ? m_asyncSQL[i]->CountQueryFinished() : 0; }
DWORD CountAsyncCopiedQuery(int i) { return m_asyncSQL[i] ? m_asyncSQL[i]->GetCopiedQueryCount() : 0; }
void ResetCounter()
{
for (int i = 0; i < SQL_MAX_NUM; ++i)
{
if (m_mainSQL[i])
{
m_mainSQL[i]->ResetQueryFinished();
m_mainSQL[i]->ResetCopiedQueryCount();
}
if (m_asyncSQL[i])
{
m_asyncSQL[i]->ResetQueryFinished();
m_asyncSQL[i]->ResetCopiedQueryCount();
}
}
}
private:
std::unique_ptr<CAsyncSQL2> m_mainSQL[SQL_MAX_NUM];
std::unique_ptr<CAsyncSQL2> m_directSQL[SQL_MAX_NUM];
std::unique_ptr<CAsyncSQL2> m_asyncSQL[SQL_MAX_NUM];
//CHARSET
public:
void SetLocale(const char * szLocale );
void QueryLocaleSet();
private:
//END_CHARSET
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,260 @@
// vim:ts=8 sw=4
#ifndef __INC_GUILD_MANAGER_H
#define __INC_GUILD_MANAGER_H
#include "Peer.h"
#include <queue>
#include <utility>
#include "../../libsql/libsql.h"
#include "../../libpoly/Poly.h"
enum
{
GUILD_WARP_WAR_CHANNEL = 99
};
class CGuildWarReserve;
struct TGuildDeclareInfo
{
BYTE bType;
DWORD dwGuildID[2];
TGuildDeclareInfo(BYTE _bType, DWORD _dwGuildID1, DWORD _dwGuildID2)
: bType(_bType)
{
dwGuildID[0] = _dwGuildID1;
dwGuildID[1] = _dwGuildID2;
}
bool operator < (const TGuildDeclareInfo& r) const
{
return ((dwGuildID[0] < r.dwGuildID[0]) || ((dwGuildID[0] == r.dwGuildID[0]) && (dwGuildID[1] < r.dwGuildID[1])));
}
TGuildDeclareInfo& operator = (const TGuildDeclareInfo& r)
{
bType = r.bType;
dwGuildID[0] = r.dwGuildID[0];
dwGuildID[1] = r.dwGuildID[1];
return *this;
}
};
struct TGuildWaitStartInfo
{
BYTE bType;
DWORD GID[2];
long lWarPrice;
long lInitialScore;
CGuildWarReserve * pkReserve;
TGuildWaitStartInfo(BYTE _bType,
DWORD _g1,
DWORD _g2,
long _lWarPrice,
long _lInitialScore,
CGuildWarReserve * _pkReserve)
: bType(_bType), lWarPrice(_lWarPrice), lInitialScore(_lInitialScore), pkReserve(_pkReserve)
{
GID[0] = _g1;
GID[1] = _g2;
}
bool operator < (const TGuildWaitStartInfo& r) const
{
return ((GID[0] < r.GID[0]) || ((GID[0] == r.GID[0]) && (GID[1] < r.GID[1])));
}
};
struct TGuildWarPQElement
{
bool bEnd;
BYTE bType;
DWORD GID[2];
DWORD iScore[2];
DWORD iBetScore[2];
TGuildWarPQElement(BYTE _bType, DWORD GID1, DWORD GID2) : bEnd(false), bType(_bType)
{
bType = _bType;
GID[0] = GID1;
GID[1] = GID2;
iScore[0] = iScore[1] = 0;
iBetScore[0] = iBetScore[1] = 0;
}
};
struct TGuildSkillUsed
{
DWORD GID;
DWORD dwSkillVnum;
// GUILD_SKILL_COOLTIME_BUG_FIX
TGuildSkillUsed(DWORD _GID, DWORD _dwSkillVnum) : GID(_GID), dwSkillVnum(_dwSkillVnum)
{
}
// END_OF_GUILD_SKILL_COOLTIME_BUG_FIX
};
inline bool operator < (const TGuildSkillUsed& a, const TGuildSkillUsed& b)
{
return ((a.GID < b.GID) || ((a.GID == b.GID) && (a.dwSkillVnum < b.dwSkillVnum)));
}
typedef struct SGuild
{
SGuild() : ladder_point(0), win(0), draw(0), loss(0), gold(0), level(0)
{
memset(szName, 0, sizeof(szName));
}
char szName[GUILD_NAME_MAX_LEN+1];
int ladder_point;
int win;
int draw;
int loss;
int gold;
int level;
} TGuild;
typedef struct SGuildWarInfo
{
time_t tEndTime;
TGuildWarPQElement * pElement;
CGuildWarReserve * pkReserve;
SGuildWarInfo() : pElement(NULL)
{
}
} TGuildWarInfo;
class CGuildWarReserve
{
public:
CGuildWarReserve(const TGuildWarReserve& rTable);
void Initialize();
TGuildWarReserve & GetDataRef()
{
return m_data;
}
void OnSetup(CPeer * peer);
bool Bet(const char * pszLogin, DWORD dwGold, DWORD dwGuild);
void Draw();
void End(int iScoreFrom, int iScoreTo);
int GetLastNoticeMin() { return m_iLastNoticeMin; }
void SetLastNoticeMin(int iMin) { m_iLastNoticeMin = iMin; }
private:
CGuildWarReserve();
TGuildWarReserve m_data;
// <login, <guild, gold>>
std::map<std::string, std::pair<DWORD, DWORD> > mapBet;
int m_iLastNoticeMin;
};
class CGuildManager : public singleton<CGuildManager>
{
public:
CGuildManager();
virtual ~CGuildManager();
void Initialize();
void Load(DWORD dwGuildID);
TGuild & TouchGuild(DWORD GID);
void Update();
void OnSetup(CPeer * peer);
void StartWar(BYTE bType, DWORD GID1, DWORD GID2, CGuildWarReserve * pkReserve = NULL);
void UpdateScore(DWORD guild_gain_point, DWORD guild_opponent, int iScore, int iBetScore);
void AddDeclare(BYTE bType, DWORD guild_from, DWORD guild_to);
void RemoveDeclare(DWORD guild_from, DWORD guild_to);
bool TakeBetPrice(DWORD dwGuildTo, DWORD dwGuildFrom, long lWarPrice);
bool WaitStart(TPacketGuildWar * p);
void RecvWarEnd(DWORD GID1, DWORD GID2);
void RecvWarOver(DWORD dwGuildWinner, DWORD dwGuildLoser, bool bDraw, long lWarPrice);
void ChangeLadderPoint(DWORD GID, int change);
void UseSkill(DWORD dwGuild, DWORD dwSkillVnum, DWORD dwCooltime);
INT GetGuildGold(DWORD dwGuild);
void DepositMoney(DWORD dwGuild, INT lGold);
void WithdrawMoney(CPeer* peer, DWORD dwGuild, INT lGold);
void WithdrawMoneyReply(DWORD dwGuild, BYTE bGiveSuccess, INT lGold);
void MoneyChange(DWORD dwGuild, DWORD dwGold);
void QueryRanking();
void ResultRanking(MYSQL_RES * pRes);
int GetRanking(DWORD dwGID);
// Reserve War
void BootReserveWar();
bool ReserveWar(TPacketGuildWar * p);
void ProcessReserveWar();
bool Bet(DWORD dwID, const char * c_pszLogin, DWORD dwGold, DWORD dwGuild);
void CancelWar(DWORD GID1, DWORD GID2);
bool ChangeMaster(DWORD dwGID, DWORD dwFrom, DWORD dwTo);
private:
void ParseResult(SQLResult * pRes);
void RemoveWar(DWORD GID1, DWORD GID2); // erase war from m_WarMap and set end on priority queue
void WarEnd(DWORD GID1, DWORD GID2, bool bDraw = false);
int GetLadderPoint(DWORD GID);
void GuildWarWin(DWORD GID);
void GuildWarDraw(DWORD GID);
void GuildWarLose(DWORD GID);
void ProcessDraw(DWORD dwGuildID1, DWORD dwGuildID2);
void ProcessWinLose(DWORD dwGuildWinner, DWORD dwGuildLoser);
bool IsHalfWinLadderPoint(DWORD dwGuildWinner, DWORD dwGuildLoser);
std::map<DWORD, TGuild> m_map_kGuild;
std::map<DWORD, std::map<DWORD, time_t> > m_mapGuildWarEndTime;
std::set<TGuildDeclareInfo> m_DeclareMap;
std::map<DWORD, std::map<DWORD, TGuildWarInfo> > m_WarMap;
typedef std::pair<time_t, TGuildWarPQElement *> stPairGuildWar;
typedef std::pair<time_t, TGuildSkillUsed> stPairSkillUsed;
typedef std::pair<time_t, TGuildWaitStartInfo> stPairWaitStart;
std::priority_queue<stPairGuildWar, std::vector<stPairGuildWar>, std::greater<stPairGuildWar> >
m_pqOnWar;
std::priority_queue<stPairWaitStart, std::vector<stPairWaitStart>, std::greater<stPairWaitStart> >
m_pqWaitStart;
std::priority_queue<stPairSkillUsed, std::vector<stPairSkillUsed>, std::greater<stPairSkillUsed> >
m_pqSkill;
std::map<DWORD, CGuildWarReserve *> m_map_kWarReserve;
CPoly polyPower;
CPoly polyHandicap;
// GID Ranking
std::map<DWORD, int> map_kLadderPointRankingByGID;
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,82 @@
#include "stdafx.h"
#include "HB.h"
#include "Main.h"
#include "DBManager.h"
#include <memory>
PlayerHB::PlayerHB()
{
m_iExpireTime = 3600; // 1 hour hotbackup default.
}
PlayerHB::~PlayerHB()
{
}
bool PlayerHB::Initialize()
{
char szQuery[128];
snprintf(szQuery, sizeof(szQuery), "SHOW CREATE TABLE player%s", GetTablePostfix());
auto pMsg(CDBManager::instance().DirectQuery(szQuery));
if (pMsg->Get()->uiNumRows == 0)
return false;
MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult);
m_stCreateTableQuery = row[1];
return true;
}
//
//
void PlayerHB::Put(DWORD id)
{
itertype(m_map_data) it = m_map_data.find(id);
if (it == m_map_data.end())
{
Query(id);
m_map_data.emplace(id, get_dword_time());
return;
}
if (time(0) - it->second > m_iExpireTime)
Query(id);
}
//
//
bool PlayerHB::Query(DWORD id)
{
time_t ct = time(0);
struct tm curr_tm = *localtime(&ct);
char szTableName[64];
snprintf(szTableName, sizeof(szTableName), "hb_%02d%02d%02d%02d_player%s",
curr_tm.tm_year - 100, curr_tm.tm_mon + 1, curr_tm.tm_mday, curr_tm.tm_hour, GetTablePostfix());
char szQuery[4096];
if (m_stTableName.compare(szTableName))
{
char szFind[32];
snprintf(szFind, sizeof(szFind), "CREATE TABLE `player%s`", GetTablePostfix());
int pos = m_stCreateTableQuery.find(szFind);
if (pos < 0)
{
sys_err("cannot find %s ", szFind);
return false;
}
snprintf(szQuery, sizeof(szQuery), "CREATE TABLE IF NOT EXISTS %s%s", szTableName, m_stCreateTableQuery.c_str() + strlen(szFind));
auto pMsg(CDBManager::instance().DirectQuery(szQuery, SQL_HOTBACKUP));
m_stTableName = szTableName;
}
snprintf(szQuery, sizeof(szQuery), "REPLACE INTO %s SELECT * FROM %splayer%s WHERE id=%u", m_stTableName.c_str(), GetPlayerDBName(), GetTablePostfix(), id);
CDBManager::instance().AsyncQuery(szQuery, SQL_HOTBACKUP);
return true;
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,25 @@
// vim:ts=8 sw=4
#ifndef __INC_METIN_II_PLAYERHB_H__
#define __INC_METIN_II_PLAYERHB_H__
class PlayerHB : public singleton<PlayerHB>
{
public:
PlayerHB();
virtual ~PlayerHB();
bool Initialize();
void Put(DWORD id);
private:
bool Query(DWORD id);
std::map<DWORD, time_t> m_map_data;
std::string m_stCreateTableQuery;
std::string m_stTableName;
int m_iExpireTime;
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,509 @@
#include "stdafx.h"
#include "QID.h"
#include "DBManager.h"
#include "ItemAwardManager.h"
#include "Peer.h"
#include "ClientManager.h"
#ifdef ENABLE_EXTEND_ITEM_AWARD
#include <algorithm>
#include <cfloat>
#include <unordered_set>
#include <msl/random.h>
inline double uniform_random(const double a, const double b)
{
return msl::random_real(a, b);
}
inline float gauss_random(const float fAverage, const float sigma)
{
static bool bHasNextGaussian = false;
static float fNextGaussian = 0.0f;
if (bHasNextGaussian)
{
bHasNextGaussian = false;
return (fNextGaussian * sigma) + fAverage;
}
else
{
double v1(0), v2(0), s(0);
do
{
v1 = uniform_random(-1.f, 1.f);
v2 = uniform_random(-1.f, 1.f);
s = (v1 * v1) + (v2 * v2);
} while (s >= 1.f || fabs(s) < FLT_EPSILON);
const double multiplier = sqrtf(-2 * logf(s) / s);
fNextGaussian = v2 * multiplier;
bHasNextGaussian = true;
return (v1 * multiplier) * sigma + fAverage;
}
}
#endif
DWORD g_dwLastCachedItemAwardID = 0;
ItemAwardManager::ItemAwardManager()
{
}
ItemAwardManager::~ItemAwardManager()
{
}
void ItemAwardManager::RequestLoad()
{
char szQuery[QUERY_MAX_LEN];
snprintf(szQuery, sizeof(szQuery), "SELECT id,login,vnum,count,socket0,socket1,socket2,"
#ifdef ENABLE_EXTEND_ITEM_AWARD
"attrtype0, attrvalue0, "
"attrtype1, attrvalue1, "
"attrtype2, attrvalue2, "
"attrtype3, attrvalue3, "
"attrtype4, attrvalue4, "
"attrtype5, attrvalue5, "
"attrtype6, attrvalue6, "
#endif
"mall,why FROM item_award WHERE taken_time IS NULL and id > %d", g_dwLastCachedItemAwardID);
CDBManager::instance().ReturnQuery(szQuery, QID_ITEM_AWARD_LOAD, 0, NULL);
}
void ItemAwardManager::Load(SQLMsg * pMsg)
{
MYSQL_RES * pRes = pMsg->Get()->pSQLResult;
for (uint i = 0; i < pMsg->Get()->uiNumRows; ++i)
{
MYSQL_ROW row = mysql_fetch_row(pRes);
int col = 0;
DWORD dwID = 0;
str_to_number(dwID, row[col++]);
if (m_map_award.find(dwID) != m_map_award.end())
continue;
TItemAward * kData = new TItemAward{};
kData->dwID = dwID;
trim_and_lower(row[col++], kData->szLogin, sizeof(kData->szLogin));
str_to_number(kData->dwVnum, row[col++]);
str_to_number(kData->dwCount, row[col++]);
str_to_number(kData->dwSocket0, row[col++]);
str_to_number(kData->dwSocket1, row[col++]);
str_to_number(kData->dwSocket2, row[col++]);
#ifdef ENABLE_EXTEND_ITEM_AWARD
for (size_t j = 0; j < ITEM_ATTRIBUTE_MAX_NUM; j++)
{
str_to_number(kData->aAttr[j].bType, row[col++]);
str_to_number(kData->aAttr[j].sValue, row[col++]);
}
#endif
str_to_number(kData->bMall, row[col++]);
if (row[col])
{
strlcpy(kData->szWhy, row[col], sizeof(kData->szWhy));
char* whyStr = kData->szWhy;
char cmdStr[100] = "";
strcpy(cmdStr,whyStr);
char command[20] = "";
// @fixme203 directly GetCommand instead of strcpy
CClientManager::instance().GetCommand(cmdStr, command);
//sys_err("%d, %s",pItemAward->dwID,command);
if( !(strcmp(command,"GIFT") ))
{
TPacketItemAwardInfromer giftData;
strcpy(giftData.login, kData->szLogin);
strcpy(giftData.command, command);
giftData.vnum = kData->dwVnum;
CClientManager::instance().ForwardPacket(HEADER_DG_ITEMAWARD_INFORMER,&giftData,sizeof(TPacketItemAwardInfromer));
}
}
m_map_award.emplace(dwID, kData);
printf("ITEM_AWARD load id %u bMall %d \n", kData->dwID, kData->bMall);
sys_log(0, "ITEM_AWARD: load id %lu login %s vnum %lu count %u socket %lu", kData->dwID, kData->szLogin, kData->dwVnum, kData->dwCount, kData->dwSocket0);
std::set<TItemAward *> & kSet = m_map_kSetAwardByLogin[kData->szLogin];
kSet.emplace(kData);
if (dwID > g_dwLastCachedItemAwardID)
g_dwLastCachedItemAwardID = dwID;
}
}
std::set<TItemAward *> * ItemAwardManager::GetByLogin(const char * c_pszLogin)
{
itertype(m_map_kSetAwardByLogin) it = m_map_kSetAwardByLogin.find(c_pszLogin);
if (it == m_map_kSetAwardByLogin.end())
return NULL;
return &it->second;
}
void ItemAwardManager::Taken(DWORD dwAwardID, DWORD dwItemID)
{
itertype(m_map_award) it = m_map_award.find(dwAwardID);
if (it == m_map_award.end())
{
sys_log(0, "ITEM_AWARD: Taken ID not exist %lu", dwAwardID);
return;
}
TItemAward * k = it->second;
k->bTaken = true;
// Update taken_time in database to prevent not to give him again.
char szQuery[QUERY_MAX_LEN];
snprintf(szQuery, sizeof(szQuery),
"UPDATE item_award SET taken_time=NOW(),item_id=%u WHERE id=%u AND taken_time IS NULL",
dwItemID, dwAwardID);
CDBManager::instance().ReturnQuery(szQuery, QID_ITEM_AWARD_TAKEN, 0, NULL);
}
std::map<DWORD, TItemAward *>& ItemAwardManager::GetMapAward()
{
return m_map_award;
}
std::map<std::string, std::set<TItemAward *> >& ItemAwardManager::GetMapkSetAwardByLogin()
{
return m_map_kSetAwardByLogin;
}
#ifdef USE_ITEM_AWARD_CHECK_ATTRIBUTES
/*******************************************************************\
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
||| Attribute set index, return a specific index by item type & item sub type.
||| List initialization (since C++11)
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
\*******************************************************************/
int8_t ItemAwardManager::GetItemAttributeSetIndex(const uint8_t bItemType, const uint8_t bItemSubType) const
{
using TAttributeMapT = std::map<uint8_t, std::map<uint8_t, int8_t>>;
static const TAttributeMapT mapAttrSetFields =
{
{ ITEM_WEAPON,
{
{WEAPON_ARROW, ITEM_ATTRIBUTE_NONE},
#ifdef ENABLE_QUIVER_SYSTEM
{WEAPON_QUIVER, ITEM_ATTRIBUTE_NONE},
#endif
}
},
{ ITEM_ARMOR,
{
{ARMOR_BODY, ATTRIBUTE_SET_BODY},
{ARMOR_WRIST, ATTRIBUTE_SET_WRIST},
{ARMOR_FOOTS, ATTRIBUTE_SET_FOOTS},
{ARMOR_NECK, ATTRIBUTE_SET_NECK},
{ARMOR_HEAD, ATTRIBUTE_SET_HEAD},
{ARMOR_SHIELD, ATTRIBUTE_SET_SHIELD},
{ARMOR_EAR, ATTRIBUTE_SET_EAR},
#ifdef ENABLE_PENDANT_SYSTEM
{ARMOR_PENDANT, ATTRIBUTE_SET_PENDANT},
#endif
#ifdef ENABLE_GLOVE_SYSTEM
{ARMOR_GLOVE, ATTRIBUTE_SET_GLOVE},
#endif
}
},
{ ITEM_COSTUME,
{
{COSTUME_BODY, ATTRIBUTE_SET_BODY},
{COSTUME_HAIR, ATTRIBUTE_SET_HEAD},
#ifdef ENABLE_MOUNT_COSTUME_SYSTEM
{COSTUME_MOUNT, ITEM_ATTRIBUTE_NONE},
#endif
#ifdef ENABLE_WEAPON_COSTUME_SYSTEM
{COSTUME_WEAPON, ATTRIBUTE_SET_WEAPON},
#endif
}
},
};
const auto c_iter_type = mapAttrSetFields.find(bItemType);
if (c_iter_type != mapAttrSetFields.end())
{
const auto c_iter_sub_type = c_iter_type->second.find(bItemSubType);
if (c_iter_sub_type != c_iter_type->second.end())
return c_iter_sub_type->second;
else if (c_iter_type->first == ITEM_WEAPON)
return ATTRIBUTE_SET_WEAPON;
}
return ITEM_ATTRIBUTE_NONE;
}
/*******************************************************************\
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
||| 15.04.2018 - Added a check for attr types and values min - max.
||| You can't insert wrong bonuses into a specific item.
||| Eg. Add 2000M MAX_HP on your Sword+9, was possible, now not.
||| Eg. Add +500 INT to your shield, now there's a check for min-max value of player.item_attr Lv.1 - Lv.5
||| and your 500 INT value will be replaced with max value from lvl5 of bonus, like 12 (lv5), that happen with all the bonuses,
||| same thing with the values lower than lvl1, like 5 HP_REGEN on your neck, when the minimum (lv1) is 10, the value will be replaced with 10.
||| If the bonus type can't be added into a specific item, the bonus will be ignored > deleted. (example: critical pct to armor)
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
\*******************************************************************/
void ItemAwardManager::CheckItemAttributes(TItemAward & rkItemAward, const TItemTable & rkItemTable, const std::vector<TItemAttrTable> & vec_itemAttrTable, const std::vector<TItemAttrTable> & vec_itemRareTable)
{
const auto bItemType = rkItemTable.bType;
const auto bItemSubType = rkItemTable.bSubType;
const auto iAttributeSet = GetItemAttributeSetIndex(bItemType, bItemSubType);
if (iAttributeSet != ITEM_ATTRIBUTE_NONE)
{
// remove duplicates
std::unordered_set<int> duplicates;
for (size_t i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i)
{
// clear up duplicates after reached the rare ones
if (i == ITEM_ATTRIBUTE_RARE_START)
duplicates.clear();
auto bApplyType = rkItemAward.aAttr[i].bType;
// check if already present
if (duplicates.find(bApplyType) != duplicates.end())
{
rkItemAward.aAttr[i].bType = 0;
rkItemAward.aAttr[i].sValue = 0;
continue;
}
duplicates.emplace(bApplyType);
}
for (size_t i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i)
{
const auto bApplyType = rkItemAward.aAttr[i].bType;
const TItemAttrTable * pkAttrTable{nullptr};
// skip special bonus
if (bApplyType == APPLY_SKILL_DAMAGE_BONUS || bApplyType == APPLY_NORMAL_HIT_DAMAGE_BONUS)
continue;
// check normal bonus with item_attr
if (i < ITEM_ATTRIBUTE_NORM_END)
{
for (size_t j = 0; j < vec_itemAttrTable.size() && !pkAttrTable; ++j)
{
const TItemAttrTable & rkAttrTable = vec_itemAttrTable.at(j);
if (rkAttrTable.dwApplyIndex == bApplyType)
{
const auto bAttrLevel = rkAttrTable.bMaxLevelBySet[iAttributeSet];
if (bAttrLevel > 0)
pkAttrTable = &rkAttrTable;
}
}
}
// check rare bonus with item_attr_rare
else if (i >= ITEM_ATTRIBUTE_RARE_START)
{
for (size_t j = 0; j < vec_itemRareTable.size() && !pkAttrTable; ++j)
{
const TItemAttrTable & rkAttrTable = vec_itemRareTable.at(j);
if (rkAttrTable.dwApplyIndex == bApplyType)
{
const auto bAttrLevel = rkAttrTable.bMaxLevelBySet[iAttributeSet];
if (bAttrLevel > 0)
pkAttrTable = &rkAttrTable;
}
}
}
if (pkAttrTable)
{
const auto sMinValue = static_cast<int16_t>(pkAttrTable->lValues[0]);
const auto sMaxValue = static_cast<int16_t>(pkAttrTable->lValues[(sizeof(pkAttrTable->lValues) / sizeof(pkAttrTable->lValues[0])) - 1]);
rkItemAward.aAttr[i].sValue = MINMAX(sMinValue, rkItemAward.aAttr[i].sValue, sMaxValue);
}
else
{
rkItemAward.aAttr[i].bType = 0;
rkItemAward.aAttr[i].sValue = 0;
}
}
}
}
#endif
#ifdef ENABLE_EXTEND_ITEM_AWARD
/*******************************************************************\
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
||| 02.04.2018 - Fixed unknown average/skill damage bonus value.
||| player.item_proto.addon_type = -1 (Eg. 189, 199, 299, 1139, 1179, 2159, 2179, 3169, 3219, 5119, 5129, 6019, 6069, 6079, 7169)[+0 - +9]
||| That's for the items which have addon type (-1) and you added them in item shop without bonuses like skill damage or hit damage,
||| value x, y as default, so they'll will be without bonuses and get 'bugged'.
||| Now when the item will be inserted there'll be a check if item doesn't have those bonuses (from query) add a random average/skill damage bonus value.
||| INSERT INTO player.item_award(`login`, `vnum`, `count`, `mall`) VALUES ('account', 189, 1, 1);
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
\*******************************************************************/
void ItemAwardManager::CheckItemAddonType(TItemAward & rkItemAward, const TItemTable & rkItemTable)
{
const bool bIsAddonTypeItem = (rkItemTable.sAddonType == -1);
if (!bIsAddonTypeItem)
return;
bool bHasBonus = false;
for (size_t i = 0; i < ITEM_ATTRIBUTE_MAX_NUM && !bHasBonus; ++i)
{
const auto bType = rkItemAward.aAttr[i].bType;
const auto sValue = rkItemAward.aAttr[i].sValue;
if ((bType == APPLY_SKILL_DAMAGE_BONUS || bType == APPLY_NORMAL_HIT_DAMAGE_BONUS) && sValue)
bHasBonus = true;
}
if (!bHasBonus)
{
const auto sApplySkillDamageValue = MINMAX(-30, static_cast<int16_t>((gauss_random(0, 5) + 0.5f)), 30);
const auto sApplyNormalHitValue = std::abs(sApplySkillDamageValue) <= 20 ?
(-2 * sApplySkillDamageValue) + std::abs(number(-8, 8) + number(-8, 8)) + number(1, 4) :
(-2 * sApplySkillDamageValue) + number(1, 5);
rkItemAward.aAttr[0].bType = APPLY_NORMAL_HIT_DAMAGE_BONUS;
rkItemAward.aAttr[0].sValue = sApplyNormalHitValue;
rkItemAward.aAttr[1].bType = APPLY_SKILL_DAMAGE_BONUS;
rkItemAward.aAttr[1].sValue = sApplySkillDamageValue;
// clear up possible duplicates
for (size_t i = 2; i < ITEM_ATTRIBUTE_MAX_NUM; ++i)
{
const auto bType = rkItemAward.aAttr[i].bType;
if (bType == APPLY_SKILL_DAMAGE_BONUS || bType == APPLY_NORMAL_HIT_DAMAGE_BONUS)
{
rkItemAward.aAttr[i].bType = 0;
rkItemAward.aAttr[i].sValue = 0;
}
}
}
}
/*******************************************************************\
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
||| 12.04.2019 - Added support for books.
||| Check skill types, unknown skill, skill vnum need to be saved into socket0,
||| (4=Aura of the Sword < player.skill_proto), if the skill vnum is unknown, there will be a random book based on pc races,
||| excluded skills PASSIVE, GUILD, SUPPORT.
||| INSERT INTO player.item_award(`login`, `vnum`, `count`, `mall`) VALUES ('account', 50300, 1, 1); # Random book
||| INSERT INTO player.item_award(`login`, `vnum`, `count`, `socket0`, `mall`) VALUES ('account', 50300, 1, 4, 1); # Specific book by skill vnum
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
\*******************************************************************/
void ItemAwardManager::CheckItemSkillBook(TItemAward & rkItemAward, const std::vector<TSkillTable> vec_skillTable)
{
const bool bIsBookItem = (rkItemAward.dwVnum == ITEM_SKILL_VNUM || rkItemAward.dwVnum == ITEM_SKILLFORGET_VNUM);
if (!bIsBookItem)
return;
auto dwSocket0SkillVnum = rkItemAward.dwSocket0;
bool bHasSkill = false;
for (size_t i = 0; i < vec_skillTable.size(); ++i)
{
if (vec_skillTable[i].dwVnum == dwSocket0SkillVnum)
{
bHasSkill = true;
break;
}
}
if (!bHasSkill)
{
do
{
const TSkillTable * pkSkillTable = &vec_skillTable.at(number(0, vec_skillTable.size() - 1));
if (!pkSkillTable)
continue;
const auto dwSkillVnum = pkSkillTable->dwVnum;
const auto bSkillType = pkSkillTable->bType;
if ((JOB_WARRIOR + 1 <= bSkillType && bSkillType <= JOB_SHAMAN + 1)
#ifdef ENABLE_WOLFMAN_CHARACTER
|| bSkillType == 7
#endif
)
continue;
dwSocket0SkillVnum = dwSkillVnum;
break;
}
while (true);
rkItemAward.dwSocket0 = dwSocket0SkillVnum;
}
}
/*******************************************************************\
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
||| 11.04.2019 - Fixed unstackable items.
||| Check if item count overflow occured, then set it to maximum.
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
\*******************************************************************/
void ItemAwardManager::CheckItemCount(TItemAward & rkItemAward, const TItemTable & rkItemTable)
{
const bool bIsStackableItem = (rkItemTable.dwFlags & ITEM_FLAG_STACKABLE);
if (rkItemAward.dwCount > 1 && !bIsStackableItem)
rkItemAward.dwCount = 1;
else
rkItemAward.dwCount = MINMAX(1, rkItemAward.dwCount, ITEM_MAX_COUNT);
}
/*******************************************************************\
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
||| 20.08.2021 - Fixed not slottable items.
||| New created equipments had no available slots.
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
\*******************************************************************/
void ItemAwardManager::CheckItemSocket(TItemAward & rkItemAward, const TItemTable & rkItemTable)
{
// check for limited time items
for (const auto & limit : rkItemTable.aLimits)
{
if (LIMIT_REAL_TIME == limit.bType || LIMIT_REAL_TIME_START_FIRST_USE == limit.bType)
return;
}
// check slottable sockets for non limited time items
const auto maxSockets = std::min<int>(rkItemTable.bGainSocketPct, ITEM_SOCKET_MAX_NUM);
if (maxSockets <= 0)
return;
if (maxSockets >= 1)
rkItemAward.dwSocket0 = 1;
if (maxSockets >= 2)
rkItemAward.dwSocket1 = 1;
if (maxSockets >= 3)
rkItemAward.dwSocket2 = 1;
}
/*******************************************************************\
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
||| TODO-UNFINISHED: Check if apply_type exists in bonuses.
||| Check if apply_value, apply_duration is equal with grades (1/2/3/4/5) from settings, blend.txt
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
\*******************************************************************/
void ItemAwardManager::CheckItemBlend(TItemAward & rkItemAward, const TItemTable & rkItemTable)
{
const bool bIsBlendItem = (rkItemTable.bType == ITEM_BLEND);
if (!bIsBlendItem)
return;
const auto bApplyType = rkItemAward.dwSocket0;
const auto bApplyValue = rkItemAward.dwSocket1;
const auto dwApplyDuration = rkItemAward.dwSocket2;
if (bApplyType == 0 || bApplyValue == 0 || dwApplyDuration == 0)
sys_err("ItemAwardManager: Unknown sockets for ITEM_BLEND.");
}
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,69 @@
// vim:ts=8 sw=4
#ifndef __INC_ITEM_AWARD_H
#define __INC_ITEM_AWARD_H
#include <map>
#include <set>
#include "Peer.h"
#ifdef ENABLE_EXTEND_ITEM_AWARD
enum
{
ITEM_ATTRIBUTE_NONE = -1,
ITEM_SKILL_VNUM = 50300,
ITEM_SKILLFORGET_VNUM = 70037,
};
#endif
typedef struct SItemAward
{
DWORD dwID;
char szLogin[LOGIN_MAX_LEN+1];
DWORD dwVnum;
DWORD dwCount;
DWORD dwSocket0;
DWORD dwSocket1;
DWORD dwSocket2;
char szWhy[ITEM_AWARD_WHY_MAX_LEN+1];
bool bTaken;
bool bMall;
#ifdef ENABLE_EXTEND_ITEM_AWARD
TPlayerItemAttribute aAttr[ITEM_ATTRIBUTE_MAX_NUM];
#endif
} TItemAward;
class ItemAwardManager : public singleton<ItemAwardManager>
{
public:
ItemAwardManager();
virtual ~ItemAwardManager();
void RequestLoad();
void Load(SQLMsg * pMsg);
std::set<TItemAward *> * GetByLogin(const char * c_pszLogin);
void Taken(DWORD dwAwardID, DWORD dwItemID);
#ifdef ENABLE_EXTEND_ITEM_AWARD
void CheckItemAddonType(TItemAward & pkItemAward, const TItemTable & pkItemTable);
void CheckItemCount(TItemAward & pkItemAward, const TItemTable & pkItemTable);
void CheckItemSocket(TItemAward & pkItemAward, const TItemTable & pkItemTable);
void CheckItemBlend(TItemAward & pkItemAward, const TItemTable & pkItemTable);
void CheckItemSkillBook(TItemAward & pkItemAward, const std::vector<TSkillTable> vec_skillTable);
#endif
#ifdef USE_ITEM_AWARD_CHECK_ATTRIBUTES
void CheckItemAttributes(TItemAward & pkItemAward, const TItemTable & pkItemTable, const std::vector<TItemAttrTable> & vec_itemAttrTable, const std::vector<TItemAttrTable> & vec_itemRareTable);
int8_t GetItemAttributeSetIndex(const uint8_t bItemType, const uint8_t bItemSubType) const;
#endif
// gift notify
std::map<DWORD, TItemAward *>& GetMapAward();
std::map<std::string, std::set<TItemAward *> >& GetMapkSetAwardByLogin();
private:
// ID, ItemAward pair
std::map<DWORD, TItemAward *> m_map_award;
// PID, ItemAward pair
std::map<std::string, std::set<TItemAward *> > m_map_kSetAwardByLogin;
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,160 @@
#include "stdafx.h"
#include "ItemIDRangeManager.h"
#include "Main.h"
#include "DBManager.h"
#include "ClientManager.h"
#include "Peer.h"
CItemIDRangeManager::CItemIDRangeManager()
{
m_listData.clear();
}
void CItemIDRangeManager::Build()
{
DWORD dwMin = 0;
DWORD dwMax = 0;
TItemIDRangeTable range;
for (int i = 0; ; ++i)
{
dwMin = cs_dwMinimumRange * (i + 1) + 1;
dwMax = cs_dwMinimumRange * (i + 2);
if (dwMax == cs_dwMaxItemID)
break;
if (CClientManager::instance().GetItemRange().dwMin <= dwMin &&
CClientManager::instance().GetItemRange().dwMax >= dwMax)
{
continue;
}
if (BuildRange(dwMin, dwMax, range) == true)
{
m_listData.emplace_back(range);
}
}
}
struct FCheckCollision
{
bool hasCollision;
TItemIDRangeTable range;
FCheckCollision(TItemIDRangeTable data)
{
hasCollision = false;
range = data;
}
void operator() (CPeer* peer)
{
if (hasCollision == false)
{
hasCollision = peer->CheckItemIDRangeCollision(range);
}
}
};
TItemIDRangeTable CItemIDRangeManager::GetRange()
{
TItemIDRangeTable ret;
ret.dwMin = 0;
ret.dwMax = 0;
ret.dwUsableItemIDMin = 0;
if (m_listData.size() > 0)
{
while (m_listData.size() > 0)
{
ret = m_listData.front();
m_listData.pop_front();
FCheckCollision f(ret);
CClientManager::instance().for_each_peer(f);
if (f.hasCollision == false) return ret;
}
}
for (int i = 0; i < 10; ++i)
sys_err("ItemIDRange: NO MORE ITEM ID RANGE");
return ret;
}
bool CItemIDRangeManager::BuildRange(DWORD dwMin, DWORD dwMax, TItemIDRangeTable& range)
{
char szQuery[1024];
DWORD dwItemMaxID = 0;
MYSQL_ROW row;
snprintf(szQuery, sizeof(szQuery), "SELECT MAX(id) FROM item%s WHERE id >= %u and id <= %u", GetTablePostfix(), dwMin, dwMax);
auto pMsg = CDBManager::instance().DirectQuery(szQuery);
if (pMsg != NULL)
{
if (pMsg->Get()->uiNumRows > 0)
{
row = mysql_fetch_row(pMsg->Get()->pSQLResult);
str_to_number(dwItemMaxID, row[0]);
}
}
if (dwItemMaxID == 0)
dwItemMaxID = dwMin;
else
dwItemMaxID++;
if ((dwMax < dwItemMaxID) || (dwMax - dwItemMaxID < cs_dwMinimumRemainCount))
{
sys_log(0, "ItemIDRange: Build %u ~ %u start: %u\tNOT USE remain count is below %u",
dwMin, dwMax, dwItemMaxID, cs_dwMinimumRemainCount);
}
else
{
range.dwMin = dwMin;
range.dwMax = dwMax;
range.dwUsableItemIDMin = dwItemMaxID;
snprintf(szQuery, sizeof(szQuery), "SELECT COUNT(*) FROM item%s WHERE id >= %u AND id <= %u",
GetTablePostfix(), range.dwUsableItemIDMin, range.dwMax);
pMsg = CDBManager::instance().DirectQuery(szQuery);
if (pMsg != NULL)
{
if (pMsg->Get()->uiNumRows > 0)
{
DWORD count = 0;
row = mysql_fetch_row(pMsg->Get()->pSQLResult);
str_to_number(count, row[0]);
if (count > 0)
{
sys_err("ItemIDRange: Build: %u ~ %u\thave a item", range.dwUsableItemIDMin, range.dwMax);
return false;
}
else
{
sys_log(0, "ItemIDRange: Build: %u ~ %u start:%u", range.dwMin, range.dwMax, range.dwUsableItemIDMin);
return true;
}
}
}
}
return false;
}
void CItemIDRangeManager::UpdateRange(DWORD dwMin, DWORD dwMax)
{
TItemIDRangeTable range;
if (BuildRange(dwMin, dwMax, range) == true)
{
m_listData.emplace_back(range);
}
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,25 @@
// vim:ts=4 sw=4
#ifndef __INC_METIN_II_ITEM_ID_RANGE_MANAGER_H__
#define __INC_METIN_II_ITEM_ID_RANGE_MANAGER_H__
class CItemIDRangeManager : public singleton<CItemIDRangeManager>
{
private :
const static DWORD cs_dwMaxItemID = 4290000000UL;
const static DWORD cs_dwMinimumRange = 10000000UL;
const static DWORD cs_dwMinimumRemainCount = 10000UL;
std::list<TItemIDRangeTable> m_listData;
public :
CItemIDRangeManager();
void Build();
bool BuildRange(DWORD dwMin, DWORD dwMax, TItemIDRangeTable& range);
void UpdateRange(DWORD dwMin, DWORD dwMax);
TItemIDRangeTable GetRange();
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,61 @@
#include "stdafx.h"
#include "Lock.h"
CLock::CLock()
{
}
CLock::~CLock()
{
}
void CLock::Initialize()
{
m_bLocked = false;
#ifndef __WIN32__
pthread_mutex_init(&m_lock, NULL);
#else
::InitializeCriticalSection(&m_lock);
#endif
}
void CLock::Destroy()
{
assert(!m_bLocked && "lock didn't released");
#ifndef __WIN32__
pthread_mutex_destroy(&m_lock);
#else
::DeleteCriticalSection(&m_lock);
#endif
}
int CLock::Trylock()
{
#ifndef __WIN32__
return pthread_mutex_trylock(&m_lock);
#else
return ::TryEnterCriticalSection(&m_lock);
#endif
}
void CLock::Lock()
{
#ifndef __WIN32__
pthread_mutex_lock(&m_lock);
#else
::EnterCriticalSection(&m_lock);
#endif
m_bLocked = true;
}
void CLock::Unlock()
{
assert(m_bLocked && "lock didn't issued");
m_bLocked = false;
#ifndef __WIN32__
pthread_mutex_unlock(&m_lock);
#else
::LeaveCriticalSection(&m_lock);
#endif
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,28 @@
// vim:ts=8 sw=4
#ifndef __INC_LOCK_H__
#define __INC_LOCK_H__
#ifdef __WIN32__
typedef CRITICAL_SECTION lock_t;
#else
typedef pthread_mutex_t lock_t;
#endif
class CLock
{
public:
CLock();
~CLock();
void Initialize();
void Destroy();
int Trylock();
void Lock();
void Unlock();
private:
lock_t m_lock;
bool m_bLocked;
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,123 @@
#include "stdafx.h"
#include "LoginData.h"
#include "ClientManager.h"
CLoginData::CLoginData()
{
m_dwKey = 0;
memset(m_adwClientKey, 0, sizeof(m_adwClientKey));
m_dwConnectedPeerHandle = 0;
m_dwLogonTime = 0;
memset(m_szIP, 0, sizeof(m_szIP));
m_bPlay = false;
m_bDeleted = false;
m_bBillType = 0;
m_dwBillID = 0;
m_lastPlayTime = 0;
m_dwLastPlayerID = 0;
memset(&m_data, 0, sizeof(TAccountTable));
}
TAccountTable & CLoginData::GetAccountRef()
{
return m_data;
}
void CLoginData::SetClientKey(const DWORD * c_pdwClientKey)
{
thecore_memcpy(&m_adwClientKey, c_pdwClientKey, sizeof(DWORD) * 4);
}
const DWORD * CLoginData::GetClientKey()
{
return &m_adwClientKey[0];
}
void CLoginData::SetKey(DWORD dwKey)
{
m_dwKey = dwKey;
}
DWORD CLoginData::GetKey()
{
return m_dwKey;
}
void CLoginData::SetConnectedPeerHandle(DWORD dwHandle)
{
m_dwConnectedPeerHandle = dwHandle;
}
DWORD CLoginData::GetConnectedPeerHandle()
{
return m_dwConnectedPeerHandle;
}
void CLoginData::SetLogonTime()
{
m_dwLogonTime = get_dword_time();
}
DWORD CLoginData::GetLogonTime()
{
return m_dwLogonTime;
}
void CLoginData::SetIP(const char * c_pszIP)
{
strlcpy(m_szIP, c_pszIP, sizeof(m_szIP));
}
const char * CLoginData::GetIP()
{
return m_szIP;
}
void CLoginData::SetPlay(bool bOn)
{
if (bOn)
{
sys_log(0, "SetPlay on %lu %s", GetKey(), m_data.login);
SetLogonTime();
}
else
sys_log(0, "SetPlay off %lu %s", GetKey(), m_data.login);
m_bPlay = bOn;
m_lastPlayTime = CClientManager::instance().GetCurrentTime();
}
bool CLoginData::IsPlay()
{
return m_bPlay;
}
void CLoginData::SetDeleted(bool bSet)
{
m_bDeleted = bSet;
}
bool CLoginData::IsDeleted()
{
return m_bDeleted;
}
void CLoginData::SetPremium(int * paiPremiumTimes)
{
thecore_memcpy(m_aiPremiumTimes, paiPremiumTimes, sizeof(m_aiPremiumTimes));
}
int CLoginData::GetPremium(BYTE type)
{
if (type >= PREMIUM_MAX_NUM)
return 0;
return m_aiPremiumTimes[type];
}
int * CLoginData::GetPremiumPtr()
{
return &m_aiPremiumTimes[0];
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,67 @@
// vim:ts=8 sw=4
#ifndef __INC_METIN_II_DB_LOGINDATA_H__
#define __INC_METIN_II_DB_LOGINDATA_H__
class CLoginData
{
public:
CLoginData();
TAccountTable & GetAccountRef();
void SetClientKey(const DWORD * c_pdwClientKey);
const DWORD * GetClientKey();
void SetKey(DWORD dwKey);
DWORD GetKey();
void SetConnectedPeerHandle(DWORD dwHandle);
DWORD GetConnectedPeerHandle();
void SetLogonTime();
DWORD GetLogonTime();
void SetIP(const char * c_pszIP);
const char * GetIP();
void SetPlay(bool bOn);
bool IsPlay();
void SetDeleted(bool bSet);
bool IsDeleted();
void SetBillID(DWORD id) { m_dwBillID = id; }
DWORD GetBillID() { return m_dwBillID; }
void SetBillType(BYTE type) { m_bBillType = type; }
BYTE GetBillType() { return m_bBillType; }
time_t GetLastPlayTime() { return m_lastPlayTime; }
void SetPremium(int * paiPremiumTimes);
int GetPremium(BYTE type);
int * GetPremiumPtr();
DWORD GetLastPlayerID() const { return m_dwLastPlayerID; }
void SetLastPlayerID(DWORD id) { m_dwLastPlayerID = id; }
private:
DWORD m_dwKey;
DWORD m_adwClientKey[4];
DWORD m_dwConnectedPeerHandle;
DWORD m_dwLogonTime;
char m_szIP[MAX_HOST_LENGTH+1];
bool m_bPlay;
bool m_bDeleted;
BYTE m_bBillType;
DWORD m_dwBillID;
time_t m_lastPlayTime;
int m_aiPremiumTimes[PREMIUM_MAX_NUM];
DWORD m_dwLastPlayerID;
TAccountTable m_data;
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,443 @@
#include "stdafx.h"
#include "Config.h"
#include "Peer.h"
#include "DBManager.h"
#include "ClientManager.h"
#include "GuildManager.h"
#include "ItemAwardManager.h"
#include "HB.h"
#include "PrivManager.h"
#include "MoneyLog.h"
#include "Marriage.h"
#include "Monarch.h"
#include "ItemIDRangeManager.h"
#include <signal.h>
void SetPlayerDBName(const char* c_pszPlayerDBName);
void SetTablePostfix(const char* c_pszTablePostfix);
int Start();
std::string g_stTablePostfix;
std::string g_stLocaleNameColumn = "name";
std::string g_stLocale = "latin1"; // default: euckr
std::string g_stPlayerDBName = "";
bool g_bHotBackup = false; // default: true
BOOL g_test_server = false;
int g_iPlayerCacheFlushSeconds = 60*7;
int g_iItemCacheFlushSeconds = 60*5;
int g_iLogoutSeconds = 60*10;
int g_log = 1;
// MYSHOP_PRICE_LIST
int g_iItemPriceListTableCacheFlushSeconds = 540;
// END_OF_MYSHOP_PRICE_LIST
#if defined(__FreeBSD__) && defined(__FreeBSD_version) && __FreeBSD_version<1000000
extern const char * _malloc_options;
#endif
extern void WriteVersion();
void emergency_sig(int sig)
{
if (sig == SIGSEGV)
sys_log(0, "SIGNAL: SIGSEGV");
else if (sig == SIGUSR1)
sys_log(0, "SIGNAL: SIGUSR1");
if (sig == SIGSEGV)
abort();
}
int main()
{
WriteVersion();
#if defined(__FreeBSD__) && defined(__FreeBSD_version) && __FreeBSD_version<1000000
_malloc_options = "A";
#endif
CConfig Config;
CNetPoller poller;
CDBManager DBManager;
CClientManager ClientManager;
PlayerHB player_hb;
CGuildManager GuildManager;
CPrivManager PrivManager;
CMoneyLog MoneyLog;
ItemAwardManager ItemAwardManager;
marriage::CManager MarriageManager;
CMonarch Monarch;
CItemIDRangeManager ItemIDRangeManager;
if (!Start())
return 1;
GuildManager.Initialize();
MarriageManager.Initialize();
ItemIDRangeManager.Build();
sys_log(0, "Metin2DBCacheServer Start\n");
CClientManager::instance().MainLoop();
signal_timer_disable();
DBManager.Quit();
int iCount;
while (1)
{
iCount = 0;
iCount += CDBManager::instance().CountReturnQuery(SQL_PLAYER);
iCount += CDBManager::instance().CountAsyncQuery(SQL_PLAYER);
if (iCount == 0)
break;
usleep(1000);
sys_log(0, "WAITING_QUERY_COUNT %d", iCount);
}
return 1;
}
void emptybeat(LPHEART heart, int pulse)
{
if (!(pulse % heart->passes_per_sec))
{
}
}
//
//
int Start()
{
if (!CConfig::instance().LoadFile("conf.txt"))
{
fprintf(stderr, "Loading conf.txt failed.\n");
return false;
}
if (!CConfig::instance().GetValue("TEST_SERVER", &g_test_server))
{
fprintf(stderr, "Real Server\n");
}
else
fprintf(stderr, "Test Server\n");
if (!CConfig::instance().GetValue("LOG", &g_log))
{
fprintf(stderr, "Log Off");
g_log= 0;
}
else
{
g_log = 1;
fprintf(stderr, "Log On");
}
int tmpValue;
int heart_beat = 50;
if (!CConfig::instance().GetValue("CLIENT_HEART_FPS", &heart_beat))
{
fprintf(stderr, "Cannot find CLIENT_HEART_FPS configuration.\n");
return false;
}
log_set_expiration_days(3);
if (CConfig::instance().GetValue("LOG_KEEP_DAYS", &tmpValue))
{
tmpValue = MINMAX(3, tmpValue, 30);
log_set_expiration_days(tmpValue);
fprintf(stderr, "Setting log keeping days to %d\n", tmpValue);
}
thecore_init(heart_beat, emptybeat);
signal_timer_enable(60);
char szBuf[256+1];
if (CConfig::instance().GetValue("LOCALE", szBuf, 256))
{
g_stLocale = szBuf;
sys_log(0, "LOCALE set to %s", g_stLocale.c_str());
// CHINA_DISABLE_HOTBACKUP
if ("gb2312" == g_stLocale)
{
sys_log(0, "CIBN_LOCALE: DISABLE_HOTBACKUP");
g_bHotBackup = false;
}
// END_OF_CHINA_DISABLE_HOTBACKUP
}
int iDisableHotBackup;
if (CConfig::instance().GetValue("DISABLE_HOTBACKUP", &iDisableHotBackup))
{
if (iDisableHotBackup)
{
sys_log(0, "CONFIG: DISABLE_HOTBACKUP");
g_bHotBackup = false;
}
}
if (!CConfig::instance().GetValue("TABLE_POSTFIX", szBuf, 256))
{
sys_log(0, "TABLE_POSTFIX not configured use default"); // @warme012
szBuf[0] = '\0';
}
SetTablePostfix(szBuf);
if (CConfig::instance().GetValue("PLAYER_CACHE_FLUSH_SECONDS", szBuf, 256))
{
str_to_number(g_iPlayerCacheFlushSeconds, szBuf);
sys_log(0, "PLAYER_CACHE_FLUSH_SECONDS: %d", g_iPlayerCacheFlushSeconds);
}
if (CConfig::instance().GetValue("ITEM_CACHE_FLUSH_SECONDS", szBuf, 256))
{
str_to_number(g_iItemCacheFlushSeconds, szBuf);
sys_log(0, "ITEM_CACHE_FLUSH_SECONDS: %d", g_iItemCacheFlushSeconds);
}
// MYSHOP_PRICE_LIST
if (CConfig::instance().GetValue("ITEM_PRICELIST_CACHE_FLUSH_SECONDS", szBuf, 256))
{
str_to_number(g_iItemPriceListTableCacheFlushSeconds, szBuf);
sys_log(0, "ITEM_PRICELIST_CACHE_FLUSH_SECONDS: %d", g_iItemPriceListTableCacheFlushSeconds);
}
// END_OF_MYSHOP_PRICE_LIST
if (CConfig::instance().GetValue("CACHE_FLUSH_LIMIT_PER_SECOND", szBuf, 256))
{
DWORD dwVal = 0; str_to_number(dwVal, szBuf);
CClientManager::instance().SetCacheFlushCountLimit(dwVal);
}
int iIDStart;
if (!CConfig::instance().GetValue("PLAYER_ID_START", &iIDStart))
{
sys_err("PLAYER_ID_START not configured");
return false;
}
CClientManager::instance().SetPlayerIDStart(iIDStart);
if (CConfig::instance().GetValue("NAME_COLUMN", szBuf, 256))
{
fprintf(stderr, "%s %s", g_stLocaleNameColumn.c_str(), szBuf);
g_stLocaleNameColumn = szBuf;
}
char szAddr[64], szDB[64], szUser[64], szPassword[64];
int iPort;
char line[256+1];
if (CConfig::instance().GetValue("SQL_PLAYER", line, 256))
{
sscanf(line, " %s %s %s %s %d ", szAddr, szDB, szUser, szPassword, &iPort);
sys_log(0, "connecting to MySQL server (player)");
int iRetry = 5;
do
{
if (CDBManager::instance().Connect(SQL_PLAYER, szAddr, iPort, szDB, szUser, szPassword))
{
sys_log(0, " OK");
break;
}
sys_log(0, " failed, retrying in 5 seconds");
fprintf(stderr, " failed, retrying in 5 seconds");
sleep(5);
} while (iRetry--);
fprintf(stderr, "Success PLAYER\n");
SetPlayerDBName(szDB);
}
else
{
sys_err("SQL_PLAYER not configured");
return false;
}
if (CConfig::instance().GetValue("SQL_ACCOUNT", line, 256))
{
sscanf(line, " %s %s %s %s %d ", szAddr, szDB, szUser, szPassword, &iPort);
sys_log(0, "connecting to MySQL server (account)");
int iRetry = 5;
do
{
if (CDBManager::instance().Connect(SQL_ACCOUNT, szAddr, iPort, szDB, szUser, szPassword))
{
sys_log(0, " OK");
break;
}
sys_log(0, " failed, retrying in 5 seconds");
fprintf(stderr, " failed, retrying in 5 seconds");
sleep(5);
} while (iRetry--);
fprintf(stderr, "Success ACCOUNT\n");
}
else
{
sys_err("SQL_ACCOUNT not configured");
return false;
}
if (CConfig::instance().GetValue("SQL_COMMON", line, 256))
{
sscanf(line, " %s %s %s %s %d ", szAddr, szDB, szUser, szPassword, &iPort);
sys_log(0, "connecting to MySQL server (common)");
int iRetry = 5;
do
{
if (CDBManager::instance().Connect(SQL_COMMON, szAddr, iPort, szDB, szUser, szPassword))
{
sys_log(0, " OK");
break;
}
sys_log(0, " failed, retrying in 5 seconds");
fprintf(stderr, " failed, retrying in 5 seconds");
sleep(5);
} while (iRetry--);
fprintf(stderr, "Success COMMON\n");
}
else
{
sys_err("SQL_COMMON not configured");
return false;
}
if (CConfig::instance().GetValue("SQL_HOTBACKUP", line, 256))
{
sscanf(line, " %s %s %s %s %d ", szAddr, szDB, szUser, szPassword, &iPort);
sys_log(0, "connecting to MySQL server (hotbackup)");
int iRetry = 5;
do
{
if (CDBManager::instance().Connect(SQL_HOTBACKUP, szAddr, iPort, szDB, szUser, szPassword))
{
sys_log(0, " OK");
break;
}
sys_log(0, " failed, retrying in 5 seconds");
fprintf(stderr, " failed, retrying in 5 seconds");
sleep(5);
}
while (iRetry--);
fprintf(stderr, "Success HOTBACKUP\n");
}
else
{
sys_err("SQL_HOTBACKUP not configured");
return false;
}
#ifdef ENABLE_DB_SQL_LOG
if (CConfig::instance().GetValue("SQL_LOG", line, 256))
{
sscanf(line, " %s %s %s %s %d ", szAddr, szDB, szUser, szPassword, &iPort);
sys_log(0, "connecting to MySQL server (log)");
int iRetry = 5;
do
{
if (CDBManager::instance().Connect(SQL_LOG, szAddr, iPort, szDB, szUser, szPassword))
{
sys_log(0, " OK");
break;
}
sys_log(0, " failed, retrying in 5 seconds");
fprintf(stderr, " failed, retrying in 5 seconds");
sleep(5);
} while (iRetry--);
fprintf(stderr, "Success LOG\n");
}
else
{
sys_err("SQL_LOG not configured");
return false;
}
#endif
if (!CNetPoller::instance().Create())
{
sys_err("Cannot create network poller");
return false;
}
sys_log(0, "ClientManager initialization.. ");
if (!CClientManager::instance().Initialize())
{
sys_log(0, " failed");
return false;
}
sys_log(0, " OK");
if (!PlayerHB::instance().Initialize())
{
sys_err("cannot initialize player hotbackup");
return false;
}
#ifndef __WIN32__
signal(SIGUSR1, emergency_sig);
#endif
signal(SIGSEGV, emergency_sig);
return true;
}
void SetTablePostfix(const char* c_pszTablePostfix)
{
if (!c_pszTablePostfix || !*c_pszTablePostfix)
g_stTablePostfix = "";
else
g_stTablePostfix = c_pszTablePostfix;
}
const char * GetTablePostfix()
{
return g_stTablePostfix.c_str();
}
void SetPlayerDBName(const char* c_pszPlayerDBName)
{
if (! c_pszPlayerDBName || ! *c_pszPlayerDBName)
g_stPlayerDBName = "";
else
{
g_stPlayerDBName = c_pszPlayerDBName;
g_stPlayerDBName += ".";
}
}
const char * GetPlayerDBName()
{
return g_stPlayerDBName.c_str();
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,10 @@
#ifndef __INC_MAIN_H__
#define __INC_MAIN_H__
int Start();
void End();
const char * GetTablePostfix();
const char * GetPlayerDBName();
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,136 @@
CC = clang
CXX = clang++
DB_VERSION = $(shell cat ../../__REVISION__)
LBITS := $(shell getconf LONG_BIT)
INCDIR =
LIBDIR =
BINDIR = ..
OBJDIR = .obj
$(shell if [ ! -d $(OBJDIR) ]; then mkdir $(OBJDIR); fi)
# LIST_OF_CONSTANTS BEGIN
ENABLE_GCC_AUTODEPEND = 1
ENABLE_STATIC = 0
# LIST_OF_CONSTANTS END
# Depend Path File
ifneq ($(ENABLE_GCC_AUTODEPEND), 1)
DEPFILE = Depend
endif
# Project Flags
CFLAGS = -m32 -g -Wall -O2 -pipe -fno-rtti -fno-exceptions -Wno-long-long -pthread -D_THREAD_SAFE
CFLAGS += -Wno-deprecated-declarations -Wno-nonnull-compare -Wno-deprecated-declarations -Wno-array-bounds -Wno-address
CFLAGS += -Wno-int-in-bool-context -Wno-format-truncation -Wno-deprecated-enum-enum-conversion
CXXFLAGS = -std=c++20
# for clang
ifneq '' '$(findstring clang++,$(CXX))'
CFLAGS += -Wno-invalid-source-encoding -Wno-deprecated-anon-enum-enum-conversion -Wno-unknown-warning-option
# for gcc
else ifneq '' '$(findstring g++,$(CXX))'
# for 32bit on 64bit
ifeq ($(LBITS),64)
CFLAGS += -L/usr/local/lib32/gcc12
CFLAGS += -Wl,-rpath=/usr/local/lib32/gcc12
else
# for 32bit on 32bit
CXXFLAGS += -Wl,-rpath=/usr/local/lib/gcc12
endif
endif
# MySQL
INCDIR += -I/usr/local/include/mysql
ifeq ($(LBITS),64)
LIBS += ../../../Extern/lib/libmysqlclient.a -lz
else
LIBS += /usr/local/lib/mysql/libmysqlclient.a /usr/lib/libz.a
endif
ifeq ($(ENABLE_STATIC), 1)
CFLAGS += -static
endif
# Version defines
CFLAGS += -D__USER__=\"$(USER)\" -D__HOSTNAME__=\"$(HOSTNAME)\" -D__PWD__=\"$(PWD)\" -D__DB_VERSION__=\"$(DB_VERSION)\"
# Boost
INCDIR += -I../../../Extern/include/boost
# Project Libraries
INCDIR += -I/usr/local/include
INCDIR += -I../../../Extern/include
LIBDIR += -I../../../Extern/lib
LIBDIR += -L../../libthecore/lib -L../../libsql -L../../libpoly -L../../libgame/lib
LIBS += -lthecore -lsql -lpoly -lgame -lm
# OpenSSL
ifeq ($(LBITS),64)
LIBS += /usr/lib32/libcrypto.a /usr/lib32/libssl.a
else
LIBS += -lssl -lcrypto
endif
# PROJECT_SRC_FILES BEGIN
CPPFILE = Config.cpp NetBase.cpp Peer.cpp PeerBase.cpp Main.cpp Lock.cpp DBManager.cpp \
Cache.cpp LoginData.cpp ClientManager.cpp ClientManagerPlayer.cpp ClientManagerLogin.cpp \
ClientManagerBoot.cpp ClientManagerParty.cpp ClientManagerGuild.cpp GuildManager.cpp HB.cpp \
PrivManager.cpp MoneyLog.cpp ItemAwardManager.cpp ClientManagerEventFlag.cpp Marriage.cpp \
Monarch.cpp ItemIDRangeManager.cpp ClientManagerHorseName.cpp version.cpp \
ProtoReader.cpp CsvReader.cpp
# PROJECT_SRC_FILES END
# PROJECT_OBJ_FILES BEGIN
CPPOBJS = $(CPPFILE:%.cpp=$(OBJDIR)/%.o)
ifeq ($(ENABLE_GCC_AUTODEPEND), 1)
CPPDEPS = $(CPPOBJS:%.o=%.d)
endif
# PROJECT_OBJ_FILES END
# Target Paths
MAIN_TARGET = $(BINDIR)/db_r$(DB_VERSION)
default: $(MAIN_TARGET)
$(MAIN_TARGET): $(CPPOBJS)
@echo linking $(MAIN_TARGET)
@$(CXX) $(CFLAGS) $(CXXFLAGS) $(LIBDIR) $(CPPOBJS) $(LIBS) -o $(MAIN_TARGET)
$(OBJDIR)/%.o: %.cpp
@echo compiling $<
@$(CXX) $(CFLAGS) $(CXXFLAGS) $(INCDIR) -c $< -o $@
ifeq ($(ENABLE_GCC_AUTODEPEND), 1)
@$(CXX) -MM -MG -MP $(CFLAGS) $(CXXFLAGS) $(INCDIR) -c $< -o $(OBJDIR)/$*.d
@sed -i '' -e's/$*.o:/$(OBJDIR)\/$*.o:/g' $(OBJDIR)/$*.d
endif
$(OBJDIR):
@mkdir $(OBJDIR)
symlink:
@ln -fs db_r$(DB_VERSION) $(BINDIR)/db_symlink
strip:
@cp $(BINDIR)/db_r$(DB_VERSION) $(BINDIR)/db_r
@strip $(BINDIR)/db_r
clean:
@rm -f $(CPPOBJS) $(BINDIR)/db_r*
dep:
ifeq ($(ENABLE_GCC_AUTODEPEND), 1)
@echo "Note: gcc autodepend is autodetected, so target dep skipped"
else
makedepend -f $(DEPFILE) $(INCDIR) -I/usr/include/c++/3.3 -I/usr/include/c++/4.2 -p$(OBJDIR)/ $(CPPFILE) 2> /dev/null > $(DEPFILE)
endif
# AUTO_DEPEND_CHECK BEGIN
ifeq ($(ENABLE_GCC_AUTODEPEND), 1)
sinclude $(CPPDEPS)
else
sinclude $(DEPFILE)
endif
# AUTO_DEPEND_CHECK END

View File

@ -0,0 +1,377 @@
#include "stdafx.h"
#include "Marriage.h"
#include "Main.h"
#include "DBManager.h"
#include "ClientManager.h"
namespace marriage
{
const DWORD WEDDING_LENGTH = 60 * 60; // sec
bool operator < (const TWedding& lhs, const TWedding& rhs)
{
return lhs.dwTime < rhs.dwTime;
}
bool operator > (const TWedding& lhs, const TWedding& rhs)
{
return lhs.dwTime > rhs.dwTime;
}
bool operator > (const TWeddingInfo &lhs, const TWeddingInfo& rhs)
{
return lhs.dwTime > rhs.dwTime;
}
using namespace std;
CManager::CManager()
{
}
CManager::~CManager()
{
}
bool CManager::Initialize()
{
char szQuery[1024];
snprintf(szQuery, sizeof(szQuery),
"SELECT pid1, pid2, love_point, time, is_married, p1.name, p2.name FROM marriage, player%s as p1, player%s as p2 WHERE p1.id = pid1 AND p2.id = pid2",
GetTablePostfix(), GetTablePostfix());
auto pmsg_delete(CDBManager::instance().DirectQuery("DELETE FROM marriage WHERE is_married = 0"));
auto pmsg(CDBManager::instance().DirectQuery(szQuery));
SQLResult * pRes = pmsg->Get();
sys_log(0, "MarriageList(size=%lu)", pRes->uiNumRows);
if (pRes->uiNumRows > 0)
{
for (uint uiRow = 0; uiRow != pRes->uiNumRows; ++uiRow)
{
MYSQL_ROW row = mysql_fetch_row(pRes->pSQLResult);
DWORD pid1 = 0; str_to_number(pid1, row[0]);
DWORD pid2 = 0; str_to_number(pid2, row[1]);
int love_point = 0; str_to_number(love_point, row[2]);
DWORD time = 0; str_to_number(time, row[3]);
BYTE is_married = 0; str_to_number(is_married, row[4]);
const char* name1 = row[5];
const char* name2 = row[6];
TMarriage* pMarriage = new TMarriage(pid1, pid2, love_point, time, is_married, name1, name2);
m_Marriages.emplace(pMarriage);
m_MarriageByPID.emplace(pid1, pMarriage);
m_MarriageByPID.emplace(pid2, pMarriage);
sys_log(0, "Marriage %lu: LP:%d TM:%u ST:%d %10lu:%16s %10lu:%16s ", uiRow, love_point, time, is_married, pid1, name1, pid2, name2);
}
}
return true;
}
TMarriage* CManager::Get(DWORD dwPlayerID)
{
itertype(m_MarriageByPID) it = m_MarriageByPID.find(dwPlayerID);
if (it != m_MarriageByPID.end())
return it->second;
return NULL;
}
void Align(DWORD& rPID1, DWORD& rPID2)
{
if (rPID1 > rPID2)
std::swap(rPID1, rPID2);
}
void CManager::Add(DWORD dwPID1, DWORD dwPID2, const char* szName1, const char* szName2)
{
DWORD now = CClientManager::instance().GetCurrentTime();
if (IsMarried(dwPID1) || IsMarried(dwPID2))
{
sys_err("cannot marry already married character. %d - %d", dwPID1, dwPID2);
return;
}
Align(dwPID1, dwPID2);
char szQuery[512];
snprintf(szQuery, sizeof(szQuery), "INSERT INTO marriage(pid1, pid2, love_point, time) VALUES (%u, %u, 0, %u)", dwPID1, dwPID2, now);
auto pmsg(CDBManager::instance().DirectQuery(szQuery));
SQLResult* res = pmsg->Get();
if (res->uiAffectedRows == 0 || res->uiAffectedRows == (uint32_t)-1)
{
sys_err("cannot insert marriage");
return;
}
sys_log(0, "MARRIAGE ADD %u %u", dwPID1, dwPID2);
TMarriage* pMarriage = new TMarriage(dwPID1, dwPID2, 0, now, 0, szName1, szName2);
m_Marriages.emplace(pMarriage);
m_MarriageByPID.emplace(dwPID1, pMarriage);
m_MarriageByPID.emplace(dwPID2, pMarriage);
TPacketMarriageAdd p;
p.dwPID1 = dwPID1;
p.dwPID2 = dwPID2;
p.tMarryTime = now;
strlcpy(p.szName1, szName1, sizeof(p.szName1));
strlcpy(p.szName2, szName2, sizeof(p.szName2));
CClientManager::instance().ForwardPacket(HEADER_DG_MARRIAGE_ADD, &p, sizeof(p));
}
void CManager::Update(DWORD dwPID1, DWORD dwPID2, INT iLovePoint, BYTE byMarried)
{
TMarriage* pMarriage = Get(dwPID1);
if (!pMarriage || pMarriage->GetOther(dwPID1) != dwPID2)
{
sys_err("not under marriage : %u %u", dwPID1, dwPID2);
return;
}
Align(dwPID1, dwPID2);
char szQuery[512];
snprintf(szQuery, sizeof(szQuery), "UPDATE marriage SET love_point = %d, is_married = %d WHERE pid1 = %u AND pid2 = %u",
iLovePoint, byMarried, pMarriage->pid1, pMarriage->pid2);
auto pmsg(CDBManager::instance().DirectQuery(szQuery));
SQLResult* res = pmsg->Get();
if (res->uiAffectedRows == 0 || res->uiAffectedRows == (uint32_t)-1)
{
sys_log(0, "cannot update marriage : PID:%u %u", dwPID1, dwPID2); // @warme012
return;
}
sys_log(0, "MARRIAGE UPDATE PID:%u %u LP:%u ST:%d", dwPID1, dwPID2, iLovePoint, byMarried);
pMarriage->love_point = iLovePoint;
pMarriage->is_married = byMarried;
TPacketMarriageUpdate p;
p.dwPID1 = dwPID1;
p.dwPID2 = dwPID2;
p.iLovePoint = pMarriage->love_point;
p.byMarried = pMarriage->is_married;
CClientManager::instance().ForwardPacket(HEADER_DG_MARRIAGE_UPDATE, &p, sizeof(p));
}
void CManager::Remove(DWORD dwPID1, DWORD dwPID2)
{
TMarriage* pMarriage = Get(dwPID1);
if (pMarriage)
{
sys_log(0, "Break Marriage pid1 %d pid2 %d Other %d", dwPID1, dwPID2, pMarriage->GetOther(dwPID1));
}
if (!pMarriage || pMarriage->GetOther(dwPID1) != dwPID2)
{
itertype(m_MarriageByPID) it = m_MarriageByPID.begin();
for (; it != m_MarriageByPID.end(); ++it)
{
sys_log(0, "Marriage List pid1 %d pid2 %d", it->second->pid1, it->second->pid2);
}
sys_err("not under marriage : PID:%u %u", dwPID1, dwPID2);
return;
}
Align(dwPID1, dwPID2);
char szQuery[512];
snprintf(szQuery, sizeof(szQuery), "DELETE FROM marriage WHERE pid1 = %u AND pid2 = %u", dwPID1, dwPID2);
auto pmsg(CDBManager::instance().DirectQuery(szQuery));
SQLResult* res = pmsg->Get();
if (res->uiAffectedRows == 0 || res->uiAffectedRows == (uint32_t)-1)
{
sys_err("cannot delete marriage : PID:%u %u", dwPID1, dwPID2);
return;
}
sys_log(0, "MARRIAGE REMOVE PID:%u %u", dwPID1, dwPID2);
m_Marriages.erase(pMarriage);
m_MarriageByPID.erase(dwPID1);
m_MarriageByPID.erase(dwPID2);
TPacketMarriageRemove p;
p.dwPID1 = dwPID1;
p.dwPID2 = dwPID2;
CClientManager::instance().ForwardPacket(HEADER_DG_MARRIAGE_REMOVE, &p, sizeof(p));
delete pMarriage;
}
void CManager::EngageToMarriage(DWORD dwPID1, DWORD dwPID2)
{
TMarriage* pMarriage = Get(dwPID1);
if (!pMarriage || pMarriage->GetOther(dwPID1) != dwPID2)
{
sys_err("not under marriage : PID:%u %u", dwPID1, dwPID2);
return;
}
if (pMarriage->is_married)
{
sys_err("already married, cannot change engage to marry : PID:%u %u", dwPID1, dwPID2);
return;
}
Align(dwPID1, dwPID2);
char szQuery[512];
snprintf(szQuery, sizeof(szQuery), "UPDATE marriage SET is_married = 1 WHERE pid1 = %u AND pid2 = %u",
pMarriage->pid1, pMarriage->pid2);
auto pmsg(CDBManager::instance().DirectQuery(szQuery));
SQLResult* res = pmsg->Get();
if (res->uiAffectedRows == 0 || res->uiAffectedRows == (uint32_t)-1)
{
sys_err("cannot change engage to marriage : PID:%u %u", dwPID1, dwPID2);
return;
}
sys_log(0, "MARRIAGE ENGAGE->MARRIAGE PID:%u %u", dwPID1, dwPID2);
pMarriage->is_married = 1;
TPacketMarriageUpdate p;
p.dwPID1 = dwPID1;
p.dwPID2 = dwPID2;
p.iLovePoint = pMarriage->love_point;
p.byMarried = pMarriage->is_married;
CClientManager::instance().ForwardPacket(HEADER_DG_MARRIAGE_UPDATE, &p, sizeof(p));
}
void CManager::OnSetup(CPeer* peer)
{
for (itertype(m_Marriages) it = m_Marriages.begin(); it != m_Marriages.end(); ++it)
{
TMarriage* pMarriage = *it;
{
TPacketMarriageAdd p;
p.dwPID1 = pMarriage->pid1;
p.dwPID2 = pMarriage->pid2;
p.tMarryTime = pMarriage->time;
strlcpy(p.szName1, pMarriage->name1.c_str(), sizeof(p.szName1));
strlcpy(p.szName2, pMarriage->name2.c_str(), sizeof(p.szName2));
peer->EncodeHeader(HEADER_DG_MARRIAGE_ADD, 0, sizeof(p));
peer->Encode(&p, sizeof(p));
}
{
TPacketMarriageUpdate p;
p.dwPID1 = pMarriage->pid1;
p.dwPID2 = pMarriage->pid2;
p.iLovePoint = pMarriage->love_point;
p.byMarried = pMarriage->is_married;
peer->EncodeHeader(HEADER_DG_MARRIAGE_UPDATE, 0, sizeof(p));
peer->Encode(&p, sizeof(p));
}
}
for (itertype(m_mapRunningWedding) it = m_mapRunningWedding.begin(); it != m_mapRunningWedding.end(); ++it)
{
const TWedding& t = it->second;
TPacketWeddingReady p;
p.dwPID1 = t.dwPID1;
p.dwPID2 = t.dwPID2;
p.dwMapIndex = t.dwMapIndex;
peer->EncodeHeader(HEADER_DG_WEDDING_READY, 0, sizeof(p));
peer->Encode(&p, sizeof(p));
TPacketWeddingStart p2;
p2.dwPID1 = t.dwPID1;
p2.dwPID2 = t.dwPID2;
peer->EncodeHeader(HEADER_DG_WEDDING_START, 0, sizeof(p2));
peer->Encode(&p2, sizeof(p2));
}
}
void CManager::ReadyWedding(DWORD dwMapIndex, DWORD dwPID1, DWORD dwPID2)
{
DWORD dwStartTime = CClientManager::instance().GetCurrentTime();
m_pqWeddingStart.push(TWedding(dwStartTime + 5, dwMapIndex, dwPID1, dwPID2));
}
void CManager::EndWedding(DWORD dwPID1, DWORD dwPID2)
{
itertype(m_mapRunningWedding) it = m_mapRunningWedding.find(make_pair(dwPID1, dwPID2));
if (it == m_mapRunningWedding.end())
{
sys_err("try to end wedding %u %u", dwPID1, dwPID2);
return;
}
TWedding& w = it->second;
TPacketWeddingEnd p;
p.dwPID1 = w.dwPID1;
p.dwPID2 = w.dwPID2;
CClientManager::instance().ForwardPacket(HEADER_DG_WEDDING_END, &p, sizeof(p));
m_mapRunningWedding.erase(it);
}
void CManager::Update()
{
DWORD now = CClientManager::instance().GetCurrentTime();
if (!m_pqWeddingEnd.empty())
{
while (!m_pqWeddingEnd.empty() && m_pqWeddingEnd.top().dwTime <= now)
{
TWeddingInfo wi = m_pqWeddingEnd.top();
m_pqWeddingEnd.pop();
itertype(m_mapRunningWedding) it = m_mapRunningWedding.find(make_pair(wi.dwPID1, wi.dwPID2));
if (it == m_mapRunningWedding.end())
continue;
TWedding& w = it->second;
TPacketWeddingEnd p;
p.dwPID1 = w.dwPID1;
p.dwPID2 = w.dwPID2;
CClientManager::instance().ForwardPacket(HEADER_DG_WEDDING_END, &p, sizeof(p));
m_mapRunningWedding.erase(it);
itertype(m_MarriageByPID) it_marriage = m_MarriageByPID.find(w.dwPID1);
if (it_marriage != m_MarriageByPID.end())
{
TMarriage* pMarriage = it_marriage->second;
if (!pMarriage->is_married)
{
Remove(pMarriage->pid1, pMarriage->pid2);
}
}
}
}
if (!m_pqWeddingStart.empty())
{
while (!m_pqWeddingStart.empty() && m_pqWeddingStart.top().dwTime <= now)
{
TWedding w = m_pqWeddingStart.top();
m_pqWeddingStart.pop();
TPacketWeddingStart p;
p.dwPID1 = w.dwPID1;
p.dwPID2 = w.dwPID2;
CClientManager::instance().ForwardPacket(HEADER_DG_WEDDING_START, &p, sizeof(p));
w.dwTime += WEDDING_LENGTH;
m_pqWeddingEnd.push(TWeddingInfo(w.dwTime, w.dwPID1, w.dwPID2));
m_mapRunningWedding.emplace(make_pair(w.dwPID1, w.dwPID2), w);
}
}
}
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,114 @@
// vim: ts=4 sw=4
#ifndef __MARRIAGE_H
#define __MARRIAGE_H
#include <set>
#include <queue>
#include <deque>
#include "Peer.h"
namespace marriage
{
struct TWeddingInfo
{
DWORD dwTime;
DWORD dwPID1;
DWORD dwPID2;
TWeddingInfo(DWORD time, DWORD pid1, DWORD pid2)
: dwTime(time),
dwPID1(pid1),
dwPID2(pid2)
{
}
};
struct TWedding
{
DWORD dwTime;
DWORD dwMapIndex;
DWORD dwPID1;
DWORD dwPID2;
TWedding(DWORD time, DWORD dwMapIndex, DWORD pid1, DWORD pid2)
: dwTime(time),
dwMapIndex(dwMapIndex),
dwPID1(pid1),
dwPID2(pid2)
{
}
};
extern bool operator < (const TWedding& lhs, const TWedding& rhs);
extern bool operator > (const TWedding& lhs, const TWedding& rhs);
extern bool operator > (const TWeddingInfo& lhs, const TWeddingInfo& rhs);
struct TMarriage
{
DWORD pid1;
DWORD pid2;
int love_point;
DWORD time;
BYTE is_married;
std::string name1;
std::string name2;
TMarriage(DWORD _pid1, DWORD _pid2, int _love_point, DWORD _time, BYTE _is_married, const char* name1, const char* name2)
: pid1(_pid1), pid2(_pid2), love_point(_love_point), time(_time), is_married(_is_married), name1(name1), name2(name2)
{
}
DWORD GetOther(DWORD PID)
{
if (pid1 == PID)
return pid2;
if (pid2 == PID)
return pid1;
return 0;
}
};
class CManager : public singleton<CManager>
{
public:
CManager();
virtual ~CManager();
bool Initialize();
TMarriage* Get(DWORD dwPlayerID);
bool IsMarried(DWORD dwPlayerID)
{
return Get(dwPlayerID) != NULL;
}
//void Reserve(DWORD dwPID1, DWORD dwPID2);
void Add(DWORD dwPID1, DWORD dwPID2, const char* szName1, const char* szName2);
void Remove(DWORD dwPID1, DWORD dwPID2);
void Update(DWORD dwPID1, DWORD dwPID2, INT iLovePoint, BYTE byMarried);
void EngageToMarriage(DWORD dwPID1, DWORD dwPID2);
void ReadyWedding(DWORD dwMapIndex, DWORD dwPID1, DWORD dwPID2);
void EndWedding(DWORD dwPID1, DWORD dwPID2);
void OnSetup(CPeer* peer);
void Update();
private:
std::set<TMarriage *> m_Marriages;
std::map<DWORD, TMarriage *> m_MarriageByPID;
std::priority_queue<TWedding, std::vector<TWedding>, std::greater<TWedding> > m_pqWeddingStart;
std::priority_queue<TWeddingInfo, std::vector<TWeddingInfo>, std::greater<TWeddingInfo> > m_pqWeddingEnd;
std::map<std::pair<DWORD, DWORD>, TWedding> m_mapRunningWedding;
};
}
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,291 @@
#include "stdafx.h"
#include "Monarch.h"
#include "../../common/utils.h"
#include "Main.h"
#include "ClientManager.h"
extern int g_test_server;
CMonarch::CMonarch()
{
memset(&m_MonarchInfo, 0, sizeof(MonarchInfo));
}
CMonarch::~CMonarch()
{
}
bool CMonarch::VoteMonarch(DWORD pid, DWORD selectdpid)
{
MAP_MONARCHELECTION::iterator it = m_map_MonarchElection.find(pid);
if (it == m_map_MonarchElection.end())
{
MonarchElectionInfo * p = new MonarchElectionInfo;
p->pid = pid;
p->selectedpid= selectdpid;
m_map_MonarchElection.emplace(pid, p);
char szQuery[256];
snprintf(szQuery, sizeof(szQuery),
"INSERT INTO monarch_election(pid, selectedpid, electiondata) VALUES(%d, %d, now())", pid, selectdpid);
CDBManager::instance().AsyncQuery(szQuery);
return 1;
}
return 0;
}
void CMonarch::ElectMonarch()
{
int size = GetVecMonarchCandidacy().size();
int * s = new int[size];
itertype(m_map_MonarchElection) it = m_map_MonarchElection.begin();
int idx = 0;
for (; it != m_map_MonarchElection.end(); ++it)
{
if ((idx = GetCandidacyIndex(it->second->pid)) < 0)
continue;
++s[idx];
if (g_test_server)
sys_log (0, "[MONARCH_VOTE] pid(%d) come to vote candidacy pid(%d)", it->second->pid, m_vec_MonarchCandidacy[idx].pid);
}
delete [] s;
}
bool CMonarch::IsCandidacy(DWORD pid)
{
VEC_MONARCHCANDIDACY::iterator it = m_vec_MonarchCandidacy.begin();
for (; it != m_vec_MonarchCandidacy.end(); ++it)
{
if (it->pid == pid)
return false;
}
return true;
}
bool CMonarch::AddCandidacy(DWORD pid, const char * name)
{
if (IsCandidacy(pid) == false)
return false;
MonarchCandidacy info;
info.pid = pid;
strlcpy(info.name, name, sizeof(info.name));
m_vec_MonarchCandidacy.emplace_back(info);
char szQuery[256];
snprintf(szQuery, sizeof(szQuery),
"INSERT INTO monarch_candidacy(pid, date) VALUES(%d, now())", pid);
CDBManager::instance().AsyncQuery(szQuery);
return true;
}
bool CMonarch::DelCandidacy(const char * name)
{
itertype(m_vec_MonarchCandidacy) it = m_vec_MonarchCandidacy.begin();
for (; it != m_vec_MonarchCandidacy.end(); ++it)
{
if (0 == strncmp(it->name, name, sizeof(it->name)))
{
char szQuery[256];
snprintf(szQuery, sizeof(szQuery),
"DELETE FROM monarch_candidacy WHERE pid=%d ", it->pid);
CDBManager::instance().AsyncQuery(szQuery);
m_vec_MonarchCandidacy.erase (it);
return true;
}
}
return false;
}
bool CMonarch::IsMonarch(int Empire, DWORD pid)
{
if (m_MonarchInfo.pid[Empire] != pid)
return false;
return true;
}
bool CMonarch::AddMoney(int Empire, int64_t Money)
{
if (m_MonarchInfo.money[Empire] + Money > 2000000000)
return true;
m_MonarchInfo.money[Empire] += Money;
int64_t Money64 = m_MonarchInfo.money[Empire];
char szQuery[1024];
snprintf(szQuery, sizeof(szQuery), "UPDATE monarch SET money=%lld WHERE empire=%d", Money64, Empire);
CDBManager::instance().AsyncQuery(szQuery);
return true;
}
bool CMonarch::DecMoney(int Empire, int64_t Money)
{
if (m_MonarchInfo.money[Empire] - Money < 0)
return false;
m_MonarchInfo.money[Empire] -= Money;
int64_t Money64 = m_MonarchInfo.money[Empire];
char szQuery[1024];
snprintf(szQuery, sizeof(szQuery), "UPDATE monarch SET money=%lld WHERE empire=%d", Money64, Empire);
CDBManager::instance().AsyncQuery(szQuery);
return true;
}
bool CMonarch::TakeMoney(int Empire, DWORD pid, int64_t Money)
{
if (IsMonarch(Empire, pid) == false)
return false;
if (m_MonarchInfo.money[Empire] < Money)
return false;
m_MonarchInfo.money[Empire] -= Money;
char szQuery[1024];
snprintf(szQuery, sizeof(szQuery),
"UPDATE monarch SET money=%lld WHERE empire=%d", m_MonarchInfo.money[Empire], Empire);
CDBManager::instance().AsyncQuery(szQuery);
if (g_test_server)
sys_log(0, "[MONARCH] Take money empire(%d) money(%lld)", Empire, m_MonarchInfo.money[Empire]);
return true;
}
bool CMonarch::LoadMonarch()
{
MonarchInfo * p = &m_MonarchInfo;
char szQuery[256];
snprintf(szQuery, sizeof(szQuery), "SELECT a.empire, a.pid, b.name, a.money, a.windate FROM monarch a, player%s b WHERE a.pid=b.id", GetTablePostfix());
auto pMsg = CDBManager::instance().DirectQuery(szQuery, SQL_PLAYER);
if (pMsg->Get()->uiNumRows == 0)
return false;
MYSQL_ROW row;
while ((row = mysql_fetch_row(pMsg->Get()->pSQLResult)) != nullptr)
{
int idx = 0;
int Empire = 0; str_to_number(Empire, row[idx++]);
str_to_number(p->pid[Empire], row[idx++]);
strlcpy(p->name[Empire], row[idx++], sizeof(p->name[Empire]));
str_to_number(p->money[Empire], row[idx++]);
strlcpy(p->date[Empire], row[idx++], sizeof(p->date[Empire]));
if (g_test_server)
sys_log(0, "[LOAD_MONARCH] Empire %d pid %d money %lld windate %s", Empire, p->pid[Empire], p->money[Empire], p->date[Empire]);
}
return true;
}
bool CMonarch::SetMonarch(const char * name)
{
MonarchInfo * p = &m_MonarchInfo;
char szQuery[256];
snprintf(szQuery, sizeof(szQuery), "SELECT player_index.empire, player.id, player.name, player.gold FROM player JOIN player_index ON player_index.id = player.account_id WHERE player.name = '%s'", name);
auto pMsg = CDBManager::instance().DirectQuery(szQuery, SQL_PLAYER);
if (pMsg->Get()->uiNumRows == 0)
return false;
MYSQL_ROW row;
int Empire = 0;
while ((row = mysql_fetch_row(pMsg->Get()->pSQLResult)) != nullptr)
{
int idx = 0;
str_to_number(Empire, row[idx++]);
str_to_number(p->pid[Empire], row[idx++]);
strlcpy(p->name[Empire], row[idx++], sizeof(p->name[Empire]));
p->money[Empire] = atoll(row[idx++]);
if (g_test_server)
sys_log(0, "[Set_MONARCH] Empire %d pid %d money %lld windate %s", Empire, p->pid[Empire], p->money[Empire], p->date[Empire]);
}
snprintf(szQuery, sizeof(szQuery),
"REPLACE INTO monarch (empire, name, windate, money) VALUES(%d, %d, now(), %lld)", Empire, p->pid[Empire], p->money[Empire]);
CDBManager::instance().AsyncQuery(szQuery, SQL_PLAYER);
return true;
}
bool CMonarch::DelMonarch(int Empire)
{
char szQuery[256];
snprintf(szQuery, sizeof(szQuery), "DELETE FROM monarch WHERE empire=%d", Empire);
auto pMsg = CDBManager::instance().DirectQuery(szQuery, SQL_PLAYER);
if (pMsg->Get()->uiNumRows == 0)
return false;
memset(m_MonarchInfo.name[Empire], 0, sizeof(m_MonarchInfo.name[Empire]));
m_MonarchInfo.money[Empire] = 0;
m_MonarchInfo.pid[Empire] = 0;
return true;
}
bool CMonarch::DelMonarch(const char * name)
{
for (int n = 1; n < 4; ++n)
{
if (0 == strncmp(m_MonarchInfo.name[n], name, sizeof(m_MonarchInfo.name[n])))
{
char szQuery[256];
int Empire = n;
snprintf(szQuery, sizeof(szQuery), "DELETE FROM monarch WHERE empire=%d", Empire);
auto pMsg = CDBManager::instance().DirectQuery(szQuery, SQL_PLAYER);
if (pMsg->Get()->uiNumRows == 0)
{
sys_err(" DirectQuery failed(%s)", szQuery);
return false;
}
memset(m_MonarchInfo.name[Empire], 0, 32);
m_MonarchInfo.money[Empire] = 0;
m_MonarchInfo.pid[Empire] = 0;
return true;
}
}
return false;
}
int CMonarch::GetCandidacyIndex(DWORD pid)
{
itertype(m_vec_MonarchCandidacy) it = m_vec_MonarchCandidacy.begin();
for (int n = 0; it != m_vec_MonarchCandidacy.end(); ++it, ++n)
{
if (it->pid == pid)
return n;
}
return -1;
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,71 @@
// vim: ts=4 sw=4
#ifndef METIN2_MONARCH_H
#define METIN2_MONARCH_H
#include "../../libthecore/include/stdafx.h"
#include <map>
#include <vector>
#include "../../common/singleton.h"
#include "../../common/tables.h"
class CMonarch : public singleton<CMonarch>
{
public:
typedef std::map<DWORD, MonarchElectionInfo*> MAP_MONARCHELECTION;
typedef std::vector<MonarchCandidacy> VEC_MONARCHCANDIDACY;
CMonarch();
virtual ~CMonarch();
bool VoteMonarch(DWORD pid, DWORD selectedpid);
void ElectMonarch();
bool IsCandidacy(DWORD pid);
bool AddCandidacy(DWORD pid, const char * name);
bool DelCandidacy(const char * name);
bool LoadMonarch();
bool SetMonarch(const char * name);
bool DelMonarch(int Empire);
bool DelMonarch(const char * name);
bool IsMonarch(int Empire, DWORD pid);
bool AddMoney(int Empire, int64_t Money);
bool DecMoney(int Empire, int64_t Money);
bool TakeMoney(int Empire, DWORD pid, int64_t Money);
TMonarchInfo* GetMonarch()
{
return &m_MonarchInfo;
}
VEC_MONARCHCANDIDACY& GetVecMonarchCandidacy()
{
return m_vec_MonarchCandidacy;
}
size_t MonarchCandidacySize()
{
return m_vec_MonarchCandidacy.size();
}
private:
int GetCandidacyIndex(DWORD pid);
MAP_MONARCHELECTION m_map_MonarchElection;
VEC_MONARCHCANDIDACY m_vec_MonarchCandidacy;
TMonarchInfo m_MonarchInfo;
MonarchElectionInfo* GetMonarchElection(DWORD pid)
{
MAP_MONARCHELECTION::iterator it = m_map_MonarchElection.find(pid);
if (it != m_map_MonarchElection.end())
return it->second;
return NULL;
}
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,58 @@
#include "stdafx.h"
#include "MoneyLog.h"
#include "ClientManager.h"
#include "Peer.h"
CMoneyLog::CMoneyLog()
{
}
CMoneyLog::~CMoneyLog()
{
}
void CMoneyLog::Save()
{
CPeer* peer = CClientManager::instance().GetAnyPeer();
if (!peer)
return;
for (BYTE bType = 0; bType < MONEY_LOG_TYPE_MAX_NUM; bType ++)
{
typeof(m_MoneyLogContainer[bType].begin()) it;
for (it = m_MoneyLogContainer[bType].begin(); it != m_MoneyLogContainer[bType].end(); ++it)
{
//bType;
TPacketMoneyLog p;
p.type = bType;
p.vnum = it->first;
p.gold = it->second;
peer->EncodeHeader(HEADER_DG_MONEY_LOG, 0, sizeof(p));
peer->Encode(&p, sizeof(p));
}
m_MoneyLogContainer[bType].clear();
}
/*
CPeer* peer = GetPeer();
peer->
for (BYTE bType = 0; bType < MONEY_LOG_TYPE_MAX_NUM; bType++)
{
//"INSERT INTO money_log%s VALUES('%s', %d, %d, %d)", CClientManager::instance().GetTablePostfix(),
typeof(m_MoneyLogContainer[bType].begin()) it;
for (it = m_MoneyLogContainer[bType].begin(); it != m_MoneyLogContainer[bType].end(); ++it)
{
typeof(it->second.begin())
}
}
for (BYTE bType = 0; bType < MONEY_LOG_TYPE_MAX_NUM; bType++)
m_MoneyLogContainer[bType].clear()
*/
}
void CMoneyLog::AddLog(BYTE bType, DWORD dwVnum, int iGold)
{
m_MoneyLogContainer[bType][dwVnum] += iGold;
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,21 @@
// vim: ts=8 sw=4
#ifndef __INC_MONEY_LOG
#define __INC_MONEY_LOG
#include <map>
class CMoneyLog : public singleton<CMoneyLog>
{
public:
CMoneyLog();
virtual ~CMoneyLog();
void Save();
void AddLog(BYTE bType, DWORD dwVnum, int iGold);
private:
std::map<DWORD, int> m_MoneyLogContainer[MONEY_LOG_TYPE_MAX_NUM];
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,55 @@
#include "stdafx.h"
#include "NetBase.h"
#include "Config.h"
#include "ClientManager.h"
LPFDWATCH CNetBase::m_fdWatcher = NULL;
CNetBase::CNetBase()
{
}
CNetBase::~CNetBase()
{
}
CNetPoller::CNetPoller()
{
}
CNetPoller::~CNetPoller()
{
Destroy();
}
bool CNetPoller::Create()
{
sys_log(1, "NetPoller::Create()");
if (m_fdWatcher)
return true;
m_fdWatcher = fdwatch_new(512);
if (!m_fdWatcher)
{
Destroy();
return false;
}
return true;
}
void CNetPoller::Destroy()
{
sys_log(1, "NetPoller::Destroy()");
if (m_fdWatcher)
{
fdwatch_delete(m_fdWatcher);
m_fdWatcher = NULL;
}
thecore_destroy();
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,26 @@
// vim: ts=8 sw=4
#ifndef __INC_NETWORKBASE_H__
#define __INC_NETWORKBASE_H__
class CNetBase
{
public:
CNetBase();
virtual ~CNetBase();
protected:
static LPFDWATCH m_fdWatcher;
};
class CNetPoller : public CNetBase, public singleton<CNetPoller>
{
public:
CNetPoller();
virtual ~CNetPoller();
bool Create();
void Destroy();
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,196 @@
#include "stdafx.h"
#include "Peer.h"
#include "ItemIDRangeManager.h"
CPeer::CPeer()
{
m_state = 0;
m_bChannel = 0;
m_dwHandle = 0;
m_dwUserCount = 0;
m_wListenPort = 0;
m_wP2PPort = 0;
memset(m_alMaps, 0, sizeof(m_alMaps));
m_itemRange.dwMin = m_itemRange.dwMax = m_itemRange.dwUsableItemIDMin = 0;
m_itemSpareRange.dwMin = m_itemSpareRange.dwMax = m_itemSpareRange.dwUsableItemIDMin = 0;
}
CPeer::~CPeer()
{
Close();
}
void CPeer::OnAccept()
{
m_state = STATE_PLAYING;
static DWORD current_handle = 0;
m_dwHandle = ++current_handle;
sys_log(0, "Connection accepted. (host: %s handle: %u fd: %d)", m_host, m_dwHandle, m_fd);
}
void CPeer::OnConnect()
{
sys_log(0, "Connection established. (host: %s handle: %u fd: %d)", m_host, m_dwHandle, m_fd);
m_state = STATE_PLAYING;
}
void CPeer::OnClose()
{
m_state = STATE_CLOSE;
sys_log(0, "Connection closed. (host: %s)", m_host);
sys_log(0, "ItemIDRange: returned. %u ~ %u", m_itemRange.dwMin, m_itemRange.dwMax);
CItemIDRangeManager::instance().UpdateRange(m_itemRange.dwMin, m_itemRange.dwMax);
m_itemRange.dwMin = 0;
m_itemRange.dwMax = 0;
m_itemRange.dwUsableItemIDMin = 0;
}
DWORD CPeer::GetHandle()
{
return m_dwHandle;
}
DWORD CPeer::GetUserCount()
{
return m_dwUserCount;
}
void CPeer::SetUserCount(DWORD dwCount)
{
m_dwUserCount = dwCount;
}
bool CPeer::PeekPacket(int & iBytesProceed, BYTE & header, DWORD & dwHandle, DWORD & dwLength, const char ** data)
{
if (GetRecvLength() < iBytesProceed + 9)
return false;
const char * buf = (const char *) GetRecvBuffer();
buf += iBytesProceed;
header = *(buf++);
dwHandle = *((DWORD *) buf);
buf += sizeof(DWORD);
dwLength = *((DWORD *) buf);
buf += sizeof(DWORD);
//sys_log(0, "%d header %d handle %u length %u", GetRecvLength(), header, dwHandle, dwLength);
if (iBytesProceed + dwLength + 9 > (DWORD) GetRecvLength())
{
sys_log(0, "PeekPacket: not enough buffer size: len %u, recv %d",
9+dwLength, GetRecvLength()-iBytesProceed);
return false;
}
*data = buf;
iBytesProceed += dwLength + 9;
return true;
}
void CPeer::EncodeHeader(BYTE header, DWORD dwHandle, DWORD dwSize)
{
HEADER h;
sys_log(1, "EncodeHeader %u handle %u size %u", header, dwHandle, dwSize);
h.bHeader = header;
h.dwHandle = dwHandle;
h.dwSize = dwSize;
Encode(&h, sizeof(HEADER));
}
void CPeer::EncodeReturn(BYTE header, DWORD dwHandle)
{
EncodeHeader(header, dwHandle, 0);
}
int CPeer::Send()
{
if (m_state == STATE_CLOSE)
return -1;
return (CPeerBase::Send());
}
void CPeer::SetP2PPort(WORD wPort)
{
m_wP2PPort = wPort;
}
void CPeer::SetMaps(long * pl)
{
thecore_memcpy(m_alMaps, pl, sizeof(m_alMaps));
}
void CPeer::SendSpareItemIDRange()
{
if (m_itemSpareRange.dwMin == 0 || m_itemSpareRange.dwMax == 0 || m_itemSpareRange.dwUsableItemIDMin == 0)
{
EncodeHeader(HEADER_DG_ACK_SPARE_ITEM_ID_RANGE, 0, sizeof(TItemIDRangeTable));
Encode(&m_itemSpareRange, sizeof(TItemIDRangeTable));
}
else
{
SetItemIDRange(m_itemSpareRange);
if (SetSpareItemIDRange(CItemIDRangeManager::instance().GetRange()) == false)
{
sys_log(0, "ItemIDRange: spare range set error");
m_itemSpareRange.dwMin = m_itemSpareRange.dwMax = m_itemSpareRange.dwUsableItemIDMin = 0;
}
EncodeHeader(HEADER_DG_ACK_SPARE_ITEM_ID_RANGE, 0, sizeof(TItemIDRangeTable));
Encode(&m_itemSpareRange, sizeof(TItemIDRangeTable));
}
}
bool CPeer::SetItemIDRange(TItemIDRangeTable itemRange)
{
if (itemRange.dwMin == 0 || itemRange.dwMax == 0 || itemRange.dwUsableItemIDMin == 0) return false;
m_itemRange = itemRange;
sys_log(0, "ItemIDRange: SET %s %u ~ %u start: %u", GetPublicIP(), m_itemRange.dwMin, m_itemRange.dwMax, m_itemRange.dwUsableItemIDMin);
return true;
}
bool CPeer::SetSpareItemIDRange(TItemIDRangeTable itemRange)
{
if (itemRange.dwMin == 0 || itemRange.dwMax == 0 || itemRange.dwUsableItemIDMin == 0) return false;
m_itemSpareRange = itemRange;
sys_log(0, "ItemIDRange: SPARE SET %s %u ~ %u start: %u", GetPublicIP(), m_itemSpareRange.dwMin, m_itemSpareRange.dwMax,
m_itemSpareRange.dwUsableItemIDMin);
return true;
}
bool CPeer::CheckItemIDRangeCollision(TItemIDRangeTable itemRange)
{
if (m_itemRange.dwMin < itemRange.dwMax && m_itemRange.dwMax > itemRange.dwMin)
{
sys_err("ItemIDRange: Collision!! this %u ~ %u check %u ~ %u",
m_itemRange.dwMin, m_itemRange.dwMax, itemRange.dwMin, itemRange.dwMax);
return false;
}
if (m_itemSpareRange.dwMin < itemRange.dwMax && m_itemSpareRange.dwMax > itemRange.dwMin)
{
sys_err("ItemIDRange: Collision with spare range this %u ~ %u check %u ~ %u",
m_itemSpareRange.dwMin, m_itemSpareRange.dwMax, itemRange.dwMin, itemRange.dwMax);
return false;
}
return true;
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,81 @@
// vim: ts=8 sw=4
#ifndef __INC_PEER_H__
#define __INC_PEER_H__
#include "PeerBase.h"
#include "../../common/CommonDefines.h"
class CPeer : public CPeerBase
{
protected:
virtual void OnAccept();
virtual void OnClose();
virtual void OnConnect();
public:
#pragma pack(1)
typedef struct _header
{
BYTE bHeader;
DWORD dwHandle;
DWORD dwSize;
} HEADER;
#pragma pack()
enum EState
{
STATE_CLOSE = 0,
STATE_PLAYING = 1
};
CPeer();
virtual ~CPeer();
void EncodeHeader(BYTE header, DWORD dwHandle, DWORD dwSize);
bool PeekPacket(int & iBytesProceed, BYTE & header, DWORD & dwHandle, DWORD & dwLength, const char ** data);
void EncodeReturn(BYTE header, DWORD dwHandle);
void ProcessInput();
int Send();
DWORD GetHandle();
DWORD GetUserCount();
void SetUserCount(DWORD dwCount);
void SetPublicIP(const char * ip) { m_stPublicIP = ip; }
const char * GetPublicIP() { return m_stPublicIP.c_str(); }
void SetChannel(BYTE bChannel) { m_bChannel = bChannel; }
BYTE GetChannel() { return m_bChannel; }
void SetListenPort(WORD wPort) { m_wListenPort = wPort; }
WORD GetListenPort() { return m_wListenPort; }
void SetP2PPort(WORD wPort);
WORD GetP2PPort() { return m_wP2PPort; }
void SetMaps(long* pl);
long * GetMaps() { return &m_alMaps[0]; }
bool SetItemIDRange(TItemIDRangeTable itemRange);
bool SetSpareItemIDRange(TItemIDRangeTable itemRange);
bool CheckItemIDRangeCollision(TItemIDRangeTable itemRange);
void SendSpareItemIDRange();
private:
int m_state;
BYTE m_bChannel;
DWORD m_dwHandle;
DWORD m_dwUserCount;
WORD m_wListenPort;
WORD m_wP2PPort;
long m_alMaps[MAP_ALLOW_LIMIT];
TItemIDRangeTable m_itemRange;
TItemIDRangeTable m_itemSpareRange;
std::string m_stPublicIP;
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,230 @@
#include "stdafx.h"
#include "PeerBase.h"
#include "../../common/CommonDefines.h"
CPeerBase::CPeerBase() : m_fd(INVALID_SOCKET), m_BytesRemain(0), m_outBuffer(NULL), m_inBuffer(NULL)
{
}
CPeerBase::~CPeerBase()
{
Destroy();
}
void CPeerBase::Disconnect()
{
if (m_fd != INVALID_SOCKET)
{
fdwatch_del_fd(m_fdWatcher, m_fd);
socket_close(m_fd);
m_fd = INVALID_SOCKET;
}
}
void CPeerBase::Destroy()
{
Disconnect();
if (m_outBuffer)
{
buffer_delete(m_outBuffer);
m_outBuffer = NULL;
}
if (m_inBuffer)
{
buffer_delete(m_inBuffer);
m_inBuffer = NULL;
}
}
bool CPeerBase::Accept(socket_t fd_accept)
{
struct sockaddr_in peer;
if ((m_fd = socket_accept(fd_accept, &peer)) == INVALID_SOCKET)
{
Destroy();
return false;
}
#ifdef ENABLE_PORT_SECURITY
// refuse if remote host != localhost (only the same machine must be able to connect in here)
std::string targetIP = inet_ntoa(peer.sin_addr);
if (targetIP.rfind("127.0.0.1", 0) && targetIP.rfind("192.168.", 0) && targetIP.rfind("10.", 0))
{
sys_log(0, "BLOCK CONNECTION FROM %s", inet_ntoa(peer.sin_addr));
Destroy();
return false;
}
#endif
//socket_block(m_fd);
socket_sndbuf(m_fd, 233016);
socket_rcvbuf(m_fd, 233016);
strlcpy(m_host, inet_ntoa(peer.sin_addr), sizeof(m_host));
m_wPort = peer.sin_port;
m_outBuffer = buffer_new(DEFAULT_PACKET_BUFFER_SIZE);
m_inBuffer = buffer_new(MAX_INPUT_LEN);
if (!m_outBuffer || !m_inBuffer)
{
Destroy();
return false;
}
fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_READ, false);
OnAccept();
sys_log(0, "ACCEPT FROM %s", inet_ntoa(peer.sin_addr));
return true;
}
bool CPeerBase::Connect(const char* host, WORD port)
{
strlcpy(m_host, host, sizeof(m_host));
m_wPort = port;
if ((m_fd = socket_connect(host, port)) == INVALID_SOCKET)
return false;
m_outBuffer = buffer_new(DEFAULT_PACKET_BUFFER_SIZE);
if (!m_outBuffer)
{
Destroy();
return false;
}
fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_READ, false);
OnConnect();
return true;
}
void CPeerBase::Close()
{
OnClose();
}
void CPeerBase::EncodeBYTE(BYTE b)
{
if (!m_outBuffer)
{
sys_err("Not ready to write");
return;
}
buffer_write(m_outBuffer, &b, 1);
fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_WRITE, true);
}
void CPeerBase::EncodeWORD(WORD w)
{
if (!m_outBuffer)
{
sys_err("Not ready to write");
return;
}
buffer_write(m_outBuffer, &w, 2);
fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_WRITE, true);
}
void CPeerBase::EncodeDWORD(DWORD dw)
{
if (!m_outBuffer)
{
sys_err("Not ready to write");
return;
}
buffer_write(m_outBuffer, &dw, 4);
fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_WRITE, true);
}
void CPeerBase::Encode(const void* data, DWORD size)
{
if (!m_outBuffer)
{
sys_err("Not ready to write");
return;
}
buffer_write(m_outBuffer, data, size);
fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_WRITE, true);
}
int CPeerBase::Recv()
{
if (!m_inBuffer)
{
sys_err("input buffer nil");
return -1;
}
buffer_adjust_size(m_inBuffer, MAX_INPUT_LEN >> 2);
int bytes_to_read = buffer_has_space(m_inBuffer);
ssize_t bytes_read = socket_read(m_fd, (char *) buffer_write_peek(m_inBuffer), bytes_to_read);
if (bytes_read < 0)
{
sys_err("socket_read failed %s", strerror(errno));
return -1;
}
else if (bytes_read == 0)
return 0;
buffer_write_proceed(m_inBuffer, bytes_read);
m_BytesRemain = buffer_size(m_inBuffer);
return 1;
}
void CPeerBase::RecvEnd(int proceed_bytes)
{
buffer_read_proceed(m_inBuffer, proceed_bytes);
m_BytesRemain = buffer_size(m_inBuffer);
}
int CPeerBase::GetRecvLength()
{
return m_BytesRemain;
}
const void * CPeerBase::GetRecvBuffer()
{
return buffer_read_peek(m_inBuffer);
}
int CPeerBase::GetSendLength()
{
return buffer_size(m_outBuffer);
}
int CPeerBase::Send()
{
if (buffer_size(m_outBuffer) <= 0)
return 0;
int iBufferLeft = fdwatch_get_buffer_size(m_fdWatcher, m_fd);
int iBytesToWrite = MIN(iBufferLeft, buffer_size(m_outBuffer));
if (iBytesToWrite == 0)
return 0;
int result = socket_write(m_fd, (const char *) buffer_read_peek(m_outBuffer), iBytesToWrite);
if (result == 0)
{
buffer_read_proceed(m_outBuffer, iBytesToWrite);
if (buffer_size(m_outBuffer) != 0)
fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_WRITE, true);
}
return (result);
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,73 @@
// vim: ts=8 sw=4
#ifndef __INC_PEERBASE_H__
#define __INC_PEERBASE_H__
#include "NetBase.h"
class CPeerBase : public CNetBase
{
public:
enum
{
MAX_HOST_LENGTH = 30,
MAX_INPUT_LEN = 1024 * 1024 * 2,
DEFAULT_PACKET_BUFFER_SIZE = 1024 * 1024 * 2
};
protected:
virtual void OnAccept() = 0;
virtual void OnConnect() = 0;
virtual void OnClose() = 0;
public:
bool Accept(socket_t accept_fd);
bool Connect(const char* host, WORD port);
void Close();
public:
CPeerBase();
virtual ~CPeerBase();
void Disconnect();
void Destroy();
socket_t GetFd() { return m_fd; }
void EncodeBYTE(BYTE b);
void EncodeWORD(WORD w);
void EncodeDWORD(DWORD dw);
void Encode(const void* data, DWORD size);
int Send();
template<typename T, std::enable_if_t<utils::IsRawV<T>>* = nullptr>
void Encode(const T& c_pvData) {
Encode(&c_pvData, sizeof(T));
}
template<typename C, std::enable_if_t<utils::IsContiguousV<C>>* = nullptr>
void Encode(const C& v) {
Encode(v.data(), v.size() * sizeof(typename C::value_type));
}
int Recv();
void RecvEnd(int proceed_bytes);
int GetRecvLength();
const void * GetRecvBuffer();
int GetSendLength();
const char * GetHost() { return m_host; }
WORD GetPort() { return m_wPort; }
protected:
char m_host[MAX_HOST_LENGTH + 1];
socket_t m_fd;
WORD m_wPort;
private:
int m_BytesRemain;
LPBUFFER m_outBuffer;
LPBUFFER m_inBuffer;
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,283 @@
#include "stdafx.h"
#include "PrivManager.h"
#include "ClientManager.h"
const int CHARACTER_GOOD_PRIV_DURATION = 2*60*60;
const int CHARACTER_BAD_PRIV_DURATION = 60*60;
CPrivManager::CPrivManager()
{
for (int type = 0; type < MAX_PRIV_NUM; ++type)
{
for (int empire = 0; empire < EMPIRE_MAX_NUM; ++empire)
m_aaPrivEmpire[type][empire] = 0;
}
}
CPrivManager::~CPrivManager()
{
}
//
//
void CPrivManager::Update()
{
time_t now = CClientManager::instance().GetCurrentTime();
while (!m_pqPrivGuild.empty() && m_pqPrivGuild.top().first <= now)
{
TPrivGuildData* p = m_pqPrivGuild.top().second;
m_pqPrivGuild.pop();
if (p->value != 0 && !p->bRemoved)
{
typeof(m_aPrivGuild[p->type].begin()) it = m_aPrivGuild[p->type].find(p->guild_id);
// ADD_GUILD_PRIV_TIME
if (it != m_aPrivGuild[p->type].end() && it->second == p) {
m_aPrivGuild[p->type].erase(it);
SendChangeGuildPriv(p->guild_id, p->type, 0, 0);
// END_OF_ADD_GUILD_PRIV_TIME
}
}
delete p;
}
while (!m_pqPrivEmpire.empty() && m_pqPrivEmpire.top().first <= now)
{
TPrivEmpireData* p = (m_pqPrivEmpire.top().second);
m_pqPrivEmpire.pop();
if (p->value != 0 && !p->bRemoved)
{
SendChangeEmpirePriv(p->empire, p->type, 0, 0);
m_aaPrivEmpire[p->type][p->empire] = 0;
}
delete p;
}
while (!m_pqPrivChar.empty() && m_pqPrivChar.top().first <= now)
{
TPrivCharData* p = (m_pqPrivChar.top().second);
m_pqPrivChar.pop();
if (!p->bRemoved)
{
// TODO send packet
SendChangeCharPriv(p->pid, p->type, 0);
typeof(m_aPrivChar[p->type].begin()) it = m_aPrivChar[p->type].find(p->pid);
if (it != m_aPrivChar[p->type].end())
m_aPrivChar[p->type].erase(it);
}
delete p;
}
}
void CPrivManager::AddCharPriv(DWORD pid, BYTE type, int value)
{
if (MAX_PRIV_NUM <= type)
{
sys_err("PRIV_MANAGER: AddCharPriv: wrong char priv type(%u) recved", type);
return;
}
typeof(m_aPrivChar[type].begin()) it = m_aPrivChar[type].find(pid);
if (it != m_aPrivChar[type].end())
return;
if (!value)
return;
time_t now = CClientManager::instance().GetCurrentTime();
TPrivCharData* p = new TPrivCharData(type, value, pid);
int iDuration = CHARACTER_BAD_PRIV_DURATION;
if (value > 0)
iDuration = CHARACTER_GOOD_PRIV_DURATION;
m_pqPrivChar.push(std::make_pair(now+iDuration, p));
m_aPrivChar[type].emplace(pid, p);
// TODO send packet
sys_log(0, "AddCharPriv %d %d %d", pid, type, value);
SendChangeCharPriv(pid, type, value);
}
//
//
void CPrivManager::AddGuildPriv(DWORD guild_id, BYTE type, int value, time_t duration_sec)
{
if (MAX_PRIV_NUM <= type)
{
sys_err("PRIV_MANAGER: AddGuildPriv: wrong guild priv type(%u) recved", type);
return;
}
typeof(m_aPrivGuild[type].begin()) it = m_aPrivGuild[type].find(guild_id);
time_t now = CClientManager::instance().GetCurrentTime();
time_t end = now + duration_sec;
TPrivGuildData * p = new TPrivGuildData(type, value, guild_id, end);
m_pqPrivGuild.push(std::make_pair(end, p));
// ADD_GUILD_PRIV_TIME
if (it != m_aPrivGuild[type].end())
it->second = p;
else
m_aPrivGuild[type].emplace(guild_id, p);
SendChangeGuildPriv(guild_id, type, value, end);
// END_OF_ADD_GUILD_PRIV_TIME
sys_log(0, "Guild Priv guild(%d) type(%d) value(%d) duration_sec(%d)", guild_id, type, value, duration_sec);
}
void CPrivManager::AddEmpirePriv(BYTE empire, BYTE type, int value, time_t duration_sec)
{
if (MAX_PRIV_NUM <= type)
{
sys_err("PRIV_MANAGER: AddEmpirePriv: wrong empire priv type(%u) recved", type);
return;
}
if (duration_sec < 0)
duration_sec = 0;
time_t now = CClientManager::instance().GetCurrentTime();
time_t end = now+duration_sec;
{
if (m_aaPrivEmpire[type][empire])
m_aaPrivEmpire[type][empire]->bRemoved = true;
}
TPrivEmpireData * p = new TPrivEmpireData(type, value, empire, end);
m_pqPrivEmpire.push(std::make_pair(end, p));
m_aaPrivEmpire[type][empire] = p;
// ADD_EMPIRE_PRIV_TIME
SendChangeEmpirePriv(empire, type, value, end);
// END_OF_ADD_EMPIRE_PRIV_TIME
sys_log(0, "Empire Priv empire(%d) type(%d) value(%d) duration_sec(%d)", empire, type, value, duration_sec);
}
struct FSendChangeGuildPriv
{
FSendChangeGuildPriv(DWORD guild_id, BYTE type, int value, time_t end_time_sec)
{
p.guild_id = guild_id;
p.type = type;
p.value = value;
p.bLog = 1;
// ADD_GUILD_PRIV_TIME
p.end_time_sec = end_time_sec;
// END_OF_ADD_GUILD_PRIV_TIME
}
void operator() (CPeer* peer)
{
peer->EncodeHeader(HEADER_DG_CHANGE_GUILD_PRIV, 0, sizeof(TPacketDGChangeGuildPriv));
peer->Encode(&p, sizeof(TPacketDGChangeGuildPriv));
p.bLog = 0;
}
TPacketDGChangeGuildPriv p;
};
struct FSendChangeEmpirePriv
{
FSendChangeEmpirePriv(BYTE empire, BYTE type, int value, time_t end_time_sec)
{
p.empire = empire;
p.type = type;
p.value = value;
p.bLog = 1;
// ADD_EMPIRE_PRIV_TIME
p.end_time_sec = end_time_sec;
// END_OF_ADD_EMPIRE_PRIV_TIME
}
void operator ()(CPeer* peer)
{
peer->EncodeHeader(HEADER_DG_CHANGE_EMPIRE_PRIV, 0, sizeof(TPacketDGChangeEmpirePriv));
peer->Encode(&p, sizeof(TPacketDGChangeEmpirePriv));
p.bLog = 0;
}
TPacketDGChangeEmpirePriv p;
};
struct FSendChangeCharPriv
{
FSendChangeCharPriv(DWORD pid, BYTE type, int value)
{
p.pid = pid;
p.type = type;
p.value = value;
p.bLog = 1;
}
void operator()(CPeer* peer)
{
peer->EncodeHeader(HEADER_DG_CHANGE_CHARACTER_PRIV, 0, sizeof(TPacketDGChangeCharacterPriv));
peer->Encode(&p, sizeof(TPacketDGChangeCharacterPriv));
p.bLog = 0;
}
TPacketDGChangeCharacterPriv p;
};
// ADD_GUILD_PRIV_TIME
void CPrivManager::SendChangeGuildPriv(DWORD guild_id, BYTE type, int value, time_t end_time_sec)
{
CClientManager::instance().for_each_peer(FSendChangeGuildPriv(guild_id, type, value, end_time_sec));
}
// END_OF_ADD_GUILD_PRIV_TIME
// ADD_EMPIRE_PRIV_TIME
void CPrivManager::SendChangeEmpirePriv(BYTE empire, BYTE type, int value, time_t end_time_sec)
{
CClientManager::instance().for_each_peer(FSendChangeEmpirePriv(empire, type, value, end_time_sec));
}
// END_OF_ADD_EMPIRE_PRIV_TIME
void CPrivManager::SendChangeCharPriv(DWORD pid, BYTE type, int value)
{
CClientManager::instance().for_each_peer(FSendChangeCharPriv(pid, type, value));
}
void CPrivManager::SendPrivOnSetup(CPeer* peer)
{
for (int i = 1; i < MAX_PRIV_NUM; ++i)
{
for (int e = 0; e < EMPIRE_MAX_NUM; ++e)
{
// ADD_EMPIRE_PRIV_TIME
TPrivEmpireData* pPrivEmpireData = m_aaPrivEmpire[i][e];
if (pPrivEmpireData)
{
FSendChangeEmpirePriv(e, i, pPrivEmpireData->value, pPrivEmpireData->end_time_sec)(peer);
}
// END_OF_ADD_EMPIRE_PRIV_TIME
}
for (typeof(m_aPrivGuild[i].begin()) it = m_aPrivGuild[i].begin(); it != m_aPrivGuild[i].end();++it)
{
// ADD_GUILD_PRIV_TIME
FSendChangeGuildPriv(it->first, i, it->second->value, it->second->end_time_sec)(peer);
// END_OF_ADD_GUILD_PRIV_TIME
}
for (typeof(m_aPrivChar[i].begin()) it = m_aPrivChar[i].begin(); it != m_aPrivChar[i].end(); ++it)
{
FSendChangeCharPriv(it->first, i, it->second->value)(peer);
}
}
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,101 @@
// vim: ts=8 sw=4
#ifndef __INC_PRIV_MANAGER_H
#define __INC_PRIV_MANAGER_H
#include "Peer.h"
#include <queue>
#include <utility>
struct TPrivEmpireData
{
BYTE type;
int value;
bool bRemoved;
BYTE empire;
// ADD_EMPIRE_PRIV_TIME
time_t end_time_sec;
TPrivEmpireData(BYTE type, int value, BYTE empire, time_t end_time_sec)
: type(type), value(value), bRemoved(false), empire(empire), end_time_sec(end_time_sec)
{}
// END_OF_ADD_EMPIRE_PRIV_TIME
};
struct TPrivGuildData
{
BYTE type;
int value;
bool bRemoved;
DWORD guild_id;
// ADD_GUILD_PRIV_TIME
time_t end_time_sec;
TPrivGuildData(BYTE type, int value, DWORD guild_id, time_t _end_time_sec)
: type(type), value(value), bRemoved(false), guild_id(guild_id), end_time_sec(_end_time_sec )
{}
// END_OF_ADD_GUILD_PRIV_TIME
};
struct TPrivCharData
{
BYTE type;
int value;
bool bRemoved;
DWORD pid;
TPrivCharData(BYTE type, int value, DWORD pid)
: type(type), value(value), bRemoved(false), pid(pid)
{}
};
class CPrivManager : public singleton<CPrivManager>
{
public:
CPrivManager();
virtual ~CPrivManager();
// ADD_GUILD_PRIV_TIME
void AddGuildPriv(DWORD guild_id, BYTE type, int value, time_t time_sec);
// END_OF_ADD_GUILD_PRIV_TIME
// ADD_EMPIRE_PRIV_TIME
void AddEmpirePriv(BYTE empire, BYTE type, int value, time_t time_sec);
// END_OF_ADD_EMPIRE_PRIV_TIME
void AddCharPriv(DWORD pid, BYTE type, int value);
void Update();
void SendPrivOnSetup(CPeer* peer);
private:
// ADD_GUILD_PRIV_TIME
void SendChangeGuildPriv(DWORD guild_id, BYTE type, int value, time_t end_time_sec);
// END_OF_ADD_GUILD_PRIV_TIME
// ADD_EMPIRE_PRIV_TIME
void SendChangeEmpirePriv(BYTE empire, BYTE type, int value, time_t end_time_sec);
// END_OF_ADD_EMPIRE_PRIV_TIME
void SendChangeCharPriv(DWORD pid, BYTE type, int value);
typedef std::pair<time_t, TPrivCharData *> stPairChar;
typedef std::pair<time_t, TPrivGuildData*> stPairGuild;
typedef std::pair<time_t, TPrivEmpireData*> stPairEmpire;
std::priority_queue<stPairChar, std::vector<stPairChar>, std::greater<stPairChar> >
m_pqPrivChar;
std::priority_queue<stPairGuild, std::vector<stPairGuild>, std::greater<stPairGuild> >
m_pqPrivGuild;
std::priority_queue<stPairEmpire, std::vector<stPairEmpire>, std::greater<stPairEmpire> >
m_pqPrivEmpire;
TPrivEmpireData* m_aaPrivEmpire[MAX_PRIV_NUM][EMPIRE_MAX_NUM];
std::map<DWORD, TPrivGuildData*> m_aPrivGuild[MAX_PRIV_NUM];
std::map<DWORD, TPrivCharData*> m_aPrivChar[MAX_PRIV_NUM];
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,825 @@
#include "stdafx.h"
#include <math.h>
#include "ProtoReader.h"
#include "CsvReader.h"
#include <sstream>
#include <vector>
#include <unordered_map>
#include <algorithm>
using namespace std;
#define ENABLE_NUMERIC_FIELD
#ifdef ENABLE_NUMERIC_FIELD
bool _IsNumericString(const std::string& trimInputString)
{
if (trimInputString.empty())
return false;
bool isNumber = true;
for (auto& c : trimInputString)
{
if (!std::isdigit(c) && c != '-' && c != '+')
{
isNumber = false;
break;
}
}
return isNumber;
}
#endif
inline string trim_left(const string& str)
{
string::size_type n = str.find_first_not_of(" \t\v\n\r");
return n == string::npos ? str : str.substr(n, str.length());
}
inline string trim_right(const string& str)
{
string::size_type n = str.find_last_not_of(" \t\v\n\r");
return n == string::npos ? str : str.substr(0, n + 1);
}
string trim(const string& str){return trim_left(trim_right(str));}
static string* StringSplit(string strOrigin, string strTok)
{
size_t cutAt;
int index = 0;
string* strResult = new string[30];
while ((cutAt = strOrigin.find_first_of(strTok)) != strOrigin.npos)
{
if (cutAt > 0)
{
strResult[index++] = strOrigin.substr(0, cutAt);
}
strOrigin = strOrigin.substr(cutAt+1);
}
if(strOrigin.length() > 0)
{
strResult[index++] = strOrigin.substr(0, cutAt);
}
for( int i=0;i<index;i++)
{
strResult[i] = trim(strResult[i]);
}
return strResult;
}
static const std::vector<std::string> arItemType = {
"ITEM_NONE", "ITEM_WEAPON",
"ITEM_ARMOR", "ITEM_USE",
"ITEM_AUTOUSE", "ITEM_MATERIAL",
"ITEM_SPECIAL", "ITEM_TOOL",
"ITEM_LOTTERY", "ITEM_ELK",
"ITEM_METIN", "ITEM_CONTAINER",
"ITEM_FISH", "ITEM_ROD",
"ITEM_RESOURCE", "ITEM_CAMPFIRE",
"ITEM_UNIQUE", "ITEM_SKILLBOOK",
"ITEM_QUEST", "ITEM_POLYMORPH",
"ITEM_TREASURE_BOX", "ITEM_TREASURE_KEY",
"ITEM_SKILLFORGET", "ITEM_GIFTBOX",
"ITEM_PICK", "ITEM_HAIR",
"ITEM_TOTEM", "ITEM_BLEND",
"ITEM_COSTUME", "ITEM_DS",
"ITEM_SPECIAL_DS", "ITEM_EXTRACT",
"ITEM_SECONDARY_COIN",
"ITEM_RING",
"ITEM_BELT",
"ITEM_PET", "ITEM_MEDIUM", // 35,36
"ITEM_GACHA", "ITEM_SOUL" // 37,38
"ITEM_PASSIVE" // 39
};
int get_Item_Type_Value(std::string inputString)
{
#ifdef ENABLE_NUMERIC_FIELD
if (_IsNumericString(inputString))
return std::stoi(inputString);
#endif
auto it = std::find(std::begin(arItemType), std::end(arItemType), inputString);
if (it == std::end(arItemType))
return -1;
return std::distance(std::begin(arItemType), it);
}
static const std::unordered_map<uint32_t, std::vector<std::string>> mapItemSubType {
{1, { "WEAPON_SWORD", "WEAPON_DAGGER", "WEAPON_BOW", "WEAPON_TWO_HANDED",
"WEAPON_BELL", "WEAPON_FAN", "WEAPON_ARROW", "WEAPON_MOUNT_SPEAR", "WEAPON_CLAW", "WEAPON_QUIVER", "WEAPON_BOUQUET"}},
{2, { "ARMOR_BODY", "ARMOR_HEAD", "ARMOR_SHIELD", "ARMOR_WRIST", "ARMOR_FOOTS",
"ARMOR_NECK", "ARMOR_EAR", "ARMOR_PENDANT", "ARMOR_GLOVE", "ARMOR_NUM_TYPES"}},
{3, { "USE_POTION", "USE_TALISMAN", "USE_TUNING", "USE_MOVE", "USE_TREASURE_BOX", "USE_MONEYBAG", "USE_BAIT",
"USE_ABILITY_UP", "USE_AFFECT", "USE_CREATE_STONE", "USE_SPECIAL", "USE_POTION_NODELAY", "USE_CLEAR",
"USE_INVISIBILITY", "USE_DETACHMENT", "USE_BUCKET", "USE_POTION_CONTINUE", "USE_CLEAN_SOCKET",
"USE_CHANGE_ATTRIBUTE", "USE_ADD_ATTRIBUTE", "USE_ADD_ACCESSORY_SOCKET", "USE_PUT_INTO_ACCESSORY_SOCKET",
"USE_ADD_ATTRIBUTE2", "USE_RECIPE", "USE_CHANGE_ATTRIBUTE2", "USE_BIND", "USE_UNBIND", "USE_TIME_CHARGE_PER", "USE_TIME_CHARGE_FIX", "USE_PUT_INTO_BELT_SOCKET", "USE_PUT_INTO_RING_SOCKET",
"USE_CHANGE_COSTUME_ATTR", "USE_RESET_COSTUME_ATTR", "USE_UNK33", "USE_CHANGE_ATTRIBUTE_PLUS"}},
{4, { "AUTOUSE_POTION", "AUTOUSE_ABILITY_UP", "AUTOUSE_BOMB", "AUTOUSE_GOLD", "AUTOUSE_MONEYBAG", "AUTOUSE_TREASURE_BOX"}},
{5, { "MATERIAL_LEATHER", "MATERIAL_BLOOD", "MATERIAL_ROOT", "MATERIAL_NEEDLE", "MATERIAL_JEWEL",
"MATERIAL_DS_REFINE_NORMAL", "MATERIAL_DS_REFINE_BLESSED", "MATERIAL_DS_REFINE_HOLLY"}},
{6, { "SPECIAL_MAP", "SPECIAL_KEY", "SPECIAL_DOC", "SPECIAL_SPIRIT"}},
{7, { "TOOL_FISHING_ROD"}},
{8, { "LOTTERY_TICKET", "LOTTERY_INSTANT"}},
{10, { "METIN_NORMAL", "METIN_GOLD"}},
{12, { "FISH_ALIVE", "FISH_DEAD"}},
{14, { "RESOURCE_FISHBONE", "RESOURCE_WATERSTONEPIECE", "RESOURCE_WATERSTONE", "RESOURCE_BLOOD_PEARL",
"RESOURCE_BLUE_PEARL", "RESOURCE_WHITE_PEARL", "RESOURCE_BUCKET", "RESOURCE_CRYSTAL", "RESOURCE_GEM",
"RESOURCE_STONE", "RESOURCE_METIN", "RESOURCE_ORE"}},
{16, { "UNIQUE_NONE", "UNIQUE_BOOK", "UNIQUE_SPECIAL_RIDE", "UNIQUE_3", "UNIQUE_4", "UNIQUE_5",
"UNIQUE_6", "UNIQUE_7", "UNIQUE_8", "UNIQUE_9", "USE_SPECIAL"}},
{28, { "COSTUME_BODY", "COSTUME_HAIR", "COSTUME_MOUNT", "COSTUME_ACCE", "COSTUME_WEAPON"}},
{29, { "DS_SLOT1", "DS_SLOT2", "DS_SLOT3", "DS_SLOT4", "DS_SLOT5", "DS_SLOT6"}},
{31, { "EXTRACT_DRAGON_SOUL", "EXTRACT_DRAGON_HEART"}},
{35, { "PET_EGG", "PET_UPBRINGING", "PET_BAG", "PET_FEEDSTUFF", "PET_SKILL",
"PET_SKILL_DEL_BOOK", "PET_NAME_CHANGE", "PET_EXPFOOD", "PET_SKILL_ALL_DEL_BOOK", "PET_EXPFOOD_PER",
"PET_ATTR_DETERMINE", "PET_ATTR_CHANGE", "PET_PAY", "PET_PRIMIUM_FEEDSTUFF"}},
};
int get_Item_SubType_Value(int type_value, std::string inputString)
{
inputString = trim(inputString);
#ifdef ENABLE_NUMERIC_FIELD
if (_IsNumericString(inputString))
return std::stoi(inputString);
#endif
auto itType = mapItemSubType.find(type_value);
if (itType == mapItemSubType.end())
{
sys_err("Type Out of range! (type_value: %d)", type_value);
return -1;
}
auto vecSubtype = itType->second;
auto itSubtype = std::find(vecSubtype.begin(), vecSubtype.end(), inputString);
if (itSubtype == vecSubtype.end())
{
sys_err("Subtype Out of range! (type_value: %d)", type_value);
return -1;
}
return std::distance(vecSubtype.begin(), itSubtype);
}
int get_Item_AntiFlag_Value(string inputString)
{
#ifdef ENABLE_NUMERIC_FIELD
if (_IsNumericString(inputString))
return std::stoi(inputString);
#endif
string arAntiFlag[] = {"ANTI_FEMALE", "ANTI_MALE", "ANTI_MUSA", "ANTI_ASSASSIN", "ANTI_SURA", "ANTI_MUDANG",
"ANTI_GET", "ANTI_DROP", "ANTI_SELL", "ANTI_EMPIRE_A", "ANTI_EMPIRE_B", "ANTI_EMPIRE_C",
"ANTI_SAVE", "ANTI_GIVE", "ANTI_PKDROP", "ANTI_STACK", "ANTI_MYSHOP", "ANTI_SAFEBOX", "ANTI_WOLFMAN",
"ANTI_PET20", "ANTI_PET21"};
int retValue = 0;
string* arInputString = StringSplit(inputString, "|");
for(size_t i=0;i<_countof(arAntiFlag);i++) {
string tempString = arAntiFlag[i];
for (size_t j=0; j<30 ; j++)
{
string tempString2 = arInputString[j];
if (tempString2.compare(tempString)==0) {
retValue = retValue + pow((float)2,(float)i);
}
if(tempString2.compare("") == 0)
break;
}
}
delete []arInputString;
//cout << "AntiFlag : " << antiFlagStr << " -> " << retValue << endl;
return retValue;
}
int get_Item_Flag_Value(string inputString)
{
#ifdef ENABLE_NUMERIC_FIELD
if (_IsNumericString(inputString))
return std::stoi(inputString);
#endif
string arFlag[] = {"ITEM_TUNABLE", "ITEM_SAVE", "ITEM_STACKABLE", "COUNT_PER_1GOLD", "ITEM_SLOW_QUERY", "ITEM_UNIQUE",
"ITEM_MAKECOUNT", "ITEM_IRREMOVABLE", "CONFIRM_WHEN_USE", "QUEST_USE", "QUEST_USE_MULTIPLE",
"QUEST_GIVE", "ITEM_QUEST", "LOG", "STACKABLE", "SLOW_QUERY", "REFINEABLE", "IRREMOVABLE", "ITEM_APPLICABLE"};
int retValue = 0;
string* arInputString = StringSplit(inputString, "|");
for(size_t i=0;i<_countof(arFlag);i++) {
string tempString = arFlag[i];
for (size_t j=0; j<30 ; j++)
{
string tempString2 = arInputString[j];
if (tempString2.compare(tempString)==0) {
retValue = retValue + pow((float)2,(float)i);
}
if(tempString2.compare("") == 0)
break;
}
}
delete []arInputString;
//cout << "Flag : " << flagStr << " -> " << retValue << endl;
return retValue;
}
int get_Item_WearFlag_Value(string inputString)
{
#ifdef ENABLE_NUMERIC_FIELD
if (_IsNumericString(inputString))
return std::stoi(inputString);
#endif
string arWearrFlag[] = {"WEAR_BODY", "WEAR_HEAD", "WEAR_FOOTS", "WEAR_WRIST", "WEAR_WEAPON", "WEAR_NECK", "WEAR_EAR", "WEAR_SHIELD", "WEAR_UNIQUE",
"WEAR_ARROW", "WEAR_HAIR", "WEAR_ABILITY", "WEAR_PENDANT", "WEAR_GLOVE"
};
int retValue = 0;
string* arInputString = StringSplit(inputString, "|");
for(size_t i=0;i<_countof(arWearrFlag);i++) {
string tempString = arWearrFlag[i];
for (size_t j=0; j<30 ; j++)
{
string tempString2 = arInputString[j];
if (tempString2.compare(tempString)==0) {
retValue = retValue + pow((float)2,(float)i);
}
if(tempString2.compare("") == 0)
break;
}
}
delete []arInputString;
//cout << "WearFlag : " << wearFlagStr << " -> " << retValue << endl;
return retValue;
}
int get_Item_Immune_Value(string inputString)
{
#ifdef ENABLE_NUMERIC_FIELD
if (_IsNumericString(inputString))
return std::stoi(inputString);
#endif
string arImmune[] = {"PARA","CURSE","STUN","SLEEP","SLOW","POISON","TERROR"};
int retValue = 0;
string* arInputString = StringSplit(inputString, "|");
for(size_t i=0;i<_countof(arImmune);i++) {
string tempString = arImmune[i];
for (size_t j=0; j<30 ; j++)
{
string tempString2 = arInputString[j];
if (tempString2.compare(tempString)==0) {
retValue = retValue + pow((float)2,(float)i);
}
if(tempString2.compare("") == 0)
break;
}
}
delete []arInputString;
//cout << "Immune : " << immuneStr << " -> " << retValue << endl;
return retValue;
}
int get_Item_LimitType_Value(string inputString)
{
#ifdef ENABLE_NUMERIC_FIELD
if (_IsNumericString(inputString))
return std::stoi(inputString);
#endif
string arLimitType[] = {"LIMIT_NONE", "LEVEL", "STR", "DEX", "INT", "CON", "PC_BANG", "REAL_TIME", "REAL_TIME_FIRST_USE", "TIMER_BASED_ON_WEAR"};
int retInt = -1;
//cout << "LimitType : " << limitTypeStr << " -> ";
for (unsigned int j=0;j<_countof(arLimitType);j++) {
string tempString = arLimitType[j];
string tempInputString = trim(inputString);
if (tempInputString.compare(tempString)==0)
{
//cout << j << " ";
retInt = j;
break;
}
}
//cout << endl;
return retInt;
}
int get_Item_ApplyType_Value(string inputString)
{
#ifdef ENABLE_NUMERIC_FIELD
if (_IsNumericString(inputString))
return std::stoi(inputString);
#endif
string arApplyType[] = {"APPLY_NONE", "APPLY_MAX_HP", "APPLY_MAX_SP", "APPLY_CON", "APPLY_INT", "APPLY_STR", "APPLY_DEX", "APPLY_ATT_SPEED",
"APPLY_MOV_SPEED", "APPLY_CAST_SPEED", "APPLY_HP_REGEN", "APPLY_SP_REGEN", "APPLY_POISON_PCT", "APPLY_STUN_PCT",
"APPLY_SLOW_PCT", "APPLY_CRITICAL_PCT", "APPLY_PENETRATE_PCT", "APPLY_ATTBONUS_HUMAN", "APPLY_ATTBONUS_ANIMAL",
"APPLY_ATTBONUS_ORC", "APPLY_ATTBONUS_MILGYO", "APPLY_ATTBONUS_UNDEAD", "APPLY_ATTBONUS_DEVIL", "APPLY_STEAL_HP",
"APPLY_STEAL_SP", "APPLY_MANA_BURN_PCT", "APPLY_DAMAGE_SP_RECOVER", "APPLY_BLOCK", "APPLY_DODGE", "APPLY_RESIST_SWORD",
"APPLY_RESIST_TWOHAND", "APPLY_RESIST_DAGGER", "APPLY_RESIST_BELL", "APPLY_RESIST_FAN", "APPLY_RESIST_BOW", "APPLY_RESIST_FIRE",
"APPLY_RESIST_ELEC", "APPLY_RESIST_MAGIC", "APPLY_RESIST_WIND", "APPLY_REFLECT_MELEE", "APPLY_REFLECT_CURSE", "APPLY_POISON_REDUCE",
"APPLY_KILL_SP_RECOVER", "APPLY_EXP_DOUBLE_BONUS", "APPLY_GOLD_DOUBLE_BONUS", "APPLY_ITEM_DROP_BONUS", "APPLY_POTION_BONUS",
"APPLY_KILL_HP_RECOVER", "APPLY_IMMUNE_STUN", "APPLY_IMMUNE_SLOW", "APPLY_IMMUNE_FALL", "APPLY_SKILL", "APPLY_BOW_DISTANCE",
"APPLY_ATT_GRADE_BONUS", "APPLY_DEF_GRADE_BONUS", "APPLY_MAGIC_ATT_GRADE", "APPLY_MAGIC_DEF_GRADE", "APPLY_CURSE_PCT",
"APPLY_MAX_STAMINA", "APPLY_ATTBONUS_WARRIOR", "APPLY_ATTBONUS_ASSASSIN", "APPLY_ATTBONUS_SURA", "APPLY_ATTBONUS_SHAMAN",
"APPLY_ATTBONUS_MONSTER", "APPLY_MALL_ATTBONUS", "APPLY_MALL_DEFBONUS", "APPLY_MALL_EXPBONUS", "APPLY_MALL_ITEMBONUS",
"APPLY_MALL_GOLDBONUS", "APPLY_MAX_HP_PCT", "APPLY_MAX_SP_PCT", "APPLY_SKILL_DAMAGE_BONUS", "APPLY_NORMAL_HIT_DAMAGE_BONUS",
"APPLY_SKILL_DEFEND_BONUS", "APPLY_NORMAL_HIT_DEFEND_BONUS", "APPLY_PC_BANG_EXP_BONUS", "APPLY_PC_BANG_DROP_BONUS",
"APPLY_EXTRACT_HP_PCT", "APPLY_RESIST_WARRIOR", "APPLY_RESIST_ASSASSIN", "APPLY_RESIST_SURA", "APPLY_RESIST_SHAMAN",
"APPLY_ENERGY", "APPLY_DEF_GRADE", "APPLY_COSTUME_ATTR_BONUS", "APPLY_MAGIC_ATTBONUS_PER", "APPLY_MELEE_MAGIC_ATTBONUS_PER",
"APPLY_RESIST_ICE", "APPLY_RESIST_EARTH", "APPLY_RESIST_DARK", "APPLY_ANTI_CRITICAL_PCT", "APPLY_ANTI_PENETRATE_PCT",
"APPLY_BLEEDING_REDUCE", "APPLY_BLEEDING_PCT", "APPLY_ATTBONUS_WOLFMAN", "APPLY_RESIST_WOLFMAN", "APPLY_RESIST_CLAW",
"APPLY_ACCEDRAIN_RATE", "APPLY_RESIST_MAGIC_REDUCTION", // 97,98
"APPLY_ENCHANT_ELECT", "APPLY_ENCHANT_FIRE", "APPLY_ENCHANT_ICE", "APPLY_ENCHANT_WIND", "APPLY_ENCHANT_EARTH", "APPLY_ENCHANT_DARK", // 99-104
"APPLY_ATTBONUS_CZ","APPLY_ATTBONUS_INSECT","APPLY_ATTBONUS_DESERT","APPLY_ATTBONUS_SWORD","APPLY_ATTBONUS_TWOHAND", // 105,109
"APPLY_ATTBONUS_DAGGER","APPLY_ATTBONUS_BELL","APPLY_ATTBONUS_FAN","APPLY_ATTBONUS_BOW","APPLY_ATTBONUS_CLAW", "APPLY_RESIST_HUMAN", // 110,115
"APPLY_RESIST_MOUNT_FALL", "APPLY_UNK117", "APPLY_MOUNT" // 116-118
};
int retInt = -1;
//cout << "ApplyType : " << applyTypeStr << " -> ";
for (size_t j=0;j<_countof(arApplyType);j++) {
string tempString = arApplyType[j];
string tempInputString = trim(inputString);
if (tempInputString.compare(tempString)==0)
{
//cout << j << " ";
retInt = j;
break;
}
}
//cout << endl;
return retInt;
}
int get_Mob_Rank_Value(string inputString)
{
#ifdef ENABLE_NUMERIC_FIELD
if (_IsNumericString(inputString))
return std::stoi(inputString);
#endif
string arRank[] = {"PAWN", "S_PAWN", "KNIGHT", "S_KNIGHT", "BOSS", "KING"};
int retInt = -1;
//cout << "Rank : " << rankStr << " -> ";
for (size_t j=0;j<_countof(arRank);j++) {
string tempString = arRank[j];
string tempInputString = trim(inputString);
if (tempInputString.compare(tempString)==0)
{
//cout << j << " ";
retInt = j;
break;
}
}
//cout << endl;
return retInt;
}
int get_Mob_Type_Value(string inputString)
{
#ifdef ENABLE_NUMERIC_FIELD
if (_IsNumericString(inputString))
return std::stoi(inputString);
#endif
string arType[] = { "MONSTER", "NPC", "STONE", "WARP", "DOOR", "BUILDING", "PC", "POLYMORPH_PC", "HORSE", "GOTO"};
int retInt = -1;
//cout << "Type : " << typeStr << " -> ";
for (size_t j=0;j<_countof(arType);j++) {
string tempString = arType[j];
string tempInputString = trim(inputString);
if (tempInputString.compare(tempString)==0)
{
//cout << j << " ";
retInt = j;
break;
}
}
//cout << endl;
return retInt;
}
int get_Mob_BattleType_Value(string inputString)
{
#ifdef ENABLE_NUMERIC_FIELD
if (_IsNumericString(inputString))
return std::stoi(inputString);
#endif
string arBattleType[] = { "MELEE", "RANGE", "MAGIC", "SPECIAL", "POWER", "TANKER", "SUPER_POWER", "SUPER_TANKER"};
int retInt = -1;
//cout << "Battle Type : " << battleTypeStr << " -> ";
for (size_t j=0;j<_countof(arBattleType);j++) {
string tempString = arBattleType[j];
string tempInputString = trim(inputString);
if (tempInputString.compare(tempString)==0)
{
//cout << j << " ";
retInt = j;
break;
}
}
//cout << endl;
return retInt;
}
int get_Mob_Size_Value(string inputString)
{
#ifdef ENABLE_NUMERIC_FIELD
if (_IsNumericString(inputString))
return std::stoi(inputString);
#endif
string arSize[] = { "SMALL", "MEDIUM", "BIG"}; //@fixme201 SAMLL to SMALL
int retInt = 0;
//cout << "Size : " << sizeStr << " -> ";
for (size_t j=0;j<_countof(arSize);j++) {
string tempString = arSize[j];
string tempInputString = trim(inputString);
if (tempInputString.compare(tempString)==0)
{
//cout << j << " ";
retInt = j + 1;
break;
}
}
//cout << endl;
return retInt;
}
int get_Mob_AIFlag_Value(string inputString)
{
#ifdef ENABLE_NUMERIC_FIELD
if (_IsNumericString(inputString))
return std::stoi(inputString);
#endif
string arAIFlag[] = {"AGGR","NOMOVE","COWARD","NOATTSHINSU","NOATTCHUNJO","NOATTJINNO","ATTMOB","BERSERK","STONESKIN","GODSPEED","DEATHBLOW","REVIVE",
};
int retValue = 0;
string* arInputString = StringSplit(inputString, ",");
for (size_t i =0;i<_countof(arAIFlag);i++) {
string tempString = arAIFlag[i];
for (size_t j=0; j<30 ; j++)
{
string tempString2 = arInputString[j];
if (tempString2.compare(tempString)==0) {
retValue = retValue + pow((float)2,(float)i);
}
if(tempString2.compare("") == 0)
break;
}
}
delete []arInputString;
//cout << "AIFlag : " << aiFlagStr << " -> " << retValue << endl;
return retValue;
}
int get_Mob_RaceFlag_Value(string inputString)
{
#ifdef ENABLE_NUMERIC_FIELD
if (_IsNumericString(inputString))
return std::stoi(inputString);
#endif
string arRaceFlag[] = {"ANIMAL","UNDEAD","DEVIL","HUMAN","ORC","MILGYO","INSECT","FIRE","ICE","DESERT","TREE",
"ATT_ELEC","ATT_FIRE","ATT_ICE","ATT_WIND","ATT_EARTH","ATT_DARK","ZODIAC"};
int retValue = 0;
string* arInputString = StringSplit(inputString, ",");
for(size_t i =0;i<_countof(arRaceFlag);i++) {
string tempString = arRaceFlag[i];
for (size_t j=0; j<30 ; j++)
{
string tempString2 = arInputString[j];
if (tempString2.compare(tempString)==0) {
retValue = retValue + pow((float)2,(float)i);
}
if(tempString2.compare("") == 0)
break;
}
}
delete []arInputString;
//cout << "Race Flag : " << raceFlagStr << " -> " << retValue << endl;
return retValue;
}
int get_Mob_ImmuneFlag_Value(string inputString)
{
#ifdef ENABLE_NUMERIC_FIELD
if (_IsNumericString(inputString))
return std::stoi(inputString);
#endif
string arImmuneFlag[] = {"STUN","SLOW","FALL","CURSE","POISON","TERROR", "REFLECT"};
int retValue = 0;
string* arInputString = StringSplit(inputString, ",");
for(size_t i =0;i<_countof(arImmuneFlag);i++) {
string tempString = arImmuneFlag[i];
for (size_t j=0; j<30 ; j++)
{
string tempString2 = arInputString[j];
if (tempString2.compare(tempString)==0) {
retValue = retValue + pow((float)2,(float)i);
}
if(tempString2.compare("") == 0)
break;
}
}
delete []arInputString;
//cout << "Immune Flag : " << immuneFlagStr << " -> " << retValue << endl;
return retValue;
}
#ifndef __DUMP_PROTO__
bool Set_Proto_Mob_Table(TMobTable *mobTable, cCsvTable &csvTable,std::map<int,const char*> &nameMap)
{
int col = 0;
str_to_number(mobTable->dwVnum, csvTable.AsStringByIndex(col++));
strlcpy(mobTable->szName, csvTable.AsStringByIndex(col++), sizeof(mobTable->szName));
auto it = nameMap.find(mobTable->dwVnum);
if (it != nameMap.end()) {
const char * localeName = it->second;
strlcpy(mobTable->szLocaleName, localeName, sizeof(mobTable->szLocaleName));
} else {
strlcpy(mobTable->szLocaleName, mobTable->szName, sizeof(mobTable->szLocaleName));
}
//RANK
int rankValue = get_Mob_Rank_Value(csvTable.AsStringByIndex(col++));
mobTable->bRank = rankValue;
//TYPE
int typeValue = get_Mob_Type_Value(csvTable.AsStringByIndex(col++));
mobTable->bType = typeValue;
//BATTLE_TYPE
int battleTypeValue = get_Mob_BattleType_Value(csvTable.AsStringByIndex(col++));
mobTable->bBattleType = battleTypeValue;
str_to_number(mobTable->bLevel, csvTable.AsStringByIndex(col++));
//SIZE
int sizeValue = get_Mob_Size_Value(csvTable.AsStringByIndex(col++));
mobTable->bSize = sizeValue;
//AI_FLAG
int aiFlagValue = get_Mob_AIFlag_Value(csvTable.AsStringByIndex(col++));
mobTable->dwAIFlag = aiFlagValue;
//mount_capacity;
col++;
//RACE_FLAG
int raceFlagValue = get_Mob_RaceFlag_Value(csvTable.AsStringByIndex(col++));
mobTable->dwRaceFlag = raceFlagValue;
//IMMUNE_FLAG
int immuneFlagValue = get_Mob_ImmuneFlag_Value(csvTable.AsStringByIndex(col++));
mobTable->dwImmuneFlag = immuneFlagValue;
str_to_number(mobTable->bEmpire, csvTable.AsStringByIndex(col++)); //col = 11
strlcpy(mobTable->szFolder, csvTable.AsStringByIndex(col++), sizeof(mobTable->szFolder));
str_to_number(mobTable->bOnClickType, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->bStr, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->bDex, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->bCon, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->bInt, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->dwDamageRange[0], csvTable.AsStringByIndex(col++));
str_to_number(mobTable->dwDamageRange[1], csvTable.AsStringByIndex(col++));
str_to_number(mobTable->dwMaxHP, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->bRegenCycle, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->bRegenPercent, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->dwGoldMin, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->dwGoldMax, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->dwExp, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->wDef, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->sAttackSpeed, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->sMovingSpeed, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->bAggresiveHPPct, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->wAggressiveSight, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->wAttackRange, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->dwDropItemVnum, csvTable.AsStringByIndex(col++)); //32
str_to_number(mobTable->dwResurrectionVnum, csvTable.AsStringByIndex(col++));
for (int i = 0; i < MOB_ENCHANTS_MAX_NUM; ++i)
str_to_number(mobTable->cEnchants[i], csvTable.AsStringByIndex(col++));
for (int i = 0; i < MOB_RESISTS_MAX_NUM; ++i)
str_to_number(mobTable->cResists[i], csvTable.AsStringByIndex(col++));
str_to_number(mobTable->fDamMultiply, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->dwSummonVnum, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->dwDrainSP, csvTable.AsStringByIndex(col++));
//Mob_Color
++col;
str_to_number(mobTable->dwPolymorphItemVnum, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->Skills[0].bLevel, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->Skills[0].dwVnum, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->Skills[1].bLevel, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->Skills[1].dwVnum, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->Skills[2].bLevel, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->Skills[2].dwVnum, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->Skills[3].bLevel, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->Skills[3].dwVnum, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->Skills[4].bLevel, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->Skills[4].dwVnum, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->bBerserkPoint, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->bStoneSkinPoint, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->bGodSpeedPoint, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->bDeathBlowPoint, csvTable.AsStringByIndex(col++));
str_to_number(mobTable->bRevivePoint, csvTable.AsStringByIndex(col++));
sys_log(0, "MOB #%-5d %-24s level: %-3u rank: %u empire: %d", mobTable->dwVnum, mobTable->szLocaleName, mobTable->bLevel, mobTable->bRank, mobTable->bEmpire);
return true;
}
bool Set_Proto_Item_Table(TItemTable *itemTable, cCsvTable &csvTable,std::map<int,const char*> &nameMap)
{
int col = 0;
int dataArray[33];
for (size_t i=0; i<_countof(dataArray);i++) {
int validCheck = 0;
if (i==2) {
dataArray[i] = get_Item_Type_Value(csvTable.AsStringByIndex(col));
validCheck = dataArray[i];
} else if (i==3) {
dataArray[i] = get_Item_SubType_Value(dataArray[i-1], csvTable.AsStringByIndex(col));
validCheck = dataArray[i];
} else if (i==5) {
dataArray[i] = get_Item_AntiFlag_Value(csvTable.AsStringByIndex(col));
validCheck = dataArray[i];
} else if (i==6) {
dataArray[i] = get_Item_Flag_Value(csvTable.AsStringByIndex(col));
validCheck = dataArray[i];
} else if (i==7) {
dataArray[i] = get_Item_WearFlag_Value(csvTable.AsStringByIndex(col));
validCheck = dataArray[i];
} else if (i==8) {
dataArray[i] = get_Item_Immune_Value(csvTable.AsStringByIndex(col));
validCheck = dataArray[i];
} else if (i==14) {
dataArray[i] = get_Item_LimitType_Value(csvTable.AsStringByIndex(col));
validCheck = dataArray[i];
} else if (i==16) {
dataArray[i] = get_Item_LimitType_Value(csvTable.AsStringByIndex(col));
validCheck = dataArray[i];
} else if (i==18) {
dataArray[i] = get_Item_ApplyType_Value(csvTable.AsStringByIndex(col));
validCheck = dataArray[i];
} else if (i==20) {
dataArray[i] = get_Item_ApplyType_Value(csvTable.AsStringByIndex(col));
validCheck = dataArray[i];
} else if (i==22) {
dataArray[i] = get_Item_ApplyType_Value(csvTable.AsStringByIndex(col));
validCheck = dataArray[i];
} else {
str_to_number(dataArray[i], csvTable.AsStringByIndex(col));
}
if (validCheck == -1)
{
std::ostringstream dataStream;
for (size_t j = 0; j < i; ++j)
dataStream << dataArray[j] << ",";
//fprintf(stderr, "ItemProto Reading Failed : Invalid value.\n");
sys_err("ItemProto Reading Failed : Invalid value. (index: %d, col: %d, value: %s)", i, col, csvTable.AsStringByIndex(col));
sys_err("\t%d ~ %d Values: %s", 0, i, dataStream.str().c_str());
exit(0);
}
col = col + 1;
}
{
std::string s(csvTable.AsStringByIndex(0));
size_t pos = s.find("~");
if (std::string::npos == pos)
{
itemTable->dwVnum = dataArray[0];
itemTable->dwVnumRange = 0;
}
else
{
std::string s_start_vnum (s.substr(0, pos));
std::string s_end_vnum (s.substr(pos +1 ));
int start_vnum = atoi(s_start_vnum.c_str());
int end_vnum = atoi(s_end_vnum.c_str());
if (0 == start_vnum || (0 != end_vnum && end_vnum < start_vnum))
{
sys_err ("INVALID VNUM %s", s.c_str());
return false;
}
itemTable->dwVnum = start_vnum;
itemTable->dwVnumRange = end_vnum - start_vnum;
}
}
strlcpy(itemTable->szName, csvTable.AsStringByIndex(1), sizeof(itemTable->szName));
auto it = nameMap.find(itemTable->dwVnum);
if (it != nameMap.end()) {
const char * localeName = it->second;
strlcpy(itemTable->szLocaleName, localeName, sizeof(itemTable->szLocaleName));
} else {
strlcpy(itemTable->szLocaleName, itemTable->szName, sizeof(itemTable->szLocaleName));
}
itemTable->bType = dataArray[2];
itemTable->bSubType = dataArray[3];
itemTable->bSize = MINMAX(1, dataArray[4], 3); // @fixme179
itemTable->dwAntiFlags = dataArray[5];
itemTable->dwFlags = dataArray[6];
itemTable->dwWearFlags = dataArray[7];
itemTable->dwImmuneFlag = dataArray[8];
itemTable->dwGold = dataArray[9];
itemTable->dwShopBuyPrice = dataArray[10];
itemTable->dwRefinedVnum = dataArray[11];
itemTable->wRefineSet = dataArray[12];
itemTable->bAlterToMagicItemPct = dataArray[13];
itemTable->cLimitRealTimeFirstUseIndex = -1;
itemTable->cLimitTimerBasedOnWearIndex = -1;
int i;
for (i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
{
itemTable->aLimits[i].bType = dataArray[14+i*2];
itemTable->aLimits[i].lValue = dataArray[15+i*2];
if (LIMIT_REAL_TIME_START_FIRST_USE == itemTable->aLimits[i].bType)
itemTable->cLimitRealTimeFirstUseIndex = (char)i;
if (LIMIT_TIMER_BASED_ON_WEAR == itemTable->aLimits[i].bType)
itemTable->cLimitTimerBasedOnWearIndex = (char)i;
}
for (i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
{
itemTable->aApplies[i].bType = dataArray[18+i*2];
itemTable->aApplies[i].lValue = dataArray[19+i*2];
}
for (i = 0; i < ITEM_VALUES_MAX_NUM; ++i)
itemTable->alValues[i] = dataArray[24+i];
itemTable->bGainSocketPct = dataArray[31];
itemTable->sAddonType = dataArray[32];
str_to_number(itemTable->bWeight, "0");
#ifdef ENABLE_CHECK_SELL_PRICE
auto dwPrice = itemTable->dwShopBuyPrice;
#ifndef ENABLE_NO_SELL_PRICE_DIVIDED_BY_5
dwPrice /= 5;
#endif
if (dwPrice > itemTable->dwGold)
{
sys_err("ITEM: #%-5lu %-24s SELL_OVERFLOW dwGold: %u < dwShopBuyPrice %u",
itemTable->dwVnum,
itemTable->szLocaleName,
itemTable->dwGold,
dwPrice
);
itemTable->dwGold = dwPrice;
}
#endif
return true;
}
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,34 @@
#ifndef __Item_CSV_READER_H__
#define __Item_CSV_READER_H__
#include <iostream>
#include <map>
#include "CsvReader.h"
void putItemIntoTable();
int get_Item_Type_Value(std::string inputString);
int get_Item_SubType_Value(int type_value, std::string inputString);
int get_Item_AntiFlag_Value(std::string inputString);
int get_Item_Flag_Value(std::string inputString);
int get_Item_WearFlag_Value(std::string inputString);
int get_Item_Immune_Value(std::string inputString);
int get_Item_LimitType_Value(std::string inputString);
int get_Item_ApplyType_Value(std::string inputString);
int get_Mob_Rank_Value(std::string inputString);
int get_Mob_Type_Value(std::string inputString);
int get_Mob_BattleType_Value(std::string inputString);
int get_Mob_Size_Value(std::string inputString);
int get_Mob_AIFlag_Value(std::string inputString);
int get_Mob_RaceFlag_Value(std::string inputString);
int get_Mob_ImmuneFlag_Value(std::string inputString);
//
bool Set_Proto_Mob_Table(TMobTable *mobTable, cCsvTable &csvTable, std::map<int,const char*> &nameMap);
bool Set_Proto_Item_Table(TItemTable *itemTable, cCsvTable &csvTable,std::map<int,const char*> &nameMap);
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,36 @@
#ifndef __INC_METIN_II_DB_QID_H__
#define __INC_METIN_II_DB_QID_H__
enum QID
{
QID_PLAYER, // 0
QID_ITEM, // 1
QID_QUEST, // 2
QID_AFFECT, // 3
QID_LOGIN, // 4
QID_SAFEBOX_LOAD, // 5
QID_SAFEBOX_CHANGE_SIZE, // 6
QID_SAFEBOX_CHANGE_PASSWORD, // 7
QID_SAFEBOX_CHANGE_PASSWORD_SECOND, // 8
QID_SAFEBOX_SAVE, // 9
QID_ITEM_SAVE, // 10
QID_ITEM_DESTROY, // 11
QID_QUEST_SAVE, // 12
QID_PLAYER_SAVE, // 13
QID_PLAYER_DELETE, // 15
QID_LOGIN_BY_KEY, // 16
QID_PLAYER_INDEX_CREATE, // 17
QID_ITEM_AWARD_LOAD, // 18
QID_ITEM_AWARD_TAKEN, // 19
QID_GUILD_RANKING, // 20
// MYSHOP_PRICE_LIST
QID_ITEMPRICE_SAVE,
QID_ITEMPRICE_DESTROY,
QID_ITEMPRICE_LOAD_FOR_UPDATE,
QID_ITEMPRICE_LOAD,
// END_OF_MYSHOP_PRICE_LIST
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,190 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectName>db</ProjectName>
<ProjectGuid>{ADC2E26A-C39B-4817-A24C-A99827B74EB2}</ProjectGuid>
<RootNamespace>db</RootNamespace>
<SccProjectName>
</SccProjectName>
<SccAuxPath>
</SccAuxPath>
<SccLocalPath>
</SccLocalPath>
<SccProvider>
</SccProvider>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\db\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../bin/release\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(ProjectDir)../../libmysql/6.0.2/win32;$(ProjectDir)../../../Extern/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NOMINMAX;_DEBUG;_CONSOLE;__WIN32__;_CRT_SECURE_NO_WARNINGS;_USE_32BIT_TIME_T;_WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<ProgramDataBaseFileName>$(OutDir)$(TargetName).pdb</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>libmysql.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(ProjectName)_d.exe</OutputFile>
<AdditionalLibraryDirectories>$(ProjectDir)../../libmysql/6.0.2/win32/lib;$(ProjectDir)../../../Extern/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
<IgnoreSpecificDefaultLibraries>LIBCMT;libcpmt;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(ProjectDir)../../libmysql/6.0.2/win32;$(ProjectDir)../../../Extern/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NOMINMAX;NDEBUG;_CONSOLE;__WIN32__;_CRT_SECURE_NO_WARNINGS;_USE_32BIT_TIME_T;_WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader>
</PrecompiledHeader>
<ProgramDataBaseFileName>$(OutDir)$(TargetName).pdb</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>libmysql.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)../../libmysql/6.0.2/win32/lib;$(ProjectDir)../../../Extern/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Cache.cpp" />
<ClCompile Include="ClientManager.cpp" />
<ClCompile Include="ClientManagerBoot.cpp" />
<ClCompile Include="ClientManagerEventFlag.cpp" />
<ClCompile Include="ClientManagerGuild.cpp" />
<ClCompile Include="ClientManagerHorseName.cpp" />
<ClCompile Include="ClientManagerLogin.cpp" />
<ClCompile Include="ClientManagerParty.cpp" />
<ClCompile Include="ClientManagerPlayer.cpp" />
<ClCompile Include="Config.cpp" />
<ClCompile Include="CsvReader.cpp" />
<ClCompile Include="DBManager.cpp" />
<ClCompile Include="GuildManager.cpp" />
<ClCompile Include="HB.cpp" />
<ClCompile Include="ItemAwardManager.cpp" />
<ClCompile Include="ItemIDRangeManager.cpp" />
<ClCompile Include="Lock.cpp" />
<ClCompile Include="LoginData.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="Marriage.cpp" />
<ClCompile Include="Monarch.cpp" />
<ClCompile Include="MoneyLog.cpp" />
<ClCompile Include="NetBase.cpp" />
<ClCompile Include="Peer.cpp" />
<ClCompile Include="PeerBase.cpp" />
<ClCompile Include="PrivManager.cpp" />
<ClCompile Include="ProtoReader.cpp" />
<ClCompile Include="version.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Cache.h" />
<ClInclude Include="ClientManager.h" />
<ClInclude Include="Config.h" />
<ClInclude Include="CsvReader.h" />
<ClInclude Include="DBManager.h" />
<ClInclude Include="GuildManager.h" />
<ClInclude Include="HB.h" />
<ClInclude Include="ItemAwardManager.h" />
<ClInclude Include="ItemIDRangeManager.h" />
<ClInclude Include="Lock.h" />
<ClInclude Include="LoginData.h" />
<ClInclude Include="Main.h" />
<ClInclude Include="Marriage.h" />
<ClInclude Include="Monarch.h" />
<ClInclude Include="MoneyLog.h" />
<ClInclude Include="NetBase.h" />
<ClInclude Include="Peer.h" />
<ClInclude Include="PeerBase.h" />
<ClInclude Include="PrivManager.h" />
<ClInclude Include="ProtoReader.h" />
<ClInclude Include="QID.h" />
<ClInclude Include="stdafx.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\libgame\libgame.vcxproj">
<Project>{2ab4a5a4-3eaa-4486-b93c-38e8d39bf218}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\..\libpoly\libpoly.vcxproj">
<Project>{bd8e86dd-07ba-49b0-bf04-3282da8377eb}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\..\libsql\libsql.vcxproj">
<Project>{3967853d-4e19-4548-ac3a-f6012b78e384}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\..\libthecore\libthecore.vcxproj">
<Project>{5c8620c9-5d1f-419d-8267-48d2863c3d13}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,163 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Cache.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ClientManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ClientManagerBoot.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ClientManagerEventFlag.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ClientManagerGuild.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ClientManagerHorseName.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ClientManagerLogin.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ClientManagerParty.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ClientManagerPlayer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Config.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CsvReader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DBManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GuildManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="HB.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ItemAwardManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ItemIDRangeManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Lock.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="LoginData.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Marriage.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Monarch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MoneyLog.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NetBase.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Peer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="PeerBase.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="PrivManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ProtoReader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="version.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Cache.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="ClientManager.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="Config.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="CsvReader.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="DBManager.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="GuildManager.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="HB.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="ItemAwardManager.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="ItemIDRangeManager.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="Lock.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="LoginData.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="Main.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="Marriage.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="Monarch.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="MoneyLog.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="NetBase.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="Peer.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="PeerBase.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="PrivManager.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="ProtoReader.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="QID.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="stdafx.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>

View File

@ -0,0 +1,21 @@
#ifndef __INC_METiN_II_DBSERV_STDAFX_H__
#define __INC_METiN_II_DBSERV_STDAFX_H__
#include "../../libthecore/include/stdafx.h"
#ifndef __WIN32__
#include <semaphore.h>
#else
#define isdigit iswdigit
#define isspace iswspace
#endif
#include "../../common/length.h"
#include "../../common/tables.h"
#include "../../common/singleton.h"
#include "../../common/utils.h"
#include "../../common/stl.h"
#include "../../common/service.h"
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,22 @@
#include <stdio.h>
#include <stdlib.h>
void WriteVersion()
{
#ifndef __WIN32__
FILE* fp(fopen("VERSION.txt", "w"));
if (NULL != fp)
{
fprintf(fp, "__DB_VERSION__: %s\n", __DB_VERSION__);
fprintf(fp, "%s@%s:%s\n", "cHVjaGF0eQ==", __HOSTNAME__, __PWD__);
fclose(fp);
}
else
{
fprintf(stderr, "cannot open VERSION.txt\n");
exit(0);
}
#endif
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,194 @@
#include "stdafx.h"
#include "config.h"
#include "BlueDragon.h"
#include "vector.h"
#include "utils.h"
#include "char.h"
#include "mob_manager.h"
#include "sectree_manager.h"
#include "battle.h"
#include "affect.h"
#include "BlueDragon_Binder.h"
#include "BlueDragon_Skill.h"
#include "packet.h"
#include "motion.h"
time_t UseBlueDragonSkill(LPCHARACTER pChar, unsigned int idx)
{
LPSECTREE_MAP pSecMap = SECTREE_MANAGER::instance().GetMap( pChar->GetMapIndex() );
if (NULL == pSecMap)
return 0;
int nextUsingTime = 0;
switch (idx)
{
case 0:
{
sys_log(0, "BlueDragon: Using Skill Breath");
FSkillBreath f(pChar);
pSecMap->for_each( f );
nextUsingTime = number(BlueDragon_GetSkillFactor(3, "Skill0", "period", "min"), BlueDragon_GetSkillFactor(3, "Skill0", "period", "max"));
}
break;
case 1:
{
sys_log(0, "BlueDragon: Using Skill Weak Breath");
FSkillWeakBreath f(pChar);
pSecMap->for_each( f );
nextUsingTime = number(BlueDragon_GetSkillFactor(3, "Skill1", "period", "min"), BlueDragon_GetSkillFactor(3, "Skill1", "period", "max"));
}
break;
case 2:
{
sys_log(0, "BlueDragon: Using Skill EarthQuake");
FSkillEarthQuake f(pChar);
pSecMap->for_each( f );
nextUsingTime = number(BlueDragon_GetSkillFactor(3, "Skill2", "period", "min"), BlueDragon_GetSkillFactor(3, "Skill2", "period", "max"));
if (NULL != f.pFarthestChar)
{
pChar->BeginFight( f.pFarthestChar );
}
}
break;
default:
sys_err("BlueDragon: Wrong Skill Index: %d", idx);
return 0;
}
int addPct = BlueDragon_GetRangeFactor("hp_period", pChar->GetHPPct());
nextUsingTime += (nextUsingTime * addPct) / 100;
return nextUsingTime;
}
int BlueDragon_StateBattle(LPCHARACTER pChar)
{
if (pChar->GetHPPct() > 98)
return PASSES_PER_SEC(1);
const int SkillCount = 3;
int SkillPriority[SkillCount];
static time_t timeSkillCanUseTime[SkillCount];
if (pChar->GetHPPct() > 76)
{
SkillPriority[0] = 1;
SkillPriority[1] = 0;
SkillPriority[2] = 2;
}
else if (pChar->GetHPPct() > 31)
{
SkillPriority[0] = 0;
SkillPriority[1] = 1;
SkillPriority[2] = 2;
}
else
{
SkillPriority[0] = 0;
SkillPriority[1] = 2;
SkillPriority[2] = 1;
}
time_t timeNow = static_cast<time_t>(get_dword_time());
for (int i=0 ; i < SkillCount ; ++i)
{
const int SkillIndex = SkillPriority[i];
if (timeSkillCanUseTime[SkillIndex] < timeNow)
{
int SkillUsingDuration =
static_cast<int>(CMotionManager::instance().GetMotionDuration( pChar->GetRaceNum(), MAKE_MOTION_KEY(MOTION_MODE_GENERAL, MOTION_SPECIAL_1 + SkillIndex) ));
timeSkillCanUseTime[SkillIndex] = timeNow + (UseBlueDragonSkill( pChar, SkillIndex ) * 1000) + SkillUsingDuration + 3000;
pChar->SendMovePacket(FUNC_MOB_SKILL, SkillIndex, pChar->GetX(), pChar->GetY(), 0, timeNow);
return 0 == SkillUsingDuration ? PASSES_PER_SEC(1) : PASSES_PER_SEC(SkillUsingDuration);
}
}
return PASSES_PER_SEC(1);
}
int BlueDragon_Damage (LPCHARACTER me, LPCHARACTER pAttacker, int dam)
{
if (NULL == me || NULL == pAttacker)
return dam;
if (true == pAttacker->IsMonster() && 2493 == pAttacker->GetMobTable().dwVnum)
{
for (int i=1 ; i <= 4 ; ++i)
{
if (ATK_BONUS == BlueDragon_GetIndexFactor("DragonStone", i, "effect_type"))
{
DWORD dwDragonStoneID = BlueDragon_GetIndexFactor("DragonStone", i, "vnum");
size_t val = BlueDragon_GetIndexFactor("DragonStone", i, "val");
size_t cnt = SECTREE_MANAGER::instance().GetMonsterCountInMap( pAttacker->GetMapIndex(), dwDragonStoneID );
dam += (dam * (val*cnt))/100;
break;
}
}
}
if (true == me->IsMonster() && 2493 == me->GetMobTable().dwVnum)
{
for (int i=1 ; i <= 4 ; ++i)
{
if (DEF_BONUS == BlueDragon_GetIndexFactor("DragonStone", i, "effect_type"))
{
DWORD dwDragonStoneID = BlueDragon_GetIndexFactor("DragonStone", i, "vnum");
size_t val = BlueDragon_GetIndexFactor("DragonStone", i, "val");
size_t cnt = SECTREE_MANAGER::instance().GetMonsterCountInMap( me->GetMapIndex(), dwDragonStoneID );
dam -= (dam * (val*cnt))/100;
if (dam <= 0)
dam = 1;
break;
}
}
}
if (true == me->IsStone() && 0 != pAttacker->GetMountVnum())
{
for (int i=1 ; i <= 4 ; ++i)
{
if (me->GetMobTable().dwVnum == BlueDragon_GetIndexFactor("DragonStone", i, "vnum"))
{
if (pAttacker->GetMountVnum() == BlueDragon_GetIndexFactor("DragonStone", i, "enemy"))
{
size_t val = BlueDragon_GetIndexFactor("DragonStone", i, "enemy_val");
dam *= val;
break;
}
}
}
}
return dam;
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,4 @@
extern int BlueDragon_StateBattle (LPCHARACTER);
extern time_t UseBlueDragonSkill (LPCHARACTER, unsigned int);
extern int BlueDragon_Damage (LPCHARACTER me, LPCHARACTER attacker, int dam);
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,217 @@
#include "stdafx.h"
#include "BlueDragon_Binder.h"
#include "questmanager.h"
unsigned int BlueDragon_GetSkillFactor(const size_t cnt, ...)
{
lua_State* L = quest::CQuestManager::instance().GetLuaState();
const int stack_top = lua_gettop(L);
lua_getglobal( L, "BlueDragonSetting" );
if (false == lua_istable(L, -1))
{
lua_settop( L, stack_top );
return 0;
}
va_list vl;
va_start(vl, cnt);
for( size_t i=0 ; i < cnt ; ++i )
{
const char* key = va_arg(vl, const char*);
if (NULL == key)
{
va_end(vl);
lua_settop( L, stack_top );
sys_err("BlueDragon: wrong key list");
return 0;
}
lua_pushstring( L, key );
lua_gettable( L, -2 );
if (false == lua_istable(L, -1) && i != cnt-1)
{
va_end(vl);
lua_settop( L, stack_top );
sys_err("BlueDragon: wrong key table %s", key);
return 0;
}
}
va_end(vl);
if (false == lua_isnumber(L, -1))
{
lua_settop( L, stack_top );
sys_err("BlueDragon: Last key is not a number");
return 0;
}
int val = static_cast<int>(lua_tonumber( L, -1 ));
lua_settop( L, stack_top );
return val;
}
unsigned int BlueDragon_GetRangeFactor(const char* key, const int val)
{
lua_State* L = quest::CQuestManager::instance().GetLuaState();
const int stack_top = lua_gettop(L);
lua_getglobal( L, "BlueDragonSetting" );
if (false == lua_istable(L, -1))
{
lua_settop( L, stack_top );
return 0;
}
lua_pushstring( L, key );
lua_gettable( L, -2 );
if (false == lua_istable(L, -1))
{
lua_settop( L, stack_top );
sys_err("BlueDragon: no required table %s", key);
return 0;
}
const size_t cnt = static_cast<size_t>(luaL_getn(L, -1));
for( size_t i=1 ; i <= cnt ; ++i )
{
lua_rawgeti( L, -1, i );
if (false == lua_istable(L, -1))
{
lua_settop( L, stack_top );
sys_err("BlueDragon: wrong table index %s %d", key, i);
return 0;
}
lua_pushstring( L, "min" );
lua_gettable( L, -2 );
if (false == lua_isnumber(L, -1))
{
lua_settop( L, stack_top );
sys_err("BlueDragon: no min value set %s", key);
return 0;
}
const int min = static_cast<int>(lua_tonumber(L, -1));
lua_pop(L, 1);
lua_pushstring( L, "max" );
lua_gettable( L, -2 );
if (false == lua_isnumber(L, -1))
{
lua_settop( L, stack_top );
sys_err("BlueDragon: no max value set %s", key);
return 0;
}
const int max = static_cast<int>(lua_tonumber(L, -1));
lua_pop(L, 1);
if (min <= val && val <= max)
{
lua_pushstring( L, "pct" );
lua_gettable( L, -2 );
if (false == lua_isnumber(L, -1))
{
lua_settop( L, stack_top );
sys_err("BlueDragon: no pct value set %s", key);
return 0;
}
const int pct = static_cast<int>(lua_tonumber(L, -1));
lua_settop( L, stack_top );
return pct;
}
lua_pop(L, 1);
}
lua_settop( L, stack_top );
return 0;
}
unsigned int BlueDragon_GetIndexFactor(const char* container, const size_t idx, const char* key)
{
lua_State* L = quest::CQuestManager::instance().GetLuaState();
const int stack_top = lua_gettop(L);
lua_getglobal( L, "BlueDragonSetting" );
if (false == lua_istable(L, -1))
{
lua_settop( L, stack_top );
return 0;
}
lua_pushstring( L, container );
lua_gettable( L, -2 );
if (false == lua_istable(L, -1))
{
lua_settop( L, stack_top );
sys_err("BlueDragon: no required table %s", key);
return 0;
}
lua_rawgeti( L, -1, idx );
if (false == lua_istable(L, -1))
{
lua_settop( L, stack_top );
sys_err("BlueDragon: wrong table index %s %d", key, idx);
return 0;
}
lua_pushstring( L, key );
lua_gettable( L, -2 );
if (false == lua_isnumber(L, -1))
{
lua_settop( L, stack_top );
sys_err("BlueDragon: no min value set %s", key);
return 0;
}
const unsigned int ret = static_cast<unsigned int>(lua_tonumber(L, -1));
lua_settop( L, stack_top );
return ret;
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,12 @@
enum BLUEDRAGON_STONE_EFFECT
{
DEF_BONUS = 1,
ATK_BONUS = 2,
REGEN_TIME_BONUS = 3,
REGEN_PECT_BONUS = 4,
};
extern unsigned int BlueDragon_GetRangeFactor (const char* key, const int val);
extern unsigned int BlueDragon_GetSkillFactor (const size_t cnt, ...);
extern unsigned int BlueDragon_GetIndexFactor (const char* container, const size_t idx, const char* key);
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,355 @@
#ifndef _INC_BLUE_DRAGON_SKILL_H__INC_
#define _INC_BLUE_DRAGON_SKILL_H__INC_
#include "../../common/CommonDefines.h"
struct FSkillBreath
{
EJobs Set1;
EJobs Set2;
ESex gender;
LPCHARACTER pAttacker;
FSkillBreath(LPCHARACTER p)
{
pAttacker = p;
Set1 = static_cast<EJobs>(number(0,3));
Set2 = static_cast<EJobs>(number(0,3));
gender = static_cast<ESex>(number(0,2));
}
void operator()(LPENTITY ent)
{
if (NULL != ent)
{
if (true == ent->IsType(ENTITY_CHARACTER))
{
LPCHARACTER ch = static_cast<LPCHARACTER>(ent);
if (true == ch->IsPC() && false == ch->IsDead())
{
if (NULL != ch->FindAffect(AFFECT_REVIVE_INVISIBLE, APPLY_NONE))
return;
if ((signed)BlueDragon_GetSkillFactor(2, "Skill0", "damage_area") < DISTANCE_APPROX(pAttacker->GetX()-ch->GetX(), pAttacker->GetY()-ch->GetY()))
{
sys_log(0, "BlueDragon: Breath too far (%d)", DISTANCE_APPROX(pAttacker->GetX()-ch->GetX(), pAttacker->GetY()-ch->GetY()) );
return;
}
int overlapDamageCount = 0;
int pct = 0;
if (ch->GetJob() == Set1)
{
const char* ptr = NULL;
switch ( Set1 )
{
case JOB_WARRIOR: ptr = "musa"; break;
case JOB_ASSASSIN: ptr = "assa"; break;
case JOB_SURA: ptr = "sura"; break;
case JOB_SHAMAN: ptr = "muda"; break;
#ifdef ENABLE_WOLFMAN_CHARACTER
case JOB_WOLFMAN: ptr = "wolf"; break;
#endif
default:
case JOB_MAX_NUM: return;
}
int firstDamagePercent = number(BlueDragon_GetSkillFactor(4, "Skill0", "damage", ptr, "min"), BlueDragon_GetSkillFactor(4, "Skill0", "damage", ptr, "max"));
pct += firstDamagePercent;
if (firstDamagePercent > 0)
overlapDamageCount++;
}
if (ch->GetJob() == Set2)
{
const char* ptr = NULL;
switch ( Set2 )
{
case JOB_WARRIOR: ptr = "musa"; break;
case JOB_ASSASSIN: ptr = "assa"; break;
case JOB_SURA: ptr = "sura"; break;
case JOB_SHAMAN: ptr = "muda"; break;
#ifdef ENABLE_WOLFMAN_CHARACTER
case JOB_WOLFMAN: ptr = "wolf"; break;
#endif
default:
case JOB_MAX_NUM: return;
}
int secondDamagePercent = number(BlueDragon_GetSkillFactor(4, "Skill0", "damage", ptr, "min"), BlueDragon_GetSkillFactor(4, "Skill0", "damage", ptr, "max"));
pct += secondDamagePercent;
if (secondDamagePercent > 0)
overlapDamageCount++;
}
if (GET_SEX(ch) == gender)
{
const char* ptr = NULL;
switch (gender)
{
case SEX_MALE: ptr = "male"; break;
case SEX_FEMALE: ptr = "female"; break;
default: return;
}
int thirdDamagePercent = number(BlueDragon_GetSkillFactor(4, "Skill0", "gender", ptr, "min"), BlueDragon_GetSkillFactor(4, "Skill0", "gender", ptr, "max"));
pct += thirdDamagePercent;
if (thirdDamagePercent > 0)
overlapDamageCount++;
}
switch (overlapDamageCount)
{
case 1:
ch->EffectPacket(SE_PERCENT_DAMAGE1);
break;
case 2:
ch->EffectPacket(SE_PERCENT_DAMAGE2);
break;
case 3:
ch->EffectPacket(SE_PERCENT_DAMAGE3);
break;
}
int addPct = BlueDragon_GetRangeFactor("hp_damage", pAttacker->GetHPPct());
pct += addPct;
int dam = number(BlueDragon_GetSkillFactor(3, "Skill0", "default_damage", "min"), BlueDragon_GetSkillFactor(3, "Skill0", "default_damage", "max"));
dam += (dam * addPct) / 100;
dam += (ch->GetMaxHP() * pct) / 100;
ch->Damage( pAttacker, dam, DAMAGE_TYPE_ICE );
sys_log(0, "BlueDragon: Breath to %s pct(%d) dam(%d) overlap(%d)", ch->GetName(), pct, dam, overlapDamageCount);
}
}
}
}
};
struct FSkillWeakBreath
{
LPCHARACTER pAttacker;
FSkillWeakBreath(LPCHARACTER p)
{
pAttacker = p;
}
void operator()(LPENTITY ent)
{
if (NULL != ent)
{
if (true == ent->IsType(ENTITY_CHARACTER))
{
LPCHARACTER ch = static_cast<LPCHARACTER>(ent);
if (true == ch->IsPC() && false == ch->IsDead())
{
if (NULL != ch->FindAffect(AFFECT_REVIVE_INVISIBLE, APPLY_NONE))
return;
if ((signed)BlueDragon_GetSkillFactor(2, "Skill1", "damage_area") < DISTANCE_APPROX(pAttacker->GetX()-ch->GetX(), pAttacker->GetY()-ch->GetY()))
{
sys_log(0, "BlueDragon: Breath too far (%d)", DISTANCE_APPROX(pAttacker->GetX()-ch->GetX(), pAttacker->GetY()-ch->GetY()) );
return;
}
int addPct = BlueDragon_GetRangeFactor("hp_damage", pAttacker->GetHPPct());
int dam = number( BlueDragon_GetSkillFactor(3, "Skill1", "default_damage", "min"), BlueDragon_GetSkillFactor(3, "Skill1", "default_damage", "max") );
dam += (dam * addPct) / 100;
ch->Damage( pAttacker, dam, DAMAGE_TYPE_ICE );
sys_log(0, "BlueDragon: WeakBreath to %s addPct(%d) dam(%d)", ch->GetName(), addPct, dam);
}
}
}
}
};
struct FSkillEarthQuake
{
EJobs Set1;
EJobs Set2;
ESex gender;
long MaxDistance;
LPCHARACTER pAttacker;
LPCHARACTER pFarthestChar;
FSkillEarthQuake(LPCHARACTER p)
{
pAttacker = p;
MaxDistance = 0;
pFarthestChar = NULL;
Set1 = static_cast<EJobs>(number(0,3));
Set2 = static_cast<EJobs>(number(0,3));
gender = static_cast<ESex>(number(0,2));
}
void operator()(LPENTITY ent)
{
if (NULL != ent)
{
if (true == ent->IsType(ENTITY_CHARACTER))
{
LPCHARACTER ch = static_cast<LPCHARACTER>(ent);
if (true == ch->IsPC() && false == ch->IsDead())
{
if (NULL != ch->FindAffect(AFFECT_REVIVE_INVISIBLE, APPLY_NONE))
return;
if ((signed)BlueDragon_GetSkillFactor(2, "Skill2", "damage_area") < DISTANCE_APPROX(pAttacker->GetX()-ch->GetX(), pAttacker->GetY()-ch->GetY()))
{
sys_log(0, "BlueDragon: Breath too far (%d)", DISTANCE_APPROX(pAttacker->GetX()-ch->GetX(), pAttacker->GetY()-ch->GetY()) );
return;
}
int sec = number(BlueDragon_GetSkillFactor(4, "Skill2", "stun_time", "default", "min"), BlueDragon_GetSkillFactor(4, "Skill2", "stun_time", "default", "max"));
if (ch->GetJob() == Set1)
{
const char* ptr = NULL;
switch ( Set1 )
{
case JOB_WARRIOR: ptr = "musa"; break;
case JOB_ASSASSIN: ptr = "assa"; break;
case JOB_SURA: ptr = "sura"; break;
case JOB_SHAMAN: ptr = "muda"; break;
#ifdef ENABLE_WOLFMAN_CHARACTER
case JOB_WOLFMAN: ptr = "wolf"; break;
#endif
default:
case JOB_MAX_NUM: return;
}
sec += number(BlueDragon_GetSkillFactor(4, "Skill2", "stun_time", ptr, "min"), BlueDragon_GetSkillFactor(4, "Skill2", "stun_time", ptr, "max"));
}
if (ch->GetJob() == Set2)
{
const char* ptr = NULL;
switch ( Set2 )
{
case JOB_WARRIOR: ptr = "musa"; break;
case JOB_ASSASSIN: ptr = "assa"; break;
case JOB_SURA: ptr = "sura"; break;
case JOB_SHAMAN: ptr = "muda"; break;
#ifdef ENABLE_WOLFMAN_CHARACTER
case JOB_WOLFMAN: ptr = "wolf"; break;
#endif
default:
case JOB_MAX_NUM: return;
}
sec += number(BlueDragon_GetSkillFactor(4, "Skill2", "stun_time", ptr, "min"), BlueDragon_GetSkillFactor(4, "Skill2", "stun_time", ptr, "max"));
}
if (GET_SEX(ch) == gender)
{
const char* ptr = NULL;
switch (gender)
{
case SEX_MALE: ptr = "male"; break;
case SEX_FEMALE: ptr = "female"; break;
default: return;
}
sec += number(BlueDragon_GetSkillFactor(4, "Skill2", "gender", ptr, "min"), BlueDragon_GetSkillFactor(4, "Skill2", "gender", ptr, "max"));
}
int addPct = BlueDragon_GetRangeFactor("hp_damage", pAttacker->GetHPPct());
int dam = number( BlueDragon_GetSkillFactor(3, "Skill2", "default_damage", "min"), BlueDragon_GetSkillFactor(3, "Skill2", "default_damage", "max") );
dam += (dam * addPct) / 100;
ch->Damage( pAttacker, dam, DAMAGE_TYPE_ICE);
SkillAttackAffect( ch, 1000, IMMUNE_STUN, AFFECT_STUN, POINT_NONE, 0, AFF_STUN, sec, "BDRAGON_STUN" );
sys_log(0, "BlueDragon: EarthQuake to %s addPct(%d) dam(%d) sec(%d)", ch->GetName(), addPct, dam, sec);
VECTOR vec;
vec.x = static_cast<float>(pAttacker->GetX() - ch->GetX());
vec.y = static_cast<float>(pAttacker->GetY() - ch->GetY());
vec.z = 0.0f;
Normalize( &vec, &vec );
const int nFlyDistance = 1000;
long tx = ch->GetX() + vec.x * nFlyDistance;
long ty = ch->GetY() + vec.y * nFlyDistance;
for (int i=0 ; i < 5 ; ++i)
{
if (true == SECTREE_MANAGER::instance().IsMovablePosition( ch->GetMapIndex(), tx, ty ))
{
break;
}
switch( i )
{
case 0:
tx = ch->GetX() + vec.x * nFlyDistance * -1;
ty = ch->GetY() + vec.y * nFlyDistance * -1;
break;
case 1:
tx = ch->GetX() + vec.x * nFlyDistance * -1;
ty = ch->GetY() + vec.y * nFlyDistance;
break;
case 2:
tx = ch->GetX() + vec.x * nFlyDistance;
ty = ch->GetY() + vec.y * nFlyDistance * -1;
break;
case 3:
tx = ch->GetX() + vec.x * number(1,100);
ty = ch->GetY() + vec.y * number(1,100);
break;
case 4:
tx = ch->GetX() + vec.x * number(1,10);
ty = ch->GetY() + vec.y * number(1,10);
break;
}
}
ch->Sync( tx , ty );
ch->Goto( tx , ty );
ch->CalculateMoveDuration();
ch->SyncPacket();
long dist = DISTANCE_APPROX( pAttacker->GetX() - ch->GetX(), pAttacker->GetY() - ch->GetY() );
if (dist > MaxDistance)
{
MaxDistance = dist;
pFarthestChar = ch;
}
}
}
}
}
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,222 @@
#include "stdafx.h"
#include "ClientPackageCryptInfo.h"
#include "../../common/stl.h"
#ifndef __FreeBSD__
#include "../../libthecore/include/xdirent.h"
#endif
CClientPackageCryptInfo::CClientPackageCryptInfo() : m_nCryptKeyPackageCnt(0), m_pSerializedCryptKeyStream(NULL)
{
}
CClientPackageCryptInfo::~CClientPackageCryptInfo()
{
m_vecPackageCryptKeys.clear();
m_mapPackageSDB.clear();
if( m_pSerializedCryptKeyStream )
{
delete[] m_pSerializedCryptKeyStream;
m_pSerializedCryptKeyStream = NULL;
}
}
bool CClientPackageCryptInfo::LoadPackageCryptFile( const char* pCryptFile )
{
FILE * fp = fopen(pCryptFile, "rb");
if (!fp)
return false;
int iSDBDataOffset;
fread(&iSDBDataOffset, sizeof(int), 1, fp);
int iPackageCnt;
fread( &iPackageCnt, sizeof(int), 1, fp );
m_nCryptKeyPackageCnt += iPackageCnt;
int iCryptKeySize = iSDBDataOffset - 2*sizeof(int);
{
if (0 == iCryptKeySize)
{
sys_log(0, "[PackageCryptInfo] failed to load crypt key. (file: %s, key size: %d)", pCryptFile, iCryptKeySize);
m_nCryptKeyPackageCnt -= iPackageCnt;
}
else
{
int nCurKeySize = (int)m_vecPackageCryptKeys.size();
m_vecPackageCryptKeys.resize( nCurKeySize + sizeof(int) + iCryptKeySize);
memcpy( &m_vecPackageCryptKeys[nCurKeySize], &iCryptKeySize, sizeof(int));
fread( &m_vecPackageCryptKeys[nCurKeySize + sizeof(int)], sizeof(BYTE), iCryptKeySize, fp );
sys_log(0, "[PackageCryptInfo] %s loaded. (key size: %d, count: %d, total: %d)", pCryptFile, iCryptKeySize, iPackageCnt, m_nCryptKeyPackageCnt);
}
}
//about SDB data
//total packagecnt (4byte)
// for packagecnt
// db name hash 4byte( stl.h stringhash ) +child node size(4byte)
//stream to client
// sdb file cnt( 4byte )
// for sdb file cnt
// filename hash ( stl.h stringhash )
// related map name size(4), relate map name
// sdb block size( 1byte )
// sdb blocks
int iSDBPackageCnt;
fread(&iSDBPackageCnt, sizeof(int), 1, fp);
DWORD dwPackageNameHash, dwPackageStreamSize, dwSDBFileCnt, dwFileNameHash, dwMapNameSize;
std::string strRelatedMapName;
if (0 == iCryptKeySize && 0 == iSDBPackageCnt)
return false;
for( int i = 0; i < iSDBPackageCnt; ++i )
{
fread(&dwPackageNameHash, sizeof(DWORD), 1, fp);
fread(&dwPackageStreamSize, sizeof(DWORD), 1, fp);
fread(&dwSDBFileCnt, sizeof(DWORD), 1, fp);
sys_log(0, "[PackageCryptInfo] SDB Loaded. (Name Hash : %d, Stream Size: %d, File Count: %d)", dwPackageNameHash,dwPackageStreamSize, dwSDBFileCnt);
for( int j = 0; j < (int)dwSDBFileCnt; ++j )
{
fread(&dwFileNameHash, sizeof(DWORD), 1, fp);
fread(&dwMapNameSize, sizeof(DWORD), 1, fp);
strRelatedMapName.resize( dwMapNameSize );
fread(&strRelatedMapName[0], sizeof(BYTE), dwMapNameSize, fp);
sys_log(0, "[PackageCryptInfo] \t SDB each file info loaded.(MapName: %s, NameHash: %X)", strRelatedMapName.c_str(), dwFileNameHash);
BYTE bSDBStreamSize;
std::vector<BYTE> vecSDBStream;
fread(&bSDBStreamSize, sizeof(BYTE), 1, fp);
vecSDBStream.resize(bSDBStreamSize);
fread(&vecSDBStream[0], sizeof(BYTE), bSDBStreamSize, fp);
//reconstruct it
TPackageSDBMap::iterator it = m_mapPackageSDB.find( strRelatedMapName );
if (it == m_mapPackageSDB.end())
{
TPerFileSDBInfo fileSDBInfo;
m_mapPackageSDB[strRelatedMapName] = fileSDBInfo;
}
TSupplementaryDataBlockInfo SDBInfo;
std::vector<TSupplementaryDataBlockInfo>& rSDBInfos = m_mapPackageSDB[strRelatedMapName].vecSDBInfos;
{
SDBInfo.dwPackageIdentifier = dwPackageNameHash;
SDBInfo.dwFileIdentifier = dwFileNameHash;
SDBInfo.vecSDBStream.resize(bSDBStreamSize);
memcpy(&SDBInfo.vecSDBStream[0], &vecSDBStream[0], bSDBStreamSize);
rSDBInfos.emplace_back(SDBInfo);
}
}
}
fclose(fp);
return true;
}
bool CClientPackageCryptInfo::LoadPackageCryptInfo( const char* pCryptInfoDir )
{
DIR * pDir = opendir(pCryptInfoDir);
if (!pDir)
return false;
m_nCryptKeyPackageCnt = 0;
if( m_pSerializedCryptKeyStream )
{
delete[] m_pSerializedCryptKeyStream;
m_pSerializedCryptKeyStream = NULL;
}
m_mapPackageSDB.clear();
m_vecPackageCryptKeys.clear();
const char szPrefixCryptInfoFile[] = "cshybridcrypt";
dirent * pDirEnt;
while ((pDirEnt = readdir(pDir)))
{
//if (strncmp( &(pDirEnt->d_name[0]), szPrefixCryptInfoFile, strlen(szPrefixCryptInfoFile)) )
if (std::string::npos == std::string(pDirEnt->d_name).find(szPrefixCryptInfoFile))
{
sys_log(0, "[PackageCryptInfo] %s is not crypt file. pass!", pDirEnt->d_name);
continue;
}
std::string strFullPathName = std::string(pCryptInfoDir) + std::string(pDirEnt->d_name);
sys_log(0, "[PackageCryptInfo] Try to load crypt file: %s", strFullPathName.c_str());
if (false == LoadPackageCryptFile( strFullPathName.c_str() ))
sys_err("[PackageCryptInfo] Failed to load %s", strFullPathName.c_str());
}
closedir(pDir);
return true;
}
void CClientPackageCryptInfo::GetPackageCryptKeys( BYTE** ppData, int& iDataSize )
{
int nCryptKeySize = m_vecPackageCryptKeys.size();
int iStreamSize = sizeof(int)+nCryptKeySize;
//NOTE : Crypt Key Info isn`t updated during runtime. ( in case of file reloading all data is cleared & recreated )
//it`s not safe but due to performance benefit we don`t do re-serialize.
if( m_pSerializedCryptKeyStream )
{
*ppData = m_pSerializedCryptKeyStream;
iDataSize = iStreamSize;
return;
}
if( nCryptKeySize > 0 )
{
m_pSerializedCryptKeyStream = new BYTE[iStreamSize];
memcpy(&m_pSerializedCryptKeyStream[0], &m_nCryptKeyPackageCnt, sizeof(int) );
memcpy(&m_pSerializedCryptKeyStream[sizeof(int)], &m_vecPackageCryptKeys[0], nCryptKeySize );
*ppData = m_pSerializedCryptKeyStream;
iDataSize = iStreamSize;
}
else
{
*ppData = NULL;
iDataSize = 0;
}
}
bool CClientPackageCryptInfo::GetRelatedMapSDBStreams(const char* pMapName, BYTE** ppData, int& iDataSize )
{
std::string strLowerMapName = pMapName;
stl_lowers(strLowerMapName);
TPackageSDBMap::iterator it = m_mapPackageSDB.find( strLowerMapName.c_str() );
if( it == m_mapPackageSDB.end() || it->second.vecSDBInfos.size() == 0 )
{
//sys_err("GetRelatedMapSDBStreams Failed(%s)", strLowerMapName.c_str());
return false;
}
*ppData = it->second.GetSerializedStream();
iDataSize = it->second.GetSize();
//sys_log(0, "GetRelatedMapSDBStreams Size(%d)", iDataSize);
return true;
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,110 @@
#ifndef __INC_CLIENTPACKAGE_CRYPTINFO_H
#define __INC_CLIENTPACKAGE_CRYPTINFO_H
#include <boost/unordered_map.hpp>
#pragma pack(1)
typedef struct SSupplementaryDataBlockInfo
{
DWORD dwPackageIdentifier;
DWORD dwFileIdentifier;
std::vector<BYTE> vecSDBStream;
void Serialize( BYTE* pStream )
{
memcpy(pStream, &dwPackageIdentifier, sizeof(DWORD));
memcpy(pStream+4, &dwFileIdentifier, sizeof(DWORD));
BYTE bSize = vecSDBStream.size();
memcpy(pStream+8, &bSize, sizeof(BYTE));
memcpy(pStream+9, &vecSDBStream[0], bSize);
}
DWORD GetSerializedSize() const
{
return sizeof(DWORD)*2 + sizeof(BYTE) + vecSDBStream.size();
}
} TSupplementaryDataBlockInfo;
#pragma pack()
class CClientPackageCryptInfo
{
public:
CClientPackageCryptInfo();
~CClientPackageCryptInfo();
bool LoadPackageCryptInfo( const char* pCryptInfoDir );
void GetPackageCryptKeys( BYTE** ppData, int& iDataSize );
bool GetRelatedMapSDBStreams(const char* pMapName, BYTE** ppData, int& iDataSize );
private:
bool LoadPackageCryptFile( const char* pCryptFile );
private:
int m_nCryptKeyPackageCnt;
std::vector<BYTE> m_vecPackageCryptKeys;
BYTE* m_pSerializedCryptKeyStream;
typedef struct SPerFileSDBInfo
{
SPerFileSDBInfo() : m_pSerializedStream(NULL) {}
~SPerFileSDBInfo()
{
if(m_pSerializedStream)
{
delete[]m_pSerializedStream;
}
}
DWORD GetSize() const
{
DWORD dwSize = 4; //initial vecSDBInfo count
for(int i = 0; i < (int)vecSDBInfos.size(); ++i)
{
dwSize += vecSDBInfos[i].GetSerializedSize();
}
return dwSize;
}
BYTE* GetSerializedStream()
{
//NOTE : SDB Data isn`t updated during runtime. ( in case of file reloading all data is cleared & recreated )
//it`s not safe but due to performance benefit we don`t do re-serialize.
if(m_pSerializedStream)
return m_pSerializedStream;
m_pSerializedStream = new BYTE[GetSize()];
int iWrittenOffset = 0;
int iSDBInfoSize = vecSDBInfos.size();
//write size
memcpy( m_pSerializedStream, &iSDBInfoSize, sizeof(int) );
iWrittenOffset += sizeof(int);
for(int i = 0; i < iSDBInfoSize; ++i)
{
vecSDBInfos[i].Serialize( m_pSerializedStream + iWrittenOffset );
iWrittenOffset += vecSDBInfos[i].GetSerializedSize();
}
return m_pSerializedStream;
}
std::vector<TSupplementaryDataBlockInfo> vecSDBInfos;
private:
BYTE* m_pSerializedStream;
} TPerFileSDBInfo;
typedef boost::unordered_map<std::string, TPerFileSDBInfo > TPackageSDBMap; //key: related map name
TPackageSDBMap m_mapPackageSDB;
};
#endif //__INC_CLIENTPACKAGE_CRYPTINFO_H
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,232 @@
#include "stdafx.h"
#include "config.h"
#include "DragonLair.h"
#include "entity.h"
#include "sectree_manager.h"
#include "char.h"
#include "guild.h"
#include "locale_service.h"
#include "regen.h"
#include "log.h"
#include "utils.h"
struct FWarpToDragronLairWithGuildMembers
{
DWORD dwGuildID;
long mapIndex;
long x, y;
FWarpToDragronLairWithGuildMembers( DWORD guildID, long map, long X, long Y )
: dwGuildID(guildID), mapIndex(map), x(X), y(Y)
{
}
void operator()(LPENTITY ent)
{
if (NULL != ent && true == ent->IsType(ENTITY_CHARACTER))
{
LPCHARACTER pChar = static_cast<LPCHARACTER>(ent);
if (true == pChar->IsPC())
{
if (NULL != pChar->GetGuild())
{
if (dwGuildID == pChar->GetGuild()->GetID())
{
pChar->WarpSet(x, y, mapIndex);
}
}
}
}
}
};
struct FWarpToVillage
{
void operator() (LPENTITY ent)
{
if (NULL != ent)
{
LPCHARACTER pChar = static_cast<LPCHARACTER>(ent);
if (NULL != pChar)
{
if (true == pChar->IsPC())
{
pChar->GoHome();
}
}
}
}
};
EVENTINFO(tag_DragonLair_Collapse_EventInfo)
{
int step;
CDragonLair* pLair;
long InstanceMapIndex;
tag_DragonLair_Collapse_EventInfo()
: step( 0 )
, pLair( 0 )
, InstanceMapIndex( 0 )
{
}
};
EVENTFUNC( DragonLair_Collapse_Event )
{
tag_DragonLair_Collapse_EventInfo* pInfo = dynamic_cast<tag_DragonLair_Collapse_EventInfo*>(event->info);
if ( pInfo == NULL )
{
sys_err( "DragonLair_Collapse_Event> <Factor> Null pointer" );
return 0;
}
if (0 == pInfo->step)
{
char buf[512];
snprintf(buf, 512, LC_TEXT("용가리가 %d 초만에 죽어써효ㅠㅠ"), pInfo->pLair->GetEstimatedTime());
SendNoticeMap(buf, pInfo->InstanceMapIndex, true);
pInfo->step++;
return PASSES_PER_SEC( 30 );
}
else if (1 == pInfo->step)
{
LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap( pInfo->InstanceMapIndex );
if (NULL != pMap)
{
FWarpToVillage f;
pMap->for_each( f );
}
pInfo->step++;
return PASSES_PER_SEC( 30 );
}
else
{
SECTREE_MANAGER::instance().DestroyPrivateMap( pInfo->InstanceMapIndex );
M2_DELETE(pInfo->pLair);
}
return 0;
}
CDragonLair::CDragonLair(DWORD guildID, long BaseMapID, long PrivateMapID)
: GuildID_(guildID), BaseMapIndex_(BaseMapID), PrivateMapIndex_(PrivateMapID)
{
StartTime_ = get_global_time();
}
CDragonLair::~CDragonLair()
{
}
DWORD CDragonLair::GetEstimatedTime() const
{
return get_global_time() - StartTime_;
}
void CDragonLair::OnDragonDead(LPCHARACTER pDragon)
{
sys_log(0, "DragonLair: 도라곤이 죽어써효");
LogManager::instance().DragonSlayLog( GuildID_, pDragon->GetMobTable().dwVnum, StartTime_, get_global_time() );
}
CDragonLairManager::CDragonLairManager()
{
}
CDragonLairManager::~CDragonLairManager()
{
}
bool CDragonLairManager::Start(long MapIndexFrom, long BaseMapIndex, DWORD GuildID)
{
long instanceMapIndex = SECTREE_MANAGER::instance().CreatePrivateMap(BaseMapIndex);
if (instanceMapIndex == 0) {
sys_err("CDragonLairManager::Start() : no private map index available");
return false;
}
LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(MapIndexFrom);
if (NULL != pMap)
{
LPSECTREE_MAP pTargetMap = SECTREE_MANAGER::instance().GetMap(BaseMapIndex);
if (NULL == pTargetMap)
{
return false;
}
const TMapRegion* pRegionInfo = SECTREE_MANAGER::instance().GetMapRegion( pTargetMap->m_setting.iIndex );
if (NULL != pRegionInfo)
{
FWarpToDragronLairWithGuildMembers f(GuildID, instanceMapIndex, 844000, 1066900);
pMap->for_each( f );
LairMap_.emplace(GuildID, M2_NEW CDragonLair(GuildID, BaseMapIndex, instanceMapIndex));
std::string strMapBasePath( LocaleService_GetMapPath() );
strMapBasePath += "/" + pRegionInfo->strMapName + "/instance_regen.txt";
sys_log(0, "%s", strMapBasePath.c_str());
regen_do(strMapBasePath.c_str(), instanceMapIndex, pTargetMap->m_setting.iBaseX, pTargetMap->m_setting.iBaseY, NULL, true);
return true;
}
}
return false;
}
void CDragonLairManager::OnDragonDead(LPCHARACTER pDragon, DWORD KillerGuildID)
{
if (NULL == pDragon)
return;
if (false == pDragon->IsMonster())
return;
boost::unordered_map<DWORD, CDragonLair*>::iterator iter = LairMap_.find( KillerGuildID );
if (LairMap_.end() == iter)
{
return;
}
LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap( pDragon->GetMapIndex() );
if (NULL == iter->second || NULL == pMap)
{
LairMap_.erase( iter );
return;
}
iter->second->OnDragonDead( pDragon );
tag_DragonLair_Collapse_EventInfo* info;
info = AllocEventInfo<tag_DragonLair_Collapse_EventInfo>();
info->step = 0;
info->pLair = iter->second;
info->InstanceMapIndex = pDragon->GetMapIndex();
event_create(DragonLair_Collapse_Event, info, PASSES_PER_SEC(10));
LairMap_.erase( iter );
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,36 @@
#include <boost/unordered_map.hpp>
#include "../../common/stl.h"
class CDragonLair
{
public:
CDragonLair (DWORD dwGuildID, long BaseMapID, long PrivateMapID);
virtual ~CDragonLair ();
DWORD GetEstimatedTime () const;
void OnDragonDead (LPCHARACTER pDragon);
private:
DWORD StartTime_;
DWORD GuildID_;
[[maybe_unused]] long BaseMapIndex_;
[[maybe_unused]] long PrivateMapIndex_;
};
class CDragonLairManager : public singleton<CDragonLairManager>
{
public:
CDragonLairManager ();
virtual ~CDragonLairManager ();
bool Start (long MapIndexFrom, long BaseMapIndex, DWORD GuildID);
void OnDragonDead (LPCHARACTER pDragon, DWORD KillerGuildID);
size_t GetLairCount () const { return LairMap_.size(); }
private:
boost::unordered_map<DWORD, CDragonLair*> LairMap_;
};
//martysama0134's 623a0779c74cb7565145d45548376308

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
#ifndef __INC_METIN_II_GAME_DRAGON_SOUL_H__
#define __INC_METIN_II_GAME_DRAGON_SOUL_H__
#include "../../common/length.h"
class CHARACTER;
class CItem;
class DragonSoulTable;
class DSManager : public singleton<DSManager>
{
public:
DSManager();
~DSManager();
bool ReadDragonSoulTableFile(const char * c_pszFileName);
void GetDragonSoulInfo(DWORD dwVnum, OUT BYTE& bType, OUT BYTE& bGrade, OUT BYTE& bStep, OUT BYTE& bRefine) const;
WORD GetBasePosition(const LPITEM pItem) const;
bool IsValidCellForThisItem(const LPITEM pItem, const TItemPos& Cell) const;
int GetDuration(const LPITEM pItem) const;
bool ExtractDragonHeart(LPCHARACTER ch, LPITEM pItem, LPITEM pExtractor = NULL);
bool PullOut(LPCHARACTER ch, TItemPos DestCell, IN OUT LPITEM& pItem, LPITEM pExtractor = NULL);
bool DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_REFINE_GRID_SIZE]);
bool DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_REFINE_GRID_SIZE]);
bool DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_REFINE_GRID_SIZE]);
bool DragonSoulItemInitialize(LPITEM pItem);
bool IsTimeLeftDragonSoul(LPITEM pItem) const;
int LeftTime(LPITEM pItem) const;
bool ActivateDragonSoul(LPITEM pItem);
bool DeactivateDragonSoul(LPITEM pItem, bool bSkipRefreshOwnerActiveState = false);
bool IsActiveDragonSoul(LPITEM pItem) const;
private:
void SendRefineResultPacket(LPCHARACTER ch, BYTE bSubHeader, const TItemPos& pos);
void RefreshDragonSoulState(LPCHARACTER ch);
DWORD MakeDragonSoulVnum(BYTE bType, BYTE grade, BYTE step, BYTE refine);
bool PutAttributes(LPITEM pDS);
bool RefreshItemAttributes(LPITEM pItem);
DragonSoulTable* m_pTable;
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,62 @@
// Local Includes
#include "stdafx.h"
#include <cassert>
#include <cstdlib>
#include "FSM.h"
// Constructor
CFSM::CFSM()
{
// Initialize States
m_stateInitial.Set(this, &CFSM::BeginStateInitial, &CFSM::StateInitial, &CFSM::EndStateInitial);
// Initialize State Machine
m_pCurrentState = static_cast<CState *>(&m_stateInitial);
m_pNewState = NULL;
}
//======================================================================================================
// Global Functions
// Update
void CFSM::Update()
{
// Check New State
if (m_pNewState)
{
// Execute End State
m_pCurrentState->ExecuteEndState();
// Set New State
m_pCurrentState = m_pNewState;
m_pNewState = 0;
// Execute Begin State
m_pCurrentState->ExecuteBeginState();
}
// Execute State
m_pCurrentState->ExecuteState();
}
//======================================================================================================
// State Functions
// Is State
bool CFSM::IsState(CState & State) const
{
return (m_pCurrentState == &State);
}
// Goto State
bool CFSM::GotoState(CState & NewState)
{
if (IsState(NewState) && m_pNewState == &NewState)
return true;
// Set New State
m_pNewState = &NewState;
return true;
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,35 @@
#ifndef _fsm_fsm_h
#define _fsm_fsm_h
// Local Includes
#include "state.h"
// FSM Class
class CFSM
{
protected:
CState * m_pCurrentState; // Current State
CState * m_pNewState; // New State
CStateTemplate<CFSM> m_stateInitial; // Initial State
public:
// Constructor
CFSM();
// Destructor
virtual ~CFSM() {}
// Global Functions
virtual void Update();
// State Functions
bool IsState(CState &State) const;
bool GotoState(CState &NewState);
virtual void BeginStateInitial() {}
virtual void StateInitial() {}
virtual void EndStateInitial() {}
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,135 @@
#include "stdafx.h"
#include "FileMonitor_FreeBSD.h"
#include "../../libthecore/include/log.h"
#define INVALID_KERNEL_EVENT -1
FileMonitorFreeBSD::FileMonitorFreeBSD()
{
m_KernelEventQueue = INVALID_KERNEL_EVENT;
}
FileMonitorFreeBSD::~FileMonitorFreeBSD()
{
if( m_KernelEventQueue != INVALID_KERNEL_EVENT )
{
close ( m_KernelEventQueue );
m_KernelEventQueue = INVALID_KERNEL_EVENT;
}
TMonitorFileHashMap::iterator it;
for( it = m_FileLists.begin(); it != m_FileLists.end(); ++it )
{
close(it->second.fhMonitor);
}
m_FileLists.clear();
m_MonitoredEventLists.clear();
m_TriggeredEventLists.clear();
}
void FileMonitorFreeBSD::Update(DWORD dwPulses)
{
if( m_KernelEventQueue == INVALID_KERNEL_EVENT || m_FileLists.size() == 0 )
return;
int nEvent = kevent(m_KernelEventQueue, &m_TriggeredEventLists[0], (int)m_TriggeredEventLists.size(), &m_MonitoredEventLists[0], (int)m_MonitoredEventLists.size(), NULL );
if( nEvent == INVALID_KERNEL_EVENT )
{
return;
}
else if( nEvent > 0 )
{
for( int i = 0; i < nEvent; ++i )
{
int nEventFlags = m_MonitoredEventLists[i].flags;
eFileUpdatedOptions eUpdateOption = e_FileUpdate_None;
if (nEventFlags & EV_ERROR)
eUpdateOption = e_FileUpdate_Error;
else if (nEventFlags & NOTE_DELETE)
eUpdateOption = e_FileUpdate_Deleted;
else if (nEventFlags & NOTE_EXTEND || nEventFlags & NOTE_WRITE)
eUpdateOption = e_FileUpdate_Modified;
else if (nEventFlags & NOTE_ATTRIB)
eUpdateOption = e_FileUpdate_AttrModified;
else if (nEventFlags & NOTE_LINK)
eUpdateOption = e_FileUpdate_Linked;
else if (nEventFlags & NOTE_RENAME)
eUpdateOption = e_FileUpdate_Renamed;
else if (nEventFlags & NOTE_REVOKE)
eUpdateOption = e_FileUpdate_Revoked;
if( eUpdateOption != e_FileUpdate_None )
{
TMonitorFileHashMap::iterator it;
for( it = m_FileLists.begin(); it != m_FileLists.end(); ++it )
{
FileIOContext_FreeBSD& context = it->second;
if( context.idxToEventList == i )
{
std::string strModifedFileName = it->first;
context.pListenFunc( strModifedFileName, eUpdateOption );
break;
}
}
}
}
}
}
void FileMonitorFreeBSD::AddWatch(const std::string& strFileName, PFN_FileChangeListener pListenerFunc)
{
int iFileHandle = -1;
if( (iFileHandle = open(strFileName.c_str(), O_RDONLY)) == -1)
{
sys_err("FileMonitorFreeBSD:AddWatch : can`t open file(%s).\n", strFileName.c_str());
return;
}
//create kqueue if not exists
if( m_KernelEventQueue == INVALID_KERNEL_EVENT )
m_KernelEventQueue = kqueue();
if( m_KernelEventQueue == INVALID_KERNEL_EVENT )
{
sys_err("FileMonitorFreeBSD:AddWatch : failed to create kqueue.\n");
return;
}
TMonitorFileHashMap::iterator it = m_FileLists.find( strFileName );
if( it != m_FileLists.end() )
{
sys_log(0, "FileMonitorFreeBSD:AddWatch : trying to add duplicated watch on file(%s).\n", strFileName.c_str() );
return;
}
//set file context
FileIOContext_FreeBSD context;
{
context.fhMonitor = iFileHandle;
context.idxToEventList = (int)m_MonitoredEventLists.size();
context.pListenFunc = pListenerFunc;
}
m_FileLists[strFileName] = context;
//set events
struct kevent kTriggerEvent, kMonitorEvent;
EV_SET(&kTriggerEvent, iFileHandle, EVFILT_VNODE,
EV_ADD | EV_ENABLE | EV_ONESHOT,
NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_LINK | NOTE_RENAME | NOTE_REVOKE,
0, 0);
m_TriggeredEventLists.emplace_back(kTriggerEvent);
m_MonitoredEventLists.emplace_back(kMonitorEvent);
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,47 @@
#ifndef FILEMONITOR_FREEBSD_INCLUDED
#define FILEMONITOR_FREEBSD_INCLUDED
#include "IFileMonitor.h"
#include <unistd.h>
#include <sys/event.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/time.h>
struct FileIOContext_FreeBSD
{
int fhMonitor;
int idxToEventList; // evtTrigger & evtMonitor index should be same
PFN_FileChangeListener pListenFunc;
};
class FileMonitorFreeBSD : public IFileMonitor
{
private:
FileMonitorFreeBSD(); //hidden
public:
virtual ~FileMonitorFreeBSD();
void AddWatch (const std::string& strFileName, PFN_FileChangeListener pListenerFunc);
void Update (DWORD dwPulses);
static FileMonitorFreeBSD& Instance()
{
static FileMonitorFreeBSD theMonitor;
return theMonitor;
}
private:
typedef boost::unordered_map<std::string, FileIOContext_FreeBSD> TMonitorFileHashMap;
typedef std::vector<struct kevent> TEventList;
TMonitorFileHashMap m_FileLists;
TEventList m_MonitoredEventLists;
TEventList m_TriggeredEventLists;
int m_KernelEventQueue;
};
#endif //FILEMONITOR_FREEBSD_INCLUDED
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,31 @@
#ifndef IFILEMONITOR_INCLUDED
#define IFILEMONITOR_INCLUDED
//#include <boost/function.hpp>
#include <boost/unordered_map.hpp>
enum eFileUpdatedOptions
{
e_FileUpdate_None = -1,
e_FileUpdate_Error,
e_FileUpdate_Deleted,
e_FileUpdate_Modified,
e_FileUpdate_AttrModified,
e_FileUpdate_Linked,
e_FileUpdate_Renamed,
e_FileUpdate_Revoked,
};
// TODO : in FreeBSD boost function doesn`t work with boost bind
// so currently we only support for static function ptr only
//typedef boost::function< void ( const std::string&, eFileUpdatedOptions ) > PFN_FileChangeListener;
typedef void (* PFN_FileChangeListener )(const std::string&, eFileUpdatedOptions);
struct IFileMonitor
{
virtual void Update (DWORD dwPulses) = 0;
virtual void AddWatch (const std::string& strFileName, PFN_FileChangeListener pListenerFunc) = 0;
};
#endif // IFILEMONITOR_INCLUDED
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,228 @@
CC = clang
CXX = clang++
GAME_VERSION := $(shell cat ../../__REVISION__)
LBITS := $(shell getconf LONG_BIT)
GccMajorVersion := $(shell expr `$(CXX) -dumpversion | cut -f1 -d.`)
GccMinorVersion := $(shell expr `$(CXX) -dumpversion | cut -f2 -d.`)
GccMinorEGT8 := $(shell expr $(GccMinorVersion) \>= 8)
INCDIR =
LIBDIR =
BINDIR = ..
OBJDIR = .obj
$(shell if [ ! -d $(OBJDIR) ]; then mkdir $(OBJDIR); fi)
## LIST OF CONSTANTS BEGIN
ENABLE_GOOGLE_TEST = 0
ENABLE_LUA_5_VERSION = 0
ENABLE_GCC_AUTODEPEND = 1
ENABLE_STATIC = 0
## LIST OF CONSTANTS END
# Depend Path File
ifneq ($(ENABLE_GCC_AUTODEPEND), 1)
DEPFILE = Depend
endif
# Standard Libraries
LIBS = -lm -lmd
# Project Flags
CFLAGS = -m32 -g -Wall -O2 -pipe -fexceptions -fno-strict-aliasing -pthread -D_THREAD_SAFE -DNDEBUG
CFLAGS += -Wno-deprecated-declarations -Wno-nonnull-compare -Wno-deprecated-declarations -Wno-array-bounds -Wno-address
CFLAGS += -Wno-int-in-bool-context -Wno-format-truncation -Wno-stringop-truncation -Wno-sign-compare -Wno-deprecated-enum-enum-conversion
CXXFLAGS = -std=c++20
# for clang
ifneq '' '$(findstring clang++,$(CXX))'
CFLAGS += -Wno-invalid-source-encoding -Wno-deprecated-anon-enum-enum-conversion -Wno-unknown-warning-option
# for gcc
else ifneq '' '$(findstring g++,$(CXX))'
# for 32bit on 64bit
ifeq ($(LBITS),64)
CFLAGS += -L/usr/local/lib32/gcc12
CFLAGS += -Wl,-rpath=/usr/local/lib32/gcc12
else
# for 32bit on 32bit
CXXFLAGS += -Wl,-rpath=/usr/local/lib/gcc12
endif
endif
# MySQL
INCDIR += -I/usr/local/include/mysql
ifeq ($(LBITS),64)
LIBS += ../../../Extern/lib/libmysqlclient.a -lz
else
LIBS += /usr/local/lib/mysql/libmysqlclient.a /usr/lib/libz.a
endif
ifeq ($(ENABLE_STATIC), 1)
CFLAGS += -static
endif
ifeq ($(GccMinorEGT8), 1)
CFLAGS += -Wno-unused-local-typedefs
endif
# FreeBSD stack protector
CFLAGS += -fstack-protector-all
# Version defines
CFLAGS += -D__USER__=\"$(USER)\" -D__HOSTNAME__=\"$(HOSTNAME)\" -D__PWD__=\"$(PWD)\" -D__GAME_VERSION__=\"$(GAME_VERSION)\"
# Boost
INCDIR += -I../../../Extern/include/boost
# DevIL
INCDIR += -I../../../Extern/include/IL
LIBS += ../../../Extern/lib/libIL.a
# CryptoPP
LIBS += ../../../Extern/lib/libcryptopp.a
# GTest
ifeq ($(ENABLE_GOOGLE_TEST), 1)
LIBS += /usr/local/lib/libgtest.a
CFLAGS += -DENABLE_GOOGLE_TEST
endif
# OpenSSL
INCDIR += -I/usr/include
ifeq ($(LBITS),64)
LIBS += /usr/lib32/libcrypto.a /usr/lib32/libssl.a
else
LIBS += -lssl -lcrypto
endif
# Lua
CFLAGS += -DENABLE_LUA_5_VERSION=ENABLE_LUA_5_VERSION
ifeq ($(ENABLE_LUA_5_VERSION), 2)
INCDIR += -I../../liblua/5.2/install/include
LIBDIR += -L../../liblua/5.2/install/lib
LIBS += ../../liblua/5.2/install/lib/liblua.a
else
INCDIR += -I../../liblua/5.0/include
LIBDIR += -L../../liblua/5.0/lib
LIBS += ../../liblua/5.0/lib/liblua.a ../../liblua/5.0/lib/liblualib.a
endif
# Project Libraries
INCDIR += -I../../../Extern/include
INCDIR += -I/usr/local/include
LIBDIR += -L/usr/local/lib
LIBDIR += -L../../libthecore/lib -L../../libpoly -L../../libsql -L../../libgame/lib
LIBS += -lthecore -lpoly -lsql -lgame
# PROJECT_SRC_FILES BEGIN
MAINCPP = main.cpp
CFILE = minilzo.c
CPPFILE = FSM.cpp MarkConvert.cpp MarkImage.cpp MarkManager.cpp OXEvent.cpp ani.cpp\
arena.cpp banword.cpp battle.cpp blend_item.cpp buffer_manager.cpp building.cpp castle.cpp\
char.cpp char_affect.cpp char_battle.cpp char_change_empire.cpp char_horse.cpp char_item.cpp char_manager.cpp\
char_quickslot.cpp char_resist.cpp char_skill.cpp char_state.cpp PetSystem.cpp cmd.cpp cmd_emotion.cpp cmd_general.cpp\
cmd_gm.cpp cmd_oxevent.cpp config.cpp constants.cpp crc32.cpp cube.cpp db.cpp desc.cpp\
desc_client.cpp desc_manager.cpp desc_p2p.cpp dungeon.cpp empire_text_convert.cpp entity.cpp\
entity_view.cpp event.cpp event_queue.cpp exchange.cpp file_loader.cpp fishing.cpp gm.cpp guild.cpp\
guild_manager.cpp guild_war.cpp horse_rider.cpp horsename_manager.cpp input.cpp input_auth.cpp input_db.cpp\
input_login.cpp input_main.cpp input_p2p.cpp input_udp.cpp\
item.cpp item_addon.cpp item_attribute.cpp item_manager.cpp item_manager_idrange.cpp locale.cpp\
locale_service.cpp log.cpp login_data.cpp lzo_manager.cpp marriage.cpp\
messenger_manager.cpp mining.cpp mob_manager.cpp monarch.cpp motion.cpp over9refine.cpp p2p.cpp packet_info.cpp\
party.cpp polymorph.cpp priv_manager.cpp pvp.cpp\
questevent.cpp questlua.cpp questlua_affect.cpp questlua_arena.cpp questlua_building.cpp\
questlua_danceevent.cpp questlua_dungeon.cpp questlua_forked.cpp questlua_game.cpp questlua_global.cpp\
questlua_guild.cpp questlua_horse.cpp questlua_pet.cpp questlua_item.cpp questlua_marriage.cpp questlua_mgmt.cpp\
questlua_monarch.cpp questlua_npc.cpp questlua_oxevent.cpp questlua_party.cpp questlua_pc.cpp\
questlua_quest.cpp questlua_target.cpp questmanager.cpp questnpc.cpp questpc.cpp\
refine.cpp regen.cpp safebox.cpp sectree.cpp sectree_manager.cpp sequence.cpp shop.cpp\
skill.cpp start_position.cpp target.cpp text_file_loader.cpp trigger.cpp utils.cpp vector.cpp war_map.cpp\
wedding.cpp xmas_event.cpp version.cpp panama.cpp threeway_war.cpp map_location.cpp\
BlueDragon.cpp BlueDragon_Binder.cpp DragonLair.cpp questlua_dragonlair.cpp\
skill_power.cpp affect.cpp\
FileMonitor_FreeBSD.cpp ClientPackageCryptInfo.cpp cipher.cpp\
buff_on_attributes.cpp dragon_soul_table.cpp DragonSoul.cpp\
group_text_parse_tree.cpp char_dragonsoul.cpp questlua_dragonsoul.cpp\
shop_manager.cpp shopEx.cpp item_manager_read_tables.cpp shutdown_manager.cpp\
questlua_dnd.cpp
# PROJECT_SRC_FILES END
# PROJECT_OBJ_FILES BEGIN
COBJS = $(CFILE:%.c=$(OBJDIR)/%.o)
CPPOBJS = $(CPPFILE:%.cpp=$(OBJDIR)/%.o)
ifeq ($(ENABLE_GCC_AUTODEPEND), 1)
CDEPS = $(COBJS:%.o=%.d)
CPPDEPS = $(CPPOBJS:%.o=%.d)
endif
MAINOBJ = $(MAINCPP:%.cpp=$(OBJDIR)/%.o)
ifeq ($(ENABLE_GCC_AUTODEPEND), 1)
MAINDEPS = $(MAINOBJ:%.o=%.d)
endif
# PROJECT_OBJ_FILES END
# Target Paths
MAIN_TARGET = $(BINDIR)/game_r$(GAME_VERSION)
default: $(MAIN_TARGET)
$(OBJDIR)/%.o: %.c
@echo compiling $<
@$(CC) $(CFLAGS) $(INCDIR) -c $< -o $@
ifeq ($(ENABLE_GCC_AUTODEPEND), 1)
@$(CC) -MM -MG -MP $(CFLAGS) $(INCDIR) -c $< -o $(OBJDIR)/$*.d
@sed -i '' -e's/$*.o:/$(OBJDIR)\/$*.o:/g' $(OBJDIR)/$*.d
endif
$(OBJDIR)/%.o: %.cpp
@echo compiling $<
@$(CXX) $(CFLAGS) $(CXXFLAGS) $(INCDIR) -c $< -o $@
ifeq ($(ENABLE_GCC_AUTODEPEND), 1)
@$(CXX) -MM -MG -MP $(CFLAGS) $(CXXFLAGS) $(INCDIR) -c $< -o $(OBJDIR)/$*.d
@sed -i '' -e's/$*.o:/$(OBJDIR)\/$*.o:/g' $(OBJDIR)/$*.d
endif
limit_time:
@echo update limit time
@python update_limit_time.py
$(MAIN_TARGET): $(CPPOBJS) $(COBJS) $(MAINOBJ)
@echo linking $(MAIN_TARGET)
@$(CXX) $(CFLAGS) $(CXXFLAGS) $(LIBDIR) $(COBJS) $(CPPOBJS) $(MAINOBJ) $(LIBS) -o $(MAIN_TARGET)
symlink:
@ln -fs game_r$(GAME_VERSION) $(BINDIR)/game_symlink
strip:
@cp $(MAIN_TARGET) $(BINDIR)/game_r
@strip $(BINDIR)/game_r
clean:
@echo cleaning $(MAIN_TARGET) $(OBJDIR)
@rm -f $(COBJS) $(CPPOBJS) $(MAINOBJ)
ifeq ($(ENABLE_GCC_AUTODEPEND), 1)
@rm -f $(CDEPS) $(CPPDEPS) $(MAINDEPS)
endif
@rm -f $(BINDIR)/game_r*
dep:
ifeq ($(ENABLE_GCC_AUTODEPEND), 1)
@echo "Note: gcc autodepend is autodetected, so target dep skipped"
else
makedepend -f $(DEPFILE) $(INCDIR) -I/usr/include/c++/3.3 -I/usr/include/c++/4.2 -p$(OBJDIR)/ $(CPPFILE) $(CFILE) $(MAINCPP) 2> /dev/null > $(DEPFILE)
endif
# AUTO_DEPEND_CHECK BEGIN
ifeq ($(ENABLE_GCC_AUTODEPEND), 1)
sinclude $(CDEPS)
sinclude $(CPPDEPS)
sinclude $(MAINDEPS)
else
sinclude $(DEPFILE)
endif
# AUTO_DEPEND_CHECK END

View File

@ -0,0 +1,118 @@
#include "stdafx.h"
#include "MarkManager.h"
#ifdef __WIN32__
#include <direct.h>
#endif
#define OLD_MARK_INDEX_FILENAME "guild_mark.idx"
#define OLD_MARK_DATA_FILENAME "guild_mark.tga"
static Pixel * LoadOldGuildMarkImageFile()
{
FILE * fp = fopen(OLD_MARK_DATA_FILENAME, "rb");
if (!fp)
{
sys_err("cannot open %s", OLD_MARK_INDEX_FILENAME);
return NULL;
}
int dataSize = 512 * 512 * sizeof(Pixel);
Pixel * dataPtr = (Pixel *) malloc(dataSize);
fread(dataPtr, dataSize, 1, fp);
fclose(fp);
return dataPtr;
}
bool GuildMarkConvert(const std::vector<DWORD> & vecGuildID)
{
#ifndef __WIN32__
mkdir("mark", S_IRWXU);
#else
_mkdir("mark");
#endif
#ifndef __WIN32__
if (0 != access(OLD_MARK_INDEX_FILENAME, F_OK))
#else
if (0 != _access(OLD_MARK_INDEX_FILENAME, 0))
#endif
return true;
FILE* fp = fopen(OLD_MARK_INDEX_FILENAME, "r");
if (NULL == fp)
return false;
Pixel * oldImagePtr = LoadOldGuildMarkImageFile();
if (NULL == oldImagePtr)
{
fclose(fp);
return false;
}
sys_log(0, "Guild Mark Converting Start.");
char line[256];
DWORD guild_id;
DWORD mark_id;
Pixel mark[SGuildMark::SIZE];
while (fgets(line, sizeof(line)-1, fp))
{
sscanf(line, "%u %u", &guild_id, &mark_id);
if (find(vecGuildID.begin(), vecGuildID.end(), guild_id) == vecGuildID.end())
{
sys_log(0, " skipping guild ID %u", guild_id);
continue;
}
uint row = mark_id / 32;
uint col = mark_id % 32;
if (row >= 42)
{
sys_err("invalid mark_id %u", mark_id);
continue;
}
uint sx = col * 16;
uint sy = row * 12;
Pixel * src = oldImagePtr + sy * 512 + sx;
Pixel * dst = mark;
for (int y = 0; y != SGuildMark::HEIGHT; ++y)
{
for (int x = 0; x != SGuildMark::WIDTH; ++x)
*(dst++) = *(src+x);
src += 512;
}
CGuildMarkManager::instance().SaveMark(guild_id, (BYTE *) mark);
line[0] = '\0';
}
free(oldImagePtr);
fclose(fp);
#ifndef __WIN32__
system("mv -f guild_mark.idx guild_mark.idx.removable");
system("mv -f guild_mark.tga guild_mark.tga.removable");
#else
system("move /Y guild_mark.idx guild_mark.idx.removable");
system("move /Y guild_mark.tga guild_mark.tga.removable");
#endif
sys_log(0, "Guild Mark Converting Complete.");
return true;
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,293 @@
#include "stdafx.h"
#include "MarkImage.h"
#include "crc32.h"
#include "lzo_manager.h"
#define CLZO LZOManager
CGuildMarkImage * NewMarkImage()
{
return M2_NEW CGuildMarkImage;
}
void DeleteMarkImage(CGuildMarkImage * pkImage)
{
M2_DELETE(pkImage);
}
CGuildMarkImage::CGuildMarkImage()
: m_uImg(INVALID_HANDLE)
{
memset( &m_apxImage, 0, sizeof(m_apxImage) );
}
CGuildMarkImage::~CGuildMarkImage()
{
Destroy();
}
void CGuildMarkImage::Destroy()
{
if (INVALID_HANDLE == m_uImg)
return;
ilDeleteImages(1, &m_uImg);
m_uImg = INVALID_HANDLE;
}
void CGuildMarkImage::Create()
{
if (INVALID_HANDLE != m_uImg)
return;
ilGenImages(1, &m_uImg);
}
bool CGuildMarkImage::Save(const char* c_szFileName)
{
ilEnable(IL_FILE_OVERWRITE);
ilBindImage(m_uImg);
if (!ilSave(IL_TGA, (const ILstring)c_szFileName))
return false;
return true;
}
bool CGuildMarkImage::Build(const char * c_szFileName)
{
sys_log(0, "GuildMarkImage: creating new file %s", c_szFileName);
Destroy();
Create();
ilBindImage(m_uImg);
ilEnable(IL_ORIGIN_SET);
ilOriginFunc(IL_ORIGIN_UPPER_LEFT);
BYTE * data = (BYTE *) malloc(sizeof(Pixel) * WIDTH * HEIGHT);
memset(data, 0, sizeof(Pixel) * WIDTH * HEIGHT);
if (!ilTexImage(WIDTH, HEIGHT, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, data))
{
sys_err("GuildMarkImage: cannot initialize image");
return false;
}
free(data);
ilEnable(IL_FILE_OVERWRITE);
if (!ilSave(IL_TGA, (const ILstring)c_szFileName))
return false;
return true;
}
bool CGuildMarkImage::Load(const char * c_szFileName)
{
Destroy();
Create();
ilBindImage(m_uImg);
ilEnable(IL_ORIGIN_SET);
ilOriginFunc(IL_ORIGIN_UPPER_LEFT);
if (!ilLoad(IL_TYPE_UNKNOWN, (const ILstring) c_szFileName))
{
sys_err("GuildMarkImage: %s cannot open file.", c_szFileName);
return false;
}
if (ilGetInteger(IL_IMAGE_WIDTH) != WIDTH)
{
sys_err("GuildMarkImage: %s width must be %u", c_szFileName, WIDTH);
return false;
}
if (ilGetInteger(IL_IMAGE_HEIGHT) != HEIGHT)
{
sys_err("GuildMarkImage: %s height must be %u", c_szFileName, HEIGHT);
return false;
}
ilConvertImage(IL_BGRA, IL_UNSIGNED_BYTE);
BuildAllBlocks();
return true;
}
void CGuildMarkImage::PutData(UINT x, UINT y, UINT width, UINT height, void * data)
{
ilBindImage(m_uImg);
ilSetPixels(x, y, 0, width, height, 1, IL_BGRA, IL_UNSIGNED_BYTE, data);
}
void CGuildMarkImage::GetData(UINT x, UINT y, UINT width, UINT height, void * data)
{
ilBindImage(m_uImg);
ilCopyPixels(x, y, 0, width, height, 1, IL_BGRA, IL_UNSIGNED_BYTE, data);
}
// SERVER
bool CGuildMarkImage::SaveMark(DWORD posMark, BYTE * pbImage)
{
if (posMark >= MARK_TOTAL_COUNT)
{
sys_err("GuildMarkImage::CopyMarkFromData: Invalid mark position %u", posMark);
return false;
}
DWORD colMark = posMark % MARK_COL_COUNT;
DWORD rowMark = posMark / MARK_COL_COUNT;
printf("PutMark pos %u %ux%u\n", posMark, colMark * SGuildMark::WIDTH, rowMark * SGuildMark::HEIGHT);
PutData(colMark * SGuildMark::WIDTH, rowMark * SGuildMark::HEIGHT, SGuildMark::WIDTH, SGuildMark::HEIGHT, pbImage);
DWORD rowBlock = rowMark / SGuildMarkBlock::MARK_PER_BLOCK_HEIGHT;
DWORD colBlock = colMark / SGuildMarkBlock::MARK_PER_BLOCK_WIDTH;
Pixel apxBuf[SGuildMarkBlock::SIZE];
GetData(colBlock * SGuildMarkBlock::WIDTH, rowBlock * SGuildMarkBlock::HEIGHT, SGuildMarkBlock::WIDTH, SGuildMarkBlock::HEIGHT, apxBuf);
m_aakBlock[rowBlock][colBlock].Compress(apxBuf);
return true;
}
bool CGuildMarkImage::DeleteMark(DWORD posMark)
{
Pixel image[SGuildMark::SIZE];
memset(&image, 0, sizeof(image));
return SaveMark(posMark, (BYTE *) &image);
}
// CLIENT
bool CGuildMarkImage::SaveBlockFromCompressedData(DWORD posBlock, const BYTE * pbComp, DWORD dwCompSize)
{
if (posBlock >= BLOCK_TOTAL_COUNT)
return false;
Pixel apxBuf[SGuildMarkBlock::SIZE];
lzo_uint sizeBuf = sizeof(apxBuf);
if (LZO_E_OK != lzo1x_decompress_safe(pbComp, dwCompSize, (BYTE *) apxBuf, &sizeBuf, CLZO::Instance().GetWorkMemory()))
{
sys_err("GuildMarkImage::CopyBlockFromCompressedData: cannot decompress, compressed size = %u", dwCompSize);
return false;
}
if (sizeBuf != sizeof(apxBuf))
{
sys_err("GuildMarkImage::CopyBlockFromCompressedData: image corrupted, decompressed size = %u", sizeBuf);
return false;
}
DWORD rowBlock = posBlock / BLOCK_COL_COUNT;
DWORD colBlock = posBlock % BLOCK_COL_COUNT;
PutData(colBlock * SGuildMarkBlock::WIDTH, rowBlock * SGuildMarkBlock::HEIGHT, SGuildMarkBlock::WIDTH, SGuildMarkBlock::HEIGHT, apxBuf);
m_aakBlock[rowBlock][colBlock].CopyFrom(pbComp, dwCompSize, GetCRC32((const char *) apxBuf, sizeof(Pixel) * SGuildMarkBlock::SIZE));
return true;
}
void CGuildMarkImage::BuildAllBlocks()
{
Pixel apxBuf[SGuildMarkBlock::SIZE];
sys_log(0, "GuildMarkImage::BuildAllBlocks");
for (UINT row = 0; row < BLOCK_ROW_COUNT; ++row)
for (UINT col = 0; col < BLOCK_COL_COUNT; ++col)
{
GetData(col * SGuildMarkBlock::WIDTH, row * SGuildMarkBlock::HEIGHT, SGuildMarkBlock::WIDTH, SGuildMarkBlock::HEIGHT, apxBuf);
m_aakBlock[row][col].Compress(apxBuf);
}
}
DWORD CGuildMarkImage::GetEmptyPosition()
{
SGuildMark kMark;
for (DWORD row = 0; row < MARK_ROW_COUNT; ++row)
{
for (DWORD col = 0; col < MARK_COL_COUNT; ++col)
{
GetData(col * SGuildMark::WIDTH, row * SGuildMark::HEIGHT, SGuildMark::WIDTH, SGuildMark::HEIGHT, kMark.m_apxBuf);
if (kMark.IsEmpty())
return (row * MARK_COL_COUNT + col);
}
}
return INVALID_MARK_POSITION;
}
void CGuildMarkImage::GetDiffBlocks(const DWORD * crcList, std::map<BYTE, const SGuildMarkBlock *> & mapDiffBlocks)
{
BYTE posBlock = 0;
for (DWORD row = 0; row < BLOCK_ROW_COUNT; ++row)
for (DWORD col = 0; col < BLOCK_COL_COUNT; ++col)
{
if (m_aakBlock[row][col].m_crc != *crcList)
{
mapDiffBlocks.emplace(posBlock, &m_aakBlock[row][col]);
}
++crcList;
++posBlock;
}
}
void CGuildMarkImage::GetBlockCRCList(DWORD * crcList)
{
for (DWORD row = 0; row < BLOCK_ROW_COUNT; ++row)
for (DWORD col = 0; col < BLOCK_COL_COUNT; ++col)
*(crcList++) = m_aakBlock[row][col].GetCRC();
}
////////////////////////////////////////////////////////////////////////////////
void SGuildMark::Clear()
{
for (DWORD iPixel = 0; iPixel < SIZE; ++iPixel)
m_apxBuf[iPixel] = 0xff000000;
}
bool SGuildMark::IsEmpty()
{
for (DWORD iPixel = 0; iPixel < SIZE; ++iPixel)
if (m_apxBuf[iPixel] != 0x00000000)
return false;
return true;
}
////////////////////////////////////////////////////////////////////////////////
DWORD SGuildMarkBlock::GetCRC() const
{
return m_crc;
}
void SGuildMarkBlock::CopyFrom(const BYTE * pbCompBuf, DWORD dwCompSize, DWORD crc)
{
if (dwCompSize > MAX_COMP_SIZE)
return;
m_sizeCompBuf = dwCompSize;
thecore_memcpy(m_abCompBuf, pbCompBuf, dwCompSize);
m_crc = crc;
//printf("SGuildMarkBlock::CopyFrom: %u > %u crc %u\n", sizeof(Pixel) * SGuildMarkBlock::SIZE, m_sizeCompBuf, m_crc);
}
void SGuildMarkBlock::Compress(const Pixel * pxBuf)
{
m_sizeCompBuf = MAX_COMP_SIZE;
if (LZO_E_OK != lzo1x_1_compress((const BYTE *) pxBuf, sizeof(Pixel) * SGuildMarkBlock::SIZE, m_abCompBuf, &m_sizeCompBuf, CLZO::Instance().GetWorkMemory()))
{
sys_err("SGuildMarkBlock::Compress: Error! %u > %u", sizeof(Pixel) * SGuildMarkBlock::SIZE, m_sizeCompBuf);
return;
}
//sys_log(0, "SGuildMarkBlock::Compress %u > %u", sizeof(Pixel) * SGuildMarkBlock::SIZE, m_sizeCompBuf);
m_crc = GetCRC32((const char *) pxBuf, sizeof(Pixel) * SGuildMarkBlock::SIZE);
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,112 @@
#ifndef __INC_METIN_II_MARKIMAGE_H__
#define __INC_METIN_II_MARKIMAGE_H__
#include <IL/il.h>
#include "minilzo.h"
typedef unsigned long Pixel;
struct SGuildMark
{
enum
{
WIDTH = 16,
HEIGHT = 12,
SIZE = WIDTH * HEIGHT,
};
///////////////////////////////////////////////////////////////////////////////
Pixel m_apxBuf[SIZE];
///////////////////////////////////////////////////////////////////////////////
void Clear();
bool IsEmpty();
};
struct SGuildMarkBlock
{
enum
{
MARK_PER_BLOCK_WIDTH = 4,
MARK_PER_BLOCK_HEIGHT = 4,
WIDTH = SGuildMark::WIDTH * MARK_PER_BLOCK_WIDTH,
HEIGHT = SGuildMark::HEIGHT * MARK_PER_BLOCK_HEIGHT,
SIZE = WIDTH * HEIGHT,
MAX_COMP_SIZE = (SIZE * sizeof(Pixel)) + ((SIZE * sizeof(Pixel)) >> 4) + 64 + 3
};
///////////////////////////////////////////////////////////////////////////////
Pixel m_apxBuf[SIZE];
BYTE m_abCompBuf[MAX_COMP_SIZE];
lzo_uint m_sizeCompBuf;
DWORD m_crc;
///////////////////////////////////////////////////////////////////////////////
DWORD GetCRC() const;
void CopyFrom(const BYTE * pbCompBuf, DWORD dwCompSize, DWORD crc);
void Compress(const Pixel * pxBuf);
};
class CGuildMarkImage
{
public:
enum
{
WIDTH = 512,
HEIGHT = 512,
BLOCK_ROW_COUNT = HEIGHT / SGuildMarkBlock::HEIGHT, // 10
BLOCK_COL_COUNT = WIDTH / SGuildMarkBlock::WIDTH, // 8
BLOCK_TOTAL_COUNT = BLOCK_ROW_COUNT * BLOCK_COL_COUNT, // 80
MARK_ROW_COUNT = BLOCK_ROW_COUNT * SGuildMarkBlock::MARK_PER_BLOCK_HEIGHT, // 40
MARK_COL_COUNT = BLOCK_COL_COUNT * SGuildMarkBlock::MARK_PER_BLOCK_WIDTH, // 32
MARK_TOTAL_COUNT = MARK_ROW_COUNT * MARK_COL_COUNT, // 1280
INVALID_MARK_POSITION = 0xffffffff,
};
CGuildMarkImage();
virtual ~CGuildMarkImage();
void Create();
void Destroy();
bool Build(const char * c_szFileName);
bool Save(const char* c_szFileName);
bool Load(const char* c_szFileName);
void PutData(UINT x, UINT y, UINT width, UINT height, void* data);
void GetData(UINT x, UINT y, UINT width, UINT height, void* data);
bool SaveMark(DWORD posMark, BYTE * pbMarkImage);
bool DeleteMark(DWORD posMark);
bool SaveBlockFromCompressedData(DWORD posBlock, const BYTE * pbComp, DWORD dwCompSize);
DWORD GetEmptyPosition();
void GetBlockCRCList(DWORD * crcList);
void GetDiffBlocks(const DWORD * crcList, std::map<BYTE, const SGuildMarkBlock *> & mapDiffBlocks);
private:
enum
{
INVALID_HANDLE = 0xffffffff,
};
void BuildAllBlocks();
SGuildMarkBlock m_aakBlock[BLOCK_ROW_COUNT][BLOCK_COL_COUNT];
Pixel m_apxImage[WIDTH * HEIGHT * sizeof(Pixel)];
ILuint m_uImg;
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,389 @@
#include "stdafx.h"
#include "MarkManager.h"
#include "crc32.h"
CGuildMarkImage * CGuildMarkManager::__NewImage()
{
return M2_NEW CGuildMarkImage;
}
void CGuildMarkManager::__DeleteImage(CGuildMarkImage * pkImgDel)
{
M2_DELETE(pkImgDel);
}
CGuildMarkManager::CGuildMarkManager()
{
for (DWORD i = 0; i < MAX_IMAGE_COUNT * CGuildMarkImage::MARK_TOTAL_COUNT; ++i)
m_setFreeMarkID.emplace(i);
}
CGuildMarkManager::~CGuildMarkManager()
{
for (std::map<DWORD, CGuildMarkImage *>::iterator it = m_mapIdx_Image.begin(); it != m_mapIdx_Image.end(); ++it)
__DeleteImage(it->second);
m_mapIdx_Image.clear();
}
bool CGuildMarkManager::GetMarkImageFilename(DWORD imgIdx, std::string & path) const
{
if (imgIdx >= MAX_IMAGE_COUNT)
return false;
char buf[64];
snprintf(buf, sizeof(buf), "mark/%s_%u.tga", m_pathPrefix.c_str(), imgIdx);
path = buf;
return true;
}
void CGuildMarkManager::SetMarkPathPrefix(const char * prefix)
{
m_pathPrefix = prefix;
}
bool CGuildMarkManager::LoadMarkIndex()
{
char buf[64];
snprintf(buf, sizeof(buf), "mark/%s_index", m_pathPrefix.c_str());
FILE * fp = fopen(buf, "r");
if (!fp)
return false;
DWORD guildID;
DWORD markID;
char line[256];
while (fgets(line, sizeof(line)-1, fp))
{
sscanf(line, "%u %u", &guildID, &markID);
line[0] = '\0';
AddMarkIDByGuildID(guildID, markID);
}
LoadMarkImages();
fclose(fp);
return true;
}
bool CGuildMarkManager::SaveMarkIndex()
{
char buf[64];
snprintf(buf, sizeof(buf), "mark/%s_index", m_pathPrefix.c_str());
FILE * fp = fopen(buf, "w");
if (!fp)
{
sys_err("MarkManager::SaveMarkIndex: cannot open index file.");
return false;
}
for (std::map<DWORD, DWORD>::iterator it = m_mapGID_MarkID.begin(); it != m_mapGID_MarkID.end(); ++it)
fprintf(fp, "%u %u\n", it->first, it->second);
fclose(fp);
sys_log(0, "MarkManager::SaveMarkIndex: index count %d", m_mapGID_MarkID.size());
return true;
}
void CGuildMarkManager::LoadMarkImages()
{
bool isMarkExists[MAX_IMAGE_COUNT];
memset(isMarkExists, 0, sizeof(isMarkExists));
for (std::map<DWORD, DWORD>::iterator it = m_mapGID_MarkID.begin(); it != m_mapGID_MarkID.end(); ++it)
{
DWORD markID = it->second;
if (markID < MAX_IMAGE_COUNT * CGuildMarkImage::MARK_TOTAL_COUNT)
isMarkExists[markID / CGuildMarkImage::MARK_TOTAL_COUNT] = true;
}
for (DWORD i = 0; i < MAX_IMAGE_COUNT; ++i)
if (isMarkExists[i])
__GetImage(i);
}
void CGuildMarkManager::SaveMarkImage(DWORD imgIdx)
{
std::string path;
if (GetMarkImageFilename(imgIdx, path))
if (!__GetImage(imgIdx)->Save(path.c_str()))
sys_err("%s Save failed\n", path.c_str());
}
CGuildMarkImage * CGuildMarkManager::__GetImage(DWORD imgIdx)
{
std::map<DWORD, CGuildMarkImage *>::iterator it = m_mapIdx_Image.find(imgIdx);
if (it == m_mapIdx_Image.end())
{
std::string imagePath;
if (GetMarkImageFilename(imgIdx, imagePath))
{
CGuildMarkImage * pkImage = __NewImage();
m_mapIdx_Image.emplace(imgIdx, pkImage);
if (!pkImage->Load(imagePath.c_str()))
{
pkImage->Build(imagePath.c_str());
pkImage->Load(imagePath.c_str());
}
return pkImage;
}
else
return NULL;
}
else
return it->second;
}
bool CGuildMarkManager::AddMarkIDByGuildID(DWORD guildID, DWORD markID)
{
if (markID >= MAX_IMAGE_COUNT * CGuildMarkImage::MARK_TOTAL_COUNT)
return false;
//sys_log(0, "MarkManager: guild_id=%d mark_id=%d", guildID, markID);
m_mapGID_MarkID.emplace(guildID, markID);
m_setFreeMarkID.erase(markID);
return true;
}
DWORD CGuildMarkManager::GetMarkID(DWORD guildID)
{
std::map<DWORD, DWORD>::iterator it = m_mapGID_MarkID.find(guildID);
if (it == m_mapGID_MarkID.end())
return INVALID_MARK_ID;
return it->second;
}
DWORD CGuildMarkManager::__AllocMarkID(DWORD guildID)
{
std::set<DWORD>::iterator it = m_setFreeMarkID.lower_bound(0);
if (it == m_setFreeMarkID.end())
return INVALID_MARK_ID;
DWORD markID = *it;
DWORD imgIdx = markID / CGuildMarkImage::MARK_TOTAL_COUNT;
CGuildMarkImage * pkImage = __GetImage(imgIdx);
if (pkImage && AddMarkIDByGuildID(guildID, markID))
return markID;
return INVALID_MARK_ID;
}
DWORD CGuildMarkManager::GetMarkImageCount() const
{
return m_mapIdx_Image.size();
}
DWORD CGuildMarkManager::GetMarkCount() const
{
return m_mapGID_MarkID.size();
}
// SERVER
void CGuildMarkManager::CopyMarkIdx(char * pcBuf) const
{
WORD * pwBuf = (WORD *) pcBuf;
for (std::map<DWORD, DWORD>::const_iterator it = m_mapGID_MarkID.begin(); it != m_mapGID_MarkID.end(); ++it)
{
*(pwBuf++) = it->first; // guild id
*(pwBuf++) = it->second; // mark id
}
}
// SERVER
DWORD CGuildMarkManager::SaveMark(DWORD guildID, BYTE * pbMarkImage)
{
DWORD idMark;
if ((idMark = GetMarkID(guildID)) == INVALID_MARK_ID)
{
if ((idMark = __AllocMarkID(guildID)) == INVALID_MARK_ID)
{
sys_err("CGuildMarkManager: cannot alloc mark id %u", guildID);
return false;
}
else
sys_log(0, "SaveMark: mark id alloc %u", idMark);
}
else
sys_log(0, "SaveMark: mark id found %u", idMark);
DWORD imgIdx = (idMark / CGuildMarkImage::MARK_TOTAL_COUNT);
CGuildMarkImage * pkImage = __GetImage(imgIdx);
if (pkImage)
{
pkImage->SaveMark(idMark % CGuildMarkImage::MARK_TOTAL_COUNT, pbMarkImage);
SaveMarkImage(imgIdx);
SaveMarkIndex();
}
return idMark;
}
// SERVER
void CGuildMarkManager::DeleteMark(DWORD guildID)
{
std::map<DWORD, DWORD>::iterator it = m_mapGID_MarkID.find(guildID);
if (it == m_mapGID_MarkID.end())
return;
CGuildMarkImage * pkImage;
if ((pkImage = __GetImage(it->second / CGuildMarkImage::MARK_TOTAL_COUNT)) != NULL)
pkImage->DeleteMark(it->second % CGuildMarkImage::MARK_TOTAL_COUNT);
m_setFreeMarkID.emplace(it->second);
m_mapGID_MarkID.erase(it);
SaveMarkIndex();
}
// SERVER
void CGuildMarkManager::GetDiffBlocks(DWORD imgIdx, const DWORD * crcList, std::map<BYTE, const SGuildMarkBlock *> & mapDiffBlocks)
{
mapDiffBlocks.clear();
if (m_mapIdx_Image.end() == m_mapIdx_Image.find(imgIdx))
{
sys_err("invalid idx %u", imgIdx);
return;
}
CGuildMarkImage * p = __GetImage(imgIdx);
if (p)
p->GetDiffBlocks(crcList, mapDiffBlocks);
}
// CLIENT
bool CGuildMarkManager::SaveBlockFromCompressedData(DWORD imgIdx, DWORD posBlock, const BYTE * pbBlock, DWORD dwSize)
{
CGuildMarkImage * pkImage = __GetImage(imgIdx);
if (pkImage)
pkImage->SaveBlockFromCompressedData(posBlock, pbBlock, dwSize);
return false;
}
// CLIENT
bool CGuildMarkManager::GetBlockCRCList(DWORD imgIdx, DWORD * crcList)
{
if (m_mapIdx_Image.end() == m_mapIdx_Image.find(imgIdx))
{
sys_err("invalid idx %u", imgIdx);
return false;
}
CGuildMarkImage * p = __GetImage(imgIdx);
if (p)
p->GetBlockCRCList(crcList);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////
// Symbol
///////////////////////////////////////////////////////////////////////////////////////
const CGuildMarkManager::TGuildSymbol * CGuildMarkManager::GetGuildSymbol(DWORD guildID)
{
std::map<DWORD, TGuildSymbol>::iterator it = m_mapSymbol.find(guildID);
if (it == m_mapSymbol.end())
return NULL;
return &it->second;
}
bool CGuildMarkManager::LoadSymbol(const char* filename)
{
FILE* fp = fopen(filename, "rb");
if (!fp)
return true;
else
{
DWORD symbolCount;
fread(&symbolCount, 4, 1, fp);
for (DWORD i = 0; i < symbolCount; i++)
{
DWORD guildID;
DWORD dwSize;
fread(&guildID, 4, 1, fp);
fread(&dwSize, 4, 1, fp);
TGuildSymbol gs;
gs.raw.resize(dwSize);
fread(&gs.raw[0], 1, dwSize, fp);
gs.crc = GetCRC32(reinterpret_cast<const char*>(&gs.raw[0]), dwSize);
m_mapSymbol.emplace(guildID, gs);
}
}
fclose(fp);
return true;
}
void CGuildMarkManager::SaveSymbol(const char* filename)
{
FILE* fp = fopen(filename, "wb");
if (!fp)
{
sys_err("Cannot open Symbol file (name: %s)", filename);
return;
}
DWORD symbolCount = m_mapSymbol.size();
fwrite(&symbolCount, 4, 1, fp);
for (std::map<DWORD, TGuildSymbol>::iterator it = m_mapSymbol.begin(); it != m_mapSymbol.end(); ++it)
{
DWORD guildID = it->first;
DWORD dwSize = it->second.raw.size();
fwrite(&guildID, 4, 1, fp);
fwrite(&dwSize, 4, 1, fp);
fwrite(&it->second.raw[0], 1, dwSize, fp);
}
fclose(fp);
}
void CGuildMarkManager::UploadSymbol(DWORD guildID, int iSize, const BYTE* pbyData)
{
sys_log(0, "GuildSymbolUpload guildID %u Size %d", guildID, iSize);
if (m_mapSymbol.find(guildID) == m_mapSymbol.end())
m_mapSymbol.emplace(guildID, TGuildSymbol());
TGuildSymbol& rSymbol = m_mapSymbol[guildID];
rSymbol.raw.clear();
if (iSize > 0)
{
rSymbol.raw.reserve(iSize);
std::copy(pbyData, (pbyData + iSize), std::back_inserter(rSymbol.raw));
rSymbol.crc = GetCRC32(reinterpret_cast<const char*>(pbyData), iSize);
}
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,82 @@
#ifndef __INC_METIN_II_GUILDLIB_MARK_MANAGER_H__
#define __INC_METIN_II_GUILDLIB_MARK_MANAGER_H__
#include "MarkImage.h"
class CGuildMarkManager : public singleton<CGuildMarkManager>
{
public:
enum
{
MAX_IMAGE_COUNT = 5,
INVALID_MARK_ID = 0xffffffff,
};
// Symbol
struct TGuildSymbol
{
DWORD crc;
std::vector<BYTE> raw;
};
CGuildMarkManager();
virtual ~CGuildMarkManager();
const TGuildSymbol * GetGuildSymbol(DWORD GID);
bool LoadSymbol(const char* filename);
void SaveSymbol(const char* filename);
void UploadSymbol(DWORD guildID, int iSize, const BYTE* pbyData);
// Mark
void SetMarkPathPrefix(const char * prefix);
bool LoadMarkIndex();
bool SaveMarkIndex();
void LoadMarkImages();
void SaveMarkImage(DWORD imgIdx);
bool GetMarkImageFilename(DWORD imgIdx, std::string & path) const;
bool AddMarkIDByGuildID(DWORD guildID, DWORD markID);
DWORD GetMarkImageCount() const;
DWORD GetMarkCount() const;
DWORD GetMarkID(DWORD guildID);
// SERVER
void CopyMarkIdx(char * pcBuf) const;
DWORD SaveMark(DWORD guildID, BYTE * pbMarkImage);
void DeleteMark(DWORD guildID);
void GetDiffBlocks(DWORD imgIdx, const DWORD * crcList, std::map<BYTE, const SGuildMarkBlock *> & mapDiffBlocks);
// CLIENT
bool SaveBlockFromCompressedData(DWORD imgIdx, DWORD idBlock, const BYTE * pbBlock, DWORD dwSize);
bool GetBlockCRCList(DWORD imgIdx, DWORD * crcList);
private:
// Mark
CGuildMarkImage * __NewImage();
void __DeleteImage(CGuildMarkImage * pkImgDel);
DWORD __AllocMarkID(DWORD guildID);
CGuildMarkImage * __GetImage(DWORD imgIdx);
CGuildMarkImage * __GetImagePtr(DWORD idMark);
std::map<DWORD, CGuildMarkImage *> m_mapIdx_Image; // index = image index
std::map<DWORD, DWORD> m_mapGID_MarkID; // index = guild id
std::set<DWORD> m_setFreeMarkID;
std::string m_pathPrefix;
private:
// Symbol
std::map<DWORD, TGuildSymbol> m_mapSymbol;
};
#endif
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,432 @@
#include "stdafx.h"
#include "constants.h"
#include "config.h"
#include "questmanager.h"
#include "start_position.h"
#include "packet.h"
#include "buffer_manager.h"
#include "log.h"
#include "char.h"
#include "char_manager.h"
#include "OXEvent.h"
#include "desc.h"
bool COXEventManager::Initialize()
{
m_timedEvent = NULL;
m_map_char.clear();
m_map_attender.clear();
m_vec_quiz.clear();
SetStatus(OXEVENT_FINISH);
return true;
}
void COXEventManager::Destroy()
{
CloseEvent();
m_map_char.clear();
m_map_attender.clear();
m_vec_quiz.clear();
SetStatus(OXEVENT_FINISH);
}
OXEventStatus COXEventManager::GetStatus()
{
BYTE ret = quest::CQuestManager::instance().GetEventFlag("oxevent_status");
switch (ret)
{
case 0 :
return OXEVENT_FINISH;
case 1 :
return OXEVENT_OPEN;
case 2 :
return OXEVENT_CLOSE;
case 3 :
return OXEVENT_QUIZ;
default :
return OXEVENT_ERR;
}
return OXEVENT_ERR;
}
void COXEventManager::SetStatus(OXEventStatus status)
{
BYTE val = 0;
switch (status)
{
case OXEVENT_OPEN :
val = 1;
break;
case OXEVENT_CLOSE :
val = 2;
break;
case OXEVENT_QUIZ :
val = 3;
break;
case OXEVENT_FINISH :
case OXEVENT_ERR :
default :
val = 0;
break;
}
quest::CQuestManager::instance().RequestSetEventFlag("oxevent_status", val);
}
bool COXEventManager::Enter(LPCHARACTER pkChar)
{
if (GetStatus() == OXEVENT_FINISH)
{
sys_log(0, "OXEVENT : map finished. but char enter. %s", pkChar->GetName());
return false;
}
PIXEL_POSITION pos = pkChar->GetXYZ();
if (pos.x == 896500 && pos.y == 24600)
{
return EnterAttender(pkChar);
}
else if (pos.x == 896300 && pos.y == 28900)
{
return EnterAudience(pkChar);
}
else
{
sys_log(0, "OXEVENT : wrong pos enter %d %d", pos.x, pos.y);
return false;
}
return false;
}
bool COXEventManager::EnterAttender(LPCHARACTER pkChar)
{
DWORD pid = pkChar->GetPlayerID();
m_map_char.emplace(pid, pid);
m_map_attender.emplace(pid, pid);
return true;
}
bool COXEventManager::EnterAudience(LPCHARACTER pkChar)
{
DWORD pid = pkChar->GetPlayerID();
m_map_char.emplace(pid, pid);
return true;
}
bool COXEventManager::AddQuiz(unsigned char level, const char* pszQuestion, bool answer)
{
if (m_vec_quiz.size() < (size_t) level + 1)
m_vec_quiz.resize(level + 1);
struct tag_Quiz tmpQuiz;
tmpQuiz.level = level;
strlcpy(tmpQuiz.Quiz, pszQuestion, sizeof(tmpQuiz.Quiz));
tmpQuiz.answer = answer;
m_vec_quiz[level].emplace_back(tmpQuiz);
return true;
}
bool COXEventManager::ShowQuizList(LPCHARACTER pkChar)
{
int c = 0;
for (size_t i = 0; i < m_vec_quiz.size(); ++i)
{
for (size_t j = 0; j < m_vec_quiz[i].size(); ++j, ++c)
{
pkChar->ChatPacket(CHAT_TYPE_INFO, "%d %s %s", m_vec_quiz[i][j].level, m_vec_quiz[i][j].Quiz, m_vec_quiz[i][j].answer ? LC_TEXT("") : LC_TEXT("거짓"));
}
}
pkChar->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("총 퀴즈 수: %d"), c);
return true;
}
void COXEventManager::ClearQuiz()
{
for (unsigned int i = 0; i < m_vec_quiz.size(); ++i)
{
m_vec_quiz[i].clear();
}
m_vec_quiz.clear();
}
EVENTINFO(OXEventInfoData)
{
bool answer;
OXEventInfoData()
: answer( false )
{
}
};
EVENTFUNC(oxevent_timer)
{
static BYTE flag = 0;
OXEventInfoData* info = dynamic_cast<OXEventInfoData*>(event->info);
if ( info == NULL )
{
sys_err( "oxevent_timer> <Factor> Null pointer" );
return 0;
}
switch (flag)
{
case 0:
SendNoticeMap(LC_TEXT("10초뒤 판정하겠습니다."), OXEVENT_MAP_INDEX, true);
flag++;
return PASSES_PER_SEC(10);
case 1:
SendNoticeMap(LC_TEXT("정답은"), OXEVENT_MAP_INDEX, true);
if (info->answer == true)
{
COXEventManager::instance().CheckAnswer(true);
SendNoticeMap(LC_TEXT("O 입니다"), OXEVENT_MAP_INDEX, true);
}
else
{
COXEventManager::instance().CheckAnswer(false);
SendNoticeMap(LC_TEXT("X 입니다"), OXEVENT_MAP_INDEX, true);
}
SendNoticeMap(LC_TEXT("5초 뒤 틀리신 분들을 바깥으로 이동 시키겠습니다."), OXEVENT_MAP_INDEX, true);
flag++;
return PASSES_PER_SEC(5);
case 2:
COXEventManager::instance().WarpToAudience();
COXEventManager::instance().SetStatus(OXEVENT_CLOSE);
SendNoticeMap(LC_TEXT("다음 문제 준비해주세요."), OXEVENT_MAP_INDEX, true);
flag = 0;
break;
}
return 0;
}
bool COXEventManager::Quiz(unsigned char level, int timelimit)
{
if (m_vec_quiz.size() == 0) return false;
if (level > m_vec_quiz.size()) level = m_vec_quiz.size() - 1;
if (m_vec_quiz[level].size() <= 0) return false;
if (timelimit < 0) timelimit = 30;
int idx = number(0, m_vec_quiz[level].size()-1);
SendNoticeMap(LC_TEXT("문제 입니다."), OXEVENT_MAP_INDEX, true);
SendNoticeMap(m_vec_quiz[level][idx].Quiz, OXEVENT_MAP_INDEX, true);
SendNoticeMap(LC_TEXT("맞으면 O, 틀리면 X로 이동해주세요"), OXEVENT_MAP_INDEX, true);
if (m_timedEvent != NULL) {
event_cancel(&m_timedEvent);
}
OXEventInfoData* answer = AllocEventInfo<OXEventInfoData>();
answer->answer = m_vec_quiz[level][idx].answer;
timelimit -= 15;
m_timedEvent = event_create(oxevent_timer, answer, PASSES_PER_SEC(timelimit));
SetStatus(OXEVENT_QUIZ);
m_vec_quiz[level].erase(m_vec_quiz[level].begin()+idx);
return true;
}
bool COXEventManager::CheckAnswer(bool answer)
{
if (m_map_attender.size() <= 0) return true;
itertype(m_map_attender) iter = m_map_attender.begin();
itertype(m_map_attender) iter_tmp;
m_map_miss.clear();
int rect[4];
if (answer != true)
{
rect[0] = 892600;
rect[1] = 22900;
rect[2] = 896300;
rect[3] = 26400;
}
else
{
rect[0] = 896600;
rect[1] = 22900;
rect[2] = 900300;
rect[3] = 26400;
}
LPCHARACTER pkChar = NULL;
PIXEL_POSITION pos;
for (; iter != m_map_attender.end();)
{
pkChar = CHARACTER_MANAGER::instance().FindByPID(iter->second);
if (pkChar != NULL)
{
pos = pkChar->GetXYZ();
if (pos.x < rect[0] || pos.x > rect[2] || pos.y < rect[1] || pos.y > rect[3])
{
pkChar->EffectPacket(SE_FAIL);
iter_tmp = iter;
iter++;
m_map_attender.erase(iter_tmp);
m_map_miss.emplace(pkChar->GetPlayerID(), pkChar->GetPlayerID());
}
else
{
pkChar->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("정답입니다!"));
// pkChar->CreateFly(number(FLY_FIREWORK1, FLY_FIREWORK6), pkChar);
char chatbuf[256];
int len = snprintf(chatbuf, sizeof(chatbuf),
"%s %u %u", number(0, 1) == 1 ? "cheer1" : "cheer2", (DWORD)pkChar->GetVID(), 0);
if (len < 0 || len >= (int) sizeof(chatbuf))
len = sizeof(chatbuf) - 1;
++len;
TPacketGCChat pack_chat;
pack_chat.header = HEADER_GC_CHAT;
pack_chat.size = sizeof(TPacketGCChat) + len;
pack_chat.type = CHAT_TYPE_COMMAND;
pack_chat.id = 0;
TEMP_BUFFER buf;
buf.write(&pack_chat, sizeof(TPacketGCChat));
buf.write(chatbuf, len);
pkChar->PacketAround(buf.read_peek(), buf.size());
pkChar->EffectPacket(SE_SUCCESS);
++iter;
}
}
else
{
itertype(m_map_char) err = m_map_char.find(iter->first);
if (err != m_map_char.end()) m_map_char.erase(err);
itertype(m_map_miss) err2 = m_map_miss.find(iter->first);
if (err2 != m_map_miss.end()) m_map_miss.erase(err2);
iter_tmp = iter;
++iter;
m_map_attender.erase(iter_tmp);
}
}
return true;
}
void COXEventManager::WarpToAudience()
{
if (m_map_miss.size() <= 0) return;
itertype(m_map_miss) iter = m_map_miss.begin();
LPCHARACTER pkChar = NULL;
for (; iter != m_map_miss.end(); ++iter)
{
pkChar = CHARACTER_MANAGER::instance().FindByPID(iter->second);
if (pkChar != NULL)
{
switch ( number(0, 3))
{
case 0 : pkChar->Show(OXEVENT_MAP_INDEX, 896300, 28900); break;
case 1 : pkChar->Show(OXEVENT_MAP_INDEX, 890900, 28100); break;
case 2 : pkChar->Show(OXEVENT_MAP_INDEX, 896600, 20500); break;
case 3 : pkChar->Show(OXEVENT_MAP_INDEX, 902500, 28100); break;
default : pkChar->Show(OXEVENT_MAP_INDEX, 896300, 28900); break;
}
}
}
m_map_miss.clear();
}
bool COXEventManager::CloseEvent()
{
if (m_timedEvent != NULL) {
event_cancel(&m_timedEvent);
}
itertype(m_map_char) iter = m_map_char.begin();
LPCHARACTER pkChar = NULL;
for (; iter != m_map_char.end(); ++iter)
{
pkChar = CHARACTER_MANAGER::instance().FindByPID(iter->second);
if (pkChar != NULL)
pkChar->WarpSet(EMPIRE_START_X(pkChar->GetEmpire()), EMPIRE_START_Y(pkChar->GetEmpire()));
}
Initialize(); // @fixme157 (instead of simply doing m_map_char.clear();)
return true;
}
bool COXEventManager::LogWinner()
{
itertype(m_map_attender) iter = m_map_attender.begin();
for (; iter != m_map_attender.end(); ++iter)
{
LPCHARACTER pkChar = CHARACTER_MANAGER::instance().FindByPID(iter->second);
if (pkChar)
LogManager::instance().CharLog(pkChar, 0, "OXEVENT", "LastManStanding");
}
return true;
}
bool COXEventManager::GiveItemToAttender(DWORD dwItemVnum, BYTE count)
{
itertype(m_map_attender) iter = m_map_attender.begin();
for (; iter != m_map_attender.end(); ++iter)
{
LPCHARACTER pkChar = CHARACTER_MANAGER::instance().FindByPID(iter->second);
if (pkChar)
{
pkChar->AutoGiveItem(dwItemVnum, count);
LogManager::instance().ItemLog(pkChar->GetPlayerID(), 0, count, dwItemVnum, "OXEVENT_REWARD", "", pkChar->GetDesc()->GetHostName(), dwItemVnum);
}
}
return true;
}
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,64 @@
#define OXEVENT_MAP_INDEX 113
struct tag_Quiz
{
char level;
char Quiz[256];
bool answer;
};
enum OXEventStatus
{
OXEVENT_FINISH = 0,
OXEVENT_OPEN = 1,
OXEVENT_CLOSE = 2,
OXEVENT_QUIZ = 3,
OXEVENT_ERR = 0xff
};
class COXEventManager : public singleton<COXEventManager>
{
private :
std::map<DWORD, DWORD> m_map_char;
std::map<DWORD, DWORD> m_map_attender;
std::map<DWORD, DWORD> m_map_miss;
std::vector<std::vector<tag_Quiz> > m_vec_quiz;
LPEVENT m_timedEvent;
protected :
bool CheckAnswer();
bool EnterAudience(LPCHARACTER pChar);
bool EnterAttender(LPCHARACTER pChar);
public :
bool Initialize();
void Destroy();
OXEventStatus GetStatus();
void SetStatus(OXEventStatus status);
bool LoadQuizScript(const char* szFileName);
bool Enter(LPCHARACTER pChar);
bool CloseEvent();
void ClearQuiz();
bool AddQuiz(unsigned char level, const char* pszQuestion, bool answer);
bool ShowQuizList(LPCHARACTER pChar);
bool Quiz(unsigned char level, int timelimit);
bool GiveItemToAttender(DWORD dwItemVnum, BYTE count);
bool CheckAnswer(bool answer);
void WarpToAudience();
bool LogWinner();
DWORD GetAttenderCount() { return m_map_attender.size(); }
};
//martysama0134's 623a0779c74cb7565145d45548376308

View File

@ -0,0 +1,621 @@
#include "stdafx.h"
#include "config.h"
#include "utils.h"
#include "vector.h"
#include "char.h"
#include "sectree_manager.h"
#include "char_manager.h"
#include "mob_manager.h"
#include "PetSystem.h"
#include "../../common/VnumHelper.h"
#include "packet.h"
#include "item_manager.h"
#include "item.h"
EVENTINFO(petsystem_event_info)
{
CPetSystem* pPetSystem;
};
EVENTFUNC(petsystem_update_event)
{
petsystem_event_info* info = dynamic_cast<petsystem_event_info*>( event->info );
if ( info == NULL )
{
sys_err( "check_speedhack_event> <Factor> Null pointer" );
return 0;
}
CPetSystem* pPetSystem = info->pPetSystem;
if (NULL == pPetSystem)
return 0;
pPetSystem->Update(0);
return PASSES_PER_SEC(1) / 4;
}
///////////////////////////////////////////////////////////////////////////////////////
// CPetActor
///////////////////////////////////////////////////////////////////////////////////////
CPetActor::CPetActor(LPCHARACTER owner, DWORD vnum, DWORD options)
{
m_dwVnum = vnum;
m_dwVID = 0;
m_dwOptions = options;
m_dwLastActionTime = 0;
m_pkChar = 0;
m_pkOwner = owner;
m_originalMoveSpeed = 0;
m_dwSummonItemVID = 0;
m_dwSummonItemVnum = 0;
}
CPetActor::~CPetActor()
{
this->Unsummon(
#ifdef USE_ACTIVE_PET_SEAL_EFFECT
false
#endif
);
m_pkOwner = 0;
}
void CPetActor::SetName(const char* name)
{
std::string petName = m_pkOwner->GetName();
petName += "'s ";
petName += (name) ? name : "Pet";
if (IsSummoned())
m_pkChar->SetName(petName);
m_name = petName;
}
bool CPetActor::Mount()
{
if (0 == m_pkOwner)
return false;
if (true == HasOption(EPetOption_Mountable))
m_pkOwner->MountVnum(m_dwVnum);
return m_pkOwner->GetMountVnum() == m_dwVnum;;
}
void CPetActor::Unmount()
{
if (0 == m_pkOwner)
return;
if (m_pkOwner->IsHorseRiding())
m_pkOwner->StopRiding();
}
void CPetActor::Unsummon(
#ifdef USE_ACTIVE_PET_SEAL_EFFECT
bool updateSocket
#endif
)
{
if (true == this->IsSummoned())
{
this->ClearBuff();
this->SetSummonItem(NULL
#ifdef USE_ACTIVE_PET_SEAL_EFFECT
, updateSocket
#endif
);
if (NULL != m_pkOwner)
m_pkOwner->ComputePoints();
if (NULL != m_pkChar)
M2_DESTROY_CHARACTER(m_pkChar);
m_pkChar = 0;
m_dwVID = 0;
}
}
DWORD CPetActor::Summon(const char* petName, LPITEM pSummonItem, bool bSpawnFar)
{
long x = m_pkOwner->GetX();
long y = m_pkOwner->GetY();
long z = m_pkOwner->GetZ();
if (true == bSpawnFar)
{
x += (number(0, 1) * 2 - 1) * number(2000, 2500);
y += (number(0, 1) * 2 - 1) * number(2000, 2500);
}
else
{
x += number(-100, 100);
y += number(-100, 100);
}
if (0 != m_pkChar)
{
m_pkChar->Show (m_pkOwner->GetMapIndex(), x, y);
m_dwVID = m_pkChar->GetVID();
return m_dwVID;
}
m_pkChar = CHARACTER_MANAGER::instance().SpawnMob(
m_dwVnum,
m_pkOwner->GetMapIndex(),
x, y, z,
false, (int)(m_pkOwner->GetRotation()+180), false);
if (0 == m_pkChar)
{
sys_err("[CPetSystem::Summon] Failed to summon the pet. (vnum: %d)", m_dwVnum);
return 0;
}
m_pkChar->SetPet();
m_pkChar->SetEmpire(m_pkOwner->GetEmpire());
m_dwVID = m_pkChar->GetVID();
this->SetName(petName);
this->SetSummonItem(pSummonItem);
m_pkOwner->ComputePoints();
m_pkChar->Show(m_pkOwner->GetMapIndex(), x, y, z);
return m_dwVID;
}
bool CPetActor::_UpdatAloneActionAI(float fMinDist, float fMaxDist)
{
float fDist = number(fMinDist, fMaxDist);
float r = (float)number (0, 359);
float dest_x = GetOwner()->GetX() + fDist * cos(r);
float dest_y = GetOwner()->GetY() + fDist * sin(r);
m_pkChar->SetNowWalking(true);
if (!m_pkChar->IsStateMove() && m_pkChar->Goto(dest_x, dest_y))
m_pkChar->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
m_dwLastActionTime = get_dword_time();
return true;
}
bool CPetActor::_UpdateFollowAI()
{
if (0 == m_pkChar->m_pkMobData)
{
//sys_err("[CPetActor::_UpdateFollowAI] m_pkChar->m_pkMobData is NULL");
return false;
}
if (0 == m_originalMoveSpeed)
{
const CMob* mobData = CMobManager::Instance().Get(m_dwVnum);
if (0 != mobData)
m_originalMoveSpeed = mobData->m_table.sMovingSpeed;
}
float START_FOLLOW_DISTANCE = 300.0f;
float START_RUN_DISTANCE = 900.0f;
float RESPAWN_DISTANCE = 4500.f;
int APPROACH = 200;
bool bRun = false;
DWORD currentTime = get_dword_time();
long ownerX = m_pkOwner->GetX(); long ownerY = m_pkOwner->GetY();
long charX = m_pkChar->GetX(); long charY = m_pkChar->GetY();
float fDist = DISTANCE_APPROX(charX - ownerX, charY - ownerY);
if (fDist >= RESPAWN_DISTANCE)
{
float fOwnerRot = m_pkOwner->GetRotation() * 3.141592f / 180.f;
float fx = -APPROACH * cos(fOwnerRot);
float fy = -APPROACH * sin(fOwnerRot);
if (m_pkChar->Show(m_pkOwner->GetMapIndex(), ownerX + fx, ownerY + fy))
{
return true;
}
}
if (fDist >= START_FOLLOW_DISTANCE)
{
if( fDist >= START_RUN_DISTANCE)
{
bRun = true;
}
m_pkChar->SetNowWalking(!bRun);
Follow(APPROACH);
m_pkChar->SetLastAttacked(currentTime);
m_dwLastActionTime = currentTime;
}
else
m_pkChar->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
return true;
}
bool CPetActor::Update(DWORD deltaTime)
{
bool bResult = true;
if (m_pkOwner->IsDead() || (IsSummoned() && m_pkChar->IsDead())
|| NULL == ITEM_MANAGER::instance().FindByVID(this->GetSummonItemVID())
|| ITEM_MANAGER::instance().FindByVID(this->GetSummonItemVID())->GetOwner() != this->GetOwner()
)
{
this->Unsummon();
return true;
}
if (this->IsSummoned() && HasOption(EPetOption_Followable))
bResult = bResult && this->_UpdateFollowAI();
return bResult;
}
bool CPetActor::Follow(float fMinDistance)
{
if( !m_pkOwner || !m_pkChar)
return false;
float fOwnerX = m_pkOwner->GetX();
float fOwnerY = m_pkOwner->GetY();
float fPetX = m_pkChar->GetX();
float fPetY = m_pkChar->GetY();
float fDist = DISTANCE_SQRT(fOwnerX - fPetX, fOwnerY - fPetY);
if (fDist <= fMinDistance)
return false;
m_pkChar->SetRotationToXY(fOwnerX, fOwnerY);
float fx, fy;
float fDistToGo = fDist - fMinDistance;
GetDeltaByDegree(m_pkChar->GetRotation(), fDistToGo, &fx, &fy);
if (!m_pkChar->Goto((int)(fPetX+fx+0.5f), (int)(fPetY+fy+0.5f)) )
return false;
m_pkChar->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0, 0);
return true;
}
bool CPetActor::SetSummonItem(LPITEM pItem
#ifdef USE_ACTIVE_PET_SEAL_EFFECT
, bool updateSocket
#endif
)
{
if (!pItem)
{
#ifdef USE_ACTIVE_PET_SEAL_EFFECT
LPITEM pSummonItem = ITEM_MANAGER::instance().FindByVID(m_dwSummonItemVID);
if (pSummonItem && updateSocket)
pSummonItem->SetSocket(PET_SEAL_ACTIVE_SOCKET_IDX, false);
#endif
m_dwSummonItemVID = 0;
m_dwSummonItemVnum = 0;
return false;
}
#ifdef USE_ACTIVE_PET_SEAL_EFFECT
pItem->SetSocket(PET_SEAL_ACTIVE_SOCKET_IDX, true);
#endif
m_dwSummonItemVID = pItem->GetVID();
m_dwSummonItemVnum = pItem->GetVnum();
return true;
}
bool __PetCheckBuff(const CPetActor* pPetActor)
{
bool bMustHaveBuff = true;
switch (pPetActor->GetVnum())
{
case 34004:
case 34009:
if (!pPetActor->GetOwner()->GetDungeon())
bMustHaveBuff = false;
default:
break;
}
return bMustHaveBuff;
}
void CPetActor::GiveBuff()
{
if (!__PetCheckBuff(this))
return;
LPITEM item = ITEM_MANAGER::instance().FindByVID(m_dwSummonItemVID);
if (item)
item->ModifyPoints(true);
return ;
}
void CPetActor::ClearBuff()
{
if (NULL == m_pkOwner)
return ;
TItemTable* item_proto = ITEM_MANAGER::instance().GetTable(m_dwSummonItemVnum);
if (NULL == item_proto)
return;
if (!__PetCheckBuff(this)) // @fixme129
return;
for (int i = 0; i < ITEM_APPLY_MAX_NUM; i++)
{
if (item_proto->aApplies[i].bType == APPLY_NONE)
continue;
m_pkOwner->ApplyPoint(item_proto->aApplies[i].bType, -item_proto->aApplies[i].lValue);
}
return ;
}
///////////////////////////////////////////////////////////////////////////////////////
// CPetSystem
///////////////////////////////////////////////////////////////////////////////////////
CPetSystem::CPetSystem(LPCHARACTER owner)
{
// assert(0 != owner && "[CPetSystem::CPetSystem] Invalid owner");
m_pkOwner = owner;
m_dwUpdatePeriod = 400;
m_dwLastUpdateTime = 0;
}
CPetSystem::~CPetSystem()
{
Destroy();
}
void CPetSystem::Destroy()
{
for (TPetActorMap::iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter)
{
CPetActor* petActor = iter->second;
if (0 != petActor)
{
delete petActor;
}
}
event_cancel(&m_pkPetSystemUpdateEvent);
m_petActorMap.clear();
}
bool CPetSystem::Update(DWORD deltaTime)
{
bool bResult = true;
DWORD currentTime = get_dword_time();
if (m_dwUpdatePeriod > currentTime - m_dwLastUpdateTime)
return true;
std::vector <CPetActor*> v_garbageActor;
for (TPetActorMap::iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter)
{
CPetActor* petActor = iter->second;
if (0 != petActor && petActor->IsSummoned())
{
LPCHARACTER pPet = petActor->GetCharacter();
if (NULL == CHARACTER_MANAGER::instance().Find(pPet->GetVID()))
{
v_garbageActor.emplace_back(petActor);
}
else
{
bResult = bResult && petActor->Update(deltaTime);
}
}
}
for (std::vector<CPetActor*>::iterator it = v_garbageActor.begin(); it != v_garbageActor.end(); it++)
DeletePet(*it);
m_dwLastUpdateTime = currentTime;
return bResult;
}
void CPetSystem::DeletePet(DWORD mobVnum)
{
TPetActorMap::iterator iter = m_petActorMap.find(mobVnum);
if (m_petActorMap.end() == iter)
{
sys_err("[CPetSystem::DeletePet] Can't find pet on my list (VNUM: %d)", mobVnum);
return;
}
CPetActor* petActor = iter->second;
if (0 == petActor)
sys_err("[CPetSystem::DeletePet] Null Pointer (petActor)");
else
delete petActor;
m_petActorMap.erase(iter);
}
void CPetSystem::DeletePet(CPetActor* petActor)
{
for (TPetActorMap::iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter)
{
if (iter->second == petActor)
{
delete petActor;
m_petActorMap.erase(iter);
return;
}
}
sys_err("[CPetSystem::DeletePet] Can't find petActor(0x%x) on my list(size: %d) ", petActor, m_petActorMap.size());
}
void CPetSystem::Unsummon(DWORD vnum, bool bDeleteFromList)
{
CPetActor* actor = this->GetByVnum(vnum);
if (0 == actor)
{
sys_err("[CPetSystem::GetByVnum(%d)] Null Pointer (petActor)", vnum);
return;
}
actor->Unsummon();
if (true == bDeleteFromList)
this->DeletePet(actor);
bool bActive = false;
for (TPetActorMap::iterator it = m_petActorMap.begin(); it != m_petActorMap.end(); it++)
{
bActive |= it->second->IsSummoned();
}
if (false == bActive)
{
event_cancel(&m_pkPetSystemUpdateEvent);
m_pkPetSystemUpdateEvent = NULL;
}
}
void CPetSystem::UnsummonAll()
{
for (auto & iter : m_petActorMap)
{
auto * actor = iter.second;
if (actor)
actor->Unsummon();
}
bool bActive = false;
for (auto & it : m_petActorMap)
bActive |= it.second->IsSummoned();
if (!bActive)
{
event_cancel(&m_pkPetSystemUpdateEvent);
m_pkPetSystemUpdateEvent = nullptr;
}
}
CPetActor* CPetSystem::Summon(DWORD mobVnum, LPITEM pSummonItem, const char* petName, bool bSpawnFar, DWORD options)
{
CPetActor* petActor = this->GetByVnum(mobVnum);
if (0 == petActor)
{
petActor = M2_NEW CPetActor(m_pkOwner, mobVnum, options);
m_petActorMap.emplace(mobVnum, petActor);
}
#ifdef ENABLE_NEWSTUFF
DWORD petVID = petActor->Summon(petName, pSummonItem, bSpawnFar);
if (!petVID)
sys_err("[CPetSystem::Summon(%d)] Null Pointer (petVID)", pSummonItem);
#endif
if (NULL == m_pkPetSystemUpdateEvent)
{
petsystem_event_info* info = AllocEventInfo<petsystem_event_info>();
info->pPetSystem = this;
m_pkPetSystemUpdateEvent = event_create(petsystem_update_event, info, PASSES_PER_SEC(1) / 4);
}
return petActor;
}
CPetActor* CPetSystem::GetByVID(DWORD vid) const
{
CPetActor* petActor = 0;
bool bFound = false;
for (TPetActorMap::const_iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter)
{
petActor = iter->second;
if (0 == petActor)
{
sys_err("[CPetSystem::GetByVID(%d)] Null Pointer (petActor)", vid);
continue;
}
bFound = petActor->GetVID() == vid;
if (true == bFound)
break;
}
return bFound ? petActor : 0;
}
CPetActor* CPetSystem::GetByVnum(DWORD vnum) const
{
CPetActor* petActor = 0;
TPetActorMap::const_iterator iter = m_petActorMap.find(vnum);
if (m_petActorMap.end() != iter)
petActor = iter->second;
return petActor;
}
size_t CPetSystem::CountSummoned() const
{
size_t count = 0;
for (TPetActorMap::const_iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter)
{
CPetActor* petActor = iter->second;
if (0 != petActor)
{
if (petActor->IsSummoned())
++count;
}
}
return count;
}
void CPetSystem::RefreshBuff()
{
for (TPetActorMap::const_iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter)
{
CPetActor* petActor = iter->second;
if (petActor && petActor->IsSummoned())
petActor->GiveBuff();
}
}
//martysama0134's 623a0779c74cb7565145d45548376308

Some files were not shown because too many files have changed in this diff Show More