- initial commit old TinNS (the gmake version) tinns-gmake
authorAkiko <akiko@linux-addicted.net>
Sun, 17 May 2015 06:08:26 +0000 (08:08 +0200)
committerAkiko <akiko@linux-addicted.net>
Sun, 17 May 2015 06:08:26 +0000 (08:08 +0200)
398 files changed:
docs/NPCs.txt [new file with mode: 0644]
docs/Neocron1.ChatProtocol.pdf [new file with mode: 0644]
docs/Neocron1.MainProtocol.pdf [new file with mode: 0644]
docs/TinNS.QuickInstallation.pdf [new file with mode: 0644]
docs/current_test_commands.txt [new file with mode: 0644]
docs/how_npc_scripts_work.txt [new file with mode: 0644]
docs/itemtypes.txt [new file with mode: 0644]
docs/lua_callbacks.xls [new file with mode: 0644]
docs/readme [new file with mode: 0644]
server/CHANGELOG [new file with mode: 0644]
server/LICENSE.txt [new file with mode: 0644]
server/Makefile [new file with mode: 0644]
server/WORK_IN_PROGRESS [new file with mode: 0644]
server/conf/commands.conf [new file with mode: 0644]
server/conf/gameserver.conf [new file with mode: 0644]
server/conf/global.conf [new file with mode: 0644]
server/conf/infoserver.conf [new file with mode: 0644]
server/conf/patchserver.conf [new file with mode: 0644]
server/data/scripts/lua/zippy.lua [new file with mode: 0644]
server/database/DB_v8/DB_v8_patch001.sql [new file with mode: 0644]
server/database/DB_v8/TinNS_GameDB_rev8_BaseData.sql [new file with mode: 0644]
server/database/DB_v8/changes.txt [new file with mode: 0644]
server/database/DB_v8/patch_gamedb_rev7_to_rev8.sql [new file with mode: 0644]
server/database/DB_v8/readme.txt [new file with mode: 0644]
server/database/DB_v8/unified_game DB_rev8.sql [new file with mode: 0644]
server/database/DB_v8/unified_infoDB_rev8.sql [new file with mode: 0644]
server/database/GameDB.sql [new file with mode: 0644]
server/database/GameDB_migration_rev107-rev108.sql [new file with mode: 0644]
server/database/GameDB_migration_rev81-rev82.sql [new file with mode: 0644]
server/database/GameDB_patch_rev133-rev134.sql [new file with mode: 0644]
server/database/GameDB_patch_rev134-rev140.sql [new file with mode: 0644]
server/database/InfoDB.sql [new file with mode: 0644]
server/docs/ISC Example.txt [new file with mode: 0644]
server/docs/ISC ProtDef.txt [new file with mode: 0644]
server/src/Makefile [new file with mode: 0644]
server/src/Rules.make [new file with mode: 0644]
server/src/common/Makefile [new file with mode: 0644]
server/src/common/config/Makefile [new file with mode: 0644]
server/src/common/config/config.cpp [new file with mode: 0644]
server/src/common/config/main.h [new file with mode: 0644]
server/src/common/console/Makefile [new file with mode: 0644]
server/src/common/console/console.cpp [new file with mode: 0644]
server/src/common/console/main.h [new file with mode: 0644]
server/src/common/filesystem/Makefile [new file with mode: 0644]
server/src/common/filesystem/filesystem.cpp [new file with mode: 0644]
server/src/common/filesystem/main.h [new file with mode: 0644]
server/src/common/misc/Makefile [new file with mode: 0644]
server/src/common/misc/main.h [new file with mode: 0644]
server/src/common/misc/misc.cpp [new file with mode: 0644]
server/src/common/netcode/Makefile [new file with mode: 0644]
server/src/common/netcode/connection-tcp.cpp [new file with mode: 0644]
server/src/common/netcode/connection-udp.cpp [new file with mode: 0644]
server/src/common/netcode/main.h [new file with mode: 0644]
server/src/common/netcode/message.cpp [new file with mode: 0644]
server/src/common/netcode/serversocket.cpp [new file with mode: 0644]
server/src/common/netcode/udpmanager.cpp [new file with mode: 0644]
server/src/common/regex/Makefile [new file with mode: 0644]
server/src/common/regex/regex++.cpp [new file with mode: 0755]
server/src/dev-tools/Makefile [new file with mode: 0644]
server/src/dev-tools/cleandepfile.c [new file with mode: 0755]
server/src/dev-tools/getsvnrev.cpp [new file with mode: 0644]
server/src/dev-tools/make-bin-tarball [new file with mode: 0755]
server/src/dev-tools/make-src-tarball [new file with mode: 0755]
server/src/dev-tools/setsvnrev [new file with mode: 0755]
server/src/game/Makefile [new file with mode: 0644]
server/src/game/accounts.cpp [new file with mode: 0644]
server/src/game/appartements.cpp [new file with mode: 0644]
server/src/game/buddylist.cpp [new file with mode: 0755]
server/src/game/chars.cpp [new file with mode: 0644]
server/src/game/chat.cpp [new file with mode: 0644]
server/src/game/client.cpp [new file with mode: 0644]
server/src/game/clientmanager.cpp [new file with mode: 0644]
server/src/game/commands.cpp [new file with mode: 0644]
server/src/game/configtemplate.h [new file with mode: 0644]
server/src/game/container.cpp [new file with mode: 0644]
server/src/game/decoder/Makefile [new file with mode: 0644]
server/src/game/decoder/main.h [new file with mode: 0644]
server/src/game/decoder/msgdecoder.cpp [new file with mode: 0644]
server/src/game/decoder/udp_0x08.cpp [new file with mode: 0644]
server/src/game/decoder/udp_0x08.h [new file with mode: 0644]
server/src/game/decoder/udp_0x13.cpp [new file with mode: 0644]
server/src/game/decoder/udp_0x13.h [new file with mode: 0644]
server/src/game/decoder/udp_0x1f.cpp [new file with mode: 0644]
server/src/game/decoder/udp_0x1f.h [new file with mode: 0644]
server/src/game/decoder/udp_0x22.cpp [new file with mode: 0644]
server/src/game/decoder/udp_0x22.h [new file with mode: 0644]
server/src/game/decoder/udp_0x2b.cpp [new file with mode: 0644]
server/src/game/decoder/udp_0x2b.h [new file with mode: 0644]
server/src/game/decoder/udp_OOO.cpp [new file with mode: 0644]
server/src/game/decoder/udp_OOO.h [new file with mode: 0644]
server/src/game/decoder/udp_appartment.cpp [new file with mode: 0644]
server/src/game/decoder/udp_appartment.h [new file with mode: 0644]
server/src/game/decoder/udp_charmove.cpp [new file with mode: 0644]
server/src/game/decoder/udp_charmove.h [new file with mode: 0644]
server/src/game/decoder/udp_chat.cpp [new file with mode: 0644]
server/src/game/decoder/udp_chat.h [new file with mode: 0644]
server/src/game/decoder/udp_deathrespawn.cpp [new file with mode: 0644]
server/src/game/decoder/udp_deathrespawn.h [new file with mode: 0644]
server/src/game/decoder/udp_entityposreq.cpp [new file with mode: 0644]
server/src/game/decoder/udp_entityposreq.h [new file with mode: 0644]
server/src/game/decoder/udp_hack.cpp [new file with mode: 0644]
server/src/game/decoder/udp_hack.h [new file with mode: 0644]
server/src/game/decoder/udp_helditemaction.cpp [new file with mode: 0644]
server/src/game/decoder/udp_helditemaction.h [new file with mode: 0644]
server/src/game/decoder/udp_itemmanualreload.cpp [new file with mode: 0644]
server/src/game/decoder/udp_itemmanualreload.h [new file with mode: 0644]
server/src/game/decoder/udp_itemmove.cpp [new file with mode: 0644]
server/src/game/decoder/udp_itemmove.h [new file with mode: 0644]
server/src/game/decoder/udp_itemuse.cpp [new file with mode: 0644]
server/src/game/decoder/udp_itemuse.h [new file with mode: 0644]
server/src/game/decoder/udp_killself.cpp [new file with mode: 0644]
server/src/game/decoder/udp_killself.h [new file with mode: 0644]
server/src/game/decoder/udp_multipart.cpp [new file with mode: 0644]
server/src/game/decoder/udp_multipart.h [new file with mode: 0644]
server/src/game/decoder/udp_npcdialog.cpp [new file with mode: 0644]
server/src/game/decoder/udp_npcdialog.h [new file with mode: 0644]
server/src/game/decoder/udp_outfitter.cpp [new file with mode: 0644]
server/src/game/decoder/udp_outfitter.h [new file with mode: 0644]
server/src/game/decoder/udp_packet0.cpp [new file with mode: 0644]
server/src/game/decoder/udp_packet0.h [new file with mode: 0644]
server/src/game/decoder/udp_ping.cpp [new file with mode: 0644]
server/src/game/decoder/udp_ping.h [new file with mode: 0644]
server/src/game/decoder/udp_popupresponse.cpp [new file with mode: 0755]
server/src/game/decoder/udp_popupresponse.h [new file with mode: 0755]
server/src/game/decoder/udp_pvptrade.cpp [new file with mode: 0644]
server/src/game/decoder/udp_pvptrade.h [new file with mode: 0644]
server/src/game/decoder/udp_quickaccessbelt.cpp [new file with mode: 0644]
server/src/game/decoder/udp_quickaccessbelt.h [new file with mode: 0644]
server/src/game/decoder/udp_reqinfo.cpp [new file with mode: 0644]
server/src/game/decoder/udp_reqinfo.h [new file with mode: 0644]
server/src/game/decoder/udp_subskill.cpp [new file with mode: 0644]
server/src/game/decoder/udp_subskill.h [new file with mode: 0644]
server/src/game/decoder/udp_sync.cpp [new file with mode: 0644]
server/src/game/decoder/udp_sync.h [new file with mode: 0644]
server/src/game/decoder/udp_terminal.cpp [new file with mode: 0644]
server/src/game/decoder/udp_terminal.h [new file with mode: 0644]
server/src/game/decoder/udp_useobject.cpp [new file with mode: 0644]
server/src/game/decoder/udp_useobject.h [new file with mode: 0644]
server/src/game/decoder/udp_vhc.cpp [new file with mode: 0644]
server/src/game/decoder/udp_vhc.h [new file with mode: 0644]
server/src/game/decoder/udp_worldIDinfo.cpp [new file with mode: 0644]
server/src/game/decoder/udp_worldIDinfo.h [new file with mode: 0644]
server/src/game/decoder/udp_zoning.cpp [new file with mode: 0755]
server/src/game/decoder/udp_zoning.h [new file with mode: 0644]
server/src/game/decoder/udpanalyser.cpp [new file with mode: 0644]
server/src/game/decoder/udpanalyser.h [new file with mode: 0644]
server/src/game/def/Makefile [new file with mode: 0644]
server/src/game/def/def_actionmod.cpp [new file with mode: 0644]
server/src/game/def/def_ammo.cpp [new file with mode: 0644]
server/src/game/def/def_appartements.cpp [new file with mode: 0755]
server/src/game/def/def_appplaces.cpp [new file with mode: 0644]
server/src/game/def/def_blueprintpieces.cpp [new file with mode: 0644]
server/src/game/def/def_characters.cpp [new file with mode: 0644]
server/src/game/def/def_charaction.cpp [new file with mode: 0644]
server/src/game/def/def_charkinds.cpp [new file with mode: 0644]
server/src/game/def/def_damage.cpp [new file with mode: 0644]
server/src/game/def/def_drugs.cpp [new file with mode: 0644]
server/src/game/def/def_factions.cpp [new file with mode: 0644]
server/src/game/def/def_hack.cpp [new file with mode: 0644]
server/src/game/def/def_implants.cpp [new file with mode: 0644]
server/src/game/def/def_itemcontainer.cpp [new file with mode: 0644]
server/src/game/def/def_itemmod.cpp [new file with mode: 0644]
server/src/game/def/def_itemres.cpp [new file with mode: 0644]
server/src/game/def/def_items.cpp [new file with mode: 0644]
server/src/game/def/def_mission.cpp [new file with mode: 0644]
server/src/game/def/def_npc.cpp [new file with mode: 0644]
server/src/game/def/def_npcarmor.cpp [new file with mode: 0644]
server/src/game/def/def_npcgroupspawn.cpp [new file with mode: 0644]
server/src/game/def/def_outposts.cpp [new file with mode: 0644]
server/src/game/def/def_recycles.cpp [new file with mode: 0644]
server/src/game/def/def_respawn.cpp [new file with mode: 0755]
server/src/game/def/def_scripts.cpp [new file with mode: 0644]
server/src/game/def/def_shots.cpp [new file with mode: 0644]
server/src/game/def/def_skills.cpp [new file with mode: 0644]
server/src/game/def/def_subskills.cpp [new file with mode: 0644]
server/src/game/def/def_trader.cpp [new file with mode: 0644]
server/src/game/def/def_vehicles.cpp [new file with mode: 0644]
server/src/game/def/def_vehiclesits.cpp [new file with mode: 0644]
server/src/game/def/def_weapons.cpp [new file with mode: 0644]
server/src/game/def/def_weather.cpp [new file with mode: 0644]
server/src/game/def/def_worldfile.cpp [new file with mode: 0755]
server/src/game/def/def_worldmodels.cpp [new file with mode: 0644]
server/src/game/def/def_worlds.cpp [new file with mode: 0644]
server/src/game/def/defparser.cpp [new file with mode: 0644]
server/src/game/def/gamedefs.cpp [new file with mode: 0755]
server/src/game/def/main.h [new file with mode: 0755]
server/src/game/def/world_datparser.cpp [new file with mode: 0755]
server/src/game/def/world_datstruct.h [new file with mode: 0755]
server/src/game/doortemplate.cpp [new file with mode: 0755]
server/src/game/furnituretemplate.cpp [new file with mode: 0755]
server/src/game/gamecommands/Makefile [new file with mode: 0644]
server/src/game/gamecommands/README [new file with mode: 0644]
server/src/game/gamecommands/ban.cpp [new file with mode: 0644]
server/src/game/gamecommands/brightness.cpp [new file with mode: 0644]
server/src/game/gamecommands/broadcast.cpp [new file with mode: 0644]
server/src/game/gamecommands/color.cpp [new file with mode: 0644]
server/src/game/gamecommands/debug.cpp [new file with mode: 0644]
server/src/game/gamecommands/effect.cpp [new file with mode: 0644]
server/src/game/gamecommands/givemoney.cpp [new file with mode: 0644]
server/src/game/gamecommands/h.cpp [new file with mode: 0644]
server/src/game/gamecommands/info.cpp [new file with mode: 0644]
server/src/game/gamecommands/jail.cpp [new file with mode: 0644]
server/src/game/gamecommands/kick.cpp [new file with mode: 0644]
server/src/game/gamecommands/listbans.cpp [new file with mode: 0644]
server/src/game/gamecommands/main.h [new file with mode: 0644]
server/src/game/gamecommands/npc.cpp [new file with mode: 0644]
server/src/game/gamecommands/npc_shop.cpp [new file with mode: 0644]
server/src/game/gamecommands/online.cpp [new file with mode: 0644]
server/src/game/gamecommands/rawf.cpp [new file with mode: 0644]
server/src/game/gamecommands/recall.cpp [new file with mode: 0644]
server/src/game/gamecommands/remove.cpp [new file with mode: 0644]
server/src/game/gamecommands/setlevel.cpp [new file with mode: 0644]
server/src/game/gamecommands/setmainskill.cpp [new file with mode: 0644]
server/src/game/gamecommands/setsubskill.cpp [new file with mode: 0644]
server/src/game/gamecommands/settime.cpp [new file with mode: 0644]
server/src/game/gamecommands/shun.cpp [new file with mode: 0644]
server/src/game/gamecommands/skin.cpp [new file with mode: 0644]
server/src/game/gamecommands/spawnactor.cpp [new file with mode: 0644]
server/src/game/gamecommands/speed.cpp [new file with mode: 0644]
server/src/game/gamecommands/t.cpp [new file with mode: 0644]
server/src/game/gamecommands/takemoney.cpp [new file with mode: 0644]
server/src/game/gamecommands/teleport.cpp [new file with mode: 0644]
server/src/game/gamecommands/test.cpp [new file with mode: 0644]
server/src/game/gamecommands/unban.cpp [new file with mode: 0644]
server/src/game/gamecommands/unjail.cpp [new file with mode: 0644]
server/src/game/gamecommands/unshun.cpp [new file with mode: 0644]
server/src/game/gamecommands/uptime.cpp [new file with mode: 0644]
server/src/game/gamecommands/v.cpp [new file with mode: 0644]
server/src/game/gamecommands/version.cpp [new file with mode: 0644]
server/src/game/gamecommands/warp.cpp [new file with mode: 0644]
server/src/game/gamecommands/warpto.cpp [new file with mode: 0644]
server/src/game/gamecommands/weather.cpp [new file with mode: 0644]
server/src/game/gamescript.cpp.inhib [new file with mode: 0644]
server/src/game/gameserver.cpp [new file with mode: 0644]
server/src/game/genreplist.cpp [new file with mode: 0755]
server/src/game/globals.cpp [new file with mode: 0644]
server/src/game/include/accounts.h [new file with mode: 0644]
server/src/game/include/appartements.h [new file with mode: 0644]
server/src/game/include/buddylist.h [new file with mode: 0644]
server/src/game/include/chars.h [new file with mode: 0644]
server/src/game/include/chat.h [new file with mode: 0644]
server/src/game/include/client.h [new file with mode: 0644]
server/src/game/include/clientmanager.h [new file with mode: 0644]
server/src/game/include/commands.h [new file with mode: 0644]
server/src/game/include/container.h [new file with mode: 0644]
server/src/game/include/def.h [new file with mode: 0644]
server/src/game/include/def_actionmod.h [new file with mode: 0644]
server/src/game/include/def_ammo.h [new file with mode: 0644]
server/src/game/include/def_appartements.h [new file with mode: 0755]
server/src/game/include/def_appplaces.h [new file with mode: 0644]
server/src/game/include/def_blueprintpieces.h [new file with mode: 0644]
server/src/game/include/def_characters.h [new file with mode: 0644]
server/src/game/include/def_charaction.h [new file with mode: 0644]
server/src/game/include/def_charkinds.h [new file with mode: 0644]
server/src/game/include/def_damage.h [new file with mode: 0644]
server/src/game/include/def_drugs.h [new file with mode: 0644]
server/src/game/include/def_factions.h [new file with mode: 0644]
server/src/game/include/def_hack.h [new file with mode: 0644]
server/src/game/include/def_implants.h [new file with mode: 0644]
server/src/game/include/def_itemcontainer.h [new file with mode: 0644]
server/src/game/include/def_itemmod.h [new file with mode: 0644]
server/src/game/include/def_itemres.h [new file with mode: 0644]
server/src/game/include/def_items.h [new file with mode: 0644]
server/src/game/include/def_mission.h [new file with mode: 0644]
server/src/game/include/def_npc.h [new file with mode: 0644]
server/src/game/include/def_npcarmor.h [new file with mode: 0644]
server/src/game/include/def_npcgroupspawn.h [new file with mode: 0644]
server/src/game/include/def_outposts.h [new file with mode: 0644]
server/src/game/include/def_recycles.h [new file with mode: 0644]
server/src/game/include/def_respawn.h [new file with mode: 0755]
server/src/game/include/def_scripts.h [new file with mode: 0644]
server/src/game/include/def_shots.h [new file with mode: 0644]
server/src/game/include/def_skills.h [new file with mode: 0644]
server/src/game/include/def_subskills.h [new file with mode: 0644]
server/src/game/include/def_trader.h [new file with mode: 0644]
server/src/game/include/def_vehicles.h [new file with mode: 0644]
server/src/game/include/def_vehiclesits.h [new file with mode: 0644]
server/src/game/include/def_weapons.h [new file with mode: 0644]
server/src/game/include/def_weather.h [new file with mode: 0644]
server/src/game/include/def_worldfile.h [new file with mode: 0755]
server/src/game/include/def_worldmodels.h [new file with mode: 0644]
server/src/game/include/def_worlds.h [new file with mode: 0644]
server/src/game/include/defmap.h [new file with mode: 0644]
server/src/game/include/defparser.h [new file with mode: 0644]
server/src/game/include/defs.h [new file with mode: 0755]
server/src/game/include/doortemplate.h [new file with mode: 0755]
server/src/game/include/furnituretemplate.h [new file with mode: 0755]
server/src/game/include/gamedefs.h [new file with mode: 0755]
server/src/game/include/gamescript.h [new file with mode: 0644]
server/src/game/include/gameserver.h [new file with mode: 0644]
server/src/game/include/genreplist.h [new file with mode: 0644]
server/src/game/include/globals.h [new file with mode: 0644]
server/src/game/include/inventory.h [new file with mode: 0644]
server/src/game/include/isc.h [new file with mode: 0644]
server/src/game/include/item.h [new file with mode: 0644]
server/src/game/include/lua_engine.h [new file with mode: 0644]
server/src/game/include/msgbuilder.h [new file with mode: 0644]
server/src/game/include/msgdecoder.h [new file with mode: 0644]
server/src/game/include/multipart.h [new file with mode: 0644]
server/src/game/include/npc.h [new file with mode: 0644]
server/src/game/include/npctemplate.h [new file with mode: 0644]
server/src/game/include/outpost.h [new file with mode: 0644]
server/src/game/include/rconsole.h [new file with mode: 0644]
server/src/game/include/server.h [new file with mode: 0644]
server/src/game/include/skill.h [new file with mode: 0644]
server/src/game/include/sql.h [new file with mode: 0755]
server/src/game/include/subway.h [new file with mode: 0644]
server/src/game/include/terminal.h [new file with mode: 0644]
server/src/game/include/vehicle.h [new file with mode: 0644]
server/src/game/include/vhcaccessrequest.h [new file with mode: 0644]
server/src/game/include/world_datparser.h [new file with mode: 0755]
server/src/game/include/worldactors.h [new file with mode: 0644]
server/src/game/include/worlddatatemplate.h [new file with mode: 0755]
server/src/game/include/worlds.h [new file with mode: 0755]
server/src/game/include/zoning.h [new file with mode: 0644]
server/src/game/inventory.cpp [new file with mode: 0644]
server/src/game/isc.cpp [new file with mode: 0644]
server/src/game/item.cpp [new file with mode: 0644]
server/src/game/lua_engine.cpp [new file with mode: 0644]
server/src/game/main.cpp [new file with mode: 0644]
server/src/game/main.h [new file with mode: 0644]
server/src/game/msgbuilder.cpp [new file with mode: 0644]
server/src/game/multipart.cpp [new file with mode: 0644]
server/src/game/npc.cpp [new file with mode: 0644]
server/src/game/npc_ai.cpp [new file with mode: 0644]
server/src/game/npc_conversation.cpp [new file with mode: 0644]
server/src/game/npctemplate.cpp [new file with mode: 0644]
server/src/game/outpost.cpp [new file with mode: 0644]
server/src/game/rconsole.cpp.inhib [new file with mode: 0644]
server/src/game/server.cpp [new file with mode: 0644]
server/src/game/skill.cpp [new file with mode: 0644]
server/src/game/sql.cpp [new file with mode: 0644]
server/src/game/subway.cpp [new file with mode: 0644]
server/src/game/terminal.cpp [new file with mode: 0644]
server/src/game/terminal_querydb.cpp [new file with mode: 0644]
server/src/game/terminal_receivedb.cpp [new file with mode: 0644]
server/src/game/terminal_tryaccess.cpp [new file with mode: 0644]
server/src/game/terminal_updatedb.cpp [new file with mode: 0644]
server/src/game/vehicle.cpp [new file with mode: 0644]
server/src/game/vhcaccessrequest.cpp [new file with mode: 0755]
server/src/game/worldactors.cpp [new file with mode: 0644]
server/src/game/worlddatatemplate.cpp [new file with mode: 0755]
server/src/game/worlds.cpp [new file with mode: 0755]
server/src/game/zoning.cpp [new file with mode: 0644]
server/src/include/config.h [new file with mode: 0644]
server/src/include/connection-tcp.h [new file with mode: 0644]
server/src/include/connection-udp.h [new file with mode: 0644]
server/src/include/console.h [new file with mode: 0644]
server/src/include/external.h [new file with mode: 0644]
server/src/include/filesystem.h [new file with mode: 0644]
server/src/include/message.h [new file with mode: 0644]
server/src/include/misc.h [new file with mode: 0644]
server/src/include/netcode.h [new file with mode: 0644]
server/src/include/regex++.h [new file with mode: 0755]
server/src/include/serversocket.h [new file with mode: 0644]
server/src/include/svnrevision.h [new file with mode: 0644]
server/src/include/tinns_mutex.h [new file with mode: 0644]
server/src/include/tinns_semaphore.h [new file with mode: 0644]
server/src/include/tinns_thread.h [new file with mode: 0644]
server/src/include/types.h [new file with mode: 0644]
server/src/include/version.h [new file with mode: 0644]
server/src/info/Makefile [new file with mode: 0644]
server/src/info/accounts.cpp [new file with mode: 0644]
server/src/info/accounts.h [new file with mode: 0644]
server/src/info/client.cpp [new file with mode: 0644]
server/src/info/client.h [new file with mode: 0644]
server/src/info/configtemplate.h [new file with mode: 0644]
server/src/info/globals.cpp [new file with mode: 0644]
server/src/info/globals.h [new file with mode: 0644]
server/src/info/infoserver.cpp [new file with mode: 0644]
server/src/info/infoserver.h [new file with mode: 0644]
server/src/info/main.cpp [new file with mode: 0644]
server/src/info/main.h [new file with mode: 0644]
server/src/info/server.cpp [new file with mode: 0644]
server/src/info/server.h [new file with mode: 0644]
server/src/info/sql.cpp [new file with mode: 0644]
server/src/info/sql.h [new file with mode: 0644]
server/src/options.local.exemple [new file with mode: 0644]
server/src/patch/Makefile [new file with mode: 0644]
server/src/patch/client.cpp [new file with mode: 0644]
server/src/patch/client.h [new file with mode: 0644]
server/src/patch/configtemplate.h [new file with mode: 0644]
server/src/patch/globals.cpp [new file with mode: 0644]
server/src/patch/globals.h [new file with mode: 0644]
server/src/patch/main.cpp [new file with mode: 0644]
server/src/patch/main.h [new file with mode: 0644]
server/src/patch/patchserver.cpp [new file with mode: 0644]
server/src/patch/patchserver.h [new file with mode: 0644]
server/src/patch/server.cpp [new file with mode: 0644]
server/src/patch/server.h [new file with mode: 0644]
server/tinns [new file with mode: 0644]
tools/getsvnrev/Makefile [new file with mode: 0644]
tools/getsvnrev/getsvnrev.cpp [new file with mode: 0644]
tools/pak_decompress/Makefile [new file with mode: 0644]
tools/pak_decompress/pak_decompress.cpp [new file with mode: 0644]
tools/pak_decompress/pak_decompress.jar [new file with mode: 0644]
tools/vfs_viewer/Makefile [new file with mode: 0644]
tools/vfs_viewer/vfs_viewer.c [new file with mode: 0644]

diff --git a/docs/NPCs.txt b/docs/NPCs.txt
new file mode 100644 (file)
index 0000000..77f31d2
--- /dev/null
@@ -0,0 +1,13 @@
+So far, if you type\r
+       @test 1\r
+       A copbot will spawn at your current location\r
+\r
+       @test 5 <your local ID> 17\r
+       the copbot will put out his weapon and run to a location in Plaza 1, left to medicare (i had to set a static pos here)\r
+\r
+       @test 6 <your local ID> 0 4863\r
+       the copbot will start shooting you.\r
+\r
+       type\r
+       @test 5 0 15\r
+       and the copbot will put back his weapon and stop fire
\ No newline at end of file
diff --git a/docs/Neocron1.ChatProtocol.pdf b/docs/Neocron1.ChatProtocol.pdf
new file mode 100644 (file)
index 0000000..c2df7cf
Binary files /dev/null and b/docs/Neocron1.ChatProtocol.pdf differ
diff --git a/docs/Neocron1.MainProtocol.pdf b/docs/Neocron1.MainProtocol.pdf
new file mode 100644 (file)
index 0000000..793e5d6
Binary files /dev/null and b/docs/Neocron1.MainProtocol.pdf differ
diff --git a/docs/TinNS.QuickInstallation.pdf b/docs/TinNS.QuickInstallation.pdf
new file mode 100644 (file)
index 0000000..d3071c3
Binary files /dev/null and b/docs/TinNS.QuickInstallation.pdf differ
diff --git a/docs/current_test_commands.txt b/docs/current_test_commands.txt
new file mode 100644 (file)
index 0000000..3a0570d
--- /dev/null
@@ -0,0 +1,14 @@
+Current @test commands are:\r
+\r
+@text 1 <npcID> <zoneID> <unknown1> <attackAnim>\r
+- Let <npcID> (use @debug it) attack <zoneID> which can be any npc or player\r
+  <npcID>: For non-sql NPCs, you have to remove an offset of 255; So the left security officer\r
+  in plaza 1 would have id 48 instead of 303\r
+  Unknown 1 is .. unknown yet and seems to be unimportant\r
+  attackAnim is the attack "style" of <npcID>. Varies from npc type to npc type\r
+\r
+@test 2 <faction ID> <faction ID>\r
+- Get relation of the 2 given factions. <0 means enemy\r
+\r
+\r
+! IF you find out what an "unknown" value does, tell us !
\ No newline at end of file
diff --git a/docs/how_npc_scripts_work.txt b/docs/how_npc_scripts_work.txt
new file mode 100644 (file)
index 0000000..236f42f
--- /dev/null
@@ -0,0 +1,309 @@
+(c) 2009; Written by Namikon for http://www.linux-addicted.net\r
+Last Updated: 15.10.2009\r
+----------------------------------------------------------------\r
+\r
+\r
+Hi. In this document i'll try to explain how the NPC Script-System works in\r
+Neocron.\r
+\r
+First off, we have the .lua scripts, like this one:\r
+\r
+--snip--\r
+function DIALOG()\r
+       NODE(0)\r
+               SAY("Hi there")\r
+               ANSWER("Yo man",1)\r
+       NODE(1)\r
+               SAY("See ya")\r
+               ENDDIALOG()\r
+end\r
+--snip--\r
+\r
+if you ever worked with lua, you'll notice that NODE, SAY and ANSWER are no\r
+common lua functions.\r
+Those function calls are defined in either missionheader.lua and/or \r
+dialogheader.lua. (Open scripts.def; The last entry tells you if the lua script\r
+defined in that line includes mission or dialogheader).\r
+\r
+So the lua files in the scripts/ folder cannot be executed alone. They HAVE to be\r
+combined with either dialogheader.lua or missionheader.lua.\r
+\r
+You might think now "What the heck, there is only one function, how is this supposed to work?"\r
+Thats correct. Only DIALOG() is defined. I'll explain how that works exactly below.\r
+\r
+First, in order to communicate with your lua script from c/c++ source code, you need\r
+a) An entry function, like main() that can be called from within your source\r
+b) A "callback" function, if the script needs any action to be done, like give and item\r
+   let npc die, or whatever.\r
+c) A function to deliver results back to the running script. If you call RAND(2), you might want\r
+   to know the result. Would you?\r
+\r
+For a), a function called "lSendAction" is defined\r
+For b), a function called "SendScriptMsg" is defined\r
+For c), a function called "SetResult" is defined\r
+\r
+So now how is this "single function dialog" working:\r
+You see those NODE() lines in the source. NODE is defined as:\r
+\r
+--snip--\r
+function NODE(index)   \r
+       node = index \r
+end\r
+--snip--\r
+\r
+"index" is a variable which is set to 0 uppon every script-start (mission/dialogheader, 1st line)\r
+So you have some variables, and a dozen of functions. If you start this lua script, nothing will happen.\r
+\r
+When you click on a NPC, your client sends "use item xx".\r
+The server detects if this id is an npc. If so, the server will send\r
+a packet back that tells the client what lua script to use.\r
+(The short name in scripts.def, not the entire scriptfile name; NCPD for example)\r
+\r
+Right after that packet, another one follows. This packet tells the client to call "lSendAction", with\r
+a given state number. After that, your dialog/mission script is running.\r
+\r
+lSendAction is defined as:\r
+--snip--\r
+function lSendAction (in_dialogclass, newstate)\r
+\r
+       dialogclass = in_dialogclass\r
+       state = newstate\r
+       counter = 0\r
+       \r
+       DIALOG()\r
+end\r
+--snip--\r
+\r
+There is our DIALOG() call. So what happens here? Look at the entire script that is processed after \r
+a lSendAction call:\r
+\r
+-------\r
+dialogclass, counter, state, node = 0\r
+\r
+function lSendAction (in_dialogclass, newstate)\r
+\r
+       dialogclass = in_dialogclass\r
+       state = newstate\r
+       counter = 0\r
+       \r
+       DIALOG()\r
+end\r
+\r
+function NODE(index)   \r
+       node = index \r
+end\r
+\r
+function SAY(text)\r
+       if (node==state) then\r
+               SendScriptMsg("say", dialogclass,text)\r
+       end\r
+end\r
+\r
+function ANSWER(text,resultstate)\r
+       if (node==state) then   \r
+               counter = counter + 1\r
+               SendScriptMsg("setanswer", dialogclass,counter,text,resultstate, 0)\r
+       end\r
+end\r
+\r
+function ENDDIALOG()\r
+       if (node==state) then\r
+               SendScriptMsg("enddialog", dialogclass)\r
+       end\r
+end\r
+\r
+function DIALOG()\r
+       NODE(0)\r
+               SAY("Hi there")\r
+               ANSWER("Yo man",1)\r
+       NODE(1)\r
+               SAY("See ya")\r
+               ENDDIALOG()\r
+end\r
+-------\r
+\r
+- We call "lSendAction(0,0)"\r
+- Global var "state" is now 0 (the other 2 dont matter here)\r
+- NODE() is called:\r
+-- NODE(0) is called, global var "node" is now 0\r
+-- SAY is called\r
+--- if-statement is true, state is equal node, so we call the c/c++ callback function "SendScriptMsg",\r
+    Neocron now displays "Hi there" in a dialog screen\r
+-- ANSWER() is called\r
+--- if-statement is true, state is equal node, so we call the c/c++ callback function "SendScriptMsg",\r
+    Neocron now displays "Yo man" in a dialog screen as selectable answer.\r
+-- NODE(1) is called, global var "node" is now 1\r
+-- SAY is called\r
+--- if-statement is now FALSE. state is still 0, but we're at NODE 1, nothing happens\r
+-- ENDDIALOG() is called\r
+--- if-statement is FALSE. state is still 0, but we're at NODE 1, nothing happens\r
+-- function DIALOG ends\r
+- Script execution finished\r
+\r
+Now, if we click the answer, the client sends the answernumber to us. !Nothing else! We ONLY get the\r
+answer number. Thats why in ANSWER the var "counter" is increased every call.\r
+Good for us, at the server is, lua does that for us. We only need to grab the correct answer number.\r
+\r
+Ok, we got the answernumber from our client. We know that our answer had this little 1 after its text.\r
+That 1 tells us which NODE comes next.\r
+So what would we send now to the client? Correct:\r
+\r
+- We call "lSendAction(0,1)"\r
+- Global var "state" is now 1 \r
+- NODE() is called:\r
+-- NODE(0) is called, global var "node" is now 0\r
+-- SAY is called\r
+--- if-statement is false (node = 0, state = 1)\r
+-- ANSWER is called\r
+--- if-statement is false (node = 0, state = 1)\r
+-- NODE(1) is called, global var "node" is now 1\r
+-- SAY is called\r
+--- if-statement is true, (node = 1, state = 1) so we call the c/c++ callback function "SendScriptMsg",\r
+    Neocron now displays "See ya" in a dialog screen\r
+-- ENDDIALOG() is called\r
+--- if-statement is true, (node = 1, state = 1) so we call the c/c++ callback function "SendScriptMsg",\r
+    Neocron closes the NPC dialog\r
+-- function DIALOG ends\r
+- Script execution finished\r
+\r
+So far, thats how "normal" lua scripts work. Nothing special about that.\r
+But NPC scripts are far more complex; KK wrote BlackJack and roulette games for NC2\r
+in lua. They handle epic runs, let NPCs attack and give you tons of nice items on christmas\r
+if you where a good boy(girl) last year.\r
+\r
+So far, i know that the packet where you return a node Number can be extended with\r
+and u32 (?) value; And i think this could be either a hidden result, or \r
+a defined seed for an rand() generator, not sure about that yet.\r
+\r
+For takeitem/giveitem stuff, the script stops right after it called SendScriptMsg and returns\r
+to our callback function. We have now the time to give / take any item,\r
+check faction standings,... and return the result to our script before it continues.\r
+\r
+The client does *NOT* perform any action besides SAY.. and ANSWER.. stuff.\r
+All actions that lead to an result are performed by the server.\r
+Lets take TAKEITEM(90) as example and extend our basic script from above:\r
+\r
+--snip\r
+<old script here>\r
+\r
+function TAKEITEM(itemtype)\r
+       if (node==state) then\r
+               SendScriptMsg("takeitem", dialogclass,itemtype)\r
+       end\r
+end\r
+\r
+NODE (10)\r
+  TAKEITEM(90)\r
+  if (result==1) then\r
+    SAY("Thanks for that copbot rifle")\r
+    ANSWER("You're welcome")\r
+  else\r
+    SAY("You dont have a Copbot rifle")\r
+    ANSWER("Too bad for you")\r
+  end\r
+ENDDIALOG();\r
+\r
+--snip\r
+\r
+You should already know what happens here, so i wont explain it again.\r
+Remember: \r
+- We choose the answer\r
+- The server processes the destination node\r
+- And sends us the Nodenumber back, together with results, if any.\r
+\r
+So, when the client reaches TAKEITEM(x), he will NOT take your item away,\r
+he will stop the script for a moment, like we do it on the server.\r
+\r
+Difference: The client looks inside the last lSendAction packet\r
+if there are any results. If so, he will call SendResults() and push\r
+these value(s) back to the script.\r
+You see, result is now set to the same value as it where on the server.\r
+\r
+One word about those values:\r
+They ARE integer. But KK decided that it would be cool to have negative AND positive\r
+results, they choose float as format.\r
+\r
+\r
+This RAW packet could be a positive answer to our TAKEITEM command:\r
+0E 03 91 00 1F 01 00 1A 0A 00 01 00 00 80 3F\r
+Which splits up as:\r
+0E             - Packetlen\r
+03             - Commandset 0x03\r
+09 00          - UDP ID\r
+1F             - Subcommand 1F\r
+01 00          - Local PlayerID\r
+1A             - SubSubcommand Dialog\r
+0A 00          - NODE ID to be processed next (u16 format)\r
+01             - How many values will follow?\r
+00 00 80 3F    - 1.0 in float\r
+\r
+\r
+===== !! THEORY !! =====\r
+===== !! This part is NOT verified yet !! =====\r
+\r
+If you have more than one result, for example if you take away 2 or more items,\r
+they are attached to the packet in the same order as they appear.\r
+If the first result is 0 and the second is 1,\r
+it would be like this:\r
+\r
+0E             - Packetlen\r
+03             - Commandset 0x03\r
+09 00          - UDP ID\r
+1F             - Subcommand 1F\r
+01 00          - Local PlayerID\r
+1A             - SubSubcommand Dialog\r
+0A 00          - NODE ID to be processed next (u16 format)\r
+02             - How many values will follow?\r
+00 00 00 00    - 0.0 in float (and any other format too i know...)\r
+00 00 80 3F    - 1.0 in float\r
+======================================= \r
+\r
+PM me if you can proof that this is correct, thanks!\r
+\r
+END\r
+\r
+If you find any typos, errors, whatever, please tell me over PM\r
+on linux-addicted.net.\r
+\r
+-Namikon\r
+\r
+================== PACKETS BELOW ==================\r
+The packets are defined as:\r
+\r
+\r
+"LOADSCRIPT" Packet (After USE) // SERVER > CLIENT\r
+----\r
+<u8>   Len\r
+<u8>   0x03\r
+<u16>  UDP ID\r
+<u8>   0x1F\r
+<u16>  Players ZoneID\r
+<u8>   0x18\r
+<u32>  NPCs WorldID\r
+<u32>  Some 32-bit value that changes everytime you click on an npc. We have *no* clue what this does :)\r
+<u32>  0x00000000\r
+<u8>*  Name of the script \0 terminated\r
+----\r
+\r
+"lSendAction" Packet // SERVER > CLIENT // Server tells client which node next, and what results to use\r
+----\r
+<u8>   Len\r
+<u8>   0x03\r
+<u16>  UDP ID\r
+<u8>   0x1F\r
+<u16>  Players ZoneID\r
+<u8>   0x1a\r
+<u16>  NodeID\r
+<u8>   # of Values to follow (float values)\r
+----\r
+\r
+"ANSWER x" // CLIENT > SERVER\r
+----\r
+<u8>   Len\r
+<u8>   0x03\r
+<u16>  UDP ID\r
+<u8>   0x1F\r
+<u16>  Players ZoneID\r
+<u8>   0x1a\r
+<u8>   AnswerNr\r
+----\r
diff --git a/docs/itemtypes.txt b/docs/itemtypes.txt
new file mode 100644 (file)
index 0000000..8f8b12e
--- /dev/null
@@ -0,0 +1,24 @@
+0 = Unknown/Generic    O1: None        O2: None\r
+1 = GenRep             O1: ?           O2: ?\r
+2 = Apt Station                O1: Station ID  O2: None\r
+3 = GoGo               O1: None        O2: None\r
+4 = Zoning Doors       O1: Map ID      O2: None\r
+5 = Chairs             O1: None        O2: None\r
+6 = Condition Locks    O1: Condition   O2: Option\r
+                               0 = open                O2 = None\r
+                               1 = locked and hackable O2 = difficulty\r
+                               2 = locked and Apt      O2 = Owner\r
+                               3 = locked and pay      O2 = Price\r
+7 = Venture Warps      O1: None        O2: None\r
+8 = Vehicle Depot      O1: None        O2: None\r
+9 = Holo Exit          O1: None        O2: None\r
+10 = Holo Weapon       O1: None        O2: None\r
+11 = Holo Heal         O1: None        O2: None\r
+12 = Holo Entrance     O1: None        O2: None\r
+13 = City Com          O1: None        O2: None\r
+14 = OutFitters                O1: None        O2: None\r
+15 = Cabs              O1: Owner       O2: None\r
+16 = Containers                O1: Loot Type   O2: Hackable difficulty if 0 not locked\r
+17 = Street Signs      O1: None        O2: None\r
+18 = Recreation Units  O1: None        O2: None\r
+19 = Outpost hack      O1: Owner       O2: None
\ No newline at end of file
diff --git a/docs/lua_callbacks.xls b/docs/lua_callbacks.xls
new file mode 100644 (file)
index 0000000..df16f79
Binary files /dev/null and b/docs/lua_callbacks.xls differ
diff --git a/docs/readme b/docs/readme
new file mode 100644 (file)
index 0000000..cb5fa45
--- /dev/null
@@ -0,0 +1,6 @@
+trunk/src/developing -> newest branch
+trunk/src/stable -> this is going to be a stable branch
+trunk/src/testing -> this is for testing, right now it uses an older HawkNL
+trunk/docs -> this documentation stuff
+trunk/tools -> contains some tools useful for the server and the server files
+trunk/datapack -> contains missing files, modified files and patches
diff --git a/server/CHANGELOG b/server/CHANGELOG
new file mode 100644 (file)
index 0000000..97e4502
--- /dev/null
@@ -0,0 +1,1818 @@
+<GPL>\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+</GPL>\r
+\r
+Developers:\r
+- Akiko\r
+- bakkdoor\r
+- Namikon\r
+- Hammag\r
+\r
+> Recent changes\r
+====================\r
+Namikon; 31.05.2006 22:12 GMT+1\r
+----------\r
+<General changes>\r
+- Introduced CHANGELOG file\r
+- Added version.h to enable a way to create release tarballs/binaries\r
+- Fixed a dozen of typos and bugs from the additions of the last 2 days\r
+- "Clean build"; Should compile without any error now. (Note: Not "work", "compile" :) )\r
+\r
+\r
+<Source changes>\r
+[GAME]\r
+globals.cpp :: ShutdownTinNS()\r
+  - Renamed to Shutdown()\r
+  - Added svn version output to startup procedure\r
+  - Fixed minor typos/console outputs\r
+config.cpp :: LoadOptions()\r
+  - Changed configfile, now loads data from /conf/gameserver.cfg\r
+  - Added full 2 DB support (was: "sql_*" now: "info_sql_*" and "game_sql_*")\r
+\r
+[INFO]\r
+\r
+[PATCH]\r
+globals.cpp :: ShutdownTinNS()\r
+  - Renamed to Shutdown()\r
+\r
+[ALL]\r
+misc.cpp :: GetSVNRev()\r
+  - Added handling for version.h defines\r
+====================\r
+Hammag; 06.07.2006 02:17 GMT+1\r
+----------\r
+<General changes>\r
+- Put UDP sockets in non-blocking mode.\r
+- Checked and modified all socket related stuff to work in non-blocking mode.\r
+- Lowered CPU use from 100% to ~0% by changing from sched_yield() to I/O wait sleep using Select.\r
+  This avoid runingthe main loop when there's nothing to do (some more improvements are to come\r
+  on this topic).\r
+- The socket Select now waits for any tcp OR UDP socket incoming data.\r
+- Fixed some pointer issues in netcode.\r
+\r
+\r
+<Source changes>\r
+[GAME]\r
\r
+[INFO]\r
+misc.h\r
+ - added declaration of utility function IPlongToString()\r
+misc.cpp :: IPlongToString()\r
+ - implemented function to convert IP address in u32 format to string\r
+infoserver.cpp :: HandleServerList()\r
+ - now use IPlongToString() to display server IP on Console\r
+\r
+[PATCH]\r
+\r
+[ALL]\r
+patchserver.cpp, infoserver.cpp, gameserver.cpp :: Start()\r
+ - set 10 msec timeout for socket select, which sets the max wait time\r
+  for the main loop when no activity.\r
+\r
+main.cpp\r
+ - commented out sched_yield() in main loop, as it is not needed anymore.\r
+\r
+main.h\r
+ - moved-up tinns-specific types include to ready them for netcode compilation\r
+\r
+[NETCODE]\r
+connection-tcp.cpp :: ConnectionTCP()\r
+ - moved-in non-blocking setting from ServerSocket::getTCPConnection()\r
+    for better class coherency\r
+connection-tcp.cpp :: update()\r
+ - modified to deal correctly with would-block socket writes.\r
+ - fixed a pointer and size issue in socket recv\r
+\r
+connection-udp.h :: class\r
+ - added private member m_ServerSocket\r
+ - added ServerSocket parameter in constructor prototype\r
\r
+connection-udp.cpp :: ConnectionUDP()\r
+ - modified to set m_ServerSocket from constructor parameters\r
+connection-udp.cpp :: ~ConnectionUDP()\r
+ - added socket removal from fd sets by calling m_ServerSocket->delSocketFromSet\r
+connection-udp.cpp :: update()\r
+ - modified to check m_ServerSocket->isDataAvailable() before trying to read from socket\r
+ - fixed a pointer and size issue in socket recv\r
+\r
+serversocket.h :: class\r
+ - added settimeout public method\r
+ - added fd_set m_MainSetUDP private member\r
+ - added fd_set m_MainSetGlobal private member (= m_MainSetTCP + m_MainSetUDP)\r
\r
+serversocket.cpp :: ServerSocket()\r
+ - moved m_TimeOut initialization in constructor\r
+ - added m_MainSetUDP and m_MainSetGlobal init\r
+serversocket.cpp :: settimeout()\r
+ - implemented method to set m_TimeOut to permit tuning\r
+serversocket.cpp :: open()\r
+ - added m_MainSetUDP and m_MainSetGlobal init\r
+ - added m_ListenerTCP to m_MainSetGlobal too\r
+serversocket.cpp :: update()\r
+ - now m_MainSetGlobal is copied to m_ReadSetTCP set,\r
+ - added a local fdMax for select\r
+ - use a temp timeout structure in select as select doc says select implementation\r
+    for Linux could change this value\r
+serversocket.cpp :: getUDPConnection()\r
+ - now pass this pointer to new ConnectionUDP constructor\r
+ - new UDP sockets are added to m_MainSetUDP and m_MainSetGlobal,\r
+    and kept track of in m_FdMaxUDP\r
+serversocket.cpp :: getTCPConnection()\r
+ - fixed a struct length issue (?) in accept\r
+ - now new TCP sockets are added to m_MainSetGlobal too\r
+ - moved non-blocking setting to ConnectionTCP::ConnectionTCP() for better class coherency\r
+serversocket.cpp :: delSocketFromSet()\r
+ - added removal of sockfd from m_MainSetUDP and m_MainSetGlobal too\r
\r
+====================\r
+Hammag; 30.07.2006 02:17 GMT+1\r
+----------\r
+<General changes>\r
+ - Baseline fixed, full zoning now really works with multiplayer\r
+ - Multiuser now works. Multiple login + mutual viewing.\r
+    Now a char displays as expected ingame for himself as for others.(some movement/positionning glitches remain)\r
+ - Warning: code for using items hasn't been fixed, so every thing 2nd+ user does will be\r
+     attriuted to 1st user and provoque OOO flood.\r
+     So don't try using items, except for the first user.\r
+ - added @skin command. Reminder use by @skin, little mode description in commands.cpp header\r
+\r
+<Source changes>\r
+[GAME]\r
+ - Many changes in many files\r
+ - amongst other, rewrited baseline.inc.cpp with new PMessage object as an exemple\r
+ - added PItem & PInventory classes\r
+\r
+[NETCODE]\r
+ - Added PMessage class for network message input/output\r
+ - UDP & TCP connection classes now has an interface for PMessages\r
\r
+====================\r
+Hammag; 06.08.2006 02:17 GMT+1\r
+----------\r
+<General changes>\r
+ - code for using items should now be fixed for most case (see above) so activating items in multiuser mode is no longer a limitation\r
+ - a similar issue in @warp command has been solved (and spawn location added as an optional command line parameter as in NeoX)\r
+ - further modifications to the netcode to cope with NAT. New options added to config file\r
+ - rework of the config.cpp implementation, to enable easy addition of new option and more explicit error checking. See comments at begining of config.cpp\r
+ - gametime flow fixed. Start time is set to 0 ATM\r
+ - other minor changes. See source files starts for info\r
+ - conf/gameserver.conf extended with NAT related options\r
+\r
+<Source changes>\r
+[GAME]\r
+ - Many changes in many files for modifications stated above\r
+ - Changes to ClientManager to make it work and add methods to dispatch messages to clients\r
+ - game/Makefile updated\r
\r
+[NETCODE]\r
+ - Changes in most files for modifications stated above\r
+\r
+[INFO]\r
+client.cpp :: GetAdress()\r
+  - updated implementation to use ConnectionTCP::GetRemoteAddress()\r
+\r
+[PATCH]\r
+client.cpp :: GetAdress()\r
+  - updated implementation to use ConnectionTCP::GetRemoteAddress()\r
+  \r
+====================\r
+Hammag; 24.08.2006 02:17 GMT+1\r
+----------\r
+<General changes>\r
+ - movement/positionning in multiuser is now fixed \r
+ - implemented NC messages decoding new base classes. Not used yet\r
+\r
+<Source changes>\r
+[GAME]\r
+  - added PUdpMsgDecoder class, which objects manage UDP packets decoding\r
+  - added PUdpMsgAnalyser class, which is the base class that real packet analyser objects will be derived from\r
+      Analysis exemple is not yet implemented\r
+  - added PUdpMsgUnknown class, which is the most simple exemple of final packet analyser object (used for unkown packets)\r
+\r
+====================\r
+Hammag; 26.08.2006 02:17 GMT+1\r
+----------\r
+<General changes>\r
+ - A modified source tree is now used. The corresponding changes have been applied to the whole source code,\r
+    resulting in some move to some common components directories, common includes and corresponding changes\r
+    in servers source\r
+ - A new Makefile system is now used. All makefiles have been remade accordingly.\r
+\r
+<Source changes>\r
+[ALL]\r
+Put version.h in include dir\r
+Created include/external.h\r
+Removed corresponding includes from all main.h, and replaced by external.h\r
+\r
+[CONSOLE]\r
+Moved console *.cpp files in common/console\r
+Moved console's *.h in include dir\r
+Added a main.h in common/console for specific private includes\r
+Made Console class generic, added output file as constructor parameter,\r
+  changed servers code accordingly\r
+Removed Console-> in Console->ColorText(...) in PConsole::~PConsole()\r
+\r
+[NETCODE]\r
+Moved netcode .cpp files in common/netcode\r
+Moved netcode's *.h in include dir, changed netcode's main.h to netcode.h\r
+Added a main.h in common/netcode for specific private includes\r
+\r
+====================\r
+Hammag; 27.08.2006 18:30 GMT+1\r
+----------\r
+<General changes>\r
+ - Changed config class as a common component\r
+ - Changed "misc" functions as a common components\r
+ - Removed some old code, some old defines, and changed some defines to config entry\r
+\r
+[CONFIG] \r
+Moved config .cpp file in common/config\r
+Moved config *.h in include dir\r
+Added a main.h in common/config for specific private includes\r
+Made Config class generic, added option tempate and config file as LoadOptions parameter,\r
+  changed servers code accordingly, by making use of the shared class\r
+  and adding a templateconfig.h file included in the place where config loading is done\r
+\r
+[MISC]\r
+Merged all misc functions in a single misc.h and a single misc.cpp files\r
+Moved config *.h in include dir\r
+Move the misc.cpp in common/misc\r
+Added a main.h in common/misc for specific private includes\r
+\r
+[ALL SERVERS]\r
+Modified global.cpp and main.h to use shared PConfig class and shared misc functions\r
+Removed misc.* and config.* from servers sources\r
+\r
+====================\r
+Hammag; 10.09.2006 00:00 GMT+1\r
+----------\r
+<General changes>\r
+ - Changed filesystem class as a common component\r
+ - Added command @effect to play with skins effect (see commands.cpp for details)\r
+ - Added command @speed to play with speed (see commands.cpp for details)\r
+ - Removed some more #include directive from some main.h files to put them only\r
+    when needed in .cpp file. This eliminated some unnecessary dependencies and\r
+    makes recompile faster.\r
+ - Migrated message decoding to new system for all messages types except 0x13/0x1f (yes... stil lots to do)\r
\r
+\r
+[ALL SERVERS]\r
+Moved filesystem.h to include dir, and filesystem.cpp to common/filesystem dir\r
+Removed filesystem.* from servers sources\r
+Changed patchserver and gameserver accordingly\r
+\r
+\r
+[GAME]\r
+Added game/include dir to put all .h file to highly facilitate includes.\r
+Added corresponding include directory path directive in game and game/* makefiles\r
+\r
+Put all .def related stuff in game/def subdir.\r
+*.h files are in game/include\r
+\r
+Put all message decoding related stuff in game/decoder subdir.\r
+msgdecoder.h file are in game/include.\r
+Other .h files which are not exposed to other gameserver componenets are in game/decoder subdir.\r
+\r
+Created a PMsgBuilder class to put message creating methods in it.\r
+A global PMsgBuilder* MsgBuilder instance is added to gameserver.\r
+Modified globals.*, gameserver.*, clientmanager.cpp, commands.cpp and various game/_inc accordingly\r
+\r
+Moved PGameState definition from gameserver.cpp to gameserver.h\r
+\r
+Added PChar* GetChar() method to PClient\r
+\r
+Added WorldMap request basic support in PMsgBuilder::BuildReqInfoAnswerMsg() (for futur use)\r
+Added BodyEffect and SpeedOverride members to PChar class, as well as methods to set and get these values\r
+Added support for BodyEffect and SpeedOverride in PMsgBuilder::BuildCharHelloMsg()\r
+\r
+Reorganised code related to UDP Sync in order to avoid duplicate code.\r
+Put most of corresponding message building functions in PMsgBuilder class.\r
+\r
+====================\r
+Hammag; 22.09.2006 00:00 GMT+1\r
+----------\r
+<General changes>\r
+ - Added Buddy list management (just the list though, buddy chat isn't working yet)\r
+    Added a new gameserver DB table ti save the buddy list: buddy_list \r
+ - Added Direct chat management (just char selection though, direct chat isn't working yet, and selection isn't saved in DB yet)\r
+ - Added Genrep list management. List is now working and saved. Registration of GR doesn't register the right GR though (working on that)\r
+ - Added loading of worldmodel.def and appplace.def files for later (very soon) use.\r
+ - Migrated most of message handling to new decoder system.\r
+    Item use is migrated in "a compatibility mode" until item management is fully based on world .dat  and worldmodel.def files\r
+\r
+[GAME]\r
+Removed game/_inc directory\r
+Removed all UDP message analysis and handling from gameserver.cpp\r
+Created mode decoder classes in game/decoder\r
+Moved most UDP packet creation code from gameserver.cpp to msgbuilder.cpp, using PMessages\r
+Added PBuddyList class\r
+Added PGenrepList class\r
+Added loading/saving of Buddy List and Genrep List to char loading/saving in chars.cpp\r
+\r
+Added new members to PChar to store skin color and brightness (aka "darkness")  in chars.h and char.cpp (not saved in DB yet)\r
+  and corresponding support in PMsgBuilder::BuildCharHelloMsg()\r
+Added new commands "@color" and "@brightness"\r
+\r
+====================\r
+Hammag; 27.09.2006 20:00 GMT+1\r
+----------\r
+<General changes>\r
+ - Added loading of appartements.def and respawn.def files for later (very soon) use.\r
+ - Corrected and modified dependencies management in make system.\r
+    No unwanted file date change should occure anymore\r
+\r
+[GAME]\r
+Zoning to appartment now make use of appartements.def data instead of hardcoded data (zoning.cpp)\r
+Added PMySQL::GetAptLocation() method in sql.cpp\r
+Prepared some modification for WorldItems and Appartments in sql.cpp (these methodes will later be put in specific classes)\r
+\r
+====================\r
+Hammag; 28.09.2006 17:30 GMT+1\r
+----------\r
+<General changes>\r
+ - Updated the gamserver DB install file to version 5 (database/GameDB5.zip) needed\r
+    by the current TinNS version.\r
+ - Added a SQL file to update existing gamserver DB from version 4 to version 5\r
+    (database/GameDB4_to_GameDB5.sql)\r
+ - Zoning is now fully based on NC files rather than hardcoded.\r
+  \r
+[GAME]\r
+Filename in now taken from appartments.def (for app zoning) or from worlds.ini (general case)\r
+Zoning out of appartment (Lift exit) is based on appplaces.def (was in the 27.09.2006 version already)\r
+Corrected GR use. Now GR gets it true name, and this good name can be registred in the char GR list\r
+ and seved in DB.\r
+Changlog in command.cpp updated from last additions (22.09.2006)\r
+\r
+====================\r
+Hammag; 02.10.2006 23:30 GMT+1\r
+----------\r
+<General changes>\r
+ - Started implementation of .dat worldfile parser\r
+ - added a gameserver config option dev_debug to control development debug outputs\r
\r
+[GAME]\r
+Added PWorldDatParser class, with files include/world_datparser.h and def/world_datparser.cpp\r
+  (this classes might change/be replaced by a PWorldTemplate class very soon)\r
+\r
+====================\r
+Hammag; 03.10.2006 16:30 GMT+1\r
+----------\r
+<General changes>\r
+ - Fix a big bug in gameserver causing server crash when using new character\r
+    after its creation without server restart inbetween\r
+ - added a gameserver config option auto_save_period to control character autosave period (in sec)\r
\r
+[GAME]\r
+chars.cpp/.h :\r
+  added PChar::CreateNewChar() and moved effective char creation from PChars to PChar\r
+  added PChar::SQLDelete() (but not implemented yet)\r
+  added use of auto_save_period config option in PChars::update()\r
+  removed old XML-storage related code\r
+accounts.cpp : \r
+  fixed an issue in PAccount::SetBannedStatus() that was causing the "can't update banned status" error message.\r
+gameserver.cpp :\r
+  added some more DB cleanup when a char is deleted. Still incomplete and will later be done in PChar::SQLDelete()\r
+various .cpp files:\r
+  put more log output under control of dev_debug config option\r
+\r
+====================\r
+Hammag; 04.10.2006 12:00 GMT+1\r
+----------\r
+<General changes>\r
+ - Minor fixes to avoid some warnings\r
+ - def directory removed from repository\r
\r
+====================\r
+Hammag; 08.10.2006 01:25 GMT+1\r
+----------\r
+[rev. 20]\r
+\r
+<General changes> \r
+ - fixed .pak archive deep file reading\r
+ - implemented world furniture loading from world dat file (static furniture only atm)\r
+ - implemented loading of worlds templates from .dat files (just for test now, will be used very soon)\r
+\r
+WARNING: more NC files & dirs will be needed for the gameserver from now on:\r
+./def/* (as already used by previous revisions)\r
+./worlds.pak\r
+./worlds/*\r
+./terrain.pak\r
+./terrain/*\r
+\r
+with . being the gameserver's starting dir (a config option will be added soon to set this dir to something else if wanted)\r
+\r
+[COMMON]\r
+filesystem.cpp :\r
+  Fixed package reading to enable access to "subdirectories" in archive,\r
+    as well as translation from unix to dos path separator for in-archive search             \r
+  Removed the "file not found" message the PFileSystem::Open() was issuing in the corresponding case.\r
+    A NULL returned for PFile* is sufficient for the calling proc to manage the situation.\r
+  Changed file search in archives to case-insensitive.\r
+  \r
+[GAME]\r
+def_worlds.cpp :\r
+  added quotes and spaces trim to mName and mDatFile.\r
+def/gamedefs.cpp :\r
+  minor changes in PGameDefs::LoadWorldFileDefs() to make it more silent\r
+added furnituretemplate.cpp/.h (PFurnitureItemTemplate class)\r
+added worlddatatemplate.cpp/.h (PWorldDataTemplate class)\r
+added worlds.cpp/.h (PWorld and PWorlds classes)\r
+\r
+====================\r
+Hammag; 08.10.2006 01:25 GMT+1\r
+----------\r
+[rev. 21]\r
+\r
+<General changes>\r
+ - changed ingame debug management for a more generic @debug command:\r
+    @debug 0|1  : disable|enable all debug outputs\r
+    @debug loc[ation] 0|1 : disable|enable location output on move\r
+    @debug it[emid] 0|1 : disable|enable item ID output on item use\r
+   in the last two forms, omiting 0 or 1 just toggles the debug output\r
+ - some additions on worlds data checking/loading\r
+\r
+[GAME]\r
+accounts.h :\r
+  removed IsAdminDebug() and SetAdminDebug() methods\r
+client.cpp/.h : \r
+  added GetDebugMode() and SetDebugMode() methods, along with mDebugMode[] private member.\r
+commands.cpp :\r
+  implemented new version of @debug command\r
+decoder/udp_charmove.cpp :\r
+  implemented ingame location debug output on move\r
+decoder/udp_charmove.cpp :\r
+  implemented ingame item use debug output\r
+\r
+====================\r
+Hammag; 11.10.2006 01:25 GMT+1\r
+----------\r
+[rev. 22]\r
+\r
+<General changes>\r
+ - added MySQL keepalive function to avoid connection loss on long server inactivity periods\r
+ - fixed unreleased MYSQL_RES after all DB Res queries in infoserver leading to memory leak\r
+ - reintroduced Namikon's ISC \r
+\r
+[Make]\r
+Rules.make:\r
+  fixed libs order in linker args to avoid lib not found on some systems\r
+patch/Makefile :\r
+  commented out some unused libs in linker args\r
+info/Makefile :\r
+  fixed libs order in linker args to avoid lib not found on some systems\r
+  commented out some unused libs in linker args\r
+game/Makefile :\r
+  fixed libs order in linker args to avoid lib not found on some systems\r
+  commented out some unused libs in linker args\r
+\r
+[GAME]\r
+configtemplate.h, gameserver.conf :\r
+  added 'mysql_wait_timeout' config option, to be set to value of the\r
+    wait_timout system variable from the MySQL server (default 28800 sec).\r
+    It triggers the MySQL keepalive for both gameDB and infoDB connections.\r
+    Value 0 disables this keepalive function.\r
+sql.cpp/.h :\r
+  added Update() method, which now include MySQL keepalive management and CheckResCount()\r
+  added mKeepaliveDelay and mLastKeepaliveSent members\r
+main.cpp :\r
+  updated main loop to call MySQL->Update() instead of MySQL->CheckResCount()\r
+global.cpp :\r
+  added Hammag to the coders list\r
+isc.cpp/.h : reintroduced Namikon's ISC for implementation of serverlist update\r
+  through MySQL in the coming days.\r
+  \r
+[INFO]\r
+configtemplate.h, infoserver.conf :\r
+  added 'mysql_wait_timeout' config option (see [GAME])\r
+sql.cpp/.h :\r
+  added Update() method, which now include MySQL keepalive management\r
+  added mKeepaliveDelay and mLastKeepaliveSent members\r
+  added FreeSQLResult() method to perform mysql_free_result()\r
+main.cpp :\r
+  added call to MySQL->Update() in the main loop\r
+accounts.cpp, infoserver.cpp :\r
+  added call to FreeSQLResult() where required\r
+global.cpp :\r
+  added Hammag to the coders list\r
+\r
+====================\r
+Hammag; 13.10.2006 20:00 GMT+1\r
+----------\r
+[rev. 23]\r
+\r
+<General changes>\r
+ - activated modified ISC component. Server list and user count displayed by the infoserver\r
+   are now updated by the gameserver using the "MySQL" method (same as Neopolis X)\r
+ - added 'nc_data_path' option to gameserver.conf. It must be set to the root path of the nc data,\r
+    either the NC1 directory or a copy.  ./ means reative to gameserver start dir\r
+ - 'defs_path' and 'worlds_path' are not used anymore in gameserver.conf\r
\r
+[GAME]\r
+isc.cpp/isc.h :\r
+  implemented MySQL mode\r
+  some other generic addition to the PISC class\r
+configtemplate.h :\r
+  set 'isc_method' default to 1 (i.e. MySQL mode only)\r
+  set 'isc_update_intervall' default to 60 sec\r
+def/main.h :  \r
+  values of DEF_* defines for def filenames now include patgh relative to nc_data_path\r
+gamedefs.cpp :\r
+  modified to take into account main.h modifs and nc_data_path\r
+\r
+[INFO]\r
+infoserver.cpp :\r
+  modified PInfoSrver::GSLiveCheck() to be independant of gameserver time.\r
+    No time sync is needed between servers anymore.\r
+\r
+[COMMON]\r
+filesystem.cpp :\r
+  fixed a bug when handling some files .pak archives with path starting with ./\r
+\r
+====================\r
+Hammag; 24.10.2006 17:00 GMT+1\r
+----------\r
+[rev. 24]\r
+<General changes>\r
+Internal changes only\r
+\r
+====================\r
+Hammag; 26.10.2006 02:15 GMT+1\r
+----------\r
+[rev. 25]\r
+\r
+<General changes>\r
+ - finished world data on-demand loading\r
+ - fixed an issue in world "furniture" data loading\r
\r
+[GAME]\r
+added a Worlds global object (class PWorlds)\r
+modified PChar and PClient classes to Lease/Release world when char changes location,\r
+  which shall now be done using the new PClient::ChangeCharLocation method\r
+modified decoder/udp_zoning accordingly\r
+modified def/world_datstruct.h and def/world_datparser.cpp to fix world data loading\r
+\r
+====================\r
+Hammag; 08.11.2006 22:00 GMT+1\r
+----------\r
+[rev. 26]\r
+\r
+<General changes>\r
+ - added isc_server_id in gameserver.conf, to be set to s_id value from infoserver DB.\r
+    server status should then be kept up to date in the server selection window of NC client\r
+ - fixed a bug leading to char location being reset to bad zone when login in under some circumstances\r
+ - sitting on chairs now works again and is seen by others chars. Some more thing are to be added to this though.\r
+ - all dungeon/sewers/UG entries should work. But spawning place are not always right, as it seems that info in\r
+    appplaces.def is not allways the right one (about the "entity")\r
+ - all doors should open and be seen opening by other chars. Locked doors will open like any others\r
+    as I haven't found the link bewteen button and door\r
+ - other internal changes\r
+\r
+====================\r
+Hammag; 21.11.2006 02:00 GMT+1\r
+----------\r
+[rev. 27]\r
+\r
+<General changes>\r
+ - fixed teleport-to-nowhere-when-leaving-chair issue\r
+ - implemented free chair check\r
+ - implemented nice position when leaving chair (orientation still not fixed ...)\r
+ => problem of char disapearing for others when sitting for some time still not fixed*\r
+ - added "new_char_location" option in gameserver.conf, with default to mc5 starting zone\r
+ - added starting apartment creation\r
+\r
+====================\r
+Hammag; 25.11.2006 16:45 GMT+1\r
+----------\r
+[rev. 28]\r
+\r
+<General changes>\r
+ - fixed a bug when zoning to holomatch zones\r
+ - fixed Holomatch exit (but still same problem for spawning entity as in some dungeon zoning)\r
+ - fixed UG exit (but still same problem for spawning entity as in some dungeon zoning)\r
+ - fixed appartement lift use\r
+ - fixed char-vanish-for-others-when-sitting-too-long issue\r
+    (but already sitting char still invisible for loggin-in chars)\r
+ - fixed a bug in starting apartment creation \r
+ - increased TCP timeout which caused connection loss when taking too much time creating a char\r
+ - subskill increasing now works (freely, ie. without any check against class or available skill points)\r
\r
+====================\r
+Hammag; 26.11.2006 02:00 GMT+1\r
+----------\r
+[rev. 29]\r
+\r
+<General changes>\r
+ - triggered doors now work as expected (hopefully... the trigger button is the one\r
+    closest to the door). Hack button an money button just work like standard buttons for the moment.\r
+\r
+====================\r
+Namikon; 09.12.2006 01:20 GMT+1\r
+----------\r
+[rev. 30]\r
+\r
+[GAME]\r
+ - (Hopefully) Fixed Autoaccount problem with Gameserver (Rehashing accountdata now every 30 seconds. However,\r
+   this isnt verified.)\r
+ - New command: @rehash. Does the same as the server every 30 seconds, for those who cant wait :P\r
\r
+====================\r
+Namikon; 09.12.2006 01:32 GMT+1\r
+----------\r
+[rev. 31]\r
+- Forget to update the Changelog, ^_^\r
+\r
+====================\r
+Hammag; 09.12.2006 16:40 GMT+1\r
+----------\r
+[rev. 32]\r
+This revision is mostly a commit of intermediate change to avoid future conflicts, with no new functionnalty added\r
+\r
+<General changes>\r
+ - added regexsupport for futur use in user strings control (username, password, charname, etc)\r
+\r
+[GAME]\r
+main.cpp: changed type used for time in DB rehash from u32 (causing complile warning) to std::time_t which\r
+          is the time type (for seconds) now used in gameserver.\r
+          \r
+[COMMON]\r
+regex : added the RegEx class (Simple C++ wrapper for PCRE) to the tinns lib :\r
+        common/regex/regex++.cpp\r
+        include/regex++.h\r
+\r
+====================\r
+Namikon; 10.12.2006 11:35 GMT+1\r
+----------\r
+[rev. 33]\r
+\r
+<General changes>\r
+- Added @uptime to view server's uptime ingame\r
+\r
+[GAME]\r
+gameserver.h: Added "std::time_t mServerStartupTime" and public inline "GetStartTime()" to receive Server's\r
+             startup timestamp anywhere in the source\r
+gameserver.cpp: Added mServerStartupTime to gameserver's class constructor (Var gets set one time uppon startup)\r
+commands.cpp: Added @uptime. Generates readeable output in the form (Years, Months, Weeks, Days, ...) from the\r
+              difference between mServerStartUp and the current timestamp\r
+\r
+====================\r
+Hammag; 10.12.2006 14:50 GMT+1\r
+----------\r
+[rev. 34]\r
+\r
+<General changes>\r
+ - GenReps now dont need database info anymore.\r
+   However, the solution is not satisfaying, but will do until we find better\r
+ - Fixed Makefile issue about buggy dependency files\r
+ - Removed old unused src/netcode directory (the right dir is in src/common)\r
+\r
+[GAME]\r
+worlddatatemplate.cpp : in SetLinkedObjects(), added storage of GR order to later access to entity info\r
+def/gamedef.h/.cpp : added GetRespawnEntity() to get GR entity value from respawn.def, by entry order,\r
+   with management of exceptions in zones 1 & 2\r
+decoder/udp_useobject.cpp : now use PGameDefs::GetRespawnEntity() to get the entity of a GR object\r
+\r
+[INFO]\r
+Minor change in client connection message after checking for what looked to be a memleak (but was not ! :-D )\r
+\r
+====================\r
+Namikon; 10.12.2006 15:30 GMT+1\r
+----------\r
+[rev. 35]\r
+\r
+- Added @broadcast. GM and higher can now send out "ADMIN> Server: <text>" broadcasts\r
+- Worked on Chat subsystem. Current status:\r
+> Buddy                - Sends text to Buddy, everyone in the same Zone can read. No Buddylist yet\r
+> Local                - Another problem, local is TCP on retail, we use UDP. Works for now, needs further research\r
+> Clan         - Same as Buddy\r
+> Team         - Same as Buddy\r
+> Direct       - No function yet\r
+> GM           - Done. (100%)\r
+> Admin                - Done. (100%)\r
+> All others   - Nearly done. Sends/Receives to/from correct channel, including zone/fraction/etc\r
+                 limitation. However, you cant disable channels yet, needs further research.\r
+\r
+- 2 new options in gameserver.cfg: \r
+> broadcast_new                        - If set to 1, the server will send out an broadcast to channel OOC with\r
+                                 a welcome message. Default is 0.\r
+> broadcast_new_hidestaff      - If set to 1, all "non-players" are not announced over OOC. Default is 0.\r
+- Fixed some typos in chat.h/.cpp\r
+\r
+[GAME]\r
+chat.h/.cpp    : Corrected some typos.\r
+                 Added sendBroadcast (Admin channel)\r
+                 Added sendOOCBroadcast (OOC channel)\r
+                 Added all missing sendXXX functions\r
+                 Removed several Console outputs. We know it works, no need to debug it anymore.\r
+gameserver.cpp : Changed current welcome message to new OOC broadcast method\r
+configtemplate.h: Added 2 new default values for broadcast on connect\r
+commands.cpp   : Added @broadcast command. First command which checks your accesslevel. (as announced before)\r
+\r
+====================\r
+Namikon; 10.12.2006 15:30 GMT+1\r
+----------\r
+[rev. 36+37]\r
+\r
+- Worked again on Chat subsystem. Current status:\r
+> Buddy                - Done. (100%)\r
+\r
+[GAME]\r
+buddylist.cpp / .h : Added function "IsInBuddy()" to perform a simple check "Is a buddy? y/n"\r
+chars.h                   : Added inline to pass IsBuddy to buddylist->IsInBuddy()\r
+chat.cpp          : Fixed sendBuddy function. Working as it should now\r
+\r
+====================\r
+Namikon; 10.12.2006 23:20 GMT+1\r
+----------\r
+[rev. 38]\r
+- Worked again on Chat subsystem. Current status:\r
+> Direct               - Done. (100%)\r
+\r
+[GAME]\r
+chat.cpp/.h       : Added new function sendPlayerDirect, altered main-chatloop, order is now Local, Direct, others\r
+\r
+====================\r
+Namikon; 11.12.2006 00:59 GMT+1\r
+----------\r
+[rev. 39]\r
+Last update for this weekend lol ^^\r
+- Worked again on Chat subsystem. (What else)\r
+  This release may break tinns from working, until Hammag found a way to grab the data i need for the CustomChannels.\r
+\r
+[GAME]\r
+chat.cpp/.h    : Added check for every custom channel if its enabled or not\r
+chars.cpp/.h   : Added inline and variable to hold custom channel info\r
+\r
+====================\r
+Hammag; 11.12.2006 13:00 GMT+1\r
+----------\r
+[rev. 40]\r
+ - added Custom Chat Channel selection retrieval from client packets\r
+ - temp deactivated regex lib compilation as there still are some issues with dependencies\r
\r
+[GAME]\r
+chars.h        : Added SetActiveChannels method\r
+          Regrouped some method declarations by theme\r
+decoder/udp_chat.h/.cpp : added PUdpChatChannels class for custom channel info decoding\r
+\r
+[PATCH]\r
+Minor change in client connection message, same as what has been done for infoserver.\r
+\r
+====================\r
+Hammag; 11.12.2006 20:10 GMT+1\r
+----------\r
+[rev. 41]\r
+\r
+<General changes>\r
+ - added @version command\r
+ - added directory src/tools for compile tools and corresponding makefile\r
+ - dependency files issues should hopefully be solved now once for all\r
\r
+[GAME]\r
+commands.cpp: added @version command\r
+\r
+[PATCH]\r
+Minor change in client connection message, same as what has been done for infoserver.\r
+\r
+[All Servers]\r
+Added src/include/svnrevision.h (automatically updated)\r
+Removed inclusion of version.h for everywhere, and added it to each global.cpp\r
+Added ServerVersion and SVNRevision as global strings (globals.h) for each server\r
+Modified accordingly version display at server start in global.cpp\r
+\r
+[LIBS]\r
+misc.h/.cpp: Commented out GetSVNRev() that is not used anymore\r
+\r
+[TOOLS]\r
+ - added src/tools/cleandepfile.c\r
+   cleandepfile is used to clean dependency files generated by g++\r
+ - added src/tools/setsvnrev script to update the new src/include/svnrevision.h\r
+   when needed\r
+ - updated src/Makefile and src/Rules.make accordingly\r
+   No manual action should be needed to manage svn revision number inclusion in source\r
+   Game/Info/Patch servers version can still be set in version.h\r
+\r
+====================\r
+Namikon; 11.12.2006 21:46 GMT+1\r
+----------\r
+[rev. 42]\r
+\r
+<General changes>\r
+- Fixed (hopefully) customchannels. They're not loaded / saved from/to SQL yet, but you should be able to enable/disable them.\r
+  uppon entry, all channels are disabled.\r
+\r
+Hopefully, because i cant verify it. (No time to compile and try it). Will verify (and debug) it in the next few days\r
+\r
+====================\r
+Namikon; 13.12.2006 12:02 GMT+1\r
+----------\r
+[rev. 43]\r
+- Quick update: I replaced the "old" function to check if a customchannel is enabled or not with a much\r
+  faster one. (Bitwise comparison)\r
+- Fixed an typo in chat.cpp\r
+\r
+====================\r
+Hammag; 13.12.2006 17:10 GMT+1\r
+----------\r
+[rev. 44]\r
+\r
+<General changes>\r
+ - Added missing GPL licence file LICENCE.txt\r
+ - Renamed directory tools to dev-tools to distinguish from futur NC tools\r
+ - Fixed a small prototype issue causing compile warnings in dev-tools/cleandepfile.c\r
+ - Added option DO_DEBUG in Makefile to be uncommented if you want debug symbols and not stripped binaries\r
+ - Added inclusion of src/options.local (if exists, which is not mandatory) in Makefile to set local Makefile options\r
+    This is mostly for developer use, as it enables local compilation customization without propagation to SVN,\r
+    and avoids the need to use 'svn revert Makefile' each time...\r
+    \r
+    My current options.local file looks like:\r
+#\r
+# Local Makefile custom options\r
+# not in SVN !\r
+#\r
+DO_DEBUG = y\r
+CXXFLAGS += -march=pentium4\r
+\r
+    If I don't want to use these additonal options and test the real config, I just rename it to something else.\r
+\r
+====================\r
+Namikon; 14.12.2006 22:58 GMT+1\r
+----------\r
+[rev. 45]\r
+- Updated ISC definition file (v2)\r
+- Updated isc.h: Added enum for ISC connection stages\r
+- Added ISC Example.txt to show a few examples of an  "normal" datatransfer between game and infoserver\r
+\r
+\r
+====================\r
+Hammag; 14.12.2006 23:10 GMT+1\r
+----------\r
+[rev. 46]\r
+\r
+<General changes>\r
+ - Really added missing GPL licence file LICENCE.txt this time (hopefully...)\r
+ - Some compilation warning fixes\r
+ - Added internal tools to ease sources & bin packages generation\r
+   \r
+   make sourcetar : Builds a clean archive of all that is needed to compile and run TinNS (except NC data)\r
+   make bin tar : Builds a clean archive of TinNS binaries and other files needed to run TinNS (except NC data)\r
+                  Also alerts about src/options.local presence. (To be improved as check is done AFTER compilation right now ...)\r
+   Destination directory for tarballs is set in Makefile with TARBALLS_DEST (default ~)\r
+\r
+[DEV-TOOLS]\r
+Modifies src/Makefile (added sourcetar and bintar targets) and src/Rules.make\r
+Added make-src-tarball and make-bin-tarball in src/dev-tools\r
+\r
+====================\r
+Hammag; 15.12.2006 16:40 GMT+1\r
+----------\r
+[rev. 47]\r
+\r
+<General changes>\r
+ - minor internal changes only\r
+\r
+[GAME]\r
+decoder/udp_useobject.cpp : fixed again some signed to unsigned cast issue.\r
+decoder/udp_zoning.cpp .h : added PUdpEndOfZoning class\r
+decoder/udp_OOO.cpp : made message reception verbose\r
+\r
+====================\r
+Namikon; 15.12.2006 20:02 GMT+1\r
+----------\r
+[rev. 48]\r
+\r
+<General changes>\r
+ - minor internal changes only\r
+\r
+[GAME]\r
+Updated ISC ProtDef again. The protocol itself will be called ISCP from now on (Inter-Server-Communication-Protocol)\r
+Updated infoserver.conf, added ISC config values\r
+\r
+====================\r
+Namikon; 16.12.2006 15:36 GMT+1\r
+----------\r
+[rev. 49]\r
+\r
+[IMPORTANT]\r
+From this release on, TinNS will check more and more for accountlevels.\r
+If you want admin access, you have to edit your MySQL table. (Admin: Level 100)\r
+Its not much yet, but the first steps have been made, and more will follow.\r
+Next step will be the gamemaster/admin commands.\r
+\r
+<Infoserver>\r
+- Changed default error-return for Sql Checkaccount from -12 to -99, to create free place for further errormessages\r
+- Added require_validation to infoserver.conf. You can enable this if you like to create accounts on your own,\r
+  not by autoaccount.\r
+\r
+<Gameserver>\r
+- Removed traces of old AutoAccount creation in GameServer. AutoAcc should *only* be done by Infoserver!\r
+- Added accountlevel check.\r
+\r
+====================\r
+Namikon; 17.12.2006 22:42 GMT+1\r
+----------\r
+[rev. 50]\r
+\r
+IMPORTANT:\r
+This rev keeps crashing and it also causes OutOfOrder packets, for whatever reason. we have to trace\r
+this down first.\r
+\r
+[GAME]\r
+- Fixed errors from last SVN release (Caused several segmentation faults)\r
+- Added configfile commands.conf\r
+- Added check for required accountlevel when trying to use ingame command\r
+\r
+[INFO]\r
+- Fixed errors from last SVN release (Caused several segmentation faults)\r
+- Added default values for isc stuff to configtemplate.h. I forgot to add them in the last revision\r
+\r
+====================\r
+Namikon; 18.12.2006 00:23 GMT+1\r
+----------\r
+[rev. 51]\r
+\r
+Small update:\r
+- Fixed AccountLevel (You always got full admin access after login)\r
+\r
+====================\r
+Namikon; 18.12.2006 01:57 GMT+1\r
+----------\r
+[rev. 52]\r
+\r
+- Fixed bug that you could'nt see the welcome message after login\r
+- Added (hopefully) a workaround for our SegFault problem (2 user online, 3rd is trying to connect -> SegFault)\r
+\r
+====================\r
+Namikon; 19.12.2006 03:03 GMT+1\r
+----------\r
+[rev. 53]\r
+\r
+its a pity, but the workaround didnt work. Still investigating this!\r
+MANY changes to the source, cant remember all. Here is what my brain has stored:\r
+\r
+- Direct chat completed. (If target player isnt online, you'll get this nice "Player not online" message)\r
+- ReEnabled AutoRehash, wasnt responsible for the crash\r
+- Added @kick, @info, @warpto, @recall and @setlevel. @info is tested and verified, @kick does nothing (yet) the\r
+  rest is untested but should work. (Hard to test with only 1 char online...)\r
+- Some more very small changes. If you want a detailed log, ask SVN history :D\r
+\r
+====================\r
+Hammag; 20.12.2006 21:00 GMT+1\r
+----------\r
+[rev. 54]\r
+\r
+<General changes>\r
+ - fixed bug in NC datafiles lookup when nc_data_path was set to something else than .\r
+\r
+[LIBS]\r
+filesystem/filesystem.cpp .h : added base path arg to file open method.\r
+\r
+[GAME]\r
+def/defparser.cpp, def/world_dataparser.cpp : modified accordingly to changes made to PFileSystem\r
+\r
+[PATCH]\r
+patchserver.cpp : modified accordingly to changes made to PFileSystem\r
+\r
+\r
+====================\r
+Namikon; 21.12.2006 19:28 GMT+1\r
+----------\r
+[rev. 55]\r
+\r
+*Note*\r
+The new commands have to be tested first! Dont expect them to work yet, its just a upload\r
+since the entire command files got rewritten.\r
+\r
+<General changes>\r
+ - Rewritten entire commands.cpp/.h files\r
+ - Fixed ingame command @kick. Works now as it should.\r
+   Also sets a temp-ban for a configureable amount of seconds to prevent instant-relog.\r
+ - Added new ingame coommands:\r
+   @ban <charID/nick> <xS>/<xM>/<xH>/<xD>   || @ban EvilUser 20m  <- Bans "EvilUser" for 20 minutes.\r
+   - Bans given player for given time. You can only set ONE timevalue. (Either S/M/H or D. Not case sensitive)\r
+\r
+   @unban\r
+   - Not working yet. Has to be done by direct SQL access\r
+   @listbans\r
+   - Not working yet. Has to be done by direct SQL access\r
+\r
+   @shun <charID/nick>\r
+   - Blocks all incoming char/command traffic from given client until re relogs\r
+     Returns error if already shunned\r
+\r
+   @unshun <charID/nick>\r
+   - Remove shun instantly. Returns error if not shunned\r
+\r
+   @jail <charID/nick>\r
+   - Warp given player to Regants legacy. Returns error if player is already in Regants\r
+\r
+   @unjail <charID/nick>\r
+   - Free given player from Regants. Returns error if player is not in Regants/Jailed\r
+\r
+   @teleport <charID/nick> <worldID>\r
+   - Teleport given player to given world\r
+\r
+ - Added (experimental) startscript for TinNS. Has to be testen/debugged\r
+\r
+[COMMON]\r
+ <external.h>   Added <cctype> to get access to isdigit() function\r
+ <version.h>    Increased VerNr\r
+\r
+[GAME]\r
+ <accounts.cpp/.h>   Added vars&methods to store shunned status\r
+ <globals.cpp/.h>    Added global class for gamecommands\r
+ <chat.cpp>          Changed GameCommand call to work with the new command class\r
+ <commands.cpp/.h>   Completely rewritten. Moved every ingame command into own method, called by\r
+                     a main function which takes care of all args. Maybe has to be improved later, but its ok for now.\r
+\r
+====================\r
+Namikon; 21.12.2006 21:50 GMT+1\r
+----------\r
+[rev. 56]\r
+\r
+Improved pak_decompress script from Akiko\r
+- Added errorcheck for in/output file\r
+- Added check for NC and normal zLib files\r
+  (Can unpak both)\r
+- Added optional details-output\r
+\r
+The script is now capable to be used in batchfiles, since the only output is either [OK] <filename> or [ERROR] <filename>.\r
+if you dont want this, you can specify detailed output with all errors.\r
+\r
+====================\r
+Namikon; 21.12.2006 21:55 GMT+1\r
+----------\r
+[rev. 57]\r
+\r
+Forgot the CHANGELOG ^^\r
+\r
+====================\r
+Namikon; 22.12.2006 17:33 GMT+1\r
+----------\r
+[rev. 58]\r
+\r
+<General changes>\r
+- Improved pak_decompress tool from Akiko\r
+- Added tool "getsvnrev" (Same again in src/dev_tools, required for make process)\r
+- Improved Hammag's setsvnrev bash script (Now does errorcheck and has an alternative way to\r
+  grab SVN revision if SVN is not installed)\r
+- Splitup of commands.cpp. Every command has now its own .cpp file in gamecommands/.\r
+  Makes it a lot easier to handle new commands or change/fix/remove existing ones\r
+- ReEnabled debug-output while loading world .dat files. Was commented out for some reason\r
+\r
+No real "changes" or "fixes" to main-source files. Only splitup's and new/improved devtools.\r
+See SVN->Diff for details\r
+\r
+====================\r
+Namikon; 22.12.2006 22:55 GMT+1\r
+----------\r
+[rev. 59]\r
+<internal version: 0.1.5 Dev>\r
+\r
+- Added missing Makefile for gamecommands/ subfolder\r
+- Removed check for ZoneID 552 from jail.cpp and unjail.cpp; This zone is never used\r
+- Moved mShunned from Account to chars\r
+- Added mJailed to chars with methods to identify a jailed player\r
+- Added explicit override to GM teleport and jail/unjail commands (The only way to move someone if target is jailed)\r
+- Completed shun/unshun command\r
+\r
+====================\r
+Namikon; 22.12.2006 22:55 GMT+1\r
+----------\r
+[rev. 60]\r
+<internal version: 0.1.6 Dev>\r
+\r
+- Added several security checks to game commands\r
+- Added missing status outputs on successfull gamecommand\r
+- Added solution to send an delayed positionupdate after warping\r
+\r
+====================\r
+Namikon; 23.12.2006 09:31 GMT+1\r
+----------\r
+[rev. 61]\r
+<internal version: 0.1.7 Dev>\r
+\r
+Small update:\r
+- Removed ingamecommands "addworlditem", "delworlditem" and "adddoor". TinNS gets the worlddata dynamicly from loaded\r
+  .dat files instead of MySQL Database.\r
+  \r
+commands.conf   : Removed config settings for the 3 commands mentioned above\r
+commands.cpp/.h : Commented out the 3 mentioned commands\r
+adddoor.cpp     : Commented out entire file\r
+delworlditem.cpp: Commented out entire file\r
+addworlditem.cpp: Commented out entire file\r
+\r
+====================\r
+Namikon; 24.12.2006 01:30 GMT+1\r
+----------\r
+[rev. 62-63]\r
+<internal version: 0.1.8 Dev - 0.1.10 Dev>\r
+\r
+- Added experimental char warp-aura and char disappear packets to all warp-commands\r
+  (Worked while testing, but not after implementation into the commands)\r
+- Worked on Chatsystem: Localchat 99% working. Localchat is now limited to a small area around the player\r
+  (However, the chat is sent over TCP, like all other packets. It should be UDP, but this isnt working\r
+  for some reason. If anyone finds out why, tell us please)\r
+- Added Developercommand "@test". It has no fixed function, and is not configureable by config file.\r
+  Devs can easily add stuff there to test various things.\r
+- Removed adddoor, delworlditem and addworlditem completely from SVN, they're not needed anymore\r
+- And a few things i cant remember -.-\r
+\r
+====================\r
+Namikon; 25.12.2006 00:24 GMT+1\r
+----------\r
+[rev. 64]\r
+<internal version: 0.1.11 Dev>\r
+\r
+- Fixed Blacksync issue when logging in\r
+- Disabled position update on warpto and recall commands. It's not possible at the moment to\r
+  force the client to update the charposition.\r
+  \r
+====================\r
+Namikon; 26.12.2006 22:33 GMT+1\r
+----------\r
+[rev. 65]\r
+<internal version: 0.1.13 Dev>\r
+\r
+- Added UDPManager functions to connection_udp. Keeps the last 20 important UDP messages in a queue, for\r
+  possible resend after a OOO notice by the client\r
+- Finally fixed the warpcircle and charvanish! The mentioned commands in Rev 62-63 now work as announced\r
+- UDP_ID and all related stuff moved to connection_udp. Will be more controlled in the future from there\r
+\r
+====================\r
+Namikon; 26.12.2006 22:33 GMT+1\r
+----------\r
+[rev. 66]\r
+<internal version: 0.1.14 Dev>\r
+\r
+- Added, by Stings request, serveranswer to worldroute query: "Where is the Primary App" works now.\r
+- "Fixed" SQL function GetAptLocID(). Now only decreases the location value if the given AppartmentID is higher than 100000\r
+\r
+====================\r
+Namikon; 27.12.2006 19:05 GMT+1\r
+----------\r
+[rev. 67]\r
+<internal version: 0.1.15 Dev>\r
+\r
+Small update\r
+- Added 2 error messages for genrep activation. (Wrong faction and MC5 "broken")\r
+\r
+====================\r
+Namikon; 28.12.2006 18:45 GMT+1\r
+----------\r
+[rev. 68]\r
+<internal version: 0.1.16 Dev>\r
+\r
+- 2 new ingame commands:\r
+ @givemoney <amount> [<charID or nick>]\r
+ @takemoney <amount> [<charID or nick>]\r
+ I dont think i have to explain what they do :)\r
+\r
+- Added universal udpmessage to trigger messages from text.ini\r
+\r
+====================\r
+Namikon; 28.12.2006 20:02 GMT+1\r
+----------\r
+[rev. 69]\r
+<internal version: 0.1.16H Dev>\r
+\r
+Internal Release / "Hotfix"\r
+The udpmanager was planned to cancel OOO notices, but he causes an segfault when trying to send the message.\r
+Its not clear yet why, therefore, the OOO handling got disabled. It will be re-enabled when this is fixed.\r
+\r
+====================\r
+Namikon; 30.12.2006 08:11 GMT+1\r
+----------\r
+[rev. 70]\r
+<internal version: 0.1.17 Dev>\r
+\r
+- Added "life" to hackbuttons and entrance-fee buttons. (Level GM and higher can just "use" hackbuttons, lower levels\r
+       must hack it. For entrance fee buttons, everyone must pay. Why? Well, for what is the @givemoney command ^.^)\r
+       Since hacking is not working yet, (we have to add item-usage first) make sure to set your own level to 50+, or you\r
+       wont get these doors open)\r
+- Disabled some debug outputs forgotten in the last release\r
+\r
+====================\r
+Namikon; 30.12.2006 19:41 GMT+1\r
+----------\r
+[rev. 71]\r
+<internal version: 0.1.18 Dev - 0.1.22 Dev>\r
+\r
+- Added handling class for item movement (QB<>Inv<>GoGu<>Ground), no real function yet, but its decoded\r
+- Added handling class for QuickBelt management. You can activate the flashlight in slot 0 now, and others can see it\r
+  The functions are prepared to handle any item that exists, but we dont have items working until now.\r
+- Removed Debug output from sql.cpp\r
+\r
+====================\r
+Namikon; 01.01.2007 23:32 GMT+1\r
+----------\r
+[rev. 72]\r
+<internal version: 0.1.22 Dev - 0.1.24 Dev>\r
+\r
+**** Happy new year!! ****\r
+\r
+- Item movement within quickbelt works\r
+- Added hacktool to QB to test hacking\r
+- Added the last missing staffchar (GM>)\r
+- Added decoder for inithack and starthack messages\r
+- A few more changes i cannot remember\r
+\r
+====================\r
+Namikon; 02.01.2007 20:52 GMT+1\r
+----------\r
+[rev. 73]\r
+<internal version: 0.1.25 Dev>\r
+\r
+- Added new command @spawnactor\r
+  Usage: @spawnactor <actorID> <functionType>\r
+   - ActorID can be found in models/pak_models.ini\r
+   - FunctionType defines the type of the actor.\r
+     This can be almost everything, from item containers to\r
+     apartmentlift accesspanels\r
+   This command spawns and static worldactor next to your current\r
+   position. Everyone who is within the range of UDP broadcast\r
+   can see / "use" the new actor. It isnt saved to sql yet, nor is it\r
+   managed. (You cant spawn an itemcontainer and open it)\r
+   \r
+Thanks to Sting for this release! We where working on hack-stuff (doors, hackboxes,..)\r
+when he found the required information to make this possible.\r
+\r
+====================\r
+Namikon; 04.01.2007 16:15 GMT+1\r
+----------\r
+[rev. 74]\r
+<internal version: 0.1.26 Dev>\r
+\r
+- WorldActor management class added.\r
+       Spawned actors now stay in that zone as long until someone removes them.\r
+       \r
+       To remove spawned worldactors, the @remove command has been improved:\r
+       Type "@remove actor" to set your client into "REMOVE ACTOR" mode (You'll get\r
+       an ingame notice about this)\r
+       Then simply click on any dynamic worldactors to remove them. To leave this remove mode,\r
+       type "@remove actor" again. (And again you'll get a notice about that)\r
+       \r
+       Note: You cannot remove static worldactors (those who are in the .dat files) with this.\r
+             It is possible to let them disappear (type @remove <rawID>) but they'll respawn when you re-zone.\r
+             \r
+IMPORTANT: This release requires an database update! Make sure you have the latest mysql table availeable.\r
+\r
+====================\r
+Namikon; 07.01.2007 19:40 GMT+1\r
+----------\r
+[rev. 75]\r
+<internal version: 0.1.27 Dev - 0.1.35 Dev>\r
+\r
+Huge update!\r
+\r
+- Changed default level for @remove from 100 to 50, since we can now also remove dynamic actors with it\r
+- Added security check to @remove command: You cannot remove Dynamic actors over their IDs anymore.\r
+  Remove them with @remove actor command\r
+- UDPManager rewritten. Was almost completely wrong, dunno what happend with me when i first wrote it :P\r
+  However, it works now. The last 20 UDP messages with 0x03 commandset are saved, and get resend uppon\r
+  OOO notice from the client.\r
+  The manager also watches the outgoing UDP IDs. With his, it was possible to fix an udp increment bug in the zoning process.\r
+- Messages in the VIP queue arent parsed over the udpmanager. We'll have to rename this later on (or add a new queue)\r
+- The UDP/SessionID offset is now defined in connection-udp.h\r
+- NPC subsystem added. (Yeah ^^)\r
+  All NPCs that are in npc_spawns database spawn and stay in their world. We dont have an AI, so dont expect NPCs to\r
+  do *anything* yet. (Same goes for traders or copbots) But everything is prepared\r
+- Added function "IsWorldInUse" to clientmanager. In first line required for NPC manager, to check if a world is in use or not\r
+- Reformatted several files for better readability.\r
+- Extended dynamic worldactor management:\r
+   - Spawned worldactors are functional now. (Eg: Spawn a chair and sit on it) (Function is not 100% tested, it *could* procude an segfault, report it\r
+     if the server crashes for you on a certain actorID)\r
+   - Only valid worldmodel templates are accepted now while spawning actors\r
+   - If given worldmodel template needs an linked object (For example an door) you have to add the doorID in the @spawnactor command (example below)\r
+   - On serverstart and every initworld, the database is checked for duplicate worldactor IDs. If some are found, they get deleted\r
+   - Another check is done when an worldactor is spawned. If (for any reason) an invalid worldactorset is in the Database,\r
+     it is ignored uppon spawning. (invalid means, that the actor points to an invalid object, for example door or world)\r
+- Added detailed output for SQL errors (Prints not only "ERROR" or just returns nothing, instead a full errormessage is written to console)\r
+- MsgBuilder:\r
+       - Baselinepacket changed, monsters are now "red"\r
+       - Fixed increase_udp issue in BuildZoning1Msg\r
+- Added new decoder:\r
+       - 0x08: This small (only 1 byte) "packet" is only sent when the client exits abnormal (crash, sometimes on alt+f4)\r
+         Does nothing else than closing the connection serverside.\r
+         \r
+*Note* Due the massive update of sourcecode, its likely that i forgot some debug outputs (You'll see D1, D2,.. or whatever else senseless text\r
+on the console). If you find something, tell me please over forum or bugtracker. But i will remove all outputs when i find some in the next\r
+releases\r
+\r
+====================\r
+Namikon; 07.01.2007 21:52 GMT+1\r
+----------\r
+[rev. 76]\r
+<internal version: 0.1.36 Dev>\r
+\r
+- Added hacking ability to hackbuttons (Both static and dynamic worldactors)\r
+  Itemcontainers will follow when we have a management class for them\r
+- Removed several debug outputs, and changed others\r
+- Fixed an typo in command remove\r
+\r
+====================\r
+Namikon; 08.01.2007 15:47 GMT+1\r
+----------\r
+[rev. 77]\r
+<internal version: 0.1.36 Dev>\r
+\r
+Fixed compiler error:\r
+In member function 'void ConnectionUDP::InsertUDPMessage(PMessage*)':\r
+udpmanager.cpp:133: error: conversion from 'int' to non-scalar type 'std::_Rb_tree_const_iterator >' requested\r
+on some systems\r
+\r
+====================\r
+Namikon; 11.01.2007 19:31 GMT+1\r
+----------\r
+[rev. 78-79]\r
+<internal version: 0.1.37 Dev>\r
+\r
+- Added up-to-date SQL dump to SVN. (But better use the newest neoX db!)\r
+- Fixed bug in worldactors that caused the following problems:\r
+> Spawned actors where removed uppon next serverstart/re-zone\r
+> Only one actor in a zone at once\r
+- Added first steps for ingame terminal handling\r
+\r
+====================\r
+Namikon; 13.01.2007 10:57 GMT+1\r
+----------\r
+[rev. 80]\r
+<internal version: 0.1.38 Dev>\r
+\r
+- Added a few comments in npc.cpp and removed most debug outputs\r
+- Splitted up terminal.cpp into 5 files (All stuff in one file will get too big later)\r
+- Moved TryAccess handling for terminal stuff to PTerminal class\r
+\r
+====================\r
+Hammag; 27.05.2007 12:15 GMT+2\r
+----------\r
+[rev. 81]\r
+\r
+<General changes>\r
+ - Minor internal changes\r
\r
+[MAKEFILE]\r
+- Makefile, dev_tools/Makefile, setsvnrev: Disabled the use of getsvnrev.\r
+  If someone has no SVN, and got sources from tarball, he can compile with the included svnversion.h\r
+  If he does coding, he needs SVN to commit changes, so there's no need for getsvnrev.\r
+  If he's doing coding and hasn't SVN, and got sources from tarball, then he won't have .svn files\r
+    needed by getsvnrev at hand.\r
+  As I don't see the use of getsvnrev, I disabled it. If it is really needed sometimes,I can add\r
+    a local option to enable it on a case by case basis.\r
+  Anyway, if someone submits code changes without having be given write access to SVN, he must submit\r
+    them to a tinNS dev who has access, so code review, testing and SVN management will be done properly.\r
+- Other minor change on files cleanup \r
+\r
+[GAME]\r
+- game/decoder/udp_appartment.* : minor correction on files info\r
+\r
+====================\r
+Hammag; 28.05.2007 23:15 GMT+2\r
+----------\r
+[rev. 82]\r
+\r
+<General changes>\r
+ - Major change to account management and character loading:\r
+    Accounts are not stored in-mem anymore, and database is queried when needed instead.\r
+    Chars are loaded when needed, and unloaded when not neaded anymore.\r
+ - New Gameserver Database version (6)\r
+ - Various fixes.\r
+\r
+[DATABASE]\r
+ - GameDB5.zip has been replaced by GameDB6.zip holding the full gameserver dump to be used\r
+  to get a fresh new DB needed by this revision of TinNS\r
+ - GameDB5_to_GameDB6.sql can also be applied to migrate from version 5 to 6 of gameserver DB\r
+ - infoserver DB is not changed (i.e. version 2)\r
+\r
+[GAME]\r
+More than 50 files changed.\r
+ - in addition to the changes stated above, Char creation and charslot assignement is now\r
+    fixed.\r
+    **** PLEASE MANUALLY FIX THE SLOT NUM OF EXISTING CHARS OR RECREATE THE CHARS ****\r
+    (Server will complain in logs and won't be hurt by muliple SLOT 0 chars anyway)\r
+ - @rehash command has been removed as not used anymore\r
+ - database.cpp and inclide/database.h have been deleted along with PDatabase class\r
+ - PAccounts class has been removed\r
+\r
+[NETCODE]\r
+ - Fixed mem leak in ConnectionUDP:\r
+    PMessage held in UDP backlog not being released in object destructor\r
+ - The static member PMessage::ListPools() can now be used anywhere to get a view of\r
+    message buffer pools use (in use / free buffers)\r
+\r
+====================\r
+Hammag; 05.06.2007 01:30 GMT+2\r
+----------\r
+[rev. 83]\r
+\r
+<General changes>\r
+ - fixed a bug which might be the cause of the "multiuser+char creation crash"\r
+  (hopefully solved now)\r
+ - many improvements in char movement (now much more responsively seen by others)\r
+ - Sitting chars are now visible by later login-in chars\r
+ - internal changes to PClient\r
+\r
+[GAME]\r
+ - udp_charmove.* : PUdpCharAttitudeUpdate and PUdpCharSitting code is now taken\r
+    care of in PUdpCharPosUpdate.\r
+    These two classes are removed.\r
+ - msgbuilder.* : added MsgBuilder::BuildCharPosUpdate2Msg\r
+ - client.* : added PClient::FillInUDP_ID() to take care in one place of all UDP_ID\r
+    filling-in of USP packets\r
+    added PClient::SendTCPMessage() and PClient::SendUDPMessage(), which take care\r
+    of NULL TCP or UDP sockets.\r
+  - chars.* : added PChars::CharExist() to check for char existence by name\r
+  - chat.cpp : fixed a repeated bug that led to crash when some client was connected\r
+    without a char ingame (like in char selection, creation or deletion phase) and\r
+    some chat was sent to him (like when someone else was coming ingame)\r
+\r
+====================\r
+Hammag; 09.06.2007 00:10 GMT+2\r
+----------\r
+[rev. 84]\r
+\r
+<General changes>\r
+ - fixed a bug causing the server to crash under some conditions\r
+ - fixed account management so that ingame account level setting doesn't need relog\r
+    to be effective\r
+\r
+[GAME]\r
+Started work on the type 0x20 zoning doors.\r
+Added decoder/udp_entityposreq.cpp decoder/udp_entityposreq.h\r
+\r
+[LIBS]\r
+connection-udp.cpp: Fixed a bug causing server to crash when resending packet.\r
+\r
+====================\r
+Hammag; 19.06.2007 21:10 GMT+2\r
+----------\r
+[rev. 85]\r
+\r
+<General changes>\r
+ - fixed zoning (hopefully)\r
+\r
+[GAME]\r
+Fixed zoning for "2nd type zoning" in sewers/caves and UG exits.\r
+There might remain some wrong zoning points in some case, as there seem to be some duplicate\r
+zoning spawn location in some zone data... but the "keep last spawn location" policy seem to work ok.\r
+Only spawn point issue when GRing in apt should remain.\r
+\r
+====================\r
+Hammag; 21.06.2007 01:45 GMT+2\r
+----------\r
+[rev. 86]\r
+\r
+<General changes>\r
+ - bug fix\r
+\r
+[GAME]\r
+decoder/udp_entityposreq.cpp: fixed a bug\r
+\r
+====================\r
+Hammag; 15.07.2007 19:00 GMT+2\r
+----------\r
+[rev. 87]\r
+\r
+<General changes>\r
+ - infoserver & gameserver now make use of common config/global.conf file (as least in\r
+    default conf/*.conf files)\r
+\r
+[LIBS]\r
+config.* :\r
+  - conf/*.conf file can now use the 'include' directive to include other config files\r
+  - Now use PCRE RegEx instead of "strtok", enabling rentrance and removing potential issues.\r
+  - Added GetOption & GetOptionInt with const std::string parameter\r
+  - Fixed a bug in EOF detection in the main file reading loop\r
+\r
+conf/global.conf : Moved/added following directives in conf/global.conf\r
+    minlevel = 0\r
+    username_filter = ^[a-z][\w\-]{2-14}$\r
+    password_filter = ^[[:graph:]]{3-15}$\r
+\r
+[INFO]\r
+  Added username and password syntax filter in config (username_filter and password_filter\r
+    directives, see above). Filters are case insensivite PCRE RegEx.\r
+  Note: theses filter need to protect at least against sql injection.\r
+  accounts.* : built common code with gamseserver (Not put in common tinns lib atm\r
+    because of DB access and log issues)\r
+    \r
+[GAME]\r
+  Added charname and clanname (for future use) syntax filter in config/gameserver.conf :\r
+    charname_filter = ^[a-z]+([\-\ ]?[a-z]+){0-2}$\r
+    clanname_filter = ^[a-z][\w\-\ ]{2-14}$\r
+  Filters are case insensivite PCRE RegEx.\r
+  Note: theses filter need to protect at least against sql injection.\r
+\r
+  sql.*, appartments.* : Moved Apt request methods from PMySQL to PAppartements\r
+\r
+====================\r
+Hammag; 27.10.2007 19:00 GMT+2\r
+----------\r
+[rev. 88 to 90]\r
+<General changes>\r
+  Items management\r
+\r
+[GAME]\r
+  Added container.cpp & container.h to implement classes used to manage all containers (including backpack, belt, armor, implant, processor, gogo, boxes, etc.)\r
+  Implemented basic item moves between containers.\r
+  Box content is randomly generated, and are not saved (you can use them to get rid of items)\r
+  No partial quantity move/stacking management yet\r
+  "take all" from boxes doesn't work yet (couldn't figure out yet how it works in detail)\r
+  No item to/from ground yet, no trading yet, no item type recognition/pre-req/management for implants & armors yet\r
+\r
+[LIBS]\r
+  Netcode: a bug in packet decoding was revealed, which seem to somtime lead to (maybe) infinite loop. Not fixed yet.\r
+  \r
+====================\r
+Hammag; 27.10.2007 19:00 GMT+2\r
+----------\r
+[rev. 91]\r
+\r
+[GAME]\r
+  Zoning issue fixed (a bug was leading to always load the same zone data for all zones with the same .bsp file, which is wrong)\r
+  Improved random-filled boxes\r
+  Excluded "temporary-items" from available item catalog (ItemsDef)\r
+\r
+====================\r
+Hammag; 28.10.2007 16:15 GMT+2\r
+----------\r
+[rev. 92]\r
+<General changes>\r
+  @warpto command now works.\r
+  \r
+[GAME]\r
+  Improved container loading in odrer not lo load invalid items from DB.\r
+  Items are not deleted from DB because it could cause loss of inventory\r
+   in case of issue with items.def content or loading.\r
+\r
+Hammag; 9.11.2007 23:30 GMT+2\r
+----------\r
+[rev. 93]\r
+<General changes>\r
+  Worked on subway.\r
+  Subway cabs are now spawned, can be entered, and can be exited but with a wrong pos (you get back to your starting pos :-D )\r
+  There is a delay between cab door opening/closing, and the acceptance of your entering request, so try multiple times.\r
+  Visibility between subway travellers isn't working.\r
+  \r
+  More work needed on that topic, and some server-side computations need to be fully recreated/emulated.\r
+  \r
+[GAME]\r
+  subway.cpp/.h : Added PSubway class to manage Neocron subway cabs.\r
+  Many files: Extended the Chair system to a general Seat system, used for subway and maybe for vhc.\r
+\r
+Hammag; 18.11.2007 18:45 GMT+2\r
+----------\r
+[rev. 94]\r
+<General changes>\r
+  Subway is now apparently running well.\r
+  Much work was needed to achieve that as some server-side computations were needed to emulate the subway movements.\r
+  There still may be some timing issues about the subway cab positions and door status on the long run...\r
+  Visibility between subway travellers isn't working yet. It will be done when working on vehicules to try make it all the same way.\r
+\r
+  Added subcommand @debug subway\r
+  \r
+[GAME]\r
+  subway.cpp/.h : Various changes\r
+  decoder/udp_charmove.cpp/.h , decoder/udp_useobject.cpp/.h : Various changes for subway use\r
+  chars.cpp/.h : moved PCharPosition class out of PChar, and added some required methods to it\r
+  decoder/udp_terminal.h/.cpp : started some work on that\r
+\r
+Hammag; 28.12.2007 00:50 GMT+2\r
+----------\r
+[rev. 96]\r
+<General changes>\r
+  Basic vehicle is in place.\r
+  One vhc of each type is available to every character. No prereq limitation.\r
+  Only pilot access available, and for the owner only.\r
+  No zoning yet.\r
+  Orientation issues from the others chars point of view.\r
+  Many things not implemented (and a good part still to be decoded)\r
+  \r
+[GAME]\r
+  Many changes in decoders and char, client and vehicle code.\r
+\r
+Hammag; 20.01.2008 20:00 GMT+2\r
+----------\r
+[rev. 97]\r
+<General changes>\r
+  [GAME + INFO]\r
+    sql.cpp/.h : added EscapeString() methode to PMySQL class, to permit string escape in SQL queries\r
+    *.cpp : escape all strings used in SQL queries, which is now mandatory.\r
+  [GAME + INFO + PATCH]\r
+    *.cpp : replaced strcpy(), strcat(), sprintf() with respectively strncpy(), strncat(), snprintf()\r
+      The first ones are now forbidden.\r
+\r
+Hammag; 2.02.2008 16:15 GMT+2\r
+----------\r
+[rev. 98]\r
+\r
+[Infoserver]\r
+accounts.cpp : Correction of the account creation/update SQL query - thank to drhawk ;)\r
+\r
+Hammag; 11.02.2008 20:30 GMT+2\r
+----------\r
+[rev. 99]\r
+Correction of an initialization issue that caused compilation error on some environments.\r
+\r
+Hammag; 20.04.2008 00:50 GMT+1\r
+----------\r
+[rev. 100]\r
+\r
+<Gameserver>\r
+msgbuilder.h/.cpp: added method PMessage* BuildTraderItemListMsg() (test version)\r
+decoded/upd_useobject.cpp: change so that only vhc terminal opens vhc interface\r
+client.cpp: added fragmented message type 0xac for traders\r
+chars.cpp: fixed initial inventory saving\r
+item.cpp/.h: added new method PItem::MakeStandardItem()\r
+\r
+Hammag; 15.03.2009 19:25 GMT+1\r
+----------\r
+[rev. 103]\r
+Fixed various warnings due to C++ compiler being more picky.\r
+  TinNS should now compile without warning on gcc version 4.3.2\r
+  Abort compliation on warning reactivated in makefile (-Werror)\r
+\r
+Added file options.local.exemple to set custom complilation options (read it for more info)\r
+\r
+Hammag; 19.03.2009 13:00 GMT+1\r
+----------\r
+[rev. 104]\r
+\r
+<Gameserver>\r
+  Fixed some errors in apartment Genrep'ing code\r
+  Implemted Venture Warp\r
+\r
+Hammag; 20.03.2009 14:20 GMT+1\r
+----------\r
+[rev. 105]\r
+\r
+<Gameserver>\r
+  Implemted Outfitter (not persistent yet. No need for that now)\r
+\r
+Hammag; 28.03.2009 14:20 GMT+1\r
+----------\r
+[rev. 106 - 108]\r
+\r
+<Database> (by Sting)\r
+  Slight changes to npcspawn table in Game Database.\r
+  Removal of most npc out of J01\r
+\r
+<Gameserver>\r
+  Fixed inventory so that items found in boxes and put in inventory are saved as expected\r
+  Some testing code for inventory\r
+  Fixed entry in Subway cabs, which had been broken during addition of vhc\r
+  \r
+<SVN>\r
+  Removed zipped database sql files, and put a non-compressed version instead. this will allow to track the changes made to these file.\r
+  Nota: We should later split these files in database structure files on the one hand, and database data on the other hand.\r
+\r
+Hammag; 30.03.2009 14:20 GMT+1\r
+----------\r
+[rev. 109]\r
+\r
+<Gameserver>\r
+  Added support for weapons.def\r
+\r
+Hammag; 31.03.2009 02:35 GMT+1\r
+----------\r
+[rev. 110]\r
+\r
+<Gameserver>\r
+  Modified the gamedefs system to allow easier, cleaner and C++ oriented integration of currently missing def files support.\r
+  Access to gamedefs data has changed a (little) bit, so take a look at changes in exiting code.\r
+\r
+Hammag; 04.04.2009 02:35 GMT+1\r
+----------\r
+[rev. 111]\r
+\r
+<Gameserver>\r
+  Added all .h files and declarations for all needed .def files.\r
+  Added all corresponding .cpp file with skeleton. Effective file parsing method still needed to be implemented for each .def. TinNS should complile and run however, with only a bunch of .def loading error at server start (but that's not blocking)\r
+\r
+\r
+Hammag; 11.04.2009 23:40 GMT+1\r
+----------\r
+[rev. 112-113]\r
+\r
+<Gameserver>\r
+  Implemented support for more .def files\r
+  Moved random number generation methods out of PGameServer to global functions in common/misc\r
+  Content of item boxes, trashcans, bags, etc. is now based on .def files. Cabinet content is kept as before, i.e generating fully random items.\r
+  \r
+Hammag; 18.04.2009 19:10 GMT+1\r
+----------\r
+[rev. 114-119]\r
+\r
+<Gameserver>\r
+  Implemented multi-char vhc support:\r
+    - vhc should now be seen the right way (good pos, good direction) by all present chars\r
+    - Access to spawned vhc requires owner autorization [This is still bugging for some part though]\r
+  Fixed various small things\r
+  Tried an implementation of Jumping (in order to have jumps seen by other chars) [Not tested at all]\r
+  \r
+  As these various things require at least 2 simultaneous connexions, and as I can't easily do that atm, it has not been fully tested.\r
+  \r
+  Warning: my server crashed while I was away with 2 chars connected. I didn't search for the reason, so don't let your server running on an Internet accessible host when you're away.\r
+\r
+Hammag; 18.04.2009 20:00 GMT+1\r
+----------\r
+[rev. 120]\r
+\r
+<Gameserver>\r
+  Fixed and added bug in handling deconnection of seating char that was causing the crash mentinned in the previous rev.\r
+\r
+Hammag; 28.04.2009 13:30 GMT+1\r
+----------\r
+[rev. 121-122]\r
+\r
+<Gameserver>\r
+  Fixed many little accessory things, potential bugs and discrepencies\r
+  Cleaned up source code format in some files\r
+  Deactivated as most debug output when dev_debug is not set in conf file (but setting it will generate lots of output !)\r
+  Continued work on vhc. Some small fixes and multichar tests still need to be performed\r
+\r
+Hammag; 01.05.2009 13:10 GMT+1\r
+----------\r
+[rev. 123-124]\r
+\r
+<Gameserver>\r
+  Small fixes on vhc zoning\r
+  Support for all remaining .def added. Good loading of expected data has not been validated yet.\r
+\r
+Hammag; 10.05.2009 02:15 GMT+1\r
+----------\r
+[rev. 125]\r
+\r
+<Gameserver>\r
+  Fixed loading of weapons.def\r
+  Started implementation of multiuser viewing of weapon use and basic manual weapon reload\r
+\r
+Hammag; 10.05.2009 23:55 GMT+1\r
+----------\r
+[rev. 126]\r
+\r
+<Gameserver>\r
+  Improved working and multiuser viewing of weapon reload\r
+  Started implementation of char death and respawn\r
+\r
+Hammag; 12.05.2009 18:00 GMT+1\r
+----------\r
+[rev. 127]\r
+\r
+<Gameserver>\r
+  Added support for weapon addons effects activation (flashlight/zoom(not tested)/silencer/laser)\r
+  Added weather control packet\r
+  Added zone weather control command @weather ?|<weather id> [<target char id>]\r
+  Added command @who as alias of @online\r
+  Added command @whois as alias of @info\r
+\r
+\r
+?????\r
+[rev. 128 to 132]\r
+NO ONE BOTHERED TO PUT A COMMENT IN THE CHANGELOG\r
+so.. taken from SVN log:\r
+...\r
+------------------------------------------------------------------------\r
+r130 | Namikon | 2009-06-20 23:51:31 +0200 (sam 20 jun 2009) | 4 lines\r
+\r
+- Added 2 new commands: setmainskill and setsubskill (The 1st for PSI, INT, STR,.. the 2nd for HCK,BRT, ...)\r
+- Added 2 new decoders for yet-unknown packets\r
+- Prepared future work on the npc subsystem. (They'll soon be able to shoot you :) )\r
+- Fixed subskill system. You can now increase any subskill without getting OOO Packets, as long as there are enough skillpoints left of course\r
+------------------------------------------------------------------------\r
+r132 | Namikon | 2009-06-23 16:36:42 +0200 (mar 23 jun 2009) | 3 lines\r
+\r
+As by request of Akkiko, (hopefully) fixed all files with \n\r. (Also switched by editor to only use \n now.\r
+As by request of Sting (and to revert my mistake i did a few days ago) re-enabled mUnknown and mLoot values in NPC.cpp\r
+Also reformattet the output, the old one was way to long\r
+------------------------------------------------------------------------\r
+\r
+Hammag; 07.07.2009 14:40 GMT+2\r
+----------\r
+[rev. 133]\r
+\r
+<Config>\r
+  Reverted gameserver.conf and infoserver.conf to their previous content which shouldn't be changed to installation-specific values !!!\r
+\r
+<Gameserver>\r
+  Fixed naming of added class "PPvPTrade" to PUdpPvPTrade to try a bit to keep coherent...\r
+  Added packets for held item use, drug use, recration unit use (experimental, not fully functionnal)\r
+  Fixed use of decoded packed initially taken as "hack init/start"\r
+  Fixed 2 compil-fatal SYNTAX ERRORS in npc.cpp ...\r
+  \r
diff --git a/server/LICENSE.txt b/server/LICENSE.txt
new file mode 100644 (file)
index 0000000..d511905
--- /dev/null
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/server/Makefile b/server/Makefile
new file mode 100644 (file)
index 0000000..0808a96
--- /dev/null
@@ -0,0 +1,5 @@
+.DEFAULT_GOAL := all
+
+all .DEFAULT :
+       $(MAKE) -C src $(MAKECMDGOALS)
+
diff --git a/server/WORK_IN_PROGRESS b/server/WORK_IN_PROGRESS
new file mode 100644 (file)
index 0000000..edbccc5
--- /dev/null
@@ -0,0 +1,75 @@
+The purpose of this proposed file is to give a fairly up to date view\r
+on the work in progress, to avoid double work...\r
+\r
+Hammag; 08.07.2006 - updated 21.09.2006\r
+-----\r
+The aim of current modifications are to change a bit of the general architecture of TinNS\r
+[DONE] Source tree, Makefiles, and includes will first be reorganised to permit more modularity and code sharing amongst the 3 servers,\r
+ and easy exclusion of unfinished code.\r
+ Some Makefile targets to facilitate common code individual compilation remains to be done\r
+\r
+The aim of some modifications I'll restart later will be to to finish the full character login,\r
+that is a char that displays as expected ingame (for himself at first),\r
+and has his stats, equipment and changes well kept in DB.\r
+\r
+It involves modification of:\r
+ - [DONE] full char creation with use of profession templates (for money and inventory)\r
+    except for :\r
+      - remaining SP calculation\r
+      - starting XP calculation\r
+ - additions and modifications on some char data definitions\r
+ - char items and containers management\r
+ - [DONE] char data saving in DB including inventory\r
+     But belt, implants & armor, chat conf and other secondary info not implemented yet\r
+ - modifications to char loading from DB\r
+    [DONE] for inventory\r
+    [NOT DONE] for rest of char items and complementary infos (see above)\r
+ - minor modifications to autosave\r
+    [DONE] but more improvements will have to be done when more efficiency needed\r
+ - [DONE]full filling-in of the baseline for char visual aspects, stats and inventory\r
+ - [DONE] make use of worldinfo.def, appplaces.def, appartments.def, respawn.def to manage genreping and\r
+    appartment in/out rather than hardcoded info (e.g. zoning.cpp) and manually built database.\r
+ - [DONE] make use of world .dat files and worldmodels.def to manage item use rather than\r
+    a manually built database.\r
+ - [DONE] dynamic loading/unloading of chars, non mem-resident account info\r
+\r
+Notes\r
+----------------\r
+command @skin to play with skins\r
+    Usage:  @skin #<chardef idx>\r
+                    for use with the index id from characters.def\r
+        or  @skin <model>|-|# [<head>[ <torso>[ <legs>]]]\r
+                    <model> is the model id found after the model name in characters.def\r
+                    # resets to real char skin\r
+                    - means current skin\r
+                    incrementaly optional <head>, <torso> and <legs> are values 0-9\r
+        As a side effect, just doing @skin - will display you current skin infos (and change to the same ...)\r
+\r
+command @effect to play with skins effect\r
+    Usage:  @effect <effect> [<density>]\r
+                with <effect> = 0 to 17 and <density> = 0 (max density) to 255 (min density)\r
+                <density> is meaningfull for some of the effects only\r
+    Note: you won't see the effect on yourself. Only other chars will see it ...\r
+    Effects found:\r
+    0 = no effect\r
+    1 = poison smoke\r
+    2 = electricity\r
+    3 = deflector (instant white flash)\r
+    4 = heal bubbles\r
+    5 = be a light in the darkness !!!\r
+    6 = flames\r
+    7 = stun particles\r
+    8 = group heal\r
+    9 = group deflector (?)\r
+    10= damage boost\r
+    11= group damage boost\r
+    12= shelter (instant yellow flash)\r
+    13= group deflector (?)\r
+    14= stealth\r
+    15= anti poison aura\r
+    16= I don't remember this one: swarming yellow & blue bubbles\r
+    17= true sight\r
+\r
+command @speed to play with speed\r
+    Usage:  @speed <newspeed> | #\r
+                with <speed> = 0 (no move).. 254 , 255 or # meaning "no speed override"\r
diff --git a/server/conf/commands.conf b/server/conf/commands.conf
new file mode 100644 (file)
index 0000000..d13953f
--- /dev/null
@@ -0,0 +1,117 @@
+// TinNS Gameserver IngameCommands config file\r
+// ===========================================\r
+//\r
+// Default Levels are:\r
+//   0 = unregistered user\r
+//   1 = Registered user\r
+//  30 = volunteer\r
+//  50 = GM\r
+// 100 = Admin\r
+//\r
+// But you're free to define *any* level between the given values (0-100).\r
+\r
+// Enables debug output (Send over direct chat)\r
+debug = 100\r
+\r
+// Set ingame time\r
+settime = 100\r
+\r
+// warps you to given location\r
+warp = 0\r
+\r
+// Sends you a list of all connected (online) players\r
+online = 0\r
+\r
+// Debug command to test chatmodes\r
+sendchat = 50\r
+\r
+// Changes your character appearance\r
+skin = 50\r
+\r
+// Changes your body effect (fire, poison, etc)\r
+effect = 0\r
+\r
+// Changes your running speed\r
+speed = 0\r
+\r
+// Changes your skincolor (fake "outfitter")\r
+color = 0\r
+\r
+// Changes your character brightness (fake "outfitter")\r
+brightness = 0\r
+\r
+// Removes either dynamic actors (perm) or worlditems until you rezone (temp)\r
+remove = 50\r
+\r
+// Rehash of various server values (InMem accounts at the moment, later configfiles)\r
+rehash = 100\r
+\r
+// Display server uptime\r
+uptime = 0\r
+\r
+// Display TinNS version\r
+version = 0\r
+\r
+// Send out Serverwide broadcast over ADMIN> channel without revealing your name\r
+broadcast = 100\r
+\r
+// Kicks given player (Either by Nickname or ID)\r
+kick = 50\r
+\r
+// Display details about given player (Either by Nickname or ID)\r
+info = 50\r
+\r
+// Set level of given player to xxx (Either by Nickname or ID)\r
+setlevel = 100\r
+\r
+// Warps you to given player (Either by Nickname or ID)\r
+warpto = 50\r
+\r
+// Warps given player to you (Either by Nickname or ID)\r
+recall = 50\r
+\r
+// Ban given player for given amount of seconds/minutes/hours/days\r
+ban = 50\r
+\r
+// UnBan given player\r
+unban = 50\r
+\r
+// Show a list of all bans\r
+listbans = 50\r
+\r
+// "Shun" given player. Player cant talk untill unshunned\r
+shun = 50\r
+\r
+// Remove talk-lock\r
+unshun = 50\r
+\r
+// Teleport given player to "Jail"zone (Regants legacy)\r
+jail = 50\r
+\r
+// Free the player. (Warp player to TH sec2)\r
+unjail = 50\r
+\r
+// Teleport player to given location\r
+teleport = 50\r
+\r
+// Give yourself (or someone else) cash\r
+givemoney = 50\r
+\r
+// Take away cash from your wallet (or someone else)\r
+takemoney = 50\r
+\r
+// Spawns given actor next to player\r
+spawnactor = 50\r
+\r
+// Set weather in a zone\r
+weather = 50\r
+\r
+// Set mainskill (INT,PSI,DEX,CON,STR) of own char or someone else\r
+setmainskill = 50\r
+\r
+// Set subskill (BRT,HCK,PPU,...) of own char or someone else\r
+setsubskill = 50\r
+\r
+// do actions with NPCs\r
+npc = 50\r
+\r
diff --git a/server/conf/gameserver.conf b/server/conf/gameserver.conf
new file mode 100644 (file)
index 0000000..64d4ca8
--- /dev/null
@@ -0,0 +1,135 @@
+// TinNS Gameserver configuration file\r
+// ==========================================\r
+\r
+// MySQL settings\r
+//================\r
+// Hostname of the MySQL Database (under linux, you may use "localhost")\r
+info_sql_host = 127.0.0.1\r
+// Port (Default is 3306)\r
+info_sql_port = 3306\r
+// Username\r
+info_sql_username = changeme\r
+// Password\r
+info_sql_password = changeme\r
+\r
+// Databasename containing global serverlist and account data\r
+info_sql_database = infoserver\r
+\r
+// Hostname of the MySQL Database (under linux, you may use "localhost")\r
+game_sql_host = 127.0.0.1\r
+// Port (Default is 3306)\r
+game_sql_port = 3306\r
+// Username\r
+game_sql_username = changeme\r
+// Password\r
+game_sql_password = changeme\r
+\r
+// Databasename containing world data for THIS server\r
+// Note: TinNS uses the global SQL database from MaxxJagg;\r
+// Look at the Forum for a copy!\r
+game_sql_database = gameserver\r
+\r
+// MySQL keepalive setting\r
+// set value of the wait_timout system variable from the MySQL server in sec. (same for game & info DB atm).\r
+// or 0 to disable keepalive. 28800 is the usual default value on MySQL servers\r
+mysql_wait_timeout = 28800\r
+\r
+// ISC settings\r
+// ================\r
+// Method of data exchange\r
+// 0: Disable data exchange. For stand-alone gameserver [Debug/internal setting]\r
+// 1: MySQL; Same way as NeoPolis works, updates gameserver status every 'isc_update_intervall' seconds to sqlDB or everytime\r
+//    something is changed (User logon/logoff)\r
+//    Use this if you want to use an php script for server status on webpages\r
+// 2: ISC; Uses ISC (Inter Server Communication) for data exchange. Every Gameserver will connect\r
+//    to the infoserver over network. This is a special method from TinNS. Much more data about the\r
+//    gameserver will be transfered, also you'll be able to control the infoserver from ingame if you are\r
+//    serveradmin (Level 100)\r
+// 3: MySQL & ISC. Uses ISC for data exchange AND updates the infoserver MySQL DB for webbased status scripts\r
+//isc_method = 2\r
+// DO NOT ENABLE ISC IN THIS VERSION (it won't do anything anyway ...)\r
+isc_method = 1\r
+\r
+// Server id. Must match the s_id field in server_list table from infoserver DB\r
+isc_server_id = 1\r
+// Intervall when infoDB is automaticaly updated. Required for isc_method 1 & 3, ignored for isc_method 0 and 2\r
+// This value must be coherent (that is lower by 10) with the one set for 'gameserver_livecheck' in infoserver.conf\r
+isc_update_intervall = 50\r
+// Optimisation to avoid some useless updats of infoDB\r
+isc_delayed_update_intervall = 6\r
+// IP of the infoserver to connect to (Required for isc_method 2 & 3)\r
+isc_infoserverip = 127.0.0.1\r
+// Port defined in infoserver.conf (Required for isc_method 2 & 3)\r
+isc_infoserverport = 9991\r
+// Passwort required to connect to infoserver (Required for isc_method 2 & 3)\r
+isc_connect_pw = changeme\r
+\r
+// Gameserver settings\r
+//=====================\r
+// Name of the GameServer\r
+server_name = Irata\r
+\r
+// IP Adress of the Gameserver when reached without NAT (what you care for on your local network)\r
+server_ip = 127.0.0.1\r
+// Network adress that is to be considered as non-NATed. Put 0 if no NAT is used at all\r
+no_nat_net = 1\r
+// IP Adress of the Gameserver when reached with NAT (e.g. for users connecting from Internet thought your firewall or router when you have multiple computers)\r
+// no effect if no_nat_net is 0\r
+server_nat_ip = 123.123.123.123\r
+\r
+// TCP port the gameserver listens on.\r
+// Default is 12000\r
+gameserver_port = 12000\r
+\r
+// UDP port range used. There should be enough to permit [maxclients] simultaneous connections\r
+gameserver_udpport_min = 5000\r
+gameserver_udpport_max = 5099\r
+\r
+// Patchlevel the Gameserver runs\r
+server_version = 200\r
+\r
+// max number of clients. default 128, min 1, max 2048\r
+maxclients = 100\r
+\r
+// how many slots are reserved for gamemasters. default 10\r
+gm_slots = 10\r
+\r
+// NOTE : 'defs_path' and 'worlds_path' have been removed\r
+// locations of NC data files root directory\r
+// default is . i.e. the gameserver's start directory\r
+// path starting with a / are absolute path, others are relative to the gameserver's start directory\r
+nc_data_path = data/\r
+\r
+\r
+// Period in sec for character auto-save. Default 300. Max 3600, 0 disables auto-save\r
+// Better not set under 60 sec\r
+auto_save_period = 300\r
+\r
+// Starting prosiotn for newly created chars\r
+new_char_location = 1085\r
+\r
+// Announce player-logins in OOC ?\r
+broadcast_new = 1\r
+\r
+// Hide staff (Everyone above normal playerlevel) from this announce?\r
+broadcast_new_hidestaff = 1\r
+\r
+// Maximum cash a player can possess ingame\r
+max_cash = 20000000\r
+\r
+// Item price modifier\r
+// Value is in %. So if you set item_price to 70, an\r
+// item with BasePrice 150 will cost 105\r
+item_price = 70\r
+\r
+// include shared configuration entries\r
+include global.conf\r
+\r
+// PCRE filters\r
+charname_filter = ^[a-z]+([\-\ ]?[a-z]+){0,2}$\r
+clanname_filter = ^[a-z][\w\-\ ]{2,14}$\r
+\r
+// Development settings\r
+//=====================\r
+// Set to non-zero to see development logs outputs\r
+dev_debug = 0\r
diff --git a/server/conf/global.conf b/server/conf/global.conf
new file mode 100644 (file)
index 0000000..99d346d
--- /dev/null
@@ -0,0 +1,17 @@
+// TinNS Global configuration file\r
+// =====================================\r
+\r
+// When set to 1, the player is rejected until his accesslevel is == 1. Use it if you like to create\r
+// your accounts over an WebInterface.\r
+// Default is 0\r
+require_validation = 0\r
+\r
+// Min level in order to login\r
+// Note: This is checked BEFORE require_validation, so if you set this to 1, users will get a strange\r
+// errormessage.\r
+// Default is 0\r
+minlevel = 0\r
+\r
+// PCRE filters\r
+username_filter = ^[a-z][\w\-]{2,14}$\r
+password_filter = ^[[:graph:]]{3,15}$\r
diff --git a/server/conf/infoserver.conf b/server/conf/infoserver.conf
new file mode 100644 (file)
index 0000000..d23cb86
--- /dev/null
@@ -0,0 +1,75 @@
+// TinNS Infoserver configuration file\r
+// =====================================\r
+\r
+// MySQL settings\r
+//================\r
+// Hostname of the MySQL Database (under linux, you may use "localhost")\r
+sql_host = 127.0.0.1\r
+\r
+// Port (Default is 3306)\r
+sql_port = 3306\r
+\r
+// Username...\r
+sql_username = changeme\r
+\r
+// Password...\r
+sql_password = changeme\r
+\r
+// Databasename of the INFOSERVER DB, NOT the gameserver one!!\r
+// Make sure in this db are 2 fields, server_status and accounts\r
+// Note: TinNS uses the global SQL database from MaxxJagg;\r
+// Look at the Forum for a copy!\r
+global_sql_database = infoserver\r
+\r
+// MySQL keepalive setting\r
+// set value of the wait_timout system variable from the MySQL server in sec. (same for game & info DB atm).\r
+// or 0 to disable keepalive. 28800 is the usual default value on MySQL servers\r
+mysql_wait_timeout = 28800\r
+\r
+// ISC settings\r
+// ================\r
+// Method of data exchange\r
+// 0: Disable data exchange. For stand-alone infoserver [Debug/internal setting]\r
+// 1: MySQL; Load Gameserverdata from MySQL Database\r
+// 2: ISC; Accept new connections from Gameservers\r
+// 3: Both; Accept new connections from Gameservers AND load data from MySQL.\r
+//     (< DEVNOTE > We need to make sure that, if 3 is selected, the infoserver ignores double servernames or IP's. -Namikon)\r
+//isc_method = 2\r
+// DO NOT ENABLE ISC IN THIS VERSION (it won't do anything anyway ...)\r
+isc_method = 1\r
+\r
+// ISC Port where the infoserver will accept incomming Gameserver connections. (Required for isc_method 2 & 3)\r
+isc_infoserverport = 9991\r
+// ISC Passwort required to connect to this infoserver (Required for isc_method 2 & 3)\r
+isc_connect_pw = changeme\r
+\r
+// Infoserver settings\r
+//================\r
+// set this to 1 if you'd like to enable automatic account creation\r
+// Default is 0\r
+auto_accounts = 0\r
+\r
+// When set to 1, the player is rejected until his accesslevel is == 1. Use it if you like to create\r
+// your accounts over an WebInterface.\r
+// Ignored when auto_accounts is enabled.\r
+// IMPORTANT: UNTIL WE HAVE A GLOBAL CONFIG FILE WORKING, PLEASE NOTE THAT YOU HAVE TO SET THE SAME VALUE IN\r
+// GAMESERVER.CONF TOO!!\r
+// Default is 0\r
+require_validation = 0\r
+\r
+// port the infoserver will listen for incomming connections\r
+// Default is 7000, and unless you haven't modified your client.exe\r
+// you should'nt change this!\r
+infoserver_port = 7000\r
+\r
+// Gameserver livecheck\r
+// How many seconds of inactivity may pass before the serverentry in server_list\r
+// is considered as "Offline" ?\r
+// Default is 60 seconds.\r
+// Note 1: Set your gameserver intervall at least 10 lower than this value\r
+// Note 2: This is NOT the interval where the server reads the Gameserver data,\r
+// its the maximum difference between two 's_lastupdate' values!\r
+gameserver_livecheck = 60\r
+\r
+// include shared configuration entries\r
+include global.conf\r
diff --git a/server/conf/patchserver.conf b/server/conf/patchserver.conf
new file mode 100644 (file)
index 0000000..6418469
--- /dev/null
@@ -0,0 +1,31 @@
+// TinNS Patchserver configuration file\r
+// =====================================\r
+\r
+// Version (Patchlevel) the Server is running\r
+server_version = 200\r
+\r
+// port the patchserver listens on.\r
+// Default is 8040\r
+patchserver_port = 8040\r
+\r
+// where the patch files are stored\r
+// Default is <binary path>/patches (./patches)\r
+patches_path = ./patches\r
+\r
+// which path to use for file requests\r
+// Default is <binary path>/files (./files)\r
+file_path = ./files\r
+\r
+// how many simultaneous file transfers are allowed\r
+// Default is 5\r
+max_file_xfers = 5\r
+\r
+// how much data to send per patchserver packet in bytes. min 64, max 4082\r
+// Default is 512\r
+patch_packet_size = 512\r
+\r
+// max number of clients. default 128, min 1, max 2048\r
+maxclients = 32\r
+\r
+// how many slots are reserved for gamemasters. default 10\r
+gm_slots = 2\r
diff --git a/server/data/scripts/lua/zippy.lua b/server/data/scripts/lua/zippy.lua
new file mode 100644 (file)
index 0000000..0abf19e
--- /dev/null
@@ -0,0 +1,18 @@
+function DIALOG()\r
+\r
+NODE(0)\r
+ SAY("Hi. Please choose, time is money!")\r
+ ANSWER("Give me 100000 NC!",2)\r
+ ANSWER("Take 100000 NC!",3)\r
+\r
+NODE(2)\r
+ GIVEMONEY(100000)\r
+ SAY("Here you go, have fun")\r
+ ENDDIALOG()\r
+\r
+NODE(3)\r
+ TAKEMONEY(100000)\r
+ SAY("Cool, thanks :)")\r
+ ENDDIALOG()\r
+\r
+end
\ No newline at end of file
diff --git a/server/database/DB_v8/DB_v8_patch001.sql b/server/database/DB_v8/DB_v8_patch001.sql
new file mode 100644 (file)
index 0000000..119ce72
--- /dev/null
@@ -0,0 +1,3 @@
+use gameserver;\r
+\r
+alter table `emails` change `e_body` `e_body` varchar(2048) character set latin1 collate latin1_swedish_ci NOT NULL;
\ No newline at end of file
diff --git a/server/database/DB_v8/TinNS_GameDB_rev8_BaseData.sql b/server/database/DB_v8/TinNS_GameDB_rev8_BaseData.sql
new file mode 100644 (file)
index 0000000..1edc36e
--- /dev/null
@@ -0,0 +1,17 @@
+USE `gameserver`;\r
+\r
+/*Data for the table `forums` */\r
+\r
+insert  into `forums`(`f_id`,`f_name`,`f_area`,`f_showname`) values (1,'bbsnctradeweap',1,'nc.trading.weapons/armor'),(2,'bbsnctraderare',1,'nc.trading.rareparts'),(3,'bbsnctradeimp',1,'nc.trading.implants/boneenforcements'),(4,'bbsnctradepsi',1,'nc.trading.psi equipment'),(5,'bbsnctradeblue',1,'nc.trading.blueprints'),(6,'bbsnctradeitem',1,'nc.trading.itemparts/raw materials'),(7,'bbsnctradedrug',1,'nc.trading.drugs'),(8,'bbsneocronmarket',1,'nc.trading.miscellaneous'),(9,'bbsncrunnerano',2,'nc.runner.anouncements'),(10,'bbsncrunnerserv',2,'nc.runner.services'),(11,'bbsncrunnereven',2,'nc.runner.events'),(12,'bbsncrunnerauct',2,'nc.runner.auctions'),(13,'bbsncrunnerclan',2,'nc.runner.clan recruitment'),(14,'bbsncrunnerfind',2,'nc.runner.find team'),(15,'bbsncrunnerhelp',2,'nc.runner.runner2runnerhelp'),(16,'bbsneocrongeneral',3,'nc.talk.general'),(17,'bbsnctalkpolitics',3,'nc.talk.political discussions'),(18,'bbfgeneral',11,'private.faction.general'),(19,'bbcgeneral',12,'private.clan.general');\r
+\r
+/*Data for the table `npc_spawns` */\r
+\r
+insert  into `npc_spawns`(`npc_id`,`npc_worldid`,`npc_nameid`,`npc_typeid`,`npc_name`,`npc_location`,`npc_x`,`npc_y`,`npc_z`,`npc_angle`,`npc_clothing`,`npc_loot`,`npc_unknown`,`npc_trader`,`npc_customname`,`npc_customscript`,`npc_shop_quality`,`npc_scripting`) values (9942,1020,385,61093,'WSK',1,33808,31332,32512,30,6612,0,8814,0,'Zippy the Trader','scripts/lua/zippy.lua',50,1),(9943,1020,388,17634,'WSK',3,30063,34111,33136,90,6616,0,14035,0,'Event Info',NULL,50,1),(9944,1018,387,32772,'WSK',101,31938,32165,32512,130,6616,0,16675,0,'Event Info',NULL,50,1),(9945,1019,215,50585,'WSK',101,34209,33864,32512,359,197,0,19499,195,NULL,NULL,50,1),(9946,1020,385,13542,'WSK',101,33261,33113,32672,2,4342,0,17892,0,'VotR Paperboy',NULL,50,1),(9947,1019,389,10890,'WSK',401,31105,32463,31936,92,6613,0,14572,0,'Event Info',NULL,50,1),(9948,1020,1629,26858,'WSK',401,31265,30718,31952,177,2827,0,12567,0,NULL,NULL,50,1),(9949,256,151,31996,'WSK',2046,32168,36946,33946,30,9888,0,738,1,NULL,NULL,50,1),(9950,261,143,58099,'WSK',2046,34016,36182,33970,30,22655,0,2306,200,NULL,NULL,50,1),(9951,963,216,356,'WSK',2046,32703,34945,33818,25,4191,0,3154,196,NULL,NULL,50,1),(9952,976,2818,15528,'WSK',2071,23436,21380,35220,185,7214,0,9785,0,NULL,NULL,50,1),(9953,971,386,5040,'WSK',2181,38000,24127,33854,264,6622,0,2590,0,NULL,NULL,50,1),(9954,1020,836,43282,'MBOTFLY',2181,43068,26020,34020,0,31788,0,405,0,NULL,NULL,50,1),(9955,988,836,41913,'MBOTFLY',2181,41537,28260,33860,0,50146,0,380,0,NULL,NULL,50,1),(9956,1006,800,15709,'MBOT',2181,42047,28256,33786,0,14348,0,220,0,NULL,NULL,50,1),(9957,1005,800,28598,'MBOT',2181,44419,23412,33445,0,8332,0,585,0,NULL,NULL,50,1),(9958,1014,672,28153,'DOGBOT',2181,38041,29414,34088,0,21948,0,221,0,NULL,NULL,50,1),(9959,984,677,32746,'WBADGUY',2181,37985,31043,33939,0,21616,0,222,0,NULL,NULL,50,1),(9960,973,606,26878,'MUTANTB',2181,26220,27158,34106,0,20679,0,490,0,NULL,NULL,50,1),(9961,975,800,11783,'MBOT',2181,31285,23969,33970,0,722,0,38,0,NULL,NULL,50,1),(9962,981,640,61001,'FLYMUT',2181,26672,26657,34281,0,20684,0,1510,0,NULL,NULL,50,1),(9963,985,610,1100,'MGMUT',2181,28040,26301,34083,0,21559,0,628,0,NULL,NULL,50,1),(9964,986,640,1159,'FLYMUT',2181,27424,27264,34328,0,21560,0,1503,0,NULL,NULL,50,1),(9965,987,626,53397,'MUTANTB',2181,26386,27672,34135,0,20680,0,407,0,NULL,NULL,50,1),(9966,999,602,19865,'MUTANTB',2181,26771,26119,34228,0,21559,0,271,0,NULL,NULL,50,1),(9967,1003,730,39449,'BROBOT',2181,25425,32173,34055,0,20939,0,4285,0,NULL,NULL,50,1);\r
+\r
+/*Data for the table `outposts` */\r
+\r
+insert  into `outposts`(`o_id`,`o_outnum`,`o_security`,`o_clan`,`o_gr`) values (1,2006,0,0,0),(2,2028,0,0,0),(3,2031,0,0,0),(4,2047,0,0,0),(5,2049,0,0,0),(6,2052,9,3,0),(7,2066,0,0,0),(8,2067,0,0,0),(9,2069,0,0,0),(10,2071,0,0,0),(11,2073,0,0,0),(12,2090,0,0,0),(13,2105,0,0,0),(14,2111,0,0,0),(15,2112,0,0,0),(16,2128,0,0,0),(17,2132,0,0,0),(18,2143,0,0,0),(19,2147,0,0,0),(20,2149,0,0,0),(21,2151,0,0,0),(22,2153,0,0,0),(23,2155,0,0,0),(24,2156,0,0,0),(25,2164,0,0,0),(26,2165,0,0,0),(27,2167,0,0,0),(28,2168,0,0,0),(29,2171,0,0,0),(30,2175,0,0,0),(31,2189,0,0,0),(32,2194,0,0,0),(33,2204,0,0,0),(34,2205,0,0,0),(35,2207,0,0,0),(36,2212,0,0,0);\r
+\r
+/*Data for the table `stockx` */\r
+\r
+insert  into `stockx`(`st_id`,`st_factid`,`st_curval`,`st_oldval`) values (1,9,1227,1227),(2,2,2499,2400),(3,6,1269,1269),(4,10,1387,1387),(5,8,676,676),(6,14,783,783),(7,15,591,591),(8,3,1779,1779),(9,5,879,879),(10,11,1581,2000),(11,4,1544,1544);\r
diff --git a/server/database/DB_v8/changes.txt b/server/database/DB_v8/changes.txt
new file mode 100644 (file)
index 0000000..beeaf17
--- /dev/null
@@ -0,0 +1,75 @@
+CHANGELOG FOR GameDB 8 and InfoDB 8\r
+-----------------------------------\r
+\r
+v7 > v8:\r
+INFOSERVER:\r
+- No changes so far\r
+\r
+GAMESERVER:\r
+Renamed table 'bug report' to 'bug_report'\r
+- Changed br_desc from VARCHAR(256) to VARCHAR(1024) as this is the size found in .tsc files\r
+\r
+Changed table "characters":\r
+- Added col c_online\r
+- Added col c_clan\r
+- Added col c_soullight\r
+\r
+Added table "clanlevels"\r
+\r
+Changed table "clans":\r
+- Renamed c_faction to cl_faction, also changed type from INT(10) to INT(2)\r
+- Renamed c_id to cl_id\r
+- Renamed c_longname to cl_name, also changed type from VARCHAR(45) to CHAR(16) as this is the size found in .tsc files\r
+- Renamed c_shortname to cl_shortdesc, also changed type from VARCHAR(45) to CHAR(64) as this is the size found in .tsc files\r
+- Added col cl_appid\r
+- Added col cl_description\r
+- Added col cl_leader\r
+- Added col cl_minsympathy\r
+- Added col cl_money\r
+- Added col cl_representative\r
+\r
+Added table "clanwars"\r
+\r
+Added table "datacubes"\r
+\r
+Changed table "forum_posts"\r
+- Added col fp_factionid\r
+- Added col fp_clanid\r
+- Changed col fp_content from VARCHAR(1024) to VARCHAR(2048) as this is the size found in .tsc files\r
+\r
+Changed table "guides"\r
+- Changed col g_content from VARCHAR(512) to TEXT, as the size in .tsc files is set to 32768\r
+- Added col g_language\r
+- Added col g_chapter\r
+- Added col g_part\r
+\r
+Added table "moneytransactions"\r
+\r
+Changed table "neochronicle"\r
+- Changed col nc_content from VARCHAR(512) to TEXT, as the size in .tsc files is set to 32768\r
+- Added col nc_lang\r
+- Added col nc_approved\r
+- Added col nc_author\r
+- Added col nc_icon\r
+\r
+Changed table "neocron articles"\r
+- Changed col na_content from VARCHAR(512) to TEXT, as the size in .tsc files is set to 32768\r
+\r
+Added table "npc_shop"\r
+\r
+Changed table "npc_spawns"\r
+- Added col npc_unknown\r
+- Added col npc_trader\r
+- Added col npc_customname\r
+- Added col npc_customscript\r
+- Added col npc_shop_quality\r
+- Added col npc_scripting\r
+\r
+Added table "stockx_depots"\r
+\r
+Added table "support"\r
+\r
+Changed table "vehicles"\r
+- Added col v_world\r
+\r
+Added table "worlds"
\ No newline at end of file
diff --git a/server/database/DB_v8/patch_gamedb_rev7_to_rev8.sql b/server/database/DB_v8/patch_gamedb_rev7_to_rev8.sql
new file mode 100644 (file)
index 0000000..7968922
--- /dev/null
@@ -0,0 +1,164 @@
+/* Create table in target */\r
+DROP TABLE `bug report`;\r
+\r
+CREATE TABLE `bug_report`(\r
+       `br_id` int(10) unsigned NOT NULL  auto_increment , \r
+       `br_type` int(10) unsigned NOT NULL  DEFAULT '0' COMMENT 'Type' , \r
+       `br_desc` varchar(1024) COLLATE latin1_swedish_ci NOT NULL  COMMENT 'Description' , \r
+       `br_fromid` int(10) unsigned NOT NULL  DEFAULT '0' COMMENT 'Char ID of reporter' , \r
+       `br_location` int(10) unsigned NOT NULL  DEFAULT '0' COMMENT 'Location where problem occured' , \r
+       `br_status` int(10) unsigned NOT NULL  DEFAULT '0' COMMENT 'Status' , \r
+       `br_datetime` varchar(45) COLLATE latin1_swedish_ci NOT NULL  COMMENT 'Date/Time' , \r
+       `br_supid` int(10) unsigned NOT NULL  DEFAULT '0' COMMENT 'Supporter ID' , \r
+       PRIMARY KEY (`br_id`) \r
+) ENGINE=InnoDB DEFAULT CHARSET='latin1';\r
+\r
+\r
+/* Alter table in target */\r
+ALTER TABLE `characters` \r
+       ADD COLUMN `c_online` int(1)   NULL DEFAULT '0' after `c_slot`, \r
+       ADD COLUMN `c_clan` int(10)   NULL DEFAULT '0' after `c_online`, \r
+       ADD COLUMN `c_soullight` int(3)   NULL DEFAULT '10' after `c_clan`, COMMENT='';\r
+\r
+/* Create table in target */\r
+CREATE TABLE `clanlevels`(\r
+       `cll_id` int(10) NOT NULL  auto_increment , \r
+       `cll_clanid` int(10) NULL  DEFAULT '0' , \r
+       `cll_level` int(2) NULL  DEFAULT '0' , \r
+       `cll_desc` char(255) COLLATE latin1_general_ci NULL  , \r
+       `cll_charid` int(10) NULL  , \r
+       PRIMARY KEY (`cll_id`) \r
+) ENGINE=MyISAM DEFAULT CHARSET='latin1';\r
+\r
+\r
+/* Alter table in target */\r
+ALTER TABLE `clans` \r
+       ADD COLUMN `cl_id` int(10) unsigned   NOT NULL auto_increment first, \r
+       ADD COLUMN `cl_shortdesc` char(16)  COLLATE latin1_general_ci NULL after `cl_id`, \r
+       ADD COLUMN `cl_name` char(64)  COLLATE latin1_general_ci NULL after `cl_shortdesc`, \r
+       ADD COLUMN `cl_faction` int(2)   NULL after `cl_name`, \r
+       ADD COLUMN `cl_description` varchar(256)  COLLATE latin1_general_ci NULL after `cl_faction`, \r
+       ADD COLUMN `cl_leader` int(10)   NULL DEFAULT '0' after `cl_description`, \r
+       ADD COLUMN `cl_money` int(10)   NULL DEFAULT '0' after `cl_leader`, \r
+       ADD COLUMN `cl_minsympathy` int(3)   NULL DEFAULT '70' after `cl_money`, \r
+       ADD COLUMN `cl_appid` int(10)   NULL DEFAULT '0' after `cl_minsympathy`, \r
+       ADD COLUMN `cl_representative` int(10)   NULL DEFAULT '0' after `cl_appid`, \r
+       DROP COLUMN `c_id`, \r
+       DROP COLUMN `c_shortname`, \r
+       DROP COLUMN `c_longname`, \r
+       DROP COLUMN `c_faction`, \r
+       DROP KEY `PRIMARY`, add PRIMARY KEY(`cl_id`), ENGINE=MyISAM, COMMENT='';\r
+\r
+/* Create table in target */\r
+CREATE TABLE `clanwars`(\r
+       `cw_id` int(10) NOT NULL  auto_increment , \r
+       `cw_initclan` int(10) NULL  DEFAULT '0' , \r
+       `cw_enemyclan` int(10) NULL  DEFAULT '0' , \r
+       `cw_starttime` varchar(45) COLLATE latin1_general_ci NULL  , \r
+       `cw_status` int(2) NULL  DEFAULT '0' , \r
+       `cw_statement_initiator` varchar(512) COLLATE latin1_general_ci NULL  , \r
+       `cw_statement_enemy` varchar(512) COLLATE latin1_general_ci NULL  , \r
+       PRIMARY KEY (`cw_id`) \r
+) ENGINE=MyISAM DEFAULT CHARSET='latin1';\r
+\r
+\r
+/* Create table in target */\r
+CREATE TABLE `datacubes`(\r
+       `cb_id` int(10) NOT NULL  auto_increment , \r
+       `cb_securitycode` char(30) COLLATE latin1_general_ci NULL  , \r
+       `cb_inscription` tinytext COLLATE latin1_general_ci NULL  , \r
+       PRIMARY KEY (`cb_id`) \r
+) ENGINE=MyISAM DEFAULT CHARSET='latin1';\r
+\r
+\r
+/* Alter table in target */\r
+ALTER TABLE `forum_posts` \r
+       CHANGE `fp_content` `fp_content` varchar(2048)  COLLATE latin1_swedish_ci NOT NULL after `fp_fromid`, \r
+       ADD COLUMN `fp_factionid` int(2)   NULL DEFAULT '0' after `fp_forumid`, \r
+       ADD COLUMN `fp_clanid` int(10)   NULL DEFAULT '0' after `fp_factionid`, COMMENT='';\r
+\r
+/* Alter table in target */\r
+ALTER TABLE `guides` \r
+       ADD COLUMN `g_language` int(2)   NULL after `g_title`, \r
+       CHANGE `g_content` `g_content` text  COLLATE latin1_swedish_ci NOT NULL after `g_language`, \r
+       ADD COLUMN `g_chapter` int(1)   NULL DEFAULT '0' after `g_content`, \r
+       ADD COLUMN `g_part` int(1)   NULL DEFAULT '0' after `g_chapter`, COMMENT='';\r
+\r
+/* Create table in target */\r
+CREATE TABLE `moneytransactions`(\r
+       `mt_id` int(10) NOT NULL  auto_increment , \r
+       `mt_clanid` int(10) NULL  DEFAULT '0' , \r
+       `mt_amount` int(10) NULL  DEFAULT '0' , \r
+       `mt_player` int(10) NULL  DEFAULT '0' , \r
+       `mt_date` char(45) COLLATE latin1_general_ci NULL  DEFAULT '2750-01-01 00:00:00' , \r
+       `mt_comment` char(255) COLLATE latin1_general_ci NULL  DEFAULT '0' , \r
+       PRIMARY KEY (`mt_id`) \r
+) ENGINE=MyISAM DEFAULT CHARSET='latin1';\r
+\r
+\r
+/* Alter table in target */\r
+ALTER TABLE `neochronicle` \r
+       CHANGE `nc_content` `nc_content` text  COLLATE latin1_swedish_ci NOT NULL after `nc_name`, \r
+       ADD COLUMN `nc_lang` int(2)   NULL after `nc_datetime`, \r
+       ADD COLUMN `nc_approved` int(1)   NULL DEFAULT '0' after `nc_lang`, \r
+       ADD COLUMN `nc_author` char(45)  COLLATE latin1_swedish_ci NULL after `nc_approved`, \r
+       ADD COLUMN `nc_icon` int(10)   NULL DEFAULT '0' after `nc_author`, COMMENT='';\r
+\r
+/* Alter table in target */\r
+ALTER TABLE `neocron articles` \r
+       CHANGE `na_content` `na_content` text  COLLATE latin1_swedish_ci NOT NULL after `na_name`, COMMENT='';\r
+\r
+/* Create table in target */\r
+CREATE TABLE `npc_shop`(\r
+       `c_npc_id` int(11) NULL  COMMENT 'The NPC WorldID' , \r
+       `c_zoneid` int(11) NULL  COMMENT 'The ZoneID in which the NPC is' , \r
+       `c_itemid` int(11) NULL  COMMENT 'ItemID for sale' , \r
+       `c_itemprice` int(11) NULL  COMMENT 'Price for this item' \r
+) ENGINE=MyISAM DEFAULT CHARSET='latin1';\r
+\r
+\r
+/* Alter table in target */\r
+ALTER TABLE `npc_spawns` \r
+       ADD COLUMN `npc_unknown` int(10) unsigned   NOT NULL DEFAULT '0' after `npc_loot`, \r
+       ADD COLUMN `npc_trader` int(10) unsigned   NOT NULL DEFAULT '0' after `npc_unknown`, \r
+       ADD COLUMN `npc_customname` varchar(80)  COLLATE latin1_swedish_ci NULL after `npc_trader`, \r
+       ADD COLUMN `npc_customscript` varchar(100)  COLLATE latin1_swedish_ci NULL after `npc_customname`, \r
+       ADD COLUMN `npc_shop_quality` int(3)   NULL DEFAULT '50' COMMENT 'The quality of items if this npc has items to sell' after `npc_customscript`, \r
+       ADD COLUMN `npc_scripting` int(1)   NULL DEFAULT '1' COMMENT '1: Scripts enabled 0: Scripts disabled' after `npc_shop_quality`, COMMENT='';\r
+\r
+/* Create table in target */\r
+CREATE TABLE `stockx_depots`(\r
+       `sxd_id` int(10) NOT NULL  auto_increment , \r
+       `sxd_playerid` int(10) NULL  DEFAULT '0' , \r
+       `sxd_st_id` int(10) NULL  DEFAULT '0' , \r
+       `sxd_amount` int(10) NULL  DEFAULT '0' , \r
+       `sxd_paid` int(10) NULL  DEFAULT '0' , \r
+       PRIMARY KEY (`sxd_id`) \r
+) ENGINE=MyISAM DEFAULT CHARSET='latin1';\r
+\r
+\r
+/* Create table in target */\r
+CREATE TABLE `support`(\r
+       `su_id` int(10) NOT NULL  auto_increment , \r
+       `su_player` int(10) NULL  DEFAULT '0' , \r
+       `su_datetime` varchar(45) COLLATE latin1_general_ci NULL  , \r
+       `su_supporterid` int(10) NULL  DEFAULT '0' , \r
+       `su_desc` char(255) COLLATE latin1_general_ci NULL  , \r
+       `su_type` int(1) NULL  DEFAULT '0' , \r
+       `su_worldid` int(10) NULL  DEFAULT '0' , \r
+       `su_inwork` int(1) NULL  DEFAULT '0' , \r
+       `su_finished` int(1) NULL  DEFAULT '0' , \r
+       PRIMARY KEY (`su_id`) \r
+) ENGINE=MyISAM DEFAULT CHARSET='latin1';\r
+\r
+\r
+/* Alter table in target */\r
+ALTER TABLE `vehicles` \r
+       ADD COLUMN `v_world` int(10)   NULL DEFAULT '0' after `v_status`, COMMENT='';\r
+\r
+/* Create table in target */\r
+CREATE TABLE `worlds`(\r
+       `wr_id` int(10) NOT NULL  DEFAULT '0' , \r
+       `wr_group` int(10) NULL  DEFAULT '0' , \r
+       PRIMARY KEY (`wr_id`) \r
+) ENGINE=MyISAM DEFAULT CHARSET='latin1';\r
diff --git a/server/database/DB_v8/readme.txt b/server/database/DB_v8/readme.txt
new file mode 100644 (file)
index 0000000..3dc7e0c
--- /dev/null
@@ -0,0 +1,13 @@
+This directory contains an UPDATE and a FULL DUMP\r
+for both InfoDB and GameDB.\r
+If you want to keep your data and just upgrade the structure,\r
+use\r
+       patch_gamedb_rev7_to_rev8.sql\r
+\r
+to get up to date. However, it is recommended to use the FULL files\r
+to build a new database.\r
+\r
+Note: For TinNS, you'll have to apply "TinNS_GameDB_rev8_BaseData.sql"\r
+after creating the base-tables!\r
+\r
+See changes.txt for information about what has changed from DB7 to DB8
\ No newline at end of file
diff --git a/server/database/DB_v8/unified_game DB_rev8.sql b/server/database/DB_v8/unified_game DB_rev8.sql
new file mode 100644 (file)
index 0000000..1a49c8e
--- /dev/null
@@ -0,0 +1,484 @@
+/*!40101 SET NAMES utf8 */;\r
+\r
+/*!40101 SET SQL_MODE=''*/;\r
+\r
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\r
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\r
+\r
+CREATE DATABASE /*!32312 IF NOT EXISTS*/`gameserver` /*!40100 DEFAULT CHARACTER SET latin1 COLLATE latin1_general_ci */;\r
+\r
+USE `gameserver`;\r
+\r
+/*Table structure for table `apartments` */\r
+\r
+DROP TABLE IF EXISTS `apartments`;\r
+\r
+CREATE TABLE `apartments` (\r
+  `apt_id` int(10) unsigned NOT NULL auto_increment,\r
+  `apt_location` int(10) unsigned NOT NULL default '0',\r
+  `apt_type` int(10) unsigned NOT NULL default '0',\r
+  `apt_password` varchar(45) NOT NULL default '',\r
+  `apt_owner` int(10) unsigned NOT NULL default '0',\r
+  PRIMARY KEY  (`apt_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `buddy_list` */\r
+\r
+DROP TABLE IF EXISTS `buddy_list`;\r
+\r
+CREATE TABLE `buddy_list` (\r
+  `bud_id` int(10) NOT NULL auto_increment,\r
+  `bud_charid` int(10) NOT NULL default '0',\r
+  `bud_buddyid` mediumint(10) NOT NULL default '0',\r
+  PRIMARY KEY  (`bud_id`)\r
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `bug_report` */\r
+\r
+DROP TABLE IF EXISTS `bug_report`;\r
+\r
+CREATE TABLE `bug_report` (\r
+  `br_id` int(10) unsigned NOT NULL auto_increment,\r
+  `br_type` int(10) unsigned NOT NULL default '0' COMMENT 'Type',\r
+  `br_desc` varchar(1024) NOT NULL COMMENT 'Description',\r
+  `br_fromid` int(10) unsigned NOT NULL default '0' COMMENT 'Char ID of reporter',\r
+  `br_location` int(10) unsigned NOT NULL default '0' COMMENT 'Location where problem occured',\r
+  `br_status` int(10) unsigned NOT NULL default '0' COMMENT 'Status',\r
+  `br_datetime` varchar(45) NOT NULL COMMENT 'Date/Time',\r
+  `br_supid` int(10) unsigned NOT NULL default '0' COMMENT 'Supporter ID',\r
+  PRIMARY KEY  (`br_id`)\r
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `characters` */\r
+\r
+DROP TABLE IF EXISTS `characters`;\r
+\r
+CREATE TABLE `characters` (\r
+  `c_id` int(10) unsigned NOT NULL auto_increment,\r
+  `c_name` varchar(45) default '',\r
+  `c_str_lvl` int(10) unsigned default '0',\r
+  `c_str_pts` int(10) unsigned default '0',\r
+  `c_int_lvl` int(10) unsigned default '0',\r
+  `c_int_pts` int(10) unsigned default '0',\r
+  `c_dex_lvl` int(10) unsigned default '0',\r
+  `c_dex_pts` int(10) unsigned default '0',\r
+  `c_con_lvl` int(10) unsigned default '0',\r
+  `c_con_pts` int(10) unsigned default '0',\r
+  `c_psi_lvl` int(10) unsigned default '0',\r
+  `c_psi_pts` int(10) unsigned default '0',\r
+  `a_id` int(10) unsigned default '0',\r
+  `c_class` int(10) unsigned default '0',\r
+  `c_profession` int(10) unsigned default '0',\r
+  `c_sex` int(10) unsigned default '0',\r
+  `c_location` int(10) unsigned default '1',\r
+  `c_mc` int(10) unsigned default '0',\r
+  `c_hc` int(10) unsigned default '0',\r
+  `c_tra` int(10) unsigned default '0',\r
+  `c_pc` int(10) unsigned default '0',\r
+  `c_rc` int(10) unsigned default '0',\r
+  `c_tc` int(10) unsigned default '0',\r
+  `c_vhc` int(10) unsigned default '0',\r
+  `c_agl` int(10) unsigned default '0',\r
+  `c_rep` int(10) unsigned default '0',\r
+  `c_rec` int(10) unsigned default '0',\r
+  `c_rcl` int(10) unsigned default '0',\r
+  `c_atl` int(10) unsigned default '0',\r
+  `c_end` int(10) unsigned default '0',\r
+  `c_for` int(10) unsigned default '0',\r
+  `c_fir` int(10) unsigned default '0',\r
+  `c_enr` int(10) unsigned default '0',\r
+  `c_xrr` int(10) unsigned default '0',\r
+  `c_por` int(10) unsigned default '0',\r
+  `c_htl` int(10) unsigned default '0',\r
+  `c_hck` int(10) unsigned default '0',\r
+  `c_brt` int(10) unsigned default '0',\r
+  `c_psu` int(10) unsigned default '0',\r
+  `c_wep` int(10) unsigned default '0',\r
+  `c_cst` int(10) unsigned default '0',\r
+  `c_res` int(10) unsigned default '0',\r
+  `c_imp` int(10) unsigned default '0',\r
+  `c_ppu` int(10) unsigned default '0',\r
+  `c_apu` int(10) unsigned default '0',\r
+  `c_mst` int(10) unsigned default '0',\r
+  `c_ppw` int(10) unsigned default '0',\r
+  `c_psr` int(10) unsigned default '0',\r
+  `c_wpw` int(10) unsigned default '0',\r
+  `c_apt` int(10) unsigned default '0',\r
+  `c_cash` int(10) unsigned default '0',\r
+  `c_head` int(10) unsigned default '0',\r
+  `c_torso` int(10) unsigned default '0',\r
+  `c_legs` int(10) unsigned default '0',\r
+  `c_str_xp` float default '0',\r
+  `c_int_xp` float default '0',\r
+  `c_dex_xp` float default '0',\r
+  `c_psi_xp` float default '0',\r
+  `c_con_xp` float default '0',\r
+  `c_pos_x` float NOT NULL default '0',\r
+  `c_pos_y` float NOT NULL default '0',\r
+  `c_pos_z` float NOT NULL default '0',\r
+  `c_angle_ud` float NOT NULL default '0',\r
+  `c_angle_lr` float NOT NULL default '0',\r
+  `c_faction` int(10) unsigned NOT NULL default '0',\r
+  `c_slot` smallint(5) unsigned NOT NULL default '0',\r
+  `c_online` int(1) default '0',\r
+  `c_clan` int(10) default '0',\r
+  `c_soullight` int(3) default '10',\r
+  PRIMARY KEY  (`c_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `clanlevels` */\r
+\r
+DROP TABLE IF EXISTS `clanlevels`;\r
+\r
+CREATE TABLE `clanlevels` (\r
+  `cll_id` int(10) NOT NULL auto_increment,\r
+  `cll_clanid` int(10) default '0',\r
+  `cll_level` int(2) default '0',\r
+  `cll_desc` char(255) collate latin1_general_ci default NULL,\r
+  `cll_charid` int(10) default NULL,\r
+  PRIMARY KEY  (`cll_id`)\r
+) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;\r
+\r
+/*Table structure for table `clans` */\r
+\r
+DROP TABLE IF EXISTS `clans`;\r
+\r
+CREATE TABLE `clans` (\r
+  `cl_id` int(10) unsigned NOT NULL auto_increment,\r
+  `cl_shortdesc` char(16) collate latin1_general_ci default NULL,\r
+  `cl_name` char(64) collate latin1_general_ci default NULL,\r
+  `cl_faction` int(2) default NULL,\r
+  `cl_description` varchar(256) collate latin1_general_ci default NULL,\r
+  `cl_leader` int(10) default '0',\r
+  `cl_money` int(10) default '0',\r
+  `cl_minsympathy` int(3) default '70',\r
+  `cl_appid` int(10) default '0',\r
+  `cl_representative` int(10) default '0',\r
+  PRIMARY KEY  (`cl_id`)\r
+) ENGINE=MyISAM AUTO_INCREMENT=1002 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;\r
+\r
+/*Table structure for table `clanwars` */\r
+\r
+DROP TABLE IF EXISTS `clanwars`;\r
+\r
+CREATE TABLE `clanwars` (\r
+  `cw_id` int(10) NOT NULL auto_increment,\r
+  `cw_initclan` int(10) default '0',\r
+  `cw_enemyclan` int(10) default '0',\r
+  `cw_starttime` varchar(45) collate latin1_general_ci default '',\r
+  `cw_status` int(2) default '0',\r
+  `cw_statement_initiator` varchar(512) collate latin1_general_ci default '',\r
+  `cw_statement_enemy` varchar(512) collate latin1_general_ci default '',\r
+  PRIMARY KEY  (`cw_id`)\r
+) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;\r
+\r
+/*Table structure for table `contacts` */\r
+\r
+DROP TABLE IF EXISTS `contacts`;\r
+\r
+CREATE TABLE `contacts` (\r
+  `c_id` int(10) unsigned NOT NULL auto_increment,\r
+  `c_listid` int(10) unsigned NOT NULL default '0' COMMENT 'Who''s list?',\r
+  `c_conid` int(10) unsigned NOT NULL default '0' COMMENT 'Char ID of person on list',\r
+  `c_type` int(10) unsigned NOT NULL default '0' COMMENT '1=Personal, 2=Business, 3=Allied',\r
+  `c_desc` varchar(256) NOT NULL,\r
+  PRIMARY KEY  (`c_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `datacubes` */\r
+\r
+DROP TABLE IF EXISTS `datacubes`;\r
+\r
+CREATE TABLE `datacubes` (\r
+  `cb_id` int(10) NOT NULL auto_increment,\r
+  `cb_securitycode` char(30) collate latin1_general_ci default '',\r
+  `cb_inscription` tinytext collate latin1_general_ci,\r
+  PRIMARY KEY  (`cb_id`)\r
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;\r
+\r
+/*Table structure for table `emails` */\r
+\r
+DROP TABLE IF EXISTS `emails`;\r
+\r
+CREATE TABLE `emails` (\r
+  `e_id` int(10) unsigned NOT NULL auto_increment,\r
+  `e_subject` varchar(128) NOT NULL default '',\r
+  `e_fromid` int(10) unsigned NOT NULL default '0',\r
+  `e_datetime` varchar(45) NOT NULL default '0',\r
+  `e_toid` int(10) unsigned NOT NULL default '0',\r
+  `e_body` varchar(512) NOT NULL,\r
+  `e_new` tinyint(1) NOT NULL default '1',\r
+  `e_replied` tinyint(1) NOT NULL default '0',\r
+  PRIMARY KEY  (`e_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `forum_posts` */\r
+\r
+DROP TABLE IF EXISTS `forum_posts`;\r
+\r
+CREATE TABLE `forum_posts` (\r
+  `fp_id` int(10) unsigned NOT NULL auto_increment,\r
+  `fp_name` varchar(45) NOT NULL default '',\r
+  `fp_fromid` int(10) unsigned NOT NULL default '0',\r
+  `fp_content` varchar(2048) NOT NULL default '',\r
+  `fp_datetime` varchar(45) NOT NULL default '',\r
+  `fp_replyid` int(10) unsigned NOT NULL default '0',\r
+  `fp_forumid` int(10) unsigned NOT NULL default '0',\r
+  `fp_factionid` int(2) default '0',\r
+  `fp_clanid` int(10) default '0',\r
+  PRIMARY KEY  (`fp_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `forums` */\r
+\r
+DROP TABLE IF EXISTS `forums`;\r
+\r
+CREATE TABLE `forums` (\r
+  `f_id` int(10) unsigned NOT NULL auto_increment,\r
+  `f_name` varchar(45) NOT NULL default '',\r
+  `f_area` int(10) unsigned NOT NULL default '0',\r
+  `f_showname` varchar(45) NOT NULL default '',\r
+  PRIMARY KEY  (`f_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `genrep` */\r
+\r
+DROP TABLE IF EXISTS `genrep`;\r
+\r
+CREATE TABLE `genrep` (\r
+  `g_id` int(10) unsigned NOT NULL auto_increment,\r
+  `g_worldid` int(10) unsigned NOT NULL default '0',\r
+  `g_stationid` int(10) unsigned NOT NULL default '0',\r
+  `g_charid` int(10) unsigned NOT NULL default '0',\r
+  PRIMARY KEY  (`g_id`)\r
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `guides` */\r
+\r
+DROP TABLE IF EXISTS `guides`;\r
+\r
+CREATE TABLE `guides` (\r
+  `g_id` int(10) unsigned NOT NULL auto_increment,\r
+  `g_type` int(10) unsigned NOT NULL default '0',\r
+  `g_title` varchar(45) NOT NULL default '',\r
+  `g_language` int(2) default NULL,\r
+  `g_content` text NOT NULL,\r
+  `g_chapter` int(1) default '0',\r
+  `g_part` int(1) default '0',\r
+  PRIMARY KEY  (`g_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `inventory` */\r
+\r
+DROP TABLE IF EXISTS `inventory`;\r
+\r
+CREATE TABLE `inventory` (\r
+  `inv_id` int(10) unsigned NOT NULL auto_increment,\r
+  `inv_charid` int(10) unsigned NOT NULL default '0',\r
+  `inv_loc` int(10) unsigned NOT NULL default '0',\r
+  `inv_x` int(10) unsigned NOT NULL default '0',\r
+  `inv_y` int(10) unsigned NOT NULL default '0',\r
+  `inv_itemid` int(10) unsigned NOT NULL default '0',\r
+  `inv_flag` int(10) unsigned NOT NULL default '0',\r
+  `inv_qty` int(10) unsigned NOT NULL default '0',\r
+  `inv_sqty` int(10) unsigned NOT NULL default '0',\r
+  `inv_cdur` int(10) unsigned NOT NULL default '0',\r
+  `inv_dmg` int(10) unsigned NOT NULL default '0',\r
+  `inv_frq` int(10) unsigned NOT NULL default '0',\r
+  `inv_hnd` int(10) unsigned NOT NULL default '0',\r
+  `inv_rng` int(10) unsigned NOT NULL default '0',\r
+  `inv_mdur` int(10) unsigned NOT NULL default '0',\r
+  `inv_slots` int(10) unsigned NOT NULL default '0',\r
+  `inv_slt1` int(10) unsigned NOT NULL default '0',\r
+  `inv_slt2` int(10) unsigned NOT NULL default '0',\r
+  `inv_slt3` int(10) unsigned NOT NULL default '0',\r
+  `inv_slt4` int(10) unsigned NOT NULL default '0',\r
+  `inv_slt5` int(10) unsigned NOT NULL default '0',\r
+  `inv_atype` int(10) unsigned NOT NULL default '0',\r
+  `inv_contain` int(10) unsigned NOT NULL default '0',\r
+  PRIMARY KEY  (`inv_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `moneytransactions` */\r
+\r
+DROP TABLE IF EXISTS `moneytransactions`;\r
+\r
+CREATE TABLE `moneytransactions` (\r
+  `mt_id` int(10) NOT NULL auto_increment,\r
+  `mt_clanid` int(10) default '0',\r
+  `mt_amount` int(10) default '0',\r
+  `mt_player` int(10) default '0',\r
+  `mt_date` char(45) collate latin1_general_ci default '2750-01-01 00:00:00',\r
+  `mt_comment` char(255) collate latin1_general_ci default '0',\r
+  PRIMARY KEY  (`mt_id`)\r
+) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;\r
+\r
+/*Table structure for table `neochronicle` */\r
+\r
+DROP TABLE IF EXISTS `neochronicle`;\r
+\r
+CREATE TABLE `neochronicle` (\r
+  `nc_id` int(10) unsigned NOT NULL auto_increment,\r
+  `nc_name` varchar(45) NOT NULL default '',\r
+  `nc_content` text NOT NULL,\r
+  `nc_datetime` varchar(45) NOT NULL default '',\r
+  `nc_lang` int(2) default NULL,\r
+  `nc_approved` int(1) default '0',\r
+  `nc_author` char(45) default '',\r
+  `nc_icon` int(10) default '0',\r
+  PRIMARY KEY  (`nc_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `neocron articles` */\r
+\r
+DROP TABLE IF EXISTS `neocron articles`;\r
+\r
+CREATE TABLE `neocron articles` (\r
+  `na_id` int(10) unsigned NOT NULL auto_increment,\r
+  `na_datetime` varchar(45) NOT NULL default '',\r
+  `na_author` varchar(45) NOT NULL default '0',\r
+  `na_name` varchar(45) NOT NULL default '',\r
+  `na_content` text NOT NULL,\r
+  `na_approval` int(10) unsigned NOT NULL default '0',\r
+  PRIMARY KEY  (`na_id`)\r
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `npc_shop` */\r
+\r
+DROP TABLE IF EXISTS `npc_shop`;\r
+\r
+CREATE TABLE `npc_shop` (\r
+  `c_npc_id` int(11) default NULL COMMENT 'The NPC WorldID',\r
+  `c_zoneid` int(11) default NULL COMMENT 'The ZoneID in which the NPC is',\r
+  `c_itemid` int(11) default NULL COMMENT 'ItemID for sale',\r
+  `c_itemprice` int(11) default NULL COMMENT 'Price for this item'\r
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;\r
+\r
+/*Table structure for table `npc_spawns` */\r
+\r
+DROP TABLE IF EXISTS `npc_spawns`;\r
+\r
+CREATE TABLE `npc_spawns` (\r
+  `npc_id` int(10) unsigned NOT NULL auto_increment,\r
+  `npc_worldid` int(10) unsigned NOT NULL default '0',\r
+  `npc_nameid` int(10) unsigned NOT NULL default '0',\r
+  `npc_typeid` int(10) unsigned NOT NULL default '0',\r
+  `npc_name` varchar(45) NOT NULL default '',\r
+  `npc_location` int(10) unsigned NOT NULL default '0',\r
+  `npc_x` int(10) unsigned NOT NULL default '0',\r
+  `npc_y` int(10) unsigned NOT NULL default '0',\r
+  `npc_z` int(10) unsigned NOT NULL default '0',\r
+  `npc_angle` int(11) NOT NULL default '0',\r
+  `npc_clothing` int(10) unsigned NOT NULL default '0',\r
+  `npc_loot` int(10) unsigned NOT NULL default '0',\r
+  `npc_unknown` int(10) unsigned NOT NULL default '0',\r
+  `npc_trader` int(10) unsigned NOT NULL default '0',\r
+  `npc_customname` varchar(80) default NULL,\r
+  `npc_customscript` varchar(100) default NULL,\r
+  `npc_shop_quality` int(3) default '50' COMMENT 'The quality of items if this npc has items to sell',\r
+  `npc_scripting` int(1) default '1' COMMENT '1: Scripts enabled 0: Scripts disabled',\r
+  PRIMARY KEY  (`npc_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=9968 DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `outposts` */\r
+\r
+DROP TABLE IF EXISTS `outposts`;\r
+\r
+CREATE TABLE `outposts` (\r
+  `o_id` int(10) unsigned NOT NULL auto_increment,\r
+  `o_outnum` int(10) unsigned NOT NULL default '0',\r
+  `o_security` int(10) unsigned NOT NULL default '0',\r
+  `o_clan` int(10) unsigned NOT NULL default '0',\r
+  `o_gr` int(10) unsigned NOT NULL default '0',\r
+  PRIMARY KEY  (`o_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=2213 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;\r
+\r
+/*Table structure for table `stockx` */\r
+\r
+DROP TABLE IF EXISTS `stockx`;\r
+\r
+CREATE TABLE `stockx` (\r
+  `st_id` int(10) unsigned NOT NULL auto_increment,\r
+  `st_factid` int(10) unsigned NOT NULL default '0',\r
+  `st_curval` float NOT NULL default '0',\r
+  `st_oldval` float NOT NULL default '0',\r
+  PRIMARY KEY  (`st_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `stockx_depots` */\r
+\r
+DROP TABLE IF EXISTS `stockx_depots`;\r
+\r
+CREATE TABLE `stockx_depots` (\r
+  `sxd_id` int(10) NOT NULL auto_increment,\r
+  `sxd_playerid` int(10) default '0',\r
+  `sxd_st_id` int(10) default '0',\r
+  `sxd_amount` int(10) default '0',\r
+  `sxd_paid` int(10) default '0',\r
+  PRIMARY KEY  (`sxd_id`)\r
+) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;\r
+\r
+/*Table structure for table `support` */\r
+\r
+DROP TABLE IF EXISTS `support`;\r
+\r
+CREATE TABLE `support` (\r
+  `su_id` int(10) NOT NULL auto_increment,\r
+  `su_player` int(10) default '0',\r
+  `su_datetime` varchar(45) collate latin1_general_ci default '',\r
+  `su_supporterid` int(10) default '0',\r
+  `su_desc` char(255) collate latin1_general_ci default '',\r
+  `su_type` int(1) default '0',\r
+  `su_worldid` int(10) default '0',\r
+  `su_inwork` int(1) default '0',\r
+  `su_finished` int(1) default '0',\r
+  PRIMARY KEY  (`su_id`)\r
+) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;\r
+\r
+/*Table structure for table `vehicles` */\r
+\r
+DROP TABLE IF EXISTS `vehicles`;\r
+\r
+CREATE TABLE `vehicles` (\r
+  `v_id` int(10) unsigned NOT NULL auto_increment,\r
+  `v_owner` int(10) unsigned NOT NULL default '0',\r
+  `v_type` int(10) unsigned NOT NULL default '0',\r
+  `v_condition` int(10) unsigned NOT NULL default '0',\r
+  `v_status` int(10) unsigned NOT NULL default '0',\r
+  `v_world` int(10) default '0',\r
+  PRIMARY KEY  (`v_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `world_actors` */\r
+\r
+DROP TABLE IF EXISTS `world_actors`;\r
+\r
+CREATE TABLE `world_actors` (\r
+  `wa_id` int(10) unsigned NOT NULL auto_increment COMMENT 'Unique ID',\r
+  `wa_actor_id` int(10) unsigned default NULL COMMENT 'u32 ID for the worldactor',\r
+  `wa_actor_map` int(10) unsigned default NULL COMMENT 'World/Zone ID',\r
+  `wa_actor_model` int(10) unsigned default NULL COMMENT 'ID of worldactor (pak_models.ini)',\r
+  `wa_actor_type` int(10) unsigned default NULL COMMENT 'Function type of the actor',\r
+  `wa_posX` int(10) unsigned default NULL,\r
+  `wa_posY` int(10) unsigned default NULL,\r
+  `wa_posZ` int(10) unsigned default NULL,\r
+  `wa_rotX` int(10) unsigned default NULL,\r
+  `wa_rotY` int(10) unsigned default NULL,\r
+  `wa_rotZ` int(10) unsigned default NULL,\r
+  `wa_option1` int(10) unsigned default NULL,\r
+  `wa_option2` int(10) unsigned default NULL,\r
+  `wa_option3` int(10) unsigned default NULL,\r
+  PRIMARY KEY  (`wa_id`)\r
+) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `worlds` */\r
+\r
+DROP TABLE IF EXISTS `worlds`;\r
+\r
+CREATE TABLE `worlds` (\r
+  `wr_id` int(10) NOT NULL default '0',\r
+  `wr_group` int(10) default '0',\r
+  PRIMARY KEY  (`wr_id`)\r
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;\r
+\r
+\r
diff --git a/server/database/DB_v8/unified_infoDB_rev8.sql b/server/database/DB_v8/unified_infoDB_rev8.sql
new file mode 100644 (file)
index 0000000..114ddc0
--- /dev/null
@@ -0,0 +1,51 @@
+/*\r
+SQLyog Enterprise - MySQL GUI v7.1 \r
+MySQL - 5.0.51a-24+lenny2 : Database - infoserver\r
+*********************************************************************\r
+*/\r\r
+\r
+/*!40101 SET NAMES utf8 */;\r
+\r
+/*!40101 SET SQL_MODE=''*/;\r
+\r
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\r
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\r
+\r
+CREATE DATABASE /*!32312 IF NOT EXISTS*/`infoserver` /*!40100 DEFAULT CHARACTER SET latin1 COLLATE latin1_general_ci */;\r
+\r
+USE `infoserver`;\r
+\r
+/*Table structure for table `accounts` */\r
+\r
+DROP TABLE IF EXISTS `accounts`;\r
+\r
+CREATE TABLE `accounts` (\r
+  `a_id` int(10) unsigned NOT NULL auto_increment,\r
+  `a_username` varchar(45) NOT NULL default '',\r
+  `a_password` varchar(45) NOT NULL default '',\r
+  `a_priv` int(10) unsigned default '0',\r
+  `a_status` int(10) unsigned default '0',\r
+  `a_bandate` int(11) unsigned NOT NULL default '0',\r
+  `a_emailaddress` varchar(255) NOT NULL,\r
+  `a_creationdate` datetime NOT NULL default '0000-00-00 00:00:00',\r
+  `a_lastused` datetime NOT NULL default '0000-00-00 00:00:00',\r
+  PRIMARY KEY  (`a_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;\r
+\r
+/*Table structure for table `server_list` */\r
+\r
+DROP TABLE IF EXISTS `server_list`;\r
+\r
+CREATE TABLE `server_list` (\r
+  `s_id` int(10) unsigned NOT NULL auto_increment,\r
+  `s_name` varchar(15) NOT NULL default 'NC server',\r
+  `s_wanaddr` varchar(15) NOT NULL default '127.0.0.1',\r
+  `s_port` int(10) unsigned NOT NULL default '12000',\r
+  `s_players` int(10) unsigned NOT NULL default '0',\r
+  `s_lastupdate` datetime NOT NULL default '0000-00-00 00:00:00',\r
+  `s_lanaddr` varchar(15) NOT NULL default '127.0.0.1',\r
+  PRIMARY KEY  (`s_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;\r
+\r
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\r
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\r
diff --git a/server/database/GameDB.sql b/server/database/GameDB.sql
new file mode 100644 (file)
index 0000000..22983b0
--- /dev/null
@@ -0,0 +1,536 @@
+-- phpMyAdmin SQL Dump
+-- version 2.8.1
+-- http://www.phpmyadmin.net
+-- 
+-- Host: localhost
+-- Generation Time: May 28, 2007 at 10:50 PM
+-- Server version: 4.1.14
+-- PHP Version: 5.2.0
+-- 
+-- Database: `gameserver`
+-- 
+CREATE DATABASE `gameserver` DEFAULT CHARACTER SET latin1 COLLATE latin1_general_ci;
+USE `gameserver`;
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `apartments`
+-- 
+
+CREATE TABLE `apartments` (
+  `apt_id` int(10) unsigned NOT NULL auto_increment,
+  `apt_location` int(10) unsigned NOT NULL default '0',
+  `apt_type` int(10) unsigned NOT NULL default '0',
+  `apt_password` varchar(45) NOT NULL default '',
+  `apt_owner` int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY  (`apt_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `apt_doors`
+-- 
+
+CREATE TABLE `apt_doors` (
+  `ad_id` int(10) unsigned NOT NULL auto_increment,
+  `ad_apt_id` int(10) unsigned NOT NULL default '0',
+  `ad_type` int(10) unsigned NOT NULL default '0',
+  `ad_apt_map` int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY  (`ad_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `apt_items`
+-- 
+
+CREATE TABLE `apt_items` (
+  `ai_id` int(10) unsigned NOT NULL auto_increment,
+  `ai_apt_id` int(10) unsigned NOT NULL default '0',
+  `ai_apt_map` int(10) unsigned NOT NULL default '0',
+  `ai_type` int(10) unsigned NOT NULL default '0',
+  `ai_option1` int(10) unsigned NOT NULL default '0',
+  `ai_option2` int(10) unsigned NOT NULL default '0',
+  `ai_option3` int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY  (`ai_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `buddy_list`
+-- 
+
+CREATE TABLE `buddy_list` (
+  `bud_id` int(10) NOT NULL auto_increment,
+  `bud_charid` int(10) NOT NULL default '0',
+  `bud_buddyid` mediumint(10) NOT NULL default '0',
+  PRIMARY KEY  (`bud_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `bug report`
+-- 
+
+CREATE TABLE `bug report` (
+  `br_id` int(10) unsigned NOT NULL auto_increment,
+  `br_type` int(10) unsigned NOT NULL default '0',
+  `br_desc` blob NOT NULL,
+  `br_fromid` int(10) unsigned NOT NULL default '0',
+  `br_location` int(10) unsigned NOT NULL default '0',
+  `br_status` int(10) unsigned NOT NULL default '0',
+  `br_datetime` varchar(45) NOT NULL default '',
+  `br_supid` int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY  (`br_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `characters`
+-- 
+
+CREATE TABLE `characters` (
+  `c_id` int(10) unsigned NOT NULL auto_increment,
+  `c_name` varchar(45) default '',
+  `c_str_lvl` int(10) unsigned default '0',
+  `c_str_pts` int(10) unsigned default '0',
+  `c_int_lvl` int(10) unsigned default '0',
+  `c_int_pts` int(10) unsigned default '0',
+  `c_dex_lvl` int(10) unsigned default '0',
+  `c_dex_pts` int(10) unsigned default '0',
+  `c_con_lvl` int(10) unsigned default '0',
+  `c_con_pts` int(10) unsigned default '0',
+  `c_psi_lvl` int(10) unsigned default '0',
+  `c_psi_pts` int(10) unsigned default '0',
+  `a_id` int(10) unsigned default '0',
+  `c_class` int(10) unsigned default '0',
+  `c_profession` int(10) unsigned default '0',
+  `c_sex` int(10) unsigned default '0',
+  `c_location` int(10) unsigned default '1',
+  `c_mc` int(10) unsigned default '0',
+  `c_hc` int(10) unsigned default '0',
+  `c_tra` int(10) unsigned default '0',
+  `c_pc` int(10) unsigned default '0',
+  `c_rc` int(10) unsigned default '0',
+  `c_tc` int(10) unsigned default '0',
+  `c_vhc` int(10) unsigned default '0',
+  `c_agl` int(10) unsigned default '0',
+  `c_rep` int(10) unsigned default '0',
+  `c_rec` int(10) unsigned default '0',
+  `c_rcl` int(10) unsigned default '0',
+  `c_atl` int(10) unsigned default '0',
+  `c_end` int(10) unsigned default '0',
+  `c_for` int(10) unsigned default '0',
+  `c_fir` int(10) unsigned default '0',
+  `c_enr` int(10) unsigned default '0',
+  `c_xrr` int(10) unsigned default '0',
+  `c_por` int(10) unsigned default '0',
+  `c_htl` int(10) unsigned default '0',
+  `c_hck` int(10) unsigned default '0',
+  `c_brt` int(10) unsigned default '0',
+  `c_psu` int(10) unsigned default '0',
+  `c_wep` int(10) unsigned default '0',
+  `c_cst` int(10) unsigned default '0',
+  `c_res` int(10) unsigned default '0',
+  `c_imp` int(10) unsigned default '0',
+  `c_ppu` int(10) unsigned default '0',
+  `c_apu` int(10) unsigned default '0',
+  `c_mst` int(10) unsigned default '0',
+  `c_ppw` int(10) unsigned default '0',
+  `c_psr` int(10) unsigned default '0',
+  `c_wpw` int(10) unsigned default '0',
+  `c_apt` int(10) unsigned default '0',
+  `c_cash` int(10) unsigned default '0',
+  `c_head` int(10) unsigned default '0',
+  `c_torso` int(10) unsigned default '0',
+  `c_legs` int(10) unsigned default '0',
+  `c_str_xp` float default '0',
+  `c_int_xp` float default '0',
+  `c_dex_xp` float default '0',
+  `c_psi_xp` float default '0',
+  `c_con_xp` float default '0',
+  `c_pos_x` float NOT NULL default '0',
+  `c_pos_y` float NOT NULL default '0',
+  `c_pos_z` float NOT NULL default '0',
+  `c_angle_ud` float NOT NULL default '0',
+  `c_angle_lr` float NOT NULL default '0',
+  `c_faction` int(10) unsigned NOT NULL default '0',
+  `c_slot` smallint(5) unsigned NOT NULL default '0',
+  PRIMARY KEY  (`c_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `contacts`
+-- 
+
+CREATE TABLE `contacts` (
+  `c_id` int(10) unsigned NOT NULL auto_increment,
+  `c_listid` int(10) unsigned NOT NULL default '0',
+  `c_conid` int(10) unsigned NOT NULL default '0',
+  `c_type` int(10) unsigned NOT NULL default '0',
+  `c_desc` blob NOT NULL,
+  PRIMARY KEY  (`c_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `emails`
+-- 
+
+CREATE TABLE `emails` (
+  `e_id` int(10) unsigned NOT NULL auto_increment,
+  `e_subject` varchar(128) NOT NULL default '',
+  `e_fromid` int(10) unsigned NOT NULL default '0',
+  `e_datetime` varchar(45) NOT NULL default '0',
+  `e_toid` int(10) unsigned NOT NULL default '0',
+  `e_body` blob NOT NULL,
+  `e_new` tinyint(1) NOT NULL default '1',
+  `e_replied` tinyint(1) NOT NULL default '0',
+  PRIMARY KEY  (`e_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `forum_posts`
+-- 
+
+CREATE TABLE `forum_posts` (
+  `fp_id` int(10) unsigned NOT NULL auto_increment,
+  `fp_name` varchar(45) NOT NULL default '',
+  `fp_fromid` int(10) unsigned NOT NULL default '0',
+  `fp_content` blob NOT NULL,
+  `fp_datetime` varchar(45) NOT NULL default '',
+  `fp_replyid` int(10) unsigned NOT NULL default '0',
+  `fp_forumid` int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY  (`fp_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `forums`
+-- 
+
+CREATE TABLE `forums` (
+  `f_id` int(10) unsigned NOT NULL auto_increment,
+  `f_name` varchar(45) NOT NULL default '',
+  `f_area` int(10) unsigned NOT NULL default '0',
+  `f_showname` varchar(45) NOT NULL default '',
+  PRIMARY KEY  (`f_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=21 ;
+
+-- 
+-- Dumping data for table `forums`
+-- 
+
+INSERT INTO `forums` (`f_id`, `f_name`, `f_area`, `f_showname`) VALUES (1, 'bbsnctradeweap', 0, 'nc.trading.weapons/armor'),
+(2, 'bbsnctraderare', 0, 'nc.trading.rareparts'),
+(3, 'bbsnctradeimp', 0, 'nc.trading.implants/boneenforcements'),
+(4, 'bbsnctradepsi', 0, 'nc.trading.psi equipment'),
+(5, 'bbsnctradeblue', 0, 'nc.trading.blueprints'),
+(6, 'bbsnctradeitem', 0, 'nc.trading.itemparts/raw materials'),
+(7, 'bbsnctradedrug', 0, 'nc.trading.drugs'),
+(8, 'bbsneocronmarket', 0, 'nc.trading.miscellaneous'),
+(9, 'bbsncrunnerano', 1, 'nc.runner.anouncements'),
+(10, 'bbsncrunnerserv', 1, 'nc.runner.services'),
+(11, 'bbsncrunnereven', 1, 'nc.runner.events'),
+(12, 'bbsncrunnerauct', 1, 'nc.runner.auctions'),
+(13, 'bbsncrunnerclan', 1, 'nc.runner.clan recruitment'),
+(14, 'bbsncrunnerfind', 1, 'nc.runner.find team'),
+(15, 'bbsncrunnerhelp', 1, 'nc.runner.runner2runnerhelp'),
+(16, 'bbsneocrongeneral', 2, 'nc.talk.general'),
+(17, 'bbsnctalkpolitics', 2, 'nc.talk.political discussions'),
+(18, 'bbfgeneral', 3, 'private.faction.general'),
+(19, 'bbcgeneral', 4, 'private.clan.general'),
+(20, 'bbsneobugreport', 2, 'Neopolis Bug Report');
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `genrep`
+-- 
+
+CREATE TABLE `genrep` (
+  `g_id` int(10) unsigned NOT NULL auto_increment,
+  `g_worldid` int(10) unsigned NOT NULL default '0',
+  `g_stationid` int(10) unsigned NOT NULL default '0',
+  `g_charid` int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY  (`g_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `guides`
+-- 
+
+CREATE TABLE `guides` (
+  `g_id` int(10) unsigned NOT NULL auto_increment,
+  `g_type` int(10) unsigned NOT NULL default '0',
+  `g_title` varchar(45) NOT NULL default '',
+  `g_content` blob NOT NULL,
+  PRIMARY KEY  (`g_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `inventory`
+-- 
+
+CREATE TABLE `inventory` (
+  `inv_id` int(10) unsigned NOT NULL auto_increment,
+  `inv_charid` int(10) unsigned NOT NULL default '0',
+  `inv_loc` int(10) unsigned NOT NULL default '0',
+  `inv_x` int(10) unsigned NOT NULL default '0',
+  `inv_y` int(10) unsigned NOT NULL default '0',
+  `inv_itemid` int(10) unsigned NOT NULL default '0',
+  `inv_type` int(10) unsigned NOT NULL default '0',
+  `inv_qty` int(10) unsigned NOT NULL default '0',
+  `inv_curdur` int(10) unsigned NOT NULL default '0',
+  `inv_dmg` int(10) unsigned NOT NULL default '0',
+  `inv_freq` int(10) unsigned NOT NULL default '0',
+  `inv_hand` int(10) unsigned NOT NULL default '0',
+  `inv_rng` int(10) unsigned NOT NULL default '0',
+  `inv_maxdur` int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY  (`inv_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `neochronicle`
+-- 
+
+CREATE TABLE `neochronicle` (
+  `nc_id` int(10) unsigned NOT NULL auto_increment,
+  `nc_name` varchar(45) NOT NULL default '',
+  `nc_content` blob NOT NULL,
+  `nc_datetime` varchar(45) NOT NULL default '',
+  PRIMARY KEY  (`nc_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `neocron articles`
+-- 
+
+CREATE TABLE `neocron articles` (
+  `na_id` int(10) unsigned NOT NULL auto_increment,
+  `na_datetime` varchar(45) NOT NULL default '',
+  `na_author` varchar(45) NOT NULL default '0',
+  `na_name` varchar(45) NOT NULL default '',
+  `na_content` blob NOT NULL,
+  `na_approval` int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY  (`na_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `npc_spawns`
+-- 
+
+CREATE TABLE `npc_spawns` (
+  `npc_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `npc_worldid` int(10) unsigned NOT NULL DEFAULT '0',
+  `npc_nameid` int(10) unsigned NOT NULL DEFAULT '0',
+  `npc_typeid` int(10) unsigned NOT NULL DEFAULT '0',
+  `npc_name` varchar(45) NOT NULL DEFAULT '',
+  `npc_location` int(10) unsigned NOT NULL DEFAULT '0',
+  `npc_x` int(10) unsigned NOT NULL DEFAULT '0',
+  `npc_y` int(10) unsigned NOT NULL DEFAULT '0',
+  `npc_z` int(10) unsigned NOT NULL DEFAULT '0',
+  `npc_angle` int(11) NOT NULL DEFAULT '0',
+  `npc_clothing` int(10) unsigned NOT NULL DEFAULT '0',
+  `npc_loot` int(10) unsigned NOT NULL DEFAULT '0',
+  `npc_unknown` int(10) unsigned NOT NULL DEFAULT '0',
+  `npc_trader` int(10) unsigned NOT NULL DEFAULT '0',
+  `npc_customname` varchar(80) DEFAULT NULL,
+  `npc_customscript` varchar(100) DEFAULT NULL,
+  PRIMARY KEY (`npc_id`)
+) ENGINE=InnoDB AUTO_INCREMENT=9916 DEFAULT CHARSET=latin1;
+
+--
+-- Dumping data for table `npc_spawns`
+--
+
+/*!40000 ALTER TABLE `npc_spawns` DISABLE KEYS */;
+INSERT INTO `npc_spawns` VALUES 
+(1,256,270,33900,'WSK',1,31972,31058,32552,90,33,0,19646,50,NULL,NULL),
+(2,262,282,51243,'WSK',1,32811,31586,32520,180,33,0,19386,57,NULL,NULL),
+(3,264,23,65186,'WLDKL',1,31573,29917,32512,180,100,0,32732,0,NULL,NULL),
+(4,265,263,10711,'WSK',1,31661,30953,32544,180,101,0,19644,50,NULL,NULL),
+(5,266,23,64049,'WLDK',1,29598,29969,32536,180,100,0,32705,33023,NULL,NULL),
+(6,304,1,13405,'PATROL_COPBOTC',1,30059,30466,32640,180,7641,0,32299,0,NULL,NULL),
+(7,306,1,56866,'PATROL_COPBOT6',1,33653,30715,32544,0,32417,0,32403,0,NULL,NULL),
+(8,312,1,7303,'PATROL_COPBOT6',1,32723,32490,32648,0,791,0,32277,0,NULL,NULL),
+(9,284,1622,63446,'WSK',3,29960,33508,33152,270,2652,0,29756,0,NULL,NULL),
+(10,290,39,44604,'SEMPL',3,27621,33353,33152,0,92,0,30496,80,NULL,NULL),
+(11,291,36,53646,'SEMPL',3,27548,33173,33152,0,92,0,30496,31,NULL,NULL),
+(12,293,39,63006,'SEMPL',3,27454,33429,33152,0,92,0,30496,80,NULL,NULL),
+(13,294,36,34060,'SEMPL',3,27397,33244,33152,0,92,0,30496,31,NULL,NULL),
+(14,273,12,14626,'DANCER',6,32958,32949,32576,0,2538,0,4512,0,NULL,NULL),
+(15,290,15,51184,'DANCER',6,33017,34974,32648,0,2537,0,572,0,NULL,NULL),
+(16,281,17,52618,'DANCER',6,32975,34960,32648,0,2537,0,572,0,NULL,NULL),
+(17,298,351,57844,'HOOKER',6,32958,32877,33312,90,2493,0,2208,0,NULL,NULL),
+(18,264,305,3099,'WSK',9,33351,32800,32256,180,4997,0,2551,230,NULL,NULL),
+(19,265,306,587,'WSK',9,33106,31095,32464,90,35249,0,363,210,NULL,NULL),
+(20,263,310,57458,'WSK',24,33895,34012,32704,180,1598,0,1351,53,NULL,NULL),
+(21,277,258,58731,'WSK',101,32812,32206,32512,270,94,0,22125,22,NULL,NULL),
+(22,261,245,52642,'WSK',1084,33622,32546,32832,0,2967,0,5292,0,NULL,NULL),
+(23,264,247,47120,'WSK',1084,32468,32928,32840,0,2651,0,5633,0,NULL,NULL),
+(24,259,191,51073,'WLDK',2181,39113,24946,33921,0,10897,0,32121,0,NULL,NULL),
+(25,258,191,20727,'WLDK',2181,35266,25184,33921,0,20212,0,32121,0,NULL,NULL),
+(26,257,191,53363,'WLDK',2181,38849,25283,33855,0,14493,0,32121,0,NULL,NULL),
+(27,256,191,48587,'WLDK',2181,38834,24848,33855,0,14493,0,32121,0,NULL,NULL),
+(28,971,386,5040,'WSK',2181,38000,24127,33854,264,6622,0,2590,0,NULL,NULL),
+(29,264,191,5462,'WLDK',2181,38384,26227,33855,0,1610,0,32082,0,NULL,NULL),
+(30,263,1686,19955,'WSK',2181,38402,26034,33855,0,805,0,960,0,NULL,NULL),
+(31,261,191,22015,'WLDK',2181,37612,25158,33855,0,59768,0,32060,0,NULL,NULL),
+(32,260,191,64663,'WLDK',2181,37609,24613,33854,0,20204,0,32058,0,NULL,NULL),
+(33,1020,836,43282,'MBOTFLY',2181,43068,26020,34020,0,31788,0,405,0,NULL,NULL),
+(34,988,836,41913,'MBOTFLY',2181,41537,28260,33860,0,50146,0,380,0,NULL,NULL),
+(35,1006,800,15709,'MBOT',2181,42047,28256,33786,0,14348,0,220,0,NULL,NULL),
+(36,1005,800,28598,'MBOT',2181,44419,23412,33445,0,8332,0,585,0,NULL,NULL),
+(37,1014,672,28153,'DOGBOT',2181,38041,29414,34088,0,21948,0,221,0,NULL,NULL),
+(38,984,677,32746,'WBADGUY',2181,37985,31043,33939,0,21616,0,222,0,NULL,NULL),
+(39,262,191,2071,'WLDK',2181,33772,27289,34104,135,58458,0,32005,0,NULL,NULL),
+(40,973,606,26878,'MUTANTB',2181,26220,27158,34106,0,20679,0,490,0,NULL,NULL),
+(41,975,800,11783,'MBOT',2181,31285,23969,33970,0,722,0,38,0,NULL,NULL),
+(42,981,640,61001,'FLYMUT',2181,26672,26657,34281,0,20684,0,1510,0,NULL,NULL),
+(43,985,610,1100,'MGMUT',2181,28040,26301,34083,0,21559,0,628,0,NULL,NULL),
+(44,986,640,1159,'FLYMUT',2181,27424,27264,34328,0,21560,0,1503,0,NULL,NULL),
+(45,987,626,53397,'MUTANTB',2181,26386,27672,34135,0,20680,0,407,0,NULL,NULL),
+(46,999,602,19865,'MUTANTB',2181,26771,26119,34228,0,21559,0,271,0,NULL,NULL),
+(47,1003,730,39449,'BROBOT',2181,25425,32173,34055,0,20939,0,4285,0,NULL,NULL);
+/*!40000 ALTER TABLE `npc_spawns` 
+ENABLE KEYS */;
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `stockx`
+-- 
+
+CREATE TABLE `stockx` (
+  `st_id` int(10) unsigned NOT NULL auto_increment,
+  `st_factid` int(10) unsigned NOT NULL default '0',
+  `st_curval` float NOT NULL default '0',
+  `st_oldval` float NOT NULL default '0',
+  PRIMARY KEY  (`st_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=12 ;
+
+-- 
+-- Dumping data for table `stockx`
+-- 
+
+INSERT INTO `stockx` (`st_id`, `st_factid`, `st_curval`, `st_oldval`) VALUES (1, 9, 1227, 1227),
+(2, 2, 2499, 2400),
+(3, 6, 1269, 1269),
+(4, 10, 1387, 1387),
+(5, 8, 676, 676),
+(6, 14, 783, 783),
+(7, 15, 591, 591),
+(8, 3, 1779, 1779),
+(9, 5, 879, 879),
+(10, 11, 1581, 1581),
+(11, 4, 1544, 1544);
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `vehicles`
+-- 
+
+CREATE TABLE `vehicles` (
+  `v_id` int(10) unsigned NOT NULL auto_increment,
+  `v_owner` int(10) unsigned NOT NULL default '0',
+  `v_type` int(10) unsigned NOT NULL default '0',
+  `v_condition` int(10) unsigned NOT NULL default '0',
+  `v_status` int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY  (`v_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `world_actors`
+-- 
+
+CREATE TABLE `world_actors` (
+  `wa_id` int(10) unsigned NOT NULL auto_increment COMMENT 'Unique ID',
+  `wa_actor_id` int(10) unsigned default NULL COMMENT 'u32 ID for the worldactor',
+  `wa_actor_map` int(10) unsigned default NULL COMMENT 'World/Zone ID',
+  `wa_actor_model` int(10) unsigned default NULL COMMENT 'ID of worldactor (pak_models.ini)',
+  `wa_actor_type` int(10) unsigned default NULL COMMENT 'Function type of the actor',
+  `wa_posX` int(10) unsigned default NULL,
+  `wa_posY` int(10) unsigned default NULL,
+  `wa_posZ` int(10) unsigned default NULL,
+  `wa_rotX` int(10) unsigned default NULL,
+  `wa_rotY` int(10) unsigned default NULL,
+  `wa_rotZ` int(10) unsigned default NULL,
+  `wa_option1` int(10) unsigned default NULL,
+  `wa_option2` int(10) unsigned default NULL,
+  `wa_option3` int(10) unsigned default NULL,
+  PRIMARY KEY  (`wa_id`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `world_doors`
+-- 
+
+CREATE TABLE `world_doors` (
+  `wd_id` int(10) unsigned NOT NULL auto_increment,
+  `wd_world_id` int(10) unsigned NOT NULL default '0',
+  `wd_type` int(10) unsigned NOT NULL default '0',
+  `wd_world_map` int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY  (`wd_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `world_items`
+-- 
+
+CREATE TABLE `world_items` (
+  `wi_id` int(10) unsigned NOT NULL auto_increment,
+  `wi_worlditem_id` int(10) unsigned NOT NULL default '0',
+  `wi_worlditem_map` int(10) unsigned NOT NULL default '0',
+  `wi_type` int(10) unsigned NOT NULL default '0',
+  `wi_option1` int(10) unsigned NOT NULL default '0',
+  `wi_option2` int(10) unsigned NOT NULL default '0',
+  `wi_option3` int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY  (`wi_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
diff --git a/server/database/GameDB_migration_rev107-rev108.sql b/server/database/GameDB_migration_rev107-rev108.sql
new file mode 100644 (file)
index 0000000..55fd0d8
--- /dev/null
@@ -0,0 +1,86 @@
+\r
+--\r
+-- Table structure for table `npc_spawns`\r
+--\r
+\r
+DROP TABLE IF EXISTS `npc_spawns`;\r
+SET @saved_cs_client     = @@character_set_client;\r
+SET character_set_client = utf8;\r
+CREATE TABLE `npc_spawns` (\r
+  `npc_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\r
+  `npc_worldid` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_nameid` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_typeid` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_name` varchar(45) NOT NULL DEFAULT '',\r
+  `npc_location` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_x` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_y` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_z` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_angle` int(11) NOT NULL DEFAULT '0',\r
+  `npc_clothing` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_loot` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_unknown` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_trader` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_customname` varchar(80) DEFAULT NULL,\r
+  `npc_customscript` varchar(100) DEFAULT NULL,\r
+  PRIMARY KEY (`npc_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=9916 DEFAULT CHARSET=latin1;\r
+SET character_set_client = @saved_cs_client;\r
+\r
+--\r
+-- Dumping data for table `npc_spawns`\r
+--\r
+\r
+LOCK TABLES `npc_spawns` WRITE;\r
+/*!40000 ALTER TABLE `npc_spawns` DISABLE KEYS */;\r
+INSERT INTO `npc_spawns` VALUES \r
+(1,256,270,33900,'WSK',1,31972,31058,32552,90,33,0,19646,50,NULL,NULL),\r
+(2,262,282,51243,'WSK',1,32811,31586,32520,180,33,0,19386,57,NULL,NULL),\r
+(3,264,23,65186,'WLDKL',1,31573,29917,32512,180,100,0,32732,0,NULL,NULL),\r
+(4,265,263,10711,'WSK',1,31661,30953,32544,180,101,0,19644,50,NULL,NULL),\r
+(5,266,23,64049,'WLDK',1,29598,29969,32536,180,100,0,32705,33023,NULL,NULL),\r
+(6,304,1,13405,'PATROL_COPBOTC',1,30059,30466,32640,180,7641,0,32299,0,NULL,NULL),\r
+(7,306,1,56866,'PATROL_COPBOT6',1,33653,30715,32544,0,32417,0,32403,0,NULL,NULL),\r
+(8,312,1,7303,'PATROL_COPBOT6',1,32723,32490,32648,0,791,0,32277,0,NULL,NULL),\r
+(9,284,1622,63446,'WSK',3,29960,33508,33152,270,2652,0,29756,0,NULL,NULL),\r
+(10,290,39,44604,'SEMPL',3,27621,33353,33152,0,92,0,30496,80,NULL,NULL),\r
+(11,291,36,53646,'SEMPL',3,27548,33173,33152,0,92,0,30496,31,NULL,NULL),\r
+(12,293,39,63006,'SEMPL',3,27454,33429,33152,0,92,0,30496,80,NULL,NULL),\r
+(13,294,36,34060,'SEMPL',3,27397,33244,33152,0,92,0,30496,31,NULL,NULL),\r
+(14,273,12,14626,'DANCER',6,32958,32949,32576,0,2538,0,4512,0,NULL,NULL),\r
+(15,290,15,51184,'DANCER',6,33017,34974,32648,0,2537,0,572,0,NULL,NULL),\r
+(16,281,17,52618,'DANCER',6,32975,34960,32648,0,2537,0,572,0,NULL,NULL),\r
+(17,298,351,57844,'HOOKER',6,32958,32877,33312,90,2493,0,2208,0,NULL,NULL),\r
+(18,264,305,3099,'WSK',9,33351,32800,32256,180,4997,0,2551,230,NULL,NULL),\r
+(19,265,306,587,'WSK',9,33106,31095,32464,90,35249,0,363,210,NULL,NULL),\r
+(20,263,310,57458,'WSK',24,33895,34012,32704,180,1598,0,1351,53,NULL,NULL),\r
+(21,277,258,58731,'WSK',101,32812,32206,32512,270,94,0,22125,22,NULL,NULL),\r
+(22,261,245,52642,'WSK',1084,33622,32546,32832,0,2967,0,5292,0,NULL,NULL),\r
+(23,264,247,47120,'WSK',1084,32468,32928,32840,0,2651,0,5633,0,NULL,NULL),\r
+(24,259,191,51073,'WLDK',2181,39113,24946,33921,0,10897,0,32121,0,NULL,NULL),\r
+(25,258,191,20727,'WLDK',2181,35266,25184,33921,0,20212,0,32121,0,NULL,NULL),\r
+(26,257,191,53363,'WLDK',2181,38849,25283,33855,0,14493,0,32121,0,NULL,NULL),\r
+(27,256,191,48587,'WLDK',2181,38834,24848,33855,0,14493,0,32121,0,NULL,NULL),\r
+(28,971,386,5040,'WSK',2181,38000,24127,33854,264,6622,0,2590,0,NULL,NULL),\r
+(29,264,191,5462,'WLDK',2181,38384,26227,33855,0,1610,0,32082,0,NULL,NULL),\r
+(30,263,1686,19955,'WSK',2181,38402,26034,33855,0,805,0,960,0,NULL,NULL),\r
+(31,261,191,22015,'WLDK',2181,37612,25158,33855,0,59768,0,32060,0,NULL,NULL),\r
+(32,260,191,64663,'WLDK',2181,37609,24613,33854,0,20204,0,32058,0,NULL,NULL),\r
+(33,1020,836,43282,'MBOTFLY',2181,43068,26020,34020,0,31788,0,405,0,NULL,NULL),\r
+(34,988,836,41913,'MBOTFLY',2181,41537,28260,33860,0,50146,0,380,0,NULL,NULL),\r
+(35,1006,800,15709,'MBOT',2181,42047,28256,33786,0,14348,0,220,0,NULL,NULL),\r
+(36,1005,800,28598,'MBOT',2181,44419,23412,33445,0,8332,0,585,0,NULL,NULL),\r
+(37,1014,672,28153,'DOGBOT',2181,38041,29414,34088,0,21948,0,221,0,NULL,NULL),\r
+(38,984,677,32746,'WBADGUY',2181,37985,31043,33939,0,21616,0,222,0,NULL,NULL),
+(39,262,191,2071,'WLDK',2181,33772,27289,34104,135,58458,0,32005,0,NULL,NULL),
+(40,973,606,26878,'MUTANTB',2181,26220,27158,34106,0,20679,0,490,0,NULL,NULL),
+(41,975,800,11783,'MBOT',2181,31285,23969,33970,0,722,0,38,0,NULL,NULL),
+(42,981,640,61001,'FLYMUT',2181,26672,26657,34281,0,20684,0,1510,0,NULL,NULL),
+(43,985,610,1100,'MGMUT',2181,28040,26301,34083,0,21559,0,628,0,NULL,NULL),
+(44,986,640,1159,'FLYMUT',2181,27424,27264,34328,0,21560,0,1503,0,NULL,NULL),
+(45,987,626,53397,'MUTANTB',2181,26386,27672,34135,0,20680,0,407,0,NULL,NULL),
+(46,999,602,19865,'MUTANTB',2181,26771,26119,34228,0,21559,0,271,0,NULL,NULL),
+(47,1003,730,39449,'BROBOT',2181,25425,32173,34055,0,20939,0,4285,0,NULL,NULL);\r
+/*!40000 ALTER TABLE `npc_spawns` \r
+ENABLE KEYS */;\r
+UNLOCK TABLES;\r
diff --git a/server/database/GameDB_migration_rev81-rev82.sql b/server/database/GameDB_migration_rev81-rev82.sql
new file mode 100644 (file)
index 0000000..6d09a0e
--- /dev/null
@@ -0,0 +1,62 @@
+-- phpMyAdmin SQL Dump
+-- version 2.8.1
+-- http://www.phpmyadmin.net
+-- 
+-- Host: localhost
+-- Generation Time: Sep 27, 2006 at 08:37 PM
+-- Server version: 4.1.14
+-- PHP Version: 4.4.0
+-- 
+-- Database: `gameserver`
+--
+-- Additions from version 4 to version 5
+-- To be applied on a gameserver database from GameDB5.sql
+--
+USE `gameserver`;
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure addition for table `npc_spawns`
+-- 
+
+ALTER TABLE `npc_spawns`
+ADD `npc_customname` VARCHAR( 80 ) NULL ,
+ADD `npc_customscript` VARCHAR( 100 ) NULL ;
+
+
+-- --------------------------------------------------------
+
+-- 
+-- Table addition: `world_actors`
+-- 
+
+CREATE TABLE IF NOT EXISTS `world_actors` (
+  `wa_id` int(10) unsigned NOT NULL auto_increment COMMENT 'Unique ID',
+  `wa_actor_id` int(10) unsigned default NULL COMMENT 'u32 ID for the worldactor',
+  `wa_actor_map` int(10) unsigned default NULL COMMENT 'World/Zone ID',
+  `wa_actor_model` int(10) unsigned default NULL COMMENT 'ID of worldactor (pak_models.ini)',
+  `wa_actor_type` int(10) unsigned default NULL COMMENT 'Function type of the actor',
+  `wa_posX` int(10) unsigned default NULL,
+  `wa_posY` int(10) unsigned default NULL,
+  `wa_posZ` int(10) unsigned default NULL,
+  `wa_rotX` int(10) unsigned default NULL,
+  `wa_rotY` int(10) unsigned default NULL,
+  `wa_rotZ` int(10) unsigned default NULL,
+  `wa_option1` int(10) unsigned default NULL,
+  `wa_option2` int(10) unsigned default NULL,
+  `wa_option3` int(10) unsigned default NULL,
+  PRIMARY KEY  (`wa_id`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
+
+-- --------------------------------------------------------
+
+-- 
+-- Optionnal: Use the following lines with TinNS ONLY (uncomment them)
+-- It doesn't matter if you don't use them
+-- 
+
+-- TRUNCATE TABLE 'apt_doors';
+-- TRUNCATE TABLE 'apt_items';
+-- TRUNCATE TABLE 'world_doors';
+-- TRUNCATE TABLE 'world_items';
diff --git a/server/database/GameDB_patch_rev133-rev134.sql b/server/database/GameDB_patch_rev133-rev134.sql
new file mode 100644 (file)
index 0000000..be6b56f
--- /dev/null
@@ -0,0 +1,78 @@
+-- Database: `gameserver`\r
+--\r
+-- New stuff for NPC Subsystem\r
+--\r
+USE `gameserver`;\r
+\r
+-- --------------------------------------------------------\r
+\r
+--\r
+-- Table structure for table `npc_spawns`\r
+--\r
+\r
+DROP TABLE IF EXISTS `npc_spawns`;\r
+SET @saved_cs_client     = @@character_set_client;\r
+SET character_set_client = utf8;\r
+CREATE TABLE `npc_spawns` (\r
+  `npc_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\r
+  `npc_worldid` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_nameid` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_typeid` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_name` varchar(45) NOT NULL DEFAULT '',\r
+  `npc_location` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_x` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_y` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_z` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_angle` int(11) NOT NULL DEFAULT '0',\r
+  `npc_clothing` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_loot` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_unknown` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_trader` int(10) unsigned NOT NULL DEFAULT '0',\r
+  `npc_customname` varchar(80) DEFAULT NULL,\r
+  `npc_customscript` varchar(100) DEFAULT NULL,\r
+  `npc_shop_quality` int(3) DEFAULT '50' NULL COMMENT 'The quality of items if this npc has items to sell',\r
+  PRIMARY KEY (`npc_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=9916 DEFAULT CHARSET=latin1;\r
+SET character_set_client = @saved_cs_client;\r
+\r
+--\r
+-- Dumping data for table `npc_spawns`\r
+--\r
+\r
+LOCK TABLES `npc_spawns` WRITE;\r
+/*!40000 ALTER TABLE `npc_spawns` DISABLE KEYS */;\r
+INSERT INTO `npc_spawns` (npc_worldid, npc_nameid, npc_typeid, npc_name, npc_location, npc_x, npc_y, npc_z, npc_angle, npc_clothing, npc_unknown, npc_trader, npc_customname)\r
+VALUES \r
+(1020,385,61093,'WSK',1,33808,31332,32512,30,6612,8814,0,'Event Info'),\r
+(1020,388,17634,'WSK',3,30063,34111,33136,90,6616,14035,0,'Event Info'),\r
+(1018,387,32772,'WSK',101,31938,32165,32512,130,6616,16675,0,'Event Info'),\r
+(1019,215,50585,'WSK',101,34209,33864,32512,359,197,19499,195,NULL),\r
+(1020,385,13542,'WSK',101,33261,33113,32672,2,4342,17892,0,'VotR Paperboy'),\r
+(1019,389,10890,'WSK',401,31105,32463,31936,92,6613,14572,0,'Event Info'),\r
+(1020,1629,26858,'WSK',401,31265,30718,31952,177,2827,12567,0,NULL),\r
+(976,2818,15528,'WSK',2071,23436,21380,35220,185,7214,9785,0,NULL),\r
+(971,386,5040,'WSK',2181,38000,24127,33854,264,6622,2590,0,NULL),\r
+(1020,836,43282,'MBOTFLY',2181,43068,26020,34020,0,31788,405,0,NULL),\r
+(988,836,41913,'MBOTFLY',2181,41537,28260,33860,0,50146,380,0,NULL),\r
+(1006,800,15709,'MBOT',2181,42047,28256,33786,0,14348,220,0,NULL),\r
+(1005,800,28598,'MBOT',2181,44419,23412,33445,0,8332,585,0,NULL),\r
+(1014,672,28153,'DOGBOT',2181,38041,29414,34088,0,21948,221,0,NULL),\r
+(984,677,32746,'WBADGUY',2181,37985,31043,33939,0,21616,222,0,NULL),\r
+(973,606,26878,'MUTANTB',2181,26220,27158,34106,0,20679,490,0,NULL),\r
+(975,800,11783,'MBOT',2181,31285,23969,33970,0,722,38,0,NULL),\r
+(981,640,61001,'FLYMUT',2181,26672,26657,34281,0,20684,1510,0,NULL),\r
+(985,610,1100,'MGMUT',2181,28040,26301,34083,0,21559,628,0,NULL),\r
+(986,640,1159,'FLYMUT',2181,27424,27264,34328,0,21560,1503,0,NULL),\r
+(987,626,53397,'MUTANTB',2181,26386,27672,34135,0,20680,407,0,NULL),\r
+(999,602,19865,'MUTANTB',2181,26771,26119,34228,0,21559,271,0,NULL),\r
+(1003,730,39449,'BROBOT',2181,25425,32173,34055,0,20939,4285,0,NULL);\r
+/*!40000 ALTER TABLE `npc_spawns` \r
+ENABLE KEYS */;\r
+UNLOCK TABLES;\r
+\r
+DROP TABLE IF EXISTS `npc_shop`;\r
+CREATE TABLE `npc_shop`(\r
+ `c_npc_id` int COMMENT 'The NPC WorldID',\r
+ `c_zoneid` int COMMENT 'The ZoneID in which the NPC is',\r
+ `c_itemid` int COMMENT 'ItemID for sale',\r
+ `c_itemprice` int COMMENT 'Price for this item');
\ No newline at end of file
diff --git a/server/database/GameDB_patch_rev134-rev140.sql b/server/database/GameDB_patch_rev134-rev140.sql
new file mode 100644 (file)
index 0000000..1d5bc2a
--- /dev/null
@@ -0,0 +1,49 @@
+/*\r
+SQLyog Community Edition- MySQL GUI v7.02 \r
+MySQL - 5.0.51a-24+lenny2 : Database - gameserver\r
+*********************************************************************\r
+*/\r
+\r
+/*!40101 SET NAMES utf8 */;\r
+\r
+/*!40101 SET SQL_MODE=''*/;\r
+\r
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\r
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\r
+\r
+CREATE DATABASE /*!32312 IF NOT EXISTS*/`gameserver` /*!40100 DEFAULT CHARACTER SET latin1 COLLATE latin1_general_ci */;\r
+\r
+USE `gameserver`;\r
+\r
+/*Table structure for table `npc_spawns` */\r
+\r
+DROP TABLE IF EXISTS `npc_spawns`;\r
+\r
+CREATE TABLE `npc_spawns` (\r
+  `npc_id` int(10) unsigned NOT NULL auto_increment,\r
+  `npc_worldid` int(10) unsigned NOT NULL default '0',\r
+  `npc_nameid` int(10) unsigned NOT NULL default '0',\r
+  `npc_typeid` int(10) unsigned NOT NULL default '0',\r
+  `npc_name` varchar(45) NOT NULL default '',\r
+  `npc_location` int(10) unsigned NOT NULL default '0',\r
+  `npc_x` int(10) unsigned NOT NULL default '0',\r
+  `npc_y` int(10) unsigned NOT NULL default '0',\r
+  `npc_z` int(10) unsigned NOT NULL default '0',\r
+  `npc_angle` int(11) NOT NULL default '0',\r
+  `npc_clothing` int(10) unsigned NOT NULL default '0',\r
+  `npc_loot` int(10) unsigned NOT NULL default '0',\r
+  `npc_unknown` int(10) unsigned NOT NULL default '0',\r
+  `npc_trader` int(10) unsigned NOT NULL default '0',\r
+  `npc_customname` varchar(80) default NULL,\r
+  `npc_customscript` varchar(100) default NULL,\r
+  `npc_shop_quality` int(3) default '50' COMMENT 'The quality of items if this npc has items to sell',\r
+  `npc_scripting` int(1) default '1' COMMENT '1: Scripts enabled 0: Scripts disabled',\r
+  PRIMARY KEY  (`npc_id`)\r
+) ENGINE=InnoDB AUTO_INCREMENT=9942 DEFAULT CHARSET=latin1;\r
+\r
+/*Data for the table `npc_spawns` */\r
+\r
+insert  into `npc_spawns`(`npc_id`,`npc_worldid`,`npc_nameid`,`npc_typeid`,`npc_name`,`npc_location`,`npc_x`,`npc_y`,`npc_z`,`npc_angle`,`npc_clothing`,`npc_loot`,`npc_unknown`,`npc_trader`,`npc_customname`,`npc_customscript`,`npc_shop_quality`,`npc_scripting`) values (9916,1020,385,61093,'WSK',1,33808,31332,32512,30,6612,0,8814,0,'Zippy the Trader','scripts/lua/zippy.lua',50,1),(9917,1018,387,32772,'WSK',101,31938,32165,32512,130,6616,0,16675,0,'Event Info',NULL,50,1),(9918,1019,215,50585,'WSK',101,34209,33864,32512,359,197,0,19499,195,'VotR Paperboy',NULL,50,1),(9919,1020,385,13542,'WSK',101,33261,33113,32672,2,4342,0,17892,0,NULL,NULL,50,1),(9920,976,2818,15528,'WSK',2071,23436,21380,35220,185,7214,0,9785,0,NULL,NULL,50,1),(9921,971,386,5040,'WSK',2181,38000,24127,33854,264,6622,0,2590,0,NULL,NULL,50,1),(9922,1020,836,43282,'MBOTFLY',2181,43068,26020,34020,0,31788,0,405,0,NULL,NULL,50,1),(9923,988,836,41913,'MBOTFLY',2181,41537,28260,33860,0,50146,0,380,0,NULL,NULL,50,1),(9924,1006,800,15709,'MBOT',2181,42047,28256,33786,0,14348,0,220,0,NULL,NULL,50,1),(9925,1005,800,28598,'MBOT',2181,44419,23412,33445,0,8332,0,585,0,NULL,NULL,50,1),(9926,1014,672,28153,'DOGBOT',2181,38041,29414,34088,0,21948,0,221,0,NULL,NULL,50,1),(9927,984,677,32746,'WBADGUY',2181,37985,31043,33939,0,21616,0,222,0,NULL,NULL,50,1),(9928,973,606,26878,'MUTANTB',2181,26220,27158,34106,0,20679,0,490,0,NULL,NULL,50,1),(9929,975,800,11783,'MBOT',2181,31285,23969,33970,0,722,0,38,0,NULL,NULL,50,1),(9930,981,640,61001,'FLYMUT',2181,26672,26657,34281,0,20684,0,1510,0,NULL,NULL,50,1),(9931,985,610,1100,'MGMUT',2181,28040,26301,34083,0,21559,0,628,0,NULL,NULL,50,1),(9932,986,640,1159,'FLYMUT',2181,27424,27264,34328,0,21560,0,1503,0,NULL,NULL,50,1),(9933,987,626,53397,'MUTANTB',2181,26386,27672,34135,0,20680,0,407,0,NULL,NULL,50,1),(9934,999,602,19865,'MUTANTB',2181,26771,26119,34228,0,21559,0,271,0,NULL,NULL,50,1),(9935,1003,730,39449,'BROBOT',2181,25425,32173,34055,0,20939,0,4285,0,NULL,NULL,50,1);\r
+\r
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\r
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\r
diff --git a/server/database/InfoDB.sql b/server/database/InfoDB.sql
new file mode 100644 (file)
index 0000000..56eb3df
--- /dev/null
@@ -0,0 +1,75 @@
+-- MySQL Administrator dump 1.4\r
+--\r
+-- ------------------------------------------------------\r
+-- Server version      5.0.18-nt\r
+\r
+\r
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;\r
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;\r
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;\r
+/*!40101 SET NAMES utf8 */;\r
+\r
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\r
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\r
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\r
+\r
+\r
+--\r
+-- Create schema infoserver\r
+--\r
+\r
+CREATE DATABASE /*!32312 IF NOT EXISTS*/ infoserver DEFAULT CHARACTER SET latin1 COLLATE latin1_general_ci;\r
+USE infoserver;\r
+\r
+--\r
+-- Table structure for table `infoserver`.`accounts`\r
+--\r
+\r
+DROP TABLE IF EXISTS `accounts`;\r
+CREATE TABLE `accounts` (\r
+  `a_id` int(10) unsigned NOT NULL auto_increment,\r
+  `a_username` varchar(45) NOT NULL default '',\r
+  `a_password` varchar(45) NOT NULL default '',\r
+  `a_priv` int(10) unsigned default '0',\r
+  `a_status` int(10) unsigned default '0',\r
+  `a_bandate` int(11) unsigned NOT NULL default '0',\r
+  PRIMARY KEY  (`a_id`)\r
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;\r
+\r
+--\r
+-- Dumping data for table `infoserver`.`accounts`\r
+--\r
+\r
+/*!40000 ALTER TABLE `accounts` DISABLE KEYS */;\r
+/*!40000 ALTER TABLE `accounts` ENABLE KEYS */;\r
+\r
+\r
+--\r
+-- Table structure for table `infoserver`.`server_list`\r
+--\r
+\r
+DROP TABLE IF EXISTS `server_list`;\r
+CREATE TABLE `server_list` (\r
+  `s_id` int(10) unsigned NOT NULL auto_increment,\r
+  `s_name` varchar(15) NOT NULL default 'NC server',\r
+  `s_addr` varchar(15) NOT NULL default '127.0.0.1',\r
+  `s_port` int(10) unsigned NOT NULL default '12000',\r
+  `s_players` int(10) unsigned NOT NULL default '0',\r
+  `s_lastupdate` datetime NOT NULL default '0000-00-00 00:00:00',\r
+  PRIMARY KEY  (`s_id`)\r
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;\r
+\r
+--\r
+-- Dumping data for table `infoserver`.`server_list`\r
+--\r
+\r
+/*!40000 ALTER TABLE `server_list` DISABLE KEYS */;\r
+/*!40000 ALTER TABLE `server_list` ENABLE KEYS */;\r
+\r
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\r
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\r
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\r
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\r
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\r
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\r
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\r
diff --git a/server/docs/ISC Example.txt b/server/docs/ISC Example.txt
new file mode 100644 (file)
index 0000000..a20d8ac
--- /dev/null
@@ -0,0 +1,47 @@
+Example for an successfull Infoserver <=> Gameserver interaction\r
+\r
+=======================================================================================================================\r
+ISC Version: 2\r
+Last Update: 13.12.2006 21:48 GMT+1\r
+=======================================================================================================================\r
+\r
+S0: Gameserver\r
+S1: Infoserver\r
+==========================\r
+Gameserver startup\r
+{\r
+       Handshake 01\r
+       S0 => S1        0xF0 0x08 0x00 0x01 0x02 0x00 0x02 0x00\r
+       S0 <= S1        0xF0 0x06 0x00 0x03 0x00 0x00\r
+       \r
+       Handshake 02 (Md5 pw hash)\r
+       S0 => S1  0xF0 0x24 0x00 0x10 0x20 0x00 0x00 0x01 0x10 0x27 0x11 0xFA 0x99 0x1F 0xFF 0xFF 0x01 0x01 0x07 0x19 0x18 0x18 0xFF 0x10 0x27 0x11 0xFA 0x99 0x1F 0xFF 0xFF 0x01 0x01 0x07 0x19 0x18 0x18 0xFF\r
+       S0 <= S1  0xF0 0x06 0x00 0x12 0x00 0x00\r
+\r
+       GS Serverdata #1 // Name= Irata\r
+       S0 => S1  0xF0 0x0B 0x00 0x20 0x05 0x00 0x49 0x72 0x61 0x74 0x61\r
+       S0 <= S1  0xF0 0x0B 0x00 0x22 0x05 0x00 0x49 0x72 0x61 0x74 0x61\r
+       \r
+       GS Serverdata #2 // IP: 192.168.178.5 Port: 12000 Patchlevel: 200\r
+       S0 => S1        0xF0 0x0E 0x00 0x30 0x08 0x00 0x01 0xB6 0x0C 0x00 0x2E 0xE0 0xC8 0x00\r
+       S0 <= S1  0xF0 0x06 0x00 0x33 0x00 0x00\r
+       \r
+       GS Serverdata #4 // Minlevel connect: 0 Minlevel see Playercount: 0 SeeServer: 0\r
+       S0 => S1  0xF0 0x0E 0x00 0x50 0x06 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r
+       S0 <= S1  0xF0 0x06 0x00 0x52 0x00 0x00\r
+\r
+       ISC Update intervall-loop\r
+       {\r
+               GS Serverdata #3 // 8 Regular players, 2 Volunteers, 0 GMs and 1 Admin online\r
+               S0 => S1        0xF0 0x0E 0x00 0x40 0x08 0x00 0x08 0x00 0x02 0x00 0x00 0x00 0x01 0x00\r
+               S0 <= S1        0xF0 0x06 0x00 0x42 0x00 0x00\r
+       }\r
+}\r
+\r
+Gameserver shutdown\r
+S0 => S1  0xF0 0x06 0x00 0xFF 0x00 0x00  // Going down now\r
+S0 <= S1  0xF0 0x06 0x00 0xF0 0x00 0x00  // Allright\r
+\r
+GS Serverdata #5 // Client identification\r
+S0 => S1  0xF0 0x08 0x00 0x60 0x02 0x00 0x2A 0x00  // Let ClientID 42 in ?\r
+S0 <= S1  0xF0 0x08 0x00 0x62 0x02 0x00 0x2A 0x00  // Yes. ClientID 42 is clean
\ No newline at end of file
diff --git a/server/docs/ISC ProtDef.txt b/server/docs/ISC ProtDef.txt
new file mode 100644 (file)
index 0000000..556cbf3
--- /dev/null
@@ -0,0 +1,81 @@
+Definition file for ISCP (Inter Server Communication Protocoll)\r
+by Namikon\r
+=========================\r
+\r
+This file defines the InterServerCommunication Protocoll (ISCP).\r
+It is used to exchange Data between Gameservers and the (Main/Master)Infoserver over\r
+an TCP connection.\r
+\r
+=======================================================================================================================\r
+ISCP Type   : TCP\r
+ISCP Version: 2\r
+Last Update : 13.12.2006 21:48 GMT+1\r
+=======================================================================================================================\r
+0xF0           ISC Protocoll\r
+<u16>          SizeOf entire packet\r
+<u8>           PacketType (Byte - Direction:Description - Data [Data format])\r
+                - "Handshake 01 - Initial connection and version check"\r
+                                                                       0x01 - GS->IS: Hello, i'm using protocoll version xxx - ISC Version (*Note1) [u16]\r
+                                               0x02 - GS<-IS: Hi. Your version is not compatible, reject. Need version xxx - ISC Version NEEDED (*Note1) [u16]\r
+                                               0x03 - GS<-IS: Hi. Your version is compatible. Need PW to connect - No data [-]\r
+\r
+                - "Handshake 02 - Connection password"\r
+                               0x10 - GS->IS: Here comes the password... - Passwort as MD5 hash (or plain?) [char/u8]\r
+                               0x11 - GS<-IS: Password wrong, denied. - No data [-]\r
+                               0x12 - GS<-IS: Password OK. You can now identify yourself - No data [-]\r
+\r
+                - "GS Serverdata Part 1: Name"\r
+                       0x20 - GS->IS: Hi, my name is XXXX - Name of Gameserver - [char/u8]\r
+                       0x21 - GS<-IS: Name invalid, cant add you. - Name of Gameserver as return - [char/u8]\r
+                       0x22 - GS<-IS: Name valid - Name of Gameserver as return - [char/u8]\r
+\r
+                - "GS Serverdata Part 2: IP, Port and version"\r
+                       0x30 - GS->IS: My IP is XXX, waiting on Port YYY for incomming connections, running at Patchlevel ZZZ (u16) - IP Port Patchlevel [X[DWORD] Y[u16] Z[u16]]\r
+                       0x31 - GS<-IS: Error; IP is already in use - IP [DWORD]\r
+                       0x32 - GS<-IS: Error; Incompatible Patchlevel - No Data [-]\r
+                       0x33 - GS<-IS: All right - No Data [-]\r
+\r
+                - "GS Serverdata Part 3: Players/Staff Online"\r
+                       0x40 - GS->IS: There are currently A Regular players, B Volunteers, C GMs and D Admins online [A[u16] B[u16] C[u16] D[u16]]\r
+                       0x41 - GS<-IS: -Reserved for further usage- (Dont think there will be any errors to report)\r
+                       0x42 - GS<-IS: All right - No Data [-]\r
+\r
+                - "GS Serverdata Part 4: Minlevel to connect to server; Minlevel to see Playercount; Minlevel to see server"\r
+                       0x50 - GS->IS: Players have to be at least Lv AA to Connect, Lv BB to see playercount and Lv CC to see me\r
+                                              - Level to connect, Level to see PlayerCount, Level to see server [A[u16] B[u16] C[u16]]\r
+                       0x51 - GS<-IS: -Reserved for further usage- (Dont think there will be any errors to report)\r
+                       0x52 - GS<-IS: All right - No Data [-]\r
+\r
+                                                               - "Common checks: Client identification"\r
+                                                                 0x60 - GS->IS: Client ID AA is trying to login. Has he passed your Login screen? [AA[u16]]\r
+                                                                 0x61 - GS<-IS: No, playerID AA is unknown. Could try to bypass loginserver [AA[u16]]\r
+                                                                 0x62 - GS<-IS: Yes, playerID AA has passed my loginscreen, let him in. [AA[u16]]\r
+                                                                 \r
+                                                               - "Infoserver control - Login"\r
+                                                                 0x90 - GS->IS: Someone is trying to login as admin in order to control infoserver over ISC - Password (md5) [u8]\r
+                                                                                                                        (This password is defined in infoserver.cfg)\r
+                                                                 0x91 - GS<-IS: Login failed, wrong PW - no data required [-]\r
+                                                                 0x92 - GS<-IS: Login success, admin commands are enabled - no data required [-]\r
+                                                                 \r
+                - "Infoserver control"\r
+                       0xA0 - GS->IS: Toogle AutoAccount creation - On(1) Off(0) [u8]\r
+                       0xA1 - GS->IS: Change level required to login - Level required to login [u16]\r
+                       0xA2 - GS->IS: Reload Infoserver configfile - no data required [-]\r
+                       0xA3 - GS->IS: Shutdown Infoserver - no data required [-]\r
+                       0xA4 - GS->IS: Hide People in OnlineList (Bitmask: Regular(1) | Volunteer(2) | GM(4) | Admin(8) => 12: Hide GM and Admin)       \r
+\r
+                - "Infoserver control - Return packets"\r
+                       0xB0 - GS<-IS: Done - No Data [-]\r
+                       0xB1 - GS<-IS: Failed; Need level admin to do that - No Data [-]\r
+\r
+                - "General returns"\r
+                       0xF0 - GS<>IS: Packet received and understood - Either no data or Checksum  [- / checksum as u8 elements]\r
+                       0xF1 - GS<>IS: Packet received but not understood. Wrong protocoll? - No Data [-]\r
+                       0xFF - GS->IS: Gameserver is going down (Not crash, normal shutdown) - No Data [-]\r
+                       \r
+<u16>           Bytes to follow (If no data is send, 0x00)\r
+<u8[]>          Data\r
+\r
+\r
+\r
+(*Note1) This is <<NOT>> the patchlevel!!! Its the version of the ISC Protocoll. Can be found in isc.h
\ No newline at end of file
diff --git a/server/src/Makefile b/server/src/Makefile
new file mode 100644 (file)
index 0000000..5741089
--- /dev/null
@@ -0,0 +1,198 @@
+#
+# TinNS main Makefile
+#
+# Adapted by Hammag from the Makefile system for Linux kernel.
+#
+
+# NOTA: Be carefull no to put extra spaces at EOL when specifing dir path !
+
+# Config options
+export CONFIG_GAMEMONKEY := n
+
+# Debug mode compilation option
+# Uncommenting the following line will activate degub symbols generation
+# and inhibit binries stripping
+#DO_DEBUG = y
+
+# Do not change TOPDIR definiton
+TOPDIR := $(shell /bin/pwd)
+
+# Source code subdirs (libraries directories excluded)
+SUBDIRS                = patch info game
+
+# Shortcut targets (when you dont want to make all)
+#  generic form is as follows, with tinnslibs rule in first if needed
+#SHORTCUT_TARGETn :=[name] : tinnslibs _dir_[sub_dir]
+# Implemented for n=0..9 atm. See at the end of the file if more needed
+
+SHORTCUT_TARGET0 :=libs : min_needed
+SHORTCUT_TARGET1 :=gameserver : min_needed _dir_game
+SHORTCUT_TARGET2 :=infoserver : min_needed _dir_info
+SHORTCUT_TARGET3 :=patchserver : min_needed _dir_patch
+
+# Directory where we want to build executables in
+BINDEST                = $(TOPDIR)/..
+
+# Commun include files stuff
+HPATH          = $(TOPDIR)/include
+FINDHPATH      = $(HPATH)
+#FINDHPATH     = $(HPATH) $(HPATH)/netcode $(HPATH)/console $(HPATH)/config
+#FINDHPATH     = $(HPATH) $(TOPDIR)/game/include $(TOPDIR)/game/decoder
+
+# TinNS libaries stuff
+LIBS           = $(TOPDIR)/lib
+LIBSSRC        = common
+
+# Common CFLAGS for all source tree
+CPPFLAGS := -I$(HPATH)
+CXXFLAGS := $(CPPFLAGS) -pedantic -W -Wall -Wno-long-long -O3 \
+   -D_GNU_SOURCE -D_THREAD_SAFE -D_REENTRANT
+#CXXFLAGS += -march=$(shell arch)
+#CXXFLAGS += -Werror
+
+# Common Linker Flags for all source tree (partial linking with LD (ld))
+LDFLAGS := -r 
+
+# Common Linker Flags for all source tree (final linking with CXX (g++))
+LINKFLAGS := -L$(LIBS)
+
+# specific files to be removed with 'make clean'
+CLEAN_FILES = $(BINDEST)/gameserver $(BINDEST)/infoserver \
+  $(BINDEST)/patchserver
+
+# defines where Source tarball and Binaries tarball will be put (for dev use)
+# Use ABSOLUTE path
+TARBALLS_DEST = ~
+
+# Include local Makefile options/override if needed (for dev use only)
+-include options.local
+
+#
+# Install stuf not done yet
+#
+# INSTALL_PATH := $TOP_DIR/..
+# export INSTALL_PATH
+
+
+#####################################################
+#***************************************************#
+# No further config should be needed after this line
+#  for usual operations
+#***************************************************#
+ifdef DO_DEBUG
+ CXXFLAGS += -O0 -ggdb
+endif
+
+CFLAGS         := CXXFLAGS
+
+HOSTCC         = gcc
+HOSTCFLAGS     = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+
+#
+# Include the make variables (CC, etc...)
+#
+CROSS_COMPILE  =
+
+CC             = $(CROSS_COMPILE)gcc
+CXX            = $(CROSS_COMPILE)g++
+LD             = $(CROSS_COMPILE)ld
+AR             = $(CROSS_COMPILE)ar
+STRIP          = $(CROSS_COMPILE)strip
+PERL           = perl
+DEPDIR         = .dep
+TOOLS = $(TOPDIR)/dev-tools
+export TOPDIR HPATH HOSTCC HOSTCFLAGS CROSS_COMPILE LD CC \
+   CXX AR STRIP MAKE CPPFLAGS CXXFLAGS CFLAGS LDFLAGS LINKFLAGS
+export BINDEST LIBS DEPDIR TOOLS DO_DEBUG
+#
+#
+#
+ALLSUBDIRS     = $(LIBSSRC) $(SUBDIRS)
+
+# directories removed with 'make clean'
+#CLEAN_DIRS = 
+
+# files removed with 'make cleaner'
+CLEANER_FILES= \
+       scripts/lxdialog/*.o scripts/lxdialog/lxdialog \
+       .hdepend dev-tools/cleandepfile \
+
+# directories removed with 'make cleaner'
+#CLEANER_DIRS = \
+       include/config
+
+
+############################################
+# Rules Start
+#
+all:   do-it-all
+
+do-it-all: min_needed tinnssubdirs
+
+min_needed: dev_tools svnrev tinnslibs
+
+#
+#
+#
+dev_tools: dummy
+       $(MAKE) -C $(TOOLS)
+  
+tinnslibs : $(patsubst %, _ldir_%, $(LIBSSRC))
+$(patsubst %, _ldir_%, $(LIBSSRC)) : dummy 
+       $(MAKE) -C $(patsubst _ldir_%, %, $@)
+
+tinnssubdirs: $(patsubst %, _dir_%, $(SUBDIRS)) tinnslibs
+$(patsubst %, _dir_%, $(SUBDIRS)) : dummy 
+       $(MAKE) -C $(patsubst _dir_%, %, $@)
+
+svnrev:
+       @$(TOOLS)/setsvnrev $(TOPDIR) $(HPATH)/svnrevision.h
+
+clean: 
+       find . \( -name '*.[oas]' -o -name core -o -name '.*.flags' \) -type f -print \
+               | grep -v lxdialog/ | xargs rm -f
+       rm -f $(CLEAN_FILES) $(BINDEST)/.*.flags
+       rm -rf $(CLEAN_DIRS)
+
+cleaner: clean 
+       find . \( -size 0 -o -name .depend -o -name .no_msg_stop \) -type f -print | xargs rm -f
+       find . -name .dep -type d -print | xargs rm -Rf
+       rm -f $(CLEANER_FILES)
+       rm -rf $(CLEANER_DIRS)
+
+distclean: cleaner
+       rm -f core `find . \( -not -type d \) -and \
+               \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
+               -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
+               -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -type f -print` 
+
+backup: cleaner
+       cd .. && tar cf - src/ | gzip -9 > tinns-svnrev-`svnversion .`-backup.gz
+       sync
+
+sourcetar:
+       @$(TOOLS)/make-src-tarball $(TARBALLS_DEST) $(HPATH)/svnrevision.h
+
+bintar: do-it-all dummy
+       @$(TOOLS)/make-bin-tarball $(TARBALLS_DEST) $(HPATH)/svnrevision.h $(BINDEST)
+       
+sums:
+       find . -type f -print | sort | xargs sum > .SUMS
+
+depend dep: 
+       @echo This rule is not used anymore. Just do make
+
+
+include Rules.make
+
+$(SHORTCUT_TARGET0)
+$(SHORTCUT_TARGET1)
+$(SHORTCUT_TARGET2)
+$(SHORTCUT_TARGET3)
+$(SHORTCUT_TARGET4)
+$(SHORTCUT_TARGET5)
+$(SHORTCUT_TARGET6)
+$(SHORTCUT_TARGET7)
+$(SHORTCUT_TARGET8)
+$(SHORTCUT_TARGET9)
+
diff --git a/server/src/Rules.make b/server/src/Rules.make
new file mode 100644 (file)
index 0000000..1d8d1e4
--- /dev/null
@@ -0,0 +1,226 @@
+#
+# This file contains rules which are shared between multiple Makefiles.
+#
+# Adapted by Hammag from the Makefile system for Linux kernel.
+#
+#####################################################
+#***************************************************#
+# This file is not intended to be modified
+#***************************************************#
+
+#
+# False targets.
+#
+.PHONY: dummy
+
+#
+# Special variables which should not be exported
+#
+unexport EXTRA_CXXFLAGS
+unexport EXTRA_LINKFLAGS
+unexport EXTRA_LDFLAGS
+unexport EXTRA_ARFLAGS
+unexport SUBDIRS
+unexport SUB_DIRS
+unexport ALL_SUB_DIRS
+unexport B_TARGET
+unexport B_REALTARGET
+unexport O_TARGET
+unexport L_TARGET
+unexport L_REALTARGET
+
+unexport obj-y
+unexport obj-n
+unexport obj-
+unexport subdir-y
+unexport subdir-n
+unexport subdir-
+
+comma  := ,
+
+
+SUB_DIRS       := $(subdir-y)
+#ALL_SUB_DIRS  := $(sort $(subdir-y) $(subdir-n) $(subdir-))
+ALL_SUB_DIRS   := $(sort $(subdir-y))
+ifdef B_TARGET
+   ifdef BINDEST
+      B_REALTARGET := $(strip $(BINDEST))/$(B_TARGET)
+   else
+      B_REALTARGET := $(B_TARGET)   
+   endif
+endif
+L_REALTARGET   := $(patsubst %,$(LIBS)/lib%.a,$(L_TARGET))
+ALL_TARGETS    := $(B_REALTARGET) $(O_TARGET) $(L_REALTARGET)
+
+#
+# Get things started.
+#
+first_rule: sub_dirs
+       $(if $(strip $(ALL_TARGETS)),@$(MAKE) --no-print-directory all_targets,)
+
+#
+# Common rules
+#
+%.o: %.cpp
+       @if [ ! -d .dep ]; then mkdir .dep ; fi
+       $(CXX) -MD -MP $(CXXFLAGS) $(EXTRA_CXXFLAGS) $(CXXFLAGS_$@) -c $< -o $@
+       @ ( \
+           $(TOOLS)/cleandepfile < $(@:.o=.d) > $(DEPDIR)/$(@:.o=.dep); \
+           rm -f $(@:.o=.d); \
+       )
+       @ ( \
+           echo 'ifeq ($(strip $(subst $(comma),:,$(CXXFLAGS) $(EXTRA_CXXFLAGS) $(CXXFLAGS_$@))),$$(strip $$(subst $$(comma),:,$$(CXXFLAGS) $$(EXTRA_CXXFLAGS) $$(CXXFLAGS_$@))))' ; \
+           echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \
+           echo 'endif' \
+       ) > $(dir $@)/.$(notdir $@).flags
+
+#
+#
+#
+all_targets: $(ALL_TARGETS)
+
+#
+# Rule to compile a set of .o files into one executable file
+#
+ifdef B_REALTARGET
+
+FULLEXT_LINKFLAGS := $(patsubst %,-l%,$(LINK_TINNSLIBS)) $(EXTRA_LINKFLAGS)
+LIBDEP := $(patsubst %,$(LIBS)/lib%.a,$(LINK_TINNSLIBS))
+
+$(B_REALTARGET): $(obj-y) $(LIBDEP)
+       @rm -f $@
+    ifneq "$(strip $(obj-y))" ""
+       $(CXX) -o $@ $(filter $(obj-y), $^) $(LINKFLAGS) $(FULLEXT_LINKFLAGS)
+        ifndef DO_DEBUG
+          @$(STRIP) $@
+        endif
+    else
+       @echo No object files to build $@ !!!
+    endif
+       @ ( \
+           echo 'ifeq ($(strip $(subst $(comma),:,$(LINKFLAGS) $(FULLEXT_LINKFLAGS) $(obj-y))),$$(strip $$(subst $$(comma),:,$$(LINKFLAGS) $$(FULLEXT_LINKFLAGS) $$(obj-y))))' ; \
+           echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \
+           echo 'endif' \
+       ) > $(dir $@)/.$(notdir $@).flags
+endif # B_REALTARGET
+
+#
+# Rule to compile a set of .o files into one .o file
+#
+ifdef O_TARGET
+$(O_TARGET): $(obj-y)
+       rm -f $@
+    ifneq "$(strip $(obj-y))" ""
+       $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) -o $@ $(filter $(obj-y), $^)
+    else
+       @echo No object files to build $@ !!!
+#      $(AR) rcs $@
+    endif
+       @ ( \
+           echo 'ifeq ($(strip $(subst $(comma),:,$(LDFLAGS) $(EXTRA_LDFLAGS) $(obj-y))),$$(strip $$(subst $$(comma),:,$$(LDFLAGS) $$(EXTRA_LDFLAGS) $$(obj-y))))' ; \
+           echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \
+           echo 'endif' \
+       ) > $(dir $@)/.$(notdir $@).flags
+endif # O_TARGET
+
+#
+# Rule to compile a set of .o files into one .a file, creating,
+#  adding or updating it
+#
+ifdef L_REALTARGET
+$(L_REALTARGET): $(obj-y)
+#      rm -f $@
+       @ if [ ! -d $(LIBS) ]; then mkdir $(LIBS); fi
+       $(if $(filter $(obj-y),$?),$(AR) $(EXTRA_ARFLAGS) rcs $@ $(filter $(obj-y),$?),)
+       @ ( \
+           echo 'ifeq ($(strip $(subst $(comma),:,$(EXTRA_ARFLAGS) $(obj-y))),$$(strip $$(subst $$(comma),:,$$(EXTRA_ARFLAGS) $$(obj-y))))' ; \
+           echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \
+           echo 'endif' \
+       ) > $(dir $@)/.$(notdir $@).flags
+endif #L_REALTARGET
+
+#
+# This make dependencies quickly
+#
+fastdep: dummy
+       @$(TOPDIR)/scripts/mkdep $(CXXFLAGS) $(EXTRA_CXXFLAGS) -- $(wildcard *.h) $(wildcard *.cpp) > .depend
+ifdef ALL_SUB_DIRS
+       @$(MAKE) $(patsubst %,_sfdep_%,$(ALL_SUB_DIRS)) _FASTDEP_ALL_SUB_DIRS="$(ALL_SUB_DIRS)"
+endif
+
+ifdef _FASTDEP_ALL_SUB_DIRS
+$(patsubst %,_sfdep_%,$(_FASTDEP_ALL_SUB_DIRS)):
+       @$(MAKE) -C $(patsubst _sfdep_%,%,$@) fastdep
+endif
+
+       
+#
+# A rule to make subdirectories
+#
+subdir-list = $(sort $(patsubst %,_subdir_%,$(SUB_DIRS)))
+sub_dirs: dummy $(subdir-list)
+
+ifdef SUB_DIRS
+$(subdir-list) : dummy
+       $(MAKE) -C $(patsubst _subdir_%,%,$@)
+endif
+
+#
+# A rule to do nothing
+#
+dummy:
+#
+# This is useful for testing
+#
+script:
+       $(SCRIPT)
+
+dep: fastdep 
+
+#
+# include dependency files if they exist
+#
+ifneq ($(wildcard $(DEPDIR)),)
+   ifneq ($(wildcard $(obj-y)),)
+      -include $(patsubst %.o,$(DEPDIR)/%.dep,$(obj-y))
+   endif
+endif
+
+ifneq ($(wildcard $(TOPDIR)/.hdepend),)
+include $(TOPDIR)/.hdepend
+endif
+
+#
+# Find files whose flags have changed and force recompilation.
+# For safety, this works in the converse direction:
+#   every file is forced, except those whose flags are positively up-to-date.
+#
+FILES_FLAGS_UP_TO_DATE :=
+
+# For use in expunging commas from flags, which mung our checking.
+comma = ,
+
+FILES_FLAGS_EXIST := $(wildcard .*.flags)
+ifdef B_TARGET
+   ifneq ($(B_REALTARGET),$(B_TARGET))
+      FILES_FLAGS_EXIST += $(wildcard $(dir $(B_REALTARGET))/.$(notdir $(B_REALTARGET)).flags)
+      FILESTEST := $(dir $(B_REALTARGET))/.$(notdir $(B_REALTARGET)).flags
+   endif
+endif
+ifdef L_REALTARGET
+   FILES_FLAGS_EXIST += $(wildcard $(dir $(L_REALTARGET))/.$(notdir $(L_REALTARGET)).flags)
+endif
+
+ifneq ($(FILES_FLAGS_EXIST),)
+include $(FILES_FLAGS_EXIST)
+endif
+
+FILES_FLAGS_CHANGED := $(strip \
+    $(filter-out $(FILES_FLAGS_UP_TO_DATE), \
+       $(obj-y) $(ALL_TARGETS) \
+       ))
+
+ifneq ($(FILES_FLAGS_CHANGED),)
+$(FILES_FLAGS_CHANGED): dummy
+endif
+
diff --git a/server/src/common/Makefile b/server/src/common/Makefile
new file mode 100644 (file)
index 0000000..f9ed1c9
--- /dev/null
@@ -0,0 +1,83 @@
+#
+# TinNS per-directory Makefile
+#
+# Adapted by Hammag from the Makefile system for Linux kernel.
+#
+# 14 Sep 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+# 
+
+######################################################
+# Target for this directory and its sub-dirs
+######################################################
+# Case 1 : target is an executable named as defined
+#B_TARGET := testor2 
+
+# Case 2 : target is a TinNS lib name
+#  (use short name, as in -l linker option) 
+#L_TARGET := tinns
+
+# Case 3 (usual): objects shall be made available to the parent dir
+#  The following line will set that automatically 
+# (Should match dir name + .o suffix)
+#O_TARGET := $(addsuffix .o,$(notdir $(shell /bin/pwd)))
+# Manualy define this only if you need to force the compiled obj name
+#O_TARGET := game.o
+
+
+######################################################
+# Local flags
+######################################################
+# local dir CXX Flags
+#EXTRA_CXXFLAGS := -I/usr/include/mysql
+
+# per-object CXX Flags
+#CXXFLAGS_funcdef2.o := -g
+
+# local dir Linker Flags (for intermediate .o linking)
+#EXTRA_LDFLAGS := 
+
+# any tinns Lib used (short name, as in -l linker option)
+#LINK_TINNSLIBS := tinns
+
+# local dir Linker Flags (for final executable linking)
+#EXTRA_LINKFLAGS := -lrt -lpthread -lz -lm -lcrypt -L"/usr/lib/mysql" -lmysqlclient
+
+
+#####################################################
+# Subdirectories
+#####################################################
+subdir-y := config console filesystem misc netcode regex 
+subdir-$(CONFIG_GAMEMONKEY)    += gamemonkey
+
+
+#####################################################
+#***************************************************#
+# No further config should be needed after this line
+#***************************************************#
+ifdef TOPDIR
+
+# build list of objects ib loca ldir
+obj-y := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
+# add final object from each subdir
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+
+include $(TOPDIR)/Rules.make
+
+else #TOPDIR undef, Makefile called from non-top dir
+
+# Memorize the first calling dir in case we wanted to
+# lauch local actions from top Makefile
+  ifndef FIRSTDIR
+    FIRSTDIR :=$(CURDIR)
+    export FIRSTDIR
+  endif
+
+uptoparent : 
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+.DEFAULT :
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+endif #TOPDIR
+
diff --git a/server/src/common/config/Makefile b/server/src/common/config/Makefile
new file mode 100644 (file)
index 0000000..5fb25e9
--- /dev/null
@@ -0,0 +1,83 @@
+#
+# TinNS per-directory Makefile
+#
+# Adapted by Hammag from the Makefile system for Linux kernel.
+#
+# 14 Sep 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+# 
+
+######################################################
+# Target for this directory and its sub-dirs
+######################################################
+# Case 1 : target is an executable named as defined
+#B_TARGET := testor2 
+
+# Case 2 : target is a TinNS lib name
+#  (use short name, as in -l linker option) 
+L_TARGET := tinns
+
+# Case 3 (usual): objects shall be made available to the parent dir
+#  The following line will set that automatically 
+# (Should match dir name + .o suffix)
+#O_TARGET := $(addsuffix .o,$(notdir $(shell /bin/pwd)))
+# Manualy define this only if you need to force the compiled obj name
+#O_TARGET := game.o
+
+
+######################################################
+# Local flags
+######################################################
+# local dir CXX Flags
+#EXTRA_CXXFLAGS := -I/usr/include/mysql
+
+# per-object CXX Flags
+#CXXFLAGS_funcdef2.o := -g
+
+# local dir Linker Flags (for intermediate .o linking)
+#EXTRA_LDFLAGS := 
+
+# any tinns Lib used (short name, as in -l linker option)
+#LINK_TINNSLIBS := tinns
+
+# local dir Linker Flags (for final executable linking)
+#EXTRA_LINKFLAGS := -lrt -lpthread -lz -lm -lcrypt -L"/usr/lib/mysql" -lmysqlclient
+
+
+#####################################################
+# Subdirectories
+#####################################################
+#subdir-y := def 
+#subdir-$(CONFIG_GAMEMONKEY)   += gamemonkey
+
+
+#####################################################
+#***************************************************#
+# No further config should be needed after this line
+#***************************************************#
+ifdef TOPDIR
+
+# build list of objects ib loca ldir
+obj-y := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
+# add final object from each subdir
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+
+include $(TOPDIR)/Rules.make
+
+else #TOPDIR undef, Makefile called from non-top dir
+
+# Memorize the first calling dir in case we wanted to
+# lauch local actions from top Makefile
+  ifndef FIRSTDIR
+    FIRSTDIR :=$(CURDIR)
+    export FIRSTDIR
+  endif
+
+uptoparent : 
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+.DEFAULT :
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+endif #TOPDIR
+
diff --git a/server/src/common/config/config.cpp b/server/src/common/config/config.cpp
new file mode 100644 (file)
index 0000000..6f22658
--- /dev/null
@@ -0,0 +1,239 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+        config.cpp\r
+\r
+        Authors:\r
+        - Akiko\r
+        - Namikon\r
+        - someone else?\r
+\r
+        MODIFIED: Unknown date / Unknown author\r
+        REASON: - initial release by unknown\r
+        MODIFIED: 23 Dec 2005 Namikon\r
+        REASON: - Added GPL\r
+        MODIFIED: 07 Jan 2006 Namikon\r
+        REASON: - Started to replace XML with CFG files        \r
+        MODIFIED: 05 Aug 2006 Hammag\r
+        REASON: - changed LoadOptions() implementation.\r
+                  This should make addition of new options really easier, as well as config syntax error tracking\r
+                  See config.h for info\r
+        MODIFIED: 27 Aug 2006 Hammag\r
+        REASON: - Modified LoadOption() methode to make it generic,\r
+                    with an options template and the config file as arguments\r
+                - Removed the ConfigTemplate that was used for gameserver only.\r
+                - Removed old unused code\r
+        MODIFIED: 25 Jun 2007 Hammag\r
+        REASON: - Added include support\r
+                - Now use PCRE RegEx instead of "strtok", enabling rentrance and removing\r
+                  potential issues.\r
+                - Added GetOption & GetOptionInt with const std::string parameter\r
+                - Fixed a bug in EOF detection in the main file reading loop\r
+*/\r
+\r
+#include "main.h"\r
+\r
+\r
+PConfig::PConfig()\r
+{\r
+  mOptValRegEx = new RegEx("^\\s*([[:graph:]]+)\\s*=\\s*(.+?)\\s*$", PCRE_CASELESS);\r
+  mIncludeRegEx = new RegEx("^\\s*include\\s+([[:graph:]]+)\\s*$", PCRE_CASELESS);\r
+}\r
+\r
+PConfig::~PConfig()\r
+{\r
+  delete mOptValRegEx;\r
+  delete mIncludeRegEx;\r
+}\r
+\r
+bool PConfig::LoadOptions(const char* nConfigTemplate[][2], const char* nConfigFile, int nDepth)\r
+{\r
+       FILE *ConfigFile;\r
+       char line[255];\r
+       std::string Opt, Val;\r
+       //int numOptions = 0;\r
+       int i;\r
+       bool Found;\r
+       bool NoError = true;\r
+  \r
+       ConfigFile = fopen(nConfigFile,"r");\r
+\r
+       if(!ConfigFile)\r
+       {\r
+           Console->Print("%s Cant open file \"%s\"", Console->ColorText(RED, BLACK, "[Error]"), nConfigFile);\r
+        return false;\r
+       }\r
+\r
+  if(nDepth)\r
+    Console->Print("%s Including file %s (nesting level %d)", Console->ColorText(GREEN, BLACK, "[Info]"), nConfigFile, nDepth);\r
+  else\r
+         Console->Print("%s Loading configuration file %s", Console->ColorText(GREEN, BLACK, "[Info]"), nConfigFile);\r
\r
+       while(!feof(ConfigFile) && fgets(line, 255, ConfigFile))\r
+       {\r
+           //Console->Print("LINE: '%s'", line);\r
+           if (line[0] == '/' && line[1] == '/')\r
+        continue;\r
+           \r
+           if(mOptValRegEx->Search(line))\r
+      {\r
+        Opt = mOptValRegEx->Match(1);\r
+        Val = mOptValRegEx->Match(2);\r
+        //Console->Print("'%s'='%s'", Opt.c_str(), Val.c_str());\r
+\r
+        Trim(&Opt);\r
+        Trim(&Val);\r
+        //Console->Print("'%s'='%s'", Opt.c_str(), Val.c_str());\r
+      }\r
+      else if(mIncludeRegEx->Search(line))\r
+      {\r
+        if(nDepth < CONFIG_MAXDEPTH)\r
+        {\r
+          std::string TargetName = mIncludeRegEx->Match(1);\r
+          std::string StartName = nConfigFile;\r
+          int BasenamePos = StartName.rfind("/");\r
+          if(BasenamePos > 0)\r
+            TargetName = StartName.substr(0, BasenamePos) + "/" + TargetName;\r
+         \r
+          NoError = LoadOptions(nConfigTemplate, TargetName.c_str(), nDepth+1) && NoError;\r
+          continue;\r
+        }\r
+        else\r
+        {\r
+          Console->Print("%s Max nesting level (%d) reached. Can't include configuration file %s", Console->ColorText(RED, BLACK, "[Error]"), CONFIG_MAXDEPTH,mIncludeRegEx->Match(1));\r
+          NoError = false;\r
+        }\r
+      }\r
+      else\r
+      {\r
+          continue;\r
+      }\r
+\r
+      i = 0;\r
+      Found = false;      \r
+      while(!Found && (nConfigTemplate[i][0][0] != '\0'))\r
+      {\r
+        if(!strcmp(Opt.c_str(), nConfigTemplate[i++][0]))\r
+        {\r
+          Found = true;\r
+          break;\r
+        }\r
+      }\r
+\r
+           if(!Opt.empty() && !Val.empty())\r
+           {\r
+               //Console->Print("#%d [%s] [%s]", numOptions, Opt.c_str(), Val.c_str());\r
+               if (Found)\r
+               {\r
+                 if (GetOption(Opt) != "")\r
+                 {\r
+                   Console->Print("%s trying to set option %s more than once (old value '%s' - new value '%s' ignored)", Console->ColorText(YELLOW, BLACK, "[Warning]"), Opt.c_str(), GetOption(Opt).c_str(), Val.c_str());\r
+                 }\r
+                 else\r
+                 {\r
+                   //Console->Print(GREEN, BLACK, "New option %s set to %s", Opt.c_str(), Val.c_str());\r
+              mOptions.insert(std::make_pair(Opt, Val));\r
+            }\r
+          }\r
+          else\r
+          {\r
+             Console->Print("%s option %s unknow and ignored (value %s)", Console->ColorText(YELLOW, BLACK, "[Warning]"), Opt.c_str(), Val.c_str());\r
+          }\r
+           }\r
+       }\r
+\r
+  // Now check for completeness and set default values when needed and available\r
+  if(!nDepth) // Check only if we're at top level (ie. not in an included file)\r
+  {\r
+    i = 0;      \r
+    while(nConfigTemplate[i][0][0] != '\0')\r
+    {\r
+      if (GetOption(nConfigTemplate[i][0]) == "")\r
+      {\r
+        if(nConfigTemplate[i][1][0] == '\0')\r
+        {\r
+          Console->Print("%s required option %s missing from config file", Console->ColorText(RED, BLACK, "[Error]"), nConfigTemplate[i][0]);\r
+          NoError = false;\r
+        }\r
+        else\r
+        {\r
+          Console->Print("%s using default value %s for option %s", Console->ColorText(GREEN, BLACK, "[Info]"), nConfigTemplate[i][1], nConfigTemplate[i][0]);\r
+          mOptions.insert(std::make_pair(nConfigTemplate[i][0], nConfigTemplate[i][1]));\r
+        }\r
+      }\r
+      ++i;\r
+    }\r
+  }\r
+\r
+  if (NoError)\r
+  {\r
+         if(nDepth)\r
+           Console->Print("%s file included", Console->ColorText(GREEN, BLACK, "[Info]") );\r
+         else\r
+      Console->Print("%s Configuration file loaded", Console->ColorText(GREEN, BLACK, "[Success]") );\r
+  }\r
+  else\r
+    Console->Print(RED, BLACK, "[Error] Fatal errors found in configuration file");\r
+       \r
+       return (NoError);\r
+}\r
+\r
+const std::string &PConfig::GetOption(const std::string Name) const\r
+{\r
+       static std::string NullString = "";\r
+       OptionsMap::const_iterator i = mOptions.find(Name);\r
+       if(i!=mOptions.end())\r
+               return i->second;\r
+\r
+       return NullString;\r
+}\r
+\r
+int PConfig::GetOptionInt(const std::string Name) const\r
+{\r
+       OptionsMap::const_iterator i = mOptions.find(Name);\r
+       if(i!=mOptions.end())\r
+               return atoi(i->second.c_str());\r
+\r
+       return 0;\r
+}\r
+/*  \r
+const std::string &PConfig::GetOption(const char *Name) const\r
+{\r
+       static std::string NullString = "";\r
+       OptionsMap::const_iterator i = mOptions.find(Name);\r
+       if(i!=mOptions.end())\r
+               return i->second;\r
+\r
+       return NullString;\r
+}\r
+\r
+int PConfig::GetOptionInt(const char *Name) const\r
+{\r
+       OptionsMap::const_iterator i = mOptions.find(Name);\r
+       if(i!=mOptions.end())\r
+               return std::atoi(i->second.c_str());\r
+\r
+       return 0;\r
+}\r
+*/\r
diff --git a/server/src/common/config/main.h b/server/src/common/config/main.h
new file mode 100644 (file)
index 0000000..e00f8be
--- /dev/null
@@ -0,0 +1,53 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       main.h - main include file, contains all needed includes and important definitions\r
+\r
+       MODIFIED: 27 Aug 2006 Hammag\r
+       REASON: - created       \r
+         \r
+*/\r
+\r
+#ifndef MAIN_H\r
+#define MAIN_H\r
+\r
+//#include "version.h"\r
+\r
+//basic includes\r
+#include "external.h"\r
+\r
+//tinns includes\r
+#include "types.h"\r
+#include "config.h"\r
+\r
+#include "console.h"\r
+#include "misc.h"\r
+\r
+using namespace std;\r
+\r
+// Better change that to a static members\r
+extern class PConsole* Console;\r
+\r
+#endif\r
+\r
diff --git a/server/src/common/console/Makefile b/server/src/common/console/Makefile
new file mode 100644 (file)
index 0000000..5fb25e9
--- /dev/null
@@ -0,0 +1,83 @@
+#
+# TinNS per-directory Makefile
+#
+# Adapted by Hammag from the Makefile system for Linux kernel.
+#
+# 14 Sep 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+# 
+
+######################################################
+# Target for this directory and its sub-dirs
+######################################################
+# Case 1 : target is an executable named as defined
+#B_TARGET := testor2 
+
+# Case 2 : target is a TinNS lib name
+#  (use short name, as in -l linker option) 
+L_TARGET := tinns
+
+# Case 3 (usual): objects shall be made available to the parent dir
+#  The following line will set that automatically 
+# (Should match dir name + .o suffix)
+#O_TARGET := $(addsuffix .o,$(notdir $(shell /bin/pwd)))
+# Manualy define this only if you need to force the compiled obj name
+#O_TARGET := game.o
+
+
+######################################################
+# Local flags
+######################################################
+# local dir CXX Flags
+#EXTRA_CXXFLAGS := -I/usr/include/mysql
+
+# per-object CXX Flags
+#CXXFLAGS_funcdef2.o := -g
+
+# local dir Linker Flags (for intermediate .o linking)
+#EXTRA_LDFLAGS := 
+
+# any tinns Lib used (short name, as in -l linker option)
+#LINK_TINNSLIBS := tinns
+
+# local dir Linker Flags (for final executable linking)
+#EXTRA_LINKFLAGS := -lrt -lpthread -lz -lm -lcrypt -L"/usr/lib/mysql" -lmysqlclient
+
+
+#####################################################
+# Subdirectories
+#####################################################
+#subdir-y := def 
+#subdir-$(CONFIG_GAMEMONKEY)   += gamemonkey
+
+
+#####################################################
+#***************************************************#
+# No further config should be needed after this line
+#***************************************************#
+ifdef TOPDIR
+
+# build list of objects ib loca ldir
+obj-y := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
+# add final object from each subdir
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+
+include $(TOPDIR)/Rules.make
+
+else #TOPDIR undef, Makefile called from non-top dir
+
+# Memorize the first calling dir in case we wanted to
+# lauch local actions from top Makefile
+  ifndef FIRSTDIR
+    FIRSTDIR :=$(CURDIR)
+    export FIRSTDIR
+  endif
+
+uptoparent : 
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+.DEFAULT :
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+endif #TOPDIR
+
diff --git a/server/src/common/console/console.cpp b/server/src/common/console/console.cpp
new file mode 100644 (file)
index 0000000..3c9d407
--- /dev/null
@@ -0,0 +1,191 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+        console.cpp\r
+\r
+        Authors:\r
+        - Akiko\r
+        - Namikon\r
+        - someone else?\r
+\r
+        MODIFIED: Unknown date / Unknown author\r
+        REASON: - initial release by unknown\r
+\r
+        MODIFIED: 25 Dec 2005 Namikon\r
+        REASON: - Added GPL\r
+        MODIFIED: 06 Jan 2006 Namikon\r
+        REASON: - Added Print() function for colored console output\r
+                - Added ColorText() to give selectable parts of an output another color\r
+                - Added LPrint() to print like eAthena does\r
+                  Dont forget to use LClose() after using LPrint :)\r
+        MODIFIED: 26 Aug 2006 Hammag\r
+        REASON: - Added nLogFile as a constructor parameter, to make the class generic             \r
+                - Removed Console-> in Console->ColorText(...) in PConsole::~PConsole()\r
+*/\r
+\r
+#include "main.h"\r
+\r
+PConsole::PConsole(const char *nLogFile)\r
+{\r
+       std::time(&mLastLogTime);\r
+       mLogFile.open(nLogFile);\r
+}\r
+\r
+PConsole::~PConsole()\r
+{\r
+    Print("%s Shutdown complete", ColorText(GREEN, BLACK, "[Done]"));\r
+       mLogFile.close();\r
+}\r
+\r
+void PConsole::Print(const char *Fmt, ...)\r
+{\r
+       static char Str[2048];\r
+       va_list args;\r
+       va_start(args, Fmt);\r
+       vsnprintf(Str, 2047, Fmt, args);\r
+       va_end(args);\r
+\r
+       std::time(&mLastLogTime);\r
+       std::tm *now = std::localtime(&mLastLogTime);\r
+\r
+       static char datestr[64];\r
+       std::snprintf(datestr, 64, "%02i/%02i %02i:%02i:%02i ", now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);\r
+       std::stringstream str;\r
+       str << datestr << Str << std::endl;\r
+\r
+       std::printf("%s", str.str().c_str());\r
+       mLogFile << str.str();\r
+       mLogFile.flush();\r
+}\r
+\r
+void PConsole::Print(COLORS foreground, COLORS background, const char *Fmt, ...)\r
+{\r
+       static char Str[2048];\r
+       va_list args;\r
+       va_start(args, Fmt);\r
+       vsnprintf(Str, 2047, Fmt, args);\r
+       va_end(args);\r
+\r
+    char c_color[13];\r
+    char c_reset[13];\r
+    std::snprintf(c_color, 13, "%c[%d;%d;%dm", 0x1B, 0, foreground + 30, background + 40);\r
+    std::snprintf(c_reset, 13, "%c[%d;%d;%dm", 0x1B, 0, 37, 40);\r
+\r
+       std::time(&mLastLogTime);\r
+       std::tm *now = std::localtime(&mLastLogTime);\r
+\r
+       static char datestr[64];\r
+       std::snprintf(datestr, 64, "%02i/%02i %02i:%02i:%02i ", now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);\r
+       std::stringstream str;\r
+       str << datestr << c_color << Str << c_reset << std::endl;\r
+\r
+       std::printf("%s", str.str().c_str());\r
+       mLogFile << str.str();\r
+\r
+       mLogFile.flush();\r
+}\r
+\r
+char *PConsole::ColorText(COLORS foreground, COLORS background, const char *Fmt, ...)\r
+{\r
+       static char Str[2048];\r
+       va_list args;\r
+       va_start(args, Fmt);\r
+       vsnprintf(Str, 2047, Fmt, args);\r
+       va_end(args);\r
+\r
+  char c_color[13];\r
+  char c_reset[13];\r
+  std::snprintf(c_color, 13, "%c[%d;%d;%dm", 0x1B, 0, foreground + 30, background + 40);\r
+  std::snprintf(c_reset, 13, "%c[%d;%d;%dm", 0x1B, 0, 37, 40);\r
+\r
+  static char returnbuffer[2048];\r
+       strncpy (returnbuffer, c_color, 2048);\r
+       strncat (returnbuffer, Str, 2047 - strlen(returnbuffer));\r
+       strncat (returnbuffer, c_reset, 2047 - strlen(returnbuffer));\r
+\r
+       return returnbuffer;\r
+}\r
+\r
+void PConsole::LPrint(const char *Fmt, ...)\r
+{\r
+       static char Str[2048];\r
+       va_list args;\r
+       va_start(args, Fmt);\r
+       vsnprintf(Str, 2047, Fmt, args);\r
+       va_end(args);\r
+\r
+       std::time(&mLastLogTime);\r
+       std::tm *now = std::localtime(&mLastLogTime);\r
+\r
+       static char datestr[64];\r
+       std::snprintf(datestr, 64, "%02i/%02i %02i:%02i:%02i ", now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);\r
+       std::stringstream str;\r
+       str << datestr << Str;\r
+\r
+       std::printf("%s", str.str().c_str());\r
+       mLogFile << str.str();\r
+       mLogFile.flush();\r
+}\r
+\r
+void PConsole::LPrint(COLORS foreground, COLORS background, const char *Fmt, ...)\r
+{\r
+    static char Str[2048];\r
+       va_list args;\r
+       va_start(args, Fmt);\r
+       vsnprintf(Str, 2047, Fmt, args);\r
+       va_end(args);\r
+\r
+    char c_color[13];\r
+    char c_reset[13];\r
+    std::snprintf(c_color, 13, "%c[%d;%d;%dm", 0x1B, 0, foreground + 30, background + 40);\r
+    std::snprintf(c_reset, 13, "%c[%d;%d;%dm", 0x1B, 0, 37, 40);\r
+\r
+       std::stringstream str;\r
+       str << c_color << Str << c_reset;\r
+\r
+       std::printf("%s", str.str().c_str());\r
+       mLogFile << str.str();\r
+\r
+       mLogFile.flush();\r
+}\r
+\r
+void PConsole::LClose()\r
+{\r
+       std::stringstream str;\r
+       str << std::endl;\r
+\r
+       std::printf("%s", str.str().c_str());\r
+       mLogFile << str.str();\r
+\r
+       mLogFile.flush();\r
+}\r
+\r
+void PConsole::Update()\r
+{\r
+       // place a marker into the log each 15 minutes if no output has been generated\r
+       std::time_t t;\r
+       std::time(&t);\r
+       if(std::difftime(t, mLastLogTime) >= 900)\r
+               Print("--MARK--");\r
+}\r
diff --git a/server/src/common/console/main.h b/server/src/common/console/main.h
new file mode 100644 (file)
index 0000000..5d87dc8
--- /dev/null
@@ -0,0 +1,47 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       main.h - main include file, contains all needed includes and important definitions\r
+\r
+       MODIFIED: 26 Aug 2006 Hammag\r
+       REASON: - created from gameserver main.h and modified as needed\r
+\r
+*/\r
+\r
+#ifndef MAIN_H\r
+#define MAIN_H\r
+\r
+//#include "version.h"\r
+\r
+//basic includes\r
+#include "external.h"\r
+\r
+//tinns includes\r
+#include "types.h"\r
+#include "console.h"\r
+\r
+using namespace std;\r
+\r
+#endif\r
+\r
diff --git a/server/src/common/filesystem/Makefile b/server/src/common/filesystem/Makefile
new file mode 100644 (file)
index 0000000..5fb25e9
--- /dev/null
@@ -0,0 +1,83 @@
+#
+# TinNS per-directory Makefile
+#
+# Adapted by Hammag from the Makefile system for Linux kernel.
+#
+# 14 Sep 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+# 
+
+######################################################
+# Target for this directory and its sub-dirs
+######################################################
+# Case 1 : target is an executable named as defined
+#B_TARGET := testor2 
+
+# Case 2 : target is a TinNS lib name
+#  (use short name, as in -l linker option) 
+L_TARGET := tinns
+
+# Case 3 (usual): objects shall be made available to the parent dir
+#  The following line will set that automatically 
+# (Should match dir name + .o suffix)
+#O_TARGET := $(addsuffix .o,$(notdir $(shell /bin/pwd)))
+# Manualy define this only if you need to force the compiled obj name
+#O_TARGET := game.o
+
+
+######################################################
+# Local flags
+######################################################
+# local dir CXX Flags
+#EXTRA_CXXFLAGS := -I/usr/include/mysql
+
+# per-object CXX Flags
+#CXXFLAGS_funcdef2.o := -g
+
+# local dir Linker Flags (for intermediate .o linking)
+#EXTRA_LDFLAGS := 
+
+# any tinns Lib used (short name, as in -l linker option)
+#LINK_TINNSLIBS := tinns
+
+# local dir Linker Flags (for final executable linking)
+#EXTRA_LINKFLAGS := -lrt -lpthread -lz -lm -lcrypt -L"/usr/lib/mysql" -lmysqlclient
+
+
+#####################################################
+# Subdirectories
+#####################################################
+#subdir-y := def 
+#subdir-$(CONFIG_GAMEMONKEY)   += gamemonkey
+
+
+#####################################################
+#***************************************************#
+# No further config should be needed after this line
+#***************************************************#
+ifdef TOPDIR
+
+# build list of objects ib loca ldir
+obj-y := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
+# add final object from each subdir
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+
+include $(TOPDIR)/Rules.make
+
+else #TOPDIR undef, Makefile called from non-top dir
+
+# Memorize the first calling dir in case we wanted to
+# lauch local actions from top Makefile
+  ifndef FIRSTDIR
+    FIRSTDIR :=$(CURDIR)
+    export FIRSTDIR
+  endif
+
+uptoparent : 
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+.DEFAULT :
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+endif #TOPDIR
+
diff --git a/server/src/common/filesystem/filesystem.cpp b/server/src/common/filesystem/filesystem.cpp
new file mode 100644 (file)
index 0000000..78454b7
--- /dev/null
@@ -0,0 +1,378 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+  filesystem.cpp\r
+  \r
+  Authors:\r
+  - Akiko\r
+  - Namikon\r
+  - someone else?\r
+  \r
+  MODIFIED: Unknown date / Unknown author\r
+  REASON: - initial release by unknown\r
+  MODIFIED: 25 Dec 2005 Namikon\r
+  REASON: - Added GPL\r
+  MODIFIED: 31 August 2005 Akiko\r
+  REASON: - modified the path handling of the open function\r
+  MODIFIED: 29 Sep 2006 Hammag\r
+  REASON: - added a safety check on read size in PFile::Read       \r
+  MODIFIED: 07 Oct 2006 Hammag\r
+  REASON: - Fixed package reading to enable access to "subdirectories" in archive,\r
+              as well as translation from unix to dos path separator for in-archive search       \r
+          - Removed the "file not found" message the PFileSystem::Open() was issuing in the corresponding case.\r
+              A NULL returned for PFile* is sufficient for the calling proc to manage the situation.\r
+          - Changed file search in archives to case-insensitive\r
+   \r
+  MODIFIED: 08 Oct 2006 Hammag\r
+  REASON: - added ClearCache() methode to clear pak cache when .pak access is not used anymore\r
+\r
+*/\r
+\r
+#include "main.h"\r
+\r
+/*\r
+       implements file access semantics for Neocron .pak files\r
+       supports both single packed files and file archives\r
+\r
+       how neocron files are accessed:\r
+       - if path/filename.ext exists, the file is opened\r
+       - (else) if path/pak_filename.ext exists, the file is opened\r
+       - (else) if an archive named path_head.pak exists, path_tail\filename.ext is opened from the archive\r
+             here path is split in path_head\path_tail\r
+       \r
+*/\r
+const s8 DELIM = '/';\r
+\r
+PFile::PFile()\r
+{\r
+       mDataSize=0;\r
+       mDataOffs=0;\r
+}\r
+\r
+PFile::~PFile()\r
+{\r
+}\r
+\r
+bool PFile::ReadData(std::FILE *F, u32 Size)\r
+{\r
+       mBuffer.reserve(Size);\r
+       std::fread(&mBuffer[0], 1, Size, F);\r
+       mDataSize = Size;\r
+       return true;\r
+}\r
+\r
+bool PFile::ReadUnpakData(std::FILE *F, u32 Size, u32 UncSize)\r
+{\r
+       std::vector<u8> temp;\r
+       temp.reserve(Size);\r
+       mBuffer.reserve(UncSize);\r
+\r
+       std::fread(&temp[0], 1, Size, F);\r
+\r
+       unsigned long us=UncSize;\r
+       unsigned long s=Size;\r
+       uncompress(&mBuffer[0], &us, &temp[0], s);\r
+       mDataSize=us;\r
+       return true;\r
+}\r
+\r
+int PFile::Read(void *Dest, u32 DestSize)\r
+{\r
+       int m = min(mDataSize-mDataOffs, DestSize);\r
+       if (m <= 0)\r
+         return 0;\r
+       memcpy(Dest, &mBuffer[mDataOffs], m);\r
+       mDataOffs+=m;\r
+       return m;\r
+}\r
+\r
+void PFile::Seek(u32 Offset)\r
+{\r
+       mDataOffs = min(mDataSize-1, Offset);\r
+}\r
+\r
+std::string PFile::ReadString()\r
+{\r
+       int l=0;\r
+       int s=mDataOffs;\r
+       char last=0;\r
+       while(mDataOffs < mDataSize && last!='\n')\r
+       {\r
+               last=mBuffer[mDataOffs++];\r
+               l++;\r
+       }\r
+\r
+       char *str = new char[l+1];\r
+       std::memcpy(str, &mBuffer[s], l);\r
+       str[l]=0;\r
+\r
+       std::string Result = str;\r
+       delete str;\r
+       return Result;\r
+}\r
+\r
+// ---------------\r
+\r
+PFileSystem::PFileSystem()\r
+{\r
+}\r
+\r
+PFileSystem::~PFileSystem()\r
+{\r
+       for(PPakFiles::iterator i=mPaks.begin(); i!=mPaks.end(); i++)\r
+       {\r
+               PPakFileList *list = i->second;\r
+               for(PPakFileList::iterator j=list->begin(); j!=list->end(); j++)\r
+                       delete j->second;\r
+               delete i->second;\r
+       }\r
+}\r
+\r
+PFileSystem::PPakFileList* PFileSystem::CachePak(const std::string &Pak, std::FILE *F)\r
+{\r
+       PPakFiles::iterator n = mPaks.find(Pak);\r
+       if(n != mPaks.end())\r
+               return n->second;\r
+\r
+       if(!F)\r
+               return 0;\r
+\r
+       PPakFileList *Result = 0;\r
+\r
+       int off = std::ftell(F);\r
+       std::fseek(F, 0, SEEK_SET);\r
+       PPakHeader header;\r
+       std::fread(&header, 1, sizeof(header), F);\r
+       if(header.mID==0x3d458cde && header.mNumFiles > 0)\r
+       {\r
+               Result = new PPakFileList();\r
+               for(int i=0; i<header.mNumFiles; i++)\r
+               {\r
+                       PPakFileHeader *h = new PPakFileHeader();\r
+                       std::fread(h, 1, 20, F);\r
+                       h->mFilename = new char[h->mNameLen+1];\r
+                       std::fread(h->mFilename, 1, h->mNameLen, F);\r
+                       Result->insert(std::make_pair(h->mFilename, h));\r
+               }\r
+               mPaks.insert(std::make_pair(Pak, Result));\r
+//Console->Print("%s: %i files registered", Pak.c_str(), header.mNumFiles);\r
+       } else\r
+       {\r
+               Console->Print("%s: invalid pakfile", Pak.c_str());\r
+       }\r
+       std::fseek(F, off, SEEK_SET);\r
+       return Result;\r
+}\r
+\r
+void PFileSystem::ClearCache()\r
+{\r
+  PFileSystem::PPakFiles::iterator nPak;\r
+  PFileSystem::PPakFileList::iterator nFList;\r
+  PPakFileHeader* FHeader;\r
+  PFileSystem::PPakFileList* FList;\r
+  \r
+  for( nPak = mPaks.begin(); nPak != mPaks.end(); nPak++)\r
+  {\r
+    FList = nPak->second;\r
+    for( nFList = FList->begin(); nFList != FList->end(); nFList++)\r
+    {\r
+      FHeader = nFList->second;\r
+      FList->erase(nFList);\r
+      delete[] FHeader->mFilename;\r
+      delete FHeader;\r
+    }\r
+    mPaks.erase(nPak);\r
+    delete FList;\r
+  }\r
+}\r
+\r
+void splitpath(const string &file, string &path, string &name, string &ext)\r
+{\r
+       unsigned long pos = file.rfind(DELIM);\r
+\r
+       if (pos == string::npos)\r
+       {\r
+               path = "";\r
+               name = file;\r
+       }\r
+       else\r
+       {\r
+               path = file.substr(0, pos);\r
+               name = file.substr(pos + 1);\r
+       }\r
+\r
+       pos = name.rfind('.');\r
+       if (pos == string::npos)\r
+       {\r
+               ext = "";\r
+       }\r
+       else\r
+       {\r
+               ext = name.substr(pos + 1);\r
+               name = name.substr(0, pos);\r
+       }\r
+}\r
+\r
+PFile *PFileSystem::Open(const std::string &Package, const char *File, std::string BasePath)\r
+{\r
+             std::string name = "";\r
+        std::string ext = "";\r
+        std::string path = "";\r
+        splitpath(File, path, name, ext);\r
+\r
+        std::string pak2;\r
+        std::string name2;\r
+\r
+        if ((BasePath == ".") || (BasePath == "./"))\r
+        {\r
+          BasePath = "";\r
+        }\r
+        else\r
+        {\r
+          if (BasePath.substr(0, 2) == "./")\r
+          {\r
+            BasePath = BasePath.substr(2, BasePath.length() -2);\r
+          }\r
+          if ( BasePath[BasePath.length()-1] != '/' )\r
+          {\r
+            BasePath += '/';\r
+          }\r
+        }\r
+//Console->Print("Basepath:%s", BasePath.c_str());\r
+     \r
+        std::string pak = Package;\r
+        if(pak=="")\r
+        {\r
+           pak=path;\r
+           if (path.substr(0, 2) == "./")\r
+           {\r
+              path = path.substr(2, path.length() -2);\r
+           }\r
+           unsigned long pos = path.find(DELIM);\r
+               if (pos == string::npos)\r
+               {\r
+                       pak2 = path;\r
+                       name2 = name;\r
+               }\r
+               else\r
+               {\r
+                       pak2 = path.substr(0, pos);\r
+                       name2 = path.substr(pos + 1) + '\\' + name;\r
+                       pos = name2.find(DELIM);\r
+                       while (pos != string::npos)\r
+                       {\r
+                         name2[pos] = '\\';\r
+                         pos = name2.find(DELIM);\r
+                       }\r
+               }\r
+        }          \r
+\r
+        std::stringstream package;\r
+        //package << pak << ".pak" << '\0';\r
+        package << BasePath << pak2 << ".pak" << '\0';\r
+        std::stringstream fname;\r
+        fname << BasePath << pak << '/' << name << "." << ext << '\0';\r
+        std::stringstream pakname;\r
+        pakname << BasePath << pak << "/pak_" << name << "." << ext << '\0';\r
+\r
+        std::FILE *f = std::fopen(fname.str().c_str(), "rb");\r
+        if(f)\r
+        {\r
+                PFile *Result = new PFile();\r
+                std::fseek(f, 0, SEEK_END);\r
+                int s = std::ftell(f);\r
+                std::fseek(f, 0, SEEK_SET);\r
+                Result->ReadData(f, s);\r
+                std::fclose(f);\r
+                return Result;\r
+        }\r
+//else\r
+//  Console->Print("File not found:%s", fname.str().c_str());\r
+        f = std::fopen(pakname.str().c_str(), "rb");\r
+        if(f)\r
+        {\r
+                PFile *Result = new PFile();\r
+                std::fseek(f, 0, SEEK_END);\r
+                int s = std::ftell(f)-16;\r
+                std::fseek(f, 12, SEEK_SET);\r
+                int os;\r
+                std::fread(&os, 1, 4, f);\r
+                Result->ReadUnpakData(f, s, os);\r
+                std::fclose(f);\r
+                return Result;\r
+        }\r
+//else\r
+//  Console->Print("Pak_ not found:%s", pakname.str().c_str());\r
+  \r
+//Console->Print("Serching package %s, file %s.%s", package.str().c_str(), name2.c_str(), ext.c_str());\r
+        f = std::fopen(package.str().c_str(), "rb");\r
+        if(f)\r
+        {\r
+                //std::string filename = name;\r
+                std::string filename = name2 + "." + ext;\r
+                           //filename.append(ext);\r
+\r
+                PPakFileHeader *file = 0;\r
+                PPakFileList *list = CachePak(std::string(package.str()), f);\r
+                for(PPakFileList::iterator i=list->begin(); i!=list->end(); i++)\r
+                {\r
+                        PPakFileHeader *h = i->second;\r
+                        if(!strcasecmp(i->first.c_str(), filename.c_str()))\r
+                        {\r
+                                file = h;\r
+                                break;\r
+                        }\r
+                }\r
+                PFile *Result = 0;\r
+                if(list && file)\r
+                {\r
+                        Result = new PFile();\r
+                        std::fseek(f, file->mOffset, SEEK_SET);\r
+                        Result->ReadUnpakData(f, file->mCompressedSize, file->mUncompressedSize);\r
+//Console->Print("%s, %s: file found", package.str().c_str(), filename.c_str());\r
+                }\r
+                else\r
+                {\r
+                        if(!list)\r
+                                //Console->Print("%s, %s: pak error", Package.c_str(), File);\r
+                                Console->Print("%s, %s: pak error", package.str().c_str(), File);\r
+//else\r
+//if(!file)\r
+//Console->Print("%s, %s: file not found", Package.c_str(), File);\r
+//  Console->Print("%s, %s: file not found", package.str().c_str(), filename.c_str());\r
+                }\r
+\r
+                std::fclose(f);\r
+                return Result;\r
+        }\r
+\r
+        return 0;\r
+}\r
+\r
+bool PFileSystem::Close(PFile *File)\r
+{\r
+       delete File;\r
+       return true;\r
+}\r
+\r
diff --git a/server/src/common/filesystem/main.h b/server/src/common/filesystem/main.h
new file mode 100644 (file)
index 0000000..d0711ef
--- /dev/null
@@ -0,0 +1,56 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       main.h - main include file, contains all needed includes and important definitions\r
+\r
+       MODIFIED: 27 Aug 2006 Hammag\r
+       REASON: - created       \r
+         \r
+*/\r
+\r
+#ifndef MAIN_H\r
+#define MAIN_H\r
+\r
+//#include "version.h"\r
+\r
+//basic includes\r
+#include "external.h"\r
+\r
+//tinns includes\r
+#include "types.h"\r
+#include "config.h"\r
+\r
+#include "console.h"\r
+#include "misc.h"\r
+\r
+#include "filesystem.h"\r
+\r
+using namespace std;\r
+\r
+// Better change that to a static members\r
+extern class PConsole* Console;\r
+//extern class PConfig* Config;\r
+\r
+#endif\r
+\r
diff --git a/server/src/common/misc/Makefile b/server/src/common/misc/Makefile
new file mode 100644 (file)
index 0000000..5fb25e9
--- /dev/null
@@ -0,0 +1,83 @@
+#
+# TinNS per-directory Makefile
+#
+# Adapted by Hammag from the Makefile system for Linux kernel.
+#
+# 14 Sep 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+# 
+
+######################################################
+# Target for this directory and its sub-dirs
+######################################################
+# Case 1 : target is an executable named as defined
+#B_TARGET := testor2 
+
+# Case 2 : target is a TinNS lib name
+#  (use short name, as in -l linker option) 
+L_TARGET := tinns
+
+# Case 3 (usual): objects shall be made available to the parent dir
+#  The following line will set that automatically 
+# (Should match dir name + .o suffix)
+#O_TARGET := $(addsuffix .o,$(notdir $(shell /bin/pwd)))
+# Manualy define this only if you need to force the compiled obj name
+#O_TARGET := game.o
+
+
+######################################################
+# Local flags
+######################################################
+# local dir CXX Flags
+#EXTRA_CXXFLAGS := -I/usr/include/mysql
+
+# per-object CXX Flags
+#CXXFLAGS_funcdef2.o := -g
+
+# local dir Linker Flags (for intermediate .o linking)
+#EXTRA_LDFLAGS := 
+
+# any tinns Lib used (short name, as in -l linker option)
+#LINK_TINNSLIBS := tinns
+
+# local dir Linker Flags (for final executable linking)
+#EXTRA_LINKFLAGS := -lrt -lpthread -lz -lm -lcrypt -L"/usr/lib/mysql" -lmysqlclient
+
+
+#####################################################
+# Subdirectories
+#####################################################
+#subdir-y := def 
+#subdir-$(CONFIG_GAMEMONKEY)   += gamemonkey
+
+
+#####################################################
+#***************************************************#
+# No further config should be needed after this line
+#***************************************************#
+ifdef TOPDIR
+
+# build list of objects ib loca ldir
+obj-y := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
+# add final object from each subdir
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+
+include $(TOPDIR)/Rules.make
+
+else #TOPDIR undef, Makefile called from non-top dir
+
+# Memorize the first calling dir in case we wanted to
+# lauch local actions from top Makefile
+  ifndef FIRSTDIR
+    FIRSTDIR :=$(CURDIR)
+    export FIRSTDIR
+  endif
+
+uptoparent : 
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+.DEFAULT :
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+endif #TOPDIR
+
diff --git a/server/src/common/misc/main.h b/server/src/common/misc/main.h
new file mode 100644 (file)
index 0000000..8159c2d
--- /dev/null
@@ -0,0 +1,52 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       main.h - main include file, contains all needed includes and important definitions\r
+\r
+       MODIFIED: 27 Aug 2006 Hammag\r
+       REASON: - created       \r
+         \r
+*/\r
+\r
+#ifndef MAIN_H\r
+#define MAIN_H\r
+\r
+//#include "version.h"\r
+\r
+//basic includes\r
+#include "external.h"\r
+#include <arpa/inet.h> // needed fo inet_ntoa() in IPlongToString()\r
+\r
+//tinns includes\r
+#include "types.h"\r
+#include "misc.h"\r
+\r
+#include "console.h"\r
+\r
+using namespace std;\r
+\r
+// Better change that to a static members if needed (PrintPacket could be outdated, or put in netcode)\r
+extern class PConsole* Console;\r
+\r
+#endif\r
diff --git a/server/src/common/misc/misc.cpp b/server/src/common/misc/misc.cpp
new file mode 100644 (file)
index 0000000..c27eeea
--- /dev/null
@@ -0,0 +1,312 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+        misc.cpp\r
+\r
+        Authors:\r
+        - Akiko\r
+        - Namikon\r
+        - someone else?\r
+\r
+        MODIFIED: Unknown date / Unknown author\r
+        REASON: - initial release by unknown\r
+\r
+        MODIFIED: 25 Dec 2005 Namikon\r
+        REASON: - Added GPL\r
+        MODIFIED: 07 Jan 2006 Namikon\r
+        REASON: - Added function to trim a string/char\r
+       MODIFIED: 01 Jul 2006 hammag\r
+       REASON: - add IPlongToString()\r
+       MODIFIED: 27 Aug 2006 Hammag\r
+       REASON: - Merged misc function from all 3 servers\r
+       MODIFIED: 11 Dec 2006 Hammag\r
+       REASON: - Commented out GetSVNRev() that is not used anymore\r
+\r
+       TODO:\r
+               - Put Network Utility function in a netutility.cpp in netcode\r
+               - Put GetAccessString() as a static member of Accounts class\r
+*/\r
+\r
+#include "main.h"\r
+\r
+u32 IPStringToDWord( const char *IP )\r
+{\r
+  if ( !IP )\r
+    return 0;\r
+\r
+  u32 a, b, c, d;\r
+  if ( std::sscanf( IP, "%u.%u.%u.%u", &a, &b, &c, &d ) != 4 )\r
+    return 0;\r
+\r
+  return ( d << 24 ) | ( c << 16 ) | ( b << 8 ) | a;\r
+}\r
+\r
+char *IPlongToString( const u32 IP )\r
+{\r
+  struct in_addr in_IP;\r
+\r
+  in_IP.s_addr = IP;\r
+  return inet_ntoa( in_IP );\r
+}\r
+\r
+//NEW\r
+//this function allow to print a packet\r
+//just for tracking values\r
+void PrintPacket( u8 *Packet, int PacketSize )\r
+{\r
+  Console->Print( "inside : PrintPacket" );\r
+\r
+  if ( PacketSize < 1 ){Console->Print( "Wrong packet" );}//do nothing\r
+  else\r
+  {\r
+    Console->Print( "PacketSize is : %d", PacketSize );\r
+\r
+    u8 value = 0;\r
+    for ( int i = 0;i < PacketSize;i++ )\r
+    {\r
+      value = *( u8* ) & Packet[i];\r
+      Console->Print( "value[%d] is : %x", i, value );\r
+    }\r
+  }\r
+\r
+}//end function\r
+\r
+void CleanUpString(std::string *nString)\r
+{\r
+    if(!nString)\r
+        return;\r
+\r
+    // Skip if string is >" "<\r
+    if(nString->length() > 3)\r
+    {\r
+        size_t tfound;\r
+        string t_replacechr ("\"");\r
+\r
+        tfound = nString->find(t_replacechr);\r
+        while(tfound != string::npos)\r
+        {\r
+            nString->replace(tfound, 1, " ");\r
+            tfound = nString->find( t_replacechr, tfound +1 );\r
+        }\r
+        // Skip if string consists of spaces now\r
+        if(strncmp(nString->c_str(), "   ", 3) == 0)\r
+        {\r
+            // Set empty\r
+            *nString = "";\r
+        }\r
+        else\r
+        {\r
+            // Trim spaces\r
+            Trim(nString);\r
+        }\r
+    }\r
+    else\r
+    {\r
+        *nString = "";\r
+    }\r
+}\r
+\r
+void Trim( char *t )\r
+{\r
+  RTrim( t );\r
+  if ( strlen( t ) )\r
+    LTrim( t );\r
+}\r
+\r
+void Trim( std::string *stString )\r
+{\r
+  RTrim( stString );\r
+  if ( stString->length() )\r
+    LTrim( stString );\r
+}\r
+\r
+void RTrim( char *t )\r
+{\r
+  char *buf;\r
+\r
+  if ( !strlen( t ) ) return;\r
+\r
+  buf = t;\r
+  buf += strlen( t ) - 1;\r
+\r
+  while ( *buf == ' ' && strlen( t ) )\r
+    *buf-- = '\0';\r
+}\r
+\r
+void RTrim( std::string *stString )\r
+{\r
+  int i;       //Count VAR\r
+\r
+  if ( !stString->length() )   //If There Is No Length\r
+    return;\r
+\r
+  i = stString->length() - 1;   //Set The Counter To The String Length -1\r
+\r
+  while ( stString->substr( i, 1 ) == " " )  //While There Is Still " "\r
+  {\r
+    *stString = stString->substr( 0, i );  //Remove Off The End Of The String\r
+    i--;         //Advance The Counter\r
+  }\r
+\r
+}\r
+\r
+void LTrim( char *t )\r
+{\r
+  char tmp[2048];    //Temp Char VAR\r
+  char *buf;     //Pointer\r
+\r
+  if ( !strlen( t ) ) return;\r
+\r
+  strncpy( tmp, t, 2048 );\r
+  tmp[2047] = 0;\r
+  buf = tmp;\r
+\r
+  while ( *buf == ' ' && strlen( buf ) ) *buf++;\r
+\r
+  strncpy( t, buf, 2048 ); // just because without length is forbidden !\r
+}\r
+\r
+void LTrim( std::string *stString )\r
+{\r
+  unsigned int i;       //Count VAR\r
+  string buf;      //Temp String VAR\r
+\r
+  if ( !stString->length() ) return;    //If The Length Is 0\r
+\r
+  i = 0;             //Setup The Counter VAR\r
+\r
+  while ( stString->substr( i, 1 ) == " " )     //While " "\r
+    i++;            //Increase Counter\r
+\r
+  if ( i == stString->length() )     //If The Whole String Is " "\r
+  {\r
+    *stString = "";          //Return Blank String\r
+    return;\r
+  }\r
+\r
+  try\r
+  {\r
+    *stString = stString->substr( i, stString->length() - i ); //Send The String Back Without The Spaces\r
+  }\r
+  catch ( ... )\r
+  {\r
+    *stString = "";          //Return Blank String\r
+    return;\r
+  }\r
+\r
+}\r
+\r
+std::string GetAccessString( int level )\r
+{\r
+  switch ( level )\r
+  {\r
+    case 0: return "Unregistered";\r
+    case 1: return "Registered";\r
+    case 30: return "Volunteer";\r
+    case 50: return "Gamemaster";\r
+    case 100: return "Administrator";\r
+  }\r
+  return "Error";\r
+}\r
+\r
+std::string &Ssprintf( const char *fmt, ... )\r
+{\r
+  static std::string tmpstring;\r
+  char buff[1024];\r
+  va_list args;\r
+\r
+  va_start( args, fmt );\r
+  vsnprintf( buff, 1024, fmt, args );\r
+  va_end( args );\r
+  buff[1023] = '\0';\r
+  tmpstring = buff;\r
+  return tmpstring;\r
+}\r
+\r
+u16 DistanceApprox( const u16 x1, const u16 y1, const u16 z1, const u16 x2, const u16 y2, const u16 z2 )\r
+{\r
+  u16 DX, DY, DZ, DMax;\r
+  u32 DMinSum, DApprox;\r
+\r
+  DMax = DX = ( x1 >= x2 ) ? x1 - x2 : x2 - x1;\r
+  DMinSum = DY = ( y1 >= y2 ) ? y1 - y2 : y2 - y1;\r
+  DZ = ( z1 >= z2 ) ? z1 - z2 : z2 - z1;\r
+  if ( DX < DY )\r
+  {\r
+    DMax = DY;\r
+    DMinSum = DX;\r
+  }\r
+  if ( DMax < DZ )\r
+  {\r
+    DMinSum += DMax;\r
+    DMax = DZ;\r
+  }\r
+  else\r
+  {\r
+    DMinSum += DZ;\r
+  }\r
+\r
+  DApprox = DMax + ( u32 )( 0.33 * DMinSum );\r
+  if ( DApprox > 65535 )\r
+  {\r
+    DApprox = 65535;\r
+  }\r
+\r
+  // We use Dapprox = max(dx, dy) + K * min(dx, dy)\r
+  // Dapprox = (DX > DY) ? DX + (DY >> 1) : DY + (DX >> 1); // Fastest, but max error on dist is around 10% real dist\r
+  //Dapprox = (u16)((DX > DY) ? DX + 0.33*DY : DY + 0.33*DX); // max error on dist is around 5%, which should be enough\r
+  /*\r
+   // for dist approx debug\r
+  float fDX, fDY, fDZ, fDist;\r
+  fDX=(x1 - x2);\r
+  fDY=(y1 - y2);\r
+  fDZ=(z1 - z2);\r
+  fDist=sqrt(fDX*fDX + fDY*fDY + fDZ*fDZ);\r
+  if (fDist != 0) Console->Print("Dist: %f\tApprox: %d\tError: %d (%d%)", fDist, DApprox, (int)(DApprox-fDist), (int)(100*(DApprox-fDist)/fDist));\r
+  */\r
+\r
+  return ( u16 )DApprox;\r
+}\r
+\r
+/*** Portable pseudo-random number generator ***/\r
+// until native standardized C++ lib support\r
+\r
+u32 mInternalRand = 1;\r
+\r
+void InitRandom( u32 nInitialisationValue )\r
+{\r
+  mInternalRand = nInitialisationValue;\r
+}\r
+\r
+u16 GetRandom( u16 MaxVal, u16 MinVal )\r
+{\r
+  mInternalRand = mInternalRand * 1103515245 + 12345; //from rand() manpage\r
+  return ( u16 )( MinVal + (( mInternalRand >> 16 ) % 32768 % ( MaxVal - MinVal + 1 ) ) );\r
+}\r
+\r
+f32 GetRandomFloat()\r
+{\r
+  mInternalRand = mInternalRand * 1103515245 + 12345; //from rand() manpage\r
+  return (( f32 )(( mInternalRand >> 16 ) % 32768 ) / ( f32 )32768 );\r
+}\r
diff --git a/server/src/common/netcode/Makefile b/server/src/common/netcode/Makefile
new file mode 100644 (file)
index 0000000..5fb25e9
--- /dev/null
@@ -0,0 +1,83 @@
+#
+# TinNS per-directory Makefile
+#
+# Adapted by Hammag from the Makefile system for Linux kernel.
+#
+# 14 Sep 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+# 
+
+######################################################
+# Target for this directory and its sub-dirs
+######################################################
+# Case 1 : target is an executable named as defined
+#B_TARGET := testor2 
+
+# Case 2 : target is a TinNS lib name
+#  (use short name, as in -l linker option) 
+L_TARGET := tinns
+
+# Case 3 (usual): objects shall be made available to the parent dir
+#  The following line will set that automatically 
+# (Should match dir name + .o suffix)
+#O_TARGET := $(addsuffix .o,$(notdir $(shell /bin/pwd)))
+# Manualy define this only if you need to force the compiled obj name
+#O_TARGET := game.o
+
+
+######################################################
+# Local flags
+######################################################
+# local dir CXX Flags
+#EXTRA_CXXFLAGS := -I/usr/include/mysql
+
+# per-object CXX Flags
+#CXXFLAGS_funcdef2.o := -g
+
+# local dir Linker Flags (for intermediate .o linking)
+#EXTRA_LDFLAGS := 
+
+# any tinns Lib used (short name, as in -l linker option)
+#LINK_TINNSLIBS := tinns
+
+# local dir Linker Flags (for final executable linking)
+#EXTRA_LINKFLAGS := -lrt -lpthread -lz -lm -lcrypt -L"/usr/lib/mysql" -lmysqlclient
+
+
+#####################################################
+# Subdirectories
+#####################################################
+#subdir-y := def 
+#subdir-$(CONFIG_GAMEMONKEY)   += gamemonkey
+
+
+#####################################################
+#***************************************************#
+# No further config should be needed after this line
+#***************************************************#
+ifdef TOPDIR
+
+# build list of objects ib loca ldir
+obj-y := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
+# add final object from each subdir
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+
+include $(TOPDIR)/Rules.make
+
+else #TOPDIR undef, Makefile called from non-top dir
+
+# Memorize the first calling dir in case we wanted to
+# lauch local actions from top Makefile
+  ifndef FIRSTDIR
+    FIRSTDIR :=$(CURDIR)
+    export FIRSTDIR
+  endif
+
+uptoparent : 
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+.DEFAULT :
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+endif #TOPDIR
+
diff --git a/server/src/common/netcode/connection-tcp.cpp b/server/src/common/netcode/connection-tcp.cpp
new file mode 100644 (file)
index 0000000..a43385c
--- /dev/null
@@ -0,0 +1,410 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       connection-tcp.cpp - a connection class for tcp\r
+\r
+       Authors:\r
+       - bakkdoor\r
+\r
+       MODIFIED: 09 Feb 2006 bakkdoor\r
+       REASON: - introduced\r
+       \r
+       MODIFIED: 27 Jun 2006 hammag\r
+       REASON: - added m_ServerSocket check in ~ConnectionTCP()\r
+               - added m_ServerSocket check in update() in disconnection case\r
+               - corrected recv *buf and len parameters in update()\r
+                 to avoid unread in-buffer data smashing\r
+                 \r
+       MODIFIED: 01 Jul 2006 hammag\r
+       REASON: - update() : modified to deal correctly with would-block socket writes.\r
+          - ConnectionTCP() : moved-in non-blocking setting from\r
+                   ServerSocket::getTCPConnection() for better class coherency\r
+\r
+  MODIFIED: 24 Jul 2006 hammag\r
+       REASON: - ConnectionTCP() : added m_SendSize, m_RecvRewind and m_RecvSize missing initialisation\r
+                 which caused nice segfaults on unlucky days :p\r
+       \r
+       MODIFIED: 24 Jul 2006 hammag\r
+       REASON: - changed member data prefix from "m_" to "m" in for homogeneity with the reste of TinNS code\r
+               - added private members data mQueueIn and mQueueOut\r
+               - added public members methods SendMessage(), GetMessage(), DeleteOutgoingMessages() and modified code accordingly\r
+               - changed old read/write methods implementation to message queues usage\r
+       NOTA:   - as previously, ConnectionTCP class takes care of separating messages in the TCP stream according\r
+                   to NC TCP packet lentgh field. Additionnaly, it does look for the 0xFE signature byte in front of the packet lentgh field.\r
+       \r
+       MODIFIED: 26 Jul 2006 hammag\r
+       REASON: - enabled multiple network send in on single update() call\r
+\r
+       MODIFIED: 05 Aug 2006 hammag\r
+       REASON: - renamed "getLocalAddress()" to "getRemoteAddress()" as it is ... what it does !\r
+       \r
+       TODO:   - add real priority management when needed. atm all outgoing messages are put in the same queue\r
+               - add pending outgoing message management in case of EAGAIN (request temp add to writeset & mngt by  the "scheduler")\r
+               - set TCP socket option SO_KEEPALIVE to be firewall-users friendly (else connexion may be lost when no zoning occurs for a long time, like in real NC ;-) )\r
+               - don't access Config object from netcode's objects. Use parameter members\r
+              set by object owner.\r
+\r
+*/\r
+\r
+#include "main.h"\r
+\r
+ConnectionTCP::ConnectionTCP(int sockfd, struct sockaddr_in addr, ServerSocket* server)\r
+{\r
+    mSockfd = sockfd;\r
+    mRemoteAddr = addr;\r
+    \r
+    if(server)\r
+    {\r
+        mServerSocket = server;\r
+    }\r
+\r
+    // set new socket to non-blocking\r
+    fcntl(mSockfd, F_SETFL, O_NONBLOCK);\r
+            \r
+    mbConnected = true; // client obviously is connected at creation...\r
+\r
+    mTimeOutValue = DEFAULT_TCP_TIMEOUT;\r
+    mLastActive = std::time(NULL);\r
+      \r
+    mReceiveBufferMsg = NULL;\r
+    mSendBufferMsg = NULL;\r
+}\r
+\r
+ConnectionTCP::~ConnectionTCP()\r
+{\r
+    if (mServerSocket)\r
+    {\r
+      mServerSocket->delSocketFromSet(mSockfd);\r
+    }\r
+    close(mSockfd);\r
+    \r
+    if (mReceiveBufferMsg)\r
+    {\r
+      delete mReceiveBufferMsg;\r
+    }\r
+    \r
+    while (!mQueueIn.empty())\r
+    {\r
+      delete mQueueIn.front();\r
+      mQueueIn.pop();\r
+    }\r
+\r
+    if (mSendBufferMsg)\r
+    {\r
+      delete mSendBufferMsg;\r
+    }\r
+}\r
+\r
+char* ConnectionTCP::getRemoteAddress()\r
+{\r
+    return inet_ntoa(mRemoteAddr.sin_addr);\r
+}\r
+\r
+bool ConnectionTCP::timeOut() const\r
+{\r
+       time_t now = std::time(NULL);\r
+       if((now-mLastActive) >= mTimeOutValue)\r
+               return true;\r
+\r
+       return false;\r
+}\r
+\r
+PMessage* ConnectionTCP::GetMessage()\r
+{\r
+  PMessage* RetVal;\r
+  \r
+  if (mQueueIn.empty())\r
+    RetVal = NULL;\r
+  else\r
+  {\r
+    RetVal = mQueueIn.front();\r
+    mQueueIn.pop();\r
+  }\r
+  return RetVal;\r
+}\r
+\r
+void ConnectionTCP::DeleteOutgoingMessages()\r
+{\r
+  while (! mQueueOut.empty())\r
+  {\r
+    delete mQueueOut.front();\r
+    mQueueOut.pop();\r
+  }  \r
+}\r
+\r
+bool ConnectionTCP::update() // non optimal read-algorithm atm, but well ... :p\r
+{\r
+  PMessage* tmpMsg;\r
+  int numBytes;\r
+  u8 const* DataStart;\r
+  u16 DataSize;\r
+  u8* MsgStart;\r
+  u16 MsgOffset;\r
+  u16 MsgLen;\r
+  \r
+  //check if data is available for this socket and if yes, read into a new PMessage and put it on incoming queue\r
+  if(mServerSocket->isDataAvailable(mSockfd))\r
+  {\r
+//Console->Print("ConnectionTCP::update() - IN Data avail");\r
+    if (mReceiveBufferMsg == NULL)\r
+    {\r
+      mReceiveBufferMsg = new PMessage(RECVBUFFERSIZE);\r
+    }\r
+    \r
+    DataSize = mReceiveBufferMsg->GetSize();\r
+    numBytes = recv(mSockfd, (char*) mReceiveBufferMsg->GetMessageDataPointer(RECVBUFFERSIZE - DataSize) + DataSize, RECVBUFFERSIZE - DataSize, 0); // get the data\r
+\r
+    if(numBytes > 0)\r
+    {\r
+//Console->Print(GREEN, BLACK, "ConnectionTCP::update() - Data received");\r
+      mbConnected = true;\r
+      mReceiveBufferMsg->ForceSize(DataSize + numBytes);\r
+      mLastActive = std::time(NULL);\r
+      \r
+      while(mReceiveBufferMsg && mReceiveBufferMsg->GetSize())\r
+      {\r
+        DataStart = mReceiveBufferMsg->GetMessageData();\r
+        DataSize = mReceiveBufferMsg->GetSize();\r
+        MsgStart = (u8*)memchr(DataStart, 0xfe, DataSize);\r
+        \r
+        if (MsgStart)\r
+        {\r
+          MsgOffset = MsgStart - DataStart;\r
+          if (MsgOffset)\r
+          {\r
+            Console->Print(YELLOW, BLACK, "ConnectionTCP::update() Message head found 0x%04hx bytes after packet start. Inbetween data will be discarded.", MsgOffset);\r
+          }\r
+          if (MsgOffset + 3 <= DataSize)\r
+          {\r
+            MsgLen = *(u16*)(DataStart + MsgOffset + 1);\r
+//Console->Print(GREEN, BLACK, "ConnectionTCP::update() TCP Message body length 0x%04hx (buffer 0x%04hx)", MsgLen, mReceiveBufferMsg->GetSize());\r
+            if (MsgOffset + 3 + MsgLen <= DataSize)\r
+            {\r
+              tmpMsg = mReceiveBufferMsg->GetChunk(MsgOffset, MsgLen + 3); // Change (MsgOffset, MsgLen + 3) to (MsgOffset + 3, MsgLen) to REMOVE head & length from message head\r
+              mQueueIn.push(tmpMsg);\r
+              \r
+              if (MsgOffset + 3 + MsgLen < DataSize)\r
+              {\r
+                 tmpMsg = mReceiveBufferMsg->GetChunk(MsgOffset + 3 + MsgLen, DataSize - (MsgOffset + 3 + MsgLen));\r
+              }\r
+              else\r
+              {\r
+                tmpMsg = NULL;\r
+              }\r
+              \r
+              delete mReceiveBufferMsg;\r
+              mReceiveBufferMsg = tmpMsg;              \r
+            }\r
+          }\r
+        }\r
+        else\r
+        {\r
+          break;\r
+        }\r
+      }\r
+    }\r
+    else if(numBytes == 0) // disconnected !!\r
+    {\r
+        mbConnected = false; // set to not-connected and close the socket\r
+        if (mServerSocket)\r
+        {\r
+          mServerSocket->delSocketFromSet(mSockfd);\r
+        }\r
+        close(mSockfd);        \r
+        return false;\r
+    }\r
+    else\r
+    {\r
+      if(errno != EAGAIN) \r
+      {                    // an error has occured -> output it to the console\r
+        perror("tcp-receive");\r
+        Console->Print(RED, BLACK, "mSockfd:%d MaxRead:%d ", mSockfd, RECVBUFFERSIZE);\r
+      }\r
+    }           \r
+  }\r
+\r
+  // send data from outgoing queue\r
+  flushSendBuffer(); // manage old write compatibility\r
+       while(! mQueueOut.empty())\r
+       {\r
+//Console->Print("ConnectionUDP::update() - OUT Data avail");\r
+         tmpMsg = mQueueOut.front();\r
+               int numBytes = send(mSockfd, (char*) tmpMsg->GetMessageData(), tmpMsg->GetSize(), 0);\r
+               if(numBytes == -1) // error while sending data -> output error-msg to console\r
+               {\r
+                 if (errno == EAGAIN)\r
+                 {\r
+                   break;\r
+                 }\r
+                 else\r
+                 {\r
+                   perror("tcp-send");\r
+                   //close(mSockfd);\r
+        return false;\r
+      }\r
+    }\r
+    else if(numBytes > 0)\r
+               {\r
+//Console->Print(GREEN, BLACK, "ConnectionTCP::update() - Data sent");\r
+                   mLastActive = std::time(NULL);\r
+        mQueueOut.pop(); // message written, we can remove it from queue\r
+        delete tmpMsg; // and delete the message\r
+               }\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+/**** Old I/F compatibility functions ****/\r
+\r
+int ConnectionTCP::getRecvBufferSize()\r
+{\r
+  PMessage* tmpMsg;\r
+  \r
+  if (mQueueIn.empty())\r
+    return 0;\r
+\r
+  tmpMsg = mQueueIn.front();\r
+       u16 _size = tmpMsg->GetSize()-tmpMsg->GetNextByteOffset();\r
+       if (_size <= 0)\r
+       {\r
+         mQueueIn.pop();\r
+         delete tmpMsg;\r
+    if (mQueueIn.empty())\r
+      return 0;\r
+    tmpMsg = mQueueIn.front();\r
+         tmpMsg->SetNextByteOffset(0);\r
+         _size = tmpMsg->GetSize();\r
+       }\r
+       return _size;\r
+}\r
+\r
+int ConnectionTCP::getSendBufferSize()\r
+{\r
+  if(mSendBufferMsg == NULL)\r
+    return 0;\r
+  else\r
+    return mSendBufferMsg->GetSize();\r
+}\r
+\r
+void ConnectionTCP::flushSendBuffer()\r
+{\r
+//Console->Print("ConnectionTCP::flushSendBuffer()");\r
+    if((mSendBufferMsg != NULL) && (mSendBufferMsg->GetSize() > 0))\r
+    {\r
+      SendMessage(mSendBufferMsg);\r
+      mSendBufferMsg = NULL;\r
+//Console->Print(YELLOW, BLACK, "ConnectionTCP::flushSendBuffer() - Data flushed");\r
+    }\r
+}\r
+\r
+const u8* ConnectionTCP::read(int* size)\r
+{\r
+  PMessage* tmpMsg;\r
+//Console->Print("ConnectionTCP::read() - trying to read up to %d bytes", *size);  \r
+  if (mQueueIn.empty() || !size)\r
+  {\r
+//Console->Print("ConnectionTCP::read() - no more packet");\r
+    return NULL;\r
+  }\r
+\r
+  tmpMsg = mQueueIn.front();\r
+       u16 _size = tmpMsg->GetSize()-tmpMsg->GetNextByteOffset();\r
+//Console->Print("ConnectionTCP::read() - %d bytes remaining in current packet", _size);\r
+       if (_size <= 0)\r
+       {\r
+//Console->Print("ConnectionTCP::read() - trying next packet");\r
+         mQueueIn.pop();\r
+         delete tmpMsg;\r
+    if (mQueueIn.empty())\r
+    {\r
+//Console->Print("ConnectionUDP::read() - no more packet");\r
+      return NULL;\r
+     }\r
+    tmpMsg = mQueueIn.front();\r
+         _size = tmpMsg->GetSize();\r
+         tmpMsg->SetNextByteOffset(0);\r
+       }\r
+       \r
+       if(*size==0)\r
+       {\r
+               *size=_size;\r
+       }\r
+       else\r
+       {\r
+               *size=min(*size, (s32)_size);\r
+       }\r
+\r
+       u8 const* ptr = tmpMsg->GetMessageData() + tmpMsg->GetNextByteOffset();\r
+       tmpMsg->SetNextByteOffset(tmpMsg->GetNextByteOffset()+ *size);\r
+//Console->Print(GREEN, BLACK, "ConnectionTCP::read() - %d bytes read", *size);\r
+       return ptr;\r
+}\r
+\r
+int ConnectionTCP::write(const void* data, int size)\r
+{\r
+  // data is stored in mSendBufferMsg. Gets queued in next flushSendBuffer() or update()\r
+  if (mSendBufferMsg == NULL)\r
+  {\r
+//Console->Print("ConnectionTCP::write() creating new mSendBufferMsg");\r
+    mSendBufferMsg = new PMessage(SENDBUFFERSIZE);\r
+  }\r
+  \r
+       mSendBufferMsg->Write(data, (u16)size);\r
+//Console->Print(GREEN, BLACK, "ConnectionUDP::write() %d bytes written to mSendBufferMsg (total size %d)", size, mSendBufferMsg->GetSize());\r
+       return size;\r
+}\r
+\r
+int ConnectionTCP::write(const char *String)\r
+{\r
+       if(!String)\r
+               return 0;\r
+\r
+       return write(String, strlen(String));\r
+}\r
+\r
+int ConnectionTCP::write(u8 Data)\r
+{\r
+       return write(&Data, sizeof(u8));\r
+}\r
+\r
+int ConnectionTCP::write(u16 Data)\r
+{\r
+       return write(&Data, sizeof(u16));\r
+}\r
+\r
+int ConnectionTCP::write(u32 Data)\r
+{\r
+       return write(&Data, sizeof(u32));\r
+}\r
+\r
+int ConnectionTCP::write(float Data)\r
+{\r
+       return write(&Data, sizeof(float));\r
+}\r
+\r
+int ConnectionTCP::write(double Data)\r
+{\r
+       return write(&Data, sizeof(double));\r
+}\r
diff --git a/server/src/common/netcode/connection-udp.cpp b/server/src/common/netcode/connection-udp.cpp
new file mode 100644 (file)
index 0000000..02220e2
--- /dev/null
@@ -0,0 +1,480 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+ connection-udp.cpp - a connection class for udp\r
+\r
+ Authors:\r
+ - bakkdoor\r
+\r
+ MODIFIED: 09 Feb 2006 bakkdoor\r
+ REASON: - introduced\r
+\r
+ MODIFIED: 27 Jun 2006 hammag\r
+ REASON: - put UDP socket in non-blocking mode in ConnectionUDP to avoid blocking\r
+           in update() as it can be called without data available.\r
+         - modified update() accordingly.\r
+         - modified flushSendBuffer() accordingly; >> !!! leads to data loss if packet could not be sent\r
+             and connection closed just after that. Is it a problem before UDP connection closure (ie logout) ???\r
+         - corrected recv *buf and len parameters in update() to avoid\r
+           unread in-buffer data smashing.\r
+         - added initialisation of addrlen in update().\r
+\r
+ MODIFIED: 01 Jul 2006 hammag\r
+ REASON: - ConnectionUDP(): modified to set m_ServerSocket\r
+         - update(): modified to check m_ServerSocket->isDataAvailable()\r
+             before trying to read from socket\r
+         - ~ConnectionUDP(): added socket removal from fd set\r
+\r
+  MODIFIED: 24 Jul 2006 hammag\r
+ REASON: - changed member data prefix from "m_" to "m" in for homogeneity with the reste of TinNS code\r
+         - added private members data mQueueIn and mQueueOut\r
+         - added public members methods SendMessage(), GetMessage(), DeleteOutgoingMessages() and modified code accordingly\r
+         - changed old read/write methods implementation to message queues usage\r
+\r
+ MODIFIED: 26 Jul 2006 hammag\r
+ REASON: - enabled multiple network receive & send in on single update() call\r
+\r
+ MODIFIED: 29 Jul 2006 hammag\r
+ REASON: - changed order of network read/write in update(): now first write, then read\r
+\r
+ MODIFIED: 05 Aug 2006 hammag\r
+ REASON: - a pseudo-connection is now established on the udp socket, so that we don't need to care\r
+             for client IP/port in later processing\r
+ REASON: - renamed "getLocalAddress()" to "getRemoteAddress()" as it is ... what it does !\r
+\r
+\r
+ TODO:   - split update so the main loop is : read - process - write - wait for something to read\r
+         - add try vector read & write with recvmsg/sendmsg\r
+         - add real priority management when needed. atm all outgoing messages are put in the same queue\r
+         - add pending outgoing message management in case of EAGAIN (request temp add to writeset & mngt by  the "scheduler")\r
+          - best sizing of receive message could be done with ioctl:\r
+             "int value;\r
+              error = ioctl(tcp_socket, ioctl_type, &value);\r
+              SIOCINQ\r
+              Gets a pointer to an integer as argument. Returns the  size  of\r
+              the next pending datagram in the integer in bytes, or 0 when no\r
+              datagram is pending."\r
+          - check incoming packets Source IP for matching with registered client IP, to avoid DOS & other things\r
+          - maybe dont allow source port change (eg. because of NAT) more than once (at the begining only) for same reasons\r
+          - check incoming messages UDP_ID to reject old messages and -if possible- request OOO granted messages (to be done at higher message decoding level thought)\r
+          - manage an ageing queue of sent granted messages for resent if OOO notified by client\r
+          - don't access Config object from netcode's objects. Use parameter members\r
+              set by object owner.\r
+*/\r
+\r
+#include "main.h"\r
+\r
+ConnectionUDP::ConnectionUDP(int sockfd, int port, int remoteadress, int remoteport, ServerSocket* server)\r
+{\r
+    mSockfd = sockfd;\r
+    mPort = port;\r
+    //Console->Print("local UDP port: %d", port);\r
+    if(server)\r
+    {\r
+        mServerSocket = server;\r
+    }\r
+\r
+    mTimeOutValue = DEFAULT_UDP_TIMEOUT;\r
+    mLastActive = std::time(NULL);\r
+\r
+    mRemoteAddr.sin_family = AF_INET;       // host byte order\r
+    mRemoteAddr.sin_port = htons(remoteport);     // short, network byte order\r
+    mRemoteAddr.sin_addr.s_addr = remoteadress;   // TODO: Get IP of client\r
+\r
+    //Bind client to server in a udp pseudo-connection\r
+    /*if(connect(sockfd, (struct sockaddr *)&mRemoteAddr, sizeof(struct sockaddr )))\r
+    {\r
+      Console->Print("Error on pseudo-connecting udp socket to %s:%d", inet_ntoa(mRemoteAddr.sin_addr),ntohs(mRemoteAddr.sin_port));\r
+      perror("udp connect"); //exception should be thrown here\r
+    }\r
+    else */\r
+    {\r
+        Console->Print("Client UDP %s:%d", inet_ntoa(mRemoteAddr.sin_addr), ntohs(mRemoteAddr.sin_port));\r
+    }\r
+    // set UDP-socket to non-blocking\r
+    fcntl(sockfd, F_SETFL, O_NONBLOCK);\r
+\r
+    //    mRemoteAddr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP\r
+    //    memset(&(mRemoteAddr.sin_zero), '\0', 8); // zero the rest of the struct\r
+    mSendBufferMsg = NULL;\r
+\r
+       mUDP_ID = 0;\r
+       mSessionID = SESSION_UDP_OFFSET;\r
+    mLastUDPID = 0;\r
+    mTransactionID = 0;\r
+}\r
+\r
+\r
+ConnectionUDP::~ConnectionUDP()\r
+{\r
+    if (mServerSocket)\r
+    {\r
+        mServerSocket->delSocketFromSet(mSockfd);\r
+    }\r
+    close(mSockfd);\r
+\r
+    if (mSendBufferMsg)\r
+    {\r
+        delete mSendBufferMsg;\r
+    }\r
+\r
+    while (!mQueueIn.empty())\r
+    {\r
+        delete mQueueIn.front();\r
+        mQueueIn.pop();\r
+    }\r
+\r
+    while (!mQueueOut.empty())\r
+    {\r
+        delete mQueueOut.front();\r
+        mQueueOut.pop();\r
+    }\r
+    while (!mVIPQueueOut.empty())\r
+    {\r
+        delete mVIPQueueOut.front();\r
+        mVIPQueueOut.pop();\r
+    }\r
+    for(PMessageMap::iterator it=UDPMessages.begin(); it!=UDPMessages.end(); it++)\r
+    {\r
+        delete it->second;\r
+        UDPMessages.erase(it);\r
+    }\r
+}\r
+\r
+\r
+bool ConnectionUDP::timeOut() const\r
+{\r
+    time_t now = std::time(NULL);\r
+    if((now-mLastActive) >= mTimeOutValue)\r
+        return true;\r
+\r
+    return false;\r
+}\r
+\r
+char* ConnectionUDP::getRemoteAddress()\r
+{\r
+    return inet_ntoa(mRemoteAddr.sin_addr);\r
+}\r
+\r
+PMessage* ConnectionUDP::GetMessage()\r
+{\r
+    PMessage* RetVal;\r
+\r
+    if (mQueueIn.empty())\r
+        RetVal = NULL;\r
+    else\r
+    {\r
+        RetVal = mQueueIn.front();
+        mQueueIn.pop();\r
+    }\r
+    return RetVal;\r
+}\r
+\r
+void ConnectionUDP::DeleteOutgoingMessages()\r
+{\r
+    while (! mQueueOut.empty())\r
+    {\r
+        PMessage* tmpMsg;\r
+        tmpMsg = mQueueOut.front();\r
+        mQueueOut.pop();\r
+        delete tmpMsg;\r
+    }\r
+    while (! mVIPQueueOut.empty())\r
+    {\r
+        PMessage* tmpMsg2;\r
+        tmpMsg2 = mVIPQueueOut.front();\r
+        mVIPQueueOut.pop();\r
+        delete tmpMsg2;\r
+    }\r
+}\r
+\r
+bool ConnectionUDP::update()\r
+{\r
+    PMessage* tmpMsg;\r
+    int numBytes;\r
+    bool gotVIPmsg;\r
+\r
+    // send data from outgoing queue\r
+    flushSendBuffer(); // manage old write compatibility\r
+\r
+    // Update messagebuffer; Erase all messages older than MAX_RETENTION\r
+    UpdateMessageBuffer();\r
+\r
+    if (! mQueueOut.empty() || ! mVIPQueueOut.empty())\r
+    {\r
+        //Console->Print(GREEN, BLACK, "ConnectionUDP::update() - Sending messages -----------------");\r
+        //  Console->Print("ConnectionUDP::update() - %d messages waiting in Output Queue", mQueueOut.size());\r
+        while(! mQueueOut.empty() || ! mVIPQueueOut.empty())\r
+        {\r
+            //Console->Print("ConnectionUDP::update() - OUT Data avail");\r
+\r
+            // First, take a look at the VIP Query. If not empty, send these packets first\r
+            gotVIPmsg = false;\r
+            if(! mVIPQueueOut.empty())\r
+            {\r
+                tmpMsg = mVIPQueueOut.front();\r
+                gotVIPmsg = true;\r
+                Console->Print("ConnectionUDP::update() - Got VIP (Very important packet) that is waiting to be sent");\r
+            }\r
+            else\r
+            {\r
+                tmpMsg = mQueueOut.front();\r
+\r
+                // We ignore VIP packets for now. They are only meant to OOO packets\r
+                InsertUDPMessage(tmpMsg);\r
+            }\r
+            //int numBytes = send(mSockfd, tmpMsg->GetMessageData(), tmpMsg->GetSize(), 0);\r
+            int numBytes = sendto(mSockfd, (char*) tmpMsg->GetMessageData(), tmpMsg->GetSize(), 0, (struct sockaddr *)&mRemoteAddr, sizeof(struct sockaddr));\r
+            if(numBytes > 0)\r
+            {\r
+                //Console->Print(GREEN, BLACK, "ConnectionUDP::update() - Data sent");\r
+                mLastActive = std::time(NULL);\r
+                if(gotVIPmsg == true)\r
+                {\r
+                    mVIPQueueOut.pop();\r
+                }\r
+                else\r
+                {\r
+                    mQueueOut.pop(); // message written, we can remove it from queue\r
+                }\r
+                //Console->Print(GREEN, BLACK, "ConnectionUDP::update() - Message sent:");\r
+                //tmpMsg->DumpHead("OUT Msg:"); // ====\r
+                //tmpMsg->Dump();\r
+                delete tmpMsg; // and delete the message\r
+            }\r
+            else\r
+            {\r
+                if (errno == EAGAIN)\r
+                {\r
+                    break;\r
+                }\r
+                else // error while sending data -> output error-msg to console\r
+                {\r
+                    perror("udp-send2");\r
+                    //close(mSockfd);\r
+                    return false;\r
+                }\r
+            }\r
+        }\r
+        //if (! mQueueOut.empty())\r
+        //  Console->Print(YELLOW, BLACK, "ConnectionUDP::update() - %d messages remaining in Output Queue", mQueueOut.size());\r
+    }\r
+\r
+    //check if data is available from this socket and if yes, read into a new PMessage and put it on incoming queue\r
+    if(mServerSocket->isDataAvailable(mSockfd))\r
+    {\r
+        //Console->Print("ConnectionUDP::update() - IN Data avail");\r
+        while (1)\r
+        {\r
+            tmpMsg = new PMessage(RECVBUFFERSIZE);\r
+            socklen_t addrlen;\r
+            addrlen = sizeof(mRemoteAddr);\r
+            //struct sockaddr_in tempAddr;  // need to built in check,\r
+            // if the incoming data is coming from the client or someone else!\r
+            //numBytes = recv(mSockfd, tmpMsg->GetMessageDataPointer(RECVBUFFERSIZE), RECVBUFFERSIZE, 0); // get the data\r
+            numBytes = recvfrom(mSockfd, (char*) tmpMsg->GetMessageDataPointer(RECVBUFFERSIZE), RECVBUFFERSIZE, 0, (struct sockaddr *)&mRemoteAddr, &addrlen);\r
+            if(numBytes > 0)\r
+            {\r
+                //Console->Print(GREEN, BLACK, "ConnectionUDP::update() - Data received");\r
+                mLastActive = std::time(NULL);\r
+                tmpMsg->ForceSize(numBytes);\r
+                mQueueIn.push(tmpMsg);\r
+                //tmpMsg->DumpHead("IN Msg :"); // ====\r
+            }\r
+            else\r
+            {\r
+                delete tmpMsg;\r
+                if(errno != EAGAIN)\r
+                {                    // an error has occured -> output it to the console\r
+                    perror("udp-receive");\r
+                    Console->Print(RED, BLACK, "mSockfd:%d MaxRead:%d ", mSockfd, RECVBUFFERSIZE);\r
+                }\r
+                break;\r
+            }\r
+        }\r
+        //Console->Print("ConnectionUDP::update() - %d messages ready in Input Queue", mQueueIn.size());\r
+    }
+\r
+    return true;\r
+}\r
+
+void ConnectionUDP::SendMessage(PMessage* nMessage, bool nVIP)\r
+{\r
+    if (nMessage)\r
+    {\r
+        if(nVIP == true)\r
+            mVIPQueueOut.push(nMessage);\r
+        else\r
+            mQueueOut.push(nMessage);\r
+    }\r
+}\r
+\r
+/**************** Old I/F compatibility stuff ******************/\r
+\r
+int ConnectionUDP::getRecvBufferSize()\r
+{\r
+    PMessage* tmpMsg;\r
+\r
+    if (mQueueIn.empty())\r
+        return 0;\r
+\r
+    tmpMsg = mQueueIn.front();\r
+    u16 _size = tmpMsg->GetSize()-tmpMsg->GetNextByteOffset();\r
+    if (_size <= 0)\r
+    {\r
+        mQueueIn.pop();\r
+        delete tmpMsg;\r
+        if (mQueueIn.empty())\r
+            return 0;\r
+        tmpMsg = mQueueIn.front();\r
+        tmpMsg->SetNextByteOffset(0);\r
+        _size = tmpMsg->GetSize();\r
+    }\r
+    return _size;\r
+}\r
+\r
+int ConnectionUDP::getSendBufferSize()\r
+{\r
+    if(mSendBufferMsg == NULL)\r
+        return 0;\r
+    else\r
+        return mSendBufferMsg->GetSize();\r
+}\r
+\r
+void ConnectionUDP::flushSendBuffer()\r
+{\r
+    //Console->Print("ConnectionUDP::flushSendBuffer()");\r
+    if((mSendBufferMsg != NULL) && (mSendBufferMsg->GetSize() > 0))\r
+    {\r
+        SendMessage(mSendBufferMsg);\r
+        mSendBufferMsg = NULL;\r
+        //Console->Print(YELLOW, BLACK, "ConnectionUDP::flushSendBuffer() - Data flushed");\r
+    }\r
+}\r
+\r
+const u8* ConnectionUDP::read(int* size)\r
+{\r
+    PMessage* tmpMsg;\r
+    //Console->Print("ConnectionUDP::read() - trying to read up to %d bytes", *size);\r
+    if (mQueueIn.empty() || !size)\r
+    {\r
+        //Console->Print("ConnectionUDP::read() - no more packet");\r
+        return NULL;\r
+    }\r
+\r
+    tmpMsg = mQueueIn.front();\r
+    u16 _size = tmpMsg->GetSize()-tmpMsg->GetNextByteOffset();\r
+    //Console->Print("ConnectionUDP::read() - %d bytes remaining in current packet", _size);\r
+    if (_size <= 0)\r
+    {\r
+        //Console->Print("ConnectionUDP::read() - trying next packet");\r
+        mQueueIn.pop();\r
+        delete tmpMsg;\r
+        if (mQueueIn.empty())\r
+        {\r
+            //Console->Print("ConnectionUDP::read() - no more packet");\r
+            return NULL;\r
+        }\r
+        tmpMsg = mQueueIn.front();\r
+        _size = tmpMsg->GetSize();\r
+        tmpMsg->SetNextByteOffset(0);\r
+    }\r
+\r
+    if(*size==0)\r
+    {\r
+        *size=_size;\r
+    }\r
+    else\r
+    {\r
+        *size=min(*size, (s32)_size);\r
+    }\r
+\r
+    u8 const* ptr = tmpMsg->GetMessageData() + tmpMsg->GetNextByteOffset();\r
+    tmpMsg->SetNextByteOffset(tmpMsg->GetNextByteOffset()+ *size);\r
+    //Console->Print(GREEN, BLACK, "ConnectionUDP::read() - %d bytes read", *size);\r
+    return ptr;\r
+}\r
+\r
+int ConnectionUDP::write(const void* data, int size)\r
+{\r
+    // data is stored in mSendBufferMsg. Gets queued in next flushSendBuffer() or update()\r
+    if (mSendBufferMsg == NULL)\r
+    {\r
+        //Console->Print("ConnectionUDP::write() creating new mSendBufferMsg");\r
+        mSendBufferMsg = new PMessage(SENDBUFFERSIZE);\r
+    }\r
+    mSendBufferMsg->Write(data, (u16)size);\r
+    //Console->Print(GREEN, BLACK, "ConnectionUDP::write() %d bytes written to mSendBufferMsg (total size %d)", size, mSendBufferMsg->GetSize());\r
+    return size;\r
+}\r
+\r
+int ConnectionUDP::write(const char *String)\r
+{\r
+    if(!String)\r
+        return 0;\r
+\r
+    return write(String, strlen(String));\r
+}\r
+\r
+int ConnectionUDP::write(u8 Data)\r
+{\r
+    return write(&Data, sizeof(u8));\r
+}\r
+\r
+int ConnectionUDP::write(u16 Data)\r
+{\r
+    return write(&Data, sizeof(u16));\r
+}\r
+\r
+int ConnectionUDP::write(u32 Data)\r
+{\r
+    return write(&Data, sizeof(u32));\r
+}\r
+\r
+int ConnectionUDP::write(float Data)\r
+{\r
+    return write(&Data, sizeof(float));\r
+}\r
+\r
+int ConnectionUDP::write(double Data)\r
+{\r
+    return write(&Data, sizeof(double));\r
+}\r
+\r
+/// ***********************************************\r
+\r
+void ConnectionUDP::SetUDP_ID(u16 id)\r
+{\r
+    if (mUDP_ID == 0xffff)\r
+    {\r
+        mUDP_ID = 0;\r
+    }\r
+    else\r
+    {\r
+        mUDP_ID = id;\r
+    }\r
+    if(mUDP_ID == 0)        // If UDPID is set to zero, erase message buffer too\r
+        ResetMessageBuffer();\r
+}\r
+\r
diff --git a/server/src/common/netcode/main.h b/server/src/common/netcode/main.h
new file mode 100644 (file)
index 0000000..b4c8fa0
--- /dev/null
@@ -0,0 +1,70 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       main.h - main include file, contains all needed includes and important definitions\r
+\r
+       MODIFIED: 26 Aug 2006 Hammag\r
+       REASON: - created from gameserver main.h and modified as needed\r
+       \r
+       TODO:   - move RECVBUFFERSIZE, SENDBUFFERSIZE, DEFAULT_TIMEOUT to config file\r
+               - change Console & Config from external to static members if possible\r
\r
+*/\r
+\r
+#ifndef MAIN_H\r
+#define MAIN_H\r
+\r
+//#include "version.h"\r
+\r
+//basic includes\r
+#include "external.h"\r
+\r
+//tinns includes\r
+#include "types.h"\r
+#include "netcode.h"\r
+\r
+#include "console.h"\r
+#include "config.h"\r
+\r
+using namespace std;\r
+\r
+/*\r
+static const int RECVBUFFERSIZE = 4096;\r
+static const int SENDBUFFERSIZE = 4096;\r
+\r
+static const time_t DEFAULT_TIMEOUT = 60;\r
+*/\r
+\r
+// To be put in config file\r
+#define RECVBUFFERSIZE 4096\r
+#define SENDBUFFERSIZE 4096\r
+#define DEFAULT_TCP_TIMEOUT 600\r
+#define DEFAULT_UDP_TIMEOUT 60\r
+\r
+// Better change that to a static members of each netcode class\r
+extern class PConsole* Console;\r
+extern class PConfig* Config;\r
+\r
+#endif\r
+\r
diff --git a/server/src/common/netcode/message.cpp b/server/src/common/netcode/message.cpp
new file mode 100644 (file)
index 0000000..6a6abe8
--- /dev/null
@@ -0,0 +1,475 @@
+
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+
+
+/*
+       message.cpp - a data message & message pool class for tcp and udp connections (and maybe more later)
+
+
+       Authors:
+       - Hammag
+
+       MODIFIED: 15 jul 2006 Hammag
+       REASON: - Creation
+*/
+
+/*
+#include "../game/main.h"
+#include "message.h"
+*/
+#include "main.h"
+
+const u16 PMessage::smMsgSizes[] = {MESSAGE_SIZES_LIST};
+PMsgData* PMessage::smMsgPoolHead[] = {MESSAGE_POOL_INIT};
+int PMessage::smMsgPoolCount[] = {MESSAGE_POOL_COUNT_INIT};
+int PMessage::smMsgCount = 0;
+
+void PMessage::CheckMsgCount()
+{
+  static int MaxMsgCount = 0;
+
+  if (smMsgCount > MaxMsgCount)
+  {
+    Console->Print("%s Max In-use messages number increasing : %d (+%d)", Console->ColorText(GREEN, BLACK, "[Info]"), smMsgCount, smMsgCount-MaxMsgCount);
+    MaxMsgCount = smMsgCount;
+  }
+}
+
+PMessage::PMessage(u16 nRequestedSize)
+{
+  GetMsgBuffer(nRequestedSize);
+  mUsedSize = 0;
+  mNextByteOffset = 0;
+  ++smMsgCount;
+  //Console->Print("Created msgnum %d", smMsgCount);
+}
+
+PMessage::PMessage(PMessage& nMessage)
+{
+  GetMsgBuffer(nMessage.mUsedSize);
+  mUsedSize = nMessage.mUsedSize;
+  mNextByteOffset = 0;
+  memcpy((void*)(mData->mBuffer), (void*)(nMessage.mData->mBuffer), (size_t)mUsedSize);
+  ++smMsgCount;
+}
+
+void PMessage::GetMsgBuffer(u16 nRequestedSize) //no optimisation to try to used larger unused buffer
+{
+//Console->Print("Allocating buffer for size %d", nRequestedSize);
+  for (mPoolId = 0; mPoolId < MESSAGE_SIZES_NB; mPoolId++)
+  {
+    if (smMsgSizes[mPoolId] >= nRequestedSize)
+      break;
+  }
+  if (mPoolId == MESSAGE_SIZES_NB)
+  {
+    Console->Print(RED, BLACK, "[PANIC] PMessage::GetDataBuffer: requested size %d too large. Aborting", nRequestedSize);
+    exit(-1);
+  }
+  mMaxSize = smMsgSizes[mPoolId];
+//Console->Print("Using Pool n� %d (size %d)", mPoolId, smMsgSizes[mPoolId]);
+
+  if ((mData = smMsgPoolHead[mPoolId]) == NULL)
+  {
+//Console->Print("Pool Empty, creating new buffers");
+    mData = new PMsgData[MESSAGE_ALLOC_NB];
+    for (int i = 0; i < MESSAGE_ALLOC_NB; i++)
+      mData[i].mBuffer = new u8[mMaxSize];
+
+    if (MESSAGE_ALLOC_NB > 1)
+    {
+      smMsgPoolHead[mPoolId] = mData + 1;
+      for (int i = 1; i < MESSAGE_ALLOC_NB-1; i++)
+        mData[i].mNextMsgData = mData + i + 1;
+      mData[MESSAGE_ALLOC_NB-1].mNextMsgData = NULL;
+    }
+    
+    smMsgPoolCount[mPoolId] += MESSAGE_ALLOC_NB;
+  }
+  else
+  {
+    smMsgPoolHead[mPoolId] = mData->mNextMsgData;
+  }
+
+//Console->Print("Buffer allocated 0x%08x", mData);
+}
+
+void PMessage::ReleaseMsgBuffer()
+{
+  mData->mNextMsgData = smMsgPoolHead[mPoolId];
+  smMsgPoolHead[mPoolId] = mData;
+//Console->Print("Buffer %08xd back in pool %d.", mData, mPoolId);
+}
+
+void PMessage::CheckAndExtend(u16 nRequestedSize) // This is SIZE checked, not max OFFSET
+{
+//Console->Print("Checking size: max %d, req %d", mMaxSize, nRequestedSize);
+  if (nRequestedSize > mMaxSize)
+  {
+//Console->Print("Extension needed (max %d, req %d)", mMaxSize, nRequestedSize);
+     PMsgData* SaveMsgBuffer = mData;
+     ReleaseMsgBuffer();
+     GetMsgBuffer(nRequestedSize);
+     memcpy((void*)mData->mBuffer, (void*)SaveMsgBuffer->mBuffer, (size_t)mUsedSize);
+//Console->Print("Original data (%d bytes) copied from %08xd to %08xd ", mUsedSize, SaveMsgBuffer, mData);
+  }
+}
+
+void PMessage::SetNextByteOffset(u16 nPos)
+{
+  if (nPos >= mMaxSize)
+    CheckAndExtend(nPos+1);
+  mNextByteOffset = nPos;
+}
+
+void PMessage::ForceSize(u16 nUsedSize)
+{
+  if (nUsedSize > mMaxSize)
+    CheckAndExtend(nUsedSize);
+  mUsedSize = nUsedSize;
+}
+
+// Writing methods
+u8* PMessage::GetMessageDataPointer(u16 nUsedSize)
+{
+  if (nUsedSize > mMaxSize)
+    CheckAndExtend(nUsedSize);
+  if (nUsedSize > mUsedSize)
+    mUsedSize = nUsedSize;
+  return (u8*) (mData->mBuffer);
+}
+
+PMessage& PMessage::Fill(u8 Value, u16 StartOffset, u16 FillSize)
+{
+  if (FillSize == 0)
+    FillSize = mMaxSize;
+  if (StartOffset >= mMaxSize)
+    return *this;
+  if (StartOffset + FillSize > mMaxSize)
+    FillSize = mMaxSize - StartOffset;
+  memset((void*)(mData->mBuffer + StartOffset), Value, (size_t)FillSize);
+  return *this;
+}
+
+PMessage& PMessage::Write(const void* nData, u16 nLength)
+{
+  u16 tmpOffset = mNextByteOffset + nLength;
+  if (tmpOffset > mMaxSize)
+    CheckAndExtend(tmpOffset);
+  memcpy((void*)(mData->mBuffer + mNextByteOffset), (void*)nData, (size_t)nLength);
+  mNextByteOffset = tmpOffset;
+  UpdateUsedSize();
+  return *this;
+}
+
+PMessage& PMessage::operator << (PMessage& nMessage)
+{
+  u16 tmpOffset = mNextByteOffset + nMessage.mUsedSize;
+  if (tmpOffset > mMaxSize)
+    CheckAndExtend(tmpOffset);
+  memcpy((void*)(mData->mBuffer + mNextByteOffset), (void*)(nMessage.mData->mBuffer), (size_t)(nMessage.mUsedSize));
+  mNextByteOffset = tmpOffset;
+  UpdateUsedSize();
+  return *this;
+}
+
+PMessage& PMessage::operator << (const char* nString) //for null terminated string ! Copies includes ending \0
+{
+  int StringL = strlen(nString)+1;
+  u16 tmpOffset = mNextByteOffset + StringL;
+  if (tmpOffset > mMaxSize)
+    CheckAndExtend(tmpOffset);
+  memcpy((void*)(mData->mBuffer + mNextByteOffset), (void*)nString, (size_t)StringL);
+  mNextByteOffset = tmpOffset;
+  UpdateUsedSize();
+  return *this;
+}
+
+PMessage& PMessage::operator << (u8 nU8)
+{
+  u16 tmpOffset = mNextByteOffset+1;
+  if (tmpOffset > mMaxSize)
+    CheckAndExtend(tmpOffset);
+  mData->mBuffer[mNextByteOffset] = nU8;
+  mNextByteOffset = tmpOffset;
+  UpdateUsedSize();
+  return *this;
+}
+
+PMessage& PMessage::operator << (u16 nU16)
+{
+  u16 tmpOffset = mNextByteOffset+2;
+  if (tmpOffset > mMaxSize)
+    CheckAndExtend(tmpOffset);
+  *(u16*)(mData->mBuffer + mNextByteOffset) = nU16;
+  mNextByteOffset = tmpOffset;
+  UpdateUsedSize();
+  return *this;
+}
+
+PMessage& PMessage::operator << (u32 nU32)
+{
+  u16 tmpOffset = mNextByteOffset+4;
+  if (tmpOffset > mMaxSize)
+    CheckAndExtend(tmpOffset);
+  *(u32*)(mData->mBuffer + mNextByteOffset) = nU32;
+  mNextByteOffset = tmpOffset;
+  UpdateUsedSize();
+  return *this;
+}
+
+PMessage& PMessage::operator << (f32 nF32)
+{
+  u16 tmpOffset = mNextByteOffset+4;
+  if (tmpOffset > mMaxSize)
+    CheckAndExtend(tmpOffset);
+  *(f32*)(mData->mBuffer + mNextByteOffset) = nF32;
+  mNextByteOffset = tmpOffset;
+  UpdateUsedSize();
+  return *this;
+}
+
+// Mixt methods
+u8& PMessage::U8Data(u16 nOffset)
+{
+  u16 tmpOffset = nOffset+1;
+  if (tmpOffset > mMaxSize)
+    CheckAndExtend(tmpOffset);
+  if (tmpOffset > mUsedSize)
+    mUsedSize = tmpOffset;
+
+  return mData->mBuffer[nOffset];
+}
+
+u16& PMessage::U16Data(u16 nOffset)
+{
+  u16 tmpOffset = nOffset+2;
+  if (tmpOffset > mMaxSize)
+    CheckAndExtend(tmpOffset);
+  if (tmpOffset > mUsedSize)
+    mUsedSize = tmpOffset;
+
+  return *(u16*)(mData->mBuffer + nOffset);
+}
+
+u32& PMessage::U32Data(u16 nOffset)
+{
+  u16 tmpOffset = nOffset+4;
+  if (tmpOffset > mMaxSize)
+    CheckAndExtend(tmpOffset);
+  if (tmpOffset > mUsedSize)
+    mUsedSize = tmpOffset;
+
+  return *(u32*)(mData->mBuffer + nOffset);
+}
+
+f32& PMessage::F32Data(u16 nOffset)
+{
+  u16 tmpOffset = nOffset+4;
+  if (tmpOffset > mMaxSize)
+    CheckAndExtend(tmpOffset);
+  if (tmpOffset > mUsedSize)
+    mUsedSize = tmpOffset;
+
+  return *(f32*)(mData->mBuffer + nOffset);
+}
+
+PMessage& PMessage::operator = (PMessage& nMessage)
+{
+  if(&nMessage != this) {
+    if (mPoolId != nMessage.mPoolId)
+    {
+  //Console->Print("Adjusting buffer before message copy: old pool %d => new pool %d", mPoolId, nMessage.mPoolId);
+      ReleaseMsgBuffer();
+      GetMsgBuffer(nMessage.mMaxSize);
+    }
+  
+    mUsedSize = nMessage.mUsedSize;
+    mNextByteOffset = nMessage.mNextByteOffset;
+    memcpy((void*)(mData->mBuffer), (void*)(nMessage.mData->mBuffer), (size_t)mMaxSize);
+  }
+  
+  return *this;
+}
+
+// Reading methods
+PMessage* PMessage::GetChunk(u16 StartOffset, u16 ChunkSize, u16 ChunkNumber)
+{
+  u16 ReqStartOffset = StartOffset + ChunkNumber * ChunkSize;
+  if (ReqStartOffset >= mUsedSize)
+    return NULL;
+  u16 RealChunkSize = (ChunkSize < mUsedSize - ReqStartOffset) ? ChunkSize : mUsedSize - ReqStartOffset;
+
+  PMessage* MsgChunk = new PMessage(RealChunkSize);
+  memcpy((void*)(MsgChunk->mData->mBuffer), (void*)(mData->mBuffer + ReqStartOffset), (size_t)RealChunkSize);
+  MsgChunk->mUsedSize = RealChunkSize;
+
+  return MsgChunk;
+}
+
+PMessage& PMessage::operator >> (std::string& nString) //read up to null or EOM
+{
+  int i;
+  u8* StringStart = mData->mBuffer + mNextByteOffset;
+  char* FinalStringStart;
+  for (i = 0; mNextByteOffset + i < mUsedSize; i++)
+  {
+    if (*(StringStart + i) == 0)
+      break;
+  }
+
+  if (mNextByteOffset + i >= mUsedSize)
+  {
+    i = mUsedSize - mNextByteOffset +1;
+    FinalStringStart = new char[i];
+    memcpy((void*)FinalStringStart, (void*)StringStart, (size_t)i);
+    mNextByteOffset = mUsedSize;
+  }
+  else
+  {
+    FinalStringStart = (char*)StringStart;
+    mNextByteOffset = mNextByteOffset + i + 1;
+  }
+
+  nString.append(FinalStringStart);
+  return *this;
+}
+
+PMessage& PMessage::operator >> (u8& nU8)
+{
+  u16 tmpOffset = mNextByteOffset+1;
+  nU8 = (tmpOffset > mUsedSize) ? 0 : mData->mBuffer[mNextByteOffset];
+  mNextByteOffset = tmpOffset;
+  return *this;
+}
+
+PMessage& PMessage::operator >> (u16& nU16)
+{
+  u16 tmpOffset = mNextByteOffset+2;
+  nU16 = (tmpOffset > mUsedSize) ? 0 : *(u16*)(mData->mBuffer + mNextByteOffset);
+  mNextByteOffset = tmpOffset;
+  return *this;
+}
+
+PMessage& PMessage::operator >> (u32& nU32)
+{
+  u16 tmpOffset = mNextByteOffset+4;
+  nU32 = (tmpOffset > mUsedSize) ? 0 : *(u32*)(mData->mBuffer + mNextByteOffset);
+  mNextByteOffset = tmpOffset;
+  return *this;
+}
+
+PMessage& PMessage::operator >> (f32& nF32)
+{
+  u16 tmpOffset = mNextByteOffset+4;
+  nF32 = (tmpOffset > mUsedSize) ? 0 : *(f32*)(mData->mBuffer + mNextByteOffset);
+  mNextByteOffset = tmpOffset;
+  return *this;
+}
+
+/* Dump functions */
+
+void PMessage::ListPools()
+{
+  PMsgData* iBuff;
+  int n;
+
+  Console->Print("--- Free buffers pool ---");
+
+  for (int i = 0; i < MESSAGE_SIZES_NB; i++)
+  {
+    iBuff = smMsgPoolHead[i];
+    n = 0;
+    while (iBuff != NULL)
+    {
+      ++n;
+      iBuff = iBuff->mNextMsgData;
+    }
+    //if (n > 0)
+      Console->Print("\tBuffer pool %d (size %d): %d used - %d free buffers", i, smMsgSizes[i], smMsgPoolCount[i]-n, n);
+    //else
+    //  Console->Print("\tBuffer pool %d (size %d): Empty", i, smMsgSizes[i]);
+  }
+}
+
+void PMessage::DumpPools()
+{
+  PMsgData* iBuff;
+  int n;
+
+  Console->Print("--- Buffers pool ---");
+
+  for (int i = 0; i < MESSAGE_SIZES_NB; i++)
+  {
+    if ((iBuff = smMsgPoolHead[i]) != NULL)
+    {
+      n = 0;
+      Console->Print("\tBuffer pool %d (size %d):", i, smMsgSizes[i]);
+      while (iBuff != NULL)
+      {
+        Console->Print("\t\t%d : 0x%08x", n++, iBuff);
+        iBuff = iBuff->mNextMsgData;
+      }
+    }
+    else
+      Console->Print("\tBuffer pool %d (size %d): Empty", i, smMsgSizes[i]);
+  }
+}
+
+void PMessage::Dump()
+{
+  char tmpStr[64];
+  std::string sDump;
+  std::string sAsciiDump;
+  int i, j;
+  char* tmpBuff = (char*) GetMessageData();
+
+  Console->Print("--- Message data (MsgData 0x%08x) ---", mData);
+  Console->Print("Buffer from pool %d (max size %d), used 0x%04hx (%d) , data at 0x%08x", mPoolId, smMsgSizes[mPoolId], mUsedSize, mUsedSize, tmpBuff);
+  for (i = 0; i < mUsedSize; i += 16)
+  {
+    snprintf(tmpStr, 64, "\t%04hx:",i);
+    sDump = tmpStr;
+    sAsciiDump = "";
+    for (j = 0; (j < 16) && ((i+j) < mUsedSize); j++)
+    {
+      snprintf(tmpStr, 64, " %02hx",(u8)tmpBuff[i+j]);
+      sDump += tmpStr;
+      sAsciiDump += ((tmpBuff[i+j]>'\x19') && (tmpBuff[i+j]<'\x7F')) ? tmpBuff[i+j] : '.';
+    }
+    while (j++ < 16)
+      sDump += "   ";
+    Console->Print("%s  %s", sDump.c_str(),sAsciiDump.c_str());
+  }
+  Console->Print("\tNext byte offset 0x%04hx (%d)", mNextByteOffset, mNextByteOffset);
+}
+
+void PMessage::DumpHead(char* nComment)
+{
+
+  char* tmpBuff = (char*) GetMessageData();
+
+  Console->Print("%s T:%02hx UID:%04hx UHID:%04hx Fnct:%02hx Seq:%04hx Cmd:%02hx Cmd2:%02hx Cmd3:%02hx",
+      nComment, (u8)tmpBuff[0], *(u16*)&tmpBuff[1], *(u16*)&tmpBuff[3], (u8)tmpBuff[6], *(u16*)&tmpBuff[7], (u8)tmpBuff[9], (u8)tmpBuff[10], (u8)tmpBuff[12] );
+
+}
diff --git a/server/src/common/netcode/serversocket.cpp b/server/src/common/netcode/serversocket.cpp
new file mode 100644 (file)
index 0000000..d604749
--- /dev/null
@@ -0,0 +1,313 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       serversocket.h - a serversocket class managing all connections (udp/tcp)\r
+\r
+       Authors:\r
+       - bakkdoor\r
+\r
+       MODIFIED: 09 Feb 2006 bakkdoor\r
+       REASON: - introduced\r
+       \r
+  MODIFIED: 27 Jun 2006 hammag\r
+       REASON: - added modif to keep m_TimeOut value in update() as select (may) modifie this\r
+                 parameter in Linux\r
+       \r
+       MODIFIED: 01 Jul 2006 hammag\r
+       REASON: - ServerSocket() : moved m_TimeOut initialization in constructor\r
+          - added settimeout() method to permit various behaviors\r
+          - ServerSocket(), open() : added m_MainSetUDP and m_MainSetGlobal init\r
+          - open() : add m_ListenerTCP to m_MainSetGlobal too\r
+          - update() : now m_MainSetGlobal is copied to m_ReadSetTCP set,\r
+                   and added a local fdMax for select\r
+          - getUDPConnection(): add new UDP socket to m_MainSetUDP and m_MainSetGlobal, \r
+                   and keep track in m_FdMaxUDP\r
+          - getTCPConnection(): add new TCP socket to m_MainSetGlobal too\r
+          - delSocketFromSet() : added removal of sockfd from m_MainSetUDP and m_MainSetGlobal too\r
+          - getTCPConnection() : moved non-blocking setting to ConnectionTCP::ConnectionTCP() for better class coherency\r
+          - getUDPConnection(): added this to new ConnectionUDP creation parameters\r
+       \r
+       MODIFIED: 05 Aug 2006 hammag\r
+       REASON: - now use UDP port in selected range for client connection (see .h)         \r
+       \r
+  TODO:   - delSocketFromSet() : Could now be improved with two separte methodes for TCP and UDP removal\r
+          - in all 3 servers: put select timeout setting in config file.\r
+               - don't access Config object from netcode's objects. Use parameter members\r
+              set by object owner.\r
+*/\r
+\r
+#include "main.h"\r
+\r
+ServerSocket::ServerSocket()\r
+{\r
+    FD_ZERO(&m_MainSetTCP);    // clear the master and temp sets\r
+    FD_ZERO(&m_ReadSetTCP);\r
+    FD_ZERO(&m_MainSetUDP);\r
+    FD_ZERO(&m_MainSetGlobal);\r
+    \r
+    m_FdMaxUDP=0;\r
+    \r
+    m_TimeOut.tv_sec = 0;\r
+    m_TimeOut.tv_usec = 30;\r
+    \r
+    //m_LastUDPPort = 5000;\r
+}\r
+\r
+ServerSocket::~ServerSocket()\r
+{\r
+    close(m_ListenerTCP);\r
+}\r
+\r
+void ServerSocket::settimeout(long timeout_sec, long timeout_usec)\r
+{\r
+  if ((timeout_sec >= 0) && (timeout_usec >= 0))\r
+  {\r
+    m_TimeOut.tv_sec = timeout_sec;\r
+    m_TimeOut.tv_usec = timeout_usec;\r
+  }\r
+    \r
+}\r
+\r
+bool ServerSocket::open(int port)\r
+{\r
+    // get the tcp listener\r
+    if ((m_ListenerTCP = socket(PF_INET, SOCK_STREAM, 0)) == -1)\r
+    {\r
+        perror("tcp-socket");\r
+        return false;\r
+    }\r
+\r
+    int yes=1;\r
+\r
+    // lose the pesky "address already in use" error message\r
+    if (setsockopt(m_ListenerTCP, SOL_SOCKET, SO_REUSEADDR, &yes,\r
+                                                        sizeof(int)) == -1) {\r
+        perror("tcp-setsockopt");\r
+        return false;\r
+    }\r
+\r
+    // bind\r
+    memset(&m_ServerAddr,0,sizeof(struct sockaddr_in));\r
+    m_ServerAddr.sin_family = AF_INET;\r
+    m_ServerAddr.sin_addr.s_addr = INADDR_ANY;\r
+    m_ServerAddr.sin_port = htons(port);\r
+\r
+    // bind with tcp sockfd\r
+    if (bind(m_ListenerTCP, (struct sockaddr *)&m_ServerAddr, sizeof(struct sockaddr)) == -1)\r
+    {\r
+        perror("tcp-bind");\r
+        return false;\r
+    }\r
+\r
+    // set listening-socket to non-blocking\r
+    fcntl(m_ListenerTCP, F_SETFL, O_NONBLOCK);\r
+\r
+    // listen\r
+    if (listen(m_ListenerTCP, 10) == -1)\r
+    {\r
+        perror("tcp-listen");\r
+        return false;\r
+    }\r
+\r
+    FD_ZERO(&m_MainSetTCP);\r
+    FD_ZERO(&m_ReadSetTCP);\r
+    FD_ZERO(&m_MainSetUDP);\r
+    FD_ZERO(&m_MainSetGlobal);\r
+    \r
+    m_FdMaxUDP=0;\r
+    \r
+    // add the listener to the master sets\r
+    FD_SET(m_ListenerTCP, &m_MainSetTCP);\r
+    FD_SET(m_ListenerTCP, &m_MainSetGlobal);\r
+\r
+    // keep track of the biggest file descriptor\r
+    m_FdMaxTCP = m_ListenerTCP; // so far, it's this one\r
+\r
+    //Console->Print("Server running on port %d", port);\r
+\r
+    return true;\r
+}\r
+\r
+void ServerSocket::update()\r
+{\r
+  struct timeval tmp_TimeOut;\r
+  int fdMax;\r
+  \r
+    // copy fd_sets from main-set to temp. read-set\r
+    m_ReadSetTCP = m_MainSetGlobal;\r
+\r
+    fdMax = max(m_FdMaxTCP, m_FdMaxUDP);\r
+    \r
+    //FD_ZERO(&m_ReadSetTCP);\r
+       //FD_SET (m_ListenerTCP, &m_ReadSetTCP);\r
+\r
+    // select incoming data for tcp & udp\r
+    tmp_TimeOut = m_TimeOut; //save m_TimeOut... will be modified by select\r
+    if (select(fdMax+1, &m_ReadSetTCP, NULL, NULL, &tmp_TimeOut) == -1)\r
+    {\r
+        perror("select");\r
+    }\r
+    \r
+    //Select exit condition logging\r
+    /*\r
+    if ((tmp_TimeOut.tv_sec == 0) && (tmp_TimeOut.tv_usec == 0))\r
+    {\r
+      Console->LPrint(GREEN, BLACK, "[Idle]");\r
+      Console->LPrint(" Exiting select on timeout (remains %d sec and %d usec)", tmp_TimeOut.tv_sec, tmp_TimeOut.tv_usec);\r
+      Console->LClose();\r
+    }\r
+    else     \r
+    {\r
+      Console->LPrint(YELLOW, BLACK, "[Active]");\r
+      Console->LPrint(" Exiting select with remaining time %d sec and %d usec", tmp_TimeOut.tv_sec, tmp_TimeOut.tv_usec);\r
+      Console->LClose();\r
+    }\r
+         */\r
+\r
+    // check for new tcp connections\r
+    if (FD_ISSET(m_ListenerTCP, &m_ReadSetTCP)) // we got one!!\r
+    {\r
+        m_bNewTCPConnection = true;\r
+    }\r
+    else\r
+    {\r
+        m_bNewTCPConnection = false;\r
+    }\r
+\r
+}\r
+\r
+bool ServerSocket::newConnection()\r
+{\r
+    return (m_bNewTCPConnection);\r
+}\r
+\r
+ConnectionTCP* ServerSocket::getTCPConnection()\r
+{\r
+    if(m_bNewTCPConnection)\r
+    {\r
+        struct sockaddr_in  RemoteAddr; // new incoming client address\r
+        socklen_t addrlen = sizeof(RemoteAddr);\r
+        int NewSockfd; // newly accept()ed socket descriptor\r
+\r
+        // handle new connections\r
+        if ((NewSockfd = accept(m_ListenerTCP, (struct sockaddr *)&RemoteAddr, &addrlen)) == -1)\r
+        {\r
+            m_bNewTCPConnection = false; // set back to normal\r
+            perror("tcp-accept");\r
+            return 0;\r
+        }\r
+        else\r
+        {\r
+            FD_SET(NewSockfd, &m_MainSetTCP); // add to master TCP set\r
+            FD_SET(NewSockfd, &m_MainSetGlobal); // add to master global set\r
+            if (NewSockfd > m_FdMaxTCP) // keep track of the maximum\r
+            {\r
+                m_FdMaxTCP = NewSockfd;\r
+            }\r
+\r
+            ConnectionTCP* tcpConn = new ConnectionTCP(NewSockfd, RemoteAddr, this);\r
+\r
+            m_bNewTCPConnection = false; // set back to normal\r
+\r
+            return tcpConn;\r
+        }\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+ConnectionUDP* ServerSocket::getUDPConnection(long remoteadress, int remoteport)\r
+{\r
+    int udpSockfd;\r
+\r
+    if ((udpSockfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)\r
+    {\r
+        perror("udp-socket");\r
+        return NULL;\r
+    }\r
+\r
+    struct sockaddr_in my_addr;\r
+\r
+    u16 Port = Config->GetOptionInt("gameserver_udpport_min");\r
+    u16 maxPort = Config->GetOptionInt("gameserver_udpport_max");\r
+\r
+    my_addr.sin_family = AF_INET;         // host byte order\r
+    my_addr.sin_port = htons(Port);     // short, network byte order\r
+    my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP\r
+    memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct\r
+\r
+    //Search a free udp port to use (could be optimised for faster port allocation)\r
+    while (bind(udpSockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)\r
+    {\r
+      if (errno == EADDRINUSE)\r
+      {       \r
+        my_addr.sin_port = htons(++Port);\r
+        if (Port > maxPort)\r
+        {\r
+          Console->Print(RED, BLACK,"No more free UDP port in configured range");\r
+          return NULL;\r
+        }\r
+      }\r
+      else\r
+      {  \r
+        perror("udp-bind");\r
+        return NULL;\r
+      }\r
+    }\r
+\r
+    FD_SET(udpSockfd, &m_MainSetUDP); // add to master UDP set\r
+    FD_SET(udpSockfd, &m_MainSetGlobal); // add to master global set\r
+    if (udpSockfd > m_FdMaxUDP) // keep track of the maximum\r
+    {\r
+        m_FdMaxUDP = udpSockfd;\r
+    }\r
+            \r
+    ConnectionUDP* udpConn = new ConnectionUDP(udpSockfd, Port, remoteadress, remoteport, this);\r
+\r
+         //m_LastUDPPort++;\r
+\r
+    return udpConn;\r
+}\r
+\r
+bool ServerSocket::isDataAvailable(int sockfd)\r
+{\r
+    if(FD_ISSET(sockfd, &m_ReadSetTCP))\r
+    {\r
+        return true;\r
+    }\r
+\r
+    return false;\r
+}\r
+\r
+void ServerSocket::delSocketFromSet(int sockfd)\r
+{\r
+    FD_CLR(sockfd, &m_MainSetTCP);\r
+    FD_CLR(sockfd, &m_MainSetUDP);\r
+    FD_CLR(sockfd, &m_MainSetGlobal);\r
+}\r
+\r
+void ServerSocket::closeServer()\r
+{\r
+    close(m_ListenerTCP);\r
+}\r
diff --git a/server/src/common/netcode/udpmanager.cpp b/server/src/common/netcode/udpmanager.cpp
new file mode 100644 (file)
index 0000000..5bed273
--- /dev/null
@@ -0,0 +1,166 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+       udpmanager.cpp - Manager for UDP Messages. Watches UDP_ID's and keeps\r
+                     message history for possible OutOfOrder requests\r
+*/\r
+\r
+#include "main.h"\r
+\r
+void ConnectionUDP::UpdateMessageBuffer()\r
+{\r
+    int erasednum = 0;\r
+    // Delete all old messages\r
+    for(PMessageMap::iterator it=UDPMessages.begin(); it!=UDPMessages.end(); it++)\r
+    {\r
+        if((int)it->first < (int)(mLastUDPID - MAX_RETENTION))\r
+        {\r
+            erasednum++;\r
+            delete it->second;\r
+            UDPMessages.erase(it);\r
+        }\r
+    }\r
+    /* // Debug output\r
+    if(erasednum > 0)\r
+        Console->Print("[UpdateMessageBuffer] Done updating messagequeue, %d entries deleted", erasednum);\r
+    */\r
+}\r
+\r
+void ConnectionUDP::ResetMessageBuffer()\r
+{\r
+    if(mUDP_ID != 0)\r
+    {\r
+        Console->Print("%s MessageQueue got erased but UDP_ID is still >0", Console->ColorText(RED, BLACK, "[WARNING]"));\r
+    }\r
+    for(PMessageMap::iterator it=UDPMessages.begin(); it!=UDPMessages.end(); it++)\r
+    {\r
+        delete it->second;\r
+        UDPMessages.erase(it);\r
+    }\r
+    mLastUDPID = 0;\r
+//    Console->Print("[udpmanager] Erased messagebuffer");\r
+}\r
+\r
+void ConnectionUDP::ReSendUDPMessage(u16 nUDP_ID)\r
+{\r
+    // ReSend packet with given UDP_ID\r
+    if(nUDP_ID > mLastUDPID)\r
+    {\r
+        Console->Print("%s Cannot resend packet with UDP_ID %d, msgnumber is higher than last known udpID", Console->ColorText(RED, BLACK, "[PANIC]"), nUDP_ID);\r
+    }\r
+    else\r
+    {\r
+        // UDP_ID seems to be valid, now search for it\r
+        PMessageMap::const_iterator it = UDPMessages.find(nUDP_ID);\r
+        if(it == UDPMessages.end())\r
+        {\r
+            int dynRetention = (int)mLastUDPID - nUDP_ID;\r
+            if(dynRetention > MAX_RETENTION)\r
+            {\r
+                Console->Print("%s Packet with UDP_ID %d not found. Increase #define MAX_RETENTION to at least %d", Console->ColorText(RED, BLACK, "[WARNING]"), nUDP_ID, dynRetention);\r
+            }\r
+            else\r
+            {\r
+                Console->Print("%s Packet with UDP_ID %d is missing in the packet queue!", Console->ColorText(RED, BLACK, "[PANIC]"), nUDP_ID);\r
+            }\r
+            Console->Print("Trying to cancel OOO notice by sending dummy packet");\r
+            PMessage* tmpMsg = new PMessage(14);\r
+            //u16 tmpSessionID = mLastUDPID + SESSION_UDP_OFFSET;\r
+            *tmpMsg << (u8)0x13;\r
+            *tmpMsg << nUDP_ID;\r
+            *tmpMsg << (u16)(nUDP_ID + SESSION_UDP_OFFSET);\r
+            *tmpMsg << (u8)0x08;\r
+            *tmpMsg << (u8)0x03;\r
+            *tmpMsg << nUDP_ID;\r
+            *tmpMsg << (u8)0x1F;\r
+            *tmpMsg << (u16)0xFFFF;     // Should do nothing, CharID 65535 should never exist\r
+            *tmpMsg << (u16)0x3C01;     // This value IS wrong way, so that nothing can happen at all\r
+            SendMessage(tmpMsg, true);\r
+        }\r
+        else if(it->second)\r
+        {\r
+            Console->Print("[OOO-Buster] ReSending UDP packet with ID %d", nUDP_ID);\r
+            // Build new message, including the missing UDP packets as content\r
+            u16 MsgSize = it->second->GetSize();\r
+            PMessage* tmpMsg = new PMessage(MsgSize + 5); // Create new message\r
+            *tmpMsg << (u8)0x13;\r
+            *tmpMsg << nUDP_ID;\r
+            *tmpMsg << (u16)(nUDP_ID + SESSION_UDP_OFFSET);\r
+//            *tmpMsg << mUDP_ID;\r
+//            *tmpMsg << mSessionID;\r
+//            *tmpMsg << *it->second; // This should work, but it doesnt! Causes segfault after sending a few packets\r
+            for(int x = 0; x < MsgSize; x++)\r
+            {\r
+                *tmpMsg << it->second->U8Data(x);\r
+            }\r
+            SendMessage(tmpMsg, true);  // Add message to outgoing VIP queue\r
+        }\r
+    }\r
+}\r
+\r
+void ConnectionUDP::InsertUDPMessage(PMessage* nMsg)\r
+{\r
+    if (!nMsg)\r
+        return;\r
+\r
+    if(nMsg->U8Data(0) != 0x13) return; // Only add real UDP messages here\r
+//  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28\r
+// 13 07 00 F2 00 05 03 02 00 11 11 05 03 03 00 11 11 05 03 04 00 11 11 05 03 05 00 11 11 05 03 06 00 11 11 05 03 07 00 11 11\r
+\r
+    // Grab submessages from packet, check if message is 0x03 commandset. If not, dont add message\r
+    PMessage* tWorkMsg = NULL;\r
+\r
+    u16 tCurPos = 5;\r
+    u8 tSubMsgLen = 0;\r
+    u16 tmpUDPID = 0;\r
+    //nMsg->Dump();\r
+    while(tCurPos < (nMsg->GetSize() - 1)) // Loop while we still have more frames. (-1: GetSize starts at 1, pos pointer at 0)\r
+    {\r
+        //Console->Print("tCurPos = %d  nMsg->GetSize = %d", tCurPos, nMsg->GetSize());\r
+        tSubMsgLen = nMsg->U8Data(tCurPos) + 1;          // Get the lenght of the frame, and add the lenght byte\r
+        if(nMsg->U8Data(tCurPos+1) != 0x03)\r
+        {\r
+            //Console->Print("Ignoring UDP message, no 0x03 commandset");\r
+            tCurPos += tSubMsgLen;                       // Set pointer to the end of this frame\r
+            continue;                                    // Skip if frame is not an 0x03 commandset\r
+        }\r
+        //Console->Print("MsgLen: %d", tSubMsgLen);\r
+        tWorkMsg = nMsg->GetChunk(tCurPos, tSubMsgLen); // get the frame.\r
+        //Console->Print("Msg:");\r
+        //tWorkMsg->Dump();\r
+        tmpUDPID = nMsg->U16Data(tCurPos + 2);                     // Get the UDP ID of this frame\r
+        //Console->Print("UDP ID: %d", tmpUDPID);\r
+        PMessageMap::const_iterator it = UDPMessages.find(tmpUDPID);                 // Try to find the UDP ID in the queue\r
+        if(it->second)                                   // If we already have this UDP msg, print error\r
+        {\r
+            Console->Print("%s Packet *NOT* added to history buffer, UdpID %d already sent! (This may cause an OOO)", Console->ColorText(RED, BLACK, "[WARNING]"), tmpUDPID);\r
+            nMsg->Dump();\r
+        }\r
+        else                                            // We dont have this msg? Add it!\r
+        {\r
+            //Console->Print("Added UDP ID %d to messagebuffer", tmpUDPID);\r
+            UDPMessages.insert(std::make_pair(tmpUDPID, tWorkMsg));\r
+            mLastUDPID++;\r
+        }\r
+        tCurPos += tSubMsgLen;                      // Set pointer to the end of this frame\r
+    }\r
+}\r
diff --git a/server/src/common/regex/Makefile b/server/src/common/regex/Makefile
new file mode 100644 (file)
index 0000000..5fb25e9
--- /dev/null
@@ -0,0 +1,83 @@
+#
+# TinNS per-directory Makefile
+#
+# Adapted by Hammag from the Makefile system for Linux kernel.
+#
+# 14 Sep 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+# 
+
+######################################################
+# Target for this directory and its sub-dirs
+######################################################
+# Case 1 : target is an executable named as defined
+#B_TARGET := testor2 
+
+# Case 2 : target is a TinNS lib name
+#  (use short name, as in -l linker option) 
+L_TARGET := tinns
+
+# Case 3 (usual): objects shall be made available to the parent dir
+#  The following line will set that automatically 
+# (Should match dir name + .o suffix)
+#O_TARGET := $(addsuffix .o,$(notdir $(shell /bin/pwd)))
+# Manualy define this only if you need to force the compiled obj name
+#O_TARGET := game.o
+
+
+######################################################
+# Local flags
+######################################################
+# local dir CXX Flags
+#EXTRA_CXXFLAGS := -I/usr/include/mysql
+
+# per-object CXX Flags
+#CXXFLAGS_funcdef2.o := -g
+
+# local dir Linker Flags (for intermediate .o linking)
+#EXTRA_LDFLAGS := 
+
+# any tinns Lib used (short name, as in -l linker option)
+#LINK_TINNSLIBS := tinns
+
+# local dir Linker Flags (for final executable linking)
+#EXTRA_LINKFLAGS := -lrt -lpthread -lz -lm -lcrypt -L"/usr/lib/mysql" -lmysqlclient
+
+
+#####################################################
+# Subdirectories
+#####################################################
+#subdir-y := def 
+#subdir-$(CONFIG_GAMEMONKEY)   += gamemonkey
+
+
+#####################################################
+#***************************************************#
+# No further config should be needed after this line
+#***************************************************#
+ifdef TOPDIR
+
+# build list of objects ib loca ldir
+obj-y := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
+# add final object from each subdir
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+
+include $(TOPDIR)/Rules.make
+
+else #TOPDIR undef, Makefile called from non-top dir
+
+# Memorize the first calling dir in case we wanted to
+# lauch local actions from top Makefile
+  ifndef FIRSTDIR
+    FIRSTDIR :=$(CURDIR)
+    export FIRSTDIR
+  endif
+
+uptoparent : 
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+.DEFAULT :
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+endif #TOPDIR
+
diff --git a/server/src/common/regex/regex++.cpp b/server/src/common/regex/regex++.cpp
new file mode 100755 (executable)
index 0000000..d3a2a88
--- /dev/null
@@ -0,0 +1,55 @@
+//
+// regex.hpp 1.0 Copyright (c) 2003 Peter Petersen (pp@on-time.de)
+// Simple C++ wrapper for PCRE
+//
+// This source file is freeware. You may use it for any purpose without
+// restriction except that the copyright notice as the top of this file as
+// well as this paragraph may not be removed or altered.
+//
+#include <string.h>
+#include "regex++.h"
+
+RegEx::RegEx(const char * regex, int options)
+{
+   const char * error;
+   int          erroffset;
+
+   re = pcre_compile(regex, options, &error, &erroffset, NULL);
+   if (re == NULL)
+      throw error;
+   pe = pcre_study(re, 0, &error);
+   pcre_fullinfo(re, pe, PCRE_INFO_CAPTURECOUNT, &substrcount);
+   substrcount++;
+   ovector = new int[3*substrcount];
+   matchlist = NULL;
+}
+
+RegEx::~RegEx()
+{
+   ClearMatchList();
+   delete ovector;
+   if (pe)
+      pcre_free(pe);
+   pcre_free(re);
+}
+
+bool RegEx::Search(const char * subject, int len, int options)
+{
+   ClearMatchList();
+   return pcre_exec(re, pe, lastsubject = subject, slen = (len >= 0) ? len : strlen(subject), 0, options, ovector, 3*substrcount) > 0;
+}
+
+bool RegEx::SearchAgain(int options)
+{
+   ClearMatchList();
+   return pcre_exec(re, pe, lastsubject, slen, ovector[1], options, ovector, 3*substrcount) > 0;
+}
+
+const char * RegEx::Match(int i)
+{
+   if (i < 0)
+      return lastsubject;
+   if (matchlist == NULL)
+      pcre_get_substring_list(lastsubject, ovector, substrcount, &matchlist);
+   return matchlist[i];
+}
diff --git a/server/src/dev-tools/Makefile b/server/src/dev-tools/Makefile
new file mode 100644 (file)
index 0000000..5ca43b1
--- /dev/null
@@ -0,0 +1,10 @@
+all: cleandepfile
+#all: cleandepfile svnrev
+
+cleandepfile: cleandepfile.c
+       $(HOSTCC) $(HOSTCFLAGS) -o $@ $<
+
+#svnrev: getsvnrev.cpp
+#      g++ -pedantic -Wall -c getsvnrev.cpp -o getsvnrev.o
+#      g++ -o getsvnrev getsvnrev.o -lstdc++ -lz
+
diff --git a/server/src/dev-tools/cleandepfile.c b/server/src/dev-tools/cleandepfile.c
new file mode 100755 (executable)
index 0000000..2ff870b
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+/*
+  This tool is to be used on output from gcc -MD -MP
+  in order to filter out standard files from dependency list
+  
+  It is needed because a simple egrep -v would not leave the file in
+  valid format
+*/
+
+/*
+       cleandepfile.c
+
+       CREATED: 11 Dec 2006 Hammag
+*/
+
+#include <string.h>
+#include <stdio.h>
+
+char in_buff[1024];
+
+char* filter_out[] = {
+  "/usr/include/",
+  "/usr/lib/",
+  "/usr/local/lib/"
+};
+#define filter_nb 3
+int filter_len[filter_nb];
+
+void init_filter(void)
+{
+  int i;
+  
+  for (i=0; i<filter_nb; i++)
+  {
+    filter_len[i] = strlen(filter_out[i]);
+  } 
+}
+
+int check_filter(char* buffer)
+{
+  int i;
+  
+  for (i=0; i<filter_nb; i++)
+  {
+    if (!strncmp(buffer, filter_out[i], filter_len[i]))
+    {
+      return 0;
+    }
+  }
+  return 1;
+}
+
+int main(int argc, char **argv)
+{
+  int ret;
+  int len;
+  int inside = 0;
+  
+  init_filter();
+  
+  while(1)
+  {
+    ret = scanf("%1023s", in_buff);
+    if (ret == EOF) break;
+    if (ret == 0) continue;
+    
+    len = strlen(in_buff);
+    switch (in_buff[len-1])
+    {
+      case ':':
+      {
+        if (check_filter(in_buff))
+        {
+          printf("\n%s", in_buff);
+          inside = 1;
+        }
+        else
+        {
+          inside = 0;
+        }
+        break; 
+      }
+      
+      case '\\':
+      {
+        if (len == 1)
+          break;
+        else
+          in_buff[len-1] = 0;
+      }
+      default:
+      {
+        if (inside && check_filter(in_buff))
+          printf(" \\\n  %s", in_buff);
+        break; 
+      }
+    }
+    
+  }
+  printf("\n");
+
+  return 0; 
+}
diff --git a/server/src/dev-tools/getsvnrev.cpp b/server/src/dev-tools/getsvnrev.cpp
new file mode 100644 (file)
index 0000000..6dcd144
--- /dev/null
@@ -0,0 +1,101 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       pak_decompress - pak file decompression tool\r
+       Copyright (C) 2005 Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       getsvnrev - a simple tool to read out actual SVN revision-number\r
+\r
+       Why?\r
+               Well for example my server doesnt have any SVN libs installed. Therefore,\r
+               the getsvnrev script fails. I need this little tool, and maybe someone else too ^^\r
+\r
+       Usage: \r
+               call getsvnrev either without parameters or with the directory you\r
+               want to know the SVN revision.\r
+       \r
+       Console output:\r
+               If no .svn directory is found, the tool returns 0.\r
+               Otherwise it will return the SVN revision of the target dir\r
+\r
+       MODIFIED: 22 Dec 2006 Namikon\r
+       REASON: - started this tool\r
+\r
+       TODO:\r
+               - Better way to get SVN rev than this (2nd number in file)\r
+*/\r
+\r
+\r
+#include <stdio.h>\r
+#include <iostream>\r
+\r
+using namespace std;\r
+\r
+int main(int argc, char **argv)\r
+{\r
+        string targetdir;\r
+       FILE *f;\r
+\r
+        if(argc == 2)\r
+       {\r
+               int i = 0;\r
+               while(argv[1][i] != '\0') { i++; };\r
+               if(argv[1][i-1] == '/')\r
+               {\r
+                       targetdir = strcat(argv[1], ".svn/entries");\r
+               }\r
+               else\r
+               {\r
+                       targetdir = strcat(argv[1], "/.svn/entries");\r
+               }\r
+        }\r
+       else\r
+       {\r
+               targetdir = ".svn/entries";\r
+       }\r
+\r
+\r
+        if ((f = fopen(targetdir.c_str(), "r")) != NULL) {\r
+                char line[255];\r
+                int rev;\r
+               bool firstnrfound = false;\r
+               \r
+               do\r
+               {\r
+                  fgets (line, 255, f);\r
+                  rev = atoi(line);\r
+                  if(rev > 0 && firstnrfound == false)\r
+                  {\r
+                       firstnrfound = true;\r
+                       rev = 0;\r
+                   }\r
+               } while (rev == 0);\r
+               \r
+                fclose(f);\r
+\r
+                cout << rev << endl;\r
+        }\r
+       else\r
+       {\r
+               cout << "0" << endl;\r
+       }\r
+       return(0);\r
+}\r
diff --git a/server/src/dev-tools/make-bin-tarball b/server/src/dev-tools/make-bin-tarball
new file mode 100755 (executable)
index 0000000..f773edd
--- /dev/null
@@ -0,0 +1,60 @@
+#!/bin/bash
+# This script is to be launched from TinNS src directory
+#
+if [[ $# -ne 3 ]]; then
+       echo
+       echo "Error - usage:" `basename $0` "<dest base path> <svnrevision.h file> <bin dir>" >&2
+       exit 1
+fi
+
+if [[ ! -d $1 ]]; then
+       echo
+       echo "Destination directory $1 doesn't exist !"
+       exit 2
+fi
+
+if [[ -f options.local ]]; then
+       echo
+       echo "WARNING: Local option file 'options.local' is present. Compiled binaries might be unsuitable for distribution depending on the options you put in this file."
+       grep -v '#' options.local |grep DO_DEBUG > /dev/null
+       if [[ $? -eq 0 ]]; then
+       echo
+               echo "Debug Symbols Generation is activated !!! Binaries will be HUGE !"
+       fi
+       echo
+       echo -e "\tContinue with archive building ? (y/N)"
+       read -s -n 1 answer
+       if [[ "$answer" != "y" ]]; then
+               exit 3
+       fi
+fi
+
+if [[ ! -d ../.svn ]]; then
+       current=`grep TINNS_SVN_REVISION $2 | sed 's/^.*"\([0-9]\+\)".*$/\1/'`
+else
+       v=`svnversion ..`
+       current=`echo $v | sed 's/^\([0-9]*:\)\?\([0-9]\+[^0-9]*\)/\2/'`
+fi
+
+destfile=$1/tinns_v2.r${current}_bin.tar.bz2
+
+cd ..
+tar -cj --exclude .svn -f $destfile -T - <<ENDOFLIST
+./LICENSE.txt
+./CHANGELOG
+./docs
+./database
+`find ./conf -name "*.conf" -type f`
+$3/gameserver
+$3/infoserver
+$3/patchserver
+ENDOFLIST
+
+echo
+if [[ $? -eq 0 ]]; then
+       echo "Binary archive built:"
+else
+       echo "An error occured ! Could not build binary archive :"
+fi
+echo $destfile
+
diff --git a/server/src/dev-tools/make-src-tarball b/server/src/dev-tools/make-src-tarball
new file mode 100755 (executable)
index 0000000..01c4984
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/bash
+# This script is to be launched from TinNS src directory
+#
+if [[ $# -ne 2 ]]; then
+       echo
+       echo "Error - usage:" `basename $0` "<dest base path> <svnrevision.h file>" >&2
+       exit 1
+fi
+
+if [[ ! -d $1 ]]; then
+       echo
+       echo "Destination directory $1 doesn't exist !"
+       exit 2
+fi
+
+if [[ ! -d ../.svn ]]; then
+       current=`grep TINNS_SVN_REVISION $2 | sed 's/^.*"\([0-9]\+\)".*$/\1/'`
+else
+       v=`svnversion ..`
+       current=`echo $v | sed 's/^\([0-9]*:\)\?\([0-9]\+[^0-9]*\)/\2/'`
+fi
+
+destfile=$1/tinns_v2.r${current}_src.tar.bz2
+
+cd ..
+tar -cj --exclude .svn -f $destfile -T - <<ENDOFLIST
+./LICENSE.txt
+./CHANGELOG
+./WORK_IN_PROGRESS
+./docs
+./database
+`find ./conf -name "*.conf" -type f`
+./src/dev-tools/setsvnrev
+./src/dev-tools/make-src-tarball
+./src/dev-tools/make-bin-tarball
+./src/Rules.make
+`find . \( -name "Makefile" -o -name "*.h" -o -name "*.cpp" -o -name "*.c" \) -type f`
+ENDOFLIST
+
+echo
+if [[ $? -eq 0 ]]; then
+       echo "Source archive built:"
+else
+       echo "An error occured ! Could not build source archive :"
+fi
+echo $destfile
+
diff --git a/server/src/dev-tools/setsvnrev b/server/src/dev-tools/setsvnrev
new file mode 100755 (executable)
index 0000000..33ccb14
--- /dev/null
@@ -0,0 +1,119 @@
+#!/bin/bash
+#
+###########################################################
+# setsvnrev script for TinNS. Original written by Hammag, #
+# improved by Namikon.                                    #
+# See bottom of file for GPL license.                     #
+###########################################################
+#                                                         #
+# Last edited: 08.01.2076 18:02 GMT +1 by Hammag          #
+#                                                         #
+###########################################################
+# How this works:                                         #
+#    Everytime you do "make", this script is called.      #
+#    It will check the current svn headerfile if its      #
+#    a new revision or just a recompile.                  #
+#    IF it is a new revision, the script tries to get     #
+#    the actual version from the official SVN             #
+#    tool "svnversion". If your server has no SVN         #
+#    installed (which is not good if you want to          #
+#    participate in TinNS dev), or it is outdated for     #
+#    some reason, you must manually update svnrev.h       #
+#    This number is then written to svnrev.h, compiled    #
+#    into Patch, Info and Gameserver, and can be viewed   #
+#    ingame by typing @version                            #
+###########################################################
+
+if [[ $# -ne 2 ]]; then
+       echo "Error - usage:" `basename $0` "<svn base path> <svnrev.h filepath>" >&2
+       exit -1
+fi
+
+#We exit silently if no SVN system seem to be used locally
+if [[ ! -d $1/.svn ]]; then exit 0; fi
+v=`svnversion $1`
+if [[ $? -ne 0 ]]; then
+       echo "###### WARNING : can't get SVN revision number ######"
+       echo " You must manually update rev number in include/version.h before any public release !"
+       if [[ ! -f .no_msg_stop ]]; then
+               echo
+               echo ---- Press a key to continue ----
+                read -s -n 1
+               touch .no_msg_stop
+       fi
+       exit 0
+fi
+#if expr "$v" : '[0-9]\+$' > /dev/null; then
+       current=`echo $v | sed 's/^\([0-9]*:\)\?\([0-9]\+\)[^0-9]*/\2/'`
+       modif=`echo $v | sed 's/^\([0-9]*:\)\?[0-9]\+[^0-9]*\(M\)/\2/'`
+       #echo svnver: $v
+       #echo current: $current
+       #echo modif: $modif
+
+       if [[ $modif == M ]]; then
+               current=$[$current + 1];
+       fi
+#else
+#      v=`$1/dev-tools/getsvnrev $1`
+#      if [ "$v" = "0" ]; then
+#              exit 0;
+#      fi
+#      if ! expr "$v" : '[0-9]\+$' > /dev/null; then
+#              echo "Error: Unable to get SVN Revision!";
+#              exit 0;
+#      fi
+#      if [ -z "$v" ]; then
+#                echo "Error: Unable to get SVN Revision!";
+#                exit 0;
+#      fi
+#      current="$v"
+#fi
+
+filever=`grep TINNS_SVN_REVISION $2 | sed 's/^.*"\([0-9]\+\)".*$/\1/'`
+#echo svnver in file: $filever
+
+if [[ $filever -ge $current ]]; then
+       echo No SVN Revision number change needed
+       exit 0;
+fi
+
+echo Updating SVN Revision number to $current
+
+cat >$2 <<ENDOFDOC
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+/*
+       THIS FILE IS GENERATED BY THE MAKE COMMAND make svnrev
+       It is to be updated by this command before each revision commit operation
+       PLEASE DON'T MODIFY BY HAND
+*/
+
+#ifndef SVN_REV_DEF
+#define SVN_REV_DEF
+
+#define TINNS_SVN_REVISION "$current"
+
+#endif
+
+ENDOFDOC
+
diff --git a/server/src/game/Makefile b/server/src/game/Makefile
new file mode 100644 (file)
index 0000000..bf15587
--- /dev/null
@@ -0,0 +1,84 @@
+#
+# TinNS per-directory Makefile
+#
+# Adapted by Hammag from the Makefile system for Linux kernel.
+#
+# 14 Sep 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+# 
+
+######################################################
+# Target for this directory and its sub-dirs
+######################################################
+# Case 1 : target is an executable named as defined
+B_TARGET := gameserver 
+
+# Case 2 : target is a TinNS lib name
+#  (use short name, as in -l linker option) 
+#L_TARGET := tinns
+
+# Case 3 (usual): objects shall be made available to the parent dir
+#  The following line will set that automatically 
+# (Should match dir name + .o suffix)
+#O_TARGET := $(addsuffix .o,$(notdir $(shell /bin/pwd)))
+# Manualy define this only if you need to force the compiled obj name
+#O_TARGET := game.o
+
+
+######################################################
+# Local flags
+######################################################
+# local dir CXX Flags
+EXTRA_CXXFLAGS := -I/usr/include/mysql -Iinclude 
+
+# per-object CXX Flags
+#CXXFLAGS_funcdef2.o := -g
+
+# local dir Linker Flags (for intermediate .o linking)
+#EXTRA_LDFLAGS := 
+
+# any tinns Lib used (short name, as in -l linker option)
+LINK_TINNSLIBS := tinns
+
+# local dir Linker Flags (for final executable linking)
+#EXTRA_LINKFLAGS := -lpthread -lm -lcrypt -lrt -L"/usr/lib/mysql" -lmysqlclient -lz
+EXTRA_LINKFLAGS := -lrt -L"/usr/lib/mysql" -lmysqlclient -lz -lpcre -llua
+
+
+#####################################################
+# Subdirectories
+#####################################################
+subdir-y := decoder def gamecommands
+#subdir-$(CONFIG_GAMEMONKEY)   += gamemonkey
+
+
+#####################################################
+#***************************************************#
+# No further config should be needed after this line
+#***************************************************#
+ifdef TOPDIR
+
+# build list of objects ib loca ldir
+obj-y := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
+# add final object from each subdir
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+
+include $(TOPDIR)/Rules.make
+
+else #TOPDIR undef, Makefile called from non-top dir
+
+# Memorize the first calling dir in case we wanted to
+# lauch local actions from top Makefile
+  ifndef FIRSTDIR
+    FIRSTDIR :=$(CURDIR)
+    export FIRSTDIR
+  endif
+
+uptoparent : 
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+.DEFAULT :
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+endif #TOPDIR
+
diff --git a/server/src/game/accounts.cpp b/server/src/game/accounts.cpp
new file mode 100644 (file)
index 0000000..cb110fa
--- /dev/null
@@ -0,0 +1,461 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       accounts.cpp\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+       MODIFIED: 26 Dec 2005 Namikon\r
+       REASON: - Added SQLLoad to PAccounts. First step in adding MySQL support to accounts\r
+       MODIFIED: 01 Jan 2006 Namikon\r
+       REASON: - Changed FmtTxt() to sprintf(). It does... uhm, the same :D\r
+       MODIFIED: 06 Jan 2006 Namikon\r
+       REASON: - Removed the old XML loading functions, and changed the SQL ones to work with the Global Neopolis/TinNS Database\r
+          - Added SetBannedStatus(<unix timestamp>) to ban/unban an account (use SetBannedStatus(0) to unban a player)\r
+       MODIFIED: 03 Oct 2006 Hammag\r
+       REASON: - Fixed an issue in PAccount::SetBannedStatus() that was causing the "can't update banned status" error message.\r
+\r
+       MODIFIED: 27 May 2007 Hammag\r
+       REASON: - Full changes for on-demand account access (no more memory-resident account data)\r
+*/\r
+\r
+\r
+/*\r
+NOTE ABOUT ACCESS LEVELS IN THE MYSQL DATABASE:\r
+a_priv:\r
+0 = unregistered user\r
+1 = Registered user\r
+30 = volunteer\r
+50 = GM\r
+100 = Admin\r
+\r
+a_status:\r
+0 = Offline\r
+1 = Online\r
+2 = Banned\r
+*/\r
+#include "main.h"\r
+#include "accounts.h"\r
+\r
+/** Static members **/\r
+RegEx* PAccount::mUsernameRegexFilter = NULL;\r
+RegEx* PAccount::mPasswordRegexFilter = NULL;\r
+\r
+bool PAccount::SetUsernameRegexFilter(const char* RegexStr)\r
+{\r
+  if(mUsernameRegexFilter)\r
+  {\r
+    delete mUsernameRegexFilter;\r
+    mUsernameRegexFilter = NULL;\r
+  }\r
+  \r
+  if(RegexStr)\r
+  {\r
+    try {\r
+      mUsernameRegexFilter = new RegEx(RegexStr, PCRE_CASELESS);\r
+    }\r
+    catch (...) {\r
+      return false;\r
+    }\r
+  }\r
+  return true;\r
+}\r
+\r
+bool PAccount::SetPasswordRegexFilter(const char* RegexStr)\r
+{\r
+  if(mPasswordRegexFilter)\r
+  {\r
+    delete mPasswordRegexFilter;\r
+    mPasswordRegexFilter = NULL;\r
+  }\r
+  \r
+  if(RegexStr)\r
+  {\r
+    try {\r
+      mPasswordRegexFilter = new RegEx(RegexStr, PCRE_CASELESS);\r
+    }\r
+    catch (...) {\r
+      return false;\r
+    }\r
+  }\r
+  return true;\r
+}\r
+\r
+bool PAccount::IsUsernameWellFormed(const char *Username)\r
+{\r
+  if(mUsernameRegexFilter)\r
+  {\r
+    return mUsernameRegexFilter->Search(Username);\r
+  }\r
+  else\r
+    return true;\r
+}\r
+\r
+bool PAccount::IsPasswordWellFormed(const char *Password)\r
+{\r
+  if(mPasswordRegexFilter)\r
+  {\r
+    return mPasswordRegexFilter->Search(Password);\r
+  }\r
+  else\r
+    return true;\r
+}\r
+\r
+/** Instance members **/           \r
+PAccount::PAccount()\r
+{\r
+       mID = 0;\r
+       mLevel = PAL_BANNED;\r
+  mStatus = PAS_OFFLINE;\r
+  mBannedUntil = 0;\r
+}\r
+\r
+PAccount::PAccount(const u32 AccountId)\r
+{\r
+  char query[256];\r
+  mID = 0;\r
+  snprintf(query, 256, "SELECT * FROM accounts WHERE a_id = %d LIMIT 1;", AccountId);\r
+  LoadFromQuery(query);\r
+}\r
+\r
+PAccount::PAccount(const char *Username)\r
+{\r
+  char query[256];\r
+  mID = 0;\r
+  if(IsUsernameWellFormed(Username)) {\r
+    char escUsername[256];\r
+    MySQL->EscapeString(Username, escUsername, 256);\r
+    snprintf(query, 256, "SELECT * FROM accounts WHERE a_username = '%s' LIMIT 1;", escUsername);\r
+    LoadFromQuery(query);\r
+  }\r
+}\r
+\r
+bool PAccount::LoadFromQuery(char* query)\r
+{\r
+  MYSQL_ROW row = 0;\r
+  MYSQL_RES *result = 0;\r
+  \r
+  bool FinalResult = false;\r
+\r
+  result = MySQL->InfoResQuery(query);\r
+  if(result == NULL)\r
+  {\r
+      Console->Print(RED, BLACK, "Failed to load AccountData from SQL");\r
+      MySQL->ShowInfoSQLError();\r
+      return false;\r
+  }\r
+\r
+  if((row = mysql_fetch_row(result)))\r
+  {\r
+    mID = atoi(row[a_id]);\r
+    mName = row[a_username];\r
+    mPassword = row[a_password];\r
+\r
+    mBannedUntil = atoi(row[a_bandate]);\r
+    if(mBannedUntil > time(NULL))\r
+    {\r
+      mStatus = PAS_BANNED;\r
+      mLevel = PAL_BANNED;\r
+    }\r
+    else\r
+    {\r
+      mStatus = PAS_OFFLINE;\r
+      mLevel = atoi(row[a_priv]);\r
+    }\r
+\r
+    FinalResult = true;\r
+  }\r
+  else\r
+  {\r
+Console->Print(YELLOW, BLACK, "Failed to load AccountData from SQL; Nothing to load...");\r
+  }\r
+  \r
+  MySQL->FreeInfoSQLResult(result);\r
+  return FinalResult;\r
+}\r
+\r
+bool PAccount::SetName(const std::string &Username)\r
+{\r
+  if(IsUsernameWellFormed(Username.c_str()))\r
+  {\r
+    mName = Username;\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    return false;\r
+  }\r
+}\r
+\r
+bool PAccount::SetPassword(const std::string &Password)\r
+{\r
+  if(IsPasswordWellFormed(Password.c_str()))\r
+  {\r
+    mPassword = Password;\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    return false;\r
+  }\r
+}\r
+\r
+bool PAccount::SetPasswordEncoded(const u8* PasswordData, int PassLen, const u8* Key)\r
+{\r
+       char Pass[128];\r
+       \r
+       if(DecodePassword(PasswordData, PassLen, Key, Pass))\r
+  {\r
+               return SetPassword((std::string)Pass);\r
+       }\r
+       else\r
+       {\r
+               Console->Print(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen);\r
+               return false;\r
+       }\r
+}\r
+\r
+bool PAccount::SetLevel(int newLevel)\r
+{\r
+  if((newLevel >= PAL_BANNED) && (newLevel <= PAL_ADMIN))\r
+  {\r
+    mLevel = newLevel;\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    return false;\r
+  }\r
+}\r
+\r
+std::string PAccount::GetLevelString() const\r
+{\r
+       switch(mLevel)\r
+       {\r
+               case PAL_BANNED : return "banned";\r
+               case PAL_UNREGPLAYER : return "unregplayer";\r
+               case PAL_REGPLAYER : return "regplayer";\r
+               case PAL_VOLUNTEER : return "volunteer";\r
+               case PAL_GM : return "gm";\r
+               case PAL_ADMIN : return "admin";\r
+       }\r
+\r
+       return "custom";\r
+}\r
+\r
+bool PAccount::SetStatus(PAccountStatus Status)\r
+{\r
+  mStatus = Status;\r
+  return true;\r
+}\r
+\r
+bool PAccount::SetBannedUntilTime(std::time_t BannedUntil)\r
+{\r
+  if ((BannedUntil == 0) || (BannedUntil > std::time(NULL)))\r
+  {\r
+    mBannedUntil = BannedUntil;\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    return false;\r
+  }\r
+}\r
+\r
+bool PAccount::DecodePassword(const u8* PasswordData, int PassLen, const u8 *Key, char* ClearPassword)\r
+{\r
+  ClearPassword[0] = 0;\r
+  \r
+  if(PassLen < 128)\r
+       {\r
+               if(Key[0]>7) // TODO: >7 correct?\r
+               {\r
+                       for(int i=0; i<PassLen; i+=2)\r
+                               ClearPassword[i>>1] = (char)(((PasswordData[i]&0xf0)>>4)\r
+                                       +((PasswordData[i+1]&0x0f)<<4)-Key[0]);\r
+                       ClearPassword[PassLen>>1]=0;\r
+               }\r
+               else\r
+               {\r
+                       for(int i=0; i<PassLen; i++)\r
+                               ClearPassword[i] = (char)(PasswordData[i]-Key[0]);\r
+                       ClearPassword[PassLen]=0;\r
+               }\r
+               return true;\r
+       }\r
+       else\r
+         return false;\r
+}\r
+\r
+bool PAccount::Authenticate(const u8* PasswordData, int PassLen, const u8 *Key)\r
+{\r
+       char Pass[128];\r
+       \r
+       if(DecodePassword(PasswordData, PassLen, Key, Pass))\r
+  {\r
+               return Authenticate(Pass);\r
+       }\r
+       else\r
+       {\r
+               Console->Print(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen);\r
+               return false;\r
+       }\r
+}\r
+\r
+bool PAccount::Authenticate(const char *Password) const\r
+{\r
+       if(mID == 0) // User doesn't exist and that hasn't been checked !\r
+       {\r
+         Console->Print(RED, BLACK, "[Bug]: user %s doesn't exist and was not checked by code !", mName.c_str());\r
+         return false;\r
+       }\r
+       \r
+       return(mPassword == Password);\r
+}\r
+\r
+bool PAccount::Create()\r
+{\r
+  if(Save(true)) {\r
+    mID = MySQL->GetLastInfoInsertId();\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    return false;\r
+  }\r
+}\r
+\r
+bool PAccount::Save(bool CreateMode)\r
+{\r
+  char escUsername[256];\r
+  char escPassword[256];\r
+  MySQL->EscapeString(mName.c_str(), escUsername, 256);\r
+  MySQL->EscapeString(mPassword.c_str(), escPassword, 256);\r
+    \r
+  std::string Query;\r
+  Query = CreateMode ? "INSERT INTO" : "UPDATE";\r
+  Query += "accounts SET ";\r
+  Query += Ssprintf(" accounts SET a_username='%s', a_password = '%s'", escUsername, escPassword);\r
+  Query += Ssprintf(", a_priv = %d, a_status = %d, a_bandate = %d", mLevel, mStatus, mBannedUntil);\r
+  if(!CreateMode )\r
+  {\r
+    Query += Ssprintf(" WHERE a_id = %d LIMIT 1", mID);\r
+  }\r
+\r
+  if(MySQL->InfoQuery(Query.c_str()))\r
+  {\r
+      Console->Print(RED, BLACK, "[Error] Failed to %s account %s (id %d)", CreateMode ? "create" : "update", mName.c_str(), mID);\r
+      MySQL->ShowInfoSQLError();\r
+      return false;\r
+  }\r
+  return true;\r
+}\r
+\r
+u32 PAccount::GetCharIdBySlot(const u32 SlotId)\r
+{\r
+  char query[256];\r
+  u32 CharId = 0;\r
+  \r
+  MYSQL_ROW row = 0;\r
+  MYSQL_RES *result = 0;\r
+  \r
+  snprintf(query, 256, "SELECT c_id FROM characters WHERE a_id = %d AND c_slot = %d LIMIT 1;", mID, SlotId);  \r
+\r
+  result = MySQL->GameResQuery(query);\r
+  if(result == NULL)\r
+  {\r
+      Console->Print(RED, BLACK, "Failed to load CharacterData from SQL");\r
+      MySQL->ShowGameSQLError();\r
+      return 0;\r
+  }\r
+\r
+  if((row = mysql_fetch_row(result)))\r
+  {\r
+    CharId = atoi(row[0]);\r
+  }\r
+  \r
+  MySQL->FreeGameSQLResult(result);\r
+  \r
+  /*** Temporary workaround to cope with DB where c_slot is not set ***/\r
+  if(!CharId)\r
+  {\r
+    snprintf(query, 256, "SELECT c_id FROM characters WHERE a_id = %d ORDER BY c_slot ASC, c_id ASC LIMIT %d, 1;", mID, SlotId);\r
+  \r
+    result = MySQL->GameResQuery(query);\r
+    if(result == NULL)\r
+    {\r
+        Console->Print(RED, BLACK, "Failed to load CharacterData from SQL");\r
+        MySQL->ShowGameSQLError();\r
+        return 0;\r
+    }\r
+    \r
+    if((row = mysql_fetch_row(result)))\r
+    {\r
+      CharId = atoi(row[0]);\r
+    }\r
+    \r
+    MySQL->FreeGameSQLResult(result);    \r
+  }\r
+  /*** End of workaround ***/\r
+  \r
+  return CharId;\r
+}\r
+\r
+\r
+std::string PAccount::GetBannedTime() const\r
+{\r
+  const char* unit[5] = {"seconds", "minutes", "hours", "days", "weeks"};\r
+  \r
+  std::time_t timediff = mBannedUntil - std::time(NULL);\r
+  if(timediff <=0)\r
+  {\r
+    return "0 more seconds. Please relog";\r
+  }\r
+\r
+  long counter;\r
+  int type;\r
+\r
+  if(timediff > 86400)   // days\r
+  {\r
+    counter = timediff / 86400;\r
+    type = 3;\r
+  }\r
+  else if(timediff > 3600)    // hours\r
+  {\r
+    counter = timediff / 3600;\r
+    type = 2;\r
+  }\r
+  else if(timediff > 60)      // Minutes\r
+  {\r
+    counter  = timediff / 60;\r
+    type = 1;\r
+  }\r
+  else      // Seconds\r
+  {\r
+    counter = timediff;\r
+    type = 0;\r
+  }\r
+\r
+  return Ssprintf("%d more %s", counter, unit[type]);\r
+}\r
diff --git a/server/src/game/appartements.cpp b/server/src/game/appartements.cpp
new file mode 100644 (file)
index 0000000..12d0269
--- /dev/null
@@ -0,0 +1,252 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+  appartements.cpp - appartements class\r
+\r
+       MODIFIED: 20 Nov 2006 Hammag\r
+       REASON: - creation\r
+       \r
+*/\r
+\r
+#include "main.h"\r
+\r
+#include "appartements.h"\r
+#include "gamedefs.h"\r
+#include "def_appartements.h"\r
+#include "worlds.h"\r
+\r
+PAppartements::PAppartements()\r
+{\r
+}\r
+\r
+//PAppartements::~PAppartements() {};\r
+\r
+u32 PAppartements::CreateBaseAppartement(u32 nCharID, std::string nPassword, u8 nFactionID)\r
+{\r
+  typedef std::vector< std::pair<int, int> > PAppVector; //<AppType, AppPlace>\r
+    \r
+  PAppVector CandidateApts;  \r
+  CandidateApts.reserve(32);\r
+  u16 j;\r
+  int AppType;\r
+  \r
+  for (std::map<int, PDefAppartement*>::const_iterator i=GameDefs->Appartements()->ConstIteratorBegin(); i!=GameDefs->Appartements()->ConstIteratorEnd(); i++)\r
+  {\r
+    if (i->second->GetFaction() == nFactionID)\r
+    {\r
+      for (j = 0; j < i->second->GetPlaceCount(); j++)\r
+      {\r
+        AppType = i->second->GetID();\r
+        if ((AppType < 220) || (AppType >= 250))\r
+        {\r
+if (gDevDebug) Console->Print("Added potential Apt of type %d in place %d", AppType, i->second->GetPlace(j));\r
+          CandidateApts.push_back(std::make_pair(AppType, i->second->GetPlace(j)));\r
+        }\r
+      }\r
+    }\r
+  }\r
+  \r
+  if(CandidateApts.size())\r
+  {\r
+    j = GetRandom(CandidateApts.size()-1);\r
+if (gDevDebug) Console->Print("Apt n� %d chosen in %d for faction %d", j+1, CandidateApts.size(), nFactionID);\r
+\r
+if (gDevDebug) Console->Print("Choosed Apt of type %d in place %d", CandidateApts[j].first, CandidateApts[j].second);    \r
+\r
+    char escPassword[256];\r
+    MySQL->EscapeString(nPassword.c_str(), escPassword, 256);\r
+    char query[256];\r
+    snprintf(query, 256, "INSERT INTO apartments (apt_id,apt_location,apt_type,apt_password, apt_owner) VALUES (NULL,'%d','%d','%s','%d');", CandidateApts[j].second, CandidateApts[j].first, escPassword, nCharID);\r
+    if ( MySQL->GameQuery(query) )\r
+    {\r
+        Console->Print(RED, BLACK, "PAppartements::CreateBaseAppartement could not add some appartement entry in the database");\r
+        Console->Print("Query was:");\r
+        Console->Print("%s", query);\r
+        MySQL->ShowGameSQLError();\r
+        return 0;\r
+    }\r
+    return (MySQL->GetLastGameInsertId());\r
+  }\r
+  else\r
+    return 0;\r
+}\r
+\r
+void PAppartements::DeleteCharAppartements(u32 nCharID)\r
+{\r
+    char query[256];\r
+    snprintf(query, 256, "DELETE FROM apartments WHERE (apt_owner='%u');", nCharID);\r
+    if ( MySQL->GameQuery(query) )\r
+    {\r
+        Console->Print(RED, BLACK, "PAppartements::DeleteCharAppartements could not delete some char %d appartement(s) entry from the database", nCharID);\r
+        Console->Print("Query was:");\r
+        Console->Print("%s", query);\r
+        MySQL->ShowGameSQLError();\r
+    }\r
+    else\r
+if (gDevDebug) Console->Print(YELLOW, BLACK, "PAppartements::DeleteCharAppartements does not delete appartements content yet");      \r
+}\r
+\r
+bool PAppartements::CanFreelyEnter(PChar* nChar, u32 nLocation)\r
+{\r
+  u32 OwnerID = GetAptOwner(nLocation);\r
+  return (OwnerID == nChar->GetID());\r
+  \r
+  // here we could manage Clan appartements access too.\r
+}\r
+\r
+int PAppartements::GetAptID(unsigned int AptLoc, const u8 *pass)\r
+{\r
+    int type;\r
+    MYSQL_RES *result;\r
+    MYSQL_ROW row;\r
+    char query[255];\r
+\r
+    if(!strcmp((const char*)pass, "Exit"))\r
+        return 1;\r
+\r
+    char escPassword[255];\r
+    MySQL->EscapeString((char*)pass, escPassword, 255);\r
+    snprintf(query, 255, "SELECT apt_id FROM apartments WHERE apt_location = %i AND apt_password = '%s'", AptLoc, escPassword);\r
+    result = MySQL->GameResQuery(query);\r
+\r
+    if(!result)\r
+    {\r
+        Console->Print("%s Cannot get AppartmentID; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
+        MySQL->ShowGameSQLError();\r
+        return 0;\r
+    }\r
+\r
+    if(mysql_num_rows(result) == 0)\r
+    {\r
+        MySQL->FreeGameSQLResult(result);\r
+        return 0;\r
+    }\r
+    else\r
+    {\r
+        row = mysql_fetch_row(result);\r
+        type = atoi(row[0]);\r
+        MySQL->FreeGameSQLResult(result);\r
+    }\r
+\r
+    return (type + PWorlds::mAptBaseWorldId);\r
+}\r
+\r
+int PAppartements::GetAptType(int AptID)\r
+{\r
+    int type;\r
+    MYSQL_RES *result;\r
+    MYSQL_ROW row;\r
+    char query[255];\r
+\r
+    snprintf(query, 225, "SELECT apt_type FROM apartments WHERE apt_id = %i", AptID - PWorlds::mAptBaseWorldId);\r
+    result = MySQL->GameResQuery(query);\r
+\r
+    if(!result)\r
+    {\r
+        Console->Print("%s Cannot get AppartmentType; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
+        MySQL->ShowGameSQLError();\r
+        return 0;\r
+    }\r
+\r
+    if(mysql_num_rows(result) == 0)\r
+    {\r
+        MySQL->FreeGameSQLResult(result);\r
+        return 0;\r
+    }\r
+    else\r
+    {\r
+        row = mysql_fetch_row(result);\r
+        type = atoi(row[0]);\r
+        MySQL->FreeGameSQLResult(result);\r
+    }\r
+\r
+    return type;\r
+}\r
+\r
+int PAppartements::GetAptOwner(int loc)\r
+{\r
+    int owner;\r
+    MYSQL_RES *result;\r
+    MYSQL_ROW row;\r
+    char query[255];\r
+\r
+    snprintf (query, 255, "SELECT apt_owner FROM apartments WHERE apt_id = %i", loc - PWorlds::mAptBaseWorldId);\r
+\r
+    result = MySQL->GameResQuery(query);\r
+    if(!result)\r
+    {\r
+        Console->Print("%s Cannot get AppartmentOwner; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
+        MySQL->ShowGameSQLError();\r
+        return 0;\r
+    }\r
+\r
+    if(mysql_num_rows(result) == 0)\r
+    {\r
+        MySQL->FreeGameSQLResult(result);\r
+        return 0;\r
+    }\r
+    else\r
+    {\r
+        row = mysql_fetch_row(result);\r
+        owner = atoi(row[0]);\r
+        MySQL->FreeGameSQLResult(result);\r
+    }\r
+\r
+    return owner;\r
+}\r
+\r
+int PAppartements::GetAptLocation(int loc)\r
+{\r
+    int Location;\r
+    MYSQL_RES *result;\r
+    MYSQL_ROW row;\r
+    char query[255];\r
+\r
+    if((u32)loc > PWorlds::mAptBaseWorldId)\r
+        loc = loc - PWorlds::mAptBaseWorldId;\r
+\r
+    snprintf (query, 255, "SELECT apt_location FROM apartments WHERE apt_id = %i", loc);\r
+\r
+//Console->Print("Q: %s", query);\r
+    result = MySQL->GameResQuery(query);\r
+    if(!result)\r
+    {\r
+        Console->Print("%s Cannot get AppartmentLocation; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
+        MySQL->ShowGameSQLError();\r
+        return 0;\r
+    }\r
+\r
+    if(mysql_num_rows(result) == 0)\r
+    {\r
+        MySQL->FreeGameSQLResult(result);\r
+        return 0;\r
+    }\r
+    else\r
+    {\r
+        row = mysql_fetch_row(result);\r
+        Location = atoi(row[0]);\r
+        MySQL->FreeGameSQLResult(result);\r
+    }\r
+\r
+    return Location;\r
+}\r
diff --git a/server/src/game/buddylist.cpp b/server/src/game/buddylist.cpp
new file mode 100755 (executable)
index 0000000..90ea3c8
--- /dev/null
@@ -0,0 +1,199 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+  buddylist.cpp - classe for chat buddylist\r
+\r
+ MODIFIED: 19 Sep 2006 Hammag\r
+ REASON: - creation\r
+\r
+ TODO: - link with a online char list, updated when needed (chars in/out, or list modified)\r
+*/\r
+\r
+#include "main.h"\r
+#include "buddylist.h"\r
+\r
+PBuddyList::PBuddyList(u32 nOwnerCharID)\r
+{\r
+    mOwnerCharID = nOwnerCharID;\r
+    mListMaxSize = mListSize = 0;\r
+    mCharIDList = NULL;\r
+}\r
+\r
+PBuddyList::~PBuddyList()\r
+{\r
+\r
+    if (mCharIDList)\r
+        delete[] mCharIDList;\r
+}\r
+\r
+bool PBuddyList::AddChar(u32 nBuddyCharID)\r
+{\r
+    char query[256];\r
+\r
+    if ((FindEntry(nBuddyCharID) >= mListSize) && (mListSize < 255))\r
+    {\r
+        if (mListSize == mListMaxSize)\r
+        {\r
+            IncreaseMaxSize();\r
+        }\r
+        mCharIDList[mListSize++] = nBuddyCharID;\r
+\r
+        snprintf(query, 256, "INSERT INTO buddy_list (bud_id,bud_charid,bud_buddyid) VALUES (NULL,'%u','%u');", mOwnerCharID, nBuddyCharID);\r
+        if ( MySQL->GameQuery(query) )\r
+        {\r
+            Console->Print(RED, BLACK, "PBuddyList::AddChar could not add some buddylisdt entry in the database");\r
+            Console->Print("Query was:");\r
+            Console->Print("%s", query);\r
+            MySQL->ShowGameSQLError();\r
+            return false;\r
+        }\r
+\r
+        return true;\r
+    }\r
+    else\r
+        return false;\r
+}\r
+\r
+bool PBuddyList::RemoveChar(u32 nBuddyCharID)\r
+{\r
+    char query[256];\r
+    u8 rEntry, i;\r
+\r
+    if ((rEntry = FindEntry(nBuddyCharID)) < mListSize)\r
+    {\r
+        --mListSize;\r
+        for (i = rEntry; i < mListSize; i++)\r
+        {\r
+            mCharIDList[i] = mCharIDList[i+1];\r
+        }\r
+        // Remove from DB here\r
+        snprintf(query, 256, "DELETE FROM buddy_list WHERE ((bud_charid='%u') AND (bud_buddyid='%u')) LIMIT 1;", mOwnerCharID, nBuddyCharID);\r
+        if ( MySQL->GameQuery(query) )\r
+        {\r
+            Console->Print(RED, BLACK, "PBuddyList::AddChar could not delete some buddylist entry from the database");\r
+            Console->Print("Query was:");\r
+            Console->Print("%s", query);\r
+            MySQL->ShowGameSQLError();\r
+            return false;\r
+        }\r
+\r
+        return true;\r
+    }\r
+    else\r
+        return false;\r
+}\r
+\r
+bool PBuddyList::SQLLoad()\r
+{\r
+    char query[256];\r
+    MYSQL_RES *result;\r
+    MYSQL_ROW row;\r
+    u8 EntriesNum;\r
+\r
+    snprintf(query, 256, "SELECT * FROM buddy_list WHERE (bud_charid='%u')", mOwnerCharID);\r
+    result = MySQL->GameResQuery(query);\r
+    if(result == NULL)\r
+    {\r
+        Console->Print(RED, BLACK, "PBuddyList::SQLLoad could not load buddylist entry from the database");\r
+        Console->Print("Query was:");\r
+        Console->Print("%s", query);\r
+        MySQL->ShowGameSQLError();\r
+        return false;\r
+    }\r
+    //Console->Print(GREEN, BLACK, "PBuddyList::SQLLoad Loading buddylist for char %d", mOwnerCharID);\r
+    mListSize = 0;\r
+    if((EntriesNum = mysql_num_rows(result)))\r
+    {\r
+        IncreaseMaxSize(EntriesNum);\r
+\r
+        while((row = mysql_fetch_row(result)))\r
+        {\r
+            mCharIDList[mListSize++] = atoi(row[bud_buddyid]);\r
+            //Console->Print(GREEN, BLACK, "PBuddyList::SQLLoad Buddylist entry %d : char %d", mListSize, mCharIDList[mListSize-1]);\r
+        }\r
+    }\r
+    MySQL->FreeGameSQLResult(result);\r
+    return true;\r
+}\r
+\r
+void PBuddyList::IncreaseMaxSize(u8 nNewMax)\r
+{\r
+    u16 tmpSize;\r
+\r
+    if (!nNewMax)\r
+    {\r
+        tmpSize = mListMaxSize + BUDDYLIST_ALLOC_SIZE;\r
+    }\r
+    else if (nNewMax > mListMaxSize)\r
+    {\r
+        tmpSize = nNewMax / BUDDYLIST_ALLOC_SIZE;\r
+        if (nNewMax % BUDDYLIST_ALLOC_SIZE)\r
+            ++tmpSize;\r
+        tmpSize *= BUDDYLIST_ALLOC_SIZE;\r
+    }\r
+    else\r
+        return;\r
+\r
+    mListMaxSize = (tmpSize < 256) ? tmpSize : 255;\r
+\r
+    u32* tmpList = new u32[mListMaxSize];\r
+    if (mCharIDList)\r
+    {\r
+        if (mListSize)\r
+        {\r
+            memcpy(tmpList, mCharIDList, sizeof(u32) * mListSize);\r
+        }\r
+\r
+        delete[] mCharIDList;\r
+    }\r
+    mCharIDList = tmpList;\r
+}\r
+\r
+u8 PBuddyList::FindEntry(u32 CharID)\r
+{\r
+    u8 i = 255;\r
+\r
+    if (mCharIDList)\r
+    {\r
+        for (i = 0; i < mListSize; i++)\r
+        {\r
+            if (mCharIDList[i] == CharID)\r
+                break;\r
+        }\r
+    }\r
+\r
+    return i;\r
+}\r
+\r
+bool PBuddyList::IsInBuddy(u32 CharID)\r
+{\r
+    if (mCharIDList)\r
+    {\r
+        for (u8 i = 0; i < mListSize; i++)\r
+        {\r
+            if (mCharIDList[i] == CharID)\r
+                return true;\r
+        }\r
+    }\r
+    return false;\r
+}\r
diff --git a/server/src/game/chars.cpp b/server/src/game/chars.cpp
new file mode 100644 (file)
index 0000000..348ee45
--- /dev/null
@@ -0,0 +1,1367 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+ chars.cpp\r
+\r
+ MODIFIED: 22 Dec 2005 Namikon\r
+ REASON: - Added GPL\r
+ MODIFIED: 01 Jan 2006 Namikon\r
+ REASON: - Added SQLLoad() function to PChar and PChars\r
+         - Changed FmtTxt() to sprintf(). It does... uhm, the same :D\r
+         - Added IsOnline var and function\r
+ MODIFIED: 06 Jan 2005 Namikon\r
+ REASON: - Added colored console ouputs\r
+            - Removed XM Load() and Save() functions\r
+            - Rewrote parts of SQLLoad to work with the global NeoPolis / TinNS database\r
+            - Added FillinCharDetails to fill the baseline up with the char details\r
+  MODIFIED: 03 Oct 2006 Hammag\r
+ REASON:   - PChar::CreateNewChar() and moved effective char creation from PChars to PChar\r
+           - added PChar::SQLDelete()\r
+             This method is put here because we want the char to be loaded when deleted from DB to avoid\r
+             any player to use it at the same time.\r
+           - added use of auto_save_period config option in PChars::update()\r
+           - removed old XML-storage related code\r
+\r
+  TODO:     - implement PChar::SQLDelete()\r
+*/\r
+\r
+#include "main.h"\r
+#include "worlds.h"\r
+#include "appartements.h"\r
+#include "container.h"\r
+#include "inventory.h"\r
+#include "vhcaccessrequest.h"\r
+\r
+// PCharCoordinates\r
+void PCharCoordinates::SetInterpolate( PCharCoordinates& Pos1, PCharCoordinates& Pos2, f32 nCoef )\r
+{\r
+  if (( nCoef < 0 ) || ( nCoef > 1 ) )\r
+  {\r
+    Console->Print( RED, BLACK, "[Error] PCharCoordinates::Interpolate : Invalid nCoef value: %f", nCoef );\r
+    nCoef = 0;\r
+  }\r
+  f32 rCoef = 1 - nCoef;\r
+\r
+  mY = ( u16 )( rCoef * Pos1.mY + nCoef * Pos2.mY );\r
+  mZ = ( u16 )( rCoef * Pos1.mZ + nCoef * Pos2.mZ );\r
+  mX = ( u16 )( rCoef * Pos1.mX + nCoef * Pos2.mX );\r
+  mUD = ( u8 )( rCoef * Pos1.mUD + nCoef * Pos2.mUD );\r
+  if ( abs( Pos1.mLR - Pos2.mLR ) < 90 )\r
+  {\r
+    mLR = ( u8 )( rCoef * Pos1.mLR + nCoef * Pos2.mLR );\r
+  }\r
+  else\r
+  {\r
+    mLR = ( u8 )(( u16 )( rCoef * ( 180.0 + ( f32 )Pos1.mLR ) + nCoef * Pos2.mLR ) % 180 );\r
+  }\r
+}\r
+\r
+u16 mY;     // Y-Position in world\r
+u16 mZ;     // Z-Position in world\r
+u16 mX;     // X-Position in world\r
+u8 mUD;     // Up - Mid - Down (d6 - 80 - 2a)\r
+u8 mLR;     // Compass direction (S..E..N..W..S [0-45-90-135-179])\r
+u8 mAct;    // Last user action state\r
+\r
+void PCharCoordinates::SetPosition( u16 nY, u16 nZ, u16 nX, u8 nUD, u8 nLR )\r
+{\r
+  mY = nY;\r
+  mZ = nZ;\r
+  mX = nX;\r
+  mUD = nUD;\r
+  if ( mUD < 0x2a )\r
+  {\r
+    mUD = 0x2a;\r
+  }\r
+  else if ( mUD > 0xd6 )\r
+  {\r
+    mUD = 0xd6;\r
+  }\r
+  mLR = nLR % 180;\r
+}\r
+\r
+\r
+// SQL Layout\r
+enum\r
+{\r
+    c_id,
+    c_name,
+    c_str_lvl,
+    c_str_pts,
+    c_int_lvl,
+    c_int_pts,
+    c_dex_lvl,
+    c_dex_pts,
+    c_con_lvl,
+    c_con_pts,
+    c_psi_lvl,
+    c_psi_pts,
+    a_id,
+    c_class,
+    c_profession,
+    c_sex,
+    c_location,
+    c_mc,
+    c_hc,
+    c_tra,
+    c_pc,
+    c_rc,
+    c_tc,
+    c_vhc,
+    c_agl,
+    c_rep,
+    c_rec,
+    c_rcl,
+    c_atl,
+    c_end,
+    c_for,
+    c_fir,
+    c_enr,
+    c_xrr,
+    c_por,
+    c_hlt,
+    c_hck,
+    c_brt,
+    c_psu,
+    c_wep,
+    c_cst,
+    c_res,
+    c_imp,
+    c_ppu,
+    c_apu,
+    c_mst,
+    c_ppw,
+    c_psr,
+    c_wpw,
+    c_apt,
+    c_cash,
+    c_head,
+    c_torso,
+    c_legs,
+    c_str_xp,
+    c_int_xp,
+    c_dex_xp,
+    c_psi_xp,
+    c_con_xp,
+    c_pos_x,
+    c_pos_y,
+    c_pos_z,
+    c_angle_ud,
+    c_angle_lr,
+    c_faction,
+    c_slot,
+    c_online,
+    c_clan,
+    c_soullight\r
+};\r
+\r
+RegEx* PChar::mCharnameRegexFilter = NULL;\r
+\r
+PChar::PChar()\r
+{\r
+  mID = 0;\r
+  mAccount = 0;\r
+  mGender = 0;\r
+  mClass = 0;\r
+  mProfession = 1;\r
+  mFaction = 1;\r
+  //mModel = 0;\r
+  //mType = 0;\r
+  mRealHead = 0;  // Base Skin elements, in complement of (computed) mType\r
+  mRealTorso = 0; // " Head shouldn't be changeable, except in case of surgery !!!\r
+  mRealLegs = 0;  // "\r
+  mSkin = 0;  // Current Skin elements\r
+  mHead = 0;  // "\r
+  mTorso = 0; // "\r
+  mLegs = 0;  // "\r
+  mHeadColor = mTorsoColor = mLegsColor = 0; // "\r
+  mHeadDarkness = mTorsoDarkness = mLegsDarkness = 0; // "\r
+\r
+  mBodyEffect = 0;\r
+  mBodyEffectDensity = 0;\r
+  mQuickBeltActiveSlot = INV_WORN_QB_NONE;\r
+\r
+  mLookingAt = 0;\r
+  mLookAtTimestamp = 0;\r
+  mLastUsedWorldObjectId = 0;\r
+\r
+  mSpeedOverride = 255; // means no override. Value 0 can be used to forbid any move.\r
+\r
+  mLocationLeased = false; // temp until char on-demand load/unload\r
+  mLocation = 0;\r
+  mStartApt = 0;\r
+  mPrimaryApt = 0;\r
+  mCash = 0;\r
+\r
+  mSeatInUseType = seat_none;\r
+  mSeatInUseObjectId = 0;\r
+  mSeatInUseSeatId = 0;\r
+  mVhcAccessRequestList = NULL;\r
+\r
+  mContainerInExclusiveUse = NULL;\r
+\r
+  mIsOnline = false;\r
+  mDirtyFlag = false;\r
+\r
+  mShunned = false;\r
+  mJailed = false;\r
+\r
+  mDialogNPC = 0;\r
+  mCurrentDialogNode = 0;\r
+\r
+  Skill = new PSkillHandler();\r
+  mBuddyList = NULL;\r
+  mGenrepList = NULL;\r
+\r
+  // Required for initial OOC Broadcast welcome message.\r
+  //Gets overwritten as soon as the first PingPacket arrives\r
+  mActiveChatChannels = 262144;
+
+  mClanLevel = 0;
+  mClanID = 0;\r
+}\r
+\r
+PChar::~PChar()\r
+{
+  // Addition; Set char's online status to OFFLINE
+  char sqlqry[50];
+  snprintf(sqlqry, 50, "UPDATE characters SET c_online = 0 WHERE c_id = %d", mID);
+  MySQL->GameQuery(sqlqry);
+\r
+  delete Skill;\r
+  delete mBuddyList;\r
+  delete mGenrepList;\r
+  delete mVhcAccessRequestList;\r
+\r
+  if ( mContainerInExclusiveUse )\r
+  {\r
+    mContainerInExclusiveUse->EndUse( mID );\r
+    Console->Print( RED, BLACK, "Warning: PChar::~PChar : Char still had exclusive use of container. Now freed." );\r
+  }\r
+\r
+  if ( mSeatInUseType != seat_none )\r
+  {\r
+    Console->Print( RED, BLACK, "Warning: PChar::~PChar : Char still using seat %d of vhc or chair %d.", mSeatInUseSeatId, mSeatInUseObjectId );\r
+  }\r
+}\r
+\r
+bool PChar::SetCharnameRegexFilter( const char* RegexStr )\r
+{\r
+  if ( mCharnameRegexFilter )\r
+  {\r
+    delete mCharnameRegexFilter;\r
+    mCharnameRegexFilter = NULL;\r
+  }\r
+\r
+  if ( RegexStr )\r
+  {\r
+    try\r
+    {\r
+      mCharnameRegexFilter = new RegEx( RegexStr, PCRE_CASELESS );\r
+    }\r
+    catch ( ... )\r
+    {\r
+      return false;\r
+    }\r
+  }\r
+  return true;\r
+}\r
+\r
+bool PChar::IsCharnameWellFormed( const char *Charname )\r
+{\r
+  if ( mCharnameRegexFilter )\r
+  {\r
+    return mCharnameRegexFilter->Search( Charname );\r
+  }\r
+  else\r
+    return true;\r
+}\r
+\r
+void PChar::SetProfession( u32 Profession )\r
+{\r
+  const PDefCharKind *def = GameDefs->CharKinds()->GetDef( Profession );\r
+  if ( def == NULL )\r
+  {\r
+    Console->Print( RED, BLACK, "Char %d: Invalid profession %d", mID, Profession );\r
+    mProfession = 10;\r
+    mClass = 0;\r
+  }\r
+  else\r
+  {\r
+    mProfession = Profession;\r
+    mClass = def->GetType();\r
+  }\r
+  SetDirtyFlag();\r
+}\r
+\r
+u32 PChar::GetSkinFromCharType( u32 nType )\r
+{\r
+  const PDefCharacter* nDefCharacter = GameDefs->Chars()->GetDef( nType );\r
+  if ( nDefCharacter )\r
+  {\r
+    return (( u32 )( nDefCharacter->GetModel() ) );\r
+  }\r
+  else\r
+    return 0;\r
+}\r
+\r
+inline u32 PChar::GetBaseModel()\r
+{\r
+  return GetSkinFromCharType( GetType() );\r
+}\r
+\r
+void PChar::SetRealLook( u32 nHead, u32 nTorso, u32 nLegs )\r
+{\r
+  mRealHead = nHead;\r
+  mRealTorso = nTorso;\r
+  mRealLegs = nLegs;\r
+  SetDirtyFlag();\r
+  ResetCurrentLook();\r
+}\r
+\r
+void PChar::GetRealLook( u32 &nSkin, u32 &nHead, u32 &nTorso, u32 &nLegs )\r
+{\r
+  nSkin = GetBaseModel();\r
+  nHead = mRealHead;\r
+  nTorso = mRealTorso;\r
+  nLegs = mRealLegs;\r
+}\r
+\r
+void PChar::SetCurrentLookFromCharType( u32 nType )\r
+{\r
+  int iHead, iTorso, iLegs;\r
+  u32 nSkin, nHead, nTorso, nLegs;\r
+  u8 nColor, nBrightness;\r
+\r
+  const PDefCharacter* nDefCharacter = GameDefs->Chars()->GetDef( nType );\r
+  if ( nDefCharacter )\r
+  {\r
+    nSkin = ( u32 ) nDefCharacter->GetModel();\r
+    iHead = nDefCharacter->GetHead();\r
+    iTorso = nDefCharacter->GetTorso();\r
+    iLegs = nDefCharacter->GetLegs();\r
+    nColor = ( u8 )( 0xff & nDefCharacter->GetColor() );\r
+    nBrightness = ( u8 )( 0xff & nDefCharacter->GetBrightness() );\r
+\r
+\r
+    if (( iHead < 0 ) || ( iTorso < 0 ) || ( iLegs < 0 ) )\r
+    {\r
+      nHead = nTorso = nLegs = 0;\r
+    }\r
+    else\r
+    {\r
+      nHead = iHead % 10;\r
+      nTorso = iTorso % 10;\r
+      nLegs = iLegs % 10;\r
+    }\r
+\r
+    SetCurrentLook( nSkin, nHead, nTorso, nLegs );\r
+    SetCurrentBodyColor( nColor, nColor, nColor, nBrightness, nBrightness, nBrightness );\r
+  }\r
+}\r
+\r
+void PChar::SetCurrentLook( u32 nSkin, u32 nHead, u32 nTorso, u32 nLegs )\r
+{\r
+  mSkin = nSkin;\r
+  mHead = nHead;\r
+  mTorso = nTorso;\r
+  mLegs = nLegs;\r
+  // Ingame skin update will be done automagically in the normal update flow\r
+  // A flag could also be set somewhere (preferably in Char si that we don't have to care if ingame or not)\r
+  //    to request quicker ingame update\r
+}\r
+\r
+void PChar::ResetCurrentLook()\r
+{\r
+  SetCurrentLook( GetSkinFromCharType( GetType() ), mRealHead, mRealTorso, mRealLegs );\r
+}\r
+\r
+// GetCurrentLook will later have to take Power Armors and GM overrides into account\r
+void PChar::GetCurrentLook( u32 &nSkin, u32 &nHead, u32 &nTorso, u32 &nLegs )\r
+{\r
+  nSkin = mSkin;\r
+  nHead = mHead;\r
+  nTorso = mTorso;\r
+  nLegs = mLegs;\r
+}\r
+\r
+void PChar::SetCurrentBodyColor( u8 nHeadColor, u8 nTorsoColor, u8 nLegsColor, u8 nHeadDarkness, u8 nTorsoDarkness, u8 nLegsDarkness )\r
+{\r
+  mHeadColor = nHeadColor;\r
+  mTorsoColor = nTorsoColor;\r
+  mLegsColor = nLegsColor;\r
+  mHeadDarkness = nHeadDarkness;\r
+  mTorsoDarkness = nTorsoDarkness;\r
+  mLegsDarkness = nLegsDarkness;\r
+}\r
+\r
+void PChar::GetCurrentBodyColor( u8 &nHeadColor, u8 &nTorsoColor, u8 &nLegsColor, u8 &nHeadDarkness, u8 &nTorsoDarkness, u8 &nLegsDarkness )\r
+{\r
+  nHeadColor = mHeadColor;\r
+  nTorsoColor = mTorsoColor;\r
+  nLegsColor = mLegsColor;\r
+  nHeadDarkness = mHeadDarkness;\r
+  nTorsoDarkness = mTorsoDarkness;\r
+  nLegsDarkness = mLegsDarkness;\r
+}\r
+\r
+void PChar::SetBaseSkills()\r
+{\r
+  const PDefCharKind *def = GameDefs->CharKinds()->GetDef( mProfession );\r
+  //Console->Print(YELLOW, BLACK, "PChar::SetBaseSkills() Profession: %d",def->GetIndex());\r
+  if ( def == NULL )\r
+  {\r
+    Console->Print( RED, BLACK, "PChar::SetBaseSkills: GetCharKindDef=NULL" );\r
+    return;\r
+  }\r
+  Skill->SetMainSkill( MS_INT, def->GetSkillInfo( MS_INT ).mStart );\r
+  Skill->SetMainSkill( MS_CON, def->GetSkillInfo( MS_CON ).mStart );\r
+  Skill->SetMainSkill( MS_DEX, def->GetSkillInfo( MS_DEX ).mStart );\r
+  Skill->SetMainSkill( MS_STR, def->GetSkillInfo( MS_STR ).mStart );\r
+  Skill->SetMainSkill( MS_PSI, def->GetSkillInfo( MS_PSI ).mStart );\r
+  // management of SP needed ? NC Client seem to calculate what remains ...\r
+  // or put SP setting after subskill setting ?\r
+  /* Skill->SetSP(MS_INT, (short) ??? ));\r
+  Skill->SetSP(MS_CON, ((short) ??? ));\r
+  Skill->SetSP(MS_DEX, (short) ??? ));\r
+  Skill->SetSP(MS_STR, (short) ??? ));\r
+  Skill->SetSP(MS_PSI, ((short) ??? )); */\r
+  // what about XPs ?\r
+  /* Skill->SetXP(MS_INT, ??? ));\r
+  Skill->SetXP(MS_CON, ??? ));\r
+  Skill->SetXP(MS_DEX, ??? ));\r
+  Skill->SetXP(MS_STR, ??? ));\r
+  Skill->SetXP(MS_PSI, ??? )); */\r
+  Console->Print( YELLOW, BLACK, "PChar::SetBaseSkills() not fully functionnal - unused skill points will be lost" );\r
+}\r
+\r
+void PChar::SetBaseSubskills( u8 NSZNb, const char* NonZeroSubskills )\r
+{\r
+  int i;\r
+\r
+  if ( NSZNb == 0 )\r
+    return;\r
+\r
+  for ( i = 0; i < NSZNb; i++ )\r
+  {\r
+    Skill->SetSubSkill(( SUB_SKILLS ) NonZeroSubskills[2 * i], ( int ) NonZeroSubskills[2 * i +1] );\r
+  }\r
+}\r
+\r
+void PChar::SetBaseInventory()\r
+{\r
+  u8 i;\r
+  u32 BaseItemID;\r
+  const PDefCharKind *def = GameDefs->CharKinds()->GetDef( mProfession );\r
+\r
+  //mCash = 5000;\r
+  mCash = def->GetStartMoney();\r
+\r
+  for ( i = 0; i < 8 ; i++ )\r
+  {\r
+    BaseItemID = def->GetStartInventory( i );\r
+    if ( BaseItemID )\r
+    {\r
+      if ( gDevDebug ) Console->Print( GREEN, BLACK, "Adding item %d to base inventory", BaseItemID );\r
+      PItem* NewItem = new PItem( BaseItemID );\r
+      if ( NewItem->GetItemID() )\r
+      {\r
+        NewItem->MakeItemStandard( 120, 180 ); // global quality range\r
+        mInventory.AddItem( NewItem );\r
+      }\r
+      else\r
+      {\r
+        Console->Print( RED, BLACK, "Invalid item ID %d in base inventory for profession %d", BaseItemID, mProfession );\r
+      }\r
+    }\r
+  }\r
+}\r
+
+void PChar::LoadClanLevel()
+{
+    MYSQL_RES *result;
+    char query[200];
+
+    snprintf(query, 200, "SELECT cll_level FROM clanlevels WHERE cll_charid = %d AND cll_clanid = %d", mID, mClanID);
+    result = MySQL->GameResQuery( query );
+    if ( result == NULL )
+    {
+        mClanID = 0;
+        Console->Print( RED, BLACK, "PChar::GetClanLevel could not load ClanLevel from the database" );
+        Console->Print( "Query was:" );
+        Console->Print( "%s", query );
+        MySQL->ShowGameSQLError();
+        return;
+    }
+    else if(mysql_num_rows(result) == 0)
+    {
+        mClanID = 0;
+        Console->Print( RED, BLACK, "PChar::GetClanLevel No level entry found for clan!" );
+        return;
+    }
+    mClanLevel = atoi(mysql_fetch_row(result)[0]);
+    if (gDevDebug) Console->Print("Loaded ClanLevel %d for char %d, clan %d", mClanLevel, mID, mClanID);
+}
+\r
+bool PChar::SQLLoad( int CharID )\r
+{\r
+  MYSQL_RES *result;\r
+  MYSQL_ROW row;\r
+  char query[1024];\r
+\r
+  snprintf( query, 1024, "SELECT * FROM characters WHERE c_id = %d LIMIT 1", CharID );\r
+  result = MySQL->GameResQuery( query );\r
+  if ( result == NULL )\r
+  {\r
+    Console->Print( RED, BLACK, "PChar::SQLLoad could not load Chardata from the database" );\r
+    Console->Print( "Query was:" );\r
+    Console->Print( "%s", query );\r
+    MySQL->ShowGameSQLError();\r
+    return false;\r
+  }\r
+  if (( row = mysql_fetch_row( result ) ) )\r
+  {\r
+    SetID( CharID );\r
+    SetName( row[c_name] );\r
+    SetAccount( atoi( row[a_id] ) );\r
+\r
+    // Gender\r
+    int genvalue = atoi( row[c_sex] );\r
+    if (( genvalue == 0 ) || ( genvalue == 1 ) )\r
+      mGender = static_cast<u32>( genvalue );\r
+    else\r
+    {\r
+      Console->Print( RED, BLACK, "Bad gender value: %d (Char ID %d)", genvalue, mID );\r
+      mGender = 0;\r
+    }\r
+\r
+    // Profession\r
+    int profvalue = atoi( row[c_profession] );\r
+    SetProfession( static_cast<u32>( profvalue ) );\r
+\r
+    // Class\r
+    //int classvalue = atoi(row[c_class]);\r
+    //if(classvalue < 4)\r
+    //    mClass = static_cast<u32>(classvalue);\r
+    //else\r
+    //{\r
+    //  Console->Print(RED, BLACK, "Bad class value: %d (Char ID %d)", classvalue, mID);\r
+    //  classvalue = 0;\r
+    //}\r
+\r
+    // Faction\r
+    int facvalue = atoi( row[c_faction] );\r
+    if ( GameDefs->Factions()->GetDef( facvalue ) )\r
+      mFaction = static_cast<u32>( facvalue );\r
+    else\r
+      mFaction = 1;\r
+\r
+    /* // Model\r
+    int modvalue = atoi(row[c_model]);\r
+    mModel = static_cast<u32>(modvalue);\r
+    mModel = 10; */\r
+    int headvalue = atoi( row[c_head] );\r
+    int torsovalue = atoi( row[c_torso] );\r
+    int legsvalue = atoi( row[c_legs] );\r
+    SetRealLook( static_cast<u32>( headvalue ), static_cast<u32>( torsovalue ), static_cast<u32>( legsvalue ) );\r
+\r
+    // Type\r
+    /*\r
+    int typevalue = std::atoi(row[c_type]);\r
+    mType = static_cast<u32>(typevalue);\r
+    //mType = 1; */\r
+\r
+    // Location\r
+    int locvalue = atoi( row[c_location] );\r
+    mLocation = static_cast<u32>( locvalue );\r
+\r
+//This assumption is not so good ... hardcoding jailed state linked with location ...\r
+    if ( mLocation == 550 || mLocation == 551 )\r
+      mJailed = true;\r
+\r
+    int posvalue = atoi( row[c_pos_x] );\r
+    Coords.mX = static_cast<u16>( posvalue );\r
+    posvalue = atoi( row[c_pos_y] );\r
+    Coords.mY = static_cast<u16>( posvalue );\r
+    posvalue = atoi( row[c_pos_z] );\r
+    Coords.mZ = static_cast<u16>( posvalue );\r
+    posvalue = atoi( row[c_angle_ud] );\r
+    Coords.mUD = static_cast<u8>( posvalue );\r
+    posvalue = atoi( row[c_angle_lr] );\r
+    Coords.mLR = static_cast<u8>( posvalue );\r
+\r
+    int primapt = atoi( row[c_apt] );\r
+    mPrimaryApt = static_cast<u32>( primapt );\r
+    mStartApt = mPrimaryApt;\r
+
+    mSoullight = atoi( row[c_soullight] );
+    mClanID = atoi( row[c_clan] );
+    if(mClanID > 0)
+        LoadClanLevel();
+\r
+    // Cash\r
+    f32 cashvalue = atof( row[c_cash] );\r
+    mCash = static_cast<u32>( cashvalue );\r
+\r
+    // ---------------------------------------------\r
+    // Loading skills --- MAIN Skills with SP and XP\r
+    // ---------------------------------------------\r
+    Skill->SetMainSkill( MS_INT, atoi( row[c_int_lvl] ) );\r
+    Skill->SetMainSkill( MS_CON, atoi( row[c_con_lvl] ) );\r
+    Skill->SetMainSkill( MS_DEX, atoi( row[c_dex_lvl] ) );\r
+    Skill->SetMainSkill( MS_STR, atoi( row[c_str_lvl] ) );\r
+    Skill->SetMainSkill( MS_PSI, atoi( row[c_psi_lvl] ) );\r
+    // ---------------------------------------------\r
+    Skill->SetSP( MS_INT, ( short )atoi( row[c_int_pts] ) );\r
+    Skill->SetSP( MS_CON, ( short )atoi( row[c_con_pts] ) );\r
+    Skill->SetSP( MS_DEX, ( short )atoi( row[c_dex_pts] ) );\r
+    Skill->SetSP( MS_STR, ( short )atoi( row[c_str_pts] ) );\r
+    Skill->SetSP( MS_PSI, ( short )atoi( row[c_psi_pts] ) );\r
+    // ---------------------------------------------\r
+    Skill->SetXP( MS_INT, atof( row[c_int_xp] ) );\r
+    Skill->SetXP( MS_CON, atof( row[c_con_xp] ) );\r
+    Skill->SetXP( MS_DEX, atof( row[c_dex_xp] ) );\r
+    Skill->SetXP( MS_STR, atof( row[c_str_xp] ) );\r
+    Skill->SetXP( MS_PSI, atof( row[c_psi_xp] ) );\r
+    // ---------------------------------------------\r
+    // SubSkills\r
+    // ---------------------------------------------\r
+    Skill->SetSubSkill( SK_MC, atoi( row[c_mc] ) );\r
+    Skill->SetSubSkill( SK_HC, atoi( row[c_hc] ) );\r
+    Skill->SetSubSkill( SK_TRA, atoi( row[c_tra] ) );\r
+    Skill->SetSubSkill( SK_FOR, atoi( row[c_for] ) );\r
+    Skill->SetSubSkill( SK_PC, atoi( row[c_pc] ) );\r
+    Skill->SetSubSkill( SK_RC, atoi( row[c_rc] ) );\r
+    Skill->SetSubSkill( SK_TC, atoi( row[c_tc] ) );\r
+    Skill->SetSubSkill( SK_VHC, atoi( row[c_vhc] ) );\r
+    Skill->SetSubSkill( SK_AGL, atoi( row[c_agl] ) );\r
+    Skill->SetSubSkill( SK_REP, atoi( row[c_rep] ) );\r
+    Skill->SetSubSkill( SK_REC, atoi( row[c_rec] ) );\r
+    Skill->SetSubSkill( SK_RCL, atoi( row[c_rcl] ) );\r
+    Skill->SetSubSkill( SK_ATL, atoi( row[c_atl] ) );\r
+    Skill->SetSubSkill( SK_END, atoi( row[c_end] ) );\r
+    Skill->SetSubSkill( SK_FIR, atoi( row[c_fir] ) );\r
+    Skill->SetSubSkill( SK_ENR, atoi( row[c_enr] ) );\r
+    Skill->SetSubSkill( SK_XRR, atoi( row[c_xrr] ) );\r
+    Skill->SetSubSkill( SK_POR, atoi( row[c_por] ) );\r
+    Skill->SetSubSkill( SK_HLT, atoi( row[c_hlt] ) );\r
+    Skill->SetSubSkill( SK_HCK, atoi( row[c_hck] ) );\r
+    Skill->SetSubSkill( SK_BRT, atoi( row[c_brt] ) );\r
+    Skill->SetSubSkill( SK_PSU, atoi( row[c_psu] ) );\r
+    Skill->SetSubSkill( SK_WEP, atoi( row[c_wep] ) );\r
+    Skill->SetSubSkill( SK_CST, atoi( row[c_cst] ) );\r
+    Skill->SetSubSkill( SK_RES, atoi( row[c_res] ) );\r
+    Skill->SetSubSkill( SK_IMP, atoi( row[c_imp] ) );\r
+    Skill->SetSubSkill( SK_PPU, atoi( row[c_ppu] ) );\r
+    Skill->SetSubSkill( SK_APU, atoi( row[c_apu] ) );\r
+    Skill->SetSubSkill( SK_MST, atoi( row[c_mst] ) );\r
+    Skill->SetSubSkill( SK_PPW, atoi( row[c_ppw] ) );\r
+    Skill->SetSubSkill( SK_PSR, atoi( row[c_psr] ) );\r
+    Skill->SetSubSkill( SK_WPW, atoi( row[c_wpw] ) );\r
+    // --------------------------------------------\r
+    // Inventory\r
+    // ---------------------------------------------\r
+    mInventory.SetCharId( mID );\r
+    mInventory.SQLLoad();\r
+\r
+    // temp value forcing, not get/saved from DB atm\r
+    mCombatRank = ( u8 )( random() % 127 ); // bad result there on randomness\r
+    mSynaptic = 0;\r
+    mIsDead = false;\r
+\r
+    mDirectCharID = 0; // until saved/loaded with char\r
+    mBuddyList = new PBuddyList( mID );\r
+    if ( !mBuddyList->SQLLoad() )\r
+    {\r
+      Console->Print( RED, BLACK, "Char ID %d : Can't load buddy list", mID );\r
+    }\r
+    //to add: Chats settings\r
+\r
+    mGenrepList = new PGenrepList( mID );\r
+    if ( !mGenrepList->SQLLoad() )\r
+    {\r
+      Console->Print( RED, BLACK, "Char ID %d : Can't load genrep list", mID );\r
+    }\r
+\r
+  }\r
+  MySQL->FreeGameSQLResult( result );
+
+  // Addition; Set char's online status to ONLINE
+  char sqlqry[50];
+  snprintf(sqlqry, 50, "UPDATE characters SET c_online = 1 WHERE c_id = %d", mID);
+  MySQL->GameQuery(sqlqry);\r
+\r
+  return true;\r
+}\r
+\r
+bool PChar::SQLCreate() // Specific method for creation in order to avoid existence check with each save\r
+{\r
+  std::string query, queryv;\r
+\r
+  query = "INSERT INTO characters (c_id";\r
+  queryv = ") VALUES (NULL";\r
+\r
+  query += ",c_name";\r
+  queryv = queryv + ",'" + mName + "'";\r
+\r
+  query += ",a_id";\r
+  queryv += Ssprintf( ",'%u'", mAccount );\r
+  query += ",c_class";\r
+  queryv += Ssprintf( ",'%u'", mClass );\r
+  query += ",c_sex";\r
+  queryv += Ssprintf( ",'%u'", mGender );\r
+  query += ",c_profession";\r
+  queryv += Ssprintf( ",'%u'", mProfession );\r
+  query += ",c_faction";\r
+  queryv += Ssprintf( ",'%u'", mFaction );\r
+  query += ",c_head";\r
+  queryv += Ssprintf( ",'%u'", mRealHead );\r
+  query += ",c_torso";\r
+  queryv += Ssprintf( ",'%u'", mRealTorso );\r
+  query += ",c_legs";\r
+  queryv += Ssprintf( ",'%u'", mRealLegs );\r
+  //query += ",c_model";\r
+  //queryv += Ssprintf(",'%u'", mModel);\r
+  //query += ",c_type";\r
+  //queryv += Ssprintf(",'%u'", mType);\r
+  query += ",c_location";\r
+  queryv += Ssprintf( ",'%u'", mLocation );\r
+  query += ",c_cash";\r
+  queryv += Ssprintf( ",'%u'", mCash );\r
+  query += ",c_slot";\r
+  queryv += Ssprintf( ",'%u'", mSlot );\r
+\r
+  query = query + queryv + ");";\r
+\r
+  if ( MySQL->GameQuery( query.c_str() ) )\r
+  {\r
+    Console->Print( RED, BLACK, "PChar::SQLCreate could not add char %s to database", mName.c_str() );\r
+    Console->Print( "Query was:" );\r
+    Console->Print( "%s", query.c_str() );\r
+    MySQL->ShowGameSQLError();\r
+    return false;\r
+  }\r
+  else\r
+  {\r
+    mID = MySQL->GetLastGameInsertId();\r
+//Console->Print(GREEN, BLACK, "New char %s got ID %d", mName.c_str(), mID);\r
+    mDirtyFlag = true;\r
+    return true;\r
+  }\r
+}\r
+\r
+bool PChar::CreateNewChar( u32 Account, const std::string &Name, u32 Gender, u32 Profession, u32 Faction,\r
+                           u32 Head, u32 Torso, u32 Legs, u8 NZSNb, const char *NonZeroSubskills, u32 Slot )\r
+{\r
+  SetName( Name );\r
+  SetGender( Gender );\r
+  SetProfession( Profession );\r
+  SetFaction( Faction );\r
+  SetRealLook( Head, Torso, Legs );\r
+  SetBaseSkills();\r
+  SetBaseSubskills( NZSNb, NonZeroSubskills );\r
+  SetBaseInventory();\r
+  SetAccount( Account );\r
+  SetCharSlot( Slot );\r
+  mLocation = Config->GetOptionInt( "new_char_location" );\r
+\r
+  // This part will have to be rewritten with proper methods\r
+  mSoullight = 10;\r
+  mCombatRank = ( u8 )( random() % 80 ); // bad result there on randomness\r
+  mSynaptic = 0;\r
+  mIsDead = false;\r
+\r
+  mDirectCharID = 0; // until saved/loaded with char\r
+\r
+  SetDirtyFlag();\r
+\r
+  if ( SQLCreate() ) // mID isn't defined before that\r
+  {\r
+    mBuddyList = new PBuddyList( mID );\r
+    mGenrepList = new PGenrepList( mID );\r
+    mStartApt = mPrimaryApt = Appartements->CreateBaseAppartement( mID, mName, mFaction );\r
+    mInventory.SetCharId( mID );\r
+\r
+    if ( mStartApt && SQLSave() && mInventory.SQLSave() )\r
+    {\r
+      return true;\r
+    }\r
+    else\r
+    {\r
+      Console->Print( YELLOW, BLACK, "New char %s (id %d) : creation aborted", mName.c_str(), mID );\r
+      if ( mID )\r
+      {\r
+        SQLDelete();\r
+        if ( mStartApt )\r
+        {\r
+          Appartements->DeleteCharAppartements( mID );\r
+        }\r
+      }\r
+    }\r
+  }\r
+  return false;\r
+}\r
+\r
+bool PChar::SQLSave()\r
+{\r
+  std::string query;\r
+  //std::string ts;\r
+\r
+  /* TODO:\r
+    - Mostly at creation/load :\r
+              c_apt, (or when first GR to primary apt to avoid creation of unused apt?)\r
+              (c_slot)\r
+    - At save/load :\r
+              SoulLight ???\r
+              FactionSymp[] ???\r
+              Chest change: style, brightness, color\r
+              Legs change: style, brightness, color\r
+              mHealt, mStamina, mMana (not in DB !!!)\r
+              How to compute MaxHealth etc. ?\r
+  */\r
+  query = "UPDATE characters SET";\r
+\r
+  query += Ssprintf( " c_location='%u'", mLocation );\r
+  query += Ssprintf( ",c_pos_x='%u'", Coords.mX );\r
+  query += Ssprintf( ",c_pos_y='%u'", Coords.mY );\r
+  query += Ssprintf( ",c_pos_z='%u'", Coords.mZ );\r
+  query += Ssprintf( ",c_angle_ud='%u'", Coords.mUD );\r
+  query += Ssprintf( ",c_angle_lr='%u'", Coords.mLR );\r
+  query += Ssprintf( ",c_cash='%u'", mCash );\r
+  query += Ssprintf( ",c_apt='%u'", mPrimaryApt );\r
+\r
+  query += Ssprintf( ",c_head='%u'", mRealHead );\r
+  query += Ssprintf( ",c_torso='%u'", mRealTorso );\r
+  query += Ssprintf( ",c_legs='%u'", mRealLegs );\r
+\r
+  query += Ssprintf( ",c_faction='%u'", mFaction );\r
+\r
+  /* This group of fiels shouldn't change in-game\r
+  query = query + ",c_name='" + mName + "'";\r
+  query += Ssprintf(",a_id='%u'", mAccount);\r
+  query += Ssprintf(",c_class='%u'", mClass);\r
+  query += Ssprintf(",c_sex='%u'", mGender);\r
+  query += Ssprintf(",c_profession='%u'", mProfession);\r
+  query += Ssprintf(",c_slot='%u'", mSlot);\r
+  // query += Ssprintf(",c_model='%u'", mModel);\r
+  // query += Ssprintf(",c_type='%u'", mType);\r
+  */\r
+\r
+  // ---------------------------------------------\r
+  // Saving skills --- MAIN Skills with SP and XP\r
+  // ---------------------------------------------\r
+  query += Ssprintf( ",c_int_lvl='%u'", Skill->GetMainSkill( MS_INT ) );\r
+  query += Ssprintf( ",c_con_lvl='%u'", Skill->GetMainSkill( MS_CON ) );\r
+  query += Ssprintf( ",c_dex_lvl='%u'", Skill->GetMainSkill( MS_DEX ) );\r
+  query += Ssprintf( ",c_str_lvl='%u'", Skill->GetMainSkill( MS_STR ) );\r
+  query += Ssprintf( ",c_psi_lvl='%u'", Skill->GetMainSkill( MS_PSI ) );\r
+  // ---------------------------------------------\r
+  query += Ssprintf( ",c_int_pts='%u'", Skill->GetSP( MS_INT ) );\r
+  query += Ssprintf( ",c_con_pts='%u'", Skill->GetSP( MS_CON ) );\r
+  query += Ssprintf( ",c_dex_pts='%u'", Skill->GetSP( MS_DEX ) );\r
+  query += Ssprintf( ",c_str_pts='%u'", Skill->GetSP( MS_STR ) );\r
+  query += Ssprintf( ",c_psi_pts='%u'", Skill->GetSP( MS_PSI ) );\r
+  // ---------------------------------------------\r
+  query += Ssprintf( ",c_int_xp='%u'", Skill->GetXP( MS_INT ) );\r
+  query += Ssprintf( ",c_con_xp='%u'", Skill->GetXP( MS_CON ) );\r
+  query += Ssprintf( ",c_dex_xp='%u'", Skill->GetXP( MS_DEX ) );\r
+  query += Ssprintf( ",c_str_xp='%u'", Skill->GetXP( MS_STR ) );\r
+  query += Ssprintf( ",c_psi_xp='%u'", Skill->GetXP( MS_PSI ) );\r
+  // ---------------------------------------------\r
+  // SubSkills\r
+  // ---------------------------------------------\r
+  query += Ssprintf( ",c_mc='%u'", Skill->GetSubSkill( SK_MC ) );\r
+  query += Ssprintf( ",c_hc='%u'", Skill->GetSubSkill( SK_HC ) );\r
+  query += Ssprintf( ",c_tra='%u'", Skill->GetSubSkill( SK_TRA ) );\r
+  query += Ssprintf( ",c_for='%u'", Skill->GetSubSkill( SK_FOR ) );\r
+  query += Ssprintf( ",c_pc='%u'", Skill->GetSubSkill( SK_PC ) );\r
+  query += Ssprintf( ",c_rc='%u'", Skill->GetSubSkill( SK_RC ) );\r
+  query += Ssprintf( ",c_tc='%u'", Skill->GetSubSkill( SK_TC ) );\r
+  query += Ssprintf( ",c_vhc='%u'", Skill->GetSubSkill( SK_VHC ) );\r
+  query += Ssprintf( ",c_agl='%u'", Skill->GetSubSkill( SK_AGL ) );\r
+  query += Ssprintf( ",c_rep='%u'", Skill->GetSubSkill( SK_REP ) );\r
+  query += Ssprintf( ",c_rec='%u'", Skill->GetSubSkill( SK_REC ) );\r
+  query += Ssprintf( ",c_rcl='%u'", Skill->GetSubSkill( SK_RCL ) );\r
+  query += Ssprintf( ",c_atl='%u'", Skill->GetSubSkill( SK_ATL ) );\r
+  query += Ssprintf( ",c_end='%u'", Skill->GetSubSkill( SK_END ) );\r
+  query += Ssprintf( ",c_fir='%u'", Skill->GetSubSkill( SK_FIR ) );\r
+  query += Ssprintf( ",c_enr='%u'", Skill->GetSubSkill( SK_ENR ) );\r
+  query += Ssprintf( ",c_xrr='%u'", Skill->GetSubSkill( SK_XRR ) );\r
+  query += Ssprintf( ",c_por='%u'", Skill->GetSubSkill( SK_POR ) );\r
+  query += Ssprintf( ",c_htl='%u'", Skill->GetSubSkill( SK_HLT ) );\r
+  query += Ssprintf( ",c_hck='%u'", Skill->GetSubSkill( SK_HCK ) );\r
+  query += Ssprintf( ",c_brt='%u'", Skill->GetSubSkill( SK_BRT ) );\r
+  query += Ssprintf( ",c_psu='%u'", Skill->GetSubSkill( SK_PSU ) );\r
+  query += Ssprintf( ",c_wep='%u'", Skill->GetSubSkill( SK_WEP ) );\r
+  query += Ssprintf( ",c_cst='%u'", Skill->GetSubSkill( SK_CST ) );\r
+  query += Ssprintf( ",c_res='%u'", Skill->GetSubSkill( SK_RES ) );\r
+  query += Ssprintf( ",c_imp='%u'", Skill->GetSubSkill( SK_IMP ) );\r
+  query += Ssprintf( ",c_ppu='%u'", Skill->GetSubSkill( SK_PPU ) );\r
+  query += Ssprintf( ",c_apu='%u'", Skill->GetSubSkill( SK_APU ) );\r
+  query += Ssprintf( ",c_mst='%u'", Skill->GetSubSkill( SK_MST ) );\r
+  query += Ssprintf( ",c_ppw='%u'", Skill->GetSubSkill( SK_PPW ) );\r
+  query += Ssprintf( ",c_psr='%u'", Skill->GetSubSkill( SK_PSR ) );\r
+  query += Ssprintf( ",c_wpw='%u'", Skill->GetSubSkill( SK_WPW ) );\r
+  // ---------------------------------------------\r
+\r
+  query += Ssprintf( " WHERE c_id='%u' LIMIT 1;", mID );\r
+\r
+  if ( MySQL->GameQuery( query.c_str() ) )\r
+  {\r
+    Console->Print( RED, BLACK, "PChar::SQLSave could not save char %s (%u) to database", mName.c_str(), mID );\r
+    Console->Print( "Query was:" );\r
+    Console->Print( "%s", query.c_str() );\r
+    MySQL->ShowGameSQLError();\r
+    return false;\r
+  }\r
+\r
+  // Chats settings (?), directs\r
+\r
+  mDirtyFlag = false;\r
+  return true;\r
+}\r
+\r
+bool PChar::SQLDelete()\r
+{\r
+  return true;\r
+}\r
+\r
+void PChar::SetOnlineStatus( bool IsOnline )\r
+{\r
+  // Deactivated, until Maxx added c_isonline row to `characters`\r
+  //char query[255];\r
+  int onlinestatus = 0;\r
+\r
+  if ( IsOnline )\r
+  {\r
+    onlinestatus = 0; // Strange ????\r
+    mIsOnline = true;\r
+  }\r
+  else\r
+  {\r
+    onlinestatus = 1; // Strange ????\r
+    mIsOnline = false;\r
+  }\r
+\r
+//    snprintf(query, 255, "UPDATE charlist SET c_isonline = %d WHERE a_id = %d AND c_id = %d", onlinestatus, mAccount, mID);\r
+//    if(MySQL->Query(query))\r
+//    {\r
+//        Console->Print("Error: Cant set onlinestatus to '%d' for Account: %d, Char: %d", onlinestatus, mAccount, mID);\r
+//        MySQL->ShowSQLError();\r
+//        return;\r
+//    }\r
+  return;\r
+}\r
+\r
+u8 PChar::GetCombatRank()\r
+{\r
+    // Override for Special Account Levels\r
+    PAccount Acc(mAccount);\r
+    if(Acc.GetLevel() == PAL_ADMIN)\r
+        return 127;\r
+    else if(Acc.GetLevel() >= PAL_GM)\r
+        return 120;\r
+    else if(Acc.GetLevel() >= PAL_VOLUNTEER)\r
+        return 50;\r
+    else\r
+        return mCombatRank;\r
+}\r
+\r
+u8 PChar::GetMainRank()\r
+{\r
+    // Override for Special Account Levels\r
+    PAccount Acc(mAccount);\r
+    if(Acc.GetLevel() == PAL_ADMIN)\r
+        return 127;\r
+    else if(Acc.GetLevel() >= PAL_GM)\r
+        return 120;\r
+    else if(Acc.GetLevel() >= PAL_VOLUNTEER)\r
+        return 50;\r
+    else\r
+    {\r
+      u16 total;\r
+      total  = Skill->GetMainSkill( MS_STR ) + Skill->GetMainSkill( MS_DEX );\r
+      total += Skill->GetMainSkill( MS_CON ) + Skill->GetMainSkill( MS_INT );\r
+      total += Skill->GetMainSkill( MS_PSI );\r
+      return (( u8 )( total / 5 ) );\r
+    }\r
+}\r
+\r
+u32 PChar::AddCash( u32 nAmount )\r
+{\r
+    return SetCash(nAmount + mCash);\r
+}\r
+\r
+u32 PChar::TakeCash( u32 nAmount )\r
+{\r
+    if(nAmount > mCash)\r
+    {\r
+        //Tries to take away more cash that user has, set to zero\r
+        return SetCash(0);\r
+    }\r
+    else\r
+    {\r
+        return SetCash(mCash-nAmount);\r
+    }\r
+}\r
+\r
+u32 PChar::SetCash( u32 nCash )\r
+{\r
+  //Console->Print("Trying to set cash to nCash: %d", nCash);\r
+  if (( int )nCash > Config->GetOptionInt( "max_cash" ) )\r
+  {\r
+    //Console->Print("Newcash would be more than dynamic maxcash, setting to maxcash");\r
+    mCash = ( u32 )Config->GetOptionInt( "max_cash" );\r
+  }\r
+  else if ( nCash > MAXCASH )\r
+  {\r
+    //Console->Print("Newcash would be more than hardcoded maxcash, setting to maxcash");\r
+    mCash = MAXCASH;\r
+  }\r
+  else\r
+  {\r
+    //Console->Print("Allright, setting to new value");\r
+    mCash = nCash;\r
+  }\r
+  //Console->Print("Returning mCash: %d", mCash);\r
+  return mCash;\r
+}\r
+\r
+\r
+bool PChar::SetQuickBeltActiveSlot( u8 nSlotID )\r
+{\r
+  if (( nSlotID == INV_WORN_QB_HAND ) || ( nSlotID == INV_WORN_QB_NONE ) )\r
+  {\r
+    mQuickBeltActiveSlot = nSlotID;\r
+    return true;\r
+  }\r
+  else if ( nSlotID <= ( INV_WORN_QB_END - INV_WORN_QB_START ) )\r
+  {\r
+    PContainer* tWorn = mInventory.GetContainer( INV_LOC_WORN );\r
+\r
+    if ( ! tWorn->IsSlotFree( nSlotID ) ) // => TODO: MUST ALSO CHECK that item is currently usable and can be held in hand\r
+    {\r
+      mQuickBeltActiveSlot = nSlotID;\r
+      return true;\r
+    }\r
+    else\r
+    {\r
+      Console->Print( "SetQuickBeltActiveSlot: SlotID %d greater than %d or free (%d)", nSlotID, INV_WORN_QB_END - INV_WORN_QB_START, tWorn->IsSlotFree( nSlotID ) );\r
+    }\r
+  }\r
+  return false;\r
+}\r
+\r
+PSeatType PChar::GetSeatInUse( u32* nObjectId, u8* nSeatId )\r
+{\r
+  if ( nObjectId )\r
+  {\r
+    *nObjectId = mSeatInUseObjectId;\r
+  }\r
+  if ( nSeatId )\r
+  {\r
+    *nSeatId = mSeatInUseSeatId;\r
+  }\r
+\r
+  return mSeatInUseType;\r
+}\r
+\r
+void PChar::SetSeatInUse( PSeatType nSeatType, u32 nObjectId, u8 nSeatId )\r
+{\r
+  mSeatInUseType = nSeatType;\r
+  mSeatInUseObjectId = nObjectId;\r
+  mSeatInUseSeatId = nSeatId;\r
+}\r
+\r
+PVhcAccessRequestList* PChar::GetVhcAccessRequestList()\r
+{\r
+  if( ! mVhcAccessRequestList )\r
+    mVhcAccessRequestList = new PVhcAccessRequestList();\r
+\r
+  return mVhcAccessRequestList;\r
+}\r
+\r
+void PChar::SetLookingAt( u16 nLocalCharID )\r
+{\r
+  mLookingAt = nLocalCharID;\r
+  mLookAtTimestamp = std::time( NULL );\r
+}\r
+\r
+u16 PChar::GetLookingAt( u16 nMaxDelaySec )\r
+{\r
+  return ((( mLookAtTimestamp + nMaxDelaySec ) >= std::time( NULL ) ) ? mLookingAt : 0 );\r
+}\r
+\r
+// ===================================\r
+\r
+PChars::PChars()\r
+{\r
+  mLastID = 0;\r
+  mLastSave = std::time( NULL );\r
+\r
+  mAutoSavePeriod = Config->GetOptionInt( "auto_save_period" );\r
+  if ( mAutoSavePeriod < 0 )\r
+  {\r
+    Console->Print( "%s auto_save_period (%d) must be strict positive.", Console->ColorText( RED, BLACK, "[Error]" ), mAutoSavePeriod );\r
+    mAutoSavePeriod = 0;\r
+  }\r
+  else if ( mAutoSavePeriod > 3600 )\r
+  {\r
+    Console->Print( "%s auto_save_period (%d) too high. Forced to 3600 sec.", Console->ColorText( YELLOW, BLACK, "[Warning]" ), mAutoSavePeriod );\r
+    mAutoSavePeriod = 0;\r
+  }\r
+\r
+  if ( mAutoSavePeriod == 0 )\r
+  {\r
+    Console->Print( "%s Auto-save disabled.", Console->ColorText( YELLOW, BLACK, "[Info]" ) );\r
+  }\r
+  else if ( mAutoSavePeriod < 60 )\r
+  {\r
+    Console->Print( "%s auto_save_period (%d) is low and might lead to high server load.", Console->ColorText( YELLOW, BLACK, "[Warning]" ), mAutoSavePeriod );\r
+  }\r
+\r
+}\r
+\r
+PChars::~PChars()\r
+{\r
+  for ( CharMap::iterator i = mChars.begin(); i != mChars.end(); i++ )\r
+    delete i->second;\r
+}\r
+\r
+bool PChars::LoadChar( u32 CharID )\r
+{\r
+  if ( !CharID )\r
+    return false;\r
+\r
+  PChar *nChar = new PChar();\r
+  if ( nChar->SQLLoad( CharID ) )\r
+  {\r
+    nChar->SetDirtyFlag( false );\r
+    return AddChar( nChar );\r
+  }\r
+  else\r
+  {\r
+    Console->Print( RED, BLACK, "[ERROR] Could not load char id %d from database", CharID );\r
+    return false;\r
+  }\r
+}\r
+\r
+bool PChars::AddChar( PChar* nChar )\r
+{\r
+  if ( !nChar )\r
+    return false;\r
+\r
+  mLastID = max( mLastID, nChar->GetID() );\r
+  if ( mChars.insert( std::make_pair( nChar->GetID(), nChar ) ).second )\r
+  {\r
+    if ( gDevDebug )\r
+      Console->Print( "%s Char: %s (id %d) added", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nChar->GetName().c_str() , nChar->GetID() );\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    Console->Print( RED, BLACK, "[ERROR] Trying to load char twice : %s (id %d)", nChar->GetName().c_str(), nChar->GetID() );\r
+    return false;\r
+  }\r
+}\r
+\r
+PChar* PChars::RemoveChar( u32 CharID )\r
+{\r
+  PChar* Result = NULL;\r
+\r
+  CharMap::iterator i = mChars.find( CharID );\r
+  if ( i != mChars.end() )\r
+  {\r
+    Result = i->second;\r
+    mChars.erase( i );\r
+    if ( gDevDebug )\r
+      Console->Print( "%s Char: %s (id %d) removed", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), Result->GetName().c_str() , Result->GetID() );\r
+  }\r
+\r
+  return Result;\r
+}\r
+\r
+void PChars::SQLSave()\r
+{\r
+  // saves all dirty-flagged chars\r
+  int nDirtyChars = 0, nSavedChars = 0;\r
+  int nDirtyInv = 0, nSavedInv = 0;\r
+\r
+  for ( CharMap::const_iterator i = mChars.begin(); i != mChars.end(); i++ )\r
+  {\r
+    PChar* Char = i->second;\r
+    if ( Char->IsDirty() )\r
+    {\r
+      ++nDirtyChars;\r
+      if ( Char->SQLSave() )\r
+        ++nSavedChars;\r
+    }\r
+    if ( Char->GetInventory()->IsDirty() )\r
+    {\r
+      ++nDirtyInv;\r
+      if ( Char->GetInventory()->SQLSave() )\r
+        ++nSavedInv;\r
+    }\r
+  }\r
+  Console->Print( "%s %i chars saved on %i dirty, %i inventories saved on %i dirty", Console->ColorText( GREEN, BLACK, "[DEBUG]" ), nSavedChars, nDirtyChars, nSavedInv, nDirtyInv );\r
+  return;\r
+}\r
+\r
+PChar* PChars::GetChar( u32 CharID ) const\r
+{\r
+  PChar *Result = 0;\r
+  CharMap::const_iterator i = mChars.find( CharID );\r
+  if ( i != mChars.end() )\r
+    Result = i->second;\r
+\r
+  return Result;\r
+}\r
+\r
+PChar* PChars::GetChar( const std::string &Name ) const\r
+{\r
+  PChar *Result = 0;\r
+  for ( CharMap::const_iterator i = mChars.begin(); i != mChars.end(); i++ )\r
+  {\r
+    if ( !/*std::*/strcasecmp( i->second->GetName().c_str(), Name.c_str() ) )\r
+    {\r
+      Result = i->second;\r
+      break;\r
+    }\r
+  }\r
+  return Result;\r
+}\r
+\r
+bool PChars::CharExist( const std::string &Name ) const\r
+{\r
+  char query[256];\r
+  int EntriesNb;\r
+  MYSQL_RES *result = 0;\r
+\r
+  char escUsername[256];\r
+  MySQL->EscapeString( Name.c_str(), escUsername, 256 );\r
+  snprintf( query, 256, "SELECT 1 FROM characters WHERE c_name = '%s' LIMIT 1;", escUsername );\r
+\r
+  result = MySQL->GameResQuery( query );\r
+  if ( result == NULL )\r
+  {\r
+    Console->Print( RED, BLACK, "[ERROR] Failed to get CharacterData from SQL" );\r
+    MySQL->ShowGameSQLError();\r
+    return true;\r
+  }\r
+\r
+  EntriesNb = mysql_num_rows( result );\r
+  MySQL->FreeGameSQLResult( result );\r
+  return( EntriesNb > 0 );\r
+}\r
+\r
+void PChars::Update()\r
+{\r
+  std::time_t t = std::time( NULL ); // changed to time() to have real time instead of cpu used time\r
+\r
+  if ( mAutoSavePeriod && (( t - mLastSave ) >= mAutoSavePeriod ) )\r
+  {\r
+    bool NeedSave = false;\r
+    for ( CharMap::const_iterator i = mChars.begin(); i != mChars.end(); i++ )\r
+    {\r
+      if ( i->second->IsAnyDirty() )\r
+      {\r
+        NeedSave = true;\r
+        break;\r
+      }\r
+    }\r
+\r
+    if ( NeedSave )\r
+    {\r
+      if ( gDevDebug ) Console->Print( "%s Some characters need autosaving...", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
+      SQLSave();\r
+      if ( gDevDebug ) Console->Print( "%s Autosave done.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
+    }\r
+    mLastSave = t;\r
+  }\r
+}\r
+\r
+//MAX_CHARS_PER_ACCOUNT\r
+int PChars::GetCharProfiles( const u32 AccountID, PCharProfile* CharSlotsArray, const u8 ArraySize )\r
+{\r
+  char query[256];\r
+  int EntriesNb = 0;\r
+\r
+  MYSQL_ROW row = 0;\r
+  MYSQL_RES *result = 0;\r
+\r
+  snprintf( query, 256, "SELECT * FROM characters WHERE a_id = %d ORDER BY c_slot ASC", AccountID );\r
+\r
+  result = MySQL->GameResQuery( query );\r
+  if ( result == NULL )\r
+  {\r
+    Console->Print( RED, BLACK, "[ERROR] Failed to load CharacterData from SQL" );\r
+    MySQL->ShowGameSQLError();\r
+    return 0;\r
+  }\r
+\r
+  //EntriesNb = mysql_num_rows(result);\r
+  int SlotID;\r
+  u32 CharID;\r
+  PChar* tmpChar = new PChar();\r
+\r
+  while (( row = mysql_fetch_row( result ) ) )\r
+  {\r
+    SlotID = atoi( row[c_slot] );\r
+    CharID = atoi( row[c_id] );\r
+    if (( SlotID >= 0 ) && ( SlotID < ArraySize ) )\r
+    {\r
+      if ( !CharSlotsArray[SlotID].in_use )\r
+      {\r
+        tmpChar->SetID( CharID );\r
+        tmpChar->SetGender( atoi( row[c_sex] ) );\r
+        tmpChar->SetProfession( atoi( row[c_profession] ) );\r
+\r
+        CharSlotsArray[SlotID].CharID = CharID;\r
+        CharSlotsArray[SlotID].Type = tmpChar->GetType();\r
+        CharSlotsArray[SlotID].Location = static_cast<u32>( atoi( row[c_location] ) );\r
+        CharSlotsArray[SlotID].Head = atoi( row[c_head] );\r
+        CharSlotsArray[SlotID].Torso = atoi( row[c_torso] );\r
+        CharSlotsArray[SlotID].Legs = atoi( row[c_legs] );\r
+        CharSlotsArray[SlotID].Name = row[c_name];\r
+        CharSlotsArray[SlotID].NameLen = CharSlotsArray[SlotID].Name.length() + 1;\r
+\r
+        CharSlotsArray[SlotID].in_use = true;\r
+        ++EntriesNb;\r
+      }\r
+      else\r
+      {\r
+        Console->Print( YELLOW, BLACK, "[Warning]Character %d using slot %d already used by char %d - Ignored", \\r
+                        CharID, SlotID, CharSlotsArray[SlotID].CharID );\r
+      }\r
+    }\r
+    else\r
+    {\r
+      Console->Print( YELLOW, BLACK, "[Warning]Character %d using invialid slot %d - Ignored", CharID, SlotID );\r
+    }\r
+  }\r
+\r
+  delete tmpChar;\r
+  MySQL->FreeGameSQLResult( result );\r
+  return EntriesNb;\r
+}\r
diff --git a/server/src/game/chat.cpp b/server/src/game/chat.cpp
new file mode 100644 (file)
index 0000000..082f1cf
--- /dev/null
@@ -0,0 +1,1144 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       chat.cpp - handles all ingame chat\r
+\r
+       Authors:\r
+       - Namikon\r
+       - bakkdoor\r
+\r
+        MODIFIED: 30 Nov 2005 Namikon/Akiko\r
+        REASON: - initial release by Namikon\r
+        MODIFIED: 11 Dec 2005 Namikon\r
+        REASON: - Added function SendDChat(Client, <text>, <nick>) to send a Direct to player\r
+                - Added Channel IDs for GameMaster (/gm) and Administrator (/admin) chat\r
+                - Added channel const's for sending chat packets\r
+                - Added function SendChat(Client, <channel>, <text>, <nick>) to send chat messages\r
+                  See chat.h for a list of availeable <channel>'s\r
+\r
+        MODIFIED: 17 Dec 2005 bakkdoor\r
+        REASON: - introduced new structure for chatsystem\r
+                - -> PChat class\r
+\r
+       ToDo:\r
+       - Add "hooks" to process chatevents everywhere in the source <-- kind of done. you can use the global PChat Instance.\r
+        Check:\r
+                Chat->send(PClient* receiver, const u8* Channel, const char* AuthorNickName, char* text, bool debugOut=false);\r
+        Example:\r
+                Chat->send(receiverClient, CHAT_DIRECT, Chars->GetChar(authorClient->GetCharID())->GetName().c_str(), text);\r
+*/\r
+\r
+#include "main.h"\r
+#include "msgbuilder.h"\r
+\r
+PChat::PChat()\r
+{\r
+}\r
+\r
+PChat::~PChat()\r
+{\r
+}\r
+\r
+/*\r
+DONE    void sendBuddy(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendLocal(PClient* author, char* text, bool debugOut=false);\r
+NEED CLANDATA    void sendClan(PClient* author, char* text, bool debugOut=false);\r
+NEED TEAMDATA    void sendTeam(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendDirect(PClient* author, PClient* receiver, char* text, bool debugOut=false);\r
+DONE    void sendZone(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendFrak(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendTradeCS(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendTradeMB(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendTradeNC(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendTradeTH(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendTradeWL(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendOOC(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendHelp(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendClanSearch(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendServicesCS(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendServicesMB(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendServicesNC(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendServicesTH(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendServicesWL(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendTeam10(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendTeam30(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendTeam50(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendTeam70(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendAdmin(PClient* author, char* text, bool debugOut=false);\r
+DONE    void sendGM(PClient* author, char* text, bool debugOut=false);\r
+*/\r
+\r
+\r
+void PChat::sendBuddy(PClient* author, const char* text, bool debugOut)\r
+{\r
+    PChar* authorChar = Chars->GetChar(author->GetCharID());\r
+    // send the message to all Buddys in list\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second && authorChar->IsBuddy(it->second->GetCharID()) == true)\r
+        {\r
+            PClient* receiver = it->second;\r
+            //Console->Print("DEBUG: Buddychat - Sending msg to %s", Chars->GetChar(receiver->GetCharID())->GetName().c_str());\r
+            send(receiver, CHAT_BUDDY, authorChar->GetName().c_str(), text, debugOut);\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendConnectedList(PClient* receiver, bool debugOut)\r
+{\r
+       const char* text = "Connected Players are:]";\r
+    send(receiver, CHAT_DIRECT, "[System", text, debugOut);\r
+\r
+    int counter = 1;\r
+\r
+    // send the list of currently connected players to receiver\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+                 char counterText[5];\r
+                 snprintf(counterText, 5, "%d", counter);\r
+\r
+        PChar* receiverChar = Chars->GetChar(it->second->GetCharID());\r
+        send(receiver, CHAT_DIRECT, (receiverChar ? receiverChar->GetName().c_str() : "*"), counterText, debugOut);\r
+\r
+        counter++;\r
+    }\r
+}\r
+\r
+\r
+void PChat::sendFrak(PClient* author, const char* text, bool debugOut)\r
+{\r
+    // send the message to all clients that have same FactionID\r
+    PChar* authorChar = Chars->GetChar(author->GetCharID());\r
+    u32 FID = authorChar->GetFaction(); // get LocationID of author\r
+\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            PClient* receiver = it->second;\r
+            PChar* receiverChar = Chars->GetChar(receiver->GetCharID());\r
+            if(receiverChar && (receiverChar->GetFaction() == FID))\r
+            {\r
+                if(chanEnabled(receiver, C_FRAK) == true)\r
+                    send(receiver, CHAT_FRAK, authorChar->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendZone(PClient* author, const char* text, bool debugOut)\r
+{\r
+    // send the message to all clients that have same ZoneID\r
+    PChar* authorChar = Chars->GetChar(author->GetCharID());\r
+    u32 ZID = authorChar->GetLocation(); // get LocationID of author\r
+\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            PClient* receiver = it->second;\r
+            PChar* receiverChar = Chars->GetChar(receiver->GetCharID());\r
+            if(receiverChar && (receiverChar->GetLocation() == ZID))\r
+            {\r
+                if(chanEnabled(receiver, C_ZONE) == true)\r
+                    send(receiver, CHAT_ZONE, authorChar->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendLocal(PClient* author, const char* text, bool debugOut)\r
+{\r
+    PChar* authorChar = Chars->GetChar(author->GetCharID());\r
+    u32 ZID = authorChar->GetLocation(); // get LocationID of author\r
+\r
+    // send the message to all clients that are in Area (Radius = X (needs to be defined somewhere!))\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            PClient* receiver = it->second;\r
+            PChar* receiverChar = Chars->GetChar(receiver->GetCharID());\r
+            if(receiverChar && (receiverChar->GetLocation() == ZID))\r
+            {\r
+                u16 distance = DistanceApprox((authorChar->Coords).mX, (authorChar->Coords).mY, (authorChar->Coords).mZ, (receiverChar->Coords).mX, (receiverChar->Coords).mY, (receiverChar->Coords).mZ);\r
+                if(distance < LOCALCHAT_MAXDISTANCE)\r
+                {\r
+                    //sendLocalchat(receiver, author, text, debugOut); // Doesnt work!\r
+                    send(receiver, CHAT_LOCAL, authorChar->GetName().c_str(), text, debugOut);\r
+                }\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendGM(PClient* author, const char* text, bool debugOut)\r
+{\r
+    if(author->GetAccountLevel() >= PAL_GM) // Only send GM> chat when user is an Gamemaster or higher\r
+    {\r
+        // send the message to all GameMasters.\r
+        for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+        {\r
+            if(author != it->second) // if its not the client, that send the message to the server\r
+            {\r
+                if(it->second) // only send if the client is existing!\r
+                {\r
+                    PClient* receiver = it->second;\r
+                    if(receiver->GetAccountLevel() >= PAL_GM) // Only send GM chat if RECEIVER is GM or higher\r
+                        send(receiver, CHAT_GM, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+                }\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendGMAdmin(PClient* author, const char* text, bool debugOut)\r
+{\r
+    if(author->GetAccountLevel() >= PAL_GM) // Only send GM> chat when user is an Gamemaster or higher\r
+    {\r
+        // send the message to ALL users online\r
+        for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+        {\r
+            if(author != it->second) // if its not the client, that send the message to the server\r
+            {\r
+                if(it->second) // only send if the client is existing!\r
+                {\r
+                    PClient* receiver = it->second;\r
+                    send(receiver, CHAT_GMADMIN, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+                }\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendAdmin(PClient* author, const char* text, bool debugOut)\r
+{\r
+    if(author->GetAccountLevel() >= PAL_ADMIN) // Only send ADMIN> chat when user is an serveradmin\r
+    {\r
+        // send the message to ALL users online\r
+        for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+        {\r
+            if(author != it->second) // if its not the client, that send the message to the server\r
+            {\r
+                if(it->second) // only send if the client is existing!\r
+                {\r
+                    PClient* receiver = it->second;\r
+                    send(receiver, CHAT_ADMIN, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+                }\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendBroadcast(const char* text, bool debugOut)\r
+{\r
+    // send the message to ALL users online\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(it->second) // only send if the client is existing!\r
+        {\r
+            PClient* receiver = it->second;\r
+            send(receiver, CHAT_ADMIN, "Server", text, debugOut);\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendOOCBroadcast(const char* text, bool debugOut)\r
+{\r
+    // send the message to ALL users online\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(it->second) // only send if the client is existing!\r
+        {\r
+            PClient* receiver = it->second;\r
+            if(chanEnabled(receiver, C_OOC) == true)\r
+                send(receiver, CHAT_OOC, "Server", text, debugOut);\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendClan(PClient* author, const char* text, bool debugOut)\r
+{\r
+    /**\r
+        NOT ABLE TO IMPLEMENT THIS CHATTYPE YET, ITS SUPERGLOBAL TILL THEN\r
+    **/\r
+    // send the message to all clients that have same ClanID\r
+    PChar* authorChar = Chars->GetChar(author->GetCharID());\r
+\r
+//    int ClanID = authorChar->getClanID(); // get clanID of author\r
+\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second)\r
+        {\r
+            PClient* receiver = it->second;\r
+            PChar* receiverChar = Chars->GetChar(receiver->GetCharID());\r
+            if(receiverChar /*&& (receiverChar->getClanID() == ClanID)*/)\r
+            {\r
+                send(receiver, CHAT_CLAN, authorChar->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+\r
+}\r
+\r
+void PChat::sendTeam(PClient* author, const char* text, bool debugOut)\r
+{\r
+    /**\r
+        NOT ABLE TO IMPLEMENT THIS CHATTYPE YET, ITS SUPERGLOBAL TILL THEN\r
+    **/\r
+    // send the message to all clients that have same TeamID\r
+\r
+    PChar* authorChar = Chars->GetChar(author->GetCharID());\r
+\r
+    //int TeamID = authorChar->getTeamID(); // get TeamID of author\r
+\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second)\r
+        {\r
+            PClient* receiver = it->second;\r
+            PChar* receiverChar = Chars->GetChar(receiver->GetCharID());\r
+            if(receiverChar /*&& (receiverChar->getTeamID() == TeamID)*/)\r
+            {\r
+                send(receiver, CHAT_TEAM, authorChar->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendPlayerDirect(PClient* author, const char* text, u32 destination, bool debugOut)\r
+{\r
+    bool tmpTargetOnline = false;\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        PClient* receiver = it->second;\r
+        PChar* receiverChar = Chars->GetChar(receiver->GetCharID());\r
+        if(receiverChar && (receiver->GetCharID() == destination))       \r
+        {\r
+            tmpTargetOnline = true;\r
+            sendDirect(author, receiver, text, debugOut);\r
+        }\r
+    }\r
+    if(tmpTargetOnline == false)\r
+    {\r
+        ConnectionTCP *Socket = author->getTCPConn();\r
+        u8 DirectTargetNotOnline[] = {0xFE, 0x07, 0x00, 0x83, 0x18, 0x01, 0x81, 0x54, 0x00, 0x00};\r
+\r
+        Socket->write(DirectTargetNotOnline, sizeof(DirectTargetNotOnline));\r
+        Socket->flushSendBuffer();\r
+    }\r
+\r
+    if(debugOut == true)\r
+    {\r
+        if(tmpTargetOnline == false)\r
+            Console->Print("[DEBUG] Requested target CharID %d is not online", destination);\r
+        else\r
+            Console->Print("[DEBUG] CharID %d found and message transmitted!", destination);\r
+    }\r
+}\r
+\r
+void PChat::sendDirect(PClient* author, PClient* receiver, const char* text, bool debugOut)\r
+{\r
+    PChar* authorChar = Chars->GetChar(author->GetCharID());\r
+\r
+    char *DChatPacket;\r
+    unsigned int packetsize = 0, c;\r
+    int LenText, LenNick, fpp, d, e, loopout;\r
+\r
+    ConnectionTCP *Socket = receiver->getTCPConn();\r
+\r
+    u8 BasicDirectPacket[] = {0xFE, 0x20, 0x00, 0x83, 0x17, 0xB7, 0x5F, 0x00, 0x00, 0x0C, 0x04, 0x00};\r
+\r
+    LenText = LenNick = fpp = 0;\r
+\r
+    do {\r
+      LenText++;\r
+    } while(text[LenText] != '\0');\r
+\r
+    do {\r
+      LenNick++;\r
+    } while(authorChar->GetName().c_str()[LenNick] != '\0');\r
+\r
+    loopout = 0;\r
+\r
+    packetsize = sizeof(BasicDirectPacket) + LenText + LenNick;\r
+\r
+    if(debugOut == true) {\r
+       Console->Print("Sizeof(TextToSend): %d || Sizeof(Nick): %d", LenText, LenNick);\r
+       Console->Print("Whole size: %d", packetsize);\r
+    }\r
+\r
+    DChatPacket = new char [packetsize];\r
+\r
+    // Copy basic packet into final packet\r
+    for(c=0;c<sizeof(BasicDirectPacket);c++) {\r
+       DChatPacket[fpp] = BasicDirectPacket[c];\r
+       fpp++;\r
+    }\r
+\r
+    // Copy Nickname into final packet\r
+    for(d=0;d<LenNick;d++) {\r
+       DChatPacket[fpp] = authorChar->GetName().c_str()[d];\r
+       fpp++;\r
+    }\r
+\r
+    // Copy Text into final packet\r
+    for(e=0;e<LenText;e++) {\r
+       DChatPacket[fpp] = text[e];\r
+       fpp++;\r
+    }\r
+\r
+    // Change Lenght bytes in final packet\r
+    DChatPacket[1] = packetsize - 3;\r
+    DChatPacket[9] = LenNick;\r
+\r
+    if(debugOut == true) {\r
+        unsigned int debugout;\r
+        for(debugout=0;debugout<packetsize;debugout++) {\r
+           Console->Print("Byte %d: %#x", debugout, DChatPacket[debugout]);\r
+        }\r
+    }\r
+\r
+    // Sending direct chat packet and removing dynamic array\r
+    Socket->write(DChatPacket, packetsize);\r
+    Socket->flushSendBuffer();\r
+    delete[] DChatPacket;\r
+}\r
+\r
+void PChat::sendLocalchat(PClient* receiver, PClient* author, const char* text, bool debugOut)\r
+{\r
+    return; // IncreaseUDP could cause OOO here. Since this function is doing nothing, we disabled it\r
+    char *LocalChatPacket;\r
+    int overallsize = 0, LenText = 0;\r
+    u8 BasicLocal[] = { 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1B };\r
+\r
+    // Get size of Text to send\r
+    do {\r
+      LenText++;\r
+    } while(text[LenText] != '\0');\r
+\r
+    // Calculate packetsize\r
+    overallsize = sizeof(BasicLocal) + LenText + 1;\r
+\r
+    if(debugOut == true)\r
+       Console->Print("Whole size: %d", overallsize);\r
+\r
+    LocalChatPacket = new char [overallsize];\r
+\r
+    // Copy basic packet into final packet\r
+    int fpp = 0;\r
+    for(unsigned int c = 0; c < sizeof(BasicLocal); c++) {\r
+       LocalChatPacket[fpp] = BasicLocal[c];\r
+       fpp++;\r
+    }\r
+\r
+    // Copy Text into final packet\r
+    for(int e = 0; e < LenText; e++) {\r
+       LocalChatPacket[fpp] = text[e];\r
+       fpp++;\r
+    }\r
+\r
+    // Terminate string\r
+    LocalChatPacket[fpp] = 0x00;\r
+\r
+    // Add UdpID, SessionID, lenght and local charid\r
+    receiver->IncreaseUDP_ID();\r
+    *(u16*)&LocalChatPacket[1] = receiver->GetUDP_ID();     // UDP\r
+    *(u16*)&LocalChatPacket[3] = receiver->GetSessionID();  // Session\r
+    *(u8*)&LocalChatPacket[5] = overallsize - 6;            // Packetlen\r
+    *(u16*)&LocalChatPacket[7] = receiver->GetUDP_ID();     // 2nd UDP\r
+    *(u16*)&LocalChatPacket[10] = author->GetLocalID();     // Local ID\r
+\r
+    // Sending local chat packet and removing dynamic array\r
+    ConnectionUDP *Socket = receiver->getUDPConn();\r
+    Socket->write(LocalChatPacket, overallsize);\r
+    Socket->flushSendBuffer();\r
+    delete[] LocalChatPacket;\r
+}\r
+\r
+void PChat::sendTradeCS(PClient* author, const char* text, bool debugOut)\r
+{\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            if(it->second) // only send if the client is existing!\r
+            {\r
+                PClient* receiver = it->second;\r
+                if(chanEnabled(receiver, C_TRADECS) == true)\r
+                    send(receiver, CHAT_TRADECS, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendTradeMB(PClient* author, const char* text, bool debugOut)\r
+{\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            if(it->second) // only send if the client is existing!\r
+            {\r
+                PClient* receiver = it->second;\r
+                if(chanEnabled(receiver, C_TRADEMB) == true)\r
+                    send(receiver, CHAT_TRADEMB, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendTradeNC(PClient* author, const char* text, bool debugOut)\r
+{\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            if(it->second) // only send if the client is existing!\r
+            {\r
+                PClient* receiver = it->second;\r
+                if(chanEnabled(receiver, C_TRADENC) == true)\r
+                    send(receiver, CHAT_TRADENC, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendTradeTH(PClient* author, const char* text, bool debugOut)\r
+{\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            if(it->second) // only send if the client is existing!\r
+            {\r
+                PClient* receiver = it->second;\r
+                if(chanEnabled(receiver, C_TRADETH) == true)\r
+                    send(receiver, CHAT_TRADETH, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendTradeWL(PClient* author, const char* text, bool debugOut)\r
+{\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            if(it->second) // only send if the client is existing!\r
+            {\r
+                PClient* receiver = it->second;\r
+                if(chanEnabled(receiver, C_TRADEWL) == true)\r
+                    send(receiver, CHAT_TRADEWL, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendOOC(PClient* author, const char* text, bool debugOut)\r
+{\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            if(it->second) // only send if the client is existing!\r
+            {\r
+                PClient* receiver = it->second;\r
+                if(chanEnabled(receiver, C_OOC) == true)\r
+                    send(receiver, CHAT_OOC, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendHelp(PClient* author, const char* text, bool debugOut)\r
+{\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            if(it->second) // only send if the client is existing!\r
+            {\r
+                PClient* receiver = it->second;\r
+                if(chanEnabled(receiver, C_HELP) == true)\r
+                    send(receiver, CHAT_HELP, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendClanSearch(PClient* author, const char* text, bool debugOut)\r
+{\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            if(it->second) // only send if the client is existing!\r
+            {\r
+                PClient* receiver = it->second;\r
+                if(chanEnabled(receiver, C_CLANSEARCH) == true)\r
+                    send(receiver, CHAT_CLANSEARCH, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendServicesCS(PClient* author, const char* text, bool debugOut)\r
+{\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            if(it->second) // only send if the client is existing!\r
+            {\r
+                PClient* receiver = it->second;\r
+                if(chanEnabled(receiver, C_SERVICECS) == true)\r
+                    send(receiver, CHAT_SERVICECS, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendServicesMB(PClient* author, const char* text, bool debugOut)\r
+{\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            if(it->second) // only send if the client is existing!\r
+            {\r
+                PClient* receiver = it->second;\r
+                if(chanEnabled(receiver, C_SERVICEMB) == true)\r
+                    send(receiver, CHAT_SERVICESMB, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendServicesNC(PClient* author, const char* text, bool debugOut)\r
+{\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            if(it->second) // only send if the client is existing!\r
+            {\r
+                PClient* receiver = it->second;\r
+                if(chanEnabled(receiver, C_SERVICENC) == true)\r
+                    send(receiver, CHAT_SERVICESNC, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendServicesTH(PClient* author, const char* text, bool debugOut)\r
+{\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            if(it->second) // only send if the client is existing!\r
+            {\r
+                PClient* receiver = it->second;\r
+                if(chanEnabled(receiver, C_SERVICETH) == true)\r
+                    send(receiver, CHAT_SERVICESTH, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendServicesWL(PClient* author, const char* text, bool debugOut)\r
+{\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            if(it->second) // only send if the client is existing!\r
+            {\r
+                PClient* receiver = it->second;\r
+                if(chanEnabled(receiver, C_SERVICEWL) == true)\r
+                    send(receiver, CHAT_SERVICESWL, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendTeam10(PClient* author, const char* text, bool debugOut)\r
+{\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            if(it->second) // only send if the client is existing!\r
+            {\r
+                PClient* receiver = it->second;\r
+                if(chanEnabled(receiver, C_TEAM10) == true)\r
+                    send(receiver, CHAT_TEAM10, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendTeam30(PClient* author, const char* text, bool debugOut)\r
+{\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            if(it->second) // only send if the client is existing!\r
+            {\r
+                PClient* receiver = it->second;\r
+                if(chanEnabled(receiver, C_TEAM30) == true)\r
+                    send(receiver, CHAT_TEAM30, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendTeam50(PClient* author, const char* text, bool debugOut)\r
+{\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            if(it->second) // only send if the client is existing!\r
+            {\r
+                PClient* receiver = it->second;\r
+                if(chanEnabled(receiver, C_TEAM50) == true)\r
+                    send(receiver, CHAT_TEAM50, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void PChat::sendTeam70(PClient* author, const char* text, bool debugOut)\r
+{\r
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
+    {\r
+        if(author != it->second) // if its not the client, that send the message to the server\r
+        {\r
+            if(it->second) // only send if the client is existing!\r
+            {\r
+                PClient* receiver = it->second;\r
+                if(chanEnabled(receiver, C_TEAM70) == true)\r
+                    send(receiver, CHAT_TEAM70, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+bool PChat::chanEnabled(PClient* Client, u32 channel)\r
+{\r
+    // Check if player has target channel enabled or disabled\r
+    PChar* TargetChar = Chars->GetChar(Client->GetCharID());\r
+    if(!TargetChar)\r
+      return false;\r
+      \r
+    u32 actChans = TargetChar->GetActiveChannels();\r
+    u32 check = actChans & channel;\r
+\r
+    if(check == channel)\r
+        return true;\r
+    else\r
+        return false;\r
+}\r
+\r
+bool PChat::send(PClient* receiver, const u8* Channel, const char* AuthorNickName, const char* text, bool debugOut)\r
+{\r
+    char *ChatPacket;\r
+    unsigned int packetsize = 0, c;\r
+    int LenText, LenNick, fpp, d, e, loopout;\r
+    u8 TargetChannel[2];\r
+\r
+//Console->Print("1: %#x", Channel[0]);\r
+//Console->Print("2: %#x", CHAT_BUDDY[0]);\r
+\r
+\r
+      if(cmpr(Channel, CHAT_BUDDY) == true) {\r
+           TargetChannel[0] = CHAT_BUDDY[0];\r
+           TargetChannel[1] = CHAT_BUDDY[1];\r
+      } else if(cmpr(Channel, CHAT_LOCAL) == true) {\r
+           TargetChannel[0] = CHAT_LOCAL[0];\r
+           TargetChannel[1] = CHAT_LOCAL[1];\r
+      } else if(cmpr(Channel, CHAT_CLAN) == true) {\r
+           TargetChannel[0] = CHAT_CLAN[0];\r
+           TargetChannel[1] = CHAT_CLAN[1];\r
+      } else if(cmpr(Channel, CHAT_TEAM) == true) {\r
+           TargetChannel[0] = CHAT_TEAM[0];\r
+           TargetChannel[1] = CHAT_TEAM[1];\r
+      } else if(cmpr(Channel, CHAT_DIRECT) == true) {\r
+           TargetChannel[0] = CHAT_DIRECT[0];\r
+           TargetChannel[1] = CHAT_DIRECT[1];\r
+      } else if(cmpr(Channel, CHAT_ZONE) == true) {\r
+           TargetChannel[0] = CHAT_ZONE[0];\r
+           TargetChannel[1] = CHAT_ZONE[1];\r
+      } else if(cmpr(Channel, CHAT_FRAK) == true) {\r
+           TargetChannel[0] = CHAT_FRAK[0];\r
+           TargetChannel[1] = CHAT_FRAK[1];\r
+      } else if(cmpr(Channel, CHAT_TRADECS) == true) {\r
+           TargetChannel[0] = CHAT_TRADECS[0];\r
+           TargetChannel[1] = CHAT_TRADECS[1];\r
+      } else if(cmpr(Channel, CHAT_TRADEMB) == true) {\r
+           TargetChannel[0] = CHAT_TRADEMB[0];\r
+           TargetChannel[1] = CHAT_TRADEMB[1];\r
+      } else if(cmpr(Channel, CHAT_TRADENC) == true) {\r
+           TargetChannel[0] = CHAT_TRADENC[0];\r
+           TargetChannel[1] = CHAT_TRADENC[1];\r
+      } else if(cmpr(Channel, CHAT_TRADETH) == true) {\r
+           TargetChannel[0] = CHAT_TRADETH[0];\r
+           TargetChannel[1] = CHAT_TRADETH[1];\r
+      } else if(cmpr(Channel, CHAT_TRADEWL) == true) {\r
+           TargetChannel[0] = CHAT_TRADEWL[0];\r
+           TargetChannel[1] = CHAT_TRADEWL[1];\r
+      } else if(cmpr(Channel, CHAT_OOC) == true) {\r
+           TargetChannel[0] = CHAT_OOC[0];\r
+           TargetChannel[1] = CHAT_OOC[1];\r
+      } else if(cmpr(Channel, CHAT_HELP) == true) {\r
+           TargetChannel[0] = CHAT_HELP[0];\r
+           TargetChannel[1] = CHAT_HELP[1];\r
+      } else if(cmpr(Channel, CHAT_CLANSEARCH) == true) {\r
+           TargetChannel[0] = CHAT_CLANSEARCH[0];\r
+           TargetChannel[1] = CHAT_CLANSEARCH[1];\r
+      } else if(cmpr(Channel, CHAT_SERVICECS) == true) {\r
+           TargetChannel[0] = CHAT_SERVICECS[0];\r
+           TargetChannel[1] = CHAT_SERVICECS[1];\r
+      } else if(cmpr(Channel, CHAT_SERVICESMB) == true) {\r
+           TargetChannel[0] = CHAT_SERVICESMB[0];\r
+           TargetChannel[1] = CHAT_SERVICESMB[1];\r
+      } else if(cmpr(Channel, CHAT_SERVICESNC) == true) {\r
+           TargetChannel[0] = CHAT_SERVICESNC[0];\r
+           TargetChannel[1] = CHAT_SERVICESNC[1];\r
+      } else if(cmpr(Channel, CHAT_SERVICESTH) == true) {\r
+           TargetChannel[0] = CHAT_SERVICESTH[0];\r
+           TargetChannel[1] = CHAT_SERVICESTH[1];\r
+      } else if(cmpr(Channel, CHAT_SERVICESWL) == true) {\r
+           TargetChannel[0] = CHAT_SERVICESWL[0];\r
+           TargetChannel[1] = CHAT_SERVICESWL[1];\r
+      } else if(cmpr(Channel, CHAT_TEAM10) == true) {\r
+           TargetChannel[0] = CHAT_TEAM10[0];\r
+           TargetChannel[1] = CHAT_TEAM10[1];\r
+      } else if(cmpr(Channel, CHAT_TEAM30) == true) {\r
+           TargetChannel[0] = CHAT_TEAM30[0];\r
+           TargetChannel[1] = CHAT_TEAM30[1];\r
+      } else if(cmpr(Channel, CHAT_TEAM50) == true) {\r
+           TargetChannel[0] = CHAT_TEAM50[0];\r
+           TargetChannel[1] = CHAT_TEAM50[1];\r
+      } else if(cmpr(Channel, CHAT_TEAM70) == true) {\r
+           TargetChannel[0] = CHAT_TEAM70[0];\r
+           TargetChannel[1] = CHAT_TEAM70[1];\r
+      } else if(cmpr(Channel, CHAT_ADMIN) == true) {\r
+           TargetChannel[0] = CHAT_ADMIN[0];\r
+           TargetChannel[1] = CHAT_ADMIN[1];\r
+      } else if(cmpr(Channel, CHAT_GMADMIN) == true) {\r
+           TargetChannel[0] = CHAT_GMADMIN[0];\r
+           TargetChannel[1] = CHAT_GMADMIN[1];\r
+      } else if(cmpr(Channel, CHAT_GM) == true) {\r
+           TargetChannel[0] = CHAT_GM[0];\r
+           TargetChannel[1] = CHAT_GM[1];\r
+      } else {\r
+         Console->Print("SendChat error: Channel %#x unknown", Channel);\r
+         return false;\r
+      }\r
+\r
+    ConnectionTCP *Socket = receiver->getTCPConn();\r
+\r
+    u8 BasicChatPacket[] = {0xFE, 0x15, 0x00, 0x83, 0x17, 0x90, 0x03, 0x00, 0x00, 0x07, 0x05, 0x0F};\r
+\r
+    LenText = LenNick = fpp = 0;\r
+\r
+    do {\r
+      LenText++;\r
+    } while(text[LenText] != '\0');\r
+\r
+    do {\r
+      LenNick++;\r
+    } while(AuthorNickName[LenNick] != '\0');\r
+\r
+    if(LenText == 0 || LenNick == 0) {\r
+       Console->Print("Error in SendChat, nickname or text is missing");\r
+       return false;\r
+    }\r
+\r
+    loopout = 0;\r
+\r
+    packetsize = sizeof(BasicChatPacket) + LenText + LenNick;\r
+\r
+    if(debugOut == true) {\r
+       Console->Print("Sizeof(TextToSend): %d || Sizeof(Nick): %d", LenText, LenNick);\r
+       Console->Print("Whole size: %d", packetsize);\r
+    }\r
+\r
+    ChatPacket = new char [packetsize];\r
+\r
+    // Copy basic packet into final packet\r
+    for(c=0;c<sizeof(BasicChatPacket);c++) {\r
+       ChatPacket[fpp] = BasicChatPacket[c];\r
+       fpp++;\r
+    }\r
+\r
+    // Copy Nickname into final packet\r
+    for(d=0;d<LenNick;d++) {\r
+       ChatPacket[fpp] = AuthorNickName[d];\r
+       fpp++;\r
+    }\r
+\r
+    // Copy Text into final packet\r
+    for(e=0;e<LenText;e++) {\r
+       ChatPacket[fpp] = text[e];\r
+       fpp++;\r
+    }\r
+\r
+    // Change Lenght bytes in final packet\r
+    ChatPacket[1] = packetsize - 3;\r
+    ChatPacket[9] = LenNick;\r
+    ChatPacket[10] = TargetChannel[0];\r
+    ChatPacket[11] = TargetChannel[1];\r
+\r
+    if(debugOut == true) {\r
+        unsigned int debugout;\r
+        for(debugout=0;debugout<packetsize;debugout++) {\r
+           Console->Print("Byte %d: %#x", debugout, ChatPacket[debugout]);\r
+        }\r
+    }\r
+\r
+    // Sending direct chat packet and removing dynamic array\r
+    Socket->write(ChatPacket, packetsize);\r
+    Socket->flushSendBuffer();\r
+    delete[] ChatPacket;\r
+\r
+    return true;\r
+}\r
+\r
+\r
+\r
+bool PChat::HandleGameChat(PClient *Client, const u8 *Packet)\r
+{\r
+    // if player is shunned, ignore all incomming chat and game commands.\r
+    // ServerAdmins are not affected by any shuns. (Should never happen anyways...)\r
+    if((Client->GetChar()->IsShunned() == true) && (Client->GetAccountLevel() < PAL_ADMIN)) return true;\r
+\r
+    int i, j, k;\r
+\r
+     u8 chattype = *(u8*)&Packet[7];\r
+// -----------------------------------------------\r
+    if(chattype == 0x1B) {\r
+      // Local chat\r
+      i = 8;\r
+      j = 0;\r
+\r
+      char ChatText[255];\r
+\r
+      do {\r
+         ChatText[j] = Packet[i];\r
+         i++;\r
+         j++;\r
+      } while (ChatText[j-1] != 0x00);\r
+\r
+      ChatText[j] = '\0';\r
+      if(ChatText[0] == '@' && sizeof(ChatText) > 2) {\r
+            GameCommands->HandleGameCommand(ChatText, Client);\r
+      } else {\r
+          // We know its working, so we dont need console output anymore\r
+            //Console->Print("Local Chat: %s", ChatText);\r
+            //Console->Print("Client CharName is: %s", Chars->GetChar(Client->GetCharID())->GetName().c_str());\r
+            sendLocal(Client, ChatText, false);\r
+      }\r
+\r
+// -----------------------------------------------\r
+   } else if (chattype == 0x3B) {\r
+      // Non-Local chat\r
+      i = 13;\r
+      j = 0;\r
+      k = 0;\r
+\r
+      char ChatText[255];\r
+\r
+      do {\r
+         ChatText[j] = Packet[i];\r
+         i++;\r
+         j++;\r
+      } while (ChatText[j-1] != 0x00);\r
+\r
+\r
+      ChatText[j] = '\0';\r
+      if(ChatText[0] == '@' && sizeof(ChatText) > 2) {\r
+            GameCommands->HandleGameCommand(ChatText, Client);\r
+      } else {\r
+        //      Console->Print("CHATLINE: %s HEX: %#X", ChatText, Packet[i-1]);\r
+        char Channel[4];\r
+\r
+        for(k = 0; k <= 3; k ++) {\r
+           Channel[k] = Packet[k+8];\r
+        }\r
+  //    Console->Print("Channel no %#x %#x %#x %#x", Channel[0], Channel[1], Channel[2], Channel[3]);\r
+\r
+        // First, check if packet is a direct-chat-packet\r
+        if(*(u8*)&Packet[8] == 0x04) {\r
+             //Console->Print("Direct Chat: %s", ChatText);\r
+             sendPlayerDirect(Client, ChatText, *(u32*)&Packet[9], false);\r
+             //sendDirect(Client, ChatText, false);\r
+             // "DIRECT> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_BUDDY) {\r
+             //Console->Print("Buddy Chat: %s", ChatText);\r
+             sendBuddy(Client, ChatText, false);\r
+             // "BUDDY> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CLAN) {\r
+             //Console->Print("Clan Chat: %s", ChatText);\r
+             sendClan(Client, ChatText, false);\r
+             // "CLAN> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_TEAM) {\r
+             //Console->Print("Team Chat: %s", ChatText);\r
+             sendTeam(Client, ChatText, false);\r
+             // "TEAM> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_ZONE) {\r
+             //Console->Print("Custom - Zone Chat: %s", ChatText);\r
+             sendZone(Client, ChatText, false);\r
+             // "ZONE> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_FRAKTION) {\r
+             //Console->Print("Custom - Fraktion Chat: %s", ChatText);\r
+             sendFrak(Client, ChatText, false);\r
+             // "FRACTION> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_TRADE_CANYON) {\r
+             //Console->Print("Custom - Trade_Canyon Chat: %s", ChatText);\r
+             sendTradeCS(Client, ChatText, false);\r
+             // "TRADE - CS> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_TRADE_MB) {\r
+             //Console->Print("Custom - Trade_MB Chat: %s", ChatText);\r
+             sendTradeMB(Client, ChatText, false);\r
+             // "TRADE - MB> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_TRADE_NC) {\r
+             //Console->Print("Custom - Trade_NC Chat: %s", ChatText);\r
+             sendTradeNC(Client, ChatText, false);\r
+             // "TRADE - NC> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_TRADE_TH) {\r
+             //Console->Print("Custom - Trade_TH Chat: %s", ChatText);\r
+             sendTradeTH(Client, ChatText, false);\r
+             // "TRADE - TH> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_TRADE_WASTE) {\r
+             //Console->Print("Custom - Trade_Waste Chat: %s", ChatText);\r
+             sendTradeWL(Client, ChatText, false);\r
+             // "TRADE - WL> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_OOC) {\r
+             //Console->Print("Custom - OOC Chat: %s", ChatText);\r
+             sendOOC(Client, ChatText, false);\r
+             // "OOC> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_PLAYERHELP) {\r
+             //Console->Print("Custom - PlayerToPlayerhelp Chat: %s", ChatText);\r
+             sendHelp(Client, ChatText, false);\r
+             // "HELP> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_CLANSEARCH) {\r
+             //Console->Print("Custom - Clansearch Chat: %s", ChatText);\r
+             sendClanSearch(Client, ChatText, false);\r
+             // "CLANSEARCH> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_SERVICES_CANYON) {\r
+             //Console->Print("Custom - Services_Canyon Chat: %s", ChatText);\r
+             sendServicesCS(Client, ChatText, false);\r
+             // "SKILL - CS> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_SERVICES_MB) {\r
+             //Console->Print("Custom - Services_MB Chat: %s", ChatText);\r
+             sendServicesMB(Client, ChatText, false);\r
+             // "SKILL - MB> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_SERVICES_NC) {\r
+             //Console->Print("Custom - Services_NC Chat: %s", ChatText);\r
+             sendServicesNC(Client, ChatText, false);\r
+             // "SKILL - NC> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_SERVICES_TH) {\r
+             //Console->Print("Custom - Services_TH Chat: %s", ChatText);\r
+             sendServicesTH(Client, ChatText, false);\r
+             // "SKILL - TH> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_SERVICES_WASTE) {\r
+             //Console->Print("Custom - Services_Waste Chat: %s", ChatText);\r
+             sendServicesWL(Client, ChatText, false);\r
+             // "SKILL - WL> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_TEAM_10) {\r
+             //Console->Print("Custom - Team10 Chat: %s", ChatText);\r
+             sendTeam10(Client, ChatText, false);\r
+             // "TEAMSEARCH 10> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_TEAM_30) {\r
+             //Console->Print("Custom - Team30 Chat: %s", ChatText);\r
+             sendTeam30(Client, ChatText, false);\r
+             // "EAMSEARCH 30> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_TEAM_50) {\r
+             //Console->Print("Custom - Team50 Chat: %s", ChatText);\r
+             sendTeam50(Client, ChatText, false);\r
+             // "EAMSEARCH 50> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_CUS_TEAM_70) {\r
+             //Console->Print("Custom - Team70 Chat: %s", ChatText);\r
+             sendTeam70(Client, ChatText, false);\r
+             // "EAMSEARCH 70> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_ADMIN) {\r
+             //Console->Print("Admin Chat: %s", ChatText);\r
+             sendAdmin(Client, ChatText, false);\r
+             // "ADMIN> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_GMADMIN) {\r
+             //Console->Print("Admin Chat: %s", ChatText);\r
+             sendGMAdmin(Client, ChatText, false);\r
+             // "ADMIN> %s: %s", PlayerName, ChatText\r
+        }\r
+        else if(*(u32*)Channel == CHANNEL_GMCHAT) {\r
+             //Console->Print("GameMaster Chat: %s", ChatText);\r
+             sendGM(Client, ChatText, false);\r
+             // "GM> %s: %s", PlayerName, ChatText\r
+        }\r
+        else {\r
+             Console->Print("Unknown Chat-Channel: %#x", *(u32*)Channel);\r
+        };\r
+  }\r
+}\r
+return (true);\r
+}\r
+\r
+bool PChat::cmpr(const u8 *Array1, const u8 *Array2) {\r
+   if(Array1[0] == Array2[0] && Array1[1] == Array2[1]) {\r
+       return true;\r
+   } else {\r
+       return false;\r
+   }\r
+}\r
diff --git a/server/src/game/client.cpp b/server/src/game/client.cpp
new file mode 100644 (file)
index 0000000..36ebd8c
--- /dev/null
@@ -0,0 +1,563 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+ client.cpp\r
+\r
+ Authors:\r
+ - v00d00\r
+ - Akiko\r
+ - Namikon\r
+\r
+ MODIFIED: 30 Nov 2005 Akiko\r
+ REASON: - added GPL\r
+            - added modifications by Namikon\r
+*/\r
+\r
+#include "main.h"\r
+\r
+#include "worlds.h"\r
+#include "msgbuilder.h"\r
+#include "subway.h"\r
+#include "decoder/udp_charmove.h"\r
+\r
+PClient::PClient( int Index )\r
+{\r
+  mAccountID = 0;\r
+  mAccountLevel = 0;\r
+  mIndex = Index;\r
+  mCharID = 0;\r
+  mConnection = PCC_NONE;\r
+  mRemotePort = 0;\r
+  m_TCPConnection = NULL;\r
+  m_UDPConnection = NULL;\r
+\r
+  for ( int i = 0; i < DEBUG_MODES ; i++ )\r
+    mDebugMode[i] = false;\r
+\r
+  //********\r
+  mAwaitingWarpto = false;\r
+  mTargetX = 0;\r
+  mTargetY = 0;\r
+  mTargetZ = 0;\r
+  //********\r
+  mActorRemoveMode = false;\r
+  mAcceptNPCUpdates = false;\r
+\r
+  testval8 = 0;\r
+}\r
+\r
+PClient::~PClient()\r
+{\r
+  if ( m_TCPConnection )\r
+  {\r
+    delete m_TCPConnection;\r
+    m_TCPConnection = NULL;\r
+  }\r
+  if ( m_UDPConnection )\r
+  {\r
+    delete m_UDPConnection;\r
+    m_UDPConnection = NULL;\r
+  }\r
+}\r
+/// ******************************************************\r
+\r
+u16 PClient::GetUDP_ID()\r
+{\r
+  if ( m_UDPConnection )\r
+    return m_UDPConnection->GetUDP_ID();\r
+  else\r
+    Console->Print( "%s Unable to get UDP_ID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );\r
+  return 0;\r
+}\r
+\r
+void PClient::SetUDP_ID( int id )\r
+{\r
+  if ( m_UDPConnection )\r
+    m_UDPConnection->SetUDP_ID( id );\r
+  else\r
+    Console->Print( "%s Unable to set UDP_ID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );\r
+}\r
+\r
+void PClient::IncreaseUDP_ID()\r
+{\r
+  if ( m_UDPConnection )\r
+    m_UDPConnection->IncreaseUDP_ID();\r
+  else\r
+    Console->Print( "%s Unable to increase UDP_ID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );\r
+}\r
+\r
+u16 PClient::GetSessionID()\r
+{\r
+  if ( m_UDPConnection )\r
+    return m_UDPConnection->GetSessionID();\r
+  else\r
+    Console->Print( "%s Unable to get UDP SessionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );\r
+  return 0;\r
+}\r
+\r
+u16 PClient::GetTransactionID()\r
+{\r
+  if ( m_UDPConnection )\r
+    return m_UDPConnection->GetTransactionID();\r
+  else\r
+    Console->Print( "%s Unable to get UDP TransactionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );\r
+  return 0;\r
+}\r
+\r
+void PClient::ResetTransactionID()\r
+{\r
+  if ( m_UDPConnection )\r
+    m_UDPConnection->ResetTransactionID();\r
+  else\r
+    Console->Print( "%s Unable to reset UDP TransactionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );\r
+}\r
+\r
+void PClient::IncreaseTransactionID( u8 nInc )\r
+{\r
+  if ( m_UDPConnection )\r
+    m_UDPConnection->IncreaseTransactionID( nInc );\r
+  else\r
+    Console->Print( "%s Unable to increase UDP TransactionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );\r
+}\r
+\r
+void PClient::FillInUDP_ID( PMessage* nMessage )\r
+{\r
+  u16 CurrPos;\r
+\r
+  if (( nMessage->GetSize() > 9 ) && ( nMessage->U8Data( 0x00 ) == 0x13 ) )\r
+  {\r
+    CurrPos = 5;\r
+    while ( CurrPos < nMessage->GetSize() ) // do UDP_ID mgt for each 0x03 subtype subpacket\r
+    {\r
+      if ( nMessage->U8Data( CurrPos + 1 ) == 0x03 )\r
+      {\r
+        IncreaseUDP_ID();\r
+        nMessage->U16Data( CurrPos + 2 ) = GetUDP_ID();\r
+      }\r
+      CurrPos = CurrPos + nMessage->U8Data( CurrPos ) + 1;\r
+    }\r
+  }\r
+  nMessage->U16Data( 0x01 ) = GetUDP_ID();\r
+  nMessage->U16Data( 0x03 ) = GetSessionID();\r
+}\r
+\r
+void PClient::FragmentAndSendUDPMessage( PMessage* nMessage, u8 nType )\r
+{\r
+  PMessage* ChunkBuffer;\r
+  PMessage* ChunkMsg;\r
+  const u16 ChunkSize = 220;\r
+  u16 StartIncUDPIDOnChunk = 0;\r
+  u16 IncludedHeaderSize = 0;\r
+  bool ReplaceFirstByte = false;\r
+  u8 ReplaceFirstByteValue = 0;\r
+  u16 MultiTriggeringSize = 0;\r
+\r
+  switch ( nType )\r
+  {\r
+    case 0x68: // Terminal ReceiveDB\r
+    {\r
+        ReplaceFirstByte = true;\r
+        ReplaceFirstByteValue = 0x21;\r
+        MultiTriggeringSize = 220;\r
+        IncludedHeaderSize = 9;\r
+        StartIncUDPIDOnChunk = 1;\r
+        break;\r
+    }\r
+    case 0x04:\r
+    {\r
+      Console->Print( RED, BLACK, "[Error] PClient::FragmentAndSendUDPMessage: Message type 0x%02x not managed yet", nType );\r
+      break;\r
+    }\r
+    case 0x05: //CharOpenContainerMsg with header & UDP_ID incremented\r
+    {\r
+      StartIncUDPIDOnChunk = 1;\r
+      IncludedHeaderSize = 9;\r
+      ReplaceFirstByte = true;\r
+      ReplaceFirstByteValue = 0x15;\r
+      MultiTriggeringSize = 230;\r
+      break;\r
+    }\r
+    case 0x06: // For sending Custom LUA Scripts to client\r
+    {\r
+        break;\r
+    }\r
+    case 0x19: //BaselineMsg (with no header)\r
+    {\r
+      break;\r
+    }\r
+    case 0xac: //BuildTraderItemListMsg with header & UDP_ID incremented\r
+    {\r
+      StartIncUDPIDOnChunk = 1;\r
+      IncludedHeaderSize = 9;\r
+      ReplaceFirstByte = true;\r
+      ReplaceFirstByteValue = 0x15;\r
+      MultiTriggeringSize = 230;\r
+      break;\r
+    }\r
+    default:\r
+    {\r
+      Console->Print( RED, BLACK, "[Error] PClient::FragmentAndSendUDPMessage: Message type 0x%02x not managed", nType );\r
+      break;\r
+    }\r
+  }\r
+\r
+  if ( nMessage->GetSize() >= MultiTriggeringSize )\r
+  {\r
+    if ( gDevDebug )\r
+      Console->Print( YELLOW, BLACK, "[Debug] Fragmenting message type 0x%02x", nType );\r
+    if ( ReplaceFirstByte )\r
+    {\r
+      nMessage->U8Data( IncludedHeaderSize ) = ReplaceFirstByteValue;\r
+    }\r
+\r
+    u16 ChunksNum = ( nMessage->GetSize() - IncludedHeaderSize + ChunkSize - 1 ) / ChunkSize;\r
+\r
+    for ( u16 ChunkID = 0; ChunkID < ChunksNum; ChunkID++ )\r
+    {\r
+      ChunkBuffer = nMessage->GetChunk( IncludedHeaderSize, ChunkSize, ChunkID );\r
+      if ( ChunkBuffer == NULL )\r
+      {\r
+        Console->Print( RED, BLACK, "[Error] PClient::FragmentAndSendUDPMessage: Bad chunk number: %d for size %d", ChunksNum, nMessage->GetSize() );\r
+        break;\r
+      }\r
+\r
+      ChunkMsg = new PMessage( ChunkSize + 15 );\r
+      if ( ChunkID >= StartIncUDPIDOnChunk )\r
+      {\r
+        IncreaseUDP_ID();\r
+      }\r
+\r
+      *ChunkMsg << ( u8 )0x13;\r
+      *ChunkMsg << ( u16 )GetUDP_ID();\r
+      *ChunkMsg << ( u16 )GetSessionID();\r
+      *ChunkMsg << ( u8 )( 9 + ChunkBuffer->GetSize() );\r
+      *ChunkMsg << ( u8 )0x03;\r
+      *ChunkMsg << ( u16 )GetUDP_ID();\r
+      *ChunkMsg << ( u8 )0x07; // Fragmented\r
+      *ChunkMsg << ( u16 )ChunkID;\r
+      *ChunkMsg << ( u16 )ChunksNum;\r
+      *ChunkMsg << ( u8 )nType;\r
+      *ChunkMsg << *ChunkBuffer;\r
+\r
+      delete ChunkBuffer;\r
+      //Console->Print(YELLOW, BLACK, "[Debug] Sending Fragment %d/%d", ChunkID+1, ChunksNum);\r
+      //ChunkMsg->Dump();\r
+      SendUDPMessage( ChunkMsg );\r
+    }\r
+    delete nMessage;\r
+  }\r
+  else\r
+  {\r
+    //Console->Print(YELLOW, BLACK, "[Debug] Sending message WITHOUT Fragmenting");\r
+    SendUDPMessage( nMessage );\r
+  }\r
+}\r
+\r
+/// ******************************************************\r
+\r
+void PClient::SetDebugMode( PDebugMode nDebugID, bool nVal )\r
+{\r
+  if ( nDebugID == DBG_ALL )\r
+  {\r
+    for ( int i = 0; i < DEBUG_MODES ; i++ )\r
+      mDebugMode[i] = nVal;\r
+  }\r
+  else\r
+    mDebugMode[nDebugID] = nVal;\r
+}\r
+\r
+bool PClient::ChangeCharLocation( u32 nLocation, bool DoForce )\r
+{\r
+  if ( gDevDebug )\r
+    Console->Print( "%s PClient::ChangeCharLocation", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
+  if ( Worlds->IsValidWorld( nLocation ) )\r
+  {\r
+    mAcceptNPCUpdates = false; // Zone changed, reject NPC updates till initial NPC spawn\r
+    PChar* tChar = GetChar();\r
+    u32 CurrentLocation = tChar->GetLocation();\r
+    if (( CurrentLocation == nLocation ) && !DoForce )\r
+      return true;\r
+\r
+    // DoForce is used in GM teleport and jail/unjail command to free player from jail\r
+    if (( tChar->IsJailed() == true ) && !DoForce )\r
+    {\r
+      if ( CurrentLocation != 550 && CurrentLocation != 551 ) // If player managed to "get out of jail" somehow, replace him there\r
+      {\r
+        // Do nothing here. This doesnt work as long as we are able to warp the player around just by\r
+        // sending some packets out. Enable/modify this if fixed\r
+        //tChar->SetLocation(550);\r
+      }\r
+      // Player still in 550 or 551 and trying to warp out (by death for example) just\r
+      // return true and let him respawn at 550 entrypoint 0\r
+      //return true;\r
+    }\r
+\r
+    PWorld* nWorld;\r
+    if (( nWorld = Worlds->LeaseWorld( nLocation ) ) )\r
+    {\r
+      if ( tChar->GetLocationLeased() )\r
+      {\r
+        // TAke care of sitting chars\r
+        u32 ChairObjectId;\r
+        u8 tSeatId;\r
+        PSeatType tSeatType;\r
+        if (( tSeatType = tChar->GetSeatInUse( &ChairObjectId, &tSeatId ) ) )\r
+        {\r
+          bool vhcZoning = false;\r
+          PSpawnedVehicle* tVhc = 0;\r
+          if ( (tSeatType == seat_vhc) && IsVhcZoning() ) // If seat is vhc,\r
+          { // Do  additionnal check\r
+            if (( tVhc = nWorld->GetSpawnedVehicules()->GetVehicle( ChairObjectId ) ) )\r
+            {\r
+              if ( tVhc->GetSeatUser( tSeatId ) == tChar->GetID() )\r
+              {\r
+                vhcZoning = true;\r
+              }\r
+            }\r
+          }\r
+\r
+          if ( ! vhcZoning )\r
+          {\r
+            PUdpCharExitChair::DoLeaveChair( tChar, this, tVhc, true );\r
+          }\r
+          /*{\r
+            Worlds->GetWorld( CurrentLocation )->CharLeaveChair( GetLocalID(), ChairObjectId );\r
+            tChar->SetSeatInUse( seat_none );\r
+          }*/\r
+        }\r
+        this->InitWarpCircle();\r
+        this->InitCharVanish();\r
+        Worlds->ReleaseWorld( CurrentLocation );\r
+      }\r
+      tChar->SetLocation( nLocation );\r
+      tChar->SetLocationLeased();\r
+\r
+      return true;\r
+    }\r
+  }\r
+  else if ( nLocation != 1 ) // try to fall back if bad location\r
+  {\r
+    Console->Print( YELLOW, BLACK, "[Warning] Client %d want to zone to invalid world %d. Falling back to world 1", mIndex, nLocation );\r
+    return ChangeCharLocation( 1, DoForce );\r
+  }\r
+\r
+  return false;\r
+}\r
+\r
+void PClient::GameDisconnect()\r
+{\r
+  mAccountID = 0;\r
+\r
+  if ( m_TCPConnection )\r
+  {\r
+    delete m_TCPConnection;\r
+    m_TCPConnection = NULL;\r
+  }\r
+\r
+  if ( m_UDPConnection )\r
+  {\r
+    delete m_UDPConnection;\r
+    m_UDPConnection = NULL;\r
+  }\r
+\r
+  /**** Will be better to put that char-saving-at-disconnect in Char destructor, when only used Chars will be loaded ****/\r
+  PChar *tChar = GetChar();\r
+  if ( tChar )\r
+  {\r
+    SetZoning();\r
+    if ( tChar->GetLocationLeased() )\r
+    {\r
+      if ( tChar->GetSeatInUse() )\r
+      {\r
+        //if(gDevDebug)\r
+          Console->Print( "%s Trying to get leaving char out of her seat", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
+        PUdpCharExitChair::DoLeaveChair( tChar, this, NULL, true );\r
+      }\r
+      /* // replaced by the lines above\r
+      PSeatType cSeatType;\r
+      u32 cSeatObjectId;\r
+      u8 cSeatId;\r
+      PWorld* cWorld;\r
+\r
+      cWorld = Worlds->GetWorld(tChar->GetLocation());\r
+      cSeatType = tChar->GetSeatInUse(&cSeatObjectId, &cSeatId);\r
+      if(cSeatType)\r
+      {\r
+        if(cSeatType == seat_chair)\r
+        {\r
+          cWorld->CharLeaveChair(GetLocalID(), cSeatObjectId);\r
+          tChar->SetSeatInUse(seat_none);\r
+        }\r
+        else if(cSeatType == seat_subway)\r
+        {\r
+          Subway->UnsetSeatUser(cSeatObjectId, cSeatId, GetLocalID());\r
+          tChar->SetSeatInUse(seat_none);\r
+        }\r
+        else if(cSeatType == seat_vhc)\r
+        {\r
+          cWorld->GetSpawnedVehicules()->GetVehicle(cSeatObjectId)->UnsetSeatUser(cSeatId, GetLocalID());\r
+          tChar->SetSeatInUse(seat_none);\r
+        }\r
+        else\r
+        {\r
+          Console->Print(RED, BLACK, "[Notice] PClient::GameDisconnect : Leaving seat of unkown type %d", cSeatType);\r
+        }\r
+      }\r
+      */\r
+    }\r
+\r
+    if ( tChar->IsDirty() )\r
+    {\r
+      bool res = tChar->SQLSave();\r
+      if ( res )\r
+        Console->Print( "%s GameDisconnect: Char %i (Client %i) saved before disconnect.", Console->ColorText( GREEN, BLACK, "[DEBUG]" ),  tChar->GetID(), mIndex );\r
+      else\r
+        Console->Print( RED, BLACK, "[DEBUG] GameDisconnect: Char %i (Client %i) saving before disconnect and FAILED.", tChar->GetID(), mIndex );\r
+    }\r
+    else\r
+    {\r
+      Console->Print( "%s GameDisconnect: Char %i (Client %i) no save needed.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), tChar->GetID(), mIndex );\r
+      if ( !tChar->IsOnline() )\r
+        Console->Print( "%s GameDisconnect: Char %i (Client %i) wasn't marked as ingame anyway...", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), tChar->GetID(), mIndex );\r
+    }\r
+\r
+    if ( tChar->GetLocationLeased() )\r
+    {\r
+      if ( gDevDebug )\r
+        Console->Print( "%s Sending char leaving effect", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
+      InitWarpCircle();\r
+      InitCharVanish();\r
+\r
+      Worlds->ReleaseWorld( tChar->GetLocation() );\r
+      tChar->SetLocationLeased( false );\r
+    }\r
+\r
+    Chars->RemoveChar( mCharID );\r
+    delete tChar;\r
+    mCharID = 0;\r
+  }\r
+  else\r
+  {\r
+    //Console->Print(YELLOW, BLACK, "GameDisconnect: Client %i had no char online.", mIndex);\r
+  }\r
+  /**********************************/\r
+\r
+  //mConnection &= ~PCC_GAME;\r
+  mConnection = PCC_NONE;\r
+}\r
+\r
+void PClient::RefreshAccountInfo( PAccount *Account )\r
+{\r
+  mAccountID = Account->GetID();\r
+  mAccountLevel = Account->GetLevel();\r
+}\r
+\r
+void PClient::Update()\r
+{\r
+  if ( m_TCPConnection )\r
+  {\r
+    if ( m_TCPConnection->timeOut() )\r
+    {\r
+      Console->Print( "%s GameSocket: Client %i: timeout", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), mIndex );\r
+      GameServer->ClientDisconnected( this );\r
+    }\r
+    else\r
+    {\r
+      if ( !m_TCPConnection->update() )\r
+      {\r
+        GameServer->ClientDisconnected( this );\r
+      }\r
+    }\r
+  }\r
+\r
+  if ( m_UDPConnection )\r
+  {\r
+    if ( m_UDPConnection->timeOut() )\r
+    {\r
+      Console->Print( "%s Game UDP: Client %i: timeout", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), mIndex );\r
+      GameServer->UDPStreamClosed( this );\r
+    }\r
+    else\r
+    {\r
+      if ( !m_UDPConnection->update() )\r
+      {\r
+        GameServer->UDPStreamClosed( this );\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+PChar* PClient::GetChar() const\r
+{\r
+  if ( mCharID )\r
+  {\r
+    return Chars->GetChar( mCharID );\r
+  }\r
+  else\r
+  {\r
+    return NULL;\r
+  }\r
+}\r
+\r
+bool PClient::GetCharAwaitingWarpto( u16* PosX, u16* PosY, u16* PosZ )\r
+{\r
+  if ( PosX )\r
+    *PosX = mTargetX;\r
+  if ( PosY )\r
+    *PosY = mTargetY;\r
+  if ( PosZ )\r
+    *PosZ = mTargetZ;\r
+\r
+  return mAwaitingWarpto;\r
+  /*\r
+    if(mAwaitingWarpto == true)\r
+    {\r
+\r
+        // Position update doesnt work. Uncomment&Change function if ever required again\r
+        mAwaitingWarpto = false;\r
+            (GetChar()->Coords).mX = mTargetX;\r
+            (GetChar()->Coords).mY = mTargetY;\r
+            (GetChar()->Coords).mZ = mTargetZ;\r
+        return true;\r
+  //        PMessage* tmpMsg_posupdate;\r
+  //\r
+  //        tmpMsg_posupdate = MsgBuilder->BuildCharPosMoveMsg(this, mTargetX, mTargetY, mTargetZ);\r
+  //        ClientManager->UDPBroadcast(tmpMsg_posupdate, this);\r
+  //        tmpMsg_posupdate = NULL;\r
+    }\r
+    return false;\r
+  */\r
+}\r
+\r
+void PClient::InitWarpCircle()\r
+{\r
+  PMessage* tmpMsg_circle = MsgBuilder->BuildCharShowGlowCircleMsg( this );\r
+  ClientManager->UDPBroadcast( tmpMsg_circle, this, 1000, true ); // send only in a 1000 radius\r
+}\r
+\r
+void PClient::InitCharVanish()\r
+{\r
+  PMessage* tmpMsg_vanish = MsgBuilder->BuildRemoveWorldObjectMsg( GetLocalID() );\r
+  ClientManager->UDPBroadcast( tmpMsg_vanish, this, 0, true );\r
+}\r
diff --git a/server/src/game/clientmanager.cpp b/server/src/game/clientmanager.cpp
new file mode 100644 (file)
index 0000000..364c1c7
--- /dev/null
@@ -0,0 +1,310 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+ client.cpp\r
+\r
+ Authors:\r
+ - bakkdoor\r
+\r
+ MODIFIED: 13 Dec 2005 bakkdoor\r
+ REASON: - introduced\r
+ MODIFIED: 29 Jul 2006 Hammag\r
+ REASON: - Added UDP broadcast fonction\r
+         - Added "zone players say Hello" fonction\r
+         - Modified the ID used as would should avoid muliplying the IDs for the same client.\r
+             Now using Client.GetLocalID() as the key (=Client.mIndex + 1) which is used in NC protocol\r
+         - Modified getClientByID()\r
+         - Removed getClientID(). Simply do Client->GetLocalID()\r
+         - Modified deleteClientFromListByID() and renamed to deleteClientFromList()\r
+         - Modified destructor as to not destroy stored clients, which is already done in PServer\r
+             (even if it could well be done here in near futur)\r
+\r
+ MODIFIED: 12 Aug 2006 Hammag\r
+ REASON: - implemented range filtering in UDPBroadcast()\r
+         - implemented the two versions of UDPBroadcast()\r
+\r
+  TODO:   - these are just begining of modif, as the Client Manager is bound to be a major component for multiplayer management\r
+*/\r
+\r
+#include "main.h"\r
+\r
+#include "msgbuilder.h"\r
+\r
+PClientManager::PClientManager()\r
+{\r
+  //mLastID = 0;\r
+}\r
+\r
+\r
+PClientManager::~PClientManager()\r
+{\r
+  /*\r
+    for(PClientMap::iterator it=mClientList.begin(); it!=mClientList.end(); it++)\r
+    {\r
+        delete it->second;\r
+    }\r
+  */\r
+}\r
+\r
+bool PClientManager::addClientToList( PClient* newClient )\r
+{\r
+  if ( !newClient )\r
+    return false;\r
+\r
+  PClientMap::const_iterator it = mClientList.find( newClient->GetLocalID() );\r
+  if ( it == mClientList.end() ) // only if client not found in list\r
+  {\r
+    /*     mClientList.insert(std::make_pair(m_LastID, newClient));\r
+            ++m_LastID; */\r
+\r
+    mClientList.insert( std::make_pair( newClient->GetLocalID(), newClient ) );\r
+    //Console->Print(GREEN, BLACK, "Client %d added to clientmanager", newClient->GetIndex());\r
+    /*        if(newClient)\r
+            {\r
+                return true;\r
+            } */\r
+    return true;\r
+  }\r
+  else\r
+    return false;\r
+}\r
+\r
+// Check if a zone is in use\r
+bool PClientManager::IsWorldInUse( u32 nWorldID ) const\r
+{\r
+  for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ )\r
+  {\r
+    if ( it->second &&  it->second->GetChar() )\r
+    {\r
+      if ( it->second->GetChar()->GetLocation() == nWorldID )\r
+        return true;\r
+    }\r
+  }\r
+  return false;\r
+}\r
+\r
+// Check if a rawObjectId belongs to a char is in use\r
+PClient* PClientManager::GetClientByCharLocalId( u32 rawObjectId, u32 nWorldID ) const\r
+{\r
+  PClient* nClient;\r
+  for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ )\r
+  {\r
+    // note: atm, charid = clientid+1 in any zone (client.h)\r
+    if ( (nClient = it->second) && ( nClient->GetLocalID() == rawObjectId ) )\r
+    {\r
+      if ( nClient->GetChar() && ( nClient->GetChar()->GetLocation() == nWorldID ) )\r
+        return nClient;\r
+    }\r
+  }\r
+  return 0;\r
+}\r
+\r
+void PClientManager::deleteClientFromList( u32 id )\r
+{\r
+  PClientMap::iterator it = mClientList.find( id );\r
+  if ( it != mClientList.end() )\r
+  {\r
+    mClientList.erase( it );\r
+    //Console->Print(YELLOW, BLACK, "Client %d removed from clientmanager", ((PClient*)(it->second))->GetIndex());\r
+  }\r
+}\r
+\r
+/* bool PClientManager::deleteClientFromList(PClient* delClient)\r
+{\r
+    for(PClientMap::iterator it=mClientList.begin(); it!=mClientList.end(); it++)\r
+    {\r
+        if(delClient == it->second)\r
+        {\r
+      //     if(it->second)\r
+      //    {\r
+      //         delete delClient;\r
+                mClientList.erase( it );\r
+                return true;\r
+      //    }\r
+        }\r
+    }\r
+    return false;\r
+} */\r
+\r
+PClient* PClientManager::getClientByID( u32 id ) const\r
+{\r
+  PClientMap::const_iterator it = mClientList.find( id );\r
+  return (( it != mClientList.end() ) ? ( PClient* )( it->second ) : NULL );\r
+}\r
+\r
+PClient* PClientManager::getClientByChar( u32 CharID ) const\r
+{\r
+  for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ )\r
+  {\r
+    if ( it->second )\r
+    {\r
+      if ( it->second->GetCharID() == CharID )\r
+        return it->second;\r
+    }\r
+  }\r
+  return NULL;\r
+}\r
+\r
+PClient* PClientManager::getClientByChar( const std::string &Name ) const\r
+{\r
+  for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ )\r
+  {\r
+    if ( it->second )\r
+    {\r
+      if ( it->second->GetChar()->GetName() == Name )\r
+        return it->second;\r
+    }\r
+  }\r
+  return NULL;\r
+}\r
+\r
+/* u32 PClientManager::getClientID(PClient* _client)\r
+{\r
+    for(PClientMap::iterator it=mClientList.begin(); it!=mClientList<p align="center"></p>.end(); it++)\r
+    {\r
+        if(_client == it->second)\r
+        {\r
+            return it->first;\r
+        }\r
+    }\r
+\r
+    return -1;\r
+} */\r
+\r
+// Distance checking doesn't care for Z axis ATM\r
+int PClientManager::UDPBroadcast( PMessage* nMessage, u32 nZoneID, u16 nX, u16 nY, u16 nZ, u16 nMaxDist, u32 nSkipCharId, bool nNPCPing )\r
+{\r
+  int msgCount = 0;\r
+  PChar* nChar;\r
+  PMessage* tmpMsg;\r
+  PClient* itClient;\r
+  u16 Dapprox;\r
+\r
+  for ( PClientMap::iterator it = mClientList.begin(); it != mClientList.end(); it++ )\r
+  {\r
+    itClient = ( PClient* )( it->second );\r
+\r
+    // Dont send NPC alive messages when client is not ready for them\r
+    if ( !itClient->IsAcceptingNPCUpdates() && nNPCPing )\r
+      continue;\r
+\r
+    if ( itClient->getUDPConn() )\r
+    {\r
+      nChar = itClient->GetChar();\r
+      if ( nChar && ( nChar->GetLocation() != nZoneID ) )// if limited to zone, do check\r
+        continue;\r
+\r
+      if (itClient->GetCharID() == nSkipCharId ) // if source of broadcast should be skipped\r
+        continue;\r
+\r
+      if ( nMaxDist ) // if limited to distance, do check\r
+      {\r
+        Dapprox = DistanceApprox(( nChar->Coords ).mX, ( nChar->Coords ).mY, ( nChar->Coords ).mZ, nX, nY, nZ );\r
+        if ( Dapprox >  nMaxDist )\r
+          continue;\r
+      }\r
+\r
+      /*tmpMsg = new PMessage(nMessage->GetMaxSize());\r
+      (*tmpMsg) = (*nMessage);*/\r
+      tmpMsg = new PMessage( *nMessage );\r
+\r
+      itClient->FillInUDP_ID( tmpMsg );\r
+      itClient->SendUDPMessage( tmpMsg );\r
+      ++msgCount;\r
+    }\r
+  }\r
+\r
+  //Console->Print("Broadcast in zone %d to %d chars", nZoneID, msgCount);\r
+  delete nMessage;\r
+  return msgCount;\r
+}\r
+\r
+int PClientManager::UDPBroadcast( PMessage* nMessage, PClient* nClient, u16 nMaxDist, bool nSkipSource, bool nNPCPing )\r
+{\r
+  PChar* nChar;\r
+  u32 skipCharId = nSkipSource ? nClient->GetCharID() : 0 ;\r
+\r
+  if ( nClient && ( nChar = nClient->GetChar() ) )\r
+  {\r
+    return UDPBroadcast( nMessage, nChar->GetLocation(), ( nChar->Coords ).mX, ( nChar->Coords ).mY, ( nChar->Coords ).mZ, nMaxDist, skipCharId, nNPCPing );\r
+  }\r
+  else\r
+  {\r
+    delete nMessage;\r
+    return 0;\r
+  }\r
+}\r
+\r
+int PClientManager::SendUDPZoneWelcomeToClient( PClient* nClient )\r
+{\r
+  int msgCount = 0;\r
+  PChar* nChar;\r
+  PChar* itChar;\r
+  PMessage* tmpMsg;\r
+  u32 nZoneID;\r
+  PClient* itClient;\r
+\r
+  if ( nClient && ( nChar = nClient->GetChar() ) ) // if nClient is set, always use its zone\r
+  {\r
+    nZoneID = nChar->GetLocation();\r
+  }\r
+  else\r
+    return 0;\r
+\r
+  for ( PClientMap::iterator it = mClientList.begin(); it != mClientList.end(); it++ )\r
+  {\r
+    if ( nClient->GetLocalID() == it->first )\r
+      continue;\r
+\r
+    itClient = ( PClient* )( it->second );\r
+    if ( itClient->getUDPConn() )\r
+    {\r
+      itChar = itClient->GetChar();\r
+      if ( itChar->GetLocation() != nZoneID ) // limit to zone\r
+        continue;\r
+\r
+      tmpMsg = MsgBuilder->BuildCharHelloMsg( itClient );\r
+\r
+      nClient->FillInUDP_ID( tmpMsg );\r
+      nClient->SendUDPMessage( tmpMsg );\r
+      //Console->Print("Welcome data sent from client %d to client %d", itClient->GetIndex(), nClient->GetIndex());\r
+      //tmpMsg->Dump();\r
+\r
+      if ( itChar->GetSeatInUse() != seat_none )\r
+      {\r
+        tmpMsg = MsgBuilder->BuildCharPosUpdateMsg( itClient );\r
+        nClient->FillInUDP_ID( tmpMsg );\r
+        nClient->SendUDPMessage( tmpMsg );\r
+\r
+        //Console->Print("Sit on chair %d sent from client %d to client %d", (itChar->GetChairInUse()+1)*1024, itClient->GetIndex(), nClient->GetIndex());\r
+        /*tmpMsg = MsgBuilder->BuildCharUseSeatMsg(itClient, (itChar->GetChairInUse()+1)*1024);\r
+        nClient->FillInUDP_ID(tmpMsg);\r
+        nClient->SendUDPMessage(tmpMsg);*/\r
+      }\r
+      ++msgCount;\r
+    }\r
+  }\r
+\r
+  return msgCount;\r
+}\r
diff --git a/server/src/game/commands.cpp b/server/src/game/commands.cpp
new file mode 100644 (file)
index 0000000..02b5f52
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+
+
+/*
+       commands.cpp - handles ingame commands (@<command>)
+
+       Authors:
+       - Namikon
+    - bakkdoor
+    - Hammag
+
+
+    File rewritten on 20th Dec 2006 by Namikon
+    Note: Later, when we add multithread support to tinns, the FlushArgs() functions
+          have to be placed ONLY in con/destructor and nowhere else.
+          Besides that, no global GameCommands, we should do that with tmpCmd = new PCommands;
+*/
+#include "main.h"
+
+#include "client.h"
+#include "msgbuilder.h"
+#include "worlds.h"
+#include "worldactors.h"
+
+PCommands::PCommands()
+{
+    FlushArgs();
+}
+
+PCommands::~PCommands()
+{
+    FlushArgs();
+}
+
+void PCommands::HandleGameCommand(char *packet, PClient *Client)
+{
+    // Start over with an empty class
+    FlushArgs();
+
+    // Grab client class
+    source = Client;
+
+    int posPacket = 1;
+    int tmpPos = 0;
+
+    //First of all, split the command itself. We only know here that it
+    // *seems* to be an command, we have no idea if the command is valid
+    do
+    {
+        // Copy command from packet to final var
+        Command[tmpPos] = packet[posPacket];
+
+        // Increment both pointers
+        posPacket++;
+        tmpPos++;
+    }
+    while (packet[posPacket] != ' ' && packet[posPacket] != '\0');
+
+    // Terminate command
+    Command[tmpPos] = '\0';
+
+
+    // To save time, only copy org packet into dumb when we really need it.
+    // On the other side, dont try to get the Args if a dumb is made.
+    if (RequirePacketDumb() == true)
+    {
+        int loopy = 0;
+        while (packet[loopy] != '\0' && loopy < (MAXDUMBSIZE - 1))
+        {
+            OrgPacketDumb[loopy] = packet[loopy];
+            loopy++;
+        }
+        OrgPacketDumb[loopy] = '\0';
+        DumbMade = true;
+        ArgC = 0; // Just to be sure...
+    }
+    else
+    {
+        // Search next arg (Maybe someone typed more than one whitespace)
+        while (packet[posPacket] == ' ' && packet[posPacket] != '\0')
+        {
+            posPacket++;
+        }
+
+        // ok, we have the command, now read the args
+        // Loop till entire chatpacket is parsed or MAXARGS is reached\r
+        bool tEncapsedString = false;
+        while (packet[posPacket] != '\0' && ArgC <= MAXARGS)
+        {
+            // First set tmpPos for next Arg to 0
+            tmpPos = 0;
+\r
+            // Now loop until next space ' '  or end '\0' is reached\r
+            // Added extraction of encapsulated strings "test 123 123"\r
+            while (packet[posPacket] != ' ' || tEncapsedString == true)
+            {\r
+                // Watch out for >"<\r
+                if(packet[posPacket] == '"')\r
+                    tEncapsedString = !tEncapsedString;\r
+                else\r
+                {\r
+                    // Copy arg from chatpacket to final arg var\r
+                    ArgV[ArgC][tmpPos] = packet[posPacket];\r
+                    tmpPos++;\r
+                }\r
+                    // Increment tmpPos and posPacket\r
+                posPacket++;\r
+                if(packet[posPacket] == '\0')\r
+                    break;\r
+            }
+            tEncapsedString = false;\r
+            // Reached either the end of packet or an whitespace
+            // Terminate current ArgV
+            ArgV[ArgC][tmpPos] = '\0';
+
+            // Heh, we got one! Now more to next arg\r
+            ArgC++;\r
+
+            // Search next arg (Maybe someone typed more than one whitespace)
+            while (packet[posPacket] == ' ' && packet[posPacket] != '\0')
+            {
+                posPacket++;
+            }
+        }
+        if (packet[posPacket] != '\0' && ArgC == MAXARGS && gDevDebug)
+            Console->Print("%s MAXARGS reached, cant parse more args for command!", Console->ColorText(YELLOW, BLACK, "[Warning]"));
+    }
+    // Check if client is allowed to perform command
+    if (CheckPermission() == false)
+        return;
+
+    // Also, if command is a developercommand, only let admins perform it
+    if (IsDevCommand() == true && IsAdmin() == false)
+        return;
+
+    if (strcmp(Command, "debug") == 0)
+    {
+        doCmddebug();
+    }
+    else if (strcmp(Command, "settime") == 0)
+    {
+        doCmdsettime();
+    }
+    else if (strcmp(Command, "warp") == 0)
+    {
+        doCmdwarp();
+    }
+    else if (strcmp(Command, "rawf") == 0)
+    {
+        doCmdrawf();
+    }
+    /* Not required anymore, TinNS gets is worlditemdata from .dat files now
+        else if(strcmp(Command, "delworlditem") == 0)
+        {
+            doCmddelworlditem();
+        }
+        else if(strcmp(Command, "addworlditem") == 0)
+        {
+            doCmdaddworlditem();
+        }
+        else if(strcmp(Command, "adddoor") == 0)
+        {
+            doCmdadddor();
+        }
+    */
+    else if ( (strcmp(Command, "online") == 0) || (strcmp(Command, "who") == 0) ) // Was: connectedList
+    {
+        doCmdconlist();
+    }
+    else if (strcmp(Command, "skin") == 0)
+    {
+        doCmdskin();
+    }
+    else if (strcmp(Command, "effect") == 0)
+    {
+        doCmdeffect();
+    }
+    else if (strcmp(Command, "speed") == 0)
+    {
+        doCmdspeed();
+    }
+    else if (strcmp(Command, "color") == 0)
+    {
+        doCmdcolor();
+    }
+    else if (strcmp(Command, "brightness") == 0)
+    {
+        doCmdbrightness();
+    }
+    else if (strcmp(Command, "remove") == 0)
+    {
+        doCmdremove();
+    }
+    /*    else if(strcmp(Command, "rehash") == 0)
+        {
+            doCmdrehash();
+        }*/
+    else if (strcmp(Command, "uptime") == 0)
+    {
+        doCmduptime();
+    }
+    else if (strcmp(Command, "version") == 0)
+    {
+        doCmdversion();
+    }
+    else if (strcmp(Command, "kick") == 0)
+    {
+        doCmdkick();
+    }
+    else if ( (strcmp(Command, "info") == 0) || (strcmp(Command, "whois") == 0) )
+    {
+        doCmdinfo();
+    }
+    else if (strcmp(Command, "setlevel") == 0)
+    {
+        doCmdsetlevel();
+    }
+    else if (strcmp(Command, "warpto") == 0)
+    {
+        doCmdwarpto();
+    }
+    else if (strcmp(Command, "recall") == 0)
+    {
+        doCmdrecall();
+    }
+    else if (strcmp(Command, "broadcast") == 0)
+    {
+        doCmdbroadcast();
+    }
+    else if (strcmp(Command, "t") == 0)
+    {
+        doCmd_dev_t();
+    }
+    else if (strcmp(Command, "h") == 0)
+    {
+        doCmd_dev_h();
+    }
+    else if (strcmp(Command, "v") == 0)
+    {
+        doCmd_dev_v();
+    }
+    else if (strcmp(Command, "ban") == 0)
+    {
+        doCmdban();
+    }
+    else if (strcmp(Command, "unban") == 0)
+    {
+        doCmdunban();
+    }
+    else if (strcmp(Command, "listbans") == 0)
+    {
+        doCmdlistbans();
+    }
+    else if (strcmp(Command, "shun") == 0)
+    {
+        doCmdshun();
+    }
+    else if (strcmp(Command, "unshun") == 0)
+    {
+        doCmdunshun();
+    }
+    else if (strcmp(Command, "jail") == 0)
+    {
+        doCmdjail();
+    }
+    else if (strcmp(Command, "unjail") == 0)
+    {
+        doCmdunjail();
+    }
+    else if (strcmp(Command, "teleport") == 0)
+    {
+        doCmdteleport();
+    }
+    else if (strcmp(Command, "test") == 0)
+    {
+        doCmdtest(); // Testcommand for various testings.
+    }
+    else if (strcmp(Command, "givemoney") == 0)
+    {
+        doCmdgivemoney();
+    }
+    else if (strcmp(Command, "takemoney") == 0)
+    {
+        doCmdtakemoney();
+    }
+    else if (strcmp(Command, "spawnactor") == 0)
+    {
+        doCmdspawnactor(); // Spawns actor next to player
+    }
+    else if (strcmp(Command, "weather") == 0)
+    {
+        doCmdweather(); // Control weather in player zone
+    }
+    else if (strcmp(Command, "setmainskill") == 0)
+    {
+        doCmdSetMainSkill();
+    }
+    else if (strcmp(Command, "setsubskill") == 0)
+    {
+        doCmdSetSubSkill();
+    }\r
+    else if (strcmp(Command, "npc") == 0)\r
+    {\r
+        doNPC();\r
+    }\r
+    else if (strcmp(Command, "npcshop") == 0)\r
+    {\r
+        doNPC_Shop();\r
+    }\r
+    // Else: unknown command. Ignore
+}
+
+bool PCommands::CheckPermission()
+{
+    if (CmdAccess->GetOptionInt(Command) > source->GetAccountLevel())
+        return false;
+    else
+        return true;
+}
+
+bool PCommands::IsAdmin()
+{
+    if (source->GetAccountLevel() >= PAL_ADMIN)
+        return true;
+    else
+        return false;
+}
+
+
+bool PCommands::GetTarget(int ArgNum)
+{
+    if (ArgNum > ArgC)
+        return false;
+
+    if (IsArgNumeric(ArgNum) == true)
+        target = GetClientByID(GetArgInt(ArgNum));
+    else
+    {
+        char tmp[50];
+        GetArgText(ArgNum, tmp, 50);
+        target = GetClientByNick(tmp);
+    }
+
+    if (target == NULL)
+        return false;
+    else
+        return true;
+}
+
+bool PCommands::IsArgNumeric(int ArgNum)
+{
+    if (ArgNum > ArgC)
+        return false;
+
+    int tmpPos = 0;
+    while (ArgV[ArgNum - 1][tmpPos] != '\0')
+    {
+        if (!isdigit(ArgV[ArgNum - 1][tmpPos]))
+            return false;
+
+        tmpPos++;
+    }
+    return true;
+}
+
+void PCommands::FlushArgs()
+{
+    // Empty all variables
+    for (int i = 0; i < MAXARGS; i++)
+        ArgV[i][0] = '\0';
+
+    Command[0] = '\0';
+    OrgPacketDumb[0] = '\0';
+
+    ArgC = 0;
+    DumbMade = false;
+    source = NULL;
+    target = NULL;
+
+}
+
+int PCommands::GetArgInt(int ArgNum)
+{
+    if (ArgNum > ArgC)
+        return 0;
+
+    int tmpIntRet = 0;
+    tmpIntRet = atoi(ArgV[ArgNum - 1]);
+    return tmpIntRet;
+}
+
+bool PCommands::GetArgText(int ArgNum, char* output, int output_size)
+{
+    if (ArgNum > ArgC)
+        return false;
+
+    int i = 0;
+
+    // Copy arg to given char array
+    while (ArgV[ArgNum - 1][i] != '\0')
+    {
+        output[i] = ArgV[ArgNum - 1][i];
+        i++;
+        if ((i + 1) == output_size)
+        {
+            output[i] = '\0';
+            return true;
+        }
+    }
+    output[i] = '\0';
+    return true;
+}
+
+PClient* PCommands::GetClientByID(int charid)
+{
+    return ClientManager->getClientByChar( charid );
+}
+/*
+PClient* PCommands::GetClientByID(int charid)
+{
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+    {
+        if(it->second)
+        {
+            PClient* target = it->second;
+            if((int)target->GetCharID() == charid)
+                return it->second;
+        }
+    }
+    return NULL;
+}
+*/
+
+PClient* PCommands::GetClientByNick(const char *nick)
+{
+    return ClientManager->getClientByChar( (std::string) nick );
+}
+/*
+PClient* PCommands::GetClientByNick(const char *nick)
+{
+    for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+    {
+        if(it->second)
+        {
+            PClient* target = it->second;
+            if(!strcasecmp(Chars->GetChar(target->GetCharID())->GetName().c_str(), nick))
+                return it->second;
+        }
+    }
+    return NULL;
+}
+*/
+
+bool PCommands::RequirePacketDumb()
+{
+    bool tmpNeedDumb = false;
+
+    if (strcmp(Command, "broadcast") == 0)
+        tmpNeedDumb = true;
+    // Add more checks here
+
+    return tmpNeedDumb;
+}
+
+bool PCommands::IsDevCommand()
+{
+    bool tmpIsDev = false;
+
+    if (strcmp(Command, "t") == 0)
+        tmpIsDev = true;
+    else if (strcmp(Command, "h") == 0)
+        tmpIsDev = true;
+    else if (strcmp(Command, "v") == 0)
+        tmpIsDev = true;
+    else if (strcmp(Command, "test") == 0)
+        tmpIsDev = true;
+    // Add more checks here
+
+    return tmpIsDev;
+}
diff --git a/server/src/game/configtemplate.h b/server/src/game/configtemplate.h
new file mode 100644 (file)
index 0000000..a94b61e
--- /dev/null
@@ -0,0 +1,137 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+    Configuration template for gameserver\r
+    Used to set available/optional/required options when loading config\r
+      with a PConfig object.\r
+\r
+       MODIFIED: 28 Sep 2006 Hammag\r
+       REASON: - added worlds_path entry\r
+  MODIFIED: 02 Oct 2006 Hammag\r
+       REASON: - added dev_debug entry\r
+\r
+  TODO: put a single data_directory entry as the root directory for all NC data\r
+\r
+*/\r
+\r
+const char* GameConfigTemplate[][2] = {\r
+  // {option_name, default_value} if default_value is empty string, it means option is mandatory\r
+  // List ends with empty string for option_name\r
+  {"info_sql_host", "127.0.0.1"},\r
+  {"info_sql_port", "3306"},\r
+  {"info_sql_username", ""},\r
+  {"info_sql_password", ""},\r
+  {"info_sql_database", "infoserver"},\r
+  {"game_sql_host", "127.0.0.1"},\r
+  {"game_sql_port", "3306"},\r
+  {"gameserver_udpport_min", "5000"},\r
+  {"gameserver_udpport_max", "5099"},\r
+  {"game_sql_username", ""},\r
+  {"game_sql_password", ""},\r
+  {"game_sql_database", "gameserver"},\r
+  {"mysql_wait_timeout", "28800"}, // value of the wait_timout system variable from the MySQL server (same for game & info DB atm). 0 to disable keepalive.\r
+  {"server_name", "TinNS"},\r
+  {"server_ip", "127.0.0.1"}, //IP address used with clients reached without NAT (see localnet)\r
+  {"no_nat_net", "0"}, // 0 is for "don't bother with NAT", else format is like 192.168.1. (with trailing dot)\r
+  {"server_nat_ip", "127.0.0.1"}, //IP address used with clients reached through NAT\r
+  {"gameserver_port", "12000"},\r
+  {"server_version", ""},\r
+  {"maxclients", "128"},\r
+  {"gm_slots", "10"},\r
+  //{"defs_path", "./defs"},\r
+  //{"worlds_path", "./worlds"},\r
+  {"nc_data_path", "."},\r
+  {"isc_method", "1"},\r
+  {"isc_server_id", ""},\r
+  {"isc_update_intervall", "60"},\r
+  {"isc_delayed_update_intervall", "6"}, // the purpose of this option is to avoid multiple infoDB update when client just disconnects/reconnects during login phases\r
+  {"isc_infoserverip", "127.0.0.1"},\r
+  {"isc_infoserverport", "9991"},\r
+  {"isc_connect_pw", "change_me"}, // make default value empty when isc ready\r
+  {"dev_debug", "0"}, // set to non-zero to activate development outputs\r
+  {"auto_save_period", "300"},\r
+  {"new_char_location", "1085"},\r
+  {"broadcast_new", "0"},\r
+  {"broadcast_new_hidestaff", "0"},\r
+  {"max_cash", "20000000"},\r
+  {"item_price", "70"},\r
+  {"require_validation", "0"},\r
+  {"minlevel", "0"},\r
+  {"username_filter", "^[a-z][\\w\\-]{2,14}$"},\r
+  {"password_filter", "^[[:graph:]]{3,15}$"},\r
+  {"charname_filter", "^[a-z]+([\\-\\ ]?[a-z]+){0,2}$"},\r
+  {"clanname_filter", "^[a-z][\\w\\-\\ ]{2,14}$"},\r
+\r
+// For futur use:\r
+//  {"max_chars_per_account", "4"},\r
+//  {"multiple_logins_per_account", "0"}, // 0=nobody, 1=gm+ only, 2=everybody\r
+//  {"multiple_ingames_per_account", "0"}, // 0=nobody, 1=gm+ only, 2=everybody (needs multiple logins ...)\r
+\r
+//  {"local_chat_range", "500"},\r
+\r
+  {"", ""} // do not change this line (end mark)\r
+};\r
+\r
+const char* CommandsTemplate[][2] = {\r
+    {"debug", "100"},\r
+    {"settime", "100"},\r
+    {"warp", "0"},\r
+//    {"delworlditem", "100"},\r
+//    {"addworlditem", "100"},\r
+//    {"adddoor", "100"},\r
+    {"online", "0"},\r
+    {"sendchat", "50"},\r
+    {"skin", "50"},\r
+    {"effect", "0"},\r
+    {"speed", "0"},\r
+    {"color", "0"},\r
+    {"brightness", "0"},\r
+    {"remove", "50"},\r
+    {"rehash", "100"},\r
+    {"uptime", "0"},\r
+    {"version", "0"},\r
+    {"broadcast", "100"},\r
+    {"kick", "50"},\r
+    {"info", "50"},\r
+    {"setlevel", "100"},\r
+    {"warpto", "50"},\r
+    {"recall", "50"},\r
+\r
+    {"ban", "50"},          // Set ban\r
+    {"unban", "50"},        // Remove ban\r
+    {"listbans", "50"},     // Show list of all banned accounts\r
+    {"shun", "50"},         // Quiet all chat\r
+    {"unshun", "50"},       // UnQuiet all chat\r
+    {"jail", "50"},         // "Jail" someone (Regants ^^)\r
+    {"unjail", "50"},       // Move him out\r
+    {"teleport", "50"},     // Warp targetplayer XX to zone YY\r
+    {"givemoney", "50"},     // Warp targetplayer XX to zone YY\r
+    {"takemoney", "50"},     // Warp targetplayer XX to zone YY\r
+    {"spawnactor", "50"},     // Spawn given actor next to player\r
+\r
+    {"weather", "50"},     // Set weather in a zone\r
+    {"setmainskill", "50"},     // Set mainskill (INT,PSI,DEX,CON,STR) of own char or someone else\r
+    {"setsubskill", "50"},     // Set subskill (BRT,HCK,PPU,...) of own char or someone else\r
+    {"npc", "50"},     // do actions with NPCs\r
+\r
+\r
+    {"", ""} // do not change this line (end mark)\r
+};\r
diff --git a/server/src/game/container.cpp b/server/src/game/container.cpp
new file mode 100644 (file)
index 0000000..fe0cf33
--- /dev/null
@@ -0,0 +1,913 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+  container.cpp - base classe for containers\r
+\r
+\r
+ MODIFIED: 28 Jul 2008 Hammag\r
+ REASON: - creation\r
+\r
+*/\r
+\r
+#include "main.h"\r
+\r
+#include "item.h"\r
+#include "container.h"\r
+\r
+/* --- PContainerEntry class --- */\r
+\r
+PContainerEntry::PContainerEntry( PItem* nItem, u8 X, u8 Y, u32 nInvID, bool SetDirty )\r
+{\r
+  mItem = nItem;\r
+  mPosX = X;\r
+  mPosY = Y;\r
+  mInvID = nInvID;\r
+  mDirtyFlag = SetDirty;\r
+}\r
+\r
+PContainerEntry::PContainerEntry( MYSQL_ROW row )\r
+{\r
+  mItem = NULL;\r
+  mInvID = atoi( row[i_invid] );\r
+  mPosX = atoi( row[i_x] );\r
+  mPosY = atoi( row[i_y] );\r
+  mDirtyFlag = false;\r
+\r
+  u32 nItemID = atoi( row[i_itemid] );\r
+  u8 nStackSize = atoi( row[i_qty] );\r
+  //     = std::atoi(row[i_type]);\r
+  u8 CurDur = atoi( row[i_curdur] );\r
+  u8 Dmg = atoi( row[i_dmg] );\r
+  u8 Freq = atoi( row[i_freq] );\r
+  u8 Hand = atoi( row[i_hand] );\r
+  u8 Rng = atoi( row[i_rng] );\r
+  u8 Dur = atoi( row[i_maxdur] );\r
+\r
+  mItem = new PItem( nItemID, nStackSize, CurDur, Dur, Dmg, Freq, Hand, Rng );\r
+}\r
+\r
+PContainerEntry::~PContainerEntry()\r
+{\r
+  delete mItem;\r
+}\r
+\r
+bool PContainerEntry::SQLSave( u32 CharID, u32 InvLoc )\r
+{\r
+  std::string query, queryv;\r
+\r
+  queryv += Ssprintf( " inv_charid='%u',inv_loc='%u',inv_x='%u',inv_y='%u'", CharID, InvLoc, mPosX, mPosY );\r
+  queryv += Ssprintf( ",inv_itemid='%u',inv_qty='%u'", mItem->mItemID, mItem->mStackSize );\r
+  //queryv += Ssprintf( ",inv_type='%u'", 0 );\r
+  queryv += Ssprintf( ",inv_cdur='%u'", mItem->mCurDuration );\r
+  queryv += Ssprintf( ",inv_dmg='%u'", mItem->mDamages );\r
+  queryv += Ssprintf( ",inv_frq='%u'", mItem->mFrequency );\r
+  queryv += Ssprintf( ",inv_hnd='%u'", mItem->mHandling );\r
+  queryv += Ssprintf( ",inv_rng='%u'", mItem->mRange );\r
+  queryv += Ssprintf( ",inv_mdur='%u'", mItem->mMaxDuration );\r
+\r
+  if ( mInvID )\r
+  {\r
+    query = "UPDATE inventory SET " + queryv;\r
+    query += Ssprintf( " WHERE inv_id='%u' LIMIT 1;", mInvID );\r
+  }\r
+  else\r
+  {\r
+    query = "INSERT INTO inventory SET " + queryv + ";";\r
+  }\r
+\r
+  if ( MySQL->GameQuery( query.c_str() ) )\r
+  {\r
+    Console->Print( RED, BLACK, "PContainerEntry::SQLSave could not add/update some inventory item in the database" );\r
+    Console->Print( "Query was:" );\r
+    Console->Print( "%s", query.c_str() );\r
+    MySQL->ShowGameSQLError();\r
+    return false;\r
+  }\r
+  else\r
+  {\r
+    if ( !mInvID )\r
+    {\r
+      mInvID = MySQL->GetLastGameInsertId();\r
+      if ( gDevDebug )\r
+        Console->Print( GREEN, BLACK, "New item %d added to inventory DB", mInvID );\r
+    }\r
+//Console->Print(YELLOW, BLACK, "PContainerEntry::SQLSave - Query was:");\r
+//Console->Print(YELLOW, BLACK, "%s", query.c_str());\r
+    mDirtyFlag = false;\r
+    return true;\r
+  }\r
+}\r
+\r
+bool PContainerEntry::SQLDelete()\r
+{\r
+  std::string query;\r
+\r
+  if ( mInvID )\r
+  {\r
+    query = Ssprintf( "DELETE FROM inventory WHERE inv_id='%u' LIMIT 1;", mInvID );\r
+\r
+    if ( MySQL->GameQuery( query.c_str() ) )\r
+    {\r
+      Console->Print( RED, BLACK, "PContainerEntry::SQLDelete could not delete some container item from the database" );\r
+      Console->Print( "Query was:" );\r
+      Console->Print( "%s", query.c_str() );\r
+      MySQL->ShowGameSQLError();\r
+      return false;\r
+    }\r
+    else\r
+    {\r
+      if ( gDevDebug )\r
+        Console->Print( GREEN, BLACK, "Item %d deleted from container DB", mInvID );\r
+      mInvID = 0;\r
+      delete mItem;\r
+      mItem = NULL;\r
+\r
+      mDirtyFlag = false;\r
+      return true;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    Console->Print( YELLOW, BLACK, "PContainerEntry::SQLDelete: Item was not in inventory DB" );\r
+    return true;\r
+  }\r
+}\r
+\r
+/* --- PContainer class --- */\r
+\r
+PContainer::PContainer( u8 nMaxSlots )\r
+{\r
+  mMaxSlots = ( nMaxSlots > CONTAINER_MAX_SIZE ? CONTAINER_MAX_SIZE : nMaxSlots ) ;\r
+  if ( mMaxSlots )\r
+    mContContent = new std::vector< PContainerEntry* >( mMaxSlots, NULL );\r
+  else\r
+    mContContent = new std::vector< PContainerEntry* >;\r
+  mCharID = 0;\r
+  mInvLoc = 0;\r
+  mExclusiveUseCharID = 0;\r
+  mDirtyFlag = false;\r
+}\r
+\r
+PContainer::~PContainer()\r
+{\r
+  for ( u8 i = 0; i < mContContent->size(); ++i )\r
+    delete mContContent->at( i );\r
+\r
+  if ( mExclusiveUseCharID )\r
+    Console->Print( RED, BLACK, "[ERROR] PContainer::~PContainer: Char %d still has exclusive access to container !!! Bad Pointer error will happen.", mExclusiveUseCharID );\r
+}\r
+\r
+bool PContainer::AddEntry( PContainerEntry* NewEntry, u8 nSlotId )\r
+{\r
+  if ( IsSlotAllowed( nSlotId ) )\r
+  {\r
+    for ( u8 i = mContContent->size(); i <= nSlotId; ++i ) // Extend as needed\r
+      mContContent->push_back( NULL );\r
+    if ( mContContent->at( nSlotId ) )\r
+    {\r
+      Console->Print( RED, BLACK, "[Warning] PContainer::AddEntry: Target entry already %d in use !!!", nSlotId );\r
+      return false;\r
+    }\r
+    mContContent->at( nSlotId ) = NewEntry;\r
+    mDirtyFlag = true;\r
+    this->SetEntryPosXY( NewEntry, nSlotId, NewEntry->mPosX, NewEntry->mPosY );\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    Console->Print( RED, BLACK, "[Warning] PContainer::AddEntry: Target entry %d not allowed (max = %d) !!!", nSlotId, mMaxSlots );\r
+    return false;\r
+  }\r
+  /* --- degug only ---\r
+  Console->Print(GREEN, BLACK, "PContainer::AddEntry: added item %d at pos (%d,%d)", NewEntry->mItem->GetItemID(), NewEntry->mPosX, NewEntry->mPosY);\r
+\r
+  Dump();\r
+  ---            --- */\r
+}\r
+\r
+void PContainer::SetEntryPosXY( PContainerEntry* nEntry, u8 nSlotId, u8 nPosX, u8 nPosY )\r
+{\r
+  nPosX = nPosY;\r
+  nEntry->Set2DPos( nSlotId, 0 );\r
+  mDirtyFlag = mDirtyFlag || nEntry->mDirtyFlag;\r
+}\r
+\r
+PContainerEntry* PContainer::RemoveEntry( u8 nSlotId )\r
+{\r
+  PContainerEntry* tEntry = NULL;\r
+\r
+  if ( nSlotId < mContContent->size() )\r
+  {\r
+    tEntry = mContContent->at( nSlotId );\r
+    mContContent->at( nSlotId ) = NULL;\r
+  }\r
+  return tEntry;\r
+}\r
+\r
+bool PContainer::GetFreeSlot( u8* nSlotId )\r
+{\r
+  return IsSlotFree( *nSlotId );\r
+}\r
+\r
+void PContainer::Compact( u8 startSlotId )\r
+{\r
+  u8 i, j;\r
+  PContainerEntry* tEntry;\r
+\r
+  for ( i = j = startSlotId; i < mContContent->size(); ++i )\r
+  {\r
+    if ( mContContent->at( i ) )\r
+    {\r
+      if ( j < i )\r
+      {\r
+        mContContent->at( j ) = tEntry = mContContent->at( i );\r
+        this->SetEntryPosXY( tEntry, j, tEntry->mPosX, tEntry->mPosX );\r
+        mContContent->at( i ) = NULL;\r
+        mDirtyFlag = true;\r
+      }\r
+      ++j;\r
+    }\r
+  }\r
+\r
+  if ( !mMaxSlots ) // reduce size only if not fixed-size\r
+  {\r
+    for ( ; j < i; ++j )\r
+      mContContent->pop_back();\r
+  }\r
+}\r
+\r
+bool PContainer::StartUse( u32 nExclusiveUseCharID )\r
+{\r
+  if ( mExclusiveUseCharID )\r
+    return false;\r
+  else\r
+  {\r
+    mExclusiveUseCharID = nExclusiveUseCharID;\r
+    return true;\r
+  }\r
+}\r
+\r
+bool PContainer::EndUse( u32 nExclusiveUseCharID )\r
+{\r
+  if ( nExclusiveUseCharID == mExclusiveUseCharID )\r
+  {\r
+    mExclusiveUseCharID = 0;\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    Console->Print( RED, BLACK, "[Warning] PContainer::EndUse called with CharID %d when CharID %d had exclusive use", nExclusiveUseCharID, mExclusiveUseCharID );\r
+    return false;\r
+  }\r
+}\r
+\r
+bool PContainer::SQLLoad()\r
+{\r
+  if ( !mCharID )\r
+  {\r
+    return false;\r
+  }\r
+\r
+  MYSQL_RES *result;\r
+  MYSQL_ROW row;\r
+  char query[1024];\r
+  PContainerEntry* NewEntry;\r
+  bool SaveDirtyFlag;\r
+  u8 nSlotId;\r
+  //u8 nPosX, nPosY, nSizeX, nSizeY;\r
+\r
+  /*if (!mContContent.empty())\r
+  {\r
+    Console->Print(RED, BLACK, "PContainer::SQLLoad: We don't want to load inventory on non-empty inventory for char %d", mCharID);\r
+    return false;\r
+  }*/\r
+\r
+  snprintf( query, 1024, "SELECT * FROM inventory WHERE inv_charid='%d' AND inv_loc='%d' ORDER BY inv_x ASC", mCharID, mInvLoc );\r
+  result = MySQL->GameResQuery( query );\r
+  if ( result == NULL )\r
+  {\r
+    Console->Print( RED, BLACK, "[Warning] PContainer::SQLLoad could not load inventory from the database" );\r
+    Console->Print( "Query was:" );\r
+    Console->Print( "%s", query );\r
+    MySQL->ShowGameSQLError();\r
+    return false;\r
+  }\r
+  while (( row = mysql_fetch_row( result ) ) )\r
+  {\r
+    NewEntry = new PContainerEntry( row );\r
+    if ( NewEntry->mItem->GetItemID() )\r
+    {\r
+      nSlotId = NewEntry->mPosX;\r
+      SaveDirtyFlag = mDirtyFlag;\r
+\r
+      if ( ! this->GetFreeSlot( &nSlotId ) || ! this->AddEntry( NewEntry, nSlotId ) )\r
+      {\r
+        Console->Print( YELLOW, BLACK, "[Warning] PContainer::SQLLoad: Can't add item %d in slot %d of char %d inventory", NewEntry->mItem->GetItemID(), nSlotId, mCharID );\r
+        delete NewEntry;\r
+        mDirtyFlag = SaveDirtyFlag;\r
+      }\r
+      else\r
+      {\r
+        mDirtyFlag  = SaveDirtyFlag || ( nSlotId != NewEntry->mPosX );\r
+      }\r
+    }\r
+    else\r
+    {\r
+      Console->Print( YELLOW, BLACK, "[Notice] Invalid item in DB (inv_id = %d) - Ignored", NewEntry->mInvID );\r
+      delete NewEntry;\r
+    }\r
+  }\r
+  MySQL->FreeGameSQLResult( result );\r
+  return true;\r
+}\r
+\r
+bool PContainer::SQLSave()\r
+{\r
+  if ( !mCharID )\r
+    return false;\r
+\r
+  PContainerEntry* ContEntry;\r
+  bool SavedOK = true;\r
+\r
+  for ( u8 i = 0; i < mContContent->size(); ++i )\r
+  {\r
+    if (( ContEntry = mContContent->at( i ) ) )\r
+    {\r
+      if (( ContEntry->mDirtyFlag ) )\r
+      {\r
+        SavedOK = SavedOK && ContEntry->SQLSave( mCharID, mInvLoc );\r
+      }\r
+    }\r
+  }\r
+\r
+  if ( SavedOK )\r
+  {\r
+    mDirtyFlag = false;\r
+  }\r
+  return SavedOK;\r
+}\r
+\r
+bool PContainer::IsSlotFree( u8 nSlotId )\r
+{\r
+  if ( !IsSlotAllowed( nSlotId ) )\r
+    return false;\r
+\r
+  if ( nSlotId >= mContContent->size() )\r
+    return true;\r
+  else\r
+    return !( mContContent->at( nSlotId ) );\r
+}\r
+\r
+bool PContainer::AddItem( PItem* NewItem, u32 nInvID, u8 nPosX, u8 nPosY, bool SetDirty )\r
+{\r
+  /* --- auto stacking not implemented yet\r
+  1 - if stackable, check if same item(S) exists\r
+  2 - - if exist\r
+  3 - - - add to stack\r
+  4 - - - if no new stack remains, update LastPutXY & return true\r
+  5 - find an empty space\r
+  6 -\r
+  x - put in new space, update LastPutXY & return true\r
+\r
+  */\r
+\r
+  if ( NewItem->GetItemID() == 0 )\r
+  {\r
+    Console->Print( RED, BLACK, "[Warning] PContainer::AddItem: invalid item : ID 0" );\r
+    return false;\r
+  }\r
+\r
+  PContainerEntry* NewEntry = new PContainerEntry( NewItem, nPosX, nPosY, nInvID, SetDirty );\r
+\r
+  if ( this->GetFreeSlot( &nPosX ) && this->AddEntry( NewEntry, nPosX ) ) // !!!! nPosX not good\r
+    return true;\r
+  else\r
+  {\r
+    delete NewEntry;\r
+    return false;\r
+  }\r
+}\r
+\r
+bool PContainer::MoveItem( u8 srcSlotId, u8 nCount, PContainer* dstContainer, u8 dstSlotId, u8 nPosX, u8 nPosY )\r
+{\r
+  if ( dstContainer == this )\r
+    return this->MoveItem( srcSlotId, nCount, dstSlotId );\r
+  else if ( dstContainer->GetFreeSlot( &dstSlotId ) )\r
+  {\r
+    u8 savePosX, savePosY;\r
+    PContainerEntry* tEntry = this->GetEntry( srcSlotId );\r
+    if ( tEntry )\r
+    {\r
+      tEntry->Get2DPos( &savePosX, &savePosY );\r
+      tEntry->Set2DPos( nPosX, nPosY );\r
+      if ( !dstContainer->AddEntry( tEntry, dstSlotId ) )\r
+      {\r
+        tEntry->Set2DPos( savePosX, savePosY );\r
+        Console->Print( RED, BLACK, "[Warning] PContainer::MoveItem - Couldn't add entry !" );\r
+        return false;\r
+      }\r
+      tEntry->Get2DPos( &nPosX, &nPosY );\r
+      tEntry->Set2DPos( savePosX, savePosY );\r
+      RemoveEntry( srcSlotId );\r
+      tEntry->Set2DPos( nPosX, nPosY );\r
+\r
+      if ( dstContainer->mCharID != this->mCharID ) // save at once if owner changes\r
+      {\r
+        if ( !tEntry->SQLSave( dstContainer->mCharID, dstContainer->mInvLoc ) ) // TODO: improve to manage non-persistent containers\r
+        {\r
+          Console->Print( RED, BLACK, "[Warning] PContainer::MoveItem - Moved entry not saved" );\r
+        }\r
+        //else\r
+        //{\r
+        //  Console->Print(GREEN, BLACK, "[Succes] PContainer::MoveItem - Moved entry saved");\r
+        //}\r
+      }\r
+      return true;\r
+    }\r
+    else\r
+    {\r
+      Console->Print( RED, BLACK, "[Warning] trying to move invalid entry %d", srcSlotId );\r
+      return false;\r
+    }\r
+  }\r
+  return false;\r
+}\r
+\r
+// !!! Not partial move yet !!!\r
+bool PContainer::MoveItem( u8 srcSlotId, u8 nCount, u8 dstSlotId )\r
+{\r
+  if ( !( IsSlotAllowed( srcSlotId ) && IsSlotAllowed( dstSlotId ) ) )\r
+    return false;\r
+\r
+  if ( srcSlotId == dstSlotId )\r
+    return true;\r
+\r
+  if (( mContContent->at( srcSlotId ) )\r
+      && ( mContContent->at( srcSlotId )->mItem->GetStackSize() >= nCount )\r
+      && IsSlotFree( dstSlotId ) )\r
+  {\r
+    PContainerEntry* tEntry = mContContent->at( dstSlotId ) = mContContent->at( srcSlotId );\r
+    tEntry->mPosX = dstSlotId;\r
+    tEntry->mPosY = 0;\r
+    tEntry->mDirtyFlag = true;\r
+    mContContent->at( srcSlotId ) = NULL;\r
+    mDirtyFlag = true;\r
+    return true;\r
+  }\r
+  else\r
+    return false;\r
+}\r
+\r
+std::vector< PContainerEntry* >* PContainer::GetEntries()\r
+{\r
+  std::vector< PContainerEntry* >* Entries = new std::vector< PContainerEntry* >;\r
+\r
+  for ( u8 i = 0; i < mContContent->size(); ++i )\r
+  {\r
+    if ( mContContent->at( i ) )\r
+      Entries->push_back( mContContent->at( i ) );\r
+  }\r
+\r
+  return Entries;\r
+}\r
+\r
+PContainerEntry* PContainer::GetEntry( u8 nSlotId )\r
+{\r
+  if ( nSlotId >= mContContent->size() )\r
+    return NULL;\r
+\r
+  return mContContent->at( nSlotId );\r
+}\r
+\r
+PItem* PContainer::GetItem( u8 nSlotId )\r
+{\r
+  PContainerEntry* tEntry = this->GetEntry( nSlotId );\r
+  return ( tEntry ? tEntry->mItem : NULL );\r
+}\r
+\r
+u8 PContainer::RandomFill( u8 nItemCount, int nItemContainerDefIndex )\r
+{\r
+  PItem* nItem = NULL;\r
+  const PDefItems* nItemDef;\r
+  u32 nItemSeqId;\r
+  u8 CreatedCount = 0;\r
+\r
+  if ( !nItemCount )\r
+    nItemCount = mMaxSlots;\r
+  if ( !nItemCount )\r
+    nItemCount = CONTAINER_MAX_SIZE;\r
+\r
+  if ( nItemContainerDefIndex >= 0 )\r
+  {\r
+    int newItemIdx, newItemIndex;\r
+    u8 newItemQuality;\r
+\r
+    const PDefItemContainer* containerDef = GameDefs->ItemContainers()->GetDef( nItemContainerDefIndex );\r
+    if ( containerDef )\r
+    {\r
+      for ( u8 i = 0; i < nItemCount; ++i )\r
+      {\r
+        newItemIdx = containerDef->GetRandomItemIdx();\r
+        if ( newItemIdx >= 0 )\r
+        {\r
+          newItemIndex = containerDef->GetItemId( newItemIdx );\r
+          newItemQuality = ( u8 )( 255 & int( 255.0 * containerDef->GetQuality( newItemIdx ) ) );\r
+          if ( newItemIndex <= 0 ) // Item group\r
+          {\r
+            newItemIndex = GameDefs->Items()->GetRandomItemIdFromGroup( -newItemIndex );\r
+          }\r
+          nItem = new PItem( newItemIndex, 1, 255, newItemQuality, newItemQuality, newItemQuality, newItemQuality, 255 );\r
+          if ( nItem->GetItemID() )\r
+          {\r
+            if ( this->AddItem( nItem ) )\r
+            {\r
+              ++CreatedCount;\r
+            }\r
+            else\r
+            {\r
+              Console->Print( YELLOW, BLACK, "[Warning] Couldn't add item %d at pos %d", nItem->GetItemID(), i );\r
+              delete nItem;\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+    else\r
+      Console->Print( YELLOW, BLACK, "[Warning] Container def not found: %d", nItemContainerDefIndex );\r
+  }\r
+  else\r
+  {\r
+    int NumItemsDefs = GameDefs->Items()->GetNumDefs();\r
+\r
+    for ( u8 i = 0; i < nItemCount; ++i )\r
+    {\r
+      nItemSeqId = GetRandom( NumItemsDefs, 1 );\r
+\r
+      if (( nItemDef = GameDefs->Items()->GetDefBySeqIndex( nItemSeqId ) ) )\r
+      {\r
+        nItem = new PItem( nItemDef->GetIndex(), 1, 255, 255, 255, 255, 255, 255 );\r
+        if ( nItem->GetItemID() )\r
+        {\r
+          if ( this->AddItem( nItem ) )\r
+          {\r
+            ++CreatedCount;\r
+          }\r
+          else\r
+          {\r
+            //Console->Print(GREEN, BLACK, "Couldn't add item % d at pos % d", nItem->GetItemID(), i);\r
+            delete nItem;\r
+          }\r
+        }\r
+      }\r
+      else\r
+        Console->Print( RED, BLACK, "[Warning] PContainer::RandomFill Couldn't find item for SEQ %d", nItemSeqId );\r
+    }\r
+  }\r
+  return CreatedCount;\r
+}\r
+\r
+void PContainer::Dump()\r
+{\r
+  PContainerEntry* tmpEntry;\r
+  PItem* tmpItem;\r
+  u8 i;\r
+  //u8 y, x;\r
+\r
+  for ( i = 0; i < mContContent->size(); ++i )\r
+  {\r
+    if (( tmpEntry = mContContent->at( i ) ) )\r
+    {\r
+      tmpItem = tmpEntry->mItem;\r
+      Console->Print( GREEN, BLACK, "%d: (%d,%d) (%d x %d) Item %d (InvID %d) %s %s", i, tmpEntry->mPosX, tmpEntry->mPosY, tmpItem->GetSizeX(), tmpItem->GetSizeY(), tmpItem->GetItemID(), tmpEntry->mInvID, tmpItem->GetName().c_str(), tmpEntry->mDirtyFlag ? "[*]" : "" );\r
+    }\r
+  }\r
+\r
+  if ( mDirtyFlag )\r
+    Console->Print( GREEN, BLACK, "Dirty" );\r
+  Console->Print( GREEN, BLACK, "------------------------------------" );\r
+}\r
+\r
+/* --- PContainerWithHoles class --- */\r
+\r
+\r
+/* --- PContainerAutoCompact --- */\r
+PContainerEntry* PContainerAutoCompact::RemoveEntry( u8 nSlotId )\r
+{\r
+  PContainerEntry* tEntry = NULL;\r
+\r
+  if ( nSlotId < mContContent->size() )\r
+  {\r
+    tEntry = mContContent->at( nSlotId );\r
+    mContContent->at( nSlotId ) = NULL;\r
+    if ( nSlotId == ( mContContent->size() - 1 ) )\r
+      mContContent->pop_back();\r
+    else\r
+      Compact( nSlotId );\r
+  }\r
+  return tEntry;\r
+}\r
+\r
+bool PContainerAutoCompact::GetFreeSlot( u8* nSlotId ) // not optimal. A "first free from end" would be better at PContainer level\r
+{\r
+  bool Found = false;\r
+\r
+  for ( *nSlotId = 0; *nSlotId < mContContent->size(); ++*nSlotId )\r
+    if ( ! mContContent->at( *nSlotId ) )\r
+    {\r
+      Found = true;\r
+      break;\r
+    }\r
+  return ( Found || IsSlotAllowed( *nSlotId ) );\r
+}\r
+\r
+bool PContainerAutoCompact::MoveItem( u8 srcSlotId, u8 nCount, u8 dstSlotId )\r
+{\r
+  srcSlotId = nCount = dstSlotId;\r
+  return false;\r
+}\r
+\r
+/* --- PContainer2D class --- */\r
+\r
+void PContainer2D::SetEntryPosXY( PContainerEntry* nEntry, u8 nSlotId, u8 nPosX, u8 nPosY )\r
+{\r
+  nSlotId = nSlotId;\r
+  if (( nPosX >= INV_BACKPACK_COLS ) || ( nPosY == 255 ) )\r
+  {\r
+    nPosX = nPosY = 0;\r
+  }\r
+  nEntry->Set2DPos( nPosX, nPosY );\r
+  mDirtyFlag = mDirtyFlag || nEntry->mDirtyFlag;\r
+}\r
+\r
+/* --- PContainer2DWorkaround --- */\r
+/////\r
+PContainer2DWorkaround::PContainer2DWorkaround( u8 nMaxSlots ) : PContainerWithHoles( nMaxSlots )\r
+{\r
+  nMaxSlots = nMaxSlots;\r
+  mNextFreeSlot = 0;\r
+  mMaxCols = 254;\r
+  mMaxRows = 254;\r
+  mRows = 0;\r
+  AddRow();\r
+}\r
+\r
+PContainer2DWorkaround::~PContainer2DWorkaround()\r
+{\r
+  for ( int i = 0; i < mRows; i++ )\r
+    delete mContSpace[i];\r
+}\r
+\r
+bool PContainer2DWorkaround::AddEntry( PContainerEntry* tEntry, u8 nSlotId )\r
+{\r
+  if ( IsSlotAllowed( nSlotId ) )\r
+  {\r
+    if ( FindValid2DPos( tEntry ) )\r
+    {\r
+      for ( u8 i = mContContent->size(); i <= nSlotId; ++i ) // Extend as needed\r
+        mContContent->push_back( NULL );\r
+      if ( mContContent->at( nSlotId ) )\r
+      {\r
+        Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::AddEntry: Target entry already %d in use !!!", nSlotId );\r
+        return false;\r
+      }\r
+      mContContent->at( nSlotId ) = tEntry;\r
+      mDirtyFlag = true;\r
+      //this->SetEntryPosXY(tEntry, nSlotId, tEntry->mPosX, tEntry->mPosY);\r
+      mDirtyFlag = mDirtyFlag || tEntry->mDirtyFlag;\r
+      SetUsed( tEntry );\r
+      return true;\r
+    }\r
+    else\r
+    {\r
+      Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::AddEntry: No 2D space left !!!", nSlotId, mMaxSlots );\r
+      return false;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::AddEntry: Target entry %d not allowed (max = %d) !!!", nSlotId, mMaxSlots );\r
+    return false;\r
+  }\r
+\r
+}\r
+\r
+PContainerEntry* PContainer2DWorkaround::RemoveEntry( u8 nSlotId )\r
+{\r
+  PContainerEntry* tEntry = NULL;\r
+\r
+  if ( nSlotId < mContContent->size() )\r
+  {\r
+    tEntry = mContContent->at( nSlotId );\r
+    mContContent->at( nSlotId ) = NULL;\r
+    //Console->Print(YELLOW, BLACK, "Cleaning (%d,%d) (%d x %d)", tEntry->mPosX, tEntry->mPosY, tEntry->mItem->GetSizeX(), tEntry->mItem->GetSizeY());\r
+    SetUsed( tEntry, false );\r
+  }\r
+  return tEntry;\r
+}\r
+\r
+bool PContainer2DWorkaround::GetFreeSlot( u8* nSlotId )\r
+{\r
+  if ( IsSlotAllowed( mNextFreeSlot ) )\r
+  {\r
+    *nSlotId = mNextFreeSlot++;\r
+    return true;\r
+  }\r
+  else\r
+    return false;\r
+}\r
+\r
+void PContainer2DWorkaround::SetEntryPosXY( PContainerEntry* nEntry, u8 nSlotId, u8 nPosX, u8 nPosY )\r
+{\r
+  nSlotId = nSlotId;\r
+  if (( nPosX == 255 ) && ( nPosY == 255 ) )\r
+  {\r
+    nEntry->Set2DPos( 255, 255 );\r
+  }\r
+  else\r
+  {\r
+    if (( nPosX >= mMaxCols ) || ( nPosY >= mMaxRows ) )\r
+    {\r
+      nPosX = nPosY = 0;\r
+    }\r
+    nEntry->Set2DPos( nPosX, nPosY );\r
+\r
+    if ( !FindValid2DPos( nEntry ) )\r
+    {\r
+      nEntry->Set2DPos( 255, 255 );\r
+      Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::SetEntryPosXY - Space position already used" );\r
+    }\r
+  }\r
+  mDirtyFlag = mDirtyFlag || nEntry->mDirtyFlag;\r
+}\r
+\r
+bool PContainer2DWorkaround::MoveItem( u8 srcSlotId, u8 nCount, u8 dstSlotId )\r
+{\r
+  srcSlotId = nCount = dstSlotId;\r
+  return false;\r
+}\r
+\r
+void PContainer2DWorkaround::AddRow()\r
+{\r
+  if ( mRows + 1 < mMaxRows )\r
+  {\r
+    std::vector<bool>* NewRow = new std::vector<bool>( mMaxCols, 0 );\r
+    mContSpace.push_back( NewRow );\r
+    ++mRows;\r
+  }\r
+}\r
+\r
+bool PContainer2DWorkaround::Is2DFree( u8 PosX, u8 PosY, u8 SizeX, u8 SizeY )\r
+{\r
+  if (( PosX == 255 ) && ( PosY == 255 ) )\r
+  {\r
+    return true;\r
+  }\r
+  if ( !Is2DPosAllowed( PosX, PosY, SizeX, SizeY ) )\r
+    return false;\r
+\r
+  u8 h, v;\r
+  for ( v = 0; ( v < SizeY ) && ( PosY + v < mRows ) ; v++ ) // what is over existing rows is free\r
+  {\r
+    for ( h = 0; h < SizeX; h++ )\r
+    {\r
+      if ( PosX + h >= mMaxCols ) // what is over max col is not free\r
+        return false;\r
+\r
+      if (( *mContSpace[PosY+v] )[PosX+h] )\r
+        return false;\r
+    }\r
+  }\r
+  return ( PosY + SizeY <= mMaxRows );\r
+}\r
+\r
+void PContainer2DWorkaround::SetUsed( PContainerEntry* nEntry, bool Value )\r
+{\r
+  u8 PosX = nEntry->mPosX;;\r
+  u8 PosY = nEntry->mPosY;\r
+  u8 SizeX = nEntry->mItem->GetSizeX();\r
+  u8 SizeY = nEntry->mItem->GetSizeY();\r
+\r
+  if ( !Is2DPosAllowed( PosX, PosY, SizeX, SizeY ) )\r
+    return;\r
+\r
+  while ( PosY + SizeY > mRows ) // add new rows when needed\r
+    AddRow();\r
+\r
+  u8 h, v;\r
+  for ( v = 0; ( v < SizeY ) && ( PosY + v < mRows ) ; v++ )\r
+  {\r
+    for ( h = 0; ( h < SizeX ) && ( PosX + h < mMaxCols ); h++ )\r
+      ( *mContSpace[PosY+v] )[PosX+h] = Value;\r
+  }\r
+}\r
+\r
+bool PContainer2DWorkaround::FindValid2DPos( PContainerEntry* nEntry )\r
+{\r
+  bool Found = false;\r
+  u8 SizeX = nEntry->mItem->GetSizeX();\r
+  u8 SizeY = nEntry->mItem->GetSizeY();\r
+  u8 dPosX, dPosY;\r
+\r
+  if ( Is2DFree( nEntry->mPosX, nEntry->mPosY, SizeX, SizeY ) )\r
+    Found = true;\r
+  else\r
+  {\r
+    dPosX = nEntry->mPosX;\r
+    dPosY = nEntry->mPosY;\r
+    if ( !Is2DPosAllowed( dPosX, dPosY, SizeX, SizeY ) )\r
+    {\r
+      dPosX = dPosY = 0;\r
+      //Console->Print(YELLOW, BLACK, "Init pos RESET");\r
+    }\r
+\r
+    while ( !Found && Is2DPosAllowed( dPosX, dPosY, SizeX, SizeY ) )\r
+    {\r
+      //Console->Print(YELLOW, BLACK, "Searching line %d", dPosY);\r
+      for ( ; dPosX <= ( mMaxCols - SizeX ); ++dPosX )\r
+      {\r
+        if (( Found = Is2DFree( dPosX, dPosY, SizeX, SizeY ) ) )\r
+          break;\r
+      }\r
+      if ( Found )\r
+      {\r
+        nEntry->mPosX = dPosX;\r
+        nEntry->mPosY = dPosY;\r
+        nEntry->mDirtyFlag = true;\r
+        //Console->Print(YELLOW, BLACK, "Success: Found new space position : (%d,%d)", dPosX, dPosY);\r
+        break;\r
+      }\r
+      ++dPosY;\r
+      dPosX = 0;\r
+    }\r
+  }\r
+  return Found;\r
+}\r
+\r
+void PContainer2DWorkaround::Dump()\r
+{\r
+  PContainer::Dump();\r
+\r
+  std::string tmpS;\r
+  u8 y, x;\r
+  for ( y = 0 ; y < mRows; y++ )\r
+  {\r
+    tmpS = "";\r
+    for ( x = 0 ; x < mMaxCols; x++ )\r
+    {\r
+      tmpS += (( *mContSpace[y] )[x] ) ? "X" : ".";\r
+    }\r
+    Console->Print( "%s", tmpS.c_str() );\r
+  }\r
+  Console->Print( GREEN, BLACK, "------------------------------------" );\r
+}\r
+\r
+/* --- PContainerAutoFindFree --- */\r
+bool PContainerAutoFindFree::GetFreeSlot( u8* nSlotId )\r
+{\r
+  bool Found = false;\r
+\r
+  for ( *nSlotId = 0; *nSlotId < mContContent->size(); ++*nSlotId )\r
+    if ( ! mContContent->at( *nSlotId ) )\r
+    {\r
+      Found = true;\r
+      break;\r
+    }\r
+\r
+  return ( Found || IsSlotAllowed( *nSlotId ) );\r
+}\r
+\r
+/* --- PContainerAutoCompactOnClose --- */\r
+bool PContainerAutoCompactOnClose::EndUse( u32 nExclusiveUseCharID )\r
+{\r
+  if ( nExclusiveUseCharID == mExclusiveUseCharID )\r
+  {\r
+    mExclusiveUseCharID = 0;\r
+    Compact();\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    Console->Print( RED, BLACK, "[ERROR] PContainerAutoCompactOnClose::EndUse called with CharID %d when CharID %d had exclusive use", nExclusiveUseCharID, mExclusiveUseCharID );\r
+    return false;\r
+  }\r
+}\r
diff --git a/server/src/game/decoder/Makefile b/server/src/game/decoder/Makefile
new file mode 100644 (file)
index 0000000..78618d5
--- /dev/null
@@ -0,0 +1,83 @@
+#
+# TinNS per-directory Makefile
+#
+# Adapted by Hammag from the Makefile system for Linux kernel.
+#
+# 14 Sep 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+# 
+
+######################################################
+# Target for this directory and its sub-dirs
+######################################################
+# Case 1 : target is an executable named as defined
+#B_TARGET := gameserver 
+
+# Case 2 : target is a TinNS lib name
+#  (use short name, as in -l linker option) 
+#L_TARGET := tinns
+
+# Case 3 (usual): objects shall be made available to the parent dir
+#  The following line will set that automatically 
+# (Should match dir name + .o suffix)
+O_TARGET := $(addsuffix .o,$(notdir $(shell /bin/pwd)))
+# Manualy define this only if you need to force the compiled obj name
+#O_TARGET := game.o
+
+
+######################################################
+# Local flags
+######################################################
+# local dir CXX Flags
+EXTRA_CXXFLAGS :=  -I/usr/include/mysql -I$(TOPDIR)/game/include
+
+# per-object CXX Flags
+#CXXFLAGS_funcdef2.o := -g
+
+# local dir Linker Flags (for intermediate .o linking)
+#EXTRA_LDFLAGS := 
+
+# any tinns Lib used (short name, as in -l linker option)
+LINK_TINNSLIBS := tinns
+
+# local dir Linker Flags (for final executable linking)
+#EXTRA_LINKFLAGS := -lrt -lpthread -lz -lm -lcrypt -L"/usr/lib/mysql" -lmysqlclient
+
+
+#####################################################
+# Subdirectories
+#####################################################
+#subdir-y := def 
+#subdir-$(CONFIG_GAMEMONKEY)   += gamemonkey
+
+
+#####################################################
+#***************************************************#
+# No further config should be needed after this line
+#***************************************************#
+ifdef TOPDIR
+
+# build list of objects ib loca ldir
+obj-y := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
+# add final object from each subdir
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+
+include $(TOPDIR)/Rules.make
+
+else #TOPDIR undef, Makefile called from non-top dir
+
+# Memorize the first calling dir in case we wanted to
+# lauch local actions from top Makefile
+  ifndef FIRSTDIR
+    FIRSTDIR :=$(CURDIR)
+    export FIRSTDIR
+  endif
+
+uptoparent : 
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+.DEFAULT :
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+endif #TOPDIR
+
diff --git a/server/src/game/decoder/main.h b/server/src/game/decoder/main.h
new file mode 100644 (file)
index 0000000..41af742
--- /dev/null
@@ -0,0 +1,91 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       main.h - main include file, contains all needed includes and important definitions\r
+\r
+       MODIFIED: 30 Aug 2006 Hammag\r
+       REASON: - created\r
+\r
+*/\r
+\r
+#ifndef MAIN_H\r
+#define MAIN_H\r
+\r
+//#include "version.h"\r
+\r
+//basic includes\r
+#include "external.h"\r
+\r
+//tinns includes\r
+#include "types.h"\r
+#include "config.h"\r
+\r
+#include "console.h"\r
+#include "misc.h"\r
+\r
+#include "netcode.h"\r
+\r
+#include "globals.h"\r
+\r
+#include "msgdecoder.h"\r
+#include "udpanalyser.h"\r
+\r
+/*\r
+#include "../gamemonkey/gmMachine.h"\r
+#include "../gamemonkey/gmCall.h"\r
+*/\r
+#include "filesystem.h"\r
+\r
+// MySQL Support // shouldn't be needed as DB-objects access class should do that\r
+#include "mysql.h"\r
+#include "sql.h"\r
+\r
+#include "skill.h"\r
+\r
+#include "chars.h"\r
+#include "accounts.h"\r
+#include "defs.h"\r
+#include "client.h"\r
+#include "server.h"\r
+#include "misc.h"\r
+#include "gameserver.h"\r
+#include "globals.h"\r
+#include "zoning.h"\r
+#include "item.h"\r
+#include "inventory.h"\r
+\r
+#include "chat.h"\r
+#include "commands.h"\r
+#include "clientmanager.h"\r
+#include "msgbuilder.h"\r
+#include "worldactors.h"\r
+#include "npc.h"
+#include "outpost.h"
+#include "multipart.h"\r
+#include "terminal.h"\r
+\r
+using namespace std;\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/decoder/msgdecoder.cpp b/server/src/game/decoder/msgdecoder.cpp
new file mode 100644 (file)
index 0000000..755a55c
--- /dev/null
@@ -0,0 +1,140 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       msgdecoder.cpp - top class for NC messages decoding\r
+\r
+       CREATION: 23 Aug 2006 Hammag\r
+\r
+       MODIFIED:\r
+       REASON: -\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "msgdecoder.h"\r
+\r
+#include "udp_0x13.h"\r
+\r
+\r
+// PUdpMsgDecoder\r
+\r
+/*\r
+    PMsgDecodeData mDecodeData;\r
+    PUdpMsgAnalyser* mCurrentAnalyser;\r
+*/\r
+    \r
+void PUdpMsgDecoder::Init(PMessage* nMessage, PClient* nClient)\r
+{\r
+  mDecodeData.mMessage = nMessage;\r
+  mDecodeData.mClient = nClient;\r
+  mDecodeData.mState = (nMessage && nClient) ? DECODE_MORE : DECODE_UNDEF;\r
+  mDecodeData.mUnknownType = 0;\r
+  mDecodeData.mHandling0x13Sub = false;\r
+       mDecodeData.Sub0x13Start = mDecodeData.Sub0x13StartNext = 0;\r
+  mPacketName.erase();\r
+  mDecodeData.mName.str(mPacketName);\r
+  mDecodeData.mErrorDetail.erase();\r
+       mDecodeData.mTraceKnownMsg = false;\r
+       mDecodeData.mTraceUnknownMsg = false;\r
+       mDecodeData.mTraceDump = false;\r
+  if (mCurrentAnalyser)\r
+  {\r
+    delete mCurrentAnalyser;\r
+    mCurrentAnalyser = NULL;\r
+  }\r
+\r
+}\r
+  \r
+PUdpMsgDecoder::PUdpMsgDecoder()\r
+{\r
+  mCurrentAnalyser = NULL;\r
+  Reset();\r
+}\r
+\r
+PUdpMsgDecoder::PUdpMsgDecoder(PMessage* nMessage, PClient* nClient)\r
+{\r
+  mCurrentAnalyser = NULL;\r
+  Init(nMessage, nClient);\r
+}\r
+\r
+PUdpMsgDecoder::~PUdpMsgDecoder()\r
+{\r
+  if (mCurrentAnalyser)\r
+  {\r
+    delete mCurrentAnalyser;\r
+  }\r
+}\r
+\r
+bool PUdpMsgDecoder::Analyse()\r
+{\r
+  PUdpMsgAnalyser* nextAnalyser;\r
+\r
+  if ((mDecodeData.mState & DECODE_MORE) || mDecodeData.mHandling0x13Sub)\r
+  {\r
+    if (mCurrentAnalyser)\r
+    {\r
+      delete mCurrentAnalyser;\r
+      mCurrentAnalyser = NULL;\r
+    }\r
+    if (mDecodeData.mHandling0x13Sub)\r
+    {\r
+      mPacketName.erase();\r
+      mDecodeData.mName.str(mPacketName);\r
+      mCurrentAnalyser = new PUdp0x13(&mDecodeData);\r
+      mDecodeData.mState = DECODE_MORE;\r
+    }\r
+    else\r
+    {\r
+      mCurrentAnalyser = new PUdpMsgAnalyser(&mDecodeData);\r
+    }\r
+\r
+    while (mDecodeData.mState & DECODE_MORE)\r
+    {\r
+      nextAnalyser = mCurrentAnalyser->Analyse();\r
+      if (mCurrentAnalyser != nextAnalyser)\r
+      {\r
+        delete mCurrentAnalyser;\r
+        mCurrentAnalyser = nextAnalyser;\r
+      }\r
+    }\r
+  }\r
+  return (!(mDecodeData.mState & (DECODE_MORE | DECODE_ERROR | DECODE_UNKNOWN)));\r
+}\r
+\r
+bool PUdpMsgDecoder::Analyse(PMessage* nMessage, PClient* nClient)\r
+{\r
+  Init(nMessage, nClient);\r
+  return Analyse();\r
+}\r
+\r
+bool PUdpMsgDecoder::DoAction()\r
+{\r
+  if (mDecodeData.mState & DECODE_ACTION_READY)\r
+  {\r
+    return mCurrentAnalyser->DoAction();\r
+  }\r
+  else\r
+  {\r
+    return false;\r
+  }\r
+}\r
diff --git a/server/src/game/decoder/udp_0x08.cpp b/server/src/game/decoder/udp_0x08.cpp
new file mode 100644 (file)
index 0000000..3fd9982
--- /dev/null
@@ -0,0 +1,55 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+       udp_0x08.cpp - decoder classes for UDP 0x08 messages\r
+\r
+       CREATION: 05 Jan 2007 Namikon\r
+\r
+       MODIFIED:\r
+       REASON: -\r
+*/\r
+\r
+#include "main.h"\r
+#include "udp_0x08.h"\r
+\r
+\r
+PUdp0x08::PUdp0x08(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)\r
+{\r
+  nDecodeData->mName << "/0x08";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdp0x08::Analyse()\r
+{\r
+    mDecodeData->mName << "=Client crash";\r
+    mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+\r
+    return this;\r
+}\r
+\r
+bool PUdp0x08::DoAction()\r
+{\r
+    // Client crashed, close connection from our side\r
+    GameServer->ClientDisconnected(mDecodeData->mClient);\r
+    mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+\r
+    return true;\r
+}\r
diff --git a/server/src/game/decoder/udp_0x08.h b/server/src/game/decoder/udp_0x08.h
new file mode 100644 (file)
index 0000000..3f3b7ef
--- /dev/null
@@ -0,0 +1,44 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_0x08.h - decoder classes for UDP 0x08 messages\r
+\r
+       CREATION: 05 Jan 2007 Namikon\r
+\r
+       MODIFIED:\r
+       REASON: -\r
+*/\r
+\r
+#ifndef UDP0X08_H\r
+#define UDP0X08_H\r
+\r
+class PUdp0x08 : public PUdpMsgAnalyser\r
+{\r
+  public:\r
+    PUdp0x08(PMsgDecodeData* nDecodeData);\r
+    //~PUdp0x08();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_0x13.cpp b/server/src/game/decoder/udp_0x13.cpp
new file mode 100644 (file)
index 0000000..400ca54
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ udp_0x13.cpp - decoder classes for UDP 0x13 messages
+
+ CREATION: 31 Aug 2006 Hammag
+
+ MODIFIED:
+ REASON: -
+*/
+
+#include "main.h"
+#include "udp_0x13.h"
+
+#include "udp_OOO.h"
+#include "udp_zoning.h"
+#include "udp_0x1f.h"
+#include "udp_0x22.h"
+#include "udp_ping.h"
+#include "udp_sync.h"
+#include "udp_charmove.h"
+#include "udp_packet0.h"
+#include "udp_vhc.h"
+#include "udp_0x2b.h"
+#include "udp_itemmanualreload.h"
+#include "udp_worldIDinfo.h"
+#include "udp_multipart.h"
+
+/**** PUdp0x13 ****/
+
+PUdp0x13::PUdp0x13( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+    nDecodeData->mName << "/0x13";
+}
+
+PUdpMsgAnalyser* PUdp0x13::Analyse()
+{
+    PMessage* TmpMsg = mDecodeData->mMessage;
+    PUdpMsgAnalyser* nextAnalyser = NULL;
+
+    if ( ! mDecodeData->mHandling0x13Sub ) // First decoding pass
+    {
+//Console->Print(" --- New 0x13 msg");
+//TmpMsg->Dump();
+        ( *TmpMsg ) >> ( mDecodeData->mClientState->UDP.mSequence ); // "LastPacket"
+        ( *TmpMsg ) >> ( mDecodeData->mClientState->UDP.mServerPacketNum ); //PID
+        mDecodeData->Sub0x13StartNext = 0;
+    }
+
+    if ( TmpMsg->EOM() )
+    {
+        Console->Print( RED, BLACK, "PUdp0x13::Analyse(): Emptied 0x13 msg handling !!!" );
+        mDecodeData->mState = DECODE_FINISHED;
+        mDecodeData->mHandling0x13Sub = false;
+        nextAnalyser = this;
+        mDecodeData->Sub0x13Start = mDecodeData->Sub0x13StartNext = 0;
+    }
+    else
+    {
+        if ( mDecodeData->mHandling0x13Sub && mDecodeData->Sub0x13StartNext )
+        {
+            TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13StartNext );
+//Console->Print("Multi 0x13 msg continuing at %d", TmpMsg->GetNextByteOffset());
+        }
+        mDecodeData->Sub0x13Start = TmpMsg->GetNextByteOffset();
+        u8 PSize = TmpMsg->U8Data( mDecodeData->Sub0x13Start );
+        u16 EndOffset = mDecodeData->Sub0x13StartNext = mDecodeData->Sub0x13Start + 1 + PSize;
+
+        if ( EndOffset >= TmpMsg->GetSize() )
+        {
+            mDecodeData->mHandling0x13Sub = false;
+            //mDecodeData->Sub0x13Start = mDecodeData->Sub0x13StartNext = 0;
+//Console->Print("Simple 0x13 msg");
+            if ( EndOffset > TmpMsg->GetSize() )
+            {
+                Console->Print( RED, BLACK, "PUdp0x13::Analyse(): Size error in 0x13 msg handling !!!" );
+                mDecodeData->mState = DECODE_ERROR;
+                mDecodeData->mErrorDetail = "Submessage too long.";
+                return this;
+            }
+        }
+        else
+        {
+//Console->Print("Multi 0x13 msg. End at %d for total length %d", EndOffset, TmpMsg->GetSize());
+            mDecodeData->mHandling0x13Sub = true;
+        }
+
+        mDecodeData->mState = DECODE_MORE;
+        u8 MsgType = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 1 );
+        /*u16 PSeq = 0; // This will have to be handled to detected missing granted-delivery messages
+        if (MsgType == 0x03)
+        PSeq = *(u16*)&Buf[Offset+2];*/
+//Console->Print("0x13 Type: %d", MsgType);
+        switch ( MsgType )
+        {
+        case 0x03:
+        {
+            mDecodeData->mName << "/0x03";
+            u8 MsgSubType = TmpMsg->U8Data( TmpMsg->GetNextByteOffset() + 4 );
+            switch ( MsgSubType )
+            {
+            case 0x01: // Out of order
+            {
+                nextAnalyser = new PUdpOOO( mDecodeData );
+                break;
+            }
+            case 0x07: // Fragmented message
+            {
+                nextAnalyser = new PUdpMultiPart( mDecodeData );
+                break;
+            }
+            case 0x08: // Client zoning completed (!!! does not happen on login)
+            {
+                nextAnalyser = new PUdpEndOfZoning( mDecodeData );
+                break;
+            }
+            case 0x1f:
+            {
+                nextAnalyser = new PUdp0x1f( mDecodeData );
+                break;
+            }
+            case 0x22:
+            {
+                nextAnalyser = new PUdp0x22( mDecodeData );
+                break;
+            }
+            case 0x2b: // Citycom (General Terminal?)
+            {
+                nextAnalyser = new PUdp0x2b( mDecodeData );
+                break;
+            }
+            case 0x27: // Request for more information about WorldID
+            {
+                nextAnalyser = new PWorldIDInfoReq( mDecodeData );
+                break;
+            }
+
+            case 0x24: // ? 06 03 03 00 24 01 00
+            default:
+            {
+                mDecodeData->mUnknownType = MsgSubType;
+                break;
+            }
+            }
+            break;
+        }
+
+        case 0x0b: // Ping
+        {
+            nextAnalyser = new PUdpPing( mDecodeData );
+            break;
+        }
+
+        case 0x0c: // Baseline
+        {
+            nextAnalyser = new PUdpSync2( mDecodeData );
+            break;
+        }
+
+        case 0x1f:
+        {
+            mDecodeData->mName << "/0x1f";
+            u8 MsgSubType = TmpMsg->U8Data( TmpMsg->GetNextByteOffset() + 4 );
+            if ( MsgSubType == 0x15 ) // Weapon reload animation start
+            {
+                nextAnalyser = new PUdpReloadAnimStart( mDecodeData );
+            }
+            else
+            {
+                mDecodeData->mUnknownType = MsgType;
+                mDecodeData->mTraceUnknownMsg = true;
+            }
+            break;
+        }
+
+        case 0x20: // Char move
+        {
+            nextAnalyser = new PUdpCharPosUpdate( mDecodeData );
+            break;
+        }
+
+        case 0x27: // Sitting object info request
+        {
+            nextAnalyser = new PUdpRequestVhcInfo( mDecodeData );
+            break;
+        }
+
+        case 0x2a: // "Packet0"
+        {
+            nextAnalyser = new PUdpPacket0( mDecodeData );
+            break;
+        }
+
+        case 0x2d: // sent when targeting another char
+        {
+            nextAnalyser = new PUdpCharTargeting( mDecodeData );
+            break;
+        }
+
+        case 0x32: // Vhc move
+        {
+            mDecodeData->mName << "/0x32";
+            u8 MsgSubType = TmpMsg->U8Data( TmpMsg->GetNextByteOffset() + 4 );
+            switch ( MsgSubType )
+            {
+            case 0x00: // Subway position update
+            {
+                nextAnalyser = new PUdpSubwayUpdate( mDecodeData );
+                break;
+            }
+            case 0x03: // Vhc position update
+            {
+                nextAnalyser = new PUdpVhcMove( mDecodeData );
+                break;
+            }
+            default:
+            {
+                mDecodeData->mUnknownType = MsgSubType;
+                break;
+            }
+            }
+            break;
+        }
+
+        default:
+        {
+            mDecodeData->mUnknownType = MsgType;
+            break;
+        }
+        }
+
+        if ( ! nextAnalyser )
+        {
+            nextAnalyser = new PUdpMsgUnknown( mDecodeData );
+        }
+
+    }
+    return nextAnalyser;
+}
diff --git a/server/src/game/decoder/udp_0x13.h b/server/src/game/decoder/udp_0x13.h
new file mode 100644 (file)
index 0000000..9dc4a21
--- /dev/null
@@ -0,0 +1,45 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_0x13.h - decoder classes for UDP 0x13 messages\r
+  \r
+       CREATION: 31 Aug 2006 Hammag\r
+\r
+       MODIFIED:\r
+       REASON: - \r
+\r
+*/\r
+\r
+#ifndef UDP0X13_H\r
+#define UDP0X13_H\r
+\r
+class PUdp0x13 : public PUdpMsgAnalyser\r
+{ \r
+  public:\r
+    PUdp0x13(PMsgDecodeData* nDecodeData);\r
+    //~PUdp0x13();\r
+    PUdpMsgAnalyser* Analyse();\r
+    //bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_0x1f.cpp b/server/src/game/decoder/udp_0x1f.cpp
new file mode 100644 (file)
index 0000000..1005f0c
--- /dev/null
@@ -0,0 +1,311 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+ udp_udp0x1f.cpp - decoder classes for UDP 0x13x03x1f messages\r
+\r
+ CREATION: 6 Sep 2006 Hammag\r
+\r
+ MODIFIED:\r
+ REASON: -\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "udp_0x1f.h"\r
+\r
+#include "udp_zoning.h"\r
+#include "udp_charmove.h"\r
+#include "udp_vhc.h"\r
+#include "udp_subskill.h"\r
+#include "udp_chat.h"\r
+#include "udp_useobject.h"\r
+#include "udp_appartment.h"\r
+#include "udp_quickaccessbelt.h"\r
+#include "udp_itemmove.h"\r
+#include "udp_hack.h"\r
+#include "udp_outfitter.h"\r
+#include "udp_helditemaction.h"\r
+#include "udp_killself.h"\r
+#include "udp_popupresponse.h"\r
+#include "udp_itemmanualreload.h"\r
+#include "udp_itemuse.h"\r
+#include "udp_deathrespawn.h"\r
+#include "udp_pvptrade.h"\r
+#include "udp_npcdialog.h"\r
+\r
+/**** PUdp0x1f ****/\r
+\r
+PUdp0x1f::PUdp0x1f( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x1f";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdp0x1f::Analyse()\r
+{\r
+  PUdpMsgAnalyser* nextAnalyser = NULL;\r
+  mDecodeData->mState = DECODE_MORE;\r
+  u8 MsgType = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 7 );\r
+  u8 MsgSubType = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 8 );\r
+\r
+  switch ( MsgType )\r
+  {\r
+    case 0x00:\r
+    {\r
+      nextAnalyser = new PUdpHeldItemBasicAction( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x01:\r
+    {\r
+      nextAnalyser = new PUdpHeldItemAimedAction( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x02:\r
+    {\r
+      nextAnalyser = new PUdpCharJump( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x17:\r
+    {\r
+      nextAnalyser = new PUdpUseObject( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x19: // NPC Dialog closed\r
+    {\r
+      nextAnalyser = new PUdpNPCDialogClose( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x1a: // NPC Dialog action/reply\r
+    {\r
+      nextAnalyser = new PUdpNPCDialogAction( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x1b:\r
+    {\r
+      nextAnalyser = new PUdpChatLocal( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x1e:  // item move QB<>INV<>GND\r
+    {\r
+      nextAnalyser = new PUdpItemMove( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x1f: // Slot use\r
+    {\r
+      nextAnalyser = new PUdpItemSlotUse( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x20: // Use item for hacking, launcher, "launcher" spell\r
+    {\r
+      nextAnalyser = new PUdpHeldItemLaunchingAction( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x22:\r
+    {\r
+      nextAnalyser = new PUdpCharExitChair( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x25:\r
+    {\r
+      mDecodeData->mName << "/0x25";\r
+      switch ( MsgSubType )\r
+      {\r
+        case 0x04: // Hack announcement?\r
+        {\r
+          nextAnalyser = new PUdpSubskillInc( mDecodeData );\r
+          break;\r
+        }\r
+        case 0x0c: // addons activation\r
+        {\r
+          nextAnalyser = new PUdpItemAddonActivation( mDecodeData );\r
+          break;\r
+        }\r
+        case 0x14: // Hack announcement?\r
+        {\r
+          nextAnalyser = new PUdpItemMoveBP( mDecodeData );\r
+          break;\r
+        }\r
+        case 0x16: // ???? confirm reload anim start ???\r
+        {\r
+          mDecodeData->mUnknownType = MsgSubType;\r
+          mDecodeData->mTraceUnknownMsg = true;\r
+          break;\r
+        }\r
+        case 0x17: // Item drop on item\r
+        {\r
+          nextAnalyser = new PUdpItemDropOnItem( mDecodeData );\r
+          break;\r
+        }\r
+        case 0x18:\r
+        {\r
+          mDecodeData->mName << "/0x18";\r
+          switch ( mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 9 ) )\r
+          {\r
+            case 0x01: // Use backpack item\r
+            {\r
+              nextAnalyser = new PUdpItemUse( mDecodeData );\r
+              break;\r
+            }\r
+            case 0x0e: // Request manual reload\r
+            {\r
+              nextAnalyser = new PUdpItemManualReload( mDecodeData );\r
+              break;\r
+            }\r
+            default:\r
+            {\r
+              mDecodeData->mUnknownType = MsgSubType;\r
+              mDecodeData->mTraceUnknownMsg = true;\r
+              break;\r
+            }\r
+          }\r
+          break;\r
+        }\r
+\r
+        case 0x1d: // ? before Packet0: 0b 03 01 00 1f 00 00 25 1d 00 00 01\r
+        case 0x1e: // ? before Packet0: 0d 03 02 00 1f 00 00 25 1e ff ff ff ff 00\r
+        default:\r
+        {\r
+          mDecodeData->mUnknownType = MsgSubType;\r
+          mDecodeData->mTraceUnknownMsg = true;\r
+          break;\r
+        }\r
+      }\r
+      break;\r
+    }\r
+    case 0x27:\r
+    {\r
+      nextAnalyser = new PUdpCloseItemContainer( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x29:\r
+    {\r
+      nextAnalyser = new PUdpHackSuccess( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x2c:\r
+    {\r
+      nextAnalyser = new PUdpHackFail( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x2e:\r
+    {\r
+      nextAnalyser = new PUdpOutfitter( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x2f:\r
+    {\r
+      nextAnalyser = new PUdpDeathRespawn( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x33:\r
+    {\r
+      nextAnalyser = new PUdpChatListAdd( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x38:\r
+    {\r
+      nextAnalyser = new PUdpAppartmentAccess( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x39:\r
+    {\r
+      nextAnalyser = new PUdpChatListRemove( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x3b:\r
+    {\r
+      nextAnalyser = new PUdpChatGlobal( mDecodeData );\r
+      break;\r
+    }\r
+    case 0x3d:\r
+    {\r
+      mDecodeData->mName << "/0x3d";\r
+      switch ( MsgSubType ) // In fact MsgSubType is U32, but only lower byte is used\r
+      {\r
+        case 0x02:\r
+        {\r
+          nextAnalyser = new PUdpAddGenrepToList( mDecodeData );\r
+          break;\r
+        }\r
+        case 0x03:\r
+        {\r
+          nextAnalyser = new PUdpAptGRZoning( mDecodeData );\r
+          break;\r
+        }\r
+        case 0x04:\r
+        {\r
+          nextAnalyser = new PUdpGenrepZoning( mDecodeData );\r
+          break;\r
+        }\r
+        case 0x09:\r
+        {\r
+          nextAnalyser = new PUdpPopupResponse( mDecodeData );\r
+          break;\r
+        }\r
+        case 0x0a:\r
+        {\r
+          nextAnalyser = new PUdpAptLocInfo( mDecodeData );\r
+          break;\r
+        }\r
+        case 0x0f:\r
+        {\r
+          nextAnalyser = new PUdpVhcUse( mDecodeData );\r
+          break;\r
+        }\r
+        case 0x10:\r
+        {\r
+          nextAnalyser = new PUdpKillSelf( mDecodeData );\r
+          break;\r
+        }\r
+        default:\r
+        {\r
+          mDecodeData->mUnknownType = MsgSubType;\r
+          break;\r
+        }\r
+      }\r
+      break;\r
+    }\r
+    case 0x3e:\r
+    {\r
+        nextAnalyser = new PUdpPvPTrade( mDecodeData );\r
+        break;\r
+    }\r
+    case 0x4c:\r
+    {\r
+      nextAnalyser = new PUdpChatChannels( mDecodeData );\r
+      break;\r
+    }\r
+    default:\r
+    {\r
+      mDecodeData->mUnknownType = MsgType;\r
+      mDecodeData->mTraceUnknownMsg = true;\r
+      break;\r
+    }\r
+  }\r
+\r
+  if ( ! nextAnalyser )\r
+  {\r
+    nextAnalyser = new PUdpMsgUnknown( mDecodeData );\r
+  }\r
+\r
+  return nextAnalyser;\r
+}\r
diff --git a/server/src/game/decoder/udp_0x1f.h b/server/src/game/decoder/udp_0x1f.h
new file mode 100644 (file)
index 0000000..47debaa
--- /dev/null
@@ -0,0 +1,45 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_udp0x1f.h - decoder classes for UDP 0x13x03x1f messages\r
+  \r
+       CREATION: 6 Sep 2006 Hammag\r
+\r
+       MODIFIED:\r
+       REASON: - \r
+\r
+*/\r
+\r
+#ifndef UDP0X1F_H\r
+#define UDP0X1F_H\r
+\r
+class PUdp0x1f : public PUdpMsgAnalyser\r
+{\r
+  public:\r
+    PUdp0x1f(PMsgDecodeData* nDecodeData);\r
+    //~PUdp0x1f();\r
+    PUdpMsgAnalyser* Analyse();\r
+    //bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_0x22.cpp b/server/src/game/decoder/udp_0x22.cpp
new file mode 100644 (file)
index 0000000..aa80a4c
--- /dev/null
@@ -0,0 +1,87 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_udp0x22.cpp - decoder classes for UDP 0x13x03x22 messages\r
+  \r
+       CREATION: 6 Sep 2006 Hammag\r
+\r
+       MODIFIED:\r
+       REASON: - \r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "udp_0x22.h"\r
+\r
+#include "udp_reqinfo.h"\r
+#include "udp_zoning.h"\r
+#include "udp_entityposreq.h"\r
+\r
+/**** PUdp0x22 ****/\r
+\r
+PUdp0x22::PUdp0x22(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)\r
+{\r
+  nDecodeData->mName << "/0x22";\r
+} \r
+\r
+PUdpMsgAnalyser* PUdp0x22::Analyse()\r
+{\r
+  PUdpMsgAnalyser* nextAnalyser = NULL;\r
+  mDecodeData->mState = DECODE_MORE;    \r
+  u8 MsgType = mDecodeData->mMessage->U8Data(mDecodeData->Sub0x13Start + 5); \r
+  switch(MsgType) // MsgType is probably u16 rather than u8\r
+  {\r
+    case 0x03: // Zoning phase 2\r
+    {       \r
+      nextAnalyser = new PUdpZoning2(mDecodeData);\r
+      break;\r
+    }\r
+    case 0x06: // Char/Clan/Rank/Map Info request\r
+    {       \r
+      nextAnalyser = new PUdpReqInfo(mDecodeData);\r
+      break;\r
+    }\r
+    case 0x0b: // Entity position request\r
+    {\r
+      nextAnalyser = new PUdpEntityPosRequest(mDecodeData);\r
+      break;\r
+    } \r
+    case 0x0d: // Zoning phase 1\r
+    {        \r
+      nextAnalyser = new PUdpZoning1(mDecodeData);\r
+      break;\r
+    }       \r
+    default:\r
+    {\r
+      mDecodeData->mUnknownType = MsgType;\r
+      break;\r
+    }\r
+  }\r
+  \r
+  if (! nextAnalyser)\r
+  {\r
+    nextAnalyser = new PUdpMsgUnknown(mDecodeData);\r
+  }\r
+\r
+  return nextAnalyser;\r
+}\r
diff --git a/server/src/game/decoder/udp_0x22.h b/server/src/game/decoder/udp_0x22.h
new file mode 100644 (file)
index 0000000..5d00741
--- /dev/null
@@ -0,0 +1,45 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_udp0x22.h - decoder classes for UDP 0x13x03x22 messages\r
+  \r
+       CREATION: 6 Sep 2006 Hammag\r
+\r
+       MODIFIED:\r
+       REASON: - \r
+\r
+*/\r
+\r
+#ifndef UDP0X22_H\r
+#define UDP0X22_H\r
+\r
+class PUdp0x22 : public PUdpMsgAnalyser\r
+{ \r
+  public:\r
+    PUdp0x22(PMsgDecodeData* nDecodeData);\r
+    //~PUdp0x22();\r
+    PUdpMsgAnalyser* Analyse();\r
+    //bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_0x2b.cpp b/server/src/game/decoder/udp_0x2b.cpp
new file mode 100644 (file)
index 0000000..c1b9b3d
--- /dev/null
@@ -0,0 +1,90 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_udp0x2b.cpp - decoder classes for UDP 0x13x03x2b messages\r
+\r
+       CREATION: 8 Jan 2007 Namikon\r
+\r
+       MODIFIED:\r
+       REASON: -\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "udp_0x2b.h"\r
+#include "udp_terminal.h"\r
+\r
+/**** PUdp0x2b ****/\r
+\r
+PUdp0x2b::PUdp0x2b(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)\r
+{\r
+  nDecodeData->mName << "/0x2b";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdp0x2b::Analyse()\r
+{\r
+  PUdpMsgAnalyser* nextAnalyser = NULL;\r
+  mDecodeData->mState = DECODE_MORE;\r
+  u8 MsgType = mDecodeData->mMessage->U8Data(mDecodeData->Sub0x13Start + 5);\r
+  switch(MsgType)\r
+  {\r
+    case 0x17: // ReceiveDB Terminal Command\r
+    {\r
+      nextAnalyser = new PUdpReceiveDB(mDecodeData);\r
+      break;\r
+    }\r
+    case 0x18: // UpdateDB Terminal Command\r
+    {\r
+      nextAnalyser = new PUdpUpdateDB(mDecodeData);\r
+      break;\r
+    }\r
+    case 0x19: // TryAccess Terminal Command\r
+    {\r
+      nextAnalyser = new PUdpTryAccessDB(mDecodeData);\r
+      break;\r
+    }\r
+    case 0x1b: // DB Query and Command\r
+    {\r
+      nextAnalyser = new PUdpQueryDB(mDecodeData);\r
+      break;\r
+    }\r
+    case 0x1f: // Citycom?\r
+    {\r
+      nextAnalyser = new PUdpTeminal0x1f(mDecodeData);\r
+      break;\r
+    }\r
+\r
+    default:\r
+    {\r
+      mDecodeData->mUnknownType = MsgType;\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (! nextAnalyser)\r
+  {\r
+    nextAnalyser = new PUdpMsgUnknown(mDecodeData);\r
+  }\r
+\r
+  return nextAnalyser;\r
+}\r
diff --git a/server/src/game/decoder/udp_0x2b.h b/server/src/game/decoder/udp_0x2b.h
new file mode 100644 (file)
index 0000000..a4d45f8
--- /dev/null
@@ -0,0 +1,45 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_udp0x2b.h - decoder classes for UDP 0x13x03x2b messages\r
+\r
+       CREATION: 8 Jan 2007 Namikon\r
+\r
+       MODIFIED:\r
+       REASON: -\r
+\r
+*/\r
+\r
+#ifndef UDP0X2B_H\r
+#define UDP0X2B_H\r
+\r
+class PUdp0x2b : public PUdpMsgAnalyser\r
+{\r
+  public:\r
+    PUdp0x2b(PMsgDecodeData* nDecodeData);\r
+    //~PUdp0x2b();\r
+    PUdpMsgAnalyser* Analyse();\r
+    //bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_OOO.cpp b/server/src/game/decoder/udp_OOO.cpp
new file mode 100644 (file)
index 0000000..25fb335
--- /dev/null
@@ -0,0 +1,60 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_OOO.cpp - decoder classe for UDP Out Of Order message\r
+\r
+       CREATION: 5 Sep 2006 Hammag\r
+\r
+       MODIFIED:\r
+       REASON: -\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "udp_OOO.h"\r
+\r
+/**** PUdpOOO ****/\r
+\r
+PUdpOOO::PUdpOOO(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)\r
+{\r
+  nDecodeData->mName << "/0x01";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpOOO::Analyse()\r
+{\r
+  mDecodeData->mName << "=Out Of Order";\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+\r
+  return this;\r
+}\r
+\r
+bool PUdpOOO::DoAction()\r
+{\r
+    u16 MissingUDP_ID = mDecodeData->mMessage->U16Data(mDecodeData->Sub0x13Start+5);\r
+\r
+    mDecodeData->mClient->getUDPConn()->ReSendUDPMessage(MissingUDP_ID);\r
+    //Console->Print("%s Out of Order packet received ! (Client is missing UDPID %d) ***not managed yet***", Console->ColorText(YELLOW, BLACK, "[Notice]"), MissingUDP_ID);\r
+\r
+    mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+    return true;\r
+}\r
diff --git a/server/src/game/decoder/udp_OOO.h b/server/src/game/decoder/udp_OOO.h
new file mode 100644 (file)
index 0000000..9dffb23
--- /dev/null
@@ -0,0 +1,45 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_OOO.h - decoder classe for UDP Out Of Order message\r
+  \r
+       CREATION: 5 Sep 2006 Hammag\r
+\r
+       MODIFIED:\r
+       REASON: - \r
+\r
+*/\r
+\r
+#ifndef UDPOOO_H\r
+#define UDPOOO_H\r
+\r
+class PUdpOOO : public PUdpMsgAnalyser\r
+{ \r
+  public:\r
+    PUdpOOO(PMsgDecodeData* nDecodeData);\r
+    //~PUdpPing();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_appartment.cpp b/server/src/game/decoder/udp_appartment.cpp
new file mode 100644 (file)
index 0000000..a80b6be
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+/*
+
+       udp_appartment.cpp - decoder classes for Navray apt location request messages
+
+       CREATION: 23 Dec 2006 Namikon
+
+       MODIFIED: 13 may 2007 Hammag
+       REASON: corrected this header
+
+*/
+
+#include "main.h"
+#include "udp_appartment.h"
+
+/**** PUdpAptLocInfo ****/
+
+PUdpAptLocInfo::PUdpAptLocInfo(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+  nDecodeData->mName << "/0x0a";
+}
+
+PUdpMsgAnalyser* PUdpAptLocInfo::Analyse()
+{
+  mDecodeData->mName << "=Requesting appartment location for NavRay";
+
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  return this;
+}
+
+bool PUdpAptLocInfo::DoAction()
+{
+Console->Print("Got request for app data");
+  PMessage* tmpMsg = MsgBuilder->BuildCharAptLocInfoMsg (mDecodeData->mClient);
+
+  if (tmpMsg)
+    mDecodeData->mClient->SendUDPMessage(tmpMsg);
+
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
diff --git a/server/src/game/decoder/udp_appartment.h b/server/src/game/decoder/udp_appartment.h
new file mode 100644 (file)
index 0000000..fd9bc2a
--- /dev/null
@@ -0,0 +1,45 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_appartment.h - decoder classes for Navray apt location request messages\r
+\r
+       CREATION: 23 Dec 2006 Namikon\r
+\r
+       MODIFIED: 13 may 2007 Hammag\r
+       REASON: corrected this header\r
+\r
+*/\r
+\r
+#ifndef UDPAPPARTMENT_H\r
+#define UDPAPPARTMENT_H\r
+\r
+class PUdpAptLocInfo : public PUdpMsgAnalyser\r
+{\r
+  public:\r
+    PUdpAptLocInfo(PMsgDecodeData* nDecodeData);\r
+    //~PUdpAptLocInfo();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_charmove.cpp b/server/src/game/decoder/udp_charmove.cpp
new file mode 100644 (file)
index 0000000..381b26b
--- /dev/null
@@ -0,0 +1,459 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+ udp_charmove.cpp - decoder classes for UDP char movement messages\r
+\r
+ CREATION: 5 Sep 2006 Hammag\r
+\r
+ MODIFIED:\r
+ REASON: -\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "udp_charmove.h"\r
+\r
+#include "worlds.h"\r
+#include "vehicle.h"\r
+#include "subway.h"\r
+\r
+#define JUMPHEIGHT 160\r
+\r
+/**** PUdpCharPosUpdate ****/\r
+\r
+PUdpCharPosUpdate::PUdpCharPosUpdate( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x20";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpCharPosUpdate::Analyse()\r
+{\r
+  mDecodeData->mName << "=Char position update";\r
+\r
+//mDecodeData->mTraceUnknownMsg = true; // temp stop being bugged with unknown move msg\r
+//mDecodeData->mTraceKnownMsg = true;\r
+\r
+  PMessage* nMsg = mDecodeData->mMessage;\r
+  nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 4 );\r
+\r
+  *nMsg >> mInfoBitfield;\r
+//bitfield [C?AL UXZY] packet read from LSB\r
+//          8.21 8421\r
+//Console->Print(YELLOW, BLACK, "[DEBUG] PUdpCharPosUpdate: Bitfield value %02x", mInfoBitfield);\r
+  if ( mInfoBitfield & 0x80 ) // Sitting on chair\r
+  {\r
+    if ( mInfoBitfield & 0x7f )\r
+    {\r
+      mDecodeData->mName << " + mixed bitfield (" << mInfoBitfield << ")";\r
+      mDecodeData->mState = DECODE_UNKNOWN | DECODE_FINISHED;\r
+      Console->Print( YELLOW, BLACK, "[DEBUG] PUdpCharPosUpdate: Client %d sent Mixed field value %x", mDecodeData->mClient->GetID(), mInfoBitfield );\r
+    }\r
+    else\r
+    {\r
+      mDecodeData->mName << " (Char sitting)";\r
+\r
+      *nMsg >> mChairItemID;\r
+      *nMsg >> mChairItemSeat;\r
+      mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+//mDecodeData->mTraceKnownMsg = true;\r
+//mDecodeData->mTraceDump = true;\r
+      if ( gDevDebug ) Console->Print( "%s Localid %d sitting on object %d (0x%08x) seat %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetLocalID(), mChairItemID, mChairItemID, mChairItemSeat );\r
+    }\r
+  }\r
+  else\r
+  {\r
+    if ( mInfoBitfield & 0x01 )\r
+    {\r
+      *nMsg >> mNewY;\r
+    }\r
+    if ( mInfoBitfield & 0x02 )\r
+    {\r
+      *nMsg >> mNewZ;\r
+    }\r
+    if ( mInfoBitfield & 0x04 )\r
+    {\r
+      *nMsg >> mNewX;\r
+    }\r
+    if ( mInfoBitfield & 0x08 )\r
+    {\r
+      *nMsg >> mNewUD;\r
+    }\r
+    if ( mInfoBitfield & 0x10 )\r
+    {\r
+      *nMsg >> mNewLR;\r
+    }\r
+    if ( mInfoBitfield & 0x20 )\r
+    {\r
+      *nMsg >> mNewAct;\r
+    }\r
+    if ( mInfoBitfield & 0x40 ) // purpose unknown\r
+    {\r
+      *nMsg >> mNewUnknown;\r
+      if ( gDevDebug && mNewUnknown )\r
+      {\r
+        Console->Print( YELLOW, BLACK, "[DEBUG] PUdpCharPosUpdate: Client %d sent field 0x40 (in %x) value %x", mDecodeData->mClient->GetID(), mInfoBitfield, mNewUnknown );\r
+      }\r
+    }\r
+\r
+    mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+  }\r
+\r
+  return this;\r
+}\r
+\r
+bool PUdpCharPosUpdate::DoAction()\r
+{\r
+  PClient* nClient = mDecodeData->mClient;\r
+  PChar* nChar = nClient->GetChar();\r
+  PMessage* tmpMsg;\r
+\r
+  if ( ! (mInfoBitfield & 0x80) )\r
+  {\r
+    u32 nSeatableObjectId;\r
+    u8 nSeatId;\r
+    if( nChar->GetSeatInUse(&nSeatableObjectId, &nSeatId) == seat_vhc )\r
+    {\r
+      tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, nSeatableObjectId, nSeatId );\r
+      nClient->FillInUDP_ID(tmpMsg);\r
+      nClient->SendUDPMessage( tmpMsg );\r
+      mChairItemID = nSeatableObjectId;\r
+      mChairItemSeat = nSeatId;\r
+      mInfoBitfield = 0x80;\r
+    }\r
+  }\r
+  \r
+  if ( mInfoBitfield & 0x80 ) // Sitting on chair\r
+  {\r
+    //tmpMsg = MsgBuilder->BuildCharSittingMsg(nClient, mChairItemID);\r
+    //tmpMsg = MsgBuilder->BuildCharSittingMsg(nClient);\r
+    //ClientManager->UDPBroadcast(tmpMsg, nClient, 5000); // TODO: Get the range from config\r
+    tmpMsg = MsgBuilder->BuildCharPosUpdateMsg( nClient );\r
+    ClientManager->UDPBroadcast( tmpMsg, nClient, 5000 ); // TODO: Get the range from config\r
+  }\r
+  else\r
+  {\r
+    bool IsRealMove = false;\r
+\r
+    if (( mInfoBitfield & 0x01 ) && ( nChar->Coords.mY != mNewY ) )\r
+    {\r
+      nChar->Coords.mY = mNewY;\r
+      IsRealMove = true;\r
+    }\r
+    if (( mInfoBitfield & 0x02 ) && ( nChar->Coords.mZ != mNewZ ) )\r
+    {\r
+      nChar->Coords.mZ = mNewZ;\r
+      IsRealMove = true;\r
+    }\r
+    if (( mInfoBitfield & 0x04 ) && ( nChar->Coords.mX != mNewX ) )\r
+    {\r
+      nChar->Coords.mX = mNewX;\r
+      IsRealMove = true;\r
+    }\r
+    if ( mInfoBitfield & 0x08 )\r
+    {\r
+      nChar->Coords.mUD = mNewUD;\r
+      //IsRealMove = true;\r
+    }\r
+    if (( mInfoBitfield & 0x10 ) && ( nChar->Coords.mLR != mNewLR ) )\r
+    {\r
+      nChar->Coords.mLR = mNewLR;\r
+      IsRealMove = true;\r
+    }\r
+    if ( mInfoBitfield & 0x20 )\r
+    {\r
+      nChar->Coords.mAct = mNewAct;\r
+    }\r
+    if ( mInfoBitfield & 0x20 )\r
+    {\r
+      nChar->Coords.mUnknown = mNewUnknown;\r
+    }\r
+    // movement action byte mask:\r
+    // 0x00 NC has no focus (player alt+tab'ed out)\r
+    // 0x02 kneeing\r
+    // 0x20 Walk mode (= not run mode)\r
+    // 0x08 left step\r
+    // 0x10 right step\r
+    // 0x40 forward\r
+    // 0x80 backward\r
+    // bits:  00000000\r
+    //        BFWRL.K.\r
+\r
+    if ( IsRealMove )\r
+    {\r
+      nChar->SetDirtyFlag();\r
+    }\r
+    /*if(IsRealMove)\r
+    if(mInfoBitfield == 0x7f)\r
+    {\r
+      tmpMsg = MsgBuilder->BuildCharPosUpdateMsg(nClient);\r
+      ClientManager->UDPBroadcast(tmpMsg, nClient, 5000); // TODO: Get the range from config\r
+    }*/\r
+\r
+    u16 nSaveZ = nChar->Coords.mZ;\r
+    if(nChar->Coords.mJumpingState)\r
+    {\r
+      mInfoBitfield |= 0x02; // Update Z and Act only\r
+      if(nChar->Coords.mJumpingState == 1)\r
+      {\r
+        if ( gDevDebug ) Console->Print( "%s Send moving jump", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
+        (nChar->Coords.mZ) += JUMPHEIGHT;\r
+        nChar->Coords.mJumpingState = 2; // Jump done\r
+      }\r
+      else\r
+        nChar->Coords.mJumpingState = 0; // No pending jump\r
+    }\r
+\r
+    tmpMsg = MsgBuilder->BuildCharPosUpdate2Msg( nClient, mInfoBitfield );\r
+\r
+    if(nChar->Coords.mJumpingState)\r
+      nChar->Coords.mZ = nSaveZ;\r
+\r
+    ClientManager->UDPBroadcast( tmpMsg, nClient, 5000, true );\r
+\r
+    if ( IsRealMove && nClient->GetDebugMode( DBG_LOCATION ) )\r
+    {\r
+      char DbgMessage[128];\r
+      f32 f[3];\r
+//      u32 h[3];\r
+      f[0] = nChar->Coords.mY - 32000;\r
+      f[1] = nChar->Coords.mZ - 32000;\r
+      f[2] = nChar->Coords.mX - 32000;\r
+      snprintf( DbgMessage, 128, "position y:%0.1f z:%0.1f x:%0.1f lr:%d (Act=%x BF=%x)", f[0], f[1], f[2], nChar->Coords.mLR, nChar->Coords.mAct , mInfoBitfield );\r
+      Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
+    }\r
+    /*{\r
+      u16 p[3];\r
+      p[0] = nChar->Coords.mY;\r
+      p[1] = nChar->Coords.mZ;\r
+      p[2] = nChar->Coords.mX;\r
+      for(int i = 0; i<3; i++)\r
+      {\r
+        if(p[i]< nChar->Coords.minPos[i])\r
+          nChar->Coords.minPos[i] = p[i];\r
+        if(p[i]> nChar->Coords.maxPos[i])\r
+          nChar->Coords.maxPos[i] = p[i];\r
+      }\r
+    }*/\r
+\r
+  if(gDevDebug && IsRealMove)\r
+    Console->Print("%s Char %d position : X(%d) Y(%d) Z(%d) U/D(%d) L/R(%d) Action(%02x)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetID(), nChar->Coords.mX, nChar->Coords.mY, nChar->Coords.mZ, nChar->Coords.mUD, nChar->Coords.mLR, nChar->Coords.mAct);\r
+  }\r
+  if ( mInfoBitfield >= 0x7f )\r
+  {\r
+    tmpMsg = MsgBuilder->BuildCharHealthUpdateMsg( nClient );\r
+    ClientManager->UDPBroadcast( tmpMsg, nClient );\r
+  }\r
+\r
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  return true;\r
+}\r
+\r
+\r
+/**** PUdpCharExitChair ****/\r
+\r
+PUdpCharExitChair::PUdpCharExitChair( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x22";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpCharExitChair::Analyse()\r
+{\r
+  mDecodeData->mName << "=Char exiting chair";\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+\r
+  return this;\r
+}\r
+\r
+bool PUdpCharExitChair::DoAction()\r
+{\r
+  DoLeaveChair( mDecodeData->mClient->GetChar(), mDecodeData->mClient );\r
+\r
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  return true;\r
+}\r
+\r
+bool PUdpCharExitChair::DoLeaveChair( PChar* nChar, PClient* nClient, PSpawnedVehicle* nVhc, bool nForce )\r
+{\r
+  if ( ! nClient )\r
+    nClient = ClientManager->getClientByChar( nChar->GetID() );\r
+  if ( ! nClient )\r
+  {\r
+    Console->Print("%s PUdpCharExitChair::DoLeaveChair called without PClient* and client not available when searching by char.", Console->ColorText( RED, BLACK, "[ERROR]" ) );\r
+    return false;\r
+  }\r
+\r
+  PMessage* tmpMsg;\r
+  u32 cSeatObjectId;\r
+  u8 cSeatId;\r
+  PSeatType cSeatType = nChar->GetSeatInUse( &cSeatObjectId, &cSeatId );\r
+  u32 tNowTime = GameServer->GetGameTime();\r
+  bool ReadyToExit = false;\r
+\r
+  // This is only for investigation on subway timing\r
+  if ( nClient->GetDebugMode( DBG_SUBWAY ) && ( cSeatType == seat_subway ) )\r
+  {\r
+    char DbgMessage[80];\r
+    u8 tCabId;\r
+    Subway->GetInfoIndex( cSeatObjectId, &tCabId );\r
+    u8 tStationId = Subway->GetStation( cSeatObjectId, tNowTime );\r
+    std::string* StationName = Subway->GetStationName( tStationId );\r
+    std::string OpenState = ( Subway->IsDoorOpen( cSeatObjectId, tNowTime ) ? "open" : "closed" );\r
+\r
+    snprintf( DbgMessage, 80, "Cab %d (%d) is in station %s (%d). Door is %s (time: %d)", tCabId, cSeatObjectId, StationName->c_str(), tStationId, OpenState.c_str(), tNowTime );\r
+    DbgMessage[79] = 0;\r
+    Chat->send( nClient, CHAT_DIRECT, "System", DbgMessage );\r
+    delete StationName;\r
+  }\r
+  // end investigation\r
+\r
+  if ( cSeatType )\r
+  {\r
+    PWorld* tWorld = Worlds->GetWorld( nChar->GetLocation() );\r
+\r
+    if ( cSeatType == seat_chair )\r
+    {\r
+      tWorld->CharLeaveChair( nClient->GetLocalID(), cSeatObjectId );\r
+      nChar->SetSeatInUse( seat_none );\r
+      ReadyToExit = true;\r
+    }\r
+    else if ( cSeatType == seat_subway )\r
+    {\r
+      if ( Subway->IsDoorOpen( cSeatObjectId, tNowTime ) || nForce )\r
+      {\r
+        Subway->GetStationExitPosition( &( nChar->Coords ), Subway->GetStation( cSeatObjectId, tNowTime ), GetRandomFloat() );\r
+        Subway->UnsetSeatUser( cSeatObjectId, cSeatId, nChar->GetID() );\r
+        nChar->SetSeatInUse( seat_none );\r
+        ReadyToExit = true;\r
+      }\r
+      else\r
+      {\r
+        tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, cSeatObjectId ); // "Damn, locked"\r
+        nClient->SendUDPMessage( tmpMsg );\r
+      }\r
+    }\r
+    else if ( cSeatType == seat_vhc )\r
+    {\r
+      PSpawnedVehicle* tVhc = tWorld->GetSpawnedVehicules()->GetVehicle( cSeatObjectId );\r
+      if ( tVhc && (!nVhc || (tVhc == nVhc) || nForce) )\r
+      {\r
+        PVhcCoordinates tCoords = tVhc->GetPosition();\r
+        tVhc->UnsetSeatUser( cSeatId, nChar->GetID() );\r
+        nChar->SetSeatInUse( seat_none );\r
+        nChar->Coords.SetPosition( tCoords.GetY(), tCoords.GetZ(), tCoords.GetX() ); // to complete with LR\r
+        ReadyToExit = true;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      Console->Print( "%s PUdpCharExitChair::DoLeaveChair : Invalid seat type %d", Console->ColorText( RED, BLACK, "[ERROR]" ), cSeatType );\r
+    }\r
+\r
+    if ( ReadyToExit )\r
+    {\r
+      nChar->SetSeatInUse( seat_none );\r
+\r
+      tmpMsg = MsgBuilder->BuildCharExitSeatMsg( nClient );\r
+      ClientManager->UDPBroadcast( tmpMsg, nClient );\r
+\r
+      if ( gDevDebug ) Console->Print( "%s Localchar %d get up from chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nClient->GetLocalID(), cSeatObjectId );\r
+      return true;\r
+    }\r
+  }\r
+\r
+  return false;\r
+}\r
+\r
+/**** PUdpCharJump ****/\r
+\r
+PUdpCharJump::PUdpCharJump( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x02";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpCharJump::Analyse()\r
+{\r
+  mDecodeData->mName << "=Char jumping";\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+\r
+  return this;\r
+}\r
+\r
+bool PUdpCharJump::DoAction()\r
+{\r
+  PClient* nClient = mDecodeData->mClient;\r
+  PChar* nChar = nClient->GetChar();\r
+\r
+  if( nChar->Coords.mAct & 0xd8 ) // if moving, don't jump now and wait next update\r
+  {\r
+    nChar->Coords.mJumpingState = 1; // Jump pending. Do at next pos update\r
+    if ( gDevDebug ) Console->Print( "%s Prepare moving jump", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
+  }\r
+  else // If not moving, jump now\r
+  {\r
+    if ( gDevDebug ) Console->Print( "%s Send static jump", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
+    u8 mInfoBitfield = 0x22; // Update Z and Act only\r
+    u16 nSaveZ = nChar->Coords.mZ;\r
+    (nChar->Coords.mZ) += JUMPHEIGHT;\r
+    PMessage* tmpMsg = MsgBuilder->BuildCharPosUpdate2Msg( nClient, mInfoBitfield );\r
+    nChar->Coords.mZ = nSaveZ;\r
+    nChar->Coords.mJumpingState = 2; // Jump done\r
+    ClientManager->UDPBroadcast( tmpMsg, nClient, 5000, true );\r
+  }\r
+\r
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+\r
+  return true;\r
+}\r
+\r
+\r
+/**** PUdpCharTargeting ****/\r
+\r
+PUdpCharTargeting::PUdpCharTargeting( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x2d";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpCharTargeting::Analyse()\r
+{\r
+  mDecodeData->mName << "=Targeting char";\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+\r
+  return this;\r
+}\r
+\r
+bool PUdpCharTargeting::DoAction()\r
+{\r
+  PClient* nClient = mDecodeData->mClient;\r
+  PChar* tChar = nClient->GetChar();\r
+  u16 CharID = mDecodeData->mMessage->U16Data( mDecodeData->Sub0x13Start + 2 );\r
+  u8 strangeval1 = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 4 );\r
+  u8 strangeval2 = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 5 );\r
+  u8 strangeval3 = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 6 );\r
+\r
+  tChar->SetLookingAt( CharID );\r
+\r
+  if ( gDevDebug )\r
+    Console->Print( "%s Char %d targeting char %d. // %d %d %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetID(), CharID, strangeval1, strangeval2, strangeval3 );\r
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  return true;\r
+}\r
diff --git a/server/src/game/decoder/udp_charmove.h b/server/src/game/decoder/udp_charmove.h
new file mode 100644 (file)
index 0000000..c66e058
--- /dev/null
@@ -0,0 +1,89 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_charmove.h - decoder classes for UDP char movement messages\r
+\r
+       CREATION: 5 Sep 2006 Hammag\r
+\r
+       MODIFIED:\r
+       REASON: -\r
+\r
+*/\r
+\r
+#ifndef UDPCHARMOVE_H\r
+#define UDPCHARMOVE_H\r
+\r
+#include "msgdecoder.h"\r
+#include "udpanalyser.h"\r
+\r
+class PUdpCharPosUpdate : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u8 mInfoBitfield;\r
+    u16 mNewY;\r
+    u16 mNewZ;\r
+    u16 mNewX;\r
+    u8 mNewUD;\r
+    u8 mNewLR;\r
+    u8 mNewAct;\r
+    u8 mNewUnknown;\r
+    u32 mChairItemID; // u16 or u32 ???\r
+    u8 mChairItemSeat;\r
+\r
+  public:\r
+    PUdpCharPosUpdate(PMsgDecodeData* nDecodeData);\r
+    //~PUdpCharMoves();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpCharExitChair : public PUdpMsgAnalyser\r
+{\r
+  public:\r
+    PUdpCharExitChair(PMsgDecodeData* nDecodeData);\r
+    //~PUdpCharExitChair();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+\r
+    //nClient is optionnal, nVhc is to limit to that vhc, nForce to force exit event when cab door closed\r
+    static bool DoLeaveChair(PChar* nChar, PClient* nClient = NULL, PSpawnedVehicle* nVhc = NULL, bool nForce = false); \r
+};\r
+\r
+class PUdpCharJump : public PUdpMsgAnalyser\r
+{\r
+  public:\r
+    PUdpCharJump(PMsgDecodeData* nDecodeData);\r
+    //~PUdpCharJump();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpCharTargeting : public PUdpMsgAnalyser\r
+{\r
+  public:\r
+    PUdpCharTargeting(PMsgDecodeData* nDecodeData);\r
+    //~PUdpCharTargeting();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+#endif\r
diff --git a/server/src/game/decoder/udp_chat.cpp b/server/src/game/decoder/udp_chat.cpp
new file mode 100644 (file)
index 0000000..34641fb
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+/*
+
+       udp_chat.h - decoder classes for UDP chat  messages
+  
+       CREATION: 15 Sep 2006 Hammag
+
+       MODIFIED: 11 Dec 2006 Hammag
+       REASON: - added PUdpChatChannels
+
+*/
+
+#include "main.h"
+#include "udp_chat.h"
+
+/**** PUdpChatLocal ****/
+
+PUdpChatLocal::PUdpChatLocal(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+  nDecodeData->mName << "/0x1b";
+} 
+
+PUdpMsgAnalyser* PUdpChatLocal::Analyse()
+{
+  mDecodeData->mName << "=Local chat";
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  
+  return this;
+}
+
+bool PUdpChatLocal::DoAction()
+{
+  // temp
+  Chat->HandleGameChat(mDecodeData->mClient, mDecodeData->mMessage->GetMessageData() + mDecodeData->Sub0x13Start);
+    /*PMessage* cMsg = mDecodeData->mMessage;
+    u32 ClientTime = cMsg->U32Data(mDecodeData->Sub0x13Start+2);
+    
+    PMessage* tmpMsg = MsgBuilder->BuildPingMsg(mDecodeData->mClient, ClientTime);
+    mDecodeData->mClient->SendUDPMessage(tmpMsg);*/
+    
+    //cMsg->SetNextByteOffset(mDecodeData->Sub0x13StartNext);
+    mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+    return true;
+}
+
+/**** PUdpChatGlobal ****/
+
+PUdpChatGlobal::PUdpChatGlobal(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+  nDecodeData->mName << "/0x3b";
+} 
+
+PUdpMsgAnalyser* PUdpChatGlobal::Analyse()
+{
+  //u16 dumb;
+  mDecodeData->mName << "=Global chat";
+
+/*  PMessage* nMsg = mDecodeData->mMessage;
+  nMsg->SetNextByteOffset(mDecodeData->Sub0x13Start + 12);
+  *nMsg >> mVehicleID; // ? not u32 ???
+  *nMsg >> dumb;
+  *nMsg >> mVehicleSeat;*/
+
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  return this;
+}
+
+bool PUdpChatGlobal::DoAction()
+{
+  // Temp
+  Chat->HandleGameChat(mDecodeData->mClient, mDecodeData->mMessage->GetMessageData() + mDecodeData->Sub0x13Start);
+/*  PMessage* tmpMsg = MsgBuilder->BuildCharEnteringVhcMsg (mDecodeData->mClient, mVehicleID, mVehicleSeat);
+  ClientManager->UDPBroadcast(tmpMsg, mDecodeData->mClient);
+*/
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
+
+/**** PUdpChatListAdd ****/
+
+PUdpChatListAdd::PUdpChatListAdd(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+  nDecodeData->mName << "/0x33";
+} 
+
+PUdpMsgAnalyser* PUdpChatListAdd::Analyse()
+{
+  mDecodeData->mName << "=Add char to chat list";
+
+  PMessage* nMsg = mDecodeData->mMessage;
+  u8 PSize = nMsg->U8Data(mDecodeData->Sub0x13Start);
+  mChatList = mDecodeData->mMessage->U8Data(mDecodeData->Sub0x13Start + 8);
+  
+  if ((mChatList == 1) || (mChatList == 2))
+  {
+    if ((PSize > 8) && (nMsg->U8Data(mDecodeData->Sub0x13StartNext -1) == 0))
+    {
+      mAddedCharname = (char*)mDecodeData->mMessage->GetMessageData() + mDecodeData->Sub0x13Start + 9;
+      mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+    }
+    else
+    {
+      mDecodeData->mState = DECODE_ERROR;
+      mDecodeData->mErrorDetail = "Invalid charname position";
+    }
+  
+    return this;
+  }
+  else
+  {
+    mDecodeData->mUnknownType = mChatList;
+    return new PUdpMsgUnknown(mDecodeData);
+  }
+}
+
+bool PUdpChatListAdd::DoAction()
+{
+  PClient* nClient = mDecodeData->mClient;
+  std::string AddedChar = mAddedCharname;
+  PChar* tChar = Chars->GetChar(AddedChar);
+  u32 AddedCharID = (tChar ? tChar->GetID() : 0);
+  bool AddResult = false;
+  
+  if (AddedCharID)
+  {
+    switch(mChatList)
+    {
+      case 1:
+      {
+        AddResult = nClient->GetChar()->SetDirectChat(AddedCharID);
+        break; 
+      }
+      case 2:
+      {
+        AddResult = nClient->GetChar()->AddBuddy(AddedCharID);
+        break; 
+      }
+    }
+  }
+  
+  if (AddResult)
+  {
+    PMessage* tmpMsg = MsgBuilder->BuildChatAddMsg (nClient, AddedCharID, mChatList);
+    nClient->SendUDPMessage(tmpMsg);
+  }
+  
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
+
+/**** PUdpChatListRemove ****/
+
+PUdpChatListRemove::PUdpChatListRemove(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+  nDecodeData->mName << "/0x39";
+} 
+
+PUdpMsgAnalyser* PUdpChatListRemove::Analyse()
+{
+  mDecodeData->mName << "=remove char from chat list";
+
+  PMessage* nMsg = mDecodeData->mMessage;
+  nMsg->SetNextByteOffset(mDecodeData->Sub0x13Start + 8);
+  (*nMsg) >> mChatList;
+  
+  if ((mChatList == 1) || (mChatList == 2))
+  {
+    (*nMsg) >> mRemovedCharID;
+    mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+    return this;
+  }
+  else
+  {
+    mDecodeData->mUnknownType = mChatList;
+    return new PUdpMsgUnknown(mDecodeData);
+  }
+}
+
+bool PUdpChatListRemove::DoAction()
+{
+  PClient* nClient = mDecodeData->mClient;
+  
+  bool RemoveResult = false;
+  
+  if (mRemovedCharID)
+  {
+    switch(mChatList)
+    {
+      case 1:
+      {
+        RemoveResult = nClient->GetChar()->SetDirectChat(0);
+        break; 
+      }
+      case 2:
+      {
+        RemoveResult = nClient->GetChar()->RemoveBuddy(mRemovedCharID);
+        break; 
+      }
+    }
+  }
+  
+  // No known response yet ...
+  /*if (AddResult)
+  {
+    PMessage* tmpMsg = MsgBuilder->BuildChatAddMsg (nClient, mRemovedCharID, mChatList);
+    nClient->SendUDPMessage(tmpMsg);
+  }*/
+  
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
+
+/**** PUdpChatChannels ****/
+
+PUdpChatChannels::PUdpChatChannels(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+  nDecodeData->mName << "/0x4c";
+} 
+
+PUdpMsgAnalyser* PUdpChatChannels::Analyse()
+{
+  mDecodeData->mName << "=update listening custom chat channels selection";
+
+  PMessage* nMsg = mDecodeData->mMessage;
+  nMsg->SetNextByteOffset(mDecodeData->Sub0x13Start + 8);
+  (*nMsg) >> mChannelFlags;
+  
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  return this;
+}
+
+bool PUdpChatChannels::DoAction()
+{
+  PChar* nChar = mDecodeData->mClient->GetChar();
+  nChar->SetActiveChannels(mChannelFlags);
+//Console->Print("Channel flag: %08x", mChannelFlags);
+
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
diff --git a/server/src/game/decoder/udp_chat.h b/server/src/game/decoder/udp_chat.h
new file mode 100644 (file)
index 0000000..8ccd966
--- /dev/null
@@ -0,0 +1,94 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_chat.h - decoder classes for UDP chat  messages\r
+  \r
+       CREATION: 15 Sep 2006 Hammag\r
+\r
+       MODIFIED: 11 Dec 2006 Hammag\r
+       REASON: - added PUdpChatChannels\r
+\r
+*/\r
+\r
+#ifndef UDPCHAT_H\r
+#define UDPCHAT_H\r
+\r
+class PUdpChatLocal : public PUdpMsgAnalyser\r
+{ \r
+  public:\r
+    PUdpChatLocal(PMsgDecodeData* nDecodeData);\r
+    //~PUdpChatLocal();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpChatGlobal : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    \r
+  public:\r
+    PUdpChatGlobal(PMsgDecodeData* nDecodeData);\r
+    //~PUdpChatGlobal();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpChatListAdd : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u8 mChatList; // 1 = Direct, 2 = Buddy List\r
+    char* mAddedCharname;\r
+    \r
+  public:\r
+    PUdpChatListAdd(PMsgDecodeData* nDecodeData);\r
+    //~PUdpChatListAdd();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpChatListRemove : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u8 mChatList;\r
+    u32 mRemovedCharID;\r
+    \r
+  public:\r
+    PUdpChatListRemove(PMsgDecodeData* nDecodeData);\r
+    //~PUdpChatListRemove();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpChatChannels : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u32 mChannelFlags; // 1 bit per custom channel, starting from LSB, in same order as in chat i/f\r
+    \r
+  public:\r
+    PUdpChatChannels(PMsgDecodeData* nDecodeData);\r
+    //~PUdpChatChannels();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_deathrespawn.cpp b/server/src/game/decoder/udp_deathrespawn.cpp
new file mode 100644 (file)
index 0000000..b6dd979
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+  TinNS (TinNS is not a Neocron Server)
+  Copyright (C) 2005 Linux Addicted Community
+  maintainer Akiko <akiko@gmx.org>
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License
+  as published by the Free Software Foundation; either version 2
+  of the License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+  02110-1301, USA.
+*/
+
+/*
+
+  udp_deathrespawn.cpp - decoder classes for UDP respawn selection after death message
+
+  CREATION: 10 May 2009 Hammag
+
+  MODIFIED:
+  REASON: -
+
+*/
+
+#include "main.h"
+#include "udp_deathrespawn.h"
+#include "udp_zoning.h"
+
+/**** PUdpDeathRespawn ****/
+
+PUdpDeathRespawn::PUdpDeathRespawn( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x2f";
+}
+
+PUdpMsgAnalyser* PUdpDeathRespawn::Analyse()
+{
+  PMessage* tmpMsg = mDecodeData->mMessage;
+
+  mDecodeData->mName << "=Death respawn selection";
+
+  tmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 8 );
+  ( *tmpMsg ) >> mEntity;
+  ( *tmpMsg ) >> mWorldId;
+
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  return this;
+}
+
+bool PUdpDeathRespawn::DoAction()
+{
+  //PClient* nClient = mDecodeData->mClient;
+  //PChar* nChar = nClient->GetChar();
+
+  //PMessage* tmpMsg = MsgBuilder->BuildReqInfoAnswerMsg(mDecodeData->mClient, mRequestType, mInfoId, Answer, len);
+  //mDecodeData->mClient->SendUDPMessage(tmpMsg);
+
+  //if ( gDevDebug )
+    Console->Print( "%s Request to respawn in zone %d, entity %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mWorldId, mEntity );
+
+  if( mWorldId == 0xffffffff )
+  {
+    PUdpAptGRZoning::DoEffectiveZoning( mDecodeData->mClient );
+  }
+  else
+  {
+    PUdpGenrepZoning::DoEffectiveZoning( mDecodeData->mClient, mWorldId, mEntity );
+  }
+
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return ( true );
+}
diff --git a/server/src/game/decoder/udp_deathrespawn.h b/server/src/game/decoder/udp_deathrespawn.h
new file mode 100644 (file)
index 0000000..358564e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+  TinNS (TinNS is not a Neocron Server)
+  Copyright (C) 2005 Linux Addicted Community
+  maintainer Akiko <akiko@gmx.org>
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License
+  as published by the Free Software Foundation; either version 2
+  of the License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+  02110-1301, USA.
+*/
+
+/*
+
+  udp_deathrespawn.h - decoder classes for UDP respawn selection after death message
+
+  CREATION: 10 May 2009 Hammag
+
+  MODIFIED:
+  REASON: -
+
+*/
+
+#ifndef UDPDEATHRESPAWN_H
+#define UDPDEATHRESPAWN_H
+
+class PUdpDeathRespawn : public PUdpMsgAnalyser
+{
+  private:
+    u32 mEntity;
+    u32 mWorldId;
+
+  public:
+    PUdpDeathRespawn( PMsgDecodeData* nDecodeData );
+    //~PUdpDeathRespawn();
+    PUdpMsgAnalyser* Analyse();
+    bool DoAction();
+};
+
+#endif
diff --git a/server/src/game/decoder/udp_entityposreq.cpp b/server/src/game/decoder/udp_entityposreq.cpp
new file mode 100644 (file)
index 0000000..db80a66
--- /dev/null
@@ -0,0 +1,109 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_entityposreq.cpp - decoder classes for UDP entity position request messages\r
+\r
+       CREATION: 8 jun 2007 Hammag\r
+\r
+       MODIFIED:\r
+       REASON: -\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "udp_entityposreq.h"\r
+\r
+#include "worlds.h"\r
+\r
+PUdpEntityPosRequest::PUdpEntityPosRequest(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)\r
+{\r
+  nDecodeData->mName << "/0x0b";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpEntityPosRequest::Analyse()\r
+{\r
+  mDecodeData->mName << "=Entity position request";\r
+\r
+//mDecodeData->mTraceUnknownMsg = true; // temp stop being bugged with unknown move msg\r
+//mDecodeData->mTraceKnownMsg = true;\r
+\r
+  PMessage* nMsg = mDecodeData->mMessage;\r
+  nMsg->SetNextByteOffset(mDecodeData->Sub0x13Start + 7);\r
+\r
+  *nMsg >> mEntityID; //(u16 ... or u32 ???)\r
+\r
+  if(mEntityID >= WORLDDATATEMPLATE_MAXPOSITEMS)\r
+  {\r
+    mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+    mDecodeData->mErrorDetail = Ssprintf("Invalid position entity ID (%d)", mEntityID);\r
+    Console->Print("%s Client[%d] sent invalid position entity Id[%d]", Console->ColorText(YELLOW, BLACK, "[Notice]"), mDecodeData->mClient->GetID(), mEntityID);\r
+    mDecodeData->mTraceDump = true;\r
+  }\r
+  else\r
+  {\r
+    mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+  }\r
+\r
+  return this;\r
+}\r
+\r
+bool PUdpEntityPosRequest::DoAction()\r
+{\r
+  PClient* nClient = mDecodeData->mClient;\r
+  PChar* nChar = nClient->GetChar();\r
+  PWorld* currentWorld = Worlds->GetWorld(nChar->GetLocation());\r
+  f32 fpX, fpY, fpZ;\r
+  u16 pX, pY, pZ;\r
+\r
+  if(currentWorld)\r
+  {\r
+    if((mEntityID < WORLDDATATEMPLATE_MAXPOSITEMS) && currentWorld->getPositionItemPosition(mEntityID, &fpX, &fpY, &fpZ))\r
+    {\r
+      pX = (u16) (fpX + 32000);\r
+      pY = (u16) (fpY + 32000);\r
+      pZ = (u16) (fpZ + 32000);\r
+\r
+if(gDevDebug) Console->Print(GREEN, BLACK, "Client %d - Sending pos for entity %d : X=%d Y=%d Z=%d", mDecodeData->mClient->GetID(), mEntityID, pX, pY, pZ);\r
+    }\r
+    else if(!nClient->GetCharAwaitingWarpto(&pX, &pY, &pZ))\r
+    {\r
+      pX = pY = pZ = 0;\r
+      Console->Print("%s Client[%d] requested invalid position entity %d. Position reset.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mDecodeData->mClient->GetID(), mEntityID);\r
+    }\r
+    \r
+    PMessage* tmpMsg;\r
+    tmpMsg = MsgBuilder->BuildEntityPositionMsg(nClient, pX, pY, pZ);\r
+    nClient->SendUDPMessage(tmpMsg);\r
+    (nChar->Coords).mY=pY;\r
+    (nChar->Coords).mZ=pZ;\r
+    (nChar->Coords).mX=pX;\r
+  }\r
+  else\r
+  {\r
+    Console->Print(RED, BLACK, "[Warning] PUdpEntityPosRequest - Invalid world (%d)", nChar->GetLocation());\r
+  }\r
+//    if(IsRealMove && nClient->GetDebugMode(DBG_LOCATION))\r
+\r
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  return true;\r
+}\r
diff --git a/server/src/game/decoder/udp_entityposreq.h b/server/src/game/decoder/udp_entityposreq.h
new file mode 100644 (file)
index 0000000..f4f37bc
--- /dev/null
@@ -0,0 +1,49 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_entityposreq.h - decoder classes for UDP entity position request messages\r
+\r
+       CREATION: 8 jun 2007 Hammag\r
+\r
+       MODIFIED:\r
+       REASON: -\r
+\r
+*/\r
+\r
+#ifndef UDPENTITYPOS_H\r
+#define UDPENTITYPOS_H\r
+\r
+class PUdpEntityPosRequest : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u16 mEntityID; // u16 or u32 ???\r
+\r
+\r
+  public:\r
+    PUdpEntityPosRequest(PMsgDecodeData* nDecodeData);\r
+    //~PUdpEntityPosRequest();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_hack.cpp b/server/src/game/decoder/udp_hack.cpp
new file mode 100644 (file)
index 0000000..1108214
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_hack.cpp - decoder classes for UDP hacking related messages
+
+ CREATION: 30 Dec 2006 Namikon
+
+ MODIFIED:
+ REASON: -
+
+*/
+
+#include "main.h"
+#include "udp_hack.h"
+#include "worlds.h"
+#include "furnituretemplate.h"
+#include "doortemplate.h"
+
+/**** PUdpHackSuccess ****/
+
+PUdpHackSuccess::PUdpHackSuccess(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+    nDecodeData->mName << "/0x29";
+}
+
+PUdpMsgAnalyser* PUdpHackSuccess::Analyse()
+{
+    mDecodeData->mName << "=Hackgame was successfull";
+
+    mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+    return this;
+}
+
+bool PUdpHackSuccess::DoAction()
+{
+    PClient* nClient = mDecodeData->mClient;
+    PChar* tChar = nClient->GetChar();
+    PWorld* CurrentWorld = Worlds->GetWorld(tChar->GetLocation());
+    const PFurnitureItemTemplate* tFurnitureTemplate = NULL;
+    const PDefWorldModel* tFurnitureModel = NULL;
+
+    u32 mRawItemID = mDecodeData->mMessage->U32Data(mDecodeData->Sub0x13Start+8);
+    if(gDevDebug) Console->Print("DEBUG: Client %d successfully hacked object %d", mDecodeData->mClient->GetID(), mRawItemID);
+
+    bool tHandleDynamicActor = false;
+    // First try to find out if we have an dynamic worldactor
+    if(WorldActors->IsDynamicActor(mRawItemID) == true)
+    {
+        // Now get the get the function value: (What kind of hackable object)
+        int tFunctionVal = WorldActors->GetWorldActorFunctionID(mRawItemID);
+
+        // Then get the FUNCTION VALUE as furniture model so we can access its subvalues etc. Here: Hack difficult
+        tFurnitureModel = GameDefs->WorldModels()->GetDef(tFunctionVal);
+        tHandleDynamicActor = true;
+    }
+    else
+    {
+        // Dat files have smaller IDs
+        u32 ItemID = mRawItemID/1024 -1;
+
+        // Now grab the template from .dat file
+        tFurnitureTemplate = CurrentWorld->GetFurnitureItemTemplate(ItemID);
+
+        // Then get the FUNCTION VALUE as furniture model so we can access its subvalues etc
+        tFurnitureModel = CurrentWorld->GetFurnitureItemModel(ItemID);
+    }
+
+
+    if(tHandleDynamicActor == false && tFurnitureTemplate != NULL)
+    {
+        if (tFurnitureTemplate->GetLinkedObjectID())
+        {
+            PMessage* tmpMsg = MsgBuilder->BuildDoorOpenMsg(0x80+tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor(tFurnitureTemplate->GetLinkedObjectID())->IsDoubleDoor());
+            ClientManager->UDPBroadcast(tmpMsg, nClient);
+        }
+        else
+        {
+            PMessage* tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg(nClient, mRawItemID);
+            nClient->SendUDPMessage(tmpMsg);
+        }
+    }
+    else
+    {
+        if (WorldActors->GetLinkedObjectID(mRawItemID))
+        {
+            PMessage* tmpMsg = MsgBuilder->BuildDoorOpenMsg(0x80+WorldActors->GetLinkedObjectID(mRawItemID), CurrentWorld->GetDoor(WorldActors->GetLinkedObjectID(mRawItemID))->IsDoubleDoor());
+            ClientManager->UDPBroadcast(tmpMsg, nClient);
+        }
+        else
+        {
+            PMessage* tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg(nClient, mRawItemID);
+            nClient->SendUDPMessage(tmpMsg);
+        }
+    }
+
+    mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+    return true;
+}
+
+
+/**** PUdpHackFail ****/
+
+PUdpHackFail::PUdpHackFail(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+    nDecodeData->mName << "/0x2C";
+}
+
+PUdpMsgAnalyser* PUdpHackFail::Analyse()
+{
+    mDecodeData->mName << "=Hackgame failed";
+
+    mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+    return this;
+}
+
+bool PUdpHackFail::DoAction()
+{
+    mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+    return true;
+}
diff --git a/server/src/game/decoder/udp_hack.h b/server/src/game/decoder/udp_hack.h
new file mode 100644 (file)
index 0000000..ffcb9fe
--- /dev/null
@@ -0,0 +1,54 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+ udp_hack.h - decoder classes for UDP hacking related messages\r
+\r
+ CREATION: 30 Dec 2006 Namikon\r
+\r
+ MODIFIED:\r
+ REASON: -\r
+\r
+*/\r
+\r
+#ifndef UDPHACK_H\r
+#define UDPHACK_H\r
+\r
+class PUdpHackFail : public PUdpMsgAnalyser\r
+{\r
+  public:\r
+    PUdpHackFail( PMsgDecodeData* nDecodeData );\r
+    //~PUdpHackFail();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpHackSuccess : public PUdpMsgAnalyser\r
+{\r
+  public:\r
+    PUdpHackSuccess( PMsgDecodeData* nDecodeData );\r
+    //~PUdpHackSuccess();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_helditemaction.cpp b/server/src/game/decoder/udp_helditemaction.cpp
new file mode 100644 (file)
index 0000000..515ce99
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_helditemaction.cpp - decoder classes for held item related messages
+
+ CREATION: 20 Mar 2009 Hammag
+
+ MODIFIED:
+ REASON: -
+
+*/
+
+#include "main.h"
+#include "udp_helditemaction.h"
+#include "worlds.h"
+#include "furnituretemplate.h"
+
+/**** PUdpHeldItemBasicAction ****/
+
+PUdpHeldItemBasicAction::PUdpHeldItemBasicAction( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x00";
+}
+
+PUdpMsgAnalyser* PUdpHeldItemBasicAction::Analyse()
+{
+  mDecodeData->mName << "=Basic action";
+
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  return this;
+}
+
+bool PUdpHeldItemBasicAction::DoAction()
+{
+  mDecodeData->mMessage->Dump();
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
+
+
+/**** PUdpHeldItemAimedAction ****/
+
+PUdpHeldItemAimedAction::PUdpHeldItemAimedAction( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x01";
+}
+
+PUdpMsgAnalyser* PUdpHeldItemAimedAction::Analyse()
+{
+  mDecodeData->mName << "=Held item Action";
+
+  PMessage* nMsg = mDecodeData->mMessage;
+  nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 8 );
+
+  ( *nMsg ) >> mWeaponId;
+  ( *nMsg ) >> mTargetRawItemID; // !!! 0x000003fe when shooting with no target
+  ( *nMsg ) >> mAiming; // aiming ??? 0 to 52 +?
+  ( *nMsg ) >> mTargetedHeight; // range 0 (bottom) to 26 (?) (top)
+  ( *nMsg ) >> mScore; // range 0 to 255(?)  Score ???
+
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  return this;
+}
+
+bool PUdpHeldItemAimedAction::DoAction()
+{
+  u16 maxBroadcastDistance = 0; // parameter.
+  PClient* nClient = mDecodeData->mClient;
+  //PChar* tChar = nClient->GetChar();
+//  PCharCoordinates& nCharCoords = nClient->GetChar()->Coords;
+  PMessage* tmpMsg;
+
+  // IF APU SPELL
+  //10: 03:be:00:1f:[02:00]:25:1a:[68:11:96:43]:[78:de:12:00:] = ????
+  //tmpMsg = MsgBuilder->BuildHeldItemUse3Msg( nClient, 0x1168, 0x4369, 0xde78, 0x0012 ); // unknwon use, unknown data (spells duration/delays ?)
+  //nClient->SendUDPMessage(tmpMsg);
+
+  //tmpMsg = MsgBuilder->BuildHeldItemUse2Msg( nClient->GetLocalID(), mTargetRawItemID ); // start spell invocation
+  //ClientManager->UDPBroadcast( tmpMsg, nClient, maxBroadcastDistance );
+
+  // END IF APU SPELL
+
+  tmpMsg = MsgBuilder->BuildHeldItemUseMsg( nClient->GetLocalID(), mWeaponId, mTargetRawItemID, mAiming, mTargetedHeight, 0 ); // 'score' is not broadcasted, but set to 0
+  ClientManager->UDPBroadcast( tmpMsg, nClient, maxBroadcastDistance, true );
+
+  // IF APU SPELL
+  // After spell invocation delay
+  // 03:8b:00:1f:[02:00]:2c:01:?[ae:bf]?:?[f5:45]?:[00:20:01:00]:[0e]:
+  tmpMsg = MsgBuilder->BuildHeldItemUse4Msg( nClient->GetLocalID(), mTargetRawItemID, 0xaebf, 0x45f5, mTargetedHeight );
+  ClientManager->UDPBroadcast( tmpMsg, nClient, maxBroadcastDistance );
+  // END IF APUI SPELL
+
+  //if ( gDevDebug )
+  Console->Print( "%s Handled item action toward target %d (0x%08x) weaponId=%d aiming=%d 'height'=%d 'score'=%d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTargetRawItemID, mTargetRawItemID, mWeaponId, mAiming, mTargetedHeight, mScore );
+  //mDecodeData->mMessage->Dump();
+
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
+
+
+/**** PUdpHeldItemLaunchingAction ****/
+
+PUdpHeldItemLaunchingAction::PUdpHeldItemLaunchingAction( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x20";
+}
+
+PUdpMsgAnalyser* PUdpHeldItemLaunchingAction::Analyse()
+{
+  mDecodeData->mName << "=Start Lauching action";
+
+  PMessage* nMsg = mDecodeData->mMessage;
+  nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 8 );
+
+  ( *nMsg ) >> mWeaponId;
+  ( *nMsg ) >> mSourceY;
+  ( *nMsg ) >> mSourceZ;
+  ( *nMsg ) >> mSourceX;
+  ( *nMsg ) >> mSourceUD;
+  ( *nMsg ) >> mSourceLR;
+  ( *nMsg ) >> mUnknown1;
+  ( *nMsg ) >> mUnknown2; // client timestamp ? => TODO: compare with data from ping request
+  ( *nMsg ) >> mTargetRawItemID;
+
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  return this;
+  /*
+1b 03 73 00 1f 01 00 20
+a6 00
+81 7d
+f0 7b
+50 7e
+6e
+e2
+7d 20
+30 ad db 45
+fe 03 00 00
+  */
+}
+
+bool PUdpHeldItemLaunchingAction::DoAction()
+{
+  PClient* nClient = mDecodeData->mClient;
+  PChar* tChar = nClient->GetChar();
+  PWorld* CurrentWorld = Worlds->GetWorld( tChar->GetLocation() );
+  const PFurnitureItemTemplate* tFurnitureTemplate = NULL;
+  const PDefWorldModel* tFurnitureModel = NULL;
+
+  u32 mRawItemID = mDecodeData->mMessage->U32Data( mDecodeData->Sub0x13Start + 24 );
+  //if(gDevDebug) Console->Print("Client %d wants to hack itemID %d ***not managed yet***", mDecodeData->mClient->GetID(), mRawItemID);
+
+  // First try to find out if we're hacking an dynamic actor
+  if ( WorldActors->IsDynamicActor( mRawItemID ) == true )
+  {
+    // Now get the get the function value: (What kind of hackable object)
+    int tFunctionVal = WorldActors->GetWorldActorFunctionID( mRawItemID );
+
+    // Then get the FUNCTION VALUE as furniture model so we can access its subvalues etc. Here: Hack difficult
+    tFurnitureModel = GameDefs->WorldModels()->GetDef( tFunctionVal );
+  }
+  else
+  {
+    // Dat files have smaller IDs
+    u32 ItemID = mRawItemID / 1024 - 1;
+
+    // Now grab the template from .dat file
+    tFurnitureTemplate = CurrentWorld->GetFurnitureItemTemplate( ItemID );
+
+    // Then get the FUNCTION VALUE as furniture model so we can access its subvalues etc
+    tFurnitureModel = CurrentWorld->GetFurnitureItemModel( ItemID );
+  }
+
+  if ( tFurnitureModel ) // We have an valid worldobject? Fine. Then start the hackgame
+  {
+    u8 tHackDifficult = tFurnitureModel->GetHackDifficulty();
+    u8 tHackPenalty = tFurnitureModel->GetHackPenalty();
+
+    // Print it!
+    if(tHackDifficult)
+    {
+      //if (gDevDebug)
+      Console->Print( "%s Client trying to hack itemID %d. Hack difficult: %d Hack penalty %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID, tHackDifficult, tHackPenalty );
+
+      PMessage* tmpMsg = MsgBuilder->BuildStartHackGameMsg( nClient, mRawItemID, tHackDifficult );
+      nClient->SendUDPMessage( tmpMsg );
+      tmpMsg = NULL;
+    }
+  }
+
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
+
+/**** PUdpItemAddonActivation ****/
+
+PUdpItemAddonActivation::PUdpItemAddonActivation( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x0c";
+}
+
+PUdpMsgAnalyser* PUdpItemAddonActivation::Analyse()
+{
+  mDecodeData->mName << "=Held item addon activation/deactivation";
+
+  mAddonIdx = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 9 );
+
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  return this;
+}
+
+bool PUdpItemAddonActivation::DoAction()
+{
+  PClient* nClient = mDecodeData->mClient;
+  //PChar* tChar = nClient->GetChar();
+  nClient->testval8 ^= ( 1 << mAddonIdx ); // Toggle state // Using testval8 for testing only!!!
+
+  PMessage* tmpMsg =  MsgBuilder->BuildHeldItemAddonActivationMsg( nClient, nClient->testval8 ); // For testing only!!!
+  ClientManager->UDPBroadcast( tmpMsg, nClient );
+
+  if ( gDevDebug )
+    Console->Print( "%s Handled item (de)activation of addon %d (0x%02x)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mAddonIdx, nClient->testval8 );
+
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
diff --git a/server/src/game/decoder/udp_helditemaction.h b/server/src/game/decoder/udp_helditemaction.h
new file mode 100644 (file)
index 0000000..a1fd84a
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_helditemaction.h - decoder classes for held item related messages
+
+ CREATION: 20 Mar 2009 Hammag
+
+ MODIFIED:
+ REASON: -
+
+*/
+
+#ifndef HELDITEMACTION_H
+#define HELDITEMACTION_H
+
+
+class PUdpHeldItemBasicAction : public PUdpMsgAnalyser
+{
+  public:
+    PUdpHeldItemBasicAction( PMsgDecodeData* nDecodeData );
+    //~PUdpHeldItemBasicAction();
+    PUdpMsgAnalyser* Analyse();
+    bool DoAction();
+};
+
+class PUdpHeldItemAimedAction : public PUdpMsgAnalyser
+{
+  private:
+    u16 mWeaponId;
+    u32 mTargetRawItemID;
+    u8 mAiming; // 0: minimal
+    u8 mTargetedHeight; // 0: bottom to 26: top
+    u8 mScore; // ??? looks quite random...
+
+  public:
+    PUdpHeldItemAimedAction( PMsgDecodeData* nDecodeData );
+    //~PUdpHeldItemAimedAction();
+    PUdpMsgAnalyser* Analyse();
+    bool DoAction();
+};
+
+class PUdpHeldItemLaunchingAction : public PUdpMsgAnalyser
+{
+  private:
+    u16 mWeaponId;
+    u16 mSourceY;
+    u16 mSourceZ;
+    u16 mSourceX;
+    u8 mSourceUD;
+    u8 mSourceLR;
+    u16 mUnknown1;
+    u32 mUnknown2; // client timestamp ? => TODO: compare with data from ping request
+    u32 mTargetRawItemID;
+
+  public:
+    PUdpHeldItemLaunchingAction( PMsgDecodeData* nDecodeData );
+    //~PUdpHeldItemLaunchingAction();
+    PUdpMsgAnalyser* Analyse();
+    bool DoAction();
+};
+
+class PUdpItemAddonActivation : public PUdpMsgAnalyser
+{
+  private:
+    u8 mAddonIdx;
+
+  public:
+    PUdpItemAddonActivation( PMsgDecodeData* nDecodeData );
+    //~PUdpItemAddonActivation();
+    PUdpMsgAnalyser* Analyse();
+    bool DoAction();
+};
+#endif
diff --git a/server/src/game/decoder/udp_itemmanualreload.cpp b/server/src/game/decoder/udp_itemmanualreload.cpp
new file mode 100644 (file)
index 0000000..d80ec66
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_itemmanualreload.cpp - decoder classes for UDP item manual reload messages
+
+ CREATION: 9 May 2009 Hammag
+
+ MODIFIED:
+ REASON: -
+
+*/
+
+#include "main.h"
+#include "udp_itemmanualreload.h"
+#include "container.h"
+
+/**** PUdpItemManualReload ****/
+
+PUdpItemManualReload::PUdpItemManualReload( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x18";
+}
+
+PUdpMsgAnalyser* PUdpItemManualReload::Analyse()
+{
+  mDecodeData->mName << "=Reloading item (manual)";
+
+  //PMessage* nMsg = mDecodeData->mMessage;
+  mUnknown = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 9 );
+  // 0e: reload
+  // 01 / slotid 0xNNNN : use item from backpack
+  if ( gDevDebug )
+    mDecodeData->mMessage->Dump();
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  return this;
+}
+
+bool PUdpItemManualReload::DoAction()
+{
+  PClient* nClient = mDecodeData->mClient;
+  PChar* tChar = nClient->GetChar();
+  
+  if ( gDevDebug )
+    Console->Print( "%s Manual reload start", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+
+  u8 activeSlot = tChar->GetQuickBeltActiveSlot();
+  if (( activeSlot != INV_WORN_QB_NONE ) && ( activeSlot != INV_WORN_QB_HAND ) )
+  {
+    u8 newAmmoCount = GetMaxLoadableAmmos( activeSlot );
+    if ( newAmmoCount )
+    {
+      PMessage* tmpMsg = MsgBuilder->BuildStartWeaponReloadMsg( nClient );
+      nClient->SendUDPMessage( tmpMsg );
+
+      tmpMsg = new PMessage( 32 );
+      nClient->IncreaseUDP_ID();
+
+      *tmpMsg << ( u8 )0x13;
+      *tmpMsg << ( u16 )nClient->GetUDP_ID();
+      *tmpMsg << ( u16 )nClient->GetSessionID();
+
+      *tmpMsg << ( u8 )0x00; // Message length
+      *tmpMsg << ( u8 )0x03;
+      *tmpMsg << ( u16 )nClient->GetUDP_ID();
+      *tmpMsg << ( u8 )0x1f;
+      *tmpMsg << ( u16 )nClient->GetLocalID();
+      *tmpMsg << ( u8 )0x25;
+      *tmpMsg << ( u8 )0x13;
+
+      nClient->IncreaseTransactionID();
+      *tmpMsg << ( u16 )nClient->GetTransactionID();
+      *tmpMsg << ( u8 )0x05; // cmd=Ammo count update
+      *tmpMsg << ( u8 )INV_LOC_WORN;
+      *tmpMsg << ( u8 )(INV_WORN_QB_START + activeSlot); // X
+      *tmpMsg << ( u8 )0x00; //(Y)
+      *tmpMsg << ( u8 )newAmmoCount; // Ammo count
+
+      ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+      nClient->SendUDPMessage( tmpMsg );
+    }
+  }
+  //else
+    //Console->Print( "%s no reloadable weapon on slot %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), activeSlot );
+
+
+  /*  PClient* nClient = mDecodeData->mClient;
+    //PChar* tChar = nClient->GetChar();
+    PMessage* tmpMsg = new PMessage(32);
+
+    nClient->IncreaseUDP_ID();
+    nClient->IncreaseTransactionID();
+
+    *tmpMsg << (u8)0x13;
+    *tmpMsg << (u16)nClient->GetUDP_ID();
+    *tmpMsg << (u16)nClient->GetSessionID();
+
+    *tmpMsg << (u8)0x00; // Message length
+    *tmpMsg << (u8)0x03;
+    *tmpMsg << (u16)nClient->GetUDP_ID();
+    *tmpMsg << (u8)0x1f;
+    *tmpMsg << (u16)nClient->GetLocalID();
+    *tmpMsg << (u8)0x25;
+    *tmpMsg << (u8)0x13;
+    *tmpMsg << (u16)nClient->GetTransactionID();
+    *tmpMsg << (u8)0x0a; // cmd=Ammo type update (?)
+    *tmpMsg << (u8)0x03;
+    *tmpMsg << (u8)0x02;
+    *tmpMsg << (u8)0x00;
+    *tmpMsg << (u8)0x00;
+    *tmpMsg << (u8)0x00;
+    nClient->IncreaseTransactionID();
+    *tmpMsg << (u16)nClient->GetTransactionID();
+    *tmpMsg << (u8)0x05; // cmd=Ammo count update
+    *tmpMsg << (u8)INV_LOC_BACKPACK;
+    *tmpMsg << (u8)0x0e; // X
+    *tmpMsg << (u8)0x00; //(Y)
+    *tmpMsg << (u8)0x03; // Ammo count
+    nClient->IncreaseTransactionID();
+    *tmpMsg << (u16)nClient->GetTransactionID();
+    *tmpMsg << (u8)0x05; // cmd=Ammo count update
+    *tmpMsg << (u8)INV_LOC_WORN;
+    *tmpMsg << (u8)0x03; // X
+    *tmpMsg << (u8)0x00; //(Y)
+    *tmpMsg << (u8)0x02; // Ammo count
+
+    (*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6);
+  tmpMsg->Dump();
+    nClient->SendUDPMessage(tmpMsg);
+  */
+  /* Resp:
+  03:33:00:1f:01:00:25:13
+  c2:01:0a:00:02:00:00:00 ?? set ammo type ?
+  c3:01:05:03:00:00:12 Update ammo left
+  c4:01:05:02:00:00:0c Update ammo left
+   
+  tt:tt:02:loc:x:y delete item
+  */
+
+  /* manual reload
+    srv resp : 13:58:00:d6:d4:08:03:58:00:1f:01:00:25:16 (do start reload anim - even if no relaod needed or no more ammo avail)
+    cli resp: 13:3f:00:bd:d4:08:03:3f:00:1f:01:00:25:25 (reload anim done , also when reaload not possible because mission ammo)
+    srv resp: 13:59:00:d7:d4:16:03:59:00:1f:01:00:25:13:8d:22:05:03:11:00:16:8e:22:05:02:00:00:0c : update inv if needed
+
+    if(mUnknown != 0x0e)
+   Console->Print(YELLOW, BLACK, "PUdpManualReloadItem: additionnal byte differs from 0x0e : %2x", mUnknown);
+  */
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
+
+u8 PUdpItemManualReload::GetMaxLoadableAmmos( u8 nBeltSlotId )
+{
+  PItem* activeItem = mDecodeData->mClient->GetChar()->GetInventory()->GetContainer( INV_DB_LOC_WORN )->GetItem( INV_WORN_QB_START + nBeltSlotId );
+  if ( activeItem && ( activeItem->GetType() == ITEM_TYPE_WEAPON ) )
+  {
+    const PDefWeapon* activeWeapon = GameDefs->Weapons()->GetDef( activeItem->GetValue1() );
+    //Console->Print( "%s Using weapon %d, type %d on slot %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), activeItem->GetValue1(), activeItem->GetType(), nBeltSlotId );
+    if ( activeWeapon )
+    {
+      int ammoId = activeWeapon->GetAmmoType(0); // not really the loaded ammo for now
+      if ( ammoId > 0 ) // weapon really uses ammos
+      {
+        const PDefAmmo* activeAmmo = GameDefs->Ammos()->GetDef( ammoId );
+        if ( activeAmmo )
+        {
+          return activeAmmo->GetMagSize();
+        }
+        //else
+          //Console->Print( "%s no valid ammo (%d) on slot %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), ammoId, nBeltSlotId );
+      }
+      //else
+        //Console->Print( "%s no usable ammo (%d) on slot %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), ammoId, nBeltSlotId );
+    }
+    //else
+      //Console->Print( "%s no valid weapon (%d, type %d) on slot %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), activeItem->GetValue1(), activeItem->GetType(), nBeltSlotId );
+  }
+  //else
+    //Console->Print( "%s no valid item on slot %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nBeltSlotId );
+  return 0;
+}
+
+/**** PUdpReloadAnimStart ****/
+
+PUdpReloadAnimStart::PUdpReloadAnimStart( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x15";
+}
+
+PUdpMsgAnalyser* PUdpReloadAnimStart::Analyse()
+{
+  mDecodeData->mName << "=Reload animation starting";
+
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  return this;
+}
+
+bool PUdpReloadAnimStart::DoAction()
+{
+  PClient* nClient = mDecodeData->mClient;
+  //PChar* tChar = nClient->GetChar();
+
+  PMessage* tmpMsg = MsgBuilder->BuildStartWeaponReloadAnimMsg( nClient );
+      ClientManager->UDPBroadcast( tmpMsg, nClient, 5000, true );
+  if ( gDevDebug )
+    Console->Print( "%s Reload animation starting", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
diff --git a/server/src/game/decoder/udp_itemmanualreload.h b/server/src/game/decoder/udp_itemmanualreload.h
new file mode 100644 (file)
index 0000000..2b296e9
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+udp_itemmanualreload.h - decoder classes for UDP item manual reload messages
+
+ CREATION: 9 May 2009 Hammag
+
+ MODIFIED:
+ REASON: -
+
+*/
+
+#ifndef MANUALITEMRELOAD_H
+#define MANUALITEMRELOAD_H
+
+class PUdpItemManualReload : public PUdpMsgAnalyser
+{
+  private:
+    u8 mUnknown;
+    u8 GetMaxLoadableAmmos( u8 nBeltSlotId );
+
+  public:
+      PUdpItemManualReload(PMsgDecodeData* nDecodeData);
+      //~PUdpItemManualReload();
+      PUdpMsgAnalyser* Analyse();
+      bool DoAction();
+};
+
+class PUdpReloadAnimStart : public PUdpMsgAnalyser
+{
+  public:
+    PUdpReloadAnimStart( PMsgDecodeData* nDecodeData );
+    //~PUdpReloadAnimStart();
+    PUdpMsgAnalyser* Analyse();
+    bool DoAction();
+};
+
+#endif
diff --git a/server/src/game/decoder/udp_itemmove.cpp b/server/src/game/decoder/udp_itemmove.cpp
new file mode 100644 (file)
index 0000000..1720743
--- /dev/null
@@ -0,0 +1,302 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+ udp_itemmove.cpp - decoder classes for UDP item move related messages\r
+\r
+ CREATION: 30 Dec 2006 Namikon\r
+\r
+ MODIFIED: 28 Aug 2007 Hammag\r
+ REASON: Moved decoding part from DoAction() to Analyse(), use natural decode methods\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "udp_itemmove.h"\r
+#include "chars.h"\r
+#include "inventory.h"\r
+#include "container.h"\r
+\r
+/**** PUdpItemMove ****/\r
+\r
+#define PUdpItemMove_NO_BOX_TAKE_ALL\r
+\r
+PUdpItemMove::PUdpItemMove( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x1e";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpItemMove::Analyse()\r
+{\r
+  mDecodeData->mName << "=Moving item";\r
+\r
+  PMessage* nMsg = mDecodeData->mMessage;\r
+  nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 8 );\r
+\r
+  *nMsg >> mSrcLoc;\r
+  *nMsg >> mSrcX;\r
+  *nMsg >> mSrcY;\r
+  *nMsg >> mDstLoc;\r
+  *nMsg >> mDstX;\r
+  *nMsg >> mDstY;\r
+  *nMsg >> mItemCnt;\r
+\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+  return this;\r
+}\r
+\r
+bool PUdpItemMove::DoAction()\r
+{\r
+//mDecodeData->mTraceDump = true;\r
+  PMessage* tmpMsg;\r
+  bool MoveSucceded = false;\r
+  PClient* nClient = mDecodeData->mClient;\r
+  PChar* tChar = nClient->GetChar();\r
+  u8 origDstX = mDstX;\r
+  u8 origDstY = mDstY;\r
+  PContainerEntry* tEntry;\r
+\r
+  PItem* tItem = NULL;\r
+\r
+  PContainer* SrcContainer = GetContainerByLoc( tChar, mSrcLoc );\r
+  if ( SrcContainer )\r
+  {\r
+    tEntry = SrcContainer->GetEntry( mSrcX );\r
+    tItem = SrcContainer->GetItem( mSrcX );\r
+    if ( mSrcLoc != mDstLoc )\r
+    {\r
+      PContainer* DstContainer = GetContainerByLoc( tChar, mDstLoc );\r
+      if ( mSrcY )\r
+        Console->Print( "%s PUdpItemMove: intramove: src Y != 0", Console->ColorText( YELLOW, BLACK, "[WARNING]" ) );\r
+#ifdef PUdpItemMove_NO_BOX_TAKE_ALL\r
+      if (( mSrcLoc != INV_LOC_BOX ) || ( mDstX != 255 ) || ( mDstY != 255 ) )\r
+      {\r
+#endif\r
+        if ( DstContainer )\r
+        {\r
+          //PContainerEntry* tEntry = SrcContainer->GetEntry(mSrcX);\r
+          MoveSucceded = SrcContainer->MoveItem( mSrcX, mItemCnt, DstContainer, mDstX, mDstX, mDstY );\r
+          /*if(tEntry)\r
+            tEntry->Get2DPos(&mDstX, &mDstY);*/\r
+        }\r
+#ifdef PUdpItemMove_NO_BOX_TAKE_ALL\r
+      }\r
+#endif\r
+    }\r
+    else\r
+    {\r
+      if ( mSrcY || mDstY )\r
+        Console->Print( "%s PUdpItemMove: intramove: src Y or dst Y != 0", Console->ColorText( YELLOW, BLACK, "[WARNING]" ) );\r
+      MoveSucceded = SrcContainer->MoveItem( mSrcX, mItemCnt, mDstX );\r
+    }\r
+  }\r
+\r
+  if ( MoveSucceded )\r
+  {\r
+    if (( mDstX == 255 ) && ( mDstY == 255 ) && ( mSrcLoc == INV_LOC_BOX ) )\r
+    {\r
+      tmpMsg = MsgBuilder->BuildUndefineduseMsg( nClient, 0x2c );\r
+      nClient->SendUDPMessage( tmpMsg );\r
+      tmpMsg = MsgBuilder->BuildBoxItemMoveMsg( nClient, tEntry, mSrcX, mSrcY, mDstLoc, mDstX, mDstY, mItemCnt );\r
+    }\r
+    else\r
+    {\r
+      tmpMsg = MsgBuilder->BuildItemMoveMsg( nClient, mSrcLoc, mSrcX, mSrcY, mDstLoc, mDstX, mDstY, mItemCnt );\r
+    }\r
+    nClient->SendUDPMessage( tmpMsg );\r
+\r
+    if ( gDevDebug )\r
+      Console->Print( "%s Success : Item move %u:%u-%u => %u:%u-%u : %u %s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mSrcLoc, mSrcX, mSrcY, mDstLoc, origDstX, origDstY, mItemCnt, tItem ? tItem->GetName().c_str() : "" );\r
+    /*Console->Print(YELLOW, BLACK, "--- Worn Inventory ---");\r
+    tChar->GetInventory()->GetContainer(INV_LOC_WORN)->Dump();\r
+    Console->Print(YELLOW, BLACK, "--- Backpack Inventory ---");\r
+    tChar->GetInventory()->GetContainer(INV_LOC_BACKPACK)->Dump();\r
+    Console->Print(YELLOW, BLACK, "--- Gogo Inventory ---");\r
+    tChar->GetInventory()->GetContainer(INV_LOC_GOGO)->Dump();\r
+    if (tChar->GetInventory()->IsDirty())\r
+      Console->Print(YELLOW, BLACK, "Inventory DIRTY"); */\r
+\r
+// => TO CHECK: deactivate item in-hand if active slot now emtpy ???\r
+  }\r
+  else\r
+  {\r
+#ifdef PUdpItemMove_NO_BOX_TAKE_ALL\r
+    if (( mSrcLoc != INV_LOC_BOX ) || ( mDstX != 255 ) || ( mDstY != 255 ) )\r
+    {\r
+#endif\r
+      if ( mDstLoc == INV_LOC_GROUND )\r
+        Chat->send( nClient, CHAT_DIRECT, "System", "Can't throw items to the ground yet." );\r
+      else\r
+        Console->Print( "%s Item move failed %u:%u-%u => %u:%u-%u : %u %s", Console->ColorText( YELLOW, BLACK, "[WARNING]" ), mSrcLoc, mSrcX, mSrcY, mDstLoc, origDstX, origDstY, mItemCnt, tItem ? tItem->GetName().c_str() : "" );\r
+      // Send 'null move'\r
+      //tmpMsg = MsgBuilder->BuildItemMoveMsg(nClient, mSrcLoc, mSrcX, mSrcY, mSrcLoc, mSrcX, mSrcY, mItemCnt);\r
+      //nClient->SendUDPMessage(tmpMsg);\r
+#ifdef PUdpItemMove_NO_BOX_TAKE_ALL\r
+    }\r
+    else\r
+    {\r
+      Chat->send( nClient, CHAT_DIRECT, "System", "'TAKE ALL' can't be used yet." );\r
+    }\r
+#endif\r
+  }\r
+\r
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  return true;\r
+}\r
+\r
+PContainer* PUdpItemMove::GetContainerByLoc( PChar* nChar, u8 nLoc )\r
+{\r
+  PContainer* tContainer = NULL;\r
+\r
+  switch ( nLoc )\r
+  {\r
+    case INV_LOC_WORN:\r
+    case INV_LOC_BACKPACK:\r
+    case INV_LOC_GOGO:\r
+      {\r
+        tContainer = nChar->GetInventory()->GetContainer( nLoc );\r
+        break;\r
+      }\r
+\r
+    case INV_LOC_BOX:\r
+      {\r
+        tContainer = nChar->GetContainerInExclusiveUse();\r
+        break;\r
+      }\r
+    case INV_LOC_GROUND:\r
+    case INV_LOC_NPCTRADE:\r
+    default:\r
+      break;\r
+  }\r
+\r
+  return tContainer;\r
+}\r
+\r
+\r
+/**** PUdpItemMoveBP ****/\r
+\r
+PUdpItemMoveBP::PUdpItemMoveBP( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x14";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpItemMoveBP::Analyse()\r
+{\r
+  mDecodeData->mName << "=Moving item";\r
+\r
+  PMessage* nMsg = mDecodeData->mMessage;\r
+  nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 9 );\r
+\r
+  *nMsg >> mSrcSlotId;\r
+  *nMsg >> mDumb;\r
+  *nMsg >> mDstX;\r
+  *nMsg >> mDstY;\r
+\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+  return this;\r
+}\r
+\r
+bool PUdpItemMoveBP::DoAction()\r
+{\r
+//mDecodeData->mTraceDump = true;\r
+//  PMessage* tmpMsg;\r
+  bool MoveSucceded = false;\r
+  PClient* nClient = mDecodeData->mClient;\r
+  PChar* tChar = nClient->GetChar();\r
+\r
+  PContainer2DWorkaround* SrcContainer = tChar->GetInventory()->GetBackpackContainer();\r
+  if ( SrcContainer )\r
+  {\r
+    if ( mDumb )\r
+      Console->Print( "%s PUdpItemMoveBP: Dumb != 0 (%d)", Console->ColorText( YELLOW, BLACK, "[WARNING]" ), mDumb );\r
+    if ( gDevDebug )\r
+      Console->Print( "%s PUdpItemMoveBP: Tyring Item move: slot %u => %u-%u", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mSrcSlotId, mDstX, mDstY );\r
+    PContainerEntry* tEntry = SrcContainer->GetEntry( mSrcSlotId );\r
+    if ( tEntry )\r
+    {\r
+      SrcContainer->SetUsed( tEntry, false );\r
+      SrcContainer->SetEntryPosXY( tEntry, mSrcSlotId, mDstX, mDstY );\r
+      SrcContainer->SetUsed( tEntry );\r
+      SrcContainer->SetDirty();\r
+      MoveSucceded = true;\r
+    }\r
+    else\r
+      Console->Print( "%s PUdpItemMoveBP: trying to use invalid slot %d", Console->ColorText( RED, BLACK, "[WARNING]" ), mSrcSlotId );\r
+  }\r
+  else\r
+  {\r
+    Console->Print( "%s trying to use invalid Backpack container", Console->ColorText( RED, BLACK, "[WARNING]" ) );\r
+  }\r
+//Console->Print(YELLOW, BLACK, "--- Backpack Inventory ---");\r
+//SrcContainer->Dump();\r
+\r
+// No answer to confirm ?\r
+//tmpMsg = NULL;\r
+\r
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  return true;\r
+}\r
+\r
+/**** PUdpItemDropOnItem ****/\r
+\r
+PUdpItemDropOnItem::PUdpItemDropOnItem( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x17";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpItemDropOnItem::Analyse()\r
+{\r
+  mDecodeData->mName << "=Dropping item on item";\r
+\r
+  PMessage* nMsg = mDecodeData->mMessage;\r
+  nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 9 );\r
+\r
+  *nMsg >> mSrcLoc;\r
+  *nMsg >> mSrcX; // Linear Idx\r
+  *nMsg >> mSrcY; // 0\r
+  *nMsg >> mDstLoc;\r
+  *nMsg >> mDstX; // Linear Idx\r
+  *nMsg >> mDstY; // 0\r
+\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+  return this;\r
+}\r
+\r
+bool PUdpItemDropOnItem::DoAction()\r
+{\r
+  PClient* nClient = mDecodeData->mClient;\r
+  PChar* tChar = nClient->GetChar();\r
+  if ( gDevDebug )\r
+    Console->Print( "%s PUdpItemDropOnItem: %u:%u-%u => %u:%u-%u", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mSrcLoc, mSrcX, mSrcY, mDstLoc, mDstX, mDstY );\r
+  PContainer* SrcContainer = PUdpItemMove::GetContainerByLoc( tChar, mSrcLoc );\r
+  PContainer* DstContainer = PUdpItemMove::GetContainerByLoc( tChar, mDstLoc );\r
+  if ( SrcContainer && DstContainer )\r
+  {\r
+    PItem* sItem = SrcContainer->GetItem( mSrcX );\r
+    PItem* dItem = DstContainer->GetItem( mDstX );\r
+\r
+    if ( gDevDebug )\r
+      Console->Print( "%s Drop item %s on %s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), sItem ? sItem->GetName().c_str() : "???", dItem ? dItem->GetName().c_str() : "???" );\r
+  }\r
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  return true;\r
+}\r
diff --git a/server/src/game/decoder/udp_itemmove.h b/server/src/game/decoder/udp_itemmove.h
new file mode 100644 (file)
index 0000000..334d6c7
--- /dev/null
@@ -0,0 +1,88 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+ udp_itemmove.h - decoder classes for UDP item move related messages\r
+\r
+ CREATION: 30 Dec 2006 Namikon\r
+\r
+ MODIFIED:\r
+ REASON: -\r
+\r
+*/\r
+\r
+#ifndef UDPITEMMOVE_H\r
+#define UDPITEMMOVE_H\r
+\r
+class PUdpItemMove : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u8 mSrcLoc;\r
+    u8 mSrcX;\r
+    u8 mSrcY;\r
+    u8 mDstLoc;\r
+    u8 mDstX;\r
+    u8 mDstY;\r
+    u8 mItemCnt;\r
+\r
+  public:\r
+      PUdpItemMove(PMsgDecodeData* nDecodeData);\r
+      //~PUdpItemMove();\r
+      PUdpMsgAnalyser* Analyse();\r
+      bool DoAction();\r
+\r
+         static PContainer* GetContainerByLoc(PChar* nChar, u8 nLoc);\r
+};\r
+\r
+class PUdpItemMoveBP : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u8 mSrcSlotId;\r
+    u8 mDumb;\r
+    u8 mDstX;\r
+    u8 mDstY;\r
+    \r
+  public:\r
+      PUdpItemMoveBP(PMsgDecodeData* nDecodeData);\r
+      //~PUdpItemMove();\r
+      PUdpMsgAnalyser* Analyse();\r
+      bool DoAction();\r
+};\r
+\r
+class PUdpItemDropOnItem : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u8 mSrcLoc;\r
+    u8 mSrcX;\r
+    u8 mSrcY;\r
+    u8 mDstLoc;\r
+    u8 mDstX;\r
+    u8 mDstY;\r
+\r
+  public:\r
+       PUdpItemDropOnItem(PMsgDecodeData* nDecodeData);\r
+       //~PUdpItemDropOnItem();\r
+       PUdpMsgAnalyser* Analyse();\r
+       bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_itemuse.cpp b/server/src/game/decoder/udp_itemuse.cpp
new file mode 100644 (file)
index 0000000..4f7eed9
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_itemuse.cpp - decoder classes for UDP inventory item use messages
+
+ CREATION: 9 May 2009 Hammag
+
+ MODIFIED:
+ REASON: -
+
+*/
+
+#include "main.h"
+#include "udp_itemuse.h"
+
+
+/**** PUdpItemUse ****/
+
+PUdpItemUse::PUdpItemUse( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x01";
+}
+
+PUdpMsgAnalyser* PUdpItemUse::Analyse()
+{
+  mDecodeData->mName << "=Inventory item use";
+/*
+  PMessage* nMsg = mDecodeData->mMessage;
+  nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 8 );
+
+  ( *nMsg ) >> mWeaponId;
+  ( *nMsg ) >> mTargetRawItemID; // !!! 0x000003fe when shooting with no target
+  ( *nMsg ) >> mUnknown2; // aiming ??? 0 to 52 +?
+  ( *nMsg ) >> mTargetedHeight; // range 0 (bottom) to 26 (?) (top)
+  ( *nMsg ) >> mScore; // range 0x00 to 0xff  Score ???
+*/
+
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  return this;
+}
+
+bool PUdpItemUse::DoAction()
+{
+  //PClient* nClient = mDecodeData->mClient;
+  //PChar* tChar = nClient->GetChar();
+
+  //PMessage* tmpMsg = MsgBuilder->BuildHeldItemUsedMsg( nClient->GetLocalID(), mWeaponId, mTargetRawItemID, mUnknown2, mTargetedHeight, 0 ); // 'score' is not broadcasted, but set to 0
+  //ClientManager->UDPBroadcast( tmpMsg, nClient );
+
+  //if ( gDevDebug )
+  {
+    Console->Print( "%s Using inventory item", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+    mDecodeData->mMessage->Dump();
+  }
+
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
diff --git a/server/src/game/decoder/udp_itemuse.h b/server/src/game/decoder/udp_itemuse.h
new file mode 100644 (file)
index 0000000..9b2d7e0
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_itemuse.h - decoder classes for UDP inventory item use messages
+
+ CREATION: 9 May 2009 Hammag
+
+ MODIFIED:
+ REASON: -
+
+*/
+
+#ifndef ITEMUSE_H
+#define ITEMUSE_H
+
+class PUdpItemUse : public PUdpMsgAnalyser
+{
+/*  private:
+    u16 mWeaponId;
+    u32 mTargetRawItemID;
+    u8 mUnknown2;
+    u8 mTargetedHeight;
+    u8 mScore; // ??? looks quite random...
+*/
+  public:
+    PUdpItemUse( PMsgDecodeData* nDecodeData );
+    //~PUdpItemUse();
+    PUdpMsgAnalyser* Analyse();
+    bool DoAction();
+};
+
+#endif
diff --git a/server/src/game/decoder/udp_killself.cpp b/server/src/game/decoder/udp_killself.cpp
new file mode 100644 (file)
index 0000000..441b53d
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_killself.cpp - decoder classe for UDP /set kill_self 1 messages
+
+ CREATION: 13 Apr 2009 Hammag
+
+*/
+
+
+#include "main.h"
+#include "udp_killself.h"
+
+PUdpKillSelf::PUdpKillSelf( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x10";
+}
+
+PUdpMsgAnalyser* PUdpKillSelf::Analyse()
+{
+  mDecodeData->mName << "=Char Kill self";
+
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  return this;
+}
+
+bool PUdpKillSelf::DoAction()
+{
+  PClient* nClient = mDecodeData->mClient;
+
+  PMessage* tmpMsg = MsgBuilder->BuildCharDeathMsg( nClient, 0 );
+  ClientManager->UDPBroadcast( tmpMsg, nClient );
+
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+
+  /* Server resp:
+  13:a8:00:a8:e2:
+  16: 03:a5:00:1b:01:10:00:80:24:ea:7c:cb:80:25:77:80:86:80:62:00:01:00: // Spwan belt object (?)
+  09: 03:a6:00:1f:01:00:25:23:1c: // "UndefinedUseMsg" with arg 0x1c
+  0b: 03:a7:00:1f:01:00:16:00:00:00:00: // Char Dead status
+  0e: 03:a8:00:1f:01:00:25:13:10:19:02:02:0d:00 // Inventory delete item (=item dropped to belt)
+  */
+}
diff --git a/server/src/game/decoder/udp_killself.h b/server/src/game/decoder/udp_killself.h
new file mode 100644 (file)
index 0000000..19ddf47
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_killself.h - decoder classe for UDP /set kill_self 1 messages
+
+ CREATION: 13 Apr 2009 Hammag
+
+*/
+
+#ifndef UDPKILLSELF_H
+#define UDPKILLSELF_H
+
+class PUdpKillSelf : public PUdpMsgAnalyser
+{
+    public:
+        PUdpKillSelf(PMsgDecodeData* nDecodeData);
+        //~PUdpKillSelf();
+        PUdpMsgAnalyser* Analyse();
+        bool DoAction();
+};
+
+#endif
diff --git a/server/src/game/decoder/udp_multipart.cpp b/server/src/game/decoder/udp_multipart.cpp
new file mode 100644 (file)
index 0000000..be79334
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_multipart.cpp - decoder classes for UDP multipart messages (0x07)
+
+ CREATION: 25 Oct 2009 Namikon
+
+ MODIFIED:
+ REASON: -
+
+*/
+
+#include "main.h"
+#include "udp_multipart.h"
+
+/**** PUdpMultiPart ****/
+
+PUdpMultiPart::PUdpMultiPart( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x07";
+}
+
+PUdpMsgAnalyser* PUdpMultiPart::Analyse()
+{
+    mDecodeData->mName << "=Multipart Message";
+
+    PMessage* TmpMsg = mDecodeData->mMessage;
+
+    u8 tChunkSize = 0;
+
+    ( *TmpMsg ) >> tChunkSize;
+    TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 5 );
+    ( *TmpMsg ) >> mChunkNr;
+    ( *TmpMsg ) >> mChunkTotal;
+    ( *TmpMsg ) >> mSequence;
+
+    tChunkSize -= 9;
+    int tCurPos = mDecodeData->Sub0x13Start + 10;
+
+    mChunk = new PMessage(tChunkSize);
+    mChunk = TmpMsg->GetChunk(tCurPos, tChunkSize);
+
+    //if (gDevDebug) Console->Print("Received MULTIPART fragment. ChunkNr: %d of %d, SequenceNr: %d ChunkSize: %d", mChunkNr, mChunkTotal, mSequence, mChunk->GetSize());
+    //if (gDevDebug) mChunk->Dump();
+
+    mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+    return this;
+}
+
+bool PUdpMultiPart::DoAction()
+{
+    if ( mDecodeData->mState & DECODE_ACTION_READY )
+    {
+        MultiPartHandler->AddMultiPartChunk(mDecodeData->mClient, mChunk, mChunkNr, mChunkTotal, mSequence);
+        return true;
+    }
+    else
+        return false;
+}
diff --git a/server/src/game/decoder/udp_multipart.h b/server/src/game/decoder/udp_multipart.h
new file mode 100644 (file)
index 0000000..e338158
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_multipart.h - decoder classes for UDP multipart messages (0x07)
+
+ CREATION: 25 Oct 2009 Namikon
+
+ MODIFIED:
+ REASON: -
+
+*/
+
+#ifndef UDPMULTIPART_H
+#define UDPMULTIPART_H
+
+class PUdpMultiPart : public PUdpMsgAnalyser
+{
+  private:
+    u16 mChunkNr;
+    u16 mChunkTotal;
+    u8 mSequence;
+    PMessage* mChunk;
+
+  public:
+    PUdpMultiPart( PMsgDecodeData* nDecodeData );
+    //~PUdpPing();
+    PUdpMsgAnalyser* Analyse();
+    bool DoAction();
+};
+
+#endif
diff --git a/server/src/game/decoder/udp_npcdialog.cpp b/server/src/game/decoder/udp_npcdialog.cpp
new file mode 100644 (file)
index 0000000..c76c655
--- /dev/null
@@ -0,0 +1,138 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+ udp_npcdialog.cpp - decoder classes for UDP NPC Dialog-Messages\r
+\r
+ CREATION: 13 Oct 2009 Namikon\r
+\r
+ MODIFIED:\r
+ REASON: -\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "udp_npcdialog.h"\r
+\r
+/**** PUdpNPCDialogClose ****/\r
+\r
+PUdpNPCDialogClose::PUdpNPCDialogClose( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+    nDecodeData->mName << "/0x19";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpNPCDialogClose::Analyse()\r
+{\r
+    mDecodeData->mName << "=NPC Dialog closed";\r
+\r
+    mPlayerID = mDecodeData->mMessage->U16Data( mDecodeData->Sub0x13Start + 5 );\r
+    mNPCID = mDecodeData->mMessage->U32Data( mDecodeData->Sub0x13Start + 8 );\r
+\r
+    mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+    return this;\r
+}\r
+\r
+bool PUdpNPCDialogClose::DoAction()\r
+{\r
+    if ( mDecodeData->mState & DECODE_ACTION_READY )\r
+    {\r
+        if (gDevDebug)\r
+            Console->Print( "%s PUdpNPCDialogClose: Client %d closed dialog with NPC %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mPlayerID, mNPCID );\r
+\r
+        // Set DialogNPC for player to 0\r
+        mDecodeData->mClient->GetChar()->SetDialogNPC(0);\r
+        if (gDevDebug) Console->Print("[DEBUG PUdpNPCDialogClose::DoAction] New DialogPartner for Client %d is now %u", mPlayerID, mDecodeData->mClient->GetChar()->GetDialogNPC());\r
+\r
+        mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+        return true;\r
+    }\r
+    else\r
+        return false;\r
+}\r
+/**** PUdpNPCDialogAction ****/\r
+\r
+PUdpNPCDialogAction::PUdpNPCDialogAction( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+    nDecodeData->mName << "/0x1a";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpNPCDialogAction::Analyse()\r
+{\r
+    mDecodeData->mName << "=NPC Dialog action";\r
+\r
+    mPlayerID = mDecodeData->mMessage->U16Data( mDecodeData->Sub0x13Start + 5 );\r
+    mAnswerNr = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 8 );\r
+\r
+    mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+    return this;\r
+}\r
+\r
+bool PUdpNPCDialogAction::DoAction()\r
+{\r
+    if ( mDecodeData->mState & DECODE_ACTION_READY )\r
+    {\r
+        if (gDevDebug)\r
+            Console->Print( "%s PUdpNPCDialogAction: Client %d selected dialog answer %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mPlayerID, mAnswerNr );\r
+\r
+        PClient* nClient = mDecodeData->mClient;\r
+        PChar* tChar = nClient->GetChar();\r
+        bool tSuccess = false;\r
+\r
+        // First check if client has an NPC to talk to set (just to be sure)\r
+        if (tChar->GetDialogNPC() != 0)\r
+        {\r
+            // Player has an NPC to talk to. Next, get the NPC instance\r
+            PNPC* targetNPC = 0;\r
+            PNPCWorld* currentNPCWorld = NPCManager->GetWorld( tChar->GetLocation() );\r
+            if ( currentNPCWorld )\r
+            {\r
+                //Console->Print(">>> Searching NPC");\r
+                targetNPC = currentNPCWorld->GetNPC( tChar->GetDialogNPC() );\r
+                if ( targetNPC )\r
+                {\r
+                    Console->Print( "%s Player talks to NPC %u, answer %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), tChar->GetDialogNPC(), mAnswerNr );\r
+                    // Continue conversation with given answer. Current node is stored in tChar* class, and NPC handles next steps\r
+                    // also sends out the required packet\r
+                    targetNPC->DoConversation(nClient, mAnswerNr);\r
+                    tSuccess = true;\r
+                }\r
+            }\r
+        }\r
+        else\r
+        {\r
+            Console->Print( "%s Dialog request received, but player has no active NPC dialog set, dropping", Console->ColorText( RED, BLACK, "[ERROR]" ));\r
+            tSuccess = true;\r
+        }\r
+        if(tSuccess == false)\r
+        {\r
+            Console->Print( "%s Player talks to NPC %u, but npc isnt active anymore. Resetting dialog state for client", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), tChar->GetDialogNPC() );\r
+            tChar->SetDialogNode(0);\r
+            tChar->SetDialogNPC(0);\r
+        }\r
+\r
+        mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+        return true;\r
+    }\r
+    else\r
+        return false;\r
+}\r
+\r
diff --git a/server/src/game/decoder/udp_npcdialog.h b/server/src/game/decoder/udp_npcdialog.h
new file mode 100644 (file)
index 0000000..40e68db
--- /dev/null
@@ -0,0 +1,62 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+ udp_npcdialog.h - decoder classes for UDP NPC Dialog-Messages\r
+\r
+ CREATION: 13 Oct 2009 Namikon\r
+\r
+ MODIFIED:\r
+ REASON: -\r
+\r
+*/\r
+\r
+#ifndef UDPNPCDIALOG_H\r
+#define UDPNPCDIALOG_H\r
+\r
+class PUdpNPCDialogClose : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u16 mPlayerID;\r
+    u32 mNPCID;\r
+\r
+  public:\r
+    PUdpNPCDialogClose( PMsgDecodeData* nDecodeData );\r
+    //~PUdpNPCDialogClose();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpNPCDialogAction : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u16 mPlayerID;\r
+    u8 mAnswerNr;\r
+\r
+  public:\r
+    PUdpNPCDialogAction( PMsgDecodeData* nDecodeData );\r
+    //~PUdpNPCDialogAction();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_outfitter.cpp b/server/src/game/decoder/udp_outfitter.cpp
new file mode 100644 (file)
index 0000000..c414e49
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_outfitter.cpp - decoder classes for UDP outfitter related messages
+
+ CREATION: 20 Mar 2009 Hammag
+
+ MODIFIED:
+ REASON: -
+
+*/
+
+#include "main.h"
+#include "udp_outfitter.h"
+
+
+/**** PUdpOutfitter ****/
+
+PUdpOutfitter::PUdpOutfitter(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+    nDecodeData->mName << "/0x2e";
+}
+
+PUdpMsgAnalyser* PUdpOutfitter::Analyse()
+{
+    mDecodeData->mName << "=Outfitter validation";
+
+       u16 tUnknown;
+       PMessage* nMsg = mDecodeData->mMessage;
+       nMsg->SetNextByteOffset(mDecodeData->Sub0x13Start + 8);
+
+       (*nMsg) >> mSkin;
+       (*nMsg) >> tUnknown;
+       (*nMsg) >> mHead;
+       (*nMsg) >> mTorso;
+       (*nMsg) >> mLegs;
+       (*nMsg) >> mHeadColor;
+       (*nMsg) >> mTorsoColor;
+       (*nMsg) >> mLegsColor;
+       (*nMsg) >> mHeadDarkness;
+       (*nMsg) >> mTorsoDarkness;
+       (*nMsg) >> mLegsDarkness;
+
+    mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+    return this;
+}
+
+bool PUdpOutfitter::DoAction()
+{
+       PClient* nClient = mDecodeData->mClient;
+    PChar* tChar = nClient->GetChar();
+       
+       /* Some validity checks against char model and equipment can be done here */
+       /* as well as payment */
+
+       tChar->SetCurrentLook(mSkin, mHead, mTorso, mLegs);
+       tChar->SetCurrentBodyColor(mHeadColor, mTorsoColor, mLegsColor, mHeadDarkness, mTorsoDarkness, mLegsDarkness);
+
+    PMessage* tmpMsg = MsgBuilder->BuildCharHelloMsg(nClient);
+    ClientManager->UDPBroadcast(tmpMsg, nClient);
+       
+
+    mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+    return true;
+}
\ No newline at end of file
diff --git a/server/src/game/decoder/udp_outfitter.h b/server/src/game/decoder/udp_outfitter.h
new file mode 100644 (file)
index 0000000..b6c72e2
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_outfitter.h - decoder classes for UDP outfitter related messages
+
+ CREATION: 20 Mar 2009 Hammag
+
+ MODIFIED:
+ REASON: -
+
+*/
+
+#ifndef UDPOUTFITTER_H
+#define UDPOUTFITTER_H
+
+class PUdpOutfitter : public PUdpMsgAnalyser
+{
+       private:
+               u32 mSkin;
+               u8 mHead;
+               u8 mTorso;
+               u8 mLegs;
+               u8 mHeadColor;
+               u8 mTorsoColor;
+               u8 mLegsColor;
+               u8 mHeadDarkness;
+               u8 mTorsoDarkness;
+               u8 mLegsDarkness;
+
+    public:
+        PUdpOutfitter(PMsgDecodeData* nDecodeData);
+        //~PUdpOutfitter();
+        PUdpMsgAnalyser* Analyse();
+        bool DoAction();
+};
+
+#endif
diff --git a/server/src/game/decoder/udp_packet0.cpp b/server/src/game/decoder/udp_packet0.cpp
new file mode 100644 (file)
index 0000000..f8c3b76
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+/*
+
+       udp_packet0.h - decoder classes for UDP "Packet0" messages
+  
+       CREATION: 31 Aug 2006 Hammag
+
+       MODIFIED:
+       REASON: - 
+
+*/
+
+#include "main.h"
+#include "udp_packet0.h"
+
+/**** PUdpPacket0 ****/
+
+PUdpPacket0::PUdpPacket0(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+  nDecodeData->mName << "/0x2a";
+//nDecodeData->mTraceDump=true;
+//mDecodeData->mTraceKnownMsg = true;
+} 
+
+PUdpMsgAnalyser* PUdpPacket0::Analyse()
+{
+  mDecodeData->mName << "=Packet0";
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  
+  return this;
+}
+
+bool PUdpPacket0::DoAction()
+{
+  if (mDecodeData->mState & DECODE_ACTION_READY)
+  {
+    PMessage* tmpMsg = MsgBuilder->BuildPacket0Msg(mDecodeData->mClient);
+    mDecodeData->mClient->SendUDPMessage(tmpMsg);
+
+    //mDecodeData->mMessage->SetNextByteOffset(mDecodeData->Sub0x13StartNext);    
+    mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+    return true;
+  }
+  else
+    return false; 
+}
diff --git a/server/src/game/decoder/udp_packet0.h b/server/src/game/decoder/udp_packet0.h
new file mode 100644 (file)
index 0000000..cde160f
--- /dev/null
@@ -0,0 +1,45 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_packet0.h - decoder classes for UDP "Packet0" messages\r
+  \r
+       CREATION: 31 Aug 2006 Hammag\r
+\r
+       MODIFIED:\r
+       REASON: - \r
+\r
+*/\r
+\r
+#ifndef UDPPACKET0_H\r
+#define UDPPACKET0_H\r
+\r
+class PUdpPacket0 : public PUdpMsgAnalyser\r
+{ \r
+  public:\r
+    PUdpPacket0(PMsgDecodeData* nDecodeData);\r
+    //~PUdpPacket0();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_ping.cpp b/server/src/game/decoder/udp_ping.cpp
new file mode 100644 (file)
index 0000000..0cbd470
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_ping.cpp - decoder classes for UDP Ping messages
+
+ CREATION: 31 Aug 2006 Hammag
+
+ MODIFIED:
+ REASON: -
+
+*/
+
+#include "main.h"
+#include "udp_ping.h"
+
+/**** PUdpPing ****/
+
+PUdpPing::PUdpPing( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x0b";
+}
+
+PUdpMsgAnalyser* PUdpPing::Analyse()
+{
+  mDecodeData->mName << "=Ping";
+
+  mClientTime = mDecodeData->mMessage->U32Data( mDecodeData->Sub0x13Start + 2 );
+
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  return this;
+}
+
+bool PUdpPing::DoAction()
+{
+  if ( mDecodeData->mState & DECODE_ACTION_READY )
+  {
+   // if(gDevDebug)
+    //  Console->Print( "%s PUdpPing: Client timestamp %d (0x%08x)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mClientTime, mClientTime );
+
+    PMessage* tmpMsg = MsgBuilder->BuildPingMsg( mDecodeData->mClient, mClientTime );
+    mDecodeData->mClient->SendUDPMessage( tmpMsg );
+
+    mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+    return true;
+  }
+  else
+    return false;
+}
diff --git a/server/src/game/decoder/udp_ping.h b/server/src/game/decoder/udp_ping.h
new file mode 100644 (file)
index 0000000..b8d6dca
--- /dev/null
@@ -0,0 +1,48 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+ udp_ping.h - decoder classes for UDP Ping messages\r
+\r
+ CREATION: 31 Aug 2006 Hammag\r
+\r
+ MODIFIED:\r
+ REASON: -\r
+\r
+*/\r
+\r
+#ifndef UDPPING_H\r
+#define UDPPING_H\r
+\r
+class PUdpPing : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u32 mClientTime;\r
+\r
+  public:\r
+    PUdpPing( PMsgDecodeData* nDecodeData );\r
+\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_popupresponse.cpp b/server/src/game/decoder/udp_popupresponse.cpp
new file mode 100755 (executable)
index 0000000..b4b6c8a
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_popupresponse.cpp - decoder classes for some UDP Popup response messages
+
+ CREATION: 14 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "udp_popupresponse.h"
+#include "vhcaccessrequest.h"
+#include "worlds.h"
+#include "udp_vhc.h"
+
+
+/**** PUdp0x1f ****/
+
+PUdpPopupResponse::PUdpPopupResponse( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x09";
+}
+
+PUdpMsgAnalyser* PUdpPopupResponse::Analyse()
+{
+  PUdpMsgAnalyser* nextAnalyser = NULL;
+  mDecodeData->mState = DECODE_MORE;
+  u8 MsgType = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 12 ); //u32 but only u8 used
+
+  switch ( MsgType )
+  {
+    case 0x06:
+    {
+      nextAnalyser = new PUdpVhcAccessResponse( mDecodeData );
+      break;
+    }
+    case 0x07:
+    {
+      nextAnalyser = new PUdpVentureWarpConfirm( mDecodeData );
+      break;
+    }
+    default:
+    {
+      mDecodeData->mUnknownType = MsgType;
+      mDecodeData->mTraceUnknownMsg = true;
+      break;
+    }
+  }
+
+  if ( ! nextAnalyser )
+  {
+    nextAnalyser = new PUdpMsgUnknown( mDecodeData );
+  }
+
+  return nextAnalyser;
+}
+
+/**** PUdpVentureWarpConfirm ****/
+
+PUdpVentureWarpConfirm::PUdpVentureWarpConfirm( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x05";
+}
+
+PUdpMsgAnalyser* PUdpVentureWarpConfirm::Analyse()
+{
+  mDecodeData->mName << "=Venture Warp confirmation";
+
+  PMessage* cMsg = mDecodeData->mMessage;
+  cMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 16 );
+  ( *cMsg ) >> mUnknown1;
+  ( *cMsg ) >> mUnknown2;
+  ( *cMsg ) >> mRawItemId;
+  ( *cMsg ) >> mStatus;
+  //cMsg->Dump();
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  return this;
+}
+
+bool PUdpVentureWarpConfirm::DoAction()
+{
+  PClient* nClient = mDecodeData->mClient;
+
+  if ( mStatus == 1 )
+  {
+    u32 newLocation;
+    do
+    {
+      newLocation = Worlds->GetWorldIdFromWorldmap( GetRandom( PWorlds::mOutdoorWorldmapHSize, 0 ), GetRandom( PWorlds::mOutdoorWorldmapVSize, 0 ) );
+    }
+    while ( ! newLocation );
+
+    u16 nEntity = 10;
+    u16 nEntityType = 1;
+
+    PMessage* tmpMsg = MsgBuilder->BuildAptLiftUseMsg( nClient, newLocation, nEntity, nEntityType );
+    nClient->SendUDPMessage( tmpMsg );
+
+    if ( gDevDebug )
+      Console->Print( "Client[%d]: Venture Warping to zone %d (entity %d/%d)", nClient->GetID(), newLocation, nEntity, nEntityType );
+  }
+
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
+
+
+/**** PUdpVhcAccessResponse ****/
+
+PUdpVhcAccessResponse::PUdpVhcAccessResponse( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x06";
+}
+
+PUdpMsgAnalyser* PUdpVhcAccessResponse::Analyse()
+{
+  mDecodeData->mName << "=Response to vhc access request";
+
+  PMessage* cMsg = mDecodeData->mMessage;
+  cMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 16 );
+  ( *cMsg ) >> mVhcAccessRequestId;
+  ( *cMsg ) >> mUnknown;
+  ( *cMsg ) >> mStatus;
+
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  return this;
+}
+
+bool PUdpVhcAccessResponse::DoAction()
+{
+  PClient* nClient = mDecodeData->mClient;
+  PChar* nChar = nClient->GetChar();
+  PVhcAccessRequestList* nAccessRequests = nChar->GetVhcAccessRequestList();
+
+  if ( gDevDebug )
+    Console->Print( "Access response for Req n°%d : %d (unknown %d)", mVhcAccessRequestId, mStatus, mUnknown );
+
+  if ( nAccessRequests->RegisterResponse( mVhcAccessRequestId, ( mStatus == 1 ) ) )
+  {
+    u32 requesterCharId = 0;
+    u32 vehicleId = 0;
+    nAccessRequests->GetInfo( mVhcAccessRequestId, &requesterCharId, &vehicleId );
+    PClient* requesterClient = ClientManager->getClientByChar( requesterCharId );
+    PChar* requesterChar = ( requesterClient ? requesterClient->GetChar() : NULL );
+
+    if ( requesterChar && nAccessRequests->Check( mVhcAccessRequestId ) )
+    {
+      PWorld* CurrentWorld = Worlds->GetWorld( requesterChar->GetLocation() );
+      if ( CurrentWorld )
+      {
+        PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicules()->GetVehicleByGlobalId( vehicleId );
+
+        if ( tVhc )
+        {
+          PUdpVhcUse::DoFreeSitting( requesterClient,  tVhc, tVhc->GetLocalId() );
+        }
+      }
+    }
+    else
+    {
+      PMessage* tmpMsg = MsgBuilder->BuildText100Msg( requesterClient, 20, 0 ); // "req refused" msg
+      requesterClient->SendUDPMessage( tmpMsg );
+    }
+  }
+
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
diff --git a/server/src/game/decoder/udp_popupresponse.h b/server/src/game/decoder/udp_popupresponse.h
new file mode 100755 (executable)
index 0000000..a6106b8
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_popupresponse.cpp - decoder classes for some UDP Popup response messages
+
+ CREATION: 14 Apr 2009 Hammag
+*/
+
+
+#ifndef UDPPOPUPRESP_H
+#define UDPPOPUPRESP_H
+
+class PUdpPopupResponse : public PUdpMsgAnalyser
+{
+  public:
+    PUdpPopupResponse( PMsgDecodeData* nDecodeData );
+    //~PUdpPopupResponse();
+    PUdpMsgAnalyser* Analyse();
+    //bool DoAction();
+};
+
+class PUdpVentureWarpConfirm : public PUdpMsgAnalyser
+{
+  private:
+    u32 mRawItemId;
+    u16 mStatus;
+    u32 mUnknown1;
+    u16 mUnknown2;
+  public:
+    PUdpVentureWarpConfirm( PMsgDecodeData* nDecodeData );
+    //~PUdpVentureWarpConfirm();
+    PUdpMsgAnalyser* Analyse();
+    bool DoAction();
+};
+
+class PUdpVhcAccessResponse : public PUdpMsgAnalyser
+{
+  private:
+    u32 mVhcAccessRequestId;
+    u16 mStatus;
+    u16 mUnknown;
+  public:
+    PUdpVhcAccessResponse( PMsgDecodeData* nDecodeData );
+    //~PUdpVhcAccessResponse();
+    PUdpMsgAnalyser* Analyse();
+    bool DoAction();
+};
+
+#endif
diff --git a/server/src/game/decoder/udp_pvptrade.cpp b/server/src/game/decoder/udp_pvptrade.cpp
new file mode 100644 (file)
index 0000000..bbb3554
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_pvptrade.cpp - decoder classes for UDP "Request for more information about WorldID xx"
+
+ CREATION: 20 Jun 2009 Namikon
+
+ MODIFIED: 4 Jul 2009 Hammag
+ REASON: Corrected class name
+
+*/
+
+#include "main.h"
+#include "udp_pvptrade.h"
+
+/**** PPvPTrade ****/
+
+PUdpPvPTrade::PUdpPvPTrade(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+    nDecodeData->mName << "/0x3e";
+}
+
+PUdpMsgAnalyser* PUdpPvPTrade::Analyse()
+{
+    mDecodeData->mName << "=Switch PvP Trading";
+
+    mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+    return this;
+}
+
+bool PUdpPvPTrade::DoAction()
+{
+    // TODO: Handle client PvP trade switch on/off
+    mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+    return true;
+}
diff --git a/server/src/game/decoder/udp_pvptrade.h b/server/src/game/decoder/udp_pvptrade.h
new file mode 100644 (file)
index 0000000..27f7afa
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_pvptrade.h - decoder classes for UDP "Request for more information about WorldID xx"
+
+ CREATION: 20 Jun 2009 Namikon
+
+ MODIFIED: 4 Jul 2009 Hammag
+ REASON: Corrected class name
+
+*/
+
+#ifndef UDPPVPTRADE_H
+#define UDPPVPTRADE_H
+
+class PUdpPvPTrade : public PUdpMsgAnalyser
+{
+public:
+    PUdpPvPTrade(PMsgDecodeData* nDecodeData);
+    //~PUdpPvPTrade();
+    PUdpMsgAnalyser* Analyse();
+    bool DoAction();
+};
+
+#endif
diff --git a/server/src/game/decoder/udp_quickaccessbelt.cpp b/server/src/game/decoder/udp_quickaccessbelt.cpp
new file mode 100644 (file)
index 0000000..5dda2a5
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_quickaccessbelt.cpp - decoder classes for UDP Quickaccessbelt related messages
+
+ CREATION: 30 Dec 2006 Namikon
+
+ MODIFIED: 1 Sept 2007 Hammage
+ REASON: Put analysis code in Analyse() and change to use new item management methods
+
+*/
+
+#include "main.h"
+#include "udp_quickaccessbelt.h"
+#include "container.h"
+#include "inventory.h"
+
+/**** PUdpItemSlotUse ****/
+
+PUdpItemSlotUse::PUdpItemSlotUse( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x1f";
+}
+
+PUdpMsgAnalyser* PUdpItemSlotUse::Analyse()
+{
+  mDecodeData->mName << "=Active QuickBelt Slot";
+
+  mTargetSlot = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 8 );
+  // TODO : Check on mTargetSlot value + put set to INV_WORN_QB_HAND for hand
+  if ( mTargetSlot == 255 ) // H "slot 0" Hand
+    mTargetSlot = INV_WORN_QB_HAND;
+
+  //if(mTargetSlot == 11) //  ALT-H ?
+
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  return this;
+}
+
+bool PUdpItemSlotUse::DoAction()
+{
+  PClient* nClient = mDecodeData->mClient;
+  PChar* tChar = nClient->GetChar();
+  PItem* targetItem = NULL;
+  bool tUsable = false;
+  bool tUsableInHand = false;
+  u16 nWeaponId = 0;
+
+  if( gDevDebug )
+    Console->Print( "%s Client trying to activate item in slot %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTargetSlot );
+
+  u8 currentActiveSlot = tChar->GetQuickBeltActiveSlot();
+  if ( mTargetSlot == INV_WORN_QB_HAND )
+  {
+    if( gDevDebug )
+      Console->Print( "%s Want to use Hand", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+    tUsable = true;
+    tUsableInHand = true;
+  }
+  else
+  {
+    targetItem = tChar->GetInventory()->GetContainer( INV_LOC_WORN )->GetItem( INV_WORN_QB_START + mTargetSlot );
+    if ( targetItem )
+    {
+      // TODO : do the real check;
+      if( gDevDebug )
+        Console->Print( "%s Want to use existing item", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+      tUsable = true;
+      tUsableInHand = true;
+      nWeaponId = targetItem->GetValue1();
+    }
+  }
+
+//TODO:
+// if tUsableInHand
+//  must check if weapon and allowed in zone
+//  and change tUsableInHand to false if needed
+
+  if ( tUsable && !tUsableInHand )
+  {
+    // active item in belt, but don't take in hand
+    if ( gDevDebug )
+      Console->Print( "%s activation of QB item slot %d (%s)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTargetSlot, targetItem->GetName().c_str() );
+  }
+  else
+  {
+    if ( !tUsable )
+    {
+      if ( gDevDebug )
+        Console->Print( "%s Want to use non-usable item", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+      mTargetSlot = INV_WORN_QB_NONE; // if not usable, unequip active one
+    }
+
+    if ( mTargetSlot == currentActiveSlot ) // if same as active, unequip active one
+    {
+      if ( gDevDebug )
+        Console->Print( "%s Want to use active slot", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+      mTargetSlot = INV_WORN_QB_NONE;
+    }
+
+    if ( mTargetSlot != currentActiveSlot ) // now do somthing only if not same as active
+    {
+      if ( tChar->SetQuickBeltActiveSlot( mTargetSlot ) )
+      {
+        PMessage* tmpMsg;
+        tmpMsg = MsgBuilder->BuildCharHelloMsg( nClient );
+        ClientManager->UDPBroadcast( tmpMsg, nClient );
+
+        tmpMsg = MsgBuilder->BuildUndefineduseMsg( nClient, 59 );
+        nClient->SendUDPMessage( tmpMsg );
+
+        if ( nWeaponId > 0 )
+        {
+          tmpMsg = MsgBuilder->BuildCharUseQBSlotMsg2( nClient );
+          nClient->SendUDPMessage( tmpMsg );
+        }
+        tmpMsg = MsgBuilder->BuildCharUseQBSlotMsg3( nClient, mTargetSlot );
+        nClient->SendUDPMessage( tmpMsg );
+
+        tmpMsg = MsgBuilder->BuildCharUseQBSlotMsg4( nClient, nWeaponId );
+        nClient->SendUDPMessage( tmpMsg );
+
+        if ( gDevDebug )
+          Console->Print("%s activation of QB item slot %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTargetSlot );
+      }
+      else Console->Print( "%s activation of QB slot %d refused by PChar", Console->ColorText( YELLOW, BLACK, "[WARNING]" ), mTargetSlot );
+    }
+    else
+    {
+      Console->Print( "%s Same slot %d as active - should not happen", Console->ColorText( YELLOW, BLACK, "[WARNING]" ), mTargetSlot );
+    }
+  }
+
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
diff --git a/server/src/game/decoder/udp_quickaccessbelt.h b/server/src/game/decoder/udp_quickaccessbelt.h
new file mode 100644 (file)
index 0000000..3a79c5f
--- /dev/null
@@ -0,0 +1,48 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_quickaccessbelt.h - decoder classes for UDP Quickaccessbelt related messages\r
+\r
+       CREATION: 30 Dec 2006 Namikon\r
+\r
+       MODIFIED:\r
+       REASON: -\r
+\r
+*/\r
+\r
+#ifndef UDPITEMSLOT_H\r
+#define UDPITEMSLOT_H\r
+\r
+class PUdpItemSlotUse : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u8 mTargetSlot;\r
+    \r
+  public:\r
+    PUdpItemSlotUse(PMsgDecodeData* nDecodeData);\r
+    //~PUdpItemSlotUse();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_reqinfo.cpp b/server/src/game/decoder/udp_reqinfo.cpp
new file mode 100644 (file)
index 0000000..d3cff4f
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_reqinfo.cpp - decoder classes for UDP Char/Clan/Map info request messages
+
+ CREATION: 6 Sep 2006 Hammag
+
+ MODIFIED:
+ REASON: -
+
+*/
+
+#include "main.h"
+#include "udp_reqinfo.h"
+
+/**** PUdpCharInfo ****/
+
+PUdpReqInfo::PUdpReqInfo(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+    mRequestType = 0;
+    nDecodeData->mName << "/0x06";
+}
+
+PUdpMsgAnalyser* PUdpReqInfo::Analyse()
+{
+    PMessage* tmpMsg = mDecodeData->mMessage;
+
+    mDecodeData->mName << "=Info Request";
+
+    tmpMsg->SetNextByteOffset(mDecodeData->Sub0x13Start + 7);
+    (*tmpMsg) >> mRequestType;
+    (*tmpMsg) >> mInfoId;
+
+    switch(mRequestType)
+    {
+        case 0:
+        {
+            mDecodeData->mName << "/0x00=Char Name";
+            break;
+        }
+        case 1:
+        {
+            mDecodeData->mName << "/0x01=Clan Long Name";
+            break;
+        }\r
+        case 3:\r
+        {\r
+            mDecodeData->mName << "/0x03=NPC Script";\r
+            break;\r
+        }
+        case 4:
+        {
+            mDecodeData->mName << "/0x04=Clan Short Name";
+            break;
+        }
+        case 5:
+        {
+            mDecodeData->mName << "/0x05=Clan Rank Name";
+            break;
+        }
+        case 7:
+        {
+            mDecodeData->mName << "/0x07=World Map";
+            break;
+        }
+        default:
+        {
+            mDecodeData->mUnknownType = mRequestType;
+            return new PUdpMsgUnknown(mDecodeData);
+        }
+    }
+
+    mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+    return this;
+}
+
+bool PUdpReqInfo::DoAction()
+{
+    MYSQL_RES* result = NULL;
+    MYSQL_ROW row;
+    char query[255];
+    char txtmsg[32];
+    void* Answer = NULL;
+    int len;
+
+    query[0]='\0';
+
+    switch (mRequestType)
+    {
+        case 0: //Name Request
+        //Console->Print("Client %d (char %d): Character Name Request for CharID %i", mDecodeData->mClient->GetID(), mDecodeData->mClient->GetCharID(), mInfoId);
+        snprintf (query, 255, "SELECT c_name FROM characters WHERE c_id = %i", mInfoId);
+        break;
+        case 1: //Clan Long Name
+        Console->Print("Client %d : Clan Long Name Request for ClanID %i", mDecodeData->mClient->GetID(), mInfoId);
+        snprintf (query, 255, "SELECT cl_name FROM clans WHERE cl_id = %i", mInfoId);
+        break;\r
+        case 3: // NPC Script\r
+        Console->Print("Client %d:: Requested LUA script for NPC %i", mDecodeData->mClient->GetID(), mInfoId);\r
+        snprintf (query, 255, "SELECT npc_customscript FROM npc_spawns WHERE npc_id = %i", mInfoId);\r
+        break;
+        case 4: //Clan Short name
+        Console->Print("Client %d : Clan Short Name Request for ClanID %i", mDecodeData->mClient->GetID(), mInfoId);
+        snprintf (query, 255, "SELECT cl_shortdesc FROM clans WHERE cl_id = %i", mInfoId);
+        break;
+        case 5: //Clan Rank
+        Console->Print("Client %d : Clan Rank Name Request for ClanID %i", mDecodeData->mClient->GetID(), mInfoId);
+        //snprintf (query, 255, "SELECT cll_desc FROM clanlevels INNER JOIN clans ON (cl_id = cll_clanid) WHERE cl_id = %d AND cll_level = %d", mInfoId, mClanRank);
+        snprintf(txtmsg, 32, "Undef");
+        Answer = txtmsg;
+        break;
+        case 7: //World Map
+        //Console->Print("Client %d : World Map Request", mDecodeData->mClient->GetID());
+        // Process request
+        break;
+        default:
+        Console->Print(RED, BLACK, "Client %d : Unhandled Info Request Type %i, Id %i", mDecodeData->mClient->GetID(), mRequestType, mInfoId);
+        return false;
+        break;
+    }
+
+    if (query[0])
+    {
+        result = MySQL->GameResQuery(query);
+        if(!result)
+        {
+            Console->Print(RED, BLACK, "%s Cannot get do SQL query %s ; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"), query);
+            MySQL->ShowGameSQLError();
+            snprintf(txtmsg, 32, "Error");
+            Answer = txtmsg;
+        }
+        else
+        {
+            if(mysql_num_rows(result) == 0)
+            {
+                snprintf(txtmsg, 32, "Unknown");
+                Answer = txtmsg;
+            }
+            else
+            {
+                row = mysql_fetch_row(result);
+                Answer = row[0];
+            }
+        }
+    }
+
+    if (mRequestType == 7)
+    {
+        u8 WorldMapData[] = { // Temp map for test, with Attack None/GR All security setting
+                                0xd6, 0x07, 0x05, // BT@Simmons
+                                0xfe, 0x07, 0x0b, // CM // No effect: not on OP zone
+                                0xea, 0x07, 0x03, // Next // No effect: not on OP zone
+                                0x12, 0x08, 0x0f, // TG@Gravis !!! Kick them out !!!
+                            };
+        len = sizeof(WorldMapData);
+        Answer = (void*) WorldMapData;
+    }
+    else
+    {
+        if (!Answer)
+        {
+            Console->Print(RED, BLACK, "PUdpReqInfo::DoAction() : Answer not defined !!!", Console->ColorText(RED, BLACK, "[Error]"));
+            return false;
+        }
+        len = (int)(strlen((char*)Answer)+1);
+    }
+
+    if(result)
+    {
+        MySQL->FreeGameSQLResult(result);
+    }
+\r
+    // Special case for NPC Scripts. We have only the NAME of the script in "Answer"\r
+    // We need to load the filecontents first; Also, the reply msg is different\r
+    // from normal reqinfo messages\r
+    if(mRequestType == 3)\r
+    {\r
+        u32 tFileLen = 0;\r
+        PFile* fLua = NULL;\r
+        fLua = Filesystem->Open( "", (char*)Answer, Config->GetOption( "nc_data_path" ) );\r
+        std::string tLUAScript = "";\r
+        if(fLua)\r
+        {\r
+            tFileLen = fLua->GetSize();\r
+            char* t_content = new char[tFileLen+1];\r
+            memset(t_content, '\0', tFileLen+1);\r
+\r
+            fLua->Read( t_content, tFileLen );\r
+            fLua = NULL;\r
+\r
+            Filesystem->Close( fLua );\r
+            tLUAScript =  t_content;  // APPEND the script to our existing lua headerfile\r
+            delete t_content;\r
+            if (gDevDebug) Console->Print( "%s [PUdpReqInfo::DoAction()] Loaded LUA Script %s", Console->ColorText( GREEN, BLACK, "[SUCCESS]" ), (char*)Answer );\r
+        }\r
+        else\r
+        {\r
+            Console->Print( "%s [PUdpReqInfo::DoAction()] Unable to load LUA Script %s", Console->ColorText( RED, BLACK, "[ERROR]" ), (char*)Answer );\r
+            return false;\r
+        }\r
+        PMessage* tmpMsg = MsgBuilder->BuildReqNPCScriptAnswerMsg( mInfoId, &tLUAScript );\r
+        mDecodeData->mClient->FragmentAndSendUDPMessage(tmpMsg, 0x06);\r
+        return true;\r
+    }\r
+
+    PMessage* tmpMsg = MsgBuilder->BuildReqInfoAnswerMsg(mDecodeData->mClient, mRequestType, mInfoId, Answer, len);\r
+    mDecodeData->mClient->SendUDPMessage(tmpMsg);\r
+
+    mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+    return (query[0]);
+}
diff --git a/server/src/game/decoder/udp_reqinfo.h b/server/src/game/decoder/udp_reqinfo.h
new file mode 100644 (file)
index 0000000..9c02e27
--- /dev/null
@@ -0,0 +1,49 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_reqinfo.h - decoder classes for UDP Char info request messages\r
+  \r
+       CREATION: 6 Sep 2006 Hammag\r
+\r
+       MODIFIED:\r
+       REASON: - \r
+\r
+*/\r
+\r
+#ifndef UDPREQINFO_H\r
+#define UDPREQINFO_H\r
+\r
+class PUdpReqInfo : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u16 mRequestType;\r
+    u32 mInfoId;\r
+    \r
+  public:\r
+    PUdpReqInfo(PMsgDecodeData* nDecodeData);\r
+    //~PUdpCharInfo();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_subskill.cpp b/server/src/game/decoder/udp_subskill.cpp
new file mode 100644 (file)
index 0000000..e3c0fce
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+/*
+
+       udp_subskill.h - decoder classes for UDP subskill increasing messages
+
+       CREATION: 15 Sep 2006 Hammag
+
+       MODIFIED:
+       REASON: -
+
+*/
+
+#include "main.h"
+#include "udp_subskill.h"
+
+/**** PUdpSubskillInc ****/
+
+PUdpSubskillInc::PUdpSubskillInc(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+    nDecodeData->mName << "/0x04";
+}
+
+PUdpMsgAnalyser* PUdpSubskillInc::Analyse()
+{
+    mDecodeData->mName << "=Subskill increase request";
+    SubskillID = mDecodeData->mMessage->U16Data(mDecodeData->Sub0x13Start+9);
+
+    mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+
+    return this;
+}
+
+bool PUdpSubskillInc::DoAction()
+{
+    PClient* nClient = mDecodeData->mClient;
+    PChar* nChar = nClient->GetChar();
+
+    // Function tries to increase given subskill. If it fails, returnvalue is -1.
+    // If success, returnvalue is amount of skillpoints left
+    int tRemainingSkillPoints = 0;
+    tRemainingSkillPoints = nChar->Skill->IncreaseSubSkill(SubskillID);
+
+    if ( tRemainingSkillPoints > -1 )
+    {
+        PMessage* tmpMsg = MsgBuilder->BuildSubskillIncMsg(nClient, SubskillID, tRemainingSkillPoints); // last is remaining skillpoints
+        nClient->SendUDPMessage(tmpMsg);
+    }
+    else
+    {
+        // Send NACK, or just ignore..
+    }
+    /*if(nChar->Skill->IncSubSkillPossible(SubskillID) == true)
+    {
+        int tRemainingSkillPoints = 0;
+        nChar->Skill->IncreaseSubSkill(SubskillID); // SubskillID
+        PMessage* tmpMsg = MsgBuilder->BuildSubskillIncMsg(nClient, SubskillID, tRemainingSkillPoints); // last is remaining skillpoints
+        nClient->SendUDPMessage(tmpMsg);
+    }*/
+
+    mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+    return true;
+}
diff --git a/server/src/game/decoder/udp_subskill.h b/server/src/game/decoder/udp_subskill.h
new file mode 100644 (file)
index 0000000..8720ce1
--- /dev/null
@@ -0,0 +1,48 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_subskill.h - decoder classes for UDP subskill increasing messages\r
+  \r
+       CREATION: 15 Sep 2006 Hammag\r
+\r
+       MODIFIED:\r
+       REASON: - \r
+\r
+*/\r
+\r
+#ifndef UDPSUBSKILL_H\r
+#define UDPSUBSKILL_H\r
+\r
+class PUdpSubskillInc : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u16 SubskillID;\r
+    \r
+  public:\r
+    PUdpSubskillInc(PMsgDecodeData* nDecodeData);\r
+    //~PUdpSubskillInc();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_sync.cpp b/server/src/game/decoder/udp_sync.cpp
new file mode 100644 (file)
index 0000000..43ec275
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_sync.cpp - decoder classes for UDP Sync messages
+
+ CREATION: 30 Aug 2006 Hammag
+
+ MODIFIED:
+ REASON: -
+
+ TODO : put chunking code from PUdpSync2::DoAction() in a SendChunkedMessqage(PClient* nClient, PMessage* nMessage, u8 nChunkSize = 220)
+*/
+
+#include "main.h"
+#include "udp_sync.h"
+#include "worlds.h"
+#include "vehicle.h"
+
+/**** PUdpSync0 ****/
+
+PUdpSync0::PUdpSync0( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x01";
+}
+
+PUdpMsgAnalyser* PUdpSync0::Analyse()
+{
+  if ( mDecodeData->mMessage->GetSize() == 10 )
+  {
+    mDecodeData->mName << "=Sync0";
+    if ( mDecodeData->mClientState->UDP.mState != PGameState::UDP::GUS_SYNC1 )
+    {
+      mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+    }
+    else
+    {
+      mDecodeData->mState = DECODE_FINISHED;
+    }
+    return this;
+  }
+  else
+  {
+    return new PUdpMsgUnknown( mDecodeData );
+  }
+}
+
+bool PUdpSync0::DoAction()
+{
+  if (( mDecodeData->mState & DECODE_ACTION_READY ) && ( mDecodeData->mClientState->UDP.mState != PGameState::UDP::GUS_SYNC1 ) )
+  {
+    GetToSync1( mDecodeData );
+    return true;
+  }
+  else
+  {
+    mDecodeData->mErrorDetail = "No action ready or client already in Sync1";
+    return false;
+  }
+}
+
+void PUdpSync0::GetToSync1( PMsgDecodeData* nDecodeData )
+{
+  PClient* nClient = nDecodeData->mClient;
+  nClient->SetZoning();
+
+  u32 loc = nClient->GetChar()->GetLocation();
+//Console->Print("inside HandleGame : Location: %d", loc);
+  SendZone( nClient, loc );
+
+  // "aliverep" ?
+  PMessage* tmpMsg = MsgBuilder->BuildAliveRepMsg( nClient );
+  nClient->SendUDPMessage( tmpMsg );
+
+  nDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  //State->UDP.mSynced=true;
+  nDecodeData->mClientState->UDP.mState = PGameState::UDP::GUS_SYNC1;// To change later
+//Console->Print("Initialize: UDP_ID");
+  nClient->SetUDP_ID( 0 );
+}
+
+
+/**** PUdpSync1 ****/
+
+PUdpSync1::PUdpSync1( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x03";
+}
+
+PUdpMsgAnalyser* PUdpSync1::Analyse()
+{
+  mDecodeData->mName << "=Sync1";
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+
+  return this;
+}
+
+bool PUdpSync1::DoAction()
+{
+  if (( mDecodeData->mState & DECODE_ACTION_READY ) && ( mDecodeData->mClientState->UDP.mState == PGameState::UDP::GUS_SYNC1 ) )
+  {
+
+    /*PMessage* tmpMsg = new PMessage(15);
+    PClient* nClient = mDecodeData->mClient;
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << (u8)0x13;
+    *tmpMsg << (u16)nClient->GetUDP_ID();
+    *tmpMsg << (u16)nClient->GetSessionID();
+    *tmpMsg << (u8)0x0a; // Message length place;
+    *tmpMsg << (u8)0x03;
+    *tmpMsg << (u16)nClient->GetUDP_ID();
+    *tmpMsg << (u8)0x23;
+    *tmpMsg << (u8)0x0f;
+    *tmpMsg << (u8)0x00; // ??
+    *tmpMsg << (u8)0x03; // ??
+    *tmpMsg << (u8)0x00; // ??
+    *tmpMsg << (u8)0x01; // ??
+    *tmpMsg << (u8)0x00; // ??
+
+    (*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6);
+    nClient->SendUDPMessage(tmpMsg);*/
+
+    mDecodeData->mClientState->UDP.mState = PGameState::UDP::GUS_SYNC2;
+    mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+    return true;
+  }
+  else
+    return false;
+}
+
+/**** PUdpSync2 ****/
+
+PUdpSync2::PUdpSync2( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x0c";
+}
+
+PUdpMsgAnalyser* PUdpSync2::Analyse()
+{
+  mDecodeData->mName << "=Sync2";
+
+  mClientTime = mDecodeData->mMessage->U32Data( mDecodeData->Sub0x13Start + 2 );
+
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+  return this;
+}
+
+bool PUdpSync2::DoAction()
+{
+  if (( mDecodeData->mState & DECODE_ACTION_READY ) && ( mDecodeData->mClientState->UDP.mState == PGameState::UDP::GUS_SYNC2 ) )
+  {
+    PClient* nClient = mDecodeData->mClient;
+
+    // Baseline message chunking & sending
+    PMessage* BaselineMsg = MsgBuilder->BuildBaselineMsg( nClient );
+    nClient->FragmentAndSendUDPMessage( BaselineMsg, 0x19 );
+
+    // Sending "CharInfo3/Zoning2Msg" message
+    // Removed because same as Zoning2Msg
+    PMessage* Zoning2Msg = MsgBuilder->BuildZoning2Msg( nClient, mClientTime );
+    nClient->SendUDPMessage( Zoning2Msg );
+
+    mDecodeData->mClientState->UDP.mState = PGameState::UDP::GUS_SYNC3;
+    nClient->SetZoning( false );
+
+    // If char is sitting (vhz zoning), send it now to client
+    u32 nSeatableObjectId;
+    u8 nSeatId;
+    if( nClient->GetChar()->GetSeatInUse(&nSeatableObjectId, &nSeatId) )
+    {
+      if( gDevDebug )
+        Console->Print( YELLOW, BLACK, "[DEBUG] PUdpSync2::DoAction : Char %d sitting on vhc id %d, seat %d", nClient->GetLocalID(), nSeatableObjectId, nSeatId  );
+      PMessage* SittingMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, nSeatableObjectId, nSeatId );
+      nClient->FillInUDP_ID(SittingMsg);
+      nClient->SendUDPMessage( SittingMsg );
+    }
+
+    //Temp: send Subway to client if in subway
+    if ( nClient->GetChar()->GetLocation() == PWorlds::mNcSubwayWorldId )
+    {
+      PMessage* SubwayMsg = MsgBuilder->BuildSubwaySpawnMsg( nClient, false );
+      nClient->SendUDPMessage( SubwayMsg );
+      SubwayMsg = MsgBuilder->BuildSubwaySpawnMsg( nClient, true );
+      nClient->SendUDPMessage( SubwayMsg );
+    }
+
+    // Send spawned vehicles
+    PWorld* CurrentWorld = Worlds->GetWorld( nClient->GetChar()->GetLocation() );
+    if ( CurrentWorld )
+    {
+      PSpawnedVhcList* VhcList = CurrentWorld->GetSpawnedVehicules()->GetSpawnedVehicles();
+      PSpawnedVehicle* VhcEntry;
+      PMessage* VhcMsg;
+
+      while ( ! VhcList->empty() )
+      {
+        VhcEntry = VhcList->front();
+        VhcList->pop();
+        if( gDevDebug )
+          Console->Print( YELLOW, BLACK, "[DEBUG] PUdpSync2::DoAction : Send info for vhc id %d", VhcEntry->GetLocalId() );
+        VhcMsg = MsgBuilder->BuildVhcPosUpdateMsg( VhcEntry );
+        nClient->FillInUDP_ID( VhcMsg );
+        nClient->SendUDPMessage( VhcMsg );
+        VhcMsg = MsgBuilder->BuildVhcInfoMsg( nClient, VhcEntry );
+        nClient->SendUDPMessage( VhcMsg );
+      }
+    }
+
+    // Dispatching info to & from other chars in zone
+    int nbSent;
+    nbSent = ClientManager->SendUDPZoneWelcomeToClient( nClient );
+//Console->Print(GREEN, BLACK, " %d Welcome message were sent to client %d", nbSent, Client->GetIndex());
+
+    PMessage* HelloMsg = MsgBuilder->BuildCharHelloMsg( nClient );
+    nbSent = ClientManager->UDPBroadcast( HelloMsg, nClient );
+//Console->Print(GREEN, BLACK, "Client %d: Hello message sent to %d chars", Client->GetIndex(), nbSent);
+
+    // Send worldactors to client
+    WorldActors->InitWorld( nClient );
+
+    // Send NPC information to client
+    NPCManager->InitPlayer( nClient );
+
+    //Console->Print("OP Data inc");
+    Outposts->SendOPAreaData( nClient );
+
+    mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+    return true;
+  }
+  else
+    return false;
+}
diff --git a/server/src/game/decoder/udp_sync.h b/server/src/game/decoder/udp_sync.h
new file mode 100644 (file)
index 0000000..3326de8
--- /dev/null
@@ -0,0 +1,68 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+ udp_sync.h - decoder classes for UDP Sync messages\r
+\r
+ CREATION: 30 Aug 2006 Hammag\r
+\r
+ MODIFIED:\r
+ REASON: -\r
+\r
+*/\r
+\r
+#ifndef UDPSYNC_H\r
+#define UDPSYNC_H\r
+\r
+class PUdpSync0 : public PUdpMsgAnalyser\r
+{\r
+  public:\r
+    PUdpSync0( PMsgDecodeData* nDecodeData );\r
+    //~PUdpSync0();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+\r
+    static void GetToSync1( PMsgDecodeData* nDecodeData );\r
+};\r
+\r
+class PUdpSync1 : public PUdpMsgAnalyser\r
+{\r
+  public:\r
+    PUdpSync1( PMsgDecodeData* nDecodeData );\r
+    //~PUdpSync1();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpSync2 : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u32 mClientTime;\r
+\r
+  public:\r
+    PUdpSync2( PMsgDecodeData* nDecodeData );\r
+    //~PUdpSync2();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_terminal.cpp b/server/src/game/decoder/udp_terminal.cpp
new file mode 100644 (file)
index 0000000..317fe39
--- /dev/null
@@ -0,0 +1,618 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+ udp_terminal.cpp - decoder classes for UDP terminal related messages\r
+\r
+ CREATION: 8 Jan 2007 Namikon\r
+\r
+ MODIFIED:\r
+ REASON: -\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "udp_terminal.h"\r
+#include "terminal.h"\r
+#include "vehicle.h"\r
+#include "udp_charmove.h"\r
+#include "worlds.h"\r
+#include "furnituretemplate.h"\r
+#include <math.h>\r
+\r
+/*******************************************************************************************/\r
+/**** PUdpReceiveDB ****/\r
+/*******************************************************************************************/\r
+PUdpReceiveDB::PUdpReceiveDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x17";\r
+  mOptionsCount = 0;\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpReceiveDB::Analyse()\r
+{\r
+  PMessage* TmpMsg = mDecodeData->mMessage;\r
+  u16 Unknown3, OptionSize;\r
+\r
+  mDecodeData->mName << "=ReceiveDB request from client";\r
+\r
+  mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 );\r
+  TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 17 );\r
+  ( *TmpMsg ) >> mUnknown2; // Some unknown var maxx used. No idea what that is\r
+  ( *TmpMsg ) >> mUnknown1; // command name size\r
+  ( *TmpMsg ) >> mDBId; // variable, increments => DB ID. Look in several terminal .tsc files, ENV(DBID) it is!\r
+  ( *TmpMsg ) >> Unknown3; // constant ? => Size of Options!\r
+  ( *TmpMsg ) >> mCommandName; // null terminated string\r
+\r
+\r
+  while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) )\r
+  {\r
+    ( *TmpMsg ) >> OptionSize;\r
+    if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )\r
+    {\r
+      ( *TmpMsg ) >> mOptions[mOptionsCount++];\r
+      //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)!\r
+    }\r
+    else\r
+    {\r
+      break;\r
+    }\r
+  }\r
+\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+  return this;\r
+}\r
+\r
+bool PUdpReceiveDB::DoAction()\r
+{\r
+  //PMessage* tmpMsg;\r
+  //PClient* tClient = mDecodeData->mClient;\r
+  //PChar* tChar = tClient->GetChar();\r
+  bool Result = false;\r
+\r
+  if ( gDevDebug )\r
+  {\r
+    Console->Print( "%s ReceiveDB request from client", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
+    Console->Print( "%s Open Terminal - Terminal session %04x (?) - Unknown1 %04x - DBId %04x - Unknown2 %02x", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId, mUnknown1, mDBId, mUnknown2 );\r
+    Console->Print( "%s Command: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mCommandName.c_str() );\r
+    for ( u8 i = 0; i < mOptionsCount; ++i )\r
+      Console->Print( "%s Option %d: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), i, mOptions[i].c_str() );\r
+  }\r
+\r
+  if ( mCommandName == "VehicleListing" )\r
+  {\r
+    Result = ActionVehicleListing();\r
+  }\r
+  else if ( mCommandName == "VehicleControl" )\r
+  {\r
+    Result = ActionVehicleControl();\r
+  }\r
+  else\r
+  {\r
+      // Let Terminal try before error\r
+      Result = Terminal->HandleReceiveDB(mDecodeData->mClient, mTerminalSessionId, &mCommandName, mOptions, mOptionsCount, mDBId, mUnknown2);\r
+  }\r
+\r
+  if ( !Result )\r
+  {\r
+    Console->Print( "%s PUdpReceiveDB - Error or unknown command %s", Console->ColorText( RED, BLACK, "[WARNING]" ), mCommandName.c_str() );\r
+    for ( u8 i = 0; i < mOptionsCount; ++i )\r
+      Console->Print( "%s Option %d: '%s'", Console->ColorText( RED, BLACK, "[NOTICE]" ), i, mOptions[i].c_str() );\r
+  }\r
+\r
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  return Result;\r
+}\r
+\r
+bool PUdpReceiveDB::ActionVehicleListing()\r
+{\r
+  PMessage* tmpMsg;\r
+  PClient* tClient = mDecodeData->mClient;\r
+  PChar* tChar = tClient->GetChar();\r
+\r
+  if ( mOptionsCount == 3 ) // CharId, StartVhcEntry, MaxVhcEntries\r
+  {\r
+    if ((( u32 )atol( mOptions[0].c_str() ) ) != tChar->GetID() )\r
+    {\r
+      // Err: invalid CharId. Can alert, But we don't care :-) (except if used for other terminal function)\r
+    }\r
+    // !!! some more check/regex on values to do before using !!!\r
+    u16 StartIndex = atoi( mOptions[1].c_str() );\r
+    u16 MaxEntries = atoi( mOptions[2].c_str() );\r
+\r
+    u8 nStatus = 1;\r
+    u16 nErrcode = 0;\r
+\r
+    tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode );\r
+    tClient->SendUDPMessage( tmpMsg );\r
+\r
+    PVhcInfoList* VhcList = Vehicles->GetCharVehicles( tChar->GetID(), MaxEntries, StartIndex );\r
+    if ( ! VhcList->empty() )\r
+    {\r
+      u16 NumEntries = VhcList->size();\r
+      std::string* Answer = new std::string[4 * NumEntries];\r
+      u16 Index = 0;\r
+      PVehicleInformation* EntryInfo;\r
+//Console->Print("VHc entries : %d", NumEntries);\r
+\r
+      while ( ! VhcList->empty() )\r
+      {\r
+        EntryInfo = VhcList->front();\r
+        VhcList->pop();\r
+        Answer[Index++] = Ssprintf( "%u", EntryInfo->GetVehicleId() ); //vhcId\r
+        Answer[Index++] = Ssprintf( "%u", EntryInfo->GetVehicleType() ); //vhcType\r
+        Answer[Index++] = Ssprintf( "%u", EntryInfo->GetStatus() ); //vhcStatus 0:parking, 1:in_service, 2:destroyed\r
+        Answer[Index++] = Ssprintf( "%u", EntryInfo->GetHealth() ); //vhcHealth%\r
+//Console->Print("Entry: %s/%s/%s/%s", Answer[Index-4].c_str(), Answer[Index-3].c_str(), Answer[Index-2].c_str(), Answer[Index-1].c_str());\r
+        delete EntryInfo;\r
+      }\r
+\r
+      tmpMsg = MsgBuilder->BuildDBAnswerMsg( tClient, &mCommandName, Answer, NumEntries, 4 );\r
+      tClient->SendUDPMessage( tmpMsg );\r
+      delete [] Answer;\r
+    }\r
+    delete VhcList;\r
+\r
+    return true;\r
+  }\r
+  else\r
+    return false;\r
+  /*\r
+  // Option1=CharId, Option2=resultEntryStart, Option3=maxResultEntries\r
+  S=> 03/2b/1a <u16 size incl 0><u8 bool succes ?><u16 err code ?>VehicleListing+0\r
+  13 2a 00 7c be 19\r
+  03 2a 00 2b 1a 0f 00 01 00 00 56 65 68 69 63 6c  .*.+......Vehicl\r
+  65 4c 69 73 74 69 6e 67 00  eListing.\r
+  S=> 03/2b/17 0f 00 08 00 04 00 <0f 00><u16 entries nb><04 00>\r
+  VehicleListing+0\r
+  <id_size incl 0><id_string +0>\r
+  <type_size><type_id_string? +0>\r
+  <status_size><status_string +0> (val: 0=stored)\r
+  <health_size><health_string +0> (val: 0-255)\r
+  ==\r
+  03/2b/17 0f 00 01 00 04 00 <0f 00><u16 entries nb><04 00>\r
+  31\r
+  03 54 00 2b 17 0f 00 01 00 04 00 56 65 68 69 63 6c 65 4c 69 73 74  .....VehicleList\r
+  69 6e 67 00 06 00 32 35 32 37 37 00 03 00 36 30  ing...25277...60\r
+  00 02 00 30 00 04 00 32 35 35 00  ...0...255.\r
+  */\r
+}\r
+\r
+bool PUdpReceiveDB::ActionVehicleControl()\r
+{\r
+  PMessage* tmpMsg;\r
+  PClient* tClient = mDecodeData->mClient;\r
+\r
+  if ( mOptionsCount == 2 ) // VhcId, CharId\r
+  {\r
+    // !!! validate values !!!\r
+    u8 nStatus = 1;\r
+    u16 nErrcode = 0;\r
+\r
+    tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode );\r
+    tClient->SendUDPMessage( tmpMsg );\r
+\r
+    u32 VhcId = ( u32 )atol( mOptions[0].c_str() );\r
+    PVehicleInformation EntryInfo;\r
+    if ( Vehicles->GetVehicleInfo( VhcId, &EntryInfo ) )\r
+    {\r
+      std::string* Answer = new std::string[4];\r
+      Answer[0] = Ssprintf( "%u", EntryInfo.GetVehicleType() ); //vhcType\r
+      Answer[1] = Ssprintf( "%u", EntryInfo.GetStatus() ); //vhcStatus\r
+      Answer[2] = Ssprintf( "%u", EntryInfo.GetHealth() ); //vhcHealth%\r
+      Answer[3] = Ssprintf( "%u", ( 255 - EntryInfo.GetHealth() ) * 1000 * EntryInfo.GetVehicleType() / 255 ); //Repair cost\r
+      if ( gDevDebug )\r
+        Console->Print( "%s Entry: %s/%s/%s/%s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), Answer[0].c_str(), Answer[1].c_str(), Answer[2].c_str(), Answer[3].c_str() );\r
+      tmpMsg = MsgBuilder->BuildDBAnswerMsg( tClient, &mCommandName, Answer, 1, 4 );\r
+      tClient->SendUDPMessage( tmpMsg );\r
+      delete [] Answer;\r
+    }\r
+    return true;\r
+  }\r
+  else\r
+    return false;\r
+  /*\r
+  // Option1=VhcId, Option2=CharId\r
+  S=> 03/2b/1a VehicleControl\r
+  13 77 00 c9 be 19\r
+  03 76 00 2b 1a 0f 00 01 00 00 56 65 68 69 63 6c  .v.+......Vehicl\r
+  65 43 6f 6e 74 72 6f 6c 00  eControl.\r
+  S=> 03/2b/17 0f 00 01 00 04 00 VehicleControl  4 0 255 4255(\r
+  2f\r
+  03 77 00 2b 17 0f 00 01 00 04 00 56 65 68 69 63 6c 65 43 6f 6e 74  .....VehicleCont\r
+  72 6f 6c 00 02 00 34 00 02 00 30 00 04 00 32 35  rol...4...0...25\r
+  35 00 05 00 34 32 35 35 00                       5...4255.\r
+  */\r
+}\r
+\r
+/*******************************************************************************************/\r
+/**** PUdpUpdateDB ****/\r
+/*******************************************************************************************/\r
+PUdpUpdateDB::PUdpUpdateDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x18";\r
+  mOptionsCount = 0;\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpUpdateDB::Analyse()\r
+{\r
+  PMessage* TmpMsg = mDecodeData->mMessage;\r
+  u16 Unknown3, OptionSize;\r
+\r
+  mDecodeData->mName << "=UpdateDB request from client";\r
+\r
+  mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 );\r
+  TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 17 );\r
+  ( *TmpMsg ) >> mUnknown2; // Some unknown var maxx used. No idea what that is\r
+  ( *TmpMsg ) >> mUnknown1; // command name size\r
+  ( *TmpMsg ) >> mDBId; // variable, increments => DB ID. Look in several terminal .tsc files, ENV(DBID) it is!\r
+  ( *TmpMsg ) >> Unknown3; // constant ? => Size of Options!\r
+  ( *TmpMsg ) >> mCommandName; // null terminated string\r
+\r
+\r
+  while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) )\r
+  {\r
+    ( *TmpMsg ) >> OptionSize;\r
+    if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )\r
+    {\r
+      ( *TmpMsg ) >> mOptions[mOptionsCount++];\r
+      //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)!\r
+    }\r
+    else\r
+    {\r
+      break;\r
+    }\r
+  }\r
+\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+  return this;\r
+}\r
+\r
+bool PUdpUpdateDB::DoAction()\r
+{\r
+  if ( gDevDebug )
+  {
+    Console->Print( "%s UpdateDB request from client", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+    Console->Print( "%s Open Terminal - Terminal session %04x (?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId );
+    Console->Print( "%s Command: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mCommandName.c_str() );
+    for ( u8 i = 0; i < mOptionsCount; ++i )
+      Console->Print( "%s Option %d: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), i, mOptions[i].c_str() );
+  }\r
+   bool Result = false;\r
+    Result = Terminal->HandleUpdateDB(mDecodeData->mClient, mTerminalSessionId, &mCommandName, mOptions, mOptionsCount, mDBId, mUnknown2);
+\r
+ if ( !Result )\r
+  {
+    Console->Print( "%s PUdpUpdateDB - Error or unknown command %s", Console->ColorText( RED, BLACK, "[WARNING]" ), mCommandName.c_str() );\r
+    for ( u8 i = 0; i < mOptionsCount; ++i )\r
+      Console->Print( "%s Option %d: '%s'", Console->ColorText( RED, BLACK, "[NOTICE]" ), i, mOptions[i].c_str() );
+  }\r
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  return true;\r
+}\r
+/*******************************************************************************************/\r
+/**** PUdpTryAccessDB ****/\r
+/*******************************************************************************************/\r
+PUdpTryAccessDB::PUdpTryAccessDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x19";\r
+  mOptionsCount = 0;\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpTryAccessDB::Analyse()\r
+{\r
+  PMessage* TmpMsg = mDecodeData->mMessage;\r
+  u16 Unknown3, OptionSize;\r
+\r
+  mDecodeData->mName << "=TryAccess request from client";\r
+\r
+  mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 );\r
+  TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 17 );\r
+  ( *TmpMsg ) >> mUnknown2; // Some unknown var maxx used. No idea what that is\r
+  ( *TmpMsg ) >> mUnknown1; // command name size\r
+  ( *TmpMsg ) >> mDBId; // variable, increments => DB ID. Look in several terminal .tsc files, ENV(DBID) it is!\r
+  ( *TmpMsg ) >> Unknown3; // constant ? => Size of Options!\r
+  ( *TmpMsg ) >> mCommandName; // null terminated string\r
+\r
+\r
+  while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) )\r
+  {\r
+    ( *TmpMsg ) >> OptionSize;\r
+    if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )\r
+    {\r
+      ( *TmpMsg ) >> mOptions[mOptionsCount++];\r
+      //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)!\r
+    }\r
+    else\r
+    {\r
+      break;\r
+    }\r
+  }\r
+\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+  return this;\r
+}\r
+\r
+bool PUdpTryAccessDB::DoAction()\r
+{\r
+    // Let the terminal class handle the request\r
+    Terminal->HandleTryAccess(mDecodeData->mClient, mTerminalSessionId, &mCommandName, mOptions, mOptionsCount, mDBId, mUnknown2);\r
+\r
+    mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+    return true;\r
+}\r
+/*******************************************************************************************/\r
+/**** PUdpQueryDB ****/\r
+/*******************************************************************************************/\r
+PUdpQueryDB::PUdpQueryDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x1b";\r
+  mOptionsCount = 0;\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpQueryDB::Analyse()\r
+{\r
+  PMessage* TmpMsg = mDecodeData->mMessage;\r
+  u16 OptionSize;\r
+\r
+  mDecodeData->mName << "=QueryDB request from client";\r
+\r
+  mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 );\r
+  TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 18 );\r
+  ( *TmpMsg ) >> OptionSize; // Size of data\r
+  ( *TmpMsg ) >> OptionSize; // Size of DB Command Name\r
+  if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )\r
+  {\r
+    ( *TmpMsg ) >> mDBCommandName;\r
+  }\r
+  ( *TmpMsg ) >> OptionSize; // Size of Command Name\r
+  if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )\r
+  {\r
+    ( *TmpMsg ) >> mCommandName; // null terminated string\r
+  }\r
+\r
+  while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) )\r
+  {\r
+    ( *TmpMsg ) >> OptionSize;\r
+    if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )\r
+    {\r
+      ( *TmpMsg ) >> mOptions[mOptionsCount++];\r
+      //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)!\r
+    }\r
+    else\r
+    {\r
+      break;\r
+    }\r
+  }\r
+\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+  return this;\r
+}\r
+\r
+bool PUdpQueryDB::DoAction()\r
+{\r
+  //PMessage* tmpMsg;\r
+  //PClient* tClient = mDecodeData->mClient;\r
+  bool Result = false;\r
+\r
+  if ( gDevDebug )\r
+  {\r
+    Console->Print( "%s QueryDB request from client", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
+    Console->Print( "%s Open Terminal - Terminal session %04x (?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId );\r
+    Console->Print( "%s DBCommand: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDBCommandName.c_str() );\r
+    Console->Print( "%s Command: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mCommandName.c_str() );\r
+    for ( u8 i = 0; i < mOptionsCount; ++i )\r
+      Console->Print( "%s Option %d: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), i, mOptions[i].c_str() );\r
+  }\r
+\r
+  if ( mDBCommandName == "SPAWNVEHICLE" )\r
+  {\r
+    Result = ActionSpawnVehicle();\r
+  }\r
+  else if ( mDBCommandName == "REPAIRVEHICLE" )\r
+  {\r
+    Result = ActionRepairVehicle();\r
+  }\r
+  else if ( mDBCommandName == "DISMISSVEHICLE" )\r
+  {\r
+    Result = ActionDismissVehicle();\r
+  }\r
+  else\r
+  {\r
+      // Let Terminal try before error\r
+      Result = Terminal->HandleQueryDB(mDecodeData->mClient, &mDBCommandName, &mCommandName, mOptions, mOptionsCount);\r
+  }\r
+\r
+  if ( !Result )\r
+  {\r
+    Console->Print( "%s PUdpQueryDB - Error or unknown command %s", Console->ColorText( RED, BLACK, "[WARNING]" ), mDBCommandName.c_str() );\r
+    for ( u8 i = 0; i < mOptionsCount; ++i )\r
+      Console->Print( "%s Option %d: '%s'", Console->ColorText( RED, BLACK, "[NOTICE]" ), i, mOptions[i].c_str() );\r
+  }\r
+\r
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  return Result;\r
+}\r
+\r
+bool PUdpQueryDB::ActionSpawnVehicle()\r
+{\r
+  PMessage* tmpMsg;\r
+  PClient* tClient = mDecodeData->mClient;\r
+  PChar* tChar = tClient->GetChar();\r
+\r
+  if ( mOptionsCount == 3 ) // 0, VhcId, CharId\r
+  {\r
+    u32 VhcId = ( u32 )atol( mOptions[1].c_str() );\r
+    //u32 CharId = (u32)atol(mOptions[2].c_str());\r
+    // !!! validate values !!!\r
+    // !!! + check CharId = current char && CharId is owner of VhcId\r
+    u8 nStatus = 1; // 1=OK, 0=Err\r
+    u16 nErrcode = 16; // 0=n/a 16=Already Spawned // MsdId = 2500+nErrcode [MISC]\r
+\r
+    tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode );\r
+    tClient->SendUDPMessage( tmpMsg );\r
+\r
+    PVhcCoordinates NewPosition;\r
+    PWorld* CurrentWorld = Worlds->GetWorld( tChar->GetLocation() );\r
+    bool relativePos = false;\r
+    if ( tChar->GetLastUsedObject() && !WorldActors->IsDynamicActor( tChar->GetLastUsedObject() ) && CurrentWorld )\r
+    {\r
+      const PFurnitureItemTemplate* tFurnitureTemplate = CurrentWorld->GetFurnitureItemTemplate( tChar->GetLastUsedObject() / 1024 - 1 );\r
+      if ( tFurnitureTemplate && ( tFurnitureTemplate->GetFunctionType() == 28 ) ) // vhc term\r
+      {\r
+        f32 decal = 1000; // distance at which to spawn the vhc\r
+        f32 nPosX, nPosY, nPosZ;\r
+        tFurnitureTemplate->GetPos( &nPosX, &nPosY, &nPosZ );\r
+        nPosX += 32000;\r
+        nPosY += 32000;\r
+        f32 dX = ( tChar->Coords.mX - nPosX );\r
+        f32 dY = ( tChar->Coords.mY - nPosY );\r
+        f32 d = decal / sqrt( dX * dX + dY * dY );\r
+        NewPosition.SetPosition( static_cast<u16>( nPosY + d * dY ), ( tChar->Coords ).mZ + 100, static_cast<u16>( nPosX + d * dX ), ( tChar->Coords ).mUD, 34683, 32403 );\r
+        relativePos = true;\r
+      }\r
+    }\r
+\r
+    if( ! relativePos )\r
+      NewPosition.SetPosition(( tChar->Coords ).mY, ( tChar->Coords ).mZ + 150, ( tChar->Coords ).mX, ( tChar->Coords ).mUD, 34683, 32403 );\r
+\r
+    PSpawnedVehicle* NewVhc = Vehicles->SpawnVehicle( VhcId, tChar->GetLocation(), &NewPosition );\r
+    if ( NewVhc )\r
+    {\r
+      tmpMsg = MsgBuilder->BuildVhcPosUpdateMsg( NewVhc );\r
+      ClientManager->UDPBroadcast( tmpMsg, tChar->GetLocation() );\r
+    }\r
+\r
+    return true;\r
+  }\r
+  else\r
+    return false;\r
+}\r
+\r
+bool PUdpQueryDB::ActionRepairVehicle()\r
+{\r
+  PMessage* tmpMsg;\r
+  PClient* tClient = mDecodeData->mClient;\r
+\r
+  if ( mOptionsCount == 3 ) // 0, VhcId, CharId\r
+  {\r
+    //u32 VhcId = (u32)atol(mOptions[1].c_str());\r
+    //u32 CharId = (u32)atol(mOptions[2].c_str());\r
+    // !!! validate values !!!\r
+\r
+    u8 nStatus = 1; // 1=OK, 0=Err\r
+    u16 nErrcode = 18; // 0=n/a 18=Still Spawned, 19=Not enough money\r
+\r
+    tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode );\r
+    tClient->SendUDPMessage( tmpMsg );\r
+\r
+    // Action here\r
+\r
+    return true;\r
+  }\r
+  else\r
+    return false;\r
+}\r
+\r
+bool PUdpQueryDB::ActionDismissVehicle()\r
+{\r
+  PMessage* tmpMsg;\r
+  PClient* tClient = mDecodeData->mClient;\r
+  //PChar* tChar = tClient->GetChar();\r
+  bool Result = false;\r
+\r
+  if ( mOptionsCount == 3 ) // 0, VhcId, CharId\r
+  {\r
+    u32 VhcId = ( u32 )atol( mOptions[1].c_str() );\r
+    //u32 CharId = (u32)atol(mOptions[2].c_str());\r
+    // !!! validate values !!!\r
+    // !!! + check CharId = current char && CharId is owner of VjhcId\r
+    // !!! Check vhc empty\r
+    u8 nStatus = 0; // 1=OK, 0=Err\r
+    u16 nErrcode = 17; // 0=n/a 17=Not Spawned\r
+    PVehicleInformation nInfo;\r
+    u32 tLocalId = 0;\r
+    u32 tLocation = 0;\r
+\r
+    PSpawnedVehicle* tVhc = Vehicles->GetSpawnedVehicle( VhcId );\r
+    if ( tVhc )\r
+    {\r
+      tLocalId = tVhc->GetLocalId();\r
+      tLocation = tVhc->GetLocation();\r
+      u32 tCharId;\r
+      PChar* tChar;\r
+      for ( u8 i = 0; i < tVhc->GetNumSeats(); ++i )\r
+      {\r
+        if (( tCharId = tVhc->GetSeatUser( i ) ) )\r
+        {\r
+          if (( tChar = Chars->GetChar( tCharId ) ) )\r
+          {\r
+            PUdpCharExitChair::DoLeaveChair( tChar, NULL, tVhc );\r
+          }\r
+        }\r
+      }\r
+      Result = Vehicles->UnspawnVehicle( VhcId );\r
+    }\r
+\r
+    if ( Result )\r
+    {\r
+      nStatus = 1;\r
+      nErrcode = 0;\r
+    }\r
+    tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode );\r
+    tClient->SendUDPMessage( tmpMsg );\r
+\r
+    if ( Result )\r
+    {\r
+      tmpMsg = MsgBuilder->BuildRemoveWorldObjectMsg( tLocalId );\r
+      ClientManager->UDPBroadcast( tmpMsg, tLocation );\r
+    }\r
+    return true;\r
+  }\r
+  else\r
+    return false;\r
+}\r
+\r
+/*******************************************************************************************/\r
+/**** PUdpTeminal0x1f ****/\r
+/*******************************************************************************************/\r
+PUdpTeminal0x1f::PUdpTeminal0x1f( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x1f";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpTeminal0x1f::Analyse()\r
+{\r
+  mDecodeData->mName << "=Open Terminal";\r
+  mTerminalSessionId = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 6 );\r
+\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+  return this;\r
+}\r
+\r
+bool PUdpTeminal0x1f::DoAction()\r
+{\r
+  if ( gDevDebug )\r
+    Console->Print( "%s Open Terminal - Terminal session %04x (?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId );\r
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  return true;\r
+}\r
diff --git a/server/src/game/decoder/udp_terminal.h b/server/src/game/decoder/udp_terminal.h
new file mode 100644 (file)
index 0000000..24a0270
--- /dev/null
@@ -0,0 +1,135 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_terminal.h - decoder classes for UDP terminal related messages\r
+\r
+       CREATION: 8 Jan 2007 Namikon\r
+\r
+       MODIFIED:\r
+       REASON: -\r
+\r
+*/\r
+\r
+#ifndef UDPTERMINAL_H\r
+#define UDPTERMINAL_H\r
+\r
+\r
+\r
+class PUdpReceiveDB : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    static const u8 mMaxOptions = 9; // Largest: forum\forenlist.tsc(21, 114,...)\r
+    u16 mTerminalSessionId;\r
+    std::string mCommandName;\r
+    std::string mOptions[mMaxOptions];\r
+    u8 mOptionsCount;\r
+\r
+    u16 mUnknown1;\r
+    u8 mUnknown2;\r
+    u16 mDBId;\r
+\r
+               bool ActionVehicleListing();\r
+               bool ActionVehicleControl();\r
+\r
+  public:\r
+    PUdpReceiveDB(PMsgDecodeData* nDecodeData);\r
+    //~PUdpReceiveDB();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpUpdateDB : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    static const u8 mMaxOptions = 7; // Largest: forum\bbcnewthread.tsc(66):\r
+    u16 mTerminalSessionId;\r
+    std::string mCommandName;\r
+    std::string mOptions[mMaxOptions];\r
+    u8 mOptionsCount;\r
+\r
+    u16 mUnknown1;\r
+    u8 mUnknown2;\r
+    u16 mDBId;\r
+\r
+  public:\r
+    PUdpUpdateDB(PMsgDecodeData* nDecodeData);\r
+    //~PUdpUpdateDB();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpTryAccessDB : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    static const u8 mMaxOptions = 9; // Largest: stockx\depot.tsc(227):\r
+    u16 mTerminalSessionId;\r
+    std::string mCommandName;\r
+    std::string mOptions[mMaxOptions];\r
+    u8 mOptionsCount;\r
+\r
+    u16 mUnknown1;\r
+    u8 mUnknown2;\r
+    u16 mDBId;\r
+  public:\r
+    PUdpTryAccessDB(PMsgDecodeData* nDecodeData);\r
+    //~PUdpTryAccessDB();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpQueryDB : public PUdpMsgAnalyser // Also called "ServerMessage" in .tsc scripts!\r
+{\r
+  private:\r
+    static const u8 mMaxOptions = 5; // Largest: politics\transcomment.tsc(36):\r
+    u16 mTerminalSessionId;\r
+    u16 mDBId;\r
+    std::string mDBCommandName;\r
+    std::string mCommandName;\r
+    std::string mOptions[mMaxOptions];\r
+    u8 mOptionsCount;\r
+\r
+               bool ActionSpawnVehicle();\r
+               bool ActionRepairVehicle();\r
+               bool ActionDismissVehicle();\r
+\r
+  public:\r
+    PUdpQueryDB(PMsgDecodeData* nDecodeData);\r
+    //~PUdpQueryDB();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpTeminal0x1f : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u16 mTerminalSessionId;\r
+\r
+  public:\r
+    PUdpTeminal0x1f(PMsgDecodeData* nDecodeData);\r
+    //~PUdpTeminal0x1f();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_useobject.cpp b/server/src/game/decoder/udp_useobject.cpp
new file mode 100644 (file)
index 0000000..7a42e26
--- /dev/null
@@ -0,0 +1,907 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+ udp_useobject.cpp - decoder classes for object use related messages\r
+\r
+ CREATION: 17 Sep 2006 Hammag\r
+\r
+ MODIFIED:\r
+ REASON: -\r
+\r
+  TODO: use only RawObjectIDs to avoid complication & errors\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "udp_useobject.h"\r
+#include "worlds.h"\r
+#include "furnituretemplate.h"\r
+#include "doortemplate.h"\r
+#include "appartements.h"\r
+#include "container.h"\r
+#include "subway.h"\r
+#include "vhcaccessrequest.h"\r
+#include "udp_vhc.h"\r
+\r
+u32 gVhcId = 0x3ff;\r
+\r
+/**** PUdpVhcMove ****/\r
+\r
+PUdpUseObject::PUdpUseObject( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x17";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpUseObject::Analyse()\r
+{\r
+  mDecodeData->mName << "=Object use";\r
+\r
+  mRawItemID = mDecodeData->mMessage->U32Data( mDecodeData->Sub0x13Start + 8 );\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+  return this;\r
+}\r
+\r
+bool PUdpUseObject::DoAction()\r
+{\r
+  PClient* nClient = mDecodeData->mClient;\r
+  PChar* nChar = nClient->GetChar();\r
+  u32 ItemID;\r
+  char DbgMessage[128];\r
+  PMessage* tmpMsg;\r
+\r
+  bool tHandleDynamicActor = false;\r
+\r
+  /*PMessage* cMsg = mDecodeData->mMessage;\r
+  u32 ClientTime = cMsg->U32Data(mDecodeData->Sub0x13Start+2);\r
+\r
+  tmpMsg = MsgBuilder->BuildPingMsg(mDecodeData->mClient, ClientTime);\r
+  mDecodeData->mClient->SendUDPMessage(tmpMsg);*/\r
+\r
+  nChar->SetLastUsedObject( mRawItemID );\r
+\r
+  if ( nClient->IsInRemoveActorMode() == true )\r
+  {\r
+    if ( WorldActors->IsDynamicActor( mRawItemID ) == true )\r
+    {\r
+      WorldActors->DelWorldActor( nClient, mRawItemID );\r
+      mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+      return true;\r
+    }\r
+    else\r
+      Chat->send( nClient, CHAT_DIRECT, "System", "This is not an dynamic worldactor. To remove it please type @remove <rawID>" );\r
+  }\r
+\r
+  if ( gDevDebug )\r
+  {\r
+    Console->Print( "Char at y=%f (0x%04x) z=%f (0x%04x) x=%f (0x%04x)", ( f32 )( nChar->Coords.mY - 32000 ), nChar->Coords.mY, ( f32 )( nChar->Coords.mZ - 32000 ), nChar->Coords.mZ, ( f32 )( nChar->Coords.mX - 32000 ), nChar->Coords.mX );\r
+    if ( mRawItemID & 1023 )\r
+      Console->Print( "using item %d (0x%08x)", mRawItemID, mRawItemID );\r
+    else\r
+      Console->Print( "using item %d (0x%08x) [dat entry %d (0x%08x)]", mRawItemID, mRawItemID, mRawItemID / 1024 - 1, mRawItemID / 1024 - 1 );\r
+  }\r
+\r
+  if ( nClient->GetDebugMode( DBG_ITEMID ) )\r
+  {\r
+    if ( mRawItemID & 1023 )\r
+      snprintf( DbgMessage, 128, "using item [raw: %d (0x%08x)]", mRawItemID, mRawItemID );\r
+    else\r
+      snprintf( DbgMessage, 128, "using item %d (0x%08x) [raw: %d (0x%08x)]", mRawItemID / 1024 - 1, mRawItemID / 1024 - 1, mRawItemID, mRawItemID );\r
+    Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
+  }\r
+\r
+  PWorld* CurrentWorld = Worlds->GetWorld( nChar->GetLocation() );\r
+  if ( CurrentWorld )\r
+  {\r
+    if ( WorldActors->IsDynamicActor( mRawItemID ) == true )\r
+    {\r
+      tHandleDynamicActor = true;\r
+      if ( gDevDebug )\r
+        Console->Print( "%s Dynamic actor found, processing...", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
+    }\r
+\r
+    if ( mRawItemID & 1023 && tHandleDynamicActor == false ) // non-furniture objects\r
+    {\r
+      if ( mRawItemID > 0x80 ) // maybe door\r
+      {\r
+        if ( nClient->GetDebugMode( DBG_ITEMID ) )\r
+        {\r
+          snprintf( DbgMessage, 128, "Door : %d", mRawItemID - 0x80 );\r
+          Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
+        }\r
+        const PDoorTemplate* tDoor = CurrentWorld->GetDoor( mRawItemID - 0x80 );\r
+        if ( tDoor )\r
+        {\r
+          if ( tDoor->IsTriggeredDoor() )\r
+          {\r
+            tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, mRawItemID );\r
+            nClient->SendUDPMessage( tmpMsg );\r
+          }\r
+          else\r
+          {\r
+            if ( gDevDebug )\r
+              Console->Print( "%s Opening %s door %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), ( tDoor->IsDoubleDoor() ? "double" : "simple" ), mRawItemID - 0x80 );\r
+            tmpMsg = MsgBuilder->BuildDoorOpenMsg( mRawItemID, tDoor->IsDoubleDoor() );\r
+            ClientManager->UDPBroadcast( tmpMsg, nClient );\r
+          }\r
+          mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+        }\r
+      }\r
+      if ( !( mDecodeData->mState & DECODE_ACTION_DONE ) ) // else might be PC, NPC, VHC\r
+      {\r
+        if ( gDevDebug )\r
+          Console->Print( "%s Clicking on char, npc or vhc %d (%x) - time = %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID, mRawItemID, GameServer->GetGameTime() );\r
+\r
+        if ( PSpawnedVehicles::IsPotentialSpawnedVehicle( mRawItemID ) )\r
+        {\r
+          bool vhcFound = false;\r
+\r
+          if ( nChar->GetSeatInUse() == seat_none ) // Refuse if Char is already sitting somewhere\r
+          {\r
+            PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicules()->GetVehicle( mRawItemID );\r
+            if ( tVhc )\r
+            {\r
+              if ( gDevDebug )\r
+                Console->Print( "%s Using vhc %d (0x%04x)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID, mRawItemID );\r
+              vhcFound = true;\r
+\r
+              if ( tVhc->GetInformation().GetOwnerCharId() ==  nChar->GetID() ) // Requester is the owner\r
+              {\r
+                PUdpVhcUse::DoFreeSitting( nClient,  tVhc, mRawItemID );\r
+              }\r
+              else // Requester is not the owner\r
+              {\r
+                if ( tVhc->GetNumSeats() == 1 ) // single seat vhc\r
+                {\r
+                  tmpMsg = MsgBuilder->BuildText100Msg( nClient, 17, mRawItemID ); // "Not your vhc" msg\r
+                  nClient->SendUDPMessage( tmpMsg );\r
+                } // multi seats vhc\r
+                else if ( ! tVhc->IsCharInside( tVhc->GetInformation().GetOwnerCharId() ) )\r
+                {\r
+                  tmpMsg = MsgBuilder->BuildText100Msg( nClient, 18, mRawItemID ); // "Owner not on board" msg\r
+                  nClient->SendUDPMessage( tmpMsg );\r
+                }\r
+                else if ( tVhc->GetNbFreeSeats() == 0 )\r
+                {\r
+                  tmpMsg = MsgBuilder->BuildText100Msg( nClient, 5, mRawItemID ); // "No free seat" msg\r
+                  nClient->SendUDPMessage( tmpMsg );\r
+                }\r
+                else\r
+                {\r
+                  // Send request to owner\r
+                  PClient* ownerClient = ClientManager->getClientByChar( tVhc->GetInformation().GetOwnerCharId() );\r
+                  if ( ownerClient )\r
+                  {\r
+                    PChar* ownerChar = ownerClient->GetChar();\r
+                    // We could check for valid allowed access before adding a new one\r
+                    u32 newReqId = ownerChar->GetVhcAccessRequestList()->Add( nChar->GetID(), tVhc->GetInformation().GetVehicleId() );\r
+                    if ( newReqId )\r
+                    {\r
+                      tmpMsg = MsgBuilder->BuildVhcAccessRequestMsg( ownerClient, newReqId, nChar->GetID(), nClient->GetID(), tVhc->GetInformation().GetVehicleId() );\r
+                      ownerClient->SendUDPMessage( tmpMsg );\r
+                      tmpMsg = MsgBuilder->BuildText100Msg( nClient, 19, mRawItemID ); // "req transmitted" msg\r
+                      nClient->SendUDPMessage( tmpMsg );\r
+                    }\r
+                  }\r
+                  else\r
+                  {\r
+                    tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID ); // Undefined failure / Owner not available\r
+                    nClient->SendUDPMessage( tmpMsg );\r
+                  }\r
+                }\r
+              }\r
+              //////// Msg100 id\r
+              //22 can't use that seat\r
+            }\r
+            else if (( nChar->GetLocation() == PWorlds::mNcSubwayWorldId ) && Subway->IsValidSubwayCab( mRawItemID ) && ( nChar->GetSeatInUse() == seat_none ) ) // Entering subway\r
+            {\r
+              vhcFound = true;\r
+              if ( Subway->IsDoorOpen( mRawItemID, GameServer->GetGameTime() ) )\r
+              {\r
+                u8 freeSeat = Subway->GetFreeSeat( mRawItemID );\r
+                if ( freeSeat && Subway->SetSeatUser( mRawItemID, freeSeat, nChar->GetID() ) )\r
+                {\r
+                  nChar->SetSeatInUse( seat_subway, mRawItemID, freeSeat );\r
+                  tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, mRawItemID, freeSeat );\r
+                  ClientManager->UDPBroadcast( tmpMsg, nClient );\r
+                }\r
+                else\r
+                {\r
+                  tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, mRawItemID );\r
+                  nClient->SendUDPMessage( tmpMsg );\r
+                }\r
+              }\r
+              else\r
+              {\r
+                tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, mRawItemID );\r
+                nClient->SendUDPMessage( tmpMsg );\r
+              }\r
+            }\r
+            // else error: invalid vhc\r
+          } // else char alreay sitting\r
+          if ( vhcFound )\r
+            mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+        }\r
+\r
+        if ( !( mDecodeData->mState & DECODE_ACTION_DONE ) ) // not a vhc\r
+        {\r
+          // Is it a PC ?\r
+          PClient* tClient;\r
+          if (( tClient = CurrentWorld->GetClientByCharLocalId( mRawItemID ) ) )\r
+          {\r
+            /*if(gDevDebug)*/\r
+            Console->Print( "%s clicking on PC %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID );\r
+            tmpMsg = MsgBuilder->BuildCharInteractionMenuMsg( nClient, mRawItemID );\r
+            nClient->SendUDPMessage( tmpMsg );\r
+            mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+          }\r
+        }\r
+\r
+        if ( !( mDecodeData->mState & DECODE_ACTION_DONE ) ) // not a vhc nor a pc\r
+        {
+            //Console->Print(">>> Searching world");\r
+          // Is it a NPC ?\r
+          PNPC* targetNPC = 0;\r
+          PNPCWorld* currentNPCWorld = NPCManager->GetWorld( nChar->GetLocation() );\r
+          if ( currentNPCWorld )\r
+          {
+              //Console->Print(">>> Searching NPC (SQL Version)");\r
+            targetNPC = currentNPCWorld->GetNPC( mRawItemID );
+            if(!targetNPC)
+            {
+                //Console->Print(">>> Searching NPC (DEF Version)");
+                // Note to myself: This is UGLY!!!! and BAD!!! but it works for now. CHANGE THIS!
+                targetNPC = currentNPCWorld->GetNPC( mRawItemID - 255 );
+            }\r
+          }\r
+          if ( targetNPC )\r
+          {
+            /*if(gDevDebug)*/\r
+            Console->Print( "%s Player talks to NPC %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID );\r
+            //if(gDevDebug) tContainer->Dump();\r
+\r
+            // Well its not "start a conversation" its more "User clicked NPC, do anything with it (Trade, script,...)
+            targetNPC->StartConversation(nClient);\r
+\r
+            //tmpMsg = MsgBuilder->BuildTraderItemListMsg( nClient, mRawItemID );\r
+            //tmpMsg->Dump();\r
+            //nClient->FragmentAndSendUDPMessage( tmpMsg, 0xac );\r
+          }\r
+        }\r
+\r
+        mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+      }\r
+    }\r
+    else // furniture objects\r
+    {\r
+      const PFurnitureItemTemplate* tFurnitureTemplate = NULL;\r
+      const PDefWorldModel* tFurnitureModel = NULL;\r
+      if ( tHandleDynamicActor == false )\r
+      {\r
+        // We have an STATIC ACTOR, which means we DONT KNOW the FUNCTION VALUE from pak_worldmodel.def yet\r
+        // (the setentry one). So we need to get it over the .dat file:\r
+\r
+        // Dat files have smaller IDs\r
+        ItemID = mRawItemID / 1024 - 1;\r
+\r
+        // Now grab the template from .dat file\r
+        tFurnitureTemplate = CurrentWorld->GetFurnitureItemTemplate( ItemID );\r
+\r
+        // Then get the FUNCTION VALUE as furniture model so we can access its subvalues etc\r
+        tFurnitureModel = CurrentWorld->GetFurnitureItemModel( ItemID );\r
+      }\r
+      else\r
+      {\r
+        // We have an DYNAMIC ACTOR, which means we DO KNOW the FUNCTION VALUE (stored in SQL).\r
+\r
+        // First, assign the RawID to the "real" itemID, which is used for several objects to identify them clientside\r
+        ItemID = mRawItemID;\r
+\r
+        // Now get the get the function value:\r
+        int tFunctionVal = WorldActors->GetWorldActorFunctionID( mRawItemID );\r
+\r
+        // Then get the FUNCTION VALUE as furniture model so we can access its subvalues etc\r
+        tFurnitureModel = GameDefs->WorldModels()->GetDef( tFunctionVal );\r
+\r
+        if ( gDevDebug )\r
+          Console->Print( "%s Processing dynmic actor %d with Functionvalue %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID, tFunctionVal );\r
+      }\r
+\r
+      if ( tFurnitureModel ) // valid active furniture (else invalid or passive furniture)\r
+      {\r
+        if ( nClient->GetDebugMode( DBG_ITEMID ) )\r
+        {\r
+          snprintf( DbgMessage, 128, "Item : %s", tFurnitureModel->GetName().c_str() );\r
+          Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
+        }\r
+\r
+        if ( tFurnitureModel->GetUseFlags() & ufChair )\r
+        {\r
+          u32 cSeatObjectId;\r
+          PSeatType cSeatType = nChar->GetSeatInUse( &cSeatObjectId );\r
+          if (( cSeatType == seat_none ) || ( cSeatType == seat_chair ) )\r
+          {\r
+            if ( CurrentWorld->CharUseChair( nClient->GetLocalID(), ItemID ) )\r
+            {\r
+              if ( gDevDebug )\r
+                Console->Print( "%s Localchar %d was previously using chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nClient->GetLocalID(), cSeatObjectId );\r
+              if (( cSeatType ) && ( cSeatObjectId != ItemID ) )\r
+              {\r
+                CurrentWorld->CharLeaveChair( nClient->GetLocalID(), cSeatObjectId );\r
+              }\r
+              nChar->SetSeatInUse( seat_chair, ItemID );\r
+              if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )\r
+              {\r
+                tFurnitureTemplate->GetFrontPos( &( nChar->Coords.mX ), &( nChar->Coords.mY ), &( nChar->Coords.mZ ) );\r
+                //(nChar->Coords).mLR = tFurnitureTemplate->GetFrontLR();\r
+              }\r
+              else\r
+              {\r
+                WorldActors->GetFrontPos( mRawItemID, &( nChar->Coords.mX ), &( nChar->Coords.mY ), &( nChar->Coords.mZ ) );\r
+                //(nChar->Coords).mLR = WorldActors->GetFrontLR();\r
+              }\r
+\r
+              tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, mRawItemID );\r
+              ClientManager->UDPBroadcast( tmpMsg, nClient );\r
+            }\r
+            else\r
+            {\r
+              tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, mRawItemID ); // "Already in use" msg\r
+              nClient->SendUDPMessage( tmpMsg );\r
+            }\r
+          }\r
+\r
+          mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+        }\r
+        else\r
+        {\r
+          if ( gDevDebug )\r
+            Console->Print( "%s Item function type: %d value: %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), tFurnitureModel->GetFunctionType(), tFurnitureModel->GetFunctionValue() );\r
+\r
+          DbgMessage[0] = 0;\r
+          switch ( tFurnitureModel->GetFunctionType() )\r
+          {\r
+            case 6: //Respawn Station (GenRep)\r
+            {\r
+              u32 nLocation = nChar->GetLocation();\r
+              u16 nEntity;\r
+              if ( Worlds->IsPotentialAppartement( nLocation ) )\r
+              {\r
+                nLocation = 0xffffffff; // (u32)-1;\r
+                nEntity = 0xffff; //(u16)-1;\r
+              }\r
+              else\r
+              {\r
+                //nEntity = MySQL->GetWorldItemOption(mRawItemID/256, nLocation, 1);\r
+                // This is a kind of nearly-not-hardcoded-hack ...\r
+                int nEntityInt = 0;\r
+                if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )\r
+                {\r
+                  nEntityInt = GameDefs->Respawns()->GetRespawnEntity( nChar->GetLocation(), tFurnitureTemplate->GetLinkedObjectID() );\r
+                }\r
+                else\r
+                {\r
+                  nEntityInt = GameDefs->Respawns()->GetRespawnEntity( nChar->GetLocation(), WorldActors->GetLinkedObjectID( mRawItemID ) );\r
+                }\r
+\r
+                nEntity = ( nEntityInt < 0 ? 0xffff : ( u16 )nEntityInt );\r
+              }\r
+\r
+              tmpMsg = MsgBuilder->BuildCharUseGenrepMsg( nClient, mRawItemID, nLocation, nEntity );\r
+              nClient->SendUDPMessage( tmpMsg );\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+\r
+            case 7: //GoGuardian\r
+            {\r
+              tmpMsg = MsgBuilder->BuildCharUseGogoMsg( nClient );\r
+              nClient->SendUDPMessage( tmpMsg );\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+\r
+            case 9: //Appartement Eingang\r
+            {\r
+              tmpMsg = MsgBuilder->BuildCharUseLiftMsg( nClient, mRawItemID, tFurnitureModel->GetFunctionValue() );\r
+              nClient->SendUDPMessage( tmpMsg );\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+\r
+            case 10: //Appartement Ein/Ausgang\r
+            {\r
+              tmpMsg = MsgBuilder->BuildCharUseLiftMsg( nClient, mRawItemID, 0 );\r
+              nClient->SendUDPMessage( tmpMsg );\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+\r
+            case 15: //HOLOMATCH EXIT\r
+            {\r
+              // temp hack + wrong entity... guess it works same as function 20\r
+              u32 HoloNum = nChar->GetLocation() - 90000; // value 1 to 16, to transalte to 540..547 550..557 for worldmodel.def\r
+\r
+              const PDefWorldModel* tHoloExitModel = GameDefs->WorldModels()->GetDef( 539 + HoloNum + ( HoloNum > 8 ? 2 : 0 ) );\r
+              if ( tHoloExitModel && ( tHoloExitModel->GetFunctionType() == 14 ) ) // we use the Holomatch entry. Takes care of bad zone id\r
+              {\r
+                const PDefAppPlace* nAppPlace = GameDefs->AppPlaces()->GetDef( tHoloExitModel->GetFunctionValue() );\r
+                if ( nAppPlace )\r
+                {\r
+                  u32 Location = nAppPlace->GetExitWorldID();\r
+                  u16 Entity = nAppPlace->GetExitWorldEntity();\r
+                  u8 SewerLevel = 0;\r
+\r
+                  tmpMsg = MsgBuilder->BuildChangeLocationMsg( nClient, Location, Entity, SewerLevel, 0 ); //mRawItemID\r
+                  nClient->SendUDPMessage( tmpMsg );\r
+                  if ( gDevDebug )\r
+                    Console->Print( "%s Holoexit: Client[%d] Char[%s] moving to zone %d (%s)", Console->ColorText( GREEN, BLACK, "[Debug]" ), nClient->GetID(), nChar->GetName().c_str(), Location, nAppPlace->GetName().c_str() );\r
+                  if ( gDevDebug )\r
+                    Console->Print( "%s Location=%d Entity=%d Level=%d", Console->ColorText( CYAN, BLACK, "[Debug]" ), Location, Entity, SewerLevel );\r
+                }\r
+                else\r
+                {\r
+                  Console->Print( "%s Client[%d] Char[%s] invalid destination %d (appplaces.def)", Console->ColorText( RED, BLACK, "[Warning]" ), nClient->GetID(), nChar->GetName().c_str(), tFurnitureModel->GetFunctionValue() );\r
+                }\r
+              }\r
+              else\r
+              {\r
+                Console->Print( "%s Client[%d] Char[%s] invalid holoentry used %d", Console->ColorText( RED, BLACK, "[Warning]" ), nClient->GetID(), nChar->GetName().c_str(), tFurnitureModel->GetFunctionValue() );\r
+              }\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+            case 18: // "WORLDCHANGEACTOR"\r
+            case 20: // "DATFILE WORLDCHANGE ACTOR"\r
+            case 29: //Underground Exit\r
+            {\r
+              const PDefAppPlace* nAppPlace;\r
+              if ( tFurnitureModel->GetFunctionType() == 29 )\r
+              {\r
+                nAppPlace = GameDefs->AppPlaces()->GetDef( nChar->GetLocation() ); // special for UG exit\r
+              }\r
+              else\r
+              {\r
+                nAppPlace = GameDefs->AppPlaces()->GetDef( tFurnitureModel->GetFunctionValue() );\r
+              }\r
+              if ( nAppPlace )\r
+              {\r
+                u32 Location = nAppPlace->GetExitWorldID();\r
+                u16 Entity = nAppPlace->GetExitWorldEntity();\r
+                u8 SewerLevel = 0;\r
+                //if(((tFurnitureModel->GetFunctionType() == 20) && nAppPlace->GetSewerLevel()) || (tFurnitureModel->GetFunctionType() == 29))\r
+                if (( tFurnitureModel->GetFunctionType() == 20 ) || ( tFurnitureModel->GetFunctionType() == 29 ) )\r
+                {\r
+                  SewerLevel = 1;\r
+                }\r
+\r
+                tmpMsg = MsgBuilder->BuildChangeLocationMsg( nClient, Location, Entity, SewerLevel, mRawItemID ); //mRawItemID\r
+                nClient->SendUDPMessage( tmpMsg );\r
+                if ( gDevDebug )\r
+                {\r
+                  Console->Print( "%s Dungeon in/out: Client[%d] Char[%s] moving to zone %d, %s", Console->ColorText( GREEN, BLACK, "[Debug]" ), nClient->GetID(), nChar->GetName().c_str(), Location, nAppPlace->GetName().c_str() );\r
+                  Console->Print( "%s Location=%d Entity=%d Level=%d", Console->ColorText( CYAN, BLACK, "[Debug]" ), Location, Entity, SewerLevel );\r
+                  Console->Print( "%s Function: %d, Value: %d - Sewer level in appplaces.def for this point: %d", Console->ColorText( CYAN, BLACK, "[Debug]" ), tFurnitureModel->GetFunctionType(), tFurnitureModel->GetFunctionValue(), nAppPlace->GetSewerLevel() );\r
+                  Console->Print( "%s Worldmodel id: %d", Console->ColorText( CYAN, BLACK, "[Debug]" ), tFurnitureModel->GetID() );\r
+                }\r
+              }\r
+              else\r
+              {\r
+                Console->Print( "%s Client[%d] Char[%s] invalid destination %d (appplaces.def)", Console->ColorText( RED, BLACK, "[Warning]" ), nClient->GetID(), nChar->GetName().c_str(), tFurnitureModel->GetFunctionValue() );\r
+                // send a "refused" msg ?\r
+              }\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              //nextAnalyser = new PUdpCharJump(mDecodeData);\r
+              break;\r
+            }\r
+\r
+            case 2: //Terminal\r
+            case 3: //Outfitter\r
+            case 16: //HOLOMATCH REFRESH\r
+            case 17: //HOLOMATCH HEAL & Recreation units\r
+            case 26: //Outpost Switch\r
+            {\r
+              tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
+              nClient->SendUDPMessage( tmpMsg );\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+\r
+            case 31: //Venture Warp Station\r
+            {\r
+              tmpMsg = MsgBuilder->BuildCharUseVentureWarpMsg( nClient, mRawItemID );\r
+              nClient->SendUDPMessage( tmpMsg );\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+\r
+            case 28: //Fahrzeug Depot Interface\r
+            {\r
+              tmpMsg = MsgBuilder->BuildCharUseVhcTerminalMsg( nClient, mRawItemID );\r
+              nClient->SendUDPMessage( tmpMsg );\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+\r
+            case 11: //Appartement Klingel/�ffner\r
+            {\r
+              if ( Appartements->CanFreelyEnter( nChar, nChar->GetLocation() ) )\r
+              {\r
+                if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )\r
+                {\r
+                  if ( tFurnitureTemplate->GetLinkedObjectID() )\r
+                  {\r
+                    tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() );\r
+                    ClientManager->UDPBroadcast( tmpMsg, nClient );\r
+                  }\r
+                  else\r
+                  {\r
+                    tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );\r
+                    nClient->SendUDPMessage( tmpMsg );\r
+                  }\r
+                }\r
+                else\r
+                {\r
+                  if ( WorldActors->GetLinkedObjectID( mRawItemID ) )\r
+                  {\r
+                    tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + WorldActors->GetLinkedObjectID( mRawItemID ), CurrentWorld->GetDoor( WorldActors->GetLinkedObjectID( mRawItemID ) )->IsDoubleDoor() );\r
+                    ClientManager->UDPBroadcast( tmpMsg, nClient );\r
+                  }\r
+                  else\r
+                  {\r
+                    tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );\r
+                    nClient->SendUDPMessage( tmpMsg );\r
+                  }\r
+                }\r
+              }\r
+              else\r
+              {\r
+                tmpMsg = MsgBuilder->BuildFurnitureActivateMsg( nClient, mRawItemID, 5 ); // Ring\r
+                ClientManager->UDPBroadcast( tmpMsg, nClient );\r
+              }\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+\r
+            case 12: //Standard Button\r
+            {\r
+              if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )\r
+              {\r
+                if ( tFurnitureTemplate->GetLinkedObjectID() )\r
+                {\r
+                  tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() );\r
+                  ClientManager->UDPBroadcast( tmpMsg, nClient );\r
+                }\r
+                else\r
+                {\r
+                  tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
+                  nClient->SendUDPMessage( tmpMsg );\r
+                }\r
+              }\r
+              else\r
+              {\r
+                if ( WorldActors->GetLinkedObjectID( mRawItemID ) )\r
+                {\r
+                  tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + WorldActors->GetLinkedObjectID( mRawItemID ), CurrentWorld->GetDoor( WorldActors->GetLinkedObjectID( mRawItemID ) )->IsDoubleDoor() );\r
+                  ClientManager->UDPBroadcast( tmpMsg, nClient );\r
+                }\r
+                else\r
+                {\r
+                  tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
+                  nClient->SendUDPMessage( tmpMsg );\r
+                }\r
+              }\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+            case 13: //Hack Button\r
+            {\r
+              if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )\r
+              {\r
+                if ( tFurnitureTemplate->GetLinkedObjectID() )\r
+                {\r
+                  if ( nClient->GetAccountLevel() >= PAL_GM ) // Allow GameMasters and higher to just bypass HackButtons\r
+                  {\r
+                    tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() );\r
+                    ClientManager->UDPBroadcast( tmpMsg, nClient );\r
+                  }\r
+                  else\r
+                  {\r
+                    tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 106 ); // Damn, locked!\r
+                    nClient->SendUDPMessage( tmpMsg );\r
+                  }\r
+\r
+                }\r
+                else\r
+                {\r
+                  tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );\r
+                  nClient->SendUDPMessage( tmpMsg );\r
+                }\r
+              }\r
+              else\r
+              {\r
+                u32 linkobjID = WorldActors->GetLinkedObjectID( mRawItemID );\r
+                if ( linkobjID )\r
+                {\r
+                  if ( nClient->GetAccountLevel() >= PAL_GM ) // Allow GameMasters and higher to just bypass HackButtons\r
+                  {\r
+                    tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + linkobjID, CurrentWorld->GetDoor( linkobjID )->IsDoubleDoor() );\r
+                    ClientManager->UDPBroadcast( tmpMsg, nClient );\r
+                  }\r
+                  else\r
+                  {\r
+                    tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 106 ); // Damn, locked!\r
+                    nClient->SendUDPMessage( tmpMsg );\r
+                  }\r
+\r
+                }\r
+                else\r
+                {\r
+                  tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );\r
+                  nClient->SendUDPMessage( tmpMsg );\r
+                }\r
+              }\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+\r
+            case 23: //EINTRITTSGELD BUTTON\r
+            {\r
+              if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )\r
+              {\r
+                if ( tFurnitureTemplate->GetLinkedObjectID() )\r
+                {\r
+                  u32 OldCash = nChar->GetCash();\r
+                  u32 DoorFee = ( u32 )tFurnitureModel->GetFunctionValue();\r
+                  if ( OldCash >= DoorFee )\r
+                  {\r
+                    u32 NewCash = nChar->SetCash( OldCash - DoorFee );\r
+                    PMessage* tmpMsg_cash = MsgBuilder->BuildCharMoneyUpdateMsg( nClient, NewCash );\r
+                    nClient->SendUDPMessage( tmpMsg_cash );\r
+                    tmpMsg_cash = NULL;\r
+                    tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() );\r
+                    ClientManager->UDPBroadcast( tmpMsg, nClient );\r
+                  }\r
+                  else\r
+                  {\r
+                    tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 12 );  // You dont have enough money!\r
+                    nClient->SendUDPMessage( tmpMsg );\r
+                  }\r
+                }\r
+                else\r
+                {\r
+                  tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );\r
+                  nClient->SendUDPMessage( tmpMsg );\r
+                }\r
+              }\r
+              else\r
+              {\r
+                u32 linkobjID = WorldActors->GetLinkedObjectID( mRawItemID );\r
+                if ( linkobjID )\r
+                {\r
+                  u32 OldCash = nChar->GetCash();\r
+                  u32 DoorFee = ( u32 )tFurnitureModel->GetFunctionValue();\r
+                  if ( OldCash >= DoorFee )\r
+                  {\r
+                    u32 NewCash = nChar->SetCash( OldCash - DoorFee );\r
+                    PMessage* tmpMsg_cash = MsgBuilder->BuildCharMoneyUpdateMsg( nClient, NewCash );\r
+                    nClient->SendUDPMessage( tmpMsg_cash );\r
+                    tmpMsg_cash = NULL;\r
+                    tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + linkobjID, CurrentWorld->GetDoor( linkobjID )->IsDoubleDoor() );\r
+                    ClientManager->UDPBroadcast( tmpMsg, nClient );\r
+                  }\r
+                  else\r
+                  {\r
+                    tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 12 );  // You dont have enough money!\r
+                    nClient->SendUDPMessage( tmpMsg );\r
+                  }\r
+                }\r
+                else\r
+                {\r
+                  tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );\r
+                  nClient->SendUDPMessage( tmpMsg );\r
+                }\r
+              }\r
+\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+            case 1: //Itemcontainer\r
+            {\r
+              // TODO: Add check if container is already open / Make containers persistent\r
+              // PContainer* tContainer = World->GetContainer(mRawItemID);\r
+              PContainer* tContainer = new PContainerAutoCompactOnClose( INV_CABINET_MAXSLOTS );\r
+              int functionVal = tFurnitureModel->GetFunctionValue();\r
+              if ( functionVal <= 5 ) // force full random for cabinets for item testing\r
+                functionVal = -1;\r
+              tContainer->RandomFill( INV_CABINET_MAXSLOTS, functionVal );\r
+\r
+              /*nItem = new PItem(19, 1, 250, 250, 250, 250, 250, 250);\r
+              if(nItem->GetItemID());\r
+                tContainer->AddItem(nItem);*/\r
+              if ( gDevDebug ) Console->Print( "%s Temporary container created", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
+              //if(gDevDebug) tContainer->Dump();\r
+              if ( tContainer->StartUse( nChar->GetID() ) )\r
+              {\r
+                nChar->SetContainerInExclusiveUse( tContainer );\r
+                tmpMsg = MsgBuilder->BuildCharOpenContainerMsg( nClient, mRawItemID, tContainer );\r
+                //tmpMsg->Dump();\r
+                nClient->FragmentAndSendUDPMessage( tmpMsg, 0x05 );\r
+              }\r
+              else\r
+              {\r
+                tmpMsg = MsgBuilder->BuildFurnitureActivateMsg( nClient, mRawItemID, 10 );\r
+                nClient->SendUDPMessage( tmpMsg );\r
+                tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, mRawItemID );\r
+                nClient->SendUDPMessage( tmpMsg );\r
+              }\r
+\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+            case 32: // Text message\r
+            {\r
+              tmpMsg = MsgBuilder->BuildText100Msg( nClient, ( u8 )( 255 & tFurnitureModel->GetFunctionValue() ), mRawItemID );\r
+              nClient->SendUDPMessage( tmpMsg );\r
+\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+            // Temp placeholder implementations ============================\r
+            case 4: //Trader\r
+            {\r
+              snprintf( DbgMessage, 128, "That's a trader" );\r
+              Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
+              tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
+              nClient->SendUDPMessage( tmpMsg );\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+            case 5: //Mineral\r
+            {\r
+              snprintf( DbgMessage, 128, "That's some minerals" );\r
+              Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
+              tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
+              nClient->SendUDPMessage( tmpMsg );\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+            case 8: //Hackterminal\r
+            {\r
+              snprintf( DbgMessage, 128, "That's a hacking terminal" );\r
+              Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
+              tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
+              nClient->SendUDPMessage( tmpMsg );\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+            case 14: //HOLOMATCH ENTRANCE\r
+            {\r
+              snprintf( DbgMessage, 128, "That's an holomatch entrance" );\r
+              Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
+              tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
+              nClient->SendUDPMessage( tmpMsg );\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+            case 19: //CLANTERMINAL\r
+            {\r
+              snprintf( DbgMessage, 128, "That's a clan terminal" );\r
+              Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
+              tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
+              nClient->SendUDPMessage( tmpMsg );\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+            case 25: //EXPLOSIVE\r
+            {\r
+              snprintf( DbgMessage, 128, "That's explosive !" );\r
+              Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
+              tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
+              nClient->SendUDPMessage( tmpMsg );\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+            case 0: //May be roadsign if touchable\r
+            {\r
+              if ( ( tFurnitureModel->GetUseFlags() & ufTouchable ) ) // Touchable ?\r
+              {\r
+                snprintf( DbgMessage, 128, "You're at %s", tFurnitureModel->GetName().c_str() );\r
+                Chat->send( nClient, CHAT_GM, "Information", DbgMessage );\r
+                tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
+                nClient->SendUDPMessage( tmpMsg );\r
+                mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+                break;\r
+              }\r
+              // else we continue to undefined\r
+            }\r
+            case 27: //Old goguardian\r
+              //case 21: //LOCATION FOR 20\r
+              //case 22: //\r
+            case 24: //TUTORIALEXIT\r
+              //case 30: //Static FX (Value=Type. 1=Fire 2=Smoke 3=Steam 4=Sparkle)\r
+            {\r
+              tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
+              nClient->SendUDPMessage( tmpMsg );\r
+              mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+              break;\r
+            }\r
+\r
+            default:\r
+              break;\r
+          }\r
+        }\r
+      }\r
+      else\r
+      {\r
+        if ( gDevDebug )\r
+          Console->Print( "%s Item not known from world template (maybe seen as PASSIVE ?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
+      }\r
+    }\r
+\r
+    mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  }\r
+  else\r
+  {\r
+    Console->Print( RED, BLACK, "[ERROR] PUdpUseObject::DoAction : No World defined for client %d (char %d)", nClient->GetID(), nChar->GetID() );\r
+    mDecodeData->mState = DECODE_ACTION_FAILED | DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  }\r
+\r
+  return true;\r
+}\r
+\r
+/**** PUdpCloseItemContainer ****/\r
+\r
+PUdpCloseItemContainer::PUdpCloseItemContainer( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x27";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpCloseItemContainer::Analyse()\r
+{\r
+  mDecodeData->mName << "=Closing item container";\r
+\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+  return this;\r
+}\r
+\r
+bool PUdpCloseItemContainer::DoAction()\r
+{\r
+//  PClient* nClient = mDecodeData->mClient;\r
+//  PChar* nChar = nClient->GetChar();\r
+\r
+  PChar* nChar = mDecodeData->mClient->GetChar();\r
+  PContainer* tContainer = nChar->GetContainerInExclusiveUse();\r
+  if ( tContainer )\r
+  {\r
+    nChar->SetContainerInExclusiveUse( NULL );\r
+    tContainer->EndUse( nChar->GetID() );\r
+    if ( ! tContainer->GetOwnerId() )\r
+    {\r
+      delete tContainer;\r
+      if ( gDevDebug ) Console->Print( "%s Temporary container deleted", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
+    }\r
+  }\r
+\r
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  return true;\r
+}\r
diff --git a/server/src/game/decoder/udp_useobject.h b/server/src/game/decoder/udp_useobject.h
new file mode 100644 (file)
index 0000000..f87a2b0
--- /dev/null
@@ -0,0 +1,60 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udp_useobject.h - decoder classes for object use related messages\r
+\r
+       CREATION: 17 Sep 2006 Hammag\r
+\r
+       MODIFIED:\r
+       REASON: -\r
+\r
+*/\r
+\r
+#ifndef UDPUSEOBJECT_H\r
+#define UDPUSEOBJECT_H\r
+\r
+class PUdpUseObject : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u32 mRawItemID;\r
+\r
+    void OldHandler(); // Temp during migration only\r
+\r
+  public:\r
+    PUdpUseObject(PMsgDecodeData* nDecodeData);\r
+    //~PUdpUseObject();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpCloseItemContainer : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+\r
+  public:\r
+    PUdpCloseItemContainer(PMsgDecodeData* nDecodeData);\r
+    //~PUdpCloseItemContainer();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+#endif\r
diff --git a/server/src/game/decoder/udp_vhc.cpp b/server/src/game/decoder/udp_vhc.cpp
new file mode 100644 (file)
index 0000000..ba99f97
--- /dev/null
@@ -0,0 +1,444 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+ udp_vhc.h - decoder classes for UDP vehicle related messages\r
+\r
+ CREATION: 5 Sep 2006 Hammag\r
+\r
+ MODIFIED:\r
+ REASON: -\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "worlds.h"\r
+#include "vehicle.h"\r
+#include "udp_vhc.h"\r
+#include "subway.h"\r
+\r
+/**** PUdpVhcMove ****/\r
+\r
+PUdpVhcMove::PUdpVhcMove( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x32";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpVhcMove::Analyse()\r
+{\r
+  mDecodeData->mName << "=Vhc move";\r
+\r
+  PMessage* nMsg = mDecodeData->mMessage;\r
+  nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 2 );\r
+\r
+  *nMsg >> mVhcLocalId;\r
+  *nMsg >> mMoveType; // 0 for subway/chair, 3 for vhc, 7 in nc2.2\r
+  *nMsg >> mNewY;\r
+  *nMsg >> mNewZ;\r
+  *nMsg >> mNewX;\r
+  *nMsg >> mNewUD; // neutral :=0x7f, > := upward, < := downward\r
+  *nMsg >> mNewLR;\r
+  *nMsg >> mNewRoll; // neutral := 0x7fff > := bank left, < := bank right\r
+  *nMsg >> mUnk1;\r
+  *nMsg >> mFF;\r
+  *nMsg >> mAction;\r
+//0 = not moving\r
+//&01 = Left\r
+//&02 = Right\r
+//&04 = Forward\r
+//&08 = Back\r
+//&10 = Shoot button\r
+//&20 = Pushing down\r
+//&40 = Pulling up\r
+//\r
+  /*\r
+  --- rolling front+left\r
+  13 b0 00 02 bf\r
+  15\r
+  32\r
+  c9 03 =short VhcId\r
+  07\r
+  c3 66 37 8b 47 6e 80 2a 88 70 27 22\r
+  81\r
+  01 00\r
+  ff = speed% ?\r
+  05 = forward+left ?\r
+  => srv resp\r
+  13 6b 01 bd bf\r
+  18\r
+  03 6a 01 32 c9 03 07 8b 66 37 8b d9 6d 80 e0 8f\r
+  ea 27 22 81 01 00 ff 05\r
+  0c\r
+  03 6b 01 1f 01 00 30 5e 79 36 87 87\r
+  13\r
+  32 c9 03 03 8b 66 38 8b d9 6d 7f 2a 88 92 7f 01 00 00 05\r
+  0b\r
+  20 ed 03 5d 5a c8 8d 9b 7b c2 00\r
+\r
+  --- stopped\r
+  13 88 01 da bf\r
+  13\r
+  32\r
+  c9 03 =short VhcId\r
+  03\r
+  05\r
+  66 36 8b 90 6d 7f 5b 9d 00\r
+  80\r
+  01 00\r
+  00 = speed% ?\r
+  00 = no move\r
+\r
+  */\r
+  if ( gDevDebug )\r
+  {\r
+    Console->Print( YELLOW, BLACK, "[DEBUG] VHC move type %d - objid %d", mMoveType, mVhcLocalId );\r
+    //nMsg->Dump();\r
+    Console->Print( "X=%d Y=%d Z=%d Act=%d", mNewX - 768, mNewY - 768, mNewZ - 768, mAction );\r
+    Console->Print( "LR=%d UD=%d Ro=%d Unk=%d Act=%02x ff=%x", mNewLR, mNewUD, mNewRoll, mUnk1, mAction, mFF );\r
+    Console->Print( "Msg len: %d", nMsg->U8Data( mDecodeData->Sub0x13Start ) );\r
+  }\r
+\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+  return this;\r
+}\r
+\r
+bool PUdpVhcMove::DoAction()\r
+{\r
+  PClient* nClient = mDecodeData->mClient;\r
+  //PCharCoordinates* nCoords = &(nClient->GetChar()->Coords);\r
+  PWorld* CurrentWorld = Worlds->GetWorld( nClient->GetChar()->GetLocation() );\r
+\r
+  if ( CurrentWorld )\r
+  {\r
+    PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicules()->GetVehicle( mVhcLocalId );\r
+    if ( tVhc )\r
+    {\r
+      //Todo: calc & mem Speed & Accel vectors\r
+      PVhcCoordinates nPos;\r
+      nPos.SetPosition( mNewY - 768, mNewZ - 768, mNewX - 768, mNewUD, mNewLR, mNewRoll, mAction, mUnk1, mFF );\r
+      tVhc->SetPosition( &nPos );\r
+      PMessage* tmpMsg = MsgBuilder->BuildVhcPosUpdate2Msg( tVhc );\r
+      ClientManager->UDPBroadcast( tmpMsg, mDecodeData->mClient );\r
+\r
+      tmpMsg = MsgBuilder->BuildVhcPosUpdateMsg( tVhc );\r
+      ClientManager->UDPBroadcast( tmpMsg, mDecodeData->mClient );\r
+\r
+      if( CurrentWorld->CheckVhcNeedZoning( &nPos ) )\r
+      {\r
+        u32 destWorldId;\r
+        PVhcCoordinates destPos;\r
+\r
+        if (( destWorldId = CurrentWorld->GetVhcZoningDestination( tVhc, &destPos ) ) )\r
+        {\r
+          if ( nClient->GetDebugMode( DBG_LOCATION ) )\r
+          {\r
+            u8 pH = 0;\r
+            u8 pV = 0;\r
+            Worlds->GetWorldmapFromWorldId( destWorldId, pH, pV );\r
+            char DbgMessage[128];\r
+            snprintf( DbgMessage, 128, "Vhc zoning to zone %c%02d (id %d)", ( 'a' + pV ), pH, destWorldId );\r
+            Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
+          }\r
+  \r
+          DoVhcZoning( tVhc, nClient->GetChar()->GetLocation(), destWorldId, &destPos );\r
+        }\r
+      }\r
+    }\r
+    else\r
+      Console->Print( RED, BLACK, "[Error] PUdpVhcMove: Inexistant vhc Id %d", mVhcLocalId );\r
+  }\r
+\r
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  return true;\r
+}\r
+\r
+// Failures are not managed yet\r
+bool PUdpVhcMove::DoVhcZoning( PSpawnedVehicle* currVhc, u32 currWorldId, u32 destWorldId, PVhcCoordinates* destPos )\r
+{\r
+  u32 seatedCharsId[8];\r
+  u32 vhcGlobalId = currVhc->GetVehicleId();\r
+  u32 vhcLocalId = currVhc->GetLocalId();\r
+  PVhcCoordinates currCoords = currVhc->GetPosition();\r
+  u8 numSeats = currVhc->GetNumSeats();\r
+  u32 sittingCharId;\r
+  PClient* sittingClient;\r
+  PClient* sittingClients[8];\r
+  PMessage* tmpMsg;\r
+\r
+  for ( u8 i = 0; i < numSeats; ++i )\r
+  {\r
+    // Save seated chars list\r
+    seatedCharsId[i] = sittingCharId = currVhc->GetSeatUser( i );\r
+\r
+    if ( sittingCharId )\r
+    {\r
+      sittingClients[i] = sittingClient = ClientManager->getClientByChar( sittingCharId );\r
+      // Tag each client as zoning to avoid transient side effects\r
+      sittingClient->SetZoning();\r
+      sittingClient->SetVhcZoning();\r
+      // Trigger zoning\r
+      //tmpMsg = MsgBuilder->BuildGenrepZoningMsg( sittingClient, destWorldId, 0 ); // unknown value // 0x62bc or 0x2d4e\r
+      //sittingClient->SendUDPMessage( tmpMsg );\r
+      // We send the unseat msg to the corresponding client only.\r
+      sittingClient->GetChar()->Coords.SetPosition( currCoords.GetY(), currCoords.GetZ(), currCoords.GetX() );\r
+      tmpMsg = MsgBuilder->BuildCharExitSeatMsg( sittingClient );\r
+      sittingClient->FillInUDP_ID( tmpMsg );\r
+      sittingClient->SendUDPMessage( tmpMsg );\r
+    }\r
+    else\r
+      sittingClients[i] = 0;\r
+  }\r
+\r
+  // Unspawn vhc instance from local world\r
+  Vehicles->UnspawnVehicle( vhcGlobalId );\r
+  tmpMsg = MsgBuilder->BuildRemoveWorldObjectMsg( vhcLocalId );\r
+  ClientManager->UDPBroadcast( tmpMsg, currWorldId );\r
+\r
+  // Spawn vhc instance in destWorld\r
+  PSpawnedVehicle* destVhc = Vehicles->SpawnVehicle( vhcGlobalId, destWorldId, destPos );\r
+  if ( destVhc )\r
+  {\r
+    tmpMsg = MsgBuilder->BuildVhcPosUpdateMsg( destVhc );\r
+    ClientManager->UDPBroadcast( tmpMsg, destWorldId );\r
+\r
+    vhcLocalId = destVhc->GetLocalId();\r
+\r
+    // Update chars seat in use and restore vhc used seats\r
+    PChar* sittingChar;\r
+    for ( u8 i = 0; i < numSeats; ++i )\r
+    {\r
+      if (( sittingClient = sittingClients[i] ) )\r
+      {\r
+        //if ( gDevDebug )\r
+          Console->Print( "%s PUdpVhcMove::DoVhcZoning : Char %d sitting on vhc %d, seat %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), seatedCharsId[i], vhcLocalId, i );\r
+        sittingChar = sittingClient->GetChar();\r
+        sittingChar->SetSeatInUse( seat_vhc, vhcLocalId, i );\r
+        sittingChar->Coords.SetPosition( destPos->GetY(), destPos->GetZ(), destPos->GetX() );\r
+        destVhc->SetSeatUser( i, seatedCharsId[i] );\r
+      }\r
+    }\r
+  }\r
+  else\r
+  {\r
+    for ( u8 i = 0; i < numSeats; ++i )\r
+    {\r
+      if ( sittingClients[i] )\r
+      {\r
+        sittingClients[i]->GetChar()->SetSeatInUse( seat_none );\r
+      }\r
+    }\r
+\r
+    return false;\r
+  }\r
+\r
+  return true;\r
+\r
+}\r
+\r
+/**** PUdpVhcUse ****/\r
+\r
+PUdpVhcUse::PUdpVhcUse( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x0f";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpVhcUse::Analyse()\r
+{\r
+  mDecodeData->mName << "=Try enter vhc";\r
+\r
+  PMessage* nMsg = mDecodeData->mMessage;\r
+  nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 12 );\r
+  *nMsg >> mVehicleID; // u32\r
+  *nMsg >> mVehicleSeat;\r
+\r
+  if ( gDevDebug )\r
+    Console->Print( "%s Localid %d trying to enter vhc %d on seat %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetLocalID(), mVehicleID, mVehicleSeat );\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+  return this;\r
+}\r
+\r
+bool PUdpVhcUse::DoAction()\r
+{\r
+  PClient* nClient = mDecodeData->mClient;\r
+  PChar* nChar = nClient->GetChar();\r
+  PMessage* tmpMsg;\r
+\r
+  if ( nChar->GetSeatInUse() == seat_none ) // Refuse if Char is already sitting somewhere\r
+  {\r
+    PWorld* CurrentWorld = Worlds->GetWorld( nChar->GetLocation() );\r
+    if ( CurrentWorld )\r
+    {\r
+      PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicules()->GetVehicle( mVehicleID );\r
+      if ( tVhc )\r
+      {\r
+        if ( tVhc->SetSeatUser( mVehicleSeat, nChar->GetID() ) ) // Char was able to sit\r
+        {\r
+          nChar->SetSeatInUse( seat_vhc, mVehicleID, mVehicleSeat );\r
+          tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, mVehicleID, mVehicleSeat );\r
+          ClientManager->UDPBroadcast( tmpMsg, nClient );\r
+        }\r
+        else\r
+        {\r
+          tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, mVehicleID ); // Already in use\r
+          nClient->SendUDPMessage( tmpMsg );\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  return true;\r
+}\r
+\r
+void PUdpVhcUse::DoFreeSitting( PClient* nClient,  PSpawnedVehicle* nVhc, u32 nRawVhcLocalId, u8 nSeatId )\r
+{\r
+  PMessage* tmpMsg;\r
+\r
+  if (( nVhc->GetNbFreeSeats() > 1 ) && ( nSeatId > nVhc->GetNumSeats() ) )\r
+  {\r
+    u8 freeSeats = nVhc->GetFreeSeatsFlags();\r
+    tmpMsg = MsgBuilder->BuildCharUseVhcMsg( nClient, nRawVhcLocalId, nVhc->GetInformation().GetVehicleType(), freeSeats );\r
+    nClient->SendUDPMessage( tmpMsg ); // Open seat selection window\r
+  }\r
+  else\r
+  {\r
+    if ( nSeatId <= nVhc->GetNumSeats() )\r
+    {\r
+      if ( nVhc->GetSeatUser( nSeatId ) )\r
+      {\r
+        tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, nRawVhcLocalId ); // Already in use\r
+        nClient->SendUDPMessage( tmpMsg );\r
+      }\r
+    }\r
+    else\r
+    {\r
+      nSeatId = nVhc->GetFirstFreeSeat();\r
+\r
+      if ( nSeatId != 255 )\r
+      {\r
+        if ( nVhc->SetSeatUser( nSeatId, nClient->GetChar()->GetID() ) ) // Char was able to sit\r
+        {\r
+          nClient->GetChar()->SetSeatInUse( seat_vhc, nRawVhcLocalId, nSeatId );\r
+          tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, nRawVhcLocalId, nSeatId );\r
+          ClientManager->UDPBroadcast( tmpMsg, nClient );\r
+        }\r
+        else\r
+        {\r
+          tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, nRawVhcLocalId ); // Undefined failure\r
+          nClient->SendUDPMessage( tmpMsg );\r
+        }\r
+      }\r
+      else\r
+      {\r
+        tmpMsg = MsgBuilder->BuildText100Msg( nClient, 5, nRawVhcLocalId ); // "No free seat" msg\r
+        nClient->SendUDPMessage( tmpMsg );\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+/**** PUdpSubwayUpdate ****/\r
+\r
+PUdpSubwayUpdate::PUdpSubwayUpdate( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x00";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpSubwayUpdate::Analyse()\r
+{\r
+  u8 Dumb;\r
+\r
+  mDecodeData->mName << "=Subway update";\r
+\r
+  PMessage* nMsg = mDecodeData->mMessage;\r
+  nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 2 );\r
+\r
+  *nMsg >> mVehicleID;\r
+  *nMsg >> Dumb;\r
+  *nMsg >> mPosition;\r
+  *nMsg >> mDoorOpened;\r
+\r
+  if ( gDevDebug )\r
+    Console->Print( "%s Subway update 0x%4x : pos 0x%4x, status 0x%2x", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mVehicleID, mPosition, mDoorOpened );\r
+\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+  return this;\r
+}\r
+\r
+bool PUdpSubwayUpdate::DoAction()\r
+{\r
+  /* No real use for that ?\r
+    Subway->UpdateInfo(mVehicleID, mPosition, mDoorOpened);\r
+\r
+    PMessage* tmpMsg = MsgBuilder->BuildSubwaySingleUpdateMsg(mVehicleID, mPosition, mDoorOpened);\r
+    ClientManager->UDPBroadcast(tmpMsg, mDecodeData->mClient);\r
+  */\r
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  return true;\r
+}\r
+\r
+/**** PUdpRequestVhcInfo ****/\r
+\r
+PUdpRequestVhcInfo::PUdpRequestVhcInfo( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
+{\r
+  nDecodeData->mName << "/0x27";\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpRequestVhcInfo::Analyse()\r
+{\r
+  mDecodeData->mName << "=Request seatable object info";\r
+\r
+  PMessage* nMsg = mDecodeData->mMessage;\r
+  nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 2 );\r
+\r
+  *nMsg >> mVehicleID;\r
+\r
+  if ( gDevDebug )\r
+    Console->Print( "%s Request Seatable Info for 0x%04x :", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mVehicleID );\r
+\r
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
+  return this;\r
+}\r
+\r
+bool PUdpRequestVhcInfo::DoAction()\r
+{\r
+  PClient* nClient = mDecodeData->mClient;\r
+  //PCharCoordinates* nCoords = &(nClient->GetChar()->Coords);\r
+  PWorld* CurrentWorld = Worlds->GetWorld( nClient->GetChar()->GetLocation() );\r
+\r
+  if ( CurrentWorld )\r
+  {\r
+    PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicules()->GetVehicle( mVehicleID );\r
+    if ( tVhc )\r
+    {\r
+      if ( gDevDebug )\r
+        Console->Print("%s Sending Info for vhcId 0x%04x : type %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mVehicleID, tVhc->GetInformation().GetVehicleType() );\r
+      PMessage* tmpMsg = MsgBuilder->BuildVhcInfoMsg( nClient, tVhc );\r
+      nClient->SendUDPMessage( tmpMsg );\r
+    }\r
+    else\r
+      Console->Print( RED, BLACK, "[Error] PUdpRequestVhcInfo: Inexistant vhc Id %d", mVehicleID );\r
+  }\r
+\r
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
+  return true;\r
+}\r
diff --git a/server/src/game/decoder/udp_vhc.h b/server/src/game/decoder/udp_vhc.h
new file mode 100644 (file)
index 0000000..bca7a2b
--- /dev/null
@@ -0,0 +1,101 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+ udp_vhc.h - decoder classes for UDP vehicle related messages\r
+\r
+ CREATION: 5 Sep 2006 Hammag\r
+\r
+ MODIFIED:\r
+ REASON: -\r
+\r
+*/\r
+\r
+#ifndef UDPVHC_H\r
+#define UDPVHC_H\r
+\r
+class PSpawnedVehicle;\r
+class PVhcCoordinates;\r
+\r
+class PUdpVhcMove : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u16 mVhcLocalId;\r
+    u16 mNewY;\r
+    u16 mNewZ;\r
+    u16 mNewX;\r
+    u16 mNewLR;\r
+    u16 mNewRoll;\r
+    u16 mUnk1; // always 0x0001 ?\r
+    u8 mMoveType;\r
+    u8 mNewUD;\r
+    u8 mFF; // always 0xff ?\r
+    u8 mAction; // &1 = Left, &2 = Right, &4 = Forward, &8 = Backward\r
+  public:\r
+    PUdpVhcMove( PMsgDecodeData* nDecodeData );\r
+    //~PUdpVhcMove();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+    bool DoVhcZoning( PSpawnedVehicle* currVhc, u32 currWorldId, u32 destWorldId, PVhcCoordinates* destPos );\r
+};\r
+\r
+class PUdpVhcUse : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u32 mVehicleID;\r
+    u8 mVehicleSeat;\r
+\r
+  public:\r
+    PUdpVhcUse( PMsgDecodeData* nDecodeData );\r
+    //~PUdpVhcUse();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+    static void DoFreeSitting(PClient* nClient,  PSpawnedVehicle* nVhc, u32 nRawVhcLocalId, u8 nSeatId = 254);\r
+};\r
+\r
+class PUdpSubwayUpdate : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u32 mVehicleID;\r
+    u16 mPosition;\r
+    u8 mDoorOpened;\r
+\r
+  public:\r
+    PUdpSubwayUpdate( PMsgDecodeData* nDecodeData );\r
+    //~PUdpSubwayUpdate();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpRequestVhcInfo : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u32 mVehicleID;\r
+\r
+  public:\r
+    PUdpRequestVhcInfo( PMsgDecodeData* nDecodeData );\r
+    //~PUdpRequestVhcInfo();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udp_worldIDinfo.cpp b/server/src/game/decoder/udp_worldIDinfo.cpp
new file mode 100644 (file)
index 0000000..51b0dd1
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_worldIDinfo.cpp - decoder classes for UDP "Request for more information about WorldID xx"
+
+ CREATION: 20 Jun 2009 Namikon
+
+ MODIFIED:
+ REASON: -
+
+*/
+
+#include "main.h"
+#include "udp_worldIDinfo.h"
+
+/**** PWorldIDInfoReq ****/
+
+PWorldIDInfoReq::PWorldIDInfoReq(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+    nDecodeData->mName << "/0x27";
+}
+
+PUdpMsgAnalyser* PWorldIDInfoReq::Analyse()
+{\r
+    PMessage* tmpMsg = mDecodeData->mMessage;
+    mDecodeData->mName << "=WorldID Info Req.";\r
+\r
+    tmpMsg->SetNextByteOffset(mDecodeData->Sub0x13Start + 5);\r
+    (*tmpMsg) >> mInfoId;\r
+
+    mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+    return this;
+}
+
+bool PWorldIDInfoReq::DoAction()
+{\r
+    PNPC* targetNPC = NULL;\r
+\r
+    PNPCWorld* currentNPCWorld = NPCManager->GetWorld( mDecodeData->mClient->GetChar()->GetLocation() );\r
+    if ( currentNPCWorld )\r
+    {\r
+        targetNPC = currentNPCWorld->GetNPC( mInfoId );\r
+        if(!targetNPC)\r
+        {\r
+            // Search for DEF version of NPC (remember, def IDs are on 255 offset!\r
+            // Note to myself: This is UGLY!!!! and BAD!!! but it works for now. CHANGE THIS!\r
+            targetNPC = currentNPCWorld->GetNPC( mInfoId - 255 );\r
+        }\r
+    }\r
+    if (!targetNPC)\r
+    {\r
+        // No NPC, skipping\r
+        return true;\r
+    }\r
+\r
+    currentNPCWorld->SendSingleNPCInfo(mDecodeData->mClient, targetNPC);
+    // TODO: Handle client request here!
+    // Note: It *seems* that the client sends this "eek, giev info about ID xxx"
+    // if the NPC/WorldID is "not in the world", means the coods are pointing
+    // the NPC somewhere below ground or inside a wall. However, not 100% sure about that
+    mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+    return true;
+}
diff --git a/server/src/game/decoder/udp_worldIDinfo.h b/server/src/game/decoder/udp_worldIDinfo.h
new file mode 100644 (file)
index 0000000..9289463
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_worldIDinfo.h - decoder classes for UDP "Request for more information about WorldID xx"
+
+ CREATION: 20 Jun 2009 Namikon
+
+ MODIFIED:
+ REASON: -
+
+*/
+
+#ifndef UDPWORLDIDINFO_H
+#define UDPWORLDIDINFO_H
+
+class PWorldIDInfoReq : public PUdpMsgAnalyser
+{\r
+    u32 mInfoId;\r
+
+public:
+    PWorldIDInfoReq(PMsgDecodeData* nDecodeData);
+    //~PWorldIDInfoReq();
+    PUdpMsgAnalyser* Analyse();
+    bool DoAction();
+};
+
+#endif
diff --git a/server/src/game/decoder/udp_zoning.cpp b/server/src/game/decoder/udp_zoning.cpp
new file mode 100755 (executable)
index 0000000..6a8c5ec
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ udp_zoning.cpp - decoder classes for UDP Zoning messages
+
+ CREATION: 6 Sep 2006 Hammag
+
+ MODIFIED: 15 Dec 2006 Hammag
+ REASON: - added PUdpEndOfZoning management class
+
+*/
+
+#include "main.h"
+#include "udp_zoning.h"
+
+#include "udp_sync.h"
+#include "worlds.h"
+#include "appartements.h"
+
+/**** PUdpZoning1 ****/
+
+PUdpZoning1::PUdpZoning1( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x0d";
+}
+
+PUdpMsgAnalyser* PUdpZoning1::Analyse()
+{
+  mDecodeData->mName << "=Zoning phase 1";
+
+  PMessage* cMsg = mDecodeData->mMessage;
+  u8 dumb8;
+  u16 dumb16;
+  //mUnknown = cMsg->U16Data(mDecodeData->Sub0x13Start+7);
+  //mNewLocation = cMsg->U32Data(mDecodeData->Sub0x13Start+11);
+  //mNewEntity = cMsg->U16Data(mDecodeData->Sub0x13Start+15);
+
+  cMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 7 );
+  *cMsg >> dumb8; // u8 = 0x01 in NC1, other in NC2.2 ?
+  *cMsg >> mUnknown; //u8
+  *cMsg >> dumb16; //u16 unkown use
+  *cMsg >> mNewLocation; //u32
+  *cMsg >> mNewEntity; //u16
+  //*cMsg >> dumb16; //u16 0x0000
+//Console->Print("Zoning Stage 1: New location: %d, Entity %d, Unknown %d", mNewLocation, mNewEntity, (u16)mUnknown);
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+
+  return this;
+}
+
+bool PUdpZoning1::DoAction()
+{
+  mDecodeData->mClient->ChangeCharLocation( mNewLocation );
+
+//Console->Print("Zoning Stage 1: New location: %d", mNewLocation);
+
+  mDecodeData->mClient->SetZoning();
+
+  PMessage* tmpMsg = MsgBuilder->BuildZoning1Msg( mDecodeData->mClient, mNewEntity, mUnknown );
+  mDecodeData->mClient->SendUDPMessage( tmpMsg );
+
+  //Temp
+  /*if ( mDecodeData->mClient->GetDebugMode( DBG_LOCATION ) )
+  {
+    char DbgMessage[128];
+    PCharCoordinates &C = (mDecodeData->mClient->GetChar()->Coords);
+    snprintf( DbgMessage, 128, "pos min/max y:%d/%d z:%d/%d x:%d/%d", C.minPos[0], C.maxPos[0], C.minPos[1], C.maxPos[1], C.minPos[2], C.maxPos[2] );
+    Chat->send( mDecodeData->mClient, CHAT_GM, "Debug", DbgMessage );
+    
+    for(int i=0; i<3; i++)
+      { C.minPos[i] = 0xffff; C.maxPos[i] = 0; }
+  }*/
+
+//Console->Print("Zoning Stage 1: packet sent");
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
+
+/**** PUdpZoning2 ****/
+
+PUdpZoning2::PUdpZoning2( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x03";
+}
+
+PUdpMsgAnalyser* PUdpZoning2::Analyse()
+{
+  mDecodeData->mName << "=Zoning phase 2";
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+
+  return this;
+}
+
+bool PUdpZoning2::DoAction()
+{
+//Console->Print("Zoning Stage 2: Sending Ready packet");
+  PMessage* tmpMsg = MsgBuilder->BuildZoningTCPReadyMsg(); // Not always sent (dongeon door 20)
+  mDecodeData->mClient->SendTCPMessage( tmpMsg );
+
+//Console->Print("Zoning Stage 2: Sending Zone information");
+  PUdpSync0::GetToSync1( mDecodeData );
+
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
+
+/**** PUdpGenrepZoning ****/
+
+PUdpGenrepZoning::PUdpGenrepZoning( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x04";
+}
+
+PUdpMsgAnalyser* PUdpGenrepZoning::Analyse()
+{
+  mDecodeData->mName << "=Genrep Zoning";
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+
+  PMessage* cMsg = mDecodeData->mMessage;
+  cMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 12 );
+  *cMsg >> mNewLocation; // u32
+  *cMsg >> mNewEntity; //u16
+
+  return this;
+}
+
+bool PUdpGenrepZoning::DoAction()
+{
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return PUdpGenrepZoning::DoEffectiveZoning( mDecodeData->mClient, mNewLocation, mNewEntity );
+}
+
+bool PUdpGenrepZoning::DoEffectiveZoning( PClient* nClient, u32  nNewLocation, u16 nNewEntity )
+{
+  PMessage* tmpMsg = MsgBuilder->BuildGenrepZoningMsg( nClient, nNewLocation, nNewEntity );
+  nClient->SendUDPMessage( tmpMsg );
+
+  //Client_Sockets[ClientNum].CharInfo.Flags = PFLAG_ZONING; //Player started zoning
+  nClient->ChangeCharLocation( nNewEntity );
+
+  tmpMsg = MsgBuilder->BuildZoning1Msg( nClient, nNewEntity );
+  nClient->SendUDPMessage( tmpMsg );
+
+  if ( gDevDebug ) Console->Print( "Client[%d]: Genrep Zoning to zone %d entity %d", nClient->GetID(), nNewLocation, nNewEntity );
+
+  return true;
+}
+
+/**** PUdpAptGRZoning ****/
+
+PUdpAptGRZoning::PUdpAptGRZoning( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x03";
+}
+
+PUdpMsgAnalyser* PUdpAptGRZoning::Analyse()
+{
+  mDecodeData->mName << "=Genrep Apt Zoning";
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+
+  return this;
+}
+
+bool PUdpAptGRZoning::DoAction()
+{
+  /*
+    //u16 newEntity = cMsg->U16Data(mDecodeData->Sub0x13Start+12); // always 0x0047 ? Not a location/entity anyway...
+
+    u32 newLocation = PWorlds::mAptBaseWorldId + nClient->GetChar()->GetBaseApartment();
+    u16 newEntity = 0;
+  */
+
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return PUdpAptGRZoning::DoEffectiveZoning( mDecodeData->mClient );
+}
+
+bool PUdpAptGRZoning::DoEffectiveZoning( PClient* nClient )
+{
+  u32 newLocation = PWorlds::mAptBaseWorldId + nClient->GetChar()->GetBaseApartment();
+  u16 newEntity = 0;
+
+  PMessage* tmpMsg = MsgBuilder->BuildGenrepZoningMsg( nClient, newLocation, newEntity );
+  nClient->SendUDPMessage( tmpMsg );
+
+  if ( ! nClient->ChangeCharLocation( newLocation ) )
+    Console->Print( "Client[%d]: Bad Apartment location %d", nClient->GetID(), newLocation );
+
+  //Client_Sockets[ClientNum].CharInfo.Flags = PFLAG_ZONING; //Player started zoning
+
+  tmpMsg = MsgBuilder->BuildZoning1Msg( nClient, newEntity );
+  nClient->SendUDPMessage( tmpMsg );
+
+  if ( gDevDebug )
+    Console->Print( "Client[%d]: Genrep Zoning to Base Apartment (zone %d - entity %d)", nClient->GetID(), newLocation, newEntity );
+
+  return true;
+}
+
+/**** PUdpAddGenrepToList ****/
+
+PUdpAddGenrepToList::PUdpAddGenrepToList( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x02";
+}
+
+PUdpMsgAnalyser* PUdpAddGenrepToList::Analyse()
+{
+  mDecodeData->mName << "=Add Genrep to list";
+
+  PMessage* nMsg = mDecodeData->mMessage;
+  // LocalID @offset 10
+  nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 12 );
+  *nMsg >> mLocation;
+  *nMsg >> mEntity;
+
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+
+  return this;
+}
+
+bool PUdpAddGenrepToList::DoAction()
+{
+  PClient* nClient = mDecodeData->mClient;
+
+//Console->Print("Client[%d]: Adding Genrep (location %d - entity %d)", nClient->GetID(), mLocation, mEntity);
+
+  if ( mLocation == 1086 && mEntity == 1111 )
+  {
+    PMessage* tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 160 );
+    nClient->SendUDPMessage( tmpMsg );
+  }
+  else
+  {
+    nClient->GetChar()->AddGenrep( mLocation, mEntity );
+    PMessage* tmpMsg = MsgBuilder->BuildGenrepAddToListMsg( nClient, mLocation, mEntity );
+    nClient->SendUDPMessage( tmpMsg );
+  }
+
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
+
+/**** PUdpAppartmentAccess ****/
+
+PUdpAppartmentAccess::PUdpAppartmentAccess( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x38";
+}
+
+PUdpMsgAnalyser* PUdpAppartmentAccess::Analyse()
+{
+  mDecodeData->mName << "=Try acces appartment";
+
+  PMessage* nMsg = mDecodeData->mMessage;
+  nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 9 );
+  mAppartmentPlace = nMsg->U16Data( mDecodeData->Sub0x13Start + 9 );
+  mPassword = ( char* )nMsg->GetMessageData() + mDecodeData->Sub0x13Start + 14;
+  // NO SIZE ????? DO SIZE CHECK !
+
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+
+  return this;
+}
+
+bool PUdpAppartmentAccess::DoAction()
+{
+  PMessage* tmpMsg;
+  u32 AppLoc, Location, Entity;
+  PClient* nClient = mDecodeData->mClient;
+  PChar* nChar = nClient->GetChar();
+
+  Location = nChar->GetLocation();
+  if ( gDevDebug ) Console->Print( "Client[%d]: Apt Access I/F (place %d - password %s)", nClient->GetID(), mAppartmentPlace, mPassword );
+  if (( Location > PWorlds::mAptBaseWorldId ) && ( !strcmp( "Exit", mPassword ) ) )
+  {
+    AppLoc = Appartements->GetAptLocation( Location );
+    const PDefAppPlace* nAppPlace = ( AppLoc ? GameDefs->AppPlaces()->GetDef( AppLoc ) : 0 );
+    if ( nAppPlace )
+    {
+      Location = nAppPlace->GetExitWorldID();
+      Entity = nAppPlace->GetExitWorldEntity();
+    }
+    else
+    {
+      Location = 1; //PLAZA 1
+      Entity = 100; //TYPHERRA MEMORIAL GR 1
+    }
+    tmpMsg = MsgBuilder->BuildChangeLocationMsg( nClient, Location, Entity );
+  }
+  else
+  {
+    u32 Location = Appartements->GetAptID( mAppartmentPlace, ( u8* )mPassword );
+    if ( Location > 1 )
+    {
+      tmpMsg = MsgBuilder->BuildAptLiftUseMsg( nClient, Location, 1 );
+      nClient->ChangeCharLocation( Location );
+    }
+    else if ( Location < 1 )
+    {
+      tmpMsg = MsgBuilder->BuildAptLiftFailedMsg( nClient );
+    }
+    else
+      tmpMsg = NULL;
+
+    mDecodeData->mTraceDump = true;
+  }
+
+  if ( tmpMsg )
+    nClient->SendUDPMessage( tmpMsg );
+
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
+
+/**** PUdpEndOfZoning ****/
+
+PUdpEndOfZoning::PUdpEndOfZoning( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+  nDecodeData->mName << "/0x08";
+}
+
+PUdpMsgAnalyser* PUdpEndOfZoning::Analyse()
+{
+  mDecodeData->mName << "=End of zoning";
+  mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+
+  return this;
+}
+
+bool PUdpEndOfZoning::DoAction()
+{
+// Nothing implemented yet
+  mDecodeData->mClient->SetZoning( false );
+  mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+  return true;
+}
diff --git a/server/src/game/decoder/udp_zoning.h b/server/src/game/decoder/udp_zoning.h
new file mode 100644 (file)
index 0000000..37a4b0e
--- /dev/null
@@ -0,0 +1,120 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+ udp_zoning.h - decoder classes for UDP Zoning messages\r
+\r
+ CREATION: 6 Sep 2006 Hammag\r
+\r
+ MODIFIED: 15 Dec 2006 Hammag\r
+ REASON: - added PUdpEndOfZoning management class\r
+\r
+*/\r
+\r
+#ifndef UDPZONING_H\r
+#define UDPZONING_H\r
+\r
+class PUdpZoning1 : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u32 mNewLocation;\r
+    u16 mNewEntity;\r
+    u8 mUnknown;\r
+  public:\r
+    PUdpZoning1( PMsgDecodeData* nDecodeData );\r
+    //~PUdpZoning1();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpZoning2 : public PUdpMsgAnalyser\r
+{\r
+  public:\r
+    PUdpZoning2( PMsgDecodeData* nDecodeData );\r
+    //~PUdpZoning2();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpGenrepZoning : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u32 mNewLocation;\r
+    u16 mNewEntity;\r
+\r
+  public:\r
+    PUdpGenrepZoning( PMsgDecodeData* nDecodeData );\r
+    //~PUdpGenrepZoning();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+    static bool DoEffectiveZoning( PClient* nClient, u32  nNewLocation, u16 nNewEntity );\r
+};\r
+\r
+class PUdpAptGRZoning : public PUdpMsgAnalyser\r
+{\r
+  public:\r
+    PUdpAptGRZoning( PMsgDecodeData* nDecodeData );\r
+    //~PUdpAptGRZoning();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+    static bool DoEffectiveZoning( PClient* nClient );\r
+};\r
+\r
+class PUdpAddGenrepToList : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u32 mLocation;\r
+    u16 mEntity;\r
+\r
+  public:\r
+    PUdpAddGenrepToList( PMsgDecodeData* nDecodeData );\r
+    //~PUdpAddGenrepToList();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+class PUdpAppartmentAccess : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+    u16 mAppartmentPlace;\r
+    char* mPassword;\r
+\r
+  public:\r
+    PUdpAppartmentAccess( PMsgDecodeData* nDecodeData );\r
+    //~PUdpAppartmentAccess();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+\r
+class PUdpEndOfZoning : public PUdpMsgAnalyser\r
+{\r
+  private:\r
+\r
+  public:\r
+    PUdpEndOfZoning( PMsgDecodeData* nDecodeData );\r
+    //~PUdpEndOfZoning();\r
+    PUdpMsgAnalyser* Analyse();\r
+    bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/decoder/udpanalyser.cpp b/server/src/game/decoder/udpanalyser.cpp
new file mode 100644 (file)
index 0000000..d625b81
--- /dev/null
@@ -0,0 +1,146 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udpanalyser.cpp - Analyser class top (used only by PUdpMsgDecoder)\r
+  Also includes the PUdpMsgUnknown derived class\r
+\r
+       CREATION: 23 Aug 2006 Hammag\r
+\r
+       MODIFIED: 30 Aug 2006 Hammag\r
+       REASON: - moved these two class in file distinct from PUdpMsgDecoder.\r
+               - made implementation\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "udpanalyser.h"\r
+\r
+#include "udp_sync.h"\r
+#include "udp_0x13.h"\r
+#include "udp_0x08.h"\r
+\r
+/**** PUdpMsgAnalyser ****/\r
+\r
+int PUdpMsgAnalyser::smAnaCount = 0; // temp for check\r
+\r
+PUdpMsgAnalyser::PUdpMsgAnalyser(PMsgDecodeData* nDecodeData)\r
+{\r
+  mDecodeData = nDecodeData;\r
+  if (++smAnaCount > 2) // temp for check\r
+    Console->Print(RED, BLACK, "Analyser instances count: %d", smAnaCount);  // temp for check\r
+}\r
+\r
+PUdpMsgAnalyser::~PUdpMsgAnalyser()\r
+{\r
+  --smAnaCount;\r
+}\r
+\r
+PUdpMsgAnalyser* PUdpMsgAnalyser::Analyse()\r
+{\r
+  PUdpMsgAnalyser* nextAnalyser;\r
+  u8 MsgType;\r
+\r
+  mDecodeData->mState = DECODE_MORE;\r
+//mDecodeData->mTraceKnownMsg = true; // Don't want to trace all known messages\r
+mDecodeData->mTraceUnknownMsg = true; // Want to show all unknown messages\r
+\r
+  *(mDecodeData->mMessage) >> MsgType;\r
+  switch(MsgType)\r
+  {\r
+    case 0x01:\r
+    {\r
+      nextAnalyser = new PUdpSync0(mDecodeData);\r
+      break;\r
+    }\r
+    case 0x03:\r
+    {\r
+      nextAnalyser = new PUdpSync1(mDecodeData);\r
+      break;\r
+    }\r
+    case 0x08:\r
+    {\r
+        nextAnalyser = new PUdp0x08(mDecodeData);\r
+        break;\r
+    }\r
+    case 0x13:\r
+    {\r
+      nextAnalyser = new PUdp0x13(mDecodeData);\r
+      break;\r
+    }\r
+    default:\r
+    {\r
+      mDecodeData->mUnknownType = MsgType;\r
+      nextAnalyser = new PUdpMsgUnknown(mDecodeData);\r
+      break;\r
+    }\r
+  }\r
+ return nextAnalyser;\r
+}\r
+\r
+bool PUdpMsgAnalyser::DoAction()\r
+{\r
+  return false; // no action at this level\r
+}\r
+\r
+\r
+/**** Unkown UDP message ****/\r
+\r
+PUdpMsgUnknown::PUdpMsgUnknown(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)\r
+{\r
+  char hexstr[16];\r
+\r
+  nDecodeData->mState = DECODE_UNKNOWN;\r
+  snprintf(hexstr, 16, "/0x%02x", mDecodeData->mUnknownType);\r
+  mDecodeData->mName << hexstr;\r
+  nDecodeData->mName << "=Unknown";\r
+}\r
+\r
+/*PUdpMsgUnknown::~PUdpMsgUnknown()\r
+{\r
+}*/\r
+\r
+/*bool PUdpMsgUnknown::DoAction()\r
+{\r
+  return false;\r
+}*/\r
+\r
+/**** Ignore UDP message ****/\r
+\r
+PUdpMsgIgnore::PUdpMsgIgnore(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)\r
+{\r
+  char hexstr[16];\r
+\r
+  nDecodeData->mState = DECODE_FINISHED;\r
+  snprintf(hexstr, 16, "/0x%02x", mDecodeData->mUnknownType);\r
+  mDecodeData->mName << hexstr;\r
+  nDecodeData->mName << "=Ignore";\r
+}\r
+\r
+/*PUdpMsgUnknown::~PUdpMsgUnknown()\r
+{\r
+}*/\r
+\r
+/*bool PUdpMsgUnknown::DoAction()\r
+{\r
+  return false;\r
+}*/\r
diff --git a/server/src/game/decoder/udpanalyser.h b/server/src/game/decoder/udpanalyser.h
new file mode 100644 (file)
index 0000000..61627c2
--- /dev/null
@@ -0,0 +1,74 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       udpanalyser.h - Analyser class top (used only by PUdpMsgDecoder)\r
+  Also includes the PUdpMsgUnknown derived class\r
+  and the PUdpMsgIgnore derived class\r
+  \r
+       CREATION: 23 Aug 2006 Hammag\r
+\r
+       MODIFIED: 30 Aug 2006 Hammag\r
+       REASON: - moved these two class in file distinct from PUdpMsgDecoder.\r
+\r
+*/\r
+\r
+#ifndef UDPANALYSER_H\r
+#define UDPANALYSER_H\r
+\r
+class PUdpMsgAnalyser\r
+{\r
+  friend class PUdpMsgDecoder;\r
+  \r
+       protected:\r
+    PMsgDecodeData* mDecodeData;\r
+\r
+  public:        \r
+    PUdpMsgAnalyser(PMsgDecodeData* nDecodeData);\r
+    virtual ~PUdpMsgAnalyser();\r
+    \r
+    virtual PUdpMsgAnalyser* Analyse();\r
+    virtual bool DoAction();\r
+    \r
+    static int smAnaCount; // temp for check\r
+\r
+};\r
+\r
+class PUdpMsgUnknown : public PUdpMsgAnalyser\r
+{ \r
+  public:\r
+    PUdpMsgUnknown(PMsgDecodeData* nDecodeData);\r
+    //~PUdpMsgUnknown();\r
+    \r
+    //bool DoAction();\r
+};\r
+\r
+class PUdpMsgIgnore : public PUdpMsgAnalyser\r
+{ \r
+  public:\r
+    PUdpMsgIgnore(PMsgDecodeData* nDecodeData);\r
+    //~PUdpMsgUnknown();\r
+    \r
+    //bool DoAction();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/def/Makefile b/server/src/game/def/Makefile
new file mode 100644 (file)
index 0000000..67efa8a
--- /dev/null
@@ -0,0 +1,83 @@
+#
+# TinNS per-directory Makefile
+#
+# Adapted by Hammag from the Makefile system for Linux kernel.
+#
+# 14 Sep 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+# 
+
+######################################################
+# Target for this directory and its sub-dirs
+######################################################
+# Case 1 : target is an executable named as defined
+#B_TARGET := gameserver 
+
+# Case 2 : target is a TinNS lib name
+#  (use short name, as in -l linker option) 
+#L_TARGET := tinns
+
+# Case 3 (usual): objects shall be made available to the parent dir
+#  The following line will set that automatically 
+# (Should match dir name + .o suffix)
+O_TARGET := $(addsuffix .o,$(notdir $(shell /bin/pwd)))
+# Manualy define this only if you need to force the compiled obj name
+#O_TARGET := game.o
+
+
+######################################################
+# Local flags
+######################################################
+# local dir CXX Flags
+EXTRA_CXXFLAGS :=  -I$(TOPDIR)/game/include
+
+# per-object CXX Flags
+#CXXFLAGS_funcdef2.o := -g
+
+# local dir Linker Flags (for intermediate .o linking)
+#EXTRA_LDFLAGS := 
+
+# any tinns Lib used (short name, as in -l linker option)
+LINK_TINNSLIBS := tinns
+
+# local dir Linker Flags (for final executable linking)
+#EXTRA_LINKFLAGS := -lrt -lpthread -lz -lm -lcrypt -L"/usr/lib/mysql" -lmysqlclient
+
+
+#####################################################
+# Subdirectories
+#####################################################
+#subdir-y := def 
+#subdir-$(CONFIG_GAMEMONKEY)   += gamemonkey
+
+
+#####################################################
+#***************************************************#
+# No further config should be needed after this line
+#***************************************************#
+ifdef TOPDIR
+
+# build list of objects ib loca ldir
+obj-y := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
+# add final object from each subdir
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+
+include $(TOPDIR)/Rules.make
+
+else #TOPDIR undef, Makefile called from non-top dir
+
+# Memorize the first calling dir in case we wanted to
+# lauch local actions from top Makefile
+  ifndef FIRSTDIR
+    FIRSTDIR :=$(CURDIR)
+    export FIRSTDIR
+  endif
+
+uptoparent : 
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+.DEFAULT :
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+endif #TOPDIR
+
diff --git a/server/src/game/def/def_actionmod.cpp b/server/src/game/def/def_actionmod.cpp
new file mode 100644 (file)
index 0000000..3a59c17
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_actionmod.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_actionmod.h"
+
+PDefActionMod::PDefActionMod()
+{
+}
+
+bool PDefActionMod::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  int maxFields = 3;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi( i->c_str() ); break;
+      case 2 :
+        mStartValue = atof( i->c_str() ); break;
+      case 3 :
+      {
+        mNumOfSsq = atoi( i->c_str() );
+        if( mNumOfSsq > 8 )
+          mNumOfSsq = 8;
+        maxFields = 3 + 2 * mNumOfSsq;
+        break;
+      }
+      default :
+        if( (Idx >= 4) && (Idx <= maxFields) )
+        {
+          if(Idx & 1)
+          {
+            mModFactor[(Idx - 4) / 2] = atof( i->c_str() );
+          }
+          else
+          {
+            mSsqId[(Idx - 4) / 2] = atoi( i->c_str() );
+          }
+        }
+        break;
+    }
+
+    if ( Idx >= maxFields )
+      break;
+  }
+
+  return ((Idx == maxFields));
+}
diff --git a/server/src/game/def/def_ammo.cpp b/server/src/game/def/def_ammo.cpp
new file mode 100644 (file)
index 0000000..8e2c2b9
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_ammo.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_ammo.h"
+
+PDefAmmo::PDefAmmo()
+{
+  mShotId = mMagSize = mWeaponShotId = mDamageId = 0;
+}
+
+bool PDefAmmo::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi( i->c_str() ); break;
+      case 2 :
+        mDamageId = atoi( i->c_str() ); break;
+      case 3 :
+        mWeaponShotId = atoi( i->c_str() ); break;
+      case 4 :
+        mMagSize = atoi( i->c_str() ); break;
+      case 5 :
+        mShotId = atoi( i->c_str() ); break;
+      default :
+        break;
+    }
+
+    if ( Idx >= 5 )
+      break;
+  }
+
+  return ((Idx >= 4));
+}
diff --git a/server/src/game/def/def_appartements.cpp b/server/src/game/def/def_appartements.cpp
new file mode 100755 (executable)
index 0000000..5e05b8f
--- /dev/null
@@ -0,0 +1,81 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       def_appartements.cpp\r
+\r
+       MODIFIED: 22 Sep 2006 Hammag\r
+       REASON: - Creation\r
+       \r
+*/\r
+\r
+#include "main.h"\r
+\r
+PDefAppartement::PDefAppartement()\r
+{\r
+}\r
+\r
+bool PDefAppartement::LoadFromDef(PTokenList *Tokens)\r
+{\r
+  mFaction = 0;\r
+       int Idx=0;\r
+       for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
+       {\r
+               switch(Idx)\r
+               {\r
+                       case 0: // setentry\r
+                                       continue;\r
+\r
+                       case 1: // index\r
+                               mIndex = atoi(i->c_str()); break;\r
+\r
+                       case 2: // name\r
+                               mName = *i; break;\r
+\r
+                       case 3: // world name\r
+                               mWorldName = *i; break;\r
+                               \r
+                       case 4: // value\r
+                               mValue = atoi(i->c_str()); break;\r
+\r
+                       case 5: // number of places\r
+                               mPlaceCount = atoi(i->c_str()); break;\r
+                                 \r
+                 case 6:\r
+                 case 7:\r
+                 case 8:\r
+                 case 9:\r
+                 case 10:\r
+                 case 11:\r
+                 case 12:\r
+                 case 13:\r
+                   mPlace[Idx-6] = atoi(i->c_str()); break;\r
+                     \r
+                       case 14: // faction if base appartement\r
+                               mFaction = atoi(i->c_str()); break;                   \r
+               }\r
+       }\r
+//Console->Print("%04d:%s file:%s val:%d places:%d pl1:%d pl2:%d pl8:%d faction:%d",\r
+//      mIndex, mName.c_str(), mWorldName.c_str(), mValue, mPlaceCount, mPlace[0], mPlace[1], mPlace[7], mFaction);\r
+       return true;\r
+}\r
diff --git a/server/src/game/def/def_appplaces.cpp b/server/src/game/def/def_appplaces.cpp
new file mode 100644 (file)
index 0000000..3c4797a
--- /dev/null
@@ -0,0 +1,64 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+/*\r
+       def_appplaces.cpp\r
+\r
+       Created: 21 Sep 2006 Hammag\r
+       REASON: -\r
+*/\r
+\r
+#include "main.h"\r
+\r
+PDefAppPlace::PDefAppPlace()\r
+{\r
+}\r
+\r
+bool PDefAppPlace::LoadFromDef(PTokenList *Tokens)\r
+{\r
+       int Idx=0;\r
+       for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
+       {\r
+               switch(Idx)\r
+               {\r
+                       case 0: // setentry\r
+                                       continue;\r
+\r
+                       case 1: // index\r
+                               mIndex = atoi(i->c_str()); break;\r
+\r
+                       case 2: // name\r
+                               mName = *i; break;\r
+\r
+                       case 3: // Exit World\r
+                               mExitWorldID = atoi(i->c_str()); break;\r
+                               \r
+                       case 4: // Exit World entity\r
+                               mExitWorldEntity = atoi(i->c_str()); break;\r
+\r
+                       case 5: // Sewer level\r
+                               mSewerLevel = atoi(i->c_str()); break;\r
+               }\r
+       }\r
+\r
+       return true;\r
+}\r
diff --git a/server/src/game/def/def_blueprintpieces.cpp b/server/src/game/def/def_blueprintpieces.cpp
new file mode 100644 (file)
index 0000000..54aafcf
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_blueprintpieces.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_blueprintpieces.h"
+
+PDefBlueprintPieces::PDefBlueprintPieces()
+{
+}
+
+
+bool PDefBlueprintPieces::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  int maxFields = 3;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi( i->c_str() ); break;
+      case 2 :
+        mMaxPieceNum = atoi( i->c_str() ); break;
+      case 3 :
+      {
+        mPieceNum = atoi( i->c_str() );
+        if ( mPieceNum > 20 )
+          mPieceNum = 20;
+        maxFields = 3 + mPieceNum;
+        break;
+      }
+      default :
+        if (( Idx >= 4 ) && ( Idx <= maxFields ) )
+        {
+          mPieceId[ Idx - 4 ] = atoi( i->c_str() );
+        }
+        break;
+    }
+
+    if ( Idx >= maxFields )
+      break;
+  }
+
+  return (( Idx == maxFields ) );
+}
diff --git a/server/src/game/def/def_characters.cpp b/server/src/game/def/def_characters.cpp
new file mode 100644 (file)
index 0000000..a744265
--- /dev/null
@@ -0,0 +1,94 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+        def_characters.cpp\r
+\r
+        Authors:\r
+        - Akiko\r
+        - Namikon\r
+        - someone else?\r
+\r
+        MODIFIED: Unknown date / Unknown author\r
+        REASON: - initial release by unknown\r
+\r
+        MODIFIED: 25 Dec 2005 Namikon\r
+        REASON: - Added GPL\r
+*/\r
+\r
+#include "main.h"\r
+\r
+// characters.def contains all ingame characters (player types, npc's, monsters)\r
+\r
+PDefCharacter::PDefCharacter()\r
+{\r
+       mIndex = -1;\r
+       mName = "unknown";\r
+       mModel = -1;\r
+}\r
+\r
+bool PDefCharacter::LoadFromDef(PTokenList *Tokens)\r
+{\r
+       int Idx=0;\r
+       for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
+       {\r
+               switch(Idx)\r
+               {\r
+                       case 0 :        // setentry\r
+                               continue;\r
+\r
+                       case 1 :\r
+                               mIndex = atoi(i->c_str()); break;\r
+\r
+                       case 2 :\r
+                               mName = *i; break;\r
+\r
+                       case 3 :\r
+                               mModel = atoi(i->c_str()); break;\r
+                                 \r
+                       case 4 : // 0\r
+                               continue;\r
+                                 \r
+                       case 5 :\r
+                               mHead = atoi(i->c_str()); break;\r
+                                 \r
+                       case 6 :\r
+                               mTorso = atoi(i->c_str()); break;\r
+                                 \r
+                       case 7 :\r
+                               mLegs = atoi(i->c_str()); break;\r
+                               \r
+                       case 8 :\r
+                               mColor = atoi(i->c_str()); break;\r
+                               \r
+                       case 9 :\r
+                               mBrightness = atoi(i->c_str()); break;\r
+               }\r
+\r
+               if(Idx==9)\r
+                       return true;\r
+       }\r
+\r
+       return false;\r
+}\r
+\r
diff --git a/server/src/game/def/def_charaction.cpp b/server/src/game/def/def_charaction.cpp
new file mode 100644 (file)
index 0000000..00d6486
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+
+
+/*
+ def_charaction.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_charaction.h"
+
+PDefCharAction::PDefCharAction()
+{
+}
+
+bool PDefCharAction::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  int maxFields = 2;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi( i->c_str() ); break;
+      case 2 :
+      {
+        mNumOfSsq = atoi( i->c_str() );
+        if ( mNumOfSsq > 8 )
+          mNumOfSsq = 8;
+        maxFields = 2 + 2 * mNumOfSsq;
+        break;
+      }
+      default :
+        if (( Idx >= 3 ) && ( Idx <= maxFields ) )
+        {
+          if ( Idx & 1 )
+          {
+            mSsqId[( Idx - 3 ) / 2] = atoi( i->c_str() );
+          }
+          else
+          {
+            mModFactor[( Idx - 3 ) / 2] = atof( i->c_str() );
+          }
+        }
+        break;
+    }
+
+    if ( Idx >= maxFields )
+      break;
+  }
+
+  return (( Idx == maxFields ) );
+}
diff --git a/server/src/game/def/def_charkinds.cpp b/server/src/game/def/def_charkinds.cpp
new file mode 100644 (file)
index 0000000..dc940b7
--- /dev/null
@@ -0,0 +1,188 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+        def_charkinds.cpp\r
+\r
+        Authors:\r
+        - Akiko\r
+        - Namikon\r
+        - someone else?\r
+\r
+        MODIFIED: Unknown date / Unknown author\r
+        REASON: - initial release by unknown\r
+\r
+        MODIFIED: 25 Dec 2005 Namikon\r
+        REASON: - Added GPL\r
+*/\r
+\r
+#include "main.h"\r
+\r
+// charkinds are character templates used for player char creation\r
+\r
+PDefCharKind::PDefCharKind()\r
+{\r
+       mSkillInfo = 0;\r
+       memset(mInventory, 0, sizeof(mInventory));\r
+}\r
+\r
+PDefCharKind::~PDefCharKind()\r
+{\r
+       delete [] mSkillInfo;\r
+       for(PSkillPtsMap::const_iterator i=mSkillPts.begin(); i!=mSkillPts.end(); i++)\r
+               delete i->second;\r
+       for(PSubSkillPtsMap::const_iterator i=mSubSkillPts.begin(); i!=mSubSkillPts.end(); i++)\r
+               delete i->second;\r
+       for(PStartLevelMap::const_iterator i=mStartLevels.begin(); i!=mStartLevels.end(); i++)\r
+               delete i->second;\r
+}\r
+\r
+bool PDefCharKind::LoadFromDef(PTokenList *Tokens)\r
+{\r
+       int NumSkills = GameDefs->Skills()->GetNumDefs();\r
+       //int NumSubSkills = GameDefs->SubSkills()->GetNumDefs();\r
+\r
+       int SkillInfoStart = 4;\r
+       int TrainPtsStart = SkillInfoStart+NumSkills*3;\r
+       int LevelsStart = TrainPtsStart + 32*2;\r
+       int MoneyStart = LevelsStart + 16*2;\r
+       int InventoryStart = MoneyStart+1;\r
+\r
+       mSkillInfo = new PSkillInfo[NumSkills];\r
+\r
+       int Idx=0;\r
+       for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
+       {\r
+               switch(Idx)\r
+               {\r
+                       case 0 :        // setentry\r
+                               continue;\r
+\r
+                       case 1 :\r
+                               mIndex = atoi(i->c_str()); break;\r
+\r
+                       case 2 :\r
+                               mName = *i; break;\r
+\r
+                       case 3 :\r
+                               mType = atoi(i->c_str()); break;\r
+\r
+               }\r
+\r
+               if((Idx >= SkillInfoStart) && (Idx < TrainPtsStart)) // skill info\r
+               {\r
+                       int SkillIdx = (Idx-SkillInfoStart)/3;\r
+                       int Value = atoi(i->c_str());\r
+\r
+                       // start, max, grow per skill\r
+                       switch((Idx-SkillInfoStart)%3)\r
+                       {\r
+                               case 0 : mSkillInfo[SkillIdx].mStart = Value; break;\r
+                               case 1 : mSkillInfo[SkillIdx].mMax = Value; break;\r
+                               case 2 : mSkillInfo[SkillIdx].mGrow = Value; break;\r
+                       }\r
+               } else\r
+               // 32 skill/subskill train pts\r
+               if((Idx >= TrainPtsStart) && (Idx < LevelsStart))\r
+               {\r
+                       static int SkillIndex = 0;\r
+                       int Index = Idx-TrainPtsStart;\r
+                       if((Index&1)==0)\r
+                       {\r
+                               SkillIndex = atoi(i->c_str());\r
+                       } else\r
+                       {\r
+                               if(SkillIndex >= 1000)  // skill\r
+                               {\r
+                                       const PDefSkill *Skill = GameDefs->Skills()->GetDef(SkillIndex-1000);\r
+                                       if(Skill)\r
+                                       {\r
+                                               int Index = Skill->GetIndex()-1;\r
+                                               PSkillPtsInfo *CurrentSkillPts = new PSkillPtsInfo();\r
+                                               CurrentSkillPts->mSkill = Index;\r
+                                               CurrentSkillPts->mPoints = atoi(i->c_str());\r
+                                               mSkillPts.insert(std::make_pair(Index, CurrentSkillPts));\r
+                                       } else\r
+                                       {\r
+                                               if(SkillIndex-1000 != 0)\r
+                                                       Console->Print("Charkind def: invalid skill index %i", SkillIndex-1000);\r
+                                       }\r
+                               } else  // subskill\r
+                               {\r
+                                       const PDefSubSkill *SubSkill = GameDefs->SubSkills()->GetDef(SkillIndex);\r
+                                       if(SubSkill)\r
+                                       {\r
+                                               int Index = SubSkill->GetIndex()-1;\r
+                                               PSubSkillPtsInfo *CurrentSubSkillPts = new PSubSkillPtsInfo();\r
+                                               CurrentSubSkillPts->mSubSkill = Index;\r
+                                               CurrentSubSkillPts->mPoints = atoi(i->c_str());\r
+                                               mSubSkillPts.insert(std::make_pair(Index, CurrentSubSkillPts));\r
+                                       } else\r
+                                       {\r
+                                               if(SkillIndex != 0)\r
+                                                       Console->Print("Charkind def: invalid subskill index %i", SkillIndex);\r
+                                       }\r
+                               }\r
+                       }\r
+               } else\r
+               // 16 subskill start levels\r
+               if((Idx >= LevelsStart) && (Idx < MoneyStart))\r
+               {\r
+                       static int LevelIndex = 0;\r
+                       int Index = Idx-NumSkills*3+4+(32*2);\r
+                       if((Index&1)==0)\r
+                       {\r
+                               LevelIndex = atoi(i->c_str());\r
+                       } else\r
+                       {\r
+                               if(LevelIndex > 0)\r
+                               {\r
+                                       const PDefSubSkill *SubSkill = GameDefs->SubSkills()->GetDef(LevelIndex);\r
+                                       if(SubSkill)\r
+                                       {\r
+                                               PStartLevelInfo *Level = new PStartLevelInfo();\r
+                                               Level->mSubSkill = SubSkill->GetIndex();\r
+                                               Level->mLevel = atoi(i->c_str());\r
+                                               mStartLevels.insert(std::make_pair(Level->mSubSkill, Level));\r
+                                       } else\r
+                                       {\r
+                                               Console->Print("Charkind def: invalid subskill index %i", LevelIndex);\r
+                                       }\r
+                               }\r
+                       }\r
+               } else\r
+               // money\r
+               if((Idx >= MoneyStart) && (Idx < InventoryStart))\r
+               {\r
+                       mMoney = atoi(i->c_str());\r
+               } else\r
+               // inventory\r
+               if((Idx >= InventoryStart) && (Idx < InventoryStart+8))\r
+               {\r
+                       mInventory[Idx-InventoryStart] = atoi(i->c_str());\r
+               }\r
+       }\r
+       \r
+       return true;\r
+}\r
+\r
diff --git a/server/src/game/def/def_damage.cpp b/server/src/game/def/def_damage.cpp
new file mode 100644 (file)
index 0000000..fefd05b
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_damage.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_damage.h"
+
+PDefDamage::PDefDamage()
+{
+}
+
+bool PDefDamage::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  int maxFields = 3;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi( i->c_str() ); break;
+      case 2 :
+        break;
+      case 3 :
+      {
+        mDamageNum = atoi( i->c_str() );
+        if ( mDamageNum > 4 )
+          mDamageNum = 4;
+        maxFields = 3 + 3 * mDamageNum;
+        break;
+      }
+      default :
+        if (( Idx >= 4 ) && ( Idx <= maxFields ) )
+        {
+          switch (( Idx - 4 ) % 3 )
+          {
+            case 0:
+              mDamageValue[( Idx - 4 ) / 3] = atoi( i->c_str() ); break;
+            case 1:
+              mDamageEffect[( Idx - 4 ) / 3] = atoi( i->c_str() ); break;
+            case 2:
+              mDamageType[( Idx - 4 ) / 3] = atoi( i->c_str() ); break;
+          }
+        }
+        break;
+    }
+
+    if ( Idx >= maxFields )
+      break;
+  }
+
+  // Try to fix wrong size field
+  if( Idx < maxFields )
+  {
+    mDamageNum = ( Idx - 4 ) / 3;
+    if( (( Idx - 4 ) % 3) == 2 )
+      ++mDamageNum;
+  }
+  return ( Idx >= 3 );
+}
+/*
+class PDefDamage : public PDef
+{
+  private :
+    //int mIndex;
+    //int mSoundIndex; // no use
+    int mDamageNum;
+    int mDamageValue[4];
+    int mDamageEffect[4];
+    int mDamageType[4];
+    // int mEffectNum; // Are effects needed ? (server or client triggered ?)
+    // int mEffectId[4]; // ?
+    // int mEffectTarget[4]; // float ?
+    // int mEffectValue[4]; // float ?
+    // int mEffectamorId[4]; // ????
+
+  public :
+    PDefDamage();
+    //~PDefDamage();
+*/
diff --git a/server/src/game/def/def_drugs.cpp b/server/src/game/def/def_drugs.cpp
new file mode 100644 (file)
index 0000000..c55ec57
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_drug.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_drugs.h"
+
+PDefDrug::PDefDrug()
+{
+}
+
+bool PDefDrug::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  int maxFields = 5;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi( i->c_str() ); break;
+      case 2 :
+        mType = atoi( i->c_str() ); break;
+      case 3 :
+        break;
+      case 4:
+        mDuration = atoi( i->c_str() ); break;
+      case 5 :
+      {
+        mChangeNum = atoi( i->c_str() );
+        if ( mChangeNum > 8 )
+          mChangeNum = 8;
+        maxFields = 5 + 3 * mChangeNum;
+        break;
+      }
+      default :
+        if (( Idx >= 6 ) && ( Idx <= maxFields ) )
+        {
+          switch (( Idx - 6 ) % 3 )
+          {
+            case 0:
+              mChangeType[( Idx - 6 ) / 3] = atoi( i->c_str() ); break;
+            case 1:
+              mChangeScale[( Idx - 6 ) / 3] = atof( i->c_str() ); break;
+            case 2:
+              mChangeTarget[( Idx - 6 ) / 3] = atoi( i->c_str() ); break;
+          }
+        }
+        break;
+    }
+
+    if ( Idx >= maxFields )
+      break;
+  }
+
+  return (( Idx == maxFields ) );
+}
diff --git a/server/src/game/def/def_factions.cpp b/server/src/game/def/def_factions.cpp
new file mode 100644 (file)
index 0000000..34ca985
--- /dev/null
@@ -0,0 +1,93 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+        def_factions.cpp\r
+\r
+        Authors:\r
+        - Akiko\r
+        - Namikon\r
+        - someone else?\r
+\r
+        MODIFIED: Unknown date / Unknown author\r
+        REASON: - initial release by unknown\r
+\r
+        MODIFIED: 25 Dec 2005 Namikon\r
+        REASON: - Added GPL\r
+*/\r
+\r
+#include "main.h"\r
+\r
+PDefFaction::PDefFaction()\r
+{\r
+       memset(mRelations, 0, sizeof(mRelations)); // ... array members supposed to by auto-initialized by C++\r
+}\r
+\r
+bool PDefFaction::LoadFromDef(PTokenList *Tokens)\r
+{\r
+       int Idx=0;\r
+       for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
+       {\r
+           // setfracc 19      "Monster"       -1024   0       0       -1024   -1024   -1024   -1\r
+               switch(Idx)\r
+               {\r
+                       case 0 : // setfrac\r
+                               continue;\r
+\r
+                       case 1 :\r
+                               mIndex = atol(i->c_str()); break;\r
+\r
+            case 2 :\r
+                mName = *i;\r
+                CleanUpString(&mName);\r
+                break;\r
+\r
+                       case 3 :\r
+                               mStartValue = atol(i->c_str()); break;\r
+\r
+                       case 4 :\r
+                               mAffected = atol(i->c_str())!=0; break;\r
+\r
+                       case 5 :\r
+                               mSL = atol(i->c_str()); break;\r
+\r
+                       default :\r
+                       {\r
+                               if(Idx-6 < NUMFACTIONS)\r
+                                       mRelations[Idx-6] = atol(i->c_str()); break;\r
+                       }\r
+               }\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+int PDefFaction::GetRelation(int Faction) const\r
+{\r
+       // faction 0 has no relations\r
+       if(Faction <= 0 || Faction > NUMFACTIONS)\r
+               return 0;\r
+\r
+       return mRelations[Faction-1];\r
+}\r
+\r
diff --git a/server/src/game/def/def_hack.cpp b/server/src/game/def/def_hack.cpp
new file mode 100644 (file)
index 0000000..63926f4
--- /dev/null
@@ -0,0 +1,65 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+        def_hack.cpp\r
+\r
+        Authors:\r
+        - Akiko\r
+        - Namikon\r
+        - someone else?\r
+\r
+        MODIFIED: Unknown date / Unknown author\r
+        REASON: - initial release by unknown\r
+\r
+        MODIFIED: 25 Dec 2005 Namikon\r
+        REASON: - Added GPL\r
+*/\r
+\r
+#include "main.h"\r
+\r
+PDefHack::PDefHack()\r
+{\r
+}\r
+\r
+bool PDefHack::LoadFromDef(PTokenList *Tokens)\r
+{\r
+       int Idx=0;\r
+       for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
+       {\r
+               switch(Idx)\r
+               {\r
+                       case 0: // setentry\r
+                               continue ;\r
+\r
+\r
+                       case 1: // index\r
+                               mIndex = atoi(i->c_str()); break;\r
+\r
+\r
+               }\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
diff --git a/server/src/game/def/def_implants.cpp b/server/src/game/def/def_implants.cpp
new file mode 100644 (file)
index 0000000..f77024a
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_implants.cpp
+
+    CREATED: 29 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_implants.h"
+
+bool PDefImplant::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  int maxFields = 5;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi( i->c_str() ); break;
+      case 2 :
+        mType = atoi( i->c_str() ); break;
+      case 3:
+        mDuration = atoi( i->c_str() ); break;
+      case 4 :
+      {
+        mChangeNum = atoi( i->c_str() );
+        if ( mChangeNum > 8 )
+          mChangeNum = 8;
+        maxFields = 4 + 3 * mChangeNum;
+        break;
+      }
+      default :
+        if (( Idx >= 5 ) && ( Idx <= maxFields ) )
+        {
+          switch (( Idx - 5 ) % 3 )
+          {
+            case 0:
+              mChangeType[( Idx - 5 ) / 3] = atoi( i->c_str() ); break;
+            case 1:
+              mChangeScale[( Idx - 5 ) / 3] = atof( i->c_str() ); break;
+            case 2:
+              mChangeTarget[( Idx - 5 ) / 3] = atoi( i->c_str() ); break;
+          }
+        }
+        break;
+    }
+
+    if ( Idx >= maxFields )
+      break;
+  }
+
+  return (( Idx == maxFields ) );
+}
diff --git a/server/src/game/def/def_itemcontainer.cpp b/server/src/game/def/def_itemcontainer.cpp
new file mode 100644 (file)
index 0000000..0df8e6a
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_itemcontainer.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_itemcontainer.h"
+
+PDefItemContainer::PDefItemContainer()
+{
+  mNumItems = 0;
+  for(int i=0; i<6; ++i)
+  {
+      mChance[i] = mItemId[i] = mCumulatedChance[i] = 0;
+      mQuality[i] = 0;
+  }
+}
+
+bool PDefItemContainer::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi( i->c_str() ); break;
+      case 2 :
+        mNumItemsAtOnce = atoi( i->c_str() ); break;
+      case 3 :
+        mRespawnTime = atoi( i->c_str() ); break;
+      case 4 :
+        mNumItems = atoi( i->c_str() ); break;
+      default :
+        if( (Idx >= 5) && (Idx <= 22) )
+        {
+          switch ( ((Idx-5) % 3) )
+          {
+            case 0:
+              mItemId[int((Idx - 5)/3)] = atoi( i->c_str() ); break;
+            case 1:
+              mQuality[int((Idx - 5)/3)] = atof( i->c_str() ); break;
+            case 2:
+              mChance[int((Idx - 5)/3)] = atoi( i->c_str() ); break;
+          }
+        }
+        break;
+    }
+
+    if ( Idx >= 22 )
+      break;
+  }
+
+  if (Idx >= 22)
+  {
+    BuildCumulatedChance();
+    return true;
+  }
+  else
+    return false;
+}
+
+void PDefItemContainer::BuildCumulatedChance()
+{
+  mCumulatedChance[0] = mChance[0];
+  for(int i = 1; i < mNumItems; ++i)
+  {
+    mCumulatedChance[i] = mCumulatedChance[i-1] + mChance[i];
+  }
+}
+
+int PDefItemContainer::GetRandomItemIdx() const
+{
+  int i = -1;
+  
+  if(mNumItems > 0)
+  {
+    int randomValue = GetRandom( mCumulatedChance[mNumItems-1], 1 );
+    for(i = 0; i < mNumItems; ++i)
+    {
+      if(randomValue <= mCumulatedChance[i])
+        break;
+    }
+  }
+  return i;
+}
diff --git a/server/src/game/def/def_itemmod.cpp b/server/src/game/def/def_itemmod.cpp
new file mode 100644 (file)
index 0000000..ed32329
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_itemmod.cpp
+
+    CREATED: 04 Avr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_itemmod.h"
+
+PDefItemMod::PDefItemMod()
+{
+  for ( int i = 0; i < 4; ++i )
+  {
+    mChangeTarget[i] = 0;
+    mChangeScale[i] = mChangeValue[0] = 0;
+  }
+}
+
+bool PDefItemMod::LoadFromDef ( PTokenList *Tokens )
+{
+  int Idx = 0;
+  int maxFields = 4;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi ( i->c_str() ); break;
+      case 2 :
+        mType = atoi ( i->c_str() ); break;
+      case 3:
+        break;
+      case 4 :
+      {
+        mChangeNum = atoi ( i->c_str() );
+        if ( mChangeNum > 4 )
+          mChangeNum = 4;
+        maxFields = 4 + 3 * mChangeNum;
+        break;
+      }
+      case 17 :
+        mName = *i; break;
+      default :
+        if ( ( Idx >= 5 ) && ( Idx <= maxFields ) )
+        {
+          switch ( ( Idx - 5 ) % 3 )
+          {
+            case 0:
+              mChangeTarget[ ( Idx - 5 ) / 3] = atoi ( i->c_str() ); break;
+            case 1:
+              mChangeValue[ ( Idx - 5 ) / 3] = atof ( i->c_str() ); break;
+            case 2:
+              mChangeScale[ ( Idx - 5 ) / 3] = atof ( i->c_str() ); break;
+          }
+        }
+        break;
+    }
+
+    if ( Idx >= 18 )
+      break;
+  }
+
+  return ( ( Idx >= 17 ) );
+}
diff --git a/server/src/game/def/def_itemres.cpp b/server/src/game/def/def_itemres.cpp
new file mode 100644 (file)
index 0000000..6e72e6b
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_itemres.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_itemres.h"
+
+PDefItemRestriction::PDefItemRestriction()
+{
+}
+
+bool PDefItemRestriction::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  int maxFields = 2;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi( i->c_str() ); break;
+      case 2 :
+      {
+        mNumRestrictions = atoi( i->c_str() );
+        if( mNumRestrictions > 6 )
+          mNumRestrictions = 6;
+        maxFields = 2 + 2 * mNumRestrictions;
+        break;
+      }
+      default :
+        if( (Idx >= 3) && (Idx <= maxFields) )
+        {
+          if(Idx & 1)
+          {
+            mSsqId[(Idx - 3) / 2] = atoi( i->c_str() );
+          }
+          else
+          {
+            mMinValue[(Idx - 3) / 2] = atoi( i->c_str() );
+          }
+        }
+        break;
+    }
+
+    if ( Idx >= maxFields )
+      break;
+  }
+
+  return ((Idx == maxFields));
+}
diff --git a/server/src/game/def/def_items.cpp b/server/src/game/def/def_items.cpp
new file mode 100644 (file)
index 0000000..f870547
--- /dev/null
@@ -0,0 +1,256 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+        def_item.cpp\r
+\r
+        Authors:\r
+        - Akiko\r
+        - Namikon\r
+        - someone else?\r
+\r
+        MODIFIED: Unknown date / Unknown author\r
+        REASON: - initial release by unknown\r
+\r
+        MODIFIED: 25 Dec 2005 Namikon\r
+        REASON: - Added GPL\r
+\r
+        MODIFIED: 10 Jul Hammag\r
+        REASON: - Full Item Def implementation\r
+*/\r
+\r
+#include "main.h"\r
+#define GAMEDEFS_DEFITEMSMAXSEQ 100\r
+\r
+\r
+PDefItems::PDefItems()\r
+{\r
+  //mIndex = 0;\r
+  mModel = 0;\r
+  mType = 0;\r
+  mValue1 = 0;\r
+  mValue2 = 0;\r
+  mValue3 = 0;\r
+  //mBmNum = 0;\r
+  //mmBmNumIndex = 0;\r
+  mSizeX = 1;\r
+  mSizeY = 1;\r
+  //mSmallbmnum = 0;\r
+  mWeight = 0;\r
+  mStackable = 0;\r
+  mFillWeight = 0;\r
+  mQualifier = 0;\r
+  mGfxMods = 0;\r
+  mItemGroupID = 0;\r
+  mTextDescID = 0;\r
+  mBasePrice = 0;\r
+  mTechlevel = 0;\r
+  mItemflags = 0;\r
+  // std::mShortname = "";\r
+}\r
+\r
+bool PDefItems::LoadFromDef( PTokenList *Tokens )\r
+{\r
+  int Idx = 0;\r
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )\r
+  {\r
+    switch ( Idx )\r
+    {\r
+      case 0: // setentry\r
+        continue;\r
+      case 1: // index\r
+        mIndex = atoi( i->c_str() ); break;\r
+      case 2: // name\r
+        mName = *i; break;\r
+      case 3:\r
+        mModel = atoi(i->c_str()); // used for IG display\r
+        break;\r
+      case 4:\r
+        mType = atoi( i->c_str() ); break;\r
+      case 5:\r
+        mValue1 = atoi( i->c_str() ); break;\r
+      case 6:\r
+        mValue2 = atoi( i->c_str() ); break;\r
+      case 7:\r
+        mValue3 = atoi( i->c_str() ); break;\r
+      case 8:\r
+        // mBmNum = atoi(i->c_str()); // used IG for inventory display\r
+        break;\r
+      case 9:\r
+        // mmBmNumIndex = atoi(i->c_str()); // used IG for inventory display\r
+        break;\r
+      case 10:\r
+        mSizeX = atoi( i->c_str() ); break;\r
+      case 11:\r
+        mSizeY = atoi( i->c_str() ); break;\r
+      case 12:\r
+        // mSmallbmnum = atoi(i->c_str()); // used IG for inventory display\r
+        break;\r
+      case 13:\r
+        mWeight = atof( i->c_str() ); break;\r
+      case 14:\r
+        mStackable = atoi( i->c_str() ); break;\r
+      case 15:\r
+        mFillWeight = atof( i->c_str() ); break;\r
+      case 16:\r
+        mQualifier = atoi( i->c_str() ); break;\r
+      case 17:\r
+        mGfxMods = atoi( i->c_str() ); break;\r
+      case 18:\r
+        mItemGroupID = atoi( i->c_str() ); break;\r
+      case 19:\r
+        mTextDescID = atoi( i->c_str() ); break;\r
+      case 20:\r
+        mBasePrice = atoi( i->c_str() ); break;\r
+      case 21:\r
+        mTechlevel = atoi( i->c_str() ); break;\r
+      case 22:\r
+        mItemflags = atoi( i->c_str() ); break;\r
+      case 23:\r
+        // mShortname = *i; // used IG for display on inventories Icons\r
+        break;\r
+    }\r
+  }\r
+\r
+  return true;\r
+}\r
+\r
+\r
+PDefItemsMap::PDefItemsMap()\r
+{\r
+  mMapItCache = NULL;\r
+  mMapItCacheCount = 0;\r
+  mMaxItemGroupId = -1;\r
+}\r
+\r
+PDefItemsMap::~PDefItemsMap()\r
+{\r
+  delete [] mMapItCache;\r
+}\r
+\r
+void PDefItemsMap::BuildMapItCache()\r
+{\r
+  int CacheEntryIdx = 0;\r
+  int EntrySeqIdx = 1;\r
+\r
+  mMapItCacheCount = 1 + ( mDefs.size() / GAMEDEFS_DEFITEMSMAXSEQ );\r
+\r
+  if ( mMapItCacheCount )\r
+  {\r
+    if( mMapItCache )\r
+    {\r
+      delete [] mMapItCache;\r
+    }\r
+    mMapItCache = new std::map<int, PDefItems*>::const_iterator[mMapItCacheCount];\r
+    mMapItCache[CacheEntryIdx++] = mDefs.begin();\r
+\r
+    std::map<int, PDefItems*>::const_iterator It = mDefs.begin();\r
+    while ( It != mDefs.end() )\r
+    {\r
+      if ( EntrySeqIdx++ == GAMEDEFS_DEFITEMSMAXSEQ )\r
+      {\r
+        mMapItCache[CacheEntryIdx++] = It;\r
+        EntrySeqIdx = 1;\r
+      }\r
+      It++;\r
+    }\r
+  }\r
+}\r
+\r
+void PDefItemsMap::BuildItemGroups()\r
+{\r
+  //std::map<int, std::vector<int> > mItemGroups;\r
+  // Implementation more complicated than needed but avoid too many realloc\r
+  \r
+  // Group size conting\r
+  std::map<int, int> groupSize;\r
+  for ( std::map<int, PDefItems*>::const_iterator i = mDefs.begin(); i != mDefs.end(); i++ )\r
+    groupSize[ i->second->GetItemGroupID() ]++;\r
+\r
+  // Item group vectors size reservation\r
+  mItemGroups.clear();\r
+  for ( std::map<int, int>::const_iterator i = groupSize.begin(); i != groupSize.end(); i++ )\r
+  {\r
+    mItemGroups[i->first].reserve(i->second);\r
+    if(i->first > mMaxItemGroupId)\r
+      mMaxItemGroupId = i->first;\r
+    //Console->Print("Item group %d : %d items", i->first, i->second);\r
+  }\r
+  \r
+  // Effective groups building\r
+  for ( std::map<int, PDefItems*>::const_iterator i = mDefs.begin(); i != mDefs.end(); i++ )\r
+    mItemGroups[ i->second->GetItemGroupID() ].push_back(i->first); // i->first is ItemIndex\r
+}\r
+\r
+bool PDefItemsMap::Load(const char* nName, const char* nFilename)\r
+{\r
+  if( PDefMap<PDefItems>::Load( nName, nFilename) )\r
+  {\r
+    BuildMapItCache();\r
+    BuildItemGroups();\r
+    return ( true );\r
+  }\r
+  else\r
+    return ( false );\r
+}\r
+\r
+const PDefItems* PDefItemsMap::GetDefBySeqIndex( int nSeqIndex ) const\r
+{\r
+  int CacheEntryIdx = nSeqIndex / GAMEDEFS_DEFITEMSMAXSEQ;\r
+  if ( CacheEntryIdx >= mMapItCacheCount )\r
+    return NULL;\r
+\r
+  std::map<int, PDefItems*>::const_iterator It = mMapItCache[CacheEntryIdx];\r
+  int EntrySeqIdx = CacheEntryIdx * GAMEDEFS_DEFITEMSMAXSEQ;\r
+\r
+  while (( EntrySeqIdx < nSeqIndex ) && ( It != mDefs.end() ) )\r
+  {\r
+    EntrySeqIdx++;\r
+    It++;\r
+  }\r
+\r
+  if (( EntrySeqIdx == nSeqIndex ) && ( It != mDefs.end() ) )\r
+  {\r
+    return It->second;\r
+  }\r
+  else\r
+    return NULL;\r
+}\r
+\r
+int PDefItemsMap::GetRandomItemIdFromGroup( int nGroupId ) const\r
+{\r
+  if( (nGroupId >= 0) && (nGroupId <= mMaxItemGroupId) )\r
+  {\r
+    std::map<int, std::vector<int> >::const_iterator selectedEntry = mItemGroups.find(nGroupId);\r
+    if(selectedEntry != mItemGroups.end())\r
+    {\r
+      int groupSize = selectedEntry->second.size();\r
+      if( groupSize )\r
+      {\r
+        return selectedEntry->second[GetRandom(groupSize - 1, 0)];\r
+      }\r
+    }\r
+  }\r
+\r
+  return 0;\r
+}\r
diff --git a/server/src/game/def/def_mission.cpp b/server/src/game/def/def_mission.cpp
new file mode 100644 (file)
index 0000000..0472335
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_mission.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_mission.h"
+
+PDefMission::PDefMission()
+{
+}
+
+bool PDefMission::LoadFromDef ( PTokenList *Tokens )
+{
+  int Idx = 0;
+  int arrayIdx, arraySubIdx;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi ( i->c_str() ); break;
+      case 2 :
+        mSourceId = atoi ( i->c_str() ); break;
+      case 3:
+        mStartDialog = *i; break;
+      case 4 :
+        mDescTextId = atoi ( i->c_str() ); break;
+      case 33 :
+        mEndMoney = atoi ( i->c_str() ); break;
+      case 34 :
+        mEndXp = atoi ( i->c_str() ); break;
+      case 35 :
+        mMaxTime = atoi ( i->c_str() ); break;
+      case 36 :
+        mDifficulty = atoi ( i->c_str() ); break;
+      case 37 :
+        mMinFactionValue = atoi ( i->c_str() ); break;
+      case 38 :
+        mPoints = atoi ( i->c_str() ); break;
+      case 39 :
+        mFlags = atoi ( i->c_str() ); break;
+      default :
+        if ( ( Idx >= 5 ) && ( Idx <= 16 ) )
+        {
+          arrayIdx = ( Idx - 5 ) / 3;
+          switch ( ( Idx - 5 ) % 3 )
+          {
+            case 0:
+              mNpcType[arrayIdx] = atoi ( i->c_str() ); break;
+            case 1:
+              mNpcDialog[arrayIdx] = *i; break;
+            case 2:
+              mNpcDialogStartState[arrayIdx] = atoi ( i->c_str() ); break;
+          }
+        }
+        else if ( ( Idx >= 17 ) && ( Idx <= 32 ) )
+        {
+          arrayIdx = ( Idx - 17 ) / 4;
+          arraySubIdx = ( Idx - 17 ) % 4;
+          if ( arraySubIdx == 0 )
+            mTargetType[arrayIdx] = atoi ( i->c_str() );
+          else
+            mTargetValue[arrayIdx][ arraySubIdx - 1 ] = atoi ( i->c_str() );
+
+          break;
+        }
+        break;
+    }
+
+    if ( Idx >= 39 )
+      break;
+  }
+
+  return ( ( Idx >= 38 ) );
+}
diff --git a/server/src/game/def/def_npc.cpp b/server/src/game/def/def_npc.cpp
new file mode 100644 (file)
index 0000000..7467b76
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_npc.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_npc.h"
+
+PDefNpc::PDefNpc()
+{
+  mFlags = 0;
+}
+
+bool PDefNpc::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi( i->c_str() ); break;
+      case 2 :
+        mModel = atoi( i->c_str() ); break;
+      case 4 :
+        mNGT = atoi( i->c_str() ); break;
+      case 5 :
+        mGender = atoi( i->c_str() ); break;
+      case 6 :
+        mFaction = atoi( i->c_str() ); break;
+      case 7 :
+        mHealth = atoi( i->c_str() ); break;
+      case 8 :
+        mArmorId = atoi( i->c_str() ); break;
+      case 9 :
+        mWeaponId = atoi( i->c_str() ); break;
+      case 10 :
+        mDialogScript = *i;\r
+        CleanUpString(&mDialogScript);\r
+        break;
+      case 11 :
+        mCombat = atoi( i->c_str() ); break;
+      case 12 :
+        mLoot = atoi( i->c_str() ); break;
+      case 13 :
+        mMovementEnd = atoi( i->c_str() ); break;
+      case 14 :
+        mFunctionType = atoi( i->c_str() ); break;
+      case 15 :
+        mModelScaling = atof( i->c_str() ); break;
+      case 16 :
+        mMoneyLoose = atoi( i->c_str() ); break;
+      case 17 :
+        mSkillScale = atof( i->c_str() ); break;
+      case 18 :
+        mStandardScript = *i;\r
+        CleanUpString(&mStandardScript);\r
+        break;
+      case 19 :
+        mStandardParameter = *i;\r
+        CleanUpString(&mStandardParameter);\r
+        break;
+      case 20 :
+        mMass = atoi( i->c_str() ); break;
+      case 24 :
+        mFlags = atoi( i->c_str() ); break;
+      default :
+        break;
+    }
+
+    if ( Idx >= 24 )
+      break;
+  }
+
+  return ((Idx >= 20));
+}\r
diff --git a/server/src/game/def/def_npcarmor.cpp b/server/src/game/def/def_npcarmor.cpp
new file mode 100644 (file)
index 0000000..5eeec97
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_npcarmor.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_npcarmor.h"
+
+PDefNpcArmor::PDefNpcArmor()
+{
+}
+
+bool PDefNpcArmor::LoadFromDef ( PTokenList *Tokens )
+{
+  int Idx=0;
+  for ( PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;;
+      case 1 :
+        mIndex = atoi ( i->c_str() ); break;
+      default :
+        if ( ( Idx - 2 ) < 7 )
+        {
+          mValue[Idx - 2] = atoi ( i->c_str() );
+        }
+        break;
+    }
+  }
+
+  return ( Idx >= 8 );
+}
diff --git a/server/src/game/def/def_npcgroupspawn.cpp b/server/src/game/def/def_npcgroupspawn.cpp
new file mode 100644 (file)
index 0000000..49b98a2
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_npcgroupspawn.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_npcgroupspawn.h"
+
+PDefNpcGroupSpawn::PDefNpcGroupSpawn()
+{
+  mNumNpc = 0;
+  for(int i=0; i<8; ++i)
+    mSpawnChance[i] = mFunctionValue[i] = mNpcType[i] = 0;
+
+}
+
+
+bool PDefNpcGroupSpawn::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi( i->c_str() ); break;
+      case 2 :
+        mIgnoreNearPC = atoi( i->c_str() ); break;
+      case 3 :
+        mNumNpc = atoi( i->c_str() ); break;
+      default :
+        if( (Idx >= 4) && (Idx <= (3 + 5*mNumNpc)) && (Idx <= (43)) )
+        {
+          switch ( ((Idx - 4) % 5) )
+          {
+            case 0:
+              mNpcType[int((Idx - 4)/5)] = atoi( i->c_str() ); break;
+            case 1:
+              mScript[int((Idx - 4)/5)] = *i; break;
+            case 2:
+              mScriptParameter[int((Idx - 4)/5)] = *i ; break;
+            case 3:
+              mFunctionValue[int((Idx - 4)/5)] = atoi( i->c_str() ); break;
+            case 4:
+              mSpawnChance[int((Idx - 4)/5)] = atoi( i->c_str() ); break;
+          }
+        }
+        break;
+    }
+
+    if ( Idx >= 43 )
+      break;
+  }
+
+  return ((Idx >= (3 + 5*mNumNpc)));
+}
+
+/*
+class PDefNpcGroupSpawn : public PDef
+{
+  private :
+    //int mIndex;
+    int mIgnoreNearPC;
+    int mNumNpc; // Size of the list. But that should be the size of the group...
+    int mNpcType[8];
+    std::string mScript[8];
+    std::string mScriptParameter[8];
+    int mFunctionValue[8];
+    int mSpawnChance[8];
+
+  public :
+    PDefNpcGroupSpawn();
+    //~PDefNpcGroupSpawn();
+*/
+
diff --git a/server/src/game/def/def_outposts.cpp b/server/src/game/def/def_outposts.cpp
new file mode 100644 (file)
index 0000000..18fe599
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_outposts.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_outposts.h"
+
+PDefOutpost::PDefOutpost()
+{
+  for ( int i = 0;  i < 8; ++i )
+    mInfluenceZone[i] = 0;
+}
+
+bool PDefOutpost::LoadFromDef ( PTokenList *Tokens )
+{
+  int Idx=0;
+  for ( PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0: // setentry
+        break;
+      case 1: // index
+        mIndex = atoi ( i->c_str() ); break;
+      case 2:
+        mName = *i; break;
+      case 3:
+        mType = atoi ( i->c_str() ); break;
+      case 4:
+        mStandardFaction = atoi ( i->c_str() ); break;
+      case 5:
+        mRevenue = atof ( i->c_str() ); break;
+      case 6:
+        mConquestReward = atof ( i->c_str() ); break;
+      case 7:
+        mMaxSecurity = atoi ( i->c_str() ); break;
+      default :
+        if ( ( Idx - 8 ) < 8 )
+        {
+          mInfluenceZone[Idx - 8] = atoi ( i->c_str() );
+        }
+        break;
+    }
+
+    if ( Idx == 15 )
+      break;
+  }
+
+  return ( Idx >= 7 );
+}
diff --git a/server/src/game/def/def_recycles.cpp b/server/src/game/def/def_recycles.cpp
new file mode 100644 (file)
index 0000000..2b1e0e2
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_recycles.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_recycles.h"
+
+PDefRecycle::PDefRecycle()
+{
+}
+
+bool PDefRecycle::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  int maxFields = 4;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        //mIndex = atoi ( i->c_str() );
+        break;
+      case 2 : // We use resultitem as index
+        mIndex = mResultItemId = atoi ( i->c_str() ); break;
+      case 3:
+        mBuildTime = atoi ( i->c_str() ); break;
+      case 4 :
+      {
+        mNumParts = atoi ( i->c_str() );
+        if ( mNumParts > 8 )
+          mNumParts = 8;
+        maxFields = 4 + mNumParts;
+        break;
+      }
+      default :
+        if ( ( Idx >= 5 ) && ( Idx <= maxFields ) )
+        {
+              mPartId[ Idx - 5 ] = atoi ( i->c_str() ); break;
+        }
+        break;
+    }
+
+    if ( Idx >= 12 )
+      break;
+  }
+
+  return ( ( Idx >= 5 ) );
+}
diff --git a/server/src/game/def/def_respawn.cpp b/server/src/game/def/def_respawn.cpp
new file mode 100755 (executable)
index 0000000..9a23f5c
--- /dev/null
@@ -0,0 +1,95 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+ def_respawn.cpp\r
+\r
+ MODIFIED: 22 Sep 2006 Hammag\r
+ REASON: - Creation\r
+\r
+*/\r
+\r
+#include "main.h"\r
+\r
+PDefRespawn::PDefRespawn()\r
+{\r
+}\r
+\r
+bool PDefRespawn::LoadFromDef( PTokenList *Tokens )\r
+{\r
+  int Idx = 0;\r
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )\r
+  {\r
+    switch ( Idx )\r
+    {\r
+      case 0: // setentry\r
+        continue;\r
+\r
+      case 1: // index\r
+        mIndex = atoi( i->c_str() ); break;\r
+\r
+      case 2: // value\r
+        mWorldID = atoi( i->c_str() ); break;\r
+\r
+      case 3: // value\r
+        mEntityID = atoi( i->c_str() ); break;\r
+\r
+      case 4: // value\r
+        mHazardLevel = atoi( i->c_str() ); break;\r
+\r
+      case 5: // name\r
+        mName = *i; break;\r
+\r
+      case 6: // world name\r
+        mFlag = *i; break;\r
+    }\r
+  }\r
+\r
+  return true;\r
+}\r
+\r
+// class PDefRespawnMap defined in gamedefs.h\r
+int PDefRespawnsMap::GetRespawnEntity( u32 nWorldID, u16 nGROrder ) const\r
+{\r
+  u16 tOrder = 0;\r
+\r
+  for ( std::map<int, PDefRespawn*>::const_iterator it = mDefs.begin(); it != mDefs.end(); it++ )\r
+  {\r
+    if (( u32 )( it->second->GetWorldID() ) == nWorldID )\r
+    {\r
+      ++tOrder;\r
+      if (( nWorldID == 1 ) || ( nWorldID == 2 ) ) // hack for zones 1 & 2\r
+      {\r
+        if (( 3 - tOrder ) == nGROrder )\r
+        {\r
+          return ( it->second->GetEntityID() );\r
+        }\r
+      }\r
+      else if ( tOrder == nGROrder )\r
+      {\r
+        return ( it->second->GetEntityID() );\r
+      }\r
+    }\r
+  }\r
+  return 0;\r
+}\r
diff --git a/server/src/game/def/def_scripts.cpp b/server/src/game/def/def_scripts.cpp
new file mode 100644 (file)
index 0000000..d83115d
--- /dev/null
@@ -0,0 +1,132 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+/*\r
+ def_scripts.cpp\r
+\r
+    CREATED: 12 Oct 2009 Namikon\r
+*/\r
+\r
+#include "main.h"\r
+\r
+\r
+PDefScripts::PDefScripts()\r
+{\r
+    mIdentifier = "";\r
+    mLuaFile = "";\r
+}\r
+\r
+bool PDefScripts::LoadFromDef( PTokenList *Tokens )\r
+{\r
+  int Idx = 0;\r
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )\r
+  {\r
+    switch ( Idx )\r
+    {\r
+      case 0 : // setentry\r
+        continue;\r
+      case 1 : // index\r
+        mIndex = atoi(i->c_str()); break;\r
+      case 2 :\r
+        mIdentifier = *i;\r
+        CleanUpString(&mIdentifier);\r
+        break;\r
+      case 3 :\r
+        mLuaFile = *i;\r
+        CleanUpString(&mLuaFile);\r
+        break;\r
+      case 4 :\r
+        mScriptHeader = *i;\r
+        CleanUpString(&mScriptHeader);\r
+        break;\r
+        continue;\r
+    }\r
+  }\r
+\r
+  return true;\r
+}\r
+\r
+/*\r
+bool PDefScriptsMap::Load(const char* nName, const char* nFilename)\r
+{\r
+  mName = nName;\r
+  if(mName.empty())\r
+  {\r
+    Console->Print( "%s Defs name not defined", Console->ColorText( RED, BLACK, "[ERROR]" ) );\r
+    return (false);\r
+  }\r
+\r
+  if(! *nFilename)\r
+  {\r
+    Console->Print( "%s Filename not defined for %s defs", Console->ColorText( RED, BLACK, "[ERROR]" ), mName.c_str() );\r
+    return (false);\r
+  }\r
+\r
+  PDefParser parser;\r
+  int nDefs = 0, nErrors = 0, nDup = 0;\r
+\r
+  if ( parser.Parse( nFilename ) )\r
+  {\r
+    const PDefTokenList &t = parser.GetTokens();\r
+\r
+    for ( PDefTokenList::const_iterator i = t.begin(); i != t.end(); i++ )\r
+    {\r
+      PDefScripts *it = new PDefScripts();\r
+      bool loadfail = !it->LoadFromDef( *i ), insertfail = false;\r
+\r
+      if ( !loadfail )\r
+        insertfail = !mDefs.insert( std::make_pair( it->GetIndex(), it ) ).second;\r
+      if ( loadfail || insertfail )\r
+      {\r
+        if ( insertfail )\r
+        {\r
+          ++nDup;\r
+          if ( gDevDebug ) Console->Print( "%s ini error (new duplicate id %i discarded)", mName.c_str(), it->GetIndex(), it->GetName().c_str() );\r
+        }\r
+        else\r
+        {\r
+          Console->Print( "%s ini load error @ %i", mName.c_str(), nDefs + nErrors );\r
+          ++nErrors;\r
+        }\r
+        delete it;\r
+      }\r
+      else\r
+        ++nDefs;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    Console->Print( "%s Error loading %s ini defs", Console->ColorText( RED, BLACK, "[ERROR]" ), mName.c_str() );\r
+    return ( false );\r
+  }\r
+\r
+  if ( nErrors > 0 )\r
+    Console->Print( "%s Loaded %i %s ini defs, %i error(s).", Console->ColorText( RED, BLACK, "[ERROR]" ), nDefs, mName.c_str(), nErrors );\r
+  else\r
+    Console->Print( "%s Loaded %i %s ini defs, %i error(s).", Console->ColorText( GREEN, BLACK, "[Success]" ), nDefs, mName.c_str(), nErrors );\r
+\r
+  if ( nDup )\r
+    Console->Print( "%s %d duplicate entries ignored in %s ini defs.", Console->ColorText( YELLOW, BLACK, "[Notice]" ), nDup, mName.c_str() );\r
+\r
+  return ( true );\r
+}\r
+*/\r
diff --git a/server/src/game/def/def_shots.cpp b/server/src/game/def/def_shots.cpp
new file mode 100644 (file)
index 0000000..29d5607
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_shots.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_shots.h"
+
+PDefShot::PDefShot()
+{ }
+
+bool PDefShot::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi( i->c_str() ); break;
+      case 2 :
+        mDamageId = atoi( i->c_str() ); break;
+      case 3 :
+        mMass = atoi( i->c_str() ); break;
+      case 4 :
+        mRadius = atoi( i->c_str() ); break;
+      case 5 :
+        mSpeed = atof( i->c_str() ); break;
+      default :
+        break;
+    }
+
+    if ( Idx >= 5 )
+      break;
+  }
+
+  return (( Idx >= 5 ) );
+}
diff --git a/server/src/game/def/def_skills.cpp b/server/src/game/def/def_skills.cpp
new file mode 100644 (file)
index 0000000..f0bf1e5
--- /dev/null
@@ -0,0 +1,99 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+        def_skills.cpp\r
+\r
+        Authors:\r
+        - Akiko\r
+        - Namikon\r
+        - someone else?\r
+\r
+        MODIFIED: Unknown date / Unknown author\r
+        REASON: - initial release by unknown\r
+\r
+        MODIFIED: 25 Dec 2005 Namikon\r
+        REASON: - Added GPL\r
+*/\r
+\r
+#include "main.h"\r
+\r
+// skill.def includes skill names and skill/subskill mapping\r
+\r
+PDefSkill::PDefSkill()\r
+{\r
+       mSubSkills = 0;\r
+       mNumSubSkills = 0;\r
+}\r
+\r
+PDefSkill::~PDefSkill()\r
+{\r
+       delete [] mSubSkills;\r
+}\r
+\r
+bool PDefSkill::LoadFromDef(PTokenList *Tokens)\r
+{\r
+       int Idx=0;\r
+       for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
+       {\r
+               switch(Idx)\r
+               {\r
+                       case 0 :        // setentry\r
+                               continue;\r
+\r
+                       case 1 :\r
+                               mIndex = atol(i->c_str()); break;\r
+\r
+                       case 2 :\r
+                               mName = *i; break;\r
+\r
+                       case 3 :\r
+                               mShortName = *i; break;\r
+\r
+                       case 4 :\r
+                       {\r
+                               mNumSubSkills = atol(i->c_str());\r
+                               mSubSkills = new int[mNumSubSkills];\r
+                               std::memset(mSubSkills, 0, sizeof(int)*mNumSubSkills);\r
+                               break;\r
+                       }\r
+               }\r
+\r
+               if(Idx >= 5)\r
+               {\r
+                       mSubSkills[Idx-5] = atoi(i->c_str());\r
+                       if(!GameDefs->SubSkills()->GetDef(mSubSkills[Idx-5]))\r
+                       {\r
+                               Console->Print("Skill def error: skill %s refers to nonexistant subskill %i", mShortName.c_str(), mSubSkills[Idx-5]);\r
+                               return false;\r
+                       }\r
+               }\r
+       }\r
+\r
+       if(Idx-5 != mNumSubSkills)\r
+       {\r
+               Console->Print("Warning: skill %s has incorrect number of subskills", mShortName.c_str());\r
+               Console->Print("  Expected %i, available %i", mNumSubSkills, Idx-5);\r
+       }\r
+       return true;\r
+}\r
diff --git a/server/src/game/def/def_subskills.cpp b/server/src/game/def/def_subskills.cpp
new file mode 100644 (file)
index 0000000..b414d82
--- /dev/null
@@ -0,0 +1,91 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+        def_subskills.cpp\r
+\r
+        Authors:\r
+        - Akiko\r
+        - Namikon\r
+        - someone else?\r
+\r
+        MODIFIED: Unknown date / Unknown author\r
+        REASON: - initial release by unknown\r
+\r
+        MODIFIED: 25 Dec 2005 Namikon\r
+        REASON: - Added GPL\r
+*/\r
+\r
+#include "main.h"\r
+\r
+// subskill.def, names and parameters of all subskills\r
+\r
+PDefSubSkill::PDefSubSkill()\r
+{\r
+       mActionModifiers = 0;\r
+       mNumActionModifiers = 0;\r
+}\r
+\r
+PDefSubSkill::~PDefSubSkill()\r
+{\r
+       delete [] mActionModifiers;\r
+}\r
+\r
+bool PDefSubSkill::LoadFromDef(PTokenList *Tokens)\r
+{\r
+       int Idx=0;\r
+       for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
+       {\r
+               switch(Idx)\r
+               {\r
+                       case 0 :        // setentry\r
+                               continue;\r
+\r
+                       case 1 :\r
+                               mIndex = atoi(i->c_str()); break;\r
+\r
+                       case 2 :\r
+                               mName = *i; break;\r
+\r
+                       case 3 :\r
+                               mShortName = *i; break;\r
+\r
+                       case 4 :\r
+                               mStrengthenFactor = static_cast<float>(atof(i->c_str())); break;\r
+\r
+                       case 5 :\r
+                       {\r
+                               mNumActionModifiers = atoi(i->c_str());\r
+                               mActionModifiers = new int[mNumActionModifiers];\r
+                               std::memset(mActionModifiers, 0, sizeof(int)*mNumActionModifiers);\r
+                               break;\r
+                       }\r
+               }\r
+\r
+               if(Idx>=6)\r
+                       mActionModifiers[Idx-6] = atoi(i->c_str());\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
diff --git a/server/src/game/def/def_trader.cpp b/server/src/game/def/def_trader.cpp
new file mode 100644 (file)
index 0000000..e642431
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_trader.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_trader.h"
+
+PDefTrader::PDefTrader()
+{
+  mQuality = mType = 0;
+  mWealthRespawn = mMaxWealth = 0;
+  for(int i=0; i<DEF_TRADER_MAXENTRIES; ++i)
+  {
+      mItemId[i] = 0;
+      mItemPriceScale[i] = 0;
+  }
+}
+
+bool PDefTrader::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  int maxFields = 5 + 2 * DEF_TRADER_MAXENTRIES;
+
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi( i->c_str() ); break;
+      case 2 :
+        mType = atoi( i->c_str() ); break;
+      case 3 :
+        mMaxWealth = atof( i->c_str() ); break;
+      case 4 :
+        mWealthRespawn = atof( i->c_str() ); break;
+      case 5 :
+        mQuality = atoi( i->c_str() ); break;
+      default :
+        if( (Idx >= 6) && (Idx <= maxFields) )
+        {
+          if(Idx & 1)
+          {
+            if(i->find_first_of('/') == string::npos) // Take care of the "1/5" format
+            {
+              mItemPriceScale[int((Idx - 6) / 2)] = atof( i->c_str() );
+            }
+            else
+            {
+              mItemPriceScale[int((Idx - 6) / 2)] = 1; // Workaround until we know what to do with "1/5"
+            }
+          }
+          else
+          {
+            mItemId[int((Idx - 6) / 2)] = atoi( i->c_str() );
+          }
+        }
+        break;
+    }
+
+    if ( Idx >= maxFields )
+      break;
+  }
+
+  return ((Idx >= 7)); // We suppose there must be at least one item entry
+}
diff --git a/server/src/game/def/def_vehicles.cpp b/server/src/game/def/def_vehicles.cpp
new file mode 100644 (file)
index 0000000..6bab124
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_vehicles.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_vehicles.h"
+
+PDefVhc::PDefVhc()
+{
+    mNumSeats = mArmor = mHealth = mModel = 0;
+    mName = "undefined";
+    for(int i=0; i<8; ++i)
+      mSeatId[i] = -1;
+}
+
+bool PDefVhc::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi( i->c_str() ); break;
+      case 2 :
+        mModel = atoi( i->c_str() ); break;
+      case 3 :
+        mName = *i; break;
+      case 34 :
+        mHealth = atoi( i->c_str() ); break;
+      case 35 :
+        mArmor = atoi( i->c_str() ); break;
+      default :
+        if( (Idx >= 16) && (Idx <= 23) )
+        {
+          mSeatId[Idx - 16] = atoi( i->c_str() );
+          if(mSeatId[Idx - 16] >= 0) // In theroy, we should check that it is a valid VhcSeat Index
+            ++mNumSeats;
+        }
+        break;
+    }
+
+    if ( Idx >= 36 )
+      break;
+  }
+
+  return ((Idx >= 35));
+}
diff --git a/server/src/game/def/def_vehiclesits.cpp b/server/src/game/def/def_vehiclesits.cpp
new file mode 100644 (file)
index 0000000..85b5ea4
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_vehiclesits.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_vehiclesits.h"
+
+PDefVhcSeat::PDefVhcSeat()
+{
+  mTL = mWeaponId = mType = 0;
+  mName = "undefined";
+  for(int i=0; i<3; ++i)
+    mLeaveAngle[i] = mLeavePos[i] = 0;
+  mDamageFactor = 0;
+}
+
+bool PDefVhcSeat::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi( i->c_str() ); break;
+      case 2 :
+        mType = atoi( i->c_str() ); break;
+      case 3 :
+        mName = *i; break;
+      case 30 :
+        mWeaponId = atoi( i->c_str() ); break;
+      case 31 :
+        mTL = atoi( i->c_str() ); break;
+      case 32 :
+        mDamageFactor = atof( i->c_str() ); break;
+      default :
+        if( (Idx >= 10) && (Idx <= 12) )
+        {
+          mLeavePos[Idx - 10] = atof( i->c_str() );
+        }
+        else if( (Idx >= 13) && (Idx <= 15) )
+        {
+          mLeaveAngle[Idx - 13] = atof( i->c_str() );
+        }
+        break;
+    }
+
+    if ( Idx >= 34 )
+      break;
+  }
+
+  return ((Idx >= 34));
+}
diff --git a/server/src/game/def/def_weapons.cpp b/server/src/game/def/def_weapons.cpp
new file mode 100644 (file)
index 0000000..193e125
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+
+/*
+ def_weapons.cpp
+
+    CREATED: 29 Mar 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_weapons.h"
+
+PDefWeapon::PDefWeapon()
+{
+  mIndex = -1;
+  mName = "unknown";
+  mItemIndex = mAmmoUse = mPSIuse = mWeaponType = mDiscardable = mMaxRange = 0;
+  mAggressiveWeapon = mAmmoStartFlags = mShotCnt = mBaseWeaponId = 0;
+  mAmmoTypes[0] = mAmmoTypes[1] = mAmmoTypes[2] = mAmmoTypes[3] = 0;
+  mAmmoTypes[4] = mAmmoTypes[5] = mAmmoTypes[6] = mAmmoTypes[7] = 0;
+  mItemModGroup = mItemModGroupFlags = mRareWeaponFx = 0;
+  mStaminaUse = mSkillFactor = mDamageMultiplicator = 0;
+}
+
+bool PDefWeapon::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        continue;
+      case 1 :
+        mIndex = atoi( i->c_str() ); break;
+      case 2 :
+        mName = *i; break;
+      case 3 :
+        continue; //int mFpsmodel;
+      case 4 :
+        continue; //int mAttachmodel;
+      case 5 :
+        continue; //int mMunactor;
+      case 6 :
+        continue; //float mDroptime; // useful ?
+      case 7 :
+        mItemIndex = atoi( i->c_str() ); break;
+      case 8 :
+      case 9 :
+      case 10 :
+        continue; //int effectcolor[3]; // R,G,B
+      case 11 :
+        continue; //int dynamiclight;
+      case 12 :
+        continue; //float lighttime;
+      case 13 :
+        continue; //int soundindex;
+      case 14 :
+        continue; //float mShotTime; // useful ?
+      case 15 :
+        mAmmoUse = atoi( i->c_str() ); break;
+      case 16 :
+        mPSIuse = atoi( i->c_str() ); break;
+      case 17 :
+        mStaminaUse = atof( i->c_str() ); break;
+      case 18 :
+        continue; //float upthrow;
+      case 19 :
+        continue; //int weaponHold; // ???
+      case 20 :
+        mWeaponType = atoi( i->c_str() ); break;
+      case 21 :
+        mDiscardable = atoi( i->c_str() ); break;
+      case 22 :
+        mSkillFactor = atof( i->c_str() ); break;
+      case 23 :
+        continue; //int mintgtRad;
+      case 24 :
+        continue; //int maxtgtRad;
+      case 25 :
+        mMaxRange = atoi( i->c_str() ); break;
+      case 26 :
+        mAggressiveWeapon = atoi( i->c_str() ); break;
+      case 27 :
+        mDamageMultiplicator = atof( i->c_str() ); break;
+      case 28 :
+      case 29 :
+      case 30 :
+      case 31 :
+      case 32 :
+      case 33 :
+      case 34 :
+      case 35 :
+        mAmmoTypes[Idx - 28] = atoi( i->c_str() ); break; // If mAmmoTypes[0] < 0 => =-damageId, no ammo
+      case 36 :
+        mAmmoStartFlags = atoi( i->c_str() ); break; // ???
+      case 37 :
+        continue; //int customclasstype; // ?
+      case 38 :
+        continue; //int unknown // ?
+      case 39 :
+        mShotCnt = atoi( i->c_str() ); break;
+      case 40 :
+        continue; //float shotduration; // maybe useful later
+      case 41 :
+        continue; //std::string shotfx;
+      case 42 :
+        continue; //float attachposx;
+      case 43 :
+        continue; //float attachposy;
+      case 44 :
+        continue; //float attachposz;
+      case 45 :
+        continue; //float fpposx;
+      case 46 :
+        continue; //float fpposy;
+      case 47 :
+        continue; //float fpposz;
+      case 48 :
+        mBaseWeaponId = atoi( i->c_str() ); break;
+      case 49 :
+        continue; //int weaponcolor;
+      case 50 :
+        continue; //int reloadsound;
+      case 51 :
+        mItemModGroup = atoi( i->c_str() ); break;
+      case 52 :
+        mItemModGroupFlags = atoi( i->c_str() ); break;
+      case 53 :
+        mRareWeaponFx = atoi( i->c_str() ); break;
+    }
+
+    if ( Idx >= 53 )
+      break;
+  }
+
+  return (( Idx == 52 ) || ( Idx == 53 ) );
+}
diff --git a/server/src/game/def/def_weather.cpp b/server/src/game/def/def_weather.cpp
new file mode 100644 (file)
index 0000000..726fb3c
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_weather.cpp
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#include "main.h"
+#include "def_weather.h"
+
+PDefWeather::PDefWeather()
+{
+  mNumWeathers = mSectionId = 0;
+  for(int i=0; i<8; ++i)
+      mDuration[i] = mWeatherId[i] = 0;
+}
+
+bool PDefWeather::LoadFromDef( PTokenList *Tokens )
+{
+  int Idx = 0;
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+  {
+    switch ( Idx )
+    {
+      case 0 : // setentry
+        break;
+      case 1 :
+        mIndex = atoi( i->c_str() ); break;
+      case 2 :
+        mSectionId = atoi( i->c_str() ); break;
+      case 3 :
+        mNumWeathers = atoi( i->c_str() ); break;
+      default :
+        if( (Idx >= 4) && (Idx <= (3 + 2*mNumWeathers))  && (Idx <= 19) )
+        {
+          if(Idx & 1)
+          {
+            mDuration[int((Idx - 4)/2)] = atoi( i->c_str() );
+          }
+          else
+          {
+            mWeatherId[int((Idx - 4)/2)] = atoi( i->c_str() );
+          }
+        }
+        break;
+    }
+
+    if ( Idx >= 19 )
+      break;
+  }
+
+  return ((Idx >= (3 + 2*mNumWeathers)));
+}
diff --git a/server/src/game/def/def_worldfile.cpp b/server/src/game/def/def_worldfile.cpp
new file mode 100755 (executable)
index 0000000..75f4c68
--- /dev/null
@@ -0,0 +1,158 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+/*\r
+       def_worldfile.cpp (infos from worlds/worlds.ini)\r
+\r
+       MODIFIED: 28 Sep 2007 Hammag\r
+       REASON: - Creation\r
+       \r
+       NOTA: Some entries in worlds.ini share the same Id ...\r
+             e.g: 505: techtown_enter 1/1a/1b/2\r
+             As we don't know what it means & how it is supposed to be handled,\r
+             we keep the first one for the moment. (this is managed in gamedef.cpp)\r
+       TODO: Add a config entry to select the Nth entry for each such case,\r
+             as well as a config entry to select the default entry to be kept (first/last)\r
+*/\r
+\r
+#include "main.h"\r
+\r
+PDefWorldFile::PDefWorldFile()\r
+{\r
+       mFileInWorldsDir = false;\r
+}\r
+\r
+bool PDefWorldFile::LoadFromDef(PTokenList *Tokens)\r
+{\r
+       int Idx=0;\r
+       int StartPos = 0;\r
+       int TailLen = 0;\r
+       int Len;\r
+       \r
+       for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
+       {\r
+               switch(Idx)\r
+               {\r
+                       case 0: // setentry\r
+                               continue;\r
+\r
+                       case 1: // index\r
+                               mIndex = atoi(i->c_str()); break;\r
+\r
+                       case 2: // name\r
+                       {\r
+                         Len = (*i).length();\r
+\r
+        while((StartPos = (*i).find("\\",StartPos))>-1)\r
+          (*i)[StartPos]='/';\r
+        StartPos = 0;\r
+        \r
+        if ((*i)[0] == '\"')\r
+          StartPos = 1;\r
+        \r
+                         if ( (*i).substr(StartPos,9) == "./worlds/" )\r
+                         {\r
+                           mFileInWorldsDir = true;\r
+                           StartPos += 9;\r
+                         }\r
+                         else if ( (*i).substr(StartPos,2) == "./" )\r
+          StartPos += 2;\r
+        \r
+        if ((*i)[Len-1] == '\"')\r
+          TailLen = 1;           \r
+                         if ( (Len > (StartPos+TailLen+4)) && ((*i)[Len-TailLen-4] == '.') )\r
+                           TailLen += 4;\r
+                           \r
+                         mName = (*i).substr(StartPos,Len-StartPos-TailLen); // remove prefix, extension and doublequotes                              \r
+                               \r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+\r
+       return (Idx == 3);\r
+}\r
+\r
+// class PDefWorldFileMap defined in gamedefs.h\r
+bool PDefWorldFilesMap::Load(const char* nName, const char* nFilename)\r
+{\r
+  mName = nName;\r
+  if(mName.empty())\r
+  {\r
+    Console->Print( "%s Defs name not defined", Console->ColorText( RED, BLACK, "[ERROR]" ) );\r
+    return (false);\r
+  }\r
+  \r
+  if(! *nFilename)\r
+  {\r
+    Console->Print( "%s Filename not defined for %s defs", Console->ColorText( RED, BLACK, "[ERROR]" ), mName.c_str() );\r
+    return (false);\r
+  }\r
+\r
+  PDefParser parser;\r
+  int nDefs = 0, nErrors = 0, nDup = 0;\r
+\r
+  if ( parser.Parse( nFilename ) )\r
+  {\r
+    const PDefTokenList &t = parser.GetTokens();\r
+\r
+    for ( PDefTokenList::const_iterator i = t.begin(); i != t.end(); i++ )\r
+    {\r
+      PDefWorldFile *it = new PDefWorldFile();\r
+      bool loadfail = !it->LoadFromDef( *i ), insertfail = false;\r
+\r
+      if ( !loadfail )\r
+        insertfail = !mDefs.insert( std::make_pair( it->GetIndex(), it ) ).second;\r
+      if ( loadfail || insertfail )\r
+      {\r
+        if ( insertfail )\r
+        {\r
+          ++nDup;\r
+          if ( gDevDebug ) Console->Print( "%s ini error (new duplicate id %i discarded)", mName.c_str(), it->GetIndex(), it->GetName().c_str() );\r
+        }\r
+        else\r
+        {\r
+          Console->Print( "%s ini load error @ %i", mName.c_str(), nDefs + nErrors );\r
+          ++nErrors;\r
+        }\r
+        delete it;\r
+      }\r
+      else\r
+        ++nDefs;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    Console->Print( "%s Error loading %s ini defs", Console->ColorText( RED, BLACK, "[ERROR]" ), mName.c_str() );\r
+    return ( false );\r
+  }\r
+\r
+  if ( nErrors > 0 )\r
+    Console->Print( "%s Loaded %i %s ini defs, %i error(s).", Console->ColorText( RED, BLACK, "[ERROR]" ), nDefs, mName.c_str(), nErrors );\r
+  else\r
+    Console->Print( "%s Loaded %i %s ini defs, %i error(s).", Console->ColorText( GREEN, BLACK, "[Success]" ), nDefs, mName.c_str(), nErrors );\r
+\r
+  if ( nDup )\r
+    Console->Print( "%s %d duplicate entries ignored in %s ini defs.", Console->ColorText( YELLOW, BLACK, "[Notice]" ), nDup, mName.c_str() );\r
+\r
+  return ( true );\r
+}\r
diff --git a/server/src/game/def/def_worldmodels.cpp b/server/src/game/def/def_worldmodels.cpp
new file mode 100644 (file)
index 0000000..f5de348
--- /dev/null
@@ -0,0 +1,70 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+/*\r
+       def_WorldModels.cpp\r
+\r
+       Created: 21 Sep 2006 Hammag\r
+       REASON: -\r
+*/\r
+\r
+#include "main.h"\r
+\r
+PDefWorldModel::PDefWorldModel()\r
+{\r
+}\r
+\r
+bool PDefWorldModel::LoadFromDef(PTokenList *Tokens)\r
+{\r
+       int Idx=0;\r
+       for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
+       {\r
+               switch(Idx)\r
+               {\r
+                       case 0: // setentry\r
+                                       continue;\r
+\r
+                       case 1: // index\r
+                               mIndex = atoi(i->c_str()); break;\r
+\r
+                       case 2: // name\r
+                               mName = *i; break;\r
+\r
+                       case 3: // use flag\r
+                               mUseFlags = atoi(i->c_str()); break;\r
+                               \r
+                       case 4: // function type\r
+                               mFunctionType = atoi(i->c_str()); break;\r
+\r
+                       case 5: // function value\r
+                               mFunctionValue = atoi(i->c_str()); break;\r
+                                 \r
+                       case 6: // hack difficulty\r
+                               mHackDifficulty = atoi(i->c_str()); break;\r
+\r
+                       case 7: // hack penalty\r
+                               mHackPenalty = atoi(i->c_str()); break;\r
+               }\r
+       }\r
+\r
+       return true;\r
+}\r
diff --git a/server/src/game/def/def_worlds.cpp b/server/src/game/def/def_worlds.cpp
new file mode 100644 (file)
index 0000000..ff7c55a
--- /dev/null
@@ -0,0 +1,128 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+        def_worlds.cpp\r
+\r
+        Authors:\r
+        - Akiko\r
+        - Namikon\r
+        - someone else?\r
+\r
+        MODIFIED: Unknown date / Unknown author\r
+        REASON: - initial release by unknown\r
+        MODIFIED: 25 Dec 2005 Namikon\r
+        REASON: - Added GPL\r
+\r
+        MODIFIED: 07 Oct 2006 Hammag\r
+        REASON: - Added quotes and spaces trim to mName and mDatFile.\r
+*/\r
+\r
+#include "main.h"\r
+\r
+PDefWorld::PDefWorld()\r
+{\r
+}\r
+\r
+bool PDefWorld::LoadFromDef( PTokenList *Tokens )\r
+{\r
+  int Idx = 0;\r
+  int StartPos = 0;\r
+  int TailLen = 0;\r
+  int Len;\r
+\r
+  for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )\r
+  {\r
+    switch ( Idx )\r
+    {\r
+      case 0: // setentry\r
+        continue;\r
+      case 3: // music\r
+        continue;\r
+\r
+      case 1: // index\r
+        mIndex = atoi( i->c_str() ); break;\r
+\r
+      case 2: // name\r
+      {\r
+        Len = ( *i ).length();\r
+\r
+        if (( *i )[0] == '\"' )\r
+          StartPos = 1;\r
+\r
+        while (( *i )[StartPos] == ' ' )\r
+          ++StartPos;\r
+\r
+        if (( *i )[Len-1] == '\"' )\r
+          TailLen = 1;\r
+\r
+        while (( Len - TailLen > 0 ) && (( *i )[Len-TailLen-1] == ' ' ) )\r
+          ++TailLen;\r
+\r
+        if ( StartPos >= Len - TailLen )\r
+          mName = "";\r
+        else\r
+          mName = ( *i ).substr( StartPos, Len - StartPos - TailLen );\r
+\r
+        break;\r
+      }\r
+\r
+      case 4: // datfile\r
+      {\r
+        Len = ( *i ).length();\r
+\r
+        while (( StartPos = ( *i ).find( "\\", StartPos ) ) > -1 )\r
+          ( *i )[StartPos] = '/';\r
+        StartPos = 0;\r
+\r
+        if (( *i )[0] == '\"' )\r
+          StartPos = 1;\r
+\r
+        while (( *i )[StartPos] == ' ' )\r
+          ++StartPos;\r
+\r
+        if (( StartPos <= Len - 2 ) && (( *i ).substr( StartPos, 2 ) == "./" ) )\r
+          StartPos += 2;\r
+\r
+        if (( *i )[Len-1] == '\"' )\r
+          TailLen = 1;\r
+\r
+        while (( Len - TailLen > 0 ) && (( *i )[Len-TailLen-1] == ' ' ) )\r
+          ++TailLen;\r
+\r
+        if ( StartPos >= Len - TailLen )\r
+          mDatFile = "";\r
+        else\r
+          mDatFile = ( *i ).substr( StartPos, Len - StartPos - TailLen );\r
+\r
+        break;\r
+      }\r
+\r
+      case 5:\r
+        mFlags = atoi( i->c_str() ); break;\r
+    }\r
+  }\r
+\r
+  return true;\r
+}\r
+\r
diff --git a/server/src/game/def/defparser.cpp b/server/src/game/def/defparser.cpp
new file mode 100644 (file)
index 0000000..b1288a3
--- /dev/null
@@ -0,0 +1,158 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+        defparser.cpp\r
+\r
+        Authors:\r
+        - Akiko\r
+        - Namikon\r
+        - someone else?\r
+\r
+        MODIFIED: Unknown date / Unknown author\r
+        REASON: - initial release by unknown\r
+\r
+        MODIFIED: 25 Dec 2005 Namikon\r
+        REASON: - Added GPL\r
+*/\r
+\r
+#include "main.h"\r
+\r
+PDefParser::PDefParser()\r
+{\r
+}\r
+\r
+PDefParser::~PDefParser()\r
+{\r
+       for(PDefTokenList::iterator i=mTokens.begin(); i!=mTokens.end(); i++)\r
+               delete *i;\r
+}\r
+\r
+bool PDefParser::Parse(const char *File)\r
+{\r
+       PFile *f = Filesystem->Open("", File, Config->GetOption("nc_data_path"));\r
+       enum { NOPE, MAYBE, LINE, BLOCK, MAYBE_END } Comment = NOPE;\r
+\r
+       if(f)\r
+       {\r
+               while(!f->Eof())\r
+               {\r
+                       std::string Str = f->ReadString();\r
+                       int Len = Str.length();\r
+                       if(Len <= 0)\r
+                               continue;\r
+\r
+                       if(Str.substr(0, 3)!="set")\r
+                               continue;\r
+\r
+                       //Console->Print("%s", Str.c_str());//NEW was commented , just to be sure of what we are reading\r
+\r
+                       PTokenList *List = new PTokenList();\r
+                       int Start=0, Tokens=0;\r
+                       bool Quote=false;\r
+                       for(int i=0; i<Len; i++)\r
+                       {\r
+                               if(Str[i]=='\r' || Str[i]=='\n' || Str[i]=='|' || Str[i]==';')\r
+                               {\r
+                                       if(Comment < LINE)\r
+                                       {\r
+                                               int End=i-1;\r
+                                               if(End >= Start)\r
+                                               {\r
+                                                       List->push_back(std::string(Str.substr(Start, (End-Start)+1)));\r
+                                                       Tokens++;\r
+                                                       break;\r
+                                               }\r
+                                               Quote=false;\r
+                                       }\r
+                                       if(Comment != BLOCK)\r
+                                               Comment=NOPE;\r
+                                       break;\r
+                               }\r
+\r
+                               if(!Quote)\r
+                               {\r
+                                       if(Comment < LINE && (Str[i]=='\t' || Str[i]==',' || Str[i]==' ' || Str[i]==';' || Str[i]=='|' || i==Len-1))\r
+                                       {\r
+                                               int End=i-1;\r
+                                               if(End >= Start)\r
+                                               {\r
+                                                       List->push_back(std::string(Str.substr(Start, (End-Start)+1)));\r
+                                                       Tokens++;\r
+                                               }\r
+                                               Start=i+1;\r
+                                       }\r
+\r
+                                       if(Str[i] <= ' ')\r
+                                               continue;\r
+\r
+                                       if(Str[i]=='*')\r
+                                       {\r
+                                               if(Comment==MAYBE)\r
+                                                       Comment=BLOCK;\r
+                                               else\r
+                                               if(Comment==BLOCK)\r
+                                                       Comment=MAYBE_END;\r
+                                       } else\r
+                                       if(Str[i]=='/')\r
+                                       {\r
+                                               if(Comment==MAYBE)\r
+                                               {\r
+                                                       // second slash, skip rest of line\r
+                                                       Comment=LINE;\r
+                                                       break;\r
+                                               } else\r
+                                               if(Comment==MAYBE_END)\r
+                                               {\r
+                                                       Comment=NOPE;   // comment block ends\r
+                                                       Start=i+1;\r
+                                               } else\r
+                                                       if(Comment != BLOCK)\r
+                                                               Comment=MAYBE;  // first slash\r
+                                       } else\r
+                                       {\r
+                                               if(Comment==MAYBE)\r
+                                                       Comment=NOPE;   // stand-alone slash\r
+                                               else\r
+                                               if(Comment==MAYBE_END)\r
+                                                       Comment=BLOCK;  // comment block did not end\r
+                                       }\r
+                               }\r
+\r
+                               if(Str[i]=='"')\r
+                                       Quote ^= true;\r
+                       }\r
+\r
+                       if(Tokens > 0)\r
+                               mTokens.push_back(List);\r
+                       else\r
+                               delete List;\r
+               }\r
+       } else\r
+       {\r
+               Console->Print("%s PDefParser::Parse: could not open file %s", Console->ColorText( RED, BLACK, "[ERROR]" ), File);\r
+               return false;\r
+       }\r
+\r
+       return true;\r
+}\r
diff --git a/server/src/game/def/gamedefs.cpp b/server/src/game/def/gamedefs.cpp
new file mode 100755 (executable)
index 0000000..a862945
--- /dev/null
@@ -0,0 +1,114 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+ gamedefs - this part loads "all" the definitions found in defs/\r
+\r
+ MODIFIED: 30 August 2005 Akiko\r
+ REASON: - added this fency header\r
+  - changed the path of every def file to fellow the TinNS way (loading by the config.xml)\r
+  - reformated code for easier reading\r
+ MODIFIED: 31 August 2005 Akiko\r
+ REASON: - updated paths for the def files\r
+ MODIFIED: 25 Dec 2005 Namikon\r
+ REASON: - Added GPL\r
+ MODIFIED: 06 Jan 2006\r
+ REASON: - Added GetCharKindDef(), was missing somehow\r
+ MODIFIED: 21 Sep 2005 Hammag\r
+ REASON: - Added PDefWorldModel related stuff\r
+         - Added PDefAppPlace related stuff\r
+         - completed PGameDefs destructor\r
+  MODIFIED: 22 Sep 2005 Hammag\r
+ REASON: - Added PDefAppartement related stuff\r
+         - Added PDefRespawn related stuff\r
+  MODIFIED: 28 Sep 2005 Hammag\r
+ REASON: - Added PDefWorldFile related stuff\r
+\r
+  MODIFIED: 07 Oct 2005 Hammag\r
+ REASON: - Added (inline) methods to get const iterators on Appartment and WorldFile maps\r
+\r
+ --------------------------------------------------------------------\r
+ WARNING:\r
+ When adding new .def support, don't forget to add required stuff in PGameDefs::Init()\r
+   (compiler won't complain if you don't add that)\r
+ --------------------------------------------------------------------\r
+\r
+ NOTA: as PGameDefs uses the PDefParser class, which uses the PFileSystem and PFile classes,\r
+   files are searched in the same way as the NC client does:\r
+     - first try to load the file in unpacked form from the given directory,\r
+     - else tries to load the file in packed form from the given directory,\r
+         appending pak_ to its name,\r
+     - else tries to load the packed file from the .pak archive which name is\r
+         derived from the last part of the path.\r
+\r
+*/\r
+\r
+#include "main.h"\r
+\r
+PGameDefs::PGameDefs() {}\r
+PGameDefs::~PGameDefs() {}\r
+\r
+bool PGameDefs::Init()\r
+{\r
+  Console->Print( "Initializing game defs..." );\r
+  bool Res = true;\r
+\r
+  Res |= mActionModsDefs.Load ("Action mods", "defs/actionmod.def");\r
+  Res |= mAmmosDefs.Load ("Ammos", "defs/ammo.def");\r
+  Res |= mAppartementsDefs.Load ("Apartments", "defs/appartements.def");\r
+  Res |= mAppPlacesDefs.Load ("App Places", "defs/appplaces.def");\r
+  Res |= mBlueprintPiecesDefs.Load ("Blueprint pieces", "defs/blueprintpieces.def");\r
+  Res |= mCharsDefs.Load ("Chars", "defs/characters.def");\r
+  Res |= mCharActionsDefs.Load ("Char actions", "defs/charaction.def");\r
+  Res |= mDamagesDefs.Load ("Damage", "defs/damage.def");\r
+  Res |= mDrugsDefs.Load ("Drugs", "defs/drugs.def");\r
+  Res |= mFactionsDefs.Load ("Factions", "defs/fractions.def");\r
+  //Res |= mHacksDefs.Load ("Hack", "defs/hack.def");\r
+  Res |= mImplantsDefs.Load ("Implants", "defs/implants.def");\r
+  Res |= mItemContainersDefs.Load ("Item containers", "defs/itemcontainer.def");\r
+  Res |= mItemModsDefs.Load ("Item mods", "defs/itemmod.def");\r
+  Res |= mItemRestrictionsDefs.Load ("Item restrictions", "defs/itemres.def");\r
+  Res |= mItemsDefs.Load ("Items", "defs/items.def");\r
+  Res |= mMissionsDefs.Load ("Missions", "defs/missionbase.def");\r
+  Res |= mNpcArmorsDefs.Load ("NPC Armors", "defs/npcarmor.def");\r
+  Res |= mNpcGroupSpawnsDefs.Load ("NPC group spawns", "defs/npcgroupspawn.def");\r
+  Res |= mNpcsDefs.Load ("NPC", "defs/npc.def");\r
+  Res |= mOutpostsDefs.Load ("Outposts", "defs/outposts.def");\r
+  Res |= mRecyclesDefs.Load ("Recycles", "defs/recycles.def");\r
+  Res |= mRespawnsDefs.Load ("Respawns", "defs/respawn.def");\r
+  Res |= mShotsDefs.Load ("Shots", "defs/shots.def");\r
+  Res |= mSubSkillsDefs.Load ("Subskills", "defs/subskill.def"); // Loading before skills is required\r
+  Res |= mSkillsDefs.Load ("Skills", "defs/skills.def");\r
+  Res |= mCharKindsDefs.Load ("Char kinds", "defs/charkinds.def"); // Loading after skills is required\r
+  Res |= mTradersDefs.Load ("Traders", "defs/trader.def");\r
+  Res |= mVhcsDefs.Load ("Vehicles", "defs/vehicles.def");\r
+  Res |= mVhcSeatsDefs.Load ("Vehicle seats", "defs/vehiclesits.def");\r
+  Res |= mWeaponsDefs.Load ("Weapons", "defs/weapons.def");\r
+  Res |= mWeathersDefs.Load ("Weathers", "defs/weather.def");\r
+  Res |= mWorldsDefs.Load ("Worldinfo", "defs/worldinfo.def");\r
+  Res |= mWorldFilesDefs.Load ("World files", "worlds/worlds.ini");\r
+  Res |= mWorldModelsDefs.Load ("World models", "defs/worldmodel.def");\r
+\r
+  Res |= mScriptDefs.Load ("Script defs", "defs/scripts.def");\r
+\r
+  return ( Res );\r
+}\r
diff --git a/server/src/game/def/main.h b/server/src/game/def/main.h
new file mode 100755 (executable)
index 0000000..8dfafb3
--- /dev/null
@@ -0,0 +1,97 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       main.h - main include file, contains all needed includes and important definitions\r
+\r
+       MODIFIED: 30 Aug 2006 Hammag\r
+       REASON: - created       \r
+       MODIFIED: 21 Sep 2006 Hammag\r
+       REASON: - added def_worldmodels related stuff   \r
+  MODIFIED: 22 Sep 2006 Hammag\r
+       REASON: - added def_appartements related stuff\r
+               - added def_appplaces related stuff\r
+               - added def_respawn related stuff\r
+       MODIFIED: 28 Sep 2006 Hammag\r
+       REASON: - added def_worldfile (worlds.ini) related stuff                  \r
+         \r
+*/\r
+\r
+#ifndef MAIN_H\r
+#define MAIN_H\r
+\r
+//#include "version.h"\r
+\r
+//basic includes\r
+#include "external.h"\r
+\r
+//tinns includes\r
+#include "types.h"\r
+#include "config.h"\r
+\r
+#include "console.h"\r
+#include "misc.h"\r
+\r
+#include "globals.h"\r
+\r
+#include "filesystem.h"\r
+#include "defparser.h"\r
+#include "defs.h"\r
+\r
+\r
+// The following defines are NOT used anymore\r
+#define DEF_CHARACTERS "defs/characters.def"\r
+#define DEF_SKILLS "defs/skills.def"\r
+#define DEF_SUBSKILLS "defs/subskill.def"\r
+#define DEF_CHARKINDS "defs/charkinds.def"\r
+#define DEF_WORLDINFO "defs/worldinfo.def"\r
+#define DEF_FRACTIONS "defs/fractions.def"\r
+#define DEF_HACK "defs/hack.def"\r
+#define DEF_ITEMS "defs/items.def"\r
+#define DEF_WORLDMODEL "defs/worldmodel.def"\r
+#define DEF_APPPLACES "defs/appplaces.def"\r
+#define DEF_APPARTEMENTS "defs/appartements.def"\r
+#define DEF_RESPAWN "defs/respawn.def"\r
+#define DEF_WEAPONS "defs/weapons.def"\r
+#define DEF_AMMO "defs/ammo.def"\r
+#define DEF_BLUEPRINTPIECES "defs/blueprintpieces.def"\r
+#define DEF_DAMMAGE "defs/dammage.def"\r
+#define DEF_DRUGS "defs/drugs.def"\r
+#define DEF_IMPLANTS "defs/implants.def"\r
+#define DEF_ITEMMOD "defs/itemmod.def"\r
+#define DEF_ITEMRES "defs/itemres.def"\r
+#define DEF_NPC "defs/npc.def"\r
+#define DEF_NPCARMOR "defs/npcarmor.def"\r
+#define DEF_NPCGROUPSPAWN "defs/npcgroupspawn.def"\r
+#define DEF_NPCLOOT "defs/npcloot.def"\r
+#define DEF_OUTPOSTS "defs/outposts.def"\r
+#define DEF_RECYCLES "defs/recycles.def"\r
+#define DEF_TRADER "defs/trader.def"\r
+#define DEF_VEHICLES "defs/vehicles.def"\r
+#define DEF_VEHICLESEATS "defs/vehiclesits.def"\r
+#define WRLD_WORLDFILE "worlds/worlds.ini"\r
+\r
+using namespace std;\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/def/world_datparser.cpp b/server/src/game/def/world_datparser.cpp
new file mode 100755 (executable)
index 0000000..07843de
--- /dev/null
@@ -0,0 +1,528 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+
+
+/*
+ world_datparser.h
+ Class to parse .dat world files
+
+ MODIFIED: 29 Sep 2006 Hammag
+ REASON: - Creation
+
+MODIFIED: 21 Jun 2009 Namikon
+REASON: - Added NPC Template stuff
+        - reformatted for better reading
+
+*/
+
+#include "main.h"
+
+#include "world_datparser.h"
+#include "world_datstruct.h"
+
+#include "worlddatatemplate.h"
+#include "furnituretemplate.h"
+#include "doortemplate.h"
+#include "npctemplate.h"
+
+#include <math.h>
+
+const u16 nonDiscardUseFlags = ufTouchable | ufUsable | ufChair | ufToolTarget ; // furniture always to keep even if function type = 0
+
+PWorldDatParser::PWorldDatParser()
+{
+    f = NULL;
+}
+
+PWorldDatParser::~PWorldDatParser()
+{
+
+}
+
+int PWorldDatParser::LoadDatFile( const std::string& nFilename, PWorldDataTemplate* nWorld, const bool nDiscardPassiveObjects, const bool nTestAccesOnly )
+{
+    PWorldFileHeader FileHeader;
+    PSectionHeader SectionHeader;
+    PSec2ElemHeader Sec2ElemHeader;
+
+    u32 FileLen;
+    u32 NextSectionOffset = 0;
+    u32 NextElementOffset;
+    bool ProcessOK;
+
+    mWorld = nWorld;
+    mDiscardPassiveObjects = nDiscardPassiveObjects;
+
+    if ( mNCDataPath == "" )
+    {
+        mNCDataPath = Config->GetOption( "nc_data_path" );
+    }
+
+    if ( gDevDebug )
+        Console->Print( "Reading file %s/%s", mNCDataPath.c_str(), nFilename.c_str() );
+    f = Filesystem->Open( "", nFilename.c_str(), mNCDataPath );
+
+    if ( nTestAccesOnly )
+    {
+        ProcessOK = ( bool )f;
+        Filesystem->Close( f );
+        return ( ProcessOK ? 0 : -1 );
+    }
+
+    if ( f )
+    {
+        FileLen = f->GetSize();
+
+        // Section 1
+        if (gDevDebug)
+            Console->Print( "Reading file header (section 1) ... " );
+        f->Read( &FileHeader, sizeof( PWorldFileHeader ) );
+        if (( FileHeader.mHeaderSize != 0x00000008 )
+                || ( FileHeader.mHeaderSig != 0x000fcfcf )
+                || ( FileHeader.mSection != 0x00000001 ) )
+        {
+            if (gDevDebug)
+                Console->Print( "Read header: %08x / %08x / %08x",  FileHeader.mHeaderSize, FileHeader.mHeaderSig, FileHeader.mSection);
+            Filesystem->Close( f );
+            return -2;
+        }
+        NextSectionOffset += FileHeader.mHeaderSize + 4;
+
+        // Other Sections
+        //  Header
+        while ( ! f->Eof() )
+        {
+            f->Seek( NextSectionOffset ); // Make sure we are at the computed offset
+            if (gDevDebug)
+                Console->Print( "Reading next section header ... " );
+            if (( u32 )( f->Read( &SectionHeader, sizeof( PSectionHeader ) ) ) < sizeof( PSectionHeader ) )
+            {
+                Filesystem->Close( f );
+                return -3;
+            }
+
+            if (( SectionHeader.mHeaderSize != 0x0000000c ) || ( SectionHeader.mHeaderSig != 0x0000ffcf ) )
+            {
+                Filesystem->Close( f );
+                return -2;
+            }
+
+            if ( SectionHeader.mSection == 0 )
+            {
+                if (gDevDebug)
+                    Console->Print( "Ending section reached" );
+                break;
+            }
+
+            NextElementOffset = NextSectionOffset + SectionHeader.mHeaderSize + 4;
+            NextSectionOffset = NextElementOffset + SectionHeader.mDataSize;
+            if (gDevDebug)
+                Console->Print( "Processing section %d (size %d)", SectionHeader.mSection, SectionHeader.mDataSize );
+
+            if ( SectionHeader.mSection == 2 )
+            {
+                //int cnt=0;
+                if ( gDevDebug )
+                    Console->Print( "Element Type 3 size: %d or %d", sizeof( PSec2ElemType3a ), sizeof( PSec2ElemType3a ) + sizeof( PSec2ElemType3b ) );
+                while ( NextElementOffset < NextSectionOffset )
+                {
+                    f->Seek( NextElementOffset ); // Make sure we are at the computed offset
+
+                    //if ( gDevDebug )
+                    //    Console->Print( "Reading next element header ... " );
+                    if (( u32 )( f->Read( &Sec2ElemHeader, sizeof( PSec2ElemHeader ) ) ) < sizeof( PSec2ElemHeader ) )
+                    {
+                        Filesystem->Close( f );
+                        return -3;
+                    }
+                    if (( Sec2ElemHeader.mHeaderSize != 0x0000000c ) || ( Sec2ElemHeader.mHeaderSig != 0x0ffefef1 ) )
+                    {
+                        Filesystem->Close( f );
+                        return -2;
+                    }
+                    NextElementOffset += ( Sec2ElemHeader.mHeaderSize + 4 + Sec2ElemHeader.mDataSize );
+                    //if (gDevDebug) Console->Print("Found element %d of type %d, size %d", ++cnt, Sec2ElemHeader.mElementType, Sec2ElemHeader.mDataSize);
+                    switch ( Sec2ElemHeader.mElementType )
+                    {
+                    case 1000003:
+                    {
+                        ProcessOK = ProcessSec2ElemType3( Sec2ElemHeader.mDataSize );
+                        break;
+                    }
+                    case 1000005:
+                    {
+                        ProcessOK = ProcessSec2ElemType5( Sec2ElemHeader.mDataSize );
+                        break;
+                    }
+                    case 1000006:
+                    {
+                        ProcessOK = ProcessSec2NPCEntry( Sec2ElemHeader.mDataSize );
+                        break;
+                    }
+                    default:
+                    {
+                        if (gDevDebug) Console->Print( "Ignoring SectionID %d, not supportet yet", Sec2ElemHeader.mElementType );
+                        ProcessOK = true;
+                        break;
+                    }
+                    }
+
+                    if ( !ProcessOK )
+                        return -4;
+                }
+            }
+            else
+            {
+                if ( gDevDebug )
+                    Console->Print( "Section %d ignored", SectionHeader.mSection );
+                continue;
+            }
+
+        }
+
+        Filesystem->Close( f );
+    }
+    else
+    {
+        return -1;
+    }
+
+    return 0;
+}
+
+bool PWorldDatParser::ProcessSec2ElemType3( u32 nSize ) // furniture
+{
+    PSec2ElemType3a DataA;
+    PSec2ElemType3b DataB;
+    const PDefWorldModel* nWorldModel;
+    std::string nName;
+    const u32 sza = sizeof( PSec2ElemType3a );
+    const u32 szb = sizeof( PSec2ElemType3a ) + sizeof( PSec2ElemType3b );
+
+    if (( nSize != szb ) && ( nSize != sza ) )
+    {
+        Console->Print( RED, BLACK, "[ERROR] Wrong size for Sec2ElemType3 (%d read vs %d or %d needed", nSize, sza, szb );
+        return false;
+    }
+    if (( u32 )( f->Read( &DataA, sza ) ) < sza )
+    {
+        Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType3a" );
+        return false;
+    }
+    if ( nSize == szb )
+    {
+        if (( u32 )( f->Read( &DataB, sizeof( PSec2ElemType3b ) ) ) < sizeof( PSec2ElemType3b ) )
+        {
+            Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType3b" );
+            return false;
+        }
+    }
+    else
+    {
+        DataB.mBoxLowerY = DataB.mBoxLowerZ = DataB.mBoxLowerX = 0;
+        DataB.mBoxUpperY = DataB.mBoxUpperZ = DataB.mBoxUpperX = 0;
+    }
+
+    if ( DataA.mWorldmodelID )
+    {
+        nWorldModel = GameDefs->WorldModels()->GetDef( DataA.mWorldmodelID );
+        if ( nWorldModel )
+            nName = nWorldModel->GetName();
+        else
+            nName = "UNKNOWN";
+    }
+    else
+    {
+        nName = "PASSIVE";
+        nWorldModel = NULL;
+    }
+
+    /* if (gDevDebug) {
+    Console->Print("-------------------------------------------------------");
+    Console->Print("%s (%d) : ID %d", nName.c_str(), DataA.mWorldmodelID, DataA.mObjectID);
+    if (!nWorldModel) Console->Print("y:%f z:%f x:%f model %d", DataA.mPosY , DataA.mPosZ, DataA.mPosX, DataA.mModelID);
+    Console->Print("Scale:%f Uk2:0x%08x Uk3:0x%08x", DataA.mScale, DataA.mUnknown2, DataA.mUnknown3);
+    Console->Print("Uk4:0x%08x Uk5:0x%04x", DataA.mUnknown4, DataA.mUnknown5);
+    //Console->Print("Ly:%f Lz:%f Lx:%f", DataB.mBoxLowerY, DataB.mBoxLowerZ, DataB.mBoxLowerX);
+    //Console->Print("Uy:%f Uz:%f Ux:%f", DataB.mBoxUpperY, DataB.mBoxUpperZ, DataB.mBoxUpperX);
+    }*/
+
+    if (( !nWorldModel || ( !nWorldModel->GetFunctionType() && !( nWorldModel->GetUseFlags() & nonDiscardUseFlags ) ) ) && mDiscardPassiveObjects )
+    {
+        //if ( gDevDebug )
+        //    Console->Print( "Discarded" );
+        return true;
+    }
+
+    PFurnitureItemTemplate* nItem = new PFurnitureItemTemplate;
+    nItem->mObjectID = DataA.mObjectID;
+
+    // The commented out values are not loaded from dat file atm because they are not used yet.
+    nItem->mPosY = DataA.mPosY; // float pos values are kept 0-centered
+    nItem->mPosZ = DataA.mPosZ;
+    nItem->mPosX = DataA.mPosX;
+//  nItem->mRotY = DataA.mRotY;
+    nItem->mRotZ = DataA.mRotZ;
+//  nItem->mRotX = DataA.mRotX;
+//  nItem->mScale = DataA.mScale;
+//  nItem->mUnknown2 = DataA.mUnknown2;
+    nItem->mModelID = DataA.mModelID;
+//  nItem->mUnknown3 = DataA.mUnknown3;
+//  nItem->mUnknown4 = DataA.mUnknown4;
+    nItem->mWorldmodelID = DataA.mWorldmodelID;
+//  nItem->mUnknown5 = DataA.mUnknown5;
+
+//  nItem->mBoxLowerY = DataB.mBoxLowerY;
+//  nItem->mBoxLowerZ = DataB.mBoxLowerZ;
+//  nItem->mBoxLowerX = DataB.mBoxLowerX;
+//  nItem->mBoxUpperY = DataB.mBoxUpperY;
+//  nItem->mBoxUpperZ = DataB.mBoxUpperZ;
+//  nItem->mBoxUpperX = DataB.mBoxUpperX;
+
+    nItem->mDefWorldModel = nWorldModel;
+    /*u16 func=nWorldModel->GetFunctionType();
+    if((func==18) || (func==20) || (func==29))
+    Console->Print("gate model: %d", DataA.mWorldmodelID);*/
+
+    float Angle = ( 180 + DataA.mRotZ ) * 3.14159 / 180;
+    float Radius = abs(( int )(( DataB.mBoxUpperX - DataB.mBoxLowerX ) / 2 ) );
+    if ( Radius == 0 )
+    {
+        Radius = 10;
+    }
+    Radius *= DataA.mScale;
+    Radius += 5;
+
+    // int pos values are change to match char pos scale (32000 centered)
+    nItem->mFrontPosY = ( u16 )( 32000 + DataA.mPosY + Radius * sinf( Angle ) );
+    nItem->mFrontPosZ = ( u16 )( 32000 + DataA.mPosZ );
+    nItem->mFrontPosX = ( u16 )( 32000 + DataA.mPosX + Radius * cosf( Angle ) );
+    nItem->mFrontLR = ( u8 )( 0.5 * ( DataA.mRotZ + ( DataA.mRotZ < 0 ? 360 : 0 ) ) );
+
+    mWorld->AddFurnitureItem( nItem );
+
+    return true;
+}
+
+bool PWorldDatParser::ProcessSec2ElemType5( u32 nSize ) // doors
+{
+    PSec2ElemType5Start Data;
+    char StringData[64];
+
+    const PDefWorldModel* nWorldModel;
+    std::string nName;
+    char* ActorString;
+    char* ParamString;
+
+    const u32 sza = sizeof( PSec2ElemType5Start );
+
+    if (( nSize < sza ) )
+    {
+        Console->Print( RED, BLACK, "[ERROR] Wrong size for Sec2ElemType5 (%d read vs %d needed", nSize, sza );
+        return false;
+    }
+    if (( u32 )( f->Read( &Data, sza ) ) < sza )
+    {
+        Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType5start" );
+        return false;
+    }
+    u32 szb = Data.mActorStringSize  + Data.mParamStringSize;
+
+    if ( nSize != ( sza + szb ) )
+    {
+        Console->Print( RED, BLACK, "[ERROR] Wrong size for Sec2ElemType5 (%d read vs %d needed", nSize, sza + szb );
+        return false;
+    }
+    else
+    {
+        if ( szb > 64 )
+        {
+            Console->Print( RED, BLACK, "[Warning] String data too long in Sec2ElemType5 End String. End will be ignored" );
+            szb = 64;
+        }
+        if (( u32 )( f->Read( StringData, szb ) ) < szb )
+        {
+            Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType5 End Strings" );
+            return false;
+        }
+    }
+
+    if ( Data.mWorldmodelID )
+    {
+        nWorldModel = GameDefs->WorldModels()->GetDef( Data.mWorldmodelID );
+        if ( nWorldModel )
+            nName = nWorldModel->GetName();
+        else
+            nName = "UNKNOWN";
+    }
+    else
+    {
+        nName = "PASSIVE";
+        nWorldModel = NULL;
+    }
+
+    StringData[Data.mActorStringSize - 1] = 0;
+    ActorString = StringData;
+    StringData[szb - 1] = 0;
+    ParamString = StringData + Data.mActorStringSize;
+    /*
+        if ( gDevDebug )
+        {
+            Console->Print( "-------------------------------------------------------" );
+            Console->Print( "Door %s (%d) : ID %d", nName.c_str(), Data.mWorldmodelID, Data.mDoorID );
+            Console->Print( "y:%f z:%f x:%f", Data.mPosY , Data.mPosZ, Data.mPosX );
+            Console->Print( "Uk1:0x%04x Uk1bis:0x%04x Uk5:0x%04x", Data.mUnknown1, Data.mUnknown1bis, Data.mUnknown5 );
+            Console->Print( "Type=%s Param=%s", ActorString, ParamString );
+        }
+    */
+// Let's keep knowledge of doors even without models !
+    /*  if ((!nWorldModel || (!nWorldModel->GetFunctionType() && !(nWorldModel->GetUseFlags() & nonDiscardUseFlags))) && mDiscardPassiveObjects)
+      {
+    if (gDevDebug) Console->Print("Discarded");
+    if (gDevDebug)
+    {
+    Console->Print("Door %s (%d) : ID %d", nName.c_str(), Data.mWorldmodelID, Data.mDoorID);
+    Console->Print("Type=%s Param=%s", ActorString, ParamString);
+    }
+        return true;
+      }*/
+
+    PDoorTemplate* nDoor = new PDoorTemplate;
+    nDoor->mDoorID = Data.mDoorID;
+
+    //nDoor->mUnknown1 = Data.mUnknown1; //18 00
+    //nDoor->mUnknown1bis = Data.mUnknown1bis; //00 00 ? varies
+    nDoor->mPosY = Data.mPosY;
+    nDoor->mPosZ = Data.mPosZ;
+    nDoor->mPosX = Data.mPosX;
+    //nDoor->mUnknown5 = Data.mUnknown5; //00 00 ? second byte varies
+    nDoor->mWorldmodelID = Data.mWorldmodelID; //door type from worldmodel.def
+    nDoor->mDefWorldModel = nWorldModel;
+
+    nDoor->SetDoorTypeName( ActorString );
+    nDoor->SetDoorParameters( ParamString );
+
+    mWorld->AddDoor( nDoor );
+
+    return true;
+}
+
+bool PWorldDatParser::ProcessSec2NPCEntry( u32 nSize )
+{
+    PSec2NPC_EntryPart1         tNPCPartA;
+    PSec2NPC_EntryPart2         tNPCPartB;
+    string                      tActorName;
+    string                      tAngle;
+    char                        tStrBuffer[64];
+
+    u32 tSizeOfA = sizeof(tNPCPartA);
+    u32 tSizeOfB = sizeof(tNPCPartB);
+
+    // Are we able to read enough bytes from the file? means: CAN we safely read our entire struct from the file?
+    if ( nSize < tSizeOfA )
+    {
+        Console->Print( RED, BLACK, "[ERROR] Wrong size for PSec2NPC_EntryPart1 (%d read vs %d needed", nSize, tSizeOfA );
+        return false;
+    }
+    // yes we can! So read it now. If we reach EOF, break
+    if (( u32 )( f->Read( &tNPCPartA, tSizeOfA ) ) < tSizeOfA )
+    {
+        Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry" );
+        return false;
+    }
+    // Now we have the header. lets check if we have some waypoints for this NPC
+    // Size of entire NPC entry in file
+    u32 tCompleteNPCSize = tSizeOfA + tNPCPartA.mActorStringSize + tNPCPartA.mAngleStringSize;
+    if ( tNPCPartA.mHasAdditionalCoords > 0 )
+    {
+        // It has additional coords, add 'em
+        tCompleteNPCSize += tSizeOfB*tNPCPartA.mHasAdditionalCoords;
+    }
+
+    // Do a last check if we're on the correct size
+    if ( nSize != tCompleteNPCSize )
+    {
+        Console->Print( RED, BLACK, "[ERROR] Wrong size for PSec2NPC_Entry (%d available vs %d expected", nSize, tCompleteNPCSize );
+        Console->Print( RED, BLACK, "NPC ID was: %d", tNPCPartA.mNpcID);
+        return false;
+    }
+    // We are. Continue reading!
+    // Assign the 2 strings and watch out for EOF!
+    memset(tStrBuffer, 0, 64);
+    if (( u32 )( f->Read( tStrBuffer, tNPCPartA.mActorStringSize ) ) < tNPCPartA.mActorStringSize )
+    {
+        Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry mActorStringSize" );
+        return false;
+    }
+    tActorName = tStrBuffer;
+
+    memset(tStrBuffer, 0, 64);
+    if (( u32 )( f->Read( tStrBuffer, tNPCPartA.mAngleStringSize ) ) < tNPCPartA.mAngleStringSize )
+    {
+        Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry mAngleStringSize" );
+        return false;
+    }
+    tAngle = tStrBuffer;
+
+    // We're done. Now create new NPC entry
+    PNPCTemplate* tNPC = new PNPCTemplate;
+
+    // and assing all that stuff
+    tNPC->SetUnknown1(tNPCPartA.mUnknown1);
+    tNPC->SetPosX(tNPCPartA.mPosX);
+    tNPC->SetPosY(tNPCPartA.mPosY);
+    tNPC->SetPosZ(tNPCPartA.mPosZ);
+    tNPC->SetNPCTypeID(tNPCPartA.mNPCTypeID);
+    tNPC->SetActorStrSize(tNPCPartA.mActorStringSize);
+    tNPC->SetAngleStrSize(tNPCPartA.mAngleStringSize);
+    tNPC->SetNpcID(tNPCPartA.mNpcID);
+    tNPC->SetUnknown2a(tNPCPartA.mUnknown2a);
+    tNPC->SetUnknown2b(tNPCPartA.mUnknown2b);
+    tNPC->SetUnknown2c(tNPCPartA.mUnknown2c);
+    tNPC->SetTradeID/*SetUnknown3*/(tNPCPartA.mTradeID/*mUnknown3*/);
+    tNPC->SetUnknown4(tNPCPartA.mUnknown4);
+
+    tNPC->SetActorName(tActorName);
+    tNPC->SetAngle(tAngle);
+
+    // Read additional Waypoints if available
+    u8 tCurrWayP = 0;
+    if ( tNPCPartA.mHasAdditionalCoords > 0 )
+    {
+        while ( tCurrWayP < tNPCPartA.mHasAdditionalCoords )
+        {
+            memset(&tNPCPartB, 0, tSizeOfB);
+            if (( u32 )( f->Read( &tNPCPartB, tSizeOfB ) ) < tSizeOfB )
+            {
+                Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry while reading WayPoints" );
+                return false;
+            }
+            tNPC->AddWayPoint(tNPCPartB.mPosX, tNPCPartB.mPosY, tNPCPartB.mPosZ, tCurrWayP);
+            tCurrWayP++;
+        }
+    }
+
+    if (gDevDebug) Console->Print("Added NPC ID %d", tNPCPartA.mNpcID);
+
+    mWorld->AddNPC(tNPC);
+    return true;
+}
diff --git a/server/src/game/def/world_datstruct.h b/server/src/game/def/world_datstruct.h
new file mode 100755 (executable)
index 0000000..d567674
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+
+/*
+       world_datstruct.h
+       .dat world files internal structures
+
+       MODIFIED: 29 Sep 2006 Hammag
+       REASON: - Creation
+*/
+
+#ifndef WORLD_DATSTRUCT_H
+#define WORLD_DATSTRUCT_H
+
+struct PWorldFileHeader
+{
+    u32 mHeaderSize; // must be 08 00 00 00, = header size after this field
+    u32 mHeaderSig; // must be CF CF 0F 00
+    u32 mSection; // must be 01 00 00 00
+};
+
+struct PSectionHeader
+{
+    u32 mHeaderSize; // must be 0C 00 00 00
+    u32 mHeaderSig; // must be CF FF 00 00
+    u32 mSection; // 00 00 00 00 means end
+    u32 mDataSize;
+};
+
+struct PSec2ElemHeader
+{
+    u32 mHeaderSize; // must be 0C 00 00 00
+    u32 mHeaderSig; // must be F1 FE FE 0F
+    u32 mElementType; // 1000003, 1000005 or 1000014
+    u32 mDataSize;
+};
+
+struct PSec2ElemType3a //static object ?
+{
+    f32 mPosY; //= u16 PosY - 32000
+    f32 mPosZ;
+    f32 mPosX;
+    f32 mRotY;
+    f32 mRotZ;
+    f32 mRotX;
+    f32 mScale; //00 00 80 3F ? = float(1.000000) !!! => scale factor ?????
+    u32 mUnknown2; //01 00 00 00 ?
+    u16 mModelID; // points to models.ini
+    u32 mUnknown3; //00 00 00 00 ?
+    u32 mUnknown4; //00 00 00 00 ?
+    u16 mWorldmodelID; // points to worldmodel.def
+    u16 mUnknown5; //12 00 ?
+    u32 mObjectID;
+};
+struct PSec2ElemType3b //this part is optional
+{
+    f32 mBoxLowerY; //Bounding box, for useflag "64 - selfconstructing colisionbox"
+    f32 mBoxLowerZ; // s32 or u32 ?
+    f32 mBoxLowerX;
+    f32 mBoxUpperY;
+    f32 mBoxUpperZ;
+    f32 mBoxUpperX;
+};
+
+struct PSec2ElemType5Start //door
+{
+    u16 mUnknown1; //18 00
+    u16 mUnknown1bis; //00 00 ? varies
+    f32 mPosY;
+    f32 mPosZ;
+    f32 mPosX;
+    u8 mActorStringSize; //string size with ending 0
+    u8 mParamStringSize; //string size with ending 0
+    u16 mUnknown5; //00 00 ? second byte varies
+    u16 mDoorID; // but what is the link with ObjectID sent in Use message (can't find the base offset .. or 0x80 for doors ???)
+    u16 mWorldmodelID; //door type from worldmodel.def
+};
+//Actor As String //null terminated string
+//Params As String //null terminated string - for DDOOR, 2nd param is the ID of the other (half)door (*)
+//param1 = 2 => simple lateral move ?, 3 => door frontal+lateral move (as at Typherra memorial) ?
+//last param = 0/1 for lateral move direction ? no ...
+//(*) here is the bug(?) that makes open only one half of a double door
+
+/*
+struct PSec2ElemType6Start //npc
+{
+  u16 mUnknown1; //20 00 ?
+  u16 mUnknown2; //12 00 ?
+  f32 mPosY;
+  f32 mPosZ;
+  f32 mPosX;
+  u32 mNPCTypeID; //npc type in npc.def
+  u8 mActorStringSize; //string size with ending 0
+  u8 mParamStringSize; //string size with ending 0
+  u16 mNpcID; // kind of ?
+  u32 mUnknown3; //01 00 00 00 ?
+  u16 mUnknown4; //00 00 ?
+  u16 mUnknown5; //04 00 ?
+};
+  //Actor As String //null terminated string
+  //Params As String //null terminated string - Seem to be the facing angle in degres
+struct PSec2ElemType6End
+{
+  f32 mPosY2; //second position for movement ?
+  f32 mPosZ2; //
+  f32 mPosX2; //
+};
+*/
+struct PSec2NPC_EntryPart1
+{
+    u32       mUnknown1; // Is always 0x20001200, in every log. maybe header for NPCs?
+    f32       mPosY;
+    f32       mPosZ;
+    f32       mPosX;
+    u32       mNPCTypeID; //npc type in npc.def
+    u8        mActorStringSize; //string size with ending 0
+    u8        mAngleStringSize; //string size with ending 0
+    u16       mNpcID;
+    u8        mHasAdditionalCoords;
+    u8        mUnknown2a;
+    u8        mUnknown2b;
+    u8        mUnknown2c;
+    u16       mTradeID; //mUnknown3; //00 00 ?
+    u16       mUnknown4; //04 00 ?
+};
+
+//    u8    mActorName[mActorStringSize];
+//    u8    mAngle[mAngleStringSize];
+
+struct PSec2NPC_EntryPart2  // Waypoints! or something like that...
+{
+    f32       mPosY;
+    f32       mPosZ;
+    f32       mPosX;
+};
+
+
+//  u16 mStrSize; //non-zero terminated string size
+//  Name As String //non-zero terminated string
+struct PSec2ElemType15End //area definition/sound ?
+{
+    f32 mUnknown1;
+    f32 mUnknown2;
+    f32 mUnknown3;
+    f32 mUnknown4;
+    f32 mUnknown5;
+};
+
+#endif
+
diff --git a/server/src/game/doortemplate.cpp b/server/src/game/doortemplate.cpp
new file mode 100755 (executable)
index 0000000..85388de
--- /dev/null
@@ -0,0 +1,91 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+/*\r
+  doortemplate.cpp - world door template class\r
+\r
+       MODIFIED: 05 Nov 2006 Hammag\r
+       REASON: - creation\r
+       \r
+       TODO: - mem corruption occurs if mDoorParameters[] is given a size of 6, and that 6 max param can be accepted\r
+               This bug occurs in world 105. Reason not found yet :-x\r
+*/\r
+\r
+\r
+#include "main.h"\r
+#include "doortemplate.h"\r
+\r
+PDoorTemplate::PDoorTemplate()\r
+{\r
+  mDoorID = 0;\r
+  mWorldmodelID = 0;\r
+  mDefWorldModel = NULL;\r
+  mIsDoubleDoor = false;\r
+  mIsTriggeredDoor = false;\r
+}\r
+\r
+PDoorTemplate::~PDoorTemplate()\r
+{\r
+  \r
+}\r
+\r
+void PDoorTemplate::SetDoorParameters(char* nDoorParametersString)\r
+{\r
+  char* SepPos;\r
+  int ParamNum = 0;\r
+//Console->Print("door parameter: %s", nDoorParametersString);\r
+  while ( *nDoorParametersString && (SepPos = strchr(nDoorParametersString, ',')) && (ParamNum < 4))\r
+  {\r
+    *SepPos = 0;\r
+    mDoorParameters[ParamNum++] = atoi(nDoorParametersString);\r
+    nDoorParametersString = SepPos + 1;\r
+  }\r
+  if (*nDoorParametersString)\r
+  {\r
+    if (ParamNum < 4)\r
+      mDoorParameters[ParamNum] = atoi(nDoorParametersString);\r
+    //else\r
+    //  Console->Print(RED, BLACK, "[ERROR] More than 4 parameters in Sec2ElemType5 ParamString");\r
+  }\r
+}\r
+\r
+void PDoorTemplate::SetDoorTypeName(char* nDoorTypeName)\r
+{\r
+  mDoorTypeName = nDoorTypeName;\r
+\r
+  if (mDoorTypeName == "DDOOR")\r
+  {\r
+    mIsDoubleDoor = true;\r
+  }\r
+  else if (mDoorTypeName == "TRIGDD")\r
+  {\r
+    mIsDoubleDoor = true;\r
+    mIsTriggeredDoor = true;\r
+  }\r
+  else if (mDoorTypeName == "TRIGDOOR")\r
+  {\r
+    mIsTriggeredDoor = true;\r
+  }\r
+  else if (mDoorTypeName == "NBUTTON")\r
+  {\r
+    mIsTriggeredDoor = false;\r
+  }\r
+}\r
diff --git a/server/src/game/furnituretemplate.cpp b/server/src/game/furnituretemplate.cpp
new file mode 100755 (executable)
index 0000000..9ec8a6f
--- /dev/null
@@ -0,0 +1,46 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+/*\r
+  furnituretemplate.cpp - world furniture template class\r
+\r
+       MODIFIED: 04 Oct 2006 Hammag\r
+       REASON: - creation\r
+       \r
+*/\r
+\r
+\r
+#include "main.h"\r
+#include "furnituretemplate.h"\r
+\r
+PFurnitureItemTemplate::PFurnitureItemTemplate()\r
+{\r
+  mObjectID = 0;\r
+  mModelID = 0;\r
+  mWorldmodelID = 0;\r
+  mDefWorldModel = NULL;\r
+  mLinkedObjectID = 0;\r
+}\r
+\r
+PFurnitureItemTemplate::~PFurnitureItemTemplate()\r
+{\r
+  \r
+}\r
diff --git a/server/src/game/gamecommands/Makefile b/server/src/game/gamecommands/Makefile
new file mode 100644 (file)
index 0000000..78618d5
--- /dev/null
@@ -0,0 +1,83 @@
+#
+# TinNS per-directory Makefile
+#
+# Adapted by Hammag from the Makefile system for Linux kernel.
+#
+# 14 Sep 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+# 
+
+######################################################
+# Target for this directory and its sub-dirs
+######################################################
+# Case 1 : target is an executable named as defined
+#B_TARGET := gameserver 
+
+# Case 2 : target is a TinNS lib name
+#  (use short name, as in -l linker option) 
+#L_TARGET := tinns
+
+# Case 3 (usual): objects shall be made available to the parent dir
+#  The following line will set that automatically 
+# (Should match dir name + .o suffix)
+O_TARGET := $(addsuffix .o,$(notdir $(shell /bin/pwd)))
+# Manualy define this only if you need to force the compiled obj name
+#O_TARGET := game.o
+
+
+######################################################
+# Local flags
+######################################################
+# local dir CXX Flags
+EXTRA_CXXFLAGS :=  -I/usr/include/mysql -I$(TOPDIR)/game/include
+
+# per-object CXX Flags
+#CXXFLAGS_funcdef2.o := -g
+
+# local dir Linker Flags (for intermediate .o linking)
+#EXTRA_LDFLAGS := 
+
+# any tinns Lib used (short name, as in -l linker option)
+LINK_TINNSLIBS := tinns
+
+# local dir Linker Flags (for final executable linking)
+#EXTRA_LINKFLAGS := -lrt -lpthread -lz -lm -lcrypt -L"/usr/lib/mysql" -lmysqlclient
+
+
+#####################################################
+# Subdirectories
+#####################################################
+#subdir-y := def 
+#subdir-$(CONFIG_GAMEMONKEY)   += gamemonkey
+
+
+#####################################################
+#***************************************************#
+# No further config should be needed after this line
+#***************************************************#
+ifdef TOPDIR
+
+# build list of objects ib loca ldir
+obj-y := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
+# add final object from each subdir
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+
+include $(TOPDIR)/Rules.make
+
+else #TOPDIR undef, Makefile called from non-top dir
+
+# Memorize the first calling dir in case we wanted to
+# lauch local actions from top Makefile
+  ifndef FIRSTDIR
+    FIRSTDIR :=$(CURDIR)
+    export FIRSTDIR
+  endif
+
+uptoparent : 
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+.DEFAULT :
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+endif #TOPDIR
+
diff --git a/server/src/game/gamecommands/README b/server/src/game/gamecommands/README
new file mode 100644 (file)
index 0000000..b1ab49f
--- /dev/null
@@ -0,0 +1,18 @@
+How to add new IngameCommands:\r
+\r
+- Write your gamecommand into a single .cpp file. No return value, no parameters.\r
+  The function name should be: doCmd<yourcommand>\r
+  also, add this method to class PCommands.\r
+  Example:\r
+       void PCommands::doCmdExampe() {};\r
+       \r
+- Open commands.h: Add the command-function prototype to the class\r
+- Open commands.cpp: Add a new else if() for your command\r
+- If your command is a developer command, make sure to add it to PCommands::IsDevCommand()\r
+- If your command works with the packetdumb instead of pre-striped args, make sure to add\r
+  your command to PCommands::RequirePacketDumb()\r
+- Open configtemplate.h: Add a new default level for your command\r
+- Open commands.conf: Add the command.\r
+- Save everything\r
+\r
+ Done :)
\ No newline at end of file
diff --git a/server/src/game/gamecommands/ban.cpp b/server/src/game/gamecommands/ban.cpp
new file mode 100644 (file)
index 0000000..97f103b
--- /dev/null
@@ -0,0 +1,113 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdban()\r
+{\r
+    bool SyntaxError = false;\r
+    if(ArgC < 2)\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    if(SyntaxError == true)\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "Usage", "@ban <charID or nickname> <xS(econds)>/<xM(inutes)>/<xH(ours)>/<xD(ays)>");\r
+        return;\r
+    }\r
+\r
+    if(IsArgNumeric(1) == true)\r
+    {\r
+        target = GetClientByID(GetArgInt(1));\r
+    }\r
+    else\r
+    {\r
+        char tmp_destNick[50];\r
+        GetArgText(1, tmp_destNick, 50);\r
+        target = GetClientByNick(tmp_destNick);\r
+    }\r
+\r
+    if(target == NULL) // If victim isnt found, return error\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "System", "No such player");\r
+        return;\r
+    }\r
+    if(source->GetAccountLevel() <= target->GetAccountLevel())\r
+    {\r
+        char tmpMsg[200];\r
+        snprintf(tmpMsg, 199, "Cant ban %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());\r
+        tmpMsg[199] = '\0';\r
+        Chat->send(source, CHAT_DIRECT, "System", tmpMsg);\r
+        return;\r
+    }\r
+    char tmpTimeVal[10];\r
+    GetArgText(2, tmpTimeVal, 10);\r
+\r
+    int loop_i = 0;\r
+    char tmp_atoi[10];\r
+\r
+    while(isdigit(tmpTimeVal[loop_i]) != 0 && loop_i < 10)\r
+    {\r
+        tmp_atoi[loop_i] = tmpTimeVal[loop_i];\r
+        loop_i++;\r
+    }\r
+    char timefactor[1];\r
+    timefactor[0] = tmpTimeVal[loop_i];\r
+    int timevalue = atoi(tmp_atoi);\r
+    int time_to_ban = 0;\r
+\r
+    if(strcasecmp(timefactor, "s") == 0 )\r
+    {\r
+        time_to_ban = timevalue;\r
+    }\r
+    else if(strcasecmp(timefactor, "m") == 0 )\r
+    {\r
+        time_to_ban = timevalue * 60;\r
+    }\r
+    else if(strcasecmp(timefactor, "h") == 0 )\r
+    {\r
+        time_to_ban = timevalue * 60 * 60;\r
+    }\r
+    else if(strcasecmp(timefactor, "d") == 0 )\r
+    {\r
+        time_to_ban = timevalue * 60 * 60 * 24;\r
+    }\r
+    else\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "Usage", "@ban <charID or nickname> <xS(econds)>/<xM(inutes)>/<xH(ours)>/<xD(ays)>");\r
+        return;\r
+    }\r
+    \r
+    int final_bantime = std::time(NULL) + time_to_ban;\r
+    PAccount Acc(target->GetAccountID());\r
+    Acc.SetBannedUntilTime(final_bantime);\r
+    Acc.Save();\r
+\r
+    target->InitCharVanish();\r
+\r
+    GameServer->ClientDisconnected(target);  // Now kick the player (Hes banned :) )\r
+\r
+    char tmpMsg_success[81];\r
+    snprintf(tmpMsg_success, 80, "Successfully banned %s", target->GetChar()->GetName().c_str());\r
+    tmpMsg_success[80] = '\0';\r
+    Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success);\r
+    return;\r
+}\r
diff --git a/server/src/game/gamecommands/brightness.cpp b/server/src/game/gamecommands/brightness.cpp
new file mode 100644 (file)
index 0000000..a34ebf7
--- /dev/null
@@ -0,0 +1,63 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdbrightness()\r
+{\r
+    bool SyntaxError = false;\r
+    if(ArgC < 1)\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    if(SyntaxError == true)\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "Usage", "@brightness -|<head brightness: 0..255> [-|<torso brightness>]  [-|<legs brightness>]");\r
+        return;\r
+    }\r
+\r
+    char tmp_v1[30];\r
+    char tmp_v2[30];\r
+    char tmp_v3[30];\r
+\r
+    GetArgText(1, tmp_v1, 30);\r
+    GetArgText(2, tmp_v2, 30);\r
+    GetArgText(3, tmp_v3, 30);\r
+\r
+    u8 val1, val2, val3, val4, val5, val6;\r
+    char effStr[128];\r
+    PMessage* tmpMsg;\r
+\r
+    source->GetChar()->GetCurrentBodyColor(val1, val2, val3, val4, val5, val6);\r
+    if(tmp_v1[0] != '-')\r
+    val4 = (u8)(atoi(tmp_v1) & 0xff);\r
+    if((tmp_v2[0] != '-') && (tmp_v2[0] != '\0'))\r
+    val5 = (u8)(atoi(tmp_v2) & 0xff);\r
+    if((tmp_v3[0] != '-') && (tmp_v3[0] != '\0'))\r
+    val6 = (u8)(atoi(tmp_v3) & 0xff);\r
+    source->GetChar()->SetCurrentBodyColor(val1, val2, val3, val4, val5, val6);\r
+\r
+    tmpMsg = MsgBuilder->BuildCharHelloMsg(source);\r
+    ClientManager->UDPBroadcast(tmpMsg, source);\r
+    snprintf(effStr, 127, "Body brightness set to values %d %d %d", val4, val5, val6);\r
+    effStr[127] = '\0';\r
+    Chat->send(source, CHAT_DIRECT, "System", effStr);\r
+}\r
diff --git a/server/src/game/gamecommands/broadcast.cpp b/server/src/game/gamecommands/broadcast.cpp
new file mode 100644 (file)
index 0000000..301dcad
--- /dev/null
@@ -0,0 +1,32 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdbroadcast()\r
+{\r
+    if(DumbMade == false)\r
+    {\r
+        Console->Print("%s Missing packetdumb in PCommands::doCmdbroadcast for declared broadcast function!", Console->ColorText(RED, BLACK, "[PANIC]"));\r
+        return;\r
+    }\r
+\r
+    Chat->sendBroadcast(OrgPacketDumb+11);\r
+}\r
diff --git a/server/src/game/gamecommands/color.cpp b/server/src/game/gamecommands/color.cpp
new file mode 100644 (file)
index 0000000..1d861f4
--- /dev/null
@@ -0,0 +1,63 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdcolor()\r
+{\r
+    bool SyntaxError = false;\r
+    if(ArgC < 1)\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    if(SyntaxError == true)\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "Usage", "@color -|<head color: 0..255> [-|<torso color>]  [-|<legs color>]");\r
+        return;\r
+    }\r
+\r
+    char tmp_v1[30];\r
+    char tmp_v2[30];\r
+    char tmp_v3[30];\r
+\r
+    GetArgText(1, tmp_v1, 30);\r
+    GetArgText(2, tmp_v2, 30);\r
+    GetArgText(3, tmp_v3, 30);\r
+\r
+    u8 val1, val2, val3, val4, val5, val6;\r
+    char effStr[128];\r
+    PMessage* tmpMsg;\r
+\r
+    source->GetChar()->GetCurrentBodyColor(val1, val2, val3, val4, val5, val6);\r
+    if(tmp_v1[0] != '-')\r
+    val1 = (u8)(atoi(tmp_v1) & 0xff);\r
+    if((tmp_v2[0] != '-') && (tmp_v2[0] != '\0'))\r
+    val2 = (u8)(atoi(tmp_v2) & 0xff);\r
+    if((tmp_v3[0] != '-') && (tmp_v3[0] != '\0'))\r
+    val3 = (u8)(atoi(tmp_v3) & 0xff);\r
+    source->GetChar()->SetCurrentBodyColor(val1, val2, val3, val4, val5, val6);\r
+\r
+    tmpMsg = MsgBuilder->BuildCharHelloMsg(source);\r
+    ClientManager->UDPBroadcast(tmpMsg, source);\r
+    snprintf(effStr, 127, "Body color set to values %d %d %d", val1, val2, val3);\r
+    effStr[127] = '\0';\r
+    Chat->send(source, CHAT_DIRECT, "System", effStr);\r
+}\r
diff --git a/server/src/game/gamecommands/debug.cpp b/server/src/game/gamecommands/debug.cpp
new file mode 100644 (file)
index 0000000..6a63e3a
--- /dev/null
@@ -0,0 +1,94 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmddebug()\r
+{\r
+    PDebugMode nWhat = DBG_ALL;\r
+    int nHow = -1;\r
+    const char* DbgTarget = "all";\r
+    char DbgMessage[80];\r
+    const char* Usage = "@debug [loc[ation] | it[emid] | sub[way]] [0|1]";\r
+    \r
+    if(ArgC > 0)\r
+    {\r
+      if(IsArgNumeric(1) == true)\r
+      {\r
+          if(GetArgInt(1) == 0)\r
+          {\r
+              nHow = 0;\r
+          }\r
+          else\r
+          {\r
+              nHow = 1;\r
+          }\r
+      }\r
+      else\r
+      {\r
+          char tmp[10];\r
+          if(GetArgText(1, tmp, 10))\r
+          {\r
+              if(strncmp(tmp, "loc", 3) == 0)\r
+              {\r
+                  nWhat = DBG_LOCATION;\r
+                  DbgTarget = "location";\r
+              }\r
+              else if(strncmp(tmp, "it", 2) == 0)\r
+              {\r
+                  nWhat = DBG_ITEMID;\r
+                  DbgTarget = "itemid";\r
+              }\r
+              else if(strncmp(tmp, "sub", 3) == 0)\r
+              {\r
+                  nWhat = DBG_SUBWAY;\r
+                  DbgTarget = "subway";\r
+              }\r
+          }\r
+      }\r
+  \r
+      if (nWhat != DBG_ALL)\r
+      {\r
+          if(ArgC == 1)\r
+          {\r
+              nHow = (source->GetDebugMode(nWhat) ? 0 : 1); // toggle if no arg\r
+          }\r
+          else if(ArgC > 1 && GetArgInt(2) == 0)\r
+          {\r
+              nHow = 0;\r
+          }\r
+          else if(ArgC > 1 && GetArgInt(2) == 1)\r
+          {\r
+              nHow = 1;\r
+          }\r
+      }\r
+    }\r
+    \r
+    if (nHow != -1)\r
+    {\r
+        source->SetDebugMode(nWhat, nHow);\r
+        snprintf(DbgMessage, 80, "Debug %s is now %s", DbgTarget, (nHow ? "ENABLED" : "DISABLED"));\r
+        Chat->send(source, CHAT_DIRECT, "System", DbgMessage);\r
+    }\r
+    else\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "Usage", Usage);\r
+    }\r
+}\r
diff --git a/server/src/game/gamecommands/effect.cpp b/server/src/game/gamecommands/effect.cpp
new file mode 100644 (file)
index 0000000..8f602c6
--- /dev/null
@@ -0,0 +1,54 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdeffect()\r
+{\r
+    bool SyntaxError = false;\r
+    if(ArgC < 1)\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    if(IsArgNumeric(1) == false)\r
+        SyntaxError = true;\r
+\r
+    if(SyntaxError == true)\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "Usage", "@effect <effect: 0=none, 1 .. 17> [<density: 0=max .. 255=min>]");\r
+        return;\r
+    }\r
+\r
+    u8 val1, val2;\r
+    char effStr[128];\r
+    PMessage* tmpMsg;\r
+\r
+    val1 = (u8)(GetArgInt(1) & 0xff);\r
+    val2 = (u8)(GetArgInt(2) & 0xff);\r
+\r
+    source->GetChar()->SetBodyEffect(val1, val2);\r
+\r
+    tmpMsg = MsgBuilder->BuildCharHelloMsg(source);\r
+    ClientManager->UDPBroadcast(tmpMsg, source);\r
+    snprintf(effStr, 127, "Body effect set to value %d with density %d (but you can see it yourself)", val1, val2);\r
+    effStr[127] = '\0';\r
+    Chat->send(source, CHAT_DIRECT, "System", effStr);\r
+}\r
diff --git a/server/src/game/gamecommands/givemoney.cpp b/server/src/game/gamecommands/givemoney.cpp
new file mode 100644 (file)
index 0000000..94f2679
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+#include "main.h"
+
+void PCommands::doCmdgivemoney()
+{
+    u32 cashtoadd = 0;
+    bool SyntaxError = false;
+    if (ArgC < 1)
+    {
+        SyntaxError = true;
+    }
+
+    if (IsArgNumeric(1) == false)
+    {
+        SyntaxError = true;
+    }
+    else
+    {
+        cashtoadd = (u32)GetArgInt(1);
+    }
+    if (cashtoadd == 0)
+    {
+        SyntaxError = true;
+    }
+
+    if (SyntaxError == true)
+    {
+        Chat->send(source, CHAT_DIRECT, "Usage", "@givemoney <amount> [<charID or nickname>]");
+        return;
+    }
+
+    if (ArgC == 2)
+    {
+        if (IsArgNumeric(2) == true)
+        {
+            target = GetClientByID(GetArgInt(2));
+        }
+        else
+        {
+            char tmp_destNick[50];
+            GetArgText(2, tmp_destNick, 50);
+            target = GetClientByNick(tmp_destNick);
+        }
+        if (target == NULL)
+        {
+            Chat->send(source, CHAT_DIRECT, "System", "No such player");
+            return;
+        }
+        if (source->GetAccountLevel() <= target->GetAccountLevel())
+        {
+            char tmpMsg[200];
+            snprintf(tmpMsg, 199, "Cant manipulate %s's credits, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());
+            tmpMsg[199] = '\0';
+            Chat->send(source, CHAT_DIRECT, "System", tmpMsg);
+            return;
+        }
+
+        u32 oldcashval = target->GetChar()->GetCash();
+        u32 newcashvalue = target->GetChar()->SetCash(oldcashval + cashtoadd);
+        u32 diffcash = newcashvalue - oldcashval;
+
+        PMessage* tmpMsg_cash = MsgBuilder->BuildCharMoneyUpdateMsg(target, newcashvalue);
+        target->SendUDPMessage(tmpMsg_cash);
+        tmpMsg_cash = NULL;
+
+        char tmpMsg_success[200];
+        snprintf(tmpMsg_success, 199, "Added %d NC to %s's wallet (Has now %d NC)", diffcash, target->GetChar()->GetName().c_str(), newcashvalue);
+        tmpMsg_success[199] = '\0';
+        Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success);
+    }
+    else
+    {
+        u32 oldcashval = source->GetChar()->GetCash();
+        u32 newcashvalue = source->GetChar()->SetCash(oldcashval + cashtoadd);
+
+        PMessage* tmpMsg_cash = MsgBuilder->BuildCharMoneyUpdateMsg(source, newcashvalue);
+        source->SendUDPMessage(tmpMsg_cash);
+        tmpMsg_cash = NULL;
+        //Console->Print("oldcashval: %d  newcashvalue: %d", oldcashval, newcashvalue);
+    }
+}
diff --git a/server/src/game/gamecommands/h.cpp b/server/src/game/gamecommands/h.cpp
new file mode 100644 (file)
index 0000000..3d4ccd9
--- /dev/null
@@ -0,0 +1,75 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmd_dev_h()\r
+{\r
+  if(IsAdmin() == false)\r
+    return;\r
+\r
+  if(source->GetAccountLevel() < PAL_ADMIN)\r
+    return;\r
+\r
+\r
+\r
+  PMessage* tmpMsg = MsgBuilder->BuildEntityPositionMsg(source, GetArgInt(1) & 0xffff, GetArgInt(2) & 0xffff, GetArgInt(3) & 0xffff);\r
+  source->SendUDPMessage(tmpMsg);\r
+/*\r
+  u8 val1, val2, val3, val4;\r
+  char tmpStr[128];\r
+  \r
+  if(ArgC > 0)\r
+  {\r
+    val1 = (u8)(GetArgInt(1) & 0xff);\r
+    val2 = (u8)(GetArgInt(2) & 0xff);\r
+    val3 = (u8)(GetArgInt(3) & 0xff);\r
+    val4 = (ArgC > 3) ? (u8)(GetArgInt(4) & 0xff) : 0x01;\r
+  }\r
+  else\r
+  {\r
+    val1 = 0xff;\r
+    val2 = 0xff;\r
+    val3 = 0xff;\r
+    val4 = 0x01;\r
+  }\r
+\r
+    PMessage* tmpMsg = new PMessage(14);  \r
+\r
+       *tmpMsg << (u8)0x13;\r
+       *tmpMsg << (u16)0x0000; //source->GetUDP_ID(); // just placeholder, must be set outside\r
+       *tmpMsg << (u16)0x0000;  // source->GetSessionID(); // just placeholder, must be set outside\r
+       *tmpMsg << (u8)0x00; // Message length placeholder;\r
+       *tmpMsg << (u8)0x1f;\r
+       *tmpMsg << (u16)source->GetLocalID();\r
+       *tmpMsg << (u8)0x30;\r
+       *tmpMsg << (u8)val1; //Head Heath (% ?) (45%)\r
+       *tmpMsg << (u8)val2; //Body Heath (35%)\r
+       *tmpMsg << (u8)val3; //Feet Heath (20%)\r
+       *tmpMsg << (u8)val4;\r
+\r
+    (*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6);\r
+    ClientManager->UDPBroadcast(tmpMsg, source);\r
+\r
+    snprintf(tmpStr, 127, "Data set to values 0x%02x 0x%02x", val1, val2);\r
+    tmpStr[127] = '\0';\r
+    Chat->send(source, CHAT_DIRECT, "System", tmpStr);\r
+    */\r
+}\r
diff --git a/server/src/game/gamecommands/info.cpp b/server/src/game/gamecommands/info.cpp
new file mode 100644 (file)
index 0000000..b4f372b
--- /dev/null
@@ -0,0 +1,117 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdinfo()\r
+{\r
+    bool SyntaxError = false;\r
+    if(ArgC < 1)\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    if(SyntaxError == true)\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "Usage", "@info <charID or nickname>");\r
+        return;\r
+    }\r
+\r
+    if(IsArgNumeric(1) == true)\r
+    {\r
+        target = GetClientByID(GetArgInt(1));\r
+    }\r
+    else\r
+    {\r
+        char tmp_destNick[50];\r
+        GetArgText(1, tmp_destNick, 50);\r
+        target = GetClientByNick(tmp_destNick);\r
+    }\r
+\r
+    if(target == NULL) // If victim isnt found, return error\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "System", "No such player");\r
+        return;\r
+    }\r
+    // *************** Checks done, proceed with command\r
+    /*\r
+        DIRECT> System: PlayerInformation\r
+        DIRECT> Info: CharID     : %d     // victim->GetCharID();\r
+        DIRECT> Info: AccountID  : %d     // victim->GetAccount()->GetID();\r
+        DIRECT> Info: LoginName  : %s     // victim->GetAccount()->GetName();\r
+        DIRECT> Info: AccessLevel: %d     // victim->GetAccountLevel();\r
+        DIRECT> Info: Current Loc: %d     // Chars->GetChar(source->GetCharID())->GetLocation();\r
+        DIRECT> Info: IP address : %s     // victim->GetAddress():\r
+\r
+        Maybe for future addons...\r
+        DIRECT> System: CharInformation\r
+        DIRECT> Info: Faction      : %d     // Chars->GetChar(source->GetCharID())->GetFaction();\r
+        DIRECT> Info: Cash         : %d     // Chars->GetChar(source->GetCharID())->GetCash();\r
+        DIRECT> Info: Soullight    : %d     // Chars->GetChar(source->GetCharID())->GetSoullight();\r
+    */\r
+    \r
+    PAccount Acc(target->GetAccountID());\r
+    \r
+    // If source != target\r
+    if(source->GetAccountID() != target->GetAccountID())\r
+    {\r
+        // Check if accesslevel is lower\r
+        if(source->GetAccountLevel() <= target->GetAccountLevel())\r
+        {\r
+            char tmpMsg[200];\r
+            snprintf(tmpMsg, 199, "Cant display info about %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());\r
+            tmpMsg[199] = '\0';\r
+            Chat->send(source, CHAT_DIRECT, "System", tmpMsg);\r
+            return;\r
+        }\r
+    }\r
+\r
+    char tmpInfo_head[151];\r
+    char tmpInfo_cID[151];\r
+    char tmpInfo_aID[151];\r
+    char tmpInfo_Login[151];\r
+    char tmpInfo_AxxLv[151];\r
+    char tmpInfo_Loc[151];\r
+    char tmpInfo_IP[151];\r
+\r
+    snprintf(tmpInfo_head, 150,     "PlayerInformation");\r
+    snprintf(tmpInfo_cID, 150,      "CharID     : %d",  target->GetCharID());\r
+    snprintf(tmpInfo_aID, 150,      "AccountID  : %d",  Acc.GetID());\r
+    snprintf(tmpInfo_Login, 150,    "LoginName  : %s",  Acc.GetName().c_str());\r
+    snprintf(tmpInfo_AxxLv, 150,    "AccessLevel: %d",  Acc.GetLevel());\r
+    snprintf(tmpInfo_Loc, 150,      "Current Loc: %d",  Chars->GetChar(target->GetCharID())->GetLocation());\r
+    snprintf(tmpInfo_IP, 150,       "IP address : %s",  target->GetAddress());\r
+    \r
+    tmpInfo_head[150] = '\0';\r
+    tmpInfo_cID[150] = '\0';\r
+    tmpInfo_aID[150] = '\0';\r
+    tmpInfo_Login[150] = '\0';\r
+    tmpInfo_AxxLv[150] = '\0';\r
+    tmpInfo_Loc[150] = '\0';\r
+    tmpInfo_IP[150] = '\0';\r
+\r
+    Chat->send(source, CHAT_DIRECT, "System", tmpInfo_head);\r
+    Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_cID);\r
+    Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_aID);\r
+    Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_Login);\r
+    Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_AxxLv);\r
+    Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_Loc);\r
+    Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_IP);\r
+}\r
diff --git a/server/src/game/gamecommands/jail.cpp b/server/src/game/gamecommands/jail.cpp
new file mode 100644 (file)
index 0000000..d3c60eb
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+#include "main.h"
+
+void PCommands::doCmdjail()
+{
+  bool SyntaxError = false;
+  if ( ArgC < 1 )
+  {
+    SyntaxError = true;
+  }
+
+  if ( SyntaxError == true )
+  {
+    Chat->send( source, CHAT_DIRECT, "Usage", "@jail <charID or nickname>" );
+    return;
+  }
+
+  if ( IsArgNumeric( 1 ) == true )
+  {
+    target = GetClientByID( GetArgInt( 1 ) );
+  }
+  else
+  {
+    char tmp_destNick[50];
+    GetArgText( 1, tmp_destNick, 50 );
+    target = GetClientByNick( tmp_destNick );
+  }
+
+  if ( target == NULL ) // If victim isnt found, return error
+  {
+    Chat->send( source, CHAT_DIRECT, "System", "No such player" );
+    return;
+  }
+  // Check accountlevel (Only higher's can perform commands on lower's)
+  if ( source->GetAccountLevel() <= target->GetAccountLevel() )
+  {
+    char tmpMsg[200];
+    snprintf( tmpMsg, 199, "Cant jail %s, target level is higher or equal to yours!", Chars->GetChar( target->GetCharID() )->GetName().c_str() );
+    tmpMsg[199] = '\0';
+    Chat->send( source, CHAT_DIRECT, "System", tmpMsg );
+    return;
+  }
+
+  u32 currLoc = target->GetChar()->GetLocation();
+  // Make sure that target player is not already in Regants
+  if ( currLoc == 550 || currLoc == 551 )
+  {
+    Chat->send( source, CHAT_DIRECT, "System", "Target player is already jailed!" );
+    return;
+  }
+
+// *************** Checks done, proceed with command
+
+  int destZone = 550; // DarkMetal #1
+  if ( target->ChangeCharLocation( destZone, true ) )
+  {
+    PMessage* tmpMsg_zone = MsgBuilder->BuildAptLiftUseMsg( target, destZone, 0 );
+    target->SendUDPMessage( tmpMsg_zone );
+    tmpMsg_zone = NULL;
+
+    char tmpMsg_success[81];
+    snprintf( tmpMsg_success, 80, "Successfully jailed %s", target->GetChar()->GetName().c_str() );
+    tmpMsg_success[80] = '\0';
+    Chat->send( source, CHAT_DIRECT, "System", tmpMsg_success );
+    return;
+  }
+  else
+  {
+    Console->Print( "%s Unable to change location for player %d to %d", Console->ColorText( RED, BLACK, "[PANIC]" ), target->GetCharID(), destZone );
+  }
+}
diff --git a/server/src/game/gamecommands/kick.cpp b/server/src/game/gamecommands/kick.cpp
new file mode 100644 (file)
index 0000000..49edb01
--- /dev/null
@@ -0,0 +1,78 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdkick()\r
+{\r
+    bool SyntaxError = false;\r
+    if(ArgC < 1)\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    if(SyntaxError == true)\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "Usage", "@kick <charID or nickname>");\r
+        return;\r
+    }\r
+\r
+    if(IsArgNumeric(1) == true)\r
+    {\r
+        target = GetClientByID(GetArgInt(1));\r
+    }\r
+    else\r
+    {\r
+        char tmp_destNick[50];\r
+        GetArgText(1, tmp_destNick, 50);\r
+        target = GetClientByNick(tmp_destNick);\r
+    }\r
+\r
+    if(target == NULL) // If victim isnt found, return error\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "System", "No such player");\r
+        return;\r
+    }\r
+\r
+    // Make sure only people with a higher level than victim can kick victim\r
+    if(source->GetAccountLevel() <= target->GetAccountLevel())\r
+    {\r
+        char tmpMsg[200];\r
+        snprintf(tmpMsg, 199, "Cant kick %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());\r
+        tmpMsg[199] = '\0';\r
+        Chat->send(source, CHAT_DIRECT, "System", tmpMsg);\r
+        return;\r
+    }\r
+\r
+// *************** Checks done, proceed with command\r
+    int final_bantime = std::time(NULL) + 60;               // Ban 60 seconds (Anti-Rejoin)\r
+    PAccount Acc(target->GetAccountID());\r
+    Acc.SetBannedUntilTime(final_bantime);\r
+    Acc.Save();\r
+\r
+    target->InitCharVanish();\r
+    GameServer->ClientDisconnected(target);                 // Kick\r
+\r
+    Console->Print("%s %s (Lv %d) kicked %s (Lv %d)", Console->ColorText(YELLOW, BLACK, "[GameCommand]"), Chars->GetChar(source->GetCharID())->GetName().c_str(), source->GetAccountLevel(), Chars->GetChar(target->GetCharID())->GetName().c_str(), target->GetAccountLevel());\r
+    char successmsg[100];\r
+    snprintf(successmsg, 99, "Kicked %s", Chars->GetChar(target->GetCharID())->GetName().c_str());\r
+    successmsg[99] = '\0';\r
+    Chat->send(source, CHAT_DIRECT, "System", successmsg);\r
+}\r
diff --git a/server/src/game/gamecommands/listbans.cpp b/server/src/game/gamecommands/listbans.cpp
new file mode 100644 (file)
index 0000000..e82f97f
--- /dev/null
@@ -0,0 +1,28 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdlistbans()\r
+{\r
+    Chat->send(source, CHAT_DIRECT, "System", "Sorry, namikon was too lazy to code that ^^");\r
+    Chat->send(source, CHAT_DIRECT, "System", "Please wait until the ban is removed automaticly or edit your sqlDB");\r
+    return;\r
+}\r
diff --git a/server/src/game/gamecommands/main.h b/server/src/game/gamecommands/main.h
new file mode 100644 (file)
index 0000000..dfdd5cd
--- /dev/null
@@ -0,0 +1,87 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       main.h - main include file, contains all needed includes and important definitions\r
+\r
+       MODIFIED: 30 Aug 2006 Hammag\r
+       REASON: - created\r
+\r
+*/\r
+\r
+#ifndef MAIN_H\r
+#define MAIN_H\r
+\r
+//#include "version.h"\r
+\r
+//basic includes\r
+#include "external.h"\r
+\r
+//tinns includes\r
+#include "types.h"\r
+#include "config.h"\r
+\r
+#include "console.h"\r
+#include "misc.h"\r
+\r
+#include "netcode.h"\r
+\r
+#include "globals.h"\r
+\r
+/*\r
+#include "../gamemonkey/gmMachine.h"\r
+#include "../gamemonkey/gmCall.h"\r
+*/\r
+\r
+// MySQL Support // shouldn't be needed as DB-objects access class should do that\r
+#include "mysql.h"\r
+#include "sql.h"\r
+\r
+#include "filesystem.h"\r
+#include "defparser.h"\r
+\r
+#include "skill.h"\r
+\r
+#include "chars.h"\r
+#include "accounts.h"\r
+#include "defs.h"\r
+#include "client.h"\r
+#include "server.h"\r
+#include "misc.h"\r
+#include "gameserver.h"\r
+#include "zoning.h"\r
+#include "item.h"\r
+#include "inventory.h"\r
+\r
+#include "chat.h"\r
+#include "commands.h"\r
+#include "clientmanager.h"\r
+#include "msgbuilder.h"\r
+#include "worlds.h"\r
+#include "worldactors.h"\r
+#include "npc.h"\r
+\r
+using namespace std;\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/gamecommands/npc.cpp b/server/src/game/gamecommands/npc.cpp
new file mode 100644 (file)
index 0000000..0efa269
--- /dev/null
@@ -0,0 +1,284 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doNPC()\r
+{\r
+    bool SyntaxError = false;\r
+    if(ArgC < 2)\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    if(SyntaxError == true)\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "Usage", "@npc <what> [<worldID>]");\r
+        Chat->send(source, CHAT_DIRECT, "Usage", " <what> can be:");\r
+        Chat->send(source, CHAT_DIRECT, "lua <id> 1/0", "Enables/Disables scripts");\r
+        Chat->send(source, CHAT_DIRECT, "reloadlua <id>", "Reloads LUA script");\r
+        Chat->send(source, CHAT_DIRECT, "spawn <id> [<name>]", "Spawns an NPC");\r
+        Chat->send(source, CHAT_DIRECT, "remove <id>", "Removes an NPC");\r
+        Chat->send(source, CHAT_DIRECT, "help <cmd>", "Displays detailed help for any command");\r
+\r
+        /* more to add here... spawn, remove, ... */\r
+        return;\r
+    }\r
+    // Get subcommand\r
+    char tmp_npccommand[50];\r
+    GetArgText(1, tmp_npccommand, 50);\r
+\r
+    // Dont search for NPC ID when commands HELP and SPAWN are used\r
+    PNPC* targetNPC = NULL;\r
+    PNPCWorld* currentNPCWorld = NULL;\r
+    if(strncmp(tmp_npccommand, "spawn", 5) != 0 && strncmp(tmp_npccommand, "help", 4) != 0)\r
+    {\r
+        currentNPCWorld = NPCManager->GetWorld( source->GetChar()->GetLocation() );\r
+        if ( currentNPCWorld )\r
+        {\r
+            targetNPC = currentNPCWorld->GetNPC( GetArgInt(2) );\r
+            if(!targetNPC)\r
+            {\r
+                // Search for DEF version of NPC (remember, def IDs are on 255 offset!\r
+                // Note to myself: This is UGLY!!!! and BAD!!! but it works for now. CHANGE THIS!\r
+                targetNPC = currentNPCWorld->GetNPC( GetArgInt(1) - 255 );\r
+            }\r
+        }\r
+        if (!targetNPC)\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Invalid NPC ID");\r
+            return;\r
+        }\r
+    }\r
+\r
+    if(strncmp(tmp_npccommand, "help", 4) == 0)\r
+    {\r
+        char tmp_help[50];\r
+        GetArgText(2, tmp_help, 50);\r
+\r
+        if(strncmp(tmp_help, "reloadlua", 9) == 0)\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "reloadlua", "Forces the server to reload any LUA script attached to the NPC");\r
+            return;\r
+        }\r
+        else if(strncmp(tmp_help, "spawn", 5) == 0)\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "spawn", "Spawns an NPC on your current location");\r
+            Chat->send(source, CHAT_DIRECT, "Params", "<spawnID> - See npc.def");\r
+            Chat->send(source, CHAT_DIRECT, "Params", "[<Name>] - Optional name for NPC");\r
+            return;\r
+        }\r
+        else if(strncmp(tmp_help, "remove", 6) == 0)\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "remove", "Removes an NPC");\r
+            Chat->send(source, CHAT_DIRECT, "Params", "<worldID> - Use @debug it to get ID");\r
+            Chat->send(source, CHAT_DIRECT, "Params", "[keep] - Dont delete NPC from SQL");\r
+            return;\r
+        }\r
+        else if(strncmp(tmp_help, "help", 4) == 0)\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "help", "Yes... help...");\r
+            return;\r
+        }\r
+        else\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "help", "No such command");\r
+            return;\r
+        }\r
+    }\r
+    else if(strncmp(tmp_npccommand, "spawn", 5) == 0)\r
+    {\r
+// ------------------------------\r
+        PNPCWorld* tNPCWorld = NPCManager->GetWorld( source->GetChar()->GetLocation() );\r
+        if (!tNPCWorld)\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Error NPC World is inactive");\r
+            Console->Print("%s Error NPC World is inactive but players are there!", Console->ColorText(RED,BLACK, "[PANIC]"));\r
+            return;\r
+        }\r
+        // Get requested spawn ID from Input\r
+        // @npc spawn 12\r
+        int tSpawnID = GetArgInt(2);\r
+        // Check if ID is valid\r
+        const PDefNpc* t_defNpc = GameDefs->Npcs()->GetDef(tSpawnID);\r
+        if(!t_defNpc)\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Invalid SpawnID");\r
+            return;\r
+        }\r
+        char tCustomName[80];\r
+        tCustomName[0] = '\0';\r
+        if(ArgC == 3)\r
+            GetArgText(3, tCustomName, 80);\r
+\r
+        u16 tNPCPosX = source->GetChar()->Coords.mX + 768;\r
+        u16 tNPCPosY = source->GetChar()->Coords.mY + 768;\r
+        u16 tNPCPosZ = source->GetChar()->Coords.mZ + 768;\r
+        u32 tLocation = source->GetChar()->GetLocation();\r
+\r
+        u8 tAngle = source->GetChar()->Coords.mLR;\r
+        string tNPCAngle = Ssprintf( "%d", tAngle );\r
+\r
+        string tNPCScript = t_defNpc->GetStandardScript();\r
+        u32 tNPCHealth = t_defNpc->GetHealth() * NPC_HEALTHFACTOR;\r
+\r
+        /*-------------------------------------------------------*/\r
+        // Get the highest NPC Id for current zone\r
+        /*-------------------------------------------------------*/\r
+        MYSQL_RES *result = NULL;\r
+        char tSql[100];\r
+        snprintf(tSql, 100, "SELECT IFNULL(MAX(npc_worldid)+1,0) FROM npc_spawns WHERE npc_location = %d", tLocation);\r
+        result = MySQL->GameResQuery(tSql);\r
+        if(!result)\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Error on DB insert, NPC not added");\r
+            MySQL->ShowGameSQLError();\r
+            return;\r
+        }\r
+\r
+        int tNewWorldID = atoi(mysql_fetch_row(result)[0]);\r
+\r
+        if(tNewWorldID == 0)\r
+            tNewWorldID = NEW_NPC_ZONEID_START;\r
+\r
+        /*-------------------------------------------------------*/\r
+        // Insert NPC into DB\r
+        /*-------------------------------------------------------*/\r
+        char tSql2[500];\r
+        snprintf(tSql2, 500, "INSERT INTO npc_spawns (npc_worldid, npc_nameid, npc_typeid, npc_name, npc_location, npc_x, npc_y, npc_z, npc_angle, npc_clothing, npc_loot, npc_unknown, npc_trader, npc_customname) VALUES (%d, %d, %d, \"%s\", %d, %d, %d, %d, %d, %d, %d, %d, %d, \"%s\")",\r
+            tNewWorldID, tSpawnID, GetRandom(65000, 1000), tNPCScript.c_str(), tLocation, tNPCPosX, tNPCPosY, tNPCPosZ, atoi(tNPCAngle.c_str()),\r
+            GetRandom(65000, 1000), t_defNpc->GetLoot(), tNPCHealth, 0, tCustomName);\r
+\r
+        if(MySQL->GameQuery(tSql2))\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Error on DB insert, NPC not added");\r
+            MySQL->ShowGameSQLError();\r
+            return;\r
+        }\r
+        /*-------------------------------------------------------*/\r
+        // Grab last insert ID to tell NPCWorld later\r
+        /*-------------------------------------------------------*/\r
+        int tNPC_SQLID = MySQL->GetLastGameInsertId();\r
+        if(tNPC_SQLID == 0)\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Error on DB insert, please check your DB");\r
+            Console->Print("%s LastInsertID is 0 without SQL Error after query", Console->ColorText(RED,BLACK, "[PANIC]"));\r
+            return;\r
+        }\r
+        /*-------------------------------------------------------*/\r
+        // Tell NPCWorld to load NPC with given SQL\r
+        /*-------------------------------------------------------*/\r
+        tNPCWorld->AddNPC(tNPC_SQLID, tNewWorldID);\r
+\r
+        char retMsg[100];\r
+        snprintf(retMsg, 100, "NPC spawned. WorldID: %d", tNewWorldID);\r
+        Chat->send(source, CHAT_DIRECT, "System", retMsg);\r
+        return;\r
+// ------------------------------\r
+    }\r
+    else if(strncmp(tmp_npccommand, "remove", 6) == 0 && targetNPC && currentNPCWorld)\r
+    {\r
+        char tmp_option[50];\r
+        if(ArgC == 3)\r
+            GetArgText(3, tmp_option, 50);\r
+\r
+        if(strncmp(tmp_option, "keep", 4) != 0)\r
+        {\r
+            if(targetNPC->IsSQLNPC() == true)\r
+            {\r
+                char sql[100];\r
+                char sql2[100];\r
+                snprintf(sql, 100, "DELETE FROM npc_spawns WHERE npc_id = %d", targetNPC->GetNPCSQLID());\r
+                snprintf(sql2, 100, "DELETE FROM npc_shop WHERE c_npc_id = %d and c_zoneid = %d", targetNPC->GetNPCID(), source->GetChar()->GetLocation());\r
+                if(MySQL->GameQuery(sql))\r
+                {\r
+                    Chat->send(source, CHAT_DIRECT, "System", "Unable to remove NPC from SQL");\r
+                    Console->Print("%s Unable to remove NPC from SQL", Console->ColorText(RED, BLACK, "[Error]"));\r
+                    MySQL->ShowGameSQLError();\r
+                }\r
+                if(MySQL->GameQuery(sql2))\r
+                {\r
+                    Chat->send(source, CHAT_DIRECT, "System", "Unable to remove NPC Shop settings from SQL");\r
+                    Console->Print("%s Unable to remove NPC shop settings from SQL", Console->ColorText(RED, BLACK, "[Error]"));\r
+                    MySQL->ShowGameSQLError();\r
+                }\r
+            }\r
+        }\r
+        Chat->send(source, CHAT_DIRECT, "System", "Removing NPC...");\r
+        currentNPCWorld->DelNPC(targetNPC->GetNPCID());\r
+        return;\r
+    }\r
+    else if(strncmp(tmp_npccommand, "reloadlua", 9) == 0 && targetNPC)\r
+    {\r
+        if(targetNPC->ReloadLUAScript() == true)\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "LUA script reload successfull");\r
+            return;\r
+        }\r
+        else\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "LUA script reload failed");\r
+            return;\r
+        }\r
+    }\r
+    else if(strncmp(tmp_npccommand, "lua", 3) == 0 && targetNPC)\r
+    {\r
+        if(ArgC < 3)\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "Syntax", "@npc <id> lua 1/0");\r
+            return;\r
+        }\r
+        if(IsArgNumeric(3) == false)\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "Syntax", "@npc <id> lua 1/0");\r
+            return;\r
+        }\r
+\r
+        int tVal = GetArgInt(3);\r
+        targetNPC->SetScripting(tVal);\r
+\r
+\r
+        if(targetNPC->IsSQLNPC() == true)\r
+        {\r
+            char sql[100];\r
+            snprintf(sql, 100, "UPDATE npc_spawns SET npc_scripting = %d WHERE npc_id = %d", tVal, targetNPC->GetNPCSQLID());\r
+            if(MySQL->GameQuery(sql))\r
+            {\r
+                Chat->send(source, CHAT_DIRECT, "System", "Unable to set scripting value in SQL");\r
+                Console->Print("%s Unable to set scripting value in SQL", Console->ColorText(RED, BLACK, "[Error]"));\r
+                MySQL->ShowGameSQLError();\r
+            }\r
+        }\r
+\r
+        if(tVal == 1)\r
+            Chat->send(source, CHAT_DIRECT, "System", "LUA scripting is now enabled");\r
+        else\r
+            Chat->send(source, CHAT_DIRECT, "Syntax", "LUA scripting is now disabled");\r
+\r
+        return;\r
+    }\r
+    else\r
+    {\r
+        char buff[100];\r
+        snprintf(buff, 100, "Unknown command: '%s'", tmp_npccommand);\r
+        Chat->send(source, CHAT_DIRECT, "System", buff);\r
+        return;\r
+    }\r
+}\r
diff --git a/server/src/game/gamecommands/npc_shop.cpp b/server/src/game/gamecommands/npc_shop.cpp
new file mode 100644 (file)
index 0000000..6a26804
--- /dev/null
@@ -0,0 +1,252 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doNPC_Shop()\r
+{\r
+    bool SyntaxError = false;\r
+    if(ArgC < 2)\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    if(IsArgNumeric(1) == true)\r
+    {\r
+        target = GetClientByID(GetArgInt(1));\r
+    }\r
+    else\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    if(SyntaxError == true)\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "Usage", "@npcshop <worldID> <what>");\r
+        Chat->send(source, CHAT_DIRECT, "Usage", " <what> can be:");\r
+        Chat->send(source, CHAT_DIRECT, "setquality <1-255>", "Sets itemquality in shop");\r
+        Chat->send(source, CHAT_DIRECT, "additem <id> <price>", "Adds item <ID> with <Price>");\r
+        Chat->send(source, CHAT_DIRECT, "delitem <id>", "Removes item <ID>");\r
+        Chat->send(source, CHAT_DIRECT, "setdefshop <id>", "ID from trader.def; Use 0 to unset");\r
+        Chat->send(source, CHAT_DIRECT, "reload", "Reloads shop list");\r
+        Chat->send(source, CHAT_DIRECT, "remove", "Disables the shop");\r
+        Chat->send(source, CHAT_DIRECT, "setallbuyer", "Makes NPC an allbuyer (Yo's)");\r
+\r
+        /* more to add here... spawn, remove, ... */\r
+        return;\r
+    }\r
+\r
+    PNPC* targetNPC = NULL;\r
+    PNPCWorld* currentNPCWorld = NPCManager->GetWorld( source->GetChar()->GetLocation() );\r
+    if ( currentNPCWorld )\r
+    {\r
+        targetNPC = currentNPCWorld->GetNPC( GetArgInt(1) );\r
+        if(!targetNPC)\r
+        {\r
+            // Search for DEF version of NPC (remember, def IDs are on 255 offset!\r
+            // Note to myself: This is UGLY!!!! and BAD!!! but it works for now. CHANGE THIS!\r
+            targetNPC = currentNPCWorld->GetNPC( GetArgInt(1) - 255 );\r
+        }\r
+    }\r
+    if (!targetNPC)\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "System", "Invalid NPC ID");\r
+        return;\r
+    }\r
+\r
+    // Get subcommand\r
+    char tmp_npccommand[50];\r
+    GetArgText(2, tmp_npccommand, 50);\r
+\r
+    if(strncmp(tmp_npccommand, "setallbuyer", 11) == 0)\r
+    {\r
+        int tItemID = -1;\r
+        int tPrice = 0;\r
+        int tNPCID = targetNPC->GetNPCID();\r
+        int tZoneID = source->GetChar()->GetLocation();\r
+\r
+        char sqlq[200];\r
+        snprintf(sqlq, 200, "INSERT INTO npc_shop (`c_npc_id`, `c_zoneid`, `c_itemid`, `c_itemprice`) VALUES (%d, %d, %d, %d)", tNPCID, tZoneID, tItemID, tPrice);\r
+        if(MySQL->GameQuery(sqlq))\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Error on DB insert, nothing changed");\r
+        }\r
+        else\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "NPC is now an allbuyer");\r
+        }\r
+        return;\r
+\r
+    }\r
+    else if(strncmp(tmp_npccommand, "additem", 7) == 0)\r
+    {\r
+        int tItemID = GetArgInt(3);\r
+        int tPrice = GetArgInt(4);\r
+        int tNPCID = targetNPC->GetNPCID();\r
+        int tZoneID = source->GetChar()->GetLocation();\r
+        const PDefItems* t_item = GameDefs->Items()->GetDef(tItemID);\r
+        if(!t_item)\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Invalid ItemID");\r
+            return;\r
+        }\r
+        char sqlq[200];\r
+        snprintf(sqlq, 200, "INSERT INTO npc_shop (`c_npc_id`, `c_zoneid`, `c_itemid`, `c_itemprice`) VALUES (%d, %d, %d, %d)", tNPCID, tZoneID, tItemID, tPrice);\r
+        if(MySQL->GameQuery(sqlq))\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Error on DB insert, item not added");\r
+        }\r
+        else\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Item added to shop");\r
+        }\r
+        return;\r
+    }\r
+    else if(strncmp(tmp_npccommand, "delitem", 7) == 0)\r
+    {\r
+        int tItemID = GetArgInt(3);\r
+        int tNPCID = targetNPC->GetNPCID();\r
+        int tZoneID = source->GetChar()->GetLocation();\r
+        char sqlq[200];\r
+        snprintf(sqlq, 200, "DELETE FROM npc_shop WHERE `c_npc_id` = %d and `c_zoneid` = %d and `c_itemid` = %d LIMIT 1", tNPCID, tZoneID, tItemID);\r
+        if(MySQL->GameQuery(sqlq))\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Error on DB update, item not removed");\r
+        }\r
+        else\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Item removed from shop");\r
+        }\r
+        return;\r
+    }\r
+    else if(strncmp(tmp_npccommand, "setdefshop", 10) == 0)\r
+    {\r
+        int tNewTraderDef = GetArgInt(3);\r
+        const PDefTrader* nTraderDef = GameDefs->Traders()->GetDef(tNewTraderDef);\r
+\r
+        // Valid trader definition?\r
+        if(!nTraderDef)\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Invalid Traderdef ID");\r
+            return;\r
+        }\r
+\r
+        char sqlq[200];\r
+        char sqlq2[200];\r
+        bool success = false;\r
+        snprintf(sqlq, 200, "UPDATE npc_spawns SET `npc_trader` = %d WHERE `npc_id` = %d", tNewTraderDef, targetNPC->GetNPCSQLID());\r
+        if(!MySQL->GameQuery(sqlq))\r
+        {\r
+            snprintf(sqlq2, 200, "UPDATE npc_spawns SET `npc_trader` = 0 WHERE `npc_id` = %d", targetNPC->GetNPCSQLID());\r
+            if(!MySQL->GameQuery(sqlq2))\r
+                success = true;\r
+        }\r
+\r
+        if(success == true)\r
+        {\r
+            // Set new trader and remove existing shoplist\r
+            targetNPC->SetTrader(tNewTraderDef);\r
+            targetNPC->ReloadShopList();\r
+            Chat->send(source, CHAT_DIRECT, "System", "NPC acts now as defined TraderShop");\r
+        }\r
+        else\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Error while removing shop");\r
+        }\r
+\r
+\r
+        return;\r
+    }\r
+    else if(strncmp(tmp_npccommand, "remove", 6) == 0)\r
+    {\r
+        int tZoneID = source->GetChar()->GetLocation();\r
+        int tNPCID = targetNPC->GetNPCID();\r
+        char sqlq[200];\r
+        bool success = false;\r
+        snprintf(sqlq, 200, "DELETE FROM npc_shop WHERE `c_npc_id` = %d and `c_zoneid` = %d", tNPCID, tZoneID);\r
+        if(MySQL->GameQuery(sqlq))\r
+        {\r
+            snprintf(sqlq, 200, "UPDATE npc_spawns SET `npc_trader` = 0 WHERE `npc_id` = %d", targetNPC->GetNPCSQLID());\r
+            if(MySQL->GameQuery(sqlq))\r
+                success = false;\r
+            else\r
+                success = true;\r
+        }\r
+        if(success == true)\r
+        {\r
+            // Remove shoplist\r
+            targetNPC->ReloadShopList();\r
+            Chat->send(source, CHAT_DIRECT, "System", "Shop removed from NPC");\r
+        }\r
+        else\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Error while removing shop");\r
+        }\r
+\r
+\r
+        return;\r
+    }\r
+    else if(strncmp(tmp_npccommand, "reload", 6) == 0)\r
+    {\r
+        if(targetNPC->ReloadShopList() == true)\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Shoplist reload successfull");\r
+            return;\r
+        }\r
+        else\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Shoplist reload failed");\r
+            return;\r
+        }\r
+    }\r
+    else if(strncmp(tmp_npccommand, "setquality", 10) == 0)\r
+    {\r
+        u8 tNewLv = (u8)GetArgInt(3);\r
+        if(targetNPC->IsSQLNPC() == true)\r
+        {\r
+            char sqlq[200];\r
+            snprintf(sqlq, 200, "UPDATE npc_spawns SET `npc_shop_quality` = %d WHERE `npc_id` = %d", tNewLv, targetNPC->GetNPCSQLID());\r
+            if(MySQL->GameQuery(sqlq))\r
+            {\r
+                Chat->send(source, CHAT_DIRECT, "System", "Error while updating SQL. New quality will be lost on reload");\r
+            }\r
+        }\r
+\r
+        if(targetNPC->SetShopQuality(tNewLv) == true)\r
+        {\r
+            char tBuff[100];\r
+            snprintf(tBuff, 100, "Itemquality of this NPC is now %u", tNewLv);\r
+            Chat->send(source, CHAT_DIRECT, "System", tBuff);\r
+            return;\r
+        }\r
+        else\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "Cannot set ItemQuality. (Make sure you entered 1-255 and NPC is loaded from SQL)");\r
+            return;\r
+        }\r
+    }\r
+    else\r
+    {\r
+        char buff[100];\r
+        snprintf(buff, 100, "Unknown command: '%s'", tmp_npccommand);\r
+        Chat->send(source, CHAT_DIRECT, "System", buff);\r
+        return;\r
+    }\r
+}\r
diff --git a/server/src/game/gamecommands/online.cpp b/server/src/game/gamecommands/online.cpp
new file mode 100644 (file)
index 0000000..a7080cb
--- /dev/null
@@ -0,0 +1,27 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdconlist()\r
+{\r
+    if (gDevDebug) Console->Print("IngameCommand: Sending connected-player-list to charID %d", source->GetCharID());\r
+    Chat->sendConnectedList(source, false);\r
+}\r
diff --git a/server/src/game/gamecommands/rawf.cpp b/server/src/game/gamecommands/rawf.cpp
new file mode 100644 (file)
index 0000000..7796f72
--- /dev/null
@@ -0,0 +1,103 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdrawf()\r
+{\r
+    bool SyntaxError = false;\r
+    bool DebugMode = false;\r
+    int Prot = 0;  // 0: Error 1: UDP 2: TCP\r
+\r
+    if(ArgC < 2)\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    char file_to_send[50], protocol_to_use[10];\r
+    GetArgText(1, file_to_send, 50);\r
+    GetArgText(2, protocol_to_use, 10);\r
+\r
+    if(strcmp(protocol_to_use, "udp") == 0)\r
+    {\r
+        Prot = 1;\r
+    }\r
+    else if(strcmp(protocol_to_use, "tcp") == 0)\r
+    {\r
+        Prot = 2;\r
+    }\r
+    else if(strcmp(protocol_to_use, "debug") == 0)\r
+    {\r
+        DebugMode = true;\r
+    }\r
+    else\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    if(SyntaxError == true)\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "Usage", "@rawf <file> <udp/tcp/debug>");\r
+        return;\r
+    }\r
+\r
+    ifstream::pos_type size;\r
+    char *buffer;\r
+\r
+    ifstream hexdump (file_to_send, ios::in|ios::binary|ios::ate);\r
+    if (hexdump.is_open())\r
+    {\r
+        if (gDevDebug) Console->Print("IngameCommand: Sending packet file %s", file_to_send);\r
+\r
+        size = hexdump.tellg();\r
+        buffer = new char [size];\r
+        hexdump.seekg (0, ios::beg);\r
+\r
+        hexdump.read (buffer, size);\r
+        hexdump.close();\r
+        if(DebugMode == true)\r
+        {\r
+            int k;\r
+            Console->Print("Byte dump of %s:", file_to_send);\r
+            for(k=0;k<size;k++)\r
+            {\r
+                Console->Print("Byte %d: %#x", k, buffer[k]);\r
+            }\r
+        }\r
+        else\r
+        {\r
+            if(Prot == 1)\r
+                source->getUDPConn()->write(buffer, size);\r
+            else if(Prot == 2)\r
+                source->getTCPConn()->write(buffer, size);\r
+            else // Should never happen...\r
+                Console->Print("%s unable to determine protocol in PCommands::doCmdrawf", Console->ColorText(RED, BLACK, "[Error]"));\r
+        }\r
+\r
+        delete[] buffer;\r
+    }\r
+    else\r
+    {\r
+        char output[100];\r
+        Console->Print("IngameCommand: Unable to send file %s", file_to_send);\r
+        snprintf(output, 100, "File not found: %s", file_to_send);\r
+        Chat->send(source, CHAT_DIRECT, "System", output);\r
+    }\r
+}\r
diff --git a/server/src/game/gamecommands/recall.cpp b/server/src/game/gamecommands/recall.cpp
new file mode 100644 (file)
index 0000000..5a73f4d
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+#include "main.h"
+
+void PCommands::doCmdrecall()
+{
+  bool SyntaxError = false;
+  if ( ArgC < 1 )
+  {
+    SyntaxError = true;
+  }
+
+  if ( SyntaxError == true )
+  {
+    Chat->send( source, CHAT_DIRECT, "Usage", "@recall <charID or nickname>" );
+    return;
+  }
+
+  if ( IsArgNumeric( 1 ) == true )
+  {
+    target = GetClientByID( GetArgInt( 1 ) );
+  }
+  else
+  {
+    char tmp_destNick[50];
+    GetArgText( 1, tmp_destNick, 50 );
+    target = GetClientByNick( tmp_destNick );
+  }
+
+  if ( target == NULL ) // If victim isnt found, return error
+  {
+    Chat->send( source, CHAT_DIRECT, "System", "No such player" );
+    return;
+  }
+  // Check accountlevel (Only higher's can perform commands on lower's)
+  if ( source->GetAccountLevel() <= target->GetAccountLevel() )
+  {
+    char tmpMsg[200];
+    snprintf( tmpMsg, 199, "Cant warp %s to you, target level is higher or equal to yours!", Chars->GetChar( target->GetCharID() )->GetName().c_str() );
+    tmpMsg[199] = '\0';
+    Chat->send( source, CHAT_DIRECT, "System", tmpMsg );
+    return;
+  }
+
+  // Warp target player to GM/Admin
+  int destZone = Chars->GetChar( source->GetCharID() )->GetLocation();
+  if ( !Worlds->IsValidWorld( destZone ) )
+  {
+    Console->Print( "%s Can't change location, destZone '%d' is invalid for some reason", Console->ColorText( RED, BLACK, "[PANIC]" ), destZone );
+    return;
+  }
+// *************** Checks done, proceed with command
+
+  if ( target->ChangeCharLocation( destZone ), true )
+  {
+    PMessage* tmpMsg_zone = MsgBuilder->BuildAptLiftUseMsg( target, destZone, 0 );
+    target->SendUDPMessage( tmpMsg_zone );
+    tmpMsg_zone = NULL;
+
+    u16 nNewX, nNewY, nNewZ;
+    nNewX = source->GetChar()->Coords.mX;
+    nNewY = source->GetChar()->Coords.mY;
+    nNewZ = source->GetChar()->Coords.mZ;
+    target->SetAwaitingWarpto( true, nNewX, nNewY, nNewZ );
+
+    char tmpMsg_success[81];
+    snprintf( tmpMsg_success, 80, "Successfully recalled %s", target->GetChar()->GetName().c_str() );
+    tmpMsg_success[80] = '\0';
+    Chat->send( source, CHAT_DIRECT, "System", tmpMsg_success );
+    return;
+  }
+  else
+  {
+    Console->Print( "%s Unable to change location for player %d to %d", Console->ColorText( RED, BLACK, "[PANIC]" ), target->GetCharID(), destZone );
+  }
+}
diff --git a/server/src/game/gamecommands/remove.cpp b/server/src/game/gamecommands/remove.cpp
new file mode 100644 (file)
index 0000000..4348b10
--- /dev/null
@@ -0,0 +1,82 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdremove()\r
+{\r
+    bool SyntaxError = false;\r
+    if(ArgC < 1)\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+    if(SyntaxError == true)\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "Usage", "@remove actor/<raw item id>");\r
+        return;\r
+    }\r
+\r
+    char tmp_v1[30];\r
+    GetArgText(1, tmp_v1, 30);\r
+\r
+    if(strcmp(tmp_v1, "actor") == 0)\r
+    {\r
+        if(source->IsInRemoveActorMode() == false)\r
+        {\r
+            source->SetRemoveActorMode(true);\r
+            Chat->send(source, CHAT_DIRECT, "System", "You are now in REMOVE ACTOR mode. Rightclick an actor to remove it, type command again to disable mode");\r
+        }\r
+        else\r
+        {\r
+            source->SetRemoveActorMode(false);\r
+            Chat->send(source, CHAT_DIRECT, "System", "REMOVE ACTOR mode disabled");\r
+        }\r
+        return;\r
+    }\r
+\r
+    if(IsArgNumeric(1) == true)\r
+    {\r
+        u32 tTest = GetArgInt(1);\r
+        if(WorldActors->IsDynamicActor(tTest) == true)\r
+        {\r
+            Chat->send(source, CHAT_DIRECT, "System", "You cannot remove dynamic actors over their ID!");\r
+            return;\r
+        }\r
+        u32 TargetID;\r
+        char delStr[128];\r
+        PMessage* tmpMsg;\r
+\r
+        TargetID = (u32)(atoi(tmp_v1) & 0xffffffff);\r
+        tmpMsg = MsgBuilder->BuildFurnitureActivateMsg(source, TargetID, 5);\r
+\r
+        ClientManager->UDPBroadcast(tmpMsg, source);\r
+        tmpMsg = MsgBuilder->BuildFurnitureActivateMsg(source, TargetID, 9);\r
+\r
+        ClientManager->UDPBroadcast(tmpMsg, source);\r
+        snprintf(delStr, 127, "Item %d removed.", TargetID);\r
+        delStr[127] = '\0';\r
+        Chat->send(source, CHAT_DIRECT, "System", delStr);\r
+    }\r
+    else\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "System", "Invalid argument given");\r
+        return;\r
+    }\r
+}\r
diff --git a/server/src/game/gamecommands/setlevel.cpp b/server/src/game/gamecommands/setlevel.cpp
new file mode 100644 (file)
index 0000000..02692d7
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+#include "main.h"
+
+void PCommands::doCmdsetlevel()
+{
+    int destLevel = 0;
+    bool SyntaxError = false;
+    if (ArgC < 2)
+    {
+        SyntaxError = true;
+    }
+
+    if (IsArgNumeric(2) == false)
+    {
+        SyntaxError = true;
+    }
+    else
+    {
+        destLevel = GetArgInt(2);
+    }
+
+    if (SyntaxError == true)
+    {
+        Chat->send(source, CHAT_DIRECT, "Usage", "@setlevel <charID or nickname> <newlevel 1-99>");
+        return;
+    }
+
+    if (IsArgNumeric(1) == true)
+    {
+        target = GetClientByID(GetArgInt(1));
+    }
+    else
+    {
+        char tmp_destNick[50];
+        GetArgText(1, tmp_destNick, 50);
+        target = GetClientByNick(tmp_destNick);
+    }
+
+    if (target == NULL) // If victim isnt found, return error
+    {
+        Chat->send(source, CHAT_DIRECT, "System", "No such player");
+        return;
+    }
+    if (source->GetAccountLevel() <= target->GetAccountLevel())
+    {
+        char tmpMsg[200];
+        snprintf(tmpMsg, 199, "Cant set new level for %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());
+        tmpMsg[199] = '\0';
+        Chat->send(source, CHAT_DIRECT, "System", tmpMsg);
+        return;
+    }
+
+    PAccount Acc(target->GetAccountID());
+    Acc.SetLevel(destLevel);
+    Acc.Save();
+    source->RefreshAccountInfo(&Acc);
+
+    char tmpMsg[60], tmpMsg2[60];
+    snprintf(tmpMsg, 59, "Set level for player %s to %d", Chars->GetChar(target->GetCharID())->GetName().c_str(), destLevel);
+    snprintf(tmpMsg2, 59, "**POOF** Your new accesslevel is now %d", destLevel);
+
+    tmpMsg[59] = '\0';
+    tmpMsg2[59] = '\0';
+
+    Chat->send(source, CHAT_DIRECT, "System", tmpMsg);
+    Chat->send(target, CHAT_DIRECT, "System", tmpMsg2);
+}
diff --git a/server/src/game/gamecommands/setmainskill.cpp b/server/src/game/gamecommands/setmainskill.cpp
new file mode 100644 (file)
index 0000000..aa2dd4f
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+#include "main.h"
+
+void PCommands::doCmdSetMainSkill()
+{
+    u8 tNewLevel = 0;
+    u8 tMainSkill = 0;
+
+    bool SyntaxError = false;
+    if (ArgC < 2)
+    {
+        SyntaxError = true;
+    }
+
+    if (IsArgNumeric(1) == false)
+        SyntaxError = true;
+    else
+        tMainSkill = (u16)GetArgInt(1);
+
+    if (IsArgNumeric(2) == false)
+        SyntaxError = true;
+    else
+        tNewLevel = (u8)GetArgInt(2);
+
+    if (tNewLevel == 0)
+        SyntaxError = true;
+
+    if ( source->GetChar()->Skill->IsValidMainSkill(tMainSkill) == false)
+        SyntaxError = true;
+
+    if (SyntaxError == true)
+    {
+        Chat->send(source, CHAT_DIRECT, "Usage", "@setmainskill <1-5> <1-255> [<charID or nickname>]");
+        Chat->send(source, CHAT_DIRECT, "Usage", "1:STR 2:DEX 3:CON 4:INT 5:PSI");
+        return;
+    }
+
+    PClient *temp_target = NULL;
+    if ( ArgC == 3 )
+    {
+        if (IsArgNumeric(3) == true)
+        {
+            temp_target = GetClientByID(GetArgInt(3));
+        }
+        else
+        {
+            char tmp_destNick[50];
+            GetArgText(3, tmp_destNick, 50);
+            temp_target = GetClientByNick(tmp_destNick);
+        }
+        if (temp_target == NULL)
+        {
+            Chat->send(source, CHAT_DIRECT, "System", "No such player");
+            return;
+        }
+    }
+    else
+        temp_target = source;
+
+    // Now setting player's Skill tMainSkill to tNewLevel
+    u8 tOldLevel = 0;
+    u16 tNewSkillPoints = 0;
+    int tLevelDiff = 0;
+
+    // Grab old Level
+    tOldLevel = temp_target->GetChar()->Skill->GetMainSkill(tMainSkill);
+    tLevelDiff = tNewLevel - tOldLevel;
+    if ( tLevelDiff == 0 )
+    {
+        Chat->send(source, CHAT_DIRECT, "System", "Not setting anything. No difference at all");
+        return;
+    }
+    else if ( tLevelDiff > 0 ) // INCreasing mainskill
+    {
+        tNewSkillPoints = tLevelDiff*5;
+        temp_target->GetChar()->Skill->SetSP(tMainSkill, tNewSkillPoints);
+    }
+    else if ( tLevelDiff < 0 ) // DECreasing mainskill
+    {
+        // Set all subskills to zero, and add tNewLevel*5 skillpoints
+        temp_target->GetChar()->Skill->ZeroMSSubSkills(tMainSkill);
+        temp_target->GetChar()->Skill->SetSP(tMainSkill, tNewLevel*5);
+        tNewSkillPoints = 0;
+        // Not perfect, player has to rezone for the correct values. Need a way to do massupdate subskills...
+        // But on the other side, its not very common to DEcrease someone's skills, isnt it?
+    }
+    temp_target->GetChar()->Skill->SetMainSkill(tMainSkill, tNewLevel);
+
+    char tmp[50];
+    snprintf(tmp, 50, "Setting Level to %d", tNewLevel);
+    Chat->send(source, CHAT_DIRECT, "System", tmp);
+    //PMessage* PMsgBuilder::BuildLevelUpMessage( PClient* nClient, u8 nMainSkill, u8 nNewLevel, u16 nFreeSkillPoints)
+    PMessage* tmpMsg_setLv = MsgBuilder->BuildLevelUpMessage(temp_target, tMainSkill, tNewLevel, tNewSkillPoints);
+    temp_target->SendUDPMessage(tmpMsg_setLv);
+    tmpMsg_setLv = NULL;
+    temp_target = NULL;
+}
diff --git a/server/src/game/gamecommands/setsubskill.cpp b/server/src/game/gamecommands/setsubskill.cpp
new file mode 100644 (file)
index 0000000..27c0f75
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+#include "main.h"
+
+void PCommands::doCmdSetSubSkill()
+{
+    u8 tNewLevel = 0;
+    u8 tSubSkill = 0;
+
+    bool SyntaxError = false;
+    if (ArgC < 2)
+    {
+        SyntaxError = true;
+    }
+
+    if (IsArgNumeric(1) == false)
+        SyntaxError = true;
+    else
+        tSubSkill = (u16)GetArgInt(1);
+
+    if (IsArgNumeric(2) == false)
+        SyntaxError = true;
+    else
+        tNewLevel = (u8)GetArgInt(2);
+
+    if (tNewLevel == 0)
+        SyntaxError = true;
+
+    if ( source->GetChar()->Skill->IsValidSubSkill(tSubSkill) == false)
+        SyntaxError = true;
+
+    if (SyntaxError == true)
+    {
+        Chat->send(source, CHAT_DIRECT, "Usage", "@setsubskill <1-45> <1-255> [<charID or nickname>]");
+        Chat->send(source, CHAT_DIRECT, "Usage", "See the GameMaster reference for IDs");
+        return;
+    }
+
+    PClient *temp_target = NULL;
+    if ( ArgC == 3 )
+    {
+        if (IsArgNumeric(3) == true)
+        {
+            temp_target = GetClientByID(GetArgInt(3));
+        }
+        else
+        {
+            char tmp_destNick[50];
+            GetArgText(3, tmp_destNick, 50);
+            temp_target = GetClientByNick(tmp_destNick);
+        }
+        if (temp_target == NULL)
+        {
+            Chat->send(source, CHAT_DIRECT, "System", "No such player");
+            return;
+        }
+    }
+    else
+        temp_target = source;
+
+
+    // Now setting player's Skill tMainSkill to tNewLevel
+    u8 tOldLevel = 0;
+    int tLevelDiff = 0;
+
+    // Grab old Level
+    tOldLevel = temp_target->GetChar()->Skill->GetSubSkill(tSubSkill);
+    tLevelDiff = tNewLevel - tOldLevel;
+    if ( tLevelDiff == 0 )
+    {
+        Chat->send(source, CHAT_DIRECT, "System", "Not setting anything. No difference at all");
+        return;
+    }
+    temp_target->GetChar()->Skill->SetSubSkill(tSubSkill, tNewLevel);
+
+    char tmp[50];
+    snprintf(tmp, 50, "Setting Level to %d", tNewLevel);
+    Chat->send(source, CHAT_DIRECT, "System", tmp);
+
+    MAIN_SKILLS tMainSkill = temp_target->GetChar()->Skill->GetMSfromSS(tSubSkill);
+    PMessage* tmpMsg_setSLv = MsgBuilder->BuildSubskillIncMsg(temp_target, tSubSkill, temp_target->GetChar()->Skill->GetSP(tMainSkill));
+    temp_target->SendUDPMessage(tmpMsg_setSLv);
+    tmpMsg_setSLv = NULL;
+    temp_target = NULL;
+}
diff --git a/server/src/game/gamecommands/settime.cpp b/server/src/game/gamecommands/settime.cpp
new file mode 100644 (file)
index 0000000..4d67ed8
--- /dev/null
@@ -0,0 +1,36 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdsettime()\r
+{\r
+    if(ArgC < 1 && GetArgInt(1) == 0)\r
+    {\r
+       Chat->send(source, CHAT_DIRECT, "Usage", "@settime <raw timevalue>");\r
+       return;\r
+    }\r
+\r
+    int newtime = 0;\r
+    newtime = GetArgInt(1);\r
+\r
+    GameServer->SetGameTime(newtime);\r
+    Console->Print("IngameCommand: CharID %d set ingametime to %d", source->GetCharID(), newtime);\r
+}\r
diff --git a/server/src/game/gamecommands/shun.cpp b/server/src/game/gamecommands/shun.cpp
new file mode 100644 (file)
index 0000000..8a39cc2
--- /dev/null
@@ -0,0 +1,76 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdshun()\r
+{\r
+    bool SyntaxError = false;\r
+    if(ArgC < 1)\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    if(SyntaxError == true)\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "Usage", "@shun <charID or nickname>");\r
+        return;\r
+    }\r
+\r
+    if(IsArgNumeric(1) == true)\r
+    {\r
+        target = GetClientByID(GetArgInt(1));\r
+    }\r
+    else\r
+    {\r
+        char tmp_destNick[50];\r
+        GetArgText(1, tmp_destNick, 50);\r
+        target = GetClientByNick(tmp_destNick);\r
+    }\r
+\r
+    if(target == NULL) // If victim isnt found, return error\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "System", "No such player");\r
+        return;\r
+    }\r
+    if(source->GetAccountLevel() <= target->GetAccountLevel())\r
+    {\r
+        char tmpMsg[200];\r
+        snprintf(tmpMsg, 199, "Cant shun %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());\r
+        tmpMsg[199] = '\0';\r
+        Chat->send(source, CHAT_DIRECT, "System", tmpMsg);\r
+        return;\r
+    }\r
+    if(target->GetChar()->IsShunned() == false)\r
+    {\r
+        target->GetChar()->SetShun(true);\r
+\r
+        char tmpMsg_success[81];\r
+        snprintf(tmpMsg_success, 80, "Successfully shunned %s", target->GetChar()->GetName().c_str());\r
+        tmpMsg_success[80] = '\0';\r
+        Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success);\r
+        return;\r
+    }\r
+    else\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "System", "Player is already shunned");\r
+        return;\r
+    }\r
+}\r
diff --git a/server/src/game/gamecommands/skin.cpp b/server/src/game/gamecommands/skin.cpp
new file mode 100644 (file)
index 0000000..64feec4
--- /dev/null
@@ -0,0 +1,121 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdskin()\r
+{\r
+// -------------------------------------------------------\r
+/*\r
+Usage:  @skin #<chardef idx>\r
+              for use with the index id from characters.def\r
+  or  @skin <model>|-|# [<head>[ <torso>[ <legs>]]]\r
+              <model> is the model id found after the model name in characters.def\r
+              # resets to real char skin (optionnaly modified by following args)\r
+              - means current skin\r
+              incrementaly optional <head>, <torso> and <legs> are values 0-9\r
+*/\r
+    bool SyntaxError = false;\r
+    if(ArgC < 1)\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    u32 Skinval1, Skinval2, Skinval3, Skinval4;\r
+    PChar *SkinChar = Chars->GetChar(source->GetCharID());\r
+    std::stringstream SkinChat;\r
+    char SkinStr[128];\r
+\r
+    if(SyntaxError == true)\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "Usage", "@skin ( #<chardef idx> ) | ( <model> | # [<head>[ <torso>[ <legs>]]] )");\r
+        return;\r
+    }\r
+\r
+    char tmpval[30];\r
+    GetArgText(1, tmpval, 30);\r
+    if((tmpval[0] == '#') && (tmpval[1] != '\0'))\r
+    {\r
+        Skinval1 = atoi(tmpval+1);\r
+        SkinChar->SetCurrentLookFromCharType(atoi(tmpval+1));\r
+        SkinChat << "Skin set to the skin of char type ";\r
+        SkinChat << (int)Skinval1;\r
+    }\r
+    else\r
+    {\r
+        if ((tmpval[0] == '#') && (tmpval[1] == '\0'))\r
+        {\r
+            SkinChar->GetRealLook(Skinval1, Skinval2, Skinval3, Skinval4);\r
+        }\r
+        else if ((tmpval[0] == '-') && (tmpval[1] == '\0'))\r
+        {\r
+            SkinChar->GetCurrentLook(Skinval1, Skinval2, Skinval3, Skinval4);\r
+        }\r
+        else\r
+        {\r
+            Skinval1 = GetArgInt(1);\r
+        }\r
+\r
+        char tmp_arg2[30];\r
+        char tmp_arg3[30];\r
+        char tmp_arg4[30];\r
+\r
+        GetArgText(2, tmp_arg2, 30);\r
+        GetArgText(3, tmp_arg3, 30);\r
+        GetArgText(4, tmp_arg4, 30);\r
+\r
+        if(tmp_arg2[0] != '\0')\r
+        {\r
+            if(tmp_arg2[0] != '-')\r
+            {\r
+                tmp_arg2[1] = '\0';\r
+                Skinval2 = GetArgInt(2);\r
+            }\r
+            if(tmp_arg3[0] != '\0')\r
+            {\r
+                if(tmp_arg3[0] != '-')\r
+                {\r
+                    tmp_arg3[1] = '\0';\r
+                    Skinval3 = GetArgInt(3);\r
+                }\r
+                if(tmp_arg4[0] != '\0')\r
+                {\r
+                    if(tmp_arg4[0] != '-')\r
+                    {\r
+                        tmp_arg4[1] = '\0';\r
+                        Skinval4 = GetArgInt(4);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        SkinChar->SetCurrentLook(Skinval1, Skinval2, Skinval3, Skinval4);\r
+\r
+        SkinChat << "Skin set to model ";\r
+        SkinChat << (int)Skinval1 << " with head " << (int)Skinval2 << ", torso " << (int)Skinval3 << ", legs " << (int)Skinval4;\r
+    }\r
+\r
+    snprintf(SkinStr, 127, "%s", SkinChat.str().c_str());\r
+    SkinStr[127] = '\0';\r
+    Chat->send(source, CHAT_DIRECT, "System", SkinStr);\r
+\r
+    PMessage* tmpMsg = MsgBuilder->BuildCharHelloMsg(source);\r
+    ClientManager->UDPBroadcast(tmpMsg, source);\r
+}\r
diff --git a/server/src/game/gamecommands/spawnactor.cpp b/server/src/game/gamecommands/spawnactor.cpp
new file mode 100644 (file)
index 0000000..87532b5
--- /dev/null
@@ -0,0 +1,112 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdspawnactor()\r
+{\r
+    bool SyntaxError = false;\r
+    if(ArgC < 2)\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    if(IsArgNumeric(1) == false || IsArgNumeric(2) == false)\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    u16 tmpActorID = (u16)GetArgInt(1);\r
+    u16 tmpFunctionID = (u16)GetArgInt(2);\r
+    u16 tmpOption1 = 0;\r
+    u16 tmpOption2 = 0;\r
+    u16 tmpOption3 = 0;\r
+\r
+    if(ArgC > 2)\r
+    {\r
+        if(IsArgNumeric(3) == false)\r
+        {\r
+            SyntaxError = true;\r
+        }\r
+        else\r
+        {\r
+            tmpOption1 = (u16)GetArgInt(3);\r
+            if(ArgC > 3)\r
+            {\r
+                if(IsArgNumeric(4) == false)\r
+                {\r
+                    SyntaxError = true;\r
+                }\r
+                else\r
+                {\r
+                    tmpOption1 = (u16)GetArgInt(4);\r
+                    if(ArgC > 4)\r
+                    {\r
+                        if(IsArgNumeric(4) == false)\r
+                        {\r
+                            SyntaxError = true;\r
+                        }\r
+                        else\r
+                        {\r
+                            tmpOption1 = (u16)GetArgInt(5);\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    if(tmpActorID == 0)\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    if(SyntaxError == true)\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "Usage", "@spawnactor <actorID> <functionID> [<option1> <option2> <option3>]");\r
+        return;\r
+    }\r
+\r
+    if(WorldActors->IsValidWAFunction(tmpFunctionID) == true)\r
+    {\r
+        if(WorldActors->RequiresLinkedObject(tmpFunctionID == true))\r
+        {\r
+            if(WorldActors->IsValidLinkedObject(source, tmpOption1, tmpFunctionID) == false)\r
+            {\r
+                if(tmpOption1 == 0)\r
+                    Chat->send(source, CHAT_DIRECT, "System", "Error: This functionID requires an linked object");\r
+                else if(tmpOption1 == 18)\r
+                    Chat->send(source, CHAT_DIRECT, "System", "Error: Invalid destination world");\r
+                else\r
+                    Chat->send(source, CHAT_DIRECT, "System", "Error: Invalid worldobjectID to link to");\r
+                return;\r
+            }\r
+        }\r
+        WorldActors->AddWorldActor(source, tmpActorID, tmpFunctionID, tmpOption1, tmpOption2, tmpOption3);\r
+    }\r
+    else\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "System", "Error: This is an invalid function ID");\r
+        return;\r
+    }\r
+    //PMessage* tmpMsg = MsgBuilder->BuiltSpawnObjectMsg(source, tmpActorID, tmpFunctionID, mWOID++);\r
+    //ClientManager->UDPBroadcast(tmpMsg, source);\r
+    //tmpMsg = NULL;\r
+}\r
diff --git a/server/src/game/gamecommands/speed.cpp b/server/src/game/gamecommands/speed.cpp
new file mode 100644 (file)
index 0000000..a3a4e58
--- /dev/null
@@ -0,0 +1,55 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdspeed()\r
+{\r
+// Speed override setting.\r
+// Usage: @speed <newspeed> | #\r
+//  with <speed> = 0 (no move).. 254 , 255 or # meaning "no speed override"\r
+\r
+    bool SyntaxError = false;\r
+    if(ArgC < 1)\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    if(SyntaxError == true)\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "Usage", "@speed <newspeed: 0 .. 254 > | 255 | #");\r
+        return;\r
+    }\r
+    char tmpval[30];\r
+    GetArgText(1, tmpval, 30);\r
+\r
+    u8 val1;\r
+    char effStr[128];\r
+    PMessage* tmpMsg;\r
+\r
+    val1 = ((tmpval[0] == '#') ? 255 : (u8)(atoi(tmpval) & 0xff));\r
+    source->GetChar()->SetSpeedOverride(val1);\r
+\r
+    tmpMsg = MsgBuilder->BuildCharHelloMsg(source);\r
+    ClientManager->UDPBroadcast(tmpMsg, source);\r
+    snprintf(effStr, 127, "Speed override set to value %d ", val1);\r
+    effStr[127] = '\0';\r
+    Chat->send(source, CHAT_DIRECT, "System", effStr);\r
+}\r
diff --git a/server/src/game/gamecommands/t.cpp b/server/src/game/gamecommands/t.cpp
new file mode 100644 (file)
index 0000000..a20da9b
--- /dev/null
@@ -0,0 +1,491 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmd_dev_t()\r
+{\r
+  const char* usage = "Usage: @t r <rawid> (to remove object) | @t d <rawid> [<v1=74> [<v2=29>]] (to send death packet to object with args v1 v2)";\r
+  char tmpStr[128];\r
+  const char* textMsg = usage;\r
+  PMessage* tmpMsg = NULL;\r
+  char Arg1[30];\r
+\r
+  if ( IsAdmin() == false )\r
+    return;\r
+\r
+  Arg1[0] = tmpStr[0] = '\0';\r
+\r
+  if ( ArgC >= 2 )\r
+  {\r
+    GetArgText( 1, Arg1, 30 );\r
+    u32 targetObjectId = GetArgInt( 2 ) & 0xffffffff;\r
+    if ( Arg1[0] == 't' )\r
+    {\r
+      u8 val1;\r
+      if ( ArgC >= 3 )\r
+      {\r
+        int val2 = GetArgInt( 3 );\r
+        tmpMsg = new PMessage( 32 );\r
+        source->IncreaseUDP_ID();\r
+        *tmpMsg << ( u8 )0x13;\r
+        *tmpMsg << ( u16 )source->GetUDP_ID();\r
+        *tmpMsg << ( u16 )source->GetSessionID();\r
+        *tmpMsg << ( u8 )0x00; // Message length\r
+        *tmpMsg << ( u8 )0x03;\r
+        *tmpMsg << ( u16 )source->GetUDP_ID();\r
+        *tmpMsg << ( u8 )0x2d;\r
+        *tmpMsg << ( u32 )targetObjectId;\r
+        *tmpMsg << ( u8 )0x01;\r
+        *tmpMsg << ( u32 )val2;\r
+  \r
+        ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );\r
+        source->SendUDPMessage( tmpMsg );\r
+        snprintf( tmpStr, 127, "Sent 13/03/2d msg to object id 0x%08x with values 6/%d", targetObjectId, val2 );\r
+        textMsg = tmpStr;\r
+      }\r
+      else for(val1 = 2; val1 < 255; ++val1)\r
+      {\r
+        if(val1 == 6) continue;\r
+        tmpMsg = new PMessage( 15 );\r
+        source->IncreaseUDP_ID();\r
+        *tmpMsg << ( u8 )0x13;\r
+        *tmpMsg << ( u16 )source->GetUDP_ID();\r
+        *tmpMsg << ( u16 )source->GetSessionID();\r
+        *tmpMsg << ( u8 )0x00; // Message length\r
+        *tmpMsg << ( u8 )0x03;\r
+        *tmpMsg << ( u16 )source->GetUDP_ID();\r
+        *tmpMsg << ( u8 )0x2d;\r
+        *tmpMsg << ( u32 )targetObjectId;\r
+        *tmpMsg << ( u8 )val1; \r
+  \r
+        ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );\r
+        source->SendUDPMessage( tmpMsg );\r
+        snprintf( tmpStr, 127, "Sent 13/03/2d msg to object id 0x%08x with value %d", targetObjectId, val1 );\r
+        textMsg = tmpStr;\r
+        tmpStr[127] = '\0';\r
+        Chat->send( source, CHAT_DIRECT, "System", textMsg );\r
+        source->getUDPConn()->update();\r
+        source->getTCPConn()->update();\r
+        sleep(1);\r
+      }\r
+      tmpMsg = NULL;\r
+    }\r
+    else if ( Arg1[0] == 'd' )\r
+    {\r
+      u8 val1 = 0x4a; // default values\r
+      u8 val2 = 0x1e;\r
+\r
+      if ( ArgC >= 3 )\r
+        val1 = GetArgInt( 3 ) & 0xff;\r
+      if ( ArgC >= 4 )\r
+        val2 = GetArgInt( 4 ) & 0xff;\r
+      tmpMsg = MsgBuilder->BuildNpcDeathMsg( source, targetObjectId, val1, val2 );\r
+      snprintf( tmpStr, 127, "Sending Death update to object id 0x%08x with values 0x%02x 0x%02x", targetObjectId, val1, val2 );\r
+      textMsg = tmpStr;\r
+    }\r
+    else if ( Arg1[0] == 'm' )\r
+    {\r
+      u8 nTxtGroupID = targetObjectId & 0xff;\r
+      u16 nTxtID = 10;\r
+      //u32 nVal = 0;\r
+      if ( ArgC >= 3 )\r
+        nTxtID = GetArgInt( 3 ) & 0xffff;\r
+      //if(ArgC >= 4)\r
+      //  val2 = GetArgInt(4) & 0xff;\r
+\r
+      tmpMsg = new PMessage( 20 );\r
+\r
+      source->IncreaseUDP_ID();\r
+      *tmpMsg << ( u8 )0x13;\r
+      *tmpMsg << ( u16 )source->GetUDP_ID();\r
+      *tmpMsg << ( u16 )source->GetSessionID();\r
+      *tmpMsg << ( u8 )0x0e; // Message length\r
+      *tmpMsg << ( u8 )0x03;\r
+      *tmpMsg << ( u16 )source->GetUDP_ID();\r
+      *tmpMsg << ( u8 )0x1f;\r
+      *tmpMsg << ( u16 )source->GetLocalID();\r
+      *tmpMsg << ( u8 )0x25; // ??\r
+      *tmpMsg << ( u8 )0x15; // ??\r
+      *tmpMsg << nTxtGroupID;\r
+      *tmpMsg << nTxtID;\r
+      *tmpMsg << ( u16 )0x00; // ??\r
+      *tmpMsg << ( u8 )0x01;\r
+      *tmpMsg << ( u8 )0x04;\r
+      *tmpMsg << ( u32 )0x00;\r
+      //*tmpMsg << (u8)0x00; // ??\r
+      //*tmpMsg << (u8)0x00; // ??\r
+      //*tmpMsg << (u32)nVal;\r
+\r
+      ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );\r
+      snprintf( tmpStr, 127, "Using msg n %d from group %d", nTxtID, nTxtGroupID );\r
+      textMsg = tmpStr;\r
+\r
+      source->SendUDPMessage( tmpMsg );\r
+      tmpMsg = NULL;\r
+    }\r
+    else if ( Arg1[0] == 'e' )\r
+    {\r
+      targetObjectId = 1004; //target=int\r
+      u16 nval = 5;\r
+      u8 nType = 1; // 1=+ 2=-\r
+      u16 nDur = 20;\r
+      u8 nparam = 1;\r
+\r
+        nparam = GetArgInt( 2 ) && 0xff;\r
+\r
+        tmpMsg = new PMessage( 32 );\r
+\r
+        source->IncreaseUDP_ID();\r
+        *tmpMsg << ( u8 )0x13;\r
+        *tmpMsg << ( u16 )source->GetUDP_ID();\r
+        *tmpMsg << ( u16 )source->GetSessionID();\r
+        *tmpMsg << ( u8 )0x0e; // Message length\r
+        *tmpMsg << ( u8 )0x03;\r
+        *tmpMsg << ( u16 )source->GetUDP_ID();\r
+        *tmpMsg << ( u8 )0x1f;\r
+        *tmpMsg << ( u16 )source->GetLocalID();\r
+        *tmpMsg << ( u8 )0x25; // ??\r
+        *tmpMsg << ( u8 )0x06; // ??\r
+        *tmpMsg << ( u8 )0x01; // 1 effect\r
+        *tmpMsg << ( u8 )0x01; // effect on intox level ????\r
+        *tmpMsg << ( u16 )nDur;\r
+        *tmpMsg << ( u16 )(700+(targetObjectId % 100)); //item id Thyronol\r
+        *tmpMsg << ( u8 )nType;\r
+        *tmpMsg << ( u16 )(nval*100); //u32 in nc2.2\r
+        *tmpMsg << ( u16 )targetObjectId;\r
+\r
+\r
+        ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );\r
+        snprintf( tmpStr, 127, "Sendind drug mod to stat %d, %s %d", targetObjectId, (nType == 1 ? "inc" : "dec"), nval );\r
+        textMsg = tmpStr;\r
+\r
+        source->SendUDPMessage( tmpMsg );\r
+        tmpMsg = NULL;\r
+    }\r
+    else if ( Arg1[0] == 'w' )\r
+    {\r
+      /*targetObjectId &= 0xffff;\r
+      u16 val1 = 0;\r
+      if ( ArgC >= 3 )\r
+        val1 = GetArgInt( 3 ) & 0xffff;\r
+*/\r
+      tmpMsg = new PMessage( 15 );\r
+\r
+      source->IncreaseUDP_ID();\r
+\r
+      *tmpMsg << ( u8 )0x13;\r
+      *tmpMsg << ( u16 )source->GetUDP_ID();\r
+      *tmpMsg << ( u16 )source->GetSessionID();\r
+      *tmpMsg << ( u8 )0x0a; // Message length place;\r
+      *tmpMsg << ( u8 )0x03;\r
+      *tmpMsg << ( u16 )source->GetUDP_ID();\r
+      *tmpMsg << ( u8 )0x23;\r
+      *tmpMsg << ( u16 )0x0012; // cmd = ?\r
+      *tmpMsg << ( u16 )0x0007;\r
+      *tmpMsg << ( u32 )0x00000000;\r
+\r
+      ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );\r
+\r
+      snprintf( tmpStr, 127, "Sending w msg " );\r
+      textMsg = tmpStr;\r
+\r
+      source->SendUDPMessage( tmpMsg );\r
+      tmpMsg = NULL;\r
+    }\r
+    else if ( Arg1[0] == 'x' )\r
+    {\r
+      u8 val1 = targetObjectId &= 0xff;\r
+\r
+      tmpMsg = MsgBuilder->BuildUndefineduseMsg( source, val1 );\r
+\r
+      snprintf( tmpStr, 127, "Sending x msg with param %d (0x%2x)", val1, val1 );\r
+      textMsg = tmpStr;\r
+\r
+      source->SendUDPMessage( tmpMsg );\r
+      tmpMsg = NULL;\r
+    }\r
+  }\r
+\r
+  tmpStr[127] = '\0';\r
+  Chat->send( source, CHAT_DIRECT, "System", textMsg );\r
+\r
+  if ( tmpMsg )\r
+    ClientManager->UDPBroadcast( tmpMsg, source );\r
+}\r
+\r
+/*** Packet fields testing. Please do not delete (Hammag)\r
+void PCommands::doCmd_dev_t()\r
+{\r
+    if(IsAdmin() == false)\r
+        return;\r
+\r
+    char Arg1[30], Arg2[30];\r
+\r
+    Arg1[0] = '\0';\r
+    Arg2[0] = '\0';\r
+\r
+    if(ArgC > 0)\r
+    {\r
+        GetArgText(1, Arg1, 30);\r
+        if(ArgC > 1)\r
+        {\r
+            GetArgText(2, Arg2, 30);\r
+        }\r
+    }\r
+\r
+    u32 val1;\r
+    u8 val2;\r
+    char tmpStr[128];\r
+    static PMessage* tmpMsg = NULL;\r
+    bool SetUDP_IDNeeded = true;\r
+    PChar* nChar = source->GetChar();\r
+    (nChar->Coords).mY += 20;\r
+    (nChar->Coords).mZ += 20;\r
+    (nChar->Coords).mX += 20;\r
+\r
+    if (!tmpMsg)\r
+    {\r
+      tmpMsg = MsgBuilder->BuildPacket0Msg(source);\r
+      //tmpMsg = MsgBuilder->BuildCharHelloMsg(source);\r
+      SetUDP_IDNeeded = false;\r
+    }\r
+\r
+    if(Arg1[0] != '\0' && Arg2[0] != '\0')\r
+    {\r
+        val1 = atoi(Arg1);\r
+        val2 = (u8)(atoi(Arg2) & 0xff);\r
+        //tmpMsg->U8Data(16 + val1) = val2;\r
+        tmpMsg->U8Data(10 + val1) = val2;\r
+        snprintf(tmpStr, 127, "Data #%d set to value 0x%02x", val1, val2);\r
+    }\r
+    else\r
+    {\r
+      if (tmpMsg)\r
+        delete tmpMsg;\r
+      //tmpMsg = MsgBuilder->BuildCharHelloMsg(source);\r
+      tmpMsg = MsgBuilder->BuildPacket0Msg(source);\r
+      SetUDP_IDNeeded = false;\r
+      snprintf(tmpStr, 127, "Data reset to normal values");\r
+    }\r
+\r
+    tmpStr[127] = '\0';\r
+    Chat->send(source, CHAT_DIRECT, "System", tmpStr);\r
+\r
+    PMessage* SendMsg = new PMessage(*tmpMsg);\r
+    if(SetUDP_IDNeeded) {\r
+      source->FillInUDP_ID(SendMsg);\r
+    }\r
+    SendMsg->Dump();\r
+    //ClientManager->UDPBroadcast(SendMsg, source);\r
+    source->SendUDPMessage(SendMsg);\r
+}\r
+***/\r
+\r
+/*** Subwy testing. Please do not delete (Hammag)\r
+void PCommands::doCmd_dev_t()\r
+{\r
+  if(IsAdmin() == false)\r
+      return;\r
+\r
+  char tmpStr[128];\r
+ u8 SubWay[] = {0x13, 0x71, 0x00, 0x9b, 0xde,\r
+  //Subway 1 (fc 03)\r
+  0x11,\r
+  0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xfc, 0x03, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\r
+  0x0d,\r
+  0x03, 0x71, 0x00, 0x2d, 0xfc, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
+  0x00, 0x00, 0x00,\r
+  //Subway 2 (fb 03)\r
+  0x11,\r
+  0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xfb, 0x03, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0xf0, 0x41, 0x00, 0x01,\r
+  0x0d,\r
+  0x03, 0x71, 0x00, 0x2d, 0xfb, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
+  0x00, 0x00, 0x00,\r
+  //Subway 3 (fa 03)\r
+  0x11,\r
+  0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xfa, 0x03, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x70, 0x42, 0x00, 0x01,\r
+  0x0d,\r
+  0x03, 0x71, 0x00, 0x2d, 0xfa, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
+  0x00, 0x00, 0x00,\r
+  //Subway 4 (f9 03)\r
+  0x11,\r
+  0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf9, 0x03, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0xb4, 0x42, 0x00, 0x01,\r
+  0x0d,\r
+  0x03, 0x71, 0x00, 0x2d, 0xf9, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
+  0x00, 0x00, 0x00,\r
+  //Subway 5 (f8 03)\r
+  0x11,\r
+  0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf8, 0x03, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0xf0, 0x42, 0x00, 0x01,\r
+  0x0d,\r
+  0x03, 0x71, 0x00, 0x2d, 0xf8, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
+  0x00, 0x00, 0x00,\r
+  //Subway 6 (f7 03)\r
+  0x11,\r
+  0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf7, 0x03, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x16, 0x43, 0x00, 0x01,\r
+  0x0d,\r
+  0x03, 0x71, 0x00, 0x2d, 0xf7, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
+  0x00, 0x00, 0x00};\r
+\r
+ u8 SubWay2[] = {0x13, 0x71, 0x00, 0x9b, 0xde,\r
+  //Subway 7 (f6 03)\r
+  0x11,\r
+  0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf6, 0x03, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x34, 0x43, 0x00, 0x01,\r
+  0x0d,\r
+  0x03, 0x71, 0x00, 0x2d, 0xf6, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
+  0x00, 0x00, 0x00,\r
+  //Subway 8 (f5 03)\r
+  0x11,\r
+  0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf5, 0x03, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x52, 0x43, 0x00, 0x01,\r
+  0x0d,\r
+  0x03, 0x71, 0x00, 0x2d, 0xf5, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
+  0x00, 0x00, 0x00,\r
+  //Subway 9 (f4 03)\r
+  0x11,\r
+  0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf4, 0x03, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x70, 0x43, 0x00, 0x01,\r
+  0x0d,\r
+  0x03, 0x71, 0x00, 0x2d, 0xf4, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
+  0x00, 0x00, 0x00,\r
+  //Subway 10 (f3 03)\r
+  0x11,\r
+  0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf3, 0x03, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x87, 0x43, 0x00, 0x01,\r
+  0x0d,\r
+  0x03, 0x71, 0x00, 0x2d, 0xf3, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
+  0x00, 0x00, 0x00,\r
+  //Subway 11 (f2 03)\r
+  0x11,\r
+  0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf2, 0x03, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x96, 0x43, 0x00, 0x01,\r
+  0x0d,\r
+  0x03, 0x71, 0x00, 0x2d, 0xf2, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
+  0x00, 0x00, 0x00};\r
+\r
+ if (source->GetChar()->GetLocation() != 1000)\r
+  return;\r
+\r
+ //SubWay List\r
+ //Subway 1\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay[7] = source->GetUDP_ID();\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay[25] = source->GetUDP_ID();\r
+\r
+ //Subway 2\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay[39] = source->GetUDP_ID();\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay[57] = source->GetUDP_ID();\r
+\r
+ //Subway 3\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay[71] = source->GetUDP_ID();\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay[89] = source->GetUDP_ID();\r
+\r
+ //Subway 4\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay[103] = source->GetUDP_ID();\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay[121] = source->GetUDP_ID();\r
+\r
+ //Subway 5\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay[135] = source->GetUDP_ID();\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay[153] = source->GetUDP_ID();\r
+\r
+ //Subway 6\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay[167] = source->GetUDP_ID();\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay[185] = source->GetUDP_ID();\r
+\r
+ //Subway 7\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay2[7] = source->GetUDP_ID();\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay2[25] = source->GetUDP_ID();\r
+\r
+ //Subway 8\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay2[39] = source->GetUDP_ID();\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay2[57] = source->GetUDP_ID();\r
+\r
+ //Subway 9\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay2[71] = source->GetUDP_ID();\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay2[89] = source->GetUDP_ID();\r
+\r
+ //Subway 10\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay2[103] = source->GetUDP_ID();\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay2[121] = source->GetUDP_ID();\r
+\r
+ //Subway 11\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay2[135] = source->GetUDP_ID();\r
+ source->IncreaseUDP_ID();\r
+ *(u16*)&SubWay2[153] = source->GetUDP_ID();\r
+\r
+ *(u16*)&SubWay[1] = source->GetUDP_ID();\r
+ *(u16*)&SubWay[3] = source->GetSessionID();\r
+\r
+ PMessage* msg;\r
+ msg = new PMessage(197);\r
+ msg->Write(SubWay, sizeof(SubWay));\r
+Console->Print("---- Working 1 ----");\r
+msg->Dump();\r
+  source->SendUDPMessage(msg);\r
+msg = MsgBuilder->BuildSubwaySpawnMsg(source, false);\r
+Console->Print("---- Not Working 1 ----");\r
+msg->Dump();\r
+source->SendUDPMessage(msg);\r
+\r
+ *(u16*)&SubWay2[1] = source->GetUDP_ID();\r
+ *(u16*)&SubWay2[3] = source->GetSessionID();\r
+\r
+ msg = new PMessage(197);\r
+ msg->Write(SubWay2, sizeof(SubWay2));\r
+Console->Print("---- Working 2 ----");\r
+msg->Dump();\r
+  source->SendUDPMessage(msg);\r
+msg = MsgBuilder->BuildSubwaySpawnMsg(source, true);\r
+Console->Print("---- Not Working 2 ----");\r
+msg->Dump();\r
+source->SendUDPMessage(msg);\r
+\r
+  snprintf(tmpStr, 127, "Initial subway data sent");\r
+  tmpStr[127] = '\0';\r
+  Chat->send(source, CHAT_DIRECT, "System", tmpStr);\r
+}\r
+***/\r
diff --git a/server/src/game/gamecommands/takemoney.cpp b/server/src/game/gamecommands/takemoney.cpp
new file mode 100644 (file)
index 0000000..771d2c7
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+#include "main.h"
+
+void PCommands::doCmdtakemoney()
+{
+    u32 cashtodel = 0;
+    bool SyntaxError = false;
+    if(ArgC < 1)
+    {
+        SyntaxError = true;
+    }
+
+    if(IsArgNumeric(1) == false)
+    {
+        SyntaxError = true;
+    }
+    else
+    {
+        cashtodel = (u32)GetArgInt(1);
+    }
+    if(cashtodel == 0)
+        return;
+
+    if(SyntaxError == true)
+    {
+        Chat->send(source, CHAT_DIRECT, "Usage", "@takemoney <amount> [<charID or nickname>]");
+        return;
+    }
+
+    if(ArgC == 2)
+    {
+        if(IsArgNumeric(2) == true)
+        {
+            target = GetClientByID(GetArgInt(2));
+        }
+        else
+        {
+            char tmp_destNick[50];
+            GetArgText(2, tmp_destNick, 50);
+            target = GetClientByNick(tmp_destNick);
+        }
+        if(target == NULL)
+        {
+            Chat->send(source, CHAT_DIRECT, "System", "No such player");
+            return;
+        }
+        if(source->GetAccountLevel() <= target->GetAccountLevel())
+        {
+            char tmpMsg[200];
+            snprintf(tmpMsg, 199, "Cant manipulate %s's credits, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());
+            tmpMsg[199] = '\0';
+            Chat->send(source, CHAT_DIRECT, "System", tmpMsg);
+            return;
+        }
+
+        u32 newcashvalue = 0;
+        u32 oldcashval = target->GetChar()->GetCash();
+
+        if(oldcashval >= cashtodel)
+            newcashvalue = target->GetChar()->SetCash(oldcashval - cashtodel);
+
+        u32 diffcash = newcashvalue + oldcashval;
+
+        PMessage* tmpMsg_cash = MsgBuilder->BuildCharMoneyUpdateMsg(target, newcashvalue);
+        target->SendUDPMessage(tmpMsg_cash);
+        tmpMsg_cash = NULL;
+
+        char tmpMsg_success[200];
+        snprintf(tmpMsg_success, 199, "Stole %d NC from %s's wallet (Has now %d NC)", diffcash, target->GetChar()->GetName().c_str(), newcashvalue);
+        tmpMsg_success[199] = '\0';
+        Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success);
+    }
+    else
+    {
+        u32 newcashvalue = 0;
+        u32 oldcashval = source->GetChar()->GetCash();
+
+        if(oldcashval >= cashtodel)
+            newcashvalue = source->GetChar()->SetCash(oldcashval - cashtodel);
+
+        PMessage* tmpMsg_cash = MsgBuilder->BuildCharMoneyUpdateMsg(source, newcashvalue);
+        source->SendUDPMessage(tmpMsg_cash);
+        tmpMsg_cash = NULL;
+    }
+}
diff --git a/server/src/game/gamecommands/teleport.cpp b/server/src/game/gamecommands/teleport.cpp
new file mode 100644 (file)
index 0000000..3320f00
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+#include "main.h"
+
+void PCommands::doCmdteleport()
+{
+    bool SyntaxError = false;
+    if(ArgC < 2)
+    {
+        SyntaxError = true;
+    }
+
+    if(IsArgNumeric(2) == false)
+    {
+        SyntaxError = true;
+    }
+
+    if(SyntaxError == true)
+    {
+        Chat->send(source, CHAT_DIRECT, "Usage", "@teleport <charID or nickname> <destination worldID>");
+        return;
+    }
+
+    if(IsArgNumeric(1) == true)
+    {
+        target = GetClientByID(GetArgInt(1));
+    }
+    else
+    {
+        char tmp_destNick[50];
+        GetArgText(1, tmp_destNick, 50);
+        target = GetClientByNick(tmp_destNick);
+    }
+
+    if(target == NULL) // If victim isnt found, return error
+    {
+        Chat->send(source, CHAT_DIRECT, "System", "No such player");
+        return;
+    }
+    // Check accountlevel (Only higher's can perform commands on lower's)
+    if(source->GetAccountLevel() <= target->GetAccountLevel())
+    {
+        char tmpMsg[200];
+        snprintf(tmpMsg, 199, "Cant teleport %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());
+        tmpMsg[199] = '\0';
+        Chat->send(source, CHAT_DIRECT, "System", tmpMsg);
+        return;
+    }
+
+    int destZone = GetArgInt(2);
+    if (!Worlds->IsValidWorld(destZone))
+    {
+        Chat->send(source, CHAT_DIRECT, "System", "Invalid zoneID");
+        return;
+    }
+// *************** Checks done, proceed with command
+    source->InitWarpCircle();
+    source->InitCharVanish();
+
+    if (target->ChangeCharLocation(destZone, true))
+    {
+        target->InitWarpCircle();
+        target->InitCharVanish();
+
+        PMessage* tmpMsg_zone = MsgBuilder->BuildAptLiftUseMsg (target, destZone, 0);
+        target->SendUDPMessage(tmpMsg_zone);
+        tmpMsg_zone = NULL;
+
+        char tmpMsg_success[81];
+        snprintf(tmpMsg_success, 80, "Successfully teleported %s to World %d", target->GetChar()->GetName().c_str(), destZone);
+        tmpMsg_success[80] = '\0';
+        Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success);
+        return;
+    }
+    else
+    {
+        Console->Print("%s Unable to change location for player %d to %d", Console->ColorText(RED, BLACK, "[PANIC]"), target->GetCharID(), destZone);
+    }
+}
diff --git a/server/src/game/gamecommands/test.cpp b/server/src/game/gamecommands/test.cpp
new file mode 100644 (file)
index 0000000..ec04531
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+#include "main.h"
+
+void PCommands::doCmdtest()
+{
+    if (GetArgInt(1) == 1)\r
+    {\r
+        if(ArgC < 5)\r
+            return;\r
+\r
+        PNPC* targetNPC = NULL;\r
+        PNPCWorld* currentNPCWorld = NULL;\r
+        currentNPCWorld = NPCManager->GetWorld( source->GetChar()->GetLocation() );\r
+        if ( currentNPCWorld )\r
+        {\r
+            targetNPC = currentNPCWorld->GetNPC( GetArgInt(2) );\r
+            if(!targetNPC)\r
+                return;\r
+            // @test 15 <npcID> <target_to_attack> <unknown u8 value>\r
+            targetNPC->Attack(GetArgInt(3), (u8)GetArgInt(5), (u8)GetArgInt(4));\r
+        }\r
+    }\r
+    else if (GetArgInt(1) == 2)\r
+    {\r
+        if(ArgC < 3)\r
+            return;\r
+\r
+        int tF1 = GetArgInt(2);\r
+        int tF2 = GetArgInt(3);\r
+        const PDefFaction* tFactionA = NULL;\r
+        const PDefFaction* tFactionB = NULL;\r
+\r
+        if(tF1 > tF2)\r
+        {\r
+            tFactionA = GameDefs->Factions()->GetDef(tF1);\r
+            tFactionB = GameDefs->Factions()->GetDef(tF2);\r
+        }\r
+        else\r
+        {\r
+            tFactionA = GameDefs->Factions()->GetDef(tF2);\r
+            tFactionB = GameDefs->Factions()->GetDef(tF1);\r
+        }\r
+\r
+        if(tFactionA && tFactionB)\r
+        {\r
+            int tRel = -99;\r
+            if(tF1 > tF2)\r
+                tRel = tFactionA->GetRelation(tF2);\r
+            else\r
+                tRel = tFactionA->GetRelation(tF1);\r
+\r
+            char buff[150];\r
+            snprintf(buff, 150, "Relation between <%s> and <%s> is: %d", tFactionA->GetName().c_str(), tFactionB->GetName().c_str(), tRel);\r
+            Chat->send(source, CHAT_DIRECT, "Relations", buff);\r
+        }\r
+        else\r
+            Chat->send(source, CHAT_DIRECT, "Relations", "Invalid faction");\r
+    }\r
+
+
+
+
+
+
+    /*
+        u8 val1 = 0;
+        u8 val2 = 0;
+        u8 val3 = 0;
+        u16 val4 = 0;
+        u16 val5 = 0;
+    //    u16 val6 = 0;
+    //    u8 val7 = 0;
+
+        bool SyntaxError = false;
+        if(ArgC < 5)
+        {
+            SyntaxError = true;
+        }
+
+        if(IsArgNumeric(1) == false)
+            SyntaxError = true;
+        if(IsArgNumeric(2) == false)
+            SyntaxError = true;
+        if(IsArgNumeric(3) == false)
+            SyntaxError = true;
+        if(IsArgNumeric(4) == false)
+            SyntaxError = true;
+        if(IsArgNumeric(5) == false)
+            SyntaxError = true;
+    //    if(IsArgNumeric(6) == false)
+    //        SyntaxError = true;
+    //    if(IsArgNumeric(7) == false)
+    //        SyntaxError = true;
+
+        if(SyntaxError == true)
+        {
+            PMessage* tmpMsg1 = new PMessage(14);
+
+            *tmpMsg1 << (u8)0x13;
+            *tmpMsg1 << (u16)0x0000; // UDP ID placeholder
+            *tmpMsg1 << (u16)0x0000; // SessionID placeholder
+            *tmpMsg1 << (u8)0x08;    // Len (static, always 0x08
+            *tmpMsg1 << (u8)0x03;
+            *tmpMsg1 << (u16)0x0000; // Sub UDP ID placeholder
+            *tmpMsg1 << (u8)0x26;    // Command FADE AWAY CHAR (kinda ^^)
+            *tmpMsg1 << (u8)0x00;
+            *tmpMsg1 << (u8)0x10;
+            *tmpMsg1 << (u8)0x00;
+            *tmpMsg1 << (u8)0x80;
+            ClientManager->UDPBroadcast(tmpMsg1, source);
+        }
+
+        val1 = (u8)GetArgInt(1);
+        val2 = (u8)GetArgInt(2);
+        val3 = (u8)GetArgInt(3);
+        val4 = (u16)GetArgInt(4);
+        val5 = (u16)GetArgInt(5);
+    //    val7 = (u16)GetArgInt(7);
+
+        //tmpMsg = MsgBuilder->BuildCharUseQBSlotMsg1(source, 59);
+        //source->SendUDPMessage(tmpMsg);
+        //tmpMsg = NULL;
+
+        PMessage* tmpMsg = new PMessage(29);
+        *tmpMsg << (u8)0x13;
+       *tmpMsg << (u16)0x0000;
+       *tmpMsg << (u16)0x0000;
+       *tmpMsg << (u8)0x16; // Message length
+       *tmpMsg << (u8)0x03;
+       *tmpMsg << (u16)0x0000;
+       *tmpMsg << (u8)0x1b;
+       *tmpMsg << (u8)0x00;
+       *tmpMsg << (u8)0x10;
+       *tmpMsg << (u8)0x00;
+       *tmpMsg << (u8)0x80;
+       *tmpMsg << (u8)0x19;
+       *tmpMsg << (u8)0x55;
+       *tmpMsg << (u8)0x74;
+       *tmpMsg << (u8)0x80;
+       *tmpMsg << (u8)0x82;
+       *tmpMsg << (u8)0xc2;
+       *tmpMsg << (u8)0x84;
+       *tmpMsg << (u8)val1;
+       *tmpMsg << (u8)val2;
+       *tmpMsg << (u8)val3;
+       *tmpMsg << (u16)val4;
+       *tmpMsg << (u16)val5;
+    // *tmpMsg << (u8)0x69;
+    // *tmpMsg << (u8)0x00;
+
+        ClientManager->UDPBroadcast(tmpMsg, source);
+
+    // ***************************
+        bool SyntaxError = false;
+        if(ArgC < 1)
+        {
+            SyntaxError = true;
+        }
+
+        if(IsArgNumeric(1) == false)
+            SyntaxError = true;
+
+        if(SyntaxError == true)
+        {
+            Chat->send(source, CHAT_DIRECT, "Usage", "@test <id>");
+            return;
+        }
+
+        u16 itemID;
+        char effStr[128];
+        PMessage* tmpMsg;
+
+        itemID = (u16)GetArgInt(1);
+
+        source->GetChar()->SetItemInHand(itemID);
+
+        tmpMsg = MsgBuilder->BuildCharHelloMsg(source);
+        ClientManager->UDPBroadcast(tmpMsg, source);
+        snprintf(effStr, 127, "Item in hand changes to value %d", itemID);
+        effStr[127] = '\0';
+        Chat->send(source, CHAT_DIRECT, "System", effStr);
+    ===========================================================================
+        u16 ItemToSpawn = 0;
+        u8 Quality = 0;
+        u8 Stack = 0;
+
+        bool SyntaxError = false;
+        if(ArgC < 3)
+        {
+            SyntaxError = true;
+        }
+        else
+        {
+            if(IsArgNumeric(1) == true)
+            {
+                ItemToSpawn = (u16)GetArgInt(1);
+                if(ItemToSpawn == 0)
+                {
+                    SyntaxError = true;
+                }
+            }
+            else
+            {
+                SyntaxError = true;
+            }
+
+            if(IsArgNumeric(2) == true)
+            {
+                Quality = (u8)GetArgInt(2);
+                if(Quality == 0)
+                {
+                    SyntaxError = true;
+                }
+            }
+            else
+            {
+                SyntaxError = true;
+            }
+
+            if(IsArgNumeric(3) == true)
+            {
+                Stack = (u8)GetArgInt(3);
+                if(Stack == 0)
+                {
+                    SyntaxError = true;
+                }
+            }
+            else
+            {
+                SyntaxError = true;
+            }
+        }
+        if(SyntaxError == true)
+        {
+            Chat->send(source, CHAT_DIRECT, "Usage", "@test <itemID> <quality> <itemID>");
+            return;
+        }
+        PMessage* tmpMsg = new PMessage(29);
+        source->IncreaseUDP_ID();
+        source->IncreaseTransactionID();
+
+        *tmpMsg << (u8)0x13;
+       *tmpMsg << (u16)source->GetUDP_ID();
+       *tmpMsg << (u16)source->GetSessionID();
+       *tmpMsg << (u8)0x16; // Message length
+       *tmpMsg << (u8)0x03;
+       *tmpMsg << (u16)source->GetUDP_ID();
+       *tmpMsg << (u8)0x1f;
+       *tmpMsg << (u16)source->GetLocalID();
+       *tmpMsg << (u8)0x25; // ??
+       *tmpMsg << (u8)0x13; // ??
+        *tmpMsg << (u16)source->GetTransactionID();
+       *tmpMsg << (u8)0x18; // ??
+       *tmpMsg << (u8)0x03; // ??
+       *tmpMsg << (u8)0x01; // ??
+       *tmpMsg << (u8)0x00; // ??
+       *tmpMsg << (u8)0x05; // ??
+       *tmpMsg << (u8)0x00; // ??
+       *tmpMsg << ItemToSpawn;
+       *tmpMsg << (u8)0x02; // ??
+       *tmpMsg << (u8)0x01; // ??
+       *tmpMsg << Quality;
+       *tmpMsg << Stack;
+
+
+        source->SendUDPMessage(tmpMsg);
+        */
+}
diff --git a/server/src/game/gamecommands/unban.cpp b/server/src/game/gamecommands/unban.cpp
new file mode 100644 (file)
index 0000000..ce0a0b0
--- /dev/null
@@ -0,0 +1,26 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdunban()\r
+{\r
+    Chat->send(source, CHAT_DIRECT, "System", "Unban is not yet possible, sorry.");\r
+}\r
diff --git a/server/src/game/gamecommands/unjail.cpp b/server/src/game/gamecommands/unjail.cpp
new file mode 100644 (file)
index 0000000..86b5b04
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+#include "main.h"
+
+void PCommands::doCmdunjail()
+{
+  bool SyntaxError = false;
+  if ( ArgC < 1 )
+  {
+    SyntaxError = true;
+  }
+
+  if ( SyntaxError == true )
+  {
+    Chat->send( source, CHAT_DIRECT, "Usage", "@unjail <charID or nickname>" );
+    return;
+  }
+
+  if ( IsArgNumeric( 1 ) == true )
+  {
+    target = GetClientByID( GetArgInt( 1 ) );
+  }
+  else
+  {
+    char tmp_destNick[50];
+    GetArgText( 1, tmp_destNick, 50 );
+    target = GetClientByNick( tmp_destNick );
+  }
+
+  if ( target == NULL ) // If victim isnt found, return error
+  {
+    Chat->send( source, CHAT_DIRECT, "System", "No such player" );
+    return;
+  }
+  // Check accountlevel (Only higher's can perform commands on lower's)
+  if ( source->GetAccountLevel() <= target->GetAccountLevel() )
+  {
+    char tmpMsg[200];
+    snprintf( tmpMsg, 199, "Cant unjail %s, target level is higher or equal to yours!", Chars->GetChar( target->GetCharID() )->GetName().c_str() );
+    tmpMsg[199] = '\0';
+    Chat->send( source, CHAT_DIRECT, "System", tmpMsg );
+    return;
+  }
+
+  u32 currLoc = target->GetChar()->GetLocation();
+  // Make sure that target player is really in Regants
+  if ( currLoc != 550 && currLoc != 551 )
+  {
+    Chat->send( source, CHAT_DIRECT, "System", "Target player is not jailed!" );
+    return;
+  }
+
+// *************** Checks done, proceed with command
+
+  int destZone = 503; // TH Sec2. Maybe set to appartment later ?
+  if ( target->ChangeCharLocation( destZone, true ) )
+  {
+    PMessage* tmpMsg_zone = MsgBuilder->BuildAptLiftUseMsg( target, destZone, 0 );
+    target->SendUDPMessage( tmpMsg_zone );
+    tmpMsg_zone = NULL;
+
+    char tmpMsg_success[81];
+    snprintf( tmpMsg_success, 80, "Successfully unjailed %s", target->GetChar()->GetName().c_str() );
+    tmpMsg_success[80] = '\0';
+    Chat->send( source, CHAT_DIRECT, "System", tmpMsg_success );
+    return;
+  }
+  else
+  {
+    Console->Print( "%s Unable to change location for player %d to %d", Console->ColorText( RED, BLACK, "[PANIC]" ), target->GetCharID(), destZone );
+  }
+}
diff --git a/server/src/game/gamecommands/unshun.cpp b/server/src/game/gamecommands/unshun.cpp
new file mode 100644 (file)
index 0000000..a397541
--- /dev/null
@@ -0,0 +1,76 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdunshun()\r
+{\r
+    bool SyntaxError = false;\r
+    if(ArgC < 1)\r
+    {\r
+        SyntaxError = true;\r
+    }\r
+\r
+    if(SyntaxError == true)\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "Usage", "@shun <charID or nickname>");\r
+        return;\r
+    }\r
+\r
+    if(IsArgNumeric(1) == true)\r
+    {\r
+        target = GetClientByID(GetArgInt(1));\r
+    }\r
+    else\r
+    {\r
+        char tmp_destNick[50];\r
+        GetArgText(1, tmp_destNick, 50);\r
+        target = GetClientByNick(tmp_destNick);\r
+    }\r
+\r
+    if(target == NULL) // If victim isnt found, return error\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "System", "No such player");\r
+        return;\r
+    }\r
+    if(source->GetAccountLevel() <= target->GetAccountLevel())\r
+    {\r
+        char tmpMsg[200];\r
+        snprintf(tmpMsg, 199, "Cant unshun %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());\r
+        tmpMsg[199] = '\0';\r
+        Chat->send(source, CHAT_DIRECT, "System", tmpMsg);\r
+        return;\r
+    }\r
+    if(target->GetChar()->IsShunned() == true)\r
+    {\r
+        target->GetChar()->SetShun(false);\r
+\r
+        char tmpMsg_success[81];\r
+        snprintf(tmpMsg_success, 80, "Successfully unshunned %s", target->GetChar()->GetName().c_str());\r
+        tmpMsg_success[80] = '\0';\r
+        Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success);\r
+        return;\r
+    }\r
+    else\r
+    {\r
+        Chat->send(source, CHAT_DIRECT, "System", "Player is not shunned");\r
+        return;\r
+    }\r
+}\r
diff --git a/server/src/game/gamecommands/uptime.cpp b/server/src/game/gamecommands/uptime.cpp
new file mode 100644 (file)
index 0000000..f3a2dbb
--- /dev/null
@@ -0,0 +1,154 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmduptime()\r
+{\r
+    // get difference between var uptime and current time\r
+    std::time_t Uptime = GameServer->GetStartTime();\r
+    u32 TimeDiff = std::time(NULL) - Uptime;\r
+    u32 UpYears = 0, UpMonths = 0, UpWeeks = 0, UpDays = 0, UpHours = 0, UpMinutes = 0, UpSeconds = 0;\r
+    char tmpY[21], tmpM[21], tmpW[21], tmpD[21], tmpH[21], tmpMi[21], tmpS[21];\r
+\r
+    // 1 min = 60 sec                           = 60\r
+    // 1 hour = 60 * 60 sec                     = 3600\r
+    // 1 day = 24 * 60 * 60 sec                 = 86400\r
+    // 1 week = 7 * 24 * 60 * 60 sec            = 604800\r
+    // 1 month = 30 * 7 * 24 * 60 * 60 sec      = 18144000\r
+    // 1 year = 12 * 30 * 7 * 24 * 60 * 60 sec  = 217728000\r
+\r
+    // Split Years\r
+    while(TimeDiff >= 217728000)\r
+    {\r
+        TimeDiff = TimeDiff - 217728000;\r
+        UpYears++;\r
+    }\r
+\r
+    // Split Months\r
+    while(TimeDiff >= 18144000)\r
+    {\r
+        TimeDiff = TimeDiff - 18144000;\r
+        UpMonths++;\r
+    }\r
+\r
+    // Split Weeks\r
+    while(TimeDiff >= 604800)\r
+    {\r
+        TimeDiff = TimeDiff - 604800;\r
+        UpWeeks++;\r
+    }\r
+\r
+    // Split Days\r
+    while(TimeDiff >= 86400)\r
+    {\r
+        TimeDiff = TimeDiff - 86400;\r
+        UpDays++;\r
+    }\r
+\r
+    // Split Hours\r
+    while(TimeDiff >= 3600)\r
+    {\r
+        TimeDiff = TimeDiff - 3600;\r
+        UpHours++;\r
+    }\r
+\r
+    // Split Minutes\r
+    while(TimeDiff >= 60)\r
+    {\r
+        TimeDiff = TimeDiff - 60;\r
+        UpMinutes++;\r
+    }\r
+\r
+    // What's left are seconds\r
+    UpSeconds = TimeDiff;\r
+\r
+    // Now create output strings. Add 's' if > 1\r
+    // Years\r
+    if(UpYears > 1)\r
+        snprintf(tmpY, 20, "%d years ", UpYears);\r
+    else if(UpYears > 0)\r
+        snprintf(tmpY, 20, "%d year ", UpYears);\r
+    else\r
+        tmpY[0] = '\0';\r
+\r
+    // Months\r
+    if(UpMonths > 1)\r
+        snprintf(tmpM, 20, "%d months ", UpMonths);\r
+    else if(UpMonths > 0)\r
+        snprintf(tmpM, 20, "%d month ", UpMonths);\r
+    else\r
+        tmpM[0] = '\0';\r
+\r
+    // Weeks\r
+    if(UpWeeks > 1)\r
+        snprintf(tmpW, 20, "%d weeks ", UpWeeks);\r
+    else if(UpWeeks > 0)\r
+        snprintf(tmpW, 20, "%d week ", UpWeeks);\r
+    else\r
+        tmpW[0] = '\0';\r
+\r
+    // Days\r
+    if(UpDays > 1)\r
+        snprintf(tmpD, 20, "%d days ", UpDays);\r
+    else if(UpDays > 0)\r
+        snprintf(tmpD, 20, "%d day ", UpDays);\r
+    else\r
+        tmpD[0] = '\0';\r
+\r
+    // Hours\r
+    if(UpHours > 1)\r
+        snprintf(tmpH, 20, "%d hours ", UpHours);\r
+    else if(UpHours > 0)\r
+        snprintf(tmpH, 20, "%d hour ", UpHours);\r
+    else\r
+        tmpH[0] = '\0';\r
+\r
+    // Minutes\r
+    if(UpMinutes > 1)\r
+        snprintf(tmpMi, 20, "%d minutes and ", UpMinutes);\r
+    else if(UpMinutes > 0)\r
+        snprintf(tmpMi, 20, "%d minute and ", UpMinutes);\r
+    else\r
+        tmpMi[0] = '\0';\r
+\r
+    // Seconds\r
+    if(UpSeconds > 1 || UpSeconds == 0)\r
+        snprintf(tmpS, 20, "%d seconds.", UpSeconds);\r
+    else\r
+        snprintf(tmpS, 20, "%d second.", UpSeconds);\r
+\r
+    // Terminate all chars, just to be sure\r
+    tmpY[20] = '\0';\r
+    tmpM[20] = '\0';\r
+    tmpW[20] = '\0';\r
+    tmpD[20] = '\0';\r
+    tmpH[20] = '\0';\r
+    tmpMi[20] = '\0';\r
+    tmpS[20] = '\0';\r
+\r
+    //Copy the single msg's into one\r
+    char tmpChatMsg[300];\r
+    snprintf(tmpChatMsg, 299, "The server has been running for %s%s%s%s%s%s%s", tmpY, tmpM, tmpW, tmpD, tmpH, tmpMi, tmpS);\r
+    tmpChatMsg[299] = '\0';\r
+\r
+    // Send it out\r
+    Chat->send(source, CHAT_DIRECT, "System", tmpChatMsg);\r
+}\r
diff --git a/server/src/game/gamecommands/v.cpp b/server/src/game/gamecommands/v.cpp
new file mode 100644 (file)
index 0000000..0e8c8e7
--- /dev/null
@@ -0,0 +1,66 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmd_dev_v()\r
+{\r
+    if(IsAdmin() == false)\r
+      return;\r
+    \r
+    char Arg1[30];\r
+\r
+    Arg1[0] = '\0';\r
+\r
+    if(ArgC > 0)\r
+    {\r
+        GetArgText(1, Arg1, 30);\r
+    }\r
+\r
+    char tmpStr[128];\r
+    int testmode = 1; // change here only for u8/u16/u32 testvalue use\r
+\r
+    if(Arg1[0] != '\0')\r
+    {\r
+        switch(testmode)\r
+        {\r
+            case 0: source->testval8 = (u8)(atoi(Arg1) & 0xff); break;\r
+            case 1: source->testval16 = (u16)(atoi(Arg1) & 0xffff); break;\r
+            case 2: source->testval32 = (u32)(atoi(Arg1) & 0xffffffff); break;\r
+        }\r
+    }\r
+    else\r
+    {\r
+        source->testval8 = 0;\r
+        source->testval16 = 0;\r
+        source->testval32 = 0;\r
+    }\r
+\r
+    switch(testmode)\r
+    {\r
+        case 0: snprintf(tmpStr, 127, "Test value u8 set to 0x%02x (%d)", source->testval8, source->testval8); break;\r
+        case 1: snprintf(tmpStr, 127, "Test value u16 set to 0x%04x (%d)", source->testval16, source->testval16); break;\r
+        case 2: snprintf(tmpStr, 127, "Test value u32 set to 0x%08x (%d)", source->testval32, source->testval32); break;\r
+        default: tmpStr[0] = '\0';\r
+    }\r
+    tmpStr[127] = '\0';\r
+    Chat->send(source, CHAT_DIRECT, "System", tmpStr);\r
+\r
+}\r
diff --git a/server/src/game/gamecommands/version.cpp b/server/src/game/gamecommands/version.cpp
new file mode 100644 (file)
index 0000000..104f172
--- /dev/null
@@ -0,0 +1,30 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+#include "main.h"\r
+\r
+void PCommands::doCmdversion()\r
+{\r
+    char tmpChatMsg[300];\r
+    snprintf(tmpChatMsg, 299, "You are on TinNS server %s runnig version %s - SVN Rev. %s", Config->GetOption("server_name").c_str(), ServerVersion, SVNRevision);\r
+    tmpChatMsg[299] = '\0';\r
+\r
+    Chat->send(source, CHAT_DIRECT, "System", tmpChatMsg);\r
+}\r
diff --git a/server/src/game/gamecommands/warp.cpp b/server/src/game/gamecommands/warp.cpp
new file mode 100644 (file)
index 0000000..edc0ef5
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+#include "main.h"
+
+void PCommands::doCmdwarp()
+{
+  int SpawnPointID = 0;
+  int zoneID = 0;
+  int ZoningType = 0;
+
+  bool SyntaxError = false;
+  if ( ArgC < 1 )
+  {
+    SyntaxError = true;
+  }
+  else
+  {
+    if ( IsArgNumeric( 1 ) == true )
+    {
+      zoneID = GetArgInt( 1 );
+      if ( zoneID == 0 )
+      {
+        SyntaxError = true;
+      }
+    }
+    else
+    {
+      SyntaxError = true;
+    }
+
+    if ( ArgC > 1 )
+    {
+      if ( IsArgNumeric( 2 ) == true )
+      {
+        SpawnPointID = GetArgInt( 2 );
+        if ( ArgC > 2 )
+        {
+          ZoningType = 1;
+        }
+      }
+      else
+      {
+        SyntaxError = true;
+      }
+    }
+  }
+  if ( SyntaxError == true )
+  {
+    Chat->send( source, CHAT_DIRECT, "Usage", "@warp <zoneid> [<spawn location> [<use .def: 1>]]" );
+    return;
+  }
+
+  if ( !Worlds->IsValidWorld( zoneID ) )
+  {
+    Chat->send( source, CHAT_DIRECT, "System", "Invalid zoneID" );
+    return;
+  }
+
+  if ( source->ChangeCharLocation( zoneID, true ) )
+  {
+    if ( gDevDebug ) Console->Print( "IngameCommand: Warping player %d to zone %d (%s)", source->GetCharID(), zoneID, Worlds->GetWorld( zoneID )->GetName().c_str() );
+
+    PMessage* tmpMsg = MsgBuilder->BuildAptLiftUseMsg( source, zoneID, SpawnPointID, ZoningType );
+    source->SendUDPMessage( tmpMsg );
+  }
+  else
+  {
+    Console->Print( RED, BLACK, "IngameCommand: Can't change location when trying to warp player %d to zone %d", source->GetCharID(), zoneID );
+  }
+}
diff --git a/server/src/game/gamecommands/warpto.cpp b/server/src/game/gamecommands/warpto.cpp
new file mode 100644 (file)
index 0000000..a668124
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+#include "main.h"
+
+void PCommands::doCmdwarpto()
+{
+  bool SyntaxError = false;
+  if ( ArgC < 1 )
+  {
+    SyntaxError = true;
+  }
+
+  if ( SyntaxError == true )
+  {
+    Chat->send( source, CHAT_DIRECT, "Usage", "@warpto <charID or nickname>" );
+    return;
+  }
+
+  if ( IsArgNumeric( 1 ) == true )
+  {
+    target = GetClientByID( GetArgInt( 1 ) );
+  }
+  else
+  {
+    char tmp_destNick[50];
+    GetArgText( 1, tmp_destNick, 50 );
+    target = GetClientByNick( tmp_destNick );
+  }
+
+  if ( target == NULL ) // If victim isnt found, return error
+  {
+    Chat->send( source, CHAT_DIRECT, "System", "No such player" );
+    return;
+  }
+
+  int destZone = 0;
+  // Warp GM/Admin to target player
+  PChar* targetChar = target->GetChar();
+  destZone = targetChar->GetLocation();
+  if ( gDevDebug ) Console->Print( "%s Warping %d to location of %d (> %d)", Console->ColorText( YELLOW, BLACK, "[Notice]" ), source->GetCharID(), target->GetCharID(), destZone );
+  if ( !Worlds->IsValidWorld( destZone ) )
+  {
+    Console->Print( "%s Can't change location, destZone '%d' is invalid for some reason", Console->ColorText( RED, BLACK, "[PANIC]" ), destZone );
+    return;
+  }
+// *************** Checks done, proceed with command
+
+  if ( source->ChangeCharLocation( destZone ), true )
+  {
+    source->SetAwaitingWarpto( true, targetChar->Coords.mX, targetChar->Coords.mY, targetChar->Coords.mZ );
+    PMessage* tmpMsg_zone = MsgBuilder->BuildChangeLocationMsg( source, destZone, 10, 1, 0 );
+    source->SendUDPMessage( tmpMsg_zone );
+
+    char tmpMsg_success[81];
+    snprintf( tmpMsg_success, 80, "Successfully warped you to %s", target->GetChar()->GetName().c_str() );
+    tmpMsg_success[80] = '\0';
+    Chat->send( source, CHAT_DIRECT, "System", tmpMsg_success );
+    return;
+  }
+  else
+  {
+    Console->Print( "%s Unable to change location for player %d to %d", Console->ColorText( RED, BLACK, "[PANIC]" ), source->GetCharID(), destZone );
+  }
+}
diff --git a/server/src/game/gamecommands/weather.cpp b/server/src/game/gamecommands/weather.cpp
new file mode 100644 (file)
index 0000000..0aded50
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+  TinNS (TinNS is not a Neocron Server)
+  Copyright (C) 2005 Linux Addicted Community
+  maintainer Akiko <akiko@gmx.org>
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License
+  as published by the Free Software Foundation; either version 2
+  of the License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+  02110-1301, USA.
+*/
+#include "main.h"
+
+void PCommands::doCmdweather()
+{
+  bool SyntaxError = false;
+  if ( ArgC < 1 )
+  {
+    SyntaxError = true;
+  }
+
+  if ( SyntaxError == true )
+  {
+    Chat->send( source, CHAT_DIRECT, "Usage", "@weather ?|<weather id> [<target char id>]" );
+    return;
+  }
+
+  int wId = 0;
+  char tmp_v1[6];
+  GetArgText( 1, tmp_v1, 6 );
+
+  if ( tmp_v1[0] != '?' )
+  {
+    wId = atoi( tmp_v1 );
+    if ( wId > 0 )
+    {
+      if ( ArgC >= 2 )
+      {
+        if ( !GetTarget( 2 ) )
+        {
+          Chat->send( source, CHAT_DIRECT, "System", "Invalid target character" );
+          return;
+        }
+      }
+      else
+        target = source;
+
+      PMessage* tmpMsg = MsgBuilder->BuildWeatherControlMsg(( u16 )wId );
+      ClientManager->UDPBroadcast( tmpMsg, target );
+
+      char effStr[128];
+      snprintf( effStr, 127, "Weather set to value %d", wId );
+      effStr[127] = '\0';
+      Chat->send( source, CHAT_DIRECT, "System", effStr );
+
+      return;
+    }
+    else
+      Chat->send( source, CHAT_DIRECT, "System", "Invalid weather id" );
+  }
+
+  Chat->send( source, CHAT_DIRECT, "System", "Valid weather values:" );
+  Chat->send( source, CHAT_DIRECT, "-", "1:Bright sky 2:Single cloud 3:Cloudy" );
+  Chat->send( source, CHAT_DIRECT, "-", "4:Light rain 5:Heavy rain 6:Thunderstorm" );
+  Chat->send( source, CHAT_DIRECT, "-", "100:Sea bright sky" );
+
+}
diff --git a/server/src/game/gamescript.cpp.inhib b/server/src/game/gamescript.cpp.inhib
new file mode 100644 (file)
index 0000000..96a056f
--- /dev/null
@@ -0,0 +1,123 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+#include "main.h"\r
+\r
+PGameScript::PGameScript()\r
+{\r
+}\r
+\r
+PGameScript::~PGameScript()\r
+{\r
+       for(HookMap::iterator it = mHooks.begin(); it != mHooks.end(); it++)\r
+               delete it->second;\r
+}\r
+\r
+bool PGameScript::LoadScripts()\r
+{\r
+}\r
+\r
+bool PGameScript::Rehash()\r
+{\r
+    Console->LPrint("Rehashing GameMonkey Scripts...");\r
+       for(HookMap::iterator it = mHooks.end(); it != mHooks.begin(); it--)\r
+        mHooks.erase(it);\r
+\r
+    if(LoadScripts() == true)\r
+    {\r
+        Console->LPrint(GREEN, BLACK, "Done");\r
+        Console->LClose();\r
+        return true;\r
+    }\r
+    else\r
+    {\r
+        Console->LPrint(RED, BLACK, "Failed");\r
+        Console->LClose();\r
+        return false;\r
+    }\r
+}\r
+\r
+void PGameScript::TriggerHook(PHookTypes hook)\r
+{\r
+}\r
+\r
+\r
+bool ScriptSys::ExecuteFile(const char* a_fileName)\r
+{\r
+  FILE* scriptFile = NULL;\r
+  char* fileString = NULL;\r
+  int fileSize = 0;\r
+\r
+  GM_ASSERT(m_machine);\r
+\r
+  if( !(scriptFile = fopen(a_fileName, "rb")) )\r
+  {\r
+    return false;\r
+  }\r
+\r
+  fseek(scriptFile, 0, SEEK_END);\r
+  fileSize = ftell(scriptFile);\r
+  fseek(scriptFile, 0, SEEK_SET);\r
+  fileString = new char [fileSize+1];\r
+  fread(fileString, fileSize, 1, scriptFile);\r
+  fileString[fileSize] = 0; // Terminating null\r
+  fclose(scriptFile);\r
+\r
+  int threadId = GM_INVALID_THREAD;\r
+  int errors = m_machine->ExecuteString(fileString, &threadId, true, a_fileName);\r
+  if(errors)\r
+  {\r
+    LogAnyMachineErrorMessages();\r
+  }\r
+\r
+  delete [] fileString;\r
+\r
+  return true;\r
+}\r
+\r
+\r
+int GM_CDECL PGameScript::AddHook(gmThread *a_thread)\r
+{\r
+    GM_CHECK_NUM_PARAMS(2);\r
+    GM_CHECK_STRING_PARAM(tmphooktype, 0);\r
+    GM_CHECK_STRING_PARAM(tmpfunction, 1);\r
+\r
+    mHooks.insert(std::make_pair(tmphooktype, tmpfunction));\r
+\r
+    return GM_OK;\r
+}\r
+\r
+int PGameScript::AddTwoIntegers(int valueA, int valueB)\r
+{\r
+  int resultInt = 0;\r
+\r
+  gmCall call;\r
+\r
+  if(call.BeginGlobalFunction(&machine, "Add"))\r
+  {\r
+    call.AddParamInt(valueA);\r
+    call.AddParamInt(valueB);\r
+    call.End();\r
+    call.GetReturnedInt(resultInt);\r
+  }\r
+\r
+  return resultInt;\r
+}
\ No newline at end of file
diff --git a/server/src/game/gameserver.cpp b/server/src/game/gameserver.cpp
new file mode 100644 (file)
index 0000000..a450a8d
--- /dev/null
@@ -0,0 +1,1055 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+\r
+ gameserver.cpp - main file of the gameserver\r
+\r
+ MODIFIED: 31 Aug 2005 Akiko\r
+ REASON: - added modifications by "Sting" to get a running gameserver again\r
+  - added this header\r
+ MODIFIED: 28 Sep 2005 Akiko\r
+ REASON: - define for game server port\r
+ MODIFIED: 29 Sep 2005 Sting (modified by Akiko)\r
+ REASON: - configurable UDP port for testing\r
+  - tidied up/corrected packet sent with most character stats (character now has monk stats for testing)\r
+ MODIFIED: 27 Nov 2005 Akiko\r
+ REASON: - added Namikons fix (IPStringToDWord)\r
+  - added bluehrs packet fix\r
+ MODIFIED: 17 Dec 2005 bakkdoor\r
+        REASON: - Due the new structure for chatsystem, changed\r
+                    HandleGameChat(Client, Packet);\r
+                  to\r
+                    Chat->HandleGameChat(Client, Packet);\r
+                - Also added ClientManager->addClientToList and ClientManager->deleteClientFromList()\r
+                  (check Update() & FinalizeClient())\r
+ MODIFIED: 18 Dec 2005 Namikon\r
+ REASON: - Fixed several small issues in the main-packet if-clause (sizeof(<char>), etc)\r
+ MODIFIED: 21 Dec 2005 Namikon\r
+ REASON: - Fixed zoning (for now). The basic packet is broken somehow, still working on that\r
+ MODIFIED: 25 Dec 2005 Namikon\r
+ REASON: - Basepacket 1 and 2 fixed. (Thanks to MaxxJag!)\r
+              Zoning still works, same goes for skills/factions.\r
+              Not sure about quickbelt and inventory, but it seems to be ok\r
+ MODIFIED: 26 Dec 2005 Namikon\r
+ REASON: - Added doors\r
+            - Added support for Worlditem usage (Gogo/Genrep/Appitem/...)\r
+ MODIFIED: 01 Jan 2006 Namikon\r
+ REASON: - Changed FmtTxt() to sprintf(). It does... uhm, the same :D\r
+            - Added SetOnlineStatus to do instand updates when char is logging in\r
+ MODIFIED: 02 Jan 2006 Namikon\r
+ REASON: - Added debug output function\r
+    MODIFIED: 06 Jan 2006 Namikon\r
+    REASON: - Added color to console outputs\r
+  MODIFIED: 01 Jul 2006 hammag\r
+ REASON: - added set timeout to 10 msec (for ReadSetTCP select) in Start()\r
+           to avoid useless 100% CPU use\r
+  MODIFIED: 30 Jul 2006 hammag\r
+ REASON: - Fixed 0x13 0x03 0x1F message filters to enable other char than ID 1 to play ... :P\r
+  MODIFIED: 12 Aug 2006 hammag\r
+ REASON: - Fixed BuildCharPosUpdateMsg() to send correct characters orientation to other characters\r
+  MODIFIED: 26 Aug 2006 hammag\r
+ REASON: - removed use of GAME_PORT define as this info is available in Config object with a default value\r
+  MODIFIED: 17 Sep 2006 hammag\r
+ REASON: - Moved all UDP message management code to decoder classes\r
+         - Removed corresponding code from gameserver.cpp & .h\r
+\r
+  MODIFIED: 03 Oct 2006 hammag\r
+ REASON: - Added some more DB cleanup when a char is deleted (still incomplete and will later be done in PChar::SQLDelete() )\r
+    MODIFIED: 10 Dec 2006 Namikon\r
+ REASON: - Added new variable "mServerStartupTime". Holds the unix timestamp uppon startup. Required for @uptime\r
+              and other time-based stuff\r
+\r
+    TODO:\r
+    - Deny login if char is already online (More information about the login procedure is necessary to do that)\r
+    - Take main loop timeout setting from config file\r
+    - Add Regex control to new char name validation\r
+    - Add Check of Char offline (and unloaded) before deleting (from the char choosing i/f) if multiple login allowed for the same account\r
+    - Check if adding to Client to Client manager shouldn't be done only one UDP connection done ?\r
+        => Risk of sending UDP chat on non-socket ????\r
+*/\r
+\r
+\r
+#include "main.h"\r
+\r
+#include "msgdecoder.h"\r
+#include "msgbuilder.h"\r
+#include "appartements.h"\r
+\r
+\r
+PGameServer::PGameServer()\r
+{\r
+  mServerStartupTime = std::time( NULL );\r
+  mNumClients = 0;\r
+  MsgDecoder = new PUdpMsgDecoder();\r
+}\r
+\r
+PGameServer::~PGameServer()\r
+{\r
+  ServerSock->closeServer();\r
+  delete MsgDecoder;\r
+}\r
+\r
+void PGameServer::Start()\r
+{\r
+  u16 Port = Config->GetOptionInt( "gameserver_port" );\r
+  Console->LPrint( "Starting gameserver on port %i...", Port );\r
+\r
+  if ( ServerSock->open( Port ) )\r
+  {\r
+    Console->LPrint( GREEN, BLACK, "Success" );\r
+  }\r
+  else\r
+  {\r
+    Console->LPrint( RED, BLACK, "Failed" );\r
+  }\r
+  Console->LClose();\r
+  ServerSock->settimeout( 0, 10000 );\r
+\r
+  SetGameTime(( 1000 / 10 )*3600*12 ); //Set initial time to 12:00 on 7 Jul 2789\r
+\r
+  // Init random generator\r
+  struct timespec tmpTime;\r
+  if ( !clock_gettime( CLOCK_REALTIME, &tmpTime ) )\r
+  {\r
+    srandom(( u32 )tmpTime.tv_sec );\r
+    InitRandom( tmpTime.tv_sec );\r
+//Console->Print("Initializing random generator. First value is %d", random());\r
+  }\r
+\r
+  if ( Config->GetOptionInt( "gameserver_udpport_max" ) - Config->GetOptionInt( "gameserver_udpport_min" ) + 1 < Config->GetOptionInt( "maxclients" ) )\r
+  {\r
+    Console->Print( "%s UDP port range setting doesn't allow for the simultaneous max clients set in config", Console->ColorText( YELLOW, BLACK, "[Warning]" ) );\r
+  }\r
+\r
+}\r
+\r
+void PGameServer::SetGameTime( u32 newtime )\r
+{\r
+  if ( clock_gettime( CLOCK_REALTIME, &mStartTime ) )\r
+  {\r
+    Console->Print( RED, BLACK, "[ERROR] Clock unavailable !!!" );\r
+    perror( "clock_gettime CLOCK_REALTIME" );\r
+    mStartTime.tv_sec = 0;\r
+    mStartTime.tv_nsec = 0;\r
+  }\r
+  mBaseGameTime = newtime;\r
+}\r
+\r
+u32 PGameServer::GetGameTime()\r
+{\r
+  //const u32 TimeFactor = 375;\r
+  const u32 TimeFactor = 1000;\r
+  const u32 nsTimeFactor = 1000000000 / TimeFactor;\r
+\r
+  struct timespec tmpTime;\r
+\r
+  if ( mStartTime.tv_sec )\r
+  {\r
+    clock_gettime( CLOCK_REALTIME, &tmpTime );\r
+    return ( mBaseGameTime + (( tmpTime.tv_sec - mStartTime.tv_sec ) * TimeFactor ) + ( tmpTime.tv_nsec / nsTimeFactor ) - ( mStartTime.tv_nsec / nsTimeFactor ) );\r
+  }\r
+  else\r
+    return 0;\r
+}\r
+\r
+void PGameServer::Update()\r
+{\r
+  if ( ServerSock->newConnection() )\r
+  {\r
+    int clid = Server->NewClient();\r
+    if ( clid != -1 )\r
+    {\r
+      Console->Print( GREEN, BLACK, "[Info] Gameserver: client [%i] connected", clid );\r
+      PClient *Client = Server->GetClient( clid );\r
+      if ( Client->getTCPConn() ) Console->Print( RED, BLACK, "WARNING: Client %d : TCP Socket NOT NULL before allocation.", Client->GetID() );\r
+      ConnectionTCP* tcpConn = ServerSock->getTCPConnection();\r
+      Client->setTCPConnection( tcpConn );\r
+\r
+      //ConnectionUDP* udpConn = ServerSock->getUDPConnection();\r
+      //Client->setUDPConnection(udpConn);\r
+\r
+      Console->Print( "Client address: %s", Client->GetAddress() );\r
+      ++mNumClients;\r
+\r
+      PGameState *state = new PGameState();\r
+      ClientStates.insert( std::make_pair( Client, state ) );\r
+      state->TCP.mState = PGameState::TCP::GS_CONNECTED;\r
+\r
+      // add the new connected client to the global clientmanager for further use in chat, etc...\r
+      ClientManager->addClientToList( Client );\r
+    }\r
+    else\r
+    {\r
+      Console->Print( YELLOW, BLACK, "[Notice] Gameserver: Client connection refused (server full?)" );\r
+    }\r
+  }\r
+\r
+  /*** temp check ***/\r
+  for ( PClientMap::iterator it = ClientManager->getClientListBegin(); it != ClientManager->getClientListEnd(); it++ )\r
+  {\r
+    if ( !it->second )\r
+    {\r
+      Console->Print( RED, BLACK, "PANIC: NULL Client found in ClientManager Clients Map." );\r
+    }\r
+  }\r
+  /*** end temp check ***/\r
+\r
+  for ( GameStateMap::iterator i = ClientStates.begin(); i != ClientStates.end(); )\r
+  {\r
+    PClient *Client = i->first;\r
+    PGameState *State = i->second;\r
+    // node gets erased in FinalizeClient, increment iterator now\r
+    ++i;\r
+    if ( !ProcessClient( Client, State ) )\r
+      FinalizeClient( Client, State );\r
+  }\r
+}\r
+\r
+bool PGameServer::HandleHandshake( PGameState *State, const u8 *Packet, int PacketSize )\r
+{\r
+  //static const u8 HANDSHAKE1A[6]={0xfe, 0x03, 0x00, 0x80, 0x03, 0x68};\r
+  //PGameSocket *Socket = Client->GetGameSocket();\r
+\r
+  switch ( State->TCP.mState )\r
+  {\r
+    case PGameState::TCP::GS_HANDSHAKE0 :\r
+    {\r
+      if ( PacketSize == 6 && *( u16* )&Packet[3] == 0x0080 && Packet[5] == 0x78 )\r
+      {\r
+        //FIXME: this packet seems to be unnecessary,\r
+        // although it appears in traffic dumps\r
+        // (causes clientside "Wrong protocol" errors)\r
+\r
+        //Socket->Write(HANDSHAKE1A, 6);\r
+        State->TCP.mState = PGameState::TCP::GS_AUTHENTICATE;\r
+      }\r
+      else\r
+      {\r
+        Console->Print( YELLOW, BLACK, "[Notice] Gameserver protocol error (GS_HANDSHAKE0): invalid packet [%04x]", *( u16* )&Packet[3] );\r
+        return ( false );\r
+      }\r
+\r
+      break;\r
+    }\r
+    default:\r
+    {\r
+      break;\r
+    }\r
+  }\r
+\r
+  return true;\r
+}\r
+\r
+bool PGameServer::HandleAuthenticate( PClient *Client, PGameState *State, const u8 *Packet, int PacketSize )\r
+{\r
+  ConnectionTCP *Socket = Client->getTCPConn();\r
+\r
+  if ( PacketSize > 20 && *( u16* )&Packet[3] == 0x8084 )\r
+  {\r
+    // authentication method #1\r
+    const u8 *Key = &Packet[5];  // password key\r
+    u16 ULen = *( u16* ) & Packet[16];  // username length\r
+    u16 PLen = *( u16* ) & Packet[18];  // password length\r
+    char *UserName = ( char* ) & Packet[20]; // account name\r
+    const u8 *PW = &Packet[20+ULen]; // encoded password\r
+\r
+    // Safety controls\r
+    if ( 15 + ULen + PLen > PacketSize )\r
+    {\r
+      Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): Exessive internal size fields" );\r
+      return false;\r
+    }\r
+    if ( strnlen( UserName, ULen ) == ULen )\r
+    {\r
+      Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): non-terminated username field" );\r
+      return false;\r
+    }\r
+\r
+    bool Failed = false;\r
+\r
+    PAccount Account( UserName );\r
+    if ( Account.GetID() == 0 )\r
+    {\r
+      Console->Print( YELLOW, BLACK, "[Info] Gameserver: Unknown user %s", UserName );\r
+      Failed = true;\r
+    }\r
+    else if ( !Account.Authenticate( PW, PLen, Key ) )\r
+    {\r
+      Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s': authentication failed", UserName );\r
+      Failed = true;\r
+    }\r
+\r
+    if ( !Failed )\r
+    {\r
+      Console->Print( GREEN, BLACK, "[Info] Gameserver: User '%s' authentication successful", UserName );\r
+      if ( Account.GetLevel() == PAL_BANNED )\r
+      {\r
+        Console->Print( YELLOW, BLACK, "[Info] User %s is banned, connection refused", UserName );\r
+        // TODO: ban ip for an adjustable time span?\r
+        Failed = true; // player is banned\r
+      }\r
+\r
+      if ( Account.GetLevel() == PAL_UNREGPLAYER || Account.GetLevel() == PAL_REGPLAYER )\r
+      {\r
+        if ( Server->GetNumClients() > Server->GetMaxClients() )\r
+        {\r
+          Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from user '%s'", UserName );\r
+          Failed = true; // server full\r
+        }\r
+      }\r
+    }\r
+\r
+    if ( Failed )\r
+    {\r
+      // TODO: is this packet correct here?\r
+      u8 AUTHFAILED[15] = {0xfe, 0x0c, 0x00, 0x83, 0x86, 0x05, 0x00, 0x06, 0x00, 'E', 'R',\r
+                           'R', 'O', 'R', 0\r
+                          };\r
+      // TODO: send actual reason instead of ERROR\r
+      Socket->write( AUTHFAILED, 15 );\r
+      FinalizeClientDelayed( Client, State );\r
+      State->TCP.mState = PGameState::TCP::GS_UNKNOWN;\r
+      Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s' login refused", UserName );\r
+    }\r
+    else\r
+    {\r
+      Client->LoggedIn( &Account );\r
+      u8 AUTHOK[28] = {0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,\r
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r
+                      };\r
+      *( u32* )&AUTHOK[5] = Account.GetID();\r
+      Socket->write( AUTHOK, 28 );\r
+      State->TCP.mState = PGameState::TCP::GS_GAMEDATA;\r
+      Console->Print( GREEN, BLACK, "[Info] Gameserver: User '%s' logged in", UserName );\r
+    }\r
+  }\r
+  else if ( PacketSize > 29 && *( u16* )&Packet[3] == 0x0183 )\r
+  {\r
+    // authentication method #2, sent when game starts\r
+    const u8 *Key = &Packet[13];  // password key\r
+    u16 PLen = *( u16* ) & Packet[25];  // password length\r
+    u16 ULen = *( u16* ) & Packet[27];  // username length\r
+    char *UserName = ( char* ) & Packet[29]; // account name\r
+    const u8 *PW = &Packet[29+ULen]; // encoded password\r
+\r
+    // Safety controls\r
+    if ( 24 + ULen + PLen > PacketSize )\r
+    {\r
+      Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): Exessive internal size fields" );\r
+      return false;\r
+    }\r
+    if ( strnlen( UserName, ULen ) == ULen )\r
+    {\r
+      Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): non-terminated username field" );\r
+      return false;\r
+    }\r
+\r
+    bool Failed = false;\r
+\r
+    PAccount Account( UserName );\r
+    if ( Account.GetID() == 0 )\r
+    {\r
+      Console->Print( YELLOW, BLACK, "[Info] Gameserver: Unknown user %s", UserName );\r
+      Failed = true;\r
+    }\r
+    else if ( !Account.Authenticate( PW, PLen, Key ) )\r
+    {\r
+      Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s': authentication failed", UserName );\r
+      Failed = true;\r
+    }\r
+\r
+    if ( !Failed )\r
+    {\r
+      if ( Account.GetLevel() == PAL_BANNED )\r
+      {\r
+        Console->Print( YELLOW, BLACK, "[Info] User %s is banned, connection refused", UserName );\r
+        // TODO: ban ip for an adjustable time span?\r
+        Failed = true; // player is banned\r
+      }\r
+\r
+      if ( Account.GetLevel() == PAL_UNREGPLAYER || Account.GetLevel() == PAL_REGPLAYER )\r
+      {\r
+        if ( Server->GetNumClients() > ( Server->GetMaxClients() - Server->GetGMSlots() ) )\r
+        {\r
+          Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from regular user '%s'", UserName );\r
+          Failed = true; // server full for non-GM users\r
+        }\r
+      }\r
+      else if ( Config->GetOptionInt( "require_validation" ) == 1 && Account.GetLevel() == PAL_UNREGPLAYER )\r
+      {\r
+        Console->Print( YELLOW, BLACK, "[Info] Rejecting connection from regular user '%s', account not activated yet", UserName );\r
+        Failed = true;\r
+      }\r
+      else if ( Config->GetOptionInt( "minlevel" ) > Account.GetLevel() )\r
+      {\r
+        Console->Print( YELLOW, BLACK, "[Info] Rejecting connection from regular user '%s', insufficient level %d vs %d required", UserName, Account.GetLevel(), Config->GetOptionInt( "minlevel" ) );\r
+        Failed = true;\r
+      }\r
+      else if ( Server->GetNumClients() > Server->GetMaxClients() )\r
+      {\r
+        Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from privileged user '%s'", UserName );\r
+        Failed = true; // server full even for GM users\r
+      }\r
+    }\r
+\r
+\r
+    if ( !Failed )\r
+    {\r
+      int value = *( u32* ) & Packet[21];//i think here we must read u32 instead of u8\r
+      u32 CharID = Account.GetCharIdBySlot( value );\r
+\r
+      if ( Chars->LoadChar( CharID ) )\r
+      {\r
+        Client->SetCharID( CharID );\r
+      }\r
+      else\r
+      {\r
+        Failed = true;\r
+      }\r
+    }\r
+\r
+    if ( Failed ) // something strange happened\r
+      FinalizeClientDelayed( Client, State );\r
+    else\r
+    {\r
+      Client->LoggedIn( &Account );\r
+      /*u8 AUTHOK[28]={0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,\r
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\r
+      *(u32*)&AUTHOK[5]=Account->GetID();\r
+      Socket->Write(AUTHOK, 28);*/\r
+      //Client->SetRemoteUDPAddr(*(u32*)&Packet[5], *(u16*)&Packet[9]);\r
+      State->TCP.mState = PGameState::TCP::GS_GETSTATUS;\r
+      Console->Print( "Gameserver: User '%s' entered game (%08x:%04x)", UserName, *( u32* )&Packet[5], *( u16* )&Packet[9] );\r
+      Client->SetRemoteUDPPort( *( int* )&Packet[9] );\r
+    }\r
+  }\r
+  else\r
+  {\r
+    Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): invalid packet [%04x]", *( u16* )&Packet[3] );\r
+    return ( false );\r
+  }\r
+\r
+  return ( true );\r
+}\r
+\r
+bool PGameServer::HandleGameData( PClient *Client, PGameState *State, const u8 *Packet )\r
+{\r
+  static const u8 GAMEDATA[5] = {0xfe, 0x02, 0x00, 0x87, 0x3a};\r
+  ConnectionTCP *Socket = Client->getTCPConn();\r
+\r
+  if ( *( u16* )&Packet[3] == 0x3787 )\r
+  {\r
+    Socket->write( GAMEDATA, 5 );\r
+    State->TCP.mState = PGameState::TCP::GS_REQUESTCHARS;\r
+  }\r
+  else\r
+  {\r
+    Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GAMEDATA): invalid packet [%04x]", *( u16* )&Packet[3] );\r
+    return ( false );\r
+  }\r
+\r
+  return ( true );\r
+}\r
+\r
+bool PGameServer::HandleRequestChars( PClient *Client, PGameState *State, const u8 *Packet )\r
+{\r
+  PAccount Account( Client->GetAccountID() );\r
+\r
+  if ( !Account.GetID() )\r
+    return false;\r
+\r
+  ConnectionTCP *Socket = Client->getTCPConn();\r
+\r
+  struct PCharList\r
+  {\r
+    u16 Unknown1;\r
+    u16 NumSlots;\r
+    u16 Unknown2;\r
+  } CharList;\r
+\r
+  PCharProfile CharEntry[MAX_CHARS_PER_ACCOUNT];\r
+\r
+  const int CHARBASESIZE = 28;\r
+\r
+  if ( *( u16* )&Packet[3] == 0x8284 )\r
+  {\r
+    CharList.NumSlots = MAX_CHARS_PER_ACCOUNT;\r
+    int NameLengths = 0;\r
+\r
+    for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ )\r
+    {\r
+      CharEntry[i].CharID = 0;\r
+      CharEntry[i].Type = 0;\r
+      CharEntry[i].Color0 = 0;\r
+      CharEntry[i].Location = 1;\r
+      CharEntry[i].Unknown1 = 0;\r
+      CharEntry[i].Head = 0;\r
+      CharEntry[i].Torso = 0;\r
+      CharEntry[i].Legs = 0;\r
+      CharEntry[i].Unknown3 = 1;\r
+      CharEntry[i].Unknown4 = 1;\r
+      CharEntry[i].Unknown5 = 1;\r
+      CharEntry[i].Unknown6 = 1;\r
+      CharEntry[i].Unknown7 = 1;\r
+      CharEntry[i].Unknown8 = 0;\r
+      CharEntry[i].Unknown9 = 0;\r
+      CharEntry[i].Unknown10 = 0;\r
+      CharEntry[i].Unknown11 = 0;\r
+      CharEntry[i].Unknown12 = 0;\r
+\r
+      CharEntry[i].in_use = false;\r
+    }\r
+\r
+    Chars->GetCharProfiles( Account.GetID(), CharEntry, MAX_CHARS_PER_ACCOUNT );\r
+\r
+    for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ )\r
+    {\r
+      if ( CharEntry[i].in_use )\r
+      {\r
+        NameLengths += CharEntry[i].NameLen;\r
+      }\r
+      else\r
+      {\r
+        CharEntry[i].CharID = 0xffffffff;\r
+        CharEntry[i].NameLen = 0;\r
+      }\r
+    }\r
+\r
+    u8 PacketHeader[5] = {0xfe, 0x00, 0x00, 0x83, 0x85};\r
+    *( u16* )&PacketHeader[1] = sizeof( u16 ) * 3 + ( MAX_CHARS_PER_ACCOUNT * CHARBASESIZE ) + NameLengths + 2;\r
+    Socket->write( PacketHeader, 5 );\r
+\r
+    CharList.Unknown1 = 0x0000;\r
+    CharList.Unknown2 = CHARBASESIZE;\r
+    Socket->write( CharList.Unknown1 );\r
+    Socket->write( CharList.NumSlots );\r
+    Socket->write( CharList.Unknown2 );\r
+\r
+    for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ )\r
+    {\r
+      Socket->write( CharEntry[i].CharID );\r
+      Socket->write( CharEntry[i].Type );\r
+      Socket->write( CharEntry[i].Color0 );\r
+      Socket->write( CharEntry[i].Unknown1 );\r
+      Socket->write( CharEntry[i].Head );\r
+      Socket->write( CharEntry[i].Torso );\r
+      Socket->write( CharEntry[i].Legs );\r
+      Socket->write( CharEntry[i].Location );\r
+      Socket->write( CharEntry[i].NameLen );\r
+      Socket->write( CharEntry[i].Unknown3 );\r
+      Socket->write( CharEntry[i].Unknown4 );\r
+      Socket->write( CharEntry[i].Unknown5 );\r
+      Socket->write( CharEntry[i].Unknown6 );\r
+      Socket->write( CharEntry[i].Unknown7 );\r
+      Socket->write( CharEntry[i].Unknown8 );\r
+      Socket->write( CharEntry[i].Unknown9 );\r
+      Socket->write( CharEntry[i].Unknown10 );\r
+      Socket->write( CharEntry[i].Unknown11 );\r
+      Socket->write( CharEntry[i].Unknown12 );\r
+\r
+      if ( CharEntry[i].Name.length() > 0 )\r
+      {\r
+        Socket->write( CharEntry[i].Name.c_str() );\r
+        Socket->write(( u8 )0 );\r
+      }\r
+    }\r
+\r
+    State->TCP.mState = PGameState::TCP::GS_CHARLIST;\r
+  }\r
+  else\r
+  {\r
+    Console->Print( RED, BLACK, "Gameserver protocol error (GS_REQUESTCHARS): invalid packet [%04x]", *( u16* )&Packet[3] );\r
+    return ( false );\r
+  }\r
+\r
+  return ( true );\r
+}\r
+\r
+bool PGameServer::HandleCharList( PClient *Client, PGameState *State, const u8 *Packet, int PacketSize )\r
+{\r
+  static u8 Answer[10] = {0xfe, 0x07, 0x00, 0x83, 0x86, 0, 0, 0, 0, 0};\r
+  ConnectionTCP *Socket = Client->getTCPConn();\r
+\r
+  if ( PacketSize > 9 && *( u16* )&Packet[3] == 0x8284 )\r
+  {\r
+    u8 Mode = Packet[9];\r
+\r
+    switch ( Mode )\r
+    {\r
+      case 6: // request list\r
+        return ( HandleRequestChars( Client, State, Packet ) );\r
+\r
+      case 5: // validate name\r
+      {\r
+        if ( PacketSize < 31 )\r
+          return ( false );\r
+\r
+        // check for valid name string\r
+        bool ValidString = false;\r
+\r
+        for ( int i = 30; i < PacketSize; i++ )\r
+          if ( Packet[i] == 0 )\r
+          {\r
+            ValidString = true;\r
+            break;\r
+          }\r
+\r
+        const char *Name = ( char* ) & Packet[30];\r
+        if ( ValidString )\r
+        {\r
+          ValidString = PChar::IsCharnameWellFormed( Name );\r
+        }\r
+\r
+        if ( ValidString )\r
+        {\r
+          if ( Chars->CharExist( std::string( Name ) ) )\r
+          {\r
+            ValidString = false;\r
+          }\r
+        }\r
+\r
+        if ( ValidString )\r
+          Answer[5] = 1; // ok\r
+        else\r
+          Answer[5] = 2; // 2..6 => 'char name already in use!'\r
+\r
+        // Answer[5] = 0; // => 'unknown error'\r
+        Socket->write( Answer, 10 );\r
+        return ( true );\r
+      }\r
+\r
+      case 3: // delete char\r
+      {\r
+        PAccount Acc( Client->GetAccountID() );\r
+        u8 Num = Packet[PacketSize-1];\r
+\r
+        if ( Acc.GetID() )\r
+        {\r
+          u32 CharID = Acc.GetCharIdBySlot( Num );\r
+\r
+          // Also check that char is out of game\r
+          if (( CharID != 0 ) && ( Chars->GetChar( CharID ) == NULL ) )\r
+          {\r
+            char query[100];\r
+            snprintf( query, 100, "DELETE FROM characters WHERE c_id = %d LIMIT 1", CharID );\r
+            if ( MySQL->GameQuery( query ) )\r
+              Console->Print( RED, BLACK, "[Notice] Char %d not deleted!", CharID );\r
+            else\r
+            {\r
+              Console->Print( GREEN, BLACK, "[Info] Char %d deleted!", CharID );\r
+\r
+              snprintf( query, 100, "DELETE FROM buddy_list WHERE bud_charid = %d", CharID );\r
+              if ( MySQL->GameQuery( query ) )\r
+                Console->Print( YELLOW, BLACK, "[Notice] Char %d's buddy list not removed!", CharID );\r
+\r
+              snprintf( query, 100, "DELETE FROM genrep WHERE g_charid = %d", CharID );\r
+              if ( MySQL->GameQuery( query ) )\r
+                Console->Print( YELLOW, BLACK, "[Notice] Char %d's genrep list not removed!", CharID );\r
+\r
+              snprintf( query, 100, "DELETE FROM inventory WHERE inv_charid = %d", CharID );\r
+              if ( MySQL->GameQuery( query ) )\r
+                Console->Print( YELLOW, BLACK, "[Notice] Char %d's inventory not removed!", CharID );\r
+\r
+              Appartements->DeleteCharAppartements( CharID );\r
+            }\r
+          }\r
+          else\r
+            return false;\r
+        }\r
+        return ( true );\r
+      }\r
+\r
+      case 7: // create char\r
+      {\r
+        if ( PacketSize < 64 )\r
+          return ( false );\r
+\r
+        u32 Slot = * ( u32* ) & Packet[30];\r
+        //u32 nClass =* (u32*)&Packet[34]; // Not used - indirectly redundant with Profession\r
+        u32 Profession = * ( u32* ) & Packet[38];\r
+        u32 Gender = * ( u32* ) & Packet[42];\r
+        u32 Head = * ( u32* ) & Packet[46];\r
+        u32 Torso = * ( u32* ) & Packet[50];\r
+        u32 Legs = * ( u32* ) & Packet[54];\r
+        u32 Faction = * ( u32* ) & Packet[58];\r
+        u8 NameLen = Packet[62];\r
+        u8 NZSNb = Packet[63];\r
+\r
+        char TempName[256];\r
+        std::strncpy( TempName, ( const char* )&Packet[64], NameLen );\r
+        TempName[NameLen] = 0;\r
+\r
+        Answer[5] = 2; // return error if char creation fails\r
+\r
+        if ( PChar::IsCharnameWellFormed( TempName ) )\r
+        {\r
+          // check for already used char name - should not happen though\r
+          if ( ! Chars->CharExist( std::string( TempName ) ) )\r
+          {\r
+            PAccount Acc( Client->GetAccountID() );\r
+            PChar* nChar = new PChar();\r
+\r
+            if ( nChar->CreateNewChar( Acc.GetID(), TempName, Gender, Profession, Faction,\r
+                                       Head, Torso, Legs, NZSNb, ( const char* )&Packet[64+NameLen], Slot ) )\r
+            {\r
+              Answer[5] = 1; // return success\r
+            }\r
+            delete nChar;\r
+          }\r
+        }\r
+\r
+        Socket->write( Answer, 10 );\r
+        return ( true );\r
+      }\r
+    }\r
+  }\r
+  else\r
+  {\r
+    Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_CHARLIST): invalid packet [%04x]", *( u16* )&Packet[3] );\r
+\r
+    return ( false );\r
+  }\r
+\r
+  return true;\r
+}\r
+\r
+bool PGameServer::HandleGetStatus( PClient *Client, PGameState *State, const u8 *Packet )\r
+{\r
+  ConnectionTCP *Socket = Client->getTCPConn();\r
+\r
+  if ( *( u16* )&Packet[3] == 0x3787 )\r
+  {\r
+    static const u8 STATUS[9] = {0xfe, 0x06, 0x00, 0x87, 0x3a, 0x11, 0x00, 0x00, 0x00};\r
+\r
+    Socket->write( STATUS, 9 );\r
+    State->TCP.mState = PGameState::TCP::GS_GAMEINFO;\r
+  }\r
+  else\r
+  {\r
+    Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GETSTATUS): invalid packet [%04x]", *( u16* )&Packet[3] );\r
+\r
+    return ( false );\r
+  }\r
+\r
+  return ( true );\r
+}\r
+\r
+bool PGameServer::HandleGameInfo( PClient *Client, PGameState *State, const u8 *Packet )\r
+{\r
+// Console->Print("Inside HandleGameInfo");//NEW added\r
+\r
+  static u8 GameInfo[31] = {0xfe, 0x1c, 0x00, 0x83, 0x05, // header\r
+                            0x00, 0x00, 0x00, 0x00, // account id\r
+                            0x00, 0x00, 0x00, 0x00, // char id\r
+                            0x00, 0x00, 0x00, 0x00, // udp ip\r
+                            0x00, 0x00,   // udp port\r
+                            0x00, 0x00, 0x00, 0x00, // unknown\r
+                            0x00, 0x00, 0x00, 0x00,\r
+                            0x00, 0x00, 0x00, 0x00, // session key\r
+                           };\r
+\r
+  ConnectionTCP *Socket = Client->getTCPConn();\r
+\r
+  if ( *( u16* )&Packet[3] == 0x3c87 )\r
+  {\r
+    //int PortFix = Config->GetOptionInt("debug_mode");\r
+\r
+    ConnectionUDP* udpConn = ServerSock->getUDPConnection( IPStringToDWord( Client->GetAddress() ), Client->GetRemoteUDPPort() );\r
+    Client->setUDPConnection( udpConn );\r
+    if ( !udpConn )\r
+    {\r
+      Console->Print( RED, BLACK, "Client %d: UDP port setup failed", Client->GetID() );\r
+      ClientDisconnected( Client );\r
+    }\r
+\r
+    u16 Port = Client->getUDPConn()->getPort();\r
+\r
+    if ( Port == 0 )\r
+      Console->Print( RED, BLACK, "Client->OpenUDP() failed" );\r
+\r
+\r
+    /* if(PortFix == 1) // removed, no more use\r
+    {\r
+     Port = Config->GetOptionInt("useudpport");\r
+     Console->Print(YELLOW, BLACK, "UDP Port set to non-standard for debugging!");\r
+    }; */\r
+\r
+    u32 IP;\r
+    std::string IPServerString;\r
+// use [server_nat_ip] for server if client is NOT on [no_nat_net] (and [no_nat_net]!=0)\r
+    if ( strcmp( Config->GetOption( "no_nat_net" ).c_str(), "0" ) && strncmp( Client->GetAddress(), Config->GetOption( "no_nat_net" ).c_str(), strlen( Config->GetOption( "no_nat_net" ).c_str() ) ) )\r
+    {\r
+      IPServerString = Config->GetOption( "server_nat_ip" );\r
+    }\r
+    else // else client is "local" so use [server_ip]\r
+    {\r
+      IPServerString = Config->GetOption( "server_ip" );\r
+    }\r
+    IP = IPStringToDWord( IPServerString.c_str() );\r
+//Console->Print("IP-1 %d", IP);\r
+    if ( IP == 0 )\r
+      IP = 0x0100007f;\r
+//Console->Print("IP-2 %d", IP);\r
+    *( u32* )&GameInfo[13] = IP;\r
+    *( u16* )&GameInfo[17] = Port;\r
+    Console->Print( GREEN, BLACK, "[Info] Using UDP %s:%d on server", IPServerString.c_str(), Port );\r
+\r
+    *( u32* )&GameInfo[5] = Client->GetAccountID();\r
+    *( u32* )&GameInfo[9] = Client->GetCharID();\r
+    Console->Print( GREEN, BLACK, "[Info] Serving char id :%d", Client->GetCharID() );\r
+\r
+    Socket->write( GameInfo, 31 );\r
+    Socket->flushSendBuffer();\r
+\r
+    static const u8 READY[7] = {0xfe, 0x04, 0x00, 0x83, 0x0d, 0x00, 0x00};\r
+    Socket->write( READY, 7 );\r
+\r
+    State->TCP.mState = PGameState::TCP::GS_INGAME;\r
+    State->UDP.mState = PGameState::UDP::GUS_SYNC0;\r
+//Console->Print("Sync Reset");\r
+    Client->ResetTransactionID();\r
+\r
+    // Mark char as Online\r
+    PChar *Char = Client->GetChar();\r
+    Char->SetOnlineStatus( true ); //Also using this info to check if Char may have to be saved at client disconnect\r
+    Client->ChangeCharLocation( Char->GetLocation(), true );\r
+\r
+    // hello-message from server..\r
+    /*\r
+    std::string serverName = Config->GetOption("server_name");\r
+    std::string helloMessage = "Welcome to " + serverName + " - A TinNS Neocron Server.";\r
+    char* message = (char*) helloMessage.c_str();\r
+    Chat->send(Client, CHAT_DIRECT, "System", message, false);\r
+    */\r
+\r
+    bool SendBC = false;\r
+    if ( Config->GetOptionInt( "broadcast_new" ) == 1 )\r
+    {\r
+      if ( Config->GetOptionInt( "broadcast_new_hidestaff" ) == 1 )\r
+      {\r
+        if ( Client->GetAccountLevel() > PAL_REGPLAYER )\r
+          SendBC = false;\r
+        else\r
+          SendBC = true;\r
+      }\r
+      else\r
+      {\r
+        SendBC = true;\r
+      }\r
+    }\r
+    if ( SendBC == true )\r
+    {\r
+      std::string playerName = Chars->GetChar( Client->GetCharID() )->GetName();\r
+      std::string serverName = Config->GetOption( "server_name" );\r
+      std::string helloMessage = "Hello " + playerName + "! Welcome to " + serverName + " - A TinNS Neocron Server.";\r
+      char* message = ( char* ) helloMessage.c_str();\r
+\r
+      Chat->sendOOCBroadcast( message );\r
+    }\r
+    //Console->Print("UDP Setup: %s", nlGetErrorStr(nlGetError()));\r
+  }\r
+  else\r
+  {\r
+    Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GAMEINFO): invalid packet [%04x]", *( u16* )&Packet[3] );\r
+    return ( false );\r
+  }\r
+\r
+  return ( true );\r
+}\r
+\r
+bool PGameServer::HandleGame( PClient *Client, PGameState *State )\r
+{\r
+  //PGameSocket *Socket = Client->GetGameSocket();\r
+  ConnectionUDP *UDPSocket = Client->getUDPConn();\r
+  //Console->Print("Clientadress %s", Client->GetAddress());\r
+\r
+  //int Size = 0;\r
+  PMessage* NewMsg = UDPSocket->GetMessage();\r
+  if ( NewMsg && NewMsg->GetSize() )\r
+  {\r
+\r
+    MsgDecoder->Init( NewMsg, Client, State ); // State used temporarily\r
+    do\r
+    {\r
+      if ( MsgDecoder->Analyse() )\r
+      {\r
+        if ( gDevDebug && MsgDecoder->IsTraceKnownMsg() )\r
+          Console->Print( "%s Client[%d] msg: %s", Console->ColorText( GREEN, BLACK, "[Debug]" ), Client->GetID(), MsgDecoder->GetName().c_str() );\r
+\r
+        if ( MsgDecoder->IsActionReady() )\r
+        {\r
+          MsgDecoder->DoAction();\r
+        }\r
+      }\r
+      else if ( MsgDecoder->IsError() )\r
+      {\r
+        Console->Print( YELLOW, BLACK, "[Info] Client[%d] Decoding error: %s", Client->GetID(), MsgDecoder->GetError().c_str() );\r
+      }\r
+//      else if (MsgDecoder->GetState() == DECODE_UNKNOWN)\r
+      else if ( gDevDebug && ( MsgDecoder->GetState() == DECODE_UNKNOWN ) && MsgDecoder->IsTraceUnknownMsg() )\r
+      {\r
+        Console->Print( "%s Client[%d] Unknown msg: %s", Console->ColorText( YELLOW, BLACK, "[Info]" ), Client->GetID(), MsgDecoder->GetName().c_str() );\r
+      }\r
+\r
+//      if (MsgDecoder->IsTraceDump())\r
+      if ( gDevDebug && MsgDecoder->IsTraceDump() )\r
+      {\r
+        MsgDecoder->DumpMsg();\r
+      }\r
+\r
+    }\r
+    while ( MsgDecoder->MoreSubMsg() );\r
+  }\r
+\r
+  if ( NewMsg )\r
+  {\r
+    delete NewMsg;\r
+  }\r
+\r
+  return ( true );\r
+}\r
+\r
+bool PGameServer::ProcessClient( PClient *Client, PGameState *State )\r
+{\r
+  static const u8 HANDSHAKE0A[6] = {0xfe, 0x03, 0x00, 0x80, 0x01, 0x66};\r
+\r
+  if ( !State )\r
+  {\r
+    GameStateMap::iterator node = ClientStates.find( Client );\r
+    if ( node == ClientStates.end() )\r
+      return ( false );\r
+\r
+    State = node->second;\r
+  }\r
+\r
+  ConnectionTCP *Socket = Client->getTCPConn();\r
+  if ( !Socket ) Console->Print( RED, BLACK, "PANIC: Client %d : TCP Socket is NULL !!!", Client->GetID() );\r
+  if ( State->TCP.mWaitSend && Socket->getSendBufferSize() == 0 )\r
+    return ( false );\r
+\r
+  if ( State->TCP.mState == PGameState::TCP::GS_CONNECTED )\r
+  {\r
+    Socket->write( HANDSHAKE0A, 6 );\r
+    State->TCP.mState = PGameState::TCP::GS_HANDSHAKE0;\r
+  }\r
+\r
+  if ( State->TCP.mState == PGameState::TCP::GS_INGAME )\r
+  {\r
+    return ( HandleGame( Client, State ) );\r
+  }\r
+  else\r
+  {\r
+    int PacketSize = 0;\r
+    const u8 *Packet = Socket->read( &PacketSize );\r
+\r
+    if ( PacketSize > 0 )\r
+    {\r
+      switch ( State->TCP.mState )\r
+      {\r
+        case PGameState::TCP::GS_HANDSHAKE0:\r
+          return ( HandleHandshake( State, Packet, PacketSize ) );\r
+\r
+        case PGameState::TCP::GS_AUTHENTICATE:\r
+          return ( HandleAuthenticate( Client, State, Packet, PacketSize ) );\r
+\r
+        case PGameState::TCP::GS_GAMEDATA:\r
+          return ( HandleGameData( Client, State, Packet ) );\r
+\r
+        case PGameState::TCP::GS_REQUESTCHARS:\r
+          return ( HandleRequestChars( Client, State, Packet ) );\r
+\r
+        case PGameState::TCP::GS_CHARLIST:\r
+          return ( HandleCharList( Client, State, Packet, PacketSize ) );\r
+\r
+        case PGameState::TCP::GS_GETSTATUS:\r
+          return ( HandleGetStatus( Client, State, Packet ) );\r
+\r
+        case PGameState::TCP::GS_GAMEINFO:\r
+          return ( HandleGameInfo( Client, State, Packet ) );\r
+        default:\r
+          break;\r
+      }\r
+    }\r
+  }\r
+\r
+  return ( true );\r
+}\r
+\r
+void PGameServer::ClientDisconnected( PClient *Client )\r
+{\r
+  GameStateMap::iterator node = ClientStates.find( Client );\r
+\r
+  if ( node == ClientStates.end() )\r
+    return;\r
+\r
+  PGameState *State = node->second;\r
+  FinalizeClient( Client, State );\r
+}\r
+\r
+void PGameServer::UDPStreamClosed( PClient *Client )\r
+{\r
+  GameStateMap::iterator node = ClientStates.find( Client );\r
+\r
+  if ( node == ClientStates.end() )\r
+    return;\r
+\r
+  PGameState *State = node->second;\r
+  FinalizeClient( Client, State );\r
+}\r
+\r
+void PGameServer::FinalizeClient( PClient *Client, PGameState *State )\r
+{\r
+  Console->Print( GREEN, BLACK, "[Info] Gameserver: client %s disconnected", Client->GetAddress() );\r
+\r
+  // Isnt working somehow. I assume that mID and mAccount is deleted already.\r
+  // Mark char as Offline\r
+  //PChar *Char = Chars->GetChar(Client->GetCharID());\r
+  //Char->SetOnlineStatus(false);\r
+\r
+  // delete client from clientmanager list => Do it before we remove network access\r
+  ClientManager->deleteClientFromList( Client->GetLocalID() );\r
+\r
+  Client->GameDisconnect();\r
+  ClientStates.erase( Client );\r
+  delete State;\r
+  --mNumClients;\r
+\r
+}\r
+\r
+void PGameServer::FinalizeClientDelayed( PClient *Client, PGameState *State )\r
+{\r
+  Console->Print( GREEN, BLACK, "[Info] Gameserver: client %s is about to be disconnected", Client->GetAddress() );\r
+  State->TCP.mWaitSend = true;\r
+}\r
+\r
+PGameState* PGameServer::GetClientState( PClient* nClient )\r
+{\r
+  GameStateMap::iterator node = ClientStates.find( nClient );\r
+\r
+  if ( node == ClientStates.end() )\r
+    return NULL;\r
+  else\r
+    return node->second;\r
+}\r
diff --git a/server/src/game/genreplist.cpp b/server/src/game/genreplist.cpp
new file mode 100755 (executable)
index 0000000..f2fae95
--- /dev/null
@@ -0,0 +1,185 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+  genreplist.cpp - classe for character genrep list\r
+\r
+ MODIFIED: 20 Sep 2006 Hammag\r
+ REASON: - creation\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "genreplist.h"\r
+\r
+PGenrepList::PGenrepList(u32 nOwnerCharID)\r
+{\r
+    mOwnerCharID = nOwnerCharID;\r
+    mListMaxSize = mListSize = 0;\r
+    mGenrepList = NULL;\r
+}\r
+\r
+PGenrepList::~PGenrepList()\r
+{\r
+    if (mGenrepList)\r
+        delete[] mGenrepList;\r
+}\r
+\r
+bool PGenrepList::AddGenrep(u16 nWorldID, u16 nStationID)\r
+{\r
+    char query[256];\r
+\r
+    if ((FindEntry(nWorldID, nStationID) >= mListSize) && (mListSize < 255))\r
+    {\r
+        if (mListSize == mListMaxSize)\r
+        {\r
+            IncreaseMaxSize();\r
+        }\r
+        mGenrepList[mListSize].mWorldID = nWorldID;\r
+        mGenrepList[mListSize++].mStationID = nStationID;\r
+\r
+        snprintf(query, 256, "INSERT INTO genrep (g_id,g_worldid,g_stationid,g_charid) VALUES (NULL,'%u','%u','%u');", nWorldID, nStationID, mOwnerCharID);\r
+        if ( MySQL->GameQuery(query) )\r
+        {\r
+            Console->Print(RED, BLACK, "PGenrepList::AddGenrep could not add some genrep entry in the database");\r
+            Console->Print("Query was:");\r
+            Console->Print("%s", query);\r
+            MySQL->ShowGameSQLError();\r
+            return false;\r
+        }\r
+\r
+        return true;\r
+    }\r
+    else\r
+        return false;\r
+}\r
+\r
+/*bool PGenrepList::RemoveChar(u32 nBuddyCharID)\r
+{\r
+  char query[256];\r
+  u8 rEntry, i;\r
+\r
+  if ((rEntry = FindEntry(nBuddyCharID)) < mListSize)\r
+  {\r
+    --mListSize;\r
+    for (i = rEntry; i < mListSize; i++)\r
+    {\r
+      mGenrepList[i] = mGenrepList[i+1];\r
+    }\r
+    // Remove from DB here\r
+    snprintf(query, 256, "DELETE FROM buddy_list WHERE ((bud_charid='%u') AND (bud_buddyid='%u')) LIMIT 1;", mOwnerCharID, nBuddyCharID);\r
+    if ( MySQL->GameQuery(query) )\r
+    {\r
+        Console->Print(RED, BLACK, "PBuddyList::AddChar could not add some buddylist entry in the database");\r
+        Console->Print("Query was:");\r
+        Console->Print("%s", query);\r
+        MySQL->ShowGameSQLError();\r
+        return false;\r
+    }\r
+\r
+    return true;\r
+  }\r
+  else\r
+    return false;\r
+}*/\r
+\r
+bool PGenrepList::SQLLoad()\r
+{\r
+    char query[256];\r
+    MYSQL_RES *result;\r
+    MYSQL_ROW row;\r
+    u8 EntriesNum;\r
+\r
+    snprintf(query, 256, "SELECT * FROM genrep WHERE (g_charid='%u')", mOwnerCharID);\r
+    result = MySQL->GameResQuery(query);\r
+    if(result == NULL)\r
+    {\r
+        Console->Print(RED, BLACK, "PGenrepList::SQLLoad could not load genreplist from the database");\r
+        Console->Print("Query was:");\r
+        Console->Print("%s", query);\r
+        MySQL->ShowGameSQLError();\r
+        return false;\r
+    }\r
+    //Console->Print(GREEN, BLACK, "PGenrepList::SQLLoad Loading Genrep list for char %d", mOwnerCharID);\r
+    mListSize = 0;\r
+    if((EntriesNum = mysql_num_rows(result)))\r
+    {\r
+        IncreaseMaxSize(EntriesNum);\r
+\r
+        while((row = mysql_fetch_row(result)))\r
+        {\r
+            mGenrepList[mListSize].mWorldID = atoi(row[g_worldid]);\r
+            mGenrepList[mListSize++].mStationID = atoi(row[g_stationid]);\r
+            //Console->Print(GREEN, BLACK, "PGenrepList::SQLLoad Genrep list entry %d : world %d station %d", mListSize, mGenrepList[mListSize-1].mWorldID,mGenrepList[mListSize-1].mStationID);\r
+        }\r
+    }\r
+    MySQL->FreeGameSQLResult(result);\r
+    return true;\r
+}\r
+\r
+void PGenrepList::IncreaseMaxSize(u8 nNewMax)\r
+{\r
+    u16 tmpSize;\r
+\r
+    if (!nNewMax)\r
+    {\r
+        tmpSize = mListMaxSize + GENREPLIST_ALLOC_SIZE;\r
+    }\r
+    else if (nNewMax > mListMaxSize)\r
+    {\r
+        tmpSize = nNewMax / GENREPLIST_ALLOC_SIZE;\r
+        if (nNewMax % GENREPLIST_ALLOC_SIZE)\r
+            ++tmpSize;\r
+        tmpSize *= GENREPLIST_ALLOC_SIZE;\r
+    }\r
+    else\r
+        return;\r
+\r
+    mListMaxSize = (tmpSize < 256) ? tmpSize : 255;\r
+\r
+    PGenrepEntry* tmpList = new PGenrepEntry[mListMaxSize];\r
+    if (mGenrepList)\r
+    {\r
+        if (mListSize)\r
+        {\r
+            memcpy(tmpList, mGenrepList, sizeof(PGenrepEntry) * mListSize);\r
+        }\r
+        delete[] mGenrepList;\r
+    }\r
+    mGenrepList = tmpList;\r
+}\r
+\r
+u8 PGenrepList::FindEntry(u16 nWorldID, u16 nStationID)\r
+{\r
+    u8 i = 255;\r
+\r
+    if (mGenrepList)\r
+    {\r
+        for (i = 0; i < mListSize; i++)\r
+        {\r
+            if ((mGenrepList[i].mWorldID == nWorldID) && (mGenrepList[i].mStationID == nStationID))\r
+                break;\r
+        }\r
+    }\r
+\r
+    return i;\r
+}\r
diff --git a/server/src/game/globals.cpp b/server/src/game/globals.cpp
new file mode 100644 (file)
index 0000000..fde68e8
--- /dev/null
@@ -0,0 +1,252 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+ globals.cpp\r
+\r
+ MODIFIED: 12 September 2005 Akiko\r
+ REASON: - exchanged Pretender strings by TinNS\r
+    MODIFIED: 16 Dec 2005 bakkdoor\r
+ REASON: - Added global ClientManager and Chat Interface\r
+ MODIFIED: 22 Dec 2005 Namikon\r
+ REASON: - Added GPL\r
+ MODIFIED: 25 Dec 2005 Namikon\r
+ REASON: - Added MySQL Support\r
+            - Fixed ShutdownTinns (Wont cause segmentation fault anymore)\r
+    MODIFIED: 06 Jan 2006 Namikon\r
+    REASON: - Added color to console outputs\r
+            - Added shiny and colored copyright box :D\r
+    MODIFIED: 22 Jul 2006 Hammag\r
+    REASON: - Added Server NOT NULL check to avoid segfault when shuting down during startup\r
+    MODIFIED: 27 Aug 2006 Hammag\r
+    REASON: - Implemented shared Config class use and config template to load conf.\r
+                Added gameserver configtemplate.h include,\r
+                Added new required parameters to Config->LoadOptions()\r
+    MODIFIED: 02 Oct 2006 Hammag\r
+    REASON: - Added gDevDebug global flag to control development debug outputs (flagged messaged, dump-flagged messes, dev console->print)\r
+\r
+    TODO:   - Get logfile name from config file\r
+*/\r
+\r
+#include "main.h"\r
+#include "configtemplate.h"\r
+#include "isc.h"\r
+\r
+#include "msgbuilder.h"\r
+#include "worlds.h"\r
+#include "appartements.h"\r
+#include "npc.h"\r
+#include "subway.h"\r
+#include "terminal.h"\r
+\r
+#include "version.h"\r
+const char ServerVersion[] = TINNS_GAME_VERSION;\r
+const char SVNRevision[] = TINNS_SVN_REVISION;\r
+\r
+PVehicles *Vehicles = 0;\r
+PMySQL *MySQL = 0;\r
+PConsole *Console = 0;\r
+PServer *Server = 0;\r
+PConfig *Config = 0;\r
+PConfig *CmdAccess = 0;\r
+PGameDefs *GameDefs = 0;\r
+PChars *Chars = 0;\r
+PFileSystem *Filesystem = 0;\r
+PGameServer *GameServer = 0;\r
+ServerSocket *ServerSock = 0;\r
+PMsgBuilder *MsgBuilder = 0;\r
+PWorlds *Worlds = 0;\r
+PAppartements* Appartements = 0;\r
+PWorldActors* WorldActors = 0;\r
+PNPCManager* NPCManager = 0;\r
+PSubway* Subway = 0;\r
+PTerminal* Terminal = 0;\r
+PLuaEngine* LuaEngine = 0;
+POutpost* Outposts = 0;
+PMultiPart* MultiPartHandler = 0;\r
+\r
+//multi-user chat implementation\r
+PClientManager *ClientManager = 0;\r
+PChat *Chat = 0;\r
+PCommands *GameCommands = 0;\r
+\r
+PISC *ISC = 0;\r
+\r
+const std::string EmptyString;\r
+\r
+// Development debug output control (set by config option dev_debug)\r
+bool gDevDebug = false;\r
+\r
+bool InitTinNS()\r
+{\r
+    Console = new PConsole("log/gameserver.log"); // Make that from config file !!!\r
+    Console->Print("Starting TinNS Gameserver");\r
+    Console->Print(WHITE, BLUE, "/-------------------------------------------------------------------\\");\r
+    Console->Print(WHITE, BLUE, "|               TinNS (TinNS is not a Neocron Server)               |");\r
+    Console->Print(WHITE, BLUE, "|            Copyright (C) 2005 Linux Addicted Community            |");\r
+    Console->Print(WHITE, BLUE, "|                  maintainer Akiko <akiko@gmx.org>                 |");\r
+    Console->Print(WHITE, BLUE, "|             ==========================================            |");\r
+    Console->Print(WHITE, BLUE, "|      Head coders:                   The packet analyzing team:    |");\r
+    Console->Print(WHITE, BLUE, "|      - Akiko                         - MaxxJag                    |");\r
+    Console->Print(WHITE, BLUE, "|      - bakkdoor                      - Sting                      |");\r
+    Console->Print(WHITE, BLUE, "|      - Namikon                       - Balm                       |");\r
+    Console->Print(WHITE, BLUE, "|      - Hammag                                                     |");\r
+    Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");\r
+    Console->Print(WHITE, BLUE, "|  This project would'nt be at its current stage without the help   |");\r
+    Console->Print(WHITE, BLUE, "|        from the NeoPolis team, special thanks to you guys!        |");\r
+    Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");\r
+    Console->Print(WHITE, BLUE, "|  This project is under GPL, see any source file for more details  |");\r
+    Console->Print(WHITE, BLUE, "\\-------------------------------------------------------------------/");\r
+\r
+    //char svnrev[10];\r
+    //GetSVNRev(svnrev);\r
+    Console->LPrint("You are running TinNS Gameserver version");\r
+    Console->LPrint(GREEN, BLACK, " %s", ServerVersion);\r
+    Console->LPrint(WHITE, BLACK, " - SVN Rev");\r
+    Console->LPrint(GREEN, BLACK, " %s", SVNRevision);\r
+    Console->LClose();\r
+\r
+    Config = new PConfig();\r
+    if(!Config->LoadOptions(GameConfigTemplate, "./conf/gameserver.conf"))\r
+        return false; //Shutdown();\r
+\r
+    CmdAccess = new PConfig();\r
+    if(!CmdAccess->LoadOptions(CommandsTemplate, "./conf/commands.conf"))\r
+        return false; //Shutdown();\r
+\r
+    gDevDebug = Config->GetOptionInt("dev_debug");\r
+    std::string MyName = Config->GetOption("server_name");\r
+    std::string IP = Config->GetOption("server_ip");\r
+    char myCname[100], myCip[100];\r
+    strncpy (myCname, Console->ColorText(CYAN, BLACK, MyName.c_str()), 100);\r
+    strncpy (myCip, Console->ColorText(CYAN, BLACK, IP.c_str()), 100);\r
+    Console->Print("My name is '%s', and my address is %s", myCname, myCip);\r
+\r
+    MySQL = new PMySQL();\r
+    if(MySQL->Connect() == false)\r
+        return false; //Shutdown();\r
+\r
+    Filesystem = new PFileSystem();\r
+\r
+    GameDefs = new PGameDefs();\r
+    GameDefs->Init();\r
+\r
+    Worlds = new PWorlds();\r
+    Worlds->LoadWorlds();\r
+\r
+    WorldActors = new PWorldActors();\r
+    LuaEngine = new PLuaEngine();\r
+\r
+    NPCManager = new PNPCManager();\r
+    Appartements = new PAppartements;\r
+    Subway = new PSubway;\r
+\r
+    if (!PAccount::SetUsernameRegexFilter(Config->GetOption("username_filter").c_str()))\r
+    {\r
+      Console->Print("%s Could not creat username_filter PCRE '%s'", Console->ColorText(RED, BLACK, "[Error]"), Config->GetOption("username_filter").c_str());\r
+      return false;\r
+    }\r
+    if(!PAccount::SetPasswordRegexFilter(Config->GetOption("password_filter").c_str()))\r
+    {\r
+      Console->Print("%s Could not creat password_filter PCRE '%s'", Console->ColorText(RED, BLACK, "[Error]"), Config->GetOption("password_filter").c_str());\r
+      return false;\r
+    }\r
+\r
+    if (!PChar::SetCharnameRegexFilter(Config->GetOption("charname_filter").c_str()))\r
+    {\r
+      Console->Print("%s Could not creat charname_filter PCRE '%s'", Console->ColorText(RED, BLACK, "[Error]"), Config->GetOption("charname_filter").c_str());\r
+      return false;\r
+    }\r
+    Chars = new PChars();\r
+\r
+    ServerSock = new ServerSocket();\r
+    Server = new PServer();\r
+    GameServer = new PGameServer();\r
+    MsgBuilder = new PMsgBuilder();\r
+\r
+    Vehicles = new PVehicles();\r
+\r
+    ClientManager = new PClientManager();\r
+    Chat = new PChat();\r
+    GameCommands = new PCommands();\r
+\r
+    ISC = new PISC();\r
+    Terminal = new PTerminal();\r
+
+    Outposts = new POutpost();
+
+    MultiPartHandler = new PMultiPart();
+\r
+    return true;\r
+}\r
+\r
+void Shutdown()\r
+{
+    if(MultiPartHandler)
+        delete MultiPartHandler;
+    if(Outposts)
+        delete Outposts;\r
+    if(LuaEngine)\r
+        delete LuaEngine;\r
+    if(Terminal)\r
+        delete Terminal;\r
+    if(WorldActors)\r
+        delete WorldActors;\r
+    if(NPCManager)\r
+        delete NPCManager;\r
+    if(ISC)\r
+    {\r
+        ISC->Shutdown();\r
+        delete ISC;\r
+    }\r
+    if(Server)\r
+        Server->Shutdown();\r
+    if(GameServer)\r
+        delete GameServer;\r
+    if(Chat)\r
+        delete Chat;\r
+    if(Server)\r
+        delete Server;\r
+    if(Filesystem)\r
+        delete Filesystem;\r
+    if(GameDefs)\r
+        delete GameDefs;\r
+    if(Worlds)\r
+    {\r
+        Worlds->Shutdown();\r
+        delete Worlds;\r
+    }\r
+    if(Subway)\r
+        delete Subway;\r
+    if(Chars)\r
+        delete Chars;\r
+    if(MySQL)\r
+        delete MySQL;\r
+    if(Config)\r
+        delete Config;\r
+    if(Console)\r
+        delete Console;\r
+    if(ServerSock)\r
+        delete ServerSock;\r
+\r
+    exit(0);\r
+}\r
+\r
diff --git a/server/src/game/include/accounts.h b/server/src/game/include/accounts.h
new file mode 100644 (file)
index 0000000..1acacb0
--- /dev/null
@@ -0,0 +1,142 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       accounts.h\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+       MODIFIED: 26 Dec 2005 Namikon\r
+       REASON: - Added load/save functions for SQL DB\r
+       MODIFIED: 01 Jan 2005 Namikon\r
+       REASON: - Added bool var for ingame debug outputs for administrators\r
+       MODIFIED: 06 Jan 2005 Namikon\r
+       REASON: - Added SetBannedStatus(<unix timestamp>) to ban/unban an account (use SetBannedStatus(0) to unban a player)\r
+*/\r
+\r
+#ifndef ACCOUNTS_H\r
+#define ACCOUNTS_H\r
+\r
+#ifdef _MSC_VER\r
+       #pragma once\r
+#endif\r
+\r
+#include "regex++.h"\r
+\r
+/*\r
+0 = unregistered user\r
+1 = Registered user\r
+30 = volunteer\r
+50 = GM\r
+100 = Admin\r
+*/\r
+\r
+// New way of AccountLevel handling:\r
+// Every level is possible, the following values are only edge values. We need a bit control about that\r
+#define PAL_BANNED -1\r
+#define PAL_UNREGPLAYER 0\r
+#define PAL_REGPLAYER 1\r
+#define PAL_VOLUNTEER 30 // Special Rank: 50/50\r
+#define PAL_GM 50       // Special Rank: 120/120\r
+#define PAL_ADMIN 100   // Special Rank: 127/127\r
+\r
+// Max number of char slots per account\r
+#define MAX_CHARS_PER_ACCOUNT  4\r
+\r
+/*\r
+0 = Offline\r
+1 = Online\r
+2 = Banned\r
+*/\r
+\r
+enum PAccountStatus\r
+{\r
+    PAS_OFFLINE = 0,\r
+    PAS_ONLINE = 1,\r
+    PAS_BANNED = 2\r
+};\r
+\r
+class PAccount\r
+{\r
+       private :\r
+    // SQL Layout\r
+    enum {\r
+        a_id,\r
+        a_username,\r
+        a_password,\r
+        a_priv,\r
+        a_status,\r
+        a_bandate\r
+    };\r
+\r
+    // static members\r
+         static RegEx* mUsernameRegexFilter;\r
+         static RegEx* mPasswordRegexFilter;\r
+\r
+         // instance members\r
+         u32 mID;\r
+         std::string mName;\r
+         std::string mPassword;\r
+    int mLevel;\r
+    PAccountStatus mStatus;\r
+    std::time_t mBannedUntil;\r
+\r
+    bool LoadFromQuery(char* query);\r
+    bool DecodePassword(const u8* PasswordData, int PassLen, const u8 *Key, char* ClearPassword);\r
+\r
+       public :\r
+         PAccount();\r
+         PAccount(const u32 AccountId);\r
+         PAccount(const char *Username);\r
+\r
+         static bool SetUsernameRegexFilter(const char* RegexStr);\r
+               static bool SetPasswordRegexFilter(const char* RegexStr);\r
+               static bool IsUsernameWellFormed(const char *Username);\r
+               static bool IsPasswordWellFormed(const char *Password);\r
+\r
+               inline u32 GetID() const { return mID; }\r
+               bool SetName(const std::string &Pass);\r
+               inline const std::string &GetName() const { return mName; }\r
+               bool SetPassword(const std::string &Pass);\r
+               bool SetPasswordEncoded(const u8* PasswordData, int PassLen, const u8 *Key);\r
+               inline const std::string &GetPassword() const { return mPassword; }\r
+    bool SetLevel(int newLevel);\r
+               inline int GetLevel() const { return mLevel; }\r
+               std::string GetLevelString() const;\r
+    bool SetStatus(PAccountStatus Status);\r
+               inline PAccountStatus GetStatus() const { return mStatus; }\r
+               bool SetBannedUntilTime(std::time_t BannedUntil);\r
+    inline bool IsBanned() const { return (mBannedUntil > std::time(NULL)); }\r
+    std::string GetBannedTime() const;\r
+\r
+               bool Authenticate(const u8* PasswordData, int PassLen, const u8 *Key);\r
+               bool Authenticate(const char *Password) const;\r
+\r
+               bool Create();\r
+    bool Save(bool CreateMode = false);\r
+\r
+    u32 GetCharIdBySlot(const u32 SlotId);\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/include/appartements.h b/server/src/game/include/appartements.h
new file mode 100644 (file)
index 0000000..7978c5d
--- /dev/null
@@ -0,0 +1,53 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+  appartements.h - appartements class\r
+\r
+       MODIFIED: 20 Nov 2006 Hammag\r
+       REASON: - creation\r
+       \r
+*/\r
+\r
+#ifndef APPARTEMENTS_H\r
+#define APPARTEMENTS_H\r
+\r
+class PChar;\r
+\r
+class PAppartements\r
+{\r
+  private:\r
+    \r
+  public:\r
+    PAppartements();\r
+    //~PAppartements();\r
+    \r
+    u32 CreateBaseAppartement(u32 nCharID, std::string nPassword, u8 nFactionID);\r
+    void DeleteCharAppartements(u32 nCharID);\r
+    bool CanFreelyEnter(PChar* nChar, u32 nLocation);\r
+    int GetAptID(unsigned int AptLoc, const u8 *pass);\r
+    int GetAptType(int AptID);\r
+    int GetAptOwner(int loc);\r
+    int GetAptLocation(int loc);\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/buddylist.h b/server/src/game/include/buddylist.h
new file mode 100644 (file)
index 0000000..5a1f464
--- /dev/null
@@ -0,0 +1,67 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+  buddylist.h - classe for chat buddylist\r
+\r
+       MODIFIED: 19 Sep 2006 Hammag\r
+       REASON: - creation\r
+\r
+*/\r
+\r
+#ifndef BUDDYLIST_H\r
+#define BUDDYLIST_H\r
+\r
+#define BUDDYLIST_ALLOC_SIZE 4 // atomicity of list entries allocation\r
+\r
+class PBuddyList\r
+{\r
+  private:\r
+    enum { // buddy_list DB Table fields\r
+        bud_id = 0,\r
+        bud_charid,\r
+        bud_buddyid\r
+    };\r
+\r
+    u32 mOwnerCharID;\r
+    u8 mListMaxSize;\r
+    u8 mListSize;\r
+    u32* mCharIDList;\r
+\r
+    void IncreaseMaxSize(u8 nNewMax = 0);\r
+    u8 FindEntry(u32 CharID);\r
+\r
+  public:\r
+    PBuddyList(u32 nOwnerCharID);\r
+    ~PBuddyList();\r
+    bool AddChar(u32 nBuddyCharID);\r
+    bool RemoveChar(u32 nBuddyCharID);\r
+    inline u8 Count() { return mListSize; }\r
+    u16 GetListDataSize() { return (sizeof(u32) * mListSize); }\r
+    const void* GetListData() { return (const void*)mCharIDList; }\r
+    bool SQLLoad();\r
+\r
+    bool IsInBuddy(u32 CharID);\r
+//    bool SQLSave();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/chars.h b/server/src/game/include/chars.h
new file mode 100644 (file)
index 0000000..428591a
--- /dev/null
@@ -0,0 +1,389 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+ chars.h - this is the main file with the main function\r
+\r
+ Authors:\r
+ - Namikon\r
+\r
+ MODIFIED: 22 Dec 2005 Namikon\r
+ REASON: - Added GPL\r
+ MODIFIED: 01 Jan 2006 Namikon\r
+ REASON: - Added SQLLoad() function to PChar and PChars\r
+            - Added enum for charlist SQL Database\r
+            - Added IsOnline var and inline func for Onlinestatus of char\r
+  MODIFIED: 26 Jul 2006 Namikon\r
+ REASON:   - Added Health/MaxHealth, idem for Mana & Stamin\r
+  TODO:     - fix real current Health vs MaxHealth, also in char load/save\r
+\r
+  MODIFIED: 03 Oct 2006 Hammag\r
+ REASON:   - PChar::CreateNewChar() and moved effective char creation from PChars to PChar\r
+           - added PChar::SQLDelete()\r
+             This method is put here because we want the char to be loaded when deleted from DB to avoid\r
+             any player to use it at the same time.\r
+           - added use of auto_save_period config option in PChars::update()\r
+\r
+*/\r
+\r
+#ifndef CHARS_H\r
+#define CHARS_H\r
+\r
+#ifdef _MSC_VER\r
+#pragma once\r
+#endif\r
+\r
+#define MAXCASH 1000000000\r
+\r
+#include "inventory.h"\r
+#include "buddylist.h"\r
+#include "genreplist.h"\r
+#include "regex++.h"\r
+class PVhcAccessRequestList;\r
+\r
+enum PSeatType\r
+{\r
+  seat_none = 0,\r
+  seat_chair,\r
+  seat_subway,\r
+  seat_vhc\r
+};\r
+\r
+class PCharCoordinates\r
+{\r
+  public:\r
+    u16 mY;     // Y-Position in world // Y increases when going East\r
+    u16 mZ;     // Z-Position in world // Z increases when going up\r
+    u16 mX;     // X-Position in world // X increases when going South\r
+    u8 mUD;     // Up - Mid - Down (d6 - 80 - 2a)\r
+    u8 mLR;     // Compass direction (S..E..N..W..S [0-45-90-135-179])\r
+    u8 mAct;    // Last user action state\r
+    u8 mUnknown;// sometime sent by client with value != 0 (usual case)\r
+    // mAct:\r
+    // 0x00 NC has no focus (player alt+tab'ed out)\r
+    // 0x04 Char on ground/dead   00000100\r
+    // 0x20 Char does nothing     00100000\r
+    // 0x22 kneeing               00100010\r
+    // 0x28 left step             00101000\r
+    // 0x30 right step            00110000\r
+    // 0x40 walking (not running) 01000000 // Seems to mean Running ? - to be verfied, with default walk/run mode !!!\r
+    // 0x60 forward               01100000\r
+    // 0xA0 backward              10100000\r
+    // bits:                      BFWRL.K.\r
+\r
+    u8 mJumpingState;\r
+\r
+    //inline PCharCoordinates() { mX = mY = mZ = mUD = mLR = mAct = mUnknown = mJumpingState = 0;}\r
+    void SetPosition( u16 nY, u16 nZ, u16 nX, u8 nUD = 0x80, u8 nLR = 0 );\r
+    void SetInterpolate( PCharCoordinates& Pos1, PCharCoordinates& Pos2, f32 nCoef );\r
+\r
+    //Temp\r
+    u16 minPos[3];\r
+    u16 maxPos[3];\r
+    inline PCharCoordinates() { mX = mY = mZ = mUD = mLR = mAct = mUnknown = mJumpingState = 0; for(int i=0; i<3; ++i) { minPos[i] = 0xffff; maxPos[i] = 0; } }\r
+};\r
+\r
+class PChar\r
+{\r
+  private :\r
+    // static members\r
+    static RegEx* mCharnameRegexFilter;\r
+
+    // instance members\r
+    u32 mID;\r
+    u32 mAccount;\r
+    u8 mSlot;\r
+    std::string mName;\r
+    u32 mGender;\r
+    u32 mClass;\r
+    //u32 mType; // Removed that and only keep GetType()\r
+    u32 mProfession;\r
+    u32 mFaction;\r
+    u32 mRealHead;  // Base Skin elements, in complement of (computed) mType\r
+    u32 mRealTorso; // " Head shouldn't be changeable, except in case of surgery !!!\r
+    u32 mRealLegs;  // "\r
+    u32 mSkin;  // Current Skin elements. *** Not saved in DB atm ***\r
+    u32 mHead;  // "\r
+    u32 mTorso; // "\r
+    u32 mLegs;  // "\r
+    u8 mHeadColor;  // "\r
+    u8 mTorsoColor; // "\r
+    u8 mLegsColor;  // "\r
+    u8 mHeadDarkness;  // " // 0=Bright, 255=dark\r
+    u8 mTorsoDarkness; // "\r
+    u8 mLegsDarkness;  // "\r
+    // Skin scale factor setting remain to discover, provided they are somewhere for player chars ...\r
+\r
+    bool mLocationLeased; // temp until char on-demand load/unload\r
+    u32 mLocation;\r
+    u32 mCash;\r
+    u32 mStartApt; // set same as PrimaryApt atm\r
+    u32 mPrimaryApt;\r
+\r
+    // not saved in DB atm\r
+    PSeatType mSeatInUseType;\r
+    u32 mSeatInUseObjectId;\r
+    u8 mSeatInUseSeatId;\r
+    PVhcAccessRequestList* mVhcAccessRequestList;\r
+\r
+    PContainer* mContainerInExclusiveUse;\r
+\r
+    u16 mHealth;\r
+    u16 mMana;\r
+    u16 mStamina;\r
+\r
+    s8 mSoullight;\r
+    u8 mCombatRank; // *** Not got/saved from DB atm ***\r
+    u8 mSynaptic; // *** Not got/saved from DB atm ***\r
+    bool mIsDead; // *** Not got/saved from DB atm ***\r
+\r
+    // Only one body effect supported atm. Should be extended later to multiple effects\r
+    u8 mBodyEffect; // *** Not got/saved from DB atm ***\r
+    u8 mBodyEffectDensity; // *** Not got/saved from DB atm ***\r
+\r
+    u8 mSpeedOverride; // a hack to control move speed. Not saved in DB\r
+\r
+    u32 mDirectCharID; // for Direct Chat // *** Not got/saved from DB atm ***\r
+    PBuddyList* mBuddyList; // For Buddy list Chat\r
+    u32 mActiveChatChannels; // Active chat channels flags // *** Not got/saved from DB atm ***\r
+\r
+    PGenrepList* mGenrepList; // Character's GR list\r
+\r
+    u8 mQuickBeltActiveSlot; // QB SlotID of item "in hand", or INV_WORN_QB_HAND or INV_WORN_QB_NONE\r
+\r
+    u16 mLookingAt;  // Zone charID of currently targeted player\r
+    std::time_t mLookAtTimestamp; // Lifetimer of lookat var\r
+    u32 mLastUsedWorldObjectId; // Last world object clicked on
+
+    u8 mClanLevel; // 1-15
+    u16 mClanID;\r
+\r
+    bool mIsOnline;\r
+    bool mDirtyFlag;\r
+\r
+    bool mShunned;\r
+    bool mJailed;\r
+\r
+    u32 mDialogNPC; // NPCID the player talks to\r
+    u16 mCurrentDialogNode; // Node in .lua file we're at right now\r
+\r
+    class PInventory mInventory;\r
+\r
+  protected :\r
+    friend class PChars;\r
+    inline void SetID( u32 ID ) { mID = ID; }\r
+    inline void SetAccount( u32 Account ) { mAccount = Account; }\r
+    inline void SetCharSlot( u8 Slot ) { if ( Slot < 4 ) mSlot = Slot;} // TODO: set max slot according to server config\r
+    inline void SetName( const std::string &Name ) { mName = Name; }\r
+    inline void SetGender( u32 Gender ) { mGender = Gender; }\r
+    void SetProfession( u32 Profession );\r
+    //inline void SetClass(u32 nClass) { mClass = nClass; } // mClass is defined by setting Profession\r
+    //inline void SetType(u32 Type) { mType = Type; } // Removed. Type is computed from Gender & Profession (??? is it not Gender + Class ???)\r
+    inline void SetFaction( u32 Faction ) { mFaction = Faction; }\r
+    //inline void SetModel(u32 Model) { mModel = Model; } // Inhibited for the moment. Base model is deduced from from Gender & Class (Profession)\r
+    void SetRealLook( u32 nHead, u32 nTorso, u32 nLegs );\r
+    void SetBaseSkills();\r
+    void SetBaseSubskills( u8 NZSNb, const char* NonZeroSubskills );\r
+    void SetBaseInventory();\r
+\r
+    bool SQLCreate();\r
+\r
+  public :\r
+    PChar();\r
+    ~PChar();\r
+\r
+    static bool SetCharnameRegexFilter( const char* RegexStr );\r
+    static bool IsCharnameWellFormed( const char *Username );\r
+\r
+    PSkillHandler *Skill;\r
+    PCharCoordinates Coords;\r
+\r
+    void SetCurrentLook( u32 nSkin, u32 nHead = 0, u32 nTorso = 0, u32 nLegs = 0 );\r
+    void SetCurrentLookFromCharType( u32 nType );\r
+    void ResetCurrentLook();\r
+\r
+    void SetCurrentBodyColor( u8 nHeadColor, u8 nTorsoColor, u8 nLegsColor, u8 nHeadDarkness = 0, u8 nTorsoDarkness = 0, u8 nLegsDarkness = 0 );\r
+    inline void SetBodyEffect( u8 nEffect, u8 nDensity = 0 ) { mBodyEffect = nEffect; mBodyEffectDensity = nDensity; }\r
+    inline void SetSpeedOverride( u8 nSpeed = 255 ) { mSpeedOverride = nSpeed; }\r
+\r
+    void SetLookingAt( u16 nLocalCharID );\r
+    u16 GetLookingAt( u16 nMaxDelaySec = 1 );\r
+    inline void SetLastUsedObject ( u32 nRawItemId ) { mLastUsedWorldObjectId = nRawItemId; }\r
+    inline u32 GetLastUsedObject () const { return mLastUsedWorldObjectId; }\r
+\r
+    inline PInventory* GetInventory() { return &mInventory; }\r
+    inline u32 GetID() const { return mID; }\r
+    inline u32 GetAccount() const { return mAccount; }\r
+    inline const std::string &GetName() const { return mName; }\r
+    inline u32 GetGender() const { return mGender; }\r
+    inline u32 GetClass() const { return mClass; }\r
+    inline u32 GetType() const { return 2 * mClass + mGender; }\r
+    u32 GetSkinFromCharType( u32 nType );\r
+    void GetRealLook( u32 &nSkin, u32 &nHead, u32 &nTorso, u32 &nLegs );\r
+    void GetCurrentLook( u32 &nSkin, u32 &nHead, u32 &nTorso, u32 &nLegs );\r
+    inline void GetBodyEffect( u8 &nEffect, u8 &nDensity ) { nEffect = mBodyEffect; nDensity = mBodyEffectDensity; }\r
+\r
+    inline u8 GetQuickBeltActiveSlot() { return mQuickBeltActiveSlot; }\r
+    bool SetQuickBeltActiveSlot( u8 nSlotID );\r
+\r
+    void GetCurrentBodyColor( u8 &nHeadColor, u8 &nTorsoColor, u8 &nLegsColor, u8 &nHeadDarkness, u8 &nTorsoDarkness, u8 &nLegsDarkness );\r
+    inline u8 GetSpeedOverride() { return mSpeedOverride; }\r
+    inline u32 GetBaseModel();\r
+    inline u32 GetProfession() const { return mProfession; }\r
+    inline u16 GetMaxHealth() { return mHealth; }\r
+    inline u16 GetMaxMana() { return mMana; }\r
+    inline u16 GetMaxStamina() { return mStamina; }\r
+    inline u16 GetHealth() { return mHealth; }\r
+    inline u16 GetMana() { return mMana; }\r
+    inline u16 GetStamina() { return mStamina; }\r
+    inline u32 GetFaction() const { return mFaction; }\r
+    inline u32 GetLocation() const { return mLocation; }\r
+\r
+    inline u32 GetCash() const { return mCash; }\r
+    u32 SetCash( u32 nCash );  // Does return the new cashvalue, NO udpmessage is sent out!!\r
+    u32 AddCash( u32 nAmount );\r
+    u32 TakeCash( u32 nAmount );\r
+\r
+    inline u32 GetBaseApartment() const { return mPrimaryApt; }\r
+\r
+    inline void SetJail( bool val ) { mJailed = val; };\r
+    inline void SetShun( bool val ) { mShunned = val; };\r
+\r
+    inline bool IsJailed() { return mJailed; };\r
+    inline bool IsShunned() { return mShunned; };\r
+\r
+    inline void SetDialogNPC( u32 nNPC ) { mDialogNPC = nNPC; };\r
+    inline u32 GetDialogNPC() const { return mDialogNPC; };\r
+\r
+    inline void SetDialogNode( u16 nNode ) { mCurrentDialogNode = nNode; };\r
+    inline u16 GetDialogNode() const { return mCurrentDialogNode; };\r
+
+    inline u8 GetClanLevel() const { return mClanLevel; };
+    inline u16 GetClan() const { return mClanID; };
+    void LoadClanLevel();\r
+\r
+    inline s8 GetSoullight() const { return mSoullight; }\r
+    u8 GetMainRank();\r
+    u8 GetCombatRank();\r
+    inline u8 GetSynaptic() const { return mSynaptic; }\r
+    inline bool IsDead() const { return mIsDead; }\r
+\r
+    inline bool SetDirectChat( u32 nBuddyCharID ) { mDirectCharID = nBuddyCharID; return true; }\r
+    inline u32 GetDirectChat() { return mDirectCharID; }\r
+    inline void SetActiveChannels( u32 nChannels ) { mActiveChatChannels = nChannels; }\r
+    inline u32 GetActiveChannels() { return mActiveChatChannels; }\r
+\r
+    inline bool AddBuddy( u32 nBuddyCharID ) { return mBuddyList->AddChar( nBuddyCharID ); }\r
+    inline bool RemoveBuddy( u32 nBuddyCharID ) { return mBuddyList->RemoveChar( nBuddyCharID ); }\r
+    inline u16 GetBuddyListDataSize() { return mBuddyList->GetListDataSize(); }\r
+    inline const void* GetBuddyListData() { return mBuddyList->GetListData(); }\r
+    inline u8 GetBuddyCount() { return mBuddyList->Count(); }\r
+    inline bool IsBuddy( u32 CharID ) { return mBuddyList->IsInBuddy( CharID ); };\r
+\r
+    inline bool AddGenrep( u16 nWorldID, u16 nStationID ) { return mGenrepList->AddGenrep( nWorldID, nStationID ); }\r
+    inline u16 GetGenrepListDataSize() { return mGenrepList->GetListDataSize(); }\r
+    inline const void* GetGenrepListData() { return mGenrepList->GetListData(); }\r
+    inline u8 GetGenrepCount() { return mGenrepList->Count(); }\r
+\r
+    inline bool IsDirty() const { return mDirtyFlag; }\r
+    inline bool IsAnyDirty() const { return mDirtyFlag || mInventory.IsDirty(); }\r
+    inline bool IsOnline() { return mIsOnline; }\r
+    void SetOnlineStatus( bool IsOnline );\r
+\r
+    bool CreateNewChar( u32 Account, const std::string &Name, u32 Gender, u32 Profession, u32 Faction,\r
+                        u32 Head, u32 Torso, u32 Legs, u8 NZSNb, const char *NonZeroSubskills, u32 Slot );\r
+    bool SQLLoad( int CharID );\r
+    bool SQLSave();\r
+    inline bool SQLSaveFull() { return SQLSave() && mInventory.SQLSave(); }\r
+    bool SQLDelete(); // not implemented yet\r
+\r
+    inline void SetLocation( u32 Location ) { mLocation = Location; }\r
+    inline void SetDirtyFlag( bool Dirty = true ) { mDirtyFlag = Dirty; }\r
+\r
+    // temp until char on-demand load/unload\r
+    inline void SetLocationLeased( bool nState = true ) { mLocationLeased = nState; }\r
+    inline bool GetLocationLeased() { return mLocationLeased; }\r
+\r
+    PSeatType GetSeatInUse( u32* nObjectId = NULL, u8* nSeatId = NULL );\r
+    void SetSeatInUse( PSeatType nSeatType, u32 nObjectId = 0, u8 nSeatId = 0 );\r
+\r
+    PVhcAccessRequestList* GetVhcAccessRequestList();\r
+\r
+    inline PContainer* GetContainerInExclusiveUse() { return mContainerInExclusiveUse; }\r
+    inline void SetContainerInExclusiveUse( PContainer* nContainer ) { mContainerInExclusiveUse = nContainer; }\r
+};\r
+\r
+struct PCharProfile\r
+{\r
+  u32 CharID;\r
+  u16 Type;\r
+  u16 Color0;\r
+  u16 Unknown1;\r
+  u8 Head;\r
+  u8 Torso;\r
+  u8 Legs;\r
+  u32 Location;\r
+  u8 NameLen;\r
+  u8 Unknown3;\r
+  u8 Unknown4;\r
+  u8 Unknown5;\r
+  u8 Unknown6;\r
+  u8 Unknown7;\r
+  u8 Unknown8;\r
+  u8 Unknown9;\r
+  u8 Unknown10;\r
+  u8 Unknown11;\r
+  u8 Unknown12;\r
+  std::string Name;\r
+  bool in_use;\r
+};\r
+\r
+class PChars\r
+{\r
+  private :\r
+    typedef std::map<u32, PChar*> CharMap;\r
+    CharMap mChars;\r
+    u32 mLastID;\r
+\r
+    std::time_t mAutoSavePeriod;\r
+    std::time_t mLastSave;\r
+\r
+  public :\r
+    PChars();\r
+    ~PChars();\r
+\r
+    bool LoadChar( u32 CharID );\r
+    bool AddChar( PChar* nChar );\r
+    PChar* RemoveChar( u32 CharID );\r
+\r
+    PChar* GetChar( u32 CharID ) const;\r
+    PChar* GetChar( const std::string &Name ) const;\r
+    bool CharExist( const std::string &Name ) const;\r
+\r
+    void SQLSave();\r
+    void Update();\r
+\r
+    int GetCharProfiles( const u32 AccountID, PCharProfile* CharSlotsArray, const u8 ArraySize ); // return effective entries nb\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/chat.h b/server/src/game/include/chat.h
new file mode 100644 (file)
index 0000000..80595c5
--- /dev/null
@@ -0,0 +1,198 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+        chat.h\r
+\r
+        Authors:\r
+        - Namikon\r
+        - bakkdoor\r
+\r
+        MODIFIED: 30 Nov 2005 Namikon/Akiko\r
+        REASON: - initial release by Namikon\r
+\r
+        MODIFIED: 11 Dec 2005 Namikon\r
+        REASON: - Added function SendDChat(Client, <text>, <nick>) to send a Direct to player\r
+                - Added Channel IDs for GameMaster (/gm) and Administrator (/admin) chat\r
+                - Added channel const's for sending chat packets\r
+                - Added function SendChat(Client, <channel>, <text>, <nick>) to send chat messages\r
+                 For <channel>, use one of the u8 constants listet below\r
+\r
+        MODIFIED: 17 Dec 2005 bakkdoor\r
+        REASON: - introduced new structure for chatsystem\r
+                - -> PChat class\r
+*/\r
+\r
+#ifndef CHAT_H\r
+#define CHAT_H\r
+#define LOCALCHAT_MAXDISTANCE 1433\r
+\r
+class PChat\r
+{\r
+    private:\r
+\r
+    public:\r
+            PChat();\r
+            ~PChat();\r
+\r
+            // INCOMING CHAT\r
+            bool HandleGameChat(PClient *Client, const u8 *Packet);\r
+            bool cmpr(const u8 *Array1, const u8 *Array2);\r
+\r
+            // this function is called by the other more specific functions and simply sends the data to the receiver-client\r
+            bool send(PClient* receiver, const u8* Channel, const char* AuthorNickName, const char* text, bool debugOut=false);\r
+\r
+            // this is for debugging and sends the current connected playerlist to the receiver-client\r
+            void sendConnectedList(PClient* receiver, bool debugOut=false);\r
+\r
+            // specific channel functions:\r
+            void sendBuddy(PClient* author, const char* text, bool debugOut=false);\r
+            void sendLocal(PClient* author, const char* text, bool debugOut=false);\r
+            void sendClan(PClient* author, const char* text, bool debugOut=false);\r
+            void sendTeam(PClient* author, const char* text, bool debugOut=false);\r
+            void sendDirect(PClient* author, PClient* receiver, const char* text, bool debugOut=false);\r
+            void sendZone(PClient* author, const char* text, bool debugOut=false);\r
+            void sendFrak(PClient* author, const char* text, bool debugOut=false);\r
+            void sendTradeCS(PClient* author, const char* text, bool debugOut=false);\r
+            void sendTradeMB(PClient* author, const char* text, bool debugOut=false);\r
+            void sendTradeNC(PClient* author, const char* text, bool debugOut=false);\r
+            void sendTradeTH(PClient* author, const char* text, bool debugOut=false);\r
+            void sendTradeWL(PClient* author, const char* text, bool debugOut=false);\r
+            void sendOOC(PClient* author, const char* text, bool debugOut=false);\r
+            void sendHelp(PClient* author, const char* text, bool debugOut=false);\r
+            void sendClanSearch(PClient* author, const char* text, bool debugOut=false);\r
+            void sendServicesCS(PClient* author, const char* text, bool debugOut=false);\r
+            void sendServicesMB(PClient* author, const char* text, bool debugOut=false);\r
+            void sendServicesNC(PClient* author, const char* text, bool debugOut=false);\r
+            void sendServicesTH(PClient* author, const char* text, bool debugOut=false);\r
+            void sendServicesWL(PClient* author, const char* text, bool debugOut=false);\r
+            void sendTeam10(PClient* author, const char* text, bool debugOut=false);\r
+            void sendTeam30(PClient* author, const char* text, bool debugOut=false);\r
+            void sendTeam50(PClient* author, const char* text, bool debugOut=false);\r
+            void sendTeam70(PClient* author, const char* text, bool debugOut=false);\r
+            void sendAdmin(PClient* author, const char* text, bool debugOut=false);\r
+            void sendGM(PClient* author, const char* text, bool debugOut=false);\r
+            void sendGMAdmin(PClient* author, const char* text, bool debugOut=false);\r
+\r
+            void sendBroadcast(const char* text, bool debugOut=false);\r
+            void sendOOCBroadcast(const char* text, bool debugOut=false);\r
+            void sendPlayerDirect(PClient* author, const char* text, u32 destination, bool debugOut=false);\r
+            void sendLocalchat(PClient* receiver, PClient* author, const char* text, bool debugOut=false);\r
+            bool chanEnabled(PClient* Client, u32 channel);\r
+\r
+};\r
+\r
+/** A WARNING: DO >N O T< (!!!) CHANGE >ANY< OF THE FOLLOWING VARIABLES UNLESS YOU KNOW EXACT WHAT YOU'RE DOING! **/\r
+/** You can easily mess up the entire chat subsystem. If you're unsure, ask Namikon first! **/\r
+/*\r
+####################\r
+   CHANNEL-CODES:\r
+     (INCOMING)\r
+####################\r
+*/\r
+static const u32 CHANNEL_BUDDY = 0x00000000;                // Buddy\r
+static const u32 CHANNEL_CLAN = 0x00000002;                 // Clan\r
+static const u32 CHANNEL_TEAM = 0x00000003;                 // Team\r
+static const u32 CHANNEL_DIRECT = 0xFFFFFFFF;               // Direct UNKNOWN YET\r
+static const u32 CHANNEL_CUS_ZONE = 0x00000105;             // Custom -> Zone\r
+static const u32 CHANNEL_CUS_FRAKTION = 0x00000205;         // Custom -> Fraktion\r
+static const u32 CHANNEL_CUS_TRADE_CANYON = 0x00002005;     // Custom -> Trade Canyon\r
+static const u32 CHANNEL_CUS_TRADE_MB = 0x00000805;         // Custom -> Trade MB\r
+static const u32 CHANNEL_CUS_TRADE_NC = 0x00000405;         // Custom -> Trade NC\r
+static const u32 CHANNEL_CUS_TRADE_TH = 0x00001005;         // Custom -> Trade TH\r
+static const u32 CHANNEL_CUS_TRADE_WASTE = 0x00004005;      // Custom -> Trade Wastelands\r
+static const u32 CHANNEL_CUS_OOC = 0x04000005;              // Custom -> OOC\r
+static const u32 CHANNEL_CUS_PLAYERHELP = 0x02000005;       // Custom -> Player 2 Player help\r
+static const u32 CHANNEL_CUS_CLANSEARCH = 0x01000005;       // Custom -> Searching Clan\r
+static const u32 CHANNEL_CUS_SERVICES_CANYON = 0x00040005;  // Custom -> Runner Services Canyon\r
+static const u32 CHANNEL_CUS_SERVICES_MB = 0x00010005;      // Custom -> Runner Services MB\r
+static const u32 CHANNEL_CUS_SERVICES_NC = 0x00008005;      // Custom -> Runner Services NC\r
+static const u32 CHANNEL_CUS_SERVICES_TH = 0x00020005;      // Custom -> Runner Services TH\r
+static const u32 CHANNEL_CUS_SERVICES_WASTE = 0x00080005;   // Custom -> Runner Services Wastelands\r
+static const u32 CHANNEL_CUS_TEAM_10 = 0x00100005;          // Custom -> Searching Team ~10\r
+static const u32 CHANNEL_CUS_TEAM_30 = 0x00200005;          // Custom -> Searching Team ~30\r
+static const u32 CHANNEL_CUS_TEAM_50 = 0x00400005;          // Custom -> Searching Team ~50\r
+static const u32 CHANNEL_CUS_TEAM_70 = 0x00800005;          // Custom -> Searching Team ~70\r
+static const u32 CHANNEL_ADMIN = 0x000000FF;                // Admin chat\r
+static const u32 CHANNEL_GMADMIN = 0x000000FE;                // Admin chat\r
+static const u32 CHANNEL_GMCHAT = 0x000000FD;               // GameMaster chat\r
+/*\r
+####################\r
+   CHANNEL-CODES:\r
+     (OUTGOING)\r
+####################\r
+*/\r
+static const u8 CHAT_BUDDY[] = {0x00, 0x10};\r
+static const u8 CHAT_LOCAL[] =  {0x01, 0x10};\r
+static const u8 CHAT_CLAN[] = {0x02, 0x10};\r
+static const u8 CHAT_TEAM[] = {0x03, 0x10};\r
+static const u8 CHAT_DIRECT[] = {0x04, 0x10};\r
+static const u8 CHAT_ZONE[] = {0x05, 0x00};\r
+static const u8 CHAT_FRAK[] = {0x05, 0x01};\r
+static const u8 CHAT_TRADECS[] = {0x05, 0x05};\r
+static const u8 CHAT_TRADEMB[] = {0x05, 0x03};\r
+static const u8 CHAT_TRADENC[] = {0x05, 0x02};\r
+static const u8 CHAT_TRADETH[] = {0x05, 0x04};\r
+static const u8 CHAT_TRADEWL[] = {0x05, 0x06};\r
+static const u8 CHAT_OOC[] = {0x05, 0x12};\r
+static const u8 CHAT_HELP[] = {0x05, 0x11};\r
+static const u8 CHAT_CLANSEARCH[] = {0x05, 0x10};\r
+static const u8 CHAT_SERVICECS[] =  {0x05, 0x0A};\r
+static const u8 CHAT_SERVICESMB[] = {0x05, 0x08};\r
+static const u8 CHAT_SERVICESNC[] = {0x05, 0x07};\r
+static const u8 CHAT_SERVICESTH[] = {0x05, 0x09};\r
+static const u8 CHAT_SERVICESWL[] = {0x05, 0x0B};\r
+static const u8 CHAT_TEAM10[] = {0x05, 0x0C};\r
+static const u8 CHAT_TEAM30[] = {0x05, 0x0D};\r
+static const u8 CHAT_TEAM50[] = {0x05, 0x0E};\r
+static const u8 CHAT_TEAM70[] = {0x05, 0x0F};\r
+static const u8 CHAT_ADMIN[] = {0xFF, 0x10};\r
+static const u8 CHAT_GMADMIN[] = {0xFE, 0x10};\r
+static const u8 CHAT_GM[] = {0xFD, 0x10};\r
+\r
+/*\r
+####################\r
+   CHANNEL-CODES:\r
+(EN/DISABLE-ABLE CHANNELS)\r
+####################\r
+*/\r
+static const u32 C_ZONE = 1;\r
+static const u32 C_FRAK = 2;\r
+static const u32 C_TRADENC = 4;\r
+static const u32 C_TRADEMB = 8;\r
+static const u32 C_TRADETH = 16;\r
+static const u32 C_TRADECS = 32;\r
+static const u32 C_TRADEWL = 64;\r
+static const u32 C_SERVICENC = 128;\r
+static const u32 C_SERVICEMB = 256;\r
+static const u32 C_SERVICETH = 512;\r
+static const u32 C_SERVICECS = 1024;\r
+static const u32 C_SERVICEWL = 2048;\r
+static const u32 C_TEAM10 = 4096;\r
+static const u32 C_TEAM30 = 8192;\r
+static const u32 C_TEAM50 = 16384;\r
+static const u32 C_TEAM70 = 32768;\r
+static const u32 C_CLANSEARCH = 65536;\r
+static const u32 C_HELP = 131072;\r
+static const u32 C_OOC = 262144;\r
+#endif\r
diff --git a/server/src/game/include/client.h b/server/src/game/include/client.h
new file mode 100644 (file)
index 0000000..832eb25
--- /dev/null
@@ -0,0 +1,228 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+ client.h\r
+\r
+ Authors:\r
+ - v00d00\r
+ - Akiko\r
+ - Namikon\r
+ - bakkdoor\r
+\r
+ MODIFIED: 30 Nov 2005 Akiko\r
+ REASON: - added GPL\r
+        - added stuff from Namikon\r
+  MODIFIED: 13 Dec 2005 bakkdoor\r
+  REASON: - added multiuser chat\r
+  MODIFIED: 27 Jul 2006 Hammag\r
+  REASON: - added mTransactionID member\r
+          - re-added IncreaseUDP_ID() // but I don't understand well what SetUDP_ID() does ...\r
+  MODIFIED: 05 Aug 2006 Hammag\r
+  REASON: - changed TMP_UDP_PORT/SetTMPUDPPort()/GetTMPUDPPort() to mRemotePort/SetRemoteUDPPort()/GetRemoteUDPPort()\r
+              which corresponds to the real purpose of these members\r
+          - added GetID() as an alias os GetIndex() for better coherency with other classes\r
+  MODIFIED: 09 Oct 2006 Hammag\r
+  REASON: - added GetDebugMode() and SetDebugMode() methods\r
+\r
+\r
+  TODO:   - check that SetUDP_ID, and the mSessionID(UDP_ID_HIGH) real use,\r
+              and if UDP_ID and mSessionID must be synced (like in NeoX) or not\r
+\r
+*/\r
+\r
+#ifndef CLIENT_H\r
+#define CLIENT_H\r
+\r
+enum PClientConnection\r
+{\r
+  PCC_NONE = 0,\r
+  PCC_GAME = 1\r
+};\r
+\r
+// AccountLevel handling is part of accounts.cpp\r
+/*\r
+enum PClientLevel\r
+{\r
+ PCL_BANNED = -1,\r
+ PCL_UNREGPLAYER = 0,\r
+ PCL_REGPLAYER = 1,\r
+ PCL_VOLUNTEER = 30,\r
+ PCL_GM = 50,\r
+ PCL_ADMIN = 100\r
+};\r
+*/\r
+#define DEBUG_MODES 3\r
+enum PDebugMode\r
+{\r
+  DBG_LOCATION = 0,\r
+  DBG_ITEMID = 1,\r
+  DBG_SUBWAY = 2,\r
+  DBG_ALL = DEBUG_MODES // must always be last, with DEBUG_MODES updated as needed\r
+};\r
+\r
+\r
+class PClient\r
+{\r
+  private :\r
+    ConnectionTCP* m_TCPConnection;\r
+    ConnectionUDP* m_UDPConnection;\r
+\r
+    u32 mAccountID;\r
+    int mAccountLevel;\r
+    u32 mIndex;\r
+    u32 mCharID;\r
+\r
+//  u16 mUDP_ID;\r
+//  u16 mSessionID;\r
+//  u16 mTransactionID;\r
+\r
+    // AccountLevel handling is part of accounts.cpp\r
+    //PClientLevel mLevel;\r
+    int mConnection;\r
+    int mRemotePort;\r
+\r
+    bool mDebugMode[DEBUG_MODES];\r
+    // new multiuser-chat implementation //\r
+    int m_ZoneID;\r
+    //int[4] m_IP;\r
+\r
+    //*******\r
+    bool mActorRemoveMode;\r
+    //*******\r
+    bool mAwaitingWarpto;\r
+    u16 mTargetX;\r
+    u16 mTargetY;\r
+    u16 mTargetZ;\r
+    //*******\r
+    bool mAcceptNPCUpdates;\r
+    bool mZoning;\r
+    bool mVhcZoning;\r
+    \r
+\r
+  protected :\r
+  public :\r
+    PClient( int Index );\r
+    ~PClient();\r
+\r
+    inline bool GetDebugMode( PDebugMode nDebugID ) { return mDebugMode[nDebugID]; }\r
+    void SetDebugMode( PDebugMode nDebugID, bool nVal = true );\r
+\r
+    inline bool IsAcceptingNPCUpdates() { return mAcceptNPCUpdates; }\r
+    inline void SetAcceptNPCUpdates( bool nVal ) { mAcceptNPCUpdates = nVal; }\r
+    inline bool IsZoning() { return mZoning; }\r
+    inline void SetZoning( bool nVal = true ) { mZoning = nVal; if ( !nVal ) mVhcZoning = false; }\r
+    inline bool IsVhcZoning() { return mVhcZoning; }\r
+    inline void SetVhcZoning( bool nVal = true ) { mVhcZoning = nVal; }\r
+\r
+    inline u32 GetIndex() const { return mIndex; } // better use GetID()\r
+    inline u32 GetID() const { return mIndex; } // for better coherency with other classes\r
+    inline u32 GetLocalID() const { return mIndex + 1; }\r
+    inline u32 GetCharID() const { return mCharID; }\r
+    PChar* GetChar() const;\r
+    bool ChangeCharLocation( u32 nLocation, bool DoForce = false );\r
+\r
+    inline int GetRemoteUDPPort() const { return mRemotePort; } // Temp solution\r
+\r
+    inline bool IsInRemoveActorMode() { return mActorRemoveMode; }\r
+    inline void SetRemoveActorMode( bool nNewValue ) { mActorRemoveMode = nNewValue; }\r
+\r
+    inline void SetRemoteUDPPort( int port ) { mRemotePort = port; } // Temp solution\r
+    inline void SetCharID( int id ) { mCharID = id; }//NEW added\r
+\r
+    /*\r
+        inline u16 GetUDP_ID() const { return mUDP_ID; }\r
+        inline u16 GetSessionID() const { return SESSION_UDP_OFFSET + mUDP_ID ; }\r
+        inline u16 GetTransactionID() {return mTransactionID; }\r
+        void SetUDP_ID(int id);\r
+        inline void IncreaseUDP_ID() { SetUDP_ID(mUDP_ID + 1); }\r
+        inline void ResetTransactionID() { mTransactionID = 10170; }\r
+\r
+        inline void IncreaseTransactionID(u8 nInc = 1) { mTransactionID += nInc; }\r
+    */\r
+\r
+    // All outgoing ID's and stuff is now part of the ConnectionUDP class itself!\r
+    //    (which is not so good.... comment from Hammag)\r
+    // However, we still have full access to it through these functions\r
+    u16 GetUDP_ID();\r
+    void SetUDP_ID( int id );\r
+    void IncreaseUDP_ID();\r
+\r
+    u16 GetSessionID();\r
+\r
+    u16 GetTransactionID();\r
+    void ResetTransactionID();\r
+    void IncreaseTransactionID( u8 nInc = 1 );\r
+\r
+    void FillInUDP_ID( PMessage* nMessage );\r
+\r
+// ************************************************************************ //\r
+    // AccountLevel handling is part of accounts.cpp\r
+    //inline PClientLevel GetLevel() const { return mLevel; }\r
+\r
+    inline void setTCPConnection( ConnectionTCP* conn ) { m_TCPConnection = conn; m_UDPConnection = 0; mConnection = PCC_GAME;  }\r
+    inline void setUDPConnection( ConnectionUDP* conn ) { m_UDPConnection = conn; }\r
+\r
+    inline ConnectionTCP* getTCPConn() { return m_TCPConnection; }\r
+    inline ConnectionUDP* getUDPConn() { return m_UDPConnection; }\r
+\r
+    inline void SendTCPMessage( PMessage* nMessage ) { if ( m_TCPConnection ) { m_TCPConnection->SendMessage( nMessage ); } else { delete nMessage; } }\r
+    void FragmentAndSendUDPMessage( PMessage* nMessage, u8 nType );\r
+    inline void SendUDPMessage( PMessage* nMessage, bool nVIP = false ) { if ( m_UDPConnection ) { m_UDPConnection->SendMessage( nMessage, nVIP ); }  else { delete nMessage; } }\r
+\r
+    inline int GetConnection() const { return mConnection; }\r
+    inline const char *GetAddress() const { return m_TCPConnection->getRemoteAddress(); }\r
+    inline u32 GetAccountID() const { return mAccountID; }\r
+    inline int GetAccountLevel() const { return mAccountLevel; }\r
+\r
+    void GameDisconnect();\r
+\r
+    void RefreshAccountInfo( PAccount* Account );\r
+    inline void LoggedIn( PAccount* Account ) { RefreshAccountInfo( Account ); }\r
+    void Update();\r
+\r
+    // new multiuser-chat implementation //\r
+    inline int getZoneID() const { return m_ZoneID; } // example: canyon 650 (for local-channel...every client with same AreaID get the chatmsg)\r
+    //inline int* getIP() const { return (int*) m_IP; }\r
+\r
+    inline void SetAwaitingWarpto( bool yesno, u16 NewX, u16 NewY, u16 NewZ )\r
+    {\r
+      mAwaitingWarpto = yesno;\r
+      mTargetX = NewX;\r
+      mTargetY = NewY;\r
+      mTargetZ = NewZ;\r
+    }\r
+    bool GetCharAwaitingWarpto( u16* PosX = NULL, u16* PosY = NULL, u16* PosZ = NULL );\r
+\r
+    // Char broadcasted effects\r
+    void InitWarpCircle();\r
+    void InitCharVanish();\r
+\r
+    // used for dynamic ingame testing\r
+    u8 testval8;\r
+    u16 testval16;\r
+    u32 testval32;\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/include/clientmanager.h b/server/src/game/include/clientmanager.h
new file mode 100644 (file)
index 0000000..6f6cb77
--- /dev/null
@@ -0,0 +1,79 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+ clientmanager.h\r
+\r
+ Authors:\r
+ - bakkdoor\r
+\r
+ MODIFIED: 13 Dec 2005 bakkdoor\r
+ REASON: - introduced\r
+ MODIFIED: 29 Jul 2006 Hammag\r
+ REASON: - added UDP broadcast fonction\r
+         - added "zone players say Hello" fonction\r
+         - changed type ClientMap to PClientMap, changed members name prefix m_ to m\r
+\r
+ MODIFIED: 12 Aug 2006 Hammag\r
+ REASON: - duplicated UDPBroadcast() in two prototypes\r
+\r
+*/\r
+\r
+#ifndef CLIENTMANAGER_H\r
+#define CLIENTMANAGER_H\r
+\r
+typedef std::map<u32, PClient*> PClientMap;\r
+\r
+class PClientManager\r
+{\r
+  private:\r
+    //int       mLastID;\r
+    PClientMap mClientList;\r
+\r
+  public:\r
+    PClientManager();\r
+    ~PClientManager();\r
+\r
+    PClientMap::iterator   getClientListBegin() { return mClientList.begin(); }\r
+    PClientMap::iterator   getClientListEnd() { return mClientList.end(); }\r
+\r
+    bool addClientToList( PClient* newClient );\r
+    //void deleteClientFromListByID(int id);\r
+    void deleteClientFromList( u32 id );\r
+    //bool deleteClientFromList(PClient* delClient); // maybe no use for this...\r
+    PClient* getClientByID( u32 u32 ) const; // returns pointer to a client for further use\r
+    PClient* getClientByChar( u32 CharID ) const;\r
+    PClient* getClientByChar( const std::string &Name ) const;\r
+    // int getClientID(PClient* _client); do _client->GetLocalID()\r
+    bool IsWorldInUse( u32 nWorldID ) const; // Temp until world content fully managed by world\r
+    PClient* GetClientByCharLocalId( u32 rawObjectId, u32 nWorldID  ) const; // Temp (called by world) until world content fuly managed by world\r
+\r
+    // each function return the number of messages sent.\r
+    int UDPBroadcast( PMessage* nMessage, u32 nZoneID, u16 nX = 0, u16 nY = 0, u16 nZ = 0, u16 nMaxDist = 0, u32 nSkipCharId = 0, bool nNPCPing = false );\r
+    int UDPBroadcast( PMessage* nMessage, PClient* nClient, u16 nMaxDist = 0, bool nSkipSource = false, bool nNPCPing = false );\r
+    int SendUDPZoneWelcomeToClient( PClient* nClient );\r
+\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/include/commands.h b/server/src/game/include/commands.h
new file mode 100644 (file)
index 0000000..c4f1b15
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+
+
+/*
+       commands.h
+
+       Authors:
+       - Namikon
+
+       MODIFIED: 11 Dec 2005 Namikon
+       REASON: - initial release
+       MODIFIED: 15 Dec 2005 Namikon
+       REASON: - Added SendRawFile(...)
+
+*/
+
+#ifndef COMMANDS_H
+#define COMMANDS_H
+#define MAXARGS 10       // Define the max nr. of args here. Should never be more than 4, but who knows...
+#define MAXDUMBSIZE 256 // Max size of packetdumb
+
+class PCommands
+{
+private:
+    char OrgPacketDumb[MAXDUMBSIZE];    // Raw dumb of original packet
+    char Command[30];           // Command itself without @
+    char ArgV[MAXARGS][30];     // Array of arg-values
+    int ArgC;                   // Nr of args in array (To perform checks only, ArgV is terminated!)
+    bool DumbMade;              // Set TRUE if dumb is made
+
+    PClient* GetClientByID(int charid);
+    PClient* GetClientByNick(const char *nick);
+
+    PClient *source;            // "sender" of command
+    PClient *target;            // possible "target" of command
+
+    bool GetTarget(int ArgNum);     // Get target by ArgV index
+    bool CheckPermission();         // Checks permission depending on commands.conf file
+    bool IsArgNumeric(int ArgNum);  // is_numeric function from VB, loved this one :D
+    //bool SendRawFile(PClient *Client, char *FileName, int protokoll);  <- UnUsed??
+    bool RequirePacketDumb();       // Detect if command needs access to the entire packet or just the args
+    bool IsDevCommand();            // To add Developer only commands without documentation in commands.conf
+    bool IsAdmin();                 // Check if sender is Admin
+
+    int GetArgInt(int ArgNum);  // Get ArgV[x] as integer (if possible)
+
+    bool GetArgText(int ArgNum, char* output, int output_size); // Get ArgV[x] as char array
+
+    void FlushArgs();           // Empty all vars for next command
+
+
+    /// ------- Begin commandset -------
+    void doCmddebug();
+    void doCmdsettime();
+    void doCmdwarp();
+    void doCmdrawf();
+    // Not required anymore, TinNS gets is worlditemdata from .dat files now
+    // void doCmddelworlditem();
+    // void doCmdaddworlditem();
+    // void doCmdadddor();
+    void doCmdconlist();
+    void doCmdskin();
+    void doCmdeffect();
+    void doCmdspeed();
+    void doCmdcolor();
+    void doCmdbrightness();
+    void doCmdremove();
+    void doCmduptime();
+    void doCmdversion();
+    void doCmdkick();
+    void doCmdinfo();
+    void doCmdsetlevel();
+    void doCmdwarpto();
+    void doCmdrecall();
+    void doCmdbroadcast();
+    void doCmd_dev_t();
+    void doCmd_dev_h();
+    void doCmd_dev_v();
+    void doCmdban();
+    void doCmdunban();
+    void doCmdlistbans();
+    void doCmdshun();
+    void doCmdunshun();
+    void doCmdjail();
+    void doCmdunjail();
+    void doCmdteleport();
+    void doCmdgivemoney();
+    void doCmdtakemoney();
+    void doCmdspawnactor();
+    void doCmdeditactor();
+    void doCmdweather();
+    void doCmdSetMainSkill();
+    void doCmdSetSubSkill();\r
+    void doNPC();\r
+    void doNPC_Shop();
+
+    void doCmdtest();
+    /// ------- End commandset -------
+
+public:
+    PCommands();
+    ~PCommands();
+
+    void HandleGameCommand(char *packet, PClient *Client);
+};
+#endif
diff --git a/server/src/game/include/container.h b/server/src/game/include/container.h
new file mode 100644 (file)
index 0000000..08cec1e
--- /dev/null
@@ -0,0 +1,232 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+  container.h - base classe for containers\r
+\r
+\r
+ MODIFIED: 28 Jul 2008 Hammag\r
+ REASON: - creation\r
+\r
+*/\r
+\r
+#ifndef CONTAINER_H\r
+#define CONTAINER_H\r
+\r
+#define CONTAINER_MAX_SIZE 254\r
+\r
+class PItem;\r
+\r
+class PContainerEntry\r
+{\r
+  friend class PContainer;\r
+  friend class PContainer2D;\r
+  friend class PMsgBuilder;\r
+\r
+  friend class PContainer2DWorkaround;\r
+\r
+  private:\r
+    enum {\r
+      i_invid = 0,\r
+      i_charid,\r
+      i_invloc,\r
+      i_x,\r
+      i_y,\r
+      i_itemid,\r
+      //i_type,
+      i_flag,\r
+      i_qty,
+      i_sqty,\r
+      i_curdur,\r
+      i_dmg,\r
+      i_freq,\r
+      i_hand,\r
+      i_rng,\r
+      i_maxdur,
+      i_slots,
+      i_slt1,
+      i_slt2,
+      i_slt3,
+      i_slt4,
+      i_slt5,
+      i_atype,
+      i_conatin
+    };\r
+\r
+    PItem* mItem;\r
+    u8  mPosX;\r
+    u8  mPosY;\r
+    u32 mInvID;\r
+    bool mDirtyFlag;\r
+\r
+    PContainerEntry(PItem* nItem, u8 X, u8 Y, u32 nInvID = 0, bool SetDirty = true);\r
+    PContainerEntry(MYSQL_ROW row);\r
+\r
+    bool SQLSave(u32 CharID, u32 InvLoc);\r
+    bool SQLDelete();\r
+\r
+    inline void Set2DPos(u8 nPosX, u8 nPosY) { mDirtyFlag = mDirtyFlag || (mPosX != nPosX) || (mPosY != nPosY) ; mPosX = nPosX; mPosY = nPosY; }\r
+\r
+  public:\r
+    ~PContainerEntry();\r
+\r
+    inline void Get2DPos(u8* oPosX, u8* oPosY) { *oPosX = mPosX; *oPosY = mPosY; }\r
+};\r
+\r
+\r
+\r
+class PContainer // Holes allowed, no autofind free slots\r
+{\r
+       protected:\r
+    u8 mMaxSlots;\r
+    std::vector< PContainerEntry* >* mContContent;\r
+    u32 mCharID;\r
+    u32 mInvLoc;\r
+    u32 mExclusiveUseCharID;\r
+    bool mDirtyFlag;\r
+\r
+    inline bool IsSlotAllowed(u8 nSlotId) { return ((nSlotId < CONTAINER_MAX_SIZE) && (!mMaxSlots || (nSlotId < mMaxSlots))); }\r
+    virtual bool AddEntry(PContainerEntry* NewEntry, u8 nSlotId = 0);\r
+    virtual PContainerEntry* RemoveEntry(u8 nSlotId);\r
+    virtual bool GetFreeSlot(u8* nSlotId);\r
+               void Compact(u8 startSlotId = 0);\r
+\r
+  public:\r
+    PContainer(u8 nMaxSlots = 0);\r
+    virtual ~PContainer();\r
+\r
+    inline void SetInfo(u32 CharID, u32 InvLoc) { mCharID = CharID; mInvLoc = InvLoc; }\r
+    inline u32 GetOwnerId() { return mCharID; }\r
+\r
+    inline bool IsDirty() { return mDirtyFlag; }\r
+    inline void SetDirty() { mDirtyFlag = true; }\r
+\r
+    bool StartUse(u32 nExclusiveUseCharID = 0);\r
+    virtual bool EndUse(u32 nExclusiveUseCharID = 0);\r
+\r
+    bool SQLLoad();\r
+    bool SQLSave();\r
+\r
+    bool IsSlotFree(u8 nSlotId);\r
+    virtual bool AddItem(PItem* NewItem, u32 nInvID = 0, u8 nPosX = 0, u8 nPosY = 0, bool SetDirty = true);\r
+\r
+    virtual bool MoveItem(u8 srcSlotId, u8 nCount, u8 dstSlotId);\r
+    bool MoveItem(u8 srcSlotId, u8 nCount, PContainer* dstContainer, u8 dstSlotId = 0, u8 nPosX = 0, u8 nPosY = 0);\r
+         virtual void SetEntryPosXY(PContainerEntry* nEntry, u8 nSlotId, u8 nPosX = 0, u8 nPosY = 0);\r
+\r
+    virtual u8 RandomFill(u8 nItemCount = 0, int nItemContainerDefIndex = -1);\r
+\r
+    PContainerEntry* GetEntry(u8 nSlotId);\r
+    std::vector< PContainerEntry* >* GetEntries();\r
+    PItem* GetItem(u8 nSlotId);\r
+\r
+    virtual void Dump();\r
+};\r
+\r
+\r
+class PContainerWithHoles : public PContainer // Holes allowed, no autofind free slots\r
+{\r
+  public:\r
+    PContainerWithHoles(u8 nMaxSlots = 0) : PContainer(nMaxSlots){ nMaxSlots = nMaxSlots; }\r
+    virtual ~PContainerWithHoles() {}\r
+};\r
+\r
+\r
+class PContainerAutoCompact : public PContainer // No holes allowed, automatic add to end slot (no control on insertion slot)\r
+{\r
+       protected:\r
+    virtual PContainerEntry* RemoveEntry(u8 nSlotId);\r
+    virtual bool GetFreeSlot(u8* nSlotId);\r
+\r
+  public:\r
+    PContainerAutoCompact(u8 nMaxSlots = 0) : PContainer(nMaxSlots){ nMaxSlots = nMaxSlots; }\r
+    virtual ~PContainerAutoCompact() {}\r
+\r
+    virtual bool MoveItem(u8 srcSlotId, u8 nCount, u8 dstSlotId);\r
+};\r
+\r
+\r
+class PContainer2D : public PContainerAutoCompact // + slotId not used, non-significant XY used (no XY check yet)\r
+{\r
+  public:\r
+    PContainer2D(u8 nMaxSlots = 0) : PContainerAutoCompact(nMaxSlots){ nMaxSlots = nMaxSlots; }\r
+    virtual ~PContainer2D() {}\r
+\r
+               virtual void SetEntryPosXY(PContainerEntry* nEntry, u8 nSlotId, u8 nPosX = 0, u8 nPosY = 0);\r
+};\r
+\r
+class PContainer2DWorkaround : public PContainerWithHoles // Holes allowed, autofind free slot (always increasing id)\r
+{\r
+  private:\r
+    u8 mNextFreeSlot;\r
+    std::vector< std::vector<bool>* > mContSpace;\r
+    u8 mMaxCols;\r
+    u8 mMaxRows;\r
+    u8 mRows;\r
+\r
+    void AddRow();\r
+\r
+    inline bool Is2DPosAllowed(u8 PosX, u8 PosY, u8 SizeX, u8 SizeY)\r
+    {\r
+      return ((PosX < mMaxCols-SizeX+1) && (PosY < mMaxRows-SizeY+1));\r
+    }\r
+    bool Is2DFree(u8 PosX, u8 PosY, u8 SizeX, u8 SizeY);\r
+    bool FindValid2DPos(PContainerEntry* nEntry);\r
+\r
+\r
+  protected:\r
+    bool AddEntry(PContainerEntry* NewEntry, u8 nSlotId = 0);\r
+    PContainerEntry* RemoveEntry(u8 nSlotId);\r
+    bool GetFreeSlot(u8* nSlotId);\r
+\r
+  public:\r
+    PContainer2DWorkaround(u8 nMaxSlots = 0);\r
+    ~PContainer2DWorkaround();\r
+\r
+    bool MoveItem(u8 srcSlotId, u8 nCount, u8 dstSlotId);\r
+\r
+    void Set2DPosMax(u8 MaxPosX, u8 MaxPosY = 254) { mMaxCols = MaxPosX; mMaxRows = MaxPosY; }\r
+    void SetEntryPosXY(PContainerEntry* nEntry, u8 nSlotId, u8 nPosX = 0, u8 nPosY = 0);\r
+    void SetUsed(PContainerEntry* nEntry, bool Value = true);\r
+    void Dump();\r
+};\r
+\r
+class PContainerAutoFindFree : public PContainerWithHoles // No holes kept after EndUse, automatic find first free slots (no control on insertion slot)\r
+{\r
+  protected:\r
+    virtual bool GetFreeSlot(u8* nSlotId);\r
+\r
+  public:\r
+    PContainerAutoFindFree(u8 nMaxSlots = 0) : PContainerWithHoles(nMaxSlots){ nMaxSlots = nMaxSlots; }\r
+    virtual ~PContainerAutoFindFree() {}\r
+};\r
+\r
+class PContainerAutoCompactOnClose : public PContainerAutoFindFree // No holes kept after EndUse, automatic find first free slots (no control on insertion slot)\r
+{\r
+  public:\r
+    PContainerAutoCompactOnClose(u8 nMaxSlots = 0) : PContainerAutoFindFree(nMaxSlots){ nMaxSlots = nMaxSlots; }\r
+    virtual ~PContainerAutoCompactOnClose() {}\r
+\r
+    virtual bool EndUse(u32 nExclusiveUseCharID = 0);\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/def.h b/server/src/game/include/def.h
new file mode 100644 (file)
index 0000000..ed95d6f
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def.h
+
+    CREATED: 03 Apr 2009 Hammag
+*/
+
+#ifndef DEF_H
+#define DEF_H
+
+extern const std::string EmptyString;
+
+/* mother class for PDef* classes */
+/* provides default members required for def file loading */
+class PDef
+{
+  protected :
+    int mIndex;
+
+  public :
+    PDef() : mIndex(0) {};
+    //~PDef() {};
+
+    inline bool LoadFromDef( PTokenList *Tokens ) { Tokens = Tokens; return false; };
+
+    inline int GetIndex() const { return mIndex; }
+    inline const std::string &GetName() const { return EmptyString; }
+};
+
+#endif
+
diff --git a/server/src/game/include/def_actionmod.h b/server/src/game/include/def_actionmod.h
new file mode 100644 (file)
index 0000000..277f620
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_actionmod.h
+
+    CREATED: 31 Mar 2009 Hammag
+*/
+
+#ifndef DEF_ACTIONMOD_H
+#define DEF_ACTIONMOD_H
+
+#include "def.h"
+
+class PDefActionMod : public PDef
+{
+  private :
+    //int mIndex;
+    float mStartValue;
+    int mNumOfSsq;
+    int mSsqId[8];
+    float mModFactor[8];
+
+  public :
+    PDefActionMod();
+    //~PDefActionMod();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+    inline float GetStartValue() const { return mStartValue; }
+    inline int GetNumOfSsq() const { return mNumOfSsq; }
+    inline int GetSsqId(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mNumOfSsq)) ? mSsqId[nIdx] : 0) ; }
+       inline float GetModFactor(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mNumOfSsq)) ? mModFactor[nIdx] : 0) ; }
+};
+
+#endif
diff --git a/server/src/game/include/def_ammo.h b/server/src/game/include/def_ammo.h
new file mode 100644 (file)
index 0000000..a9425e5
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_ammo.h
+
+    CREATED: 02 Apr 2009 Hammag
+*/
+
+#ifndef DEF_AMMO_H
+#define DEF_AMMO_H
+
+#include "def.h"
+
+class PDefAmmo : public PDef
+{
+  private :
+    //int mIndex;
+       int mDamageId; // related to damage.def
+       int mWeaponShotId; // related to shots.def ?
+       int mMagSize;
+    int mShotId; // related to shots.def ??? strange: hardly ever set in ammo.def
+
+  public :
+    PDefAmmo();
+    //~PDefAmmo();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+    inline int GetDamageId() const { return mDamageId; }
+       inline int GetWeaponShotId() const { return mWeaponShotId; }
+    inline int GetMagSize() const { return mMagSize; }
+       inline int GetShotId() const { return mShotId; }
+};
+
+#endif
diff --git a/server/src/game/include/def_appartements.h b/server/src/game/include/def_appartements.h
new file mode 100755 (executable)
index 0000000..fd8f93b
--- /dev/null
@@ -0,0 +1,71 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       def_appartements.h\r
+\r
+       MODIFIED: 22 Sep 2006 Hammag\r
+       REASON: - Creation\r
+       \r
+*/\r
+\r
+#ifndef DEF_APPARTEMENTS_H\r
+#define DEF_APPARTEMENTS_H\r
+\r
+#include "def.h"\r
+\r
+class PDefAppartement : public PDef\r
+{\r
+       private :\r
+               //int mIndex;\r
+               std::string mName;\r
+               std::string mWorldName;\r
+               int mValue;\r
+               int mPlaceCount;\r
+               int mPlace[8];\r
+               int mFaction;\r
+\r
+       public :\r
+               PDefAppartement();\r
+               //~PDefAppartement();\r
+\r
+               bool LoadFromDef(PTokenList *Tokens);\r
+\r
+               inline int GetID() const { return mIndex; }\r
+               inline const std::string &GetName() const { return mName; }\r
+               inline const std::string &GetWorldName() const { return mWorldName; }\r
+               inline int GetValue() const { return mValue; }\r
+               inline int GetPlaceCount() const { return mPlaceCount; }\r
+               inline int GetPlace(int nIdx) const { return ( (nIdx < mPlaceCount) ? mPlace[nIdx] : 0 ); }\r
+               inline int GetFaction() const { return mFaction; }\r
+};\r
+\r
+\r
+class PDefAppartementsMap : public PDefMap<PDefAppartement>\r
+{\r
+  public:\r
+    inline std::map<int, PDefAppartement*>::const_iterator ConstIteratorBegin() const { return mDefs.begin(); }\r
+    inline std::map<int, PDefAppartement*>::const_iterator ConstIteratorEnd() const { return mDefs.end(); }\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/def_appplaces.h b/server/src/game/include/def_appplaces.h
new file mode 100644 (file)
index 0000000..ce35c33
--- /dev/null
@@ -0,0 +1,57 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+/*\r
+       def_appplaces.h\r
+\r
+       Created: 21 Sep 2006 Hammag\r
+       REASON: -\r
+*/\r
+\r
+#ifndef DEF_APPPLACES_H\r
+#define DEF_APPPLACES_H\r
+\r
+#include "def.h"\r
+\r
+class PDefAppPlace : public PDef\r
+{\r
+       private :\r
+               //int mIndex;\r
+               std::string mName;\r
+               int mExitWorldID;\r
+               int mExitWorldEntity;\r
+               int mSewerLevel;\r
+               \r
+       public :\r
+               PDefAppPlace();\r
+               //~PDefAppPlace();\r
+\r
+               bool LoadFromDef(PTokenList *Tokens);\r
+\r
+               inline const std::string &GetName() const { return mName; }\r
+               inline int GetExitWorldID() const { return mExitWorldID; }\r
+               inline int GetExitWorldEntity() const { return mExitWorldEntity; }\r
+               inline int GetSewerLevel() const { return mSewerLevel; }\r
+\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/def_blueprintpieces.h b/server/src/game/include/def_blueprintpieces.h
new file mode 100644 (file)
index 0000000..c08fceb
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+
+
+/*
+ def_blueprintpieces.h
+
+    CREATED: 31 Mar 2009 Hammag
+*/
+
+#ifndef DEF_BLUEPRINTPIECES_H
+#define DEF_BLUEPRINTPIECES_H
+
+#include "def.h"
+
+class PDefBlueprintPieces : public PDef
+{
+  private :
+    //int mIndex; // related Item Type
+    int mMaxPieceNum;
+    int mPieceNum;
+    int mPieceId[20];
+
+  public :
+    PDefBlueprintPieces();
+    //~PDefBlueprintPieces();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+    inline int GetMaxPieceNum() const { return mMaxPieceNum; }
+    inline int GetPieceNum() const { return mPieceNum; }
+    inline int GetPieceId(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mPieceNum)) ? mPieceId[nIdx] : 0) ; }
+};
+
+#endif
diff --git a/server/src/game/include/def_characters.h b/server/src/game/include/def_characters.h
new file mode 100644 (file)
index 0000000..ac83801
--- /dev/null
@@ -0,0 +1,67 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       def_characters.h\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+       \r
+       MODIFIED: 29 Jul 2006 Hammag\r
+       REASON:  - Added skin modifiers fields\r
+*/\r
+\r
+#ifndef DEF_CHARACTERS_H\r
+#define DEF_CHARACTERS_H\r
+\r
+#include "def.h"\r
+\r
+class PDefCharacter : public PDef\r
+{\r
+       private :\r
+               //int mIndex;\r
+               std::string mName;\r
+               int mModel;\r
+               int mHead;\r
+               int mTorso;\r
+               int mLegs;\r
+               int mColor;\r
+               int mBrightness;\r
+               \r
+       public :\r
+               PDefCharacter();\r
+               //~PDefCharacter();\r
+\r
+               bool LoadFromDef(PTokenList *Tokens);\r
+\r
+               inline const std::string &GetName() const { return mName; }\r
+               inline int GetModel() const { return mModel; }\r
+               inline int GetHead() const { return mHead; }\r
+               inline int GetTorso() const { return mTorso; }\r
+               inline int GetLegs() const { return mLegs; }\r
+               inline int GetColor() const { return mColor; }\r
+               inline int GetBrightness() const { return mBrightness; }\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/include/def_charaction.h b/server/src/game/include/def_charaction.h
new file mode 100644 (file)
index 0000000..d78cd7d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+
+
+/*
+ def_charaction.h
+
+    CREATED: 31 Mar 2009 Hammag
+*/
+
+#ifndef DEF_CHARACTION_H
+#define DEF_CHARACTION_H
+
+#include "def.h"
+
+class PDefCharAction : public PDef
+{
+  private :
+    //int mIndex;
+    int mNumOfSsq;
+    int mSsqId[8];
+    float mModFactor[8];
+
+  public :
+    PDefCharAction();
+    //~PDefCharAction();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+    inline int GetNumOfSsq() const { return mNumOfSsq; }
+    inline int GetSsqId(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mNumOfSsq)) ? mSsqId[nIdx] : 0) ; }
+       inline int GetModFactor(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mNumOfSsq)) ? mModFactor[nIdx] : 0) ; }
+};
+
+#endif
diff --git a/server/src/game/include/def_charkinds.h b/server/src/game/include/def_charkinds.h
new file mode 100644 (file)
index 0000000..ce2fd7e
--- /dev/null
@@ -0,0 +1,117 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       def_charkinds.h\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+*/\r
+\r
+#ifndef DEF_CHARKINDS_H\r
+#define DEF_CHARKINDS_H\r
+\r
+#include "def.h"\r
+\r
+struct PSkillInfo\r
+{\r
+       int mStart;\r
+       int mMax;\r
+       int mGrow;\r
+\r
+       inline PSkillInfo()\r
+       {\r
+               mStart = mMax = mGrow = 0;\r
+       }\r
+};\r
+\r
+struct PSkillPtsInfo\r
+{\r
+       int mSkill;\r
+       int mPoints;\r
+\r
+       inline PSkillPtsInfo()\r
+       {\r
+               mSkill = mPoints = 0;\r
+       }\r
+};\r
+\r
+struct PSubSkillPtsInfo\r
+{\r
+       int mSubSkill;\r
+       int mPoints;\r
+\r
+       inline PSubSkillPtsInfo()\r
+       {\r
+               mSubSkill = mPoints = 0;\r
+       }\r
+};\r
+\r
+struct PStartLevelInfo\r
+{\r
+       int mSubSkill;\r
+       int mLevel;\r
+\r
+       inline PStartLevelInfo()\r
+       {\r
+               mSubSkill = mLevel = 0;\r
+       }\r
+\r
+};\r
+\r
+class PDefCharKind : public PDef\r
+{\r
+       private :\r
+               typedef std::map<int, PSkillPtsInfo*> PSkillPtsMap;\r
+               typedef std::map<int, PSubSkillPtsInfo*> PSubSkillPtsMap;\r
+               typedef std::map<int, PStartLevelInfo*> PStartLevelMap;\r
+\r
+               //int mIndex;\r
+               std::string mName;\r
+               int mType;\r
+\r
+               // TODO: shouldnt this be a map?\r
+               PSkillInfo *mSkillInfo;\r
+\r
+               PSkillPtsMap mSkillPts;\r
+               PSubSkillPtsMap mSubSkillPts;\r
+               PStartLevelMap mStartLevels;\r
+               int mMoney;\r
+               u32 mInventory[8];\r
+       public :\r
+               PDefCharKind();\r
+               ~PDefCharKind();\r
+\r
+               bool LoadFromDef(PTokenList *Tokens);\r
+\r
+               inline const std::string &GetName() const { return mName; }\r
+               inline int GetType() const { return mType; }\r
+               inline const PSkillInfo &GetSkillInfo(int Skill) const { return mSkillInfo[Skill-1]; }\r
+\r
+    inline int GetStartMoney() const { return mMoney; }\r
+    inline u32 GetStartInventory(u8 Index) const { return ((Index < 7) ?  mInventory[Index] : 0); }\r
+               // TODO: mission get() functions\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/include/def_damage.h b/server/src/game/include/def_damage.h
new file mode 100644 (file)
index 0000000..3ee337f
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+
+
+/*
+ def_damage.h
+
+    CREATED: 31 Mar 2009 Hammag
+*/
+
+#ifndef DEF_DAMAGE_H
+#define DEF_DAMAGE_H
+
+#include "def.h"
+
+class PDefDamage : public PDef
+{
+  private :
+    //int mIndex;
+    //int mSoundIndex; // no use
+    int mDamageNum;
+    int mDamageValue[4];
+    int mDamageEffect[4];
+    int mDamageType[4];
+    /* int mEffectNum; // Are effects needed ? (server or client triggered ?)
+       int mEffectId[4]; // ?
+       int mEffectTarget[4]; // float ?
+       int mEffectValue[4]; // float ?
+       int mEffectamorId[4]; // ????
+    */
+  public :
+    PDefDamage();
+    //~PDefDamage();
+
+    bool LoadFromDef ( PTokenList *Tokens );
+
+    inline int GetDamageNum() const { return mDamageNum; }
+    inline int GetDamageValue ( int nIdx ) const { return ( ( ( nIdx >= 0 ) && ( nIdx < mDamageNum ) ) ? mDamageValue[nIdx] : 0 ) ; }
+    inline int GetDamageEffect ( int nIdx ) const { return ( ( ( nIdx >= 0 ) && ( nIdx < mDamageNum ) ) ? mDamageEffect[nIdx] : 0 ) ; }
+    inline int GetDamageType ( int nIdx ) const { return ( ( ( nIdx >= 0 ) && ( nIdx < mDamageNum ) ) ? mDamageType[nIdx] : 0 ) ; }
+    /* inline int GetEffectNum() const { return mEffectNum; }
+        inline int GetEffectId(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mEffectNum)) ? mEffectId[nIdx] : 0) ; }
+       inline int GetEffectTarget(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mEffectNum)) ? mEffectTarget[nIdx] : 0) ; }
+       inline int GetEffectValue(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mEffectNum)) ? mEffectValue[nIdx] : 0) ; }
+       inline int GetEffectamorId(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mEffectNum)) ? mEffectamorId[nIdx] : 0) ; }
+       */
+};
+
+#endif
diff --git a/server/src/game/include/def_drugs.h b/server/src/game/include/def_drugs.h
new file mode 100644 (file)
index 0000000..25f446f
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_drug.h
+
+    CREATED: 31 Mar 2009 Hammag
+*/
+
+#ifndef DEF_DRUG_H
+#define DEF_DRUG_H
+
+#include "def.h"
+
+class PDefDrug : public PDef
+{
+  protected :
+    //int mIndex;
+    int mType;
+    //int mUseSound;
+    int mDuration;
+    int mChangeNum;
+    int mChangeType[8]; // 1: bonus, 2:malus, ... other ?
+    float mChangeScale[8];
+    int mChangeTarget[8];
+
+  public :
+    PDefDrug();
+    //~PDefDrug();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+    inline int GetType() const { return mType; }
+    inline int GetDuration() const { return mDuration; }
+    inline int GetChangeNum() const { return mChangeNum; }
+    inline int GetChangeType( int nIdx ) const { return ((( nIdx >= 0 ) && ( nIdx < mChangeNum ) ) ? mChangeType[nIdx] : 0 ) ; }
+    inline float GetChangeScale( int nIdx ) const { return ((( nIdx >= 0 ) && ( nIdx < mChangeNum ) ) ? mChangeScale[nIdx] : 0 ) ; }
+    inline int GetChangeTarget( int nIdx ) const { return ((( nIdx >= 0 ) && ( nIdx < mChangeNum ) ) ? mChangeTarget[nIdx] : 0 ) ; }
+};
+
+//type of drug:
+//1 normal Drug
+//2 Skill ver�ndernder PSI Spruch K�mpfer
+//3 Skill ver�ndernder PSI Spruch Supporter
+//4 Skill ver�ndernder PSI Spruch Resists
+//6+A274  PSI entferne Sprcuh
+
+// drugeffects  < 1000  Subskill
+//  <2000 Skill
+//  <2100 Energy  (permanent)
+//  <2200 Maxenergy
+//  <2300 Armor
+//  <2400 Subskills
+//  3000-3500 Actionmods
+
+#endif
diff --git a/server/src/game/include/def_factions.h b/server/src/game/include/def_factions.h
new file mode 100644 (file)
index 0000000..51e0ffa
--- /dev/null
@@ -0,0 +1,61 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       def_factions.h\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+*/\r
+\r
+#ifndef DEF_FACTIONS_H\r
+#define DEF_FACTIONS_H\r
+\r
+#include "def.h"\r
+\r
+static const int NUMFACTIONS = 20;     // for faction relations only\r
+\r
+class PDefFaction : public PDef\r
+{\r
+       private :\r
+               //int mIndex;\r
+               std::string mName;\r
+               int mStartValue;\r
+               bool mAffected;\r
+               int mSL;\r
+               int mRelations[NUMFACTIONS];\r
+       public :\r
+               PDefFaction();\r
+               //~PDefFaction();\r
+\r
+               bool LoadFromDef(PTokenList *Tokens);\r
+\r
+               inline const std::string &GetName() const { return mName; }\r
+               inline int GetStartValue() const { return mStartValue; }\r
+               inline bool GetAffected() const { return mAffected; }\r
+               inline int GetSL() const { return mSL; };\r
+               int GetRelation(int Faction) const;\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/include/def_hack.h b/server/src/game/include/def_hack.h
new file mode 100644 (file)
index 0000000..de074d3
--- /dev/null
@@ -0,0 +1,51 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       def_hack.h\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+*/\r
+\r
+#ifndef DEF_HACK_H\r
+#define DEF_HACK_H\r
+\r
+#include "def.h"\r
+\r
+class PDefHack : public PDef\r
+{\r
+       private :\r
+               //int mIndex;\r
+               //qui aggiungere valori\r
+       public :\r
+               PDefHack();\r
+               //~PDefHack();\r
+\r
+               bool LoadFromDef(PTokenList *Tokens);\r
+\r
+               //qui aggiungere funzioni per i gets\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/include/def_implants.h b/server/src/game/include/def_implants.h
new file mode 100644 (file)
index 0000000..a3e4e7a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_implants.h
+
+    CREATED: 02 Apr 2009 Hammag
+*/
+
+#ifndef DEF_IMPLANTS_H
+#define DEF_IMPLANTS_H
+
+#include "def_drugs.h"
+
+// Implants Id 1 to 5 correspond to OP Zone bonus: mine, factory, lab, fort and comlink respectively
+
+class PDefImplant : public PDefDrug
+{
+  public:
+    bool LoadFromDef( PTokenList *Tokens );
+};
+
+#endif
diff --git a/server/src/game/include/def_itemcontainer.h b/server/src/game/include/def_itemcontainer.h
new file mode 100644 (file)
index 0000000..7e9796c
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_itemcontainer.h
+
+    CREATED: 02 Apr 2009 Hammag
+*/
+
+#ifndef DEF_ITEMCONTAINER_H
+#define DEF_ITEMCONTAINER_H
+
+#include "def.h"
+
+class PDefItemContainer : public PDef
+{
+  private :
+    //int mIndex;
+       int mNumItemsAtOnce;
+       int mRespawnTime;
+       int mNumItems;
+    int mItemId[6]; // <0: Group, >0: Item
+    float mQuality[6]; // usually <1, <=> % ?
+       int mChance[6]; // a weight, not a %
+
+    int mCumulatedChance[6]; // Computed data in order to select random item entry
+
+    void BuildCumulatedChance();
+
+  public :
+    PDefItemContainer();
+    //~PDefItemContainer();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+       inline int GetNumItemsAtOnce() const { return mNumItemsAtOnce; }
+       inline int GetRespawnTime() const { return mRespawnTime; }
+    inline int GetNumItems() const { return mNumItems; }
+    inline int GetItemId(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mNumItems)) ? mItemId[nIdx] : 0) ; }
+       inline float GetQuality(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mNumItems)) ? mQuality[nIdx] : 0) ; }
+       inline int GetChance(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mNumItems)) ? mChance[nIdx] : 0) ; }
+    int GetRandomItemIdx() const; // Return Idx based on Entry chance
+};
+
+#endif
diff --git a/server/src/game/include/def_itemmod.h b/server/src/game/include/def_itemmod.h
new file mode 100644 (file)
index 0000000..40f6e21
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_itemmod.h
+
+    CREATED: 31 Mar 2009 Hammag
+*/
+
+#ifndef DEF_ITEMMOD_H
+#define DEF_ITEMMOD_H
+
+#include "def.h"
+
+class PDefItemMod : public PDef
+{
+  private :
+    //int mIndex;
+       int mType; // if mType > 0, it refers to a weapon type from weapons.def +1
+       //int mDuration; // "implant base build time" = ???? always 0 anyway...
+       int mChangeNum;
+    int mChangeTarget[4]; // qualifier id      0 - 7   item qualifier id       4=range 
+    float mChangeValue[4];
+       float mChangeScale[4];
+       std::string mName;
+       //int mIconId;
+
+  public :
+    PDefItemMod();
+    //~PDefItemMod();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+    inline const std::string &GetName() const { return mName; }
+    inline int GetType() const { return mType; }
+       //inline int GetDuration() const { return mDuration; }
+    inline int GetChangeNum() const { return mChangeNum; }
+    inline int GetChangeTarget(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mChangeNum)) ? mChangeTarget[nIdx] : 0) ; }
+       inline float GetChangeValue(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mChangeNum)) ? mChangeValue[nIdx] : 0) ; }
+       inline float GetChangeScale(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mChangeNum)) ? mChangeScale[nIdx] : 0) ; }
+};
+
+#endif
diff --git a/server/src/game/include/def_itemres.h b/server/src/game/include/def_itemres.h
new file mode 100644 (file)
index 0000000..d599861
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_itemres.h
+
+    CREATED: 02 Apr 2009 Hammag
+*/
+
+#ifndef DEF_ITEMRESTRICTION_H
+#define DEF_ITEMRESTRICTION_H
+
+#include "def.h"
+
+class PDefItemRestriction : public PDef
+{
+  private :
+    //int mIndex;
+       int mNumRestrictions;
+    int mSsqId[6]; // Skill/Subs
+       int mMinValue[6];
+
+  public :
+    PDefItemRestriction();
+    //~PDefItemRestriction();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+       inline int GetNumRestrictions() const { return mNumRestrictions; }
+    inline int GetSsqId(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mNumRestrictions)) ? mSsqId[nIdx] : 0) ; }
+       inline float GetMinValue(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mNumRestrictions)) ? mMinValue[nIdx] : 0) ; }
+};
+
+#endif
diff --git a/server/src/game/include/def_items.h b/server/src/game/include/def_items.h
new file mode 100644 (file)
index 0000000..f21c735
--- /dev/null
@@ -0,0 +1,115 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       def_items.h\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+\r
+  MODIFIED: 10 Jul Hammag\r
+  REASON: - Full Item Def implementation\r
+*/\r
+\r
+#ifndef DEF_ITEMS_H\r
+#define DEF_ITEMS_H\r
+\r
+#include "def.h"\r
+\r
+class PDefItems : public PDef\r
+{\r
+       private :\r
+\r
+    //int mIndex;//1\r
+    std::string mName;//2\r
+    int mModel; // used for IG display\r
+    int mType;\r
+    int mValue1;\r
+    int mValue2;\r
+    int mValue3;\r
+    // int mBmNum; // used IG for inventory display\r
+    // int mmBmNumIndex; // used IG for inventory display\r
+    int mSizeX;\r
+    int mSizeY;\r
+    // int mSmallbmnum; // used IG for inventory display\r
+    float mWeight;\r
+    int mStackable;\r
+    float mFillWeight;\r
+    int mQualifier;\r
+    int mGfxMods;\r
+    int mItemGroupID;\r
+    int mTextDescID;\r
+    int mBasePrice;\r
+    int mTechlevel;\r
+    int mItemflags;\r
+    // std::mShortname; // used IG for display on inventories Icons\r
+\r
+       public :\r
+               PDefItems();\r
+               //~PDefItems();\r
+\r
+               bool LoadFromDef(PTokenList *Tokens);\r
+\r
+               inline const std::string &GetName() const { return mName; }\r
+        inline int GetModel() const { return mModel; }\r
+               inline int GetType() const { return mType; }\r
+               inline int GetValue1() const { return mValue1; }\r
+               inline int GetValue2() const { return mValue2; }\r
+               inline int GetValue3() const { return mValue3; }\r
+               inline int GetSizeX() const { return mSizeX; }\r
+               inline int GetSizeY() const { return mSizeY; }\r
+               inline float GetWeight() const { return mWeight; }\r
+               inline bool IsStackable() const { return (mStackable == 1); }\r
+               inline float GetFillWeight() const { return mFillWeight; }\r
+               inline int GetQualifier() const { return mQualifier; }\r
+               inline int GetGfxMods() const { return mGfxMods; }\r
+               inline int GetItemGroupID() const { return mItemGroupID; }\r
+               inline int GetTextDescID() const { return mTextDescID; }\r
+               inline int GetBasePrice() const { return mBasePrice; }\r
+               inline int GetTechlevel() const { return mTechlevel; }\r
+               inline int GetItemflags() const { return mItemflags; }\r
+};\r
+\r
+\r
+class PDefItemsMap : public PDefMap<PDefItems>\r
+{\r
+  private:\r
+    std::map<int, PDefItems*>::const_iterator* mMapItCache;\r
+    int mMapItCacheCount;\r
+    std::map<int, std::vector<int> > mItemGroups;\r
+    int mMaxItemGroupId;\r
+    void BuildMapItCache();\r
+    void BuildItemGroups();\r
+\r
+  public:\r
+    PDefItemsMap();\r
+    ~PDefItemsMap();\r
+    bool Load(const char* nName, const char* nFilename);\r
+    const PDefItems* GetDefBySeqIndex( int nSeqIndex ) const;\r
+    int GetRandomItemIdFromGroup( int nGroupId ) const;\r
+\r
+    inline std::map<int, PDefItems*>::const_iterator ConstIteratorBegin() const { return mDefs.begin(); }\r
+    inline std::map<int, PDefItems*>::const_iterator ConstIteratorEnd() const { return mDefs.end(); }\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/def_mission.h b/server/src/game/include/def_mission.h
new file mode 100644 (file)
index 0000000..7ff31b7
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_mission.h
+
+    CREATED: 02 Apr 2009 Hammag
+*/
+
+#ifndef DEF_MISSION_H
+#define DEF_MISSION_H
+
+#include "def.h"
+
+class PDefMission : public PDef
+{
+  private :
+    //int mIndex;
+       int mSourceId;
+    std::string mStartDialog;
+       int mDescTextId;
+       int mNpcType[4];
+    std::string mNpcDialog[4];
+       int mNpcDialogStartState[4];
+    int mTargetType[4];
+    int mTargetValue[4][3];
+    int mEndMoney;
+    int mEndXp;
+    int mMaxTime;
+    int mDifficulty;
+    int mMinFactionValue;
+    int mPoints;
+    int mFlags;
+
+  public :
+    PDefMission();
+    //~PDefMission();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+    inline int GetSourceId() const { return mSourceId; }
+    inline const std::string &GetStartDialog() const { return mStartDialog; }
+    inline int GetDescTextId() const { return mDescTextId; }
+    inline int GetNpcType(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < 4)) ? mNpcType[nIdx] : 0) ; }
+       inline const std::string &GetNpcDialog(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < 4)) ? mNpcDialog[nIdx] : EmptyString) ; }
+    inline int GetNpcDialogStartState(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < 4)) ? mNpcDialogStartState[nIdx] : 0) ; }
+       inline int GetTargetType(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < 4)) ? mTargetType[nIdx] : 0) ; }
+    inline int GetTargetValue(int nIdx, int nValIdx) const { return ( ((nIdx >= 0) && (nIdx < 4) && (nValIdx >= 0) && (nValIdx < 3)) ? mTargetValue[nIdx][nValIdx] : 0) ; }
+       inline int GetEndMoney() const { return mEndMoney; }
+    inline int GetEndXp() const { return mEndXp; }
+       inline int GetMaxTime() const { return mMaxTime; }
+    inline int GetDifficulty() const { return mDifficulty; }
+    inline int GetMinFactionValue() const { return mMinFactionValue; }
+       inline int GetPoints() const { return mPoints; }
+    inline int GetFlags() const { return mFlags; }
+};
+
+/*
+//mission source ID    > 0 NPC Type for mission source < 0 Terminal ID for mission source
+       
+//mission NPC Type     > 0 NPC Type for mission NPC    < 0 Fraction ID for mission NPC         
+//mission target Type  1 - kill NPC    2 - kill NPC type       "3 - dialogtrigger"     4 - kill NPC type range 5-dialogtrigger + counter       "6 - conquer outpost"   7 - conquer outpost + counter   8 - conquer + hold outpost              9-KillPlayer    10 - LootNPC    11 - LootNPCType
+
+//target value 1       ID of related mission NPC       > 0 NPC Type of NPCs to kill    < 0 FractionID of NPCs to kill  "ID of related mission NPC"     > 0 NPC Type of NPCs to kill    ID of related mission NPC       "> 0 outpost Type < 0 current outpost factionid"        > 0 outpost type < 0 original outpost faction type      > 0 outpost Type < 0 current outpost factionid          PlayerFaction   ID of related Mission NPC(0-4)  > 0 NPC Type of NPCs to kill    < 0 FractionID of NPCs to kill
+       
+//target value 2               Count of NPCs to kill   "ID of DialogTrigger"   Count of NPCs to kill   ID of DialogTrigger             Count of outposts to conquer    time to hold outpost            Kill Cnt        ItemID  NPC Cnt
+
+//target value 3                               Range of NPC Type       Trigger Counter - must reach 0 to be successfull                                        Max Leveldiff           Item ID
+//missionflags (bit field)
+// NPC0 No Search      1       
+// NPC1 No Search      2       
+// NPC2 No Search      4
+// NPC3 No Search      8
+*/
+#endif
diff --git a/server/src/game/include/def_npc.h b/server/src/game/include/def_npc.h
new file mode 100644 (file)
index 0000000..7edc88d
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_npc.h
+
+    CREATED: 03 Apr 2009 Hammag
+*/
+
+#ifndef DEF_NPC_H
+#define DEF_NPC_H
+
+#include "def.h"
+
+class PDefNpc : public PDef
+{
+  private :
+    //int mIndex;
+    int mModel; // <0: from characters.def, >0: from models.ini, [players] section (?)
+    //int mSoundId; // always 0: not used
+    int mNGT; // ? 1 - 4
+    int mGender; // 0 - 1
+    int mFaction;
+    int mHealth;
+    int mArmorId; // -1 or ref to NpcArmor
+    int mWeaponId;
+    std::string mDialogScript;
+    int mCombat; // ? 20 - 800
+    int mLoot; // 0 or ref to ItemContained
+    int mMovementEnd; // 0 - 4
+    int mFunctionType; // 0 - 4
+    float mModelScaling; // 0 - 0.9
+    int mMoneyLoose; // 0 - 190
+    float mSkillScale; // 0 - 120
+    std::string mStandardScript;
+    std::string mStandardParameter;
+    int mMass; // 1 - 10000
+    //int mStartHour; // not used
+    //int mEndHour; // not used
+    //std::string mTempScript; // not used
+    int mFlags; // values: 513, 259, 256, 128, 64, 48, 35, 34, 33, 32, 2, 1, 0
+\r
+  public :
+    PDefNpc();
+    //~PDefNpc();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+    inline int GetModel() const { return mModel; }
+    inline int GetNGT() const { return mNGT; }
+    inline int GetGender() const { return mGender; }
+    inline int GetFaction() const { return mFaction; }
+    inline int GetHealth() const { return mHealth; }
+    inline int GetArmorId() const { return mArmorId; }
+    inline int GetWeaponId() const { return mWeaponId; }
+    inline const std::string &GetDialogScript() const { return mDialogScript; }
+    inline int GetCombat() const { return mCombat; }
+    inline int GetLoot() const { return mLoot; }
+    inline int GetMovementEnd() const { return mMovementEnd; }
+    inline int GetFunctionType() const { return mFunctionType; }
+    inline float GetModelScaling() const { return mModelScaling; }
+    inline int GetMoneyLoose() const { return mMoneyLoose; }
+    inline float GetSkillScale() const { return mSkillScale; }
+    inline const std::string &GetStandardScript() const { return mStandardScript; }
+    inline const std::string &GetStandardParameter() const { return mStandardParameter; }
+    inline int GetMass() const { return mMass; }
+    inline int GetFlags() const { return mFlags; }
+};
+
+#endif
+
diff --git a/server/src/game/include/def_npcarmor.h b/server/src/game/include/def_npcarmor.h
new file mode 100644 (file)
index 0000000..6e48e5b
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_npcarmor.h
+
+    CREATED: 04 Apr 2009 Hammag
+*/
+
+#ifndef DEF_NPCARMOR_H
+#define DEF_NPCARMOR_H
+
+#include "def.h"
+
+class PDefNpcArmor : public PDef
+{
+  private :
+    //int mIndex;
+    int mValue[7]; // force piercing fire energy xray psi poison
+
+  public :
+    PDefNpcArmor();
+    //~PDefNpcArmor();
+
+    bool LoadFromDef ( PTokenList *Tokens );
+
+    inline int GetValue ( int nIdx ) const { return ( ( ( nIdx >= 0 ) && ( nIdx < 7 ) ) ? mValue[nIdx] : 0 ) ; }
+};
+
+#endif
diff --git a/server/src/game/include/def_npcgroupspawn.h b/server/src/game/include/def_npcgroupspawn.h
new file mode 100644 (file)
index 0000000..9f4f5e2
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_npcgroupspawn.h
+
+    CREATED: 03 Apr 2009 Hammag
+*/
+
+#ifndef DEF_NPCGROUPSPAWN_H
+#define DEF_NPCGROUPSPAWN_H
+
+#include "def.h"
+
+class PDefNpcGroupSpawn : public PDef
+{
+  private :
+    //int mIndex;
+    int mIgnoreNearPC;
+    int mNumNpc; // Size of the list. But that should be the size of the group...
+    int mNpcType[8];
+    std::string mScript[8];
+    std::string mScriptParameter[8];
+    int mFunctionValue[8];
+    int mSpawnChance[8];
+
+  public :
+    PDefNpcGroupSpawn();
+    //~PDefNpcGroupSpawn();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+    inline int GetIgnoreNearPC() const { return mIgnoreNearPC; }
+    inline int GetNumNpc() const { return mNumNpc; }
+    inline int GetNpcType(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mNumNpc)) ? mNpcType[nIdx] : 0) ; }
+    inline const std::string& GetScript(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mNumNpc)) ? mScript[nIdx] : EmptyString) ; }
+    inline const std::string& GetScriptParameter(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mNumNpc)) ? mScriptParameter[nIdx] : EmptyString) ; }
+    inline int GetFunctionValue(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mNumNpc)) ? mFunctionValue[nIdx] : 0) ; }
+    inline int GetSpawnChance(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mNumNpc)) ? mSpawnChance[nIdx] : 0) ; }
+};
+
+#endif
+
diff --git a/server/src/game/include/def_outposts.h b/server/src/game/include/def_outposts.h
new file mode 100644 (file)
index 0000000..ba626f7
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_outposts.h
+
+    CREATED: 03 Apr 2009 Hammag
+*/
+
+#ifndef DEF_OUTPOSTS_H
+#define DEF_OUTPOSTS_H
+
+#include "def.h"
+
+class PDefOutpost : public PDef
+{
+  private :
+    //int mIndex;
+    std::string mName;
+    int mType;
+    int mStandardFaction;
+    float mRevenue;
+    float mConquestReward;
+    int mMaxSecurity;
+    int mInfluenceZone[8]; // ex: 12 for zone A12, 112 for B12
+
+  public :
+    PDefOutpost();
+    //~PDefOutpost();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+    inline const std::string &GetName() const { return mName; }
+    inline int GetType() const { return mType; }
+    inline int GetStandardFaction() const { return mStandardFaction; }
+    inline float GetRevenue() const { return mRevenue; }
+    inline float GetConquestReward() const { return mConquestReward; }
+    inline int GetMaxSecurity() const { return mMaxSecurity; }
+    inline int GetInfluenceZone(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < 8)) ? mInfluenceZone[nIdx] : 0) ; }
+};
+
+#endif
+
diff --git a/server/src/game/include/def_recycles.h b/server/src/game/include/def_recycles.h
new file mode 100644 (file)
index 0000000..b03b8ae
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_recycles.h
+
+    CREATED: 03 Apr 2009 Hammag
+*/
+
+#ifndef DEF_RECYCLES_H
+#define DEF_RECYCLES_H
+
+#include "def.h"
+
+class PDefRecycle : public PDef
+{
+  private :
+    //int mIndex;
+    int mResultItemId; // We use resultitem as mIndex
+    int mBuildTime;
+    int mNumParts;
+    int mPartId[8];
+
+  public :
+    PDefRecycle();
+    //~PDefRecycle();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+    inline int GetResultItemId() const { return mResultItemId; }
+    inline int GetBuildTime() const { return mBuildTime; }
+    inline int GetNumParts() const { return mNumParts; }
+    inline int GetPartId(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mNumParts)) ? mPartId[nIdx] : 0 ) ; }
+};
+
+#endif
+
diff --git a/server/src/game/include/def_respawn.h b/server/src/game/include/def_respawn.h
new file mode 100755 (executable)
index 0000000..3ede3f9
--- /dev/null
@@ -0,0 +1,68 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       def_respawn.h\r
+\r
+       MODIFIED: 22 Sep 2006 Hammag\r
+       REASON: - Creation\r
+       \r
+*/\r
+\r
+#ifndef DEF_RESPAWN_H\r
+#define DEF_RESPAWN_H\r
+\r
+#include "def.h"\r
+\r
+class PDefRespawn : public PDef\r
+{\r
+       private :\r
+               //int mIndex;\r
+               int mWorldID;\r
+               int mEntityID; // Station ID\r
+               int mHazardLevel;\r
+               std::string mName; // Description\r
+               std::string mFlag; // ???\r
+\r
+       public :\r
+               PDefRespawn();\r
+               //~PDefRespawn();\r
+\r
+               bool LoadFromDef(PTokenList *Tokens);\r
+\r
+               inline int GetWorldID() const { return mWorldID; }\r
+               inline int GetEntityID() const { return mEntityID; }\r
+               inline int GetHazardLevel() const { return mHazardLevel; }\r
+               inline const std::string &GetName() const { return mName; }\r
+               inline const std::string &GetFlag() const { return mFlag; }\r
+\r
+};\r
+\r
+\r
+class PDefRespawnsMap : public PDefMap<PDefRespawn>\r
+{\r
+  public:\r
+    int GetRespawnEntity( u32 nWorldID, u16 nGROrder ) const;\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/def_scripts.h b/server/src/game/include/def_scripts.h
new file mode 100644 (file)
index 0000000..5a9bf23
--- /dev/null
@@ -0,0 +1,62 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+ def_scripts.h\r
+\r
+    CREATED: 12 Oct 2009 Namikon\r
+*/\r
+\r
+#ifndef DEF_SCRIPTS_H\r
+#define DEF_SCRIPTS_H\r
+\r
+#include "def.h"\r
+\r
+class PDefScripts : public PDef\r
+{\r
+  private :\r
+    //int mIndex;\r
+    std::string mIdentifier;\r
+    std::string mLuaFile;\r
+    std::string mScriptHeader;\r
+\r
+  public :\r
+    PDefScripts();\r
+    //~PDefWeapon();\r
+\r
+    bool LoadFromDef( PTokenList *Tokens );\r
+\r
+    inline const std::string &GetIdentifier() const { return mIdentifier; }\r
+    inline const std::string &GetLuaFile() const { return mLuaFile; }\r
+    inline const std::string &GetScriptHeader() const { return mScriptHeader; }\r
+};\r
+\r
+class PDefScriptsMap : public PDefMap<PDefScripts>\r
+{\r
+  public:\r
+    //bool Load(const char* nName, const char* nFilename);\r
+    inline std::map<int, PDefScripts*>::const_iterator ConstIteratorBegin() const { return mDefs.begin(); }\r
+    inline std::map<int, PDefScripts*>::const_iterator ConstIteratorEnd() const { return mDefs.end(); }\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/def_shots.h b/server/src/game/include/def_shots.h
new file mode 100644 (file)
index 0000000..128b12c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_shots.h
+
+    CREATED: 03 Apr 2009 Hammag
+*/
+
+#ifndef DEF_SHOTS_H
+#define DEF_SHOTS_H
+
+#include "def.h"
+
+class PDefShot : public PDef
+{
+  private :
+    //int mIndex;
+    int mDamageId;
+    int mMass;
+    int mRadius;
+    float mSpeed;
+    //int mHitSound;
+    //int mCustomType;
+    //std::string mCustomFrameFx;
+    //std::string mCustomHitFx;
+
+  public :
+    PDefShot();
+    //~PDefShot();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+    inline int GetDamageId() const { return mDamageId; }
+    inline int GetMass() const { return mMass; }
+    inline int GetRadius() const { return mRadius; }
+    inline int GetSpeed() const { return mSpeed; }
+};
+
+#endif
+
diff --git a/server/src/game/include/def_skills.h b/server/src/game/include/def_skills.h
new file mode 100644 (file)
index 0000000..b70675b
--- /dev/null
@@ -0,0 +1,57 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       def_skills.h\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+*/\r
+\r
+#ifndef DEF_SKILLS_H\r
+#define DEF_SKILLS_H\r
+\r
+#include "def.h"\r
+\r
+class PDefSkill : public PDef\r
+{\r
+       private :\r
+               //int mIndex;\r
+               std::string mName;\r
+               std::string mShortName;\r
+               int mNumSubSkills;\r
+               int *mSubSkills;\r
+       public :\r
+               PDefSkill();\r
+               ~PDefSkill();\r
+\r
+               bool LoadFromDef(PTokenList *Tokens);\r
+\r
+               inline const std::string &GetName() const { return mName; }\r
+               inline const std::string &GetShortName() const { return mShortName; }\r
+               inline int GetNumSubSkills() const { return mNumSubSkills; }\r
+               inline int GetSubSkill(int Index) const { return mSubSkills[Index]; }\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/include/def_subskills.h b/server/src/game/include/def_subskills.h
new file mode 100644 (file)
index 0000000..f7d0390
--- /dev/null
@@ -0,0 +1,59 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       def_subskill.h\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+*/\r
+\r
+#ifndef DEF_SUBSKILLS_H\r
+#define DEF_SUBSKILLS_H\r
+\r
+#include "def.h"\r
+\r
+class PDefSubSkill : public PDef\r
+{\r
+       private :\r
+               //int mIndex;\r
+               std::string mName;\r
+               std::string mShortName;\r
+               float mStrengthenFactor;\r
+               int mNumActionModifiers;\r
+               int *mActionModifiers;\r
+       public :\r
+               PDefSubSkill();\r
+               ~PDefSubSkill();\r
+\r
+               bool LoadFromDef(PTokenList *Tokens);\r
+\r
+               inline const std::string &GetName() const { return mName; }\r
+               inline const std::string &GetShortName() const { return mShortName; }\r
+               inline float GetStrengthenFactor() const { return mStrengthenFactor; }\r
+               inline int GetNumActionModifiers() const { return mNumActionModifiers; }\r
+               inline int GetActionModifier(int Index) const { return mActionModifiers[Index]; }\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/include/def_trader.h b/server/src/game/include/def_trader.h
new file mode 100644 (file)
index 0000000..bbb246d
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_trader.h
+
+    CREATED: 03 Apr 2009 Hammag
+*/
+
+#ifndef DEF_TRADER_H
+#define DEF_TRADER_H
+
+#include "def.h"
+#define DEF_TRADER_MAXENTRIES 17
+
+class PDefTrader : public PDef
+{
+  private :
+    //int mIndex;
+    int mType;
+    float mMaxWealth;
+    float mWealthRespawn;
+    int mQuality;
+    int mItemId[DEF_TRADER_MAXENTRIES]; // <0: item group
+    float mItemPriceScale[DEF_TRADER_MAXENTRIES]; // sometime string like "1/5" ??? <=> 0.2 or Sell:1 / Buy 5 ????
+
+  public :
+    PDefTrader();
+    //~PDefTrader();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+    inline int GetType() const { return mType; }
+    inline float GetMaxWealth() const { return mMaxWealth; }
+    inline float GetWealthRespawn() const { return mWealthRespawn; }
+    inline int GetQuality() const { return mQuality; }
+    inline int GetItemId(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < DEF_TRADER_MAXENTRIES)) ? mItemId[nIdx] : 0 ) ; }
+    inline float GetItemPriceScale(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < DEF_TRADER_MAXENTRIES)) ? mItemPriceScale[nIdx] : 0 ) ; }
+};
+/* Trader/Buyer mType
+//     1       weapons 
+//     2       ammo    
+//     3       armor   
+//     4       tools   
+//     5       psi equipment   
+//     
+//     10      chemicals       
+//     11      item parts      
+//     12      implants        
+//     13      bone enforcements       
+//     
+//     16      Buy anything    
+//     
+//     20      refreshments    
+//     21      drugs   
+//     22      medicaments     
+//     23      real estates    
+//     24      vehicles        
+//     
+*/
+#endif
+
diff --git a/server/src/game/include/def_vehicles.h b/server/src/game/include/def_vehicles.h
new file mode 100644 (file)
index 0000000..9ffcca2
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_vehicles.h
+
+    CREATED: 03 Apr 2009 Hammag
+*/
+
+#ifndef DEF_VEHICLES_H
+#define DEF_VEHICLES_H
+
+#include "def.h"
+
+class PDefVhc : public PDef
+{
+  private :
+    //int mIndex; // field 1
+    int mModel;
+    std::string mName;
+    /*
+    float mLeftFront; // field 4
+    float mFront;
+    float mRightBack;
+    float mBack;
+    float mSideFriction;
+    float mDownFriction;
+    float mForwardFriction;
+    float mAcceleration;
+    float mBrakeFactor;
+    float mTurnSpeed;
+    float mFullTurnDelay;
+    int mAnimClass; // field 15
+    */
+    int mSeatId[8]; // fields 16 - 23
+    /*
+    float mSpeedTiltFactor; // field 24
+    float mSpeedGlideFactor;
+    float mMinHover;
+    float mMaxHover;
+    float mHoverLoopLen;
+    int mWheelCnt;
+    float mWheelSpeed;
+    float mMaxDive;
+    int mEffectsID;
+    int mShowDebugBouncer; // field 33
+    */
+    int mHealth;
+    int mArmor;
+    //int mSoundStartindex; // field 36
+
+    // Additionnal info
+    int mNumSeats;
+    
+  public :
+    PDefVhc();
+    //~PDefVhc();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+    inline int GetModel() const { return mModel; }
+    inline const std::string &GetName() const { return mName; }
+    inline int GetSeatId( int nIdx ) const { return ((( nIdx >= 0 ) && ( nIdx < 8 ) ) ? mSeatId[nIdx] : -1) ; }
+    inline int GetHealth() const { return mHealth; }
+    inline int GetArmor() const { return mArmor; }
+    inline int GetNumSeats() const { return mNumSeats; }
+};
+
+#endif
+
diff --git a/server/src/game/include/def_vehiclesits.h b/server/src/game/include/def_vehiclesits.h
new file mode 100644 (file)
index 0000000..310ff77
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_vehiclesits.h
+
+    CREATED: 03 Apr 2009 Hammag
+*/
+
+#ifndef DEF_VEHICLESEATS_H
+#define DEF_VEHICLESEATS_H
+
+#include "def.h"
+
+class PDefVhcSeat : public PDef
+{
+  private :
+    //int mIndex; //Field 1
+    int mType;
+    std::string mName; //Field 3
+    //BasePosX Y Z
+    //BaseAngleX Y Z
+    float mLeavePos[3]; //X Y Z - Fields 10-12
+    float mLeaveAngle[3]; //X Y Z - Fields 13-15
+    //FirePosX Y Z //Field 16
+    //XLock Ylock MinX MaxX TurnSpeed ForceExternalCam ShowActor 
+    //SitBone RotXBone RotYBone WeaponBone
+    int mWeaponId; //Field 30
+    int mTL;
+    float mDamageFactor;
+    //SitAnimType SitYOffset //Field 33
+    //SitFlags
+
+  public :
+    PDefVhcSeat();
+    //~PDefVhcSeat();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+    inline int GetType() const { return mType; }
+    inline const std::string &GetName() const { return mName; }
+    inline float GetLeavePos(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < 3)) ? mLeavePos[nIdx] : 0) ; }
+    inline float GetLeaveAngle(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < 3)) ? mLeaveAngle[nIdx] : 0) ; }
+    inline int GetWeaponId() const { return mWeaponId; }
+    inline int GetTL() const { return mTL; }
+    inline float GetDamageFactor() const { return mDamageFactor; }
+};
+/*
+mType:
+0 - Driver                     (Ground vhc)
+1 - Gunner
+2 - Passenger
+3 - Driver/Gunner
+4 - Pilot                      (Flying vhc)
+5 - Pilot/Gunner               (Flying vhc)
+6 - Pilot                      (Senkrechtstarter ????)
+
+mFlags:
+1 - Winkel f�r Spieler und Waffe wird auf Fahrzeugrichtung gelockt. Zielrichtung darf nur leicht von der Fahrzeugrichtung abweichen
+2 - Spieler wird gelockt
+4 - Waffe ist nicht um X Achse drehbar
+8 - Waffe ist nicht um Y Achse drehbar
+16 - Spielermodel um 180 Grad gedreht
+*/
+#endif
+
diff --git a/server/src/game/include/def_weapons.h b/server/src/game/include/def_weapons.h
new file mode 100644 (file)
index 0000000..bebdab7
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+
+
+/*
+ def_weapons.h
+
+    CREATED: 29 Mar 2009 Hammag
+*/
+
+#ifndef DEF_WEAPONS_H
+#define DEF_WEAPONS_H
+
+#include "def.h"
+
+class PDefWeapon : public PDef
+{
+  private :
+    //int mIndex;
+    std::string mName;
+    //int mFpsmodel;
+    //int mAttachmodel;
+    //int mMunactor;
+    //float mDroptime; // useful ?
+    int mItemIndex;
+    //int effectcolor[3]; // R,G,B
+    //int dynamiclight;
+    //float lighttime;
+    //int soundindex;
+    //float mShotTime; // useful ?
+    int mAmmoUse;
+    int mPSIuse;
+    float mStaminaUse;
+    //float upthrow;
+    //int weaponHold; // ???
+    int mWeaponType;
+    int mDiscardable;
+    float mSkillFactor;
+    //int mintgtRad;
+    //int maxtgtRad;
+    int mMaxRange;
+    int mAggressiveWeapon;
+    float mDamageMultiplicator;
+    int mAmmoTypes[8];
+    int mAmmoStartFlags; // ???
+    //int customclasstype; // ?
+    //int unknown // ?
+    int mShotCnt;
+    //float shotduration; // maybe useful later ?
+    //std::string shotfx;
+    //float attachposx;
+    //float attachposy;
+    //float attachposz;
+    //float fpposx;
+    //float fpposy;
+    //float fpposz;
+    int mBaseWeaponId;
+    //int weaponcolor;
+    //int reloadsound;
+    int mItemModGroup;
+    int mItemModGroupFlags;
+    int mRareWeaponFx;
+
+  public :
+    PDefWeapon();
+    //~PDefWeapon();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+    inline const std::string &GetName() const { return mName; }
+    inline int GetItemID() const { return mItemIndex; }
+    inline int GetAmmoUse() const { return mAmmoUse; }
+    inline int GetPsiUse() const { return mPSIuse; }
+    inline float GetStaminaUse() const { return mStaminaUse; }
+    inline int GetWeaponType() const { return mWeaponType; }
+    inline bool IsDiscardable() const { return mDiscardable; }
+    inline float GetSkillFactor() const { return mSkillFactor; }
+    inline int GetMaxRange() const { return mMaxRange; }
+    inline bool IsAggressiveWeapon() const { return mAggressiveWeapon; }
+    inline float GetDamageMultiplicator() const { return mDamageMultiplicator; }
+    inline int GetAmmoType(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < 8)) ? mAmmoTypes[nIdx] : 0) ; }
+    inline int GetAmmoStartFlags() const { return mAmmoStartFlags; } 
+    inline int GetShotCnt() const { return mShotCnt; }
+    inline int GetBaseWeaponId() const { return mBaseWeaponId; }
+    inline int GetItemModGroup() const { return mItemModGroup; }
+    inline int GetItemModGroupFlags() const { return mItemModGroupFlags; }
+    inline int GetRareWeaponFx() const { return mRareWeaponFx; }
+};
+
+#endif
diff --git a/server/src/game/include/def_weather.h b/server/src/game/include/def_weather.h
new file mode 100644 (file)
index 0000000..5d7a016
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ def_weather.h
+
+    CREATED: 03 Apr 2009 Hammag
+*/
+
+#ifndef DEF_WEATHER_H
+#define DEF_WEATHER_H
+
+#include "def.h"
+//weathersectionid weathercnt weatherid length end
+class PDefWeather : public PDef
+{
+  private :
+    //int mIndex;
+    int mSectionId;
+    int mNumWeathers;
+    int mWeatherId[8];
+    int mDuration[8];
+
+  public :
+    PDefWeather();
+    //~PDefWeather();
+
+    bool LoadFromDef( PTokenList *Tokens );
+
+    inline int GetSectionId() const { return mSectionId; }
+    inline int GetNumWeathers() const { return mNumWeathers; }
+    inline int GetWeatherId(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mNumWeathers)) ? mWeatherId[nIdx] : 0 ) ; }
+    inline int GetDuration(int nIdx) const { return ( ((nIdx >= 0) && (nIdx < mNumWeathers)) ? mDuration[nIdx] : 0 ) ; }
+};
+
+/* mWeatherId
+//BRIGHTSKY            (1)
+//SINGLECLOUDS         (2)
+//CLOUDY               (3)
+
+//LIGHTRAIN            (4)
+//HEAVYRAIN            (5)
+//THUNDERSTORM         (6)
+
+//SNOW                 (7)
+//SANDSTORM            (8)
+//FALLOUT              (9)
+
+//SEA_BRIGHTSKY                (100)
+*/
+#endif
+
diff --git a/server/src/game/include/def_worldfile.h b/server/src/game/include/def_worldfile.h
new file mode 100755 (executable)
index 0000000..b5dfbd3
--- /dev/null
@@ -0,0 +1,62 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       def_worldfile.h (infos from worlds/worlds.ini)\r
+\r
+       MODIFIED: 28 Sep 2007 Hammag\r
+       REASON: - Creation\r
+*/\r
+\r
+#ifndef DEF_WORLDFILE_H\r
+#define DEF_WORLDFILE_H\r
+\r
+#include "def.h"\r
+\r
+class PDefWorldFile : public PDef\r
+{\r
+       private :\r
+               //int mIndex;\r
+               std::string mName; // dat filename with ending extension and starting ./ or ./worlds/ REMOVED\r
+               bool mFileInWorldsDir; // TRUE if worlds/ must be appendend before mName to get real file name (dat file at least)\r
+               \r
+       public :\r
+               PDefWorldFile();\r
+               //~PDefWorldFile();\r
+\r
+               bool LoadFromDef(PTokenList *Tokens);\r
+\r
+               inline const std::string &GetName() const { return mName; }\r
+               inline const std::string GetBasicFileName() const { return (mFileInWorldsDir ? (std::string("worlds/") + mName) : mName); };\r
+};\r
+\r
+\r
+class PDefWorldFilesMap : public PDefMap<PDefWorldFile>\r
+{\r
+  public:\r
+    bool Load(const char* nName, const char* nFilename);\r
+    inline std::map<int, PDefWorldFile*>::const_iterator ConstIteratorBegin() const { return mDefs.begin(); }\r
+    inline std::map<int, PDefWorldFile*>::const_iterator ConstIteratorEnd() const { return mDefs.end(); }\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/def_worldmodels.h b/server/src/game/include/def_worldmodels.h
new file mode 100644 (file)
index 0000000..3d4ff27
--- /dev/null
@@ -0,0 +1,62 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+/*\r
+       def_WorldModels.h\r
+\r
+       Created: 21 Sep 2006 Hammag\r
+       REASON: -\r
+*/\r
+\r
+#ifndef DEF_WORLDMODELS_H\r
+#define DEF_WORLDMODELS_H\r
+\r
+#include "def.h"\r
+\r
+class PDefWorldModel : public PDef\r
+{\r
+       private :\r
+               //int mIndex;\r
+               std::string mName;\r
+               int mUseFlags;\r
+               int mFunctionType;\r
+               int mFunctionValue;\r
+               int mHackDifficulty;\r
+               int mHackPenalty;\r
+               \r
+       public :\r
+               PDefWorldModel();\r
+               //~PDefWorldModel();\r
+\r
+               bool LoadFromDef(PTokenList *Tokens);\r
+\r
+               inline int GetID() const { return mIndex; }\r
+               inline const std::string &GetName() const { return mName; }\r
+               inline int GetUseFlags() const { return mUseFlags; }\r
+               inline int GetFunctionType() const { return mFunctionType; }\r
+               inline int GetFunctionValue() const { return mFunctionValue; }\r
+               inline int GetHackDifficulty() const { return mHackDifficulty; }\r
+               inline int GetHackPenalty() const { return mHackPenalty; }\r
+\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/def_worlds.h b/server/src/game/include/def_worlds.h
new file mode 100644 (file)
index 0000000..3b94bf6
--- /dev/null
@@ -0,0 +1,54 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       def_worlds.h\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+*/\r
+\r
+#ifndef DEF_WORLDS_H\r
+#define DEF_WORLDS_H\r
+\r
+#include "def.h"\r
+\r
+class PDefWorld : public PDef\r
+{\r
+       private :\r
+               //int mIndex;\r
+               std::string mName;\r
+               std::string mDatFile;\r
+               int mFlags;\r
+       public :\r
+               PDefWorld();\r
+               //~PDefWorld();\r
+\r
+               bool LoadFromDef(PTokenList *Tokens);\r
+\r
+               inline const std::string &GetName() const { return mName; }\r
+               inline const std::string &GetDatFile() const { return mDatFile; }\r
+               inline int GetFlags() const { return mFlags; }\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/defmap.h b/server/src/game/include/defmap.h
new file mode 100644 (file)
index 0000000..9bc5038
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+
+
+/*
+ defmap.h
+ Definiton of template class for def maps.
+
+    CREATED: 30 Mar 2009 Hammag
+*/
+
+template <class T> class PDefMap
+{
+  protected:
+    std::string mName;
+    std::map<int, T*> mDefs;
+
+    void Clear();
+
+  public:
+    PDefMap () {};
+    ~PDefMap ();
+
+    bool Load(const char* nName, const char* nFilename);
+    inline int GetNumDefs() const { return mDefs.size(); }
+    const T* GetDef( int Index ) const;
+};
+
+template <class T> PDefMap<T>::~PDefMap()
+{
+  Clear();
+}
+
+template <class T> void PDefMap<T>::Clear()
+{
+  for ( typename std::map<int, T*>::iterator i = mDefs.begin(); i != mDefs.end(); i++ )
+    delete i->second;
+  mDefs.clear();
+}
+
+template <class T> bool PDefMap<T>::Load(const char* nName, const char* nFilename)
+{
+  mName = nName;
+  if(mName.empty())
+  {
+    Console->Print( "%s Defs name not defined", Console->ColorText( RED, BLACK, "[ERROR]" ) );
+    return (false);
+  }
+  
+  if(! *nFilename)
+  {
+    Console->Print( "%s Filename not defined for %s defs", Console->ColorText( RED, BLACK, "[ERROR]" ), mName.c_str() );
+    return (false);
+  }
+
+  PDefParser parser;
+  int nDefs = 0, nErrors = 0;
+
+  if ( parser.Parse( nFilename ) )
+  {
+    const PDefTokenList &t = parser.GetTokens();
+
+    for ( PDefTokenList::const_iterator i = t.begin(); i != t.end(); i++ )
+    {
+      T* entry = new T();
+      bool insertfail = false;
+      bool loadfail = ! entry->LoadFromDef( *i );
+
+      if ( !loadfail )
+        insertfail = ! mDefs.insert( std::make_pair( entry->GetIndex(), entry ) ).second;
+
+      if ( loadfail || insertfail )
+      {
+        if ( insertfail )
+          Console->Print( "%s %s def error (duplicate id %i): %s", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ),  mName.c_str(), entry->GetIndex(), entry->GetName().c_str() );
+        else
+          Console->Print( "%s def load error @ %i", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), mName.c_str(), nDefs + nErrors );
+        ++nErrors;
+        delete entry;
+      }
+      else
+        ++nDefs;
+    }
+  }
+  else
+  {
+    Console->Print( "%s Error loading %s defs", Console->ColorText( YELLOW, BLACK, "[WARNING]" ),  mName.c_str() );
+    return (false);
+  }
+
+  if ( nErrors > 0 )
+    Console->Print( "%s Loaded %i %s defs, %i error(s).", Console->ColorText( RED, BLACK, "[WARNING]" ), nDefs,  mName.c_str(), nErrors );
+  else
+    Console->Print( "%s Loaded %i %s defs, %i error(s).", Console->ColorText( GREEN, BLACK, "[Success]" ), nDefs,  mName.c_str(), nErrors );
+
+  return ( true );
+}
+
+template <class T> const T* PDefMap<T>::GetDef( int Index ) const
+{
+  T* Result;
+
+  typename std::map<int, T*>::const_iterator i = mDefs.find( Index );
+  Result = ( ( i != mDefs.end() ) ? i->second : NULL );
+
+  return ( Result );
+}
diff --git a/server/src/game/include/defparser.h b/server/src/game/include/defparser.h
new file mode 100644 (file)
index 0000000..332662c
--- /dev/null
@@ -0,0 +1,53 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       defparser.h\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+*/\r
+\r
+#ifndef DEFPARSER_H\r
+#define DEFPARSER_H\r
+\r
+#ifdef _MSC_VER\r
+       #pragma once\r
+#endif\r
+\r
+typedef std::list<std::string> PTokenList;\r
+typedef std::list<PTokenList*> PDefTokenList;\r
+\r
+class PDefParser\r
+{\r
+       private :\r
+               PDefTokenList mTokens;\r
+       public :\r
+               PDefParser();\r
+               ~PDefParser();\r
+               bool Parse(const char *File);\r
+               inline const PDefTokenList &GetTokens() const { return mTokens; }\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/include/defs.h b/server/src/game/include/defs.h
new file mode 100755 (executable)
index 0000000..9f644c7
--- /dev/null
@@ -0,0 +1,81 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       defs.h - include file for all def_* files related stuff used by all modules\r
+\r
+       MODIFIED: 21 Sep 2006 Hammag\r
+       REASON: - created\r
+\r
+*/\r
+\r
+#ifndef DEFS_H\r
+#define DEFS_H\r
+\r
+#include "defparser.h"\r
+#include "defmap.h"\r
+\r
+#include "def_actionmod.h"\r
+#include "def_ammo.h"\r
+#include "def_appartements.h"\r
+#include "def_appplaces.h"\r
+#include "def_blueprintpieces.h"\r
+#include "def_characters.h"\r
+#include "def_charaction.h"\r
+#include "def_charkinds.h"\r
+#include "def_damage.h"\r
+#include "def_drugs.h"\r
+#include "def_factions.h"\r
+#include "def_hack.h"\r
+#include "def_implants.h"\r
+#include "def_itemcontainer.h"\r
+#include "def_itemmod.h"\r
+#include "def_itemres.h"\r
+#include "def_items.h"\r
+#include "def_mission.h"\r
+#include "def_npcarmor.h"\r
+#include "def_npcgroupspawn.h"\r
+#include "def_npc.h"\r
+#include "def_outposts.h"\r
+#include "def_recycles.h"\r
+#include "def_respawn.h"\r
+#include "def_shots.h"\r
+#include "def_skills.h"\r
+#include "def_subskills.h"\r
+#include "def_trader.h"\r
+#include "def_vehicles.h"\r
+#include "def_vehiclesits.h"\r
+#include "def_weapons.h"\r
+#include "def_weather.h"\r
+#include "def_worlds.h"\r
+#include "def_worldfile.h"\r
+#include "def_worldmodels.h"\r
+\r
+#include "def_scripts.h"\r
+\r
+#include "gamedefs.h"\r
+\r
+using namespace std;\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/include/doortemplate.h b/server/src/game/include/doortemplate.h
new file mode 100755 (executable)
index 0000000..fc8f9d1
--- /dev/null
@@ -0,0 +1,79 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+/*\r
+  doortemplate.h - world door template class\r
+\r
+       MODIFIED: 05 Nov 2006 Hammag\r
+       REASON: - creation\r
+       \r
+*/\r
+\r
+\r
+#ifndef DOORTEMPLATE_H\r
+#define DOORTEMPLATE_H\r
+\r
+#include "def_worldmodels.h"\r
+\r
+class PDoorTemplate\r
+{\r
+  friend class PWorldDatParser;\r
+  \r
+  private:\r
+    u16 mDoorID;\r
+\r
+    // The commented out values are not loaded from dat file atm because they are not used yet.\r
+    //u16 mUnknown1; //18 00\r
+    //u16 mUnknown1bis; //00 00 ? varies\r
+    f32 mPosY;\r
+    f32 mPosZ;\r
+    f32 mPosX;\r
+    //u16 mUnknown5; //00 00 ? second byte varies\r
+    u16 mWorldmodelID; //door type from worldmodel.def\r
+\r
+    std::string mDoorTypeName;  \r
+    int mDoorParameters[4];\r
+    bool mIsDoubleDoor;\r
+    bool mIsTriggeredDoor;\r
+    \r
+    const PDefWorldModel* mDefWorldModel;\r
+\r
+  public:\r
+    PDoorTemplate();\r
+    ~PDoorTemplate();\r
+\r
+    inline u16 GetID() { return mDoorID; }\r
+    inline u16 GetUseFlags() { return (mDefWorldModel ? mDefWorldModel->GetUseFlags() : 0); }\r
+    inline u16 GetFunctionType() { return (mDefWorldModel ? mDefWorldModel->GetFunctionType() : 0); }\r
+    inline int GetFunctionValue() { return (mDefWorldModel ?  mDefWorldModel->GetFunctionValue() : 0); }\r
+    inline const std::string& GetName() const { return (mDefWorldModel ?  mDefWorldModel->GetName() : EmptyString ); } /// !!!!\r
+    inline const PDefWorldModel* GetDefWorldModel() const { return mDefWorldModel; }\r
+    \r
+    inline void GetPos(f32* nPosX, f32* nPosY, f32* nPosZ) const { *nPosY = mPosY; *nPosZ = mPosZ; *nPosX = mPosX;}\r
+    inline u16 GetOtherDoorID() { return ( mIsDoubleDoor ? mDoorParameters[1] : 0 ); }\r
+    inline bool IsDoubleDoor() const { return mIsDoubleDoor; }\r
+    inline bool IsTriggeredDoor() const { return mIsTriggeredDoor; }\r
+    \r
+    void SetDoorTypeName(char* nDoorTypeName);\r
+    void SetDoorParameters(char* nDoorParametersString);\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/furnituretemplate.h b/server/src/game/include/furnituretemplate.h
new file mode 100755 (executable)
index 0000000..9f84ebb
--- /dev/null
@@ -0,0 +1,144 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+/*\r
+  furnituretemplate.h - world furniture template class\r
+\r
+ MODIFIED: 04 Oct 2006 Hammag\r
+ REASON: - creation\r
+\r
+*/\r
+\r
+\r
+#ifndef FURNITURETEMPLATE_H\r
+#define FURNITURETEMPLATE_H\r
+\r
+#include "def_worldmodels.h"\r
+\r
+enum // Furniture Use flags (cumlative)\r
+{\r
+  ufTouchable = 1,\r
+  ufUsable = 2,\r
+  ufNoCollision = 4,\r
+  ufChair = 8,\r
+  ufToolTarget = 16,\r
+  ufSelfCollisionBox = 64,\r
+  ufGraphicalEffect = 128,\r
+  ufNoSelectionBox = 256\r
+};\r
+\r
+class PFurnitureItemTemplate\r
+{\r
+    friend class PWorldDatParser;\r
+\r
+  private:\r
+    u32 mObjectID;\r
+\r
+    // The commented out values are not loaded from dat file atm because they are not used yet.\r
+    f32 mPosY; //= mPosY from dat file + 32000, to be coherent with char Pos scale\r
+    f32 mPosZ;\r
+    f32 mPosX;\r
+    //f32 mRotY;\r
+    f32 mRotZ;\r
+    //f32 mRotX;\r
+    //u32 mScale; //00 00 80 3F ?  = float(1.0000) scale factor ? // mostly used by holoscreens (passiv object)\r
+    //u32 mUnknown2; //01 00 00 00 ?\r
+    u16 mModelID; // points to models.ini\r
+    //u32 mUnknown3; //00 00 00 00 ?\r
+    //u32 mUnknown4; //00 00 00 00 ?\r
+    u16 mWorldmodelID; // points to worldmodel.def\r
+    //u16 mUnknown5; //12 00 ? // changes sometime (ex: c288 ...)\r
+\r
+    //f32 mBoxLowerY; //Bounding box, for use when ufSelfCollisionBox is set in mUseFlags.\r
+    //f32 mBoxLowerZ;\r
+    //f32 mBoxLowerX;\r
+    //f32 mBoxUpperY;\r
+    //f32 mBoxUpperZ;\r
+    //f32 mBoxUpperX;\r
+\r
+    u16 mFrontPosY;\r
+    u16 mFrontPosZ;\r
+    u16 mFrontPosX;\r
+    u8 mFrontLR;\r
+\r
+    const PDefWorldModel* mDefWorldModel;\r
+\r
+    u32 mLinkedObjectID; // for buttons, stores the corresponding triggered door\r
+    // fo GR, stores order of the GR entity (spawn point) to later choose from respawn.def data\r
+\r
+  public:\r
+    PFurnitureItemTemplate();\r
+    ~PFurnitureItemTemplate();\r
+\r
+    inline u32 GetID() const { return mObjectID; }\r
+    inline u16 GetUseFlags() const { return ( mDefWorldModel ? mDefWorldModel->GetUseFlags() : 0 ); }\r
+    inline u16 GetFunctionType() const { return ( mDefWorldModel ? mDefWorldModel->GetFunctionType() : 0 ); }\r
+    inline int GetFunctionValue() const{ return ( mDefWorldModel ?  mDefWorldModel->GetFunctionValue() : 0 ); }\r
+    inline const std::string& GetName() const { return ( mDefWorldModel ?  mDefWorldModel->GetName() : EmptyString ); } /// !!!!\r
+    inline const PDefWorldModel* GetDefWorldModel() const { return mDefWorldModel; }\r
+    inline u8 GetFrontLR() const { return mFrontLR; }\r
+    inline void GetFrontPos( u16* nFrontPosX, u16* nFrontPosY, u16* nFrontPosZ ) const { *nFrontPosY = mFrontPosY; *nFrontPosZ = mFrontPosZ; *nFrontPosX = mFrontPosX;}\r
+    inline void GetPos( f32* nPosX, f32* nPosY, f32* nPosZ ) const { *nPosY = mPosY; *nPosZ = mPosZ; *nPosX = mPosX;}\r
+\r
+    inline void SetLinkedObjectID( u32 nID ) { mLinkedObjectID = nID; }\r
+    inline u32 GetLinkedObjectID() const { return mLinkedObjectID; }\r
+\r
+};\r
+\r
+#endif\r
+\r
+// *** from worldmodel.def ***\r
+\r
+//function Type\r
+// 0 - none\r
+//  1 - Itemcontainer\r
+// 2 - Terminal\r
+// 3 - Outfitter\r
+// 4 - Trader\r
+// 5 - Mineral\r
+// 6 - Respawn Station\r
+// 7 - GoGuardian\r
+// 8 - Hackterminal\r
+// 9 - Appartement Eingang\r
+// 10 - Appartement Ein/Ausgang\r
+// 11 - Appartement Klingel/�ffner\r
+// 12 - Standard Button\r
+// 13 - Hack Button\r
+// 14 - HOLOMATCH ENTRANCE\r
+// 15 - HOLOMATCH EXIT\r
+// 16 - HOLOMATCH REFRESH\r
+// 17 - HOLOMATCH HEAL\r
+// 18 - WORLDCHANGEACTOR\r
+// 19 - CLANTERMINAL\r
+// 20 - DATFILE WORLDCHANGE ACTOR\r
+// 21 - LOCATION FOR 20\r
+// 22 -\r
+// 23 - EINTRITTSGELD BUTTON\r
+// 24- TUTORIALEXIT\r
+// 25 - EXPLOSIVE\r
+// 26 - Outpost Switch\r
+// 27 - Old goguardian\r
+// 28 - Fahrzeug Depot Interface\r
+// 29 - Underground Exit\r
+// 30 - Static FX (Value=Type. 1=Fire 2=Smoke 3=Steam 4=Sparkle)\r
+// 31 - Venture Warp Station\r
+// 32 - functionvalue+100 gibt eine Meldung aus der Text.ini [MISC] an.\r
+//\r
diff --git a/server/src/game/include/gamedefs.h b/server/src/game/include/gamedefs.h
new file mode 100755 (executable)
index 0000000..486caee
--- /dev/null
@@ -0,0 +1,178 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+ gamedefs.h\r
+\r
+ MODIFIED: 25 Dec 2005 Namikon\r
+ REASON: - Added GPL\r
+ MODIFIED: 21 Sep 2005 Hammag\r
+ REASON: - Added PDefWorldModel related stuff\r
+         - Added PDefAppPlace related stuff\r
+  MODIFIED: 22 Sep 2005 Hammag\r
+ REASON: - Added PDefAppartement related stuff\r
+         - Added PDefRespawn related stuff\r
+  MODIFIED: 28 Sep 2005 Hammag\r
+ REASON: - Added PDefWorldFile related stuff\r
+\r
+  MODIFIED: 07 Oct 2005 Hammag\r
+ REASON: - Added methods to get const iterators on Appartment and WorldFile maps\r
+\r
+*/\r
+\r
+#ifndef GAMEDEFS_H\r
+#define GAMEDEFS_H\r
+\r
+#include "defs.h"\r
+\r
+typedef PDefMap<PDefActionMod> PDefActionModsMap;\r
+typedef PDefMap<PDefAmmo> PDefAmmosMap;\r
+class PDefAppartementsMap; // Derived classe for addition of specific members\r
+typedef PDefMap<PDefAppPlace> PDefAppPlacesMap; // No derived class needed here\r
+typedef PDefMap<PDefBlueprintPieces> PDefBlueprintPiecesMap;\r
+typedef PDefMap<PDefCharacter> PDefCharactersMap;\r
+typedef PDefMap<PDefCharAction> PDefCharActionsMap;\r
+typedef PDefMap<PDefCharKind> PDefCharKindsMap;\r
+typedef PDefMap<PDefDamage> PDefDamagesMap;\r
+typedef PDefMap<PDefDrug> PDefDrugsMap;\r
+typedef PDefMap<PDefFaction> PDefFactionsMap;\r
+//typedef PDefMap<PDefHack> PDefHacksMap; // File not used by KK\r
+typedef PDefMap<PDefImplant> PDefImplantsMap;\r
+typedef PDefMap<PDefItemContainer> PDefItemContainersMap;\r
+typedef PDefMap<PDefItemMod> PDefItemModsMap;\r
+typedef PDefMap<PDefItemRestriction> PDefItemRestrictionsMap;\r
+class PDefItemsMap;\r
+typedef PDefMap<PDefMission> PDefMissionsMap;\r
+typedef PDefMap<PDefNpcArmor> PDefNpcArmorsMap;\r
+typedef PDefMap<PDefNpcGroupSpawn> PDefNpcGroupSpawnsMap;\r
+typedef PDefMap<PDefNpc> PDefNpcsMap;\r
+typedef PDefMap<PDefOutpost> PDefOutpostsMap;\r
+typedef PDefMap<PDefRecycle> PDefRecyclesMap;\r
+class PDefRespawnsMap;\r
+typedef PDefMap<PDefShot> PDefShotsMap;\r
+typedef PDefMap<PDefSkill> PDefSkillsMap;\r
+typedef PDefMap<PDefSubSkill> PDefSubSkillsMap;\r
+typedef PDefMap<PDefTrader> PDefTradersMap;\r
+typedef PDefMap<PDefVhc> PDefVhcsMap;\r
+typedef PDefMap<PDefVhcSeat> PDefVhcSeatsMap;\r
+typedef PDefMap<PDefWeapon> PDefWeaponsMap;\r
+typedef PDefMap<PDefWeather> PDefWeathersMap;\r
+typedef PDefMap<PDefWorld> PDefWorldsMap;\r
+class PDefWorldFilesMap;\r
+typedef PDefMap<PDefWorldModel> PDefWorldModelsMap;\r
+\r
+class PDefScriptsMap;\r
+//typedef PDefMap<PDefScripts> PDefScriptsMap;\r
+// ___Add new entries here in alpÄ¥abetical order___\r
+\r
+\r
+class PGameDefs\r
+{\r
+  private :\r
+    PDefActionModsMap mActionModsDefs;\r
+    PDefAmmosMap mAmmosDefs;\r
+    PDefAppartementsMap mAppartementsDefs;\r
+    PDefAppPlacesMap mAppPlacesDefs;\r
+    PDefBlueprintPiecesMap mBlueprintPiecesDefs;\r
+    PDefCharactersMap mCharsDefs;\r
+    PDefCharActionsMap mCharActionsDefs;\r
+    PDefCharKindsMap mCharKindsDefs;\r
+    PDefDamagesMap mDamagesDefs;\r
+    PDefDrugsMap mDrugsDefs;\r
+    PDefFactionsMap mFactionsDefs;\r
+    //PDefHacksMap mHacksDefs;\r
+    PDefImplantsMap mImplantsDefs;\r
+    PDefItemContainersMap mItemContainersDefs;\r
+    PDefItemModsMap mItemModsDefs;\r
+    PDefItemRestrictionsMap mItemRestrictionsDefs;\r
+    PDefItemsMap mItemsDefs;\r
+    PDefMissionsMap mMissionsDefs;\r
+    PDefNpcArmorsMap mNpcArmorsDefs;\r
+    PDefNpcGroupSpawnsMap mNpcGroupSpawnsDefs;\r
+    PDefNpcsMap mNpcsDefs;\r
+    PDefOutpostsMap mOutpostsDefs;\r
+    PDefRecyclesMap mRecyclesDefs;\r
+    PDefRespawnsMap mRespawnsDefs;\r
+    PDefShotsMap mShotsDefs;\r
+    PDefSkillsMap mSkillsDefs;\r
+    PDefSubSkillsMap mSubSkillsDefs;\r
+    PDefTradersMap mTradersDefs;\r
+    PDefVhcsMap mVhcsDefs;\r
+    PDefVhcSeatsMap mVhcSeatsDefs;\r
+    PDefWeaponsMap mWeaponsDefs;\r
+    PDefWeathersMap mWeathersDefs;\r
+    PDefWorldsMap mWorldsDefs;\r
+    PDefWorldFilesMap mWorldFilesDefs;\r
+    PDefWorldModelsMap mWorldModelsDefs;\r
+\r
+    PDefScriptsMap mScriptDefs;\r
+    // ___Add new entries here___\r
+\r
+  public :\r
+    PGameDefs();\r
+    ~PGameDefs();\r
+\r
+    bool Init();\r
+\r
+    inline const PDefActionModsMap* ActionMods() const { return &mActionModsDefs; }\r
+    inline const PDefAmmosMap* Ammos() const { return &mAmmosDefs; }\r
+    inline const PDefAppartementsMap* Appartements() const { return &mAppartementsDefs; }\r
+    inline const PDefAppPlacesMap* AppPlaces() const { return &mAppPlacesDefs; }\r
+    inline const PDefBlueprintPiecesMap* BlueprintPieces() const { return &mBlueprintPiecesDefs; }\r
+    inline const PDefCharactersMap* Chars() const { return &mCharsDefs; }\r
+    inline const PDefCharActionsMap* CharActions() const { return &mCharActionsDefs; }\r
+    inline const PDefCharKindsMap* CharKinds() const { return &mCharKindsDefs; }\r
+    inline const PDefDamagesMap* Damages() const { return &mDamagesDefs; }\r
+    inline const PDefDrugsMap* Drugs() const { return &mDrugsDefs; }\r
+    inline const PDefFactionsMap* Factions() const { return &mFactionsDefs; }\r
+    //inline const PDefHacksMap* Hacks() const { return &mHacksDefs; }\r
+    inline const PDefImplantsMap* Implants() const { return &mImplantsDefs;}\r
+    inline const PDefItemContainersMap* ItemContainers() const { return &mItemContainersDefs; }\r
+    inline const PDefItemModsMap* ItemMods() const { return &mItemModsDefs; }\r
+    inline const PDefItemRestrictionsMap* ItemRestrictions() const { return & mItemRestrictionsDefs; }\r
+    inline const PDefItemsMap* Items() const { return &mItemsDefs; }\r
+    inline const PDefMissionsMap* Missions() const { return &mMissionsDefs; }\r
+    inline const PDefNpcArmorsMap* NpcArmors() const { return & mNpcArmorsDefs; }\r
+    inline const PDefNpcGroupSpawnsMap* GroupSpawns() const { return &mNpcGroupSpawnsDefs; }\r
+    inline const PDefNpcsMap* Npcs() const { return &mNpcsDefs; }\r
+    inline const PDefOutpostsMap* Outposts() const { return &mOutpostsDefs; }\r
+    inline const PDefRecyclesMap* Recycles() const { return &mRecyclesDefs; }\r
+    inline const PDefRespawnsMap* Respawns() const { return &mRespawnsDefs; }\r
+    inline const PDefShotsMap* Shots() const { return &mShotsDefs; }\r
+    inline const PDefSkillsMap* Skills() const { return &mSkillsDefs; }\r
+    inline const PDefSubSkillsMap* SubSkills() const { return &mSubSkillsDefs; }\r
+    inline const PDefTradersMap* Traders() const { return &mTradersDefs; }\r
+    inline const PDefVhcsMap* Vhcs() const { return &mVhcsDefs; }\r
+    inline const PDefVhcSeatsMap* VhcSeats() const { return &mVhcSeatsDefs; }\r
+    inline const PDefWeaponsMap* Weapons() const { return &mWeaponsDefs; }\r
+    inline const PDefWeathersMap* Weathers() const { return &mWeathersDefs; }\r
+    inline const PDefWorldsMap* Worlds() const { return &mWorldsDefs; }\r
+    inline const PDefWorldFilesMap* WorldFiles() const { return &mWorldFilesDefs; }\r
+    inline const PDefWorldModelsMap* WorldModels() const { return &mWorldModelsDefs; }\r
+\r
+    inline const PDefScriptsMap* Scripts() const { return &mScriptDefs; }\r
+    // ___Add new entries here___\r
+\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/gamescript.h b/server/src/game/include/gamescript.h
new file mode 100644 (file)
index 0000000..382bbe7
--- /dev/null
@@ -0,0 +1,47 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+#ifndef GAMESCRIPT_H\r
+#define GAMESCRIPT_H\r
+\r
+enum PHookTypes\r
+{\r
+    HOOK_CHAT,\r
+    HOOK_TRADE,\r
+    HOOK_ZONE\r
+};\r
+\r
+class PGameScript\r
+{\r
+    private:\r
+               typedef std::map<PHookTypes, std::string> HookMap;\r
+               HookMap mHooks;\r
+\r
+    public:\r
+        PGameScript();\r
+        ~PGameScript();\r
+\r
+        bool LoadScripts();\r
+        bool Rehash();\r
+        void TriggerHook(PHookTypes hook);\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/gameserver.h b/server/src/game/include/gameserver.h
new file mode 100644 (file)
index 0000000..f45511b
--- /dev/null
@@ -0,0 +1,144 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+ gameserver.h\r
+\r
+ Authors:\r
+ - v00d00\r
+ - Akiko\r
+\r
+ MODIFIED: 30 Nov 2005 Akiko\r
+ REASON: - added GPL\r
+*/\r
+\r
+#ifndef GAMESERVER_H\r
+#define GAMESERVER_H\r
+\r
+struct PGameState\r
+{\r
+  struct TCP\r
+  {\r
+    enum State\r
+    {\r
+      GS_UNKNOWN,\r
+      GS_CONNECTED,\r
+      GS_HANDSHAKE0,\r
+      GS_AUTHENTICATE,\r
+      GS_GAMEDATA,\r
+      GS_REQUESTCHARS,\r
+      GS_CHARLIST,\r
+      GS_GETSTATUS,\r
+      GS_GAMEINFO,\r
+      GS_INGAME\r
+    } mState;\r
+\r
+    bool mWaitSend; // wait-for-completition flag\r
+  } TCP;\r
+\r
+  struct UDP\r
+  {\r
+    enum State\r
+    {\r
+      GUS_UNKNOWN,\r
+      GUS_SYNC0,\r
+      GUS_SYNC1,\r
+      GUS_SYNC2,\r
+      GUS_SYNC3\r
+    } mState;\r
+\r
+    bool mSynced;\r
+    u16 mServerPacketNum;\r
+    u16 mSequence;\r
+    //u16 mClientPacketNum;\r
+  } UDP;\r
+\r
+  PGameState()\r
+  {\r
+    TCP.mState = TCP::GS_UNKNOWN;\r
+    TCP.mWaitSend = false;\r
+\r
+    UDP.mState = UDP::GUS_UNKNOWN;\r
+    UDP.mSynced = false;\r
+    UDP.mServerPacketNum = 0x9c9f;\r
+    UDP.mSequence = 2;\r
+    //UDP.mClientPacketNum = 0;\r
+  };\r
+};\r
+\r
+class PUdpMsgDecoder;\r
+\r
+class PGameServer\r
+{\r
+  private :\r
+    std::time_t mServerStartupTime;\r
+    int mNumClients;\r
+    u32 mBaseGameTime;\r
+    struct timespec mStartTime;\r
+\r
+    typedef std::map<PClient*, struct PGameState*> GameStateMap;\r
+    GameStateMap ClientStates;\r
+    PUdpMsgDecoder* MsgDecoder;\r
+\r
+  protected :\r
+    bool ProcessClient( PClient *Client, PGameState *State = 0 );\r
+    void FinalizeClient( PClient *Client, PGameState *State );\r
+    void FinalizeClientDelayed( PClient *Client, PGameState *State );\r
+\r
+//  bool HandleHandshake(PClient *Client, PGameState *State, const u8 *Packet, int PacketSize);\r
+    bool HandleHandshake( PGameState *State, const u8 *Packet, int PacketSize );\r
+\r
+    bool HandleAuthenticate( PClient *Client, PGameState *State, const u8 *Packet, int PacketSize );\r
+//  bool HandleGameData(PClient *Client, PGameState *State, const u8 *Packet, int PacketSize);\r
+    bool HandleGameData( PClient *Client, PGameState *State, const u8 *Packet );\r
+\r
+//  bool HandleRequestChars(PClient *Client, PGameState *State, const u8 *Packet, int PacketSize);\r
+    bool HandleRequestChars( PClient *Client, PGameState *State, const u8 *Packet );\r
+\r
+    bool HandleCharList( PClient *Client, PGameState *State, const u8 *Packet, int PacketSize );\r
+//  bool HandleGetStatus(PClient *Client, PGameState *State, const u8 *Packet, int PacketSize);\r
+    bool HandleGetStatus( PClient *Client, PGameState *State, const u8 *Packet );\r
+\r
+//  bool HandleGameInfo(PClient *Client, PGameState *State, const u8 *Packet, int PacketSize);\r
+    bool HandleGameInfo( PClient *Client, PGameState *State, const u8 *Packet );\r
+\r
+    bool HandleGame( PClient *Client, PGameState *State );\r
+\r
+  public :\r
+    PGameServer();\r
+    ~PGameServer();\r
+\r
+    void Start();\r
+    void Update();\r
+    void ClientDisconnected( PClient *Client );\r
+    void UDPStreamClosed( PClient *Client );\r
+    void SetGameTime( u32 newtime );\r
+    u32 GetGameTime();\r
+\r
+    inline std::time_t GetStartTime() const { return mServerStartupTime; };\r
+\r
+    PGameState* GetClientState( PClient* nClient );\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/include/genreplist.h b/server/src/game/include/genreplist.h
new file mode 100644 (file)
index 0000000..043945d
--- /dev/null
@@ -0,0 +1,71 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+  genreplist.h - classe for character genrep list\r
+\r
+       MODIFIED: 20 Sep 2006 Hammag\r
+       REASON: - creation\r
+       \r
+*/\r
+\r
+#ifndef GENREPLIST_H\r
+#define GENREPLIST_H\r
+\r
+#define GENREPLIST_ALLOC_SIZE 4 // atomicity of list entries allocation\r
+\r
+class PGenrepList\r
+{\r
+  private:\r
+    enum { // genrep DB Table fields\r
+        g_id = 0,\r
+        g_worldid,\r
+        g_stationid,\r
+        g_charid\r
+    };\r
+    struct PGenrepEntry\r
+    {\r
+      u16 mWorldID;\r
+      u16 mStationID;\r
+    };\r
+    \r
+    u32 mOwnerCharID;\r
+    u8 mListMaxSize;\r
+    u8 mListSize;\r
+    PGenrepEntry* mGenrepList;\r
+    \r
+    void IncreaseMaxSize(u8 nNewMax = 0);\r
+    u8 FindEntry(u16 nWorldID, u16 nStationID);\r
+    \r
+  public:\r
+    PGenrepList(u32 nOwnerCharID);\r
+    ~PGenrepList();\r
+    bool AddGenrep(u16 nWorldID, u16 nStationID);\r
+    //bool RemoveChar(u32 nBuddyCharID);    \r
+    inline u8 Count() { return mListSize; }\r
+    u16 GetListDataSize() { return (sizeof(PGenrepEntry) * mListSize); }\r
+    const void* GetListData() { return (const void*)mGenrepList; }\r
+    bool SQLLoad();\r
+//    bool SQLSave();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/globals.h b/server/src/game/include/globals.h
new file mode 100644 (file)
index 0000000..04b730a
--- /dev/null
@@ -0,0 +1,92 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+       globals.h\r
+\r
+       MODIFIED: 12 September 2005 Akiko\r
+       REASON: - exchanged Pretender Strings by TinNS\r
+                - removed some Windows specific code\r
+       MODIFIED: 16 Dec 2005 bakkdoor\r
+       REASON: - Added global ClientManager and Chat Interface\r
+       MODIFIED: 22 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+\r
+*/\r
+\r
+#ifndef GLOBALS_H\r
+#define GLOBALS_H\r
+\r
+extern class PLuaEngine *LuaEngine;\r
+\r
+extern class ServerSocket *ServerSock;\r
+extern class PConsole *Console;\r
+//extern class PRConsole *RemoteConsole;\r
+extern class PConfig *Config;\r
+extern class PConfig *CmdAccess;\r
+\r
+extern class PGameDefs *GameDefs;\r
+extern class PFileSystem *Filesystem;\r
+extern class PServer *Server;\r
+\r
+extern class PGameServer *GameServer;\r
+extern class PChars *Chars;\r
+\r
+extern class PMsgBuilder *MsgBuilder;\r
+extern class PWorlds *Worlds;\r
+extern class PAppartements* Appartements;\r
+extern class PWorldActors* WorldActors;\r
+extern class PTerminal* Terminal;\r
+//extern class gmMachine machine;   // Virtual Machine instance\r
+\r
+//multiuser chat\r
+extern class PClientManager *ClientManager;\r
+extern class PNPCManager* NPCManager;\r
+extern class PChat *Chat;\r
+extern class PCommands *GameCommands;\r
+
+extern class POutpost *Outposts;
+extern class PMultiPart *MultiPartHandler;
+\r
+// Development debug output control\r
+extern bool gDevDebug;\r
+\r
+//MySQL-Support\r
+extern class PMySQL* MySQL;\r
+\r
+//Vehicles\r
+extern class PVehicles *Vehicles;\r
+extern class PSubway* Subway;\r
+\r
+//Infoserver update\r
+extern class PISC *ISC;\r
+\r
+//Empty string\r
+extern const std::string EmptyString;\r
+\r
+extern const char ServerVersion[];\r
+extern const char SVNRevision[];\r
+\r
+bool InitTinNS();\r
+void Shutdown();\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/include/inventory.h b/server/src/game/include/inventory.h
new file mode 100644 (file)
index 0000000..6c20906
--- /dev/null
@@ -0,0 +1,116 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+  inventory.h - classes for inventories\r
+                  (inventory, belt, armor, implants, gogo, processor(?), maybe other containers(?) )\r
+\r
+       MODIFIED: 10 Jul 2006 Hammag\r
+       REASON: - creation\r
+\r
+\r
+*/\r
+\r
+#ifndef INVENTORY_H\r
+#define INVENTORY_H\r
+\r
+//NC containers message locations\r
+#define INV_LOC_GROUND 1\r
+#define INV_LOC_WORN 2\r
+#define INV_LOC_BACKPACK 3\r
+#define INV_LOC_BOX 4\r
+#define INV_LOC_NPCTRADE 5\r
+#define INV_LOC_GOGO 18\r
+#define INV_LOC_BOX2 255\r
+//PC-Trade window = ?\r
+\r
+//Inventory containers info\r
+#define INV_WORN_QB_START 0\r
+#define INV_WORN_QB_END 9\r
+#define INV_WORN_QB_NONE 99\r
+#define INV_WORN_QB_HAND 11\r
+\r
+#define INV_WORN_PROC_START 12\r
+#define INV_WORN_PROC_END 24\r
+\r
+#define INV_WORN_IMP_START 26\r
+#define INV_WORN_IMP_END 38\r
+\r
+#define INV_WORN_ARMOR_START 39\r
+#define INV_WORN_ARMOR_END 43\r
+\r
+#define INV_WORN_COLS 44\r
+#define INV_WORN_MAXSLOTS 44\r
+\r
+\r
+#define INV_BACKPACK_COLS 10\r
+\r
+#define INV_GOGO_COLS 5\r
+#define INV_GOGO_MAXSLOTS 50\r
+\r
+#define INV_CABINET_COLS 5\r
+#define INV_CABINET_MAXSLOTS 33\r
+\r
+// inv_loc values in database\r
+#define INV_DB_LOC_GOGO 1\r
+#define INV_DB_LOC_WORN 2\r
+#define INV_DB_LOC_BACKPACK 3\r
+\r
+class PItem;\r
+class PContainer;\r
+class PContainerWithHoles;\r
+class PContainer2DWorkaround;\r
+class PContainerAutoFindFree;\r
+\r
+class PInventory\r
+{\r
+  private:\r
+    PContainerWithHoles* mWorn; // PContainerLinearSlots\r
+    PContainer2DWorkaround* mBackpack; // PContainer2DAreas\r
+    PContainerAutoFindFree* mGogo; // PContainerLinearSlots\r
+    \r
+  public:\r
+\r
+    PInventory();\r
+    ~PInventory();\r
+    \r
+    void SetCharId(u32 CharID);\r
+    bool SQLLoad();\r
+    bool SQLSave();\r
+    PContainer* GetContainer(u8 nInvLoc);\r
+    inline PContainer2DWorkaround* GetBackpackContainer() { return mBackpack; }\r
+\r
+    bool IsDirty() const;\r
+      \r
+    bool AddItem(PItem* NewItem, u8 nInvLoc = INV_LOC_BACKPACK, u32 nInvID = 0, u8 nPosX = 0, u8 nPosY = 0, bool SetDirty = true);\r
+    //bool CheckItem(u32 ItemID, u8 StackSize = 1);\r
+    //PItem *GetItem(u32 ItemID, u8 StackSize = 1);\r
+    //PItem *GetItemByPos(u8 nPosX, u8 nPosY, u8 StackSize = 1);\r
+    //bool MoveItem(u8 oPosX, u8 oPosY, u8 dPosX, u8 dPosY);\r
+\r
+    //bool QB_IsFree(u8 nSlot);\r
+    //void QB_SetSlot(u8 nSlot, u16 nItemID);\r
+    //u16 QB_GetSlot(u8 nSlot);\r
+    //void QB_Move(u8 nSlotSRC, u8 nSlotDST);\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/isc.h b/server/src/game/include/isc.h
new file mode 100644 (file)
index 0000000..abc8eb6
--- /dev/null
@@ -0,0 +1,98 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+/*\r
+  isc.h\r
+\r
+  MODIFIED: Unknown date / Namikon\r
+  REASON: - initial release by Namikon\r
+       MODIFIED: 13 Oct 2006 Hammag\r
+       REASON: - Implemented MySQL isc method\r
+\r
+*/\r
+\r
+#ifndef ISC_H\r
+#define ISC_H\r
+\r
+#define ISC_VER 2\r
+\r
+// Part of mConStatus bitmask\r
+#define ISC_CONNECTED 1\r
+#define ISC_ADMIN 2\r
+\r
+\r
+class PISC\r
+{\r
+       private:\r
+        enum PISC_Status\r
+        {\r
+            ISC_NOTCONNECTED,\r
+            ISC_HANDSHAKE01,  // "Hello" msg sent, awaiting answer\r
+            ISC_HANDSHAKE02,  // PW sent, awaiting answer\r
+            ISC_GSDATA01,     // Servername sent, awaiting answer\r
+            ISC_GSDATA02,     // IP, Port & Patchlevel sent, awaiting blabla..\r
+            ISC_GSDATA03,     // Players / Staff onlinecounter sent, ...\r
+            ISC_GSDATA04,     // Minlevel to connect, minlevel to see Playercount, minlevel to see server sent,....\r
+            ISC_CLIENTIDENT,  // Awaiting client identification answer\r
+            ISC_ADMINLOGIN,   // Awaiting answer to Infoserver control login request\r
+            ISC_ICTRL_AUTOACC,// Infoserver control: Awaiting response to AutoAccount command\r
+            ISC_ICTRL_LOGLV,  // Infoserver control: Awaiting response to LoginLevel command\r
+            ISC_ICTRL_RELOAD, // Infoserver control: Awaiting response to Reload command\r
+            ISC_ICTRL_SHUTD,  // Infoserver control: Awaiting response to Shutdown command\r
+            ISC_ICTRL_HIDE,   // Infoserver control: Awaiting response to HidePeople command\r
+            ISC_IDLE          // Updateloop running\r
+        } mLinkStatus;\r
+\r
+        u16 mConStatus;     // Bitmask of Connection status\r
+\r
+        int isc_method;\r
+\r
+        bool use_isc;\r
+        char isc_pwd;\r
+\r
+        bool use_mysql;\r
+        int m_server_id;\r
+        std::time_t mysql_update_intervall;\r
+        std::time_t mysql_delayed_update_intervall;\r
+        std::time_t mysql_last_update_time;\r
+        int mysql_last_client_count;\r
+        std::time_t mysql_last_count_decrease_time;\r
+\r
+        void Start_isc();\r
+        void Update_isc();\r
+        void Shutdown_isc();\r
+\r
+        void Start_mysql();\r
+        void Update_mysql();\r
+        bool do_mysql_db_update(int players, bool shutdown = false);\r
+        void Shutdown_mysql();\r
+\r
+       public:\r
+               PISC();\r
+               ~PISC();\r
+\r
+               void Start();\r
+               void Update();\r
+               void Shutdown();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/item.h b/server/src/game/include/item.h
new file mode 100644 (file)
index 0000000..aaed849
--- /dev/null
@@ -0,0 +1,144 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+  item.h - item class\r
+\r
+       MODIFIED: 11 Jul 2006 Hammag\r
+       REASON: - creation\r
+       \r
+        TODO: Add CreatorID (for "named" item), CurrentMunitionID, CurrentMunitionNb (for weapons & charge-items: muns, medkit, etc.) to DB, equipped/free slots, & corresponding code\r
+*/\r
+\r
+#ifndef ITEM_H\r
+#define ITEM_H\r
+\r
+#define MAX_ITEMSTACK_SIZE 250\r
+\r
+//Type\r
+#define ITEM_TYPE_VARIOUS 0\r
+#define ITEM_TYPE_WEAPON 1\r
+#define ITEM_TYPE_AMMO 2\r
+#define ITEM_TYPE_HEALTH 3\r
+#define ITEM_TYPE_IMPLANT 4\r
+#define ITEM_TYPE_DRUG 5\r
+#define ITEM_TYPE_MOD 6\r
+#define ITEM_TYPE_GFXMOD 7\r
+#define ITEM_TYPE_BLUEPRINT 8\r
+#define ITEM_TYPE_ARMOR 9\r
+#define ITEM_TYPE_PSIMOD 10\r
+#define ITEM_TYPE_PSIMODREADY 11\r
+#define ITEM_TYPE_REPAIR 12\r
+#define ITEM_TYPE_RECYCLER 13\r
+#define ITEM_TYPE_DATACUBE 14\r
+#define ITEM_TYPE_CONSTRUCTOR 15\r
+#define ITEM_TYPE_RESEARCHER 16\r
+#define ITEM_TYPE_IMPLANTER 17\r
+#define ITEM_TYPE_APARTMENTKEY 18\r
+#define ITEM_TYPE_CLANKEY 19\r
+#define ITEM_TYPE_CASHCUBE 20\r
+#define ITEM_TYPE_AUTOWEAPON 21\r
+#define ITEM_TYPE_VHCKEY 22\r
+#define ITEM_TYPE_UNIDENTPART 24\r
+#define ITEM_TYPE_WRECKEDPART 25\r
+#define ITEM_TYPE_SALVAGE 26\r
+#define ITEM_TYPE_VHCCOMPONENT 27\r
+#define ITEM_TYPE_RECORDABLE 28\r
+\r
+                                                                                                                                               \r
+\r
+// gfxmodflags                                                                                                                                                                         \r
+#define ITEM_MOD_FLASHLIGHT 1  \r
+#define ITEM_MOD_SCOP 2\r
+#define ITEM_MOD_SILENCER 4\r
+#define ITEM_MOD_LASERPOINTER 8\r
+\r
+// itemflags:\r
+#define ITEM_FLAG_RESEARCHABLE 1\r
+#define ITEM_FLAG_NO_DROP 2\r
+#define ITEM_FLAG_NO_MAX_REPAIRE_DECAY 4\r
+#define ITEM_FLAG_AMMO 8 // for loadable ammo\r
+// not sure for ITEM_FLAG_AMMO\r
+\r
+class PItem\r
+{\r
+  friend class PContainerEntry;\r
+  friend class PMsgBuilder;\r
+\r
+  private:\r
+    u32 mItemID;\r
+    const PDefItems* mDefItem;\r
+    \r
+    bool mStackable;\r
+    u8 mStackSize;\r
+    \r
+    u32 mLoadedAmmoId;\r
+    u8 mLoadedAmmoNb;\r
+\r
+    u8 mPropertiesFlags;\r
+    \r
+    u8 mCurDuration;\r
+    u8 mMaxDuration;\r
+    u8 mDamages;\r
+    u8 mFrequency;\r
+    u8 mHandling;\r
+    u8 mRange;\r
+    \r
+    u8 mUsedSlots;\r
+    u8 mMaxSlots;\r
+    u8 mSlot[5];\r
+    u8 mModificators;\r
+    \r
+    u32 mConstructorId;\r
+    \r
+  public:\r
+    PItem(u32 ItemID, u8 nStackSize = 1, u8 CurDur = 0, u8 MaxDur = 0, u8 Dmg = 0, u8 Freq = 0, u8 Hand = 0, u8 Rng = 0);\r
+    //~PItem();\r
+    void MakeItemStandard(u8 GlobalQualityMin = 120, u8 GlobalQualityMax = 180);\r
+        \r
+    inline u32 GetItemID() {return mItemID; }\r
+    \r
+    inline int GetType() { return mDefItem->GetType(); }\r
+    inline u8 GetItemflags() { return mDefItem->GetItemflags(); }\r
+    inline const std::string &GetName() const { return mDefItem->GetName(); }\r
+    inline u8 GetSizeX() { return mDefItem->GetSizeX(); }\r
+    inline u8 GetSizeY() { return mDefItem->GetSizeY(); }\r
+    inline float GetWeight() { return mStackSize * mDefItem->GetWeight(); }\r
+    inline float GetSingleUnitWeight() { return mDefItem->GetWeight(); }\r
+    inline float GetFillWeight() { return mDefItem->GetFillWeight(); }\r
+    inline u32 GetBasePrice() { return mDefItem->GetBasePrice(); }\r
+    inline u16 GetTechlevel() { return mDefItem->GetTechlevel(); }\r
+    inline int GetValue1() { return mDefItem->GetValue1(); }\r
+    inline int GetValue2() { return mDefItem->GetValue2(); }\r
+    inline int GetValue3() { return mDefItem->GetValue3(); }\r
+    inline int GetQualifier() { return mDefItem->GetQualifier(); }        \r
+    \r
+    inline bool IsStackable() { return mDefItem->IsStackable(); }\r
+    inline u8 GetStackSize() { return mStackSize; }\r
+    u8 AddToStack(u8 ItemNb); // return the nb of items NOT added\r
+    u8 TakeFromStack(u8 ItemNb); // return the nb of retreived items        \r
+\r
+    //mItemGroupID = def->GetItemGroupID();\r
+    \r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/lua_engine.h b/server/src/game/include/lua_engine.h
new file mode 100644 (file)
index 0000000..719019a
--- /dev/null
@@ -0,0 +1,77 @@
+/*\r
+TinNS (TinNS is not a Neocron Server)\r
+Copyright (C) 2005 Linux Addicted Community\r
+maintainer Akiko <akiko@gmx.org>\r
+\r
+This program is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU General Public License\r
+as published by the Free Software Foundation; either version 2\r
+of the License, or (at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+lua_engine.h - TinNS Lua engine for processing NPC scripts\r
+\r
+CREATION: 13 Oct 2009 Namikon\r
+\r
+*/\r
+\r
+#ifndef PLUA_H\r
+#define PLUA_H\r
+\r
+extern "C" {\r
+  #include <lua.h>\r
+  #include <lauxlib.h>\r
+  #include <lualib.h>\r
+}\r
+\r
+#define PLUAENGINE_DEFAULT      0\r
+#define PLUAENGINE_GETANSWER    4096\r
+#define PLUAENGINE_EXECUTENODE  8192\r
+\r
+class PLuaEngine\r
+{\r
+    private:\r
+        PClient* mTargetClient;\r
+\r
+        bool mRunning;\r
+        lua_State *mLua;\r
+\r
+        std::vector<int> mReturnValues;\r
+\r
+\r
+        // Return Values\r
+        int mReturn_INT;\r
+//        std::string mReturn_STR;\r
+        // add more if needed...\r
+\r
+        void CleanUp();\r
+        bool ExecuteScript(std::string nLUAScript, int nNode, int nDialogClass = 0);\r
+\r
+    public:\r
+        PLuaEngine();\r
+        ~PLuaEngine();\r
+\r
+        // To check if LUA Script has syntax errors or whatever\r
+        bool CheckLUAFile(std::string nLUAScript);\r
+        void AddScriptResult(int nResult);\r
+        void ProcessDialogScript(PClient* nClient, std::string mLUAFile, int nAnswer);\r
+        inline PClient* GetBoundClient() { return mTargetClient; };\r
+\r
+        inline void SetReturnINT(int nValue) { mReturn_INT = nValue; };\r
+        // inline void SetReturnSTR(std::string nValue) { mReturn_STR = nValue; };\r
+};\r
+\r
+\r
+#endif\r
diff --git a/server/src/game/include/msgbuilder.h b/server/src/game/include/msgbuilder.h
new file mode 100644 (file)
index 0000000..d8410c0
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ msgbuilder.h - a classes to build NC messages
+
+ CREATION: 30 Aug 2006 Hammag
+
+ MODIFIED:
+ REASON: -
+
+*/
+
+#ifndef MSGBUILDER_H
+#define MSGBUILDER_H
+
+class PClient;
+class PMessage;
+class PContainerEntry;
+class PContainer;
+class PSpawnedVehicle;
+
+class PMsgBuilder
+{
+private:
+
+public:
+    PMsgBuilder() {};
+    ~PMsgBuilder() {};
+
+// Following methods for broadcasted messages do NOT include UDP_ID increment
+// when needed, nor UDP_ID / SessionID setting
+// as these must be set on a destination client basis
+    PMessage* BuildCharHelloMsg( PClient* nClient );
+    PMessage* BuildCharHealthUpdateMsg( PClient* nClient );
+    PMessage* BuildCharDeathMsg( PClient* nClient, u32 nKillerCharId = 0 );
+    PMessage* BuildCharPosUpdateMsg( PClient* nClient );
+    PMessage* BuildCharPosUpdate2Msg( PClient* nClient, u8 InfoBitfield = 0x7f );
+    //PMessage* BuildCharSittingMsg( PClient* nClient ); // Not used anymore, done by BuildCharPosUpdateMsg
+    PMessage* BuildCharExitSeatMsg( PClient* nClient );
+    PMessage* BuildDoorOpenMsg( u32 nRawItemID, bool nDoubleDoor = false );
+    PMessage* BuildCharUseSeatMsg( PClient* nClient, u32 nRawObjectId, u8 nSeatId = 0 );
+    PMessage* BuildCharShowGlowCircleMsg( PClient* nClient );
+
+    PMessage* BuildSpawnWorldObjectMsg( u16 nModelID, u16 nFunctionID, u32 nWOID, u16 nPosX, u16 nPosY, u16 nPosZ, u8 nRotX, u8 nRotY, u8 nRotZ );
+    PMessage* BuildRemoveWorldObjectMsg( u32 nWOID );
+    PMessage* BuildWeatherControlMsg( u16 nWeatherId );
+
+    PMessage* BuildSubwaySingleUpdateMsg( u32 nVehicleID, u16 nPosition, u8 nDoorOpened );
+    PMessage* BuildVhcHealthUpdateMsg( PSpawnedVehicle* nVehicle );
+    PMessage* BuildVhcPosUpdateMsg( PSpawnedVehicle* nVehicle );
+    PMessage* BuildVhcPosUpdate2Msg( PSpawnedVehicle* nVehicle );
+
+    PMessage* BuildStartWeaponReloadAnimMsg( PClient* nClient );
+    PMessage* BuildHeldItemUseMsg( u16 nUserCharLocalId, u16 nWeaponId, u32 nTargetRawItemID, u8 nAiming, u8 nTargetedHeight, u8 nScore = 0 );
+    PMessage* BuildHeldItemUse2Msg( u16 nUserCharLocalId, u32 nTargetRawItemID );
+    PMessage* BuildHeldItemUse4Msg( u16 nUserCharLocalId, u32 nTargetRawItemID, u16 nUnknown1, u16 nUnknown2, u8 nTargetedHeight );
+    PMessage* BuildHeldItemAddonActivationMsg( PClient* nClient, u8 nState );
+
+    // Temp. NPC update message for testing
+    PMessage* BuildNpcDeathMsg( PClient* nClient, u32 nNpcId, u8 unknown1 = 0x4a, u8 npcAction = 0x1e );
+
+    PMessage* BuildNPCMassInfoMsg( u32 nWorldID, u16 nTypeID, u16 nClothing, u16 nNameID, u16 nPosY, u16 nPosZ, u16 nPosX, u16 nHealth, u16 nTraderID, string* nAngleStr, string* nNpcName, string* nCustomName);\r
+    PMessage* BuildNPCMassAliveMsg( u32 nWorldID, u16 nX, u16 nY, u16 nZ, u8 nActionStatus, u8 nHealth, u8 nAction );\r
+    PMessage* BuildNPCMassUpdateMsg( u32 nWorldID, u16 nX, u16 nY, u16 nZ, u8 nActionStatus, u8 nHealth, u16 nTarget, u8 nAction );\r
+    // Moved here since its a zone broadcast!\r
+    PMessage* BuildNpcCleanupMsg( u32 nNpcId, u8 nCmd = 6 ); // see implementation about nCmd\r
+
+// Following methods for unicast messages DO include UDP_ID increment and
+// UDP_ID / SessionID setting when needed (at least for now)
+    PMessage* BuildOutpostClanInfoMsg( PClient* nClient, u32 nClanID, u8 nFaction );\r
+    PMessage* BuildTryAccessAnswerMsg(PClient* nClient, char *nArea, bool nAllowed);\r
+    PMessage* BuildReceiveDBAnswerMsg( PClient* nClient, PMessage* nResultBuffer, std::string* nCommandName, u16 nNumRows, u16 nNumFields);\r
+    PMessage* BuildYouGotEmailsMsg( PClient* nClient, u8 nMailCount );\r
+\r
+    PMessage* BuildNPCStartDialogMsg( PClient* nClient, u32 nNPCWorldID, string* nDialogScript  );\r
+    PMessage* BuildNPCDialogReplyMsg( PClient* nClient, u16 nNextNode, std::vector<int>*nResultBuffer);\r
+    PMessage* BuildReqNPCScriptAnswerMsg( u32 nInfoId, string* nNPCScript );\r
+    PMessage* BuildNPCShoppingListMsg( PClient* nClient, PMessage* nContentList, int nWorldID, u8 nItemQuality);\r
+    PMessage* BuildNPCBeginAllBuyerTradeMsg( PClient* nClient, int nWorldID );\r
+\r
+    PMessage* BuildNPCSingleInfoMsg( PClient* nClient, u32 nWorldID, u16 nTypeID, u16 nClothing, u16 nNameID, u16 nPosY, u16 nPosZ, u16 nPosX, u16 nHealth, u16 nTraderID, string* nAngleStr, string* nNpcName, string* nCustomName);\r
+    PMessage* BuildNPCSingleAliveMsg( PClient* nClient, u32 nWorldID, u16 nX, u16 nY, u16 nZ, u8 nActionStatus, u8 nHealth, u8 nAction );\r
+    PMessage* BuildNPCSingleUpdateMsg( PClient* nClient, u32 nWorldID, u16 nX, u16 nY, u16 nZ, u8 nActionStatus, u8 nHealth, u16 nTarget, u8 nAction );\r
+\r
+    // NEW for testing. Combined update message\r
+    PMessage* BuildNPCUpdateMsg(u32 nWorldID, u16 nPosY, u16 nPosZ, u16 nPosX, u8 nActionBM, u16 nHealth, u8 nWeaponState, u8 nUnknown, u32 nTargetID = 0);\r
+\r
+    PMessage* BuildReqInfoAnswerMsg( PClient* nClient, u16 nReqType, u32 nInfoId, void* nResponse, u16 nResponseLength );
+
+    PMessage* BuildPacket0Msg( PClient* nClient );
+    PMessage* BuildPingMsg( PClient* nClient, u32 nClientTime );
+    PMessage* BuildBaselineMsg( PClient* nClient );
+    PMessage* BuildAliveRepMsg( PClient* nClient );
+
+    PMessage* BuildZoning1Msg( PClient* nClient, u16 nEntity, u8 nUnknown = 0 );
+    PMessage* BuildZoningTCPReadyMsg();
+    PMessage* BuildSendZoneTCPMsg( u32 nLocation, std::string* nWorldName );
+    PMessage* BuildZoning2Msg( PClient* nClient, u32 nClientTime );
+    PMessage* BuildGenrepZoningMsg( PClient* nClient, u32 nLocation, u16 nEntity );
+
+    PMessage* BuildGenrepAddToListMsg( PClient* nClient, u32 nLocation, u16 nEntity );
+
+    PMessage* BuildAptLiftUseMsg( PClient* nClient, u32 nLocation, u16 nEntity, u8 nEntityType = 0 );
+    PMessage* BuildAptLiftFailedMsg( PClient* nClient );
+    PMessage* BuildChangeLocationMsg( PClient* nClient, u32 nLocation, u16 nEntity, u8 nEntityType = 0, u32 nRawItemID = 0 );
+    PMessage* BuildEntityPositionMsg( PClient* nClient, u16 pX, u16 pY, u16 pZ );
+
+    PMessage* BuildCharAptLocInfoMsg( PClient* nClient );
+
+    PMessage* BuildLevelUpMessage( PClient* nClient, u8 nMainSkill, u8 nNewLevel, u16 nFreeSkillPoints);
+    PMessage* BuildSubskillIncMsg( PClient* nClient, u8 nSubskill, u16 nSkillPoints );
+    PMessage* BuildChatAddMsg( PClient* nClient, u32 nAddedCharID, u8 nMode ); // mode = 1 for Direct, 2 for Buddy
+
+    PMessage* BuildText100Msg( PClient* nClient, u8 nTxtMsgId, u32 nRawObjectID );
+    PMessage* BuildTextIniMsg( PClient* nClient, u8 nTxtGroupID, u16 nTxtID );
+
+    PMessage* BuildCharInteractionMenuMsg( PClient* nClient, u32 nRawTargetID );
+
+    PMessage* BuildFurnitureActivateMsg( PClient* nClient, u32 nRawObjectID, u8 nActionValue );
+    PMessage* BuildCharUseFurnitureMsg( PClient* nClient, u32 nRawObjectID );
+    PMessage* BuildCharUseVhcTerminalMsg( PClient* nClient, u32 nRawObjectID );
+    PMessage* BuildCharUseGogoMsg( PClient* nClient );
+    PMessage* BuildCharUseVentureWarpMsg( PClient* nClient, u32 nRawObjectID );
+    PMessage* BuildVhcAccessRequestMsg (PClient* nClient, u32 nRequestId, u32 nRequesterCharId, u32 nRequesterLocalId, u32 nVhcRawObjectID );
+    PMessage* BuildCharUseGenrepMsg( PClient* nClient, u32 nRawObjectID, u32 nLocation, u16 nEntity );
+    PMessage* BuildCharUseLiftMsg( PClient* nClient, u32 nRawObjectID, u16 nAptPlace );
+    PMessage* BuildCharUseVhcMsg( PClient* nClient, u32 nRawObjectID, u16 nVhcType, u16 nAvailableSeats );
+
+    PMessage* BuildCharMoneyUpdateMsg( PClient* nClient, u32 nCredits );
+    PMessage* BuildUndefineduseMsg( PClient* nClient, u8 nValue );
+    PMessage* BuildCharUseQBSlotMsg2( PClient* nClient, u16 nV1 = 100, u16 nV2 = 100, u16 nV3 = 100, u16 nV4 = 100, u16 nV5 = 100, u16 nV6 = 100, u16 nV7 = 0 );
+    PMessage* BuildCharUseQBSlotMsg3( PClient* nClient, u8 nSlot );
+    PMessage* BuildCharUseQBSlotMsg4( PClient* nClient, u16 nWeaponId );
+    PMessage* BuildContainerContentList( PContainer* nContainer, u8 nLocType );
+    PMessage* BuildContainerContentEntry( PContainerEntry* nEntry, u8 nLocType );
+
+    PMessage* BuildCharOpenContainerMsg( PClient* nClient, u32 nContainerID, PContainer* nContainer );
+    PMessage* BuildItemMoveMsg( PClient* nClient, u8 nSource, u8 nSrcX, u8 nSrcY, u8 nDestination, u8 nDestX, u8 nDestY, u8 nItemCnt );
+    PMessage* BuildBoxItemMoveMsg( PClient* nClient, PContainerEntry* nEntry, u8 nSrcX, u8 nSrcY, u8 nDestination, u8 nDestX, u8 nDestY, u8 nItemCnt );
+    PMessage* BuildStartWeaponReloadMsg( PClient* nClient );
+
+    PMessage* BuildStartHackGameMsg( PClient* nClient, u32 nWorldObjID, u8 nHackDifficult );
+
+    PMessage* BuildSubwaySpawnMsg( PClient* nClient, bool IsSecondMessage );
+    //PMessage* BuildSubwayFullUpdateMsg(PClient* nClient);
+    PMessage* BuildVhcInfoMsg( PClient* nClient, PSpawnedVehicle* nVehicle );
+
+    PMessage* BuildDBRequestStatusMsg( PClient* nClient, std::string* nCommandName, u8 nStatus, u16 nErrCode );
+    PMessage* BuildDBAnswerMsg( PClient* nClient, std::string* nCommandName, std::string* nAnswerData, u16 nRows, u16 nCols );
+
+    PMessage* BuildTraderItemListMsg( PClient* nClient, u32 nTraderNpcID );
+
+    PMessage* BuildHeldItemUse3Msg(  PClient* nClient, u16 nUnknown1, u16 nUnknown2, u16 nUnknown3, u16 nUnknown4  );
+
+    PMessage* BuildCharUseTimedDrugMsg( PClient* nClient, const PDefDrug* nDrugDef, u16 nItemId );
+    PMessage* BuildCharUseInstantDrugMsg( PClient* nClient, const PDefDrug* nDrugDef );
+    PMessage* BuildCharUseRecreationUnitMsg( PClient* nClient, u32 nObjectId );
+};
+
+#endif
diff --git a/server/src/game/include/msgdecoder.h b/server/src/game/include/msgdecoder.h
new file mode 100644 (file)
index 0000000..a1a03cf
--- /dev/null
@@ -0,0 +1,107 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       msgdecoder.h - top class for NC messages decoding\r
+\r
+       CREATION: 23 Aug 2006 Hammag\r
+\r
+       MODIFIED:\r
+       REASON: -\r
+\r
+*/\r
+\r
+#ifndef MSGDECODER_H\r
+#define MSGDECODER_H\r
+\r
+struct PGameState;\r
+class PClient;\r
+class PMessage;\r
+class PUdpMsgAnalyser;\r
+\r
+#define DECODE_UNDEF 0\r
+#define DECODE_ERROR 1 // one error occured on the current decoding step\r
+#define DECODE_UNKNOWN 2 // the current decoded (sub)message is unkown\r
+#define DECODE_MORE 4 // more decoding needed for the (sub)message\r
+#define DECODE_FINISHED 8 // decoding if finished for the whole message\r
+#define DECODE_ACTION_READY 16 // an action is ready to be done\r
+#define DECODE_ACTION_DONE 32 // the action triggered hasn't to be triggered again\r
+#define DECODE_ACTION_IGNORED 64 // the action wasn't performed for some (good) reason (to combine or not with DONE)\r
+#define DECODE_ACTION_FAILED 128 // the action failed totally or partially (to combine or not with DONE)\r
+\r
+\r
+struct PMsgDecodeData\r
+{\r
+         PMessage* mMessage;\r
+         PClient* mClient;\r
+         u8 mState;\r
+         u8 mUnknownType;\r
+         bool mHandling0x13Sub;\r
+         u16 Sub0x13Start;\r
+         u16 Sub0x13StartNext;\r
+         std::stringstream mName;\r
+         std::string mErrorDetail;\r
+         bool mTraceKnownMsg;\r
+         bool mTraceUnknownMsg;\r
+         bool mTraceDump;\r
+         PGameState* mClientState; // Temporary until State is put back in Client object\r
+};\r
+\r
+// UDP Message decoder\r
+// boolean methods return true if successful\r
+\r
+class PUdpMsgDecoder\r
+{\r
+       private:\r
+    PMsgDecodeData mDecodeData;\r
+    PUdpMsgAnalyser* mCurrentAnalyser;\r
+    std::string mPacketName;\r
+    std::string mTmpName;\r
+\r
+    void Init(PMessage* nMessage, PClient* nClient);\r
+\r
+       public:\r
+         PUdpMsgDecoder();\r
+    PUdpMsgDecoder(PMessage* nMessage, PClient* nClient);\r
+    ~PUdpMsgDecoder();\r
+    \r
+    bool Analyse();\r
+    bool Analyse(PMessage* nMessage, PClient* nClient); // Can be used on non initialized or already used object\r
+    // Temporary form until State is put back in Client object\r
+    inline void Init(PMessage* nMessage, PClient* nClient, PGameState *nClientState) { mDecodeData.mClientState = nClientState; Init(nMessage, nClient); }\r
+    inline u8 GetState() { return mDecodeData.mState; }\r
+    inline bool IsError() { return (mDecodeData.mState & DECODE_ERROR); }\r
+    inline bool IsKnown() { return (!(mDecodeData.mState & DECODE_UNKNOWN)); }\r
+    inline bool MoreSubMsg() { return mDecodeData.mHandling0x13Sub; }\r
+    inline bool IsActionReady() { return (mDecodeData.mState & DECODE_ACTION_READY); }\r
+    inline bool IsActionDone() { return (mDecodeData.mState & DECODE_ACTION_DONE); }\r
+    inline bool IsTraceKnownMsg() { return mDecodeData.mTraceKnownMsg; }\r
+         inline bool IsTraceUnknownMsg() { return mDecodeData.mTraceUnknownMsg; }\r
+         inline bool IsTraceDump() { return mDecodeData.mTraceDump; }\r
+         inline void DumpMsg() { if (mDecodeData.mMessage) mDecodeData.mMessage->Dump(); }\r
+    inline std::string const &GetName() { return (mTmpName = mDecodeData.mName.str()); }\r
+    inline std::string const &GetError() { return mDecodeData.mErrorDetail; }\r
+    bool DoAction();\r
+    inline void Reset() { Init(NULL, NULL); }\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/multipart.h b/server/src/game/include/multipart.h
new file mode 100644 (file)
index 0000000..7b52e52
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ multipart.h - Handling of incomming multipart messages
+
+ CREATION: 31 Aug 2006 Hammag
+
+ MODIFIED:
+ REASON: -
+*/
+
+#ifndef MULTIPART_H
+#define MULTIPART_H
+
+#define MAX_SEQUENCE_LIFE   10 // In seconds
+
+typedef struct // A single chunk of any multipart sequence
+{
+    u16 smChunkNr;
+    //u16 smChunkTotal;
+    PMessage* smChunk;
+} s_MessageChunk;
+
+typedef vector<s_MessageChunk> vecMsgChunk; // The vector of an specific multipart sequence, containing all chunks
+typedef struct
+{
+    time_t smTimeStamp;      // To keep track of sequence's lifetimer
+    u16 smChunkTotal;       // Total amount of chunks for this sequence
+    vecMsgChunk smvChunk;       // The chunkvector
+    PClient *smClient;      // Required to call terminal class
+} s_SequenceEntry;
+
+typedef map<u8, s_SequenceEntry> PMultipartMap; // Map of all vectors, indexed by sequencenumber <u8>
+
+
+class PMultiPart
+{
+  private:
+    PMultipartMap MsgMap;
+    void AssembleChunk(u16 nSequence);
+    void ProcessPacket(PClient *nClient, PMessage *tmpMsg);
+
+// Required to process packets here
+    static const u8 mMaxOptions = 7;
+    std::string mCommandName;
+    std::string mOptions[mMaxOptions];
+    u8 mOptionsCount;
+    u16 mDBId;
+// ---------------------------------
+
+  public:
+    PMultiPart();
+    ~PMultiPart();
+
+    void Update(); // Check for complete/timed out sequences
+    // Adds an multipart frame
+    void AddMultiPartChunk(PClient *nClient, PMessage *nChunk, u16 nChunkNumber, u16 nChunkTotal, u8 nSequence);
+};
+
+#endif
\ No newline at end of file
diff --git a/server/src/game/include/npc.h b/server/src/game/include/npc.h
new file mode 100644 (file)
index 0000000..9177ef7
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ npc.h - Management class for NPC worldactors
+
+ CREATION: 04 Jan 2007 Namikon
+
+ MODIFIED: 28 Apr 2009 Hammag
+ REASON: changed worlds Id from u16 (wrong !!!) to u32
+
+*/
+
+#ifndef NPC_H
+#define NPC_H
+\r
+// Healthfactor for NPCs (see old npc.def)\r
+#define NPC_HEALTHFACTOR 15\r
+\r
+// Minimum time in seconds that has to pass before an NPC\r
+// gets his heartbeat send\r
+#define NPC_HEARTBEAT_MIN 5\r
+// Maximum time in seconds that is allowed to pass without\r
+// an NPC heartbeat\r
+#define NPC_HEARTBEAT_MAX 20\r
+\r
+// If no custom NPC is set in this Zone, what ID to start with?\r
+#define NEW_NPC_ZONEID_START 1000\r
+
+// How many seconds have to pass until the zone gets reset?
+// Reset in: NPCs and PWorld object gets deleted and reloaded when
+// next player syncs to that zone.
+#define ZONE_RESET_AFTER 600
+
+// How many seconds have to pass until the NPC is "revived"
+#define NPC_RESPAWN_AFTER 300
+
+// How many seconds have to pass until we need an NPC "keepalive" packet?
+#define NPC_ALIVE_MSG 15
+\r
+// How often a NPC should check if an enemy is nearby?\r
+#define NPC_ENEMYCHECK 5\r
+\r
+#define NPC_ACTIONSTATE_SITGND  0x00\r
+#define NPC_ACTIONSTATE_ATTACK  0x01\r
+//#define NPC_ACTIONSTATE_?       0x02\r
+//#define NPC_ACTIONSTATE_?       0x04\r
+//#define NPC_ACTIONSTATE_?       0x08\r
+#define NPC_ACTIONSTATE_KNEEL   0x10\r
+#define NPC_ACTIONSTATE_PASSIVE 0x20\r
+#define NPC_ACTIONSTATE_IDLE    0x40\r
+#define NPC_ACTIONSTATE_DEATH   0x80\r
+\r
+#define NPC_SHOOT_IDLE      15\r
+#define NPC_SHOOT_SINGLE    16\r
+#define NPC_SHOOT_AUTO1     17\r
+#define NPC_SHOOT_AUTO2     18\r
+\r
+class PNPC;
+class PNPCWorld;
+
+typedef std::map<u32, PNPC*> PNPCMap;
+typedef std::map<u32, PNPCWorld*> PNPCWorldMap;
+\r
+typedef struct
+{
+       u16 ItemID;\r
+       u32 Price;
+} stShopListEntry;
+\r
+class PNPC
+{
+private:
+    // SQL layout
+    enum
+    {
+        npc_id,
+        npc_worldid,
+        npc_nameid,
+        npc_typeid,
+        npc_name,
+        npc_location,
+        npc_x,
+        npc_y,
+        npc_z,
+        npc_angle,
+        npc_clothing,
+        npc_loot,
+        npc_unknown,
+        npc_trader,  // trader.def entry, or clan/faction data!
+        npc_customname,
+        npc_customscript,\r
+        npc_shop_quality,\r
+        npc_scripting
+    };
+\r
+    std::time_t mNextUpdate;    // Timestamp for next heartbeat\r
+    std::time_t mNextEnemyCheck; // Timestamp for next enemycheck\r
+    inline void PushUpdateTimer() { mNextUpdate = std::time(NULL) + GetRandom(NPC_HEARTBEAT_MAX, NPC_HEARTBEAT_MIN); };\r
+
+    // SQL values
+    u32 mID;
+    u32 mWorldID;
+    u16 mNameID;
+    u16 mTypeID;
+    u16 mClothing;
+    u16 mPosX;
+    u16 mPosY;
+    u16 mPosZ;
+    s8 mAngle;
+    u16 mLoot;
+    u16 mTrader;\r
+    u8 mItemQuality; // Used for Shopping stuff\r
+    u8 mUnknown;\r
+\r
+    std::string mDialogScript;\r
+    std::string mLUAFile; // Load File; Preloaded uppon NPC creation\r
+\r
+    std::vector<stShopListEntry> mVectItemsInShop;    // We need to keep track of the itemorder for shopping\r
+    void AddToVectorList(u16 nItemID, u32 nPrice);\r
+    inline const stShopListEntry* GetItemNum(u32 nIdx) const { if(nIdx > mVectItemsInShop.size()) { return NULL; } else { return &mVectItemsInShop[nIdx]; }};\r
+\r
+    bool mScripting;    // Manual override to disable scripting for an NPC TRUE: Scripts will be executed FALSE: Scripts will be ignored\r
+
+    std::string mName;
+    std::string mCustomName;
+    std::string mCustomLua;
+
+    std::time_t mRespawn;    // Respawn timer
+
+    // Runtime values
+    //bool mDeath;        // Death...\r
+    u8 mFaction;        // NPC's faction\r
+
+    u16 mHealth;         // NPC Current Health-Value\r
+    u16 mMaxHealth;      // NPC Max Health value\r
+    u32 mTarget;        // Current focused player
+    bool mDirty;        // Needs update to clients
+
+    // WorldID Fix 10.10.2009
+    bool mFromDEF;      // to differ DEF NPCs from SQL NPCs
+    bool mSuccess;      // NPC load successfull?\r
+\r
+
+    u8 mAction;         // Current action\r
+    inline u8 GetActionStatus() const { return mAction; };\r
+    // 00000001 (  1) 0x01: Attack-Mode (Depends on WeaponStatus)\r
+    // 00000010 (  2) 0x02: ?\r
+    // 00000100 (  4) 0x04: ?\r
+    // 00001000 (  8) 0x08: ?\r
+    // 00010000 ( 16) 0x10: kneel\r
+    // 00100000 ( 32) 0x20: Passive-Mode  (Depends on WeaponStatus. Difference between 0x01: NPC does NOT open fire)\r
+    // 01000000 ( 64) 0x40: Idle\r
+    // 10000000 (128) 0x80: Die\r
+\r
+    u8 mWeaponStatus;\r
+    inline u8 GetWeaponStatus() const { return mWeaponStatus; };\r
+    // 00001111 (15) 0x0F: Follow given target with eyes / Put weapon away if pulled\r
+    // 00010000 (16) 0x10: Pull weapon if not pulled / If pulled, attack\r
+    // 00010001 (17) 0x11: Pull weapon and attack\r
+
+\r
+    bool SQL_Load();
+    bool DEF_Load(u32 nWorldID);
+\r
+    PNPC( int nSQLID );\r
+    PNPC( int nDEFID, u32 nWorldID );\r
+    ~PNPC();\r
+\r
+    void InitVars();\r
+    void ContentListAddItem(PMessage* nContentList, u16 nItemID, u32 nBasePrice = 0, bool nAddToList = true);\r
+    void ContentListAddItemGroup(PMessage* nContentList, u32 nItemGroupID);\r
+    void StartDialog( PClient* nClient/*, string &nDialogscript */);\r
+\r
+    bool DoSQLShoppingList( PClient* nClient, PMessage* nContentList );\r
+    bool HasSQLShoppingList( PClient* nClient );\r
+    bool IsAllbuyer( PClient* nClient );\r
+    bool LoadLUAScript();\r
+\r
+    inline u32 GetRealWorldID() { if(mFromDEF == true) return mWorldID+255; else return mWorldID; };
+
+public:
+    friend class PNPCWorld;
+\r
+    inline void StopAttack() { mDirty = true; mAction = NPC_ACTIONSTATE_IDLE; mWeaponStatus = NPC_SHOOT_IDLE; };\r
+    inline void Attack( PClient* nClient, u8 nType = NPC_SHOOT_SINGLE, u8 nUnknown = 90 ) { Attack(nClient->GetChar()->GetID(), nType, nUnknown); };\r
+    void Attack( u32 nWorldID, u8 nType = NPC_SHOOT_SINGLE, u8 nUnknown = 90 );\r
+\r
+    inline void Move( u16 nNewX, u16 nNewY, u16 nNewZ )
+    {
+        mPosX = nNewX;
+        mPosY = nNewY;
+        mPosZ = nNewZ;
+        mDirty = true;
+    }
+
+    void Die(); // ... die?
+    void Update(); // Check respawn timer
+    void StartConversation( PClient* nClient );\r
+    void DoConversation( PClient* nClient, u8 nAnswer ) ;\r
+\r
+    // GameCommands\r
+    bool ReloadLUAScript();\r
+    bool ReloadShopList();\r
+    bool SetShopQuality(u8 nNewVal);\r
+    inline bool IsSQLNPC() const { return !mFromDEF; };\r
+    inline int GetNPCID() const { return mWorldID; };\r
+    inline int GetNPCSQLID() const { return mID; };\r
+    inline void SetTrader( u16 nTraderDef ) { mTrader = nTraderDef; };\r
+    inline void SetScripting(bool nVal) { mScripting = nVal; };\r
+    inline u8 GetFaction() const { return mFaction; };\r
+};
+
+// *****************************************
+
+class PNPCWorld
+{
+private:
+    std::time_t mCreation;  // Creation time. (Required to check zone-reset timer
+    std::time_t mLastAliveMsg;  // Time of last "ping" message to keep NPCs in world
+
+    PNPCMap mNPCs;
+    PNPCMap::iterator GetNPCListBegin()
+    {
+        return mNPCs.begin();
+    }
+    PNPCMap::iterator GetNPCListEnd()
+    {
+        return mNPCs.end();
+    }
+
+    bool mSuccessfullInit;
+
+    u32 mWorldID;
+
+    PNPCWorld( u32 nWorldID );
+    ~PNPCWorld();
+
+    void Update();
+
+    // Send all NPCs to one player (Initial zone setup)
+    void MSG_SendNPCs( PClient* nClient );
+
+    // Send "alive" message for all NPCs as zone broadcast to everyone
+    //void MSG_SendAlive();
+
+    bool LoadNPCfromSQL();
+    bool LoadNPCfromDEF();\r
+\r
+    void BroadcastNewNPC(PNPC* nNpc);\r
+    void CheckForEnemies(PNPC* nNPC);
+
+public:
+    friend class PNPCManager;
+    PNPC* GetNPC( u32 nNPCID );\r
+\r
+    // Functions to add/remove an NPC while server is running\r
+    void SendSingleNPCInfo( PClient* nClient, PNPC* nNpc ); // Send\r
+    bool AddNPC(u32 nSQL_ID, u32 nRaw_ID); // Load single SQL NPC from given SQL ID\r
+    void DelNPC(u32 nWorldID); // Remove given NPC from list. Works for *all* npcs\r
+                                                     // but uppon zone reset they're back.
+};
+
+// *****************************************
+
+class PNPCManager
+{
+private:
+    PNPCWorldMap mWorlds;
+    PNPCWorldMap::iterator GetWorldListBegin()
+    {
+        return mWorlds.begin();
+    }
+    PNPCWorldMap::iterator GetWorldListEnd()
+    {
+        return mWorlds.end();
+    }
+
+public:
+    PNPCManager();
+    ~PNPCManager();
+
+    void Update();
+    PNPCWorld* InitWorld( u32 nWorldID );
+
+    PNPCWorld* GetWorld( u32 nWorldID );
+    void InitPlayer( PClient* nClient ); // Player is entering zone
+};
+
+#endif
diff --git a/server/src/game/include/npctemplate.h b/server/src/game/include/npctemplate.h
new file mode 100644 (file)
index 0000000..7c14a54
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+TinNS (TinNS is not a Neocron Server)
+Copyright (C) 2005 Linux Addicted Community
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+*/
+
+
+/*
+npctemplate.h - NPC template class
+
+MODIFIED: 21 Jun 2009 Namikon
+REASON: - creation
+
+*/
+
+#ifndef NPCTEMPLATE_H
+#define NPCTEMPLATE_H
+struct s_f32coords
+{
+    f32 mX;
+    f32 mY;
+    f32 mZ;
+};
+typedef std::map<u32, s_f32coords*> PWaypointMap;
+
+class PNPCTemplate
+{
+    friend class PWorldDatParser;
+
+private:
+
+    PWaypointMap mWayPoints;
+
+    u32       mUnknown1; // Is always 0x20001200, in every log. maybe header for NPCs?
+    f32       mPosY;
+    f32       mPosZ;
+    f32       mPosX;
+    u32       mNPCTypeID; //npc type in npc.def
+    u8        mActorStringSize; //string size with ending 0
+    u8        mAngleStringSize; //string size with ending 0
+    u16       mNpcID;
+    u8        mHasAdditionalCoords; // Seems to be the NUMBER OF additional Coords for the NPC ("Coords" = X/Y/Z in f32, not u16!!)
+    u8        mUnknown2a;
+    u8        mUnknown2b;
+    u8        mUnknown2c;
+    u16       mTradeID;  //mUnknown3; //00 00 ?
+    u16       mUnknown4; //04 00 ?
+    string    mActorName;
+    string    mAngle;
+
+    /* // Not sure about that. Commented out until someone finds out how to deal with those "extra" informations
+    f32 mWaypoint1_Y;
+    f32 mWaypoint1_Z;
+    f32 mWaypoint1_X;
+    f32 mWaypoint2_Y;
+    f32 mWaypoint2_Z;
+    f32 mWaypoint2_X;
+    f32 mWaypoint3_Y;
+    f32 mWaypoint3_Z;
+    f32 mWaypoint3_X;
+    f32 mWaypoint4_Y;
+    f32 mWaypoint4_Z;
+    f32 mWaypoint4_X;
+    f32 mWaypoint5_Y;
+    f32 mWaypoint5_Z;
+    f32 mWaypoint5_X;
+    */
+
+public:
+    PNPCTemplate();
+    ~PNPCTemplate();
+
+    void AddWayPoint(f32 nX, f32 nY, f32 nZ, u8 nID);
+    // TODO: Add GetWaypoint function
+
+    inline u32 GetUnknown1() const
+    {
+        return mUnknown1;
+    };
+    inline f32 GetPosX() const
+    {
+        return mPosY;
+    };
+    inline f32 GetPosY() const
+    {
+        return mPosZ;
+    };
+    inline f32 GetPosZ() const
+    {
+        return mPosX;
+    };
+    inline u32 GetNPCTypeID() const
+    {
+        return mNPCTypeID;
+    };
+    inline u8 GetActorStrSize() const
+    {
+        return mActorStringSize;
+    };
+    inline u8 GetAngleStrSize() const
+    {
+        return mAngleStringSize;
+    };
+    inline u16 GetNpcID() const
+    {
+        return mNpcID;
+    };
+    inline u8 GetHasAdditionalCoords() const
+    {
+        return mHasAdditionalCoords;
+    };
+    inline u8 GetUnknown2a() const
+    {
+        return mUnknown2a;
+    };
+    inline u8 GetUnknown2b() const
+    {
+        return mUnknown2b;
+    };
+    inline u8 GetUnknown2c() const
+    {
+        return mUnknown2c;
+    };
+    inline u16 /*GetUnknown3*/GetTradeID() const
+    {
+        return mTradeID;//mUnknown3;
+    };
+    inline u16 GetUnknown4() const
+    {
+        return mUnknown4;
+    };
+    inline string GetActorName() const
+    {
+        return mActorName;
+    };
+    inline string GetAngle() const
+    {
+        return mAngle;
+    };
+
+
+    inline void SetUnknown1( u32 nValue )
+    {
+        mUnknown1 = nValue;
+    };
+    inline void SetPosX( f32 nValue )
+    {
+        mPosY = nValue;
+    };
+    inline void SetPosY( f32 nValue )
+    {
+        mPosZ = nValue;
+    };
+    inline void SetPosZ( f32 nValue )
+    {
+        mPosX = nValue;
+    };
+    inline void SetNPCTypeID( u32 nValue )
+    {
+        mNPCTypeID = nValue;
+    };
+    inline void SetActorStrSize( u8 nValue )
+    {
+        mActorStringSize = nValue;
+    };
+    inline void SetAngleStrSize( u8 nValue )
+    {
+        mAngleStringSize = nValue;
+    };
+    inline void SetNpcID( u16 nValue )
+    {
+        mNpcID = nValue;
+    };
+    inline void SetHasAdditionalCoords( u8 nValue )
+    {
+        mHasAdditionalCoords = nValue;
+    };
+    inline void SetUnknown2a( u8 nValue )
+    {
+        mUnknown2a = nValue;
+    };
+    inline void SetUnknown2b( u8 nValue )
+    {
+        mUnknown2b = nValue;
+    };
+    inline void SetUnknown2c( u8 nValue )
+    {
+        mUnknown2c = nValue;
+    };
+    inline void /*SetUnknown3*/SetTradeID( u16 nValue )
+    {
+        /*mUnknown3*/mTradeID = nValue;
+    };
+    inline void SetUnknown4( u16 nValue )
+    {
+        mUnknown4 = nValue;
+    };
+    inline void SetActorName( string nValue )
+    {
+        mActorName = nValue;
+    };
+    inline void SetAngle( string nValue )
+    {
+        mAngle = nValue;
+    };
+};
+
+#endif
diff --git a/server/src/game/include/outpost.h b/server/src/game/include/outpost.h
new file mode 100644 (file)
index 0000000..22e5c50
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+TinNS (TinNS is not a Neocron Server)
+Copyright (C) 2005 Linux Addicted Community
+maintainer Akiko <akiko@gmx.org>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+*/
+
+/*
+
+outpost.h - TinNS outpost handling
+
+CREATION: 24 Oct 2009 Namikon
+
+*/
+
+class POutpost
+{
+    private:
+
+    public:
+        POutpost();
+        ~POutpost();
+
+        bool IsZoneOPArea(u32 nZoneID);     // checks if given zoneID is either outpost zone or underground of OP
+        void SendOPAreaData(PClient* nClient); // Sends OP data to client (Owning clan/faction)
+        u32 GetCurrentClan(u32 nOutpostID); // Get current ClanID of given Outpost
+};
+
diff --git a/server/src/game/include/rconsole.h b/server/src/game/include/rconsole.h
new file mode 100644 (file)
index 0000000..21a59dd
--- /dev/null
@@ -0,0 +1,55 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       rconsole.h\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+*/\r
+\r
+#ifndef RCONSOLE_H\r
+#define RCONSOLE_H\r
+\r
+#ifdef _MSC_VER\r
+       #pragma once\r
+#endif\r
+\r
+class PRConsole\r
+{\r
+       private :\r
+               typedef std::list<struct PRConClient*> ClientList;\r
+               ClientList mClients;\r
+\r
+               void ProcessClient(PRConClient* Client);\r
+               void Prompt(PRConClient *Client);\r
+       public :\r
+               PRConsole();\r
+               ~PRConsole();\r
+\r
+               void Start();\r
+               void Update();\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/include/server.h b/server/src/game/include/server.h
new file mode 100644 (file)
index 0000000..7bb29f0
--- /dev/null
@@ -0,0 +1,56 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       server.h\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+*/\r
+\r
+#ifndef SERVER_H\r
+#define SERVER_H\r
+\r
+class PServer\r
+{\r
+       private :\r
+               int mMaxClients;\r
+               int mGMSlots;\r
+               int mNumClients;\r
+               std::vector<PClient*> mClients;\r
+       protected :\r
+       public :\r
+               PServer();\r
+               ~PServer();\r
+\r
+               inline int GetMaxClients() const { return mMaxClients; }\r
+               inline int GetGMSlots() const { return mGMSlots; }\r
+               inline int GetNumClients() const { return mNumClients; }\r
+               int NewClient();\r
+               PClient *GetClient(int Client) const;\r
+               void Update();\r
+               void Shutdown();\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/include/skill.h b/server/src/game/include/skill.h
new file mode 100644 (file)
index 0000000..74a93c6
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+
+
+/*
+       skill.h
+
+       Authors:
+       - Namikon
+       - bakkdoor
+
+       MODIFIED: 17 Dec 2005 Namikon
+       REASON: - Initial Release
+       MODIFIED: 17 Dec 2005 bakkdoor
+       REASON: - Fixed some typos and small bugs
+       MODIFIED: 18 Dec 2005 Namikon
+       REASON: - Moved Structs to new file, added vars for XP and SkillPoints
+                - Added initial skillhandling
+       MODIFIED: 01 Jan 2006 Namikon
+       REASON: - Added SetMainSkill()
+            - Added SetSubSkill()
+            - Added SetXP()
+            - Added SetSP()
+            - Removed IncreaseSubSkill and IncreaseMainSkill
+            - Fixed typo in SUB_SKILLS enum
+       MODIFIED: 19 Sep 2006 Hammag
+       REASON: - Added destructor for struct PSkills in order to free allocated memory
+                   and avoid memory leak.
+       MODIFIED: 25 Nov 2006 Hammag
+       REASON: - Changed from enums (MAIN_SKILLS & SUB_SKILLS) to define, because there is no
+                 simple way to call methods with enum-type params when using arbitrary data (from the client in the present case).
+                 Values should even be taken from def_skills & def_subskills, with global constants
+
+*/
+
+#ifndef SKILL_H
+#define SKILL_H
+
+#define SUB_SKILLS u8
+#define SK_MC 1
+#define SK_HC 2
+#define SK_TRA 3
+#define SK_FOR 22
+#define SK_PC 10
+#define SK_RC 11
+#define SK_TC 12
+#define SK_VHC 13
+#define SK_AGL 14
+#define SK_REP 15
+#define SK_REC 16
+#define SK_RCL 17
+#define SK_ATL 20
+#define SK_END 21
+#define SK_FIR 23
+#define SK_ENR 24
+#define SK_XRR 25
+#define SK_POR 26
+#define SK_HLT 27
+#define SK_HCK 30
+#define SK_BRT 31
+#define SK_PSU 32
+#define SK_WEP 33
+#define SK_CST 34
+#define SK_RES 35
+#define SK_IMP 36
+#define SK_PPU 40
+#define SK_APU 41
+#define SK_MST 42
+#define SK_PPW 43
+#define SK_PSR 44
+#define SK_WPW 45
+
+#define MAIN_SKILLS u8
+#define MS_STR 1
+#define MS_DEX 2
+#define MS_CON 3
+#define MS_INT 4
+#define MS_PSI 5
+
+
+class PSkillHandler
+{
+private:
+    struct PMainSkills
+    {
+        int mINT;
+        int mCON;
+        int mSTR;
+        int mDEX;
+        int mPSI;
+        unsigned short mINTsp;
+        unsigned short mCONsp;
+        unsigned short mSTRsp;
+        unsigned short mDEXsp;
+        unsigned short mPSIsp;
+        float mINTxp;
+        float mCONxp;
+        float mSTRxp;
+        float mDEXxp;
+        float mPSIxp;
+
+        inline PMainSkills()
+        {
+            mINT = mCON = mSTR = mDEX = mPSI = 0;
+            mINTsp = mCONsp = mSTRsp = mDEXsp = mPSIsp = 0;
+            mINTxp = mCONxp = mSTRxp = mDEXxp = mPSIxp = 0.f;
+        }
+    };
+
+    struct PSubSkillINT
+    {
+        int mHCK;
+        int mBRT;
+        int mPSU;
+        int mWEP;
+        int mCST;
+        int mRES;
+        int mIMP;
+        int mWPW;
+
+        inline PSubSkillINT()
+        {
+            mHCK = mBRT = mPSU = mWEP = mCST = mRES = mIMP = mWPW = 0;
+        }
+    };
+
+    struct PSubSkillCON
+    {
+        int mATL;
+        int mEND;
+        int mFIR;
+        int mENR;
+        int mXRR;
+        int mPOR;
+        int mHLT;
+
+        inline PSubSkillCON()
+        {
+            mATL = mEND = mFIR = mENR = mXRR = mPOR = mHLT = 0;
+        }
+    };
+
+    struct PSubSkillSTR
+    {
+        int mMC;
+        int mHC;
+        int mTRA;
+        int mFOR;
+
+        inline PSubSkillSTR()
+        {
+            mMC = mHC = mTRA = mFOR = 0;
+        }
+    };
+
+    struct PSubSkillDEX
+    {
+        int mPC;
+        int mRC;
+        int mTC;
+        int mVHC;
+        int mAGL;
+        int mREP;
+        int mREC;
+        int mRCL;
+
+        inline PSubSkillDEX()
+        {
+            mPC = mRC = mTC = mVHC = mAGL = mREP = mREC = mRCL = 0;
+        }
+    };
+
+    struct PSubSkillPSI
+    {
+        int mPPU;
+        int mAPU;
+        int mMST;
+        int mPPW;
+        int mPSR;
+
+        inline PSubSkillPSI()
+        {
+            mPPU = mAPU = mMST = mPPW = mPSR = 0;
+        }
+    };
+
+    struct PSkills
+    {
+        PMainSkills *Main;
+        PSubSkillINT *INT;
+        PSubSkillCON *CON;
+        PSubSkillSTR *STR;
+        PSubSkillDEX *DEX;
+        PSubSkillPSI *PSI;
+
+        inline PSkills()
+        {
+            Main = new PMainSkills();
+            INT = new PSubSkillINT();
+            CON = new PSubSkillCON();
+            STR = new PSubSkillSTR();
+            DEX = new PSubSkillDEX();
+            PSI = new PSubSkillPSI();
+        }
+
+        inline ~PSkills()
+        {
+            delete Main;
+            delete INT;
+            delete CON;
+            delete STR;
+            delete DEX;
+            delete PSI;
+        }
+    };
+
+    PSkills m_Skills;
+    bool IncSubSkillPossible(SUB_SKILLS Skill);
+
+public:
+
+    void SetSubSkill(SUB_SKILLS Skill, int value);
+    void SetMainSkill(MAIN_SKILLS Skill, int value);
+    void SetXP(MAIN_SKILLS Skill, float value);
+    void SetSP(MAIN_SKILLS Skill, short value);
+
+    int GetMainSkill(MAIN_SKILLS Skill);
+    int GetSubSkill(SUB_SKILLS Skill);
+    int GetSKPCost(SUB_SKILLS Skill);
+
+    // Get Mainskill from given Subskill, client doesn't tell us this
+    MAIN_SKILLS GetMSfromSS(SUB_SKILLS Skill);
+
+    bool IsValidSubSkill(SUB_SKILLS Skill);
+    bool IsValidMainSkill(MAIN_SKILLS Skill);
+
+    void ZeroMSSubSkills(MAIN_SKILLS Skill);
+
+    int IncreaseSubSkill(SUB_SKILLS Skill);
+
+    unsigned short GetSP(MAIN_SKILLS Skill);
+    float GetXP(MAIN_SKILLS Skill);
+};
+
+#endif
diff --git a/server/src/game/include/sql.h b/server/src/game/include/sql.h
new file mode 100755 (executable)
index 0000000..dbb8dc2
--- /dev/null
@@ -0,0 +1,115 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       sql.h - handles all mysql interactions\r
+\r
+       Authors:\r
+       - Namikon\r
+       - bakkdoor\r
+\r
+        MODIFIED: 24 Dec 2005 Namikon\r
+        REASON: - initial release by Namikon\r
+        MODIFIED: 26 Dec 2005 Namikon\r
+        REASON: - Added GetWorldDoorType() for door interaction\r
+                - Added GetWorldItemType() for item interaction\r
+                - Added FmtTxt() for printf() like parsing of text\r
+                - Added GetWorldItemOption() for item interaction\r
+        MODIFIED: 30 Dec 2005 bakkdoor\r
+        REASON: - changed mysql_init() parameter to null to prevent segfault\r
+                - added checking for dbHandle to prevent segfault\r
+        MODIFIED: 07 Jul 2006 Hammag                \r
+        REASON: - Added GetLastGameInsertId() and GetLastInfoInsertId()        \r
+        MODIFIED: 26 Jul 2006 Hammag                \r
+        REASON: - Added CheckResCount() for DB Res memory leak tracking (to be done in the main loop)\r
+                    rather than through Info/GameResQuery()\r
+                - fixed InfoDBInuse and GameDBInuse updating\r
+                - inhibited Info/GameDBInuse warning message in Info/GameResQuery()\r
+        MODIFIED: 27 Sep 2006 Hammag                \r
+        REASON: - Added GetAptLocation() method\r
+        MODIFIED: 12 Oct 2006 Hammag                \r
+        REASON: - Added Update() method\r
+                - added mKeepaliveDelay and mLastKeepaliveSent members\r
+        MODIFIED: 25 Jun 2007 Hammag\r
+        REASON: - Moved all Appartements related methods to PAppartements class\r
+                \r
+        TODO: take all non-pure SQL DB access stuff out of this class        \r
+*/\r
+\r
+#ifndef MYSQL_H\r
+#define MYSQL_H\r
+\r
+class PMySQL\r
+{\r
+    private:\r
+        int info_port;\r
+        char info_host[100];\r
+         char info_userName[100];\r
+        char info_password[100];\r
+        char info_database[100];\r
+        MYSQL *info_dbHandle;\r
+        std::time_t mKeepaliveDelay;\r
+        std::time_t mLastKeepaliveSent;\r
+\r
+        int game_port;\r
+        char game_host[100];\r
+       char game_userName[100];\r
+        char game_password[100];\r
+        char game_database[100];\r
+        MYSQL *game_dbHandle;\r
+\r
+        int GameDBInuse;\r
+        int InfoDBInuse;\r
+\r
+    public:\r
+        PMySQL();\r
+        ~PMySQL();\r
+\r
+        void Update();\r
+        void CheckResCount();\r
+        \r
+        inline MYSQL *GetInfoHandle() { return info_dbHandle; };\r
+        inline MYSQL *GetGameHandle() { return game_dbHandle; };\r
+\r
+        bool Connect();\r
+\r
+        int InfoQuery(const char *query);\r
+        MYSQL_RES *InfoResQuery(const char *query);\r
+        int GameQuery(const char *query);\r
+        MYSQL_RES *GameResQuery(const char *query);\r
+\r
+        /*int GetWorldItemType(unsigned short ID, int Location);\r
+        int GetWorldItemOption(unsigned short ID, int Location, int option);\r
+        int GetWorldDoorType(unsigned int ID, int Location);*/\r
+        \r
+        void ShowInfoSQLError();\r
+        void ShowGameSQLError();\r
+        void FreeGameSQLResult(MYSQL_RES *res);\r
+        void FreeInfoSQLResult(MYSQL_RES *res);\r
+        \r
+        inline u32 GetLastGameInsertId() { return mysql_insert_id(game_dbHandle); };\r
+        inline u32 GetLastInfoInsertId() { return mysql_insert_id(info_dbHandle); };\r
+        \r
+        u32 EscapeString(const char* nText, char* dText, u32 dMaxLength);\r
+};\r
+#endif\r
diff --git a/server/src/game/include/subway.h b/server/src/game/include/subway.h
new file mode 100644 (file)
index 0000000..a5de337
--- /dev/null
@@ -0,0 +1,87 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+  subway.h - subway class\r
+\r
+       MODIFIED: 9 Nov 2007 Hammag\r
+       REASON: - creation\r
+       \r
+*/\r
+\r
+#ifndef SUBWAY_H\r
+#define SUBWAY_H\r
+\r
+class PSubway\r
+{\r
+  friend class PMsgBuilder;\r
+\r
+  struct PSubwayInfo\r
+  {\r
+    u16 mVhcId;\r
+    u16 mPosition;\r
+    u8 mDoorOpened;\r
+    u32 mSeatUsersId[4];\r
+  };\r
+\r
+  public:\r
+    static const u16 mCabsNumber = 11;\r
+    static const u32 mCabsBaseId = 0x03f2;\r
+    static const u32 mCabsBaseHealth = 100; //should take that from .def instead...\r
+    static const u8 mStationsNumber = 8;\r
+    \r
+  private:\r
+    static const u16 mSubwayInitData [];\r
+    static const u32 mCabLoopTime;\r
+    static const u32 mCab0TimeOffset;\r
+    static const s32 mTimingAdjust;\r
+    static const u32 mCabIntervalTime;\r
+    static const u32 mOpenDoorOffset [];\r
+    static const u32 mOpenDoorDuration [];\r
+    static const char* mSubwayStationName [];\r
+    static PCharCoordinates mCabExitPositions [2][mStationsNumber];\r
+    \r
+    PSubwayInfo mSubways[mCabsNumber];\r
+\r
+public:    \r
+    bool GetInfoIndex(u32 nVhcId, u8 *Index = NULL);\r
+    \r
+  public:\r
+    PSubway();\r
+    //~PSubway();\r
+    \r
+    inline bool IsValidSubwayCab(u32 nVhcId) {return GetInfoIndex(nVhcId); }\r
+    bool UpdateInfo(u32 nVhcId, u16 nPosition, u8 nDoorOpened);\r
+    u16 GetPosition(u32 nVhcId);\r
+    \r
+    u32 GetTimeOffset(u32 nVhcId, u32 nTime);\r
+    u8 GetStation(u32 nVhcId, u32 nTime, u32* TimeOffset = NULL);\r
+    bool IsDoorOpen(u32 nVhcId, u32 nTime);\r
+    std::string* GetStationName(u8 nStationId);\r
+    bool GetStationExitPosition(PCharCoordinates* nPosition, u8 nStationId, f32 nCoef = 0.5);\r
+    \r
+    u8 GetFreeSeat(u32 nVhcId);\r
+    bool SetSeatUser(u32 nVhcId, u8 nSeat, u32 nCharId);\r
+    bool UnsetSeatUser(u32 nVhcId, u8 nSeat, u32 nCharId);\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/terminal.h b/server/src/game/include/terminal.h
new file mode 100644 (file)
index 0000000..9dc6c53
--- /dev/null
@@ -0,0 +1,63 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       terminal.h - Management class for Terminal actions (Citycom, keys, vehicledepot, ...)\r
+\r
+       MODIFIED: 08 Jan 2007 Namikon\r
+       REASON: - Created\r
+\r
+*/\r
+\r
+#ifndef TERMINAL_H\r
+#define TERMINAL_H\r
+\r
+class PTerminal\r
+{\r
+    private:\r
+        void SendTryAccessAnswer(PClient* nClient, char *nArea, bool nAllowed);\r
+        char mSQLQuery[500];\r
+\r
+        int mResultFields;\r
+        void EraseVars();\r
+\r
+        char mConPrefix[50];
+
+        inline bool ChkOpt(u8 nNumOptions, u8 nReqOpt) { if(nNumOptions < nReqOpt) return false; else return true; };\r
+        bool DoStockXCheck(PClient* nClient, int nAmountEntered, int nNewAmount);
+\r
+    public:\r
+        PTerminal();\r
+        //~PTerminal();\r
+\r
+        // Check accesslevel of Player for various Terminal actions\r
+        bool CheckAccess(PClient* nClient, char *nArea, u16 nCmdNr, char *nOption1, char *nOption2, char *nOption3);\r
+        u8 GetNewEmailCount(PClient* nClient, bool nNoticeClient = true);\r
+        // Handle ReceiveDB queries\r
+        bool HandleQueryDB(PClient* nClient, std::string *nDBCommandName, std::string *nCommandName, std::string *nOptions, u8 nNumOptions);\r
+        bool HandleReceiveDB(PClient* nClient, u16 mTerminalSessionId, std::string *nCommandName, std::string *nOptions, u8 nNumOptions, u16 nDBID, u8 nUnknown);\r
+        bool HandleTryAccess(PClient* nClient, u16 mTerminalSessionId, std::string *nCommandName, std::string *nOptions, u8 nNumOptions, u16 nDBID, u8 nUnknown, bool nCheckOnly = false);\r
+        bool HandleUpdateDB(PClient* nClient, u16 mTerminalSessionId, std::string *nCommandName, std::string *nOptions, u8 nNumOptions, u16 nDBID, u8 nUnknown);\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/vehicle.h b/server/src/game/include/vehicle.h
new file mode 100644 (file)
index 0000000..fb08a9a
--- /dev/null
@@ -0,0 +1,220 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+ vehicle.h - Vehicle handling\r
+\r
+ Authors:\r
+ - Namikon\r
+\r
+        MODIFIED: 08 Jan 2006 Namikon\r
+        REASON: - initial release by Namikon\r
+*/\r
+\r
+#ifndef VEHICLE_H\r
+#define VEHICLE_H\r
+\r
+class PDefVhc;\r
+\r
+class PVhcCoordinates\r
+{\r
+    friend class PSpawnedVehicle;\r
+\r
+  private:\r
+    u16 mY;     // Y-Position in world\r
+    u16 mZ;     // Z-Position in world\r
+    u16 mX;     // X-Position in world\r
+    u8 mUD;     // Up - Mid - Down (d6 - 80 - 2a) // Pitch\r
+    u16 mLR;     // Yaw\r
+    u16 mRoll;\r
+    u16 mUnknown; // Usually 0x0001\r
+    u8 mFF; // Usually 0xff ...\r
+    u8 mAct;    // Last user action state\r
+    // mAct: bit field\r
+    //0x00 = not moving\r
+    //0x01 = Left\r
+    //0x02 = Right\r
+    //0x04 = Forward\r
+    //0x08 = Back\r
+    //0x20 = Pushing down\r
+    //0x40 = Pulling up\r
+\r
+  public:\r
+    inline PVhcCoordinates() { mX = mY = mZ = mAct = 0; mUD = 128; mLR = 34683; mRoll = 32403;}\r
+\r
+    void SetPosition( u16 nY, u16 nZ, u16 nX, u8 nUD, u16 nLR, u16 nRoll, u8 nAct = 0, u16 nUnknown = 1, u8 nFF = 0xff );\r
+    void SetInterpolate( const PVhcCoordinates& Pos1, const PVhcCoordinates& Pos2, f32 nCoef );\r
+    inline u16 GetX() const { return mX; }\r
+    inline u16 GetY() const { return mY; }\r
+    inline u16 GetZ() const { return mZ; }\r
+    inline u8 GetUD() const { return mUD; }\r
+    inline u16 GetLR() const { return mLR; }\r
+    inline u16 GetRoll() const { return mRoll; }\r
+    inline u8 GetAct() const { return mAct; }\r
+    inline u8 GetUnknown() const { return mUnknown; }\r
+    inline u8 GetFF() const { return mFF; }\r
+};\r
+\r
+class PVehicleInformation\r
+{\r
+    friend class PSpawnedVehicle;\r
+    friend class PVehicles;\r
+\r
+  private:\r
+    u32 mVehicleId;\r
+    u32 mOwnerCharId;\r
+    u32 mHealth; // or f32 ???\r
+    u8 mVehicleType;\r
+    u8 mStatus; //vhcStatus 0:parking, 1:in_service, 2:destroyed\r
+\r
+  public:\r
+    inline PVehicleInformation( u32 nVehicleId = 0, u32 nOwnerCharId = 0, u32 nHealth = 0, u8 nVehicleType = 0, u8 nStatus = 0 ) :\r
+        mVehicleId( nVehicleId ),\r
+        mOwnerCharId( nOwnerCharId ),\r
+        mHealth( nHealth ),\r
+        mVehicleType( nVehicleType ),\r
+        mStatus( nStatus )\r
+    { }\r
+\r
+    inline u32 GetVehicleId() const { return mVehicleId; }\r
+    inline u32 GetOwnerCharId() const { return mOwnerCharId; }\r
+    inline u32 GetHealth() const { return mHealth; } // or f32 ???\r
+    inline u8 GetVehicleType() const { return mVehicleType; }\r
+    inline u8 GetStatus() const { return mStatus; }\r
+    bool SetStatus( u8 nStatus );\r
+\r
+    bool Load( u32 nVehicleId );\r
+    bool Save();\r
+    bool Destroy();\r
+};\r
+\r
+class PSpawnedVehicle\r
+{\r
+  private:\r
+    static const u8 mSeatsFlags[];\r
+\r
+  private:\r
+    u32 mLocalId;\r
+    PVehicleInformation mInfo;\r
+    u32 mLocation;\r
+    PVhcCoordinates mCoords;\r
+    const PDefVhc* mVhcDef;\r
+\r
+    u32 mSeatUserId[8];\r
+    u8 mFreeSeatsFlags;\r
+    u8 mNbFreeSeats;\r
+\r
+    u16 minmax[4][2]; //Temp\r
+\r
+  public:\r
+    PSpawnedVehicle( u32 nLocalId, PVehicleInformation const* nVhcInfo, u32 nLocation, PVhcCoordinates const* nVhcPos );\r
+\r
+    inline u32 GetVehicleId() const { return mInfo.mVehicleId; }\r
+    inline u32 GetLocalId() const { return mLocalId; }\r
+    inline const PVhcCoordinates& GetPosition() const { return mCoords; }\r
+    inline const PVehicleInformation& GetInformation() const { return mInfo; }\r
+    inline bool SetStatus( u8 nStatus ) { return mInfo.SetStatus( nStatus ); }\r
+\r
+    void SetLocation( u32 nLocation );\r
+    inline u32 GetLocation() const { return mLocation; }\r
+    void SetPosition( PVhcCoordinates const* nVhcPos );\r
+\r
+    inline bool Save() { return mInfo.Save(); }\r
+\r
+    int GetNumSeats() const;\r
+    inline u32 GetSeatUser( u8 nSeatId ) const { return (( nSeatId < 8 ) ? mSeatUserId[nSeatId] : 0 ); }\r
+    bool SetSeatUser( u8 nSeatId, u32 nCharId );\r
+    bool UnsetSeatUser( u8 nSeatId, u32 nCharId );\r
+    bool IsCharInside( u32 nCharId ) const;\r
+    inline u8 GetFreeSeatsFlags() const { return mFreeSeatsFlags; }\r
+    inline u8 GetNbFreeSeats() const { return mNbFreeSeats; }\r
+    u8 GetFirstFreeSeat() const;\r
+\r
+    //SetHealth(const u32 nHealth);\r
+    //u32 DoDamage(const u32 nHealthDec);\r
+    //u32 DoRepair(const u32 nHealthInc);\r
+};\r
+\r
+typedef std::map<u32, PSpawnedVehicle*> PSpawnedVhcMap;\r
+typedef std::queue<PVehicleInformation*> PVhcInfoList;\r
+class PVehicles\r
+{\r
+  private:\r
+    PSpawnedVhcMap mSpawnedVehicles;\r
+\r
+    bool RegisterSpawnedVehicle( PSpawnedVehicle*  nSpawnedVehicle );\r
+    bool UnregisterSpawnedVehicle( u32 nVehicleId );\r
+\r
+  public:\r
+    PVehicles();\r
+    ~PVehicles();\r
+\r
+    //u32 CreateVehicle(u32 nOwnerChar, u8 mVehicleType);\r
+    //bool RegisterVehicleOwner(u32 nVehiculeId, u32 nOwnerChar);\r
+    //bool DestroyVehicle(u32 nVehiculeId);\r
+    bool IsValidVehicle( u32 nVehicleId, bool nCheckOwner = false, u32 nOwnerId = 0 ) const;\r
+    inline bool IsSpawned( u32 nVehicleId ) const { return ( mSpawnedVehicles.find( nVehicleId ) != mSpawnedVehicles.end() ); }\r
+    PSpawnedVehicle* GetSpawnedVehicle( u32 nVehicleId ) const;\r
+    bool GetVehicleInfo( u32 nVehicleId, PVehicleInformation* nInfo ) const;\r
+    PSpawnedVehicle* SpawnVehicle( u32 nVehicleId, u32 nLocation, PVhcCoordinates const* nVhcPos ); // Refuses for subway zone atm\r
+    bool UnspawnVehicle( u32 nVehicleId );\r
+\r
+    PVhcInfoList* GetCharVehicles( u32 nCharId, u16 nMaxCount = 0, u16 nStartIndex = 0 );\r
+\r
+};\r
+\r
+typedef std::vector<PSpawnedVehicle*> PSpawnedVhcVector;\r
+typedef std::queue<PSpawnedVehicle*> PSpawnedVhcList;\r
+\r
+class PSpawnedVehicles\r
+{\r
+    friend class PWorld;\r
+\r
+  public:\r
+    static const u32 mVhcBaseLocalId = 0x03fd; //Vhc local Id are allocated downward from this value. Could br 0x3ff, but 0x3fe is used as "target" when shooting nowhere\r
+    static const u16 mMaxLocalVhc = 127;\r
+\r
+    inline static bool IsPotentialSpawnedVehicle( u32 nLocalId )\r
+    { return (( nLocalId <= mVhcBaseLocalId ) && (( mVhcBaseLocalId - nLocalId ) < mMaxLocalVhc ) ); }\r
+\r
+  private:\r
+    PSpawnedVhcVector mSpawnedVehicles;\r
+    u16 mNextFreeHint;\r
+    u32 mLocation;\r
+\r
+    inline void SetLocation( u32 nLocation ) { mLocation = nLocation; }\r
+\r
+  public:\r
+    PSpawnedVehicles();\r
+    ~PSpawnedVehicles();\r
+\r
+    inline bool IsSpawned( u32 nLocalId ) const { return (( nLocalId <= mVhcBaseLocalId ) && (( mVhcBaseLocalId - nLocalId ) < mSpawnedVehicles.size() ) && mSpawnedVehicles[mVhcBaseLocalId-nLocalId] ); }\r
+    PSpawnedVehicle* SpawnVehicle( PVehicleInformation const* nVhcInfo, PVhcCoordinates const* nVhcPos );\r
+    PSpawnedVehicle* GetVehicle( u32 nLocalId );\r
+    PSpawnedVehicle* GetVehicleByGlobalId( u32 nVehicleId ) const;\r
+    bool UnspawnVehicle( u32 nVehicleId );\r
+\r
+    PSpawnedVhcList* GetSpawnedVehicles() const;\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/vhcaccessrequest.h b/server/src/game/include/vhcaccessrequest.h
new file mode 100644 (file)
index 0000000..7769488
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+/*
+  vhcaccessrequest.h - classe for pendinf vhc access requests
+               
+
+ CREATION: 14 Apr 2009 Hammag
+
+*/
+
+#ifndef VHCACCESSREQ_H
+#define VHCACCESSREQ_H
+
+class PVhcAccessRequest
+{
+       public:
+               //u32 mRequestId;
+               std::time_t mTimestamp;
+               u32 mCharId;
+               u32 mVhcGlobalId;
+               u8 mStatus; // 0: no answer yet, 1: access allowed (refused req are dropped) 2: result checked
+
+               PVhcAccessRequest();
+               PVhcAccessRequest(u32 nRequesterCharId, u32 nVhcGlobalId);
+};
+
+class PVhcAccessRequestList
+{
+       typedef std::map<u32, PVhcAccessRequest> PVhcAccessRequestMap; 
+
+       private:
+               PVhcAccessRequestMap mActiveRequests;
+               u32 mNextRequestId;
+
+               std::time_t mResponseWaitTime; // How long do we wait for owner answer
+               std::time_t mCheckWaitTime; // How long do we wait for user access check (0: remaining time from mResponseWaitTime)
+               std::time_t mReuseWaitTime; // How long do we allow user to re-use the autorization after first check
+
+               void DropTimedOut();
+
+       public:
+               PVhcAccessRequestList() ;
+               ~PVhcAccessRequestList();
+
+               void SetParameters(std::time_t nResponseWaitTime, std::time_t nCheckWaitTime, std::time_t nReuseWaitTime);
+               
+               u32 Add(u32 nRequesterCharId, u32 nVhcGlobalId);
+        bool GetInfo(u32 nRequestId, u32* oRequesterCharId, u32* oVehicleId) const;
+               bool RegisterResponse(u32 nRequestId, bool nStatus);
+               bool Check(u32 nRequestId, u32 nRequesterCharId = 0, u32 nVhcGlobalId = 0);
+};
+
+#endif
diff --git a/server/src/game/include/world_datparser.h b/server/src/game/include/world_datparser.h
new file mode 100755 (executable)
index 0000000..20b199b
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+
+
+/*
+       world_datparser.h
+       Class to parse .dat world files
+
+       MODIFIED: 29 Sep 2006 Hammag
+       REASON: - Creation
+*/
+
+#ifndef WORLD_DATPARSER_H
+#define WORLD_DATPARSER_H
+
+class PFile;
+class PWorldDataTemplate;
+
+class PWorldDatParser
+{
+private :
+    PFile* f;
+    std::string mNCDataPath;
+
+    PWorldDataTemplate* mWorld;
+    bool mDiscardPassiveObjects;
+
+    bool ProcessSec2ElemType3(u32 nSize);
+    bool ProcessSec2ElemType5(u32 nSize);
+    bool ProcessSec2NPCEntry(u32 nSize);
+
+public :
+    PWorldDatParser();
+    ~PWorldDatParser();
+
+    int LoadDatFile(const std::string& nFilename, PWorldDataTemplate* nWorld, const bool nDiscardPassiveObjects = true, const bool nTestAccesOnly = false);
+
+};
+
+#endif
+
diff --git a/server/src/game/include/worldactors.h b/server/src/game/include/worldactors.h
new file mode 100644 (file)
index 0000000..83a6225
--- /dev/null
@@ -0,0 +1,189 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+ worldactors.h - Management class for dynamic worldactors\r
+\r
+ CREATION: 02 Jan 2007 Namikon\r
+\r
+ MODIFIED:\r
+ REASON: -\r
+\r
+*/\r
+\r
+/*\r
+Current known WorldActors:\r
+\r
+- Furniture\r
+1       Door\r
+2       Wooden Door\r
+3       Tech Door\r
+5       Lift\r
+6       Shutter\r
+9       Airlock\r
+10      Chair\r
+11      Wooden Chair\r
+12      Bench\r
+13      Table\r
+14      Recreation Unit\r
+\r
+- Interactions\r
+21      Gen rep\r
+22      Go Guardian\r
+99      Outfitter\r
+23/29   Venture Warp\r
+90      City Com\r
+98      Home term\r
+104     Home term\r
+160-195 Hack term\r
+900     Carport Term\r
+\r
+- Cabinets\r
+150     Cabinet\r
+101     Secure Cabinet\r
+105     Safe\r
+106     High Security Safe\r
+\r
+- Hack Boxes\r
+700     Light Weapon Box\r
+703     Medium\r
+720     Ammo Box\r
+740     Armour Box\r
+750     Equipment Box\r
+780     Psi Box\r
+\r
+- Containers\r
+134     Old Bag\r
+120     Trashcan\r
+125     Old Bag\r
+126     Mutant Cooking Pot\r
+127     Rotten Box\r
+128     Rusty Box\r
+133     Steel Box\r
+130     Bunch of Bones\r
+136     Dead Technician (Loot)\r
+137     Corpse (Loot)\r
+\r
+- Others\r
+131     Pile of Stones\r
+8       Rock\r
+510     Tree Trunk\r
+790     Burning Barrel\r
+800     Explosive Barrel\r
+\r
+- Costs\r
+15      Pay 20nc\r
+16      Pay 50nc\r
+17      Pay 100nc\r
+18      Pay 150nc\r
+19      Pay 200nc\r
+20      Pay 500nc\r
+\r
+*/\r
+\r
+\r
+#ifndef WORLDACTORS_H\r
+#define WORLDACTORS_H\r
+\r
+// Start from this offset (00 00 80 00)\r
+#define DYNACTORIDSTART 8388608\r
+\r
+class PWorldActors\r
+{\r
+    private:\r
+       // SQL Layout\r
+        enum\r
+        {\r
+            wa_id,\r
+            wa_actor_id,\r
+            wa_actor_map,\r
+            wa_actor_model,\r
+            wa_actor_type,\r
+            wa_posX,\r
+            wa_posY,\r
+            wa_posZ,\r
+            wa_rotX,\r
+            wa_rotY,\r
+            wa_rotZ,\r
+            wa_option1,\r
+            wa_option2,\r
+            wa_option3\r
+        };\r
+\r
+        void SpawnWA(u32 nWorld, u16 nActorID, u16 nFunctionID, u32 nWOID, u16 nPosX, u16 nPosY, u16 nPosZ, u8 nRotX, u8 nRotY, u8 nRotZ);\r
+        void VanishWA(u32 nWorld, u32 nWAid);\r
+\r
+        // Get next availeable WorldactorID. First, try to find ID in known .dat files, then\r
+        // Get the currently highest ID from SQL and add +1\r
+        // select distinct wi_worlditem_id from world_items order by wi_worlditem_id desc limit 1;\r
+        u32 GetNextFreeWAID();\r
+\r
+    public:\r
+        PWorldActors();\r
+        ~PWorldActors();\r
+\r
+        // Sends initial zone setup to client (after zoning-in)\r
+        void InitWorld(PClient* nClient);\r
+\r
+        // Add new worldactor to database and spawn it. Returns created WorldID\r
+        // Position is taken from nClient, same as the worldID and calls the mainfunction\r
+        // The function values are optional (used for interactive objects, gogo or genrep)\r
+        u32 AddWorldActor(PClient* nClient, u16 nActorID, u16 nFuncID, u16 nOpt1 = 0, u16 nOpt2 = 0, u16 nOpt3 = 0);\r
+\r
+        // Add new worldactor to database and spawn it. Returns created WorldID\r
+        // The function values are optional (used for interactive objects, gogo or genrep)\r
+        u32 AddWorldActor(u32 nWorldID, u16 nActorID, u16 nFuncID, u16 nPosX, u16 nPosY, u16 nPosZ, u8 nRotX, u8 nRotY, u8 nRotZ, u16 nOpt1 = 0, u16 nOpt2 = 0, u16 nOpt3 = 0);\r
+\r
+        // Remove worldactor in given world from SQL and game\r
+        void DelWorldActor(PClient* nClient, u32 nWAid);\r
+\r
+        // Get functionvalues for worldactor\r
+        void GetWAoption(u32 nWAid, u16 nWorld, u16 &nValue1, u16 &nValue2, u16 &nValue3);\r
+\r
+        // Get SQL ID from world and worldID\r
+        int GetWASQLID(u32 nWAid, u32 nWorld);\r
+\r
+        // Check if actorID is dynamic\r
+        bool IsDynamicActor(u32 nWAid);\r
+\r
+        // Not needed. Better re-spawn the actor\r
+        //bool EditWorldActor(u32 nWorldID, int nOption1 = -1, int nOption2 = -1, int nOption3 = -1);\r
+\r
+        int GetWorldActorFunctionID(u32 nWAid);\r
+\r
+        void GetFrontPos(u32 nWAID, u16* mX, u16* mY, u16* mZ); // For chairs\r
+        int GetLinkedObjectID(u32 nWAID); // OptionValue 1 is used for linked object!\r
+\r
+        // Check if given functionID does exist\r
+        bool IsValidWAFunction(int nFunctionID);\r
+\r
+        // Checks if this functionID required an linked object or not\r
+        bool RequiresLinkedObject(int nFunctionID);\r
+\r
+        // Checks if the given worldobjectID is valid for this type of functionID\r
+        bool IsValidLinkedObject(PClient *nClient, u16 nOption1, int nFunctionID);\r
+\r
+        // Checks for double actor-IDs and deletes them from DB\r
+        void DoActorCheck();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/game/include/worlddatatemplate.h b/server/src/game/include/worlddatatemplate.h
new file mode 100755 (executable)
index 0000000..2e1ded4
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+
+/*
+  worlddatatemplate.cpp - world data template (from worlds .dat files) class
+
+       MODIFIED: 04 Oct 2006 Hammag
+       REASON: - creation
+
+    MODIFIED: 21 Jun 2009 Namikon
+    REASON: - Added NPC Template stuff
+
+*/
+
+
+#ifndef WORLDDATATEMPLATE_H
+#define WORLDDATATEMPLATE_H
+
+#define WORLDDATATEMPLATE_MAXPOSITEMS 11
+
+class PFurnitureItemTemplate;
+typedef std::map<u32, PFurnitureItemTemplate*> PFurnitureItemsMap;
+
+class PDoorTemplate;
+typedef std::map<u32, PDoorTemplate*> PDoorsMap;
+
+class PNPCTemplate;
+typedef std::map<u32, PNPCTemplate*> PNPCsMap;
+
+class PWorldDataTemplate
+{
+private:
+    std::string mName; // (datfile) relative path+filename without leading ./ or ./worlds/ nor .dat extension
+    std::string mBspName; // (bsp file) relative path+filename without leading ./ or ./worlds/ nor .bsp extension
+    PFurnitureItemsMap mFurnitureItems;
+    PDoorsMap mDoors;
+    PNPCsMap mNPCs;
+    PFurnitureItemTemplate* mPositionItems[WORLDDATATEMPLATE_MAXPOSITEMS];
+
+    int mUseCount;
+
+    void DatFileDataCleanup();
+    void SetLinkedObjects(); // This method implements some workarouds for some world objects on which we lack info.
+
+public:
+    PWorldDataTemplate();
+    ~PWorldDataTemplate();
+
+    bool LoadDatFile(const std::string& WorldTemplateName, const std::string& nFilename, const bool nTestAccesOnly = false);
+    inline const std::string& GetName()
+    {
+        return mName;
+    }
+    inline const std::string& GetBspName()
+    {
+        return mBspName;
+    }
+
+    inline void IncreaseUseCount()
+    {
+        ++mUseCount;
+    }
+    inline int DecreaseUseCount()
+    {
+        return (mUseCount ? --mUseCount : 0);
+    }
+    inline int GetUseCount()
+    {
+        return mUseCount;
+    }
+
+    u32 AddFurnitureItem(PFurnitureItemTemplate* nItem);
+    const PFurnitureItemTemplate* GetFurnitureItem(u32 ItemID);
+    bool getPositionItemPosition(u8 PosID, f32* pX, f32* pY, f32* pZ);
+
+    u32 AddDoor(PDoorTemplate* nDoor);
+    const PDoorTemplate* GetDoor(u32 DoorID);
+
+    u32 AddNPC(PNPCTemplate* nNPC);
+
+    // External functions for NPCManager
+    const PNPCTemplate* GetNPC(u32 NPCID);
+    inline const PNPCsMap *GetNPCMap() const
+    {
+        return &mNPCs;
+    }; // called by class PNPCWorld to get all NPCs for this world
+};
+
+#endif
diff --git a/server/src/game/include/worlds.h b/server/src/game/include/worlds.h
new file mode 100755 (executable)
index 0000000..3906779
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+
+/*
+  worlds.h - world class and world map class
+
+ MODIFIED: 06 Oct 2006 Hammag
+ REASON: - creation
+
+*/
+
+
+#ifndef WORLDS_H
+#define WORLDS_H
+
+#include "worlddatatemplate.h"
+#include "vehicle.h"
+
+typedef std::map<u32, int> PChairsInUseMap;
+
+class PWorld
+{
+    friend class PWorlds;
+
+public:
+    static u16 const mZoneOutLimitOffset;
+    static u16 const mBottomZoneOutLimit;
+    static u16 const mBottomZoneInLimit;
+    static u16 const mTopZoneOutLimit;
+    static u16 const mTopZoneInLimit;
+
+private:
+    u32 mID;
+    bool mIsAppartment;
+    int mUseCount;
+    PWorldDataTemplate* mWorldDataTemplate;
+    PChairsInUseMap mChairsInUseMap;
+    PSpawnedVehicles mSpawnedVehicles;
+
+    inline void IncreaseUseCount()
+    {
+        ++mUseCount;
+    }
+    inline int DecreaseUseCount()
+    {
+        return ( mUseCount ? --mUseCount : 0 );
+    }
+    inline int GetUseCount()
+    {
+        return mUseCount;
+    }
+    bool Load( u32 nWorldID );
+
+public:
+    PWorld();
+    ~PWorld();
+
+    inline std::string GetName()
+    {
+        return ( mWorldDataTemplate ? mWorldDataTemplate->GetName() : EmptyString );
+    }
+    inline std::string GetBspName()
+    {
+        return ( mWorldDataTemplate ? mWorldDataTemplate->GetBspName() : EmptyString );
+    }
+    inline bool IsAppartment()
+    {
+        return mIsAppartment;
+    }
+    inline const PFurnitureItemTemplate* GetFurnitureItemTemplate( u32 nItemID )
+    {
+        return ( mWorldDataTemplate ? mWorldDataTemplate->GetFurnitureItem( nItemID ) : NULL ) ;
+    }
+    const PDefWorldModel* GetFurnitureItemModel( u32 nItemID );
+    inline const PDoorTemplate* GetDoor( u32 nDoorID )
+    {
+        return ( mWorldDataTemplate ? mWorldDataTemplate->GetDoor( nDoorID ) : NULL );
+    }
+    inline bool getPositionItemPosition( u8 PosID, f32* pX, f32* pY, f32* pZ )
+    {
+        return ( mWorldDataTemplate ? mWorldDataTemplate->getPositionItemPosition( PosID, pX, pY, pZ ) : false );
+    }
+
+    bool CharUseChair( int CharLocalID, u32 nItemID );
+    void CharLeaveChair( int CharLocalID, u32 nItemID );
+
+    PClient* GetClientByCharLocalId( u32 rawObjectId ) const; // returns Client if object is a PC char, and 0 if not.
+
+    inline PSpawnedVehicles* GetSpawnedVehicules()
+    {
+        return &mSpawnedVehicles;
+    }
+    bool CheckVhcNeedZoning( PVhcCoordinates const* nPos ) const;
+    u32 GetVhcZoningDestination( PSpawnedVehicle const* nVhc, PVhcCoordinates* nPos = 0 ) const;
+
+    // Evil thing... bounced through stuff :| wasnt able to find a better solution for this
+    inline const PNPCsMap       *GetNPCMap() const
+    {
+        return (mWorldDataTemplate ? mWorldDataTemplate->GetNPCMap() : NULL);
+    };
+    inline const PNPCTemplate   *GetNPCTemplate( u32 nNPCID ) const
+    {
+        return (mWorldDataTemplate ? mWorldDataTemplate->GetNPC( nNPCID ) : NULL );
+    };
+};
+
+
+typedef std::map<u32, PWorld*> PWorldsMap;
+typedef std::map<std::string, PWorldDataTemplate*> PWorldDataTemplatesMap;
+
+class PWorlds
+{
+    friend class PWorld;
+
+public:
+    static u32 const mNcSubwayWorldId;
+    static u32 const mAptBaseWorldId;
+    static u32 const mOutdoorBaseWorldId;
+    static u32 const mOutdoorWorldIdVIncrement;
+    static u8 const mOutdoorWorldmapHSize;
+    static u8 const mOutdoorWorldmapVSize;
+    static u32 const mOutdoorMaxWorldId;
+
+private:
+    bool mPreloadWorldsTemplates;
+    bool mPreloadStaticWorlds;
+
+    PWorldsMap mStaticWorldsMap; // lists all valid static worlds, with second=NULL if not loaded
+    PWorldsMap mOnDemandWorldsMap; // mostly appartments. Could be used for instance dungeons too, but instance dungeons are crap :p
+    PWorldDataTemplatesMap mWorldDataTemplatesMap;
+
+    bool LeaseWorldDataTemplate( const std::string& nBspName, const std::string& nFileName, const bool nPreloadPhase = false );
+    void ReleaseWorldDataTemplate( const std::string& nFileName );
+    void UnloadWorldDataTemplate( const std::string& nFileName );
+    PWorldDataTemplate* GetWorldDataTemplate( const std::string& nFileName );
+    PWorld* LeaseWorld( u32 nWorldID, const bool nPreloadPhase );
+
+public:
+    PWorlds();
+    ~PWorlds();
+
+    bool LoadWorlds();
+    bool IsValidWorld( u32 nWorldID ) const;
+    inline PWorld* LeaseWorld( u32 nWorldID )
+    {
+        return LeaseWorld( nWorldID, false );
+    }
+    PWorld* GetWorld( u32 nWorldID );
+    void ReleaseWorld( u32 nWorldID );
+    bool IsAppartment( u32 nWorldID );
+    inline bool IsPotentialAppartement( u32 nWorldID )
+    {
+        return ( nWorldID > PWorlds::mAptBaseWorldId );
+    }
+
+    void Update();
+    void Shutdown();
+
+    u32 GetWorldIdFromWorldmap( u8 mapH, u8 mapV ) const;  // H & V pos are 0-based
+    bool GetWorldmapFromWorldId( u32 nWorldId, u8& mapH, u8& mapV ) const;
+};
+
+#endif
diff --git a/server/src/game/include/zoning.h b/server/src/game/include/zoning.h
new file mode 100644 (file)
index 0000000..b79007d
--- /dev/null
@@ -0,0 +1,46 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       zoning.h\r
+\r
+       Authors:\r
+       - Namikon\r
+\r
+       MODIFIED: XX Dec 2005 Namikon\r
+       REASON: - Initial Release\r
+       MODIFIED: 23 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+       MODIFIED: 28 Jul 2005 Hammag\r
+       REASON: - changed loc parameter type from int to u32\r
+       \r
+*/\r
+\r
+#ifndef ZONING_H\r
+#define ZONING_H\r
+\r
+//void SendZone(PClient *Client, PGameState *State,int loc);\r
+void SendZone(PClient *Client, u32 loc);\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/inventory.cpp b/server/src/game/inventory.cpp
new file mode 100644 (file)
index 0000000..8b601a9
--- /dev/null
@@ -0,0 +1,153 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+  inventory.cpp - classes for inventories\r
+                  (inventory, belt, armor, implants, gogo, processor(?), maybe other containers(?) )\r
+\r
+ MODIFIED: 10 Jul 2006 Hammag\r
+ REASON: - creation : Quick and dirty main inventory (backpack) management\r
+\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "inventory.h"\r
+#include "container.h"\r
+\r
+\r
+/* --- PInventory class --- */\r
+\r
+PInventory::PInventory ()\r
+{\r
+  mWorn = new PContainerWithHoles(INV_WORN_MAXSLOTS);\r
+  //mBackpack = new PContainer2D();\r
+  mBackpack = new PContainer2DWorkaround(); // until Inside-Backpack item moving issues are solved\r
+  mBackpack->Set2DPosMax(INV_BACKPACK_COLS);\r
+  mGogo = new PContainerAutoFindFree(INV_GOGO_MAXSLOTS);\r
+}\r
+\r
+PInventory::~PInventory ()\r
+{\r
+  delete mWorn;\r
+  delete mBackpack;\r
+  delete mGogo;\r
+}\r
+\r
+void PInventory::SetCharId(u32 CharID)\r
+{\r
+  mWorn->SetInfo(CharID, INV_DB_LOC_WORN);\r
+  mBackpack->SetInfo(CharID, INV_DB_LOC_BACKPACK);\r
+  mGogo->SetInfo(CharID, INV_DB_LOC_GOGO);\r
+}\r
+\r
+bool PInventory::SQLLoad()\r
+{\r
+  return ( mWorn->SQLLoad() && mBackpack->SQLLoad() && mGogo->SQLLoad() );\r
+  \r
+/*bool ret = mWorn->SQLLoad() && mBackpack->SQLLoad() && mGogo->SQLLoad();\r
+Console->Print(YELLOW, BLACK, "--- Worn Inventory ---");\r
+mWorn->Dump();\r
+Console->Print(YELLOW, BLACK, "--- Backpack Inventory ---");\r
+mBackpack->Dump();\r
+Console->Print(YELLOW, BLACK, "--- Gogo Inventory ---");\r
+mGogo->Dump();\r
+Console->Print(YELLOW, BLACK, "--- End Inventory ---");\r
+return ret;*/\r
+}\r
+\r
+bool PInventory::SQLSave()\r
+{\r
+  return mWorn->SQLSave() && mBackpack->SQLSave() && mGogo->SQLSave();\r
+}\r
+\r
+bool PInventory::IsDirty() const\r
+{\r
+  return (mWorn && mWorn->IsDirty()) || (mBackpack && mBackpack->IsDirty()) || (mGogo && mGogo->IsDirty());\r
+}\r
+\r
+PContainer* PInventory::GetContainer(u8 nInvLoc)\r
+{\r
+  PContainer* tContainer;\r
+  switch(nInvLoc)\r
+  {\r
+    case INV_LOC_WORN:\r
+      tContainer = mWorn;\r
+      break;\r
+    case INV_LOC_BACKPACK:\r
+      tContainer = mBackpack;\r
+      break;\r
+    case INV_LOC_GOGO:\r
+      tContainer = mGogo;\r
+      break;\r
+    default:\r
+      tContainer = NULL;\r
+  }\r
+  return tContainer;\r
+}\r
+\r
+bool PInventory::AddItem(PItem *NewItem, u8 nInvLoc, u32 nInvID, u8 nPosX, u8 nPosY, bool SetDirty)\r
+{\r
+  PContainer* destContainer = GetContainer(nInvLoc);\r
+  return(destContainer ? destContainer->AddItem(NewItem, nInvID, nPosX, nPosY, SetDirty) : false);\r
+}\r
+\r
+/*\r
+bool PInventory::QB_IsFree(u8 nSlot)\r
+{\r
+    if(nSlot > 9)\r
+        return false;\r
+\r
+    //    if (gDevDebug) Console->Print("Checking QBSlot %d. Content: %d", nSlot, mQuickAccessBelt[nSlot]);\r
+    if(mQuickAccessBelt[nSlot] == 0)\r
+        return true;\r
+    else\r
+        return false;\r
+}\r
+\r
+void PInventory::QB_SetSlot(u8 nSlot, u16 nItemID)\r
+{\r
+    if(nSlot > 9)\r
+        return;\r
+    //    if (gDevDebug) Console->Print("Setting QBSlot %d. Newcontent: %d Oldcontent: %d", nSlot, nItemID, mQuickAccessBelt[nSlot]);\r
+    mQuickAccessBelt[nSlot] = nItemID;\r
+}\r
+\r
+u16 PInventory::QB_GetSlot(u8 nSlot)\r
+{\r
+    if(nSlot > 9)\r
+        return 0;\r
+    //    if (gDevDebug) Console->Print("Getting QBSlot %d. Content: %d", nSlot, mQuickAccessBelt[nSlot]);\r
+    return mQuickAccessBelt[nSlot];\r
+}\r
+\r
+void PInventory::QB_Move(u8 nSlotSRC, u8 nSlotDST)\r
+{\r
+    if(nSlotSRC > 9 || nSlotDST > 9)\r
+        return;\r
+\r
+    //    if (gDevDebug) Console->Print("Moving QBSlot %d [%d] to %d [%d]", nSlotSRC, mQuickAccessBelt[nSlotSRC], nSlotDST, mQuickAccessBelt[nSlotDST]);\r
+    mQuickAccessBelt[nSlotDST] = mQuickAccessBelt[nSlotSRC];\r
+    mQuickAccessBelt[nSlotSRC] = 0;\r
+    //    if (gDevDebug) Console->Print("Moving done. %d [%d] %d [%d]", nSlotSRC, mQuickAccessBelt[nSlotSRC], nSlotDST, mQuickAccessBelt[nSlotDST]);\r
+}\r
+*/\r
diff --git a/server/src/game/isc.cpp b/server/src/game/isc.cpp
new file mode 100644 (file)
index 0000000..c5a270f
--- /dev/null
@@ -0,0 +1,214 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+  isc.cpp\r
+\r
+  MODIFIED: Unknown date / Namikon\r
+  REASON: - initial release by Namikon\r
+       MODIFIED: 13 Oct 2006 Hammag\r
+       REASON: - Implemented MySQL isc method\r
+\r
+  TODO:\r
+    - implement ISC protocol\r
+*/\r
+\r
+#include "main.h"\r
+\r
+#include "isc.h"\r
+\r
+PISC::PISC()\r
+{\r
+  use_isc = false;\r
+  use_mysql = false;\r
+}\r
+\r
+PISC::~PISC()\r
+{\r
+}\r
+\r
+void PISC::Start()\r
+{\r
+  isc_method = Config->GetOptionInt("isc_method");\r
+\r
+  if(isc_method & 1)\r
+  {\r
+      Console->Print("%s Infoserver updating over MySQL is enabled", Console->ColorText(GREEN, BLACK, "[Info]"));\r
+      use_mysql = true;\r
+  }\r
+  if(isc_method & 2)\r
+  {\r
+      Console->Print("%s Infoserver updating over ISC is enabled, update intervall: infoserver: %s", Console->ColorText(GREEN, BLACK, "[Info]"), "?");\r
+      use_isc = true;\r
+      Console->Print("%s Infoserver updating over ISC not implemented yet. DISABLED", Console->ColorText(YELLOW, BLACK, "[Notice]"));\r
+      use_isc = false;\r
+  }\r
+  if(!(use_isc || use_mysql))\r
+  {\r
+      Console->Print("%s ISC and MySQL are both disabled, infoserver will NOT be updated", Console->ColorText(YELLOW, BLACK, "[Notice]"));\r
+  }\r
+\r
+  if (use_isc)\r
+    Start_isc();\r
+  \r
+  if (use_mysql)\r
+    Start_mysql();\r
+\r
+}\r
+\r
+void PISC::Update()\r
+{\r
+  if (use_isc)\r
+    Update_isc();\r
+  \r
+  if (use_mysql)\r
+    Update_mysql();     \r
+}\r
+\r
+void PISC::Shutdown()\r
+{\r
+  if (use_isc)\r
+  {\r
+    use_isc = false;\r
+    Shutdown_isc();\r
+  }\r
+  \r
+  if (use_mysql)\r
+  {\r
+    use_mysql = false;\r
+    Shutdown_mysql();\r
+  }\r
+}\r
+\r
+/*** ISC protocol mode specific ***/\r
+\r
+void PISC::Start_isc()\r
+{\r
+  u16 Port = Config->GetOptionInt("isc_infoserverport");\r
+       if (Port == 0)\r
+       {\r
+               Console->Print("%s Unable to start ISC, isc_infoserverport setting is invalid");\r
+               use_isc = false;\r
+               return;\r
+       }\r
+       Console->Print("Trying to connect to infoserver...", Port);\r
+       // Add function for initial connect here and store the connectioninfo somewhere\r
+}\r
+\r
+void PISC::Update_isc()\r
+{\r
+  \r
+}\r
+\r
+void PISC::Shutdown_isc()\r
+{\r
+  \r
+}\r
+\r
+\r
+/*** IMySQL mode specific ***/\r
+\r
+void PISC::Start_mysql()\r
+{\r
+  m_server_id = Config->GetOptionInt("isc_server_id");\r
+  mysql_update_intervall = Config->GetOptionInt("isc_update_intervall");\r
+  if (mysql_update_intervall < 10)\r
+  {\r
+    Console->Print("%s value for 'isc_update_intervall' too low (%d). Set to 10 sec.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mysql_update_intervall);\r
+    mysql_update_intervall = 10;\r
+  }\r
+  \r
+  mysql_delayed_update_intervall = Config->GetOptionInt("isc_delayed_update_intervall");\r
+  if (mysql_delayed_update_intervall < 0)\r
+  {\r
+    Console->Print("%s value for 'isc_delayed_update_intervall' is invalid (%d). Set to 0 sec (immediate update)", Console->ColorText(YELLOW, BLACK, "[Notice]"), mysql_delayed_update_intervall);\r
+    mysql_delayed_update_intervall = 0;\r
+  }\r
+    \r
+  mysql_last_update_time = 0;\r
+  mysql_last_client_count = 0;\r
+  mysql_last_count_decrease_time = 0;\r
+  \r
+  Update_mysql();\r
+}\r
+\r
+void PISC::Update_mysql()\r
+{\r
+  bool do_update = false;\r
+  std::time_t t = std::time(NULL);\r
+  int client_count = Server->GetNumClients();\r
+  \r
+  if (((t - mysql_last_update_time) >= mysql_update_intervall) || (client_count > mysql_last_client_count))\r
+  {\r
+    do_update = true;\r
+//if(gDevDebug) Console->Print("%s ISC : time or more clients", Console->ColorText(GREEN, BLACK, "[Debug]"));\r
+  }\r
+  else if (client_count < mysql_last_client_count)\r
+  {\r
+    if(mysql_last_count_decrease_time && ((t - mysql_last_count_decrease_time) >= mysql_delayed_update_intervall))\r
+    {\r
+      do_update = true;\r
+//if(gDevDebug) Console->Print("%s ISC : less clients timed out", Console->ColorText(GREEN, BLACK, "[Debug]"));\r
+    }\r
+    else if (!mysql_last_count_decrease_time)\r
+    {\r
+      mysql_last_count_decrease_time = t;\r
+//if(gDevDebug) Console->Print("%s ISC : Starting less clients time count", Console->ColorText(GREEN, BLACK, "[Debug]"));\r
+    }\r
+  }\r
+  else if (mysql_last_count_decrease_time && (client_count == mysql_last_client_count))\r
+  {\r
+    mysql_last_count_decrease_time = 0;\r
+//if(gDevDebug) Console->Print("%s ISC : Canceling less clients time count", Console->ColorText(GREEN, BLACK, "[Debug]"));    \r
+  }\r
+  \r
+  if (do_update)\r
+  {\r
+    do_mysql_db_update(client_count);\r
+    mysql_last_client_count = client_count;\r
+    mysql_last_count_decrease_time = 0;\r
+    mysql_last_update_time = std::time(NULL);\r
+  }\r
+  \r
+}\r
+\r
+void PISC::Shutdown_mysql()\r
+{\r
+  use_mysql = false;\r
+  do_mysql_db_update(0,true);\r
+}\r
+\r
+bool PISC::do_mysql_db_update(int players, bool shutdown)\r
+{\r
+  char query[256];\r
+  snprintf (query, 256, "UPDATE `server_list` SET `s_players` = '%d', `s_lastupdate` = %s WHERE `s_id` = %d LIMIT 1;", players, (shutdown ? "'0'" : "NOW()"), m_server_id);\r
+\r
+//if(gDevDebug) Console->Print("%s Updating Infoserver over MySQL.", Console->ColorText(GREEN, BLACK, "[Debug]"));\r
+  if(MySQL->InfoQuery(query))\r
+  {\r
+    use_mysql = false;\r
+    Console->Print("%s Could not update Infoserver over MySQL. Updating DISABLED. Error was:", Console->ColorText(RED, BLACK, "[ERROR]"));\r
+    MySQL->ShowInfoSQLError();\r
+    return false;\r
+  }\r
+  else\r
+    return true;\r
+}\r
diff --git a/server/src/game/item.cpp b/server/src/game/item.cpp
new file mode 100644 (file)
index 0000000..cdd275b
--- /dev/null
@@ -0,0 +1,129 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+  item.cpp - item class\r
+\r
+       MODIFIED: 11 Jul 2006 Hammag\r
+       REASON: - creation\r
+       \r
+*/\r
+\r
+#include "main.h"\r
+\r
+#include "item.h"\r
+#include "gamedefs.h"\r
+#include "def_items.h"\r
+\r
+PItem::PItem(u32 ItemID, u8 nStackSize, u8 CurDur, u8 MaxDur, u8 Dmg, u8 Freq, u8 Hand, u8 Rng)\r
+{\r
+  mDefItem = GameDefs->Items()->GetDef(ItemID);\r
+  if (mDefItem) {\r
+    mItemID = ItemID;\r
+    mStackable = mDefItem->IsStackable();\r
+    mStackSize = mStackable ? nStackSize : 1;\r
+\r
+    mLoadedAmmoId = 0;\r
+    mLoadedAmmoNb = 0;\r
+\r
+    mPropertiesFlags = 0;\r
+\r
+    mUsedSlots = mMaxSlots = 0;\r
+    mModificators = 0;\r
+    \r
+    mConstructorId = 0;\r
+    //mType = mDefItem->GetType();\r
+    //mValue1 = mDefItem->GetValue1();\r
+    //mValue2 = mDefItem->GetValue2();\r
+    //mValue3 = mDefItem->GetValue3();\r
+    //mSizeX = mDefItem->GetSizeX();\r
+    //mSizeY = mDefItem->GetSizeY();   \r
+    //mWeight = mDefItem->GetWeight();\r
+    //mFillWeight = mDefItem->GetFillWeight();\r
+    //mQualifier = mDefItem->GetQualifier();\r
+    //mItemGroupID = mDefItem->GetItemGroupID();       \r
+    //mBasePrice = mDefItem->GetBasePrice();\r
+    //mTechlevel = mDefItem->GetTechlevel();\r
+    //mItemflags = mDefItem->GetItemflags();\r
+\r
+    //if (!mStackable) // only non-stackable items can have quality stats (?)\r
+    //{\r
+    //  mStackSize = 1;\r
+      mCurDuration = CurDur;\r
+      mMaxDuration = MaxDur;\r
+      mDamages = Dmg;\r
+      mFrequency = Freq;\r
+      mHandling = Hand;\r
+      mRange = Rng;\r
+    //}\r
+  }\r
+  else\r
+  {\r
+    mItemID = 0;\r
+    Console->Print(YELLOW, BLACK, "PItem::PItem: Invalid item ID %d", ItemID);\r
+  }\r
+}\r
+\r
+void PItem::MakeItemStandard(u8 GlobalQualityMin, u8 GlobalQualityMax)\r
+{\r
+  if(GlobalQualityMin > GlobalQualityMax) GlobalQualityMin = GlobalQualityMax;\r
+\r
+  mCurDuration = 255;\r
+  mMaxDuration = 255;\r
+  if(GlobalQualityMin == GlobalQualityMax)\r
+  {\r
+       mDamages = GlobalQualityMin;\r
+       mFrequency = GlobalQualityMin;\r
+       mHandling = GlobalQualityMin;\r
+       mRange = GlobalQualityMin;\r
+  }\r
+  else\r
+  {\r
+       mDamages = (u8) GetRandom(GlobalQualityMax, GlobalQualityMin);\r
+       mFrequency = (u8) GetRandom(GlobalQualityMax, GlobalQualityMin);\r
+       mHandling = (u8) GetRandom(GlobalQualityMax, GlobalQualityMin);\r
+       mRange = (u8) GetRandom(GlobalQualityMax, GlobalQualityMin);\r
+  }\r
+  \r
+}\r
+\r
+u8 PItem::AddToStack(u8 ItemNb) // returns nb of items not added\r
+{\r
+  u8 addedItems = 0;\r
+  if (mStackable)\r
+  {\r
+    addedItems = (ItemNb <= (MAX_ITEMSTACK_SIZE - mStackSize)) ? ItemNb : (MAX_ITEMSTACK_SIZE - mStackSize);\r
+    mStackSize += addedItems;\r
+  }\r
+  return (ItemNb - addedItems);\r
+}\r
+\r
+u8 PItem::TakeFromStack(u8 ItemNb)\r
+{\r
+  u8 retreivedItems = 0;\r
+  if (mStackable)\r
+  {\r
+       retreivedItems = min(mStackSize, ItemNb);\r
+       mStackSize -= retreivedItems;\r
+  }\r
+  return retreivedItems; \r
+}\r
diff --git a/server/src/game/lua_engine.cpp b/server/src/game/lua_engine.cpp
new file mode 100644 (file)
index 0000000..01c3d45
--- /dev/null
@@ -0,0 +1,337 @@
+/*\r
+TinNS (TinNS is not a Neocron Server)\r
+Copyright (C) 2005 Linux Addicted Community\r
+maintainer Akiko <akiko@gmx.org>\r
+\r
+This program is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU General Public License\r
+as published by the Free Software Foundation; either version 2\r
+of the License, or (at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+lua_engine.cpp - TinNS Lua engine for processing NPC scripts\r
+\r
+CREATION: 13 Oct 2009 Namikon\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "msgbuilder.h"\r
+\r
+// ******************************************************************\r
+// ATTENTION  ATTENTION  ATTENTION  ATTENTION  ATTENTION  ATTENTION\r
+// ******************************************************************\r
+/*\r
+   This function is the CALLBACK function for Neocron lua scripts.\r
+   Every command inside any .lua file will result in a call to\r
+   SendScriptMsg(xx), which ends up here.\r
+\r
+   For currently known callbacks, look in the docs/ folder,\r
+   file lua_callbacks.xls. It also contains the status and\r
+   all parameters with return values that are required to handle\r
+   script requests. If you're extending this function,\r
+   please note it in the xls file!\r
+*/\r
+// ******************************************************************\r
+int npcscript_callback(lua_State *nLua)\r
+{\r
+    PClient* tClient = LuaEngine->GetBoundClient();\r
+    if(tClient == NULL)\r
+    {\r
+        Console->Print("%s [npcscript_callback] No client is set, unable to process actions!", Console->ColorText(RED, BLACK, "[Error]"));\r
+        return 0;\r
+    }\r
+\r
+    // Get dialogclass and ScriptMsg from LUA call\r
+    std::string tScriptMsg = lua_tostring(nLua, 1);\r
+    int tDialogClass = lua_tointeger(nLua, 2);\r
+\r
+    // Only execute any commands (getmoney, takemoney, etc) when we're told to do so!\r
+    bool tExecCommands = false;\r
+    if((tDialogClass&PLUAENGINE_EXECUTENODE) == PLUAENGINE_EXECUTENODE)\r
+    {\r
+        tExecCommands = true;\r
+    }\r
+\r
+    // Check which ScriptMsg we have\r
+    if(tScriptMsg == "setanswer")\r
+    {\r
+        // its an setanswer\r
+        // see if we're requested to return the node for any special answer number\r
+        if((tDialogClass&PLUAENGINE_GETANSWER) == PLUAENGINE_GETANSWER)\r
+        {\r
+            // looks like that. Get the answernumber to check for and answernumber from lua\r
+            int tAnswerNr = tDialogClass - PLUAENGINE_GETANSWER;\r
+            int tLuaAnswerNr = lua_tointeger(nLua, 3);\r
+\r
+            // Now check answernumber, and if positive, set the returnvalue in LuaEngine\r
+            if(tAnswerNr == tLuaAnswerNr)\r
+            {\r
+                LuaEngine->SetReturnINT(lua_tointeger(nLua, 5));\r
+                // We're done here; exit function\r
+                return 1;\r
+            }\r
+        }\r
+    }\r
+    else if(tScriptMsg == "givemoney" && tExecCommands == true)\r
+    // Give the player money\r
+    // Script syntax: GIVEMONEY(amount)\r
+    // Return Values: None\r
+    {\r
+        int tAmount = lua_tointeger(nLua, 3);\r
+\r
+        /*int tNewMoneyValue = */tClient->GetChar()->AddCash(tAmount);\r
+\r
+        // This issnt required, since the client adds the money already. It\r
+        // isnt added twice, but you get the message twice and thats confusing :)\r
+        //PMessage* tmpMsg = MsgBuilder->BuildCharMoneyUpdateMsg(tClient, tNewMoneyValue);\r
+        //tClient->SendUDPMessage(tmpMsg);\r
+\r
+        if (gDevDebug) Console->Print("GIVEMONEY from script; Added %d credits", tAmount);\r
+    }\r
+    else if(tScriptMsg == "takemoney" && tExecCommands == true)\r
+    // Takes away money from player\r
+    // Script syntax: TAKEMONEY(amount)\r
+    // Return Values: 1 (Success) 0 (Failed)\r
+    {\r
+        int tAmount = lua_tointeger(nLua, 3);\r
+        if (gDevDebug) Console->Print("TAKEMONEY from script");\r
+\r
+        if(tClient->GetChar()->GetCash() < (u32)tAmount)\r
+        {\r
+            // Cannot take cash, player has less than amount required\r
+            LuaEngine->AddScriptResult(0);\r
+            if (gDevDebug) Console->Print("..FAILED player has not enough money (-%d)", tAmount);\r
+        }\r
+        else\r
+        {\r
+            // TakeMOney successfull. Reduce players credits and send money update\r
+            int tNewMoneyValue = tClient->GetChar()->TakeCash(tAmount);\r
+            PMessage* tmpMsg = MsgBuilder->BuildCharMoneyUpdateMsg(tClient, tNewMoneyValue);\r
+            tClient->SendUDPMessage(tmpMsg);\r
+\r
+            // TakeMoney successfull. Return 1\r
+            LuaEngine->AddScriptResult(1);\r
+            if (gDevDebug) Console->Print("..SUCCESS player had enough (-%d)", tAmount);\r
+        }\r
+    }\r
+    else if(tScriptMsg == "rand" && tExecCommands == true)\r
+    // Generate random number from 0 to tRange\r
+    // Script syntax: RAND(range)\r
+    // Return Values: 0 to range\r
+    {\r
+        int tRange = lua_tointeger(nLua, 3);\r
+\r
+        int tRandomVal = GetRandom(tRange, 0);\r
+        LuaEngine->AddScriptResult(tRandomVal);\r
+        if (gDevDebug) Console->Print("RAND(%d) from script. Result: %d", tRange, tRandomVal);\r
+    }\r
+    else if(tScriptMsg == "takeitem" && tExecCommands == true)\r
+    // Takes away an item from players inventory\r
+    // Script syntax: TAKEITEM(itemID)\r
+    // Return Values: 1 (Success) 0 (Failed)\r
+    {\r
+        int tItemID = lua_tointeger(nLua, 3);\r
+        // Check if player has item ID tItemID and take it away\r
+        // No clean way to take item away yet, fake answer until then.\r
+        int tRes = GetRandom (1, 0);\r
+        LuaEngine->AddScriptResult(tRes); // TakeItem was SUCCESSFULL\r
+\r
+        if (gDevDebug) Console->Print("TAKEITEM(%d) from script. Random result: %d", tItemID, tRes);\r
+    }\r
+    else if(tScriptMsg == "giveitem" && tExecCommands == true)\r
+    // Give an item to player, with given quality\r
+    // Script syntax: GIVEITEM(itemID)\r
+    // Return Values: None\r
+    {\r
+        int tItemID = lua_tointeger(nLua, 3);\r
+        int tQuality = lua_tointeger(nLua, 4);\r
+        // Give item tItemID in quality tQuality to player\r
+\r
+        PItem* NewItem = new PItem( tItemID );\r
+        if ( NewItem->GetItemID() )\r
+        {\r
+            NewItem->MakeItemStandard( tQuality, tQuality ); // Set Quality of item to tQuality\r
+            tClient->GetChar()->GetInventory()->AddItem( NewItem );\r
+            // TODO: Find a way to refresh inventory\r
+            if (gDevDebug) Console->Print("GIVEITEM(%d,%d) from script. Result: %d", tItemID, tQuality);\r
+        }\r
+        else\r
+        {\r
+            // Error, invalid ItemID in script..?\r
+            if (gDevDebug) Console->Print("GIVEITEM(%d,%d) from script. Fail: Unknown itemID", tItemID, tQuality);\r
+\r
+            // Do nothing\r
+        }\r
+    }\r
+    return 1;\r
+}\r
+// *************************************************************\r
+bool PLuaEngine::CheckLUAFile(std::string nLUAScript)\r
+{\r
+    luaL_openlibs(mLua);\r
+    if (luaL_loadstring(mLua, nLUAScript.c_str()) || lua_pcall(mLua, 0, 0, 0)) {\r
+        Console->Print("[PLuaEngine::CheckLUAFile] Error in LUA Script: %s", lua_tostring(mLua, -1));\r
+        return false;\r
+    }\r
+\r
+    // Check if we have the 2 main functions present\r
+    lua_getglobal(mLua, "lSendAction");\r
+    if(!lua_isfunction(mLua,-1))\r
+    {\r
+        Console->Print("[PLuaEngine::CheckLUAFile] LUA Script is missing function \"lSendAction)\"");\r
+        lua_pop(mLua,1);\r
+        return false;\r
+    }\r
+    // Check if we have the 2 main functions present\r
+    lua_getglobal(mLua, "SetResult");\r
+    if(!lua_isfunction(mLua,-1))\r
+    {\r
+        Console->Print("[PLuaEngine::CheckLUAFile] LUA Script is missing function \"SetResult)\"");\r
+        lua_pop(mLua,1);\r
+        return false;\r
+    }\r
+\r
+    // LUA File is ok\r
+    return true;\r
+}\r
+\r
+void PLuaEngine::ProcessDialogScript(PClient* nClient, std::string nLUAFile, int nAnswer)\r
+{\r
+    mTargetClient = nClient;\r
+    PChar* tChar = nClient->GetChar();\r
+\r
+    // Get current node ID the player is on\r
+    u16 tNodeID = tChar->GetDialogNode();\r
+\r
+    // First, get the new node ID based on the answer the client gave us. DO NOT execute any commands from\r
+    // Script yet. Resulting node is in mReturn_INT\r
+    ExecuteScript(nLUAFile, tNodeID, nAnswer + PLUAENGINE_GETANSWER);\r
+\r
+    //int tNextNode = LuaEngine->GetNextNodeFromAnswer(nLUAFile, tNodeID, nAnswer);\r
+    // Now execute target Node. Process all requests by Script, and tell client the results (if any)\r
+    if(LuaEngine->ExecuteScript(nLUAFile, mReturn_INT, PLUAENGINE_EXECUTENODE) == false)\r
+    {\r
+        Console->Print("ERROR while processing LUA Script, skip");\r
+        return;\r
+    }\r
+    else\r
+    {\r
+        // Set the new node in client\r
+        tChar->SetDialogNode((u16)mReturn_INT);\r
+        // Now send the new node (together with the answer-buffer) to the client.\r
+        // After this packet hits the client, it will show the given node\r
+        PMessage* tmpMsg = MsgBuilder->BuildNPCDialogReplyMsg(nClient, tChar->GetDialogNode(), &mReturnValues);\r
+        nClient->SendUDPMessage(tmpMsg);\r
+    }\r
+\r
+    // Cleanup everything\r
+    mTargetClient = NULL;\r
+    CleanUp();\r
+}\r
+\r
+void PLuaEngine::AddScriptResult(int nResult)\r
+{\r
+    if(!mRunning)\r
+    {\r
+        Console->Print("%s [PLuaEngine::AddScriptResult] Trying to set lua result while no lua script is running", Console->ColorText(YELLOW, BLACK, "[Warning]"));\r
+        return;\r
+    }\r
+\r
+    // Insert new returnvalue to buffer\r
+    mReturnValues.push_back(nResult);\r
+\r
+    // Push result back to LUA Script\r
+    lua_getglobal(mLua, "SetResult");\r
+    lua_pushnumber(mLua, nResult);   // newstate\r
+\r
+    if (lua_pcall(mLua, 1, 0, 0) != 0)\r
+    {\r
+        Console->Print("%s [npcscript_callback] Unable to return result '%s'", Console->ColorText(RED, BLACK, "[Error]"), lua_tostring(mLua, -1));\r
+    }\r
+}\r
+\r
+PLuaEngine::PLuaEngine()\r
+{\r
+    mLua = lua_open();\r
+    mRunning = false;\r
+}\r
+\r
+void PLuaEngine::CleanUp()\r
+{\r
+    // CleanUp vars, empty vectors, etc\r
+    mRunning = false;\r
+    mReturnValues.erase(mReturnValues.begin(), mReturnValues.end());\r
+}\r
+\r
+PLuaEngine::~PLuaEngine()\r
+{\r
+    lua_close(mLua);\r
+}\r
+\r
+bool PLuaEngine::ExecuteScript(std::string nLUAScript, int nNode, int nDialogClass)\r
+{\r
+    // Make sure we have an bound client to work with\r
+    if(mTargetClient == NULL)\r
+    {\r
+        Console->Print("%s [PLuaEngine::ExecuteScript] No Client has been bound. Cannot run lua script", Console->ColorText(RED, BLACK, "[Error]"));\r
+        return false;\r
+    }\r
+\r
+    // Open LUA libs\r
+    luaL_openlibs(mLua);\r
+\r
+    // Try to load script and check for syntax errors\r
+    if (luaL_loadstring(mLua, nLUAScript.c_str()) || lua_pcall(mLua, 0, 0, 0)) {\r
+        Console->Print("%s [PLuaEngine::ExecuteScript] Unable to execute lua script: '%s'", Console->ColorText(RED, BLACK, "[Error]"), lua_tostring(mLua, -1));\r
+        return false;\r
+    }\r
+\r
+    // Register callback function for NPC Script actions\r
+    lua_register(mLua, "SendScriptMsg", npcscript_callback);\r
+\r
+    // Get handle for lua main() function\r
+    lua_getglobal(mLua, "lSendAction");\r
+\r
+    // Error if function isnt found\r
+    if(!lua_isfunction(mLua,-1))\r
+    {\r
+        Console->Print("%s [PLuaEngine::ExecuteScript] Unable to execute lua script; Script has no entry function (lSendAction)", Console->ColorText(RED, BLACK, "[Error]"));\r
+        lua_pop(mLua,1);\r
+        return false;\r
+    }\r
+    // Push our vars to the script\r
+    // DialogClass is a loopback value for our callback function, to detect different\r
+    // script runs (with or without execution of command)\r
+    lua_pushnumber(mLua, nDialogClass);\r
+    lua_pushnumber(mLua, nNode);\r
+\r
+    /*\r
+       run LUA Script (2 arguments, 0 result, 0 errorhandler)\r
+       Only allow callback actions while lua is running (mRunning = true)\r
+    */\r
+\r
+    mRunning = true;\r
+    int tLuaResult = lua_pcall(mLua, 2, 0, 0);\r
+    mRunning = false;\r
+\r
+    if (tLuaResult != 0)\r
+    {\r
+        Console->Print("%s [PLuaEngine::ExecuteScript] Unable to execute lua script: '%s'", Console->ColorText(RED, BLACK, "[Error]"), lua_tostring(mLua, -1));\r
+        return false;\r
+    }\r
+\r
+    return true;\r
+}\r
diff --git a/server/src/game/main.cpp b/server/src/game/main.cpp
new file mode 100644 (file)
index 0000000..b4c3d4f
--- /dev/null
@@ -0,0 +1,104 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       main.cpp - this is the main file with the main function\r
+\r
+       MODIFIED: 12 Sep 2005 Akiko\r
+       REASON: - removed some of the Windows specific code\r
+               - replaced SleepEx method by the Linux equivalent\r
+       MODIFIED: 26 Sep 2005 Akiko\r
+       REASON: - added GPL\r
+    MODIFIED: 23 Dec 2005 bakkdoor\r
+         REASON: - Added <csignal> & signalHandler -> catch strg-c and shutdown nicely\r
+    MODIFIED: 25 Dec 2005 Namikon\r
+         REASON: - Fixed shutdown procedure, wont cause segfault anymore\r
+    MODIFIED: 06 Jan 2006 Namikon\r
+    REASON: - Added color to console outputs\r
+    MODIFIED: 01 Jul 2006 Hammag\r
+         REASON: - commented out sched_yield() in main loop, as it is\r
+                   not needed anymore with a right timeout for ReadSetTCP select\r
+    MODIFIED: 26 Jul 2006 Hammag\r
+         REASON: - added memory leak check in the main loop for unreleased DB Ressources and messages\r
+\r
+*/\r
+\r
+#include "main.h"\r
+\r
+#include "worlddatatemplate.h" // temp\r
+#include "worlds.h" // temp\r
+\r
+#include "isc.h"\r
+\r
+// for handling strg-c signal to shutdown in correct way\r
+void signal_handler(int signal)\r
+{\r
+    if (signal == SIGINT)\r
+    {\r
+        //cout << "Shutting down TinNS" << endl;\r
+\r
+        //exit(0);\r
+        Shutdown();\r
+    }\r
+    else\r
+    {\r
+        psignal(signal, "Unkown signal: ");\r
+    }\r
+}\r
+\r
+int main()\r
+{\r
+    // Connect signal with handlerfunction\r
+    signal(SIGINT, signal_handler); // TODO: change for sigaction()\r
+\r
+\r
+       if(!InitTinNS())\r
+       {\r
+         if(Console)\r
+           Console->Print("%s Aborting startup.", Console->ColorText(RED, BLACK, "[Fatal]"));\r
+               Shutdown(); // exits with 0 ...\r
+  }\r
+\r
+       //RemoteConsole->Start();\r
+       GameServer->Start();\r
+       //GameServer->SetGameTime(0);\r
+       ISC->Start();\r
+\r
+       Console->Print("Gameserver is now %s. Waiting for clients...", Console->ColorText(GREEN, BLACK, "Online"));\r
+\r
+       while(1)\r
+       {\r
+         ServerSock->update();\r
+    NPCManager->Update();\r
+               Server->Update();\r
+               Chars->Update();\r
+               GameServer->Update();\r
+               PMessage::CheckMsgCount(); // Memory leak check\r
+               MySQL->Update(); // Memory leak check   and MySQL keepalive\r
+               ISC->Update();\r
+               Console->Update();
+               MultiPartHandler->Update();\r
+       }\r
+\r
+       return 0;\r
+}\r
diff --git a/server/src/game/main.h b/server/src/game/main.h
new file mode 100644 (file)
index 0000000..a77b975
--- /dev/null
@@ -0,0 +1,115 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       main.h - main include file, contains all needed includes and important definitions\r
+\r
+       MODIFIED: 31 Aug 2005 Akiko\r
+       REASON: - updating def file definitions to match the changes in gamedefs.cpp\r
+               - added define for charfiles path\r
+               - added define for database path\r
+       MODIFIED: 26 Sep 2005 Akiko\r
+       REASON: - reformated code\r
+               - added GPL\r
+               - added infoserver default port as define\r
+               - added my threading model (mutex.h, semaphore.h, thread.h)\r
+               - added basic includes pthread.h, semaphore.h and errno.h\r
+       MODIFIED: 28 Sep 2005 Akiko\r
+       REASON: - added define for game server port\r
+       MODIFIED: 30 Nov 2005 Akiko\r
+       REASON: - added chat.h for the chat part from Namikon\r
+       MODIFIED: 02 Dec 2005 Akiko\r
+       REASON: - commented out mutex.h, thread.h, semaphore.h\r
+       MODIFIED: 22 Dec 2005 Namikon/bakkdoor\r
+       REASON: - Added commands.h, skill.h, clientmanager.h\r
+    MODIFIED: 23 Dec 2005 bakkdoor\r
+       REASON: - Added <csignal> for main.cpp -> catch strg-c and shutdown nicely\r
+    MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added mysql.h, sql.h for MySQL support\r
+    MODIFIED: 01 Jan 2006 Namikon\r
+       REASON: - Moved skill.h before chars.h (char.h needs skill.h now)\r
+    MODIFIED: 30 May 2006 Namikon\r
+       REASON: - Removed all useless includes to complete the server splitup; Also renamed tinns.h to main.h\r
+    MODIFIED: 6 Jul 2006 Hammag\r
+         REASON: - moved include "types.h" before include "../netcode/main.h" to permit compile\r
+    MODIFIED: 10 Jul 2006 Hammag\r
+         REASON: - added inventory.h\r
+         REASON: - added item.h\r
+    MODIFIED: 26 Jul 2006 Hammag\r
+         REASON: - removed     #define GAME_PORT which is not used anymore (now in config file)\r
+\r
+*/\r
+\r
+#ifndef MAIN_H\r
+#define MAIN_H\r
+\r
+//#include "version.h"\r
+\r
+//basic includes\r
+#include "external.h"\r
+\r
+//tinns includes\r
+#include "types.h"\r
+#include "netcode.h"\r
+/*\r
+#include "../gamemonkey/gmMachine.h"\r
+#include "../gamemonkey/gmCall.h"\r
+*/\r
+#include "console.h"\r
+\r
+// MySQL Support\r
+#include "mysql.h"\r
+#include "sql.h"\r
+\r
+#include "config.h"\r
+#include "filesystem.h"\r
+#include "defparser.h"\r
+\r
+\r
+#include "skill.h"\r
+#include "chars.h"\r
+#include "accounts.h"\r
+#include "client.h"\r
+#include "server.h"\r
+#include "misc.h"\r
+#include "gameserver.h"\r
+#include "globals.h"\r
+#include "defs.h"\r
+#include "zoning.h"\r
+#include "item.h"\r
+#include "inventory.h"\r
+#include "worldactors.h"\r
+#include "npc.h"\r
+#include "outpost.h"
+#include "multipart.h"
+#include "terminal.h"\r
+
+#include "lua_engine.h"\r
+#include "chat.h"\r
+#include "commands.h"\r
+#include "clientmanager.h"\r
+\r
+using namespace std;\r
+\r
+#endif\r
+\r
diff --git a/server/src/game/msgbuilder.cpp b/server/src/game/msgbuilder.cpp
new file mode 100644 (file)
index 0000000..e97e421
--- /dev/null
@@ -0,0 +1,3700 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ msgbuilder.h - a classes to build NC messages
+
+ CREATION: 30 Aug 2006 Hammag
+
+ MODIFIED:
+ REASON: -
+
+*/
+
+#include "main.h"
+#include "msgbuilder.h"
+
+#include "worlds.h"
+#include "appartements.h"
+#include "vehicle.h"
+#include "subway.h"
+#include "item.h"
+#include "container.h"
+
+PMessage* PMsgBuilder::BuildOutpostClanInfoMsg( PClient* nClient, u32 nClanID, u8 nFaction )
+{
+        PMessage* tmpMsg = new PMessage();
+        nClient->IncreaseUDP_ID();
+
+        *tmpMsg << (u8)0x13;
+       *tmpMsg << (u16)nClient->GetUDP_ID();
+       *tmpMsg << (u16)nClient->GetSessionID();
+       *tmpMsg << (u8)0x13; // Message length
+       *tmpMsg << (u8)0x03;
+       *tmpMsg << (u16)nClient->GetUDP_ID();
+       *tmpMsg << (u8)0x23;
+
+       //*tmpMsg << (u16)GetArgInt(2);
+       *tmpMsg << (u16)14;
+       *tmpMsg << (u8)0x00;
+       *tmpMsg << (f32)nClanID; // ClanID f32
+       *tmpMsg << (u8)nFaction;  // Faction
+       // The next 3 bytes are unknown.
+       // However, with this combination, the OP and its bonuses are
+       // set correctly; eg Own clan full bonus, friend clan 75%, etc
+       *tmpMsg << (u8)0x06; // 6? 0x06
+       *tmpMsg << (u8)0x14; // 0? 0x14
+       *tmpMsg << (u8)0x0b; // 11? 0x0b
+        *tmpMsg << (u32)nClanID; // ClanID u32
+
+        ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+        return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharHelloMsg( PClient* nClient )
+{
+    PChar *nChar = nClient->GetChar();
+    u32 nSkin, nHead, nTorso, nLegs;
+    u8 nHeadColor, nTorsoColor, nLegsColor, nHeadDarkness, nTorsoDarkness, nLegsDarkness;
+
+    nChar->GetCurrentLook( nSkin, nHead, nTorso, nLegs );
+    nChar->GetCurrentBodyColor( nHeadColor, nTorsoColor, nLegsColor, nHeadDarkness, nTorsoDarkness, nLegsDarkness );
+
+    PMessage* tmpMsg = new PMessage( );
+
+    u8 currentActiveSlot = nChar->GetQuickBeltActiveSlot();
+    u16 weaponId = 0;
+    switch ( currentActiveSlot )
+    {
+    case INV_WORN_QB_NONE:
+        //weaponId = 0;
+        break;
+    case INV_WORN_QB_HAND:
+        weaponId = 5; // <= TODO: set it somewhere
+        break;
+    default:
+        PItem* currentItem = nChar->GetInventory()->GetContainer( INV_LOC_WORN )->GetItem( INV_WORN_QB_START + currentActiveSlot );
+        //Todo : item addons & effects
+        //ItemInHandID = currentItem->GetItemID():
+        if ( currentItem )
+            weaponId = currentItem->GetValue1();
+        //else
+        //ItemInHandID = 0;
+        break;
+    }
+
+    //nClient->IncreaseUDP_ID(); // This must be done outside
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; //Client->GetUDP_ID(); // just placeholder, must be set outside
+    *tmpMsg << ( u16 )0x0000;  // Client->GetSessionID(); // just placeholder, must be set outside
+    *tmpMsg << ( u8 )0x00; // size placeholder, set later in the function
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )0x0000; // Client->GetUDP_ID(); // just placeholder, must be set outside
+    *tmpMsg << ( u8 )0x25;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u32 )nChar->GetID();
+
+    *tmpMsg << ( u8 )0x60; // 0x40 if current faction epic done (master), | 0x80 to display [afk] | 0x20 if LE in
+    *tmpMsg << ( u8 )(( nChar->GetSpeedOverride() == 255 ) ? 10 : nChar->GetSpeedOverride() ); // move speed, reset by client (and for him only) when getting fall damage
+    *tmpMsg << ( u8 )0x08; // ??? something to do with speed ?
+    *tmpMsg << ( u16 )weaponId; // WeaponID of the weapon in hand
+    *tmpMsg << ( u8 )0x01; // ???
+    *tmpMsg << ( u8 )0x01; // ???
+    *tmpMsg << ( u8 )( 128 + nChar->GetSoullight() );
+
+    *tmpMsg << ( u8 )nChar->GetMainRank(); // in fact, Ranks are of type s8, but it doesn't matter much
+    *tmpMsg << ( u8 )nChar->GetCombatRank();
+    *tmpMsg << ( u8 )nChar->GetFaction();
+
+    *tmpMsg << ( u8 )0x00; // This was 0x21 for an GM, with faction 0x00. However, no visible change when set...
+    *tmpMsg << ( u8 )0x0f; // size of the next bloc (skin + ?clan?)
+    // Current skin
+    *tmpMsg << ( u16 )nSkin;
+    *tmpMsg << ( u8 )nHead;
+    *tmpMsg << ( u8 )nTorso;
+    *tmpMsg << ( u8 )nLegs;
+    // Skin colors
+    *tmpMsg << ( u8 )nHeadColor;
+    *tmpMsg << ( u8 )nTorsoColor;
+    *tmpMsg << ( u8 )nLegsColor;
+    *tmpMsg << ( u8 )nHeadDarkness; // (0=bright 255=dark)
+    *tmpMsg << ( u8 )nTorsoDarkness;
+    *tmpMsg << ( u8 )nLegsDarkness;
+    *tmpMsg << ( u8 )0x00; // ??? << not sure at all // eg: 0x3e
+    *tmpMsg << ( u8 )0x00; // eg: 0x03
+    *tmpMsg << ( u8 )0x00; // eg: 0xa3
+    *tmpMsg << ( u8 )0x00; // eg: 0x03
+
+    //Name
+    *tmpMsg << ( u8 )(( nChar->GetName() ).length() + 1 );
+    *tmpMsg << ( nChar->GetName() ).c_str();
+    //Body effects
+    u8 cBodyEffect, cEffectDensity;
+    nChar->GetBodyEffect( cBodyEffect, cEffectDensity );
+    if ( cBodyEffect )
+    {
+        *tmpMsg << ( u8 )0x06; // size of effect list : 6 bytes/effect. Only one supported atm
+        *tmpMsg << ( u8 )cBodyEffect; // effect type (0=none, effecive values 1 - 17)
+        *tmpMsg << ( u8 )cEffectDensity; // density: 0=max, 0xff=min (for some effects only)
+        *tmpMsg << ( u8 )0x00; // ???
+        *tmpMsg << ( u8 )0x00; // ???
+        *tmpMsg << ( u8 )0x00; // ???
+        *tmpMsg << ( u8 )0x00; // ???
+    }
+    else
+    {
+        *tmpMsg << ( u8 )0x00; // size of empty effect list
+    }
+
+    // Clans working, yeah :D
+    u16 tClanVal = nChar->GetClan();
+    if(tClanVal > 0)
+    {
+        u8 tClanLevel = nChar->GetClanLevel();
+        u32 tmpVal;
+        tmpVal = tClanVal << 4;
+        tmpVal |= tClanLevel;
+        *tmpMsg << ( u8 )0x04;
+        *tmpMsg << ( u32 )tmpVal;
+    }
+    else
+        *tmpMsg << ( u8 )0x00; // ending null
+    // alternate interpretation to this "ending null"/optional bloc:
+    /* *tmpMsg << (u8)0x04; // size of unknown bloc ... 0x00 when empty (aka the "ending null")
+     *tmpMsg << (u8)0x0b; // vary ... ??? 0b, eb, ee, ...
+     *tmpMsg << (u8)0x44; // vary ... ???
+     *tmpMsg << (u8)0x00; // these two seem always null
+     *tmpMsg << (u8)0x00; */
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildReqNPCScriptAnswerMsg( u32 nInfoId, string* nNPCScript )\r
+{\r
+    PMessage* tmpMsg;\r
+\r
+    tmpMsg = new PMessage();\r
+\r
+    *tmpMsg << ( u8 )0x19;\r
+    *tmpMsg << ( u16 )0x0006; // InfoQuery\r
+    *tmpMsg << ( u16 )0x0003; // NPC Script\r
+    *tmpMsg << ( u32 )nInfoId;\r
+    *tmpMsg << nNPCScript->c_str();\r
+\r
+    return tmpMsg;\r
+\r
+}\r
+\r
+PMessage* PMsgBuilder::BuildYouGotEmailsMsg( PClient* nClient, u8 nMailCount )\r
+{\r
+    PMessage* tmpMsg = new PMessage();\r
+    nClient->IncreaseUDP_ID();\r
+\r
+    *tmpMsg << ( u8 )0x13;\r
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();\r
+    *tmpMsg << ( u16 )nClient->GetSessionID();\r
+    *tmpMsg << ( u8 )0x0c;\r
+    *tmpMsg << ( u8 )0x03;\r
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();\r
+    *tmpMsg << ( u8 )0x1f;\r
+    *tmpMsg << ( u16 )nClient->GetLocalID();\r
+    *tmpMsg << ( u8 )0x3d;\r
+    *tmpMsg << ( u8 )0x0c;\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u8 )nMailCount;\r
+\r
+    return tmpMsg;\r
+}\r
+\r
+PMessage* PMsgBuilder::BuildReceiveDBAnswerMsg( PClient* nClient, PMessage* nResultBuffer, std::string* nCommandName, u16 nNumRows, u16 nNumFields)\r
+{\r
+    PMessage* tmpMsg = new PMessage();\r
+/*    nClient->IncreaseUDP_ID();\r
+\r
+    *tmpMsg << ( u8 )0x13;\r
+    *tmpMsg << ( u16 )0x0000;\r
+    *tmpMsg << ( u16 )0x0000;\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u8 )0x03;\r
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();\r
+    *tmpMsg << ( u8 )0x2b;\r
+    *tmpMsg << ( u8 )0x1a;\r
+    if(nCommandName->length() > 0)\r
+        *tmpMsg << ( u8 )0x01;\r
+    else\r
+        *tmpMsg << ( u8 )0x00;\r
+\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << *nCommandName;\r
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );\r
+\r
+    // 2nd message\r
+    *tmpMsg << ( u16 )(13 + nCommandName->length() + nResultBuffer->GetSize()); // ??\r
+*/\r
+    nClient->IncreaseUDP_ID();\r
+\r
+    *tmpMsg << ( u8 )0x13;\r
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();\r
+    *tmpMsg << ( u16 )nClient->GetSessionID();\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u8 )0x03;\r
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();\r
+    *tmpMsg << ( u8 )0x2b;\r
+    *tmpMsg << ( u8 )0x17;\r
+    *tmpMsg << ( u16 )(nCommandName->length()+1);\r
+    *tmpMsg << ( u16 )nNumRows;\r
+    *tmpMsg << ( u16 )nNumFields;\r
+    *tmpMsg << *nCommandName;\r
+    *tmpMsg << *nResultBuffer;\r
+\r
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );\r
+\r
+\r
+    return tmpMsg;\r
+                       //len = (unsigned int)strlen(DB);\r
+                       //SendBuffer[0] = 0x13;\r
+                       //SendBuffer[5] = 11 + len;\r
+                       //SendBuffer[6] = 0x03;\r
+                       //Network_IncrementUDP (ClientNum);\r
+                       //*(unsigned short*)&SendBuffer[7] = Client_Sockets[ClientNum].UDP_ID;\r
+       //              SendBuffer[9] = 0x2b;\r
+       //              SendBuffer[10] = 0x1a;\r
+       //              *(unsigned short*)&SendBuffer[11] = len;\r
+       //              if (num == 0)\r
+       //                      SendBuffer[13] = 0x00;\r
+       //              else\r
+       //                      SendBuffer[13] = 0x01;\r
+       //              SendBuffer[14] = 0x00;\r
+       //              SendBuffer[15] = 0x00;\r
+       //              strcpy (SendBuffer+16, DB);\r
+       //              plen = 17+len;\r
+\r
+       //              SendBuffer[plen] = 13+len+slen;\r
+       //              SendBuffer[plen+1] = 0x03;\r
+       //              Network_IncrementUDP (ClientNum);\r
+       //              *(unsigned short*)&SendBuffer[plen+2] = Client_Sockets[ClientNum].UDP_ID;\r
+       //              *(unsigned short*)&SendBuffer[1] = Client_Sockets[ClientNum].UDP_ID;\r
+       //              *(unsigned short*)&SendBuffer[3] = Client_Sockets[ClientNum].UDP_ID_HIGH;\r
+       //              SendBuffer[plen+4] = 0x2b;\r
+       //              SendBuffer[plen+5] = 0x17;\r
+       //              *(unsigned short*)&SendBuffer[plen+6] = len+1;\r
+       //              *(unsigned short*)&SendBuffer[plen+8] = num;\r
+       //              *(unsigned short*)&SendBuffer[plen+10] = Fields;\r
+       //              //Fieldnum is defined in each DB below\r
+       //              strcpy (SendBuffer+plen+12, DB);\r
+       //              plen += 13+len;\r
+\r
+       //              for (i=0;i<slen;i++)\r
+       //                      SendBuffer[plen+i] = TempBuffer[i];\r
+\r
+\r
+}\r
+\r
+\r
+PMessage* PMsgBuilder::BuildTryAccessAnswerMsg(PClient* nClient, char *nArea, bool nAllowed)\r
+{\r
+    PMessage* tmpMsg = new PMessage();\r
+    //u8 i = (u8)strlen(nArea);\r
+\r
+    nClient->IncreaseUDP_ID();\r
+\r
+    *tmpMsg << (u8)0x13;\r
+    *tmpMsg << (u16)nClient->GetUDP_ID();\r
+    *tmpMsg << (u16)nClient->GetSessionID();\r
+    *tmpMsg << (u8)0x00;\r
+    *tmpMsg << (u8)0x03;\r
+    *tmpMsg << (u16)nClient->GetUDP_ID();\r
+    *tmpMsg << (u8)0x2b;\r
+    *tmpMsg << (u8)0x1a;\r
+    *tmpMsg << (u16)(strlen(nArea)+1);\r
+\r
+    if(nAllowed)\r
+        *tmpMsg << (u8)0x01;\r
+    else\r
+        *tmpMsg << (u8)0x00;\r
+\r
+    *tmpMsg << (u8)0x00;\r
+    *tmpMsg << (u8)0x00;\r
+    *tmpMsg << nArea;\r
+\r
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );\r
+    return tmpMsg;\r
+}\r
+
+PMessage* PMsgBuilder::BuildReqInfoAnswerMsg( PClient* nClient, u16 nReqType, u32 nInfoId, void* nResponse, u16 nResponseLength )
+{
+    PMessage* tmpMsg;
+
+    tmpMsg = new PMessage( 18 + nResponseLength );
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x00; // Message length placeholder;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x23;
+    *tmpMsg << ( u16 )0x0006; // cmd
+    *tmpMsg << ( u16 )nReqType; // wrong size here (u32) for buffer size u16 in NeoX
+    *tmpMsg << ( u32 )nInfoId;
+    tmpMsg->Write( nResponse, nResponseLength );
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharHealthUpdateMsg( PClient* nClient )
+{
+    PMessage* tmpMsg = new PMessage( 14 );
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; //Client->GetUDP_ID(); // just placeholder, must be set outside
+    *tmpMsg << ( u16 )0x0000;  // Client->GetSessionID(); // just placeholder, must be set outside
+    *tmpMsg << ( u8 )0x00; // Message length placeholder;
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x30;
+    *tmpMsg << ( u8 )0x64; //Head Heath =Head HP/(3 *0.45)(with max Head HP = 45% of total)
+    *tmpMsg << ( u8 )0x64; //Body Heath =Body HP/(3 *0.35)(for max 35% of total)
+    *tmpMsg << ( u8 )0x64; //Feet Heath =Feet HP/(3 *0.20)(for max 20% of total)
+    *tmpMsg << ( u8 )0x01; // Sta/Mana ?
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharDeathMsg( PClient* nClient, u32 nKillerCharId )
+{
+    PMessage* tmpMsg = new PMessage( 17 );
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; //Client->GetUDP_ID(); // just placeholder, must be set outside
+    *tmpMsg << ( u16 )0x0000;  // Client->GetSessionID(); // just placeholder, must be set outside
+    *tmpMsg << ( u8 )0x00; // Message length placeholder;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )0x0000; // Client->GetUDP_ID(); // just placeholder, must be set outside
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x16;
+    *tmpMsg << ( u32 )nKillerCharId;
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharPosUpdateMsg( PClient* nClient )
+{
+    PMessage* tmpMsg = new PMessage( 32 );
+    PChar* nChar = nClient->GetChar();
+
+    u32 cSeatObjectId;
+    u8 cSeatId;
+    PSeatType cSeatType = nChar->GetSeatInUse( &cSeatObjectId, &cSeatId );
+    if ( cSeatType == seat_chair )   // temp ! Must migrate to RAW
+    {
+        cSeatObjectId = ( cSeatObjectId + 1 ) * 1024;
+    }
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; //Client->GetUDP_ID(); // just placeholder, must be set outside
+    *tmpMsg << ( u16 )0x0000;  // Client->GetSessionID(); // just placeholder, must be set outside
+    *tmpMsg << ( u8 )0x00; // Message length placeholder;
+    *tmpMsg << ( u8 )0x1b;
+    *tmpMsg << ( u32 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x03;
+    if ( cSeatType )
+    {
+        *tmpMsg << ( u32 )cSeatObjectId;
+        *tmpMsg << ( u16 )cSeatId; // testing... else 0x0000
+    }
+    else
+    {
+        *tmpMsg << ( u16 )(( nChar->Coords ).mY );
+        *tmpMsg << ( u16 )(( nChar->Coords ).mZ );
+        *tmpMsg << ( u16 )(( nChar->Coords ).mX );
+    }
+    *tmpMsg << ( u16 )( 31910 + ( nChar->Coords ).mUD - 50 );  // Up - Mid - Down  mUD=(d6 - 80 - 2a) NeoX original offset: 31910
+    *tmpMsg << ( u16 )( 31820 + ( nChar->Coords ).mLR*2 - 179 ); // Compass direction mLR=(S..E..N..W..S [0-45-90-135-179]) There still is a small buggy movement when slowly crossing the South axis from the right
+    if ( cSeatType )
+    {
+        *tmpMsg << ( u8 )0x00;
+        *tmpMsg << ( u8 )0x10;
+    }
+    else
+    {
+        *tmpMsg << ( u8 )(( nChar->Coords ).mAct );
+        *tmpMsg << ( u8 )0x00;
+    }
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharPosUpdate2Msg( PClient* nClient, u8 InfoBitfield )
+{
+    PMessage* tmpMsg = new PMessage( 32 );
+    PChar* nChar = nClient->GetChar();
+
+    if ( InfoBitfield == 0x80 )
+    {
+        Console->Print( RED, BLACK, "[ERROR] PMsgBuilder::BuildCharPosUpdate2Msg : using InfoBitfield=0x80 forbidden. Using 0x7f instead." );
+        InfoBitfield = 0x7f;
+    }
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; //Client->GetUDP_ID(); // just placeholder, must be set outside
+    *tmpMsg << ( u16 )0x0000;  // Client->GetSessionID(); // just placeholder, must be set outside
+    *tmpMsg << ( u8 )0x00; // Message length placeholder;
+    *tmpMsg << ( u8 )0x20;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )InfoBitfield;
+
+    if ( InfoBitfield & 0x01 )
+    {
+        *tmpMsg << ( u16 )(( nChar->Coords ).mY );
+    }
+    if ( InfoBitfield & 0x02 )
+    {
+        *tmpMsg << ( u16 )(( nChar->Coords ).mZ );
+    }
+    if ( InfoBitfield & 0x04 )
+    {
+        *tmpMsg << ( u16 )(( nChar->Coords ).mX );
+    }
+    if ( InfoBitfield & 0x08 )
+    {
+        *tmpMsg << ( u8 )(( nChar->Coords ).mUD );
+    }
+    if ( InfoBitfield & 0x10 )
+    {
+        *tmpMsg << ( u8 )(( nChar->Coords ).mLR );
+    }
+    if ( InfoBitfield & 0x20 )
+    {
+        *tmpMsg << ( u8 )(( nChar->Coords ).mAct );
+    }
+    /*if(InfoBitfield & 0x40) // Not used (?)
+    {
+      *tmpMsg << (u8)((nChar->Coords).mUnknown);
+    }*/
+    /*if(InfoBitfield & 0x80) // mRoll ????
+    {
+      *tmpMsg << (u8)((nChar->Coords).mUnknown);
+    }*/
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+/*
+PMessage* PMsgBuilder::BuildCharSittingMsg( PClient* nClient )
+{
+  PMessage* tmpMsg = new PMessage( 24 );
+  PChar* nChar = nClient->GetChar();
+
+  *tmpMsg << ( u8 )0x13;
+  *tmpMsg << ( u16 )0x0000; //Client->GetUDP_ID(); // just placeholder, must be set outside
+  *tmpMsg << ( u16 )0x0000;  // Client->GetSessionID(); // just placeholder, must be set outside
+  *tmpMsg << ( u8 )0x00; // Message length placeholder;
+  *tmpMsg << ( u8 )0x32;
+  *tmpMsg << ( u16 )nClient->GetLocalID();
+  *tmpMsg << ( u8 )0x00; // Type = chair/subway ???
+  *tmpMsg << ( u8 )0x00;
+  *tmpMsg << ( u8 )0x03; // Type = chair ???
+  *tmpMsg << ( u16 )(( nChar->Coords ).mY );
+  *tmpMsg << ( u16 )(( nChar->Coords ).mZ );
+  *tmpMsg << ( u16 )(( nChar->Coords ).mX );
+  *tmpMsg << ( u16 )( 31910 + ( nChar->Coords ).mUD - 50 );  // Up - Mid - Down  mUD=(d6 - 80 - 2a) NeoX original offset: 31910
+  *tmpMsg << ( u16 )( 31820 + ( nChar->Coords ).mLR*2 - 179 ); // Compass direction mLR=(S..E..N..W..S [0-45-90-135-179]) There still is a small buggy movement when slowly crossing the South axis from the right
+  *tmpMsg << ( u8 )(( nChar->Coords ).mAct );
+  *tmpMsg << ( u8 )0x00;
+
+  ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+  return tmpMsg;
+}
+*/
+
+PMessage* PMsgBuilder::BuildCharUseSeatMsg( PClient* nClient, u32 nRawObjectId, u8 nSeatId )
+{
+    PMessage* tmpMsg = new PMessage( 18 );
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; // nClient->GetUDP_ID() placeholder
+    *tmpMsg << ( u16 )0x0000; // nClient->GetSessionID()placeholder
+
+    *tmpMsg << ( u8 )0x0c; // Sub message length;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )0x0000; // ++ nClient->GetUDP_ID() placeholder
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x21;
+    *tmpMsg << ( u32 )nRawObjectId;
+    *tmpMsg << ( u8 )nSeatId; // 0x00 for real chair, 1+ for subway cab
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharExitSeatMsg( PClient* nClient )
+{
+    PMessage* tmpMsg = new PMessage( 22 );
+    PChar* nChar = nClient->GetChar();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; // nClient->GetUDP_ID() placeholder
+    *tmpMsg << ( u16 )0x0000; // nClient->GetSessionID()placeholder
+    *tmpMsg << ( u8 )0x00; // Message length placeholder;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )0x0000; // nClient->GetUDP_ID() placeholder
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x22;
+    *tmpMsg << ( u16 )(( nChar->Coords ).mY + 768 ) ;
+    *tmpMsg << ( u16 )(( nChar->Coords ).mZ + 768 ) ;
+    *tmpMsg << ( u16 )(( nChar->Coords ).mX + 768 ) ;
+    *tmpMsg << ( u8 )( nChar->Coords ).mUD;
+    *tmpMsg << ( u8 )( nChar->Coords ).mLR;
+    *tmpMsg << ( u8 )( nChar->Coords ).mAct;
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildPacket0Msg( PClient* nClient )
+{
+    PMessage* tmpMsg = new PMessage( 70 );
+    PChar* nChar = nClient->GetChar();
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x00; // Message length placeholder;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x2c;
+    *tmpMsg << ( u8 )0x01; // ??
+    *tmpMsg << ( u8 )0x01; // ??
+    *tmpMsg << ( u32 )0x00000000;
+    *tmpMsg << ( f32 )(( nChar->Coords ).mY - 32000 );
+    *tmpMsg << ( f32 )(( nChar->Coords ).mZ - 32000 );
+    *tmpMsg << ( f32 )(( nChar->Coords ).mX - 32000 );
+    *tmpMsg << ( u32 )0x00000000;
+    *tmpMsg << ( u32 )0x00000000;
+    *tmpMsg << ( u32 )0x00000000;
+    *tmpMsg << ( u8 )0x01; // ????
+    *tmpMsg << ( u8 )0x00;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u8 )0x07;
+    *tmpMsg << ( u8 )0x02;
+    *tmpMsg << ( u8 )0x00;
+    *tmpMsg << ( u32 )0x00000000;
+    *tmpMsg << ( u32 )0x00000000;
+    *tmpMsg << ( u32 )0x00000000;
+    *tmpMsg << ( u32 )0x00000000;
+    *tmpMsg << ( u32 )0x00000000;
+    *tmpMsg << ( u32 )0x00000000;
+
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildPingMsg( PClient* nClient, u32 nClientTime )
+{
+    PMessage* tmpMsg = new PMessage( 15 );
+    u32 LocalTime = GameServer->GetGameTime();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x00; // Message length placeholder;
+    *tmpMsg << ( u8 )0x0b;
+    *tmpMsg << ( u32 )LocalTime;
+    *tmpMsg << ( u32 )nClientTime;
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildBaselineMsg( PClient* nClient )
+{
+    PMessage* BaselineMsg = new PMessage( 512 );
+    PMessage SectionMsg( 256 );
+
+    PChar *nChar = nClient->GetChar();
+    const PDefCharKind *def = GameDefs->CharKinds()->GetDef( nChar->GetProfession() );
+    PSkillHandler *Skill = nChar->Skill;
+
+    nClient->IncreaseTransactionID( 3 );
+
+    // Head
+    *BaselineMsg << ( u8 )0x22;
+    *BaselineMsg << ( u8 )0x02; // ?
+    *BaselineMsg << ( u8 )0x01; // ?
+
+    // ---- Section 1 ----
+    *BaselineMsg << ( u8 )0x01; // section id
+
+    SectionMsg << ( u8 )0xfa; // ?  // // section content at offset 3
+    SectionMsg << ( u8 )nChar->GetProfession();
+    SectionMsg << ( u16 )nClient->GetTransactionID(); // Transaction ID ? 0x8aa0
+    SectionMsg << ( u32 )nChar->GetID();
+    SectionMsg << ( u8 )0x0e; // ? 0x0e in NeoX, 0x10 in Tinns ... doesn't seem to matter
+    SectionMsg << ( u8 )0x00; // ?
+
+    *BaselineMsg << ( u16 )SectionMsg.GetSize();
+    *BaselineMsg << SectionMsg;
+    SectionMsg.Reset();
+
+    // ---- Section 2 ----
+    *BaselineMsg << ( u8 )0x02; // section id
+    SectionMsg << ( u8 )0x04; // ?  // section content at offset 3
+    SectionMsg << ( u8 )0x50; // ?
+    SectionMsg << ( u16 )500; // nChar->GetHealth();
+    SectionMsg << ( u16 )500; // nChar->GetMaxHealth();
+    SectionMsg << ( u16 )500; // nChar->GetMana();
+    SectionMsg << ( u16 )500; // nChar->GetMaxMana();
+    SectionMsg << ( u16 )500; // nChar->GetStamina();
+    SectionMsg << ( u16 )500; // nChar->GetMaxStamina();
+    SectionMsg << ( u16 )0x00ff; // ?
+    SectionMsg << ( u16 )0x00ff; // ?
+    SectionMsg << ( u16 )0x00e1; // (nChar->GetHealth() + 1); // ? Probably Head Health (45% of total) 0x0065
+    SectionMsg << ( u16 )0x0147; // (nChar->GetHealth() + 1); // ? Torso Health (35% of total)
+    SectionMsg << ( u16 )0x0147; // (nChar->GetHealth() + 1); // ? Legs Health (20% of total)
+    SectionMsg << ( u8 )100; // 100 - SI
+    SectionMsg << ( u8 )0x80; // The lower this value is, the more your char has a "drug effect" on it 0x00 = unmoveable
+    SectionMsg << ( u16 )0x0000;
+
+    *BaselineMsg << ( u16 )SectionMsg.GetSize();
+    *BaselineMsg << SectionMsg;
+    SectionMsg.Reset();
+
+    // ---- Section 3 ----
+    *BaselineMsg << ( u8 )0x03; // section id
+
+    SectionMsg << ( u8 )0x06; // ?  // section content at offset 3
+    SectionMsg << ( u8 )0x09; // ?
+    SectionMsg << ( u32 )0x00000000; // ?
+    SectionMsg << ( u32 )0x00000000; // ?
+    SectionMsg << ( u8 )0x01; // ?
+
+    SectionMsg << ( u8 )Skill->GetMainSkill( MS_STR );
+    SectionMsg << ( u16 )Skill->GetSP( MS_STR );
+    SectionMsg << ( u32 )Skill->GetXP( MS_STR );
+    SectionMsg << ( u8 )def->GetSkillInfo( MS_STR ).mGrow;
+    SectionMsg << ( u8 )def->GetSkillInfo( MS_STR ).mMax;
+
+    SectionMsg << ( u8 )Skill->GetMainSkill( MS_DEX );
+    SectionMsg << ( u16 )Skill->GetSP( MS_DEX );
+    SectionMsg << ( u32 )Skill->GetXP( MS_DEX );
+    SectionMsg << ( u8 )def->GetSkillInfo( MS_DEX ).mGrow;
+    SectionMsg << ( u8 )def->GetSkillInfo( MS_DEX ).mMax;
+
+    SectionMsg << ( u8 )Skill->GetMainSkill( MS_CON );
+    SectionMsg << ( u16 )Skill->GetSP( MS_CON );
+    SectionMsg << ( u32 )Skill->GetXP( MS_CON );
+    SectionMsg << ( u8 )def->GetSkillInfo( MS_CON ).mGrow;
+    SectionMsg << ( u8 )def->GetSkillInfo( MS_CON ).mMax;
+
+    SectionMsg << ( u8 )Skill->GetMainSkill( MS_INT );
+    SectionMsg << ( u16 )Skill->GetSP( MS_INT );
+    SectionMsg << ( u32 )Skill->GetXP( MS_INT );
+    SectionMsg << ( u8 )def->GetSkillInfo( MS_INT ).mGrow;
+    SectionMsg << ( u8 )def->GetSkillInfo( MS_INT ).mMax;
+
+    SectionMsg << ( u8 )Skill->GetMainSkill( MS_PSI );
+    SectionMsg << ( u16 )Skill->GetSP( MS_PSI );
+    SectionMsg << ( u32 )Skill->GetXP( MS_PSI );
+    SectionMsg << ( u8 )def->GetSkillInfo( MS_PSI ).mGrow;
+    SectionMsg << ( u8 )def->GetSkillInfo( MS_PSI ).mMax;
+
+    SectionMsg << ( u16 )0x0000; // ?
+    SectionMsg << ( u8 )0x00; // ?
+    SectionMsg << ( u8 )0x08; // ?
+
+    *BaselineMsg << ( u16 )SectionMsg.GetSize();
+    *BaselineMsg << SectionMsg;
+    SectionMsg.Reset();
+
+    // ---- Section 4 ----
+    *BaselineMsg << ( u8 )0x04; // section id
+
+    SectionMsg << ( u8 )0x2e; // ?  // section content at offset 3
+    SectionMsg << ( u8 )0x02; // ?
+    SectionMsg << ( u8 )0x00; // spare
+    SectionMsg << ( u8 )0x01; // cost
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_MC );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_MC );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_HC );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_HC );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_TRA );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_TRA );
+    SectionMsg << ( u8 )0x00; // spare
+    SectionMsg << ( u8 )0x01; // cost
+    SectionMsg << ( u8 )0x00; // spare
+    SectionMsg << ( u8 )0x01; // cost
+    SectionMsg << ( u8 )0x00; // spare
+    SectionMsg << ( u8 )0x01; // cost
+    SectionMsg << ( u8 )0x00; // spare
+    SectionMsg << ( u8 )0x01; // cost
+    SectionMsg << ( u8 )0x00; // spare
+    SectionMsg << ( u8 )0x01; // cost
+    SectionMsg << ( u8 )0x00; // spare
+    SectionMsg << ( u8 )0x01; // cost
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_PC );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_PC );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_RC );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_RC );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_TC );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_TC );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_VHC );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_VHC );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_AGL );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_AGL );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_REP );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_REP );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_REC );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_REC );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_RCL );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_RCL );
+    SectionMsg << ( u8 )0x00; // spare
+    SectionMsg << ( u8 )0x01; // cost
+    SectionMsg << ( u8 )0x00; // spare
+    SectionMsg << ( u8 )0x01; // cost
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_ATL );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_ATL );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_END );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_END );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_FOR );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_FOR );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_FIR );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_FIR );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_ENR );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_ENR );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_XRR );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_XRR );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_POR );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_POR );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_HLT );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_HLT );
+    SectionMsg << ( u8 )0x00; // spare
+    SectionMsg << ( u8 )0x01; // cost
+    SectionMsg << ( u8 )0x00; // spare
+    SectionMsg << ( u8 )0x01; // cost
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_HCK );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_HCK );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_BRT );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_BRT );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_PSU );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_PSU );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_WEP );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_WEP );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_CST );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_CST );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_RES );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_RES );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_IMP );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_IMP );
+    SectionMsg << ( u8 )0x00; // spare
+    SectionMsg << ( u8 )0x01; // cost
+    SectionMsg << ( u8 )0x00; // spare
+    SectionMsg << ( u8 )0x01; // cost
+    SectionMsg << ( u8 )0x00; // spare
+    SectionMsg << ( u8 )0x01; // cost
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_PPU );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_PPU );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_APU );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_APU );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_MST );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_MST );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_PPW );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_PPW );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_PSR );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_PSR );
+    SectionMsg << ( u8 )Skill->GetSubSkill( SK_WPW );
+    SectionMsg << ( u8 )Skill->GetSKPCost( SK_WPW );
+
+    *BaselineMsg << ( u16 )SectionMsg.GetSize();
+    *BaselineMsg << SectionMsg;
+    SectionMsg.Reset();
+
+    // ---- Section 5 ----
+    *BaselineMsg << ( u8 )0x05; // section id
+
+    PMessage* ContentList = BuildContainerContentList( nChar->GetInventory()->GetContainer( INV_LOC_BACKPACK ), INV_LOC_BACKPACK );
+    SectionMsg << *ContentList;
+    delete ContentList;
+
+    *BaselineMsg << ( u16 )SectionMsg.GetSize();
+    *BaselineMsg << SectionMsg;
+    SectionMsg.Reset();
+
+    // ---- Section 6 ----
+    *BaselineMsg << ( u8 )0x06; // section id
+
+    ContentList = BuildContainerContentList( nChar->GetInventory()->GetContainer( INV_LOC_WORN ), INV_LOC_WORN );
+    SectionMsg << *ContentList;
+    delete ContentList;
+
+    /*    SectionMsg << (u8)0x04; // QB/Armor/Implants items nb  // section content at offset 3
+
+        // THIS IS A TEMP SOLUTION UNTIL WE HAVE ITEM STUFF WORKING ===== BEGIN
+        SectionMsg << (u16)0x06;     // Size of item
+        SectionMsg << (u16)0x00;     // Location: Quickbelt slot 0
+        SectionMsg << (u16)0x0051;   // ItemID: 81, Flashlight
+        SectionMsg << (u8)0x01;      // Datatype
+        SectionMsg << (u8)0x00;      // Data
+    */
+
+    /****
+    SectionMsg << (u8)0x04; // QB/Armor/Implants items nb  // section content at offset 3
+
+    // THIS IS A TEMP SOLUTION UNTIL WE HAVE ITEM STUFF WORKING ===== BEGIN
+    SectionMsg << (u16)0x001b;     // Size of item
+    SectionMsg << (u8)0x00;     // Location: Quickbelt slot 0
+    SectionMsg << (u8)0x00; // nop (Y)
+    SectionMsg << (u16)0x0003;   // ItemID: 3, assault riffle
+    SectionMsg << (u8)(0x01|0x02|0x10|0x40);      // Datatype
+
+    //SectionMsg << (u8)0x01; // for 0x80. Use ???
+
+    SectionMsg << (u8)0x00; // Qty / remaining ammos
+
+    SectionMsg << (u8)0x06; // Qual entries
+    SectionMsg << (u8)0x40; // current qual
+    SectionMsg << (u8)0x80; // dmg
+    SectionMsg << (u8)0xc0; // freq
+    SectionMsg << (u8)0xa0; // handl
+    SectionMsg << (u8)0xb0; // range
+    SectionMsg << (u8)0xff; // max qual <= always last
+
+    SectionMsg << (u8)0x07; // addons bitflag: flashlight=1, scope, silencer, laserpointer
+
+    SectionMsg << (u8)0x02; // used slots
+    SectionMsg << (u8)0x05; // max slots
+    SectionMsg << (u16)1526; // slots / explo ammo
+    SectionMsg << (u16)21; // riffle-barrel
+    SectionMsg << (u16)0x0000;
+    SectionMsg << (u16)0x0000;
+    SectionMsg << (u16)0x0000;
+    *****/
+    /*
+    SectionMsg << (u16)0x06;     // Size of item
+    SectionMsg << (u8)0x01;     // Location: Quickbelt slot 1
+    SectionMsg << (u8)0x00; // nop (Y)
+    SectionMsg << (u16)0x0023;   // ItemID: 35, Med Kit
+    SectionMsg << (u8)0x01;      // Data=ammo count
+    SectionMsg << (u8)0x03;      // Data
+    */
+    /*
+        SectionMsg << (u16)0x06;     // Size of item
+        SectionMsg << (u16)0x01;     // Location: Quickbelt slot 0
+        SectionMsg << (u16)0x0055;   // ItemID: 81, Flashlight
+        SectionMsg << (u8)0x01;      // Datatype
+        SectionMsg << (u8)0x00;      // Data
+
+        SectionMsg << (u16)0x06;     // Size of item
+        SectionMsg << (u16)0x02;     // Location: Quickbelt slot 0
+        SectionMsg << (u16)0x176F;   // ItemID: 81, Flashlight
+        SectionMsg << (u8)0x01;      // Datatype
+        SectionMsg << (u8)0x00;      // Data
+
+
+        SectionMsg << (u16)0x08;      // Size of item
+        SectionMsg << (u16)0x1a;      // Location: Brain #1
+        SectionMsg << (u16)0x08fc;    // ItemID: Law enforcer
+        SectionMsg << (u8)0x02;       // Datatype. 02: Item Duration information follows
+        SectionMsg << (u8)0x02;       // SubDatatype02: Full itemdetails follow
+        SectionMsg << (u8)0x2a;       // Current duration
+        SectionMsg << (u8)0x2a;       // Max duration
+    */
+//    nChar->GetInventory()->QB_SetSlot(0, 81); // Add Flashlight to QB slot 1
+//    nChar->GetInventory()->QB_SetSlot(1, 85); // Add Flashlight to QB slot 1
+//    nChar->GetInventory()->QB_SetSlot(2, 5999); // Add Flashlight to QB slot 1
+    // THIS IS A TEMP SOLUTION UNTIL WE HAVE ITEM STUFF WORKING ===== END
+    /*
+     StatsBuffer[len+3] = 0; //Number of items
+     plen = 4;
+     for (i=0;i<MAX_INVENTORY;i++)
+     {
+      for (t=0;t<128;t++)
+      {
+       if (CurrentChar.QuickBelt[t]-1 != i)
+        continue;
+       *(unsigned short*)&StatsBuffer[len+plen] = 6;    //Data size of item
+       *(unsigned short*)&StatsBuffer[len+plen+2] = t;  //X position in Inventory
+       *(unsigned short*)&StatsBuffer[len+plen+4] = CurrentChar.ItemList[CurrentChar.QuickBelt[t]-1].ItemID; //Item ID
+       *(unsigned short*)&StatsBuffer[len+plen+6] = CurrentChar.ItemList[CurrentChar.QuickBelt[t]-1].Qty;   //Quantity
+       plen += 8;
+       *(unsigned short*)&StatsBuffer[len+3] += 1;      //Add to item
+       break;
+      }
+    */
+    /*if (CurrentChar.Inventory[i].ItemID == 0)     //Last Item
+     break;
+    if (CurrentChar.Inventory[i].Location != 2)     //Not Quickbelt, skip it
+     continue;
+    if (Def_GetItemType(CurrentChar.Inventory[i].ItemID) == 1)
+    {
+     //18 00 01 00 08 00 63 00 06 ff c8 c8 c8 c8 ff 00 01 00 28 04 00 01 04 ff 01
+     //12 00 11    5f 07 23 00 06 eb a4 99 a3 a5 ff 04 00 01 04 ff 01
+     //13 00 05 00 03 02 23 00 06 6d c4 c4 c4 c4 ff 04 00 01 04 ff 00
+     //17 00 05    9d 01 73 28 06 13 c1 c1 c1 c1 ff 00 01 01 f1 05 04
+     //|Size|Slot|ItemID|???  |? |Du|    Stats  |MD|?????????????????|
+     *(unsigned short*)&StatsBuffer[len+plen] = 19; //Size
+     *(unsigned short*)&StatsBuffer[len+plen+2] = CurrentChar.Inventory[i].LocX; //Slot
+     *(unsigned short*)&StatsBuffer[len+plen+4] = CurrentChar.Inventory[i].ItemID;//Item ID
+     StatsBuffer[len+plen+6] = 0x23;            //0x73 = Ranged, 0x63 = close/spell
+     StatsBuffer[len+plen+7] = CurrentChar.Inventory[i].Qty;      //Quantity
+     StatsBuffer[len+plen+8] = 0x06;            //0x06
+     StatsBuffer[len+plen+9] = CurrentChar.Inventory[i].CurDur;     //Current Durability
+     StatsBuffer[len+plen+10] = CurrentChar.Inventory[i].Damage;     //Stats
+     StatsBuffer[len+plen+11] = CurrentChar.Inventory[i].Freq;     //Stats
+     StatsBuffer[len+plen+12] = CurrentChar.Inventory[i].Hand;     //Stats
+     StatsBuffer[len+plen+13] = CurrentChar.Inventory[i].Rng;     //Stats
+     StatsBuffer[len+plen+14] = CurrentChar.Inventory[i].MaxDur;     //Max Durability
+     StatsBuffer[len+plen+15] = 0x04;           //Size or part
+     StatsBuffer[len+plen+16] = 0x00;           //follow or ?
+     StatsBuffer[len+plen+17] = 0x01;           //Ammo loaded?
+     StatsBuffer[len+plen+18] = 0x04;           //0x04 if not named, 0x0a if named
+     StatsBuffer[len+plen+19] = 0x05;           //0x06 if named, 0xff for no ammo needed, no idea otherwise
+     StatsBuffer[len+plen+20] = 0x0f;           //Binary representation of ammo allowed 0x01 = normal
+     plen+=21;
+    }
+    else
+    {
+     *(unsigned short*)&StatsBuffer[len+plen] = 6;         //Size of Item Data
+     *(unsigned short*)&StatsBuffer[len+plen+2] = CurrentChar.Inventory[i].LocX;  //Slot
+     *(unsigned short*)&StatsBuffer[len+plen+4] = CurrentChar.Inventory[i].ItemID; //Item ID
+     *(unsigned short*)&StatsBuffer[len+plen+6] = CurrentChar.Inventory[i].Qty;  //Quantity
+     plen+= 8;
+    }
+    StatsBuffer[len+3] += 1;*/
+
+    *BaselineMsg << ( u16 )SectionMsg.GetSize();
+    *BaselineMsg << SectionMsg;
+    SectionMsg.Reset();
+
+    // ---- Section 7 ----
+    *BaselineMsg << ( u8 )0x07; // section id
+
+    SectionMsg << ( u8 )0x00; // ?? // section content at offset 3
+
+    *BaselineMsg << ( u16 )SectionMsg.GetSize();
+    *BaselineMsg << SectionMsg;
+    SectionMsg.Reset();
+
+    // ---- Section 0c ----
+    *BaselineMsg << ( u8 )0x0c; // section id
+
+    ContentList = BuildContainerContentList( nChar->GetInventory()->GetContainer( INV_LOC_GOGO ), INV_LOC_GOGO );
+    SectionMsg << *ContentList;
+
+    delete ContentList;
+
+    *BaselineMsg << ( u16 )SectionMsg.GetSize();
+    *BaselineMsg << SectionMsg;
+    SectionMsg.Reset();
+
+    // ---- Section 8 ----
+    *BaselineMsg << ( u8 )0x08; // section id
+
+    u32 nSkin, nHead, nTorso, nLegs;
+    nChar->GetRealLook( nSkin, nHead, nTorso, nLegs );
+
+    SectionMsg << ( u8 )0x0a; // ? // section content at offset 3
+    SectionMsg << ( u32 )nChar->GetCash();
+
+    // Genrep list
+    SectionMsg << ( u16 )nChar->GetGenrepCount(); //Number of GR tagged (Tinns value on u8 only)
+    SectionMsg << ( u8 )0x04;
+    if ( nChar->GetGenrepCount() ) // For each entry : (u16)genrep.g_worldid, (u16)genrep.g_stationid
+    {
+        SectionMsg.Write( nChar->GetGenrepListData(), nChar->GetGenrepListDataSize() );
+    }
+
+    SectionMsg << ( u8 )0x04;
+    SectionMsg << ( u8 )0x04;
+    SectionMsg << ( u8 )0x00;
+
+    // Direct chat
+    if ( nChar->GetDirectChat() )
+    {
+        SectionMsg << ( u8 )1;
+        SectionMsg << ( u32 )nChar->GetDirectChat();
+    }
+    else
+    {
+        SectionMsg << ( u8 )0;
+    }
+
+    // Buddy Chat
+    SectionMsg << ( u8 )nChar->GetBuddyCount(); //Number of Buddies
+    if ( nChar->GetBuddyCount() ) // For each buddy (u32)buddy CharID
+    {
+        SectionMsg.Write( nChar->GetBuddyListData(), nChar->GetBuddyListDataSize() );
+    }
+    SectionMsg << ( u8 )0x00;
+
+    SectionMsg << ( u16 )nClient->GetTransactionID(); // ??
+    //SectionMsg << (u32)0x00000000;
+    SectionMsg << ( u32 )0x00000000;
+    SectionMsg << ( u32 )0x00000000; // Epic status ?
+    SectionMsg << ( u16 )nSkin;
+    SectionMsg << ( u8 )nHead;
+    SectionMsg << ( u8 )nTorso;
+    SectionMsg << ( u8 )nLegs;
+    SectionMsg << ( u8 )0x00; // Rank
+    SectionMsg << ( u32 )( nChar->GetBaseApartment() + PWorlds::mAptBaseWorldId ); // 0x22, 0x00, 0x00, 0x00, //Primary Apartment (GR activated) ???
+    SectionMsg << ( u8 )0x01; // ?
+    SectionMsg << ( u8 )0x00; // ?
+    SectionMsg << ( u8 )0x00; // ?
+    SectionMsg << ( u8 )0x00; // ?
+    SectionMsg << ( u8 )0x00; // ?
+
+    *BaselineMsg << ( u16 )SectionMsg.GetSize();
+    *BaselineMsg << SectionMsg;
+    SectionMsg.Reset();
+
+    // ---- Section 9 ----
+    *BaselineMsg << ( u8 )0x09; // section id
+
+    SectionMsg << ( u16 )0x15; // Nb of factions // section content at offset 3
+    SectionMsg << ( u16 )nChar->GetFaction();
+    SectionMsg << ( u8 )0x04; // ?
+    SectionMsg << ( f32 ) 1000.0f*1000.0f; // 96.0f*9000.0f; // SL
+    // Faction Sympathies Points effective sympathie is Square root of these points, abs value rounded down (beware of the sign ! :p)
+    SectionMsg << ( f32 ) 1000.0f*1250.0f; // City Admin => 111
+    SectionMsg << ( f32 ) 1000.0f*1000.0f; // Diamond => 100
+    SectionMsg << ( f32 ) 1000.0f* -750.0f; // Next => -86
+    SectionMsg << ( f32 ) 1000.0f*500.0f; // Tangent => 70
+    SectionMsg << ( f32 ) 1000.0f* -250.0f; // Biotech => -50
+    SectionMsg << ( f32 ) 1000.0f*0.0f; // ProtoPharm => 0
+    SectionMsg << ( f32 ) 1000.0f*1000.0f; // Trader's Union
+    SectionMsg << ( f32 ) 1000.0f*1000.0f; // Tsunami
+    SectionMsg << ( f32 ) 1000.0f*1000.0f; // Black Dragons
+    SectionMsg << ( f32 ) 1000.0f*1000.0f; // City Mercs
+    SectionMsg << ( f32 ) 1000.0f*1000.0f; // Crahn Sect
+    SectionMsg << ( f32 ) 1000.0f*1000.0f; // Dome Of York
+    SectionMsg << ( f32 ) 1000.0f* -1000.0f; // Anarchy Breed
+    SectionMsg << ( f32 ) 1000.0f*1000.0f; // Fallen Angels
+    SectionMsg << ( f32 ) 1000.0f*1000.0f; // Twilight Guardian
+    SectionMsg << ( f32 ) 1000.0f* -1000.0f; // Regeant's Legacy
+    SectionMsg << ( f32 ) 1000.0f* -1000.0f; // Regeant's Mutants
+    SectionMsg << ( f32 ) 1000.0f* -1000.0f; // Insects
+    SectionMsg << ( f32 ) 1000.0f* -1000.0f; // Monsters
+    SectionMsg << ( f32 ) 1000.0f*1000.0f; // Unknown
+    SectionMsg << ( f32 ) 1000.0f*1000.0f; // Highest SL?
+
+    SectionMsg << ( u32 )0x00000000; // Epic done Data : bit 2^FactionID set <=> Epic done
+    SectionMsg << ( u8 )nChar->GetFaction(); // Faction ??? wrong size ...
+
+    *BaselineMsg << ( u16 )SectionMsg.GetSize();
+    *BaselineMsg << SectionMsg;
+    SectionMsg.Reset();
+
+    // ---- Section 0a ----
+    *BaselineMsg << ( u8 )0x0a; // section id
+
+    // Clan data ?
+    *BaselineMsg << ( u16 )SectionMsg.GetSize();
+    *BaselineMsg << SectionMsg;
+    SectionMsg.Reset();
+
+    // ---- Section 0b ----
+    *BaselineMsg << ( u8 )0x0b; // section id
+
+    SectionMsg << ( u8 )0x00; // ?? // section content at offset 3
+
+    *BaselineMsg << ( u16 )SectionMsg.GetSize();
+    *BaselineMsg << SectionMsg;
+    SectionMsg.Reset();
+
+    // ---- Section 0d ----
+    *BaselineMsg << ( u8 )0x0d; // section id
+
+    SectionMsg << ( u8 )0xfa; // ?? // section content at offset 3
+    SectionMsg << ( u8 )nChar->GetProfession();
+    SectionMsg << ( u16 )nClient->GetTransactionID(); // ?? TransactionID ? 0x8aa0
+    SectionMsg << ( u32 )nChar->GetID();
+
+    *BaselineMsg << ( u16 )SectionMsg.GetSize();
+    *BaselineMsg << SectionMsg;
+    SectionMsg.Reset();
+
+    return BaselineMsg;
+}
+
+PMessage* PMsgBuilder::BuildAliveRepMsg( PClient* nClient )
+{
+    PMessage* tmpMsg = new PMessage( 7 );
+
+    // u8 up[] = {0x04, 0x01, 0x00, 0xe3, 0x6b, 0xe6, 0xee};
+    *tmpMsg << ( u8 )0x04;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0xe3; // ? not always...
+    *tmpMsg << ( u8 )0x6b; // ? not always...
+    *tmpMsg << ( u16 )( nClient->getUDPConn()->getPort() ); // really ?
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildZoning1Msg( PClient* nClient, u16 nEntity, u8 nUnknown )
+{
+    PMessage* tmpMsg = new PMessage( 42 );
+
+    nClient->IncreaseUDP_ID();
+    nClient->IncreaseTransactionID(); // from NeoX
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x0c; // Message length place;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID(); // from NeoX
+    *tmpMsg << ( u8 )0x25; // ??
+    *tmpMsg << ( u8 )0x13; // ??
+    *tmpMsg << ( u16 )nClient->GetTransactionID(); // from NeoX / ?? right ???
+    // In case of apt GR or NC2.2 ?
+    // *tmpMsg << (u8)0x04; // len ?
+    // *tmpMsg << (u32)AptWorldID; // len ?
+    // nClient->IncreaseTransactionID();
+    // *tmpMsg << (u16)nClient->GetTransactionID();
+    *tmpMsg << ( u8 )0x0e; // cmd => but not for zoning, because used in non-zoning situation
+    *tmpMsg << ( u8 )0x02; // ?? from NeoX
+    //(*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6);
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x17; // Message length place;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x23;
+    *tmpMsg << ( u16 )0x0004; // cmd
+    *tmpMsg << ( u32 )0x00000000; // from NeoX
+    *tmpMsg << ( u32 )0x00000000; // from NeoX
+    *tmpMsg << ( u8 )nUnknown;
+    *tmpMsg << ( u16 )nEntity;
+    *tmpMsg << ( u16 )0x0000; // from NeoX
+    *tmpMsg << ( u16 )nClient->GetTransactionID(); // from NeoX
+    *tmpMsg << ( u16 )0x0000; // from NeoX
+
+    // We DO need this! This is a multiframe packet, and the first UDP/SessionID set *HAS* to be
+    // as high as the last UDP/SessionID set in the frame!
+    tmpMsg->U16Data( 1 ) = nClient->GetUDP_ID();
+    tmpMsg->U16Data( 3 ) = nClient->GetSessionID();
+
+    //(*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6);
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildZoningTCPReadyMsg()
+{
+    PMessage* tmpMsg = new PMessage( 7 );
+
+    //static const u8 READY[7] = {0xfe, 0x04, 0x00, 0x83, 0x0d, 0x00, 0x00};
+    *tmpMsg << ( u8 )0xfe;
+    *tmpMsg << ( u16 )0x0004; //length
+    *tmpMsg << ( u8 )0x83; //cmd
+    *tmpMsg << ( u8 )0x0d; // sub-cmd
+    *tmpMsg << ( u16 )0x0000;
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildSendZoneTCPMsg( u32 nLocation, std::string* nWorldName )
+{
+    PMessage* tmpMsg = new PMessage( 14 + nWorldName->size() );
+
+    *tmpMsg << ( u8 )0xfe;
+    *tmpMsg << ( u16 )0x0000; // size placeholder
+    *tmpMsg << ( u8 )0x83;
+    *tmpMsg << ( u8 )0x0c;
+    *tmpMsg << ( u32 )nLocation;
+    *tmpMsg << ( u32 )0x00000000;
+    tmpMsg->Write( nWorldName->c_str(), nWorldName->size() + 1 );
+
+    tmpMsg->U16Data( 1 ) = ( u16 )( tmpMsg->GetSize() - 3 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildZoning2Msg( PClient* nClient, u32 nClientTime )
+{
+    PMessage* tmpMsg = new PMessage( 22 );
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x00; // Message length placeholder;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x0d;
+    *tmpMsg << ( u32 )GameServer->GetGameTime();
+
+    *tmpMsg << ( u32 )nClientTime;
+
+    *tmpMsg << ( u8 )0xe5; // ??? varies
+    *tmpMsg << ( u8 )0x0a; // ??? varies
+    *tmpMsg << ( u8 )0xbb; // ??? varies
+    *tmpMsg << ( u8 )0x00; // ??? usually 0
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildGenrepZoningMsg( PClient* nClient, u32 nLocation, u16 nEntity )
+{
+    PMessage* tmpMsg = new PMessage( 50 );
+
+    nClient->IncreaseUDP_ID();
+
+    tmpMsg->Fill( 0 );
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x00; // Message length placeholder;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x23;
+    *tmpMsg << ( u16 )0x000c; // cmd
+    tmpMsg->SetNextByteOffset( 38 );
+    *tmpMsg << ( u32 )0xffffffff;
+    *tmpMsg << ( u32 )nLocation;
+    *tmpMsg << ( u16 )nEntity;
+    *tmpMsg << ( u16 )0x0000;
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildGenrepAddToListMsg( PClient* nClient, u32 nLocation, u16 nEntity )
+{
+    PMessage* tmpMsg = new PMessage( 23 );
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x00; // Message length placeholder;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x3d;
+    *tmpMsg << ( u32 )0x00000002;
+    *tmpMsg << ( u32 )nLocation;
+    *tmpMsg << ( u16 )nEntity;
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildAptLiftUseMsg( PClient* nClient, u32 nLocation, u16 nEntity, u8 nEntityType )
+{
+    PMessage* tmpMsg = new PMessage( 43 );
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+
+    *tmpMsg << ( u8 )0x0f; // Message length placeholder;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x38;
+    *tmpMsg << ( u8 )0x04; // Accepted (?)
+    *tmpMsg << ( u8 )nEntityType; // "Sewer Level"
+    *tmpMsg << ( u32 )nLocation;
+    *tmpMsg << ( u16 )nEntity;
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildAptLiftFailedMsg( PClient* nClient )
+{
+    PMessage* tmpMsg = new PMessage( 14 );
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+
+    *tmpMsg << ( u8 )0x08; // Message length placeholder;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x38;
+    *tmpMsg << ( u8 )0x03; // Refused
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildChangeLocationMsg( PClient* nClient, u32 nLocation, u16 nEntity, u8 nEntityType, u32 nRawItemID )
+{
+    PMessage* tmpMsg = new PMessage( 28 );
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+
+    if ( nRawItemID )
+    {
+        *tmpMsg << ( u8 )0x06; // Sub message length;
+        *tmpMsg << ( u8 )0x2d; // Item use response;
+        *tmpMsg << ( u32 )nRawItemID;
+        *tmpMsg << ( u8 )0x0a; // Use allowed
+    }
+
+    *tmpMsg << ( u8 )0x0f; // Sub message length;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x38;
+    *tmpMsg << ( u8 )0x04; // Accepted (?)
+    *tmpMsg << ( u8 )nEntityType;
+    *tmpMsg << ( u32 )nLocation;
+    *tmpMsg << ( u16 )nEntity;
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildEntityPositionMsg( PClient* nClient, u16 pX, u16 pY, u16 pZ )
+{
+    PMessage* tmpMsg = new PMessage( 18 );
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x00; // Message length placeholder;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x23;
+    *tmpMsg << ( u16 )0x000a;
+    *tmpMsg << ( u16 )( pY + 768 );
+    *tmpMsg << ( u16 )( pZ + 768 );
+    *tmpMsg << ( u16 )( pX + 768 );
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharAptLocInfoMsg( PClient* nClient )
+{
+    PMessage* tmpMsg = new PMessage( 21 );
+    nClient->IncreaseUDP_ID();
+
+    int BaseAppId = nClient->GetChar()->GetBaseApartment();
+    u32 AptLocation = ( u32 )Appartements->GetAptLocation( BaseAppId );
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x0f;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x3d;
+    *tmpMsg << ( u32 )0x0000000b;
+    *tmpMsg << ( u32 )AptLocation;
+
+    return tmpMsg;
+}
+
+// OLD FUNCTION, REWRITTEN BELOW
+/*
+PMessage* PMsgBuilder::BuildSubskillIncMsg( PClient* nClient, u8 nSubskill, u16 nSkillPoints )
+{
+  PMessage* tmpMsg = new PMessage( 33 );
+
+  *tmpMsg << ( u8 )0x13;
+  *tmpMsg << ( u16 )nClient->GetUDP_ID();
+  *tmpMsg << ( u16 )nClient->GetSessionID();
+
+  nClient->IncreaseUDP_ID();
+  *tmpMsg << ( u8 )0x09; // SubMessage length;
+  *tmpMsg << ( u8 )0x03;
+  *tmpMsg << ( u16 )nClient->GetUDP_ID();
+  *tmpMsg << ( u8 )0x1f;
+  *tmpMsg << ( u16 )nClient->GetLocalID();
+  *tmpMsg << ( u8 )0x25;
+  *tmpMsg << ( u8 )0x23;
+  *tmpMsg << ( u8 )0x41; // 0x28 ?? // 0x 18 // 0x2c
+
+  nClient->IncreaseUDP_ID();
+  nClient->IncreaseTransactionID(); // testing ...
+  *tmpMsg << ( u8 )0x11; // SubMessage length;
+  *tmpMsg << ( u8 )0x03;
+  *tmpMsg << ( u16 )nClient->GetUDP_ID();
+  *tmpMsg << ( u8 )0x1f;
+  *tmpMsg << ( u16 )nClient->GetLocalID();
+  *tmpMsg << ( u8 )0x25;
+  *tmpMsg << ( u8 )0x13;
+  *tmpMsg << ( u16 )nClient->GetTransactionID(); // testing / 0x0000 ????
+  *tmpMsg << ( u8 )0x09; // ?
+  *tmpMsg << ( u16 )nSubskill;
+  *tmpMsg << ( u16 )nClient->GetChar()->Skill->GetSubSkill( nSubskill ); // nSubskill ?
+  *tmpMsg << ( u16 )nSkillPoints;
+
+  //(*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6);
+
+  return tmpMsg;
+}
+*/\r
+// NPC Dialog. Start dialog with NPC\r
+PMessage* PMsgBuilder::BuildNPCStartDialogMsg( PClient* nClient, u32 nNPCWorldID, string* nDialogScript  )\r
+{\r
+    PMessage* tmpMsg = new PMessage();\r
+    nClient->IncreaseUDP_ID();\r
+\r
+\r
+    *tmpMsg << ( u8 )0x13;\r
+    *tmpMsg << ( u16 ) 0x0000; // UDP Placeholder\r
+    *tmpMsg << ( u16 ) 0x0000; // UDP Placeholder\r
+    *tmpMsg << ( u8 )0x00; // Message length\r
+    *tmpMsg << ( u8 )0x03;\r
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();\r
+    *tmpMsg << ( u8 )0x1f;\r
+    *tmpMsg << ( u16 )nClient->GetLocalID();\r
+    *tmpMsg << ( u8 )0x18;\r
+    *tmpMsg << ( u32 ) nNPCWorldID;\r
+\r
+    // Todo: is this correct? random u32 value??\r
+    *tmpMsg << ( u16 ) GetRandom( 65535, 4369 );\r
+    *tmpMsg << ( u16 ) GetRandom( 65535, 4369 );\r
+    *tmpMsg << ( u32 ) 0x0000;\r
+    *tmpMsg << nDialogScript->c_str();\r
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );\r
+\r
+    nClient->IncreaseUDP_ID();\r
+\r
+    *tmpMsg << ( u8 )0x0a;\r
+    *tmpMsg << ( u8 )0x03;\r
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();\r
+    *tmpMsg << ( u8 )0x1f;\r
+    *tmpMsg << ( u16 )nClient->GetLocalID();\r
+    *tmpMsg << ( u8 )0x1a;\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u8 )0x00;\r
+\r
+    tmpMsg->U16Data( 1 ) = nClient->GetUDP_ID();\r
+    tmpMsg->U16Data( 3 ) = nClient->GetSessionID();\r
+\r
+    return tmpMsg;\r
+}\r
+// NPC Dialog. Send next node number in lua script to client\r
+PMessage* PMsgBuilder::BuildNPCDialogReplyMsg( PClient* nClient, u16 nNextNode, std::vector<int>*nResultBuffer)\r
+{\r
+    PMessage* tmpMsg = new PMessage();\r
+\r
+    nClient->IncreaseUDP_ID();\r
+\r
+    *tmpMsg << ( u8 )0x13;\r
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();;\r
+    *tmpMsg << ( u16 )nClient->GetSessionID();;\r
+    *tmpMsg << ( u8 )0x00; // SubMessage length;\r
+\r
+    *tmpMsg << ( u8 )0x03;\r
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();;\r
+    *tmpMsg << ( u8 )0x1f;\r
+    *tmpMsg << ( u16 )nClient->GetLocalID();\r
+    *tmpMsg << ( u8 )0x1a;\r
+    *tmpMsg << ( u16 )nNextNode;\r
+    //*tmpMsg << ( u8 )nNumResults;\r
+    *tmpMsg << ( u8 )nResultBuffer->size();\r
+\r
+    std::vector<int>::const_iterator it;\r
+\r
+    for(it = nResultBuffer->begin(); it != nResultBuffer->end(); it++)\r
+    {\r
+        *tmpMsg << ( f32 )*(it);\r
+    }\r
+\r
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );\r
+\r
+    return tmpMsg;\r
+}\r
+PMessage* PMsgBuilder::BuildNPCBeginAllBuyerTradeMsg( PClient* nClient, int nWorldID )\r
+{\r
+    PMessage* tmpMsg = new PMessage();\r
+    nClient->IncreaseUDP_ID();\r
+\r
+    *tmpMsg << ( u8 )0x13;\r
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();\r
+    *tmpMsg << ( u16 )nClient->GetSessionID();\r
+    *tmpMsg << ( u8 )0x00; // Message length\r
+    *tmpMsg << ( u8 )0x03;\r
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();\r
+    *tmpMsg << ( u8 )0x1f;\r
+    *tmpMsg << ( u16 )nClient->GetLocalID();\r
+    *tmpMsg << ( u8 )0x26;\r
+    *tmpMsg << ( u32 ) nWorldID;\r
+    *tmpMsg << ( u8 )0x01; // Traders inventory\r
+    *tmpMsg << ( u16 )0xFFFF; // Traders inventory\r
+\r
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );\r
+\r
+    return tmpMsg;\r
+}\r
+\r
+PMessage* PMsgBuilder::BuildNPCShoppingListMsg( PClient* nClient, PMessage* nContentList, int nWorldID, u8 nItemQuality)\r
+{\r
+    PMessage* tmpMsg = new PMessage();\r
+    nClient->IncreaseUDP_ID();\r
+\r
+    *tmpMsg << ( u8 )0x13;\r
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();\r
+    *tmpMsg << ( u16 )nClient->GetSessionID();\r
+    *tmpMsg << ( u8 )0x00; // Message length\r
+    *tmpMsg << ( u8 )0x03;\r
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();\r
+    *tmpMsg << ( u8 )0x1f;\r
+    *tmpMsg << ( u16 )nClient->GetLocalID();\r
+    *tmpMsg << ( u8 )0x26;\r
+    *tmpMsg << ( u32 ) nWorldID;\r
+    *tmpMsg << ( u8 )0x01; // Traders inventory\r
+    *tmpMsg << ( u16 )( nContentList->GetSize() / 6 ); // List entries\r
+    *tmpMsg << ( u8 )nItemQuality; // Items quality\r
+    *tmpMsg << *nContentList;\r
+\r
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );\r
+\r
+    return tmpMsg;\r
+}\r
+\r
+// ==========================\r
+PMessage* PMsgBuilder::BuildNPCSingleInfoMsg( PClient* nClient, u32 nWorldID, u16 nTypeID, u16 nClothing,\r
+u16 nNameID, u16 nPosY, u16 nPosZ, u16 nPosX, u16 nUnknown,\r
+u16 nTraderID, string* nAngleStr, string* nNpcName, string* nCustomName)\r
+// Initial NPC Packet that defines how the NPC look, etc\r
+{\r
+//    u8 tMsgLen = 29 + nNpcName->size() + nAngleStr->size() + nCustomName->size();\r
+\r
+    PMessage* tmpMsg = new PMessage();\r
+    nClient->IncreaseUDP_ID();\r
+\r
+    *tmpMsg << ( u8 )0x13; // Begin UDP message\r
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();\r
+    *tmpMsg << ( u16 )nClient->GetSessionID();\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u8 )0x03;\r
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();\r
+    *tmpMsg << ( u8 )0x28;\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u8 )0x01;\r
+    *tmpMsg << ( u32 )nWorldID;\r
+    *tmpMsg << ( u16 )nTypeID;\r
+    *tmpMsg << ( u16 )nClothing;\r
+    *tmpMsg << ( u16 )nNameID;\r
+    *tmpMsg << ( u16 )nPosY;\r
+    *tmpMsg << ( u16 )nPosZ;\r
+    *tmpMsg << ( u16 )nPosX;\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u16 )nUnknown;\r
+    *tmpMsg << ( u16 )nTraderID;\r
+    *tmpMsg << nNpcName->c_str();\r
+    *tmpMsg << nAngleStr->c_str();\r
+    if(nCustomName->length() > 1)\r
+        *tmpMsg << nCustomName->c_str();\r
+\r
+    (*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6);\r
+    return tmpMsg;\r
+}\r
+\r
+PMessage* PMsgBuilder::BuildNPCMassInfoMsg( u32 nWorldID, u16 nTypeID, u16 nClothing,\r
+u16 nNameID, u16 nPosY, u16 nPosZ, u16 nPosX, u16 nHealth,\r
+u16 nTraderID, string* nAngleStr, string* nNpcName, string* nCustomName)\r
+// Initial NPC Packet that defines how the NPC look, etc\r
+{\r
+//    u8 tMsgLen = 29 + nNpcName->size() + nAngleStr->size() + nCustomName->size();\r
+\r
+    PMessage* tmpMsg = new PMessage();\r
+\r
+    *tmpMsg << ( u8 )0x13; // Begin UDP message\r
+    *tmpMsg << ( u16 )0x0000;\r
+    *tmpMsg << ( u16 )0x0000;\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u8 )0x03;\r
+    *tmpMsg << ( u16 )0x0000;\r
+    *tmpMsg << ( u8 )0x28;\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u8 )0x01;\r
+    *tmpMsg << ( u32 )nWorldID;\r
+    *tmpMsg << ( u16 )nTypeID;\r
+    *tmpMsg << ( u16 )nClothing;\r
+    *tmpMsg << ( u16 )nNameID;\r
+    *tmpMsg << ( u16 )nPosY;\r
+    *tmpMsg << ( u16 )nPosZ;\r
+    *tmpMsg << ( u16 )nPosX;\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u16 )nHealth;\r
+    *tmpMsg << ( u16 )nTraderID;\r
+    *tmpMsg << nNpcName->c_str();\r
+    *tmpMsg << nAngleStr->c_str();\r
+    if(nCustomName->length() > 1)\r
+        *tmpMsg << nCustomName->c_str();\r
+\r
+    (*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6);\r
+    return tmpMsg;\r
+}\r
+\r
+// **************\r
+PMessage* PMsgBuilder::BuildNPCUpdateMsg(u32 nWorldID, u16 nPosY, u16 nPosZ, u16 nPosX, u8 nActionBM, u16 nHealth, u8 nWeaponState, u8 nUnknown, u32 nTargetID)\r
+{\r
+    PMessage* tmpMsg = new PMessage();\r
+\r
+    *tmpMsg << ( u8 )0x13;\r
+    *tmpMsg << ( u16 )0x0000;\r
+    *tmpMsg << ( u16 )0x0000;\r
+    *tmpMsg << ( u8 )0x00;      // len\r
+    *tmpMsg << ( u8 )0x1b;      // NPC Update\r
+    *tmpMsg << ( u32 )nWorldID; // NPCs world ID\r
+    *tmpMsg << ( u8 )0x1f;      // Parameters\r
+    *tmpMsg << ( u16 )nPosY;    // Position Y\r
+    *tmpMsg << ( u16 )nPosZ;    // Position Z\r
+    *tmpMsg << ( u16 )nPosX;    // Position X\r
+    *tmpMsg << ( u8 )nActionBM; // NPCs current action-bitmask\r
+    *tmpMsg << ( u16 )nHealth;   // Health value\r
+    if(nTargetID > 0)\r
+        *tmpMsg << ( u32 )nTargetID; // WorldID of NPCs target (if any)\r
+    *tmpMsg << ( u8 )nUnknown;\r
+    *tmpMsg << ( u8 )nWeaponState;\r
+\r
+    (*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6);\r
+\r
+    return tmpMsg;\r
+}\r
+// **************\r
+\r
+PMessage* PMsgBuilder::BuildNPCSingleAliveMsg( PClient* nClient, u32 nWorldID, u16 nX, u16 nY, u16 nZ, u8 nActionStatus, u8 nHealth, u8 nAction )\r
+{\r
+    PMessage* tmpMsg = new PMessage();\r
+\r
+    *tmpMsg << ( u8 )0x13; // Begin UDP message\r
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();\r
+    *tmpMsg << ( u16 )nClient->GetSessionID();\r
+    *tmpMsg << ( u8 )0x11;\r
+    *tmpMsg << ( u8 )0x1B;\r
+    *tmpMsg << ( u32 )nWorldID;\r
+    *tmpMsg << ( u8 )0x1F;\r
+    *tmpMsg << ( u16 )nY;\r
+    *tmpMsg << ( u16 )nZ;\r
+    *tmpMsg << ( u16 )nX;\r
+    *tmpMsg << ( u8 )nActionStatus;\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u8 )nHealth;\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u8 )nAction;\r
+\r
+    return tmpMsg;\r
+}\r
+\r
+PMessage* PMsgBuilder::BuildNPCMassAliveMsg( u32 nWorldID, u16 nX, u16 nY, u16 nZ, u8 nActionStatus, u8 nHealth, u8 nAction )\r
+{\r
+    PMessage* tmpMsg = new PMessage();\r
+\r
+    *tmpMsg << ( u8 )0x13; // Begin UDP message\r
+    *tmpMsg << ( u16 )0x0000;\r
+    *tmpMsg << ( u16 )0x0000;\r
+    *tmpMsg << ( u8 )0x11;\r
+    *tmpMsg << ( u8 )0x1B;\r
+    *tmpMsg << ( u32 )nWorldID;\r
+    *tmpMsg << ( u8 )0x1F;\r
+    *tmpMsg << ( u16 )nY;\r
+    *tmpMsg << ( u16 )nZ;\r
+    *tmpMsg << ( u16 )nX;\r
+    *tmpMsg << ( u8 )nActionStatus;\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u8 )nHealth;\r
+    *tmpMsg << ( u8 )0x00;\r
+    *tmpMsg << ( u8 )nAction;\r
+\r
+    return tmpMsg;\r
+}\r
+\r
+PMessage* PMsgBuilder::BuildNPCMassUpdateMsg( u32 nWorldID, u16 nX, u16 nY, u16 nZ, u8 nActionStatus, u8 nHealth, u16 nTarget, u8 nAction )\r
+{\r
+    PMessage* tmpMsg = new PMessage();\r
+\r
+    *tmpMsg << ( u8 )0x13; // Begin UDP message\r
+    *tmpMsg << ( u16 )0x0000;\r
+    *tmpMsg << ( u16 )0x0000;\r
+    *tmpMsg << ( u8 )0x15; // Message length\r
+    *tmpMsg << ( u8 )0x1b;\r
+    *tmpMsg << ( u32 )nWorldID;\r
+    *tmpMsg << ( u8 )0x1F;\r
+    *tmpMsg << ( u16 )nY;\r
+    *tmpMsg << ( u16 )nZ;\r
+    *tmpMsg << ( u16 )nX;\r
+    *tmpMsg << ( u8 )nActionStatus;\r
+    *tmpMsg << ( u8 )0x77; // ?\r
+    *tmpMsg << ( u8 )nHealth;\r
+    *tmpMsg << ( u16 )nTarget;\r
+    *tmpMsg << ( u8 )0x00; // ?\r
+    *tmpMsg << ( u8 )0x00; // ?\r
+    *tmpMsg << ( u8 )0x00; // ?\r
+    *tmpMsg << ( u8 )nAction;\r
+\r
+    return tmpMsg;\r
+}\r
+\r
+// ==========================\r
+\r
+PMessage* PMsgBuilder::BuildNPCSingleUpdateMsg( PClient* nClient, u32 nWorldID, u16 nX, u16 nY, u16 nZ, u8 nActionStatus, u8 nHealth, u16 nTarget, u8 nAction )\r
+{\r
+    PMessage* tmpMsg = new PMessage();\r
+\r
+    *tmpMsg << ( u8 )0x13; // Begin UDP message\r
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();\r
+    *tmpMsg << ( u16 )nClient->GetSessionID();\r
+    *tmpMsg << ( u8 )0x15; // Message length\r
+    *tmpMsg << ( u8 )0x1b;\r
+    *tmpMsg << ( u32 )nWorldID;\r
+    *tmpMsg << ( u8 )0x1F;\r
+    *tmpMsg << ( u16 )nY;\r
+    *tmpMsg << ( u16 )nZ;\r
+    *tmpMsg << ( u16 )nX;\r
+    *tmpMsg << ( u8 )nActionStatus;\r
+    *tmpMsg << ( u8 )0x77; // ?\r
+    *tmpMsg << ( u8 )nHealth;\r
+    *tmpMsg << ( u16 )nTarget;\r
+    *tmpMsg << ( u8 )0x00; // ?\r
+    *tmpMsg << ( u8 )0x00; // ?\r
+    *tmpMsg << ( u8 )0x00; // ?\r
+    *tmpMsg << ( u8 )nAction;\r
+\r
+    return tmpMsg;\r
+}\r
+// ==========================\r
+PMessage* PMsgBuilder::BuildSubskillIncMsg( PClient* nClient, u8 nSubskill, u16 nSkillPoints )
+{
+    PMessage* tmpMsg = new PMessage( 33 );
+
+    nClient->IncreaseUDP_ID();
+    u16 tFirstUDPID = nClient->GetUDP_ID();
+
+    nClient->IncreaseUDP_ID();
+    u16 tSecondUDPID = nClient->GetUDP_ID();
+    u16 tSecondSessionID = nClient->GetSessionID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )tSecondUDPID;
+    *tmpMsg << ( u16 )tSecondSessionID;
+
+    *tmpMsg << ( u8 )0x09; // SubMessage length;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )tFirstUDPID;
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x25;
+    *tmpMsg << ( u8 )0x23;
+    *tmpMsg << ( u8 )0x27;
+
+    nClient->IncreaseTransactionID();
+    *tmpMsg << ( u8 )0x11; // SubMessage length;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )tSecondUDPID;
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x25;
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetTransactionID(); // testing / 0x0000 ????
+    *tmpMsg << ( u8 )0x09; // ?
+    *tmpMsg << ( u16 )nSubskill;
+    *tmpMsg << ( u16 )nClient->GetChar()->Skill->GetSubSkill( nSubskill ); // nSubskill ?
+    *tmpMsg << ( u16 )nSkillPoints;
+
+    //(*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6);
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildLevelUpMessage( PClient* nClient, u8 nMainSkill, u8 nNewLevel, u16 nFreeSkillPoints)
+{
+    PMessage* tmpMsg = new PMessage(21);
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << (u8)0x13;
+    *tmpMsg << (u16)nClient->GetUDP_ID();
+    *tmpMsg << (u16)nClient->GetSessionID();
+    *tmpMsg << (u8)0x0F;
+    *tmpMsg << (u8)0x03;
+    *tmpMsg << (u16)nClient->GetUDP_ID();
+    *tmpMsg << (u8)0x1F;
+    *tmpMsg << (u16)nClient->GetLocalID();
+    *tmpMsg << (u8)0x25;
+    *tmpMsg << (u8)0x0B;
+    *tmpMsg << (u16)nMainSkill;
+    *tmpMsg << (u8)nNewLevel;
+    *tmpMsg << (u16)nFreeSkillPoints;
+    *tmpMsg << (u8)0x00;
+    *tmpMsg << (u8)0x00;
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildChatAddMsg( PClient* nClient, u32 nAddedCharID, u8 nMode )
+{
+    PMessage* tmpMsg = new PMessage( 18 );
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+
+    *tmpMsg << ( u8 )0x00; // Message length placeholder;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x32;
+    *tmpMsg << ( u8 )nMode;
+    *tmpMsg << ( u32 )nAddedCharID;
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildDoorOpenMsg( u32 nRawItemID, bool nDoubleDoor )
+{
+    //PMessage* tmpMsg = new PMessage(37);
+    PMessage* tmpMsg = new PMessage( 21 );
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; //Client->GetUDP_ID(); // just placeholder, must be set outside
+    *tmpMsg << ( u16 )0x0000;  // Client->GetSessionID(); // just placeholder, must be set outside
+
+    *tmpMsg << ( u8 )0x0f; // Sub-message length;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )0x0000; //++Client->GetUDP_ID(); // just placeholder, must be set outside
+    *tmpMsg << ( u8 )0x1b;
+    *tmpMsg << ( u32 )nRawItemID;
+    *tmpMsg << ( u8 )0x20; //?
+    if ( nDoubleDoor )
+    {
+        *tmpMsg << ( u16 )0x0005; //?
+        *tmpMsg << ( u16 )0x0000; //?
+        *tmpMsg << ( u16 )0x1500; //?
+    }
+    else
+    {
+        *tmpMsg << ( u16 )0x0000; //?
+        *tmpMsg << ( u16 )0x00c8; //? or 0x64 ?
+        *tmpMsg << ( u16 )0x10ff; //?
+    }
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+// Message from text.ini, section [MISC], id = 100+nTxtMsgId
+PMessage* PMsgBuilder::BuildText100Msg( PClient* nClient, u8 nTxtMsgId, u32 nRawObjectID )
+{
+    PMessage* tmpMsg = new PMessage( 17 );
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+
+    *tmpMsg << ( u8 )0x0c; // Message length;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x31;
+    *tmpMsg << ( u8 )nTxtMsgId;
+    *tmpMsg << ( u32 )nRawObjectID;
+
+    //(*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6);
+
+    return tmpMsg;
+}
+
+// Same as BuildText100Msg, but here we can specify *ANY* text from text.ini, not limited to section [MISC]
+// 1: [DIALOG]
+// 2: [STATEMENT]
+// 3: [GUI] + [playertextures]
+// 4: [TERMINAL]
+// 5: [MENU]
+// 6: [MISC]
+// 7: [ITEMDESC]
+// 8: [HELPTEXT]
+PMessage* PMsgBuilder::BuildTextIniMsg( PClient* nClient, u8 nTxtGroupID, u16 nTxtID )
+{
+    PMessage* tmpMsg = new PMessage( 20 );
+
+    nClient->IncreaseUDP_ID();
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x0e; // Message length
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x25; // ??
+    *tmpMsg << ( u8 )0x15; // ??
+    *tmpMsg << nTxtGroupID;
+    *tmpMsg << nTxtID;
+    *tmpMsg << ( u8 )0x00; // ??
+    *tmpMsg << ( u8 )0x00; // ??
+    *tmpMsg << ( u8 )0x00; // ??
+
+    //(*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6);
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharInteractionMenuMsg( PClient* nClient, u32 nRawTargetID )
+{
+    PMessage* tmpMsg = new PMessage( 17 );
+
+    nClient->IncreaseUDP_ID();
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x0b; // Message length
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x4d;
+    *tmpMsg << ( u32 )nRawTargetID;
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildFurnitureActivateMsg( PClient* nClient, u32 nRawObjectID, u8 nActionValue )
+{
+    PMessage* tmpMsg = new PMessage( 12 );
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+
+    *tmpMsg << ( u8 )0x06; // SubMessage length;
+    *tmpMsg << ( u8 )0x2d;
+    *tmpMsg << ( u32 )nRawObjectID;
+    *tmpMsg << ( u8 )nActionValue; // known valid are 5 (ring), 9 (remove) and 10 (clic)
+
+    //(*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6);
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharUseFurnitureMsg( PClient* nClient, u32 nRawObjectID )
+{
+    PMessage* tmpMsg = new PMessage( 24 );
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+
+    *tmpMsg << ( u8 )0x06; // SubMessage length;
+    *tmpMsg << ( u8 )0x2d;
+    *tmpMsg << ( u32 )nRawObjectID;
+    *tmpMsg << ( u8 )0x0a;
+
+    *tmpMsg << ( u8 )0x0b; // SubMessage length;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x17;
+    *tmpMsg << ( u32 )nRawObjectID;
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharUseVhcTerminalMsg( PClient* nClient, u32 nRawObjectID )
+{
+    PMessage* tmpMsg = new PMessage( 24 );
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+
+    *tmpMsg << ( u8 )0x06; // SubMessage length;
+    *tmpMsg << ( u8 )0x2d;
+    *tmpMsg << ( u32 )nRawObjectID;
+    *tmpMsg << ( u8 )0x0a;
+
+    *tmpMsg << ( u8 )0x07; // SubMessage length;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x4a;
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharUseGogoMsg( PClient* nClient )
+{
+    PMessage* tmpMsg = new PMessage( 17 );
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+
+    *tmpMsg << ( u8 )0x0b; // Message length;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x3d;
+    *tmpMsg << ( u32 )0x0000000d; // cmd
+
+    //(*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6);
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharUseVentureWarpMsg( PClient* nClient, u32 nRawObjectID )
+{
+    PMessage* tmpMsg = new PMessage( 17 );
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+
+    *tmpMsg << ( u8 )0x0b; // Message length;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x3d;
+    *tmpMsg << ( u32 )0x00000008; // cmd
+    *tmpMsg << ( u32 )0x00000007; // cmd ?
+    *tmpMsg << ( u32 )0x00000002; // ?
+    *tmpMsg << ( u16 )0x0004; // ?
+    *tmpMsg << nRawObjectID;
+    // *tmpMsg << (u8)0x13; // ? Seems we can do without...
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildVhcAccessRequestMsg( PClient* nClient, u32 nRequestId, u32 nRequesterCharId, u32 nRequesterLocalId, u32 nVhcRawObjectID )
+{
+    PMessage* tmpMsg = new PMessage( 40 );
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+
+    *tmpMsg << ( u8 )0x22; // Message length;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x3d;
+    *tmpMsg << ( u32 )0x00000008; // cmd
+    *tmpMsg << ( u32 )0x00000005; // cmd ?
+    *tmpMsg << ( u32 )nRequestId;
+    *tmpMsg << ( u16 )0x000c; // ? length ?
+    *tmpMsg << nRequesterCharId; //u32
+    *tmpMsg << nRequesterLocalId; // ? u32
+    *tmpMsg << nVhcRawObjectID;
+    *tmpMsg << ( u8 )0x08; // ?
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+/* S->C
+13:ff:00:72:d6:22:
+03:ff:00:1f:03:00:
+3d:
+08:00:00:00:
+05:00:00:00:
+01:00:00:00:
+0c:00:
+2f:d8:01:00:
+02:00:00:00:
+5d:03:00:00:
+08:
+*/
+
+/* C->S RESP: OK
+13:79:00:ec:d5:17:
+03:79:00:1f:03:00:
+3d:
+09:00:00:00:
+06:00:00:00:
+02:00:00:00:
+01:00:
+01:00
+*/
+/* C->S RESP: NOK
+13:74:00:e7:d5:17:
+03:74:00:1f:03:00:
+3d:
+09:00:00:00:
+06:00:00:00:
+01:00:00:00:
+01:00:
+00:00
+
+*/
+
+PMessage* PMsgBuilder::BuildCharUseGenrepMsg( PClient* nClient, u32 nRawObjectID, u32 nLocation, u16 nEntity )
+{
+    PMessage* tmpMsg = new PMessage( 24 );
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+
+    *tmpMsg << ( u8 )0x06; // SubMessage length;
+    *tmpMsg << ( u8 )0x2d;
+    *tmpMsg << ( u32 )nRawObjectID;
+    *tmpMsg << ( u8 )0x0a;
+
+    // this submessage is only needed to set to location/entity of the GR for a potential record in the char's GR list
+    *tmpMsg << ( u8 )0x0d; // SubMessage length;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x2d;
+    *tmpMsg << ( u32 )nLocation;
+    *tmpMsg << ( u16 )nEntity;
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharUseLiftMsg( PClient* nClient, u32 nRawObjectID, u16 nAptPlace )
+{
+    PMessage* tmpMsg = new PMessage( 29 );
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+
+    *tmpMsg << ( u8 )0x06; // SubMessage length;
+    *tmpMsg << ( u8 )0x2d;
+    *tmpMsg << ( u32 )nRawObjectID;
+    *tmpMsg << ( u8 )0x0a;
+
+    *tmpMsg << ( u8 )0x11; // SubMessage length;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x38;
+    *tmpMsg << ( u8 )0x01;
+    *tmpMsg << ( u32 )nRawObjectID;
+    *tmpMsg << ( u16 )nAptPlace;
+    *tmpMsg << ( u16 )0x0000;
+    *tmpMsg << ( u8 )0x00;
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharShowGlowCircleMsg( PClient* nClient )
+{
+    PMessage* tmpMsg = new PMessage( 14 );
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; // UDP ID placeholder
+    *tmpMsg << ( u16 )0x0000; // SessionID placeholder
+    *tmpMsg << ( u8 )0x08;  // Len (static, always 0x08
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )0x0000; // Sub UDP ID placeholder
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x3c; // Command SHOW GLOWING CIRCLE (kinda ^^)
+    *tmpMsg << ( u8 )0x01; // "on" ?
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharMoneyUpdateMsg( PClient* nClient, u32 nCredits )
+{
+    PMessage* tmpMsg = new PMessage( 21 );
+    nClient->IncreaseUDP_ID();
+    nClient->IncreaseTransactionID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x0f; // Message length
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x25; // cmd
+    *tmpMsg << ( u8 )0x13; // cmd
+    *tmpMsg << ( u16 )nClient->GetTransactionID();
+    *tmpMsg << ( u8 )0x04; // cmd
+    *tmpMsg << nCredits;
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildUndefineduseMsg( PClient* nClient, u8 nValue )
+{
+    PMessage* tmpMsg = new PMessage( 15 );
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x09; // Message length
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x25;
+    *tmpMsg << ( u8 )0x23;
+    *tmpMsg << nValue;
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharUseQBSlotMsg2( PClient* nClient, u16 nV1, u16 nV2, u16 nV3, u16 nV4, u16 nV5, u16 nV6, u16 nV7 )
+{
+    // lol? Whats this?
+    PMessage* tmpMsg = new PMessage( 28 );
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x16; // Message length
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x25; // cmd
+    *tmpMsg << ( u8 )0x22; // cmd
+    *tmpMsg << nV1;
+    *tmpMsg << nV2;
+    *tmpMsg << nV3;
+    *tmpMsg << nV4;
+    *tmpMsg << nV5;
+    *tmpMsg << nV6;
+    *tmpMsg << nV7;
+    /* *tmpMsg << (u8)0x64; // ??
+     *tmpMsg << (u8)0x00; // ??
+     *tmpMsg << (u8)0x64; // ??
+     *tmpMsg << (u8)0x00; // ??
+     *tmpMsg << (u8)0x64; // ??
+     *tmpMsg << (u8)0x00; // ??
+     *tmpMsg << (u8)0x64; // ??
+     *tmpMsg << (u8)0x00; // ??
+     *tmpMsg << (u8)0x64; // ??
+     *tmpMsg << (u8)0x00; // ??
+     *tmpMsg << (u8)0x64; // ??
+     *tmpMsg << (u8)0x00; // ??
+     *tmpMsg << (u8)0x00; // ??
+     *tmpMsg << (u8)0x00; // ??
+    */
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharUseQBSlotMsg3( PClient* nClient, u8 nSlot )
+{
+    PMessage* tmpMsg = new PMessage( 19 );
+    nClient->IncreaseUDP_ID();
+    nClient->IncreaseTransactionID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x0d; // Message length
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x25; // cmd
+    *tmpMsg << ( u8 )0x13; // cmd
+    *tmpMsg << ( u16 )nClient->GetTransactionID();
+    *tmpMsg << ( u8 )0x0b; // cmd
+    *tmpMsg << nSlot; // ??
+    *tmpMsg << ( u8 )0x00; // ??
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharUseQBSlotMsg4( PClient* nClient, u16 nWeaponId )
+{
+    PMessage* tmpMsg = new PMessage( 16 );
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x0a; // Message length
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x2f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x02; // ??
+    *tmpMsg << ( u8 )0x02; // ??
+    *tmpMsg << nWeaponId;
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildContainerContentList( PContainer* nContainer, u8 nLocType )
+{
+    PMessage* tmpMsg = new PMessage( 256 );
+    std::vector< PContainerEntry* >* Entries = nContainer->GetEntries();
+    PContainerEntry* tEntry;
+    PMessage* entryMsg;
+
+//Console->Print(YELLOW, BLACK, "BuildContainerContentList for loc %d", nLocType);
+    if ( nLocType != INV_LOC_BOX )
+    {
+        if ( nLocType == INV_LOC_BACKPACK )
+            *tmpMsg << ( u16 )Entries->size(); // items nb
+        else
+            *tmpMsg << ( u8 )Entries->size(); // items nb
+    }
+
+    for ( u16 i = 0; i < Entries->size(); ++i )
+    {
+        tEntry = Entries->at( i );
+        entryMsg = BuildContainerContentEntry( tEntry, nLocType );
+//if(tEntry->mItem->mItemID == 390)
+//{
+//Console->Print(YELLOW, BLACK, "BuildContainerContentList entry %d - size %d", i, entryMsg->GetSize());
+//entryMsg->Dump();
+//}
+        *tmpMsg << *entryMsg;
+        delete entryMsg;
+    }
+
+    delete Entries;
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildContainerContentEntry( PContainerEntry* nEntry, u8 nLocType )
+{
+    PMessage* tmpMsg = new PMessage( 16 );
+    PItem* tItem;
+    u8 dataFlags, Qualifier;
+
+    tItem = nEntry->mItem;
+    dataFlags = Qualifier = 0x00 ;
+
+    if (( tItem->mItemID == 390 ) /* testing */ || tItem->mLoadedAmmoNb )
+    {
+        dataFlags |= 0x01;
+    }
+    if (( tItem->GetType() == ITEM_TYPE_WEAPON ) || ( tItem->GetType() == ITEM_TYPE_BLUEPRINT ) || ( tItem->GetType() == ITEM_TYPE_WRECKEDPART )/*|| (tItem->GetType() == ITEM_TYPE_APARTMENTKEY) || (tItem->GetType() == ITEM_TYPE_CLANKEY) || (tItem->GetType() == ITEM_TYPE_VHCKEY) */ ) // testing loaded ammo type & BP attributes
+    {
+        dataFlags |= 0x20;
+    }
+
+    switch ( tItem->GetType() )
+    {
+    case ITEM_TYPE_WEAPON:
+    case ITEM_TYPE_AUTOWEAPON:
+        Qualifier = 6;
+        dataFlags |= 0x02;
+        break;
+    case ITEM_TYPE_IMPLANT:
+    case ITEM_TYPE_ARMOR:
+        Qualifier = 2;
+        dataFlags |= 0x02;
+        break;
+    default:
+        Qualifier = 0;
+        break;
+    }
+
+    if ( tItem->IsStackable() && tItem->mStackSize )
+    {
+        dataFlags |= 0x04;
+    }
+
+    if (( tItem->mModificators ) || ( tItem->mItemID == 390 ) ) // TEST
+        dataFlags |= 0x10;
+
+    if ( tItem->mMaxSlots || ( tItem->mItemID == 390 ) ) // TEST
+        dataFlags |= 0x40;
+
+
+
+    if ( nLocType == INV_LOC_BOX )
+        *tmpMsg << ( u8 )0x00;   // Size of item placeholder
+    else
+        *tmpMsg << ( u16 )0x0000;   // Size of item placeholder
+
+    switch ( nLocType )
+    {
+    case INV_LOC_WORN:
+        *tmpMsg << ( u8 )nEntry->mPosX; // X Location
+        *tmpMsg << ( u8 )0x00; // just nothing
+        break;
+    case INV_LOC_BACKPACK:
+        *tmpMsg << ( u8 )0x00; // just nothing again
+        *tmpMsg << ( u8 )nEntry->mPosX; // X Location
+        *tmpMsg << ( u8 )nEntry->mPosY; // Y Location
+        break;
+    case INV_LOC_GOGO:
+        *tmpMsg << ( u8 )nEntry->mPosX;
+        break;
+    case INV_LOC_BOX:
+    case INV_LOC_BOX2:
+        break;
+    default:
+        break;
+    }
+
+    *tmpMsg << ( u16 )tItem->mItemID; // ItemID
+    *tmpMsg << ( u8 )dataFlags; // (0x01|0x02|0x04|0x10|0x20|0x40|0x80); // Datatypes
+
+    if ( dataFlags & 0x01 )
+    {
+        if ( tItem->GetType() == ITEM_TYPE_WEAPON ) // TESTING
+            *tmpMsg << ( u8 )6; // Remaining ammos
+        else
+            *tmpMsg << ( u8 )tItem->mLoadedAmmoNb; // Remaining ammos
+    }
+
+    if ( dataFlags & 0x02 )
+    {
+        *tmpMsg << ( u8 )Qualifier; // Qual entries
+        if ( Qualifier >= 2 )
+        {
+            *tmpMsg << ( u8 )tItem->mCurDuration; // current qual
+            if ( Qualifier == 6 )
+            {
+                *tmpMsg << ( u8 )tItem->mDamages; // dmg
+                *tmpMsg << ( u8 )tItem->mFrequency; // freq
+                *tmpMsg << ( u8 )tItem->mHandling; // handl
+                *tmpMsg << ( u8 )tItem->mRange; // range
+            }
+            *tmpMsg << ( u8 )tItem->mMaxDuration; // max qual
+        }
+    }
+
+    if ( dataFlags & 0x10 )
+    {
+        if ( tItem->mItemID == 390 ) // test
+            *tmpMsg << ( u8 )4;
+        else
+            *tmpMsg << ( u8 )tItem->mModificators; // addons bitflag: flashlight=1, scope, silencer, laserpointer
+    }
+
+    if ( dataFlags & 0x40 )
+    {
+        if ( tItem->mItemID == 390 ) // test
+        {
+            *tmpMsg << ( u8 )3;
+            *tmpMsg << ( u8 )3;
+            *tmpMsg << ( u16 )0x000b; // enlarged
+            *tmpMsg << ( u16 )0x05de; // phosophore
+            *tmpMsg << ( u16 )( -3 ); // silencer
+        }
+        else
+        {
+
+            *tmpMsg << ( u8 )tItem->mUsedSlots; // used slots
+            *tmpMsg << ( u8 )tItem->mMaxSlots; // max slots
+            for ( u8 j = 0; j < tItem->mMaxSlots; ++j )
+                *tmpMsg << ( u16 )(( j < tItem->mUsedSlots ) ? tItem->mSlot[j] : 0 ); // mod in slot
+        }
+    }
+
+    if ( dataFlags & 0x20 ) // loaded ammo type ????
+    {
+        u16 lengthFieldOffset = tmpMsg->GetNextByteOffset();
+        *tmpMsg << ( u16 )0x0000; // length placeholder
+
+        if ( tItem->GetType() == ITEM_TYPE_WEAPON )
+        {
+            *tmpMsg << ( u8 )0x01; // ammo info
+            *tmpMsg << ( u8 )0x04; // total length ?
+            *tmpMsg << ( u8 )0x00; // + baseammo => current ammoId. 0xff => undefined
+            *tmpMsg << ( u8 )0xff; // supported ammos bitmap (all here)
+        }
+
+        if ( false && ( tItem->GetType() == ITEM_TYPE_APARTMENTKEY ) ) // activated Apartment key
+        {
+            *tmpMsg << ( u8 )0x02; // ammo info
+            *tmpMsg << ( u8 )0x06; // total length
+            *tmpMsg << ( u32 )123456; // apartmentObjectID ?
+        }
+
+        if ( false && ( tItem->GetType() == ITEM_TYPE_CLANKEY ) ) // activated ClanKey
+        {
+            *tmpMsg << ( u8 )0x04; // BP of... info
+            *tmpMsg << ( u8 )0x0a; // total length
+            *tmpMsg << ( u32 )1234; // ClanID ?
+            *tmpMsg << ( u32 )123456; // apartmentObjectID ?
+        }
+
+        if ( tItem->GetType() == ITEM_TYPE_BLUEPRINT ) // BP
+        {
+            *tmpMsg << ( u8 )0x05; // BP of... info
+            *tmpMsg << ( u8 )0x06; // total length
+            *tmpMsg << ( u32 )486; // ItemID ("Tangent Sniper Rifle")
+        }
+
+        if ( false && ( tItem->GetType() == ITEM_TYPE_VHCKEY ) ) // activated VHC Key
+        {
+            *tmpMsg << ( u8 )0x08; // VHC Key
+            *tmpMsg << ( u8 )0x0a; // total length
+            *tmpMsg << ( u32 )654321; // vhcObjectID ?
+            *tmpMsg << ( u32 )123456; // Owner CharID ?
+        }
+
+        if ( false && ( tItem->GetType() == ITEM_TYPE_WRECKEDPART ) ) // Identified rare part
+        {
+            *tmpMsg << ( u8 )0x09; // Rare part
+            *tmpMsg << ( u8 )0x05; // total length
+            *tmpMsg << ( u16 )453; // Rare Item ID ? REDEEMER
+            *tmpMsg << ( u8 )0; // ??
+        }
+
+        if (( tItem->mConstructorId ) || ( tItem->mItemID == 390 ) ) // Named item /itemId 390: test
+        {
+            *tmpMsg << ( u8 )0x0a; // constructor info
+            *tmpMsg << ( u8 )0x06; // total length
+            //*tmpMsg << (u32)tItem->mConstructorId; // charID
+            *tmpMsg << ( u32 )2;
+        }
+
+        tmpMsg->U16Data( lengthFieldOffset ) = tmpMsg->GetNextByteOffset() - lengthFieldOffset - 2;
+    }
+
+    if ( dataFlags & 0x04 )
+    {
+        *tmpMsg << ( u32 )tItem->mStackSize;
+    }
+
+
+    if ( nLocType == INV_LOC_BOX )
+        tmpMsg->U8Data( 0 ) = tmpMsg->GetSize() - 1;
+    else
+        tmpMsg->U16Data( 0 ) = tmpMsg->GetSize() - 2;
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharOpenContainerMsg( PClient* nClient, u32 nContainerID, PContainer* nContainer )
+{
+    PMessage* ContentList = BuildContainerContentList( nContainer, INV_LOC_BOX );
+
+    PMessage* tmpMsg = new PMessage();
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x00; // Message length
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x26;
+    *tmpMsg << nContainerID;
+    *tmpMsg << ( u8 )0x00; // Always the same on item containers? // 0x01 for Trader (NeoX gameclient 3608)
+    *tmpMsg << ( u8 )0x64; // Always the same on item containers?
+    *tmpMsg << ( u8 )0x00; // Always the same on item containers?
+    *tmpMsg << ( u8 )0x08; // 0x08 when container is filled, 0x00 when not? At least it works..
+
+    *tmpMsg << ( u16 )( ContentList->GetSize() );
+    *tmpMsg << *ContentList;
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    delete ContentList;
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildItemMoveMsg( PClient* nClient, u8 nSource, u8 nSrcX, u8 nSrcY, u8 nDestination, u8 nDestX, u8 nDestY, u8 nItemCnt )
+{
+    PMessage* tmpMsg = new PMessage( 26 );
+    nClient->IncreaseUDP_ID();
+    nClient->IncreaseTransactionID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x14; // Message length
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x25;
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetTransactionID();
+    *tmpMsg << ( u8 )0x14; // ItemMove Answer
+    *tmpMsg << nSource;
+    *tmpMsg << nSrcX;
+    *tmpMsg << nSrcY;
+    *tmpMsg << nDestination;
+    *tmpMsg << nDestX;
+    *tmpMsg << nDestY;
+    *tmpMsg << nItemCnt;
+    *tmpMsg << ( u8 )0x00; // ??
+    *tmpMsg << ( u8 )0x00; // ??
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildBoxItemMoveMsg( PClient* nClient, PContainerEntry* nEntry, u8 nSrcX, u8 nSrcY, u8 nDestination, u8 nDestX, u8 nDestY, u8 nItemCnt )
+{
+    PMessage* tmpMsg = new PMessage( 64 );
+    PMessage* entryMsg = BuildContainerContentEntry( nEntry, INV_LOC_BOX2 );
+
+    nClient->IncreaseUDP_ID();
+    nClient->IncreaseTransactionID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+
+    *tmpMsg << ( u8 )0x09; // Message length
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x25;
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetTransactionID();
+    *tmpMsg << ( u8 )0x17; // BoxItemMove Answer Src
+    *tmpMsg << ( u8 )INV_LOC_BOX; // Src = Box
+    *tmpMsg << nSrcX;
+    *tmpMsg << nSrcY;
+    *tmpMsg << nItemCnt;
+    *tmpMsg << ( u8 )0x00; // Qty high
+    *tmpMsg << ( u8 )0x18; // BoxItemMove Answer Dst
+    *tmpMsg << nDestination;
+    *tmpMsg << nDestX;
+    *tmpMsg << nDestY;
+    *tmpMsg << *entryMsg;
+    *tmpMsg << ( u8 )0x12; // ? vary ...
+    *tmpMsg << ( u8 )0x00;
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    delete entryMsg;
+    return tmpMsg;
+}
+
+/*PMessage* PMsgBuilder::BuildItemAmmoUpdateMsg (PClient* nClient, PContainerEntry* nEntry, u8 nSrcX, u8 nSrcY, u8 nDestination, u8 nDestX, u8 nDestY, u8 nItemCnt)
+{
+  PMessage* tmpMsg = new PMessage(64);
+  PMessage* entryMsg = BuildContainerContentEntry(nEntry, INV_LOC_BOX2);
+
+  nClient->IncreaseUDP_ID();
+  nClient->IncreaseTransactionID();
+
+  *tmpMsg << (u8)0x13;
+  *tmpMsg << (u16)nClient->GetUDP_ID();
+  *tmpMsg << (u16)nClient->GetSessionID();
+
+  *tmpMsg << (u8)0x09; // Message length
+  *tmpMsg << (u8)0x03;
+  *tmpMsg << (u16)nClient->GetUDP_ID();
+  *tmpMsg << (u8)0x1f;
+  *tmpMsg << (u16)nClient->GetLocalID();
+  *tmpMsg << (u8)0x25;
+  *tmpMsg << (u8)0x13;
+  *tmpMsg << (u16)nClient->GetTransactionID();
+  *tmpMsg << (u8)0x17; // BoxItemMove Answer Src
+  *tmpMsg << (u8)INV_LOC_BOX; // Src = Box
+  *tmpMsg << nSrcX;
+  *tmpMsg << nSrcY;
+  *tmpMsg << nItemCnt;
+  *tmpMsg << (u8)0x00; // Qty high
+  *tmpMsg << (u8)0x18; // BoxItemMove Answer Dst
+  *tmpMsg << nDestination;
+  *tmpMsg << nDestX;
+  *tmpMsg << nDestY;
+  *tmpMsg << *entryMsg;
+  *tmpMsg << (u8)0x12; // ? vary ...
+  *tmpMsg << (u8)0x00;
+
+  (*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6);
+
+  delete entryMsg;
+  return tmpMsg;
+}*/
+/* Resp:
+03:33:00:1f:01:00:25:13
+c2:01:0a:00:02:00:00:00 ??
+c3:01:05:03:00:00:12 Update ammo left
+c4:01:05:02:00:00:0c Update ammo left
+*/
+
+PMessage* PMsgBuilder::BuildStartHackGameMsg( PClient* nClient, u32 nWorldObjID, u8 nHackDifficult )
+{
+    PMessage* tmpMsg = new PMessage( 22 );
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x10;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x28;
+    *tmpMsg << nWorldObjID;
+    *tmpMsg << nHackDifficult;
+    *tmpMsg << ( u8 )0x28;
+    *tmpMsg << ( u8 )0x5c;
+    *tmpMsg << ( u8 )0xcf;
+    *tmpMsg << ( u8 )0x3e;
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildSubwaySpawnMsg( PClient* nClient, bool IsSecondMessage )
+{
+    PMessage* tmpMsg = new PMessage( 197 );
+    u16 First = IsSecondMessage ? 6 : 0;
+    u16 Last = IsSecondMessage ? 10 : 5;
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; // placeholder for UDP_ID;
+    *tmpMsg << ( u16 )0x0000; // placeholder for SessionID();
+
+    for ( u16 i = First; ( i <= Last ); i++ )
+    {
+        nClient->IncreaseUDP_ID();
+        *tmpMsg << ( u8 )0x11; //msg size
+        *tmpMsg << ( u8 )0x03;
+        *tmpMsg << ( u16 )nClient->GetUDP_ID();
+        *tmpMsg << ( u8 )0x28;
+        *tmpMsg << ( u16 )0x0027;
+        *tmpMsg << ( u32 )( PSubway::mCabsBaseId + i );
+        *tmpMsg << ( u16 )0x0000;
+        *tmpMsg << ( u8 )0x00;
+        *tmpMsg << ( u16 )Subway->mSubways[i].mPosition;
+        *tmpMsg << ( u8 )0x00;
+        *tmpMsg << ( u8 )Subway->mSubways[i].mDoorOpened;;
+
+        nClient->IncreaseUDP_ID(); // vhc health update
+        *tmpMsg << ( u8 )0x0d; //msg size
+        *tmpMsg << ( u8 )0x03;
+        *tmpMsg << ( u16 )nClient->GetUDP_ID();
+        *tmpMsg << ( u8 )0x2d;
+        *tmpMsg << ( u32 )( PSubway::mCabsBaseId + i );
+        *tmpMsg << ( u8 )0x0a;
+        *tmpMsg << ( u32 )PSubway::mCabsBaseHealth;
+    }
+
+    tmpMsg->U16Data( 1 ) = nClient->GetUDP_ID();
+    tmpMsg->U16Data( 3 ) = nClient->GetSessionID();
+
+    return tmpMsg;
+}
+
+/*
+PMessage* PMsgBuilder::BuildSubwayFullUpdateMsg(PClient* nClient)
+{
+    PMessage* tmpMsg = new PMessage(148);
+    *tmpMsg << (u8)0x13;
+    *tmpMsg << (u16)0x0000; // placeholder for UDP_ID;
+    *tmpMsg << (u16)0x0000; // placeholder for SessionID();
+
+    for(u8 i=0; i<PSubway::mCabsNumber; i++)
+    {
+      nClient->IncreaseUDP_ID();
+      *tmpMsg << (u8)0x0c; //msg size
+      *tmpMsg << (u8)0x03;
+      *tmpMsg << (u16)nClient->GetUDP_ID();
+      *tmpMsg << (u8)0x32;
+      *tmpMsg << (u32)(PSubway::mCabsBaseId + i);
+      *tmpMsg << (u8)0x00;
+      *tmpMsg << (u16)Subway->mSubways[i].mPosition;
+      *tmpMsg << (u8)Subway->mSubways[i].mDoorOpened;;
+  }
+
+    tmpMsg->U16Data(1) = nClient->GetUDP_ID();
+    tmpMsg->U16Data(3) = nClient->GetSessionID();
+
+    return tmpMsg;
+}
+*/
+
+PMessage* PMsgBuilder::BuildSubwaySingleUpdateMsg( u32 nVehicleID, u16 nPosition, u8 nDoorOpened )
+{
+    PMessage* tmpMsg = new PMessage( 18 );
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; // placeholder for UDP_ID;
+    *tmpMsg << ( u16 )0x0000; // placeholder for SessionID();
+
+    *tmpMsg << ( u8 )0x0c; //msg size
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )0x0000; // ++UDP_ID placeholder
+    *tmpMsg << ( u8 )0x32;
+    *tmpMsg << ( u32 )nVehicleID;
+    *tmpMsg << ( u8 )0x00;
+    *tmpMsg << ( u16 )nPosition;
+    *tmpMsg << ( u8 )nDoorOpened;
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildSpawnWorldObjectMsg( u16 nModelID, u16 nFunctionID, u32 nWOID, u16 nPosX, u16 nPosY, u16 nPosZ, u8 nRotX, u8 nRotY, u8 nRotZ )
+{
+    PMessage* tmpMsg = new PMessage( 31 );
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; // UDP placeholder
+    *tmpMsg << ( u16 )0x0000; // Session placeholder
+    *tmpMsg << ( u8 )0x16;  // Message length
+    *tmpMsg << ( u8 )0x03;  // 0x03 commandset
+    *tmpMsg << ( u16 )0x0000; // UDP placeholder
+    *tmpMsg << ( u8 )0x1b;  // Subcommandset
+    *tmpMsg << ( u32 )nWOID;  // WorldobjectID
+
+    *tmpMsg << ( u8 )0x19;  // Positiondata follows
+    *tmpMsg << ( u16 )nPosY;
+    *tmpMsg << ( u16 )nPosZ;
+    *tmpMsg << ( u16 )nPosX;
+    *tmpMsg << ( u8 )nRotY;  // Rotation X
+    *tmpMsg << ( u8 )nRotZ;  // Rotation Y
+    *tmpMsg << ( u8 )nRotX;  // Rotation Z
+    *tmpMsg << ( u16 )nModelID;
+    *tmpMsg << ( u16 )nFunctionID;
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildRemoveWorldObjectMsg( u32 nWOID )
+{
+    PMessage* tmpMsg = new PMessage( 14 );
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; // UDP ID placeholder
+    *tmpMsg << ( u16 )0x0000; // SessionID placeholder
+    *tmpMsg << ( u8 )0x08;  // Len (static, always 0x08
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )0x0000; // Sub UDP ID placeholder
+    *tmpMsg << ( u8 )0x26;  // Command FADE AWAY CHAR (kinda ^^)
+    *tmpMsg << ( u32 )nWOID;  // WorldobjectID
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildDBRequestStatusMsg( PClient* nClient, std::string* nCommandName, u8 nStatus, u16 nErrCode )
+{
+    PMessage* tmpMsg = new PMessage( 32 );
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x14; // Message length
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x2b;
+    *tmpMsg << ( u8 )0x1a;
+    *tmpMsg << ( u16 )( nCommandName->size() + 1 );
+    *tmpMsg << ( u8 )nStatus;
+    *tmpMsg << ( u16 )nErrCode;
+    *tmpMsg << ( *nCommandName );
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildDBAnswerMsg( PClient* nClient, std::string* nCommandName, std::string* nAnswerData, u16 nRows, u16 nCols )
+{
+    u8 i, j, k;
+    PMessage* tmpMsg = new PMessage( 32 );
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x14; // Message length
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x2b;
+    *tmpMsg << ( u8 )0x17;
+    *tmpMsg << ( u16 )( nCommandName->size() + 1 );
+    *tmpMsg << ( u16 )nRows;
+    *tmpMsg << ( u16 )nCols;
+    *tmpMsg << ( *nCommandName );
+
+    for ( i = 0, k = 0; i < nRows; ++i )
+    {
+        for ( j = 0; j < nCols; ++j, ++k )
+        {
+            *tmpMsg << ( u16 )( nAnswerData[k].size() + 1 );
+            *tmpMsg << nAnswerData[k];
+        }
+    }
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharUseVhcMsg( PClient* nClient, u32 nRawObjectID, u16 nVhcType, u16 nAvailableSeats )
+{
+    PMessage* tmpMsg = new PMessage( 24 );
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+
+    *tmpMsg << ( u8 )0x13; // Message length;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x3d;
+    *tmpMsg << ( u32 )0x0000000e; // cmd
+    *tmpMsg << nRawObjectID;
+    *tmpMsg << nVhcType;
+    *tmpMsg << nAvailableSeats; // Bit flags
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildVhcInfoMsg( PClient* nClient, PSpawnedVehicle* nVehicle )
+{
+    PMessage* tmpMsg = new PMessage( 32 );
+    PVhcCoordinates VhcPos = nVehicle->GetPosition();
+    PVehicleInformation VhcInfo = nVehicle->GetInformation();
+
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+
+    *tmpMsg << ( u8 )0x00; // Message length placeholder;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x28;
+    *tmpMsg << ( u16 )0x0031;
+    *tmpMsg << ( u32 )nVehicle->GetLocalId();
+    *tmpMsg << ( u8 )0x02;
+    *tmpMsg << ( u16 )( VhcPos.GetY() + 768 );
+    *tmpMsg << ( u16 )( VhcPos.GetZ() + 768 );
+    *tmpMsg << ( u16 )( VhcPos.GetX() + 768 );
+    *tmpMsg << ( u8 )VhcPos.GetUD();
+    *tmpMsg << ( u16 )VhcPos.GetLR();
+    *tmpMsg << ( u16 )VhcPos.GetRoll();
+    *tmpMsg << ( u8 )VhcInfo.GetVehicleType();
+    *tmpMsg << ( u8 )0xff;
+    *tmpMsg << ( u32 )0x00000000;
+    *tmpMsg << ( u16 )0x0000;
+    *tmpMsg << ( u8 )0x00;
+    *tmpMsg << ( u8 )0x01; // ? changes
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+/*PMessage* PMsgBuilder::BuildVhcInfoMsg( PClient* nClient, PSpawnedVehicle* nVehicle )
+{
+  PMessage* tmpMsg = new PMessage( 32 );
+  PVhcCoordinates VhcPos = nVehicle->GetPosition();
+  PVehicleInformation VhcInfo = nVehicle->GetInformation();
+
+  nClient->IncreaseUDP_ID();
+
+  *tmpMsg << ( u8 )0x13;
+  *tmpMsg << ( u16 )nClient->GetUDP_ID();
+  *tmpMsg << ( u16 )nClient->GetSessionID();
+
+  *tmpMsg << ( u8 )0x00; // Message length placeholder;
+  *tmpMsg << ( u8 )0x03;
+  *tmpMsg << ( u16 )nClient->GetUDP_ID();
+  *tmpMsg << ( u8 )0x28;
+  *tmpMsg << ( u16 )0x0031;
+  *tmpMsg << ( u32 )nVehicle->GetLocalId();
+  *tmpMsg << ( u8 )0x02;
+  *tmpMsg << ( u16 )( VhcPos.GetY() + 768 );
+  *tmpMsg << ( u16 )( VhcPos.GetZ() + 768 );
+  *tmpMsg << ( u16 )( VhcPos.GetX() + 768 );
+  *tmpMsg << ( u8 )VhcPos.GetUD();
+  *tmpMsg << ( u16 )VhcPos.GetLR();
+  *tmpMsg << ( u16 )VhcPos.GetRoll();
+  *tmpMsg << ( u8 )VhcInfo.GetVehicleType();
+  *tmpMsg << ( u32 )0x00000000;
+  *tmpMsg << ( u32 )0x00000000;
+  *tmpMsg << ( u32 )0x00000000;
+  *tmpMsg << ( u16 )0x0000;
+  u32 tCharId;
+  for(u8 i = 0; i < 8; ++i)
+  {
+    if( (tCharId = nVehicle->GetSeatUser(i)) )
+    {
+      *tmpMsg << tCharId;
+    }
+    else
+    {
+      *tmpMsg << ( u32 )0xffffffff;
+    }
+    *tmpMsg << i;
+    *tmpMsg << ( u16 )0x0000;
+  }
+
+  ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+  return tmpMsg;
+}*/
+/* ????
+13 f7 00 49 bf
+5d
+03 f7 00
+28 31 00
+c9 03 00 00 = Object ID
+02
+47 ff
+00 cd
+c3 c3
+d7
+d7 ec
+00 00
+29
+2b 65 35 8b 8c 6c 7f 80 96
+5f 26 00 80 00
+ff ff ff ff 00 00 00
+ff ff ff ff 01 00 00
+ff ff ff ff 02 00 00
+ff ff ff ff 03 00 00
+ff ff ff ff 04 00 00
+ff ff ff ff 05 00 00
+ff ff ff ff 06 00 00
+ff ff ff ff 07 00 00
+
+*/
+
+PMessage* PMsgBuilder::BuildVhcHealthUpdateMsg( PSpawnedVehicle* nVehicle )
+{
+    PMessage* tmpMsg = new PMessage( 19 );
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; // placeholder for UDP_ID;
+    *tmpMsg << ( u16 )0x0000; // placeholder for SessionID();
+
+    *tmpMsg << ( u8 )0x0d; //msg size
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )0x0000; // placeholder for ++UDP_ID
+    *tmpMsg << ( u8 )0x2d;
+    *tmpMsg << ( u32 )nVehicle->GetLocalId();
+    *tmpMsg << ( u8 )0x0a; // Health update
+    *tmpMsg << ( f32 )( nVehicle->GetInformation().GetHealth() );
+
+    return tmpMsg;
+}
+
+// NB: same as BuildCharSittingMsg. To be merged later when classes are adapted
+PMessage* PMsgBuilder::BuildVhcPosUpdateMsg( PSpawnedVehicle* nVehicle )
+{
+    PMessage* tmpMsg = new PMessage( 33 );
+    PVhcCoordinates VhcPos = nVehicle->GetPosition();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; //Client->GetUDP_ID(); // just placeholder, must be set outside
+    *tmpMsg << ( u16 )0x0000;  // Client->GetSessionID(); // just placeholder, must be set outside
+
+    *tmpMsg << ( u8 )0x00; // Message length placeholder;
+    *tmpMsg << ( u8 )0x32;
+    *tmpMsg << ( u16 )( nVehicle->GetLocalId() & 0xffff );
+    *tmpMsg << ( u8 )0x03; // We suppose we use move type 3, as in client message
+    *tmpMsg << ( u16 )( VhcPos.GetY() + 768 ); // +768 or +0 ??? All Char/Vhc/NPC/Objet offset to clean up...
+    *tmpMsg << ( u16 )( VhcPos.GetZ() + 768 );
+    *tmpMsg << ( u16 )( VhcPos.GetX() + 768 );
+    *tmpMsg << ( u8 )VhcPos.GetUD();
+    *tmpMsg << ( u16 )VhcPos.GetLR();
+    *tmpMsg << ( u16 )VhcPos.GetRoll();
+    *tmpMsg << ( u16 )VhcPos.GetUnknown();
+    *tmpMsg << ( u8 )0x00;
+    *tmpMsg << ( u8 )VhcPos.GetAct();
+    /* What is that for ????
+    *tmpMsg << ( u8 )0x02; // <= these two u8 corresond to mUnknown... = additionnal data ?
+    *tmpMsg << ( u8 )0x00; // maybe weapon related ?
+    *tmpMsg << ( u16 )0x0000;
+    *tmpMsg << ( u16 )0x0001;
+    *tmpMsg << ( u16 )0x8000;
+    *tmpMsg << ( u16 )0x8000;
+    */
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildVhcPosUpdate2Msg( PSpawnedVehicle* nVehicle )
+{
+    PMessage* tmpMsg = new PMessage( 28 );
+    PVhcCoordinates VhcPos = nVehicle->GetPosition();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; // placeholder for UDP_ID;
+    *tmpMsg << ( u16 )0x0000; // placeholder for SessionID();
+
+    *tmpMsg << ( u8 )0x00; //msg size
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )0x0000; // ++UDP_ID placeholder
+    *tmpMsg << ( u8 )0x32;
+    *tmpMsg << ( u16 )( nVehicle->GetLocalId() & 0xffff );
+    *tmpMsg << ( u8 )0x03; // 0x07 in nc2.2, and one more field (same a received msg)
+    *tmpMsg << ( u16 )( VhcPos.GetY() + 768 ); // +768 or +0 ??? All Char/Vhc/NPC/Objet offset to clean up...
+    *tmpMsg << ( u16 )( VhcPos.GetZ() + 768 );
+    *tmpMsg << ( u16 )( VhcPos.GetX() + 768 );
+    *tmpMsg << ( u8 )VhcPos.GetUD();
+    *tmpMsg << ( u16 )VhcPos.GetLR();
+    *tmpMsg << ( u16 )VhcPos.GetRoll();
+    *tmpMsg << ( u16 )VhcPos.GetUnknown();
+    *tmpMsg << ( u8 )VhcPos.GetFF();
+    *tmpMsg << ( u8 )VhcPos.GetAct();
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+/*
+ground vhc in NC1
+C->S
+[...] 32:fb:03:03:d4:8c:2f:84:a0:7b:7b:bf:c6:53:28:01:00:ff:05
+S->C
+[...] 32: fb:03: 03: d4:8c: 2f:84: a0:7b: 7b: bf:c6: 53:28: 01:00:ff:05
+
+  *nMsg >> mVhcLocalId;
+  *nMsg >> mMoveType; // 0 for subway, 3 for nc1 vhc, 7 for nc2 vhc // u8
+  *nMsg >> mNewY;
+  *nMsg >> mNewZ;
+  *nMsg >> mNewX;
+  *nMsg >> mNewUD; // u8
+  *nMsg >> mNewLR;
+  *nMsg >> mNewRoll;
+  *nMsg >> mUnk1;
+  *nMsg >> mFF; // u8
+  *nMsg >> mAction; // u8
+
+quad in NC2.2
+C->S
+[...] 32:c9:03:07:28:65:35:8b:8c:6c:7f:09:99:45:26:10:80:01:00:ff:05
+S->C
+[...] 32:c9:03:07:28:65:35:8b:8c:6c:7f:09:99:45:26:10:80:01:00:ff:05
+
+glider in NC2.2
+C->S
+[...] 32:4b:03:07:13:57:a9:88:89:af:86:c1:89:ec:81:64:82:01:00:ff:00
+S->C
+[...] 32:4b:03:07:98:57:c8:88:59:b0:83:5c:88:13:81:64:82:01:00:ff:00:
+[...] 32:4b:03:07:13:57:a9:88:89:af:86:c1:89:ec:81:64:82:01:00:ff:00:
+
+
+*/
+PMessage* PMsgBuilder::BuildTraderItemListMsg( PClient* nClient, u32 nTraderNpcID ) //, PContainer* nContainer)
+{
+//    PMessage* ContentList = BuildContainerContentList(nContainer, INV_LOC_BOX);
+// Tmp manual content list:
+    PMessage* ContentList = new PMessage();
+    f32 PriceCoef = 1 / 1.379942;
+    u8 Quality = 255; // Range 0 - 255
+
+    //Item 1:
+    *ContentList << ( u16 )0x05e6; // Item Id "Clan key for CityAdmin"
+    *ContentList << ( u32 )304567; // Base (?) Item price = item.def price / 1.97
+    // Displayed price is this price * 1.38 . Is this faction/barter factor ?
+    //Item 2:
+    *ContentList << ( u16 )0x05e7; // Item Id "Clan key for Diamond Real Estate"
+    *ContentList << ( u32 )( 420285 * PriceCoef );
+    //Item 3:
+    *ContentList << ( u16 )0x05e8; // Item Id "Clan key for N.E.X.T."
+    *ContentList << ( u32 )( 420285 * PriceCoef );
+    //Item 4:
+    *ContentList << ( u16 )0x060f; // Item Id "PLAZA - 2nd Lev. Apartment"
+    *ContentList << ( u32 )( 245166 * PriceCoef );
+    //Item 5:
+    *ContentList << ( u16 )0x065c; // Item Id "Normal Viarosso Apartment Alamo Living"
+    *ContentList << ( u32 )( 840571 * PriceCoef );
+    //Item 6:
+    *ContentList << ( u16 )0x065d; // Item Id "Luxus Viarosso Apartment Alamo Living"
+    *ContentList << ( u32 )( 1260856 * PriceCoef );
+
+    //Item 7:
+    *ContentList << ( u16 )355; // Item Id "HEW ï¿½Liquid Fire� Rifle"
+    *ContentList << ( u32 )( 1260856 * PriceCoef );
+
+    PMessage* tmpMsg = new PMessage();
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x00; // Message length
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x26;
+    *tmpMsg << nTraderNpcID;
+    *tmpMsg << ( u8 )0x01; // Traders inventory
+    *tmpMsg << ( u16 )( ContentList->GetSize() / 6 ); // List entries
+    *tmpMsg << ( u8 )Quality; // Items quality
+    *tmpMsg << *ContentList;
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    delete ContentList;
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildStartWeaponReloadMsg( PClient* nClient )
+{
+    PMessage* tmpMsg = new PMessage( 16 );
+    nClient->IncreaseUDP_ID();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u16 )nClient->GetSessionID();
+    *tmpMsg << ( u8 )0x00; // Message length
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )nClient->GetUDP_ID();
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x25; // cmd
+    *tmpMsg << ( u8 )0x16; // cmd
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildStartWeaponReloadAnimMsg( PClient* nClient )
+{
+    PMessage* tmpMsg = new PMessage( 13 );
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; // placeholder for UDP_ID;
+    *tmpMsg << ( u16 )0x0000; // placeholder for SessionID();
+
+    *tmpMsg << ( u8 )0x00;  // Message length placeholder;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )0x0000; // placeholder for UDP_ID;
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u8 )0x15; // cmd
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildHeldItemUseMsg( u16 nUserCharLocalId, u16 nWeaponId, u32 nTargetRawItemID, u8 nAiming, u8 nTargetedHeight, u8 nScore )
+{
+    PMessage* tmpMsg = new PMessage( 22 );
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; // placeholder for UDP_ID;
+    *tmpMsg << ( u16 )0x0000; // placeholder for SessionID();
+
+    *tmpMsg << ( u8 )0x00;  // Message length placeholder;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )0x0000; // placeholder for UDP_ID;
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )nUserCharLocalId;
+    *tmpMsg << ( u8 )0x01; // cmd
+    *tmpMsg << ( u16 )nWeaponId;
+    *tmpMsg << ( u32 )nTargetRawItemID;
+    *tmpMsg << ( u8 )nAiming;
+    *tmpMsg << ( u8 )nTargetedHeight;
+    *tmpMsg << ( u8 )nScore;
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildHeldItemUse2Msg( u16 nUserCharLocalId, u32 nTargetRawItemID )
+{
+  PMessage* tmpMsg = new PMessage( 18 );
+
+  *tmpMsg << ( u8 )0x13;
+  *tmpMsg << ( u16 )0x0000; // placeholder for UDP_ID;
+  *tmpMsg << ( u16 )0x0000; // placeholder for SessionID();
+
+  *tmpMsg << ( u8 )0x00;  // Message length placeholder;
+  *tmpMsg << ( u8 )0x03;
+  *tmpMsg << ( u16 )0x0000; // placeholder for UDP_ID;
+  *tmpMsg << ( u8 )0x1f;
+  *tmpMsg << ( u16 )nUserCharLocalId;
+  *tmpMsg << ( u8 )0x2c; // cmd
+  *tmpMsg << ( u8 )0x09; // cmd
+  *tmpMsg << ( u32 )nTargetRawItemID;
+
+  ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+  return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildHeldItemUse3Msg(  PClient* nClient, u16 nUnknown1, u16 nUnknown2, u16 nUnknown3, u16 nUnknown4 )
+{
+  PMessage* tmpMsg = new PMessage( 22 );
+  nClient->IncreaseUDP_ID();
+
+  *tmpMsg << ( u8 )0x13;
+  *tmpMsg << ( u16 )nClient->GetUDP_ID();
+  *tmpMsg << ( u16 )nClient->GetSessionID();
+  *tmpMsg << ( u8 )0x00; // Message length
+  *tmpMsg << ( u8 )0x03;
+  *tmpMsg << ( u16 )nClient->GetUDP_ID();
+  *tmpMsg << ( u8 )0x1f;
+  *tmpMsg << ( u16 )nClient->GetLocalID();
+  *tmpMsg << ( u8 )0x25; // cmd
+  *tmpMsg << ( u8 )0x1a; // cmd
+  *tmpMsg << ( u16 )nUnknown1;
+  *tmpMsg << ( u16 )nUnknown2;
+  *tmpMsg << ( u16 )nUnknown3;
+  *tmpMsg << ( u16 )nUnknown4;
+
+  ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+  return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildHeldItemUse4Msg( u16 nUserCharLocalId, u32 nTargetRawItemID, u16 nUnknown1, u16 nUnknown2, u8 nTargetedHeight )
+{
+  PMessage* tmpMsg = new PMessage( 23 );
+
+  *tmpMsg << ( u8 )0x13;
+  *tmpMsg << ( u16 )0x0000; // placeholder for UDP_ID;
+  *tmpMsg << ( u16 )0x0000; // placeholder for SessionID();
+
+  *tmpMsg << ( u8 )0x00;  // Message length placeholder;
+  *tmpMsg << ( u8 )0x03;
+  *tmpMsg << ( u16 )0x0000; // placeholder for UDP_ID;
+  *tmpMsg << ( u8 )0x1f;
+  *tmpMsg << ( u16 )nUserCharLocalId;
+  *tmpMsg << ( u8 )0x2c; // cmd
+  *tmpMsg << ( u8 )0x01; // cmd
+  *tmpMsg << ( u16 )nUnknown1;
+  *tmpMsg << ( u16 )nUnknown2;
+  *tmpMsg << ( u32 )nTargetRawItemID;
+  *tmpMsg << ( u8 )nTargetedHeight;
+
+  ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+  return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildHeldItemAddonActivationMsg( PClient* nClient, u8 nState )
+{
+    PMessage* tmpMsg = new PMessage( 15 );
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; // placeholder for UDP_ID;
+    *tmpMsg << ( u16 )0x0000; // placeholder for SessionID();
+
+    *tmpMsg << ( u8 )0x00;  // Message length placeholder;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )0x0000; // placeholder for UDP_ID;
+    *tmpMsg << ( u8 )0x2f;
+    *tmpMsg << ( u16 )nClient->GetLocalID();
+    *tmpMsg << ( u16 )0x0001; // cmd ?
+    *tmpMsg << ( u8 )( 0x60 | nState );
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildWeatherControlMsg( u16 nWeatherId )
+{
+    PMessage* tmpMsg = new PMessage( 13 );
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; // placeholder for UDP_ID;
+    *tmpMsg << ( u16 )0x0000; // placeholder for SessionID();
+
+    *tmpMsg << ( u8 )0x00;  // Message length placeholder;
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )0x0000; // placeholder for UDP_ID;
+    *tmpMsg << ( u8 )0x2e;
+    *tmpMsg << ( u8 )0x01; // cmd
+    *tmpMsg << ( u16 )nWeatherId; //see at bottom of weather.def
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharUseTimedDrugMsg( PClient* nClient, const PDefDrug* nDrugDef, u16 nItemId )
+{
+  PMessage* tmpMsg = new PMessage( 60 );
+  nClient->IncreaseUDP_ID();
+
+  *tmpMsg << ( u8 )0x13;
+  *tmpMsg << ( u16 )nClient->GetUDP_ID();
+  *tmpMsg << ( u16 )nClient->GetSessionID();
+  *tmpMsg << ( u8 )0x00; // Message length
+  *tmpMsg << ( u8 )0x03;
+  *tmpMsg << ( u16 )nClient->GetUDP_ID();
+  *tmpMsg << ( u8 )0x1f;
+  *tmpMsg << ( u16 )nClient->GetLocalID();
+  *tmpMsg << ( u8 )0x25; // cmd
+  *tmpMsg << ( u8 )0x06; // cmd
+  *tmpMsg << ( u8 )nDrugDef->GetChangeNum();
+  *tmpMsg << ( u8 )0x01; // ??? not working if 0, no apparent change if > 1
+  *tmpMsg << ( u16 )nDrugDef->GetDuration();
+  *tmpMsg << ( u16 )nItemId;
+  for( u8 i = 0; i < nDrugDef->GetChangeNum(); ++i )
+  {
+    *tmpMsg << ( u8 )nDrugDef->GetChangeType( i );
+    *tmpMsg << ( u16 )( nDrugDef->GetChangeScale( i ) * 100 );
+    *tmpMsg << ( u16 )nDrugDef->GetChangeTarget( i );
+  }
+
+  ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+  return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharUseInstantDrugMsg( PClient* nClient, const PDefDrug* nDrugDef )
+{
+  PMessage* tmpMsg = new PMessage( 60 );
+  nClient->IncreaseUDP_ID();
+
+  *tmpMsg << ( u8 )0x13;
+  *tmpMsg << ( u16 )nClient->GetUDP_ID();
+  *tmpMsg << ( u16 )nClient->GetSessionID();
+  *tmpMsg << ( u8 )0x00; // Message length
+  *tmpMsg << ( u8 )0x03;
+  *tmpMsg << ( u16 )nClient->GetUDP_ID();
+  *tmpMsg << ( u8 )0x1f;
+  *tmpMsg << ( u16 )nClient->GetLocalID();
+  *tmpMsg << ( u8 )0x25; // cmd
+  *tmpMsg << ( u8 )0x07; // cmd
+  *tmpMsg << ( u8 )nDrugDef->GetChangeNum();
+  *tmpMsg << ( u8 )0x02; // ??? other values not tested
+  for( u8 i = 0; i < nDrugDef->GetChangeNum(); ++i )
+  {
+    *tmpMsg << ( u8 )nDrugDef->GetChangeType( i );
+    *tmpMsg << ( f32 )( nDrugDef->GetChangeScale( i ) * 100 ); // f32 in nc2.2 - u16 in nc1 ???
+    *tmpMsg << ( u16 )nDrugDef->GetChangeTarget( i );
+  }
+
+  ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+  Console->Print( "%s PMsgBuilder::BuildCharUseInstantDrugMsg : data format not tested", Console->ColorText( YELLOW, BLACK, "[WARNING]" ) );
+
+  return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildCharUseRecreationUnitMsg( PClient* nClient, u32 nObjectId )
+{
+  PMessage* tmpMsg = new PMessage( 16 );
+  nClient->IncreaseUDP_ID();
+/*
+  *tmpMsg << ( u8 )0x13;
+  *tmpMsg << ( u16 )nClient->GetUDP_ID();
+  *tmpMsg << ( u16 )nClient->GetSessionID();
+  *tmpMsg << ( u8 )0x00; // Message length
+  *tmpMsg << ( u8 )0x03;
+  *tmpMsg << ( u16 )nClient->GetUDP_ID();
+  *tmpMsg << ( u8 )0x1f;
+  *tmpMsg << ( u16 )nClient->GetLocalID();
+  *tmpMsg << ( u8 )0x25; // cmd
+  *tmpMsg << ( u8 )0x16; // cmd
+
+  ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+*/
+  Console->Print( "%s PMsgBuilder::BuildCharUseRecreationUnitMsg : not implemented (target: 0x%08x)", Console->ColorText( YELLOW, BLACK,"[WARNING]" ), nObjectId );
+  return tmpMsg;
+}
+
+// For testing - packet to be broadcasted to zone
+PMessage* PMsgBuilder::BuildNpcDeathMsg( PClient* nClient, u32 nNpcId, u8 unknown1, u8 unknown2 )
+{
+    PMessage* tmpMsg = new PMessage( 19 );
+    PChar *nChar = nClient->GetChar();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000; // placeholder for UDP_ID;
+    *tmpMsg << ( u16 )0x0000; // placeholder for SessionID();
+
+    *tmpMsg << ( u8 )0x00;  // Message length placeholder;
+    *tmpMsg << ( u8 )0x1b;
+    *tmpMsg << ( u32 )nNpcId;
+    *tmpMsg << ( u8 )0x1f;
+    *tmpMsg << ( u16 )( nChar->Coords.mY + 768 + 30 ); //move Npc near to char :p
+    *tmpMsg << ( u16 )( nChar->Coords.mZ + 768 + 0 );
+    *tmpMsg << ( u16 )( nChar->Coords.mX + 768 + 30 );
+    *tmpMsg << ( u8 )2; // ??? 0x01=look at target, 0x02=?, 0x10 = kneel, 0x80 = die
+    *tmpMsg << ( u8 )1; //0=> dead on health 0 / else alive on health 0. Changes in caps
+    *tmpMsg << ( u8 )96; // health => 0 alive if prec >0 1-127 alive, <0 dead (ie u8 128-255 = neg signed values)
+    *tmpMsg << ( u16 )259; // targetId (N)PC - Here: left copbot at NC entrance (zone 2008)
+    *tmpMsg << ( u8 )0x00; // ? doesn't seem to change in caps
+    *tmpMsg << ( u8 )0x00; // ? doesn't seem to change in caps
+    *tmpMsg << ( u8 )0; // ? changes in caps
+    *tmpMsg << ( u8 )0; // ? changes in caps // moving speed somewhere ?
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    unknown2 = unknown1; // so that gcc doesn't complain if these vars are not used
+    return tmpMsg;
+}
+
+PMessage* PMsgBuilder::BuildNpcCleanupMsg( u32 nNpcId, u8 nCmd )
+{
+    PMessage* tmpMsg = new PMessage();
+
+    *tmpMsg << ( u8 )0x13;
+    *tmpMsg << ( u16 )0x0000;
+    *tmpMsg << ( u16 )0x0000;
+    *tmpMsg << ( u8 )0x00; // Message length
+    *tmpMsg << ( u8 )0x03;
+    *tmpMsg << ( u16 )0x0000;
+    *tmpMsg << ( u8 )0x2d;
+    *tmpMsg << ( u32 )nNpcId;
+    *tmpMsg << ( u8 )nCmd; // 6: npc/vhc "cleanup", 1: kill npc + msg "no reward, too small"
+
+    ( *tmpMsg )[5] = ( u8 )( tmpMsg->GetSize() - 6 );
+
+    return tmpMsg;
+}\r
+\r
+
+/*
+void Cmd_GiveItem (int ItemId, int Amount, int ClientNum)
+{
+ unsigned char SendBuffer[256];
+
+// Inventory_AddNewItem (&Client_Sockets[ClientNum].CharInfo, ItemId, Amount);
+ SendBuffer[0] = 0x13;
+ SendBuffer[5] = 0x1b;
+ SendBuffer[6] = 0x03;
+ Network_IncrementUDP (ClientNum);
+ *(unsigned short*)&SendBuffer[7] = Client_Sockets[ClientNum].UDP_ID;
+ SendBuffer[9] = 0x1f;
+ *(unsigned short*)&SendBuffer[10] = Client_Sockets[ClientNum].CharInfo.MapID;
+ SendBuffer[12] = 0x25;
+ SendBuffer[13] = 0x13;
+ Client_Sockets[ClientNum].TransactionID++;
+ *(unsigned short*)&SendBuffer[14] = Client_Sockets[ClientNum].TransactionID;//Transaction ID
+ SendBuffer[16] = 0x18;
+ SendBuffer[17] = 0x03; //Location
+ SendBuffer[18] = 0xff; // \/
+ SendBuffer[19] = 0xff; //Anywhere
+ SendBuffer[20] = 0x08;
+ SendBuffer[21] = 0x00;
+ *(unsigned short*)&SendBuffer[22] = ItemId; //Item Id
+ SendBuffer[24] = 0x05;
+ SendBuffer[25] = 0x01;
+ *(unsigned short*)&SendBuffer[26] = Amount; //Quantity
+ SendBuffer[28] = 0x00;
+ SendBuffer[29] = 0x00;
+ *(unsigned short*)&SendBuffer[30] = Client_Sockets[ClientNum].CharInfo.ItemTransactionID; //Id of Purchased Item (Client sends another packet for placement of new item)
+
+ *(unsigned short*)&SendBuffer[1] = Client_Sockets[ClientNum].UDP_ID;
+ *(unsigned short*)&SendBuffer[3] = Client_Sockets[ClientNum].UDP_ID_HIGH;
+
+ Network_SendUDP (SendBuffer, 32, ClientNum);
+}
+*/
+
+/* Unkown use packets (from nc2.2)
+13:81:00:81:e2: 0c: 03:81:00:23: 12:00: 07:00:00:00:00:00 // weather related ?
+
+13:56:00:56:e2: 40: 03:56:00:1f:01:00:25:13: f1:18:13:01:77:05:48:c7: f2:18:13:02:16:74:61:c7: f3:18:13:03:17:74:61:c7: f4:18:13:04:18:74:61:c7: f5:18:13:05:1f:2a:60:c7: f6:18:13:06:1f:2a:60:c7: f7:18:13:0b:3e:8f:6d:c7
+
+13:5c:00:5c:e2: 0c: 03:5c:00:1f:01:00:25:13: f8:18:0e:02
+
+13:xx:xx:xx:xx: 09: 03:68:00:2d: 6d:03:00:00: 06 // Action update ? other NPC update ? some vanish ?
+*/
diff --git a/server/src/game/multipart.cpp b/server/src/game/multipart.cpp
new file mode 100644 (file)
index 0000000..f7e58b8
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+ multipart.cpp - Handling of incomming multipart messages
+
+ CREATION: 31 Aug 2006 Hammag
+
+ MODIFIED:
+ REASON: -
+*/
+
+#include "main.h"
+
+PMultiPart::PMultiPart()
+{
+}
+
+PMultiPart::~PMultiPart()
+{
+
+}
+
+void PMultiPart::AssembleChunk(u16 nSequence)
+{
+    // Get the sequence number
+    PMultipartMap::iterator it;
+    it = MsgMap.find(nSequence);
+
+    // Prepare messagebuffer
+    PMessage* tmpMsg = new PMessage();
+
+    // Get number of chunks in this sequence
+    int tNumChunks = it->second.smChunkTotal;
+    int tCurrentChunk = 0;
+
+    vecMsgChunk::iterator vIt;
+    bool tLoopDetect = false; // Dont go into an endless loop!
+
+    // Assemble multiframe message. And (if required) put them together in correct order!
+    while(tCurrentChunk < tNumChunks)
+    {
+        tLoopDetect = false;
+        for (vIt = it->second.smvChunk.begin(); vIt != it->second.smvChunk.end(); vIt++)
+        {
+            // Is entry Nr. x the next chunk number we need to assemble?
+            if(it->second.smvChunk[tCurrentChunk].smChunkNr == tCurrentChunk)
+            {
+                // Push chunk into buffer
+                *tmpMsg << *(it->second.smvChunk[tCurrentChunk].smChunk);
+                // proceed with next chunk
+                tCurrentChunk++;
+
+                // Break here if we have assembled all chunks
+                if(tCurrentChunk == tNumChunks)
+                    break;
+
+                tLoopDetect = true;
+            }
+        }
+        if(tLoopDetect == false)
+        {
+            Console->Print("%s [PMultiPart::AssembleChunk] Unable to assemble Sequence %d. Missing ChunkNumer %d", Console->ColorText(RED, BLACK, "ERROR"), it->first, tCurrentChunk);
+            delete tmpMsg;
+            it->second.smTimeStamp = 0;
+        }
+    }
+    if (gDevDebug) Console->Print("%s [PMultiPart::AssembleChunk] Assembling of Sequence %d was a success", Console->ColorText(GREEN, BLACK, "Success"), it->first);
+    it->second.smTimeStamp = 0;
+    //tmpMsg->Dump();
+
+    // Note: At this point, the reassembled message should be pushed back to the messagedecoder. But since the size of the packets there is always u8
+    // it wont work with these oversized packets.
+    // I decided to process the Assembled packet right here, since the only function in clients known to send oversized frames is UpdateDB
+    ProcessPacket(it->second.smClient, tmpMsg);
+}
+
+void PMultiPart::ProcessPacket(PClient *nClient, PMessage *tmpMsg)
+{
+    mCommandName = "";
+    for(int i = 0; i < mMaxOptions; i++)
+        mOptions[i] = "";
+    mOptionsCount = 0;
+    mDBId = 0;
+
+    // Make sure we have an UpdateDB call, otherwise break and error
+    u8 MsgSubType = tmpMsg->U8Data(0);
+    u8 TerminalAction = tmpMsg->U8Data(1);
+    if(MsgSubType != 0x21 || TerminalAction != 0x18)
+    {
+        Console->Print("%s [PMultiPart::ProcessPacket] Unsupportet multipart message. Type %02x", Console->ColorText(RED, BLACK, "ERROR"), MsgSubType);
+        return;
+    }
+
+    u16 tCmdLen, Unknown3, OptionSize;
+
+    tmpMsg->SetNextByteOffset( 14 );
+    ( *tmpMsg ) >> tCmdLen;
+    ( *tmpMsg ) >> mDBId;
+    ( *tmpMsg ) >> Unknown3;
+    ( *tmpMsg ) >> mCommandName; // null terminated string
+
+    mOptionsCount = 0;
+    while (( tmpMsg->GetNextByteOffset() < tmpMsg->GetSize()  ) && ( mOptionsCount < mMaxOptions ) )
+    {
+        ( *tmpMsg ) >> OptionSize;
+        if (( tmpMsg->GetNextByteOffset() < tmpMsg->GetSize() ) && OptionSize )
+        {
+            ( *tmpMsg ) >> mOptions[mOptionsCount++];
+            //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)!
+        }
+        else
+        {
+            break;
+        }
+    }
+    /*if ( gDevDebug )
+    {
+        Console->Print( "%s Fragmented UpdateDB request from client; DBID: %d", Console->ColorText( YELLOW, BLACK, "[DEBUG]" ), mDBId );
+        Console->Print( "%s Command: '%s'", Console->ColorText( YELLOW, BLACK, "[DEBUG]" ), mCommandName.c_str() );
+        for ( u8 i = 0; i < mOptionsCount; ++i )
+            Console->Print( "%s Option %d: '%s'", Console->ColorText( YELLOW, BLACK, "[DEBUG]" ), i, mOptions[i].c_str() );
+    }*/
+    Terminal->HandleUpdateDB(nClient, 0, &mCommandName, mOptions, mOptionsCount, mDBId, 0);
+}
+
+void PMultiPart::Update()
+{
+    for ( PMultipartMap::iterator i = MsgMap.begin(); i != MsgMap.end(); i++ )
+    {
+        // Check if sequence is complete
+        if(i->second.smChunkTotal == i->second.smvChunk.size())
+        {
+            if (gDevDebug) Console->Print("[PMultiPart::Update] Sequence number %d is complete. Assembling...", i->first);
+            AssembleChunk(i->first); // timestamp value is set in this function to 0, so it gets deleted after automaticly
+        }
+
+        // Check if sequence is timed out
+        if(i->second.smTimeStamp + MAX_SEQUENCE_LIFE < time(NULL))
+        {
+            if (gDevDebug) Console->Print("[PMultiPart::Update] Sequence number %d timed out. Deleting...", i->first);
+            MsgMap.erase(i);
+        }
+    }
+}
+
+// Adds an multipart frame
+void PMultiPart::AddMultiPartChunk(PClient *nClient, PMessage *nChunk, u16 nChunkNumber, u16 nChunkTotal, u8 nSequence)
+{
+    // Search for Sequence ID in our map
+    PMultipartMap::iterator it;
+    it = MsgMap.find(nSequence);
+
+    if ( it != MsgMap.end() )
+    {   // We've found our sequence buffer
+        // Prepare the chunk
+        s_MessageChunk tChunk;
+        tChunk.smChunkNr = nChunkNumber;
+        tChunk.smChunk = nChunk;
+
+        // And push it into the vector
+        it->second.smvChunk.push_back(tChunk);
+        // Update lifetimer
+        it->second.smTimeStamp = time(NULL);
+    }
+    else
+    {
+        // Prepare our chunk
+        s_MessageChunk tChunk;
+        tChunk.smChunkNr = nChunkNumber;
+        tChunk.smChunk = nChunk;
+
+        // Generate new Sequence entry
+        s_SequenceEntry tSeq;
+        // Push our temp chunk into the vector
+        tSeq.smvChunk.push_back(tChunk);
+        // Add current timestamp
+        tSeq.smTimeStamp = time(NULL);
+        // Set chunktotal
+        tSeq.smChunkTotal = nChunkTotal;
+        // Store client
+        tSeq.smClient = nClient;
+
+        // Finally, push that into our map
+        MsgMap.insert(make_pair(nSequence, tSeq));
+    }
+}
diff --git a/server/src/game/npc.cpp b/server/src/game/npc.cpp
new file mode 100644 (file)
index 0000000..a91137e
--- /dev/null
@@ -0,0 +1,844 @@
+/*
+TinNS (TinNS is not a Neocron Server)
+Copyright (C) 2005 Linux Addicted Community
+maintainer Akiko <akiko@gmx.org>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+*/
+
+/*
+
+npc.cpp - Management class for NPC worldactors
+
+CREATION: 04 Jan 2007 Namikon
+
+MODIFIED: 28 Apr 2009 Hammag
+REASON: changed worlds/zones Id from u16 (wrong !!!) to u32
+
+*/
+
+#include "main.h"
+#include "npc.h"
+#include "worlds.h"
+#include "npctemplate.h"
+#include "worlddatatemplate.h"\r
+#include "msgbuilder.h"\r
+
+///***********************************************************************
+\r
+// Reload LUA script while running, in case we modified it and dont want to restart the entire server\r
+bool PNPC::ReloadLUAScript()\r
+{\r
+    // Erase current LUA script\r
+    mLUAFile = "";\r
+\r
+    // Reload it\r
+    return LoadLUAScript();\r
+}\r
+
+bool PNPC::DEF_Load(u32 nWorldID)
+{
+    if ( gDevDebug ) Console->Print( "[DEBUG] Now loading NPC data for NPC id %d from DEF", mWorldID );
+    const PNPCTemplate* t_defNPC = Worlds->GetWorld(nWorldID)->GetNPCTemplate(mWorldID);
+
+    mNameID = (u16)t_defNPC->GetNPCTypeID(); // 16 or 32??\r
+    const PDefNpc* t_NpcTypeDef = GameDefs->Npcs()->GetDef(mNameID);\r
+    if(!t_NpcTypeDef)\r
+    {\r
+        Console->Print("%s [PNPC::DEF_Load()] Unknown NPC Type %d in .dat file found", Console->ColorText(RED,BLACK, "[Error]"), mNameID);\r
+        return false;\r
+    }
+
+    // TODO: Find out what exactly these TypeID and ClothingID values do and where they are generated/read\r
+    // Possible (working) solution: Random seed for name generation that happens clientside
+    mTypeID = GetRandom(32767, 1);
+    mClothing = GetRandom(32767, 1);
+    // -------------
+
+    mPosX = t_defNPC->GetPosX()+32768;
+    mPosY = t_defNPC->GetPosY()+32768;
+    mPosZ = t_defNPC->GetPosZ()+32768;
+    mAngle = atoi( t_defNPC->GetAngle().c_str() );
+    mLoot = t_NpcTypeDef->GetLoot();
+    mHealth = t_NpcTypeDef->GetHealth() * NPC_HEALTHFACTOR;\r
+    mMaxHealth = mHealth;
+    mTrader = t_defNPC->GetTradeID();
+    mFaction = t_NpcTypeDef->GetFaction();
+    // WorldID Fix 10.10.2009
+    mFromDEF = true;
+
+    mName = t_defNPC->GetActorName();
+\r
+\r
+    // Load dialogscript for this NPC right uppon startup\r
+    mDialogScript = t_NpcTypeDef->GetDialogScript();\r
+    CleanUpString(&mDialogScript);\r
+\r
+    // Try to load any lua scripts\r
+    // Checks are done in target function\r
+    LoadLUAScript();\r
+    if ( gDevDebug ) Console->Print( "[DEBUG] NPC: WID:%d NID:%d TID:%d CL:%d PX:%d PY:%d PZ:%d ", mWorldID, mNameID, mTypeID, mClothing, mPosX, mPosY, mPosZ);
+    if ( gDevDebug ) Console->Print( "ANG:%d HITPOINTS:%d TRADE:%d LOOT:%d NAME:%s CNAME:%s CUSTOMSCRIPT:%s", mAngle, mHealth, mTrader, mLoot, mName.c_str(), mCustomName.c_str(), mCustomLua.c_str() );\r
+    if ( gDevDebug ) Console->Print( "DIALOGSCR:%s", mDialogScript.c_str() );
+    return true;
+}
+\r
+bool PNPC::SQL_Load()\r
+{\r
+    if ( gDevDebug ) Console->Print( "[DEBUG] Now loading NPC data for NPC id %d from SQL", mID );\r
+    MYSQL_RES *result = NULL;\r
+    MYSQL_ROW row;\r
+    char query[100];\r
+\r
+    snprintf( query, 100, "SELECT * FROM `npc_spawns` WHERE `npc_id` = %d", mID );\r
+    if ( gDevDebug ) Console->Print( "[DEBUG] Executing query %s", query );\r
+    result = MySQL->GameResQuery( query );\r
+    if ( result == NULL )\r
+    {\r
+        Console->Print( RED, BLACK, "PNPC::SQL_Load could not load NPC definition" );\r
+        Console->Print( "Query was:" );\r
+        Console->Print( "%s", query );\r
+        MySQL->ShowGameSQLError();\r
+        return false;\r
+    }\r
+    if ( mysql_num_rows( result ) == 0 )\r
+    {\r
+        if ( gDevDebug ) Console->Print( "[DEBUG] No NPCs found, returning false" );\r
+        MySQL->FreeGameSQLResult( result );\r
+        return false;\r
+    }\r
+    else if ( mysql_num_rows( result ) > 1 )\r
+    {\r
+        Console->Print( RED, BLACK, "PNPC::SQL_Load Duplicate entry for NPC %d", mID );\r
+        MySQL->FreeGameSQLResult( result );\r
+        return false;\r
+    }\r
+    if ( gDevDebug ) Console->Print( "[DEBUG] One NPC found for my ID. Now grabbing data..." );\r
+    row = mysql_fetch_row( result );\r
+\r
+    mWorldID = atoi( row[npc_worldid] );\r
+    mNameID = atoi( row[npc_nameid] );\r
+    mTypeID = atoi( row[npc_typeid] );\r
+    mClothing = atoi( row[npc_clothing] );\r
+    mPosX = atoi( row[npc_x] );\r
+    mPosY = atoi( row[npc_y] );\r
+    mPosZ = atoi( row[npc_z] );\r
+    mAngle = atoi( row[npc_angle] );\r
+    mLoot = atoi( row[npc_loot] );\r
+    mHealth = atoi( row[npc_unknown] );\r
+    mMaxHealth = mHealth;\r
+    mTrader = atoi( row[npc_trader] );\r
+    mItemQuality = atoi( row[npc_shop_quality] );\r
+    if(atoi(row[npc_scripting]) == 1)\r
+        mScripting = true;\r
+    else\r
+        mScripting = false;\r
+\r
+    if ( row[npc_name] != NULL )\r
+        mName = row[npc_name];\r
+\r
+    if ( row[npc_customname] != NULL )\r
+        mCustomName = row[npc_customname];\r
+\r
+    if ( row[npc_customscript] != NULL )\r
+        mCustomLua = row[npc_customscript];\r
+\r
+    // Now make sure we have an valid NPC here. Besides we need some more information\r
+    const PDefNpc* t_npc = GameDefs->Npcs()->GetDef(mNameID);\r
+    if(!t_npc)\r
+    {\r
+        Console->Print( RED, BLACK, "PNPC::SQL_Load Invalid NPC Type found; SQL ID: %d", mID );\r
+        return false;\r
+    }\r
+    mFaction = t_npc->GetFaction();\r
+\r
+    // Load dialogscript for this NPC right uppon startup\r
+    // !-> Only if no custom lua script is attached <-!\r
+    if(mCustomLua.length() < 1)\r
+    {\r
+        if(t_npc->GetDialogScript().length() > 3)\r
+        {\r
+            size_t tfound;\r
+            string t_dialogscript = t_npc->GetDialogScript();\r
+            string t_replacechr ("\"");\r
+\r
+            tfound = t_dialogscript.find(t_replacechr);\r
+            while(tfound != string::npos)\r
+            {\r
+                t_dialogscript.replace(tfound, 1, " ");\r
+                tfound = t_dialogscript.find( t_replacechr, tfound +1 );\r
+            }\r
+            Trim(&t_dialogscript);\r
+            if(t_dialogscript.length() > 1)\r
+            {\r
+                mDialogScript = t_dialogscript;\r
+            }\r
+        }\r
+    }\r
+    // Try to load any lua scripts\r
+    // Checks are done in target function\r
+    LoadLUAScript();\r
+\r
+    if ( gDevDebug ) Console->Print( "[DEBUG] NPC: WID:%d NID:%d TID:%d CL:%d PX:%d PY:%d PZ:%d ", mWorldID, mNameID, mTypeID, mClothing, mPosX, mPosY, mPosZ);\r
+    if ( gDevDebug ) Console->Print( "ANG:%d HITPTS:%d TRADE:%d LOOT:%d NAME:%s CNAME:%s CUSTOMSCRIPT:%s", mAngle, mHealth, mTrader, mLoot, mName.c_str(), mCustomName.c_str(), mCustomLua.c_str() );\r
+    if ( gDevDebug ) Console->Print( "DIALOGSCR:%s", mDialogScript.c_str() );\r
+    MySQL->FreeGameSQLResult( result );\r
+    return true;\r
+}\r
+\r
+bool PNPC::LoadLUAScript()\r
+{\r
+    u32 tFileLen = 0;\r
+    PFile* fLua = NULL;\r
+    string tLuaFile = "";\r
+    string tHDRFile = "";\r
+\r
+    // Load LUA script and include the correct header file\r
+    // based in mDialogScript\r
+    // if mDialogScript is empty, look at mCustomLua and load this file. Standart include header for custom\r
+    // script files is dialogheader.lua since we dont know (yet) what standart header the NC Client uses\r
+    // for custom loaded scripts.\r
+\r
+    if(mDialogScript.length() > 1)\r
+    {\r
+        // Get LUA filename from defs\r
+        const PDefScripts* tDefScripts = NULL;\r
+        std::map<int, PDefScripts*>::const_iterator itScrStart = GameDefs->Scripts()->ConstIteratorBegin();\r
+        std::map<int, PDefScripts*>::const_iterator itScrEnd = GameDefs->Scripts()->ConstIteratorEnd();\r
+        for ( std::map<int, PDefScripts*>::const_iterator i = itScrStart; i != itScrEnd; i++ )\r
+        {\r
+            tDefScripts = i->second;\r
+    //        Console->Print("[DEBUG PNPC::LoadLUAScript] Identifier: [%s] LUA: [%s]", tDefScripts->GetIdentifier().c_str(), tDefScripts->GetLuaFile().c_str());\r
+\r
+            if(tDefScripts->GetIdentifier().compare(mDialogScript) == 0)\r
+            {\r
+                break;\r
+            }\r
+        }\r
+        // If we left the loop without an positive match.. false!\r
+        if(tDefScripts->GetIdentifier().compare(mDialogScript) != 0)\r
+        {\r
+            return false;\r
+        }\r
+\r
+        // Assign our LUA file to load later\r
+        tLuaFile = tDefScripts->GetLuaFile();\r
+        // MaKe ThE sTrInG aLl lowercase! :)\r
+        std::transform(tLuaFile.begin(), tLuaFile.end(), tLuaFile.begin(), (int(*)(int))std::tolower);\r
+\r
+\r
+        // We only have 2 headerfiles, so this one is hardcoded\r
+        if(tDefScripts->GetScriptHeader() == "DIALOGHEADER")\r
+        {\r
+            tHDRFile = "scripts/lua/dialogheader.lua";\r
+        }\r
+        else if(tDefScripts->GetScriptHeader() == "MISSIONHEADER")\r
+        {\r
+            tHDRFile = "scripts/lua/missionheader.lua";\r
+        }\r
+    }\r
+    // Customlua is set?\r
+    else if(mCustomLua.length() > 1)\r
+    {\r
+        // Assign lua file and header\r
+        tLuaFile = mCustomLua;\r
+        tHDRFile = "scripts/lua/dialogheader.lua";\r
+    }\r
+    else\r
+    {\r
+        // No LUA Scripts to load. Skipping\r
+        return true;\r
+    }\r
+\r
+    // Load HEADER file\r
+    fLua = Filesystem->Open( "", tHDRFile.c_str(), Config->GetOption( "nc_data_path" ) );\r
+    if(fLua)\r
+    {\r
+        tFileLen = fLua->GetSize();\r
+        char* t_content = new char[tFileLen+1];\r
+        memset(t_content, '\0', tFileLen+1);\r
+\r
+        fLua->Read( t_content, tFileLen );\r
+        Filesystem->Close( fLua );\r
+        mLUAFile = t_content;\r
+        delete t_content;\r
+        if (gDevDebug) Console->Print( "%s [PNPC::LoadLUAScript] Loaded LUA Header Script %s", Console->ColorText( GREEN, BLACK, "[SUCCESS]" ), tHDRFile.c_str() );\r
+    }\r
+    else\r
+    {\r
+        Console->Print( "%s [PNPC::LoadLUAScript] Unable to load LUA Header script %s NPC is now DISABLED for scripting", Console->ColorText( RED, BLACK, "[ERROR]" ), tLuaFile.c_str() );\r
+        // We encountered an error while loading. Make sure this NPC will never act as Dialog NPC!\r
+        mLUAFile = "";\r
+        mCustomLua = "";\r
+        mDialogScript = "";\r
+        return false;\r
+    }\r
+\r
+    // Reset vars\r
+    tFileLen = 0;\r
+    fLua = NULL;\r
+\r
+    fLua = Filesystem->Open( "", tLuaFile.c_str(), Config->GetOption( "nc_data_path" ) );\r
+    if(fLua)\r
+    {\r
+        tFileLen = fLua->GetSize();\r
+        char* t_content = new char[tFileLen+1];\r
+        memset(t_content, '\0', tFileLen+1);\r
+\r
+        fLua->Read( t_content, tFileLen );\r
+        Filesystem->Close( fLua );\r
+        mLUAFile += t_content;  // APPEND the script to our existing lua headerfile\r
+        delete t_content;\r
+        if (gDevDebug) Console->Print( "%s [PNPC::LoadLUAScript] Loaded LUA Script %s", Console->ColorText( GREEN, BLACK, "[SUCCESS]" ), tLuaFile.c_str() );\r
+        //Console->Print( "%s", mLUAFile.c_str() );\r
+    }\r
+    else\r
+    {\r
+        Console->Print( "%s [PNPC::LoadLUAScript] Unable to load LUA Script %s NPC is now DISABLED for scripting", Console->ColorText( RED, BLACK, "[ERROR]" ), tLuaFile.c_str() );\r
+        // We encountered an error while loading. Make sure this NPC will never act as Dialog NPC!\r
+        mLUAFile = "";\r
+        mCustomLua = "";\r
+        mDialogScript = "";\r
+        return false;\r
+    }\r
+    // LUA file prepared. Check if LUA file is valid\r
+    if(LuaEngine->CheckLUAFile(mLUAFile) == true)\r
+    {\r
+        // Everything is fine. NPC is ready for action\r
+        return true;\r
+    }\r
+    else\r
+    {\r
+        // LUA file seems to be corrupt\r
+        mLUAFile = "";\r
+        mCustomLua = "";\r
+        mDialogScript = "";\r
+        return false;\r
+    }\r
+}\r
+
+void PNPC::Die()
+{
+    if ( gDevDebug ) Console->Print( "[DEBUG] NPC dying now" );
+    mHealth = 0;
+    mAction = NPC_ACTIONSTATE_DEATH;
+    mRespawn = std::time( NULL ) + NPC_RESPAWN_AFTER;
+    mDirty = true;
+}
+
+void PNPC::Update()
+{\r
+    // Has to be changed for mobs later
+    if ( std::time( NULL ) >= mRespawn && (mAction&NPC_ACTIONSTATE_DEATH) )
+    {\r
+        if ( gDevDebug ) Console->Print( "[DEBUG] NPC Update: Respawn timer triggered! Setting NPC back to life" );
+        mHealth = mMaxHealth;
+        mAction = NPC_ACTIONSTATE_IDLE;\r
+        mWeaponStatus = NPC_SHOOT_IDLE;
+        mDirty = true;
+    }\r
+}
+\r
+void PNPC::InitVars()
+{
+    mID = 0;
+    mWorldID = 0;
+    mNameID = 0;
+    mTypeID = 0;
+    mClothing = 0;
+    mPosX = 0;
+    mPosY = 0;
+    mPosZ = 0;
+    mAngle = 0;
+    mHealth = 0;\r
+    mUnknown = 0;
+    mTrader = 0;
+    mLoot = 0;\r
+    mDialogScript = "";
+    mName = "";
+    mCustomName = "";
+    mCustomLua = "";
+    mAction = NPC_ACTIONSTATE_IDLE;\r
+    mWeaponStatus = NPC_SHOOT_IDLE;
+    //mDeath = false;
+    mTarget = 0;
+    mDirty = false; // No need to send instand update
+    // WorldID Fix 10.10.2009
+    mFromDEF = false;\r
+    mItemQuality = 50;\r
+    mScripting = true;\r
+    mFaction = 0;\r
+\r
+    // Set next update timer for this NPC to 10 - 30 seconds\r
+    // Note: this is for regular heartbeats only. If npc is dirty,\r
+    // an update is sent anyway\r
+    mNextUpdate = std::time(NULL) + GetRandom(30, 10);
+}
+\r
+void PNPC::Attack( u32 nWorldID, u8 nType, u8 nUnknown )\r
+{\r
+    mDirty = true;\r
+    mTarget = nWorldID;\r
+    mAction = NPC_ACTIONSTATE_ATTACK;\r
+    mWeaponStatus = nType;\r
+    mUnknown = nUnknown;\r
+}\r
+
+PNPC::PNPC( int nSQLID )
+{
+    InitVars();
+//if(gDevDebug) Console->Print("[DEBUG] New NPC instance created. ID is %d", nSQLID);
+    mID = nSQLID;
+    if ( SQL_Load() == false )  // Try to load NPC contents
+        mSuccess = false;
+    else
+        mSuccess = true;
+}
+
+PNPC::PNPC( int nDEFID, u32 nWorldID )
+{
+    InitVars();
+//if(gDevDebug) Console->Print("[DEBUG] New NPC instance created. ID is %d", nSQLID);
+    mWorldID = nDEFID;
+    if ( DEF_Load(nWorldID) == false )  // Try to load NPC contents
+        mSuccess = false;
+    else
+        mSuccess = true;
+}
+
+PNPC::~PNPC()
+{
+//if(gDevDebug) Console->Print("[DEBUG] NPC ID %d terminated", mID);
+}
+/*
+u8 PNPC::GetActionStatus()
+{
+    if ( mDeath == true )
+    {
+        return 128; // 128 triggers "death" animation
+    }
+    else
+    {
+        return 3; // 3 is the value found in many packets. However, no idea what this does
+    }
+}
+*/
+///***********************************************************************
+///***********************************************************************
+\r
+// Broadcast a single NPC\r
+void PNPCWorld::BroadcastNewNPC(PNPC* nNpc)\r
+{\r
+    std::string tAngleStr = Ssprintf( "%d", nNpc->mAngle );\r
+    PMessage* tmpMsg = MsgBuilder->BuildNPCMassInfoMsg (nNpc->mWorldID, nNpc->mTypeID, nNpc->mClothing, nNpc->mNameID, nNpc->mPosY,\r
+                                                        nNpc->mPosZ, nNpc->mPosX, nNpc->mHealth, nNpc->mTrader, &tAngleStr,\r
+                                                        &nNpc->mName, &nNpc->mCustomName);\r
+\r
+    ClientManager->UDPBroadcast( tmpMsg, mWorldID );\r
+}\r
+\r
+\r
+bool PNPCWorld::AddNPC(u32 nSQL_ID, u32 nRaw_ID)\r
+{\r
+    PNPC* tmpNpc = new PNPC( nSQL_ID );\r
+    if(tmpNpc->mSuccess == true)\r
+    {\r
+        // Now broadcast the new NPC to all clients\r
+        BroadcastNewNPC(tmpNpc);\r
+        mNPCs.insert( std::make_pair( nRaw_ID, tmpNpc ) );\r
+        tmpNpc = NULL;\r
+        if ( gDevDebug ) Console->Print( "[PNPCWorld::AddNPC] Custom NPC added" );\r
+    }\r
+    else\r
+    {\r
+        if ( gDevDebug ) Console->Print( "[PNPCWorld::AddNPC] Custom NPC not added due error" );\r
+        delete tmpNpc;\r
+        return false;\r
+    }\r
+\r
+    return true;\r
+}\r
+\r
+void PNPCWorld::DelNPC(u32 nWorldID)\r
+{\r
+    PNPCMap::iterator it = mNPCs.find( nWorldID );\r
+    if ( it == mNPCs.end() )\r
+        return;\r
+\r
+    // Delete NPC from Map\r
+    mNPCs.erase(it);\r
+\r
+    // Send Vanish message to clients\r
+    PMessage* tmpMsg = MsgBuilder->BuildRemoveWorldObjectMsg(nWorldID);\r
+    ClientManager->UDPBroadcast( tmpMsg, mWorldID );\r
+\r
+    return;\r
+}\r
+\r
+void PNPCWorld::SendSingleNPCInfo( PClient* nClient, PNPC* nNpc )\r
+{\r
+    std::string tAngleStr = Ssprintf( "%d", nNpc->mAngle );\r
+    PMessage* tmpMsg = MsgBuilder->BuildNPCSingleInfoMsg (nClient, nNpc->GetRealWorldID(), nNpc->mTypeID, nNpc->mClothing, nNpc->mNameID, nNpc->mPosY,\r
+                                                        nNpc->mPosZ, nNpc->mPosX, nNpc->mHealth, nNpc->mTrader, &tAngleStr,\r
+                                                        &nNpc->mName, &nNpc->mCustomName);\r
+\r
+    nClient->SendUDPMessage( tmpMsg );\r
+    return;\r
+}\r
+
+void PNPCWorld::MSG_SendNPCs( PClient* nClient )
+{\r
+    PNPC* nNpc = NULL;\r
+    for ( PNPCMap::iterator it = mNPCs.begin(); it != mNPCs.end(); it++ )\r
+    {\r
+        nNpc = it->second;\r
+\r
+        std::string tAngleStr = Ssprintf( "%d", nNpc->mAngle );\r
+        PMessage* tmpMsg = MsgBuilder->BuildNPCSingleInfoMsg (nClient, nNpc->GetRealWorldID(), nNpc->mTypeID, nNpc->mClothing, nNpc->mNameID, nNpc->mPosY,\r
+                                                            nNpc->mPosZ, nNpc->mPosX, nNpc->mHealth, nNpc->mTrader, &tAngleStr,\r
+                                                            &nNpc->mName, &nNpc->mCustomName);\r
+\r
+        nClient->SendUDPMessage( tmpMsg );\r
+    }\r
+\r
+    return;\r
+}
+
+bool PNPCWorld::LoadNPCfromSQL()
+{
+// Load NPC defs from MySQL
+    MYSQL_RES *result = NULL;
+    MYSQL_ROW row;
+    char query[100];
+
+    snprintf( query, 100, "SELECT * FROM `npc_spawns` WHERE `npc_location` = %d", mWorldID );
+//if(gDevDebug) Console->Print("[DEBUG] Query is: %s", query);
+    result = MySQL->GameResQuery( query );
+    if ( result == NULL )
+    {
+        Console->Print( RED, BLACK, "PNPCWorld::PNPCWorld could not load NPC definition" );
+        Console->Print( "Query was:" );
+        Console->Print( "%s", query );
+        MySQL->ShowGameSQLError();
+        return false;
+    }
+    if ( mysql_num_rows( result ) == 0 ) // No NPCs found
+    {
+        MySQL->FreeGameSQLResult( result );
+//if(gDevDebug) Console->Print("[NPC] No NPCs for this world found");
+        return true;
+    }
+//if(gDevDebug) Console->Print("[DEBUG] Found NPCs, now adding!");
+    PNPC* tmpNpc = NULL;
+    u32 tRawID = 0;
+    int tSQLID = 0;
+    while (( row = mysql_fetch_row( result ) ) )
+    {
+        tRawID = atoi( row[PNPC::npc_worldid] );
+        tSQLID = atoi( row[PNPC::npc_id] );
+        tmpNpc = new PNPC( tSQLID );
+        if ( tmpNpc->mSuccess == true )
+        {
+            //if(gDevDebug) Console->Print("[DEBUG] NPC init successfull, adding to list");
+            mNPCs.insert( std::make_pair( tRawID, tmpNpc ) );
+            tmpNpc = NULL;
+        }
+        else
+        {
+            //if(gDevDebug) Console->Print("[DEBUG] NPC init failed, removing link");
+            delete tmpNpc;
+        }
+    }
+    if ( gDevDebug ) Console->Print( "[DEBUG] NPC Load from MySQL done" );
+    MySQL->FreeGameSQLResult( result );
+    return true;
+}
+
+bool PNPCWorld::LoadNPCfromDEF()
+{
+    const PNPCsMap* tNPCmap = Worlds->GetWorld(mWorldID)->GetNPCMap(); // Get the NPC Map for this world
+
+    PNPC* tmpNpc = NULL;
+    u32 tDEFID = 0;
+
+    for ( PNPCsMap::const_iterator i = tNPCmap->begin(); i != tNPCmap->end(); i++ )
+    {
+// call PNPC with NPC ID and WorldID
+        tDEFID = i->first;
+        tmpNpc = new PNPC( tDEFID, mWorldID );
+        if ( tmpNpc->mSuccess == true )
+        {
+            mNPCs.insert( std::make_pair( tDEFID, tmpNpc ) );
+            tmpNpc = NULL;
+        }
+        else
+        {
+            delete tmpNpc;
+        }
+    }
+    if ( gDevDebug ) Console->Print( "[DEBUG] NPC Load from .def done" );
+    return true;
+}
+
+PNPCWorld::PNPCWorld( u32 nWorldID )
+{
+//if(gDevDebug) Console->Print("[DEBUG] New world got initialized! Now starting to add NPCs. (WorldID %d)", nWorldID);
+
+// Assign WorldValues now
+    mCreation = std::time( NULL );
+    mWorldID = nWorldID;
+    mLastAliveMsg = 0;
+    LoadNPCfromSQL();
+    LoadNPCfromDEF();
+}
+
+PNPCWorld::~PNPCWorld()
+{
+    if ( gDevDebug ) Console->Print( "[DEBUG] Erasing all NPCs" );
+// Erase all NPCs
+    for ( PNPCMap::iterator it = mNPCs.begin(); it != mNPCs.end(); it++ )
+    {
+        delete it->second;
+        mNPCs.erase( it );
+    }
+}\r
+\r
+void PNPCWorld::Update() // v2; New send function\r
+{\r
+    // Updates NPC in a World.\r
+    // If NPC is dirty, send "large" update. Else\r
+    // send small "i'm alive" message\r
+    std::time_t tNow = std::time(NULL);\r
+    PNPC* tNPC = NULL;\r
+    for ( PNPCMap::iterator it = mNPCs.begin(); it != mNPCs.end(); it++ )\r
+    {\r
+        if ( it->second )\r
+        {\r
+            tNPC = it->second;\r
+            // Check for enemies nearby\r
+            CheckForEnemies(tNPC);\r
+            // Let NPC make themselfs "dirty"\r
+            tNPC->Update();\r
+            // Only update dirty npcs\r
+            if ( tNPC->mDirty == true || tNPC->mNextUpdate <= tNow)\r
+            {\r
+                PMessage* tmpMsg = MsgBuilder->BuildNPCUpdateMsg(tNPC->GetRealWorldID(),\r
+                                                                 tNPC->mPosY,\r
+                                                                 tNPC->mPosZ,\r
+                                                                 tNPC->mPosX,\r
+                                                                 tNPC->GetActionStatus(),\r
+                                                                 tNPC->mHealth,\r
+                                                                 tNPC->GetWeaponStatus(),\r
+                                                                 tNPC->mUnknown,\r
+                                                                 tNPC->mTarget);\r
+\r
+                ClientManager->UDPBroadcast( tmpMsg, mWorldID );\r
+                tNPC->mDirty = false;\r
+                tNPC->PushUpdateTimer();\r
+            }\r
+        }\r
+    }\r
+\r
+    return;\r
+}
+/*\r
+void PNPCWorld::Update()
+{\r
+    // Updates NPC in a World.\r
+    // If NPC is dirty, send "large" update. Else\r
+    // send small "i'm alive" message\r
+    std::time_t tNow = std::time(NULL);\r
+    PNPC* tNPC = NULL;\r
+    for ( PNPCMap::iterator it = mNPCs.begin(); it != mNPCs.end(); it++ )\r
+    {\r
+        if ( it->second )\r
+        {\r
+            tNPC = it->second;\r
+            // Check for enemies nearby\r
+            CheckForEnemies(tNPC);\r
+            // Let NPC make themselfs "dirty"\r
+            tNPC->Update();\r
+            // Only update dirty npcs\r
+            if ( tNPC->mDirty == true )\r
+            {\r
+                PMessage* tmpMsg = MsgBuilder->BuildNPCMassUpdateMsg( tNPC->GetRealWorldID(), tNPC->mPosX, tNPC->mPosY,\r
+                                                                     tNPC->mPosZ, tNPC->GetActionStatus(), tNPC->mHealth, tNPC->mTarget, tNPC->mAction);\r
+\r
+                ClientManager->UDPBroadcast( tmpMsg, mWorldID );\r
+                tNPC->mDirty = false;\r
+                // Large update also counts as small one, inc update counter\r
+                tNPC->PushUpdateTimer();\r
+            }\r
+            else if(tNPC->mNextUpdate <= tNow)\r
+            {\r
+                PMessage* tmpMsg = MsgBuilder->BuildNPCMassAliveMsg( tNPC->GetRealWorldID(), tNPC->mPosX, tNPC->mPosY,\r
+                                                                     tNPC->mPosZ, tNPC->GetActionStatus(), tNPC->mHealth, tNPC->mAction);\r
+\r
+                ClientManager->UDPBroadcast( tmpMsg, mWorldID );\r
+                tNPC->PushUpdateTimer();\r
+            }\r
+        }\r
+    }\r
+\r
+    return;\r
+}
+*/\r
+PNPC* PNPCWorld::GetNPC( u32 nNPCID )
+{
+    if ( gDevDebug ) Console->Print( "[DEBUG] Searching for NPC %d in list", nNPCID );
+    PNPCMap::const_iterator it = mNPCs.find( nNPCID );
+    if ( it == mNPCs.end() ) // only if client not found in list
+        return NULL;
+    else
+        return it->second;
+}
+
+///***********************************************************************
+///***********************************************************************
+
+PNPCManager::PNPCManager()
+{
+    if ( gDevDebug ) Console->Print( "[DEBUG] NPCManager wakeup!" );
+// Nothing yet
+}
+
+PNPCManager::~PNPCManager()
+{
+    if ( gDevDebug ) Console->Print( "[DEBUG] NPCManager shutdown" );
+    for ( PNPCWorldMap::iterator it = mWorlds.begin(); it != mWorlds.end(); it++ )
+    {
+        delete it->second;
+        mWorlds.erase( it );
+    }
+}
+
+void PNPCManager::InitPlayer( PClient* nClient )
+{
+    if ( gDevDebug ) Console->Print( "[DEBUG] Player entered zone, doing init" );
+// Ok, player entered zone. First, get zone!
+    u32 nZone = nClient->GetChar()->GetLocation();
+    if ( gDevDebug ) Console->Print( "[DEBUG] Now searching for zone %d in list", nZone );
+// Search worldmanager for this zone
+    PNPCWorld* tmpWorld = GetWorld( nZone );
+
+    if ( tmpWorld != NULL )
+    {
+        if ( gDevDebug ) Console->Print( "[DEBUG] World found, poking MSG_SendNPCs" );
+// World found? Fine. Then poke the class to send its content to the client
+        tmpWorld->MSG_SendNPCs( nClient );
+    }
+    else
+    {
+        if ( gDevDebug ) Console->Print( "[DEBUG] World not found, creating...." );
+// World not found! OMG! Create it!
+        tmpWorld = InitWorld( nZone );
+        if ( tmpWorld == NULL )
+        {
+            Console->Print( "%s Unable to init NPCs for world %d", Console->ColorText( RED, BLACK, "[ERROR]" ), nZone );
+            return;
+        }
+        if ( gDevDebug ) Console->Print( "[DEBUG] Done. Poking MSG_SendNPCs" );
+// now we have the world, poke it to send its content
+        tmpWorld->MSG_SendNPCs( nClient );
+        //tmpWorld->MSG_SendAlive( nClient ); // Force instand-update of NPCs for this client
+    }
+}
+
+PNPCWorld* PNPCManager::InitWorld( u32 nWorldID )
+{
+    if ( gDevDebug ) Console->Print( "[DEBUG] InitWorld triggered: ID %d", nWorldID );
+    PNPCWorld* tmpWorld = NULL;
+    tmpWorld = new PNPCWorld( nWorldID );
+    if ( tmpWorld != NULL )
+    {
+        if ( gDevDebug ) Console->Print( "[DEBUG] World created. Adding to list..." );
+        mWorlds.insert( std::make_pair( nWorldID, tmpWorld ) );
+        if ( gDevDebug ) Console->Print( "[DEBUG] ... and returning instance" );
+        return tmpWorld;
+    }
+    else
+    {
+        if ( gDevDebug ) Console->Print( "[DEBUG] Failed to init world. Returning NULL" );
+        return NULL;
+    }
+}
+
+void PNPCManager::Update()
+{
+    static std::time_t lastdebug = std::time( NULL );
+// Loop all worlds
+//    if(lastdebug < std::time(NULL))
+//        if(gDevDebug) Console->Print("[DEBUG] WorldLoop still running...");
+
+    for ( PNPCWorldMap::iterator it = mWorlds.begin(); it != mWorlds.end(); it++ )
+    {
+// Make sure target still exists
+        if ( it->second )
+        {
+            // Getworld, and check if zone is in use
+            PNPCWorld* tWorld = it->second;
+            if ( ClientManager->IsWorldInUse( tWorld->mWorldID ) == true )
+            {
+                //if(lastdebug < std::time(NULL))
+                //    if(gDevDebug) Console->Print("[DEBUG] World is in use, poking management class to update itself");
+                // World is in use. Now send "dirty" npcs or alive messages
+                tWorld->Update();
+            }
+            else
+            {
+                //if(lastdebug < std::time(NULL))
+                //    if(gDevDebug) Console->Print("[DEBUG] World not in use. Checking lifetimer...");
+
+                if (( tWorld->mCreation + ZONE_RESET_AFTER ) <= std::time( NULL ) )
+                    //if(tWorld->mCreation <= std::time(NULL))
+                {
+                    if ( gDevDebug ) Console->Print( "[DEBUG] World reached ZONE_RESET timeout. Erasing..." );
+                    // World is unused sine ZONE_RESET_AFTER minutes, deleting now
+                    delete it->second;
+                    mWorlds.erase( it );
+                }
+                else
+                {
+                    // Keep LastAliveMessage up to date until someone enters zone
+                    tWorld->mLastAliveMsg = std::time( NULL );
+                    //  if(lastdebug < std::time(NULL))
+                    //      if(gDevDebug) Console->Print("[DEBUG] World still within ZONE_RESET timeout");
+                }
+            }
+        }
+    }
+    if ( lastdebug < std::time( NULL ) )
+    {
+        lastdebug = std::time( NULL ) + 3;
+//if(gDevDebug) Console->Print("[DEBUG] next updateloopmsg in 3 seconds");
+    }
+}
+
+PNPCWorld* PNPCManager::GetWorld( u32 nWorldID )
+{
+    if ( gDevDebug ) Console->Print( "[DEBUG] Trying to get instance for worldid %d", nWorldID );
+    PNPCWorldMap::const_iterator it = mWorlds.find( nWorldID );
+    if ( it == mWorlds.end() )
+    {
+        if ( gDevDebug ) Console->Print( "[DEBUG] Not found, returning NULL" );
+        return NULL;
+    }
+    else
+    {
+        if ( gDevDebug ) Console->Print( "[DEBUG] Found. Returning address" );
+        return it->second;
+    }
+}
diff --git a/server/src/game/npc_ai.cpp b/server/src/game/npc_ai.cpp
new file mode 100644 (file)
index 0000000..4de4760
--- /dev/null
@@ -0,0 +1,108 @@
+#include "main.h"\r
+#include "npc.h"\r
+\r
+// First try of an "AI" :P\r
+void PNPCWorld::CheckForEnemies(PNPC* nNPC)\r
+{\r
+    //return;\r
+    std::time_t tNow = time(NULL);\r
+    // Is it time for next enemy check?\r
+\r
+    // Temp: Skip that for IDs below 1000\r
+    if(nNPC->GetRealWorldID() < 1000)\r
+        return;\r
+    // -------------\r
+\r
+    if(tNow > nNPC->mNextEnemyCheck)\r
+    {\r
+        //Console->Print("[NPC AI] Checking enemy status for NPC %d", nNPC->GetRealWorldID());\r
+        nNPC->mNextEnemyCheck = time(NULL) + NPC_ENEMYCHECK;\r
+        // Loop all NPCs in my world\r
+\r
+        // tNearestEnemy[0] = WorldID | tNearestEnemy[1] = Distance to us\r
+        u32 tNearestEnemy[2] = {0,0};\r
+\r
+        for ( PNPCMap::iterator it = mNPCs.begin(); it != mNPCs.end(); it++ )\r
+        {\r
+            if(it->second)\r
+            {\r
+                PNPC* tNPC = it->second;\r
+                // Is target = me?\r
+                if(tNPC->GetRealWorldID() == nNPC->GetRealWorldID())\r
+                    continue;\r
+\r
+                u16 tDistance = DistanceApprox(nNPC->mPosX, nNPC->mPosY, nNPC->mPosZ, tNPC->mPosX, tNPC->mPosY, tNPC->mPosZ);\r
+\r
+                // Is NPC infight?\r
+                if(nNPC->GetActionStatus() == NPC_ACTIONSTATE_ATTACK)\r
+                {\r
+                    // If not infight with current target, skip here\r
+                    if(nNPC->mTarget != tNPC->GetRealWorldID())\r
+                        continue;\r
+\r
+                    // He IS with target infight. Check range\r
+                    if(tDistance > 1500)\r
+                        nNPC->StopAttack(); // Enemy ran away :( cancel fight\r
+                    else\r
+                    {\r
+                        //nNPC->Attack(tNPC->GetRealWorldID());\r
+                        continue;           // Enemy is still in range, good! keep attacking him\r
+                    }\r
+\r
+                }\r
+                // Ok, NPC is not infight, so lets check if current iterator target is in range\r
+                if(tDistance > 800)\r
+                    continue;   // No, he's not\r
+\r
+                // He is! Look closer at him. Get Faction standing\r
+                int tFactionMe = nNPC->mFaction;\r
+                int tFactionHim = tNPC->mFaction;\r
+                //Console->Print("[NPC AI] Checking InRange NPC %d; MyFac: %d HisFac: %d", tNPC->GetRealWorldID(), tFactionMe, tFactionHim);\r
+\r
+                // Hey, we're friends :)\r
+                if(tFactionMe == tFactionHim)\r
+                    continue;\r
+\r
+                const PDefFaction* tFaction = NULL;\r
+                int tStanding = 0;\r
+                // Always check higher faction against lower faction\r
+                if(tFactionMe > tFactionHim)\r
+                {\r
+                    tFaction = GameDefs->Factions()->GetDef(tFactionMe);\r
+                    if(!tFaction)\r
+                    {\r
+                        Console->Print("Unknown faction: %d", tFactionMe);\r
+                        continue;\r
+                    }\r
+                    tStanding = tFaction->GetRelation(tFactionHim);\r
+                }\r
+                else\r
+                {\r
+                    tFaction = GameDefs->Factions()->GetDef(tFactionHim);\r
+                    if(!tFaction)\r
+                    {\r
+                        Console->Print("Unknown faction: %d", tFactionHim);\r
+                        continue;\r
+                    }\r
+                    tStanding = tFaction->GetRelation(tFactionMe);\r
+                }\r
+                // Enemies? omg! Check distance!\r
+                if(tStanding < 0)\r
+                {\r
+                    if(tNearestEnemy[1] > tDistance || tNearestEnemy[0] == 0)\r
+                    {\r
+                        // This enemy is even closer than the stored one, or we dont have any enemy yet\r
+                        tNearestEnemy[0] = tNPC->GetRealWorldID();\r
+                        tNearestEnemy[1] = tDistance;\r
+                        Console->Print("NPC ID %d (Distance %d) is an Faction enemy, Standing: %d. Remembering him!", tNearestEnemy[0], tNearestEnemy[1], tStanding);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        if(tNearestEnemy[0] > 0)\r
+        {\r
+            Console->Print("NPC ID %d now attacking NPC ID %d", nNPC->GetRealWorldID(), tNearestEnemy[0]);\r
+            nNPC->Attack(tNearestEnemy[0]);\r
+        }\r
+    }\r
+}\r
diff --git a/server/src/game/npc_conversation.cpp b/server/src/game/npc_conversation.cpp
new file mode 100644 (file)
index 0000000..875d595
--- /dev/null
@@ -0,0 +1,367 @@
+/*\r
+TinNS (TinNS is not a Neocron Server)\r
+Copyright (C) 2005 Linux Addicted Community\r
+maintainer Akiko <akiko@gmx.org>\r
+\r
+This program is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU General Public License\r
+as published by the Free Software Foundation; either version 2\r
+of the License, or (at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+npc_conversation.cpp - Split up file for NPC conversations (Trade and QuestStuff)\r
+\r
+CREATION: 11 Oct 2009 Namikon\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "npc.h"\r
+#include "worlds.h"\r
+#include "npctemplate.h"\r
+#include "worlddatatemplate.h"\r
+#include "msgbuilder.h"\r
+\r
+///***********************************************************************\r
+\r
+bool PNPC::SetShopQuality(u8 nNewVal)\r
+{\r
+    // Ignore that setting if NPC is loaded from .def\r
+    if(mFromDEF == true)\r
+        return false;\r
+\r
+    if(nNewVal == 0)\r
+        return false;\r
+\r
+    mItemQuality = nNewVal;\r
+    return true;\r
+}\r
+\r
+bool PNPC::ReloadShopList()\r
+{\r
+    // Shop list will be reloaded uppon next click\r
+    mVectItemsInShop.erase(mVectItemsInShop.begin(), mVectItemsInShop.end());\r
+    return true;\r
+}\r
+\r
+void PNPC::AddToVectorList(u16 nItemID, u32 nPrice)\r
+{\r
+    stShopListEntry tEntry;\r
+    tEntry.ItemID = nItemID;\r
+    tEntry.Price = nPrice;\r
+    Console->Print("New item in buffer: %d price %d", tEntry.ItemID, tEntry.Price);\r
+    mVectItemsInShop.push_back(tEntry);\r
+}\r
+\r
+void PNPC::ContentListAddItem(PMessage* nContentList, u16 nItemID, u32 nBasePrice, bool nAddToList)\r
+{\r
+    // Items with baseprice = 0 are ignored!\r
+    if(nBasePrice == 0)\r
+        return;\r
+\r
+    // Modify baseprice with Config value\r
+    f32 tPerCent = Config->GetOptionInt("item_price");\r
+    tPerCent = tPerCent / 100;\r
+    u32 tPrice = nBasePrice * tPerCent;\r
+    *nContentList << ( u16 ) nItemID;\r
+    *nContentList << ( u32 )( tPrice );\r
+\r
+    if(nAddToList)\r
+        AddToVectorList(nItemID, tPrice);\r
+\r
+    if (gDevDebug) Console->Print("[PNPC::ContentListAddItem] Adding item: ID: %d Price: %u", nItemID, tPrice);\r
+}\r
+\r
+void PNPC::ContentListAddItemGroup(PMessage* nContentList, u32 nItemGroupID)\r
+{\r
+    const PDefItems* tDefItems = NULL;\r
+    std::map<int, PDefItems*>::const_iterator itStart = GameDefs->Items()->ConstIteratorBegin();\r
+    std::map<int, PDefItems*>::const_iterator itEnd = GameDefs->Items()->ConstIteratorEnd();\r
+    for ( std::map<int, PDefItems*>::const_iterator i = itStart; i != itEnd; i++ )\r
+    {\r
+        tDefItems = i->second;\r
+        if((u32)tDefItems->GetItemGroupID() == nItemGroupID)\r
+        {\r
+            // Pricing: Use Baseprice\r
+            // If Baseprice is 0, use Quality * Techlevel * 2\r
+            u32 tPrice = tDefItems->GetBasePrice();\r
+            if(tPrice == 0)\r
+            {\r
+                tPrice = tDefItems->GetTechlevel() * mItemQuality * 2;\r
+            }\r
+\r
+            ContentListAddItem(nContentList, i->first, tPrice);\r
+        }\r
+    }\r
+}\r
+\r
+bool PNPC::DoSQLShoppingList( PClient* nClient, PMessage* nContentList )\r
+{\r
+    MYSQL_RES *result = NULL;\r
+    MYSQL_ROW row;\r
+    char query[100];\r
+\r
+    snprintf( query, 100, "SELECT * FROM `npc_shop` WHERE `c_npc_id` = %d AND `c_zoneid` = %d", mWorldID, nClient->GetChar()->GetLocation());\r
+    if (gDevDebug) Console->Print( "[PNPC::DoSQLShoppingList] Executing query %s", query );\r
+    result = MySQL->GameResQuery( query );\r
+    if ( result == NULL )\r
+    {\r
+        Console->Print( YELLOW, BLACK, "[PNPC::DoSQLShoppingList] could not load shoplist from SQL" );\r
+        Console->Print( "Query was:" );\r
+        Console->Print( "%s", query );\r
+        MySQL->ShowGameSQLError();\r
+        return false;\r
+    }\r
+    if ( mysql_num_rows( result ) == 0 )\r
+    {\r
+        if (gDevDebug) Console->Print( YELLOW, BLACK, "[PNPC::DoSQLShoppingList] No items found in SQL for NPC %d", mWorldID);\r
+        MySQL->FreeGameSQLResult( result );\r
+        return false;\r
+    }\r
+\r
+    f32 tPerCent = Config->GetOptionInt("item_price");\r
+    tPerCent = tPerCent / 100;\r
+\r
+    while((row = mysql_fetch_row(result)))\r
+    {\r
+        const PDefItems* t_item = GameDefs->Items()->GetDef(atoi( row[2] ));\r
+        if(t_item)\r
+        {\r
+            // Pricing: If no value in DB is set, use Baseprice\r
+            // If Baseprice is 0, use Quality * Techlevel * 2\r
+            u32 tPrice = atoi(row[3]);\r
+            if(tPrice == 0)\r
+            {\r
+                tPrice = t_item->GetBasePrice();\r
+                if(tPrice == 0)\r
+                {\r
+                    tPrice = t_item->GetTechlevel() * mItemQuality * 2;\r
+                }\r
+            }\r
+\r
+            // Modify price as told in config\r
+            tPrice = tPrice * tPerCent;\r
+            u16 tItemID = atoi(row[2]);\r
+\r
+            *nContentList << ( u16 ) tItemID;\r
+            *nContentList << ( u32 ) tPrice;\r
+\r
+            // Store item position in list for later trade stuff\r
+            AddToVectorList(tItemID, tPrice);\r
+\r
+            if (gDevDebug) Console->Print("Adding item: ID: %d Price: %d",  tItemID, tPrice);\r
+        }\r
+    }\r
+    MySQL->FreeGameSQLResult( result );\r
+    return true;\r
+}\r
+\r
+bool PNPC::IsAllbuyer( PClient* nClient )\r
+{\r
+    MYSQL_RES *result = NULL;\r
+    char query[100];\r
+\r
+    snprintf( query, 100, "SELECT * FROM `npc_shop` WHERE `c_npc_id` = %d AND `c_zoneid` = %d and `c_itemid` = -1", mWorldID, nClient->GetChar()->GetLocation());\r
+    Console->Print( "[PNPC::IsAllbuyer] Executing query %s", query );\r
+    result = MySQL->GameResQuery( query );\r
+    if ( result == NULL )\r
+    {\r
+        Console->Print( YELLOW, BLACK, "[PNPC::IsAllbuyer] could not check if npc is allbuyer" );\r
+        Console->Print( "Query was:" );\r
+        Console->Print( "%s", query );\r
+        MySQL->ShowGameSQLError();\r
+        return false;\r
+    }\r
+    int count = mysql_num_rows(result);\r
+    MySQL->FreeGameSQLResult( result );\r
+    if(count > 0)\r
+        return true;\r
+    else\r
+        return false;\r
+}\r
+\r
+bool PNPC::HasSQLShoppingList( PClient* nClient )\r
+{\r
+    MYSQL_RES *result = NULL;\r
+    char query[100];\r
+\r
+    snprintf( query, 100, "SELECT * FROM `npc_shop` WHERE `c_npc_id` = %d AND `c_zoneid` = %d", mWorldID, nClient->GetChar()->GetLocation());\r
+    Console->Print( "[PNPC::HasSQLShoppingList] Executing query %s", query );\r
+    result = MySQL->GameResQuery( query );\r
+    if ( result == NULL )\r
+    {\r
+        Console->Print( YELLOW, BLACK, "[PNPC::HasSQLShoppingList] could not load shoplist from SQL" );\r
+        Console->Print( "Query was:" );\r
+        Console->Print( "%s", query );\r
+        MySQL->ShowGameSQLError();\r
+        return false;\r
+    }\r
+    int count = mysql_num_rows(result);\r
+    MySQL->FreeGameSQLResult( result );\r
+    if(count > 0)\r
+        return true;\r
+    else\r
+        return false;\r
+}\r
+\r
+void PNPC::StartDialog( PClient* nClient/*, string &nDialogscript*/ )\r
+{\r
+    std::string t_ScriptName = "";\r
+    if(mFromDEF == false && mCustomLua.length() > 1)\r
+    {\r
+        char tmpnum[11];\r
+        snprintf(tmpnum, 11, "%d", mID);\r
+        t_ScriptName = tmpnum;\r
+    }\r
+    else\r
+    {\r
+        t_ScriptName = mDialogScript;\r
+    }\r
+\r
+    u32 tWorldID = GetRealWorldID();\r
+    // Starts dialog with NPC\r
+    // First, set required values in client's char\r
+    nClient->GetChar()->SetDialogNPC(mWorldID);\r
+    nClient->GetChar()->SetDialogNode(0);\r
+\r
+    // Second generate start-dialog message\r
+    PMessage* tmpMsg = MsgBuilder->BuildNPCStartDialogMsg(nClient, tWorldID, &t_ScriptName);\r
+    nClient->SendUDPMessage(tmpMsg);\r
+\r
+    Console->Print("[PNPC::StartDialog] Sending NPC DialogStart for Script %s", t_ScriptName.c_str());\r
+    return;\r
+}\r
+\r
+void PNPC::StartConversation( PClient* nClient )\r
+{\r
+    // Set Offset to mWorldID\r
+    // .def NPCs need this offset in order to work\r
+    u32 tRealID = GetRealWorldID();\r
+\r
+    // Check if NPC has script for talking\r
+    // OR\r
+    // Check if NPC is from SQL and has a custom LUA script stored in DB\r
+    if(mScripting == true)\r
+    {\r
+        if(mDialogScript.length() > 0 || (mFromDEF == false && mCustomLua.length() > 1))\r
+        {\r
+            StartDialog(nClient);\r
+            return;\r
+        }\r
+    }\r
+\r
+    // Check if NPC has a TradeID\r
+    Console->Print("[DEBUG] NPC WorldID %u  NPC TraderDefID %u", tRealID, mTrader);\r
+    if(IsAllbuyer(nClient) == true)\r
+    {\r
+        PMessage* tmpMsg = MsgBuilder->BuildNPCBeginAllBuyerTradeMsg(nClient, tRealID);\r
+        nClient->SendUDPMessage(tmpMsg);\r
+\r
+        return;\r
+    }\r
+\r
+    if(mTrader > 0)\r
+    {\r
+        // NPC is a trader. Fetch trader template from def\r
+        const PDefTrader* nTraderDef = GameDefs->Traders()->GetDef(mTrader);\r
+\r
+        // Is the NPC a trading one? (Def-defined)\r
+        if(nTraderDef)\r
+        {\r
+            // Preparing ItemList for shopping\r
+            PMessage* ContentList = new PMessage();\r
+\r
+            // Check if we already have our Vector filled with itemIDs\r
+            if(mVectItemsInShop.size() > 0)\r
+            {\r
+                Console->Print("Using Vector shopping list");\r
+                vector <stShopListEntry>::iterator it;\r
+                for(it = mVectItemsInShop.begin(); it < mVectItemsInShop.end(); it++)\r
+                    ContentListAddItem(ContentList, (*it).ItemID, (*it).Price, false);\r
+            }\r
+            else\r
+            {\r
+                int t_ItemGroupID = nTraderDef->GetType();\r
+                int t_CurrItem = 0;\r
+                int t_DefItemEnt = nTraderDef->GetItemId(t_CurrItem);\r
+                while(t_DefItemEnt != 0)\r
+                {\r
+                    // Loop through all item(groups) in trader.def\r
+                    if(t_DefItemEnt < 0)\r
+                    {\r
+                        // We got a ItemGroup\r
+                        ContentListAddItemGroup(ContentList, (t_DefItemEnt * -1));\r
+                    }\r
+                    else\r
+                    {\r
+                        // We got a normal Item\r
+                        ContentListAddItem(ContentList, t_DefItemEnt, 0, nTraderDef->GetQuality());\r
+                    }\r
+\r
+                    t_DefItemEnt = nTraderDef->GetItemId(++t_CurrItem);\r
+                }\r
+                if (gDevDebug) Console->Print("[PNPC::StartConversation] TraderTemplate: %d, Type: %d", mTrader, t_ItemGroupID);\r
+            }\r
+\r
+\r
+            // Step 2: Send Packet to start trade\r
+            PMessage* tmpMsg = MsgBuilder->BuildNPCShoppingListMsg(nClient, ContentList, tRealID, nTraderDef->GetQuality());\r
+            nClient->FragmentAndSendUDPMessage(tmpMsg, 0xac);\r
+\r
+            delete ContentList;\r
+        }\r
+        else\r
+        {\r
+            Console->Print( YELLOW, BLACK, "[PNPC::StartConversation] unknown/invalid traderID ignoring traderequest" );\r
+            return;\r
+        }\r
+    }\r
+    // Not a regular trader? Check if we have some SQL Based shopping list\r
+    else if(HasSQLShoppingList(nClient) == true)\r
+    {\r
+        PMessage* ContentList = new PMessage();\r
+        if(DoSQLShoppingList(nClient, ContentList) == true)\r
+        {\r
+            PMessage* tmpMsg = MsgBuilder->BuildNPCShoppingListMsg(nClient, ContentList, tRealID, mItemQuality);\r
+            nClient->FragmentAndSendUDPMessage(tmpMsg, 0xac);\r
+\r
+            delete ContentList;\r
+        }\r
+        else\r
+        {\r
+            Console->Print( RED, BLACK, "[PNPC::StartConversation] Failed to generate SQL Shopping list" );\r
+            delete ContentList;\r
+        }\r
+        return;\r
+    }\r
+    else\r
+    {\r
+        // No script found? No shopping list? Well, then this NPC looks.. inactive :)\r
+        if (gDevDebug) Console->Print("[PNPC::StartConversation] Inactive NPC");\r
+        return;\r
+    }\r
+}\r
+\r
+\r
+// DoConversation:\r
+// nClient : The client which startet the conversation / is doing it right now\r
+// nAnswer: the Answer the player clicked\r
+void PNPC::DoConversation( PClient* nClient, u8 nAnswer )\r
+{\r
+    // LUA Engine v3: Let the LuaEngine handle everything!\r
+    LuaEngine->ProcessDialogScript(nClient, mLUAFile, nAnswer);\r
+\r
+    return;\r
+}\r
diff --git a/server/src/game/npctemplate.cpp b/server/src/game/npctemplate.cpp
new file mode 100644 (file)
index 0000000..6d280fc
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+
+/*
+npctemplate.cpp - NPC template class
+
+MODIFIED: 21 Jun 2009 Namikon
+REASON: - creation
+
+*/
+
+
+#include "main.h"
+#include "npctemplate.h"
+
+PNPCTemplate::PNPCTemplate()
+{
+    mUnknown1 = 0;
+    mPosY = 0.0f;
+    mPosZ = 0.0f;
+    mPosX = 0.0f;
+    mNPCTypeID = 0;
+    mActorStringSize = 0;
+    mAngleStringSize = 0;
+    mNpcID = 0;
+    mHasAdditionalCoords = 0;
+    mUnknown2a = 0;
+    mUnknown2b = 0;
+    mUnknown2c = 0;
+    /*mUnknown3*/mTradeID = 0;
+    mUnknown4 = 0;
+    mActorName = "";
+    mAngle = "";
+}
+
+PNPCTemplate::~PNPCTemplate()
+{
+    // Cleanup waypoints
+    for ( PWaypointMap::iterator i = mWayPoints.begin(); i != mWayPoints.end(); i++ )
+        delete i->second;
+}
+
+void PNPCTemplate::AddWayPoint(f32 nX, f32 nY, f32 nZ, u8 nID)
+{
+    struct s_f32coords *tWayPoint = new s_f32coords;
+    tWayPoint->mX = nX;
+    tWayPoint->mY = nY;
+    tWayPoint->mZ = nZ;
+
+    if ( mWayPoints.insert( std::make_pair( nID, tWayPoint)).second )
+        if ( gDevDebug ) Console->Print( "%s Waypoint %d (X %0.1f Y %0.1f Z %0.1f) added to NPC", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nID, nX, nY, nZ );
+}
diff --git a/server/src/game/outpost.cpp b/server/src/game/outpost.cpp
new file mode 100644 (file)
index 0000000..91c3f57
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+TinNS (TinNS is not a Neocron Server)
+Copyright (C) 2005 Linux Addicted Community
+maintainer Akiko <akiko@gmx.org>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+*/
+
+/*
+
+outpost.cpp - TinNS outpost handling
+
+CREATION: 24 Oct 2009 Namikon
+
+*/
+
+#include "main.h"
+#include "msgbuilder.h"
+
+POutpost::POutpost()
+{
+}
+
+POutpost::~POutpost()
+{
+}
+
+u32 POutpost::GetCurrentClan(u32 nOutpostID)
+{
+    MYSQL_RES *result = NULL;
+    char tQuery[200];
+
+    snprintf(tQuery, 200, "SELECT o_clan FROM outposts WHERE o_outnum = %d", nOutpostID);
+    result = MySQL->GameResQuery(tQuery);
+
+    if(!result)
+    {
+        Console->Print("%s [POutpost::GetCurrentClan] Cannot query SQL. Query was: %s", Console->ColorText(RED,BLACK,"Error"), tQuery);
+        MySQL->ShowGameSQLError();
+        return 0;
+    }
+
+    if(mysql_num_rows(result) == 0)
+    {
+        Console->Print("%s [POutpost::GetCurrentClan] Invalid or missing Outpost data for Outpost: %d", Console->ColorText(RED,BLACK,"Error"), nOutpostID);
+        return 0;
+    }
+
+    u32 tClanID = atoi(mysql_fetch_row(result)[0]);
+
+    MySQL->FreeGameSQLResult(result);
+    return tClanID;
+}
+
+// Check if given nZoneID is an outpost area
+bool POutpost::IsZoneOPArea(u32 nZoneID)
+{
+    // Outpost ID == WorldID
+    // Outpost Underground = WorldID + 2000
+    // Only process possible outpost zones and their undergrounds
+
+    if((nZoneID > 2005 && nZoneID < 2213) || (nZoneID > 4005 && nZoneID < 4213))
+    {
+        const PDefWorld* tWorldDef = GameDefs->Worlds()->GetDef( nZoneID );
+        if ( tWorldDef )
+            return true;
+    }
+    return false;
+}
+
+// Sends Outpostinfo to client
+void POutpost::SendOPAreaData(PClient* nClient)
+{
+    if(!nClient)
+        return;
+
+    MYSQL_RES *result = NULL;
+    MYSQL_ROW row = NULL;
+    char tQuery[200];
+    int nZoneID = nClient->GetChar()->GetLocation();
+
+    if(IsZoneOPArea(nZoneID) == false)
+    {
+        if (gDevDebug) Console->Print("ZoneID %d is not an outpost. Skipping", nZoneID);
+        return;
+    }
+    // Fix underground ID
+    if(nZoneID > 4000)
+        nZoneID -= 2000;
+
+    snprintf(tQuery, 200, "SELECT cl_id, cl_faction FROM clans INNER JOIN outposts ON (o_clan = cl_id) WHERE o_outnum = %d", nZoneID);
+    result = MySQL->GameResQuery(tQuery);
+
+    if(!result)
+    {
+        Console->Print("%s [POutpost::SendOPAreaData] Cannot query SQL. Query was: %s", Console->ColorText(RED,BLACK,"Error"), tQuery);
+        MySQL->ShowGameSQLError();
+        return;
+    }
+
+    if(mysql_num_rows(result) == 0)
+    {
+        Console->Print("%s [POutpost::SendOPAreaData] Invalid or missing Outpost data for ZoneID: %d", Console->ColorText(RED,BLACK,"Error"), nZoneID);
+        return;
+    }
+
+    row = mysql_fetch_row(result);
+
+    u32 tClanID = atoi(row[0]);
+    u8 tFactionID = atoi(row[1]);
+
+    MySQL->FreeGameSQLResult(result);
+
+    Console->Print("ZoneID %d is an outpost. Sending Clan/Faction information... Clan: %d Faction: %d", nZoneID, tClanID, tFactionID);
+    PMessage* tMsg = MsgBuilder->BuildOutpostClanInfoMsg( nClient, tClanID, tFactionID );
+    nClient->SendUDPMessage( tMsg );
+}
diff --git a/server/src/game/rconsole.cpp.inhib b/server/src/game/rconsole.cpp.inhib
new file mode 100644 (file)
index 0000000..285c78e
--- /dev/null
@@ -0,0 +1,265 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+        rconsole.cpp\r
+\r
+        Authors:\r
+        - Akiko\r
+        - Namikon\r
+        - someone else?\r
+\r
+        MODIFIED: Unknown date / Unknown author\r
+        REASON: - initial release by unknown\r
+\r
+        MODIFIED: 25 Dec 2005 Namikon\r
+        REASON: - Added GPL\r
+*/\r
+\r
+#include "main.h"\r
+\r
+static const int RCON_INPUTLEN = 512;\r
+\r
+struct PRConClient\r
+{\r
+       enum\r
+       {\r
+               RCCS_AUTH,\r
+               RCCS_AUTH_USER,\r
+               RCCS_AUTH_PASS,\r
+               RCCS_VALID,\r
+               RCCS_DISCONNECT\r
+       } mState;\r
+\r
+       PSocket *mSocket;\r
+       PAccount *mAccount;\r
+       char mInput[RCON_INPUTLEN];\r
+       int mInputLen;\r
+       bool mEcho;\r
+       std::clock_t mSleep, mSleepStart;\r
+       int mNumFailures;\r
+\r
+       inline PRConClient(NLsocket &Sock)\r
+       {\r
+               mSocket = new PSocket(Sock);\r
+               mAccount = 0;\r
+               mInputLen = 0;\r
+               mEcho = true;\r
+               mSleep = 0;\r
+               mSleepStart = 0;\r
+               mNumFailures = 0;\r
+       }\r
+\r
+       inline ~PRConClient()\r
+       {\r
+               delete mSocket;\r
+       }\r
+\r
+       inline void Print(const char *Fmt, ...)\r
+       {\r
+               static char Str[256];\r
+               va_list args;\r
+               va_start(args, Fmt);\r
+               vsnprintf(Str, 255, Fmt, args);\r
+               va_end(args);\r
+               mSocket->Write(Str);\r
+       }\r
+\r
+};\r
+\r
+PRConsole::PRConsole()\r
+{\r
+       mListener = NL_INVALID;\r
+}\r
+\r
+PRConsole::~PRConsole()\r
+{\r
+       if(mListener != NL_INVALID)\r
+               nlClose(mListener);\r
+\r
+       for(ClientList::iterator i=mClients.begin(); i!=mClients.end(); i++)\r
+               delete *i;\r
+}\r
+\r
+void PRConsole::Start()\r
+{\r
+  // CHECK FOR rconsole enabled!!!\r
+       Console->LPrint("Starting remote console...");\r
+       u16 Port = Config->GetOptionInt("rconsole_port");\r
+       mListener = nlOpen(Port, NL_TCP);\r
+       if(mListener == NL_INVALID)\r
+       {\r
+               Console->LPrint(RED, BLACK, "[ERROR]");\r
+               Console->LPrint(" Remote console failed");\r
+               Console->LClose();\r
+               return;\r
+       }\r
+\r
+       Console->LPrint(GREEN, BLACK, "Success");\r
+       Console->LClose();\r
+       nlListen(mListener);\r
+}\r
+\r
+void PRConsole::Update()\r
+{\r
+       if(mListener==NL_INVALID)\r
+               return;\r
+\r
+       NLsocket temp = nlAcceptConnection(mListener);\r
+       if(temp != NL_INVALID)\r
+       {\r
+               // TODO: print client ip addr\r
+               Console->Print("RConsole: client connected");\r
+               PRConClient *cl = new PRConClient(temp);\r
+               cl->mState = PRConClient::RCCS_AUTH;\r
+               mClients.push_back(cl);\r
+               cl->Print("TinNS shell [%s]\r\n", TINNS_VERSION);\r
+       }\r
+\r
+       for(ClientList::iterator i=mClients.begin(); i!=mClients.end();)\r
+       {\r
+               ClientList::iterator j=i;\r
+               PRConClient *cl = *i;\r
+               ++i;\r
+               if(!cl->mSocket->Update() || cl->mSocket->TimeOut())\r
+               {\r
+                       Console->Print("RConsole: client disconnected");\r
+                       mClients.erase(j);\r
+                       delete cl;\r
+                       continue;\r
+               }\r
+\r
+               if(cl->mSleep > 0)\r
+               {\r
+                       std::clock_t t = std::clock();\r
+                       cl->mSleep -= (t-cl->mSleepStart);\r
+                       cl->mSleepStart = t;\r
+\r
+                       if(cl->mSleep < 0)\r
+                               cl->mSleep = 0;\r
+\r
+                       // flush socket while sleeping\r
+                       int Size=0;\r
+                       cl->mSocket->Read(&Size);\r
+\r
+                       continue;\r
+               }\r
+\r
+               if(cl->mState==PRConClient::RCCS_AUTH)\r
+               {\r
+                       cl->Print("\r\nlogin: ");\r
+                       cl->mState = PRConClient::RCCS_AUTH_USER;\r
+               }\r
+\r
+               const u8 *Buf = 0;\r
+               int Size=0;\r
+               if((bool)(Buf = cl->mSocket->Read(&Size)))\r
+               {\r
+                       for(int i=0; i<Size; i++)\r
+                               if(cl->mInputLen < RCON_INPUTLEN)\r
+                               {\r
+                                       switch(Buf[i])\r
+                                       {\r
+                                               case 0x08 :\r
+                                               {\r
+                                                       if(cl->mInputLen > 0)\r
+                                                       {\r
+                                                               if(cl->mEcho)\r
+                                                                       cl->mSocket->Write(Buf[i]);\r
+                                                               cl->mInput[cl->mInputLen]=0;\r
+                                                               --cl->mInputLen;\r
+                                                       }\r
+                                                       break;\r
+                                               }\r
+\r
+                                               case '\n' :\r
+                                               {\r
+                                                       if(cl->mEcho)\r
+                                                               cl->mSocket->Write(Buf[i]);\r
+                                                       cl->mInput[cl->mInputLen]=0;\r
+                                                       ProcessClient(cl);\r
+                                                       cl->mInputLen = 0;\r
+                                                       break;\r
+                                               }\r
+\r
+                                               default :\r
+                                               {\r
+                                                       cl->mInput[cl->mInputLen++]=Buf[i];\r
+                                                       if(cl->mEcho)\r
+                                                               cl->mSocket->Write(Buf[i]);\r
+                                                       break;\r
+                                               }\r
+                                       }\r
+                               }\r
+               }\r
+       }\r
+}\r
+\r
+void PRConsole::ProcessClient(PRConClient* Client)\r
+{\r
+       Console->Print(">%s", Client->mInput);\r
+       if(Client->mInputLen > 1)\r
+       {\r
+               if(Client->mInput[Client->mInputLen-1] == '\r')\r
+                       Client->mInput[Client->mInputLen-1]=0;\r
+\r
+               if(Client->mState == PRConClient::RCCS_AUTH_USER)\r
+               {\r
+                       Client->mAccount = Database->GetAccount(Client->mInput);\r
+                       Client->mState = PRConClient::RCCS_AUTH_PASS;\r
+                       Client->Print("password: ");\r
+                       Client->mEcho = false;\r
+               } else\r
+               if(Client->mState == PRConClient::RCCS_AUTH_PASS)\r
+               {\r
+                       Client->mEcho = true;\r
+                       if((!Client->mAccount) || (Client->mAccount->GetPassword() != Client->mInput) || (!Client->mAccount->IsConsoleAllowed()))\r
+                       {\r
+                               Client->Print("Invalid user or password\r\n");\r
+                               Client->mSleepStart = std::clock();\r
+                               ++Client->mNumFailures;\r
+                               if(Client->mNumFailures >= 3)\r
+                               {\r
+                                       // sleep 1 minute\r
+                                       Client->mSleep = 60*CLOCKS_PER_SEC;\r
+                                       Client->mNumFailures = 0;\r
+                               } else\r
+                                       Client->mSleep = 5*CLOCKS_PER_SEC;\r
+\r
+                               Client->mState = PRConClient::RCCS_AUTH;\r
+                       } else\r
+                       {\r
+                               Client->Print("\r\n\nUser %s logged in\r\n", Client->mAccount->GetName().c_str());\r
+                               Client->mState = PRConClient::RCCS_VALID;\r
+                               // disconnect after 30 minutes lacking socket activity\r
+                               Client->mSocket->SetTimeOutValue(1800);\r
+                               Prompt(Client);\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+void PRConsole::Prompt(PRConClient *Client)\r
+{\r
+       Client->Print("$ ", Client->mAccount->GetName().c_str(), Config->GetOption("server_name").c_str());\r
+}\r
diff --git a/server/src/game/server.cpp b/server/src/game/server.cpp
new file mode 100644 (file)
index 0000000..df19173
--- /dev/null
@@ -0,0 +1,116 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+        server.cpp\r
+\r
+        Authors:\r
+        - Akiko\r
+        - Namikon\r
+        - someone else?\r
+\r
+        MODIFIED: Unknown date / Unknown author\r
+        REASON: - initial release by unknown\r
+\r
+        MODIFIED: 25 Dec 2005 Namikon\r
+        REASON: - Added GPL\r
+*/\r
+#include "main.h"\r
+\r
+PServer::PServer()\r
+{\r
+       mNumClients = 0;\r
+       mMaxClients = Config->GetOptionInt("maxclients");\r
+       mGMSlots = Config->GetOptionInt("gm_slots");\r
+       if(mMaxClients==0)\r
+               mMaxClients=1;\r
+       if(mGMSlots==0)\r
+               mGMSlots=1;\r
+       Console->Print("Max clients: %i / GM slots: %i", mMaxClients, mGMSlots);\r
+       mClients.reserve(mMaxClients + mGMSlots);\r
+       for(int i=0; i<mMaxClients+mGMSlots; i++)\r
+               mClients[i]=0;\r
+}\r
+\r
+PServer::~PServer()\r
+{\r
+       for(int i=0; i<mMaxClients+mGMSlots; i++)\r
+               delete mClients[i];\r
+}\r
+\r
+int PServer::NewClient()\r
+{\r
+       if(mNumClients==mMaxClients+mGMSlots)\r
+               return -1;\r
+\r
+       for(int i=0; i<mMaxClients+mGMSlots; i++)\r
+       {\r
+               if(!mClients[i])\r
+               {\r
+                       mClients[i]=new PClient(i);\r
+                       ++mNumClients;\r
+                       return i;\r
+               }\r
+       }\r
+       return -1;\r
+}\r
+\r
+PClient *PServer::GetClient(int Client) const\r
+{\r
+       if(Client < 0 || Client >= mMaxClients+mGMSlots)\r
+               return 0;\r
+\r
+       return mClients[Client];\r
+}\r
+\r
+void PServer::Update()\r
+{\r
+       for(int i=0; i<mMaxClients+mGMSlots; i++)\r
+       {\r
+               if(mClients[i])\r
+               {\r
+                       mClients[i]->Update();\r
+                       if(mClients[i]->GetConnection()==PCC_NONE && mClients[i]->getTCPConn() == 0)\r
+                       {\r
+                               Console->Print("Removing client %i...", i);\r
+                               delete mClients[i];\r
+                               mClients[i]=0;\r
+                               --mNumClients;\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+void PServer::Shutdown()\r
+{\r
+    Console->Print("======================");\r
+       Console->Print("Shutting down Gameserver...");\r
+       for(int i=0; i<mMaxClients+mGMSlots; i++)\r
+       {\r
+               if(mClients[i])\r
+               {\r
+                       delete mClients[i];\r
+                       mClients[i]=0;\r
+               }\r
+       }\r
+}\r
+\r
+//SELECT `s_name` , NOW( ) , `s_lastupdate` , NOW( ) - `s_lastupdate` FROM `server_list` \r
diff --git a/server/src/game/skill.cpp b/server/src/game/skill.cpp
new file mode 100644 (file)
index 0000000..74b76b2
--- /dev/null
@@ -0,0 +1,698 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+
+
+/*
+       skill.cpp
+
+       Authors:
+       - Namikon
+
+       MODIFIED: 18 Dec 2005 Namikon
+       REASON: - Initial Release
+       MODIFIED: 01 Jan 2006 Namikon
+       REASON: - Initial Release
+            - Added SetMainSkill()
+            - Added SetSubSkill()
+            - Added SetXP()
+            - Added SetSP()
+            - Removed IncreaseSubSkill and IncreaseMainSkill
+
+*/
+#include "main.h"
+
+void PSkillHandler::SetMainSkill(MAIN_SKILLS Skill, int value)
+{
+    switch (Skill)
+    {
+    case MS_STR:
+        m_Skills.Main->mSTR = value;
+        break;
+
+    case MS_DEX:
+        m_Skills.Main->mDEX = value;
+        break;
+
+    case MS_CON:
+        m_Skills.Main->mCON = value;
+        break;
+
+    case MS_INT:
+        m_Skills.Main->mINT = value;
+        break;
+
+    case MS_PSI:
+        m_Skills.Main->mPSI = value;
+        break;
+    };
+}
+
+void PSkillHandler::SetSubSkill(SUB_SKILLS Skill, int value)
+{
+    switch (Skill)
+    {
+// STR Skills ------------------------
+    case SK_MC:
+        m_Skills.STR->mMC = value;
+        break;
+
+    case SK_HC:
+        m_Skills.STR->mHC = value;
+        break;
+
+    case SK_TRA:
+        m_Skills.STR->mTRA = value;
+        break;
+
+    case SK_FOR:
+        m_Skills.STR->mFOR = value;
+        break;
+// DEX Skills ------------------------
+    case SK_PC:
+        m_Skills.DEX->mPC = value;
+        break;
+
+    case SK_RC:
+        m_Skills.DEX->mRC = value;
+        break;
+
+    case SK_TC:
+        m_Skills.DEX->mTC = value;
+        break;
+
+    case SK_VHC:
+        m_Skills.DEX->mVHC = value;
+        break;
+
+    case SK_AGL:
+        m_Skills.DEX->mAGL = value;
+        break;
+
+    case SK_REP:
+        m_Skills.DEX->mREP = value;
+        break;
+
+    case SK_REC:
+        m_Skills.DEX->mREC = value;
+        break;
+
+    case SK_RCL:
+        m_Skills.DEX->mRCL = value;
+        break;
+// CON Skills ------------------------
+    case SK_ATL:
+        m_Skills.CON->mATL = value;
+        break;
+
+    case SK_END:
+        m_Skills.CON->mEND = value;
+        break;
+
+    case SK_FIR:
+        m_Skills.CON->mFIR = value;
+        break;
+
+    case SK_ENR:
+        m_Skills.CON->mENR = value;
+        break;
+
+    case SK_XRR:
+        m_Skills.CON->mXRR = value;
+        break;
+
+    case SK_POR:
+        m_Skills.CON->mPOR = value;
+        break;
+
+    case SK_HLT:
+        m_Skills.CON->mHLT = value;
+        break;
+// INT Skills ------------------------
+    case SK_HCK:
+        m_Skills.INT->mHCK = value;
+        break;
+
+    case SK_BRT:
+        m_Skills.INT->mBRT = value;
+        break;
+
+    case SK_PSU:
+        m_Skills.INT->mPSU = value;
+        break;
+
+    case SK_WEP:
+        m_Skills.INT->mWEP = value;
+        break;
+
+    case SK_CST:
+        m_Skills.INT->mCST = value;
+        break;
+
+    case SK_RES:
+        m_Skills.INT->mRES = value;
+        break;
+
+    case SK_IMP:
+        m_Skills.INT->mIMP = value;
+        break;
+
+    case SK_WPW:
+        m_Skills.INT->mWPW = value;
+        break;
+// PSI Skills ------------------------
+    case SK_PPU:
+        m_Skills.PSI->mPPU = value;
+        break;
+
+    case SK_APU:
+        m_Skills.PSI->mAPU = value;
+        break;
+
+    case SK_MST:
+        m_Skills.PSI->mMST = value;
+        break;
+
+    case SK_PPW:
+        m_Skills.PSI->mPPW = value;
+        break;
+
+    case SK_PSR:
+        m_Skills.PSI->mPSR = value;
+        break;
+    };
+}
+
+void PSkillHandler::SetXP(MAIN_SKILLS Skill, float value)
+{
+    switch (Skill)
+    {
+    case MS_STR:
+        m_Skills.Main->mSTRxp = value;
+        break;
+
+    case MS_DEX:
+        m_Skills.Main->mDEXxp = value;
+        break;
+
+    case MS_CON:
+        m_Skills.Main->mCONxp = value;
+        break;
+
+    case MS_INT:
+        m_Skills.Main->mINTxp = value;
+        break;
+
+    case MS_PSI:
+        m_Skills.Main->mPSIxp = value;
+        break;
+    };
+}
+
+void PSkillHandler::SetSP(MAIN_SKILLS Skill, short value)
+{
+    switch (Skill)
+    {
+    case MS_STR:
+        m_Skills.Main->mSTRsp = value;
+        break;
+
+    case MS_DEX:
+        m_Skills.Main->mDEXsp = value;
+        break;
+
+    case MS_CON:
+        m_Skills.Main->mCONsp = value;
+        break;
+
+    case MS_INT:
+        m_Skills.Main->mINTsp = value;
+        break;
+
+    case MS_PSI:
+        m_Skills.Main->mPSIsp = value;
+        break;
+    };
+}
+
+int PSkillHandler::GetMainSkill(MAIN_SKILLS Skill)
+{
+    switch (Skill)
+    {
+    case MS_STR:
+        return m_Skills.Main->mSTR;
+        break;
+
+    case MS_DEX:
+        return m_Skills.Main->mDEX;
+        break;
+
+    case MS_CON:
+        return m_Skills.Main->mCON;
+        break;
+
+    case MS_INT:
+        return m_Skills.Main->mINT;
+        break;
+
+    case MS_PSI:
+        return m_Skills.Main->mPSI;
+        break;
+    }
+    return 0;
+}
+
+int PSkillHandler::GetSubSkill(SUB_SKILLS Skill)
+{
+    switch (Skill)
+    {
+// STR Skills ------------------------
+    case SK_MC:
+        return m_Skills.STR->mMC;
+        break;
+
+    case SK_HC:
+        return m_Skills.STR->mHC;
+        break;
+
+    case SK_TRA:
+        return m_Skills.STR->mTRA;
+        break;
+
+    case SK_FOR:
+        return m_Skills.STR->mFOR;
+        break;
+// DEX Skills ------------------------
+    case SK_PC:
+        return m_Skills.DEX->mPC;
+        break;
+
+    case SK_RC:
+        return m_Skills.DEX->mRC;
+        break;
+
+    case SK_TC:
+        return m_Skills.DEX->mTC;
+        break;
+
+    case SK_VHC:
+        return m_Skills.DEX->mVHC;
+        break;
+
+    case SK_AGL:
+        return m_Skills.DEX->mAGL;
+        break;
+
+    case SK_REP:
+        return m_Skills.DEX->mREP;
+        break;
+
+    case SK_REC:
+        return m_Skills.DEX->mREC;
+        break;
+
+    case SK_RCL:
+        return m_Skills.DEX->mRCL;
+        break;
+// CON Skills ------------------------
+    case SK_ATL:
+        return m_Skills.CON->mATL;
+        break;
+
+    case SK_END:
+        return m_Skills.CON->mEND;
+        break;
+
+    case SK_FIR:
+        return m_Skills.CON->mFIR;
+        break;
+
+    case SK_ENR:
+        return m_Skills.CON->mENR;
+        break;
+
+    case SK_XRR:
+        return m_Skills.CON->mXRR;
+        break;
+
+    case SK_POR:
+        return m_Skills.CON->mPOR;
+        break;
+
+    case SK_HLT:
+        return m_Skills.CON->mHLT;
+        break;
+// INT Skills ------------------------
+    case SK_HCK:
+        return m_Skills.INT->mHCK;
+        break;
+
+    case SK_BRT:
+        return m_Skills.INT->mBRT;
+        break;
+
+    case SK_PSU:
+        return m_Skills.INT->mPSU;
+        break;
+
+    case SK_WEP:
+        return m_Skills.INT->mWEP;
+        break;
+
+    case SK_CST:
+        return m_Skills.INT->mCST;
+        break;
+
+    case SK_RES:
+        return m_Skills.INT->mRES;
+        break;
+
+    case SK_IMP:
+        return m_Skills.INT->mIMP;
+        break;
+
+    case SK_WPW:
+        return m_Skills.INT->mWPW;
+        break;
+// PSI Skills ------------------------
+    case SK_PPU:
+        return m_Skills.PSI->mPPU;
+        break;
+
+    case SK_APU:
+        return m_Skills.PSI->mAPU;
+        break;
+
+    case SK_MST:
+        return m_Skills.PSI->mMST;
+        break;
+
+    case SK_PPW:
+        return m_Skills.PSI->mPPW;
+        break;
+
+    case SK_PSR:
+        return m_Skills.PSI->mPSR;
+        break;
+    };
+    return 0;
+}
+
+int PSkillHandler::GetSKPCost(SUB_SKILLS Skill)
+{
+    int skillvalue = GetSubSkill(Skill);
+
+    if (skillvalue < 50)
+    {
+        return 1;
+    }
+    else if (skillvalue < 75)
+    {
+        return 2;
+    }
+    else if (skillvalue < 100)
+    {
+        return 3;
+    }
+    else
+    {
+        return 5;
+    }
+}
+
+unsigned short PSkillHandler::GetSP(MAIN_SKILLS Skill)
+{
+    switch (Skill)
+    {
+    case MS_STR:
+        return m_Skills.Main->mSTRsp;
+        break;
+
+    case MS_DEX:
+        return m_Skills.Main->mDEXsp;
+        break;
+
+    case MS_CON:
+        return m_Skills.Main->mCONsp;
+        break;
+
+    case MS_INT:
+        return m_Skills.Main->mINTsp;
+        break;
+
+    case MS_PSI:
+        return m_Skills.Main->mPSIsp;
+        break;
+    };
+    return 0;
+}
+
+float PSkillHandler::GetXP(MAIN_SKILLS Skill)
+{
+    switch (Skill)
+    {
+    case MS_STR:
+        return m_Skills.Main->mSTRxp;
+        break;
+
+    case MS_DEX:
+        return m_Skills.Main->mDEXxp;
+        break;
+
+    case MS_CON:
+        return m_Skills.Main->mCONxp;
+        break;
+
+    case MS_INT:
+        return m_Skills.Main->mINTxp;
+        break;
+
+    case MS_PSI:
+        return m_Skills.Main->mPSIxp;
+        break;
+    };
+    return 0;
+}
+
+MAIN_SKILLS PSkillHandler::GetMSfromSS(SUB_SKILLS Skill)
+{
+    switch (Skill)
+    {
+    case SK_HCK:
+    case SK_BRT:
+    case SK_PSU:
+    case SK_WEP:
+    case SK_CST:
+    case SK_RES:
+    case SK_IMP:
+    case SK_WPW:
+        return MS_INT;
+        break;
+
+    case SK_ATL:
+    case SK_END:
+    case SK_FIR:
+    case SK_ENR:
+    case SK_XRR:
+    case SK_POR:
+    case SK_HLT:
+        return MS_CON;
+        break;
+
+    case SK_MC:
+    case SK_HC:
+    case SK_TRA:
+    case SK_FOR:
+        return MS_STR;
+        break;
+
+    case SK_PC:
+    case SK_RC:
+    case SK_TC:
+    case SK_VHC:
+    case SK_AGL:
+    case SK_REP:
+    case SK_REC:
+    case SK_RCL:
+        return MS_DEX;
+        break;
+
+    case SK_PPU:
+    case SK_APU:
+    case SK_MST:
+    case SK_PPW:
+    case SK_PSR:
+        return MS_PSI;
+        break;
+
+    default:
+        return 0;
+        break;
+    }
+}
+
+bool PSkillHandler::IncSubSkillPossible(SUB_SKILLS Skill)
+{
+    // Check if player is able to inc the given subskill (Enough points left to do that)
+    MAIN_SKILLS tMainSkill = GetMSfromSS(Skill);
+
+    // Failsafe
+    if ( tMainSkill == 0 )
+        return false;
+
+    // Compare amount of available skillpoints for given mainskill
+    // with the amount of points required to increase the subskill
+    if ( GetSP( tMainSkill ) >= GetSKPCost( Skill ))
+        return true;
+    else
+        return false;
+}
+
+int PSkillHandler::IncreaseSubSkill(SUB_SKILLS Skill)
+{
+    // Not enough points left? Then exit here
+    if ( IncSubSkillPossible( Skill ) == false)
+        return -1;
+
+    MAIN_SKILLS tMainSkill = GetMSfromSS( Skill );
+    // Remove skillpoints from availabe ones
+    SetSP( tMainSkill, GetSP( tMainSkill ) - GetSKPCost( Skill ));
+
+    // Set new value
+    SetSubSkill(Skill, GetSubSkill( Skill ) + 1 );
+    return GetSP( tMainSkill );
+}
+
+void PSkillHandler::ZeroMSSubSkills(MAIN_SKILLS Skill)
+{
+    // Set all SubSkills for the given Mainskill to Zero
+    switch ( Skill )
+    {
+    case MS_STR:
+        SetSubSkill(SK_MC,0);
+        SetSubSkill(SK_HC,0);
+        SetSubSkill(SK_TRA,0);
+        SetSubSkill(SK_FOR,0);
+        break;
+
+    case MS_DEX:
+        SetSubSkill(SK_PC,0);
+        SetSubSkill(SK_RC,0);
+        SetSubSkill(SK_TC,0);
+        SetSubSkill(SK_VHC,0);
+        SetSubSkill(SK_AGL,0);
+        SetSubSkill(SK_REP,0);
+        SetSubSkill(SK_REC,0);
+        SetSubSkill(SK_RCL,0);
+        break;
+
+    case MS_CON:
+        SetSubSkill(SK_ATL,0);
+        SetSubSkill(SK_END,0);
+        SetSubSkill(SK_FIR,0);
+        SetSubSkill(SK_ENR,0);
+        SetSubSkill(SK_XRR,0);
+        SetSubSkill(SK_POR,0);
+        SetSubSkill(SK_HLT,0);
+        break;
+
+    case MS_INT:
+        SetSubSkill(SK_HCK,0);
+        SetSubSkill(SK_BRT,0);
+        SetSubSkill(SK_PSU,0);
+        SetSubSkill(SK_WEP,0);
+        SetSubSkill(SK_CST,0);
+        SetSubSkill(SK_RES,0);
+        SetSubSkill(SK_IMP,0);
+        SetSubSkill(SK_WPW,0);
+        break;
+
+    case MS_PSI:
+        SetSubSkill(SK_PPU,0);
+        SetSubSkill(SK_APU,0);
+        SetSubSkill(SK_MST,0);
+        SetSubSkill(SK_PPW,0);
+        SetSubSkill(SK_PSR,0);
+        break;
+    }
+}
+
+bool PSkillHandler::IsValidSubSkill(SUB_SKILLS Skill)
+{
+    switch (Skill)
+    {
+    case SK_HCK:
+    case SK_BRT:
+    case SK_PSU:
+    case SK_WEP:
+    case SK_CST:
+    case SK_RES:
+    case SK_IMP:
+    case SK_WPW:
+    case SK_ATL:
+    case SK_END:
+    case SK_FIR:
+    case SK_ENR:
+    case SK_XRR:
+    case SK_POR:
+    case SK_HLT:
+    case SK_MC:
+    case SK_HC:
+    case SK_TRA:
+    case SK_FOR:
+    case SK_PC:
+    case SK_RC:
+    case SK_TC:
+    case SK_VHC:
+    case SK_AGL:
+    case SK_REP:
+    case SK_REC:
+    case SK_RCL:
+    case SK_PPU:
+    case SK_APU:
+    case SK_MST:
+    case SK_PPW:
+    case SK_PSR:
+        return true;
+        break;
+
+    default:
+        return false;
+        break;
+    }
+}
+
+bool PSkillHandler::IsValidMainSkill(MAIN_SKILLS Skill)
+{
+    switch ( Skill )
+    {
+    case MS_STR:
+    case MS_DEX:
+    case MS_CON:
+    case MS_INT:
+    case MS_PSI:
+        return true;
+        break;
+    default:
+        return false;
+        break;
+    }
+}
diff --git a/server/src/game/sql.cpp b/server/src/game/sql.cpp
new file mode 100644 (file)
index 0000000..3812bdc
--- /dev/null
@@ -0,0 +1,487 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       sql.cpp - handles all mysql interactions\r
+\r
+       Authors:\r
+       - Namikon\r
+       - bakkdoor\r
+\r
+        MODIFIED: 24 Dec 2005 Namikon\r
+        REASON: - initial release by Namikon\r
+        MODIFIED: 26 Dec 2005 Namikon\r
+        REASON: - Fixed Connect and Query function\r
+                - Added GetWorldDoorType() for door interaction\r
+                - Added GetWorldItemType() for item interaction\r
+                - Added GetWorldItemOption() for item interaction\r
+        MODIFIED: 30 Dec 2005 bakkdoor\r
+        REASON: - changed mysql_init() parameter to null to prevent segfault\r
+                - added checking for dbHandle to prevent segfault\r
+        MODIFIED: 01 Jan 2006 Namikon\r
+        REASON: - Removed 2 Console outputs in ResQuery()\r
+                - Added missing "return NULL" to ResQuery\r
+        MODIFIED: 06 Jan 2006 Namikon\r
+        REASON: - Added color to console outputs\r
+                - Changed a few lines on the Get* functions (another std::atoi thing)\r
+        MODIFIED: 26 Jul 2006 Hammag\r
+        REASON: - Added CheckResCount() for DB Res memory leak tracking (to be done in the main loop)\r
+                    rather than through Info/GameResQuery()\r
+                - fixed InfoDBInuse and GameDBInuse updating\r
+                - inhibited Info/GameDBInuse warning message in Info/GameResQuery()\r
+        MODIFIED: 27 Sep 2006 Hammag\r
+        REASON: - Added GetAptLocation() method\r
+                - Modified Apt & Item info methods as they should work, but it doesn't match the DB\r
+                  So commented out some changes\r
+                  DB shouln't be used anymore for that soon anyway\r
+        MODIFIED: 25 Jun 2007 Hammag\r
+        REASON: - Moved all Appartements related methods to PAppartements class\r
+\r
+*/\r
+#include "main.h"\r
+\r
+PMySQL::PMySQL()\r
+{\r
+    InfoDBInuse = 0;\r
+    GameDBInuse = 0;\r
+    info_port = Config->GetOptionInt("info_sql_port");\r
+    strncpy(info_host, Config->GetOption("info_sql_host").c_str(), 100);\r
+    strncpy(info_userName, Config->GetOption("info_sql_username").c_str(), 100);\r
+    strncpy(info_password, Config->GetOption("info_sql_password").c_str(), 100);\r
+    strncpy(info_database, Config->GetOption("info_sql_database").c_str(), 100);\r
+\r
+    game_port = Config->GetOptionInt("game_sql_port");\r
+    strncpy(game_host, Config->GetOption("game_sql_host").c_str(), 100);\r
+    strncpy(game_userName, Config->GetOption("game_sql_username").c_str(), 100);\r
+    strncpy(game_password, Config->GetOption("game_sql_password").c_str(), 100);\r
+    strncpy(game_database, Config->GetOption("game_sql_database").c_str(), 100);\r
+\r
+    mKeepaliveDelay = (std::time_t) (Config->GetOptionInt("mysql_wait_timeout") * 0.9) ; // we take 90% of the wait_timeout to trigger keepalive\r
+    if (mKeepaliveDelay == 0)\r
+    {\r
+      Console->Print("%s MySQL keepalive disabled by config", Console->ColorText(GREEN, BLACK, "[Info]"));\r
+    }\r
+    else if (mKeepaliveDelay < 60)\r
+    {\r
+      Console->Print("%s Configuration option 'mysql_wait_timeout' is too low (%d sec). Reset to 60 sec.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mKeepaliveDelay);\r
+      mKeepaliveDelay = 60;\r
+    }\r
+    mLastKeepaliveSent = 0;\r
+}\r
+\r
+PMySQL::~PMySQL()\r
+{\r
+    Console->Print("Closing MySQL connection...");\r
+    mysql_close(info_dbHandle);\r
+    mysql_close(game_dbHandle);\r
+}\r
+\r
+void PMySQL::Update()\r
+{\r
+    CheckResCount(); // Check for MYSQL_RES mem leak\r
+\r
+    // MySQL keepalive\r
+    std::time_t t = std::time(NULL);\r
+    if ((mKeepaliveDelay > 0) && ((t - mLastKeepaliveSent) > mKeepaliveDelay))\r
+    {\r
+      MYSQL_RES *result;\r
+      char query[24];\r
+      snprintf (query, 24, "SELECT NOW()");\r
+\r
+      result = GameResQuery(query);\r
+      if(!result)\r
+      {\r
+          Console->Print("%s Can't send GameDB keepalive; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
+          ShowGameSQLError();\r
+          return;\r
+      }\r
+      else\r
+        FreeGameSQLResult(result);\r
+\r
+      result = InfoResQuery(query);\r
+      if(!result)\r
+      {\r
+          Console->Print("%s Can't send InfoDB keepalive; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
+          ShowInfoSQLError();\r
+          return;\r
+      }\r
+      else\r
+        FreeInfoSQLResult(result);\r
+\r
+      mLastKeepaliveSent = std::time(NULL);\r
+      if (gDevDebug) Console->Print("%s MySQL keepalive sent", Console->ColorText(GREEN, BLACK, "[Debug]"));\r
+    }\r
+}\r
+\r
+void PMySQL::CheckResCount()\r
+{\r
+  static int MaxInfoDBCount = 0;\r
+  static int MaxGameDBCount = 0;\r
+\r
+  if (InfoDBInuse > MaxInfoDBCount)\r
+  {\r
+    Console->Print("%s Max In-use InfoDB Resources number increasing : %d (+%d)", Console->ColorText(YELLOW, BLACK, "[Notice]"), InfoDBInuse, InfoDBInuse-MaxInfoDBCount);\r
+    MaxInfoDBCount = InfoDBInuse;\r
+  }\r
+\r
+  if (GameDBInuse > MaxGameDBCount)\r
+  {\r
+    Console->Print("%s Max In-use GameDB Resources number increasing : %d (+%d)", Console->ColorText(YELLOW, BLACK, "[Notice]"), GameDBInuse, GameDBInuse-MaxGameDBCount);\r
+    MaxGameDBCount = GameDBInuse;\r
+  }\r
+}\r
+\r
+bool PMySQL::Connect()\r
+{\r
+    Console->LPrint("Establishing link to Infoserver Database...");\r
+\r
+    info_dbHandle = mysql_init(NULL);\r
+\r
+    if(!info_dbHandle)\r
+    {\r
+        Console->LPrint(RED, BLACK, "[ERROR]");\r
+        Console->LClose();\r
+        Console->Print(" Unable to create MySQL-Handle!");\r
+        exit(0);\r
+    }\r
+\r
+    if(!mysql_real_connect(info_dbHandle, info_host, info_userName, info_password, info_database, info_port, NULL, 0))\r
+    {\r
+        Console->LPrint(RED, BLACK, "[ERROR]");\r
+        Console->LClose();\r
+        Console->Print("Unable to connect to Infoserver Database. MySQL returned: %s", mysql_error(info_dbHandle));\r
+    }\r
+    else\r
+    {\r
+        Console->LPrint(GREEN, BLACK, "Success");\r
+        Console->LClose();\r
+    }\r
+// <><><><><><><><> Gameserver DB <><><><><><><><>\r
+    Console->LPrint("Establishing link to Gameserver Database...");\r
+\r
+    game_dbHandle = mysql_init(NULL);\r
+\r
+    if(!game_dbHandle)\r
+    {\r
+        Console->LPrint(RED, BLACK, "[ERROR]");\r
+        Console->LClose();\r
+        Console->Print(" Unable to create MySQL-Handle!");\r
+        exit(0);\r
+    }\r
+\r
+    if(!mysql_real_connect(game_dbHandle, game_host, game_userName, game_password, game_database, game_port, NULL, 0))\r
+    {\r
+        Console->LPrint(RED, BLACK, "[ERROR]");\r
+        Console->LClose();\r
+        Console->Print("Unable to connect to Gameserver Database. MySQL returned: %s", mysql_error(game_dbHandle));\r
+        return false;\r
+    }\r
+    else\r
+    {\r
+        Console->LPrint(GREEN, BLACK, "Success");\r
+        Console->LClose();\r
+        return true;\r
+    }\r
+\r
+}\r
+// ----------------------------------------------------\r
+MYSQL_RES *PMySQL::InfoResQuery(const char *query)\r
+{\r
+    int sql_result = 0;\r
+    MYSQL_RES *result;\r
+\r
+    sql_result = mysql_real_query(info_dbHandle, query, strlen(query));\r
+    if(sql_result)\r
+    {\r
+        return NULL;\r
+    }\r
+    result = mysql_store_result(info_dbHandle);\r
+    if(!result)\r
+    {\r
+        return NULL;\r
+    }\r
+    //if(InfoDBInuse == true)\r
+    /*if(InfoDBInuse > 0)\r
+    {\r
+        Console->Print("%s another (%d) info_dbHandle result is still in use", Console->ColorText(YELLOW, BLACK, "[Warning]"), InfoDBInuse);\r
+    }*/\r
+\r
+    //InfoDBInuse = true;\r
+    InfoDBInuse++;\r
+    return result;\r
+}\r
+\r
+int PMySQL::InfoQuery(const char *query)\r
+{\r
+    int sql_result = 0;\r
+    sql_result = mysql_real_query(info_dbHandle, query, strlen(query));\r
+\r
+    return sql_result;\r
+}\r
+\r
+void PMySQL::ShowInfoSQLError()\r
+{\r
+    Console->Print(RED, BLACK, "MySQL Error: %s", mysql_error(info_dbHandle));\r
+}\r
+void PMySQL::FreeInfoSQLResult(MYSQL_RES *res)\r
+{\r
+    if(InfoDBInuse > 0)\r
+    {\r
+        mysql_free_result(res);\r
+        InfoDBInuse--;\r
+    }\r
+    else\r
+        Console->Print("PMySQL::FreeInfoSQLResult: Nothing to free...");\r
+}\r
+// ----------------------------------------------------\r
+MYSQL_RES *PMySQL::GameResQuery(const char *query)\r
+{\r
+    int sql_result = 0;\r
+    MYSQL_RES *result;\r
+\r
+    sql_result = mysql_real_query(game_dbHandle, query, strlen(query));\r
+    if(sql_result)\r
+    {\r
+        return NULL;\r
+    }\r
+    result = mysql_store_result(game_dbHandle);\r
+    if(!result)\r
+    {\r
+        return NULL;\r
+    }\r
+    /*if(GameDBInuse > 0)\r
+    {\r
+        Console->Print("%s another (%d) game_dbHandle result is still in use", Console->ColorText(YELLOW, BLACK, "[Warning]"), GameDBInuse);\r
+    }*/\r
+\r
+    //GameDBInuse = true;\r
+    GameDBInuse++;\r
+    return result;\r
+}\r
+\r
+int PMySQL::GameQuery(const char *query)\r
+{\r
+    int sql_result = 0;\r
+    sql_result = mysql_real_query(game_dbHandle, query, strlen(query));\r
+\r
+    return sql_result;\r
+}\r
+\r
+void PMySQL::ShowGameSQLError()\r
+{\r
+    Console->Print(RED, BLACK, "MySQL Error: %s", mysql_error(game_dbHandle));\r
+}\r
+\r
+void PMySQL::FreeGameSQLResult(MYSQL_RES *res)\r
+{\r
+    if(GameDBInuse > 0)\r
+    {\r
+        mysql_free_result(res);\r
+        GameDBInuse--;\r
+    }\r
+    else\r
+        Console->Print("PMySQL::FreeGameSQLResult: Nothing to free...");\r
+}\r
+\r
+u32 PMySQL::EscapeString(const char* nText, char* dText, u32 dMaxLength)\r
+{\r
+  u32 nLength = strlen(nText);\r
+  u32 tMax = (dMaxLength - 1)/2;\r
+  if(nLength > tMax)\r
+  {\r
+    nLength = tMax;\r
+  }\r
+\r
+  return mysql_real_escape_string(game_dbHandle, dText, nText, nLength);\r
+}\r
+\r
+// ----------------------------------------------------\r
+/*\r
+int PMySQL::GetWorldItemType(unsigned short ID, int Location)\r
+{\r
+    char query[2048];\r
+    MYSQL_RES *result;\r
+    MYSQL_ROW row;\r
+\r
+    if (Location > 100000)\r
+    {\r
+      //int nAppLoc = GetAptLocation(Location);\r
+      int nAppLoc = Location - 100000; // temp as DB doesn't link with App world ID, but with app ID\r
+      if (nAppLoc)\r
+        snprintf(query, 2048, "SELECT ai_type FROM apt_items WHERE ai_apt_id = %d AND ai_apt_map = %d", ID, nAppLoc);\r
+      else\r
+        return 0;\r
+    }\r
+    else\r
+      snprintf(query, 2048, "SELECT wi_type FROM world_items WHERE wi_worlditem_id = %d AND wi_worlditem_map = %d", ID, Location);\r
+\r
+    result = GameResQuery(query);\r
+    if(!result)\r
+    {\r
+        Console->Print("%s Cannot get WorldItemType; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
+        ShowGameSQLError();\r
+        return 0;\r
+    }\r
+    else\r
+    {\r
+        if(mysql_num_rows(result) > 1)\r
+        {\r
+            FreeGameSQLResult(result);\r
+            return -2;\r
+        }\r
+        else\r
+        {\r
+            row = mysql_fetch_row(result);\r
+            if(row == NULL)\r
+            {\r
+                FreeGameSQLResult(result);\r
+                return -1;\r
+            }\r
+            int ret_val = std::atoi(row[0]);\r
+            FreeGameSQLResult(result);\r
+            return ret_val;\r
+        }\r
+    }\r
+//    else\r
+//  {\r
+//      FreeGameSQLResult(result);\r
+//      return -1;\r
+//  }\r
+//\r
+    return -1;\r
+}\r
+\r
+int PMySQL::GetWorldItemOption(unsigned short ID, int Location, int option)\r
+{\r
+    char query[2048];\r
+    MYSQL_RES *result;\r
+    MYSQL_ROW row;\r
+    if(option != 1 && option != 2 && option != 3)\r
+    {\r
+        return -1;\r
+    }\r
+\r
+    if (Location > 100000)\r
+    {\r
+      //int nAppLoc = GetAptLocation(Location);\r
+      int nAppLoc = Location - 100000; // temp as DB doesn't link with App world ID, but with app ID\r
+      if (nAppLoc)\r
+        snprintf(query, 2048, "SELECT ai_option%d FROM apt_items WHERE ai_apt_id = %d AND ai_apt_map = %d", option, ID, nAppLoc);\r
+      else\r
+        return 0;\r
+    }\r
+    else\r
+      snprintf(query, 2048, "SELECT wi_option%d FROM world_items WHERE wi_worlditem_id = %d AND wi_worlditem_map = %d", option, ID, Location);\r
+\r
+    result = GameResQuery(query);\r
+    if(!result)\r
+    {\r
+        Console->Print("%s Cannot get WorldItemOption; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
+        ShowGameSQLError();\r
+        return 0;\r
+    }\r
+    else\r
+    {\r
+        if(mysql_num_rows(result) > 1)\r
+        {\r
+            FreeGameSQLResult(result);\r
+            return -2;\r
+        }\r
+        else\r
+        {\r
+            row = mysql_fetch_row(result);\r
+            if(row == NULL)\r
+            {\r
+                FreeGameSQLResult(result);\r
+                return -1;\r
+            }\r
+            int ret_val = std::atoi(row[0]);\r
+            FreeGameSQLResult(result);\r
+            return ret_val;\r
+        }\r
+    }\r
+//\r
+//  else\r
+//  {\r
+//      FreeGameSQLResult(result);\r
+//      return -1;\r
+//  }\r
+\r
+    return -1;\r
+}\r
+\r
+int PMySQL::GetWorldDoorType(unsigned int ID, int Location) // To be removed\r
+{\r
+    char query[2048];\r
+    MYSQL_RES *result;\r
+    MYSQL_ROW row;\r
+\r
+Console->Print(RED, BLACK, "PMySQL::GetWorldDoorType: DATABASE MUST NOT BE USED ANYMORE FOR DOORS INFO !!!");\r
+    if (Location > 100000)\r
+    {\r
+      //int nAppLoc = GetAptLocation(Location);\r
+      int nAppLoc = Location - 100000; // temp as DB doesn't link with App world ID, but with app ID\r
+      if (nAppLoc)\r
+        snprintf(query, 2048, "SELECT ad_type FROM apt_doors, apartments WHERE apt_doors.ad_apt_map = apartments.apt_type AND apt_doors.ad_apt_id = %i AND apartments.apt_id = %i", ID, nAppLoc);\r
+      else\r
+        return 0;\r
+    }\r
+    else\r
+    {\r
+        snprintf(query, 2048, "SELECT wd_type FROM world_doors WHERE wd_world_id = %d AND wd_world_map = %d", ID, Location);\r
+    }\r
+    result = GameResQuery(query);\r
+\r
+    if(!result)\r
+    {\r
+        Console->Print("%s Cannot get WorldDoorType; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
+        ShowGameSQLError();\r
+        return 0;\r
+    } else {\r
+        if(mysql_num_rows(result) > 1)\r
+        {\r
+            FreeGameSQLResult(result);\r
+            return -2;\r
+        }\r
+        else\r
+        {\r
+            row = mysql_fetch_row(result);\r
+            if(row == NULL)\r
+            {\r
+                FreeGameSQLResult(result);\r
+                return -1;\r
+            }\r
+            int ret_val = std::atoi(row[0]);\r
+            FreeGameSQLResult(result);\r
+            return ret_val;\r
+        }\r
+    }\r
+//\r
+//    else\r
+//    {\r
+//        FreeGameSQLResult(result);\r
+//        return -1;\r
+//    }\r
+//\r
+    return -1;\r
+}*/\r
diff --git a/server/src/game/subway.cpp b/server/src/game/subway.cpp
new file mode 100644 (file)
index 0000000..24ac2af
--- /dev/null
@@ -0,0 +1,261 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+  subway.h - subway class\r
+\r
+       MODIFIED: 9 Nov 2007 Hammag\r
+       REASON: - creation\r
+       \r
+*/\r
+\r
+/*\r
+(Real time)\r
+Full cycle = 328860 ms\r
+Network delay = TBD\r
+\r
+Offset =MOD(M86-122778+(M85*29896);328860)\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "subway.h"\r
+#include "chars.h" // for PCharCoordinates only\r
+\r
+// Determines relative position of cabs, but how ???\r
+const u16 PSubway::mSubwayInitData [] = {0x4396, 0x4387, 0x4370, 0x4352, 0x4334, 0x4316, 0x42f0, 0x42b4, 0x4270, 0x41f0, 0x0000};\r
+const u32 PSubway::mCabLoopTime = 328860;\r
+const u32 PSubway::mCab0TimeOffset = 122778;\r
+const s32 PSubway::mTimingAdjust = 0;\r
+const u32 PSubway::mCabIntervalTime = 29896;\r
+const u32 PSubway::mOpenDoorOffset [] = { 0, 42500, 83000, 146800, 170700, 226200, 262800, 303200 };\r
+const u32 PSubway::mOpenDoorDuration [] = { 8500, 6900, 12000, 7500, 8800, 9000, 8500, 9300 };\r
+const char* PSubway::mSubwayStationName[] = { "Pla => Oz", "Vr => Oz", "Pp => Oz", "Oz end", "Oz => Pla", "Pp => Pla", "Vr => Pla", "Pla end" };\r
+PCharCoordinates PSubway::mCabExitPositions [2][mStationsNumber];\r
+\r
+\r
+PSubway::PSubway()\r
+{\r
+  for(u8 i=0; i<mCabsNumber; i++)\r
+  {\r
+    mSubways[i].mVhcId = mCabsBaseId+i;\r
+    mSubways[i].mPosition = mSubwayInitData[i];\r
+    mSubways[i].mDoorOpened = 0;\r
+    for(u8 j=0; j<4; j++)\r
+    {\r
+      mSubways[i].mSeatUsersId[j] = 0;\r
+    }\r
+  }\r
+  \r
+  mCabExitPositions[0][0].SetPosition(32000-5205, 32000-608, 32000-4766, 0x80, 0);\r
+  mCabExitPositions[1][0].SetPosition(32000-5764, 32000-608, 32000-4766, 0x80, 0);\r
+\r
+  mCabExitPositions[0][1].SetPosition(32000+7290, 32000-600, 32000-500, 0x80, 45);\r
+  mCabExitPositions[1][1].SetPosition(32000+7290, 32000-600, 32000-0, 0x80, 45); \r
+\r
+  mCabExitPositions[0][2].SetPosition(32000-2300, 32000-600, 32000+7985, 0x80, 0);\r
+  mCabExitPositions[1][2].SetPosition(32000-2850, 32000-600, 32000+7985, 0x80, 0); \r
+\r
+  mCabExitPositions[0][3].SetPosition(32000-1700, 32000-596, 32000+1840, 0x80, 90);\r
+  mCabExitPositions[1][3].SetPosition(32000-1250, 32000-596, 32000+1840, 0x80, 90); \r
+\r
+  mCabExitPositions[0][4].SetPosition(32000-1700, 32000-596, 32000+1570, 0x80, 0);\r
+  mCabExitPositions[1][4].SetPosition(32000-1250, 32000-596, 32000+1570, 0x80, 0);    \r
+  \r
+  mCabExitPositions[0][5].SetPosition(32000-2300, 32000-600, 32000+8625, 0x80, 90);\r
+  mCabExitPositions[1][5].SetPosition(32000-2850, 32000-600, 32000+8625, 0x80, 90);   \r
\r
+  mCabExitPositions[0][6].SetPosition(32000+7815, 32000-600, 32000-500, 0x80, 135);\r
+  mCabExitPositions[1][6].SetPosition(32000+7815, 32000-600, 32000-0, 0x80, 135); \r
\r
+  mCabExitPositions[0][7].SetPosition(32000-5205, 32000-608, 32000-4092, 0x80, 0);\r
+  mCabExitPositions[1][7].SetPosition(32000-5764, 32000-608, 32000-4092, 0x80, 0); \r
+}\r
+\r
+u32 PSubway::GetTimeOffset(u32 nVhcId, u32 nTime)\r
+{\r
+  u8 tIndex;\r
+  \r
+  if(!GetInfoIndex(nVhcId, &tIndex))\r
+  {\r
+    Console->Print(RED, BLACK, "[Error] PSubway::GetTimeOffset : invalid cab VhcId %d", nVhcId);\r
+    return 0;\r
+  }\r
+\r
+  return ((nTime + mCabLoopTime - mCab0TimeOffset + mTimingAdjust + (tIndex * mCabIntervalTime)) % mCabLoopTime);\r
+}\r
+\r
+u8 PSubway::GetStation(u32 nVhcId, u32 nTime, u32* TimeOffset)\r
+{  \r
+  s8 i;\r
+  \r
+  u32 tTimeOffset = GetTimeOffset(nVhcId, nTime);\r
+  if(TimeOffset)\r
+  {\r
+    *TimeOffset = tTimeOffset;\r
+  }\r
+   \r
+  for(i = mStationsNumber-1; (i >= 0) && (tTimeOffset < mOpenDoorOffset[i]); --i) ;\r
+\r
+  return i;\r
+}\r
+\r
+bool PSubway::IsDoorOpen(u32 nVhcId, u32 nTime)\r
+{\r
+  u32 TimeOffset;\r
+  u8 tStation;\r
+  \r
+  if(!GetInfoIndex(nVhcId))\r
+  {\r
+    Console->Print(RED, BLACK, "[Error] PSubway::IsDoorOpen : invalid cab VhcId %d", nVhcId);\r
+    return false;  \r
+  }\r
+  else\r
+  {\r
+    tStation = GetStation(nVhcId, nTime, &TimeOffset);\r
+    return ((TimeOffset-mOpenDoorOffset[tStation]) <= mOpenDoorDuration[tStation]);\r
+  }\r
+}\r
+\r
+std::string* PSubway::GetStationName(u8 nStationId)\r
+{\r
+  if(nStationId < mStationsNumber)\r
+  {\r
+    return new std::string(mSubwayStationName[nStationId]);\r
+  }\r
+  else\r
+  {\r
+    Console->Print(RED, BLACK, "[Error] PSubway::GetStationName : invalid subway station %d", nStationId);\r
+    return new std::string("Error");\r
+  }\r
+}\r
+\r
+bool PSubway::GetStationExitPosition(PCharCoordinates* nPosition, u8 nStationId, f32 nCoef)\r
+{\r
+  if(nStationId < mStationsNumber)\r
+  {\r
+    nPosition->SetInterpolate(mCabExitPositions[0][nStationId], mCabExitPositions[1][nStationId], nCoef);\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    Console->Print(RED, BLACK, "[Error] PSubway::SetStationExitPosition : invalid subway station %d", nStationId);\r
+    return false;\r
+  } \r
+}\r
+\r
+bool PSubway::GetInfoIndex(u32 nVhcId, u8 *Index)\r
+{\r
+  s32 tIndex = nVhcId - mCabsBaseId;\r
+  if ((tIndex >= 0) && (tIndex < mCabsNumber))\r
+  {\r
+    if(Index)\r
+    {\r
+      *Index = (u8)tIndex;\r
+    }\r
+    return true;\r
+  }\r
+  else\r
+    return false;\r
+}\r
+\r
+bool PSubway::UpdateInfo(u32 nVhcId, u16 nPosition, u8 nDoorOpened)\r
+{\r
+  u8 tIndex;\r
+  if(GetInfoIndex(nVhcId, &tIndex))\r
+  {\r
+    mSubways[tIndex].mPosition = nPosition;\r
+//if(mSubways[tIndex].mDoorOpened != nDoorOpened)\r
+//  Console->Print("[DEBUG] Subway cab %08x : door now %s ", nVhcId, nDoorOpened ? "opened" : "closed" );\r
+  \r
+    mSubways[tIndex].mDoorOpened = nDoorOpened;\r
+\r
+    return true;\r
+  }\r
+  else\r
+    return false;\r
+}\r
+\r
+u16 PSubway::GetPosition(u32 nVhcId)\r
+{\r
+  u8 tIndex;\r
+  if(GetInfoIndex(nVhcId, &tIndex))\r
+  {\r
+    return mSubways[tIndex].mPosition;\r
+  }\r
+  else\r
+    return 0;\r
+}\r
+\r
+u8 PSubway::GetFreeSeat(u32 nVhcId)\r
+{\r
+  u8 tIndex;\r
+  u8 tSeatFound = 0;\r
+  if(GetInfoIndex(nVhcId, &tIndex))\r
+  {\r
+    for(u8 j=0; j<4; j++)\r
+    {\r
+      if(! mSubways[tIndex].mSeatUsersId[j])\r
+      {\r
+        tSeatFound = j+1;\r
+        break;\r
+      }\r
+    }\r
+    return tSeatFound;\r
+  }\r
+  else\r
+    return 0;\r
+}\r
+\r
+bool PSubway::SetSeatUser(u32 nVhcId, u8 nSeat, u32 nCharId)\r
+{\r
+  u8 tIndex;\r
+\r
+  if(GetInfoIndex(nVhcId, &tIndex) && (nSeat >= 1) && (nSeat <= 4))\r
+  {\r
+    if(! mSubways[tIndex].mSeatUsersId[nSeat-1])\r
+    {\r
+      mSubways[tIndex].mSeatUsersId[nSeat-1] = nCharId;\r
+//Console->Print("[DEBUG] Char %d using seat %d of subway cab %08x, ", nCharId, nSeat, nVhcId);\r
+      return true;\r
+    }\r
+  }\r
+\r
+  return false;\r
+}\r
+\r
+bool PSubway::UnsetSeatUser(u32 nVhcId, u8 nSeat, u32 nCharId)\r
+{\r
+  u8 tIndex;\r
+\r
+  if(GetInfoIndex(nVhcId, &tIndex) && (nSeat >= 1) && (nSeat <= 4))\r
+  {\r
+    if(mSubways[tIndex].mSeatUsersId[nSeat-1] == nCharId)\r
+    {\r
+      mSubways[tIndex].mSeatUsersId[nSeat-1] = 0;\r
+//Console->Print("[DEBUG] Char %d leaving seat %d of subway cab %08x, ", nCharId, nSeat, nVhcId);\r
+      return true;\r
+    }\r
+  }\r
+\r
+  return false;\r
+}\r
diff --git a/server/src/game/terminal.cpp b/server/src/game/terminal.cpp
new file mode 100644 (file)
index 0000000..fab9bb0
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+
+
+/*
+       terminal.cpp - Management class for Terminal actions (Citycom, keys, vehicledepot, ...)
+
+       MODIFIED: 08 Jan 2007 Namikon
+       REASON: - Created
+
+*/
+
+#include "main.h"
+#include "terminal.h"\r
+#include "msgbuilder.h"
+\r
+\r
+PTerminal::PTerminal()\r
+{\r
+    snprintf(mConPrefix, 50, "[PConsole]");\r
+    EraseVars();\r
+}\r
+\r
+void PTerminal::EraseVars()\r
+{\r
+    memset(mSQLQuery, '\0', 500);\r
+    mResultFields = 0;\r
+}\r
+
+u8 PTerminal::GetNewEmailCount(PClient* nClient, bool nNoticeClient)
+{
+    MYSQL_RES *result = NULL;
+    MYSQL_ROW row;
+    char query[100];
+
+    snprintf(query, 100, "SELECT count(*) FROM emails WHERE e_toid = %d AND e_new = 1", nClient->GetCharID());
+    if(gDevDebug) Console->Print("[DEBUG] Query is: %s", query);
+    result = MySQL->GameResQuery(query);
+    if(result == NULL)
+    {
+        Console->Print(RED, BLACK, "PTerminal::GetNewEmailCount could not get emailcount");
+        Console->Print("Query was:");
+        Console->Print("%s", query);
+        MySQL->ShowGameSQLError();
+        return 0;
+    }
+    if(mysql_num_rows(result) == 0) // No Mails found
+    {
+        MySQL->FreeGameSQLResult(result);
+        if(gDevDebug) Console->Print("[DEBUG] No new emails for this char");
+        return 0;
+    }
+    if(gDevDebug) Console->Print("[DEBUG] Found new email, sending notice");
+
+    row = mysql_fetch_row(result);
+    u8 tRetVal = (u8)atoi(row[0]);
+    MySQL->FreeGameSQLResult(result);
+\r
+    if(nNoticeClient)\r
+    {
+        PMessage* tmpMsg = MsgBuilder->BuildYouGotEmailsMsg(nClient, tRetVal);\r
+        nClient->SendUDPMessage(tmpMsg);\r
+    }
+    return tRetVal;
+}
+
diff --git a/server/src/game/terminal_querydb.cpp b/server/src/game/terminal_querydb.cpp
new file mode 100644 (file)
index 0000000..eee384c
--- /dev/null
@@ -0,0 +1,128 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       terminal_querydb.cpp - Management class for Terminal actions (Citycom, keys, vehicledepot, ...)\r
+       > Sub-File for terminal "ReceiveDB" command\r
+\r
+       MODIFIED: 18 Oct 2009 Namikon\r
+       REASON: - Created\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "terminal.h"\r
+#include "msgbuilder.h"\r
+\r
+\r
+bool PTerminal::HandleQueryDB(PClient* nClient, std::string *nDBCommandName, std::string *nCommandName, std::string *nOptions, u8 nNumOptions)\r
+{\r
+    EraseVars();
+
+    bool tOk = false;\r
+\r
+    if(!strcmp(nDBCommandName->c_str(), "ACM"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "CHANGELEADER"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "CHANGERANK"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "CHECKRUNNER"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "CSM"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "DELETECLAN"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "DISMISSMEMBER"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "DISMISSVEHICLE"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "GIVEMONEY"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "JOINCLAN"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "KICKPLAYER"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "QUITCLAN"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "REPAIRVEHICLE"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "SPAWNVEHICLE"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "TAKEFACTIONMONEY"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "TAKEMONEY"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "TRADESTOCKX"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "WARPPLAYER"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else if(!strcmp(nDBCommandName->c_str(), "WARPPLAYERTOWORLD"))\r
+    {\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Nothing to do; Function not written yet: %s", Console->ColorText(YELLOW,BLACK,"Notice"), nDBCommandName->c_str());\r
+    }\r
+    else\r
+    {\r
+        // Ok this REALLY should'nt happen.. But who knows..?\r
+        Console->Print("%s [PTerminal::HandleQueryDB] Unknown ServerMessage: %s", Console->ColorText(RED,BLACK,"Error"), nDBCommandName->c_str());\r
+        return false;\r
+    }\r
+\r
+    return tOk;\r
+}\r
diff --git a/server/src/game/terminal_receivedb.cpp b/server/src/game/terminal_receivedb.cpp
new file mode 100644 (file)
index 0000000..51dcd38
--- /dev/null
@@ -0,0 +1,1044 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       terminal_receivedb.cpp - Management class for Terminal actions (Citycom, keys, vehicledepot, ...)\r
+       > Sub-File for terminal "ReceiveDB" command\r
+\r
+       MODIFIED: 12 Jan 2007 Namikon\r
+       REASON: - Created\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "terminal.h"\r
+#include "msgbuilder.h"\r
+\r
+bool PTerminal::HandleReceiveDB(PClient* nClient, u16 mTerminalSessionId, std::string *nCommandName, std::string *nOptions, u8 nNumOptions, u16 nDBID, u8 nUnknown)\r
+{\r
+    EraseVars();
+    int nAccessLevel = nClient->GetAccountLevel();
+    //Console->Print("DBID: %d", nDBID);\r
+\r
+    switch (nDBID)\r
+    {\r
+    case 8:\r
+        if(!ChkOpt(nNumOptions, 2)) break;
+        mResultFields = 6;
+        if(!strncmp(nOptions[0].c_str(), "date", 4))
+            //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+            snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+        else
+            //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+            snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+        break;\r
+    case 9:\r
+        if(!ChkOpt(nNumOptions, 2)) break;
+        mResultFields = 6;
+        if(!strncmp(nOptions[0].c_str(), "date", 4))
+            //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+            snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+        else
+            //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+            snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+        break;
+    case 10:\r
+        if(!ChkOpt(nNumOptions, 2)) break;
+        mResultFields = 6;
+        if(!strncmp(nOptions[0].c_str(), "date", 4))
+            //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+            snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+        else
+            //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+            snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+        break;
+    case 11:
+        if(!ChkOpt(nNumOptions, 1)) break;\r
+        mResultFields = 6;
+        //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_content FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_id = %d", atoi(nOptions[0].c_str()));
+        snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_content FROM `neochronicle` WHERE nc_id = %d", atoi(nOptions[0].c_str()));
+        //snprintf (mSQLQuery, 500, "SELECT na_id, \'\', na_datetime, na_author, na_name, na_content FROM `neocron articles` WHERE na_approval = 1 AND na_id = %d", atoi(nOptions[0].c_str()));
+\r
+        break;\r
+    case 14:
+        // 0: ID 1: Short 2: Clanname 3: FactionID 4: Faction Symp
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 6; // TODO: replace 0 with average faction sympathy
+        snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction, \"0\", \"0\" FROM `clans` WHERE cl_name LIKE \"%%%s%%\" LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
+\r
+        break;\r
+    case 16:
+        if(!ChkOpt(nNumOptions, 3)) break;\r
+        if (!strcmp (nOptions[0].c_str(), "Neocronicle"))
+        {
+            mResultFields = 5;
+            snprintf (mSQLQuery, 500, "SELECT na_id, \'0\', na_datetime, na_author, na_name FROM `neocron articles` WHERE na_approval = 1 LIMIT %s, %s", nOptions[1].c_str(), nOptions[2].c_str());
+        }
+        else
+        {
+            mResultFields = 7;
+            snprintf (mSQLQuery, 500, "SELECT na_id, \'0\', na_datetime, na_author, na_name, na_approval, \"0\" FROM `neocron articles` LIMIT %s, %s", nOptions[1].c_str(), nOptions[2].c_str());
+        }\r
+
+        break;\r
+    case 18:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 1;
+        snprintf (mSQLQuery, 500, "SELECT c_name FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));
+\r
+        break;\r
+    case 20:
+    case 21:
+        // Select either c_"name" or c_"minsympathy". Names taken from option, saves if/else
+        if(!ChkOpt(nNumOptions, 2)) break;
+        mResultFields = 1;
+        snprintf (mSQLQuery, 500, "SELECT `cl_%s` FROM `clans` WHERE `cl_id` = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()));
+
+        break;
+    case 25:\r
+        if(!ChkOpt(nNumOptions, 4)) break;
+        mResultFields = 6; // TODO: replace 0 with average faction sympathy
+        snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction, \"0\", \"0\" FROM clans WHERE cl_name > \"%s\" AND cl_name <=\"%s\" LIMIT %d, %d", nOptions[0].c_str(), nOptions[1].c_str(), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+        break;\r
+    case 26:\r
+        // 0: short 1: name 2: money 3: faction 4: fac symp 5: symp_to_join 6: cappid
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 6;
+        snprintf (mSQLQuery, 500, "SELECT cl_shortdesc, cl_name, cl_money, cl_faction, \"0\", cl_minsympathy, cl_appid FROM `clans` WHERE `cl_id` = %d", atoi(nOptions[0].c_str()));
+
+        break;\r
+    case 27:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 5;\r
+        snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_description, count(DISTINCT o_outnum), count(DISTINCT c_id) FROM outposts INNER JOIN clans ON (o_clan = cl_id) INNER JOIN characters ON (c_clan = clans.cl_id) WHERE (cl_id = %d) GROUP BY cl_id", atoi(nOptions[0].c_str()));
+
+        break;\r
+    case 28:
+        // Faction missions? Never seen them even in NC2...\r
+        Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d has not been written yet; Factionmissions..? Never seen them", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 29:\r
+        Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d Ordercol was missing. Its: [%s]", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID, nOptions[0].c_str());\r
+        break;\r
+    case 34:\r
+        // Name, Add. Info, Profession, Description, Overal Ranking, Soullight, Money, Runner Kills, Creature Kills
+        // Note: Add. Info is autogenerated clientside!
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 8;
+        snprintf (mSQLQuery, 500, "SELECT c_name, c_profession, \"0\", \"1\", \"127\", c_cash, \"0\", \"0\" FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));
+\r
+        break;\r
+    case 38:
+        // Faction missions? Never seen them even in NC2...\r
+        Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d has not been written yet; Factionmissions..? Never seen them", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 39:
+    // 0:id 1:name 2:clan 3:fac.symp\r
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_clan, \"75\" FROM characters WHERE c_name LIKE \"%s\"", nOptions[0].c_str());
+
+        break;\r
+    case 41:\r
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 5;
+        snprintf (mSQLQuery, 500, "SELECT o_outnum, o_outnum, \"0\", \"0\", \"0\" FROM outposts WHERE o_clan = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+        break;
+    case 46:
+        // charid, charname, charclanlevel, clanlevelname, charfactionsymp, char online
+        if(!ChkOpt(nNumOptions, 4)) break;
+        mResultFields = 6;
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name, cll_level, cll_desc, \"0\", c_online FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (cll_clanid = %d) AND (cll_level >= %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+        break;
+    case 47:
+        if(!ChkOpt(nNumOptions, 5)) break;
+        mResultFields = 6;
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, cll_desc, 0, c_online FROM characters INNER JOIN clanlevels ON (c_id = cll_charid) WHERE cll_level >= %d AND cll_level <= %d AND c_clan = %d ORDER BY cll_level DESC LIMIT %d, %d", atoi(nOptions[2].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str()));
+
+        break;
+    case 48:\r
+        if(!ChkOpt(nNumOptions, 2)) break;
+        mResultFields = 2;
+        snprintf (mSQLQuery, 500, "SELECT cll_desc, cll_level FROM clanlevels WHERE cll_clanid = %d AND cll_level = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+        break;
+    case 49:\r
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 2;
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));
+
+        break;
+    case 50:
+        if(!ChkOpt(nNumOptions, 1)) break;\r
+        mResultFields = 2; //Fieldnum
+        snprintf (mSQLQuery, 500, "SELECT f_showname, f_name FROM forums WHERE f_area = %d", atoi(nOptions[0].c_str()));
+\r
+        break;\r
+    case 51:
+        if(!ChkOpt(nNumOptions, 9)) break;\r
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND f_name = \'%s\' AND fp_replyid = 0 LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[7].c_str()), atoi(nOptions[8].c_str()));
+\r
+        break;\r
+    case 52:
+        if(!ChkOpt(nNumOptions, 3)) break;\r
+        mResultFields = 4;
+       snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") AND (fp_id = %d OR fp_replyid = %d)", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+        break;\r
+    case 54:
+    // id, name, rank, rankname, f.symp
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 5;
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name, cll_level, cll_desc, 0 FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (c_id = %d)", atoi(nOptions[0].c_str()));
+
+        break;\r
+    case 60: // Query for OutPost state. Result is <outpost ID> <clan ID>
+        if(!ChkOpt(nNumOptions, 2)) break;\r
+        mResultFields = 2;
+        snprintf (mSQLQuery, 500, "SELECT o_outnum, o_clan FROM outposts LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+        break;
+    case 61: // It should display the clanname, but it doesnt. seems to be clientside bug\r
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT o_outnum, o_clan, o_clan, o_security FROM outposts WHERE o_outnum = %d", atoi(nOptions[0].c_str()));
+
+        break;
+    case 75:
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 2;
+        snprintf (mSQLQuery, 500, "SELECT cll_desc, cll_level FROM clanlevels WHERE cll_clanid = %d ORDER BY cll_level DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
+\r
+        break;\r
+    case 76:
+        if(!ChkOpt(nNumOptions, 2)) break;
+        mResultFields = 1;
+        snprintf (mSQLQuery, 500, "SELECT count(c_id) FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (cll_clanid = %d AND cll_desc = \"%s\")", atoi(nOptions[0].c_str()),nOptions[1].c_str());
+
+        break;\r
+    case 85:
+        if(!ChkOpt(nNumOptions, 4)) break;
+        mResultFields = 6; // No idea why this Fac.Symp is that high... 1000000 is 100 ingame. But only for this query
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name, cll_level, cll_desc, 1000000, c_online FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (c_online = %d OR c_online = 1) AND c_clan = %d LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+        break;\r
+    case 86:\r
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 4;
+        if(!strncmp(nOptions[1].c_str(), "date", 4))
+            snprintf (mSQLQuery, 500, "SELECT mt_id, mt_amount, mt_date, c_name FROM moneytransactions INNER JOIN characters ON (mt_player = c_id) WHERE mt_clanid = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+        else
+            snprintf (mSQLQuery, 500, "SELECT mt_id, mt_amount, mt_date, c_name FROM moneytransactions INNER JOIN characters ON (mt_player = c_id) WHERE mt_clanid = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+        break;
+    case 87:\r
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT c_name, mt_date, mt_amount, mt_comment FROM moneytransactions INNER JOIN characters ON (mt_player = c_id) WHERE mt_id = %d", atoi(nOptions[0].c_str()));
+
+        break;
+    case 92:
+        if(!ChkOpt(nNumOptions, 1)) break;\r
+        // Location of player
+        mResultFields = 1;
+        snprintf (mSQLQuery, 500, "SELECT c_location FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));
+
+        break;\r
+    case 93:
+        if(!ChkOpt(nNumOptions, 1)) break;\r
+        // Name, Add. Info, Profession, Description
+        // Note: Add. Info is autogenerated clientside!
+        mResultFields = 3;
+        snprintf (mSQLQuery, 500, "SELECT c_name, c_profession, \"0\" FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));\r
+
+        break;\r
+    case 96:\r
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 1;
+        snprintf (mSQLQuery, 500, "SELECT f_showname FROM forums WHERE f_name = \"%s\"", nOptions[0].c_str());
+
+        break;
+    case 98:
+        // ID, Name, Online, 0, Soullight\r
+        if(!ChkOpt(nNumOptions, 4)) break;
+        mResultFields = 5;
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_online, \"0\", c_soullight FROM characters WHERE c_online = %d AND c_soullight <= -%d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+        break;
+    case 99:
+        // Terrorist info
+        // id, name, faction, clan, clanlevel, location\r
+        if(!ChkOpt(nNumOptions, 2)) break;
+        mResultFields = 6;
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_faction, c_clan, cll_level, c_location FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (c_id = %d AND c_soullight <= -%d)", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+        break;\r
+    case 108:\r
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 1;
+        snprintf (mSQLQuery, 500, "SELECT cl_name FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()));
+
+        break;
+    case 109:\r
+        if(!ChkOpt(nNumOptions, 1)) break;
+        // The only case where KK used an DBId twice for completely different things...
+        if(nNumOptions < 3)
+        {
+            mResultFields = 5;
+            snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_clan, cll_level, cll_desc FROM characters INNER JOIN clanlevels ON (cll_charid = c_id AND cll_clanid = c_clan) WHERE c_id = %d", atoi(nOptions[0].c_str()));
+        }
+        else if(nNumOptions == 3)
+        {
+            mResultFields = 2;
+            snprintf (mSQLQuery, 500, "SELECT c_id, apt_location FROM apartments INNER JOIN characters ON (apt_owner = c_id) WHERE (c_id = %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+        }
+
+        break;
+    case 116:\r
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 1;
+        snprintf (mSQLQuery, 500, "SELECT wr_id FROM worlds WHERE wr_group = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+        break;
+    case 125:
+        // Return position in Helpqueue. todo yet... for now its 255, we're always busy! =)\r
+        //if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 1;
+        snprintf (mSQLQuery, 500, "SELECT 255");
+
+        break;
+    case 126:\r
+        // Return position in Helpqueue. todo yet... for now its 255, we're always busy! =)
+        // This is with Datecheck, somehow..
+        //if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 1;
+        snprintf (mSQLQuery, 500, "SELECT 255");
+
+        break;\r
+    case 127:\r
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 2;
+        snprintf (mSQLQuery, 500, "SELECT c_name, apt_location FROM apartments INNER JOIN characters ON (apt_owner = c_id) WHERE (c_id = %d)", atoi(nOptions[0].c_str()));
+\r
+        break;\r
+    case 128:\r
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 1;
+        snprintf (mSQLQuery, 500, "SELECT su_id FROM support WHERE su_supporterid = %d AND su_finished = 0", atoi(nOptions[0].c_str()));
+
+    case 131:\r
+        mResultFields = 6;
+        //snprintf(mSQLQuery, 500, "SELECT br_id, br_type, c_online, c_name, br_location, br_datetime FROM `bug report`, characters WHERE c_id = br_fromid AND br_status = %d LIMIT %d, %d",
+        // atoi(nOptions[0].c_str())+atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+        snprintf(mSQLQuery, 500, "SELECT su_id, su_type, 0, c_name, su_worldid, su_datetime FROM support INNER JOIN characters ON (su_player = c_id) WHERE su_inwork = %d AND su_finished = %d LIMIT %d, %d",
+         atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+\r
+        break;\r
+    case 132:
+    // reqid, runnerid, runnername, 0, date/time, type, 0, in work, finished, desc
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 10;
+        //snprintf(mSQLQuery, 500, "SELECT br_id, br_fromid, c_name, \"0\", br_datetime, br_type, \"0\", br_status, br_status, br_desc FROM `bug report` INNER JOIN characters ON (br_fromid = c_id) WHERE br_id = %d", atoi(nOptions[0].c_str()));
+        snprintf(mSQLQuery, 500, "SELECT su_id, su_player, c_name, 0, su_datetime, su_type, su_supporterid, su_inwork, su_finished, su_desc FROM support INNER JOIN characters ON (su_player = c_id) WHERE su_id = %d", atoi(nOptions[0].c_str()));
+
+        break;\r
+    case 134:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 1;
+        snprintf(mSQLQuery, 500, "SELECT br_id FROM bug_report WHERE br_fromid = %d", atoi(nOptions[0].c_str()));
+
+        break;\r
+    case 136:
+        if(!ChkOpt(nNumOptions, 1)) break;\r
+        mResultFields = 1;
+        snprintf (mSQLQuery, 500, "SELECT c_name FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));\r
+        break;\r
+    case 137:
+        if(!ChkOpt(nNumOptions, 1)) break;
+    // runnerid, runnername, location, online\r
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_name = \"%s\"", nOptions[0].c_str());
+        break;\r
+    case 138:\r
+        if(!ChkOpt(nNumOptions, 1)) break;
+    // runnerid, runnername, location, online
+        mResultFields = 6;
+        snprintf (mSQLQuery, 500, "SELECT br_type, br_location, br_datetime, br_supid, br_status, br_desc FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str()));
+        break;\r
+    case 143:
+        if(!ChkOpt(nNumOptions, 1)) break;
+    // runnerid, runnername, location, online
+        mResultFields = 6;
+        snprintf (mSQLQuery, 500, "SELECT a.a_id, a.a_username, b.c_id, 0, b.c_location, b.c_online FROM `%s`.accounts AS a, `%s`.characters AS b WHERE b.c_name = \"%s\" AND a.a_id = b.a_id",
+                                  Config->GetOption("info_sql_database").c_str(), Config->GetOption("game_sql_database").c_str(), nOptions[0].c_str());
+        break;
+    case 144:\r
+        mResultFields = 2; // Replace "1" with Online/Offline!
+        snprintf (mSQLQuery, 500, "SELECT c_location, c_online FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));
+\r
+        break;\r
+    case 145:\r
+        mResultFields = 1;
+        snprintf (mSQLQuery, 500, "SELECT a_email FROM `%s`.accounts WHERE a_id = %d", Config->GetOption("info_sql_database").c_str(), atoi(nOptions[0].c_str()));
+\r
+        break;\r
+    case 146:\r
+        mResultFields = 4;
+        // Too bad we named the row different...
+        char tSortRow[10];
+        if(!strncmp(nOptions[1].c_str(), "world", 5))
+            strcpy(tSortRow, "location");
+        else
+            strcpy(tSortRow, "name");
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_name LIKE \"%s\" ORDER BY `c_%s` LIMIT %d, %d", nOptions[0].c_str(), tSortRow, atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+        break;\r
+    case 147:
+        mResultFields = 4;\r
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_online = %d ORDER BY `c_%s` LIMIT %d, %d", atoi(nOptions[0].c_str()), nOptions[1].c_str(), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
+
+        break;\r
+    case 148:
+        if(!ChkOpt(nNumOptions, 1)) break;\r
+        mResultFields = 5;
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name, \"0\", \"0\", c_id FROM clans INNER JOIN characters ON (cl_leader = c_id) WHERE (cl_id = %d)", atoi(nOptions[0].c_str()));
+
+        break;\r
+    case 150:
+        // Mission stuff. Will be added later!\r
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 151:
+        // Mission stuff. Will be added later!\r
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 153:\r
+        // Mission stuff. Will be added later!
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 154:\r
+        // Mission stuff. Will be added later!
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 155:\r
+        // Mission stuff. Will be added later!
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 156:\r
+        // Mission stuff. Will be added later!
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 157:\r
+        // Mission stuff. Will be added later!
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 158:\r
+        // Mission stuff. Will be added later!
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 175:
+        if(!ChkOpt(nNumOptions, 2)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT br_id, br_type, br_title, br_datetime FROM bug_report LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+        break;\r
+    case 176:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 8;
+        snprintf (mSQLQuery, 500, "SELECT br_type, br_status, br_title, br_desc, 0, br_datetime, br_location, br_fromid FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str()));
+
+        break;
+    case 181:\r
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 3;
+        snprintf (mSQLQuery, 500, "SELECT c_name, apt_location, apt_password FROM apartments INNER JOIN characters ON (c_id = apt_owner) WHERE apt_id = %d", atoi(nOptions[0].c_str()));
+
+        break;\r
+    case 183:\r
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 6;
+        snprintf (mSQLQuery, 500, "SELECT cl_id, cl_name, (SELECT count(*) FROM characters WHERE c_clan = %d), c_name, apt_id, apt_location FROM clans INNER JOIN apartments ON (cl_appid = apt_id) INNER JOIN characters ON (c_clan = cl_id) AND (apt_owner = c_id) WHERE (cl_id = %d) GROUP BY c_id", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()));
+
+        break;
+    case 186:\r
+        mResultFields = 1;
+        snprintf (mSQLQuery, 500, "SELECT c_id FROM characters WHERE c_name = \"%s\"", nOptions[0].c_str());
+\r
+        break;\r
+    case 220:\r
+        mResultFields = 4; //Fieldnum
+        snprintf (mSQLQuery, 500, "SELECT v_id, v_type, v_status, v_condition FROM vehicles WHERE v_owner = %i LIMIT %i, %i", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+\r
+        break;\r
+    case 221:\r
+        //VehicleControl order. "VehicleControl", "Type", "Status", "Condition", "Repairprice?"
+        mResultFields = 4; //Fieldnum
+        snprintf (mSQLQuery, 500, "SELECT v_type, v_status, v_condition, \"0\" FROM vehicles WHERE v_id = %s", nOptions[0].c_str());
+\r
+        break;\r
+    case 225:
+        // Statistics. Maybe later...\r
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 226:
+        // Statistics. Maybe later...\r
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 230:\r
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT st_id, st_factid, st_curval, st_curval-st_oldval FROM stockx");
+\r
+        break;\r
+    case 231:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT st_id, st_factid, st_curval, (st_curval - st_oldval) FROM stockx WHERE (st_id = %d)", atoi(nOptions[0].c_str()));
+
+        break;
+    case 232:
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 5;
+        snprintf (mSQLQuery, 500, "SELECT sxd_id, st_factid, st_curval, sxd_amount, (sxd_amount * st_curval) FROM stockx_depots INNER JOIN stockx ON (sxd_st_id = st_id) WHERE (sxd_playerid = %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+        break;\r
+    case 233:\r
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 7;
+        snprintf (mSQLQuery, 500, "SELECT st_factid, sxd_amount, (st_curval - st_oldval), st_curval, sxd_paid, (sxd_amount * st_curval), ((sxd_amount * st_curval) - sxd_paid) FROM stockx_depots INNER JOIN stockx ON (sxd_st_id = st_id) where sxd_id = %d", atoi(nOptions[0].c_str()));
+
+        break;
+    case 234:\r
+        if(!ChkOpt(nNumOptions, 2)) break;
+        mResultFields = 3;
+        snprintf (mSQLQuery, 500, "SELECT sxd_id, sxd_amount, sxd_paid FROM stockx_depots INNER JOIN stockx ON (sxd_st_id = st_id) WHERE sxd_playerid = %d AND st_factid = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+        break;
+    case 250:
+        // Influence from CharID? Is stockx gm controlled??\r
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 251:
+        // What is this "influence" ? Check this on live servers!\r
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 260:
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 2; //Fieldnum
+        snprintf (mSQLQuery, 500, "SELECT f_showname, f_name FROM forums WHERE f_area = %d+%d+%d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+        break;\r
+    case 261:
+        // Maybe even rewrite BB system.. its wrong written anyways....\r
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 262:
+        // This is wrong! 262 is the receiveDB request for FACTION threadlist. It should be limitet to that faction then\r
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND (fp_id = %s OR fp_replyid = %s)", nOptions[0].c_str(), nOptions[1].c_str());
+
+       //TODO Check this. Same (?) for ID 52,262,267,401 and 411\r
+        break;\r
+    case 266:
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND f_name = \'%s\' AND fp_replyid = 0 AND fp_clanid = %d LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+        break;\r
+    case 267:
+        mResultFields = 4;
+       snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND (fp_id = %s OR fp_replyid = %s)", nOptions[0].c_str(), nOptions[1].c_str());
+
+        break;\r
+    case 270:\r
+        Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d  Tablename/Name is: [%s] ThreadID is: [%d]", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID, atoi(nOptions[0].c_str()), nOptions[1].c_str());\r
+        break;\r
+    case 360:
+        // Gamemaster name (char), Accountname, Location, Online, CharID
+        if(!ChkOpt(nNumOptions, 3)) break;\r
+        mResultFields = 6;
+        snprintf (mSQLQuery, 500, "SELECT a.a_id, c.c_id, a.a_username, c.c_name, c.c_online, c.c_location FROM %s.characters AS c, %s.accounts AS a WHERE a.a_priv >= 50 AND c.c_online = %d AND c.a_id = a.a_id ORDER BY c.c_name LIMIT %d, %d",
+                                    Config->GetOption("game_sql_database").c_str(), Config->GetOption("info_sql_database").c_str(), atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+        break;
+    case 365:
+        // ID, short, name faction
+        if(!ChkOpt(nNumOptions, 2)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction FROM clans LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+        break;
+    case 366:
+        // ID, short, name faction WHERE clanname = %s
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction FROM clans WHERE cl_name LIKE \"%s\" LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+        break;
+    case 367:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 8;
+        snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_leader, cl_faction, cl_appid, cl_money, (SELECT count(*) FROM characters WHERE c_clan = %d) FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()));
+
+        break;
+    case 368:
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 2;
+        snprintf (mSQLQuery, 500, "SELECT cll_desc, cll_level FROM clanlevels WHERE cll_clanid = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+        break;
+    case 373:
+        if(!ChkOpt(nNumOptions, 2)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT apt_id, apt_location, apt_type, apt_password FROM apartments WHERE apt_id = %d AND apt_owner = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+        break;
+    case 375:
+        if(!ChkOpt(nNumOptions, 2)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+        break;
+    case 376:
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_name LIKE \"%s\" LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+        break;
+    case 377:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 1;
+        snprintf (mSQLQuery, 500, "SELECT DISTINCT a_id FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));
+
+        break;
+    case 378:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 5;
+        snprintf (mSQLQuery, 500, "SELECT a_username, a_email, \"Since begin\", \"Never\", FROM_UNIXTIME(a_bandate) FROM `%s`.accounts WHERE a_id = %d", Config->GetOption("info_sql_database").c_str(), atoi(nOptions[0].c_str()));
+
+        break;
+    case 379:\r
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 6;
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online, c_clan, cll_level FROM characters INNER JOIN clanlevels ON (cll_charid = c_id) WHERE c_id = %d", atoi(nOptions[0].c_str()));
+
+        break;
+    case 380: // clean
+        if(!ChkOpt(nNumOptions, 2)) break;
+        mResultFields = 2;
+        snprintf (mSQLQuery, 500, "SELECT cl_name, cll_desc FROM clans INNER JOIN clanlevels ON (cll_clanid = cl_id) WHERE cl_id = %d AND cll_level = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+        break;
+    case 381:
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, c_online FROM characters WHERE a_id = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+        break;
+    case 384: // clean
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT apt_id, apt_location, 0, apt_password FROM apartments WHERE apt_owner = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+        break;
+    case 400:
+        if(!ChkOpt(nNumOptions, 2)) break;
+        mResultFields = 4;
+       snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+        break;
+    case 401:
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 4;
+       snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") AND (fp_id = %d OR fp_replyid = %d)", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+        break;
+    case 406:
+        if(!ChkOpt(nNumOptions, 1)) break;\r
+        mResultFields = 1;
+       snprintf (mSQLQuery, 500, "SELECT count(fp_id) FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) WHERE f_name = \"%s\"", nOptions[0].c_str());
+
+        break;
+    case 410:
+        if(!ChkOpt(nNumOptions, 4)) break;
+        mResultFields = 4;
+       snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM forum_posts INNER JOIN forums ON (fp_forumid = f_area) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\" AND fp_factionid = %d) LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+        break;
+    case 411:
+        if(!ChkOpt(nNumOptions, 4)) break;
+        mResultFields = 4;
+       snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM forum_posts INNER JOIN forums ON (fp_forumid = f_area) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") AND (fp_id = %d OR fp_replyid = %d) AND (fp_factionid = %d)", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+        break;
+
+    case 420:
+        if(!ChkOpt(nNumOptions, 3)) break;\r
+        mResultFields = 6;\r
+        snprintf (mSQLQuery, 500, "SELECT e_id, e_subject, c_name, e_new, e_replied, e_datetime FROM emails, characters WHERE e_fromid = c_id AND e_toid = %i LIMIT %i, %i", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
+\r
+        break;\r
+    case 421:
+        if(!ChkOpt(nNumOptions, 1)) break;\r
+        //MailControl order. "MailControl", "Mail ID", "Subject", "From", boolean Replied, "Date/Time", "FromID", "Content"
+        mResultFields = 7;\r
+        snprintf (mSQLQuery, 500, "SELECT e_id, e_subject, c_name, e_replied, e_datetime, e_fromid, e_body FROM emails, characters WHERE e_fromid = c_id AND e_id = %s", nOptions[0].c_str());\r
+\r
+        break;
+    case 425:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        //Send mail order. "SendMail", "id"
+        mResultFields = 1;
+        snprintf (mSQLQuery, 500, "SELECT c_id FROM characters WHERE c_name = \'%s\'", nOptions[0].c_str());
+
+        break;
+    case 430:
+        if(!ChkOpt(nNumOptions, 2)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT a.c_id, a.c_conid, b.c_name, a.c_desc FROM contacts as a, characters as b WHERE a.c_conid = b.c_id AND a.c_listid = %s AND c_type = %s", nOptions[0].c_str(), nOptions[1].c_str());
+
+        break;\r
+    case 431:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT a.c_id, a.c_conid, b.c_name, a.c_desc FROM contacts as a, characters as b WHERE a.c_conid = b.c_id AND a.c_id = %s", nOptions[0].c_str());
+
+        break;
+    case 435:
+        if(!ChkOpt(nNumOptions, 2)) break;
+        mResultFields = 1;
+        snprintf (mSQLQuery, 500, "SELECT count(*) FROM contacts WHERE c_listid = %s AND c_type = %s", nOptions[0].c_str(), nOptions[1].c_str());
+
+        break;
+    case 436:
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 2;
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name FROM characters WHERE c_name LIKE \'%%%s%%\' LIMIT %s, %s", nOptions[0].c_str(), nOptions[1].c_str(), nOptions[2].c_str());
+
+        break;
+    case 437:
+        if(!ChkOpt(nNumOptions, 1)) break;\r
+        mResultFields = 1; //Fieldnum
+        snprintf (mSQLQuery, 500, "SELECT c_name FROM characters WHERE c_id = %s", nOptions[0].c_str());
+\r
+        break;
+    case 445:
+        if(!ChkOpt(nNumOptions, 4)) break;
+        mResultFields = 2;
+        snprintf (mSQLQuery, 500, "SELECT nc_id, nc_name FROM neochronicle WHERE nc_lang = %d ORDER BY nc_id DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+        break;
+    case 446:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 5;
+        snprintf (mSQLQuery, 500, "SELECT nc_id, nc_lang, nc_datetime, nc_name, nc_content FROM neochronicle WHERE nc_id = %d", atoi(nOptions[0].c_str()));
+
+        break;\r
+    case 453:
+        if(!ChkOpt(nNumOptions, 4)) break;
+        mResultFields = 5;
+        snprintf (mSQLQuery, 500, "SELECT g_id, 0, g_part, g_title, g_language FROM guides WHERE g_chapter = %d AND g_language = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+        break;
+    case 455:
+        if(!ChkOpt(nNumOptions, 4)) break;\r
+        mResultFields = 3;
+        // Opt 2 is Language
+        snprintf (mSQLQuery, 500, "SELECT g_id, g_part, g_title FROM guides WHERE g_chapter = %d AND g_language = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+\r
+        break;
+    case 456:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT g_id, g_language, g_title, g_content FROM guides WHERE g_id = %d", atoi(nOptions[0].c_str()));
+
+        break;
+    case 458: // Statisics
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;
+    case 459: // Statisics
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;
+    case 510: // ClanWars: Overview
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT cw_id, cl_name, cw_starttime, cw_status FROM clanwars INNER JOIN clans ON (cw_initclan = cl_id) or (cw_enemyclan = cl_id) WHERE (cw_enemyclan = %d OR cw_initclan = %d) AND (cl_id != %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+        break;
+    case 511: // ClanWars: Selfdeclared wars
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT cw_id, cl_name, cw_starttime, cw_status FROM clanwars INNER JOIN clans ON (cw_enemyclan = cl_id) WHERE cw_initclan = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+        break;
+    case 512: // ClanWars: Foreigndeclared wars
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 4;
+        snprintf (mSQLQuery, 500, "SELECT cw_id, cl_name, cw_starttime, cw_status FROM clanwars INNER JOIN clans ON (cw_initclan = cl_id) WHERE cw_enemyclan = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+        break;
+    case 513:
+        if(!ChkOpt(nNumOptions, 4)) break;
+        mResultFields = 2;
+        snprintf (mSQLQuery, 500, "SELECT cl_id, cl_name FROM clans WHERE cl_faction = %d AND cl_id != %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+        break;
+    case 514:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 2;
+        snprintf (mSQLQuery, 500, "SELECT cl_id, cl_name FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()));
+        break;
+    case 520:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 10;
+        snprintf (mSQLQuery, 500, "SELECT cl_faction, cl_shortdesc, cl_name, cl_description, 0, cl_appid, 80, cl_money, (SELECT count(*) FROM outposts WHERE o_clan = %d), (SELECT count(*) FROM characters WHERE c_clan = %d) FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()));
+
+        break;
+    case 521:
+        if(!ChkOpt(nNumOptions, 4)) break;
+        mResultFields = 6;
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, cll_desc, 0, c_online FROM characters INNER JOIN clanlevels ON (c_id = cll_charid) WHERE c_clan = %d AND cll_level >= %d AND cll_level < 15 LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+        break;
+    case 522:
+        if(!ChkOpt(nNumOptions, 5)) break;
+        mResultFields = 6;
+        snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, cll_desc, 0, c_online FROM characters INNER JOIN clanlevels ON (c_id = cll_charid) WHERE cll_level >= %d AND cll_level <= %d AND c_clan = %d ORDER BY cll_level DESC LIMIT %d, %d", atoi(nOptions[2].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str()));
+
+        break;
+    case 523:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 5;
+        snprintf (mSQLQuery, 500, "SELECT cl_shortdesc, cl_name, cl_leader, cl_description, cl_minsympathy FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()));
+
+        break;
+    case 540:
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 2;
+        snprintf (mSQLQuery, 500, "SELECT apt_id, apt_location FROM apartments WHERE apt_owner = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+        break;
+    case 541:
+        if(!ChkOpt(nNumOptions, 3)) break;
+        mResultFields = 2;
+        snprintf (mSQLQuery, 500, "SELECT v_id, v_type FROM vehicles WHERE v_owner = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+        break;
+    case 542:
+        if(!ChkOpt(nNumOptions, 2)) break;
+        mResultFields = 5;
+        snprintf (mSQLQuery, 500, "SELECT v_id, v_type, v_world, v_status, v_condition FROM vehicles WHERE v_owner = %d and v_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+        break;
+    case 544:
+        if(!ChkOpt(nNumOptions, 4)) break;
+        mResultFields = 1;
+        snprintf (mSQLQuery, 500, "SELECT count(*) FROM clanwars WHERE (cw_initclan = %d AND cw_enemyclan = %d) OR (cw_enemyclan = %d AND cw_initclan = %d)", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+        break;
+    case 546:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 2;
+        snprintf (mSQLQuery, 500, "SELECT cw_starttime, (TO_DAYS(NOW()) - TO_DAYS(cw_starttime)) FROM clanwars WHERE cw_id = %d", atoi(nOptions[0].c_str()));
+
+        break;
+    case 547:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        mResultFields = 6;
+        snprintf (mSQLQuery, 500, "SELECT cw_initclan, cw_enemyclan, cw_starttime, cw_status, cw_statement_initiator, cw_statement_enemy FROM clanwars WHERE cw_id = %d", atoi(nOptions[0].c_str()));
+
+        break;
+    case 557:
+        Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d means that you want to edit an DialogScript from the server. This is not supportet yet!", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;
+    case 558:\r
+        Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d means that you want to edit an DialogScript from the server. This is not supportet yet!", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;
+    case 562:
+        mResultFields = 6;
+        snprintf (mSQLQuery, 500, "SELECT cb_inscription FROM datacubes WHERE cb_id = %d", atoi(nOptions[0].c_str()));
+
+        break;
+    case 569:
+        // Faction representatives. Not stored yet... is it?\r
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;
+    case 570:
+        // Clan representatives. Stored but this query wants votes too... Maybe later
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;\r
+    case 571:
+        // Clan representatives. Stored but this query wants votes too... Maybe later
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;
+    case 572:
+        // Runner voting. Not stored yet
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 573:
+        // Next election date
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;
+    case 574:
+        mResultFields = 6;
+        snprintf (mSQLQuery, 500, "SELECT count(c_id) FROM characters WHERE c_faction = %d", atoi(nOptions[0].c_str()));
+\r
+        break;\r
+    case 575:
+        // Runner satisfaction with faction
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;
+    case 576:
+        // Check if vote from runner is already stored\r
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 582:
+        // Clan representative details. Faction rank etc... not stored yet
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;
+    case 583:
+        // Clan representative details. Faction rank etc... not stored yet
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;
+    case 584:
+        // Clan representative details. Faction rank etc... not stored yet
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;
+    case 587:
+        // Clan representative stuff again...
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;
+    case 603:
+        mResultFields = 1;
+        //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_status = 0");
+        snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_inwork = 0 AND su_finished = 0");
+
+        break;
+    case 604:
+        mResultFields = 1;
+        //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_status = 1");
+        snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_inwork = 1 AND su_finished = 0");
+
+        break;
+    case 605:
+        mResultFields = 1;
+        //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_status = 2");
+        snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_finished = 1");
+
+        break;
+    case 606:
+        mResultFields = 1;
+        //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report`");
+        snprintf (mSQLQuery, 500, "SELECT count(*) FROM support");
+
+        break;\r
+    case 607: // Dont know how to select data from sql where no data to JOIN is there anymore :/
+    // This should query ID, RunnerID and Date from bug reports where runnerID is unknown
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;
+    case 608:
+        mResultFields = 5;
+        snprintf (mSQLQuery, 500, "SELECT br_id, br_fromid, br_location, br_status, br_datetime FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str()));
+
+        break;
+    case 609:\r
+        mResultFields = 1;
+        //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_supid = %s", nOptions[0].c_str());
+        snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_supporterid = %d", atoi(nOptions[0].c_str()));
+\r
+        break;\r
+    case 610:\r
+        mResultFields = 6;
+        //snprintf (mSQLQuery, 500, "SELECT br_id, \"0\", c_name, br_location, br_status = 2, br_datetime FROM `bug report`, characters WHERE c_id = br_fromid AND br_supid = %s AND br_status > 0 LIMIT %s, %s", nOptions[0].c_str(), nOptions[1].c_str(), nOptions[2].c_str());
+        snprintf (mSQLQuery, 500, "SELECT su_id, su_supporterid, c_name, su_worldid, su_finished, su_datetime FROM support INNER JOIN characters ON (su_supporterid = c_id) WHERE su_supporterid = %d AND su_finished = 1 LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+\r
+        break;\r
+    case 611:// Well, its meant to show date specific stuff. I will rewrite this soon...
+        snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_supporterid = %d", atoi(nOptions[0].c_str()));
+        break;
+    case 612:// Well, its meant to show date specific stuff. I will rewrite this soon...
+        snprintf (mSQLQuery, 500, "SELECT su_id, su_supporterid, c_name, su_worldid, su_finished, su_datetime FROM support INNER JOIN characters ON (su_supporterid = c_id) WHERE su_supporterid = %d AND su_finished = 1 LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str()));
+        break;
+    case 625: // Faction council stuff
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;
+    case 626: // Faction council stuff
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;
+    case 627: // Faction council stuff
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;
+    case 628: // Faction council stuff
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;
+    case 629: // Faction council stuff
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+        break;
+    default:\r
+        Console->Print("%s [Pterminal::HandleReceiveDB]  Unknown QueryID %d", Console->ColorText(RED,BLACK,"Warning"), nDBID);\r
+        return false;\r
+    }
+
+    if(strlen(mSQLQuery) == 0)
+        return false;
+// ---------------
+    MYSQL_RES *result = NULL;
+    MYSQL_ROW row;
+    int tNumRows = 0;
+
+    result = MySQL->GameResQuery(mSQLQuery);
+    if (!result)
+    {
+        Console->Print("Cannot query DB. DBID: %d query was: %s", nDBID, mSQLQuery);
+        MySQL->ShowGameSQLError();
+        return false;
+    }
+
+    PMessage* tDBResult = new PMessage();
+    tNumRows = mysql_num_rows(result);
+
+    // Loop all result rows
+    for (int i = 0; i < tNumRows ; i++)
+    {
+        row = mysql_fetch_row( result ) ;
+        // Loop all result fields and push answers into Message
+        for (int t = 0; t < mResultFields; t++)
+        {
+            *tDBResult << ( u16 )(strlen(row[t]) + 1);
+            *tDBResult << row[t];
+        }
+    }
+
+    // Build result messages
+    char tCmd[100];
+    memset(tCmd, '\0', 100);
+    strncpy(tCmd, nCommandName->c_str(), 100);
+
+    PMessage* tmpMsg_allowed = MsgBuilder->BuildTryAccessAnswerMsg( nClient, tCmd, true );
+    PMessage* tmpMsg_result = MsgBuilder->BuildReceiveDBAnswerMsg( nClient, tDBResult, nCommandName, tNumRows, mResultFields);
+
+    nClient->SendUDPMessage(tmpMsg_allowed);
+    nClient->FragmentAndSendUDPMessage(tmpMsg_result, 0x68);
+
+    return true;\r
+}\r
diff --git a/server/src/game/terminal_tryaccess.cpp b/server/src/game/terminal_tryaccess.cpp
new file mode 100644 (file)
index 0000000..41356b6
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+
+
+/*
+ terminal_tryaccess.cpp - Management class for Terminal actions (Citycom, keys, vehicledepot, ...)
+ > Sub-File for terminal "TryAccess" command
+
+ MODIFIED: 12 Jan 2007 Namikon
+ REASON: - Created
+ MODIFIED: 20 Oct 2009 Namikon
+ REASON: - Rewritten
+
+*/
+
+#include "main.h"
+#include "terminal.h"
+#include "msgbuilder.h"
+
+bool PTerminal::DoStockXCheck(PClient* nClient, int nAmountEntered, int nNewAmount)
+{
+    MYSQL_RES *result = NULL;
+    char qry[100];
+    int tDepotAmount = 0;
+
+    // First check if we BUY or SELL stockx
+    snprintf(qry, 100, "SELECT sxd_amount FROM stockx_depots WHERE sxd_playerid = %d", nClient->GetChar()->GetID());
+    result = MySQL->GameResQuery(qry);
+    if (!result)
+    {
+        Console->Print("%s [PTerminal::DoStockXCheck] Cannot query DB. Query was: %s", Console->ColorText(RED, BLACK, "Error"), qry);
+        MySQL->ShowGameSQLError();
+        return false;
+    }
+
+    if(mysql_num_rows(result) > 0)
+        tDepotAmount = atoi(mysql_fetch_row(result)[0]);
+
+    MySQL->FreeGameSQLResult(result);
+
+    if(nNewAmount == tDepotAmount) // We are going to SELL stockx
+    {
+        if(nAmountEntered > tDepotAmount) // Want to sell more than we have?
+        {
+            return false;
+        }
+    }
+    else if((nNewAmount - nAmountEntered) == tDepotAmount) // We are going to BUY stockx
+    {
+        if(nNewAmount > 10000) // Hardcoded limit of 10k per faction
+        {
+            return false;
+        }
+    }
+    else // Strange unknown thing, return false just to be sure!
+    {
+        return false;
+    }
+
+    // Everything went fine
+    return true;
+}
+
+bool PTerminal::HandleTryAccess(PClient* nClient, u16 mTerminalSessionId, std::string *nCommandName, std::string *nOptions, u8 nNumOptions, u16 nDBID, u8 nUnknown, bool nCheckOnly)
+{
+    // Empty buffer
+    EraseVars();
+
+    // Stop gcc annoying about unused var
+    u8 dummy2 = nUnknown;
+    u16 dummy3 = mTerminalSessionId;
+    dummy3 = dummy2;
+
+    char mSQLQuery[500];
+    bool tGetResultFromSQL = false;
+    bool tAllowed = false;
+    int nAccessLevel = nClient->GetAccountLevel();
+    int tCharID = nClient->GetChar()->GetID();
+
+    switch(nDBID)
+    {
+        case 13: // Access to Neocronicle as GameMaster
+        if(nAccessLevel >= PAL_VOLUNTEER)
+            tAllowed = true;
+        break;
+
+        case 63: // Access to Outpost security status; ClanLevel >= 3
+            if(!ChkOpt(nNumOptions, 1)) break;
+            tGetResultFromSQL = true;
+            snprintf(mSQLQuery, 500, "SELECT count(*) FROM clanlevels INNER JOIN clans ON (cll_clanid = cl_id) INNER JOIN outposts ON (o_clan = cl_id) WHERE (o_outnum = %d AND cll_charid = %d AND cll_level >= 3)", atoi(nOptions[0].c_str()), tCharID);
+        break;
+
+        case 64: // Clan: ClanWars
+        if(!ChkOpt(nNumOptions, 1)) break;
+        tGetResultFromSQL = true;
+        snprintf(mSQLQuery, 500, "SELECT count(*) FROM clanlevels INNER JOIN clans ON (cll_clanid = cl_id) WHERE (cl_id = %d AND cll_charid = %d AND cll_level >= 14)", atoi(nOptions[0].c_str()), tCharID);
+        break;
+
+        case 72: // Clan: AdminMemberAccess & AdminMoneyAccess
+        if(!ChkOpt(nNumOptions, 1)) break;
+        tGetResultFromSQL = true;
+        snprintf(mSQLQuery, 500, "SELECT count(*) FROM clanlevels INNER JOIN clans ON (cll_clanid = cl_id) WHERE (cl_id = %d AND cll_charid = %d AND cll_level >= 9)", atoi(nOptions[0].c_str()), tCharID);
+        break;
+
+        case 73: // Clan: AdminInviteMember
+        if(!ChkOpt(nNumOptions, 1)) break;
+        tGetResultFromSQL = true;
+        snprintf(mSQLQuery, 500, "SELECT count(*) FROM clanlevels INNER JOIN clans ON (cll_clanid = cl_id) WHERE (cl_id = %d AND cll_charid = %d AND cll_level >= 10)", atoi(nOptions[0].c_str()), tCharID);
+        break;
+
+        case 74: // Clan: AdminLevelAccess & AdminChangeRank
+        if(!ChkOpt(nNumOptions, 1)) break;
+        tGetResultFromSQL = true;
+        snprintf(mSQLQuery, 500, "SELECT count(*) FROM clanlevels INNER JOIN clans ON (cll_clanid = cl_id) WHERE (cl_id = %d AND cll_charid = %d AND cll_level >= 12)", atoi(nOptions[0].c_str()), tCharID);
+        break;
+
+        case 88: // Clan: Money transfer Check if Option1 (Entered value) is lower or equal Option2 (Either my money or clan money)
+        if(!ChkOpt(nNumOptions, 2)) break;
+        if((atoi(nOptions[0].c_str()) <= atoi(nOptions[1].c_str())) && (atoi(nOptions[0].c_str()) > 0 )) // This is an not-very-well check, we do the real check later when its about to transfer the money!
+            tAllowed = true;
+        break;
+
+        case 95: // Clan: Check if given TextString is valid (Opt1 = String)
+        if(!ChkOpt(nNumOptions, 1)) break;
+        if(atoi(nOptions[0].c_str()) >= 0 && atoi(nOptions[0].c_str()) <= 15)
+            tAllowed = true;
+        break;
+
+        case 110: // GMTool Access check. If GM, allowed
+        if(nAccessLevel > PAL_VOLUNTEER)
+            tAllowed = true;
+        break;
+
+        case 184: // Clan: Delete (Opt1: ClanID Opt2: CharID Opt3: ClanMemberCount) Allow clandelete only when Leader is the only one left
+        if(!ChkOpt(nNumOptions, 1)) break;
+        tGetResultFromSQL = true;
+        // The result of this query is 0 (false) if wrong clan, is 1 (true) when clan is correct and leader is the only member left and <membercount> (false, not 1) if there are members left
+        snprintf(mSQLQuery, 500, "SELECT count(*) FROM characters INNER JOIN clans ON (c_clan = cl_id) WHERE cl_id = %d AND cl_leader = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+        break;
+
+        case 201: // Clan: Invite Member. Check if target ID has already a clan and check if he is online right now. Location doesnt matter for us :)
+        if(!ChkOpt(nNumOptions, 1)) break;
+        tGetResultFromSQL = true;
+        snprintf(mSQLQuery, 500, "SELECT count(*) FROM characters WHERE c_id = %d AND c_clan = 0 AND c_online = 1", atoi(nOptions[0].c_str()));
+        break;
+
+        case 202: // CityCom and Check if given ID is > 0
+        if(!ChkOpt(nNumOptions, 1)) break;
+        if(atoi(nOptions[0].c_str()) > 0)
+            tAllowed = true;
+        break;
+
+        case 208: // Clan: AdminDismissMember & ClanAdminAccess & AdminInviteMember // General ClanAdmin access in CityCom
+        if(!ChkOpt(nNumOptions, 1)) break;
+        if(nClient->GetChar()->GetClan() == atoi(nOptions[0].c_str()))
+            tAllowed = true;
+        break;
+
+        case 209: // Give money to clan. Level 0+ ? Just check if clan = clan here..
+        if(!ChkOpt(nNumOptions, 1)) break;
+        tGetResultFromSQL = true;
+        snprintf(mSQLQuery, 500, "SELECT count(*) FROM clanlevels INNER JOIN clans ON (cll_clanid = cl_id) WHERE (cl_id = %d AND cll_charid = %d)", atoi(nOptions[0].c_str()), tCharID);
+        break;
+
+        case 214: // Take money from clan. Level 9+
+        if(!ChkOpt(nNumOptions, 1)) break;
+        tGetResultFromSQL = true;
+        snprintf(mSQLQuery, 500, "SELECT count(*) FROM clanlevels INNER JOIN clans ON (cll_clanid = cl_id) WHERE (cl_id = %d AND cll_charid = %d AND cll_level >= 9)", atoi(nOptions[0].c_str()), tCharID);
+        break;
+
+        case 215:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        tGetResultFromSQL = true;
+        snprintf(mSQLQuery, 500, "SELECT count(*) FROM clanlevels INNER JOIN clans ON (cll_clanid = cl_id) WHERE (cl_id = %d AND cll_charid = %d AND cll_level >= 10)", atoi(nOptions[0].c_str()), tCharID);
+        break;
+
+        case 216:
+        if(!ChkOpt(nNumOptions, 1)) break;
+        tGetResultFromSQL = true;
+        snprintf(mSQLQuery, 500, "SELECT count(*) FROM clanlevels INNER JOIN clans ON (cll_clanid = cl_id) WHERE (cl_id = %d AND cll_charid = %d AND cll_level >= 12)", atoi(nOptions[0].c_str()), tCharID);
+        break;
+
+        case 217: // Access clanwars lv 14+
+        if(!ChkOpt(nNumOptions, 1)) break;
+        tGetResultFromSQL = true;
+        snprintf(mSQLQuery, 500, "SELECT count(*) FROM clanlevels INNER JOIN clans ON (cll_clanid = cl_id) WHERE (cl_id = %d AND cll_charid = %d AND cll_level >= 14)", atoi(nOptions[0].c_str()), tCharID);
+        break;
+
+        case 218: // Leader only. Access to "misc" section of clans
+        if(!ChkOpt(nNumOptions, 1)) break;
+        tGetResultFromSQL = true;
+        snprintf(mSQLQuery, 500, "SELECT count(*) FROM clans WHERE cl_id = %d AND cl_leader = %d", atoi(nOptions[0].c_str()), tCharID);
+        break;
+
+        case 239: // StockX: Buy/Sell/Trade
+        if(!ChkOpt(nNumOptions, 2)) break;
+        // We checked stockx earlier in #240. Now just proof that the calculated values are correct. EG: Option 1 > Option 2
+        if(atoi(nOptions[0].c_str()) > atoi(nOptions[1].c_str()))
+            tAllowed = true;
+        break;
+
+        case 240: // StockX. Need special handling
+        if(!ChkOpt(nNumOptions, 2)) break;
+        tAllowed = DoStockXCheck(nClient, atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+        break;
+
+        case 259: // CityComSetup: SetCategorys for Forum | Check if Runner is ProNC or ProDoY
+        if(nClient->GetChar()->GetFaction() < 7 || nClient->GetChar()->GetFaction() == 11) // 1-7 ProNC, 8-15 ProDoY 11: CityMercs
+            tAllowed = true;
+        break;
+
+        case 264: // Check if player has a faction. Deny access if not (Opt1: FactionID)
+        if(!ChkOpt(nNumOptions, 1)) break;
+        if(atoi(nOptions[0].c_str()) > 0)
+            tAllowed = true;
+        break;
+
+        case 269: // Check if player has a clan. Deny access if not (Opt1: ClanID)
+        if(!ChkOpt(nNumOptions, 1)) break;
+        if(atoi(nOptions[0].c_str()) > 0)
+            tAllowed = true;
+        break;
+
+        case 310: // Warp to another GameMaster (GM Helper level)
+        if(nAccessLevel > PAL_VOLUNTEER)
+            tAllowed = true;
+        break;
+
+        case 315: // Warp players around, from/to GM kick players
+        if(nAccessLevel >= PAL_GM)
+            tAllowed = true;
+        break;
+
+        case 320:
+        if(nAccessLevel >= PAL_GM)
+            tAllowed = true;
+        break;
+
+        case 330:
+        if(nAccessLevel >= PAL_GM)
+            tAllowed = true;
+        break;
+
+        case 340:
+        if(nAccessLevel >= PAL_GM)
+            tAllowed = true;
+        break;
+
+        case 350: // Delete Clans, StockX
+        if(nAccessLevel >= PAL_ADMIN)
+            tAllowed = true;
+        break;
+
+        case 438: // Check if Contactlist has already 20 entries. If so, allow = false
+        if(!ChkOpt(nNumOptions, 1)) break;
+        if(atoi(nOptions[0].c_str()) < 21)
+            tAllowed = true;
+        break;
+
+        case 470: // Something with clanranking... have to verify this
+        Console->Print("%s [PTerminal::TryAccess] Accesscode 470 is not supportet yet; \"DCBResetPosition\": Option1 [%s]", Console->ColorText(YELLOW, BLACK, "Notice"), nOptions[0].c_str());
+        if(nAccessLevel >= PAL_ADMIN)
+            tAllowed = true;
+        break;
+
+        case 471: // Something with TimeStamp. NC had a problem with GameTime back then, maybe this is a check if ingametime is correct
+        if(!ChkOpt(nNumOptions, 2)) break;
+        if(atoi(nOptions[0].c_str()) != atoi(nOptions[1].c_str()))
+            tAllowed = true;
+        break;
+
+        case 586: // Check if player is the current Representive of clan (Opt1: PlayerID Opt2: ClanRepID)
+        if(!ChkOpt(nNumOptions, 2)) break;
+        if(atoi(nOptions[0].c_str()) == atoi(nOptions[1].c_str()))
+            tAllowed = true;
+        Console->Print("This ID is marked as CHECK IF ITS WORKING %d", nDBID);
+        break;
+
+        case 621: // In text.ini (Section 4 text 330) it says something about clanwars.. Not sure. file: politics\administration.tsc(31)
+        Console->Print("%s [PTerminal::TryAccess] Accesscode 621 is not supportet yet; \"GetOutOfMySight\": CharID [%d] FactionRank [%d]", Console->ColorText(YELLOW, BLACK, "Notice"), atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+        if(nAccessLevel >= PAL_ADMIN)
+            tAllowed = true;
+        break;
+
+        case 622: // TakeMoney from Faction wallet. Check if Player is allowed to do this. For now, only GMs may do this
+        if(nAccessLevel >= PAL_GM)
+            tAllowed = true;
+        break;
+
+        case 624: // Same as 622, Take/Give money from/to Faction wallet. GM only
+        if(nAccessLevel >= PAL_GM)
+            tAllowed = true;
+        break;
+
+        default:
+        Console->Print("%s [PTerminal::TryAccess] Unknown DBID: %d", Console->ColorText(RED,BLACK,"Error"), nDBID);
+        return false;
+    }
+
+
+    // ----------------
+    if(tGetResultFromSQL == true)
+    {
+        MYSQL_RES *result = NULL;
+        //MYSQL_ROW row;
+        int tNumRows = 0;
+
+        result = MySQL->GameResQuery(mSQLQuery);
+        if (!result)
+        {
+            Console->Print("Cannot query DB. DBID: %d query was: %s", nDBID, mSQLQuery);
+            MySQL->ShowGameSQLError();
+            return false;
+        }
+
+        tNumRows = mysql_num_rows(result);
+        if(tNumRows == 0)
+            tAllowed = false;
+        else
+        {
+            if(atoi(mysql_fetch_row(result)[0]) == 1)
+                tAllowed = true;
+        }
+        MySQL->FreeGameSQLResult(result);
+    }
+    // ----------------
+
+
+    if (gDevDebug) Console->Print("[PTerminal::TryAccess] DBID is: [%d] LoopBack: [%s] Allowed: [%d]", nDBID, nCommandName->c_str(), tAllowed);
+    if(!nCheckOnly)
+    {
+        char tCmd[100];
+        memset(tCmd, '\0', 100);
+        strncpy(tCmd, nCommandName->c_str(), 100);
+
+        PMessage* tmpMsg = MsgBuilder->BuildTryAccessAnswerMsg(nClient, tCmd, tAllowed);
+        nClient->SendUDPMessage(tmpMsg);
+    }
+
+    return tAllowed;
+}
diff --git a/server/src/game/terminal_updatedb.cpp b/server/src/game/terminal_updatedb.cpp
new file mode 100644 (file)
index 0000000..461760f
--- /dev/null
@@ -0,0 +1,364 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       terminal_upcatedb.cpp - Management class for Terminal actions (Citycom, keys, vehicledepot, ...)\r
+       > Sub-File for terminal "UpdateDB" command\r
+\r
+       MODIFIED: 12 Jan 2007 Namikon\r
+       REASON: - Created\r
+\r
+*/\r
+\r
+#include "main.h"\r
+#include "terminal.h"\r
+#include "msgbuilder.h"\r
+\r
+\r
+bool PTerminal::HandleUpdateDB(PClient* nClient, u16 mTerminalSessionId, std::string *nCommandName, std::string *nOptions, u8 nNumOptions, u16 nDBID, u8 nUnknown)\r
+{\r
+    ostringstream tLongSQL; // omg my eyes... Stringstream is one of the worst inventions ever! Stick with printf syntax!!111
+    char tShortSQL[1024]; // Use this for small updates that will not exceed 1kb
+    memset(tShortSQL, '\0', 1024);
+    bool tSuccess = false;
+
+    //Console->Print("UpdateDB ID: %d", nDBID);\r
+    switch (nDBID)\r
+    {\r
+    case 5:\r
+        tLongSQL << "INSERT INTO neochronicle (nc_icon, nc_author, nc_datetime, nc_name, nc_content)";
+        tLongSQL << " VALUES (" << atoi(nOptions[0].c_str()) << ", \"" << nOptions[1] << "\", \"" << nOptions[2] << "\", \"" << nOptions[3] << "\", \"" << nOptions[4] << "\")";
+\r
+        break;\r
+    case 6:\r
+        // UPDATE when Neocronicle DB is changed! author must be CHAR not INT
+        break;\r
+    case 7: // Delete neocronicle\r
+        snprintf(tShortSQL, 1024, "DELETE FROM neochronicle WHERE nc_id = %d", atoi(nOptions[0].c_str()));\r
+        break;\r
+    case 12:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 53: // Runner writing to public board\r
+        snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str(), nOptions[4].c_str(), nOptions[5].c_str());\r
+        break;\r
+    case 58:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 62: // Set new outpost security
+        snprintf(tShortSQL, 1024, "UPDATE outposts SET o_security = %d WHERE o_outnum = %d AND o_clan = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
+        break;\r
+
+    case 66: // Claninfo stuff that is somehow never used... Print error if it is
+    case 67:
+        Console->Print("%s [Pterminal::HandleUpdateDB] QueryID %d should never happen. Please contact Linux Addited forums!", Console->ColorText(RED,BLACK,"Notice"), nDBID);
+        break;\r
+\r
+    case 77: // Delete old clanlevel
+        snprintf(tShortSQL, 1024, "DELETE FROM clanlevels WHERE cll_clanid = %d AND cll_level = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
+        break;\r
+    case 78: // Add new clanlevel
+        snprintf(tShortSQL, 1024, "INSERT INTO clanlevels (cll_clanid, cll_desc, cll_level) VALUES (%d, \"%s\", %d)", atoi(nOptions[0].c_str()), nOptions[1].c_str(), atoi(nOptions[2].c_str()));\r
+        break;\r
+    case 84: // Take/Give money to/from clan\r
+        tLongSQL << "INSERT INTO moneytransactions (mt_clanid, mt_player, mt_amount, mt_date, mt_comment) ";
+        tLongSQL << "VALUES (" << atoi(nOptions[0].c_str()) << ", " << atoi(nOptions[1].c_str()) << ", " << atoi(nOptions[2].c_str()) << ", \"" << nOptions[3] << "\", \"" << nOptions[4] << "\")";
+        break;\r
+    case 94: // Update runner description
+        snprintf(tShortSQL, 1024, "UPDATE characters SET c_desc = \"%s\" WHERE c_id = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()));\r
+        break;\r
+    case 97:
+        // Just ignore that... KK required some extra updates here
+        tSuccess = true;\r
+        //Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 120: // Create support call
+        snprintf(tShortSQL, 1024, "INSERT INTO support (su_player, su_worldid, su_type, su_desc) VALUES (%d, %d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str());\r
+        break;\r
+    case 121:\r
+        snprintf(tShortSQL, 1024, "UPDATE support SET su_inwork = 1, su_supporterid = %d WHERE su_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
+        break;\r
+    case 122:\r
+        snprintf(tShortSQL, 1024, "UPDATE support SET su_inwork = 0, su_supporterid = 0 WHERE su_id = %d AND su_supporterid = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
+        break;\r
+    case 123:\r
+        snprintf(tShortSQL, 1024, "UPDATE support SET su_inwork = 1, su_finished = 1, su_supporterid = %d WHERE su_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
+        break;\r
+    case 124:\r
+        snprintf(tShortSQL, 1024, "DELETE FROM support WHERE su_id = %d", atoi(nOptions[0].c_str()));\r
+        break;\r
+    case 133:
+        tSuccess = true;\r
+        //Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 139:
+        snprintf(tShortSQL, 1024, "UPDATE characters SET c_location = %d WHERE c_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
+        break;\r
+    case 142:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 149: // Changeleader 2nd step. Update clanappartment owner\r
+        snprintf(tShortSQL, 1024, "UPDATE apartments SET apt_owner = %d WHERE apt_id = %d AND apt_owner = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
+        break;\r
+    case 160: // Missions, not yet\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 161: // Missions, not yet\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 162: // Missions, not yet\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 163: // Missions, not yet\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 164: // Missions, not yet\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 165: // Missions, not yet\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 170: // Enter new bug
+        snprintf(tShortSQL, 1024, "INSERT INTO bug_report (br_type, br_status, br_title, br_desc, br_location, br_fromid, br_datetime) VALUES (%d, %d, \"%s\", \"%s\", %d, %d, NOW())", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str(), nOptions[3].c_str(), atoi(nOptions[4].c_str()), atoi(nOptions[5].c_str()));\r
+        break;\r
+    case 172: // Delete bug id %d\r
+        snprintf(tShortSQL, 1024, "DELETE FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str()));
+        break;
+    case 180:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 182:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 235:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 252:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 263: // Runner writing to Faction Board
+        snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_factionid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()), nOptions[4].c_str(), nOptions[5].c_str(), nOptions[6].c_str());\r
+        break;\r
+    case 268: // Runner writing to ClanBoard\r
+        snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_clanid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()), nOptions[4].c_str(), nOptions[5].c_str(), nOptions[6].c_str());\r
+        break;\r
+    case 370: // GM ClanRepair\r
+        snprintf(tShortSQL, 1024, "INSERT INTO clanlevels (cll_clanid, cll_level, cll_desc) VALUES (%d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str());\r
+        break;\r
+    case 385: // Clandelete 1/7 Clanlevels
+        snprintf(tShortSQL, 1024, "DELETE FROM clanlevels WHERE cl_clanid = %d", atoi(nOptions[0].c_str()));\r
+        break;\r
+    case 386: // Clandelete 2/7 Outposts
+        snprintf(tShortSQL, 1024, "UPDATE outposts SET o_clan = 0 WHERE o_clan = %d", atoi(nOptions[0].c_str()));\r
+        break;\r
+    case 387: // Clandelete 3/7 Free users from clans
+        snprintf(tShortSQL, 1024, "UPDATE characters SET c_clan = 0 WHERE c_clan = %d", atoi(nOptions[0].c_str()));\r
+        break;\r
+    case 388: // Clandelete 4/7 The clan itself
+        snprintf(tShortSQL, 1024, "DELETE FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()));\r
+        break;\r
+    case 389: // Clandelete 5/7 ?
+        tSuccess = true;\r
+        break;\r
+    case 390: // Clandelete 6/7 Clanappartment
+        snprintf(tShortSQL, 1024, "DELETE FROM apartments WHERE apt_id = %d", atoi(nOptions[0].c_str()));\r
+        break;\r
+    case 391: // Clandelete 7/7 ?
+        tSuccess = true;\r
+        break;\r
+    case 402: // GM writing to publicforum
+        snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str(), nOptions[4].c_str(), nOptions[5].c_str());\r
+        break;\r
+    case 404: // GM deleting forum entry step 1
+        snprintf(tShortSQL, 1024, "DELETE FROM forum_posts WHERE fp_id = %d", atoi(nOptions[0].c_str()));\r
+        break;\r
+    case 405: // GM deleting forum entry step 2
+        snprintf(tShortSQL, 1024, "DELETE FROM forum_posts WHERE fp_replyid = %d", atoi(nOptions[0].c_str()));\r
+        break;\r
+    case 412: // GM writing to faction forum\r
+        snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_factionid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()), nOptions[4].c_str(), nOptions[5].c_str(), nOptions[6].c_str());\r
+        break;\r
+    case 422: // Mark email as replied\r
+        snprintf(tShortSQL, 1024, "UPDATE emails SET e_replied = 1 WHERE e_id = %d", atoi(nOptions[0].c_str()));\r
+        break;\r
+    case 423: // Write new email
+        snprintf(tShortSQL, 1024, "INSERT INTO emails (e_fromid,e_toid,e_datetime,e_subject,e_body) VALUES (%d, %d, \"%s\", \"%s\", \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str(), nOptions[3].c_str(), nOptions[4].c_str());\r
+        break;\r
+    case 424: // Delete email\r
+        snprintf(tShortSQL, 1024, "DELETE FROM emails WHERE e_id = %d", atoi(nOptions[0].c_str()));\r
+        break;\r
+    case 426: // Mark email as read\r
+        snprintf(tShortSQL, 1024, "UPDATE emails SET e_new = 0 WHERE e_id = %d", atoi(nOptions[0].c_str()));\r
+        break;\r
+    case 432: // Add new contact
+        snprintf(tShortSQL, 1024, "INSERT INTO contacts (c_listid,c_conid,c_type,c_desc) VALUES (%d, %d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str());
+        break;\r
+    case 433: // Edit contact
+        snprintf(tShortSQL, 1024, "UPDATE contacts SET c_type = %d, c_desc = \"%s\" WHERE c_id = %d", atoi(nOptions[0].c_str()), nOptions[1].c_str(), atoi(nOptions[2].c_str()));
+        break;\r
+    case 434: // Delete contact\r
+        snprintf(tShortSQL, 1024, "DELETE FROM contacts WHERE c_id = %d", atoi(nOptions[0].c_str()));\r
+        break;\r
+    case 447:
+        snprintf(tShortSQL, 1024, "INSERT INTO neochronicle (nc_icon, nc_author, nc_datetime, nc_name, nc_content, nc_lang) VALUES (%d, \"%s\", \"%s\", \"%s\", \"%s\", %d)", atoi(nOptions[0].c_str()), nOptions[1].c_str(), nOptions[2].c_str(), nOptions[3].c_str(), nOptions[4].c_str(), atoi(nOptions[5].c_str()));\r
+        break;\r
+    case 450:
+        snprintf(tShortSQL, 1024, "INSERT INTO guides (g_chapter, g_part, g_title, g_content, g_language) VALUES (%d, %d, \"%s\", \"%s\", %d)", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str(), nOptions[3].c_str(), atoi(nOptions[4].c_str()));\r
+        break;\r
+    case 515: // Create new clanwar\r
+        snprintf(tShortSQL, 1024, "INSERT INTO clanwars (cw_initclan, cw_enemyclan, cw_starttime) VALUES (%d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str());\r
+        break;\r
+    case 516:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 517:
+        // Special: Check if Clan of our char is = nOption2
+        if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str()))\r
+            snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_status = %d WHERE cw_id = %d AND cw_initclan = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+        // else: SQL Query is empty = failed as result
+        break;\r
+    case 518:
+        if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str()))\r
+            snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_status = %d WHERE cw_id = %d AND cw_enemyclan = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+        // else: SQL Query is empty = failed as result
+        break;\r
+    case 519:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 525: // Update clan short\r
+        tLongSQL << "UPDATE clans SET cl_shortdesc = \"" << nOptions[0] << "\" WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str());
+
+        break;\r
+    case 526: // Update clan name\r
+        tLongSQL << "UPDATE clans SET cl_name = \"" << nOptions[0] << "\" WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str());
+
+        break;\r
+    case 527: // Update clanapp password
+        //UPDATE apartments SET apt_password = x WHERE apt_owner = x AND apt_id = (SELECT clans.cl_appid WHERE clans.cl_id = x)\r
+        tLongSQL << "UPDATE apartments SET apt_password = \"" << nOptions[0] << "\" WHERE apt_owner = " << atoi(nOptions[2].c_str()) << " AND apt_id = (SELECT cl_appid FROM clans WHERE cl_id = " << atoi(nOptions[1].c_str()) << ")";\r
+        break;\r
+    case 528:
+        tLongSQL << "UPDATE clans SET cl_minsympathy = " << atoi(nOptions[0].c_str()) << " WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str());\r
+        break;\r
+    case 529:
+        tLongSQL << "UPDATE clans SET cl_description = \"" << nOptions[0] << "\" WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str());
+        break;\r
+    case 543:
+        // Only delete if: option 2 is >= 7 (days); option0 is 5 or 6; option 4 = our clanid
+        if(atoi(nOptions[2].c_str()) >= 7)
+            if(atoi(nOptions[0].c_str()) == 5 || atoi(nOptions[0].c_str()) == 6)
+                if(nClient->GetChar()->GetClan() == atoi(nOptions[4].c_str()))
+                    snprintf(tShortSQL, 1024, "DELETE FROM clanwars WHERE (cw_status = 5 OR cw_status = 6) AND cw_id = %d AND cw_initclan = %d", atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str()));
+\r
+        //Console->Print("%s", tShortSQL);
+        break;\r
+    case 548:
+        // Check clanmembership
+        if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str()))
+            snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_statement_initiator = \"%s\" WHERE cw_id = %d AND cw_initclan = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
+        break;\r
+    case 549:
+        // Check clanmembership
+        if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str()))\r
+            snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_statement_enemy = \"%s\" WHERE cw_id = %d AND cw_enemyclan = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+        break;
+    case 555:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 556:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 561:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 577:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 578:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 579:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 580:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 581:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 585:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 590:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 591:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    case 600: // Just ok, skip it\r
+        tSuccess = true;\r
+        break;\r
+    case 601: // Just ok, skip it\r
+        tSuccess = true;\r
+        break;\r
+    case 630:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
+        break;\r
+    default:\r
+        Console->Print("%s [Pterminal::HandleUpdateDB]  Unknown QueryID %d", Console->ColorText(RED,BLACK,"Warning"), nDBID);\r
+        return false;\r
+    }\r
+
+// -------
+    if(tLongSQL.str().length() > 0)
+    {
+        if(MySQL->GameQuery(tLongSQL.str().c_str()))
+        {
+            Console->Print("Cannot update DB. query was: %s", tLongSQL.str().c_str());
+            MySQL->ShowGameSQLError();
+            tSuccess = false;
+        }
+        else
+            tSuccess = true;
+    }
+    else if(strlen(tShortSQL) > 0)
+    {
+        if(MySQL->GameQuery(tShortSQL))
+        {
+            Console->Print("Cannot update DB. query was: %s", tShortSQL);
+            MySQL->ShowGameSQLError();
+            tSuccess = false;
+        }
+        else
+            tSuccess = true;
+    }
+
+    // Notice client about UpdateDB result
+    char tCmd[100];
+    memset(tCmd, '\0', 100);
+    strncpy(tCmd, nCommandName->c_str(), 100);
+
+    PMessage* tmpMsg = MsgBuilder->BuildTryAccessAnswerMsg(nClient, tCmd, tSuccess);
+    nClient->SendUDPMessage(tmpMsg);
+    return true;\r
+}\r
diff --git a/server/src/game/vehicle.cpp b/server/src/game/vehicle.cpp
new file mode 100644 (file)
index 0000000..60ee1ad
--- /dev/null
@@ -0,0 +1,530 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+ maintainer Akiko <akiko@gmx.org>\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+ vehicle.cpp - Vehicle handling\r
+\r
+ Authors:\r
+ - Namikon\r
+\r
+        MODIFIED: 08 Jan 2006 Namikon\r
+        REASON: - initial release by Namikon\r
+*/\r
+\r
+#include "main.h"\r
+#include "vehicle.h"\r
+#include "worlds.h"\r
+\r
+// PVhcCoordinates\r
+void PVhcCoordinates::SetInterpolate( const PVhcCoordinates& Pos1, const PVhcCoordinates& Pos2, f32 nCoef )\r
+{\r
+  if (( nCoef < 0 ) || ( nCoef > 1 ) )\r
+  {\r
+    Console->Print( RED, BLACK, "[Error] PVhcCoordinates::Interpolate : Invalid nCoef value: %f", nCoef );\r
+    nCoef = 0;\r
+  }\r
+  f32 rCoef = 1 - nCoef;\r
+\r
+  mY = ( u16 )( rCoef * Pos1.mY + nCoef * Pos2.mY );\r
+  mZ = ( u16 )( rCoef * Pos1.mZ + nCoef * Pos2.mZ );\r
+  mX = ( u16 )( rCoef * Pos1.mX + nCoef * Pos2.mX );\r
+  mUD = ( u8 )( rCoef * Pos1.mUD + nCoef * Pos2.mUD );\r
+  mLR = ( u16 )( rCoef * Pos1.mLR + nCoef * Pos2.mLR );\r
+  mRoll = ( u16 )( rCoef * Pos1.mRoll + nCoef * Pos2.mRoll );\r
+}\r
+\r
+void PVhcCoordinates::SetPosition( u16 nY, u16 nZ, u16 nX, u8 nUD, u16 nLR, u16 nRoll, u8 nAct, u16 nUnknown, u8 nFF )\r
+{\r
+  mY = nY;\r
+  mZ = nZ;\r
+  mX = nX;\r
+  mUD = nUD;\r
+  mLR = nLR;\r
+  mRoll = nRoll;\r
+  mAct = nAct;\r
+  mUnknown = nUnknown;\r
+  mFF = nFF;\r
+}\r
+\r
+// PVehicleInformation\r
+//Tmp\r
+const u8 VhcTypes[] = {  1,  2,  3,  4,  5,  6,  7,  8,  9, 10,\r
+                         11, 12, 13, 50, 60, 62, 64, 65, 70\r
+                      }; // (adv.) assault gliders discarded because not ok\r
+#define VHC_DISABLE_NOVULARI\r
+#ifndef VHC_DISABLE_NOVULARI\r
+const u8 VhcTypesNum = 19;\r
+#else\r
+const u8 VhcTypesNum = 18;\r
+#endif\r
+\r
+bool PVehicleInformation::Load( u32 nVehicleId )\r
+{\r
+  u8 i;\r
+  u8 nVId = nVehicleId % 100; //Tmp\r
+  for ( i = 0; ( i < VhcTypesNum ) && ( VhcTypes[i] < nVId ); i++ ) ; //Tmp\r
+  if (( i < VhcTypesNum ) && ( VhcTypes[i] == nVId ) ) //Tmp\r
+  {\r
+    mVehicleId = nVehicleId;\r
+    mOwnerCharId = nVehicleId / 100; // tmp\r
+    mHealth = 200; // Tmp\r
+    mVehicleType = nVId; // tmp\r
+    mStatus = 0;\r
+    return true;\r
+  }\r
+  else\r
+    return false;\r
+}\r
+\r
+bool PVehicleInformation::Save()\r
+{\r
+  // Shall we Destroy() when mStatus == 2, or keep destroyed vhc in DB ?\r
+  return true;\r
+}\r
+\r
+bool PVehicleInformation::Destroy()\r
+{\r
+  if ( mStatus == 2 )\r
+  {\r
+    // Delete from DB\r
+    mVehicleId = 0;\r
+    return true;\r
+  }\r
+  else\r
+    return false;\r
+}\r
+\r
+bool PVehicleInformation::SetStatus( u8 nStatus )\r
+{\r
+  if (( mStatus != 2 ) && ( nStatus <= 2 ) )\r
+  {\r
+    mStatus = nStatus;\r
+    return true;\r
+  }\r
+  else\r
+    return false;\r
+}\r
+\r
+// PSpawnedVehicule\r
+const u8 PSpawnedVehicle::mSeatsFlags[] = { 1, 2, 4, 8, 16, 32, 64, 128 };\r
+\r
+PSpawnedVehicle::PSpawnedVehicle( u32 nLocalId, PVehicleInformation const* nVhcInfo, u32 nLocation, PVhcCoordinates const* nVhcPos )\r
+{\r
+  mLocalId = nLocalId;\r
+  mInfo = *nVhcInfo;\r
+  mLocation = nLocation;\r
+  mCoords = *nVhcPos;\r
+  for ( int i = 0; i < 8; ++i )\r
+    mSeatUserId[i] = 0;\r
+\r
+  mVhcDef = GameDefs->Vhcs()->GetDef( mInfo.mVehicleType );\r
+  if ( ! mVhcDef )\r
+  {\r
+    Console->Print( RED, BLACK, "[ERROR] Invalid vhc type %d for vhc id %d (local %d) owner char id %d", mInfo.mVehicleType, mInfo.mVehicleId, mLocalId, mInfo.mOwnerCharId );\r
+    Console->Print( RED, BLACK, "[NOTICE] Setting vhc type to %d for vhc id %d (local %d) owner char id %d", VhcTypes[0], mInfo.mVehicleId, mLocalId, mInfo.mOwnerCharId );\r
+    mInfo.mVehicleType = VhcTypes[0];\r
+    mVhcDef = GameDefs->Vhcs()->GetDef( mInfo.mVehicleType );\r
+  }\r
+\r
+  mNbFreeSeats = GetNumSeats();\r
+  if ( mNbFreeSeats > 8 )\r
+  {\r
+    Console->Print( RED, BLACK, "[ERROR] Vhc type %d has more than 8 seats (%d)", mInfo.mVehicleType, mNbFreeSeats );\r
+    mNbFreeSeats = 8;\r
+  }\r
+  for ( int i = 0; i < mNbFreeSeats; ++i )\r
+    mFreeSeatsFlags |= mSeatsFlags[i];\r
+\r
+  //Temp\r
+  for ( int i = 0; i < 4; ++i )\r
+  {\r
+    minmax[i][0] = 0xffff;\r
+    minmax[i][1] = 0;\r
+  }\r
+}\r
+\r
+void PSpawnedVehicle::SetLocation( u32 nLocation )\r
+{\r
+  mLocation = nLocation;\r
+}\r
+\r
+void PSpawnedVehicle::SetPosition( PVhcCoordinates const* nVhcPos )\r
+{\r
+  mCoords = *nVhcPos;\r
+  // Temp\r
+  if(gDevDebug)\r
+  {\r
+    if ( mCoords.mUD < minmax[0][0] ) minmax[0][0] = mCoords.mUD;\r
+    if ( mCoords.mUD > minmax[0][1] ) minmax[0][1] = mCoords.mUD;\r
+    if ( mCoords.mLR < minmax[1][0] ) minmax[1][0] = mCoords.mLR;\r
+    if ( mCoords.mLR > minmax[1][1] ) minmax[1][1] = mCoords.mLR;\r
+    if ( mCoords.mRoll < minmax[2][0] ) minmax[2][0] = mCoords.mRoll;\r
+    if ( mCoords.mRoll > minmax[2][1] ) minmax[2][1] = mCoords.mRoll;\r
+    Console->Print( "%s Min/Max: UD:%d/%d(%d) LR:%d/%d(%d) Roll:%d/%d(%d)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), minmax[0][0], minmax[0][1], mCoords.mUD, minmax[1][0], minmax[1][1], mCoords.mLR, minmax[2][0], minmax[2][1], mCoords.mRoll );\r
+  }\r
+}\r
+\r
+int PSpawnedVehicle::GetNumSeats() const\r
+{\r
+  return mVhcDef->GetNumSeats();\r
+}\r
+\r
+bool PSpawnedVehicle::SetSeatUser( u8 nSeatId, u32 nCharId )\r
+{\r
+  if ( nSeatId < mVhcDef->GetNumSeats() )\r
+  {\r
+    if ( ! mSeatUserId[nSeatId] )\r
+    {\r
+      mSeatUserId[nSeatId] = nCharId;\r
+      mFreeSeatsFlags &= ~mSeatsFlags[nSeatId];\r
+      --mNbFreeSeats;\r
+      return true;\r
+    }\r
+  }\r
+  return false;\r
+}\r
+\r
+bool PSpawnedVehicle::UnsetSeatUser( u8 nSeatId, u32 nCharId )\r
+{\r
+  if ( nSeatId < mVhcDef->GetNumSeats() )\r
+  {\r
+    if ( mSeatUserId[nSeatId] == nCharId )\r
+    {\r
+      mSeatUserId[nSeatId] = 0;\r
+      mFreeSeatsFlags |= mSeatsFlags[nSeatId];\r
+      ++mNbFreeSeats;\r
+      return true;\r
+    }\r
+  }\r
+  return false;\r
+}\r
+\r
+bool PSpawnedVehicle::IsCharInside( u32 nCharId ) const\r
+{\r
+  for ( int i = 0; i < mVhcDef->GetNumSeats(); ++i )\r
+  {\r
+    if ( mSeatUserId[i] == nCharId )\r
+      return true;\r
+  }\r
+  return false;\r
+}\r
+\r
+u8 PSpawnedVehicle::GetFirstFreeSeat() const\r
+{\r
+  for ( int i = 0; i < mVhcDef->GetNumSeats(); ++i )\r
+  {\r
+    if ( ! mSeatUserId[i] )\r
+      return i;\r
+  }\r
+\r
+  return 255;\r
+}\r
+/*u8 PSpawnedVehicle::GetFreeSeats() const\r
+{\r
+  u8 bitField = 0;\r
+\r
+  for(int i = mVhcDef->GetNumSeats() - 1; i >= 0 ; --i)\r
+  {\r
+    bitField <<= 1;\r
+    if ( ! mSeatUserId[i] )\r
+      bitField |= 1;\r
+  }\r
+\r
+  return bitField;\r
+}*/\r
+\r
+// PVehicles\r
+PVehicles::PVehicles()\r
+{\r
+\r
+}\r
+\r
+PVehicles::~PVehicles()\r
+{\r
+\r
+}\r
+\r
+bool PVehicles::RegisterSpawnedVehicle( PSpawnedVehicle* nSpawnedVehicle )\r
+{\r
+  std::pair<PSpawnedVhcMap::iterator, bool> Result = mSpawnedVehicles.insert( std::make_pair( nSpawnedVehicle->GetVehicleId(), nSpawnedVehicle ) );\r
+  return Result.second;\r
+}\r
+\r
+bool PVehicles::UnregisterSpawnedVehicle( u32 nVehicleId )\r
+{\r
+  PSpawnedVhcMap::iterator it = mSpawnedVehicles.find( nVehicleId );\r
+  if ( it != mSpawnedVehicles.end() )\r
+  {\r
+    mSpawnedVehicles.erase( it );\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    return false;\r
+  }\r
+}\r
+\r
+//u32 PVehicles::CreateVehicle(u32 nOwnerChar, u8 mVehicleType) {}\r
+//bool PVehicles::RegisterVehicleOwner(u32 nVehicleId, u32 nOwnerChar) {}\r
+//bool PVehicles::DestroyVehicle(u32 nVehicleId) {}\r
+\r
+bool PVehicles::IsValidVehicle( u32 nVehicleId, bool nCheckOwner, u32 nOwnerId ) const\r
+{\r
+  // Look in DB\r
+  // tmp\r
+  u32 tVehicleId = nVehicleId; tVehicleId = tVehicleId;\r
+  bool tCheckOwner = nCheckOwner; tCheckOwner = tCheckOwner;\r
+  u32 tOwnerId = nOwnerId; tOwnerId = tOwnerId;\r
+  return true; // tmp\r
+}\r
+\r
+PSpawnedVehicle* PVehicles::GetSpawnedVehicle( u32 nVehicleId ) const\r
+{\r
+  PSpawnedVhcMap::const_iterator it = mSpawnedVehicles.find( nVehicleId );\r
+  if ( it != mSpawnedVehicles.end() )\r
+  {\r
+    return ( it->second );\r
+  }\r
+  else\r
+  {\r
+    return NULL;\r
+  }\r
+}\r
+\r
+bool PVehicles::GetVehicleInfo( u32 nVehicleId, PVehicleInformation* nInfo ) const\r
+{\r
+  PSpawnedVehicle* tVhc = GetSpawnedVehicle( nVehicleId );\r
+  if ( tVhc )\r
+  {\r
+    *nInfo = tVhc->GetInformation();\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    return nInfo->Load( nVehicleId );\r
+  }\r
+}\r
+\r
+PVhcInfoList* PVehicles::GetCharVehicles( u32 nCharId, u16 nMaxCount, u16 nStartIndex )\r
+{\r
+  PVhcInfoList* Entries = new PVhcInfoList();\r
+  PVehicleInformation* InfoEntry;\r
+  // Tmp implementation\r
+  u16 LimitIndex = nStartIndex + nMaxCount;\r
+  if ( !nMaxCount || ( VhcTypesNum < LimitIndex ) )\r
+  {\r
+    LimitIndex = VhcTypesNum;\r
+  }\r
+\r
+  for ( u16 i = nStartIndex; ( i < LimitIndex ) ; ++i )\r
+  {\r
+    InfoEntry = new PVehicleInformation();\r
+    if ( GetVehicleInfo( nCharId * 100 + VhcTypes[i], InfoEntry ) )\r
+    {\r
+      Entries->push( InfoEntry );\r
+    }\r
+    else\r
+    {\r
+      delete InfoEntry;\r
+    }\r
+  }\r
+\r
+  return Entries;\r
+}\r
+\r
+PSpawnedVehicle* PVehicles::SpawnVehicle( u32 nVehicleId, u32 nLocation, PVhcCoordinates const* nVhcPos )\r
+{\r
+  PSpawnedVehicle* newVhc = NULL;\r
+  PWorld* cWorld;\r
+  PVehicleInformation nVhcInfo;\r
+\r
+  if (( nLocation != PWorlds::mNcSubwayWorldId ) && IsValidVehicle( nVehicleId ) && !IsSpawned( nVehicleId ) )\r
+  {\r
+    cWorld = Worlds->LeaseWorld( nLocation );\r
+\r
+    if ( cWorld && GetVehicleInfo( nVehicleId, &nVhcInfo ) )\r
+    {\r
+      newVhc = cWorld->GetSpawnedVehicules()->SpawnVehicle( &nVhcInfo, nVhcPos );\r
+      if ( newVhc )\r
+      {\r
+        if ( !RegisterSpawnedVehicle( newVhc ) )\r
+        {\r
+          Console->Print( RED, BLACK, "[Error] PVehicles::SpawnVehicle : Could not register spawned vhc" );\r
+        }\r
+        if( gDevDebug )\r
+          Console->Print( "%d Spawned vhc %d (local 0x%04x) type %d (requested: %d)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), newVhc->GetVehicleId(), newVhc->GetLocalId(), newVhc->GetInformation().GetVehicleType(), nVhcInfo.GetVehicleType() );\r
+      }\r
+      else\r
+        Console->Print( RED, BLACK, "[Error] PVehicles::SpawnVehicle : Could not create vhc" );\r
+    }\r
+\r
+    Worlds->ReleaseWorld( nLocation );\r
+  }\r
+\r
+  return newVhc;\r
+}\r
+\r
+bool PVehicles::UnspawnVehicle( u32 nVehicleId )\r
+{\r
+  PWorld* cWorld;\r
+  bool Result = false;\r
+\r
+  PSpawnedVhcMap::iterator it = mSpawnedVehicles.find( nVehicleId );\r
+  if ( it != mSpawnedVehicles.end() )\r
+  {\r
+    cWorld = Worlds->LeaseWorld( it->second->GetLocation() );\r
+\r
+    if ( cWorld )\r
+    {\r
+      if ( !it->second->Save() )\r
+      {\r
+        Console->Print( RED, BLACK, "[Error] PVehicles::UnspawnVehicle : Could not save vhc %d", nVehicleId );\r
+      }\r
+\r
+      Result = cWorld->GetSpawnedVehicules()->UnspawnVehicle( it->second->GetLocalId() );\r
+      if ( Result )\r
+      {\r
+        if ( !UnregisterSpawnedVehicle( nVehicleId ) )\r
+        {\r
+          Console->Print( RED, BLACK, "[Error] PVehicles::UnspawnVehicle : Could not unregister vhc %d", nVehicleId );\r
+        }\r
+      }\r
+    }\r
+\r
+    Worlds->ReleaseWorld( it->second->GetLocation() );\r
+  }\r
+\r
+  return Result;\r
+}\r
+\r
+//PSpawnedVehicles\r
+PSpawnedVehicles::PSpawnedVehicles()\r
+{\r
+  mNextFreeHint = 0;\r
+  mLocation = 0;\r
+}\r
+\r
+PSpawnedVehicles::~PSpawnedVehicles()\r
+{\r
+\r
+}\r
+\r
+PSpawnedVehicle* PSpawnedVehicles::SpawnVehicle( PVehicleInformation const* nVhcInfo, PVhcCoordinates const* nVhcPos )\r
+{\r
+  PSpawnedVehicle* newVhc = NULL;\r
+  u32 nSize;\r
+\r
+  if ( nVhcInfo->GetStatus() == 0 ) // only if in garage\r
+  {\r
+    nSize = mSpawnedVehicles.size();\r
+    while (( mNextFreeHint < nSize ) && mSpawnedVehicles[mNextFreeHint] )\r
+    {\r
+      ++mNextFreeHint;\r
+    }\r
+    if ( mNextFreeHint > nSize )\r
+    {\r
+      mNextFreeHint = nSize;\r
+    }\r
+    if ( mNextFreeHint == nSize )\r
+    {\r
+      mSpawnedVehicles.push_back( NULL );\r
+    }\r
+\r
+    if ( mNextFreeHint < mMaxLocalVhc )\r
+    {\r
+      newVhc = new PSpawnedVehicle( mVhcBaseLocalId - mNextFreeHint, nVhcInfo, mLocation, nVhcPos );\r
+      mSpawnedVehicles[mNextFreeHint++] = newVhc;\r
+      newVhc->SetStatus( 1 );\r
+    }\r
+  }\r
+\r
+  return newVhc;\r
+}\r
+\r
+PSpawnedVehicle* PSpawnedVehicles::GetVehicle( u32 nLocalId )\r
+{\r
+  if (( nLocalId <= mVhcBaseLocalId ) && ( nLocalId > ( mVhcBaseLocalId - mSpawnedVehicles.size() ) ) )\r
+  {\r
+    return mSpawnedVehicles[mVhcBaseLocalId - nLocalId];\r
+  }\r
+  else\r
+  {\r
+    return NULL;\r
+  }\r
+}\r
+\r
+PSpawnedVehicle* PSpawnedVehicles::GetVehicleByGlobalId( u32 nVehicleId ) const\r
+{\r
+  for ( PSpawnedVhcVector::const_iterator it = mSpawnedVehicles.begin(); it != mSpawnedVehicles.end(); it++ )\r
+  {\r
+    if (( *it )->GetVehicleId() == nVehicleId )\r
+    {\r
+      return ( *it );\r
+    }\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+bool PSpawnedVehicles::UnspawnVehicle( u32 nLocalId )\r
+{\r
+  u16 Index;\r
+  PSpawnedVehicle* tVhc;\r
+\r
+  if (( nLocalId <= mVhcBaseLocalId ) && ( nLocalId > ( mVhcBaseLocalId - mSpawnedVehicles.size() ) ) )\r
+  {\r
+    Index = mVhcBaseLocalId - nLocalId;\r
+    tVhc = mSpawnedVehicles[Index];\r
+    if ( tVhc )\r
+    {\r
+      if ( tVhc->GetInformation().GetStatus() != 2 )\r
+      {\r
+        tVhc->SetStatus( 0 );\r
+      }\r
+      delete tVhc;\r
+      mSpawnedVehicles[Index] = NULL;\r
+      if ( mNextFreeHint > Index )\r
+      {\r
+        mNextFreeHint = Index;\r
+      }\r
+      return true;\r
+    }\r
+  }\r
+\r
+  return false;\r
+}\r
+\r
+PSpawnedVhcList* PSpawnedVehicles::GetSpawnedVehicles() const\r
+{\r
+  PSpawnedVhcList* Entries = new PSpawnedVhcList();\r
+\r
+  for ( PSpawnedVhcVector::const_iterator i = mSpawnedVehicles.begin(); i !=  mSpawnedVehicles.end(); ++i )\r
+  {\r
+    if ( *i )\r
+    {\r
+      Entries->push( *i );\r
+    }\r
+  }\r
+\r
+  return Entries;\r
+}\r
diff --git a/server/src/game/vhcaccessrequest.cpp b/server/src/game/vhcaccessrequest.cpp
new file mode 100755 (executable)
index 0000000..59a9f0a
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+  vhcaccessrequest.cpp - classe for pendinf vhc access requests
+
+
+ CREATION: 14 Apr 2009 Hammag
+
+*/
+
+#include "main.h"
+#include "vhcaccessrequest.h"
+
+PVhcAccessRequest::PVhcAccessRequest()
+{
+  mVhcGlobalId = mCharId = 0;
+  mStatus = 0;
+  mTimestamp = 0;
+}
+
+PVhcAccessRequest::PVhcAccessRequest( u32 nRequesterCharId, u32 nVhcGlobalId )
+{
+  mCharId = nRequesterCharId;
+  mVhcGlobalId = nVhcGlobalId;
+  mStatus = 0;
+  mTimestamp = std::time( NULL );
+}
+
+/*
+typedef std::map<u32, PVhcAccessRequest> PVhcAccessRequestMap;
+
+PVhcAccessRequestMap mActiveRequests;
+u32 mNextRequestId;
+
+std::time_t mResponseWaitTime; // How long do we wait for owner answer
+std::time_t mCheckWaitTime; // How long do we wait for user access check (0: remaining time from mResponseWaitTime)
+std::time_t mReuseWaitTime; // How long do we allow user to re-use the autorization after first check
+*/
+void PVhcAccessRequestList::DropTimedOut()
+{
+  std::time_t now = std::time( NULL );
+  std::time_t timeout;
+
+  for ( PVhcAccessRequestMap::iterator it = mActiveRequests.begin(); it != mActiveRequests.end(); it++ )
+  {
+    switch ( it->second.mStatus )
+    {
+      case 0:
+        timeout = mResponseWaitTime;
+        break;
+      case 1:
+        timeout = ( mCheckWaitTime ? mCheckWaitTime : mResponseWaitTime );
+        break;
+      case 2:
+        timeout = mReuseWaitTime;
+        break;
+      default:
+        timeout = 0;
+        break;
+    }
+    if ( it->second.mTimestamp > ( now + timeout ) )
+    {
+      mActiveRequests.erase( it );
+    }
+  }
+}
+
+PVhcAccessRequestList::PVhcAccessRequestList()
+{
+  mNextRequestId = 1;
+  SetParameters( 10, 20, 0 );
+}
+
+PVhcAccessRequestList::~PVhcAccessRequestList()
+{
+}
+
+void PVhcAccessRequestList::SetParameters( std::time_t nResponseWaitTime, std::time_t nCheckWaitTime, std::time_t nReuseWaitTime )
+{
+  mResponseWaitTime = nResponseWaitTime;
+  mCheckWaitTime = nCheckWaitTime;
+  mReuseWaitTime = nReuseWaitTime;
+}
+
+u32 PVhcAccessRequestList::Add( u32 nRequesterCharId, u32 nVhcGlobalId )
+{
+  DropTimedOut();
+  // We could check for existing entries before
+  PVhcAccessRequest newReq( nRequesterCharId, nVhcGlobalId );
+  u32 newId = mNextRequestId;
+  mActiveRequests[newId] = newReq;
+
+  if ( ++mNextRequestId == 0 )
+    mNextRequestId = 1;
+
+  return ( newId );
+}
+
+bool PVhcAccessRequestList::GetInfo(u32 nRequestId, u32* oRequesterCharId, u32* oVehicleId) const
+{
+  PVhcAccessRequestMap::const_iterator it = mActiveRequests.find( nRequestId );
+  if ( it != mActiveRequests.end() )
+  {
+    *oRequesterCharId = it->second.mCharId;
+    *oVehicleId = it->second.mVhcGlobalId;
+    return true;
+  }
+  else
+    return false;
+}
+
+bool PVhcAccessRequestList::RegisterResponse( u32 nRequestId, bool nStatus )
+{
+  DropTimedOut();
+  PVhcAccessRequestMap::iterator it = mActiveRequests.find( nRequestId );
+  if ( it != mActiveRequests.end() )
+  {
+    if ( nStatus )
+    {
+      it->second.mStatus = 1;
+      if ( mCheckWaitTime )
+      {
+        it->second.mTimestamp = std::time( NULL );
+      }
+      return true;
+    }
+    else
+    {
+      mActiveRequests.erase( it );
+    }
+  }
+
+  return false;
+}
+
+bool PVhcAccessRequestList::Check( u32 nRequestId, u32 nRequesterCharId, u32 nVhcGlobalId )
+{
+  DropTimedOut();
+  PVhcAccessRequestMap::iterator it = mActiveRequests.find( nRequestId );
+  if ( it != mActiveRequests.end() )
+  {
+    if ( (!nRequesterCharId || (( it->second.mCharId == nRequesterCharId ) && ( it->second.mVhcGlobalId == nVhcGlobalId ))) && ( it->second.mStatus > 0 ) )
+    {
+      if ( mReuseWaitTime && ( it->second.mStatus == 1 ) )
+      {
+        it->second.mStatus = 2;
+        it->second.mTimestamp = std::time( NULL );
+      }
+      else
+      {
+        mActiveRequests.erase( it );
+      }
+
+      return true;
+    }
+  }
+  return false;
+}
diff --git a/server/src/game/worldactors.cpp b/server/src/game/worldactors.cpp
new file mode 100644 (file)
index 0000000..1ced2ec
--- /dev/null
@@ -0,0 +1,621 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+/*
+
+ worldactors.cpp - Management class for dynamic worldactors
+
+ CREATION: 02 Jan 2007 Namikon
+
+ MODIFIED:
+ REASON: -
+
+
+*/
+
+#include "main.h"
+#include "worldactors.h"
+#include "worlds.h"
+#include "msgbuilder.h"
+
+PWorldActors::PWorldActors()
+{
+    DoActorCheck();
+}
+
+PWorldActors::~PWorldActors()
+{
+}
+
+void PWorldActors::SpawnWA(u32 nWorld, u16 nActorID, u16 nFunctionID, u32 nWOID, u16 nPosX, u16 nPosY, u16 nPosZ, u8 nRotX, u8 nRotY, u8 nRotZ)
+{
+    PMessage* tmpMsg = MsgBuilder->BuildSpawnWorldObjectMsg(nActorID, nFunctionID, nWOID, nPosX, nPosY, nPosZ, nRotX, nRotY, nRotZ);
+    ClientManager->UDPBroadcast(tmpMsg, nWorld);
+}
+
+void PWorldActors::VanishWA(u32 nWorld, u32 nWAid)
+{    
+    PMessage* tmpMsg = MsgBuilder->BuildRemoveWorldObjectMsg(nWAid);
+    ClientManager->UDPBroadcast(tmpMsg, nWorld);
+}
+
+u32 PWorldActors::GetNextFreeWAID()
+{
+    if (gDevDebug) Console->Print("DEBUG: Getting next free worldactor ID...");
+    MYSQL_RES *result = NULL;
+    MYSQL_ROW row;
+    char query[100];
+
+    snprintf(query, 100, "SELECT * FROM `world_actors` ORDER BY `wa_actor_id` DESC LIMIT 1");
+    if (gDevDebug) Console->Print("DEBUG: Executing query %s", query);
+
+    result = MySQL->GameResQuery(query);
+    if(result == NULL)
+    {
+        Console->Print(RED, BLACK, "PWorldActors::GetNextFreeWAID could not get next free WorldActorID");
+        Console->Print("Query was:");
+        Console->Print("%s", query);
+        MySQL->ShowGameSQLError();
+        return 0;
+    }
+
+    row = mysql_fetch_row(result);
+    u32 newWAid;
+    if(mysql_num_rows(result) == 1)
+    {
+        newWAid = atoi(row[wa_actor_id]);
+        newWAid++;
+    }
+    else
+    {
+        newWAid = DYNACTORIDSTART;
+    }
+
+    if(newWAid < DYNACTORIDSTART)
+    {
+        newWAid = DYNACTORIDSTART;
+    }
+
+    MySQL->FreeGameSQLResult(result);
+    return newWAid;
+}
+
+void PWorldActors::InitWorld(PClient* nClient)
+{
+    DoActorCheck();
+    if (gDevDebug) Console->Print("DEBUG: Initializing WorldActors for client...");
+    u32 tZone = nClient->GetChar()->GetLocation();
+    MYSQL_RES *result = NULL;
+    MYSQL_ROW row;
+    char query[100];
+
+    snprintf(query, 100, "SELECT * FROM `world_actors` WHERE `wa_actor_map` = %d", tZone);
+    //if (gDevDebug) Console->Print("DEBUG: Executing query: %s", query);
+    result = MySQL->GameResQuery(query);
+    if(result == NULL)
+    {
+        Console->Print(RED, BLACK, "PWorldActors::InitWorld could not load WorldActor definition");
+        Console->Print("Query was:");
+        Console->Print("%s", query);
+        MySQL->ShowGameSQLError();
+        return;
+    }
+    if(mysql_num_rows(result) == 0)
+    {
+        if (gDevDebug) Console->Print("DEBUG: No dynamic actors found, skipping");
+        MySQL->FreeGameSQLResult(result);
+        return;
+    }
+    if (gDevDebug) Console->Print("DEBUG: We have dynamic actors, building message...");
+    PMessage* tmpActorSpawn = new PMessage(256);
+    *tmpActorSpawn << (u8)0x13;
+    *tmpActorSpawn << (u16)0x0000; // Placeholder
+    *tmpActorSpawn << (u16)0x0000; // Placeholder
+
+    u16 tFuncID = 0;
+    u16 tOpt1 = 0;
+    u32 tActorID = 0;
+
+    bool tActorOk = false;
+
+    while((row = mysql_fetch_row(result)))
+    {
+        tFuncID = (u16)atoi(row[wa_actor_type]);
+        tOpt1 = (u16)atoi(row[wa_option1]);
+        tActorID = (u32)atoi(row[wa_actor_id]);
+        // First make sure we have an VALID worldactor here
+        tActorOk = false;
+        if(IsValidWAFunction(tFuncID) == true)
+        {
+            if(RequiresLinkedObject(tFuncID == true))
+            {
+                if(IsValidLinkedObject(nClient, tOpt1, tFuncID) == true)
+                {
+                    tActorOk = true;
+                }
+            }
+            else
+            {
+                tActorOk = true;
+            }
+        }
+
+        if(tActorOk == true)
+        {
+            // Build multiframe message
+            nClient->IncreaseUDP_ID();
+            *tmpActorSpawn << (u8)0x16;
+            *tmpActorSpawn << (u8)0x03;
+            *tmpActorSpawn << (u16)nClient->GetUDP_ID();
+            *tmpActorSpawn << (u8)0x1b;
+            *tmpActorSpawn << tActorID;
+            *tmpActorSpawn << (u8)0x19;
+            *tmpActorSpawn << (u16)atoi(row[wa_posY]);
+            *tmpActorSpawn << (u16)atoi(row[wa_posZ]);
+            *tmpActorSpawn << (u16)atoi(row[wa_posX]);
+            *tmpActorSpawn << (u8)atoi(row[wa_rotY]);
+            *tmpActorSpawn << (u8)atoi(row[wa_rotZ]);
+            *tmpActorSpawn << (u8)atoi(row[wa_rotX]);
+            *tmpActorSpawn << (u16)atoi(row[wa_actor_model]);
+            *tmpActorSpawn << tFuncID;
+            if((tmpActorSpawn->GetSize() + 23) >= (tmpActorSpawn->GetMaxSize() - tmpActorSpawn->GetSize()))
+            {
+                //if (gDevDebug) Console->Print("DEBUG: Message is full, sending part-msg");
+                tmpActorSpawn->U16Data(0x01) = nClient->GetUDP_ID();  // Set final UDP ID
+                tmpActorSpawn->U16Data(0x03) = nClient->GetSessionID();  // Set final SessionID
+                nClient->SendUDPMessage(tmpActorSpawn);
+                tmpActorSpawn = NULL;
+
+                // ReInit message
+                tmpActorSpawn = new PMessage(256);
+                *tmpActorSpawn << (u8)0x13;
+                *tmpActorSpawn << (u16)0x0000; // Placeholder
+                *tmpActorSpawn << (u16)0x0000; // Placeholder
+                //if (gDevDebug) Console->Print("DEBUG: Done. Starting over!");
+            }
+        }
+        else
+        {
+            Console->Print("%s Dynamic worldactor %d is invalid, skipping", Console->ColorText(RED, BLACK, "[Warning]", tActorID));
+        }
+    }
+    tmpActorSpawn->U16Data(0x01) = nClient->GetUDP_ID();  // Set final UDP ID
+    tmpActorSpawn->U16Data(0x03) = nClient->GetSessionID();  // Set final SessionID
+
+    if(tmpActorSpawn->GetSize() > 5)
+        nClient->SendUDPMessage(tmpActorSpawn);
+    else
+    {
+        delete tmpActorSpawn;
+    }
+    MySQL->FreeGameSQLResult(result);
+}
+
+u32 PWorldActors::AddWorldActor(PClient* nClient, u16 nActorID, u16 nFuncID, u16 nOpt1, u16 nOpt2, u16 nOpt3)
+{
+    PChar *tChar = nClient->GetChar();
+    u16 tPosX = tChar->Coords.mX + 768;
+    u16 tPosY = tChar->Coords.mY + 768;
+    u16 tPosZ = tChar->Coords.mZ + 768;
+    u16 tLoc = tChar->GetLocation();
+
+    //if (gDevDebug) Console->Print("DEBUG: Adding worldactor %d function %d to world %d", nActorID, nFuncID, tLoc);
+    return AddWorldActor(tLoc, nActorID, nFuncID, tPosX, tPosY, tPosZ, (u8)194, (u8)128, (u8)128, nOpt1, nOpt2, nOpt3);
+}
+
+u32 PWorldActors::AddWorldActor(u32 nWorldID, u16 nActorID, u16 nFuncID, u16 nPosX, u16 nPosY, u16 nPosZ, u8 nRotX, u8 nRotY, u8 nRotZ, u16 nOpt1, u16 nOpt2, u16 nOpt3)
+{
+    if (gDevDebug) Console->Print("DEBUG: Adding new worldactor: ActorModel: %d, Function: %d, Option1: %d", nActorID, nFuncID, nOpt1);
+    u32 tNextWAID = GetNextFreeWAID(); // Grab next free WorldActorID
+    //if (gDevDebug) Console->Print("DEBUG: Next ID will be: %d", tNextWAID);
+
+    char query[512];
+    snprintf(query, 512, "INSERT INTO `world_actors`(wa_actor_id,wa_actor_map,wa_actor_model,wa_actor_type,wa_posX,wa_posY,wa_posZ,wa_rotX,wa_rotY,wa_rotZ,wa_option1,wa_option2,wa_option3)VALUES('%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d')",tNextWAID, nWorldID, nActorID, nFuncID, nPosX, nPosY, nPosZ, nRotX, nRotY, nRotZ, nOpt1, nOpt2, nOpt3);
+    //if (gDevDebug) Console->Print("DEBUG: Executing SQL query %s", query);
+    if ( MySQL->GameQuery(query) )
+    {
+        Console->Print(RED, BLACK, "WorldActors::AddWorldActor could not add worldactor to database");
+        Console->Print("Query was:");
+        Console->Print("%s", query);
+        MySQL->ShowGameSQLError();
+        return 0;
+    }
+    //if (gDevDebug) Console->Print("DEBUG: Successfully added WorldActor to Database");
+
+    // Now spawn the actor right away!
+    SpawnWA(nWorldID, nActorID, nFuncID, tNextWAID, nPosX, nPosY, nPosZ, nRotX, nRotY, nRotX);
+
+    return tNextWAID;
+}
+
+void PWorldActors::DelWorldActor(PClient* nClient, u32 nWAid)
+{
+    char query[100];
+    u16 tLoc = nClient->GetChar()->GetLocation();
+    if (gDevDebug) Console->Print("DEBUG: Removing worldactor %d from world %d", nWAid, tLoc);
+
+    snprintf(query, 100, "DELETE FROM `world_actors` WHERE `wa_actor_map` = %d AND `wa_actor_id` = %d", tLoc, nWAid);
+    //if (gDevDebug) Console->Print("DEBUG: Executing query %s", query);
+    if(MySQL->GameQuery(query))
+    {
+        Console->Print(RED, BLACK, "PWorldActors::DelWorldActor could not delete WorldActor");
+        Console->Print("Query was:");
+        Console->Print("%s", query);
+        MySQL->ShowGameSQLError();
+        return;
+    }
+    VanishWA(tLoc, nWAid);
+}
+
+void PWorldActors::GetWAoption(u32 nWAid, u16 nWorld, u16 &nValue1, u16 &nValue2, u16 &nValue3)
+{
+    MYSQL_RES *result = NULL;
+    MYSQL_ROW row;
+    char query[100];
+
+    nValue1 = 0;
+    nValue2 = 0;
+    nValue3 = 0;
+    snprintf(query, 100, "SELECT * FROM `world_actors` WHERE `wa_actor_map` = %d AND `wa_actor_id` = %d", nWorld, nWAid);
+
+    result = MySQL->GameResQuery(query);
+    if(result == NULL)
+    {
+        Console->Print(RED, BLACK, "PWorldActors::GetWAoption could not get WorldActor options");
+        Console->Print("Query was:");
+        Console->Print("%s", query);
+        MySQL->ShowGameSQLError();
+        return;
+    }
+    if(mysql_num_rows(result) == 0)
+    {
+        MySQL->FreeGameSQLResult(result);
+        return;
+    }
+
+    row = mysql_fetch_row(result);
+    nValue1 = atoi(row[wa_option1]);
+    nValue2 = atoi(row[wa_option2]);
+    nValue3 = atoi(row[wa_option3]);
+
+    MySQL->FreeGameSQLResult(result);
+}
+
+int PWorldActors::GetWASQLID(u32 nWAid, u32 nWorld)
+{
+    MYSQL_RES *result = NULL;
+    MYSQL_ROW row;
+    char query[100];
+
+    snprintf(query, 100, "SELECT * FROM `world_actors` WHERE `wa_actor_map` = %d AND `wa_actor_id` = %d", nWorld, nWAid);
+
+    result = MySQL->GameResQuery(query);
+    if(result == NULL)
+    {
+        Console->Print(RED, BLACK, "PWorldActors::GetWASQLID could not get WorldActor SQL ID");
+        Console->Print("Query was:");
+        Console->Print("%s", query);
+        MySQL->ShowGameSQLError();
+        return -1;
+    }
+    if(mysql_num_rows(result) == 0)
+    {
+        MySQL->FreeGameSQLResult(result);
+        return 0;
+    }
+
+    row = mysql_fetch_row(result);
+    int tWAid = atoi(row[wa_id]);
+    MySQL->FreeGameSQLResult(result);
+
+    return tWAid;
+}
+
+bool PWorldActors::IsDynamicActor(u32 nWAid)
+{
+    MYSQL_RES *result = NULL;
+    char query[100];
+
+    snprintf(query, 100, "SELECT * FROM `world_actors` WHERE `wa_actor_id` = %d", nWAid);
+
+    result = MySQL->GameResQuery(query);
+    if(result == NULL)
+    {
+        Console->Print(RED, BLACK, "PWorldActors::IsDynamicActor could not check if worldactor is dynamic");
+        Console->Print("Query was:");
+        Console->Print("%s", query);
+        MySQL->ShowGameSQLError();
+        return false;
+    }
+    if(mysql_num_rows(result) == 0)
+    {
+        MySQL->FreeGameSQLResult(result);
+        return false;
+    }
+    else if(mysql_num_rows(result) == 1)
+    {
+        MySQL->FreeGameSQLResult(result);
+        return true;
+    }
+    else if(mysql_num_rows(result) > 1)
+    {
+        MySQL->FreeGameSQLResult(result);
+        Console->Print("%s Duplicate entry for WorldActorID %d found", Console->ColorText(YELLOW, BLACK, "[Notice]"), nWAid);
+        return true;
+    }
+    MySQL->FreeGameSQLResult(result);
+    return false;
+}
+/* Not needed. Better re-spawn the actor
+bool PWorldActors::EditWorldActor(u32 nWorldID, int nOption1, int nOption2, int nOption3)
+{
+    if(IsDynamicActor(nWorldID) == false) // Make sure we really have this actor in DB
+        return false;
+
+    std::string query;
+    query = "UPDATE `world_actors` SET wa_option1 = ";
+    if(nOption1 > -1)
+        query += Ssprintf("%d,", nOption1);
+    else
+        query += "wa_option1,";
+
+    query += " wa_option2 = ";
+    if(nOption2 > -1)
+        query += Ssprintf("%d,", nOption2);
+    else
+        query += "wa_option1,";
+
+    query += " wa_option3 = ";
+    if(nOption3 > -1)
+        query += Ssprintf("%d", nOption3);
+    else
+        query += "wa_option1";
+
+    query += "WHERE wa_actor_id = ";
+    query += Ssprintf("%d", nWorldID);
+
+    if(MySQL->GameQuery(query.c_str()))
+    {
+        Console->Print(RED, BLACK, "PWorldActors::EditWorldActor could not update recordset for worldactor id %d", nWorldID);
+        Console->Print("Query was:");
+        Console->Print("%s", query.c_str());
+        MySQL->ShowGameSQLError();
+        return false;
+    }
+    return true;
+}
+*/
+int PWorldActors::GetWorldActorFunctionID(u32 nWAid)
+{
+    MYSQL_RES *result = NULL;
+    MYSQL_ROW row;
+    char query[100];
+
+    snprintf(query, 100, "SELECT * FROM `world_actors` WHERE `wa_actor_id` = %d", nWAid);
+
+    result = MySQL->GameResQuery(query);
+    if(result == NULL)
+    {
+        Console->Print(RED, BLACK, "PWorldActors::GetWorldActorFunctionID could not get WorldActor Function ID");
+        Console->Print("Query was:");
+        Console->Print("%s", query);
+        MySQL->ShowGameSQLError();
+        return -1;
+    }
+    if(mysql_num_rows(result) == 0)
+    {
+        MySQL->FreeGameSQLResult(result);
+        return 0;
+    }
+
+    row = mysql_fetch_row(result);
+    int tFuncID = atoi(row[wa_actor_type]);
+    MySQL->FreeGameSQLResult(result);
+
+    return tFuncID;
+}
+
+void PWorldActors::GetFrontPos(u32 nWAID, u16* mX, u16* mY, u16* mZ)
+{
+    MYSQL_RES *result = NULL;
+    MYSQL_ROW row;
+    char query[100];
+
+    u16 tNewX = 0;
+    u16 tNewY = 0;
+    u16 tNewZ = 0;
+
+    snprintf(query, 100, "SELECT * FROM `world_actors` WHERE `wa_actor_id` = %d", nWAID);
+
+    result = MySQL->GameResQuery(query);
+    if(result == NULL)
+    {
+        Console->Print(RED, BLACK, "PWorldActors::GetFrontPos could not get X/Y/Z values for worldactor");
+        Console->Print("Query was:");
+        Console->Print("%s", query);
+        MySQL->ShowGameSQLError();
+        return;
+    }
+    if(mysql_num_rows(result) == 0)
+    {
+        MySQL->FreeGameSQLResult(result);
+        return;
+    }
+
+    row = mysql_fetch_row(result);
+    tNewX = (u16)atoi(row[wa_posX]);
+    tNewY = (u16)atoi(row[wa_posY]);
+    tNewZ = (u16)atoi(row[wa_posZ]);
+
+    if(tNewX > 0) *mX = tNewX - 768;
+    if(tNewY > 0) *mY = tNewY - 768;
+    if(tNewZ > 0) *mZ = tNewZ - 768;
+
+    MySQL->FreeGameSQLResult(result);
+
+    return;
+}
+
+int PWorldActors::GetLinkedObjectID(u32 nWAID)
+{
+    MYSQL_RES *result = NULL;
+    MYSQL_ROW row;
+    char query[100];
+
+    snprintf(query, 100, "SELECT * FROM `world_actors` WHERE `wa_actor_id` = %d", nWAID);
+
+    result = MySQL->GameResQuery(query);
+    if(result == NULL)
+    {
+        Console->Print(RED, BLACK, "PWorldActors::GetLinkedObjectID could not get Linked object ID");
+        Console->Print("Query was:");
+        Console->Print("%s", query);
+        MySQL->ShowGameSQLError();
+        return 0;
+    }
+    if(mysql_num_rows(result) == 0)
+    {
+        MySQL->FreeGameSQLResult(result);
+        return 0;
+    }
+
+    row = mysql_fetch_row(result);
+    int tLinkID = atoi(row[wa_option1]);
+    MySQL->FreeGameSQLResult(result);
+
+    return tLinkID;
+}
+
+bool PWorldActors::IsValidWAFunction(int nFunctionID)
+{
+    if(nFunctionID == 0) // Special case for "unuseable" objects. 0 means "just stay in the world and do nothing"
+        return true;
+
+    // Check if given WO function is a valid one
+    const PDefWorldModel* tFurnitureModel = GameDefs->WorldModels()->GetDef(nFunctionID);
+    if(tFurnitureModel == NULL)
+        return false;
+    else
+        return true;
+}
+
+bool PWorldActors::RequiresLinkedObject(int nFunctionID)
+{
+    // Some worldactors need linked objects.
+    if(nFunctionID == 6 || nFunctionID == 11 || nFunctionID == 12 || nFunctionID == 13 || nFunctionID == 18 || nFunctionID == 23)
+        return true;
+    else
+        return false;
+}
+
+bool PWorldActors::IsValidLinkedObject(PClient *nClient, u16 nOption1, int nFunctionID)
+{
+    /*
+
+    Attention is required for the following WorldActors:
+    6 - Genrep
+        "LinkedObjectID" must be a value called GROrder. For whatever this is...
+    11 - Apartment Access / Communicator IF
+        "LinkedObjectID" must link to an Door in that sector
+    12 - Standard button
+        "LinkedObjectID" must link to an Door in that sector
+    13 - Hackbutton
+        "LinkedObjectID" must link to an Door in that sector
+    23 - Money Buttons
+        "LinkedObjectID" must link to an Door in that sector
+
+    6   - Not possible yet.
+    11  - Needs door
+    12  - Needs door
+    13  - Needs door
+    18  - Needs target world and entry point
+    23  - Needs door
+    */
+    // Check if given linked ObjectID is a valid worldobject
+    switch (nFunctionID)
+    {
+        case 6:
+        {
+            return false;
+        }
+        case 11:
+        case 12:
+        case 13:
+        case 23:
+        {
+            PWorld* CurrentWorld = Worlds->GetWorld(nClient->GetChar()->GetLocation());
+            const PDoorTemplate* tmpDoor = CurrentWorld->GetDoor(nOption1);
+            if(tmpDoor)
+                return true;
+            break;
+        }
+        case 18:
+        {
+            if(Worlds->IsValidWorld(nOption1) == true)
+                return true;
+        }
+    }
+    return false;
+}
+
+void PWorldActors::DoActorCheck()
+{
+    MYSQL_RES *result = NULL;
+    MYSQL_ROW row;
+    char query[200];
+    char query2[100];
+
+    snprintf(query, 200, "SELECT COUNT(`wa_actor_id`),`wa_actor_id` FROM `world_actors` GROUP BY `wa_actor_id` HAVING COUNT(`wa_actor_id`)>1");
+
+    result = MySQL->GameResQuery(query);
+    if(result == NULL)
+    {
+        Console->Print(RED, BLACK, "PWorldActors::DoActorCheck unable to check for double actorIDs");
+        Console->Print("Query was:");
+        Console->Print("%s", query);
+        MySQL->ShowGameSQLError();
+        return;
+    }
+    if(mysql_num_rows(result) == 0)  // Fine, we dont have double IDs
+    {
+        MySQL->FreeGameSQLResult(result);
+        return;
+    }
+
+    int tCount = 0;
+    int tID = 0;
+    while((row = mysql_fetch_row(result)))
+    {
+        tCount = atoi(row[0]);
+        tID = atoi(row[1]);
+        Console->Print("%s found double worldactor ID! (ID: %d Count: %d) Now erasing...", Console->ColorText(YELLOW, BLACK, "[Notice]"), tID, tCount);
+        snprintf(query2, 100, "DELETE FROM `world_actors` WHERE `wa_actor_id` = %d", tID);
+        if(MySQL->GameQuery(query2))
+        {
+            Console->Print(RED, BLACK, "PWorldActors::DoActorCheck unable to delete double entry %d", tID);
+            Console->Print("Query was:");
+            Console->Print("%s", query2);
+            MySQL->ShowGameSQLError();
+        }
+    }
+    MySQL->FreeGameSQLResult(result);
+    return;
+}
diff --git a/server/src/game/worlddatatemplate.cpp b/server/src/game/worlddatatemplate.cpp
new file mode 100755 (executable)
index 0000000..65c2743
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+
+/*
+  worlddatatemplate.cpp - world data template (from worlds .dat files) class
+
+ MODIFIED: 04 Oct 2006 Hammag
+ REASON: - creation
+
+ MODIFIED: 21 Jun 2009 Namikon
+ REASON: - Added NPC Template stuff
+
+*/
+
+
+#include "main.h"
+
+#include "worlddatatemplate.h"
+#include "world_datparser.h"
+#include "furnituretemplate.h"
+#include "doortemplate.h"
+#include "npctemplate.h"
+
+PWorldDataTemplate::PWorldDataTemplate()
+{
+    mUseCount = 0;
+    for ( int i = 0; i < WORLDDATATEMPLATE_MAXPOSITEMS; ++i )
+    {
+        mPositionItems[i] = NULL;
+    }
+}
+
+PWorldDataTemplate::~PWorldDataTemplate()
+{
+    DatFileDataCleanup();
+}
+
+void PWorldDataTemplate::DatFileDataCleanup()
+{
+    for ( PFurnitureItemsMap::iterator i = mFurnitureItems.begin(); i != mFurnitureItems.end(); i++ )
+        delete i->second;
+    for ( PDoorsMap::iterator i = mDoors.begin(); i != mDoors.end(); i++ )
+        delete i->second;
+    for ( PNPCsMap::iterator i = mNPCs.begin(); i != mNPCs.end(); i++ )
+        delete i->second;
+}
+
+bool PWorldDataTemplate::LoadDatFile( const std::string& WorldTemplateName, const std::string& nFilename, const bool nTestAccesOnly )
+{
+    PWorldDatParser WDatLoader;
+    int LoadResult;
+
+    DatFileDataCleanup();
+    if ( gDevDebug ) Console->Print( "%s Loading %s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nFilename.c_str() );
+    LoadResult = WDatLoader.LoadDatFile( nFilename, this, true, nTestAccesOnly ) ; // We want to discard passive objects for now
+    switch ( LoadResult )
+    {
+    case 0:
+    {
+        mName = nFilename;
+        mBspName = WorldTemplateName;
+        if ( !nTestAccesOnly )
+        {
+            SetLinkedObjects(); // temp until better solution found from .dat & .bsp files
+        }
+        return true;
+    }
+
+    case -1:
+    {
+        if ( !nTestAccesOnly )
+            Console->Print( "%s Can't read file %s", Console->ColorText( RED, BLACK, "[ERROR]" ), nFilename.c_str() );
+        break;
+    }
+
+    case - 2:
+    {
+        Console->Print( "%s Bad data", Console->ColorText( RED, BLACK, "[ERROR]" ) );
+        break;
+    }
+
+    case - 3:
+    {
+        Console->Print( "%s Unexpected end of file", Console->ColorText( RED, BLACK, "[ERROR]" ) );
+        break;
+    }
+
+    default:
+        Console->Print( "%s Unknown error %d", Console->ColorText( RED, BLACK, "[ERROR]" ), LoadResult );
+    }
+    return false;
+}
+
+u32 PWorldDataTemplate::AddFurnitureItem( PFurnitureItemTemplate* nItem )
+{
+    if ( nItem )
+    {
+        if ( mFurnitureItems.insert( std::make_pair( nItem->GetID(), nItem ) ).second )
+        {
+            if ( gDevDebug ) Console->Print( "%s Furniture item %d added to world template", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nItem->GetID() );
+
+            if ( nItem->GetFunctionType() == 21 )
+            {
+                int v = nItem->GetFunctionValue();
+                if (( v >= 0 ) && ( v < WORLDDATATEMPLATE_MAXPOSITEMS ) )
+                {
+                    if ( mPositionItems[v] )
+                    {
+                        if (( v == WORLDDATATEMPLATE_MAXPOSITEMS - 2 ) && !mPositionItems[v+1] ) // We allow that only for Pos 9 in order not to mess with other pos
+                        {
+                            Console->Print( "%s Same position %d for two position items ID %d and %d. Last one will be put on next position.", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), v, mPositionItems[v]->GetID(), nItem->GetID() );
+                            ++v;
+                        }
+                        else
+                        {
+                            Console->Print( "%s Same position %d for two position items ID %d and %d. Only last one kept.", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), v, mPositionItems[v]->GetID(), nItem->GetID() );
+                        }
+                    }
+
+                    mPositionItems[v] = nItem;
+                    /*
+                    Console->Print("Position entity %d (id 0x%x) added to world template", v, nItem->GetID());
+                    f32 fpX, fpY, fpZ;
+                    u16 pX, pY, pZ;
+                    nItem->GetPos(&fpX, &fpY, &fpZ);
+                    pX = (u16) (fpX + 32000);
+                    pY = (u16) (fpY + 32000);
+                    pZ = (u16) (fpZ + 32000);
+                    Console->Print("Position Y=%f (0x%04x) Z=%f (0x%04x) X=%f (0x%04x)", fpY, pY, fpZ, pZ, fpX, pX);
+                    */
+                }
+                else
+                {
+                    Console->Print( "%s Invalid position %d for position item ID %d. Position ignored.", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), v, nItem->GetID() );
+                }
+            }
+            return nItem->GetID();
+        }
+        else
+        {
+            Console->Print( "%s Duplicate furniture item ID %d !!! Not added to world template", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), nItem->GetID() );
+        }
+    }
+    return 0;
+}
+
+const PFurnitureItemTemplate* PWorldDataTemplate::GetFurnitureItem( u32 ItemID )
+{
+    PFurnitureItemsMap::const_iterator it = mFurnitureItems.find( ItemID );
+    if ( it == mFurnitureItems.end() )
+        return NULL;
+    else
+        return it->second;
+}
+
+bool PWorldDataTemplate::getPositionItemPosition( u8 PosID, f32* pX, f32* pY, f32* pZ )
+{
+    if (( PosID < WORLDDATATEMPLATE_MAXPOSITEMS ) && mPositionItems[PosID] )
+    {
+        mPositionItems[PosID]->GetPos( pX, pY, pZ ) ;
+        return true;
+    }
+    return false;
+}
+
+u32 PWorldDataTemplate::AddDoor( PDoorTemplate* nDoor )
+{
+    if ( nDoor )
+    {
+        if ( mDoors.insert( std::make_pair( nDoor->GetID(), nDoor ) ).second )
+        {
+            if ( gDevDebug ) Console->Print( "%s Door %d added to world template", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nDoor->GetID() );
+            return nDoor->GetID();
+        }
+        else
+        {
+            Console->Print( "%s Duplicate Door ID %d !!! Not added to world template", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), nDoor->GetID() );
+        }
+    }
+    return 0;
+}
+
+const PDoorTemplate* PWorldDataTemplate::GetDoor( u32 DoorID )
+{
+    PDoorsMap::const_iterator it = mDoors.find( DoorID );
+    if ( it == mDoors.end() )
+        return NULL;
+    else
+        return it->second;
+}
+
+
+u32 PWorldDataTemplate::AddNPC( PNPCTemplate* nNPC )
+{
+    if ( nNPC )
+    {
+        if ( mNPCs.insert( std::make_pair( nNPC->GetNpcID(), nNPC ) ).second )
+        {
+            if ( gDevDebug ) Console->Print( "%s NPC %d added to world template", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nNPC->GetNpcID() );
+            return nNPC->GetNpcID();
+        }
+        else
+        {
+            Console->Print( "%s Duplicate NPC ID %d !!! Not added to world template", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), nNPC->GetNpcID() );
+        }
+    }
+    return 0;
+}
+
+const PNPCTemplate* PWorldDataTemplate::GetNPC( u32 NPCID )
+{
+    PNPCsMap::const_iterator it = mNPCs.find( NPCID );
+    if ( it == mNPCs.end() )
+        return NULL;
+    else
+        return it->second;
+}
+
+void PWorldDataTemplate::SetLinkedObjects()
+{
+    f32 xI, yI, zI;
+    f32 xD, yD, zD;
+    f32 D2, minD2;
+    u32 minObjID;
+    u16 fnctType;
+    u16 tGROrder = 0;
+
+    for ( PFurnitureItemsMap::iterator it = mFurnitureItems.begin(); it != mFurnitureItems.end(); it++ )
+    {
+        fnctType = it->second->GetFunctionType();
+        if (( fnctType == 11 ) || ( fnctType == 12 ) || ( fnctType == 13 ) || ( fnctType == 23 ) ) // if function is apt entry button, door access if, hack button or money button
+        {
+            it->second->GetPos( &xI, &yI, &zI );
+//Console->Print("Button pos: %0.0f %0.0f %0.0f", xI, yI, zI);
+            minD2 = 1e9;
+            minObjID = 0;
+            for ( PDoorsMap::iterator dit = mDoors.begin(); dit != mDoors.end(); dit++ )
+            {
+//Console->Print("%s Found door %d (%s) : %s triggered, %s", Console->ColorText(GREEN, BLACK, "[Debug]"), dit->first, dit->second->GetName().c_str(), (dit->second->IsTriggeredDoor()?"":"not"), (dit->second->IsDoubleDoor()?"double":"single") );
+                if ( dit->second->IsTriggeredDoor() )
+                {
+                    dit->second->GetPos( &xD, &yD, &zD );
+//Console->Print("Door pos: %0.0f %0.0f %0.0f", xD, yD, zD);
+                    D2 = ( xI - xD ) * ( xI - xD ) + ( yI - yD ) * ( yI - yD ) + ( zI - zD ) * ( zI - zD );
+//Console->Print("Dist D2:%0.0f minD2:%0.0f", D2, minD2);
+                    if ( D2 < minD2 )
+                    {
+                        minD2 = D2;
+                        minObjID = 1 + dit->first;
+                    }
+                }
+            }
+            if ( minObjID-- )
+            {
+                it->second->SetLinkedObjectID( minObjID );
+                if ( gDevDebug ) Console->Print( "%s Found triggered door %d (%s) for button %d (%s)", Console->ColorText( GREEN, BLACK, "[Debug]" ), minObjID, GetDoor( minObjID )->GetName().c_str(), it->first, it->second->GetName().c_str() );
+
+            }
+            else
+            {
+                Console->Print( "%s No triggered door found for button %d (%s) in World data template %s", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), it->first, it->second->GetName().c_str(), this->GetName().c_str() );
+            }
+        }
+        else if ( fnctType == 6 ) // if function is genrep
+        {
+            it->second->SetLinkedObjectID( ++tGROrder );
+        }
+    }
+
+}
diff --git a/server/src/game/worlds.cpp b/server/src/game/worlds.cpp
new file mode 100755 (executable)
index 0000000..421a401
--- /dev/null
@@ -0,0 +1,789 @@
+/*\r
+ TinNS (TinNS is not a Neocron Server)\r
+ Copyright (C) 2005 Linux Addicted Community\r
+\r
+ This program is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 2\r
+ of the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+ 02110-1301, USA.\r
+*/\r
+\r
+\r
+/*\r
+  worlds.cpp - world class and world map class\r
+\r
+ MODIFIED: 06 Oct 2006 Hammag\r
+ REASON: - creation\r
+\r
+*/\r
+\r
+\r
+#include "main.h"\r
+\r
+#include "filesystem.h"\r
+#include "def_worlds.h"\r
+#include "gamedefs.h"\r
+#include "furnituretemplate.h"\r
+#include "worlddatatemplate.h"\r
+#include "worlds.h"\r
+#include "appartements.h"\r
+#include "vehicle.h"\r
+\r
+\r
+#include <set>\r
+\r
+/**** PWorld ****/\r
+u16 const PWorld::mZoneOutLimitOffset = 0x100;\r
+u16 const PWorld::mBottomZoneOutLimit = 0x4800 - PWorld::mZoneOutLimitOffset;\r
+u16 const PWorld::mBottomZoneInLimit = 0x4a00;\r
+u16 const PWorld::mTopZoneOutLimit = 0xb200 + PWorld::mZoneOutLimitOffset;\r
+u16 const PWorld::mTopZoneInLimit = 0xb000;\r
+\r
+PWorld::PWorld()\r
+{\r
+  mID = 0;\r
+  mUseCount = 0;\r
+  mWorldDataTemplate = NULL;\r
+}\r
+\r
+PWorld::~PWorld()\r
+{\r
+}\r
+\r
+bool PWorld::Load( u32 nWorldID )\r
+{\r
+  std::string WorldTemplateName;\r
+  std::string tFileName;\r
+  bool tCheckOK;\r
+\r
+  if ( nWorldID > PWorlds::mAptBaseWorldId )\r
+  {\r
+    //int AptTmplID = Appartements->GetAptType(nWorldID - PWorlds::mAptBaseWorldId);\r
+    int AptTmplID = Appartements->GetAptType( nWorldID );\r
+    if ( !AptTmplID )\r
+    {\r
+      Console->Print( "%s PWorld::Load - invalid apt %d", Console->ColorText( RED, BLACK, "[WARNING]" ), nWorldID - PWorlds::mAptBaseWorldId );\r
+      return false;\r
+    }\r
+    const PDefAppartement* nAppDef = GameDefs->Appartements()->GetDef( AptTmplID );\r
+    if ( !nAppDef )\r
+    {\r
+      Console->Print( "%s PWorld::Load - invalid apt type %d", Console->ColorText( RED, BLACK, "[WARNING]" ), AptTmplID );\r
+      return false;\r
+    }\r
+    WorldTemplateName = nAppDef->GetWorldName();\r
+\r
+    tFileName = std::string( "worlds/" ) + WorldTemplateName + ".dat";\r
+    tCheckOK = Worlds->LeaseWorldDataTemplate( WorldTemplateName, tFileName );\r
+    if ( !tCheckOK )\r
+    {\r
+      tFileName = WorldTemplateName + ".dat";\r
+      tCheckOK = Worlds->LeaseWorldDataTemplate( WorldTemplateName, tFileName );\r
+    }\r
+    if ( !tCheckOK )\r
+    {\r
+      Console->Print( "%s PWorld::Load - unable to lease apt world %s (%s)", Console->ColorText( RED, BLACK, "[WARNING]" ), WorldTemplateName.c_str(), tFileName.c_str() );\r
+      return false;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    const PDefWorldFile* nWorldFileDef;\r
+\r
+    if (( nWorldID > 90000 ) && ( nWorldID < 90017 ) ) // hardcoded holomatch hack\r
+    {\r
+      nWorldFileDef = NULL;\r
+      char worldName[19];\r
+      int MatchID = nWorldID - 90000;\r
+      if ( MatchID > 8 ) // to care for Neofrag 1 & 2\r
+        MatchID -= 8;\r
+      if ( MatchID > 6 )\r
+        MatchID = 6; // holomatch 7 and 8 are same as 6\r
+      snprintf( worldName, 19, "holomatch/neofrag%d", MatchID );\r
+      WorldTemplateName = worldName;\r
+    }\r
+    else\r
+    {\r
+      nWorldFileDef = GameDefs->WorldFiles()->GetDef( nWorldID );\r
+      if ( !nWorldFileDef )\r
+        return false;\r
+      WorldTemplateName = nWorldFileDef->GetName();\r
+    }\r
+\r
+    const PDefWorld* tWorldDef = GameDefs->Worlds()->GetDef( nWorldID );\r
+    if ( tWorldDef ) // should always be true here\r
+    {\r
+      if ( !( tWorldDef->GetDatFile().empty() ) )\r
+        tFileName = tWorldDef->GetDatFile();\r
+      else if ( nWorldFileDef )\r
+        tFileName = nWorldFileDef->GetBasicFileName() + ".dat";\r
+      else\r
+      {\r
+        tFileName = "worlds/";\r
+        tFileName += WorldTemplateName;\r
+        tFileName += ".dat";\r
+      }\r
+    }\r
+    else\r
+      return false; // should'nt happen here\r
+\r
+    if ( !Worlds->LeaseWorldDataTemplate( WorldTemplateName, tFileName ) )\r
+      return false;\r
+  }\r
+\r
+  mWorldDataTemplate = Worlds->GetWorldDataTemplate( tFileName );\r
+  if ( !mWorldDataTemplate )\r
+  {\r
+    Console->Print( "%s PWorld::Load : Unexpected world %d not found error", Console->ColorText( RED, BLACK, "[WARNING]" ), nWorldID );\r
+    return false;\r
+  }\r
+\r
+  mID = nWorldID;\r
+  mSpawnedVehicles.SetLocation( nWorldID );\r
+  // furniture & other world stuff loading here\r
+  Console->Print( "%s Loaded world %d", Console->ColorText( GREEN, BLACK, "[DEBUG]" ), nWorldID );\r
+  return true;\r
+}\r
+\r
+const PDefWorldModel* PWorld::GetFurnitureItemModel( u32 nItemID )\r
+{\r
+  if ( mWorldDataTemplate )\r
+  {\r
+    const PFurnitureItemTemplate* tFurniture = mWorldDataTemplate->GetFurnitureItem( nItemID );\r
+    if ( tFurniture )\r
+      return tFurniture->GetDefWorldModel();\r
+  }\r
+  return NULL;\r
+}\r
+\r
+bool PWorld::CharUseChair( int CharLocalID, u32 nItemID )\r
+{\r
+  PChairsInUseMap::iterator it = mChairsInUseMap.find( nItemID );\r
+  if ( it == mChairsInUseMap.end() ) // chair is free\r
+  {\r
+    if ( gDevDebug )\r
+      Console->Print( "%s Localchar %d now using free chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID );\r
+    mChairsInUseMap.insert( std::make_pair( nItemID, CharLocalID ) );\r
+    return true;\r
+  }\r
+  else // chair is already in use\r
+  {\r
+    if ( gDevDebug )\r
+    {\r
+      if ( it->second == CharLocalID )\r
+      {\r
+        Console->Print( "%s Localchar %d already using chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID );\r
+      }\r
+      else\r
+      {\r
+        Console->Print( "%s Localchar %d can't sit on chair %d used by localchar %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID, it->second );\r
+      }\r
+    }\r
+    return ( it->second == CharLocalID );\r
+  }\r
+}\r
+\r
+void PWorld::CharLeaveChair( int CharLocalID, u32 nItemID )\r
+{\r
+  PChairsInUseMap::iterator it = mChairsInUseMap.find( nItemID );\r
+  if (( it != mChairsInUseMap.end() ) && ( it->second == CharLocalID ) ) // chair is in use by this char\r
+  {\r
+    if ( gDevDebug )\r
+      Console->Print( "%s Localchar %d leaving chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID );\r
+    mChairsInUseMap.erase( it );\r
+  }\r
+}\r
+\r
+PClient* PWorld::GetClientByCharLocalId( u32 rawObjectId ) const\r
+{\r
+  // Temp implementation\r
+  return ClientManager->GetClientByCharLocalId( rawObjectId, mID );\r
+}\r
+\r
+bool PWorld::CheckVhcNeedZoning( PVhcCoordinates const* nPos ) const\r
+{\r
+  if ( ( nPos->GetX() <= mBottomZoneOutLimit ) || ( nPos->GetX() >= mTopZoneOutLimit ) || ( nPos->GetY() <= mBottomZoneOutLimit )   || ( nPos->GetY() >= mTopZoneOutLimit ) )\r
+    return true;\r
+  else\r
+    return false;\r
+}\r
+\r
+u32 PWorld::GetVhcZoningDestination( PSpawnedVehicle const* nVhc, PVhcCoordinates* nPos ) const\r
+{\r
+  u32 destWorldId = 0;\r
+  s16 vChange = 0;\r
+  s16 hChange = 0;\r
+  PVhcCoordinates const vhcPos = nVhc->GetPosition();\r
+  u16 posX = vhcPos.GetX();\r
+  u16 posY = vhcPos.GetY();\r
+\r
+  if ( posX <= mBottomZoneOutLimit )\r
+  {\r
+    vChange = 1;\r
+  }\r
+  else if ( posX >= mTopZoneOutLimit )\r
+  {\r
+    vChange = -1;\r
+  }\r
+\r
+  if ( posY <= mBottomZoneOutLimit )\r
+  {\r
+    hChange = -1;\r
+  }\r
+  else if ( posY >= mTopZoneOutLimit )\r
+  {\r
+    hChange = 1;\r
+  }\r
+\r
+  if ( vChange || hChange )\r
+  {\r
+    //Console->Print( YELLOW, BLACK, "[DEBUG] Limit Reached V:%d H:%d mapId:%d", vChange,hChange,mID );\r
+    u8 currH = 0;\r
+    u8 currV = 0;\r
+    s16 newH, newV;\r
+\r
+    if ( Worlds->GetWorldmapFromWorldId( mID, currH, currV ) )\r
+    {\r
+      //Console->Print( YELLOW, BLACK, "[DEBUG] current map pos V:%d H:%d", currV,currH );\r
+      newH = currH + hChange;\r
+      if ( newH < 0 )\r
+        newH = 0;\r
+      else if ( newH >= PWorlds::mOutdoorWorldmapHSize )\r
+        newH = PWorlds::mOutdoorWorldmapHSize;\r
+\r
+      newV = currV + vChange;\r
+      if ( newV < 0 )\r
+        newV = 0;\r
+      else if ( newV >= PWorlds::mOutdoorWorldmapHSize )\r
+        newV = PWorlds::mOutdoorWorldmapHSize;\r
+\r
+      //Console->Print( YELLOW, BLACK, "[DEBUG] new map pos V:%d H:%d", newV,newH );\r
+      if (( newH != currH ) || ( newV != currV ) )\r
+      {\r
+        destWorldId = Worlds->GetWorldIdFromWorldmap( newH, newV );\r
+\r
+        if ( destWorldId && nPos )\r
+        {\r
+          if ( vChange == 1 )\r
+            posX = mTopZoneInLimit;\r
+          else if ( vChange == -1 )\r
+            posX = mBottomZoneInLimit;\r
+\r
+          if ( hChange == -1 )\r
+            posY = mTopZoneInLimit;\r
+          else if ( hChange == 1 )\r
+            posY = mBottomZoneInLimit;\r
+\r
+          nPos->SetPosition( posY, vhcPos.GetZ(), posX, vhcPos.GetUD(), vhcPos.GetLR(), vhcPos.GetRoll(), vhcPos.GetAct(), vhcPos.GetUnknown(), vhcPos.GetFF() );\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  return destWorldId;\r
+}\r
+\r
+/**** PWorlds ****/\r
+u32 const PWorlds::mNcSubwayWorldId = 1000;\r
+u32 const PWorlds::mAptBaseWorldId = 100000;\r
+u32 const PWorlds::mOutdoorBaseWorldId = 2001;\r
+u32 const PWorlds::mOutdoorWorldIdVIncrement = 20;\r
+u8 const PWorlds::mOutdoorWorldmapHSize = 16;\r
+u8 const PWorlds::mOutdoorWorldmapVSize = 11;\r
+u32 const PWorlds::mOutdoorMaxWorldId = PWorlds::mOutdoorBaseWorldId + PWorlds::mOutdoorWorldIdVIncrement * ( PWorlds::mOutdoorWorldmapVSize - 1 ) + PWorlds::mOutdoorWorldmapHSize - 1;\r
+\r
+PWorlds::PWorlds()\r
+{\r
+  mPreloadWorldsTemplates = false; // to be put as config option\r
+  mPreloadStaticWorlds = false; // to be put as config option\r
+}\r
+\r
+PWorlds::~PWorlds()\r
+{\r
+  for ( PWorldsMap::iterator i = mStaticWorldsMap.begin(); i != mStaticWorldsMap.end(); i++ )\r
+    if ( i->second )\r
+    {\r
+      delete i->second;\r
+    }\r
+  for ( PWorldsMap::iterator i = mOnDemandWorldsMap.begin(); i != mOnDemandWorldsMap.end(); i++ )\r
+    if ( i->second )\r
+    {\r
+      delete i->second;\r
+    }\r
+  for ( PWorldDataTemplatesMap::iterator i = mWorldDataTemplatesMap.begin(); i != mWorldDataTemplatesMap.end(); i++ )\r
+    if ( i->second )\r
+    {\r
+      delete i->second;\r
+    }\r
+}\r
+\r
+bool PWorlds::LeaseWorldDataTemplate( const std::string& nBspName, const std::string& nFileName, const bool nPreloadPhase )\r
+{\r
+  PWorldDataTemplate* tWorldDataTemplate;\r
+\r
+  PWorldDataTemplatesMap::iterator it = mWorldDataTemplatesMap.find( nFileName );\r
+  if ( it == mWorldDataTemplatesMap.end() ) // template unkown yet\r
+  {\r
+    if ( nPreloadPhase ) // if in preload phase, we try to load it or make it known\r
+    {\r
+      tWorldDataTemplate = new PWorldDataTemplate;\r
+      if ( tWorldDataTemplate->LoadDatFile( nBspName, nFileName, !mPreloadWorldsTemplates ) )\r
+      {\r
+        if ( mPreloadWorldsTemplates )\r
+        {\r
+          mWorldDataTemplatesMap.insert( std::make_pair( nFileName, tWorldDataTemplate ) );\r
+          tWorldDataTemplate->IncreaseUseCount();\r
+        }\r
+        else\r
+        {\r
+          mWorldDataTemplatesMap.insert( std::make_pair( nFileName, ( PWorldDataTemplate* )NULL ) ); // NULL means file access OK but not preloaded yet\r
+          delete tWorldDataTemplate;\r
+        }\r
+        //return true;\r
+      }\r
+      else\r
+      {\r
+        delete tWorldDataTemplate;\r
+        return false;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      return false;\r
+    }\r
+  }\r
+  else // template already known\r
+  {\r
+    if ( !it->second  &&  !nPreloadPhase ) // template known but not already loaded and not in preload ?\r
+    {\r
+      tWorldDataTemplate = new PWorldDataTemplate;\r
+      if ( tWorldDataTemplate->LoadDatFile( nBspName, nFileName ) )\r
+      {\r
+        it->second = tWorldDataTemplate;\r
+      }\r
+      else\r
+      {\r
+        Console->Print( "%s Invalid world data template file %s", Console->ColorText( RED, BLACK, "[ERROR]" ), nFileName.c_str() );\r
+        mWorldDataTemplatesMap.erase( it );\r
+        delete tWorldDataTemplate;\r
+        return false;\r
+      }\r
+    }\r
+\r
+    if ( !nPreloadPhase )\r
+      it->second->IncreaseUseCount();\r
+\r
+    //return true;\r
+  }\r
+\r
+  return true;\r
+}\r
+\r
+void PWorlds::ReleaseWorldDataTemplate( const std::string& nFileName )\r
+{\r
+  PWorldDataTemplatesMap::iterator it = mWorldDataTemplatesMap.find( nFileName );\r
+  if (( it != mWorldDataTemplatesMap.end() ) && it->second )\r
+  {\r
+    it->second->DecreaseUseCount();\r
+  }\r
+  else\r
+    Console->Print( "%s PWorlds::ReleaseWorldDataTemplate : try to relese not loaded template %s", Console->ColorText( RED, BLACK, "[Warning]" ), nFileName.c_str() );\r
+}\r
+\r
+void PWorlds::UnloadWorldDataTemplate( const std::string& nFileName )\r
+{\r
+  PWorldDataTemplate* tWorldDataTemplate;\r
+\r
+  PWorldDataTemplatesMap::iterator it = mWorldDataTemplatesMap.find( nFileName );\r
+  if (( it != mWorldDataTemplatesMap.end() ) && it->second )\r
+  {\r
+    tWorldDataTemplate = it->second;\r
+    if ( mPreloadWorldsTemplates || ( tWorldDataTemplate->GetUseCount() > 0 ) )\r
+      Console->Print( "%s PWorlds::UnloadWorldDataTemplate : attempt to unload template %s when use count not null ou preload set", Console->ColorText( RED, BLACK, "[Warning]" ), nFileName.c_str() );\r
+    else\r
+    {\r
+      it->second = ( PWorldDataTemplate* )NULL;\r
+      delete tWorldDataTemplate;\r
+    }\r
+  }\r
+  else\r
+    Console->Print( "%s PWorlds::UnloadWorldDataTemplate : attempt to release not loaded template %s", Console->ColorText( RED, BLACK, "[Warning]" ), nFileName.c_str() );\r
+}\r
+\r
+PWorldDataTemplate* PWorlds::GetWorldDataTemplate( const std::string& nFileName )\r
+{\r
+  PWorldDataTemplatesMap::const_iterator it = mWorldDataTemplatesMap.find( nFileName );\r
+  if ( it != mWorldDataTemplatesMap.end() )\r
+    return it->second;\r
+  else\r
+    return NULL;\r
+}\r
+\r
+bool PWorlds::LoadWorlds() // once Load is done, only WorldDataTemplate registred in mWorldDataTemplatesMap\r
+{\r
+  //   will be considered as valid\r
+  std::string tFileName;\r
+  std::string tBspName;\r
+  const PDefWorld* tDefWorld;\r
+  bool tCheckOK;\r
+  int ValidCount = 0, InvalidCount = 0, DblInvCount = 0;\r
+  int DatTmplCount, BadDatTmplCount;\r
+  std::set<std::string>\r
+  InvalideFiles;\r
+\r
+  // Appartment templates checking or preloading\r
+  std::map<int, PDefAppartement*>::const_iterator itAptStart = GameDefs->Appartements()->ConstIteratorBegin();\r
+  std::map<int, PDefAppartement*>::const_iterator itAptEnd = GameDefs->Appartements()->ConstIteratorEnd();\r
+  for ( std::map<int, PDefAppartement*>::const_iterator i = itAptStart; i != itAptEnd; i++ )\r
+  {\r
+    tCheckOK = false;\r
+    tBspName = i->second->GetWorldName();\r
+    tFileName = std::string( "worlds/" ) + tBspName + ".dat";\r
+    if ( !InvalideFiles.count( tFileName ) )\r
+    {\r
+      tCheckOK = LeaseWorldDataTemplate( tBspName, tFileName, true );\r
+      if ( !tCheckOK )\r
+      {\r
+        InvalideFiles.insert( tFileName );\r
+        if ( gDevDebug )\r
+          Console->Print( RED, BLACK, "Template file %s invalid", tFileName.c_str() );\r
+      }\r
+    }\r
+    if ( !tCheckOK ) // in case full path was given without omiting worlds/ or in another dir/archive ...\r
+    {\r
+      tFileName = tBspName + ".dat";\r
+      if ( !InvalideFiles.count( tFileName ) )\r
+      {\r
+        tCheckOK = LeaseWorldDataTemplate( tBspName, tFileName, true );\r
+        if ( !tCheckOK )\r
+        {\r
+          InvalideFiles.insert( tFileName );\r
+          ++DblInvCount;\r
+        }\r
+      }\r
+    }\r
+\r
+    if ( tCheckOK )\r
+    {\r
+      ++ValidCount;\r
+      if ( gDevDebug )\r
+        Console->Print( GREEN, BLACK, "Template file %s for appartment %d (%s) loaded", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() );\r
+    }\r
+    else\r
+    {\r
+      ++InvalidCount;\r
+      if ( gDevDebug )\r
+        Console->Print( RED, BLACK, "Template file %s for appartment %d (%s) not available or invalid", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() );\r
+    }\r
+  }\r
+\r
+  DatTmplCount = mWorldDataTemplatesMap.size();\r
+  BadDatTmplCount = InvalideFiles.size();\r
+  Console->Print( "%s %d valid appartement templates checked (%d dat files)", Console->ColorText( GREEN, BLACK, "[Success]" ), ValidCount, DatTmplCount );\r
+  if ( InvalidCount )\r
+    Console->Print( "%s %d invalid appartement templates rejected (%d dat files)", Console->ColorText( YELLOW, BLACK, "[Notice]" ), InvalidCount, BadDatTmplCount - DblInvCount );\r
+\r
+  // Static worlds & static worlds templates checking or preloading\r
+  ValidCount = InvalidCount = 0;\r
+  const PDefWorldFile* tDefWorldFile;\r
+  std::map<int, PDefWorldFile*>::const_iterator itFilStart = GameDefs->WorldFiles()->ConstIteratorBegin();\r
+  std::map<int, PDefWorldFile*>::const_iterator itFilEnd = GameDefs->WorldFiles()->ConstIteratorEnd();\r
+  for ( std::map<int, PDefWorldFile*>::const_iterator i = itFilStart; i != itFilEnd; i++ )\r
+  {\r
+    tDefWorldFile = i->second;\r
+\r
+    tDefWorld = GameDefs->Worlds()->GetDef( tDefWorldFile->GetIndex() );\r
+    if ( tDefWorld ) // we only care for worlds that are present in worldinfo.def too\r
+    {\r
+      tBspName = tDefWorldFile->GetName();\r
+      if ( !( tDefWorld->GetDatFile().empty() ) )\r
+        tFileName = tDefWorld->GetDatFile();\r
+      else\r
+        tFileName = i->second->GetBasicFileName() + ".dat";\r
+\r
+      tCheckOK = false;\r
+      if ( !InvalideFiles.count( tFileName ) )\r
+      {\r
+        tCheckOK = LeaseWorldDataTemplate( tBspName, tFileName, true );\r
+        if ( !tCheckOK )\r
+        {\r
+          InvalideFiles.insert( tFileName );\r
+          if ( gDevDebug )\r
+            Console->Print( RED, BLACK, "Template file %s invalid", tFileName.c_str() );\r
+        }\r
+      }\r
+\r
+      if ( tCheckOK )\r
+      {\r
+        ++ValidCount;\r
+        if ( mPreloadStaticWorlds )\r
+        {\r
+          LeaseWorld( tDefWorldFile->GetIndex(), true ); // This will make the world ready and kept in mem (use count always >0 )\r
+        }\r
+        else\r
+        {\r
+          mStaticWorldsMap.insert( std::make_pair( tDefWorldFile->GetIndex(), ( PWorld* )NULL ) );\r
+        }\r
+        if ( gDevDebug )\r
+          Console->Print( GREEN, BLACK, "Template file %s for world %d (%s) loaded", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() );\r
+      }\r
+      else\r
+      {\r
+        ++InvalidCount;\r
+        if ( gDevDebug )\r
+          Console->Print( RED, BLACK, "Template file %s for world %d (%s) not available or invalid", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() );\r
+      }\r
+    }\r
+  }\r
+\r
+  // Hardcoded neofrag worlds ... oO ... and neofrag4.dat can't be found :-/\r
+  for ( int i = 1; i <= 16; i++ )\r
+  {\r
+    char worldName[19];\r
+    int MatchID = i;\r
+    if ( MatchID > 8 ) // to care for Neofrag 1 & 2\r
+      MatchID -= 8;\r
+    if ( MatchID > 6 )\r
+      MatchID = 6; // holomatch 7 and 8 are same as 6\r
+    snprintf( worldName, 19, "holomatch/neofrag%d", MatchID );\r
+\r
+    tDefWorld = GameDefs->Worlds()->GetDef( 90000 + i );\r
+    if ( tDefWorld ) // we only care for worlds that are present in worldinfo.def too\r
+    {\r
+      if ( !( tDefWorld->GetDatFile().empty() ) )\r
+        tFileName = tDefWorld->GetDatFile();\r
+      else\r
+      {\r
+        tFileName = "worlds/";\r
+        tFileName += worldName;\r
+        tFileName += ".dat";\r
+      }\r
+\r
+      tCheckOK = false;\r
+      if ( !InvalideFiles.count( tFileName ) )\r
+      {\r
+        tCheckOK = LeaseWorldDataTemplate( worldName, tFileName, true );\r
+        if ( !tCheckOK )\r
+        {\r
+          InvalideFiles.insert( tFileName );\r
+          if ( gDevDebug )\r
+            Console->Print( RED, BLACK, "Template file %s invalid", tFileName.c_str() );\r
+        }\r
+      }\r
+\r
+      if ( tCheckOK )\r
+      {\r
+        ++ValidCount;\r
+        if ( mPreloadStaticWorlds )\r
+        {\r
+          LeaseWorld( 90000 + i, true ); // This will make the world ready and kept in mem (use count always >0 )\r
+        }\r
+        else\r
+        {\r
+          mStaticWorldsMap.insert( std::make_pair( 90000 + i, ( PWorld* )NULL ) );\r
+        }\r
+        if ( gDevDebug )\r
+          Console->Print( GREEN, BLACK, "Template file %s for world %d (%s) loaded", tFileName.c_str(), 90000 + i, worldName );\r
+      }\r
+      else\r
+      {\r
+        ++InvalidCount;\r
+        if ( gDevDebug )\r
+          Console->Print( RED, BLACK, "Template file %s for world %d (%s) not available or invalid", tFileName.c_str(), 90000 + i, worldName );\r
+      }\r
+    }\r
+  }\r
+\r
+  Console->Print( "%s %d valid world templates checked (%d dat files)", Console->ColorText( GREEN, BLACK, "[Success]" ), ValidCount, mWorldDataTemplatesMap.size() - DatTmplCount );\r
+  if ( InvalidCount )\r
+    Console->Print( "%s %d invalid world templates rejected (%d dat files)", Console->ColorText( YELLOW, BLACK, "[Notice]" ), InvalidCount, InvalideFiles.size() - BadDatTmplCount - DblInvCount );\r
+  Console->Print( "%s %d static worlds prepared", Console->ColorText( GREEN, BLACK, "[Success]" ), mStaticWorldsMap.size() );\r
+\r
+  // release memory if World templates preload activated, this cache that won't be used anymore\r
+  // if (mPreloadWorldsTemplates) Filesystem->ClearCache();\r
+\r
+  return true;\r
+}\r
+\r
+bool PWorlds::IsValidWorld( u32 nWorldID ) const\r
+{\r
+  if ( nWorldID > PWorlds::mAptBaseWorldId )\r
+  {\r
+    if ( mOnDemandWorldsMap.count( nWorldID ) ) // Check if already loaded\r
+      return true;\r
+    else //should better do a check using a PAppartements class object to get the world template\r
+    {\r
+      //int AptTmplID = Appartements->GetAptType(nWorldID - PWorlds::mAptBaseWorldId);\r
+      int AptTmplID = Appartements->GetAptType( nWorldID );\r
+      if ( !AptTmplID )\r
+        return false;\r
+\r
+      const PDefAppartement* nAppDef = GameDefs->Appartements()->GetDef( AptTmplID );\r
+      if ( !nAppDef )\r
+        return false;\r
+\r
+      std::string tFileName = "worlds/" + nAppDef->GetWorldName() + ".dat";\r
+      PWorldDataTemplatesMap::const_iterator it = mWorldDataTemplatesMap.find( tFileName );\r
+      return ( it != mWorldDataTemplatesMap.end() );\r
+    }\r
+  }\r
+  else\r
+  {\r
+    if ( gDevDebug )\r
+      Console->Print( "%s Checking validity for world %d : %s", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID, mStaticWorldsMap.count( nWorldID ) ? "OK" : "BAD" );\r
+    return ( mStaticWorldsMap.count( nWorldID ) );\r
+  }\r
+}\r
+\r
+PWorld* PWorlds::LeaseWorld( u32 nWorldID, const bool nPreloadPhase )\r
+{\r
+  PWorldsMap::iterator it;\r
+\r
+  if ( nWorldID > PWorlds::mAptBaseWorldId )\r
+  {\r
+    it = mOnDemandWorldsMap.find( nWorldID ); // Check if already loaded\r
+    if (( it != mOnDemandWorldsMap.end() ) && it->second ) // Dynamic world shall not have a NULL it->second\r
+    {\r
+      // if loaded\r
+      it->second->IncreaseUseCount();\r
+      if ( gDevDebug )\r
+        Console->Print( "%s Leased world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID );\r
+      return it->second;\r
+    }\r
+    else // not loaded yet or invalid\r
+    {\r
+      PWorld* nWorld = new PWorld;\r
+      if ( ! nWorld->Load( nWorldID ) ) // Error when loading (shouldn't happen)\r
+      {\r
+        delete nWorld;\r
+        Console->Print( "% Could not load world %d - World now set as invalid", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID );\r
+        return NULL;\r
+      }\r
+      else\r
+      {\r
+        mOnDemandWorldsMap.insert( std::make_pair( nWorldID, nWorld ) );\r
+        nWorld->IncreaseUseCount();\r
+        if ( gDevDebug )\r
+          Console->Print( "%s Leased world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID );\r
+        return nWorld;\r
+      }\r
+    }\r
+  }\r
+  else\r
+  {\r
+    it = mStaticWorldsMap.find( nWorldID ); // Check if already loaded\r
+    if (( it == mStaticWorldsMap.end() ) && nPreloadPhase )\r
+    {\r
+      mStaticWorldsMap.insert( std::make_pair( nWorldID, ( PWorld* )NULL ) );\r
+      it = mStaticWorldsMap.find( nWorldID );\r
+    }\r
+    if ( it != mStaticWorldsMap.end() )\r
+    {\r
+      // if valid\r
+      if ( ! it->second ) // if not loaded yet\r
+      {\r
+        it->second = new PWorld;\r
+        if ( ! it->second->Load( nWorldID ) ) // Error when loading (shouldn't happen)\r
+        {\r
+          delete it->second;\r
+          Console->Print( "%s Could not load world %d - World now set as invalid", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID );\r
+          mStaticWorldsMap.erase( it ); // remove from valid worlds map\r
+          return NULL;\r
+        }\r
+      }\r
+      it->second->IncreaseUseCount();\r
+      if ( gDevDebug )\r
+        Console->Print( "%s Leased world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID );\r
+      return it->second;\r
+    }\r
+    else // invalid worldID\r
+    {\r
+      return NULL;\r
+    }\r
+  }\r
+}\r
+\r
+PWorld* PWorlds::GetWorld( u32 nWorldID )\r
+{\r
+  PWorldsMap* tMap;\r
+  PWorldsMap::iterator it;\r
+\r
+  tMap = (( nWorldID > PWorlds::mAptBaseWorldId ) ? &mOnDemandWorldsMap : &mStaticWorldsMap );\r
+\r
+  it = tMap->find( nWorldID );\r
+  if (( it != tMap->end() ) && it->second )\r
+  {\r
+    return it->second;\r
+  }\r
+  else\r
+  {\r
+    Console->Print( "%s PWorlds::GetWorld : Trying to get world %d without lease !", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID );\r
+    return NULL;\r
+  }\r
+}\r
+\r
+void PWorlds::ReleaseWorld( u32 nWorldID ) // no dynamic unload is performed atm + don't forget spawned vhc !\r
+{\r
+  PWorld* tWorld = GetWorld( nWorldID );\r
+  if ( tWorld )\r
+  {\r
+    if ( tWorld->GetUseCount() ) // this check is for dev time only\r
+    {\r
+      tWorld->DecreaseUseCount();\r
+      if ( gDevDebug )\r
+        Console->Print( "%s Released world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID );\r
+    }\r
+    else\r
+    {\r
+      Console->Print( "%s PWorlds::ReleaseWorld : Trying to release world %d with use count 0 !", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID );\r
+    }\r
+  }\r
+  else\r
+  {\r
+    Console->Print( "%s PWorlds::ReleaseWorld : Generated the invalid get world %d", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID );\r
+  }\r
+}\r
+\r
+bool PWorlds::IsAppartment( u32 nWorldID )\r
+{\r
+  return (( nWorldID > PWorlds::mAptBaseWorldId ) && IsValidWorld( nWorldID ) );\r
+}\r
+\r
+void PWorlds::Update()\r
+{}\r
+\r
+void PWorlds::Shutdown()\r
+{}\r
+\r
+u32 PWorlds::GetWorldIdFromWorldmap( u8 mapH, u8 mapV ) const\r
+{\r
+  u32 loc = 0;\r
+  if (( mapH < mOutdoorWorldmapHSize ) && ( mapV < mOutdoorWorldmapVSize ) )\r
+  {\r
+    loc = mOutdoorBaseWorldId + mOutdoorWorldIdVIncrement * mapV + mapH;\r
+    if ( ! IsValidWorld( loc ) )\r
+      loc = 0;\r
+  }\r
+  return loc;\r
+}\r
+\r
+bool PWorlds::GetWorldmapFromWorldId( u32 nWorldId, u8& mapH, u8& mapV ) const\r
+{\r
+  if (( nWorldId >= mOutdoorBaseWorldId ) && ( nWorldId <= mOutdoorMaxWorldId ) )\r
+  {\r
+    mapV = ( nWorldId - mOutdoorBaseWorldId ) / mOutdoorWorldIdVIncrement;\r
+    mapH = ( nWorldId - mOutdoorBaseWorldId ) % mOutdoorWorldIdVIncrement;\r
+    return true;\r
+  }\r
+  return false;\r
+}\r
diff --git a/server/src/game/zoning.cpp b/server/src/game/zoning.cpp
new file mode 100644 (file)
index 0000000..546ddbe
--- /dev/null
@@ -0,0 +1,103 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       Zoning - makes changing of maps possible ingame\r
+\r
+       Authors:\r
+       - initial release by unknown person\r
+       - Sting <>\r
+       - Akiko <akiko@gmx.org>\r
+       - Namikon\r
+\r
+       MODIFIED: 23 August 2005 by Sting\r
+        REASON: - TO match up with defs/pak_worldinfo.def from patch 200\r
+\r
+       MODIFIED: 27 Aug 2005 by Akiko\r
+       REASON: - reformated for better reading\r
+               - thinking about a way to optimize the case statements\r
+       MODIFIED: 28 Aug 2005 by Akiko\r
+       REASON: - continued reformating\r
+       MODIFIED: 26 Oct 2005 Akiko\r
+       REASON: - fixed a bug -> loc is a int, and the location is a 16 bit value\r
+               - added GPL\r
+       MODIFIED: 27 Nov 2005 Akiko\r
+       REASON: - fixed a very stupid bug (loc)\r
+       MODIFIED: 04 Dec 2005 Akiko\r
+       REASON: - copying int to char array (loc) correctly now\r
+       MODIFIED: 07 Jan 2006 Namikon\r
+       REASON: - Fixed zoning to / from wastelands to / from city sectors (packet1 was wrong, thanks Maxx!!)\r
+       MODIFIED: 08 Jan 2006 Namikon\r
+       REASON: - Added appartment handling\r
+            - Fixed minimap\r
+       MODIFIED: 17 Jan 2006 Namikon\r
+       REASON: - File rewritten. Now, only 1 packet is send, like the real servers (that one fixed subway)\r
+            - Fixed several worldnames\r
+       MODIFIED: 26 Jul 2006 Hammag\r
+       REASON:   - Fixed world 1086 (area mc5) worldname (from NeoX source)\r
+\r
+       MODIFIED: 28 Sep 2006 Hammag\r
+       REASON:   - Zone filename in now taken from appartments.def (for app zoning) or from worlds.ini (general case)\r
+                   rather than hardcoded.\r
+               \r
+       TODO: Put get the fallback world from config\r
+             Check for file existence before sending info to client to avoid client crash and bad location in char info\r
+             \r
+*/\r
+\r
+#include "main.h"\r
+\r
+#include "worlds.h"\r
+#include "appartements.h"\r
+#include "msgbuilder.h"\r
+\r
+void SendZone(PClient *Client, u32 loc)\r
+{\r
+       //TODO : FIX case for worldroute and 5 missing id 505\r
+  std::string worldName;\r
+       ConnectionTCP *Socket = Client->getTCPConn();\r
+       //PChar *Char = Chars->GetChar(Client->GetCharID());\r
+\r
+       Socket->SetTimeOutValue(0xffff);\r
+  \r
+  PWorld* CurrentWorld = Worlds->GetWorld(loc);\r
+  if (CurrentWorld)\r
+  {\r
+    worldName = CurrentWorld->GetBspName();\r
+    if (worldName.empty())\r
+    {\r
+      worldName = "plaza/plaza_p1"; // Should be a config entry\r
+      Console->Print("Client %d: Empty name for world %d. Redirecting to %s", Console->ColorText(RED, BLACK, "Warning"), Client->GetID(), loc, worldName.c_str());\r
+      loc = 1;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    worldName = "plaza/plaza_p1"; // Should be a config entry\r
+    Console->Print("Client %d: Invalid or not loaded world %d. Redirecting to %s", Console->ColorText(YELLOW, BLACK, "Warning"), Client->GetID(), loc, worldName.c_str());\r
+    loc = 1;\r
+  }\r
+  \r
+  PMessage* cMsg = MsgBuilder->BuildSendZoneTCPMsg(loc, &worldName);\r
+       Client->SendTCPMessage(cMsg);\r
+}\r
diff --git a/server/src/include/config.h b/server/src/include/config.h
new file mode 100644 (file)
index 0000000..822aa13
--- /dev/null
@@ -0,0 +1,107 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+        config.h\r
+\r
+        Authors:\r
+        - Akiko\r
+        - Namikon\r
+        - someone else?\r
+\r
+        MODIFIED: Unknown date / Unknown author\r
+        REASON: - initial release by unknown\r
+        MODIFIED: 23 Dec 2005 Namikon\r
+        REASON: - Added GPL\r
+        MODIFIED: 07 Jan 2006 Namikon\r
+        REASON: - Started to replace XML with CFG files        \r
+        MODIFIED: 05 Aug 2006 Hammag\r
+        REASON: - changed LoadOptions() implementation.\r
+                  This should make addition of new options really easier, as well as config syntax error tracking\r
+                  See config.h for info\r
+        MODIFIED: 27 Aug 2006 Hammag\r
+        REASON: - Modified LoadOption() methode to make it generic,\r
+                    with an options template and the config file as arguments\r
+                - Removed the ConfigTemplate that was used for gameserver only.\r
+                - Removed old unused code\r
+        MODIFIED: 25 Jun 2007 Hammag\r
+        REASON: - Added include support\r
+                - Now use PCRE RegEx instead of "strtok", enabling rentrance and removing\r
+                  potential issues.\r
+                - Added GetOption & GetOptionInt with const std::string parameter\r
+*/\r
+\r
+#ifndef CONFIG_H\r
+#define CONFIG_H\r
+\r
+#include "regex++.h"\r
+\r
+class PConfig\r
+{\r
+       private :\r
+               typedef std::map<std::string, std::string> OptionsMap;\r
+               OptionsMap mOptions;\r
+               RegEx* mOptValRegEx;\r
+               RegEx* mIncludeRegEx;\r
+               \r
+               bool LoadOptions(const char* nConfigTemplate[][2], const char* nConfigFile, int nDepth);\r
+               \r
+       public :\r
+               PConfig();\r
+               ~PConfig();\r
+\r
+               inline bool LoadOptions(const char* nConfigTemplate[][2], const char* nConfigFile)\r
+                 { return LoadOptions(nConfigTemplate, nConfigFile, 0); }\r
+               inline const std::string &GetOption(const char *Name) const { return GetOption((std::string) Name); }\r
+               const std::string &GetOption(const std::string Name) const;\r
+               int GetOptionInt(const char *Name) const { return GetOptionInt((std::string) Name); }\r
+               int GetOptionInt(const std::string Name) const;\r
+};\r
+\r
+// Max nested includes\r
+#define CONFIG_MAXDEPTH 4\r
+\r
+/*\r
+  The list of valid config options is now set in the array ConfigTemplate\r
+  A default value can be set for each option, whiches makes the option optionnal in config file\r
+  If no default value is set, the option is mandatory.\r
+  Duplicate option entries in config file are also checked, and only the first value is kept\r
+  Unkown options are rejected\r
+  Duplicates, unkown and default use generate a warning in logs but don't break options loading\r
+  Missing mandatory option generate an error in log and break option loading (imediate return false)\r
+  \r
+  The ConfigTemplate parameter must have the structure shown in the following exemple:\r
+\r
+const char* ConfigTemplate[][2] = {\r
+  // {option_name, default_value} if default_value is empty string, it means option is mandatory\r
+  // List ends with empty string for option_name\r
+  {"info_sql_host", "127.0.0.1"},\r
+  {"info_sql_port", "3306"},\r
+  {"info_sql_username", ""},\r
+  {"info_sql_password", ""},\r
+  {"", ""} // do not change this line (end mark)\r
+};\r
+\r
+*/\r
+#endif\r
+\r
diff --git a/server/src/include/connection-tcp.h b/server/src/include/connection-tcp.h
new file mode 100644 (file)
index 0000000..23ccad2
--- /dev/null
@@ -0,0 +1,127 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       connection-cpp.h - a connection class for tcp\r
+\r
+       Authors:\r
+       - bakkdoor\r
+\r
+       MODIFIED: 09 Feb 2006 bakkdoor\r
+       REASON: - introduced\r
+\r
+  MODIFIED: 25 Jul 2006 hammag\r
+       REASON: - changed member data prefix from "m_" to "m" in for homogeneity with the reste of TinNS code\r
+               - added private members data mQueueIn and mQueueOut\r
+               - added public members methods SendMessage(), GetMessage(), DeleteOutgoingMessages() and modified code accordingly\r
+               - removed old read/write member data, and added a compatibility mSendBufferMsg* member\r
+               \r
+       MODIFIED: 05 Aug 2006 hammag\r
+       REASON: - renamed "getLocalAddress()" to "getRemoteAddress()" as it is ... what it does !\r
+\r
+       MODIFIED: 26 Aug 2006 hammag\r
+       REASON: - moved RECVBUFFERSIZE, SENDBUFFERSIZE, DEFAULT_TIMEOUT decalration & definition\r
+                  in netcode's main.h (temporarily)\r
+       \r
+       TODO:   - remove old read/write compatibility methods when not needed anymore\r
+               - see .cpp for current implementation limits\r
+\r
+*/\r
+\r
+#ifndef CONNECTIONTCP_H\r
+#define CONNECTIONTCP_H\r
+\r
+class ServerSocket;\r
+\r
+class ConnectionTCP\r
+{\r
+    private:\r
+            int                 mSockfd;\r
+            struct sockaddr_in  mRemoteAddr;\r
+\r
+//            u8                  mReceiveBuffer[RECVBUFFERSIZE];\r
+//            u8                  mSendBuffer[SENDBUFFERSIZE];\r
+\r
+//            int                 mSendSize;\r
+//            int                 mRecvSize;\r
+//            int                 mRecvRewind;\r
+\r
+            std::time_t        mLastActive;\r
+            std::time_t        mTimeOutValue;\r
+\r
+            bool                mbConnected;\r
+\r
+            ServerSocket*          mServerSocket; // pointer to the serversocket\r
+            \r
+            std::queue<PMessage*> mQueueIn;\r
+            std::queue<PMessage*> mQueueOut;\r
+            \r
+            PMessage* mReceiveBufferMsg;\r
+            \r
+    public:\r
+            ConnectionTCP(int sockfd, struct sockaddr_in addr, ServerSocket* server);\r
+            ~ConnectionTCP();\r
+\r
+            struct sockaddr_in  getAddr() { return mRemoteAddr; }\r
+            int                 getSockfd() { return mSockfd; }\r
+            char*               getRemoteAddress();\r
+            \r
+                                // add pointer to serversocket-instance\r
+            void                setServer(ServerSocket* server){ if(server) { mServerSocket = server; } }\r
+\r
+            bool                timeOut() const;\r
+            inline time_t       GetTimeOutValue() const { return mTimeOutValue; }\r
+            inline void         SetTimeOutValue(time_t Value) { mTimeOutValue = Value; }\r
+\r
+            bool                           update();\r
+            bool                isConnected() { return mbConnected; }\r
+            \r
+            inline void SendMessage(PMessage* nMessage) { mQueueOut.push(nMessage); }\r
+            PMessage* GetMessage();\r
+            void DeleteOutgoingMessages();\r
+            \r
+/**************** Old I/F compatibility stuff ******************/       \r
+    private:\r
+            PMessage* mSendBufferMsg; // for old I/F compatibility only\r
+              \r
+    public:                             \r
+            void                flushSendBuffer();\r
+\r
+            int                 getRecvBufferSize();\r
+            int                 getSendBufferSize();\r
+\r
+            // returns a pointer to the internal receive buffer\r
+            // Size contains the number of octets to read (or 0 to read entire buffer)\r
+            // number of octets available is returned in Size\r
+            const u8*           read(int* size);\r
+\r
+            int                 write(const void* data, int size);\r
+            int                 write(u8 data);\r
+            int                 write(u16 data);\r
+            int                 write(u32 data);\r
+            int                 write(float data);\r
+            int                 write(double data);\r
+            int                 write(const char* string);\r
+};\r
+\r
+#endif\r
diff --git a/server/src/include/connection-udp.h b/server/src/include/connection-udp.h
new file mode 100644 (file)
index 0000000..5bdf753
--- /dev/null
@@ -0,0 +1,151 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       connection-udp.h - a connection class for udp\r
+\r
+       Authors:\r
+       - bakkdoor\r
+\r
+       MODIFIED: 09 Feb 2006 bakkdoor\r
+       REASON: - introduced\r
+\r
+       MODIFIED: 01 Jul 2006 hammag\r
+       REASON: - added private member m_ServerSocket\r
+                   and added corresponding parameter in constructor;\r
+\r
+  MODIFIED: 24 Jul 2006 hammag\r
+       REASON: - changed member data prefix from "m_" to "m" in for homogeneity with the reste of TinNS code\r
+               - added private members data mQueueIn and mQueueOut\r
+               - added public members methods SendMessage(), GetMessage(), DeleteOutgoingMessages() and modified code accordingly\r
+               - removed old read/write member data, and added a compatibility mSendBufferMsg* member\r
+\r
+       MODIFIED: 05 Aug 2006 hammag\r
+       REASON: - renamed "getLocalAddress()" to "getRemoteAddress()" as it is ... what it does !\r
+\r
+       TODO:   - remove old read/write compatibility methods when not needed anymore\r
+               - see .cpp for current implementation limits\r
+\r
+*/\r
+\r
+#ifndef CONNECTIONUDP_H\r
+#define CONNECTIONUDP_H\r
+#define MAX_RETENTION 20 // How many packets should be stored until we can delete them\r
+#define SESSION_UDP_OFFSET 37917\r
+class ServerSocket;\r
+\r
+class ConnectionUDP\r
+{\r
+    private:\r
+            int                 mSockfd;\r
+            struct sockaddr_in  mRemoteAddr;\r
+\r
+//            u8                  mReceiveBuffer[RECVBUFFERSIZE];\r
+//            u8                  mSendBuffer[SENDBUFFERSIZE];\r
+\r
+//            int                 mSendSize;\r
+//            int                 mRecvSize;\r
+//            int                 mRecvRewind;\r
+\r
+            std::time_t        mLastActive;\r
+            std::time_t        mTimeOutValue;\r
+\r
+            int                 mPort;\r
+            ServerSocket*       mServerSocket; // pointer to the serversocket\r
+\r
+            std::queue<PMessage*> mQueueIn;\r
+            std::queue<PMessage*> mQueueOut;\r
+            std::queue<PMessage*> mVIPQueueOut;\r
+\r
+    public:\r
+            ConnectionUDP(int sockfd, int port, int remoteadress, int remoteport, ServerSocket* server);\r
+            ~ConnectionUDP();\r
+\r
+            bool                update();\r
+\r
+            int                 getPort() { return mPort; }\r
+            struct sockaddr_in  getAddr() { return mRemoteAddr; }\r
+            int                 getSockfd() { return mSockfd; }\r
+            char*               getRemoteAddress();\r
+\r
+            bool                timeOut() const;\r
+            inline time_t       getTimeOutValue() const { return mTimeOutValue; }\r
+            inline void         setTimeOutValue(time_t Value) { mTimeOutValue = Value; }\r
+\r
+            void SendMessage(PMessage* nMessage, bool nVIP = false);\r
+            inline int GetReadyMessagesNumber() { return mQueueIn.size(); }\r
+            PMessage* GetMessage(); // returns NULL if no message available\r
+            void DeleteOutgoingMessages();\r
+\r
+\r
+/********************* UDP MessageBuffer stuff *********************/\r
+    private:\r
+            typedef std::map<u16, PMessage*> PMessageMap;\r
+            u16 mUDP_ID;\r
+            u16 mLastUDPID;\r
+            u16 mSessionID;\r
+            u16 mTransactionID;\r
+            PMessageMap UDPMessages;\r
+            PMessageMap::iterator GetMsgListBegin() { return UDPMessages.begin(); }\r
+            PMessageMap::iterator GetMsgListEnd() { return UDPMessages.end(); }\r
+\r
+            void InsertUDPMessage(PMessage* nMsg);  // Save message for possible OOO handling later\r
+            void UpdateMessageBuffer();             // Delete old packets, depending on define "MAX_RETENTION"\r
+            void ResetMessageBuffer();              // Done when UDP_ID gets set to zero\r
+\r
+    public:\r
+            void ReSendUDPMessage(u16 nUDP_ID);     // OOO happend, resend udp packet with UDP_ID nUDP_ID\r
+            inline u16 GetUDP_ID() const { return mUDP_ID; }\r
+            inline u16 GetSessionID() const { return SESSION_UDP_OFFSET + mUDP_ID ; }\r
+            inline u16 GetTransactionID() {return mTransactionID; }\r
+            void SetUDP_ID(u16 id);\r
+            inline void IncreaseUDP_ID() { SetUDP_ID(mUDP_ID + 1); }\r
+            inline void ResetTransactionID() { mTransactionID = 10170; }\r
+\r
+            inline void IncreaseTransactionID(u8 nInc = 1) { mTransactionID += nInc; }\r
+\r
+/**************** Old I/F compatibility stuff ******************/\r
+    private:\r
+            PMessage* mSendBufferMsg;\r
+\r
+    public:\r
+            int                 getRecvBufferSize();\r
+            int                 getSendBufferSize();\r
+            void                flushSendBuffer();\r
+            // returns a pointer to the internal receive buffer\r
+            // Size contains the number of octets to read (or 0 to read entire buffer)\r
+            // number of octets available is returned in Size\r
+            const u8*           read(int* size);\r
+\r
+            int                 write(const void* data, int size);\r
+            int                 write(u8 data);\r
+            int                 write(u16 data);\r
+            int                 write(u32 data);\r
+            int                 write(float data);\r
+            int                 write(double data);\r
+            int                 write(const char* string);\r
+\r
+\r
+};\r
+\r
+#endif\r
diff --git a/server/src/include/console.h b/server/src/include/console.h
new file mode 100644 (file)
index 0000000..7a3fe87
--- /dev/null
@@ -0,0 +1,74 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       console.h\r
+\r
+    MODIFIED: 25 Dec 2005 Namikon\r
+    REASON: - Added GPL\r
+    MODIFIED: 06 Jan 2006 Namikon\r
+    REASON: - Added Print() function for colored console output\r
+            - Added ColorText() to give selectable parts of an output another color\r
+            - Added LPrint() to print like eAthena does\r
+              Dont forget to use LClose() after using LPrint :)\r
+    MODIFIED: 26 Aug 2006 Hammag\r
+    REASON: - Added nLogFile as a constructor parameter, to make the class generic             \r
+              \r
+*/\r
+#ifndef CONSOLE_H\r
+#define CONSOLE_H\r
+\r
+enum COLORS\r
+{\r
+    BLACK,\r
+    RED,\r
+    GREEN,\r
+    YELLOW,\r
+    BLUE,\r
+    MAGENTA,\r
+    CYAN,\r
+    WHITE\r
+};\r
+\r
+class PConsole\r
+{\r
+       private :\r
+\r
+               std::ofstream mLogFile;\r
+               std::time_t mLastLogTime;\r
+       public :\r
+               PConsole(const char *nLogFile);\r
+               ~PConsole();\r
+               void Print(const char *Fmt_, ...);\r
+               void Print(COLORS foreground, COLORS background, const char *Fmt_, ...);\r
+               char *ColorText(COLORS foreground, COLORS background, const char *Fmt, ...);\r
+\r
+               void LPrint(const char *Fmt_, ...);\r
+               void LPrint(COLORS foreground, COLORS background, const char *Fmt_, ...);\r
+               void LClose();\r
+\r
+               void Update();\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/include/external.h b/server/src/include/external.h
new file mode 100644 (file)
index 0000000..8df57f6
--- /dev/null
@@ -0,0 +1,94 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       external.h - include file for all common external standard libs\r
+\r
+       MODIFIED: 31 Aug 2005 Akiko\r
+       REASON: - updating def file definitions to match the changes in gamedefs.cpp\r
+               - added define for charfiles path\r
+               - added define for database path\r
+       MODIFIED: 26 Sep 2005 Akiko\r
+       REASON: - reformated code\r
+               - added GPL\r
+               - added infoserver default port as define\r
+               - added my threading model (mutex.h, semaphore.h, thread.h)\r
+               - added basic includes pthread.h, semaphore.h and errno.h\r
+       MODIFIED: 28 Sep 2005 Akiko\r
+       REASON: - added define for game server port\r
+       MODIFIED: 30 Nov 2005 Akiko\r
+       REASON: - added chat.h for the chat part from Namikon\r
+       MODIFIED: 02 Dec 2005 Akiko\r
+       REASON: - commented out mutex.h, thread.h, semaphore.h\r
+       MODIFIED: 22 Dec 2005 Namikon/bakkdoor\r
+       REASON: - Added commands.h, skill.h, clientmanager.h\r
+    MODIFIED: 23 Dec 2005 bakkdoor\r
+       REASON: - Added <csignal> for main.cpp -> catch strg-c and shutdown nicely\r
+    MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added mysql.h, sql.h for MySQL support\r
+    MODIFIED: 01 Jan 2006 Namikon\r
+       REASON: - Moved skill.h before chars.h (char.h needs skill.h now)\r
+    MODIFIED: 30 May 2006 Namikon\r
+       REASON: - Removed all useless includes to complete the server splitup; Also renamed tinns.h to main.h\r
+    MODIFIED: 6 Jul 2006 Hammag\r
+         REASON: - moved include "types.h" before include "../netcode/main.h" to permit compile\r
+    MODIFIED: 10 Jul 2006 Hammag\r
+         REASON: - added inventory.h\r
+         REASON: - added item.h\r
+\r
+    MODIFIED: 26 Aug 2006 Hammag\r
+         REASON: - splitted from main.h, keeping external includes in this single file\r
+                   for all source tree\r
+\r
+*/\r
+\r
+#ifndef EXTERNAL_H\r
+#define EXTERNAL_H\r
+\r
+#include <cstdio>\r
+#include <ctime>\r
+#include <cstring>\r
+#include <cctype>\r
+#include <fstream>\r
+#include <vector>\r
+#include <string>\r
+#include <sstream>\r
+#include <map>\r
+#include <list>\r
+#include <queue>\r
+#include <unistd.h>\r
+#include <iostream>\r
+#include <stdarg.h>\r
+#include <string.h>\r
+#include <zlib.h>\r
+#include <pthread.h>\r
+#include <semaphore.h>\r
+#include <errno.h>\r
+#include <stdlib.h>\r
+#include <csignal>\r
+#include <netdb.h>\r
+#include <fcntl.h>\r
+#include <sys/types.h>\r
+#include <algorithm> // std::transform\r
+\r
+#endif\r
diff --git a/server/src/include/filesystem.h b/server/src/include/filesystem.h
new file mode 100644 (file)
index 0000000..8215ed8
--- /dev/null
@@ -0,0 +1,92 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       filesystem.h\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+\r
+  MODIFIED: 08 Oct 2006 Hammag\r
+  REASON: - added ClearCache() methode to clear pak cache when .pak access is not used anymore\r
+\r
+*/\r
+\r
+#ifndef FILESYSTEM_H\r
+#define FILESYSTEM_H\r
+\r
+class PFile\r
+{\r
+       friend class PFileSystem;\r
+       private :\r
+               std::vector<u8> mBuffer;\r
+               u32 mDataSize;\r
+               u32 mDataOffs;\r
+               bool ReadData(std::FILE *F, u32 Size);\r
+               bool ReadUnpakData(std::FILE *F, u32 Size, u32 UncSize);\r
+       public :\r
+               PFile();\r
+               ~PFile();\r
+               inline bool Eof() { return mDataOffs>=mDataSize; }\r
+               int Read(void *Dest, u32 DestSize);\r
+               void Seek(u32 Offset);\r
+               std::string ReadString();\r
+               inline u32 GetSize() const { return mDataSize; }\r
+};\r
+\r
+#pragma pack(push, 1)\r
+//#pragma pack(1)\r
+struct PPakHeader\r
+{\r
+       int mID;\r
+       int mNumFiles;\r
+};\r
+\r
+struct PPakFileHeader\r
+{\r
+       int mUnknown0;\r
+       int mOffset;\r
+       int mCompressedSize;\r
+       int mUncompressedSize;\r
+       int mNameLen;   // including 0\r
+       char *mFilename;\r
+};\r
+#pragma pack(pop)\r
+\r
+class PFileSystem\r
+{\r
+       private :\r
+               typedef std::map<std::string, PPakFileHeader*> PPakFileList;\r
+               typedef std::map<std::string, PPakFileList*> PPakFiles;\r
+               PPakFiles mPaks;\r
+               PPakFileList *CachePak(const std::string &Pak, std::FILE *F);\r
+       public :\r
+               PFileSystem();\r
+               ~PFileSystem();\r
+               PFile *Open(const std::string &Package, const char *File, std::string BasePath);\r
+               bool Close(PFile *File);\r
+               void ClearCache();\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/include/message.h b/server/src/include/message.h
new file mode 100644 (file)
index 0000000..601a8e4
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+
+
+/*
+       message.h - a data message & message pool class for tcp and udp connections (and maybe more later)
+
+       Authors:
+       - Hammag
+
+       MODIFIED: 15 jul 2006 Hammag
+       REASON: - Creation
+*/
+#ifndef MESSAGE_H
+#define MESSAGE_H
+
+#define MESSAGE_SIZES_LIST 32, 64, 128, 256, 512, 1024, 4096
+#define MESSAGE_POOL_INIT NULL, NULL, NULL, NULL, NULL, NULL, NULL
+#define MESSAGE_POOL_COUNT_INIT 0, 0, 0, 0, 0, 0, 0
+#define MESSAGE_SIZES_NB 7
+#define MESSAGE_ALLOC_NB 4
+
+struct PMsgData
+{
+    PMsgData* mNextMsgData;
+    u8* mBuffer; // NB: no need to manage buffer deletion atm, as they will stay until server end
+};
+//NB: putting mPoolId & mMaxSize in PMsgData rather than PMessage would be cleaner, but would put more mem overhead on each buffer
+//    Doesn't matter much as PMsgData management is done only through PMessage
+
+class PMessage
+{
+    private:
+        static const u16 smMsgSizes[MESSAGE_SIZES_NB];
+        static PMsgData* smMsgPoolHead[MESSAGE_SIZES_NB];
+        static int smMsgPoolCount[MESSAGE_SIZES_NB];
+        static int smMsgCount; //Used to trace unreleased messages with CheckMsgCount()
+
+        u8 mPoolId;
+        u16 mMaxSize;
+        PMsgData* mData;
+        u16 mUsedSize;
+        u16 mNextByteOffset;
+
+        void GetMsgBuffer(u16 nRequestedSize = 0); // the requested size is just a hint to avoid internal reaffectation of buffer
+        void ReleaseMsgBuffer();
+        void CheckAndExtend(u16 nRequestedSize);  // This is SIZE checked, not max OFFSET
+        inline void UpdateUsedSize() { if (mNextByteOffset > mUsedSize) mUsedSize = mNextByteOffset; }
+
+    public:
+        static void CheckMsgCount(); //To be used in a place where no new message should remain between calls
+
+        PMessage(u16 nRequestedSize = 0); // max size will be extended as needed in later write accesses (up to max configured size)
+        PMessage(PMessage& nMessage); // creates a (size optimized, offset reset) copy of nMessage
+        inline ~PMessage() { ReleaseMsgBuffer(); --smMsgCount; }
+
+        void SetNextByteOffset(u16 nPos);
+        inline void IncreaseNextByteOffset(u16 nIncrement) { SetNextByteOffset(mNextByteOffset + nIncrement); }
+        inline void SetNextByteAtEnd() { mNextByteOffset = mUsedSize; }
+        inline u16 GetNextByteOffset() { return mNextByteOffset; }
+        void ForceSize(u16 nUsedSize);
+        inline u16 GetSize() { return mUsedSize; }
+        inline u16 GetMaxSize() { return mMaxSize; }
+        inline bool EOM() {return (mNextByteOffset >= mUsedSize);} // End Of Message
+
+      // Writing methods
+        u8* GetMessageDataPointer(u16 nUsedSize); // extends buffer as needed by nUsedSize, and sets UsedSize at min nUsedSize
+        PMessage& Fill(u8 Value = 0, u16 StartOffset = 0, u16 FillSize = 0); // !!! Does NOT update UsedSize, fills only up to current maxSize
+        inline PMessage& Reset() { mNextByteOffset = mUsedSize = 0; return *this; }
+        inline PMessage& Clear() { return this->Fill(0).Reset(); }
+        PMessage& Write(const void* nData, u16 nLength);
+        PMessage& operator << (PMessage& nMessage);
+        PMessage& operator << (const char* nString); //for null terminated string ! Copies includes ending \0
+        inline PMessage& operator << (std::string& nString) { return (*this << nString.c_str()); }
+        PMessage& operator << (u8 nU8);
+        inline PMessage& operator << (char nChar) { return (*this << (u8) nChar);}
+        PMessage& operator << (u16 nU16);
+        PMessage& operator << (u32 nU32);
+        PMessage& operator << (f32 nF32);
+
+      // Mixt methods
+
+        //The next 3 methods do NOT update NextByteOffset, but DO increase message size (UsedSize ans MaxSize) as needed by nOffset.
+        u8& U8Data(u16 nOffset);
+        u16& U16Data(u16 nOffset);
+        u32& U32Data(u16 nOffset);
+        f32& F32Data(u16 nOffset);
+
+        //     *** didn't managed to overload [] operator :-/
+        inline u8& operator [] (u16 nOffset) { return U8Data(nOffset); }
+        //inline u16& operator [] (u16 nOffset) { return U16Data(nOffset); }
+        //u32& operator [] (u16 nOffset);
+
+        // Really makes a different message instance, with all data copied (no data shared)
+        PMessage& operator = (PMessage& nMessage);
+
+      // Reading methods
+        // ChunkNumber count from 0, return NULL for empty chunk (ie StartOffset is over UsedSize). NextByteOffset NOT updated
+        PMessage* GetChunk(u16 StartOffset, u16 ChunkSize, u16 ChunkNumber = 0);
+
+        // Return pointer to the START of message data.
+        inline u8 const* GetMessageData() { return mData->mBuffer; }
+
+        //Following methods do NOT extend message or Used, and return 0/empty string if over UsedSize
+        PMessage& operator >> (std::string& nString); //read up to null or EOM
+        PMessage& operator >> (u8& nU8);
+        inline PMessage& operator >> (char& nChar) { return (*this >> (u8&) nChar);}
+        PMessage& operator >> (u16& nU16);
+        PMessage& operator >> (u32& nU32);
+        PMessage& operator >> (f32& nF32);
+
+        // info/debug methods
+        static void ListPools();
+        static void DumpPools();
+        void Dump();
+        void DumpHead(char* nComment = "");
+};
+
+#endif
diff --git a/server/src/include/misc.h b/server/src/include/misc.h
new file mode 100644 (file)
index 0000000..bfe52e5
--- /dev/null
@@ -0,0 +1,69 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       misc.h\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+       MODIFIED: 07 Jan 2006 Namikon\r
+       REASON: - Added function to trim a string/char\r
+       MODIFIED: 27 Aug 2006 Hammag\r
+       REASON: - Merged misc function from all 3 servers\r
+       MODIFIED: 11 Dec 2006 Hammag\r
+       REASON: - Commented out GetSVNRev() that is not used anymore\r
+*/\r
+\r
+#ifndef MISC_H\r
+#define MISC_H\r
+\r
+#ifdef _MSC_VER\r
+       #pragma once\r
+#endif\r
+\r
+u32 IPStringToDWord(const char *IP);\r
+char *IPlongToString(const u32 IP);\r
+std::string GetAccessString(int level);\r
+//void GetSVNRev(char *version);\r
+\r
+void PrintPacket(u8 *Packet, int PacketSize);\r
+\r
+// Cleanup for strings read from .def\r
+void CleanUpString(std::string *nString);\r
+void Trim(char *t);\r
+void Trim(std::string *stString);\r
+void RTrim(char *t);\r
+void RTrim(std::string *stString);\r
+void LTrim(char *t);\r
+void LTrim(std::string *stString);\r
+std::string &Ssprintf(const char *fmt, ...);\r
+\r
+u16 DistanceApprox(const u16 x1, const u16 y1, const u16 z1, const u16 x2, const u16 y2, const u16 z2);\r
+f32 Distance(const f32 x1, const f32 y1, const f32 z1, const f32 x2, const f32 y2, const f32 z2);\r
+f32 Distance(const f32 x1, const f32 y1, const f32 x2, const f32 y2); // 2D only version\r
+\r
+void InitRandom(u32 nInitialisationValue);\r
+u16 GetRandom(u16 MaxVal, u16 MinVal = 0); // u16 value between MinVal and MaxVal (inclusive) with max range 32768\r
+f32 GetRandomFloat(); // f32 value between 0 and 1\r
+#endif\r
+\r
diff --git a/server/src/include/netcode.h b/server/src/include/netcode.h
new file mode 100644 (file)
index 0000000..3817f8d
--- /dev/null
@@ -0,0 +1,34 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+#ifndef NETCODE_H\r
+#define NETCODE_H\r
+\r
+#include <sys/socket.h>\r
+#include <netinet/in.h>\r
+#include <arpa/inet.h>\r
+#include "message.h"\r
+#include "connection-tcp.h"\r
+#include "connection-udp.h"\r
+#include "serversocket.h"\r
+\r
+#endif\r
+\r
diff --git a/server/src/include/regex++.h b/server/src/include/regex++.h
new file mode 100755 (executable)
index 0000000..cef75aa
--- /dev/null
@@ -0,0 +1,103 @@
+//
+// regex.h 1.0 Copyright (c) 2003 Peter Petersen (pp@on-time.de)
+// Simple C++ wrapper for PCRE
+//
+// This source file is freeware. You may use it for any purpose without
+// restriction except that the copyright notice as the top of this file as
+// well as this paragraph may not be removed or altered.
+//
+// This header file declares class RegEx, a simple and small API wrapper
+// for PCRE.
+//
+// RegEx::RegEx(const char * regex, int options = 0)
+//
+//    The constructor's first parameter is the regular expression the
+//    created object shall implement. Optional parameter options can be
+//    any combination of PCRE options accepted by pcre_compile(). If
+//    compiling the regular expression fails, an error message string is
+//    thrown as an exception.
+//
+// RegEx::~RegEx()
+//
+//    The destructor frees all resources held by the RegEx object.
+//
+// int RegEx::SubStrings(void) const
+//
+//    Method SubStrings() returns the number of substrings defined by
+//    the regular expression. The match of the entire expression is also
+//    considered a substring, so the return value will always be >= 1.
+//
+// bool RegEx::Search(const char * subject, int len = -1, int options = 0)
+//
+//    Method Search() applies the regular expression to parameter subject.
+//    Optional parameter len can be used to pass the subject's length to
+//    Search(). If not specified (or less than 0), strlen() is used
+//    internally to determine the length. Parameter options can contain
+//    any combination of options PCRE_ANCHORED, PCRE_NOTBOL, PCRE_NOTEOL.
+//    PCRE_NOTEMPTY. Search() returns true if a match is found.
+//
+// bool RegEx::SearchAgain(int options = 0)
+//
+//    SearchAgain() again applies the regular expression to parameter
+//    subject last passed to a successful call of Search(). It returns
+//    true if a further match is found. Subsequent calls to SearchAgain()
+//    will find all matches in subject. Example:
+//
+//       if (Pattern.Search(astring)) {
+//          do {
+//             printf("%s\n", Pattern.Match());
+//          } while (Pattern.SearchAgain());
+//       }
+//
+//    Parameter options is interpreted as for method Search().
+//
+// const char * RegEx::Match(int i = 1)
+//
+//    Method Match() returns a pointer to the matched substring specified
+//    with parameter i. Match() may only be called after a successful
+//    call to Search() or SearchAgain() and applies to that last
+//    Search()/SearchAgain() call. Parameter i must be less than
+//    SubStrings(). Match(-1) returns the last searched subject.
+//    Match(0) returns the match of the complete regular expression.
+//    Match(1) returns $1, etc.
+//
+// See man pcre & man pcrepattern for more info
+
+#ifndef _REGEX_H
+#define _REGEX_H
+
+#include <string.h>
+
+#ifndef _PCRE_H
+#include "pcre.h"
+#endif
+
+class RegEx
+{
+   private:
+      pcre * re;
+      pcre_extra * pe;
+      int substrcount;
+      int * ovector;
+      const char * lastsubject;
+      int slen;
+      const char * * matchlist;
+      
+      inline void ClearMatchList(void)
+      {
+         if (matchlist)
+            pcre_free_substring_list(matchlist),
+            matchlist = NULL;
+      }
+
+   public:
+      RegEx(const char * regex, int options = 0);
+      ~RegEx();
+      inline int SubStrings(void) const { return substrcount; }
+      bool Search(const char * subject, int len = -1, int options = 0);
+      bool SearchAgain(int options = 0);
+      const char * Match(int i = 1);
+
+};
+
+#endif // _REGEX_H
diff --git a/server/src/include/serversocket.h b/server/src/include/serversocket.h
new file mode 100644 (file)
index 0000000..161ad68
--- /dev/null
@@ -0,0 +1,88 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       serversocket.h - a serversocket class managing all connections (udp/tcp)\r
+\r
+       Authors:\r
+       - bakkdoor\r
+\r
+       MODIFIED: 09 Feb 2006 bakkdoor\r
+       REASON: - introduced\r
+       \r
+  MODIFIED: 01 Jul 2006 hammag\r
+       REASON: - added settimeout method\r
+       REASON: - added fd_set m_MainSetUDP private member\r
+       REASON: - added fd_set m_MainSetGlobal private member (=m_MainSetTCP + m_MainSetUDP)\r
+\r
+  MODIFIED: 05 Aug 2006 hammag\r
+       REASON: - server UDP port is now taken in the range [gameserver_udpport_min, gameserver_udpport_max] set in config\r
+               - removed m_LastUDPPort which is not used anymore (might be used again in futur for faster free udp port allocation)\r
+\r
+*/\r
+\r
+#ifndef SERVERSOCKET_H\r
+#define SERVERSOCKET_H\r
+\r
+//class Connection; // removed... this class doesn't exist\r
+\r
+class ServerSocket\r
+{\r
+    private:\r
+            fd_set              m_MainSetTCP; // master file descriptor list for tcp-connections\r
+            fd_set              m_ReadSetTCP; // temp file descriptor list for select() for tcp-connections\r
+            fd_set              m_MainSetUDP; // master file descriptor list for udp-connections\r
+            fd_set              m_MainSetGlobal; // master file descriptor list for udp+tcp connections\r
+\r
+            struct sockaddr_in  m_ServerAddr; // server address\r
+\r
+            int                 m_ListenerTCP; // listening socket descriptor\r
+\r
+            int                 m_FdMaxTCP; // highest current file-descriptor (tcp)\r
+            int                 m_FdMaxUDP; // highest current file-descriptor (udp)\r
+\r
+            bool                m_bNewTCPConnection;\r
+\r
+            //int                 m_LastUDPPort; // not used anymore\r
+\r
+            struct timeval      m_TimeOut;\r
+\r
+    public:\r
+            ServerSocket();\r
+            ~ServerSocket();\r
+\r
+            void                settimeout(long timeout_sec, long timeout_usec);\r
+            bool                open(int port);\r
+            void                update();\r
+            bool                newConnection();\r
+            ConnectionTCP*      getTCPConnection();\r
+            ConnectionUDP*      getUDPConnection(long remoteadress, int remoteport);\r
+\r
+            bool                isDataAvailable(int sockfd);\r
+\r
+            void                delSocketFromSet(int sockfd);\r
+\r
+            void                closeServer();\r
+};\r
+\r
+#endif\r
diff --git a/server/src/include/svnrevision.h b/server/src/include/svnrevision.h
new file mode 100644 (file)
index 0000000..5567e77
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       Copyright (C) 2005 Linux Addicted Community
+       maintainer Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+/*
+       THIS FILE IS GENERATED BY THE MAKE COMMAND make svnrev
+       It is to be updated by this command before each revision commit operation
+       PLEASE DON'T MODIFY BY HAND
+*/
+
+#ifndef SVN_REV_DEF
+#define SVN_REV_DEF
+
+#define TINNS_SVN_REVISION "133"
+
+#endif
+
diff --git a/server/src/include/tinns_mutex.h b/server/src/include/tinns_mutex.h
new file mode 100644 (file)
index 0000000..4c8bc8b
--- /dev/null
@@ -0,0 +1,73 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       mutex.h - part of a C++ thread model using the POSIX way\r
+\r
+       MODIFIED: 26 Sep 2005 Akiko\r
+       REASON: - started the implementaion of a thread model\r
+*/\r
+\r
+\r
+#ifndef MUTEX_H\r
+#define MUTEX_H\r
+\r
+//this class needs pthread.h, but it should come from tinns.h\r
+\r
+class Mutex {\r
+       private:\r
+               mutable pthread_mutex_t mut;\r
+               void operator = (Mutex &mut) {\r
+               }\r
+               Mutex(const Mutex &mut) {\r
+               }\r
+\r
+       public:\r
+               Mutex() {\r
+                       pthread_mutexattr_t attr;\r
+                       pthread_mutexattr_init(&attr);\r
+                       pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);\r
+                       pthread_mutex_init(&mut, &attr);\r
+                       pthread_mutexattr_destroy(&attr);\r
+               }\r
+\r
+               virtual ~Mutex() {\r
+                       pthread_mutex_unlock(&mut);\r
+                       pthread_mutex_destroy(&mut);\r
+               }\r
+\r
+               int Lock() const {\r
+                       return(pthread_mutex_lock(&mut));\r
+               }\r
+\r
+               int TryLock() const {\r
+                       return(pthread_mutex_trylock(&mut));\r
+               }\r
+\r
+               int Unlock() const {\r
+                       return(pthread_mutex_unlock(&mut));\r
+               }\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/include/tinns_semaphore.h b/server/src/include/tinns_semaphore.h
new file mode 100644 (file)
index 0000000..735b81d
--- /dev/null
@@ -0,0 +1,77 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       semaphore.h - part of the C++ threading model (an very efficently way\r
+                     of dealing with threads) - also a POSIX way\r
+\r
+       MODIFIED: 26 Sep 2005 Akiko\r
+       REASON: - started threading model\r
+*/\r
+\r
+#ifndef SEMAPHORE_H\r
+#define SEMAPHORE_H\r
+\r
+//this class uses semaphore.h, but it should come from tinns.h\r
+\r
+class Semaphore {\r
+       private:\r
+               sem_t sem;\r
+       \r
+       public:\r
+               Semaphore(int init = 0) {\r
+                       sem_init(&sem, 0, init);\r
+               }\r
+\r
+               virtual ~Semaphore() {\r
+                       sem_destroy(&sem);\r
+               }\r
+\r
+               void Wait() const {\r
+                       sem_wait((sem_t *)&sem);\r
+               }\r
+\r
+               int TryWait() const {\r
+                       return(sem_trywait((sem_t *)&sem) ? errno : 0);\r
+               }\r
+\r
+               int Post() const {\r
+                       return(sem_post((sem_t *)&sem) ? errno : 0);\r
+               }\r
+\r
+               int GetValue() const {\r
+                       int val = -1;\r
+\r
+                       sem_getvalue((sem_t *)&sem, &val);\r
+\r
+                       return(val);\r
+               }\r
+\r
+               void Reset(int init = 0) {\r
+                       sem_destroy(&sem);\r
+                       sem_init(&sem, 0, init);\r
+               }\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/include/tinns_thread.h b/server/src/include/tinns_thread.h
new file mode 100644 (file)
index 0000000..5b40ee7
--- /dev/null
@@ -0,0 +1,262 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       thread.h - main class of a C++ thread model using the POSIX way\r
+\r
+       MODIFIED: 26 Sep 2005 Akiko\r
+       REASON: - started the implementaion of a thread model\r
+       MODIFIED: 28 Sep 2005 Akiko\r
+       REASON: - fixed the issue with gxx 3.4.3 and gcc 4.x\r
+*/\r
+\r
+\r
+#ifndef THREAD_H\r
+#define THREAD_H\r
+\r
+//this class needs mutex.h, semaphore.h and pthread.h, but it should all come\r
+//from tinns.h\r
+\r
+#define INVALID_HANDLE 0\r
+\r
+typedef void *(*pthread_fn)(void*);\r
+\r
+template <typename Thread_T>\r
+class Thread {\r
+       private:\r
+               typedef struct Instance;\r
+\r
+       public:\r
+               typedef Thread_T &Thread_;\r
+               typedef const Thread_T &Thread__;\r
+               typedef pthread_t Handle;\r
+               typedef void (*Handler)(Thread_);\r
+\r
+       protected:\r
+               Thread() {\r
+               }\r
+\r
+               virtual void ThreadMain(Thread_) = 0;\r
+\r
+               static void Exit() {\r
+                       pthread_exit(0);\r
+               }\r
+\r
+               static void TestCancel() {\r
+                       pthread_testcancel();\r
+               }\r
+\r
+               static Handle Self() {\r
+                       return(Handle)pthread_self();\r
+               }\r
+\r
+       public:\r
+               static int Create(const Handler &Func, Thread__ Param, Handle *const &H = 0,\r
+                                 const bool &CreateDetached = false, const unsigned int &StackSize = 0,\r
+                                 const bool &CancelEnable = false, const bool &CancelAsync = false) {\r
+                       M_Create().Lock();\r
+                       pthread_attr_t attr;\r
+                       pthread_attr_init(&attr);\r
+\r
+                       if(CreateDetached)\r
+                               pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);\r
+\r
+                       if(StackSize)\r
+                               pthread_attr_setstacksize(&attr, StackSize);\r
+\r
+                       Instance I(Param, 0, Func, CancelEnable, CancelAsync);\r
+\r
+                       Handle h = INVALID_HANDLE;\r
+                       int run = pthread_create((pthread_t *)&h, &attr, (pthread_fn)ThreadMainHandler, (void *)&I);\r
+\r
+                       pthread_attr_destroy(&attr);\r
+\r
+                       if(H)\r
+                               *H = h;\r
+                       if(!run)\r
+                               S_Create().Wait();\r
+\r
+                       M_Create().Unlock();\r
+\r
+                       return(errno);\r
+               }\r
+\r
+               int Create(Thread__ Param, Handle *const &H = 0, const bool &CreateDetached = false,\r
+                          const unsigned int &StackSize = 0, const bool &CancelEnable = false,\r
+                          const bool &CancelAsync = false ) const {\r
+                       M_Create().Lock();\r
+                       pthread_attr_t attr;\r
+                       pthread_attr_init(&attr);\r
+\r
+                       if(CreateDetached)\r
+                               pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);\r
+\r
+                       if(StackSize)\r
+                               pthread_attr_setstacksize(&attr, StackSize);\r
+\r
+                       Instance I(Param, const_cast<Thread *>(this), 0, CancelEnable, CancelAsync);\r
+\r
+                       Handle h = INVALID_HANDLE;\r
+                       int run = pthread_create((pthread_t *)&h, &attr, (pthread_fn)ThreadMainHandler, (void *)&I);\r
+\r
+                       pthread_attr_destroy(&attr);\r
+\r
+                       if(H)\r
+                               *H = h;\r
+                       if(!run)\r
+                               S_Create().Wait();\r
+\r
+                       M_Create().Unlock();\r
+\r
+                       return(errno);\r
+               }\r
+\r
+               static int Join(Handle H) {\r
+                       return(pthread_join(H, 0));\r
+               }\r
+\r
+               static int Kill(Handle H) {\r
+                       return(pthread_cancel(H));\r
+               }\r
+\r
+               static int Detach(Handle H) {\r
+                       return(pthread_detach(H));\r
+               }\r
+\r
+       private:\r
+               static const Mutex &M_Create() {\r
+                       static Mutex M;\r
+\r
+                       return(M);\r
+               }\r
+\r
+               static const Semaphore &S_Create() {\r
+                       static Semaphore S;\r
+\r
+                       return(S);\r
+               }\r
+\r
+               static void ThreadMainHandler(Instance *Param) {\r
+                       Instance I(*Param);\r
+                       Thread_T Data(I.Data);\r
+\r
+                       S_Create().Post();\r
+\r
+                       if(I.Flags & 1) {\r
+                               pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);\r
+\r
+                               if(I.Flags & 2)\r
+                                       pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);\r
+                               else\r
+                                       pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);\r
+                       }\r
+                       else\r
+                               pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);\r
+\r
+                       if(I.Owner)\r
+                               I.Owner->ThreadMain(Data);\r
+                       else\r
+                               I.pFN(Data);\r
+\r
+                       return(0);\r
+               }\r
+\r
+               struct Instance {\r
+                       Instance(Thread__ P, Thread<Thread_T> *const &O, const Thread<Thread_T>::Handler &pH = 0,\r
+                                const bool &CE = false, const bool &CA = false) : Data(P), Owner(O), pFN(pH),\r
+                                Flags(0) {\r
+                               if(CE)\r
+                                       Flags |= 1;\r
+                               if(CA)\r
+                                       Flags |= 2;\r
+                       }\r
+\r
+                       Thread__ Data;\r
+                       Thread<Thread_T> *Owner;\r
+                       Handler pFN;\r
+                       unsigned char Flags;\r
+               };\r
+};\r
+\r
+/*\r
+       implementation without thread parameters\r
+*/\r
+\r
+/*template <>\r
+class Thread<void> {\r
+       private:\r
+               typedef struct Instance;\r
+\r
+       public:\r
+               typedef pthread_t Handle;\r
+               typedef void (*Handler)();\r
+\r
+       protected:\r
+               Thread<void>() {\r
+               }\r
+\r
+               virtual void ThreadMain() = 0;\r
+\r
+               static void Exit() {\r
+                       pthread_exit(0);\r
+               }\r
+\r
+               static void TextCancel() {\r
+                       pthread_testcancel();\r
+               }\r
+\r
+               static Handle Self() {\r
+                       return((Handle)pthread_self());\r
+               }\r
+\r
+       public:\r
+               static int Create(const Handler &Func, Handle *const &H = 0, const bool &CreateDetached = false,\r
+                                 const unsigned int &StackSize = 0, const bool &CancelEnable = false,\r
+                                 const bool &CancelAsync = false) {\r
+                       M_Create().Locl();\r
+                       pthread_attr_t attr;\r
+                       pthread_attr_init(&attr);\r
+\r
+                       if(CreateDetached)\r
+                               pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);\r
+\r
+                       if(StackSize)\r
+                               pthread_attr_setstacksize(&attr, StackSize);\r
+\r
+                       Instance I(0, Func, CancelEnable, CancelAsync);\r
+\r
+                       int run = pthread_create((pthread_t *)H, &attr, ThreadMainHandler, (void *)&I);\r
+                       pthread_attr_destroy(&attr);\r
+\r
+                       if(!run)\r
+                               S_Create().Wait();\r
+                       else if(H)\r
+                               *H = INVALID_HANDLE;\r
+\r
+                       M_Create().Unlock();\r
+\r
+                       return(errno);\r
+               } */\r
+\r
+#endif\r
+\r
diff --git a/server/src/include/types.h b/server/src/include/types.h
new file mode 100644 (file)
index 0000000..1c26202
--- /dev/null
@@ -0,0 +1,62 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       types.h\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+*/\r
+\r
+#ifndef TYPES_H\r
+#define TYPES_H\r
+\r
+// basic type definitions\r
+\r
+#ifdef WIN32\r
+       typedef signed char s8;\r
+       typedef unsigned char u8;\r
+       typedef signed short s16;\r
+       typedef unsigned short u16;\r
+       typedef signed int s32;\r
+       typedef unsigned int u32;\r
+//     #ifdef _MSC_VER\r
+//             typedef signed __int64 s64;\r
+//             typedef unsigned __int64 u64;\r
+//     #endif  // _MSC_VER\r
+       typedef float f32;\r
+       typedef double f64;\r
+#else  // no WIN32\r
+       typedef signed char s8;\r
+       typedef unsigned char u8;\r
+       typedef signed short s16;\r
+       typedef unsigned short u16;\r
+       typedef signed int s32;\r
+       typedef unsigned int u32;\r
+       //typedef signed int64 s64;\r
+       //typedef unsigned int64 u64;\r
+       typedef float f32;\r
+       typedef double f64;\r
+#endif // LINUX\r
+\r
+#endif\r
diff --git a/server/src/include/version.h b/server/src/include/version.h
new file mode 100644 (file)
index 0000000..79d0654
--- /dev/null
@@ -0,0 +1,32 @@
+/*\r
+    TinNS (TinNS is not a Neocron Server)\r
+    Copyright (C) 2005 Linux Addicted Community\r
+    maintainer Akiko <akiko@gmx.org>\r
+\r
+    This program is free software; you can redistribute it and/or\r
+    modify it under the terms of the GNU General Public License\r
+    as published by the Free Software Foundation; either version 2\r
+    of the License, or (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+    02110-1301, USA.\r
+*/\r
+\r
+#ifndef VERSION_H\r
+#define VERSION_H\r
+\r
+#include "svnrevision.h"\r
+\r
+#define TINNS_PATCH_VERSION "0.0.2 Dev"\r
+#define TINNS_INFO_VERSION "0.0.2 Dev"\r
+#define TINNS_GAME_VERSION "0.1.38 Dev"\r
+\r
+#endif\r
+\r
diff --git a/server/src/info/Makefile b/server/src/info/Makefile
new file mode 100644 (file)
index 0000000..0055f21
--- /dev/null
@@ -0,0 +1,84 @@
+#
+# TinNS per-directory Makefile
+#
+# Adapted by Hammag from the Makefile system for Linux kernel.
+#
+# 14 Sep 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+# 
+
+######################################################
+# Target for this directory and its sub-dirs
+######################################################
+# Case 1 : target is an executable named as defined
+B_TARGET := infoserver 
+
+# Case 2 : target is a TinNS lib name
+#  (use short name, as in -l linker option) 
+#L_TARGET := tinns
+
+# Case 3 (usual): objects shall be made available to the parent dir
+#  The following line will set that automatically 
+# (Should match dir name + .o suffix)
+#O_TARGET := $(addsuffix .o,$(notdir $(shell /bin/pwd)))
+# Manualy define this only if you need to force the compiled obj name
+#O_TARGET := game.o
+
+
+######################################################
+# Local flags
+######################################################
+# local dir CXX Flags
+EXTRA_CXXFLAGS := -I/usr/include/mysql
+
+# per-object CXX Flags
+#CXXFLAGS_funcdef2.o := -O0 -ggdb
+
+# local dir Linker Flags (for intermediate .o linking)
+#EXTRA_LDFLAGS := 
+
+# any tinns Lib used (short name, as in -l linker option)
+LINK_TINNSLIBS := tinns
+
+# local dir Linker Flags (for final executable linking)
+#EXTRA_LINKFLAGS := -lpthread -lm -lcrypt -L"/usr/lib/mysql" -lmysqlclient -lz
+EXTRA_LINKFLAGS := -L"/usr/lib/mysql" -lmysqlclient -lz -lpcre
+
+
+#####################################################
+# Subdirectories
+#####################################################
+#subdir-y := def 
+#subdir-$(CONFIG_GAMEMONKEY)   += gamemonkey
+
+
+#####################################################
+#***************************************************#
+# No further config should be needed after this line
+#***************************************************#
+ifdef TOPDIR
+
+# build list of objects ib loca ldir
+obj-y := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
+# add final object from each subdir
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+
+include $(TOPDIR)/Rules.make
+
+else #TOPDIR undef, Makefile called from non-top dir
+
+# Memorize the first calling dir in case we wanted to
+# lauch local actions from top Makefile
+  ifndef FIRSTDIR
+    FIRSTDIR :=$(CURDIR)
+    export FIRSTDIR
+  endif
+
+uptoparent : 
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+.DEFAULT :
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+endif #TOPDIR
+
diff --git a/server/src/info/accounts.cpp b/server/src/info/accounts.cpp
new file mode 100644 (file)
index 0000000..0a0e89b
--- /dev/null
@@ -0,0 +1,423 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       accounts.cpp\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+       MODIFIED: 26 Dec 2005 Namikon\r
+       REASON: - Added SQLLoad to PAccounts. First step in adding MySQL support to accounts\r
+       MODIFIED: 01 Jan 2006 Namikon\r
+       REASON: - Changed FmtTxt() to sprintf(). It does... uhm, the same :D\r
+       MODIFIED: 06 Jan 2006 Namikon\r
+       REASON: - Removed the old XML loading functions, and changed the SQL ones to work with the Global Neopolis/TinNS Database\r
+          - Added SetBannedStatus(<unix timestamp>) to ban/unban an account (use SetBannedStatus(0) to unban a player)\r
+       MODIFIED: 03 Oct 2006 Hammag\r
+       REASON: - Fixed an issue in PAccount::SetBannedStatus() that was causing the "can't update banned status" error message.\r
+       MODIFIED: 27 May 2007 Hammag\r
+       REASON: - Full changes for on-demand account access (no more memory-resident account data)\r
+\r
+\r
+       MODIFIED: 2 Feb 2008 Hammag\r
+       REASON: - Correction of the account creation/update SQL query (thank to drhawk ;) )\r
+*/\r
+\r
+\r
+/*\r
+NOTE ABOUT ACCESS LEVELS IN THE MYSQL DATABASE:\r
+a_priv:\r
+0 = unregistered user\r
+1 = Registered user\r
+30 = volunteer\r
+50 = GM\r
+100 = Admin\r
+\r
+a_status:\r
+0 = Offline\r
+1 = Online\r
+2 = Banned\r
+*/\r
+#include "main.h"\r
+#include "accounts.h"\r
+\r
+/** Static members **/\r
+RegEx* PAccount::mUsernameRegexFilter = NULL;\r
+RegEx* PAccount::mPasswordRegexFilter = NULL;\r
+\r
+bool PAccount::SetUsernameRegexFilter(const char* RegexStr)\r
+{\r
+  if(mUsernameRegexFilter)\r
+  {\r
+    delete mUsernameRegexFilter;\r
+    mUsernameRegexFilter = NULL;\r
+  }\r
+\r
+  if(RegexStr)\r
+  {\r
+    try {\r
+      mUsernameRegexFilter = new RegEx(RegexStr, PCRE_CASELESS);\r
+    }\r
+    catch (...) {\r
+      return false;\r
+    }\r
+  }\r
+  return true;\r
+}\r
+\r
+bool PAccount::SetPasswordRegexFilter(const char* RegexStr)\r
+{\r
+  if(mPasswordRegexFilter)\r
+  {\r
+    delete mPasswordRegexFilter;\r
+    mPasswordRegexFilter = NULL;\r
+  }\r
+\r
+  if(RegexStr)\r
+  {\r
+    try {\r
+      mPasswordRegexFilter = new RegEx(RegexStr, PCRE_CASELESS);\r
+    }\r
+    catch (...) {\r
+      return false;\r
+    }\r
+  }\r
+  return true;\r
+}\r
+\r
+bool PAccount::IsUsernameWellFormed(const char *Username)\r
+{\r
+  if(mUsernameRegexFilter)\r
+  {\r
+    return mUsernameRegexFilter->Search(Username);\r
+  }\r
+  else\r
+    return true;\r
+}\r
+\r
+bool PAccount::IsPasswordWellFormed(const char *Password)\r
+{\r
+  if(mPasswordRegexFilter)\r
+  {\r
+    return mPasswordRegexFilter->Search(Password);\r
+  }\r
+  else\r
+    return true;\r
+}\r
+\r
+/** Instance members **/\r
+PAccount::PAccount()\r
+{\r
+       mID = 0;\r
+       mLevel = PAL_BANNED;\r
+  mStatus = PAS_OFFLINE;\r
+  mBannedUntil = 0;\r
+}\r
+\r
+PAccount::PAccount(const u32 AccountId)\r
+{\r
+  char query[256];\r
+  mID = 0;\r
+  snprintf(query, 256, "SELECT * FROM accounts WHERE a_id = %d LIMIT 1;", AccountId);\r
+  LoadFromQuery(query);\r
+}\r
+\r
+PAccount::PAccount(const char *Username)\r
+{\r
+  char query[256];\r
+  mID = 0;\r
+  if(IsUsernameWellFormed(Username)) {\r
+    char escUsername[256];\r
+    MySQL->EscapeString(Username, escUsername, 256);\r
+    snprintf(query, 256, "SELECT * FROM accounts WHERE a_username = '%s' LIMIT 1;", escUsername);\r
+    LoadFromQuery(query);\r
+  }\r
+}\r
+\r
+bool PAccount::LoadFromQuery(char* query)\r
+{\r
+  MYSQL_ROW row = 0;\r
+  MYSQL_RES *result = 0;\r
+\r
+  bool FinalResult = false;\r
+\r
+  //result = MySQL->InfoResQuery(query);\r
+  result = MySQL->ResQuery(query);\r
+  if(result == NULL)\r
+  {\r
+      Console->Print(RED, BLACK, "Failed to load AccountData from SQL");\r
+      //MySQL->ShowInfoSQLError();\r
+      MySQL->ShowSQLError();\r
+      return false;\r
+  }\r
+\r
+  if((row = mysql_fetch_row(result)))\r
+  {\r
+    mID = atoi(row[a_id]);\r
+    mName = row[a_username];\r
+    mPassword = row[a_password];\r
+\r
+    mBannedUntil = atoi(row[a_bandate]);\r
+    if(mBannedUntil > std::time(NULL))\r
+    {\r
+      mStatus = PAS_BANNED;\r
+      mLevel = PAL_BANNED;\r
+    }\r
+    else\r
+    {\r
+      mStatus = PAS_OFFLINE;\r
+      mLevel = atoi(row[a_priv]);\r
+    }\r
+\r
+    FinalResult = true;\r
+  }\r
+  else\r
+  {\r
+Console->Print(YELLOW, BLACK, "Failed to load AccountData from SQL; Nothing to load...");\r
+  }\r
+\r
+  //MySQL->FreeInfoSQLResult(result);\r
+  MySQL->FreeSQLResult(result);\r
+  return FinalResult;\r
+}\r
+\r
+bool PAccount::SetName(const std::string &Username)\r
+{\r
+  if(IsUsernameWellFormed(Username.c_str()))\r
+  {\r
+    mName = Username;\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    return false;\r
+  }\r
+}\r
+\r
+bool PAccount::SetPassword(const std::string &Password)\r
+{\r
+  if(IsPasswordWellFormed(Password.c_str()))\r
+  {\r
+    mPassword = Password;\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    return false;\r
+  }\r
+}\r
+\r
+bool PAccount::SetPasswordEncoded(const u8* PasswordData, int PassLen, const u8* Key)\r
+{\r
+       char Pass[128];\r
+\r
+       if(DecodePassword(PasswordData, PassLen, Key, Pass))\r
+  {\r
+               return SetPassword((std::string)Pass);\r
+       }\r
+       else\r
+       {\r
+               Console->Print(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen);\r
+               return false;\r
+       }\r
+}\r
+\r
+bool PAccount::SetLevel(int newLevel)\r
+{\r
+  if((newLevel >= PAL_BANNED) && (newLevel <= PAL_ADMIN))\r
+  {\r
+    mLevel = newLevel;\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    return false;\r
+  }\r
+}\r
+\r
+std::string PAccount::GetLevelString() const\r
+{\r
+       switch(mLevel)\r
+       {\r
+               case PAL_BANNED : return "banned";\r
+               case PAL_UNREGPLAYER : return "unregplayer";\r
+               case PAL_REGPLAYER : return "regplayer";\r
+               case PAL_VOLUNTEER : return "volunteer";\r
+               case PAL_GM : return "gm";\r
+               case PAL_ADMIN : return "admin";\r
+       }\r
+\r
+       return "custom";\r
+}\r
+\r
+bool PAccount::SetStatus(PAccountStatus Status)\r
+{\r
+  mStatus = Status;\r
+  return true;\r
+}\r
+\r
+bool PAccount::SetBannedUntilTime(std::time_t BannedUntil)\r
+{\r
+  if ((BannedUntil == 0) || (BannedUntil > std::time(NULL)))\r
+  {\r
+    mBannedUntil = BannedUntil;\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    return false;\r
+  }\r
+}\r
+\r
+bool PAccount::DecodePassword(const u8* PasswordData, int PassLen, const u8 *Key, char* ClearPassword)\r
+{\r
+  ClearPassword[0] = 0;\r
+\r
+  if(PassLen < 128)\r
+       {\r
+               if(Key[0]>7) // TODO: >7 correct?\r
+               {\r
+                       for(int i=0; i<PassLen; i+=2)\r
+                               ClearPassword[i>>1] = (char)(((PasswordData[i]&0xf0)>>4)\r
+                                       +((PasswordData[i+1]&0x0f)<<4)-Key[0]);\r
+                       ClearPassword[PassLen>>1]=0;\r
+               }\r
+               else\r
+               {\r
+                       for(int i=0; i<PassLen; i++)\r
+                               ClearPassword[i] = (char)(PasswordData[i]-Key[0]);\r
+                       ClearPassword[PassLen]=0;\r
+               }\r
+               return true;\r
+       }\r
+       else\r
+         return false;\r
+}\r
+\r
+bool PAccount::Authenticate(const u8* PasswordData, int PassLen, const u8 *Key)\r
+{\r
+       char Pass[128];\r
+\r
+       if(DecodePassword(PasswordData, PassLen, Key, Pass))\r
+  {\r
+               return Authenticate(Pass);\r
+       }\r
+       else\r
+       {\r
+               Console->Print(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen);\r
+               return false;\r
+       }\r
+}\r
+\r
+bool PAccount::Authenticate(const char *Password) const\r
+{\r
+       if(mID == 0) // User doesn't exist and that hasn't been checked !\r
+       {\r
+         Console->Print(RED, BLACK, "[Bug]: user %s doesn't exist and was not checked by code !", mName.c_str());\r
+         return false;\r
+       }\r
+\r
+       return(mPassword == Password);\r
+}\r
+\r
+bool PAccount::Create()\r
+{\r
+  if(Save(true)) {\r
+    //mID = MySQL->GetLastInfoInsertId();\r
+    mID = MySQL->GetLastInsertId();\r
+    return true;\r
+  }\r
+  else\r
+  {\r
+    return false;\r
+  }\r
+}\r
+\r
+bool PAccount::Save(bool CreateMode)\r
+{\r
+  char escUsername[256];\r
+  char escPassword[256];\r
+  MySQL->EscapeString(mName.c_str(), escUsername, 256);\r
+  MySQL->EscapeString(mPassword.c_str(), escPassword, 256);\r
+\r
+  std::string Query;\r
+  Query = CreateMode ? "INSERT INTO" : "UPDATE";\r
+  Query += " accounts SET ";\r
+  Query += Ssprintf(" a_username='%s', a_password = '%s'", escUsername, escPassword);\r
+  Query += Ssprintf(", a_priv = %d, a_status = %d, a_bandate = %d", mLevel, mStatus, mBannedUntil);\r
+  if(!CreateMode )\r
+  {
+      Query += Ssprintf(" a_lastused = NOW()");\r
+    Query += Ssprintf(" WHERE a_id = %d LIMIT 1", mID);\r
+  }
+  else
+    Query += Ssprintf(" a_creationdate = NOW()");
+\r
+\r
+  //if(MySQL->InfoQuery(Query.c_str()))\r
+  if(MySQL->Query(Query.c_str()))\r
+  {\r
+      Console->Print(RED, BLACK, "[Error] Failed to %s account %s (id %d)", CreateMode ? "create" : "update", mName.c_str(), mID);\r
+      //MySQL->ShowInfoSQLError();\r
+      MySQL->ShowSQLError();\r
+      return false;\r
+  }\r
+  return true;\r
+}\r
+\r
+std::string PAccount::GetBannedTime() const\r
+{\r
+  const char* unit[5] = {"seconds", "minutes", "hours", "days", "weeks"};\r
+\r
+  std::time_t timediff = mBannedUntil - std::time(NULL);\r
+  if(timediff <=0)\r
+  {\r
+    return "0 more seconds. Please relog";\r
+  }\r
+\r
+  long counter;\r
+  int type;\r
+\r
+  if(timediff > 86400)   // days\r
+  {\r
+    counter = timediff / 86400;\r
+    type = 3;\r
+  }\r
+  else if(timediff > 3600)    // hours\r
+  {\r
+    counter = timediff / 3600;\r
+    type = 2;\r
+  }\r
+  else if(timediff > 60)      // Minutes\r
+  {\r
+    counter  = timediff / 60;\r
+    type = 1;\r
+  }\r
+  else      // Seconds\r
+  {\r
+    counter = timediff;\r
+    type = 0;\r
+  }\r
+\r
+  return Ssprintf("%d more %s", counter, unit[type]);\r
+}\r
diff --git a/server/src/info/accounts.h b/server/src/info/accounts.h
new file mode 100644 (file)
index 0000000..f68c142
--- /dev/null
@@ -0,0 +1,145 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       accounts.h\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+       MODIFIED: 26 Dec 2005 Namikon\r
+       REASON: - Added load/save functions for SQL DB\r
+       MODIFIED: 01 Jan 2005 Namikon\r
+       REASON: - Added bool var for ingame debug outputs for administrators\r
+       MODIFIED: 06 Jan 2005 Namikon\r
+       REASON: - Added SetBannedStatus(<unix timestamp>) to ban/unban an account (use SetBannedStatus(0) to unban a player)\r
+*/\r
+\r
+#ifndef ACCOUNTS_H\r
+#define ACCOUNTS_H\r
+\r
+#ifdef _MSC_VER\r
+       #pragma once\r
+#endif\r
+\r
+#include "regex++.h"\r
+\r
+/*\r
+0 = unregistered user\r
+1 = Registered user\r
+30 = volunteer\r
+50 = GM\r
+100 = Admin\r
+*/\r
+\r
+// New way of AccountLevel handling:\r
+// Every level is possible, the following values are only edge values. We need a bit control about that\r
+#define PAL_BANNED -1\r
+#define PAL_UNREGPLAYER 0\r
+#define PAL_REGPLAYER 1\r
+#define PAL_VOLUNTEER 30\r
+#define PAL_GM 50\r
+#define PAL_ADMIN 100\r
+\r
+// Max number of char slots per account\r
+#define MAX_CHARS_PER_ACCOUNT  4\r
+\r
+/*\r
+0 = Offline\r
+1 = Online\r
+2 = Banned\r
+*/\r
+\r
+enum PAccountStatus\r
+{\r
+    PAS_OFFLINE = 0,\r
+    PAS_ONLINE = 1,\r
+    PAS_BANNED = 2\r
+};\r
+\r
+class PAccount\r
+{\r
+       private :\r
+    // SQL Layout\r
+    enum {\r
+        a_id,\r
+        a_username,\r
+        a_password,\r
+        a_priv,\r
+        a_status,\r
+        a_bandate,
+        a_emailaddress,
+        a_creationdate,
+        a_lastused\r
+    };\r
+\r
+    // static members\r
+         static RegEx* mUsernameRegexFilter;\r
+         static RegEx* mPasswordRegexFilter;\r
+\r
+         // instance members\r
+         u32 mID;\r
+         std::string mName;\r
+         std::string mPassword;\r
+    int mLevel;\r
+    PAccountStatus mStatus;\r
+    std::time_t mBannedUntil;\r
+\r
+    bool LoadFromQuery(char* query);\r
+    bool DecodePassword(const u8* PasswordData, int PassLen, const u8 *Key, char* ClearPassword);\r
+\r
+       public :\r
+         PAccount();\r
+         PAccount(const u32 AccountId);\r
+         PAccount(const char *Username);\r
+\r
+         static bool SetUsernameRegexFilter(const char* RegexStr);\r
+               static bool SetPasswordRegexFilter(const char* RegexStr);\r
+               static bool IsUsernameWellFormed(const char *Username);\r
+               static bool IsPasswordWellFormed(const char *Password);\r
+\r
+               inline u32 GetID() const { return mID; }\r
+               bool SetName(const std::string &Pass);\r
+               inline const std::string &GetName() const { return mName; }\r
+               bool SetPassword(const std::string &Pass);\r
+               bool SetPasswordEncoded(const u8* PasswordData, int PassLen, const u8* Key);\r
+               inline const std::string &GetPassword() const { return mPassword; }\r
+    bool SetLevel(int newLevel);\r
+               inline int GetLevel() const { return mLevel; }\r
+               std::string GetLevelString() const;\r
+    bool SetStatus(PAccountStatus Status);\r
+               inline PAccountStatus GetStatus() const { return mStatus; }\r
+               bool SetBannedUntilTime(std::time_t BannedUntil);\r
+    inline bool IsBanned() const { return (mBannedUntil > std::time(NULL)); }\r
+    std::string GetBannedTime() const;\r
+\r
+               bool Authenticate(const u8* PasswordData, int PassLen, const u8 *Key);\r
+               bool Authenticate(const char *Password) const;\r
+\r
+               bool Create();\r
+    bool Save(bool CreateMode = false);\r
+\r
+    //u32 GetCharIdBySlot(const u32 SlotId);\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/info/client.cpp b/server/src/info/client.cpp
new file mode 100644 (file)
index 0000000..8e801cc
--- /dev/null
@@ -0,0 +1,69 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+#include "main.h"\r
+\r
+PClient::PClient(int Index)\r
+{\r
+       mIndex = Index;\r
+       mConnection = PCC_NONE;\r
+       mAccountID = 0;\r
+}\r
+\r
+PClient::~PClient()\r
+{\r
+    if(m_TCPConnection)\r
+    {\r
+        delete m_TCPConnection;\r
+    }\r
+}\r
+\r
+void PClient::InfoDisconnect()\r
+{\r
+    if(m_TCPConnection)\r
+    {\r
+        delete m_TCPConnection;\r
+    }\r
+    m_TCPConnection = 0;\r
+\r
+       //mConnection &= ~PCC_INFO;\r
+       mConnection = PCC_NONE;\r
+       mAccountID = 0;\r
+}\r
+\r
+void PClient::Update()\r
+{\r
+    if(m_TCPConnection)\r
+    {\r
+        if(m_TCPConnection->timeOut())\r
+        {\r
+                Console->Print("InfoSocket: Client %i: timeout", mIndex);\r
+                InfoServer->ClientDisconnected(this);\r
+        }\r
+        else\r
+        {\r
+            if(!m_TCPConnection->update())\r
+            {\r
+                InfoServer->ClientDisconnected(this);\r
+            }\r
+        }\r
+    }\r
+}\r
diff --git a/server/src/info/client.h b/server/src/info/client.h
new file mode 100644 (file)
index 0000000..25bc05a
--- /dev/null
@@ -0,0 +1,65 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+#ifndef CLIENT_H\r
+#define CLIENT_H\r
+\r
+#ifdef _MSC_VER\r
+       #pragma once\r
+#endif\r
+\r
+enum PClientConnection\r
+{\r
+       PCC_NONE = 0,\r
+       PCC_INFO = 1\r
+};\r
+\r
+class PClient\r
+{\r
+       private :\r
+    ConnectionTCP* m_TCPConnection;\r
+               int mIndex;\r
+               int mConnection;\r
+               u32 mAccountID;\r
+\r
+       protected :\r
+       public :\r
+               PClient(int Index);\r
+               ~PClient();\r
+\r
+               inline int GetIndex() const { return mIndex; }\r
+\r
+               void setTCPConnection(ConnectionTCP* conn) { m_TCPConnection = conn; mConnection = PCC_INFO; }\r
+               inline ConnectionTCP* getTCPConn() const { return m_TCPConnection; }\r
+\r
+               inline int GetConnection() const { return mConnection; }\r
+               inline const char *GetAddress() const { return m_TCPConnection->getRemoteAddress(); }\r
+\r
+    inline void setAccountID(u32 nAccountID) { mAccountID = nAccountID; }\r
+    inline u32 getAccountID() { return mAccountID; }\r
+    \r
+               void InfoDisconnect();\r
+\r
+               void Update();\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/info/configtemplate.h b/server/src/info/configtemplate.h
new file mode 100644 (file)
index 0000000..6da034a
--- /dev/null
@@ -0,0 +1,52 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+    Configuration template for infoserver\r
+    Used to set available/optional/required options when loading config\r
+      with a PConfig object.\r
+*/\r
+\r
+const char* InfoConfigTemplate[][2] = {\r
+  // {option_name, default_value} if default_value is empty string, it means option is mandatory\r
+  // List ends with empty string for option_name\r
+  {"sql_host", "127.0.0.1"}, // should be renanmed to info_sql_host\r
+  {"sql_port", "3306"}, // should be renanmed to info_sql_port\r
+  {"sql_username", ""}, // should be renanmed to info_sql_username\r
+  {"sql_password", ""}, // should be renanmed to info_sql_password\r
+  {"global_sql_database", "infoserver"}, // should be renanmed to info_sql_database\r
+  {"mysql_wait_timeout", "28800"}, // value of the wait_timout system variable from the MySQL server (same for game & info DB atm). 0 to disable keepalive.\r
+  {"auto_accounts", "0"},\r
+  {"infoserver_port", "7000"},\r
+  {"gameserver_livecheck", "60"},\r
+  {"minlevel", "0"},\r
+  {"maxclients", "50"},\r
+  {"require_validation", "0"},\r
+  {"isc_method", "1"},\r
+  {"isc_infoserverport", "9991"},\r
+  {"isc_connect_pw", "changeme"},\r
+  {"username_filter", "^[a-z][\\w\\-]{2,14}$"},\r
+  {"password_filter", "^[[:graph:]]{3,15}$"},\r
+  \r
+// For futur use:\r
+//  {"max_chars_per_account", "4"},\r
+\r
+  {"", ""} // do not change this line (end mark)\r
+};\r
diff --git a/server/src/info/globals.cpp b/server/src/info/globals.cpp
new file mode 100644 (file)
index 0000000..c0a049e
--- /dev/null
@@ -0,0 +1,217 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+    MODIFIED: 27 Aug 2006 Hammag\r
+    REASON: - Implemented shared Config class use and config template to load conf.\r
+                Added gameserver configtemplate.h include,\r
+                Added new required parameters to Config->LoadOptions()\r
+            - Added AdditionnalConfigChecks() local function, called after config loading\r
+                taken from inital infoserver's PConfig::VerifyValues\r
+*/\r
+\r
+#include "main.h"\r
+#include "configtemplate.h"\r
+\r
+#include "version.h"\r
+const char ServerVersion[] = TINNS_INFO_VERSION;\r
+const char SVNRevision[] = TINNS_SVN_REVISION;\r
+\r
+ServerSocket* ServerSock = 0;\r
+PMySQL *MySQL = 0;\r
+PConsole *Console = 0;\r
+PServer *Server = 0;\r
+PConfig *Config = 0;\r
+PInfoServer *InfoServer = 0;\r
+//PAccounts *Accounts = 0;  // To be removed\r
+\r
+bool Init()\r
+{\r
+       Console = new PConsole("log/infoserver.log"); // Make that from config file !!!\r
+       Console->Print("Starting TinNS Infoserver");\r
+       Console->Print(WHITE, BLUE, "/-------------------------------------------------------------------\\");\r
+       Console->Print(WHITE, BLUE, "|               TinNS (TinNS is not a Neocron Server)               |");\r
+  Console->Print(WHITE, BLUE, "|            Copyright (C) 2005 Linux Addicted Community            |");\r
+       Console->Print(WHITE, BLUE, "|                  maintainer Akiko <akiko@gmx.org>                 |");\r
+       Console->Print(WHITE, BLUE, "|             ==========================================            |");\r
+       Console->Print(WHITE, BLUE, "|      Head coders:                   The packet analyzing team:    |");\r
+       Console->Print(WHITE, BLUE, "|      - Akiko                         - MaxxJag                    |");\r
+       Console->Print(WHITE, BLUE, "|      - bakkdoor                      - Sting                      |");\r
+       Console->Print(WHITE, BLUE, "|      - Namikon                       - Balm                       |");\r
+       Console->Print(WHITE, BLUE, "|      - Hammag                                                     |");\r
+       Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");\r
+       Console->Print(WHITE, BLUE, "|  This project would'nt be at its current stage without the help   |");\r
+  Console->Print(WHITE, BLUE, "|        from the NeoPolis team, special thanks to you guys!        |");\r
+       Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");\r
+       Console->Print(WHITE, BLUE, "|  This project is under GPL, see any source file for more details  |");\r
+       Console->Print(WHITE, BLUE, "\\-------------------------------------------------------------------/");\r
+\r
+       //char svnrev[10];\r
+       //GetSVNRev(svnrev);\r
+       Console->LPrint("You are running TinNS Infoserver version");\r
+       Console->LPrint(GREEN, BLACK, " %s", ServerVersion);\r
+       Console->LPrint(WHITE, BLACK, " - SVN Rev");\r
+       Console->LPrint(GREEN, BLACK, " %s", SVNRevision);\r
+       Console->LClose();\r
+       \r
+       Config = new PConfig();\r
+       if(!Config->LoadOptions(InfoConfigTemplate, "./conf/infoserver.conf"))\r
+           return false; //Shutdown();\r
+  if(!AdditionnalConfigChecks())\r
+    return false; //Shutdown();\r
+\r
+       ServerSock = new ServerSocket();\r
+       Server = new PServer();\r
+       \r
+       MySQL = new PMySQL();\r
+    if(MySQL->Connect() == false)\r
+           return false; //Shutdown();\r
+\r
+       InfoServer = new PInfoServer();\r
+       //Accounts = new PAccounts(); // To be removed\r
+\r
+       return true;\r
+}\r
+\r
+void Shutdown()\r
+{\r
+  if(Server) Server->Shutdown();\r
+       if(InfoServer) delete InfoServer;\r
+       if(MySQL) delete MySQL;\r
+       if(Config) delete Config;\r
+       if(Console) delete Console;\r
+       if(ServerSock) delete ServerSock;\r
+    exit(0);\r
+}\r
+\r
+bool AdditionnalConfigChecks()\r
+{\r
+  //NOTA: empty config values are never accepted by PConfig objects\r
+  \r
+    int numErr, numWarn;\r
+    \r
+    //std::string sqlhost = Config->GetOption("sql_host");\r
+    std::string sqlusername = Config->GetOption("sql_username");\r
+    //std::string sqlpassword = Config->GetOption("sql_password");\r
+    //std::string global_sql_database = Config->GetOption("global_sql_database");\r
+    int sqlport = Config->GetOptionInt("sql_port");\r
+    int auto_accounts = Config->GetOptionInt("auto_accounts");\r
+    int infoserver_port = Config->GetOptionInt("infoserver_port");\r
+    int gameserver_livecheck = Config->GetOptionInt("gameserver_livecheck");\r
+    int minlevel = Config->GetOptionInt("minlevel");\r
+    int maxclients = Config->GetOptionInt("maxclients");\r
+\r
+    numErr = numWarn = 0;\r
+\r
+    /*if(strcmp(sqlhost.c_str(), "") == 0)\r
+    {\r
+        Console->Print("%s sql_host is empty", Console->ColorText(RED, BLACK, "Config error:"));\r
+        numErr++;\r
+    }*/\r
+\r
+    /*if(strcmp(sqlusername.c_str(), "") == 0)\r
+    {\r
+        Console->Print("%s sql_username is empty", Console->ColorText(RED, BLACK, "Config error:"));\r
+        numErr++;\r
+    }\r
+    else*/\r
+      if(strcmp(sqlusername.c_str(), "root") ==0)\r
+    {\r
+        Console->Print("%s Config: sqlusername is \"root\", which is pretty insecure.", Console->ColorText(YELLOW, BLACK, "[Warning]"));\r
+        numWarn++;\r
+    }\r
+\r
+    /*if(strcmp(sqlpassword.c_str(), "") == 0);\r
+    {\r
+        Console->Print("%s sql_password is empty", Console->ColorText(RED, BLACK, "Config error:"));\r
+        numErr++;\r
+    }\r
+\r
+    if(strcmp(global_sql_database.c_str(), "") == 0);\r
+    {\r
+        Console->Print("%s global_sql_database is empty", Console->ColorText(RED, BLACK, "Config error:"));\r
+        numErr++;\r
+    }*/\r
+\r
+    if(sqlport < 1025 || sqlport > 65535)\r
+    {\r
+        Console->Print("%s Config: sql_port is usually between 1025 and 65535!", Console->ColorText(YELLOW, BLACK, "[Warning]"));\r
+        numWarn++;\r
+    }\r
+\r
+    if(auto_accounts != 0 && auto_accounts != 1)\r
+    {\r
+        Console->Print("%s Config: auto_accounts has to be either 0 or 1!", Console->ColorText(RED, BLACK, "[Error]"));\r
+        numErr++;\r
+    }\r
+\r
+    if(infoserver_port < 1025 || infoserver_port > 65535)\r
+    {\r
+        Console->Print("%s Config: infoserver_port has to be between 1025 and 65535!", Console->ColorText(RED, BLACK, "[Error]"));\r
+        numErr++;\r
+    }\r
+    // This assertion is wrong, as sql server and info server can be on differents computers\r
+    /*else if(infoserver_port == sqlport)\r
+    {\r
+        Console->Print("%s infoserver_port has to be different from sql_port!", Console->ColorText(RED, BLACK, "Config error:"));\r
+        numErr++;\r
+    }*/\r
+\r
+    if(gameserver_livecheck <= 0)\r
+    {\r
+        Console->Print("%s Config: gameserver_livecheck cannot equal or less than 0", Console->ColorText(RED, BLACK, "[Error]"));\r
+        numErr++;\r
+    }\r
+    else if(gameserver_livecheck < 2)\r
+    {\r
+        Console->Print("%s Config: gameserver_livecheck is pretty low, this may cause increased mysql load", Console->ColorText(YELLOW, BLACK, "[Warning]"));\r
+        numWarn++;\r
+    }\r
+    else if(gameserver_livecheck > 120 && gameserver_livecheck < 600)\r
+    {\r
+        Console->Print("%s Config: gameserver_livecheck is pretty high, this may cause offline servers shown as online and a wrong usercount", Console->ColorText(YELLOW, BLACK, "[Warning]"));\r
+        numWarn++;\r
+    }\r
+    else if(gameserver_livecheck > 600)\r
+    {\r
+        Console->Print("%s Config: gameserver_livecheck is too high. Use a value between 0 and 600", Console->ColorText(RED, BLACK, "[Error]"));\r
+        numErr++;\r
+    }\r
+\r
+    if(minlevel < 0 || minlevel > 255)\r
+    {\r
+        Console->Print("%s Config: minlevel has to be between 0 and 255", Console->ColorText(RED, BLACK, "[Error]"));\r
+        numErr++;\r
+    }\r
+    \r
+    if(maxclients < 1 )\r
+    {\r
+        Console->Print("%s Config: maxclients has to be higher or equal to 1", Console->ColorText(RED, BLACK, "[Error]"));\r
+        numErr++;\r
+    }\r
+    \r
+    if(numErr == 0 /*&& numWarn == 0*/)\r
+        return true;\r
+    else\r
+        return false;\r
+}\r
+\r
+\r
diff --git a/server/src/info/globals.h b/server/src/info/globals.h
new file mode 100644 (file)
index 0000000..649489b
--- /dev/null
@@ -0,0 +1,61 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+       globals.h\r
+\r
+       MODIFIED: 12 September 2005 Akiko\r
+       REASON: - exchanged Pretender Strings by TinNS\r
+                - removed some Windows specific code\r
+       MODIFIED: 16 Dec 2005 bakkdoor\r
+       REASON: - Added global ClientManager and Chat Interface\r
+       MODIFIED: 22 Dec 2005 Namikon\r
+       REASON: - Added GPL\r
+  MODIFIED: 27 Aug 2006 Hammag\r
+  REASON: - Added AdditionnalConfigChecks() local function\r
+\r
+*/\r
+\r
+#ifndef GLOBALS_H\r
+#define GLOBALS_H\r
+\r
+#ifdef _MSC_VER\r
+       #pragma once\r
+#endif\r
+\r
+extern class ServerSocket* ServerSock;\r
+extern class PConsole *Console;\r
+extern class PServer *Server;\r
+extern class PConfig *Config;\r
+extern class PInfoServer *InfoServer;\r
+\r
+extern class PMySQL* MySQL;\r
+//extern class PAccounts* Accounts;  // To be removed\r
+\r
+extern const char ServerVersion[];\r
+extern const char SVNRevision[];\r
+\r
+bool Init();\r
+void Shutdown();\r
+bool AdditionnalConfigChecks();\r
+\r
+#endif\r
+\r
diff --git a/server/src/info/infoserver.cpp b/server/src/info/infoserver.cpp
new file mode 100644 (file)
index 0000000..ebf6d2b
--- /dev/null
@@ -0,0 +1,608 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+/*\r
+  MODIFIED: 01 Jul 2006 hammag\r
+       REASON: - added set timeout to 10 msec (for ReadSetTCP select) in Start()\r
+                 to avoid useless 100% CPU use\r
+  MODIFIED: 27 Aug 2006 hammag\r
+       REASON: - Removed INFO_PORT use as value is available from config\r
+  MODIFIED: 27 Aug 2006 hammag\r
+       REASON: - Modified GSLiveCheck() to be independant of gameserver time (no time sync needed between servers)\r
+  MODIFIED: 27 Aug 2006 hammag\r
+       REASON: - Display the client id in Client connection message rather than the always increasing mNumClients\r
+               - Removed use of mNumClients in PInfoServer. the count is done in PServer.\r
+\r
+    ToDo:\r
+    - Take main loop timeout setting from config file\r
+*/\r
+\r
+#include "main.h"\r
+\r
+struct PInfoState\r
+{\r
+       enum State\r
+       {\r
+               IS_UNKNOWN,\r
+               IS_CONNECTED,\r
+               IS_HANDSHAKE0,\r
+               IS_AUTHENTICATE,\r
+               IS_SERVERLIST\r
+       } mState;\r
+\r
+       bool mWaitSend; // wait-for-completition flag\r
+       PInfoState()\r
+       {\r
+               mState = IS_UNKNOWN;\r
+               mWaitSend = false;\r
+       };\r
+};\r
+\r
+PInfoServer::PInfoServer()\r
+{\r
+       //mNumClients = 1;\r
+       mLivecheckInterval = Config->GetOptionInt("gameserver_livecheck");\r
+}\r
+\r
+PInfoServer::~PInfoServer()\r
+{\r
+    Console->Print("Closing Infoserver...");\r
+\r
+    ServerSock->closeServer();\r
+\r
+       for(InfoStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end(); i++)\r
+               delete i->second;\r
+}\r
+\r
+void PInfoServer::Start()\r
+{\r
+       u16 Port = Config->GetOptionInt("infoserver_port");\r
+       Console->LPrint("Starting Infoserver on port %i...", Port);\r
+\r
+       if(ServerSock->open(Port))\r
+       {\r
+           Console->LPrint(GREEN, BLACK, "Success");\r
+           Console->LClose();\r
+       }\r
+       else\r
+       {\r
+               Console->LPrint(RED, BLACK, "Failed");\r
+               Console->LClose();\r
+       }\r
+       ServerSock->settimeout(0, 10000);\r
+       GSLiveCheck();\r
+}\r
+\r
+void PInfoServer::Update()\r
+{\r
+       if(ServerSock->newConnection())\r
+       {\r
+               int clid = Server->NewClient();\r
+               if(clid!=-1)\r
+               {\r
+                       Console->Print(GREEN, BLACK, "Infoserver: client [%i] connected", clid);\r
+                       PClient *Client = Server->GetClient(clid);\r
+\r
+                       ConnectionTCP* tcpConn = ServerSock->getTCPConnection();\r
+                       Client->setTCPConnection(tcpConn);\r
+\r
+                       Console->Print("Client address: %s", Client->GetAddress());\r
+                       //++mNumClients;\r
+\r
+                       PInfoState *state = new PInfoState();\r
+                       ClientStates.insert(std::make_pair(Client, state));\r
+                       state->mState = PInfoState::IS_CONNECTED;\r
+               } else\r
+               {\r
+                       Console->Print("Infoserver: Client connection refused (server full?)");\r
+               }\r
+       }\r
+\r
+       for(InfoStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end();)\r
+       {\r
+               PClient *Client = i->first;\r
+               PInfoState *State = i->second;\r
+               // node gets erased in FinalizeClient, increment iterator now\r
+               ++i;\r
+               if(!ProcessClient(Client, State))\r
+                       FinalizeClient(Client, State);\r
+       }\r
+}\r
+\r
+void PInfoServer::GSLiveCheck()\r
+{\r
+    MYSQL_ROW row;\r
+    MYSQL_RES *result;\r
+    char query[256];\r
+    snprintf (query, 256, "SELECT *, (NOW()< (`s_lastupdate` + INTERVAL %d SECOND)) FROM `server_list`", mLivecheckInterval);\r
+\r
+    result = MySQL->ResQuery(query);\r
+    if(result == NULL)\r
+    {\r
+        Console->Print("Livecheck: %s unable to read server list!", Console->ColorText(RED, BLACK, "[Warning]"));\r
+        MySQL->ShowSQLError();\r
+        return;\r
+    }\r
+    if(mysql_num_rows(result) == 0)\r
+    {\r
+        Console->Print("Livecheck: %s no gameserver found!", Console->ColorText(RED, BLACK, "[Warning]"));\r
+        MySQL->FreeSQLResult(result);\r
+        return;\r
+    }\r
+\r
+    ServerMap::iterator it;\r
+    while((row = mysql_fetch_row(result)))\r
+    {\r
+        it = Serverlist.find(atoi(row[s_id]));\r
+        if(it != Serverlist.end())\r
+        {\r
+            strncpy(it->second.mName, row[s_name], MAX_SERVER_NAME_LENGTH);\r
+            it->second.mLanIp = IPStringToDWord(row[s_lanaddr]);
+            it->second.mWanIp = IPStringToDWord(row[s_wanaddr]);\r
+            it->second.mPort = atoi(row[s_port]);\r
+            it->second.mPlayers = atoi(row[s_players]);\r
+            /* Prepared for future addon Servers by Accesslevel */\r
+            // it->second.mMinLv = atoi(row[s_minlv]);\r
+            /* ------------------------------------------------ */\r
+\r
+            // ToDo: If statement correct? Maybe GSLiveCheck() has\r
+            // to be called every mLinvecheckInterval seconds.... We'll\r
+            // see when Gameserver has been rewritten\r
+\r
+            if(row[s_timecheck] && (atoi(row[s_timecheck]) == 1))\r
+            {\r
+                it->second.mLasttimestamp = atol(row[s_lastupdate]);\r
+                it->second.mOnline = true;\r
+            }\r
+            else\r
+            {\r
+                it->second.mOnline = false;\r
+            }\r
+\r
+            it->second.mUpdated = true;\r
+        }\r
+        else\r
+        {\r
+            GameServers tmpServer;\r
+\r
+            strncpy(tmpServer.mName, row[s_name], MAX_SERVER_NAME_LENGTH);
+            tmpServer.mLanIp = IPStringToDWord(row[s_lanaddr]);
+            tmpServer.mWanIp = IPStringToDWord(row[s_wanaddr]);\r
+            tmpServer.mLasttimestamp = atol(row[s_lastupdate]);\r
+            tmpServer.mPlayers = atoi(row[s_players]);\r
+            tmpServer.mPort = atoi(row[s_port]);\r
+            tmpServer.mOnline = true;\r
+            tmpServer.mUpdated = true;\r
+            Console->Print("Added GameServer %s", tmpServer.mName);\r
+            /* Prepared for future addon Servers by Accesslevel */\r
+            //    tmpServer.mMinLv = atoi(row[s_minlv]);\r
+            /* ------------------------------------------------ */\r
+\r
+            Serverlist.insert(std::make_pair(atoi(row[s_id]), tmpServer));\r
+        }\r
+    }\r
+    MySQL->FreeSQLResult(result);\r
+\r
+       for(ServerMap::iterator it = Serverlist.begin(); it != Serverlist.end(); it++)\r
+    {\r
+        if(it->second.mUpdated == false)\r
+            Serverlist.erase(it);\r
+        else\r
+            it->second.mUpdated = false;\r
+    }\r
+\r
+}\r
+\r
+void PInfoServer::ClientDisconnected(PClient *Client)\r
+{\r
+       InfoStateMap::iterator node = ClientStates.find(Client);\r
+       if(node == ClientStates.end())\r
+               return;\r
+\r
+       PInfoState *State = node->second;\r
+       FinalizeClient(Client, State);\r
+}\r
+\r
+bool PInfoServer::HandleHandshake(PInfoState *State, const u8 *Packet, int PacketSize)\r
+{\r
+       //static const u8 HANDSHAKE1A[6]={0xfe, 0x03, 0x00, 0x80, 0x03, 0x68};\r
+\r
+       switch(State->mState)\r
+       {\r
+               case PInfoState::IS_HANDSHAKE0 :\r
+               {\r
+                       if(PacketSize==6 && *(u16*)&Packet[3]==0x0080 && Packet[5]==0x78)\r
+                       {\r
+                               //FIXME: this packet seems to be unnecessary, although it appears in traffic dumps\r
+                               // (causes clientside "Wrong protocol" errors)\r
+                               //Socket->Write(HANDSHAKE1A, 6);\r
+                               State->mState = PInfoState::IS_AUTHENTICATE;\r
+                       }\r
+                       else\r
+                       {\r
+                               Console->Print(RED, BLACK, "Infoserver protocol error (IS_HANDSHAKE0): invalid packet [%04x]", *(u16*)&Packet[3]);\r
+                               return false;\r
+                       }\r
+                       break;\r
+               }\r
+               default:\r
+                       break;\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+bool PInfoServer::HandleAuthenticate(PClient *Client, PInfoState *State, const u8 *Packet, int PacketSize)\r
+{\r
+  int returnval = 0;\r
+    // ReturnValue values:\r
+    // 0: No error\r
+    // -1: Wrong/Unknown username\r
+    // -2: Wrong Password\r
+    // -3: Malformed Auth Data. Please relog\r
+    // -4: Database error, contact admin\r
+    // -5: No such account, Account created. Please relog\r
+    // -6: Could not create autoaccount, PW too short\r
+    // -7: Could not create autoaccount, Name too short\r
+    // -8: Could not create autoaccount, PW and Name too short\r
+    // -9: Duplicate entry for Username! Contact Admin\r
+    // -10: User is banned\r
+    // -11: Insufficient access rights\r
+    // -12: Account is not yet activated (accesslevel = 0)\r
+    // -99: General fault. Contact admin\r
+       ConnectionTCP *Socket = Client->getTCPConn();\r
+       PAccount* currentAccount = NULL;\r
+\r
+       if(PacketSize > 20 && *(u16*)&Packet[3]==0x8084)\r
+       {\r
+               const u8 *Key = &Packet[5];                     // password key\r
+               u16 ULen = *(u16*)&Packet[16];          // username length\r
+               u16 PLen = *(u16*)&Packet[18];          // password length\r
+               char *UserName = (char*)&Packet[20];    // account name\r
+               const u8 *PW = &Packet[20+ULen];        // encoded password\r
+\r
+    if(UserName[ULen-1]) // Check that string is well terminated\r
+    {\r
+      Console->Print("Infoserver: Client [%d]: Username was not NULL-terminated !", Client->GetIndex());\r
+      returnval = -1;\r
+    }\r
+    else\r
+    {\r
+      currentAccount = new PAccount(UserName);\r
+      if(!currentAccount->GetID())\r
+      {\r
+        if(Config->GetOptionInt("auto_accounts")) // Autoaccount\r
+        {\r
+          delete currentAccount;\r
+          currentAccount = new PAccount();\r
+\r
+          if(!currentAccount->SetName(UserName)) // !!! len\r
+          {\r
+              returnval = -7;\r
+          }\r
+          if(!currentAccount->SetPasswordEncoded(PW, PLen, Key))\r
+          {\r
+              returnval = returnval ? -8 : -6;\r
+          }\r
+\r
+          if(!returnval)\r
+          {\r
+            if(currentAccount->Create())\r
+            {\r
+              returnval = -5;\r
+            }\r
+            else\r
+            {\r
+              returnval = -4;\r
+            }\r
+          }\r
+        }\r
+        else\r
+        {\r
+          returnval = -1;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        if(currentAccount->Authenticate(PW, PLen, Key))\r
+        { // Username & Password correct\r
+          if(currentAccount->IsBanned())\r
+          {\r
+              returnval = -10;\r
+          }\r
+          else if(currentAccount->GetLevel() < Config->GetOptionInt("minlevel")) // insufficient access rights\r
+          {\r
+              returnval = -11;\r
+          }\r
+          else if(Config->GetOptionInt("require_validation") == 1 && currentAccount->GetLevel() == PAL_UNREGPLAYER)\r
+          {\r
+              returnval = -12;\r
+          }\r
+          else\r
+          {\r
+              Client->setAccountID(currentAccount->GetID());\r
+              returnval = 0;\r
+          }\r
+\r
+        }\r
+        else\r
+        {\r
+          returnval = -2;\r
+        }\r
+      }\r
+    }\r
+\r
+               bool Failed = false;\r
+               if(returnval == 0)\r
+               {\r
+                       u8 AUTHOK[28]={0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,\r
+                                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+                                                       0x00, 0x00, 0x00, 0x00, 0x00 };\r
+                       *(u32*)&AUTHOK[5] = currentAccount->GetID();\r
+                       Socket->write(AUTHOK, 28);\r
+                       State->mState = PInfoState::IS_SERVERLIST;\r
+               }\r
+               else\r
+               {\r
+                       Console->Print("Infoserver: User '%s': authentication failed. Errorcode %d", UserName, returnval);\r
+                       Failed = true;  // auth failed\r
+               }\r
+               if(Failed == true)\r
+               {\r
+                       std::string errorReason;\r
+                       switch(returnval)\r
+                       {\r
+                           // It seems that the client cuts the line off after 40 chars...\r
+//                                 |1       |10       |20       |30       |40       |50       |60       |70       |80\r
+                           case -99:\r
+                           {\r
+                    //errorReason = "General fault in processing your login request";\r
+                    errorReason = "General fault while login request";\r
+                    break;\r
+                           }\r
+                           case -12:\r
+                           {\r
+                    //errorReason = "Account not activated. Please check your EMails";\r
+                    errorReason = "Error: Your account is not activated";\r
+                    break;\r
+                           }\r
+                           case -11:\r
+                           {\r
+                               //errorReason = "Login rejected. You have to be " + GetAccessString(Config->GetOptionInt("minlevel")) + " or higher";\r
+                               errorReason = "Level " + GetAccessString(Config->GetOptionInt("minlevel")) + " or higher required";\r
+                               break;\r
+                           }\r
+                           case -10:\r
+                           {\r
+                               errorReason = "You are banned for " + currentAccount->GetBannedTime();\r
+                               break;\r
+                           }\r
+                           case -9:\r
+                           {\r
+                               //errorReason = "Duplicate entry for this login. Contact Admin";\r
+                               errorReason = "Duplicate entry found. Contact Admin";\r
+                               break;\r
+                           }\r
+                           case -8:\r
+                           {\r
+                               //errorReason = "Autoaccount failed, name and password too short";\r
+                               errorReason = "AutoAcc failed, name and pwd too short";\r
+                               break;\r
+                           }\r
+                           case -7:\r
+                           {\r
+                               errorReason = "Autoaccount failed, name is too short";\r
+                               break;\r
+                           }\r
+                           case -6:\r
+                           {\r
+                               //errorReason = "Autoaccount failed, password is too short";\r
+                               errorReason = "Autoaccount failed, pwd is too short";\r
+                               break;\r
+                           }\r
+                           case -5:\r
+                           {\r
+                               errorReason = "New Account created, please login again";\r
+                               break;\r
+                           }\r
+                           case -4:\r
+                           {\r
+                               errorReason = "Database error, contact Administrator";\r
+                               break;\r
+                           }\r
+                           case -3:\r
+                           {\r
+                               errorReason = "Malformed AuthData. Please login again";\r
+                               break;\r
+                           }\r
+                           case -2:\r
+                           {\r
+                               errorReason = "Wrong password";\r
+                               break;\r
+                           }\r
+                           case -1:\r
+                           {\r
+                               errorReason = "Unknown username";\r
+                               break;\r
+                           }\r
+                       }\r
+                       u8 AUTHFAILED_HEADER[] = {0xfe, 0x0c, 0x00, 0x83, 0x86, 0x05, 0x00, 0x06, 0x00};\r
+                       u8 AUTHFAILED_FOOTER[] = {0x00, 0x40};\r
+                       *(u16*)&AUTHFAILED_HEADER[1] = errorReason.size() + 8;\r
+                       *(u16*)&AUTHFAILED_HEADER[7] = errorReason.size() + 1;\r
+                       //*(u8*)&AUTHFAILED_FOOTER[1] = {0x40};\r
+\r
+                       Socket->write(AUTHFAILED_HEADER, sizeof(AUTHFAILED_HEADER));\r
+                       Socket->write(errorReason.c_str(), errorReason.size());\r
+                       Socket->write(AUTHFAILED_FOOTER, sizeof(AUTHFAILED_FOOTER));\r
+                       FinalizeClientDelayed(Client, State);\r
+                       State->mState=PInfoState::IS_UNKNOWN;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               Console->Print(RED, BLACK, "Infoserver protocol error (IS_AUTHENTICATE): invalid packet [%04x]", *(u16*)&Packet[3]);\r
+               return false;\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+bool PInfoServer::HandleServerList(PClient *Client, const u8 *Packet, int PacketSize)\r
+{\r
+    u8 SERVERLIST_HEAD[] = {0xfe, 0x00, 0x00, 0x83, 0x83, 0x01, 0x00, 0x0d, 0x00};\r
+    u8 SERVERLIST[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\r
+    u8 SERVERLIST_FOOTER[] = {0x00};\r
+\r
+       ConnectionTCP *Socket = Client->getTCPConn();\r
+\r
+       u32 tID = *(u32*)&Packet[5];\r
+       PAccount* currentAccount = new PAccount(Client->getAccountID());\r
+       u32 aID = currentAccount->GetID();\r
+\r
+       if(!aID || (aID != tID))\r
+       {\r
+           Console->Print("%s invalid userID %d (auth with id %d)", Console->ColorText(YELLOW, BLACK, "Warning:"), tID, aID);\r
+           delete currentAccount;\r
+           return false;\r
+       }\r
+\r
+       if(currentAccount->GetLevel() < Config->GetOptionInt("minlevel"))\r
+       {\r
+           Console->Print("%s someone tried to bypass the login process! UserID %d", Console->ColorText(RED, BLACK, "Warning:"), aID);\r
+           delete currentAccount;\r
+           return false;\r
+       }\r
+\r
+  if(PacketSize == 31 && *(u16*)&Packet[3]==0x8284)\r
+       {\r
+    GSLiveCheck(); // Perform livecheck to have up-to-date data\r
+\r
+    int len = 0;\r
+    int num = 0;\r
+    for(ServerMap::iterator it = Serverlist.begin(); it != Serverlist.end(); it++)\r
+    {\r
+        num++;\r
+        len += 14 + strlen(it->second.mName);\r
+    }\r
+\r
+    *(u16*)&SERVERLIST_HEAD[1] = len;\r
+    *(u8*)&SERVERLIST_HEAD[5] = num;\r
+    Socket->write(SERVERLIST_HEAD, sizeof(SERVERLIST_HEAD));\r
+\r
+    for(ServerMap::iterator it = Serverlist.begin(); it != Serverlist.end(); it++)\r
+    {\r
+            /* Prepared for future addon Servers by Accesslevel */\r
+//            if(accesslevel >= it->second.mMinLv)\r
+//            {\r
+            /* ------------------------------------------------ */
+            // Todo: Set correct lan/wan IP here!\r
+      *(u32*)&SERVERLIST[0] = it->second.mLanIp;\r
+      *(u16*)&SERVERLIST[4] = it->second.mPort;\r
+      *(u8*)&SERVERLIST[8] = strlen(it->second.mName) + 1;\r
+      *(u16*)&SERVERLIST[9] = it->second.mPlayers;\r
+      if(it->second.mOnline == true)\r
+      {\r
+          Console->Print("Sending server name: %s ip: %s player: %d port: %d online: yes", it->second.mName, IPlongToString(it->second.mLanIp), it->second.mPlayers, it->second.mPort);\r
+          *(u16*)&SERVERLIST[11] = 1;\r
+      }\r
+      else if(it->second.mOnline == false)\r
+      {\r
+          Console->Print("Sending server name: %s ip: %s player: %d port: %d online: no", it->second.mName, IPlongToString(it->second.mLanIp), it->second.mPlayers, it->second.mPort);\r
+          *(u16*)&SERVERLIST[11] = 0;\r
+      }\r
+      Socket->write(SERVERLIST, sizeof(SERVERLIST));\r
+      Socket->write(it->second.mName, strlen(it->second.mName));\r
+      Socket->write(SERVERLIST_FOOTER, sizeof(SERVERLIST_FOOTER));\r
+            /* Prepared for future addon Servers by Accesslevel */\r
+//            }\r
+            /* ------------------------------------------------ */\r
+    }\r
+       }\r
+       else\r
+       {\r
+               Console->Print(RED, BLACK, "Infoserver protocol error (IS_SERVERLIST): invalid packet [%04x]", *(u16*)&Packet[3]);\r
+               delete currentAccount;\r
+               return false;\r
+       }\r
+       delete currentAccount;\r
+       return true;\r
+}\r
+\r
+bool PInfoServer::ProcessClient(PClient *Client, PInfoState *State)\r
+{\r
+       static const u8 HANDSHAKE0A[6]={0xfe, 0x03, 0x00, 0x80, 0x01, 0x66};\r
+\r
+       if(!State)\r
+       {\r
+               InfoStateMap::iterator node = ClientStates.find(Client);\r
+               if(node == ClientStates.end())\r
+                       return false;\r
+\r
+               State = node->second;\r
+       }\r
+\r
+       ConnectionTCP *Socket = Client->getTCPConn();\r
+\r
+       if(State->mWaitSend && Socket->getSendBufferSize()==0)\r
+               return false;\r
+\r
+       if(State->mState==PInfoState::IS_CONNECTED)\r
+       {\r
+               Socket->write(HANDSHAKE0A, 6);\r
+               State->mState = PInfoState::IS_HANDSHAKE0;\r
+       }\r
+\r
+       int PacketSize=0;\r
+       const u8 *Packet = Socket->read(&PacketSize);\r
+       if(PacketSize > 0)\r
+       {\r
+               switch(State->mState)\r
+               {\r
+                       case PInfoState::IS_HANDSHAKE0:\r
+                               return HandleHandshake(State, Packet, PacketSize);\r
+\r
+                       case PInfoState::IS_AUTHENTICATE:\r
+                               return HandleAuthenticate(Client, State, Packet, PacketSize);\r
+\r
+                       case PInfoState::IS_SERVERLIST:\r
+                               return HandleServerList(Client, Packet, PacketSize);\r
+                       default:\r
+                               break;\r
+               }\r
+       }\r
+       return true;\r
+}\r
+\r
+void PInfoServer::FinalizeClient(PClient *Client, PInfoState *State)\r
+{\r
+       Console->Print(RED, BLACK, "Infoserver: client %s disconnected", Client->GetAddress());\r
+       Client->InfoDisconnect();\r
+       ClientStates.erase(Client);\r
+       delete State;\r
+}\r
+\r
+void PInfoServer::FinalizeClientDelayed(PClient *Client, PInfoState *State)\r
+{\r
+       Console->Print("Infoserver: client %i is about to be disconnected", Client->GetIndex());\r
+       State->mWaitSend = true;\r
+}\r
diff --git a/server/src/info/infoserver.h b/server/src/info/infoserver.h
new file mode 100644 (file)
index 0000000..191dc0a
--- /dev/null
@@ -0,0 +1,87 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+#ifndef INFOSERVER_H\r
+#define INFOSERVER_H\r
+\r
+#ifdef _MSC_VER\r
+       #pragma once\r
+#endif\r
+\r
+#define MAX_SERVER_NAME_LENGTH 45\r
+struct GameServers\r
+{\r
+  char            mName[MAX_SERVER_NAME_LENGTH];\r
+       unsigned int    mLanIp;
+       unsigned int    mWanIp;\r
+       short           mPort;\r
+       int             mPlayers;\r
+       bool            mOnline;\r
+       bool            mUpdated;\r
+       long            mLasttimestamp;\r
+/* Prepared for future addon Servers by Accesslevel */\r
+//    int             mMinLv;\r
+/* ------------------------------------------------ */\r
+};\r
+\r
+class PInfoServer\r
+{\r
+       private :\r
+        // SQL layout\r
+        enum {\r
+            s_id,\r
+            s_name,\r
+            s_wanaddr,\r
+            s_port,\r
+            s_players,\r
+            s_lastupdate,
+            s_lanaddr,\r
+            s_timecheck // computed field, not in table !\r
+        };\r
+               //int mNumClients;\r
+               typedef std::map<PClient*, struct PInfoState*> InfoStateMap;\r
+               InfoStateMap ClientStates;\r
+\r
+               typedef std::map<int, GameServers> ServerMap;\r
+               ServerMap Serverlist;\r
+\r
+               //time_t mLastLivecheck;\r
+               int mLivecheckInterval;\r
+               void GSLiveCheck();\r
+\r
+       protected :\r
+               bool ProcessClient(PClient *Client, PInfoState *State=NULL);\r
+               void FinalizeClient(PClient *Client, PInfoState *State);\r
+               void FinalizeClientDelayed(PClient *Client, PInfoState *State);\r
+\r
+               bool HandleHandshake(PInfoState *State, const u8 *Packet, int PacketSize);\r
+               bool HandleAuthenticate(PClient *Client, PInfoState *State, const u8 *Packet, int PacketSize);\r
+               bool HandleServerList(PClient *Client, const u8 *Packet, int PacketSize);\r
+       public :\r
+               PInfoServer();\r
+               ~PInfoServer();\r
+\r
+               void Start();\r
+               void Update();\r
+               void ClientDisconnected(PClient *Client);\r
+};\r
+\r
+#endif\r
diff --git a/server/src/info/main.cpp b/server/src/info/main.cpp
new file mode 100644 (file)
index 0000000..8ad0528
--- /dev/null
@@ -0,0 +1,63 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*     \r
+        MODIFIED: 01 Jul 2006 hammag\r
+             REASON: - commented out sched_yield() in main loop, as it is\r
+                     not needed anymore with a right timeout for ReadSetTCP select\r
+                     \r
+*/\r
+\r
+#include "main.h"\r
+\r
+void signal_handler(int signal)\r
+{\r
+    if (signal == SIGINT)\r
+    {\r
+        Shutdown();\r
+    }\r
+}\r
+\r
+int main()\r
+{\r
+    signal(SIGINT, signal_handler);\r
+\r
+       if(!Init())\r
+       {\r
+         if(Console)\r
+           Console->Print("%s Aborting startup.", Console->ColorText(RED, BLACK, "[Fatal]"));\r
+               Shutdown(); // exits with 0 ...\r
+  }\r
+\r
+       InfoServer->Start();\r
+       Console->Print("Infoserver is now %s. Waiting for clients...", Console->ColorText(GREEN, BLACK, "Online"));\r
+\r
+       while(1)\r
+       {\r
+         ServerSock->update();\r
+         Server->Update();\r
+               InfoServer->Update();\r
+               MySQL->Update(); // MySQL keepalive\r
+               Console->Update();\r
+       }\r
+\r
+       return 0;\r
+}\r
diff --git a/server/src/info/main.h b/server/src/info/main.h
new file mode 100644 (file)
index 0000000..360fe4c
--- /dev/null
@@ -0,0 +1,61 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+/*\r
+    MODIFIED: 6 Jul 2006 Hammag\r
+         REASON: - moved include "types.h" before include "../netcode/main.h" to enable compile\r
+         \r
+    MODIFIED: 27 Aug 2006 Hammag\r
+         REASON: - replaced MAX_INFO_CLIENTS define by config setting\r
+                 - removed INFO_PORT define not used anymore\r
+         \r
+*/\r
+\r
+\r
+#ifndef MAIN_H\r
+#define MAIN_H\r
+\r
+//#include "version.h"\r
+\r
+//basic includes\r
+#include "external.h"\r
+\r
+//tinns includes\r
+#include "types.h"\r
+#include "netcode.h"\r
+\r
+// MySQL Support\r
+#include "mysql.h"\r
+#include "sql.h"\r
+#include "console.h"\r
+#include "config.h"\r
+#include "accounts.h"\r
+#include "client.h"\r
+#include "server.h"\r
+#include "infoserver.h"\r
+#include "misc.h"\r
+#include "globals.h"\r
+\r
+\r
+using namespace std;\r
+\r
+#endif\r
diff --git a/server/src/info/server.cpp b/server/src/info/server.cpp
new file mode 100644 (file)
index 0000000..fba8060
--- /dev/null
@@ -0,0 +1,102 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+       MODIFIED: 27 Aug 2005 Hammag\r
+       REASON: - Use mMaxClient member instead of MAX_INFO_CLIENTS define\r
+\r
+*/\r
+\r
+#include "main.h"\r
+\r
+PServer::PServer()\r
+{\r
+  mMaxClients = Config->GetOptionInt("maxclients");\r
+  \r
+       mClients.reserve(mMaxClients);\r
+       mNumClients = 0;\r
+       for(int i=0; i<mMaxClients; i++)\r
+               mClients[i]=0;\r
+}\r
+\r
+PServer::~PServer()\r
+{\r
+       for(int i=0; i<mMaxClients; i++)\r
+               delete mClients[i];\r
+}\r
+\r
+int PServer::NewClient()\r
+{\r
+       if(mNumClients==mMaxClients)\r
+               return -1;\r
+\r
+       for(int i=0; i<mMaxClients; i++)\r
+       {\r
+               if(!mClients[i])\r
+               {\r
+                       mClients[i]=new PClient(i);\r
+                       ++mNumClients;\r
+                       return i;\r
+               }\r
+       }\r
+       return -1;\r
+}\r
+\r
+PClient *PServer::GetClient(int Client) const\r
+{\r
+       if(Client < 0 || Client >= mMaxClients)\r
+               return 0;\r
+\r
+       return mClients[Client];\r
+}\r
+\r
+void PServer::Update()\r
+{\r
+       for(int i=0; i<mMaxClients; i++)\r
+       {\r
+               if(mClients[i])\r
+               {\r
+                       mClients[i]->Update();\r
+                       if(mClients[i]->GetConnection()==PCC_NONE && mClients[i]->getTCPConn() == 0)\r
+                       {\r
+                               Console->Print("Removing client ...");\r
+                               delete mClients[i];\r
+                               mClients[i]=0;\r
+                               --mNumClients;\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+void PServer::Shutdown()\r
+{\r
+    Console->Print("======================");\r
+       Console->Print("Shutting down Infoserver...");\r
+       for(int i=0; i<mMaxClients; i++)\r
+       {\r
+               if(mClients[i])\r
+               {\r
+                       delete mClients[i];\r
+                       mClients[i]=0;\r
+               }\r
+       }\r
+}\r
diff --git a/server/src/info/server.h b/server/src/info/server.h
new file mode 100644 (file)
index 0000000..3942fdd
--- /dev/null
@@ -0,0 +1,59 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       server.h\r
+\r
+       MODIFIED: 25 Dec 2005 Namikon\r
+       REASON: - Added GPL     \r
+       MODIFIED: 27 Aug 2005 Hammag\r
+       REASON: - Added mMaxClient member       \r
+*/\r
+\r
+#ifndef SERVER_H\r
+#define SERVER_H\r
+\r
+#ifdef _MSC_VER\r
+       #pragma once\r
+#endif\r
+\r
+class PServer\r
+{\r
+       private :\r
+         int mMaxClients;\r
+               int mNumClients;\r
+               std::vector<PClient*> mClients;\r
+       protected :\r
+       public :\r
+               PServer();\r
+               ~PServer();\r
+\r
+               inline int GetNumClients() const { return mNumClients; }\r
+               int NewClient();\r
+               PClient *GetClient(int Client) const;\r
+               void Update();\r
+               void Shutdown();\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/info/sql.cpp b/server/src/info/sql.cpp
new file mode 100644 (file)
index 0000000..0513752
--- /dev/null
@@ -0,0 +1,156 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+#include "main.h"\r
+\r
+PMySQL::PMySQL()\r
+{\r
+    port = Config->GetOptionInt("sql_port");\r
+    strncpy(host, Config->GetOption("sql_host").c_str(), 100);\r
+    strncpy(userName, Config->GetOption("sql_username").c_str(), 100);\r
+    strncpy(password, Config->GetOption("sql_password").c_str(), 100);\r
+    strncpy(database, Config->GetOption("global_sql_database").c_str(), 100);\r
+\r
+    mKeepaliveDelay = (std::time_t) (Config->GetOptionInt("mysql_wait_timeout") * 0.9) ; // we take 90% of the wait_timeout to trigger keepalive\r
+    if (mKeepaliveDelay == 0)\r
+    {\r
+      Console->Print("%s MySQL keepalive disabled by config", Console->ColorText(GREEN, BLACK, "[Info]"));\r
+    }\r
+    else if (mKeepaliveDelay < 60)\r
+    {\r
+      Console->Print("%s Configuration option 'mysql_wait_timeout' is too low (%d sec). Reset to 60 sec.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mKeepaliveDelay);\r
+      mKeepaliveDelay = 60;\r
+    }\r
+    mLastKeepaliveSent = 0;\r
+}\r
+\r
+PMySQL::~PMySQL()\r
+{\r
+    Console->Print("Closing MySQL connection...");\r
+    mysql_close(dbHandle);\r
+}\r
+\r
+void PMySQL::Update()\r
+{    \r
+    // MySQL keepalive\r
+    std::time_t t = std::time(NULL);\r
+    if ((mKeepaliveDelay > 0) && ((t - mLastKeepaliveSent) > mKeepaliveDelay))\r
+    {\r
+      MYSQL_RES *result;\r
+      char query[24];\r
+      snprintf (query, 24, "SELECT NOW()");\r
+\r
+      result = ResQuery(query);\r
+      if(!result)\r
+      {\r
+          Console->Print("%s Can't send InfoDB keepalive; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
+          ShowSQLError();\r
+          return;\r
+      }\r
+      else\r
+        FreeSQLResult(result);      \r
+    \r
+      mLastKeepaliveSent = std::time(NULL);\r
+//Console->Print("%s MySQL keepalive sent", Console->ColorText(GREEN, BLACK, "[Debug]"));\r
+    }\r
+}\r
+\r
+bool PMySQL::Connect()\r
+{\r
+    Console->LPrint("Establishing link to MySQL Database...");\r
+\r
+       dbHandle = mysql_init(NULL);\r
+\r
+       if(dbHandle)\r
+       {\r
+               //Console->Print("MySQL-Handle successfully initialized.");\r
+       }\r
+       else\r
+       {\r
+               Console->LPrint(RED, BLACK, "[ERROR]");\r
+               Console->LClose();\r
+               Console->Print(" MySQL-Handle couldn't be created!");\r
+               exit(0);\r
+       }\r
+\r
+    if(!mysql_real_connect(dbHandle, host, userName, password, database, port, NULL, 0))\r
+    {\r
+               Console->LPrint(RED, BLACK, "[ERROR]");\r
+               Console->LClose();\r
+        Console->Print("Unable to connect to MySQL Database. MySQL returned: %s", mysql_error(dbHandle));\r
+        return false;\r
+    }\r
+    else\r
+    {\r
+        Console->LPrint(GREEN, BLACK, "Success");\r
+        Console->LClose();\r
+        return true;\r
+    }\r
+}\r
+\r
+MYSQL_RES *PMySQL::ResQuery(const char *query)\r
+{\r
+    int sql_result = 0;\r
+    MYSQL_RES *result;\r
+\r
+    sql_result = mysql_real_query(dbHandle, query, strlen(query));\r
+    if(sql_result)\r
+    {\r
+        return NULL;\r
+    }\r
+    result = mysql_store_result(dbHandle);\r
+    if(!result)\r
+    {\r
+        return NULL;\r
+    }\r
+\r
+    return result;\r
+}\r
+\r
+int PMySQL::Query(const char *query)\r
+{\r
+    int sql_result = 0;\r
+    sql_result = mysql_real_query(dbHandle, query, strlen(query));\r
+\r
+    return sql_result;\r
+}\r
+\r
+void PMySQL::ShowSQLError()\r
+{\r
+    Console->Print(RED, BLACK, "MySQL Error: %s", mysql_error(dbHandle));\r
+}\r
+\r
+void PMySQL::FreeSQLResult(MYSQL_RES *res)\r
+{\r
+  mysql_free_result(res);\r
+}\r
+\r
+u32 PMySQL::EscapeString(const char* nText, char* dText, u32 dMaxLength)\r
+{\r
+  u32 nLength = strlen(nText);\r
+  u32 tMax = (dMaxLength - 1)/2;\r
+  if(nLength > tMax)\r
+  {\r
+    nLength = tMax;\r
+  }\r
+  \r
+  return mysql_real_escape_string(dbHandle, dText, nText, nLength);\r
+}\r
diff --git a/server/src/info/sql.h b/server/src/info/sql.h
new file mode 100644 (file)
index 0000000..319f3f2
--- /dev/null
@@ -0,0 +1,57 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+#ifndef SQL_H\r
+#define SQL_H\r
+\r
+#ifdef _MSC_VER\r
+       #pragma once\r
+#endif\r
+\r
+class PMySQL\r
+{\r
+    private:\r
+        int port;\r
+        char host[100];\r
+         char userName[100];\r
+        char password[100];\r
+        char database[100];\r
+        MYSQL *dbHandle;\r
+        std::time_t mKeepaliveDelay;\r
+        std::time_t mLastKeepaliveSent;\r
+\r
+    public:\r
+        PMySQL();\r
+        ~PMySQL();\r
+\r
+        void Update();\r
+        inline MYSQL *GetHandle() { return dbHandle; };\r
+\r
+        bool Connect();\r
+        int Query(const char *query);\r
+        MYSQL_RES *ResQuery(const char *query);\r
+        void ShowSQLError();\r
+        void FreeSQLResult(MYSQL_RES *res);\r
+        inline u32 GetLastInsertId() { return mysql_insert_id(dbHandle); };\r
+        \r
+        u32 EscapeString(const char* nText, char* dText, u32 dMaxLength);\r
+};\r
+#endif\r
diff --git a/server/src/options.local.exemple b/server/src/options.local.exemple
new file mode 100644 (file)
index 0000000..6497c01
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Local Makefile custom options
+# not in SVN !
+#
+# Copy this file as options.local to add you custom complation options
+#  so that you don't need to change the main Makefile
+# You can also uncomment some of the lines below that fit you needs
+#
+#DO_DEBUG = y
+#CXXFLAGS += -Werror
+#CXXFLAGS += -march=native
+#CXXFLAGS += -fstack-protector-all
diff --git a/server/src/patch/Makefile b/server/src/patch/Makefile
new file mode 100644 (file)
index 0000000..be767e4
--- /dev/null
@@ -0,0 +1,84 @@
+#
+# TinNS per-directory Makefile
+#
+# Adapted by Hammag from the Makefile system for Linux kernel.
+#
+# 14 Sep 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+# 
+
+######################################################
+# Target for this directory and its sub-dirs
+######################################################
+# Case 1 : target is an executable named as defined
+B_TARGET := patchserver
+
+# Case 2 : target is a TinNS lib name
+#  (use short name, as in -l linker option) 
+#L_TARGET := tinns
+
+# Case 3 (usual): objects shall be made available to the parent dir
+#  The following line will set that automatically 
+# (Should match dir name + .o suffix)
+#O_TARGET := $(addsuffix .o,$(notdir $(shell /bin/pwd)))
+# Manualy define this only if you need to force the compiled obj name
+#O_TARGET := game.o
+
+
+######################################################
+# Local flags
+######################################################
+# local dir CXX Flags
+#EXTRA_CXXFLAGS := -I/usr/include/mysql
+
+# per-object CXX Flags
+#CXXFLAGS_funcdef2.o := -g
+
+# local dir Linker Flags (for intermediate .o linking)
+#EXTRA_LDFLAGS := 
+
+# any tinns Lib used (short name, as in -l linker option)
+LINK_TINNSLIBS := tinns
+
+# local dir Linker Flags (for final executable linking)
+#EXTRA_LINKFLAGS := -lrt -lpthread -lz -lm -lcrypt
+EXTRA_LINKFLAGS := -lz -lpcre
+
+
+#####################################################
+# Subdirectories
+#####################################################
+#subdir-y := def 
+#subdir-$(CONFIG_GAMEMONKEY)   += gamemonkey
+
+
+#####################################################
+#***************************************************#
+# No further config should be needed after this line
+#***************************************************#
+ifdef TOPDIR
+
+# build list of objects ib loca ldir
+obj-y := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
+# add final object from each subdir
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+
+include $(TOPDIR)/Rules.make
+
+else #TOPDIR undef, Makefile called from non-top dir
+
+# Memorize the first calling dir in case we wanted to
+# lauch local actions from top Makefile
+  ifndef FIRSTDIR
+    FIRSTDIR :=$(CURDIR)
+    export FIRSTDIR
+  endif
+
+uptoparent : 
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+.DEFAULT :
+       $(MAKE) -C .. $(MAKECMDGOALS)
+
+endif #TOPDIR
+
diff --git a/server/src/patch/client.cpp b/server/src/patch/client.cpp
new file mode 100644 (file)
index 0000000..cf4691b
--- /dev/null
@@ -0,0 +1,65 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+#include "main.h"\r
+\r
+PClient::PClient(int Index)\r
+{\r
+       mIndex = Index;\r
+       mConnection = PCC_NONE;\r
+}\r
+\r
+PClient::~PClient()\r
+{\r
+    if(m_TCPConnection)\r
+    {\r
+        delete m_TCPConnection;\r
+    }\r
+}\r
+\r
+void PClient::Update()\r
+{\r
+    if(m_TCPConnection)\r
+    {\r
+        if(m_TCPConnection->timeOut())\r
+        {\r
+            Console->Print("Patchsocket: Client %i: timeout", mIndex);\r
+            PatchServer->ClientDisconnected(this);\r
+        }\r
+        else\r
+        {\r
+            if(!m_TCPConnection->update())\r
+            {\r
+                PatchServer->ClientDisconnected(this);\r
+            }\r
+        }\r
+       }\r
+}\r
+\r
+void PClient::PatchDisconnect()\r
+{\r
+    if(m_TCPConnection)\r
+    {\r
+        delete m_TCPConnection;\r
+    }\r
+    mConnection = PCC_NONE;\r
+    m_TCPConnection = 0;\r
+}\r
diff --git a/server/src/patch/client.h b/server/src/patch/client.h
new file mode 100644 (file)
index 0000000..0eeb1c6
--- /dev/null
@@ -0,0 +1,58 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+#ifndef CLIENT_H\r
+#define CLIENT_H\r
+\r
+enum PClientConnection\r
+{\r
+       PCC_NONE = 0,\r
+       PCC_PATCH = 1\r
+};\r
+class PClient\r
+{\r
+       private :\r
+        ConnectionTCP* m_TCPConnection;\r
+               int mIndex;\r
+               int mConnection;\r
+\r
+\r
+       protected :\r
+       public :\r
+               PClient(int Index);\r
+               ~PClient();\r
+\r
+               inline int GetIndex() const { return mIndex; }\r
+\r
+               inline int GetConnection() const { return mConnection; }\r
+               inline const char *GetAddress() const { return m_TCPConnection->getRemoteAddress(); }\r
+\r
+               void setTCPConnection(ConnectionTCP* conn) { m_TCPConnection = conn; mConnection = PCC_PATCH; }\r
+\r
+               inline ConnectionTCP* getTCPConn() { return m_TCPConnection; }\r
+\r
+               void Update();\r
+\r
+               void PatchDisconnect();\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/patch/configtemplate.h b/server/src/patch/configtemplate.h
new file mode 100644 (file)
index 0000000..daeac00
--- /dev/null
@@ -0,0 +1,40 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+    Configuration template for patchserver\r
+    Used to set available/optional/required options when loading config\r
+      with a PConfig object.\r
+*/\r
+\r
+const char* PatchConfigTemplate[][2] = {\r
+  // {option_name, default_value} if default_value is empty string, it means option is mandatory\r
+  // List ends with empty string for option_name\r
+  {"server_version", "200"},\r
+  {"patchserver_port", "8040"},\r
+  {"patches_path", "./patches"},\r
+  {"file_path", "./files"},\r
+  {"max_file_xfers", "5"},\r
+  {"patch_packet_size", "512"},\r
+  {"maxclients", "5"},\r
+  {"gm_slots", "2"},\r
+  \r
+  {"", ""} // do not change this line (end mark)\r
+};\r
diff --git a/server/src/patch/globals.cpp b/server/src/patch/globals.cpp
new file mode 100644 (file)
index 0000000..b185141
--- /dev/null
@@ -0,0 +1,95 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+/*\r
+\r
+    MODIFIED: 27 Aug 2006 Hammag\r
+    REASON: - Implemented shared Config class use and config template to load conf.\r
+                Added gameserver configtemplate.h include,\r
+                Added new required parameters to Config->LoadOptions()\r
+    \r
+    TODO:   - Get logfile name from config file\r
+    \r
+*/\r
+      \r
+#include "main.h"\r
+#include "configtemplate.h"\r
+\r
+#include "version.h"\r
+const char ServerVersion[] = TINNS_PATCH_VERSION;\r
+const char SVNRevision[] = TINNS_SVN_REVISION;\r
+\r
+ServerSocket* ServerSock = 0;\r
+PConsole *Console = 0;\r
+PServer *Server = 0;\r
+PConfig *Config = 0;\r
+PFileSystem *Filesystem = 0;\r
+PPatchServer *PatchServer = 0;\r
+\r
+bool InitTinNS()\r
+{\r
+       Console = new PConsole("log/patchserver.log");  // Make that from config file !!!\r
+       Console->Print("Starting TinNS Patchserver...");\r
+       Console->Print(WHITE, BLUE, "/-------------------------------------------------------------------\\");\r
+       Console->Print(WHITE, BLUE, "|               TinNS (TinNS is not a Neocron Server)               |");\r
+  Console->Print(WHITE, BLUE, "|            Copyright (C) 2005 Linux Addicted Community            |");\r
+       Console->Print(WHITE, BLUE, "|                  maintainer Akiko <akiko@gmx.org>                 |");\r
+       Console->Print(WHITE, BLUE, "|             ==========================================            |");\r
+       Console->Print(WHITE, BLUE, "|      Head coders:                   The packet analyzing team:    |");\r
+       Console->Print(WHITE, BLUE, "|      - Akiko                         - MaxxJag                    |");\r
+       Console->Print(WHITE, BLUE, "|      - bakkdoor                      - Sting                      |");\r
+       Console->Print(WHITE, BLUE, "|      - Namikon                       - Balm                       |");\r
+       Console->Print(WHITE, BLUE, "|      - Hammag                                                     |");\r
+       Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");\r
+       Console->Print(WHITE, BLUE, "|  This project would'nt be at its current stage without the help   |");\r
+  Console->Print(WHITE, BLUE, "|        from the NeoPolis team, special thanks to you guys!        |");\r
+       Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");\r
+       Console->Print(WHITE, BLUE, "|  This project is under GPL, see any source file for more details  |");\r
+       Console->Print(WHITE, BLUE, "\\-------------------------------------------------------------------/");\r
+\r
+       //char svnrev[10];\r
+       //GetSVNRev(svnrev);\r
+       Console->LPrint("You are running TinNS Patchserver version");\r
+       Console->LPrint(GREEN, BLACK, " %s", ServerVersion);\r
+       Console->LPrint(WHITE, BLACK, " - SVN Rev");\r
+       Console->LPrint(GREEN, BLACK, " %s", SVNRevision);\r
+       Console->LClose();\r
+       \r
+       Config = new PConfig();\r
+       if(!Config->LoadOptions(PatchConfigTemplate ,"./conf/patchserver.conf"))\r
+    Shutdown();\r
+\r
+       ServerSock = new ServerSocket();\r
+       Server = new PServer();\r
+       PatchServer = new PPatchServer();\r
+\r
+       return true;\r
+}\r
+\r
+void Shutdown()\r
+{\r
+       if(PatchServer) delete PatchServer;\r
+       if(Config) delete Config;\r
+       if(Console) delete Console;\r
+    if(ServerSock) delete ServerSock;\r
+    exit(0);\r
+}\r
+\r
diff --git a/server/src/patch/globals.h b/server/src/patch/globals.h
new file mode 100644 (file)
index 0000000..bb5eb16
--- /dev/null
@@ -0,0 +1,39 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+#ifndef GLOBALS_H\r
+#define GLOBALS_H\r
+\r
+extern class ServerSocket* ServerSock;\r
+extern class PConsole *Console;\r
+extern class PConfig *Config;\r
+extern class PFileSystem *Filesystem;\r
+extern class PServer *Server;\r
+extern class PPatchServer *PatchServer;\r
+\r
+extern const char ServerVersion[];\r
+extern const char SVNRevision[];\r
+\r
+bool InitTinNS();\r
+void Shutdown();\r
+\r
+#endif\r
+\r
diff --git a/server/src/patch/main.cpp b/server/src/patch/main.cpp
new file mode 100644 (file)
index 0000000..b2c7e80
--- /dev/null
@@ -0,0 +1,66 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+\r
+\r
+        MODIFIED: 01 Jul 2006 hammag\r
+             REASON: - commented out sched_yield() in main loop, as it is\r
+                     not needed anymore with a right timeout for ReadSetTCP select\r
+\r
+*/                     \r
+#include "main.h"\r
+\r
+// for handling strg-c signal to shutdown in correct way\r
+void signal_handler(int signal)\r
+{\r
+    if (signal == SIGINT)\r
+    {\r
+        Shutdown();\r
+    }\r
+    else\r
+    {\r
+        psignal(signal, "Unkown signal: ");\r
+    }\r
+}\r
+\r
+int main()\r
+{\r
+    // Connect signal with handlerfunction\r
+    signal(SIGINT, signal_handler);\r
+\r
+\r
+       if(!InitTinNS())\r
+               while(1)\r
+                       sleep(1);\r
+\r
+       PatchServer->Start();\r
+       Console->Print("Patchserver is now %s. Waiting for clients...", Console->ColorText(GREEN, BLACK, "Online"));\r
+\r
+       while(1)\r
+       {\r
+         ServerSock->update();\r
+         Server->Update();\r
+               PatchServer->Update();\r
+               // sched_yield();\r
+       }\r
+\r
+\r
+       return 0;\r
+}\r
+\r
diff --git a/server/src/patch/main.h b/server/src/patch/main.h
new file mode 100644 (file)
index 0000000..ce0f6bc
--- /dev/null
@@ -0,0 +1,55 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+/*\r
+    MODIFIED: 6 Jul 2006 Hammag\r
+         REASON: - moved include "types.h" before include "../netcode/main.h" to permit compile\r
+*/\r
+\r
+#ifndef MAIN_H\r
+#define MAIN_H\r
+\r
+//#include "version.h"\r
+\r
+#define PATCH_PORT 7000\r
+#define MAX_PATCH_CLIENTS 50\r
+\r
+//basic includes\r
+#include "external.h"\r
+\r
+//tinns includes\r
+#include "types.h"\r
+#include "netcode.h"\r
+\r
+#include "console.h"\r
+#include "config.h"\r
+#include "filesystem.h"\r
+#include "client.h"\r
+#include "server.h"\r
+#include "patchserver.h"\r
+#include "misc.h"\r
+#include "globals.h"\r
+\r
+using namespace std;\r
+\r
+#endif\r
+\r
diff --git a/server/src/patch/patchserver.cpp b/server/src/patch/patchserver.cpp
new file mode 100644 (file)
index 0000000..d4915f1
--- /dev/null
@@ -0,0 +1,548 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+        patchserver.cpp\r
+\r
+        Authors:\r
+        - Akiko\r
+        - Namikon\r
+        - someone else?\r
+\r
+        MODIFIED: Unknown date / Unknown author\r
+        REASON: - initial release by unknown\r
+\r
+        MODIFIED: 25 Dec 2005 Namikon\r
+        REASON: - Added GPL\r
+        MODIFIED: 06 Jan 2006 Namikon\r
+        REASON: - Added color to console outputs\r
+        \r
+        MODIFIED: 01 Jul 2006 hammag\r
+        REASON: - added set timeout to 10 msec (for ReadSetTCP select) in Start()\r
+                       to avoid useless 100% CPU use\r
+             MODIFIED: 11 Dec 2006 hammag\r
+             REASON: - Display the client id in Client connection message rather than the always increasing mNumClients\r
+                     - Removed use of mNumClients in PPatchServer. the count is done in PServer.\r
+\r
+        ToDo:\r
+          - Take main loop timeout setting from config file\r
+*/\r
+\r
+#include "main.h"\r
+\r
+struct PPatchState\r
+{\r
+       enum State\r
+       {\r
+               PS_UNKNOWN,\r
+               PS_CONNECTED,\r
+               PS_HANDSHAKE0,\r
+               PS_HANDSHAKE1,\r
+               PS_VERSIONREQUEST,\r
+               PS_GETPATCHORFILE,\r
+               PS_SENDPATCH,\r
+               PS_SENDFILE\r
+       } mState;\r
+\r
+       u16 mSerial;\r
+\r
+       u32 mCurrentPatch;\r
+       u32 mPatchOffset;\r
+       u32 mPatchSize;\r
+       std::FILE *mPatchFile;\r
+\r
+       std::string mCurrentFile;\r
+       u32 mFileOffset;\r
+       u32 mFileSize;\r
+       PFile *mSendFile;\r
+\r
+       bool mWaitSend; // wait-for-completition flag\r
+       PPatchState()\r
+       {\r
+               mState = PS_UNKNOWN;\r
+               mSerial = 0;\r
+               mCurrentPatch = 0;\r
+               mPatchOffset = 0;\r
+               mPatchFile = 0;\r
+\r
+               mCurrentFile = "";\r
+               mFileOffset = 0;\r
+               mFileSize = 0;\r
+               mSendFile = 0;\r
+\r
+               mWaitSend = false;\r
+       };\r
+\r
+       ~PPatchState()\r
+       {\r
+               if(mPatchFile)\r
+                       std::fclose(mPatchFile);\r
+               if(mSendFile)\r
+                       Filesystem->Close(mSendFile);\r
+       }\r
+};\r
+\r
+// -------------------------------------------------------\r
+\r
+PPatchServer::PPatchServer()\r
+{\r
+       //mNumClients = 1;\r
+       mNumFileTransfers = 0;\r
+}\r
+\r
+PPatchServer::~PPatchServer()\r
+{\r
+    ServerSock->closeServer();\r
+\r
+       for(PatchStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end(); i++)\r
+               delete i->second;\r
+}\r
+\r
+void PPatchServer::Start()\r
+{\r
+       u16 Port = Config->GetOptionInt("patchserver_port");\r
+       if(Port==0)\r
+               Port=PATCH_PORT;\r
+\r
+       Console->LPrint("Starting Patchserver on port %i...", Port);\r
+       if(ServerSock->open(Port))\r
+       {\r
+           Console->LPrint(GREEN, BLACK, "Success");\r
+       }\r
+       else\r
+       {\r
+               Console->LPrint(RED, BLACK, "ERROR");\r
+       }\r
+       Console->LClose();\r
+       ServerSock->settimeout(0, 10000);\r
+}\r
+\r
+void PPatchServer::Update()\r
+{\r
+    //ServerSock->update();\r
+\r
+       if(ServerSock->newConnection())\r
+       {\r
+               int clid = Server->NewClient();\r
+               if(clid!=-1)\r
+               {\r
+                       Console->Print(GREEN, BLACK, "Patchserver: client [%i] connected", clid);\r
+                       PClient *Client = Server->GetClient(clid);\r
+\r
+                       ConnectionTCP* tcpConn = ServerSock->getTCPConnection();\r
+                       Client->setTCPConnection(tcpConn);\r
+\r
+                       Console->Print("Client address: %s", Client->GetAddress());\r
+                       //++mNumClients;\r
+\r
+                       PPatchState *state = new PPatchState();\r
+                       ClientStates.insert(std::make_pair(Client, state));\r
+                       state->mState = PPatchState::PS_CONNECTED;\r
+               } else\r
+               {\r
+                       Console->Print("Patchserver: Client connection refused (server full?)");\r
+               }\r
+       }\r
+\r
+       for(PatchStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end();)\r
+       {\r
+               PClient *Client = i->first;\r
+               PPatchState *State = i->second;\r
+               // node gets erased in FinalizeClient, increment iterator now\r
+               ++i;\r
+               if(!ProcessClient(Client, State))\r
+               {\r
+                       FinalizeClient(Client, State);\r
+               }\r
+       }\r
+}\r
+\r
+void PPatchServer::FinalizeClient(PClient *Client, PPatchState *State)\r
+{\r
+       Console->Print(RED, BLACK, "Patchserver: client %s disconnected", Client->GetAddress());\r
+       Client->PatchDisconnect();\r
+       ClientStates.erase(Client);\r
+       if(State->mPatchFile)\r
+               --mNumFileTransfers;\r
+       if(State->mSendFile)\r
+               --mNumFileTransfers;\r
+       delete State;\r
+}\r
+\r
+// completes pending packets before disconnect\r
+void PPatchServer::FinalizeClientDelayed(PClient *Client, PPatchState *State)\r
+{\r
+       Console->Print("Patchserver: client %i is about to be disconnected", Client->GetIndex());\r
+       State->mWaitSend = true;\r
+}\r
+\r
+void PPatchServer::ClientDisconnected(PClient *Client)\r
+{\r
+       PatchStateMap::iterator node = ClientStates.find(Client);\r
+       if(node == ClientStates.end())\r
+               return;\r
+\r
+       PPatchState *State = node->second;\r
+       FinalizeClient(Client, State);\r
+}\r
+\r
+bool PPatchServer::HandleHandshake(PClient *Client, PPatchState *State, const u8 *Packet, int PacketSize)\r
+{\r
+       static const u8 HANDSHAKE1A[6]={0xfe, 0x03, 0x00, 0x80, 0x01, 0x73};\r
+\r
+       ConnectionTCP *Socket = Client->getTCPConn();\r
+\r
+       switch(State->mState)\r
+       {\r
+               case PPatchState::PS_HANDSHAKE0 :\r
+               {\r
+                       if(PacketSize==6 && *(u16*)&Packet[3]==0x0280 && Packet[5]==0x64)\r
+                       {\r
+                               Socket->write(HANDSHAKE1A, sizeof(HANDSHAKE1A));\r
+                               State->mState = PPatchState::PS_HANDSHAKE1;\r
+                       } else\r
+                       {\r
+                               Console->Print("Patchserver protocol error (PS_HANDSHAKE0): invalid packet [%04x]", *(u16*)&Packet[3]);\r
+                               return false;\r
+                       }\r
+\r
+                       break;\r
+               }\r
+\r
+               case PPatchState::PS_HANDSHAKE1 :\r
+               {\r
+                       if(PacketSize==6 && *(u16*)&Packet[3]==0x0080 && Packet[5]==0x6c)\r
+                               State->mState = PPatchState::PS_VERSIONREQUEST;\r
+                       else\r
+                       {\r
+                               Console->Print("Patchserver protocol error (PS_HANDSHAKE1): invalid packet [%04x]", *(u16*)&Packet[3]);\r
+                               return false;\r
+                       }\r
+                       break;\r
+               }\r
+               default:\r
+                       break;\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+bool PPatchServer::HandleVersionRequest(PClient *Client, PPatchState *State, const u8 *Packet, int PacketSize)\r
+{\r
+       static u8 VERSIONPACKET[13]={0xfe, 0x0a, 0x00, 0x37, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\r
+\r
+       ConnectionTCP *Socket = Client->getTCPConn();\r
+       if(PacketSize==9 && *(u16*)&Packet[3]==0x007b)\r
+       {\r
+               State->mSerial = *(u16*)&Packet[7];\r
+               *(u16*)&VERSIONPACKET[7]=State->mSerial;\r
+               u32 ver = Config->GetOptionInt("server_version");\r
+               *(u32*)&VERSIONPACKET[9]=ver;\r
+               Socket->write(VERSIONPACKET, 13);\r
+               State->mState = PPatchState::PS_GETPATCHORFILE;\r
+       } else\r
+       {\r
+               Console->Print("Patchserver protocol error (PS_VERSIONREQUEST): invalid packet [%04x]", *(u16*)&Packet[3]);\r
+               return false;\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+bool PPatchServer::HandleFileRequests(PClient *Client, PPatchState *State, const u8 *Packet, int PacketSize)\r
+{\r
+       static u8 STARTPATCH[13]={0xfe, 0x0a, 0x00, 0x38, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\r
+       static u8 STARTFILE[13]={0xfe, 0x0a, 0x00, 0x3b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\r
+       static u8 FILEERROR[9]={0xfe, 0x06, 0x00, 0x3d, 0x02, 0x00, 0x00, 0x00, 0x00};\r
+\r
+       ConnectionTCP *Socket = Client->getTCPConn();\r
+       // request patch\r
+       if(PacketSize==13 && *(u16*)&Packet[3]==0x007c)\r
+       {\r
+               int nmax = Config->GetOptionInt("max_file_xfers");\r
+               if(mNumFileTransfers>=nmax)\r
+               {\r
+                       Console->Print("Patchserver: max file xfers exceed, killing client %i", Client->GetIndex());\r
+                       return false;\r
+               }\r
+               if(State->mPatchFile)\r
+               {\r
+                       std::fclose(State->mPatchFile);\r
+                       State->mPatchFile=0;\r
+                       --mNumFileTransfers;\r
+               }\r
+               if(State->mSendFile)\r
+               {\r
+                       Filesystem->Close(State->mSendFile);\r
+                       State->mSendFile=0;\r
+                       --mNumFileTransfers;\r
+               }\r
+               State->mSerial = *(u16*)&Packet[7];\r
+               State->mCurrentPatch = *(u32*)&Packet[9];\r
+               Console->Print("Patchserver: Patch request from client %i (v%i)", Client->GetIndex(), State->mCurrentPatch);\r
+               if((bool)(State->mPatchSize = StartPatch(State)))\r
+               {\r
+                       Console->Print("Patchserver: Patch is available, %d bytes", State->mPatchSize);\r
+                       *(u16*)&STARTPATCH[7]=State->mSerial;\r
+                       *(u32*)&STARTPATCH[9]=State->mPatchSize;\r
+                       Socket->write(STARTPATCH, 13);\r
+                       State->mState = PPatchState::PS_SENDPATCH;\r
+               } else\r
+               {\r
+                       Console->Print("Patchserver: Patch not available");\r
+                       *(u16*)&FILEERROR[7]=State->mSerial;\r
+                       Socket->write(FILEERROR, 9);\r
+                       FinalizeClientDelayed(Client, State);\r
+                       State->mState=PPatchState::PS_UNKNOWN;\r
+                       return true;\r
+               }\r
+       } else\r
+       // request file\r
+       if(PacketSize > 9 && *(u16*)&Packet[3]==0x004d)\r
+       {\r
+               int nmax = Config->GetOptionInt("max_file_xfers");\r
+               if(mNumFileTransfers>=nmax)\r
+               {\r
+                       Console->Print("Patchserver: max file xfers exceed, killing client %i", Client->GetIndex());\r
+                       return false;\r
+               }\r
+               if(State->mPatchFile)\r
+               {\r
+                       std::fclose(State->mPatchFile);\r
+                       State->mPatchFile=0;\r
+                       --mNumFileTransfers;\r
+               }\r
+               if(State->mSendFile)\r
+               {\r
+                       Filesystem->Close(State->mSendFile);\r
+                       State->mSendFile=0;\r
+                       --mNumFileTransfers;\r
+               }\r
+               // request file\r
+               State->mSerial = *(u16*)&Packet[7];\r
+               char fn[256];\r
+               strncpy(fn, (const char*)&Packet[10], Packet[9]);\r
+               fn[Packet[9]]=0;\r
+               State->mCurrentFile = fn;\r
+\r
+               Console->Print("Patchserver: File request from client %i (%s)", Client->GetIndex(), fn);\r
+               if((bool)(State->mFileSize = StartFile(State)))\r
+               {\r
+                       Console->Print("Patchserver: File %s is available, %d bytes", State->mCurrentFile.c_str(), State->mFileSize);\r
+                       *(u16*)&STARTFILE[7]=State->mSerial;\r
+                       *(u32*)&STARTFILE[9]=State->mFileSize;\r
+                       Socket->write(STARTFILE, 13);\r
+                       State->mState = PPatchState::PS_SENDFILE;\r
+               } else\r
+               {\r
+                       Console->Print("Patchserver: Requested file %s not available", State->mCurrentFile.c_str());\r
+                       *(u16*)&FILEERROR[7]=State->mSerial;\r
+                       Socket->write(FILEERROR, 9);\r
+                       FinalizeClientDelayed(Client, State);\r
+                       State->mState=PPatchState::PS_UNKNOWN;\r
+                       return true;\r
+               }\r
+       } else\r
+       // send patch data\r
+       if(PacketSize==17 && *(u16*)&Packet[3]==0x007d)\r
+       {\r
+               State->mSerial = *(u16*)&Packet[7];\r
+               State->mCurrentPatch = *(u32*)&Packet[9];\r
+               State->mPatchOffset = *(u32*)&Packet[13];\r
+               if(!SendPatchData(Client, State))\r
+               {\r
+                       Console->Print("Patchserver: SendPatchData failed on client %i", Client->GetIndex());\r
+                       Console->Print("Patchserver: (probably due to garbage packets)");\r
+                       // state is undefined now, kill this client\r
+                       return false;\r
+               }\r
+       } else\r
+       // send file data\r
+       if(PacketSize > 13 && *(u16*)&Packet[3]==0x00037)\r
+       {\r
+               State->mSerial = *(u16*)&Packet[7];\r
+               State->mFileOffset = *(u32*)&Packet[9];\r
+               if(!SendFileData(Client, State))\r
+               {\r
+                       Console->Print("Patchserver: SendFileData failed on client %i", Client->GetIndex());\r
+                       Console->Print("Patchserver: (probably due to garbage packets)");\r
+                       // state is undefined now, kill this client\r
+                       return false;\r
+               }\r
+       } else\r
+       {\r
+               Console->Print("Patchserver protocol error (PS_GETPATCHORFILE): unknown packet");\r
+               return false;\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+u32 PPatchServer::StartPatch(PPatchState *State)\r
+{\r
+       /*std::*/stringstream path;\r
+       char patchname[13];\r
+       snprintf(patchname, 13, "sp%06d.pat", State->mCurrentPatch);\r
+       path << Config->GetOption("patches_path") << "/" << patchname << '\0';\r
+       State->mPatchFile = std::fopen(path.str().c_str(), "rb");\r
+       if(State->mPatchFile)\r
+       {\r
+               ++mNumFileTransfers;\r
+               fseek(State->mPatchFile, 0, SEEK_END);\r
+               u32 size = ftell(State->mPatchFile);\r
+               fseek(State->mPatchFile, 0, SEEK_SET);\r
+               return size;\r
+       }\r
+       return 0;\r
+}\r
+\r
+bool PPatchServer::SendPatchData(PClient *Client, PPatchState *State) const\r
+{\r
+       if(!State->mPatchFile)\r
+               return false;\r
+\r
+       u16 size = Config->GetOptionInt("patch_packet_size");\r
+\r
+       const int BUFFERSIZE = 4082;\r
+\r
+       size = std::min(BUFFERSIZE, std::max((s32)size, 64));\r
+       static u8 Buffer[BUFFERSIZE+13];\r
+\r
+       if(fseek(State->mPatchFile, State->mPatchOffset, SEEK_SET)!=0)\r
+               return false;\r
+\r
+       size = fread(&Buffer[13], 1, size, State->mPatchFile);\r
+       Buffer[0]=0xfe;\r
+       *(u16*)&Buffer[1]=size+10;\r
+       Buffer[3]=0x39;\r
+       Buffer[4]=0x02;\r
+       Buffer[5]=0x00;\r
+       Buffer[6]=0x00;\r
+       *(u16*)&Buffer[7]=State->mSerial;\r
+       *(u32*)&Buffer[9]=size;\r
+       return Client->getTCPConn()->write(Buffer, size+13)==size+13;\r
+}\r
+\r
+u32 PPatchServer::StartFile(PPatchState *State)\r
+{\r
+       // security checks: reject file paths containing ':', '..' or slashes/backslashes at the beginning\r
+       if((State->mCurrentFile.find(':') != std::string::npos)\r
+               || (State->mCurrentFile.find("..") != std::string::npos)\r
+               || (State->mCurrentFile.find('/') == 0)\r
+               || (State->mCurrentFile.find('\\') == 0))\r
+       {\r
+               return 0;\r
+       }\r
+\r
+       //std::stringstream path;\r
+       //path << Config->GetOption("file_path") << "/" << State->mCurrentFile << '\0';\r
+       State->mSendFile = Filesystem->Open("", State->mCurrentFile.c_str(), Config->GetOption("file_path"));\r
+       if(State->mSendFile)\r
+       {\r
+               ++mNumFileTransfers;\r
+               u32 size = State->mSendFile->GetSize();\r
+               return size;\r
+       }\r
+       return 0;\r
+}\r
+\r
+bool PPatchServer::SendFileData(PClient *Client, PPatchState *State) const\r
+{\r
+       if(!State->mSendFile)\r
+               return false;\r
+\r
+       u16 size = Config->GetOptionInt("patch_packet_size");\r
+\r
+       const int BUFFERSIZE = 4082;\r
+\r
+       size = std::min(BUFFERSIZE, std::max((s32)size, 1));\r
+       static u8 Buffer[BUFFERSIZE+13];\r
+\r
+       State->mSendFile->Seek(State->mFileOffset);\r
+\r
+       size = State->mSendFile->Read(&Buffer[13], size);\r
+       Buffer[0]=0xfe;\r
+       *(u16*)&Buffer[1]=size+10;\r
+       Buffer[3]=0x3c;\r
+       Buffer[4]=0x02;\r
+       Buffer[5]=0x00;\r
+       Buffer[6]=0x00;\r
+       *(u16*)&Buffer[7]=State->mSerial;\r
+       *(u32*)&Buffer[9]=size;\r
+       return Client->getTCPConn()->write(Buffer, size+13)==size+13;\r
+}\r
+\r
+bool PPatchServer::ProcessClient(PClient *Client, PPatchState *State)\r
+{\r
+       static const u8 HANDSHAKE0A[6]={0xfe, 0x03, 0x00, 0x80, 0x03, 0x6b};\r
+\r
+       if(!State)\r
+       {\r
+               PatchStateMap::iterator node = ClientStates.find(Client);\r
+               if(node == ClientStates.end())\r
+                       return false;\r
+\r
+               State = node->second;\r
+       }\r
+\r
+       ConnectionTCP *Socket = Client->getTCPConn();\r
+\r
+       if(State->mWaitSend && Socket->getSendBufferSize()==0)\r
+               return false;\r
+\r
+       if(State->mState==PPatchState::PS_CONNECTED)\r
+       {\r
+           Console->Print("Sending Handshake 0A");\r
+               Socket->write(HANDSHAKE0A, sizeof(HANDSHAKE0A));\r
+               //short unsigned int packet = (short unsigned int) HANDSHAKE0A;\r
+               //Socket->write(htons(packet));\r
+               State->mState = PPatchState::PS_HANDSHAKE0;\r
+               Socket->flushSendBuffer();\r
+       }\r
+\r
+       int PacketSize=0;\r
+       const u8 *Packet = Socket->read(&PacketSize);\r
+       if(PacketSize > 0)\r
+       {\r
+               switch(State->mState)\r
+               {\r
+                       case PPatchState::PS_HANDSHAKE1 :\r
+                       case PPatchState::PS_HANDSHAKE0 :\r
+                Console->Print("Handling Handshake 0 and 1");\r
+                               return HandleHandshake(Client, State, Packet, PacketSize);\r
+\r
+                       case PPatchState::PS_VERSIONREQUEST :\r
+                Console->Print("Handling Client Versionsrequest");\r
+                               return HandleVersionRequest(Client, State, Packet, PacketSize);\r
+\r
+                       case PPatchState::PS_GETPATCHORFILE :\r
+                       case PPatchState::PS_SENDPATCH :\r
+                       case PPatchState::PS_SENDFILE :\r
+                Console->Print("Getpatchforfile, sendpatch, sendfile");\r
+                               return HandleFileRequests(Client, State, Packet, PacketSize);\r
+                       default:\r
+                               break;\r
+               }\r
+       }\r
+       return true;\r
+}\r
diff --git a/server/src/patch/patchserver.h b/server/src/patch/patchserver.h
new file mode 100644 (file)
index 0000000..790da48
--- /dev/null
@@ -0,0 +1,60 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+#ifndef PATCHSERVER_H\r
+#define PATCHSERVER_H\r
+\r
+#ifdef _MSC_VER\r
+       #pragma once\r
+#endif\r
+\r
+class PPatchServer\r
+{\r
+       private :\r
+               int mNumClients;\r
+               int mNumFileTransfers;\r
+               typedef std::map<PClient*, struct PPatchState*> PatchStateMap;\r
+               PatchStateMap ClientStates;\r
+       protected :\r
+               bool ProcessClient(PClient *Client, PPatchState *State=0);\r
+//             u32 StartPatch(PClient *Client, PPatchState *State);\r
+               u32 StartPatch(PPatchState *State);\r
+               bool SendPatchData(PClient *Client, PPatchState *State) const;\r
+//             u32 StartFile(PClient *Client, PPatchState *State);\r
+               u32 StartFile(PPatchState *State);\r
+               bool SendFileData(PClient *Client, PPatchState *State) const;\r
+               void FinalizeClient(PClient *Client, PPatchState *State);\r
+               void FinalizeClientDelayed(PClient *Client, PPatchState *State);\r
+\r
+               bool HandleHandshake(PClient *Client, PPatchState *State, const u8 *Packet, int PacketSize);\r
+               bool HandleVersionRequest(PClient *Client, PPatchState *State, const u8 *Packet, int PacketSize);\r
+               bool HandleFileRequests(PClient *Client, PPatchState *State, const u8 *Packet, int PacketSize);\r
+       public :\r
+               PPatchServer();\r
+               ~PPatchServer();\r
+\r
+               void Start();\r
+               void Update();\r
+               void ClientDisconnected(PClient *Client);\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/src/patch/server.cpp b/server/src/patch/server.cpp
new file mode 100644 (file)
index 0000000..8337b01
--- /dev/null
@@ -0,0 +1,100 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+#include "main.h"\r
+\r
+PServer::PServer()\r
+{\r
+       mNumClients = 0;\r
+       mMaxClients = Config->GetOptionInt("maxclients");\r
+       mGMSlots = Config->GetOptionInt("gm_slots");\r
+\r
+       if(mMaxClients==0)\r
+               mMaxClients=1;\r
+       if(mGMSlots==0)\r
+               mGMSlots=1;\r
+       mClients.reserve(mMaxClients + mGMSlots);\r
+       for(int i=0; i<mMaxClients+mGMSlots; i++)\r
+               mClients[i]=0;\r
+}\r
+\r
+PServer::~PServer()\r
+{\r
+       for(int i=0; i<mMaxClients+mGMSlots; i++)\r
+               delete mClients[i];\r
+}\r
+\r
+int PServer::NewClient()\r
+{\r
+//Console->Print("%d %d", mMaxClients, mGMSlots);\r
+       if(mNumClients==mMaxClients+mGMSlots)\r
+               return -1;\r
+       for(int i=0; i<mMaxClients+mGMSlots; i++)\r
+       {\r
+               if(!mClients[i])\r
+               {\r
+                       mClients[i]=new PClient(i);\r
+                       ++mNumClients;\r
+                       return i;\r
+               }\r
+       }\r
+       return -1;\r
+}\r
+\r
+PClient *PServer::GetClient(int Client) const\r
+{\r
+       if(Client < 0 || Client >= mMaxClients+mGMSlots)\r
+               return 0;\r
+\r
+       return mClients[Client];\r
+}\r
+\r
+void PServer::Update()\r
+{\r
+       for(int i=0; i<mMaxClients+mGMSlots; i++)\r
+       {\r
+               if(mClients[i])\r
+               {\r
+                       mClients[i]->Update();\r
+                       if(mClients[i]->GetConnection()==PCC_NONE && mClients[i]->getTCPConn() == 0)\r
+                       {\r
+                               Console->Print("Removing client ...");\r
+                               delete mClients[i];\r
+                               mClients[i]=0;\r
+                               --mNumClients;\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+void PServer::Shutdown()\r
+{\r
+    Console->Print("======================");\r
+       Console->Print("Shutting down Patchserver...");\r
+       for(int i=0; i<mMaxClients+mGMSlots; i++)\r
+       {\r
+               if(mClients[i])\r
+               {\r
+                       delete mClients[i];\r
+                       mClients[i]=0;\r
+               }\r
+       }\r
+}\r
diff --git a/server/src/patch/server.h b/server/src/patch/server.h
new file mode 100644 (file)
index 0000000..1a4b6d2
--- /dev/null
@@ -0,0 +1,47 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       Copyright (C) 2005 Linux Addicted Community\r
+       maintainer Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+#ifndef SERVER_H\r
+#define SERVER_H\r
+\r
+class PServer\r
+{\r
+       private :\r
+               int mMaxClients;\r
+               int mGMSlots;\r
+               int mNumClients;\r
+               std::vector<PClient*> mClients;\r
+       protected :\r
+       public :\r
+               PServer();\r
+               ~PServer();\r
+\r
+               inline int GetMaxClients() const { return mMaxClients; }\r
+               inline int GetGMSlots() const { return mGMSlots; }\r
+               inline int GetNumClients() const { return mNumClients; }\r
+               int NewClient();\r
+               PClient *GetClient(int Client) const;\r
+               void Update();\r
+               void Shutdown();\r
+};\r
+\r
+#endif\r
+\r
diff --git a/server/tinns b/server/tinns
new file mode 100644 (file)
index 0000000..9eae49e
--- /dev/null
@@ -0,0 +1,360 @@
+#! /bin/bash
+       
+# TinNS (TinNS is not a Neocron Server)
+# Copyright (C) 2005 Linux Addicted Community
+# maintainer Akiko <akiko@gmx.org>
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+# =====================================================
+# 
+# TinNS control script
+# written by Namikon
+# 
+
+#
+# Settings (Change them if you want)
+
+# TINNS_DIR
+#  Main dir of the 3 executables "patchserver", "infoserver" and "gameserver"
+#  If this script is located in the server's directory, set this to '.'
+TINNS_DIR=.
+
+# IGNORE_ROOT
+# for security reasons, you should never run any deamon as root. Therefore, we stop the script from running.
+# If you still want to run TinNS as root, set this value to "true"
+IGNORE_ROOT=true
+
+# RUN_AS
+# If you want to start TinNS while server's boot time, uncomment RUN_AS and set the
+# accountname the server should run as.
+# Its a bad idea if you only want to use this script to start/stop the server by
+# normal users, since you'd have to enter the password for the target user everytime.
+#RUN_AS=tinns
+
+# EOS (EndOfSettings. Dont change anything below, unless you know what you're doing)
+
+
+
+cd $TINNS_DIR
+uid=`id -u $RUN_AS`
+if [ -z $uid ]; then
+       uid=$UID
+fi
+
+case "$1" in
+       start)
+# PATCHSERVER
+               if [ -e patchserver.pid ]; then
+                       echo "patchserver.pid exists... Is server running?";
+                       PID=`cat patchserver.pid`
+                       if [ `ps -A|grep "$PID"|grep patchserver|wc -c` -gt 5 ]; then
+                               echo "WARNING: patchserver process found! If you're sure the patchserver not running, remove patchserver.pid"
+                               exit 1
+                       else
+                               echo "Either the patchserver died or you kill'ed it outside this script."
+                               echo "Removing patchserver.pid..."
+                               rm patchserver.pid
+                               echo "done"
+                       fi
+               fi
+
+# INFOSERVER
+               if [ -e infoserver.pid ]; then
+                       echo "infoserver.pid exists... Is server running?";
+                       PID=`cat infoserver.pid`
+                       if [ `ps -A|grep "$PID"|grep infoserver|wc -c` -gt 5 ]; then
+                               echo "WARNING: infoserver process found! If you're sure the infoserver not running, remove infoserver.pid"
+                               exit 1
+                       else
+                               echo "Either the infoserver died or you kill'ed it outside this script."
+                               echo "Removing infoserver.pid..."
+                               rm infoserver.pid
+                               echo "done"
+                       fi
+               fi
+
+# GAMESERVER
+               if [ -e gameserver.pid ]; then
+                       echo "gameserver.pid exists... Is server running?";
+                       PID=`cat gameserver.pid`
+                       if [ `ps -A|grep "$PID"|grep gameserver|wc -c` -gt 5 ]; then
+                               echo "WARNING: gameserver process found! If you're sure the gameserver not running, remove gameserver.pid"
+                               exit 1
+                       else
+                               echo "Either the gameserver died or you kill'ed it outside this script."
+                               echo "Removing gameserver.pid..."
+                               rm gameserver.pid
+                               echo "done"
+                       fi
+               fi
+####################
+               if (! $IGNORE_ROOT) && [ "$uid" = "0" ]; then
+                       echo ">>WARNING>> DO NOT RUN THE SERVER AS ROOT <<WARNING<<"
+                       for c in $(seq 1 10); do
+                               echo -n "!"
+                               sleep 1
+                       done
+                       echo !
+                       exit 6
+               fi
+               echo "Starting TinNS..."
+
+# PATCHSERVER
+               if [ -e patchserver ]; then
+                       if [ ! -x patchserver ]; then
+                               echo "patchserver is not executable. Now trying to set it..."
+                               chmod u+x patchserver
+                       fi
+                       if [ -x patchserver ]; then
+                               SUCMD=''
+                               if [ "$RUN_AS" ]; then
+                                       su $RUN_AS -c "./patchserver -PID=patchserver.pid"
+                               else
+                                       ./patchserver -PID=patchserver.pid
+                               fi
+                       else
+                               echo "STOP: patchserver is not executable. Please fix this!"
+                               exit 4
+                       fi
+               else
+                       echo "Unable to find patchserver"
+                       exit 5
+               fi
+
+# INFOSERVER
+               if [ -e infoserver ]; then
+                       if [ ! -x infoserver ]; then
+                               echo "infoserver is not executable. Now trying to set it..."
+                               chmod u+x infoserver
+                       fi
+                       if [ -x infoserver ]; then
+                               SUCMD=''
+                               if [ "$RUN_AS" ]; then
+                                       su $RUN_AS -c "./infoserver -PID=infoserver.pid"
+                               else
+                                       ./infoserver -PID=infoserver.pid
+                               fi
+                       else
+                               echo "STOP: infoserver is not executable. Please fix this!"
+                               exit 4
+                       fi
+               else
+                       echo "Unable to find infoserver"
+                       exit 5
+               fi
+
+# GAMESERVER
+               if [ -e gameserver ]; then
+                       if [ ! -x gameserver ]; then
+                               echo "gameserver is not executable. Now trying to set it..."
+                               chmod u+x gameserver
+                       fi
+                       if [ -x gameserver ]; then
+                               SUCMD=''
+                               if [ "$RUN_AS" ]; then
+                                       su $RUN_AS -c "./gameserver -PID=gameserver.pid"
+                               else
+                                       ./gameserver -PID=gameserver.pid
+                               fi
+                       else
+                               echo "STOP: gameserver is not executable. Please fix this!"
+                               exit 4
+                       fi
+               else
+                       echo "Unable to find gameserver"
+                       exit 5
+               fi
+####################
+       ;;
+
+    stop)
+
+# PATCHSERVER
+               if [ -e patchserver.pid ]; then
+                       echo -n "Now stopping patchserver"
+                       if ( kill -TERM `cat patchserver.pid` ); then
+                               for c in $(seq 1 300); do
+                                       if [ -e patchserver.pid ]; then
+                                               echo -n "."
+                                               sleep 1
+                                       fi
+                               done
+                       fi
+                       if [ -e patchserver.pid ]; then
+                               echo "NOTICE: patchserver does not shutdown cleanly - killing now"
+                               kill -KILL `cat patchserver.pid`
+                               rm patchserver.pid
+                               sleep 5
+                       else
+                               echo "done"
+                       fi
+               else
+                       echo "patchserver.pid is missing, no patchserver running?"
+                       exit 7
+               fi
+
+# INFOSERVER
+               if [ -e infoserver.pid ]; then
+                       echo -n "Now stopping infoserver"
+                       if ( kill -TERM `cat infoserver.pid` ); then
+                               for c in $(seq 1 300); do
+                                       if [ -e infoserver.pid ]; then
+                                               echo -n "."
+                                               sleep 1
+                                       fi
+                               done
+                       fi
+                       if [ -e infoserver.pid ]; then
+                               echo "NOTICE: infoserver does not shutdown cleanly - killing now"
+                               kill -KILL `cat infoserver.pid`
+                               rm infoserver.pid
+                               sleep 5
+                       else
+                               echo "done"
+                       fi
+               else
+                       echo "infoserver.pid is missing, no infoserver running?"
+                       exit 7
+               fi
+
+# GAMESERVER
+               if [ -e gameserver.pid ]; then
+                       echo -n "Now stopping gameserver"
+                       if ( kill -TERM `cat gameserver.pid` ); then
+                               for c in $(seq 1 300); do
+                                       if [ -e gameserver.pid ]; then
+                                               echo -n "."
+                                               sleep 1
+                                       fi
+                               done
+                       fi
+                       if [ -e gameserver.pid ]; then
+                               echo "NOTICE: gameserver does not shutdown cleanly - killing now"
+                               kill -KILL `cat gameserver.pid`
+                               rm gameserver.pid
+                               sleep 5
+                       else
+                               echo "done"
+                       fi
+               else
+                       echo "gameserver.pid is missing, no patchserver running?"
+                       exit 7
+               fi
+
+####################
+
+       ;;
+       restart)
+               $0 stop && $0 start || exit 1
+       ;;
+       status)
+       # PATCHSERVER
+               PATCH_PID_ONLINE=false
+               PATCH_PROC_ONLINE=false
+
+               if [ -e patchserver.pid ]; then
+                       PATCH_PID=`cat patchserver.pid`
+                       if [ `ps -A|grep "$PATCH_PID"|wc -c` -gt 5 ]; then
+                               PATCH_PID_ONLINE=true
+                       fi
+               fi
+               
+               if [ `ps -A|grep patchserver|wc -c` -gt 5 ]; then               
+                       PATCH_PROC_ONLINE=true
+               fi
+               
+       # INFOSERVER            
+               INFO_PID_ONLINE=false
+               INFO_PROC_ONLINE=false
+
+               if [ -e infoserver.pid ]; then
+                       INFO_PID=`cat infoserver.pid`
+                       if [ `ps -A|grep "$INFO_PID"|wc -c` -gt 5 ]; then
+                               INFO_PID_ONLINE=true
+                       fi
+               fi
+               
+               if [ `ps -A|grep infoserver|wc -c` -gt 5 ]; then                
+                       INFO_PROC_ONLINE=true
+               fi
+               
+       # GAMESERVER            
+               GAME_PID_ONLINE=false
+               GAME_PROC_ONLINE=false
+
+               if [ -e gameserver.pid ]; then
+                       GAME_PID=`cat gameserver.pid`
+                       if [ `ps -A|grep "$GAME_PID"|wc -c` -gt 5 ]; then
+                               GAME_PID_ONLINE=true
+                       fi
+               fi
+               
+               if [ `ps -A|grep gameserver|wc -c` -gt 5 ]; then                
+                       GAME_PROC_ONLINE=true
+               fi
+
+               PATCHSTATUS1="Patchserver is"
+               if (($PATCH_PID_ONLINE) && ($PATCH_PROC_ONLINE)); then
+                       PATCHSTATUS2="\033[32mOnline\033[0m"
+                       PATCHSTATUS3=" "
+               fi
+               if ((! $PATCH_PID_ONLINE) && ($PATCH_PROC_ONLINE)); then
+                       PATCHSTATUS2="\033[32mOnline\033[0m"
+                       PATCHSTATUS3="\033[33m[Warning]\033[0m PID file invalid or not found"
+               fi
+               if ((! $PATCH_PID_ONLINE) && (! $PATCH_PROC_ONLINE)); then
+                       PATCHSTATUS2="\033[31mOffline\033[0m"
+                       PATCHSTATUS3=" "
+               fi
+               
+               INFOSTATUS1="Infoserver  is"
+               if (($INFO_PID_ONLINE) && ($INFO_PROC_ONLINE)); then
+                       INFOSTATUS2="\033[32mOnline\033[0m"
+                       INFOSTATUS3=" "
+               fi
+               if ((! $INFO_PID_ONLINE) && ($INFO_PROC_ONLINE)); then
+                       INFOSTATUS2="\033[32mOnline\033[0m"
+                       INFOSTATUS3="\033[33m[Warning]\033[0m PID file invalid or not found"
+               fi
+               if ((! $INFO_PID_ONLINE) && (! $INFO_PROC_ONLINE)); then
+                       INFOSTATUS2="\033[31mOffline\033[0m"
+                       INFOSTATUS3=" "
+               fi
+               
+               GAMESTATUS1="Gameserver  is"
+               if (($GAME_PID_ONLINE)&& ($GAME_PROC_ONLINE)); then
+                       GAMESTATUS2="\033[32mOnline\033[0m"
+                       GAMESTATUS3=" "
+               fi
+               if ((! $GAME_PID_ONLINE) && ($GAME_PROC_ONLINE)); then
+                       GAMESTATUS2="\033[32mOnline\033[0m"
+                       GAMESTATUS3="\033[33m[Warning]\033[0m PID file invalid or not found"
+               fi
+               if ((! $GAME_PID_ONLINE) && (! $GAME_PROC_ONLINE)); then
+                       GAMESTATUS2="\033[31mOffline\033[0m"
+                       GAMESTATUS3=" "
+               fi
+               
+               echo -e "$PATCHSTATUS1 $PATCHSTATUS2 $PATCHSTATUS3"
+               echo -e "$INFOSTATUS1 $INFOSTATUS2 $INFOSTATUS3"
+               echo -e "$GAMESTATUS1 $GAMESTATUS2 $GAMESTATUS3"
+
+       ;;
+       *)
+               echo "Usage: $0 {start|stop|restart|status}"
+               exit 2
+esac
+exit 0
diff --git a/tools/getsvnrev/Makefile b/tools/getsvnrev/Makefile
new file mode 100644 (file)
index 0000000..84418db
--- /dev/null
@@ -0,0 +1,19 @@
+CC=gcc
+CXX=g++
+CFLAGS=-pedantic -Wall
+CXX_FLAGS=$(CFLAGS)
+
+SOURCES=$(wildcard *.cpp)
+OBJECTS=$(patsubst %.cpp,%.o,$(SOURCES))
+
+%.o:%.cpp
+       $(CXX) $(CXX_FLAGS) -c $< -o $@
+        
+all: getsvnrev
+
+getsvnrev: $(OBJECTS)
+       $(CXX) -o $@ $(OBJECTS) -lstdc++ -lz
+
+clean:
+       -rm $(OBJECTS) getsvnrev
+
diff --git a/tools/getsvnrev/getsvnrev.cpp b/tools/getsvnrev/getsvnrev.cpp
new file mode 100644 (file)
index 0000000..6dcd144
--- /dev/null
@@ -0,0 +1,101 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       pak_decompress - pak file decompression tool\r
+       Copyright (C) 2005 Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       getsvnrev - a simple tool to read out actual SVN revision-number\r
+\r
+       Why?\r
+               Well for example my server doesnt have any SVN libs installed. Therefore,\r
+               the getsvnrev script fails. I need this little tool, and maybe someone else too ^^\r
+\r
+       Usage: \r
+               call getsvnrev either without parameters or with the directory you\r
+               want to know the SVN revision.\r
+       \r
+       Console output:\r
+               If no .svn directory is found, the tool returns 0.\r
+               Otherwise it will return the SVN revision of the target dir\r
+\r
+       MODIFIED: 22 Dec 2006 Namikon\r
+       REASON: - started this tool\r
+\r
+       TODO:\r
+               - Better way to get SVN rev than this (2nd number in file)\r
+*/\r
+\r
+\r
+#include <stdio.h>\r
+#include <iostream>\r
+\r
+using namespace std;\r
+\r
+int main(int argc, char **argv)\r
+{\r
+        string targetdir;\r
+       FILE *f;\r
+\r
+        if(argc == 2)\r
+       {\r
+               int i = 0;\r
+               while(argv[1][i] != '\0') { i++; };\r
+               if(argv[1][i-1] == '/')\r
+               {\r
+                       targetdir = strcat(argv[1], ".svn/entries");\r
+               }\r
+               else\r
+               {\r
+                       targetdir = strcat(argv[1], "/.svn/entries");\r
+               }\r
+        }\r
+       else\r
+       {\r
+               targetdir = ".svn/entries";\r
+       }\r
+\r
+\r
+        if ((f = fopen(targetdir.c_str(), "r")) != NULL) {\r
+                char line[255];\r
+                int rev;\r
+               bool firstnrfound = false;\r
+               \r
+               do\r
+               {\r
+                  fgets (line, 255, f);\r
+                  rev = atoi(line);\r
+                  if(rev > 0 && firstnrfound == false)\r
+                  {\r
+                       firstnrfound = true;\r
+                       rev = 0;\r
+                   }\r
+               } while (rev == 0);\r
+               \r
+                fclose(f);\r
+\r
+                cout << rev << endl;\r
+        }\r
+       else\r
+       {\r
+               cout << "0" << endl;\r
+       }\r
+       return(0);\r
+}\r
diff --git a/tools/pak_decompress/Makefile b/tools/pak_decompress/Makefile
new file mode 100644 (file)
index 0000000..b6fcf0d
--- /dev/null
@@ -0,0 +1,18 @@
+CC=gcc
+CXX=g++
+CFLAGS=-pedantic -Wall
+CXX_FLAGS=$(CFLAGS)
+
+SOURCES=$(wildcard *.cpp)
+OBJECTS=$(patsubst %.cpp,%.o,$(SOURCES))
+
+%.o:%.cpp
+       $(CXX) $(CXX_FLAGS) -c $< -o $@
+        
+all: pak_decompress
+
+pak_decompress: $(OBJECTS)
+       $(CXX) -o $@ $(OBJECTS) -lstdc++ -lz
+
+clean:
+       -rm $(OBJECTS) pak_decompress
diff --git a/tools/pak_decompress/pak_decompress.cpp b/tools/pak_decompress/pak_decompress.cpp
new file mode 100644 (file)
index 0000000..395b20b
--- /dev/null
@@ -0,0 +1,241 @@
+/*\r
+       TinNS (TinNS is not a Neocron Server)\r
+       pak_decompress - pak file decompression tool\r
+       Copyright (C) 2005 Akiko <akiko@gmx.org>\r
+\r
+       This program is free software; you can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation; either version 2\r
+       of the License, or (at your option) any later version.\r
+\r
+       This program is distributed in the hope that it will be useful,\r
+       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+       GNU General Public License for more details.\r
+\r
+       You should have received a copy of the GNU General Public License\r
+       along with this program; if not, write to the Free Software\r
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
+       02110-1301, USA.\r
+*/\r
+\r
+\r
+\r
+/*\r
+       pak_decompress - a decompression tool for single pak files\r
+\r
+       MODIFIED: 23 Sep 2005 Akiko\r
+       REASON: - started this tool\r
+       MODIFIED: 26 Sep 2005 Akiko\r
+       REASON: - added printing of some information\r
+       MODIFIED: 26 Oct 2005 Akiko\r
+       REASON: - fixed an issue belonging to portability\r
+       MODIFIED: 06 Dec 2005 Akiko\r
+       REASON: - compression ration fixed\r
+       MODIFIED: 09 Dec 2005 Akiko\r
+       REASON: - fixed typo\r
+               - compression ratio\r
+       MODIFIED: 21 Dec 2006 Namikon\r
+       REASON: - Added errorcheck for in/output file\r
+               - Added check for NC and normal zLib files\r
+\r
+       TODO:   - time needed for decompression\r
+               - ideas for a compression tool\r
+*/\r
+\r
+\r
+#include <stdio.h>\r
+#include <fstream>\r
+#include <iostream>\r
+#include <zlib.h>\r
+#include <assert.h>\r
+#include <string.h>\r
+\r
+#define CHUNK 262144\r
+\r
+using namespace std;\r
+\r
+int inf(FILE *source, FILE *dest, bool details)\r
+{\r
+       int ret;\r
+       char check;\r
+       unsigned have;\r
+       z_stream strm;\r
+       unsigned char in[CHUNK];\r
+       unsigned char out[CHUNK];\r
+\r
+       strm.zalloc = Z_NULL;\r
+       strm.zfree = Z_NULL;\r
+       strm.opaque = Z_NULL;\r
+       strm.avail_in = 0;\r
+       strm.next_in = Z_NULL;\r
+       ret = inflateInit(&strm);\r
+\r
+       if (ret != Z_OK)\r
+               return(ret);\r
+\r
+       check = fgetc(source);\r
+       if(check == 'x')\r
+       {\r
+               if(details == true) cout << "Found zLibfile" << endl;\r
+               fseek(source, 0, SEEK_SET);\r
+       }\r
+       else\r
+       {\r
+               fseek(source, 16, SEEK_SET);\r
+               check = fgetc(source);\r
+               if(check == 'x')\r
+               {\r
+                       if(details == true) cout << "Found Neocron file" << endl;\r
+                       fseek(source, 16, SEEK_SET);\r
+               }\r
+               else\r
+               {\r
+                       if(details == true) cout << "Error: No compatible file!" << endl;\r
+                       return -3;\r
+               }\r
+       }\r
+\r
+       do {\r
+               strm.avail_in = fread(in, 1, CHUNK, source);\r
+\r
+               if (ferror(source)) {\r
+                       (void)inflateEnd(&strm);\r
+\r
+                       return(Z_ERRNO);\r
+               }\r
+\r
+               if (strm.avail_in == 0)\r
+                       break;\r
+               strm.next_in = in;\r
+\r
+               do {\r
+                       strm.avail_out = CHUNK;\r
+                       strm.next_out = out;\r
+                       ret = inflate(&strm, Z_NO_FLUSH);\r
+                       assert(ret != Z_STREAM_ERROR);\r
+\r
+                       switch(ret) {\r
+                               case Z_NEED_DICT:\r
+                                       ret = Z_DATA_ERROR;\r
+                               case Z_DATA_ERROR:\r
+                               case Z_MEM_ERROR:\r
+                                       (void)inflateEnd(&strm);\r
+                                       return(ret);\r
+                               }\r
+\r
+                               have = CHUNK - strm.avail_out;\r
+\r
+                               if (fwrite(out, 1, have, dest) != have || ferror(dest)) {\r
+                                       (void)inflateEnd(&strm);\r
+\r
+                               return(Z_ERRNO);\r
+                       }\r
+               } while (strm.avail_out == 0);\r
+\r
+               assert(strm.avail_in == 0);\r
+       } while (ret != Z_STREAM_END);\r
+\r
+       (void)inflateEnd(&strm);\r
+       \r
+       return(ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR);\r
+}\r
+\r
+void zerr(int ret)\r
+{\r
+       fputs("zpipe: ", stderr);\r
+\r
+       switch(ret) {\r
+               case Z_ERRNO:\r
+                       if (ferror(stdin))\r
+                               fputs("error reading stdin\n", stderr);\r
+                       if (ferror(stdout))\r
+                               fputs("error writing stdout\n", stderr);\r
+                       break;\r
+               case Z_STREAM_ERROR:\r
+                       fputs("invalid compression level\n", stderr);\r
+                       break;\r
+               case Z_DATA_ERROR:\r
+                       fputs("invalid or incomplete deflate data\n", stderr);\r
+                       break;\r
+               case Z_MEM_ERROR:\r
+                       fputs("out of memory\n", stderr);\r
+                       break;\r
+               case Z_VERSION_ERROR:\r
+                       fputs("zlib version mismatch!\n", stderr);\r
+       }\r
+}\r
+\r
+int main(int argc, char **argv) {\r
+       int ret;\r
+       long inSize;\r
+       long outSize;\r
+       bool details;\r
+       FILE *inFile;\r
+       FILE *outFile;\r
+       std::string src;\r
+       std::string dst;\r
+\r
+       if(argc == 2) {\r
+               src = argv[1];\r
+               dst = strcat(argv[1], ".decompressed");\r
+       }\r
+       else if(argc > 2 && strcmp(argv[1], argv[2])) {\r
+               src = argv[1];\r
+               dst = argv[2];\r
+       }\r
+       else {\r
+               cout << "Usage: pak_decompress source <dest != source> <detailedoutput 1/0>" << std::endl;\r
+               return(0);\r
+       }\r
+       if(argc == 4)\r
+       {\r
+               if(argv[3][0] == '1') details = true;\r
+               else if(argv[3][0] == '0') details = false;\r
+       }\r
+       else\r
+               details = false;\r
+\r
+       inFile = fopen(src.c_str(), "rb");\r
+       outFile = fopen(dst.c_str(), "wb");\r
+\r
+       if(inFile == NULL)\r
+       {\r
+               cout << "Cannot open InFile" << endl;\r
+               return(-1);\r
+       }\r
+       if(outFile == NULL)\r
+       {\r
+               cout << "Cannot open OutFile" << endl;\r
+               return(-2);\r
+       }\r
+       ret = inf(inFile, outFile, details);\r
+\r
+       /* just to be sure - we got to the end */\r
+       fseek(inFile, 0, SEEK_END);\r
+       fseek(outFile, 0, SEEK_END);\r
+       inSize = ftell(inFile);\r
+       outSize = ftell(outFile);\r
+       \r
+       fclose(outFile);\r
+       fclose(inFile);\r
+       \r
+       if(ret == Z_OK && details == true)\r
+       {\r
+               cout << "bytes read:        " << inSize << std::endl;\r
+               cout << "bytes written:     " << outSize << std::endl;\r
+               cout << "compression ratio: " << (100-((float)inSize/(float)outSize*100)) << "%" << std::endl;\r
+       }\r
+       else if(ret == Z_OK && details == false)\r
+       {\r
+               cout << "[OK]    " << src.c_str() << endl;\r
+       }\r
+       else if(ret != Z_OK && details == false)\r
+       {\r
+               cout << "[ERROR] " << src.c_str() << endl;\r
+       }\r
+\r
+       return(ret);\r
+}\r
+\r
+\r
diff --git a/tools/pak_decompress/pak_decompress.jar b/tools/pak_decompress/pak_decompress.jar
new file mode 100644 (file)
index 0000000..7758c1e
Binary files /dev/null and b/tools/pak_decompress/pak_decompress.jar differ
diff --git a/tools/vfs_viewer/Makefile b/tools/vfs_viewer/Makefile
new file mode 100644 (file)
index 0000000..bd370f0
--- /dev/null
@@ -0,0 +1,18 @@
+CC=cc
+CXX=g++
+CFLAGS=-W -Wall -O2
+CXX_FLAGS=$(CFLAGS)
+
+SOURCES=$(wildcard *.c)
+OBJECTS=$(patsubst %.c,%.o,$(SOURCES))
+
+%.o:%.c
+       $(CXX) $(CXX_FLAGS) -c $< -o $@
+        
+all: vfs_viewer
+
+vfs_viewer: $(OBJECTS)
+       $(CXX) -o $@ $(OBJECTS)
+
+clean:
+       -rm $(OBJECTS) vfs_viewer
diff --git a/tools/vfs_viewer/vfs_viewer.c b/tools/vfs_viewer/vfs_viewer.c
new file mode 100644 (file)
index 0000000..dfb9b04
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+       TinNS (TinNS is not a Neocron Server)
+       vfs_viewer.c - NC virutal file system decompression/browsing tool
+       Copyright (C) 2005 Akiko <akiko@gmx.org>
+
+       This program is free software; you can redistribute it and/or
+       modify it under the terms of the GNU General Public License
+       as published by the Free Software Foundation; either version 2
+       of the License, or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+       02110-1301, USA.
+*/
+
+
+
+/*
+       vfs_viewer.c
+
+       Authors:
+       - Akiko <akiko@gmx.org>
+
+       ToDo:
+       - remove memory leaks, a lot of memory gets reserved but not freed
+       - adding decompressing
+       - adding file selection for decompressing
+       - adding a nice gui (kde/ncurses)
+
+       MODIFIED: 09 Dec 2005 Akiko
+       REASON: - initial release
+               - just a output fix
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef unsigned int u32;
+typedef unsigned char u8;
+
+int main(int argc, char *argv[]) {
+       // structure of the file informtion inside the virtual FS
+       struct t_file_header {
+               u32 id;
+               u32 offset;
+               u32 csize;
+               u32 dsize;
+               u32 len_name;
+               u8 *name;
+       };
+       // structure of the virtual FS
+       struct t_vfs_header {
+               u32 id;
+               u32 file_count;
+               struct t_file_header *files;
+               u8 *data;
+       };
+
+       if (argc == 2) {
+               FILE *fd;
+               struct t_vfs_header vfs_file;
+
+               fd = fopen(argv[1], "rb");
+
+               // reading the vfs header including the amount of files in the virtual FS
+               fread(&vfs_file.id, sizeof(u32), 1, fd);
+               fread(&vfs_file.file_count, sizeof(u32), 1, fd);
+
+               struct t_file_header files[vfs_file.file_count];
+
+               // reading all information from the vfs into an array and print some of them
+               u32 i;
+               for (i = 0; i < vfs_file.file_count; i++) {
+                       fread(&files[i].id, sizeof(u32), 1, fd);
+                       fread(&files[i].offset, sizeof(u32), 1, fd);
+                       fread(&files[i].csize, sizeof(u32), 1, fd);
+                       fread(&files[i].dsize, sizeof(u32), 1 ,fd);
+                       fread(&files[i].len_name, sizeof(u32), 1, fd);
+
+                       files[i].name = (u8 *)malloc(sizeof(u8)*files[i].len_name);
+                       fread(files[i].name, sizeof(u8), files[i].len_name, fd);
+                       //fseek(fd, files[i].len_name, SEEK_CUR);
+
+                       printf("Filenumber %4i: %50s (%7i/%7i) ID-%2i\n", i, files[i].name, files[i].csize, files[i].dsize, files[i].id);
+               }
+               
+               fclose(fd);
+       } else {
+               printf("Usage: vfs_viewer <nc1 vfs file>\n");
+               exit(1);
+       }
+
+       exit(0);
+}
+