Advertisement
Guest User

Untitled

a guest
May 1st, 2016
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 58.29 KB | None | 0 0
  1. /*
  2. * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License as published by the
  6. * Free Software Foundation; either version 2 of the License, or (at your
  7. * option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12. * more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17.  
  18. /* ScriptData
  19. Name: npc_commandscript
  20. %Complete: 100
  21. Comment: All npc related commands
  22. Category: commandscripts
  23. EndScriptData */
  24.  
  25. #include "ScriptMgr.h"
  26. #include "ObjectMgr.h"
  27. #include "Chat.h"
  28. #include "Transport.h"
  29. #include "CreatureGroups.h"
  30. #include "Language.h"
  31. #include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand
  32. #include "CreatureAI.h"
  33. #include "Player.h"
  34. #include "Pet.h"
  35.  
  36. template<typename E, typename T = char const*>
  37. struct EnumName
  38. {
  39. E Value;
  40. T Name;
  41. };
  42.  
  43. #define CREATE_NAMED_ENUM(VALUE) { VALUE, STRINGIZE(VALUE) }
  44.  
  45. #define NPCFLAG_COUNT 24
  46. #define FLAGS_EXTRA_COUNT 19
  47.  
  48. EnumName<NPCFlags, int32> const npcFlagTexts[NPCFLAG_COUNT] =
  49. {
  50. { UNIT_NPC_FLAG_AUCTIONEER, LANG_NPCINFO_AUCTIONEER },
  51. { UNIT_NPC_FLAG_BANKER, LANG_NPCINFO_BANKER },
  52. { UNIT_NPC_FLAG_BATTLEMASTER, LANG_NPCINFO_BATTLEMASTER },
  53. { UNIT_NPC_FLAG_FLIGHTMASTER, LANG_NPCINFO_FLIGHTMASTER },
  54. { UNIT_NPC_FLAG_GOSSIP, LANG_NPCINFO_GOSSIP },
  55. { UNIT_NPC_FLAG_GUILD_BANKER, LANG_NPCINFO_GUILD_BANKER },
  56. { UNIT_NPC_FLAG_INNKEEPER, LANG_NPCINFO_INNKEEPER },
  57. { UNIT_NPC_FLAG_PETITIONER, LANG_NPCINFO_PETITIONER },
  58. { UNIT_NPC_FLAG_PLAYER_VEHICLE, LANG_NPCINFO_PLAYER_VEHICLE },
  59. { UNIT_NPC_FLAG_QUESTGIVER, LANG_NPCINFO_QUESTGIVER },
  60. { UNIT_NPC_FLAG_REPAIR, LANG_NPCINFO_REPAIR },
  61. { UNIT_NPC_FLAG_SPELLCLICK, LANG_NPCINFO_SPELLCLICK },
  62. { UNIT_NPC_FLAG_SPIRITGUIDE, LANG_NPCINFO_SPIRITGUIDE },
  63. { UNIT_NPC_FLAG_SPIRITHEALER, LANG_NPCINFO_SPIRITHEALER },
  64. { UNIT_NPC_FLAG_STABLEMASTER, LANG_NPCINFO_STABLEMASTER },
  65. { UNIT_NPC_FLAG_TABARDDESIGNER, LANG_NPCINFO_TABARDDESIGNER },
  66. { UNIT_NPC_FLAG_TRAINER, LANG_NPCINFO_TRAINER },
  67. { UNIT_NPC_FLAG_TRAINER_CLASS, LANG_NPCINFO_TRAINER_CLASS },
  68. { UNIT_NPC_FLAG_TRAINER_PROFESSION, LANG_NPCINFO_TRAINER_PROFESSION },
  69. { UNIT_NPC_FLAG_VENDOR, LANG_NPCINFO_VENDOR },
  70. { UNIT_NPC_FLAG_VENDOR_AMMO, LANG_NPCINFO_VENDOR_AMMO },
  71. { UNIT_NPC_FLAG_VENDOR_FOOD, LANG_NPCINFO_VENDOR_FOOD },
  72. { UNIT_NPC_FLAG_VENDOR_POISON, LANG_NPCINFO_VENDOR_POISON },
  73. { UNIT_NPC_FLAG_VENDOR_REAGENT, LANG_NPCINFO_VENDOR_REAGENT }
  74. };
  75.  
  76. EnumName<Mechanics> const mechanicImmunes[MAX_MECHANIC] =
  77. {
  78. CREATE_NAMED_ENUM(MECHANIC_NONE),
  79. CREATE_NAMED_ENUM(MECHANIC_CHARM),
  80. CREATE_NAMED_ENUM(MECHANIC_DISORIENTED),
  81. CREATE_NAMED_ENUM(MECHANIC_DISARM),
  82. CREATE_NAMED_ENUM(MECHANIC_DISTRACT),
  83. CREATE_NAMED_ENUM(MECHANIC_FEAR),
  84. CREATE_NAMED_ENUM(MECHANIC_GRIP),
  85. CREATE_NAMED_ENUM(MECHANIC_ROOT),
  86. CREATE_NAMED_ENUM(MECHANIC_SLOW_ATTACK),
  87. CREATE_NAMED_ENUM(MECHANIC_SILENCE),
  88. CREATE_NAMED_ENUM(MECHANIC_SLEEP),
  89. CREATE_NAMED_ENUM(MECHANIC_SNARE),
  90. CREATE_NAMED_ENUM(MECHANIC_STUN),
  91. CREATE_NAMED_ENUM(MECHANIC_FREEZE),
  92. CREATE_NAMED_ENUM(MECHANIC_KNOCKOUT),
  93. CREATE_NAMED_ENUM(MECHANIC_BLEED),
  94. CREATE_NAMED_ENUM(MECHANIC_BANDAGE),
  95. CREATE_NAMED_ENUM(MECHANIC_POLYMORPH),
  96. CREATE_NAMED_ENUM(MECHANIC_BANISH),
  97. CREATE_NAMED_ENUM(MECHANIC_SHIELD),
  98. CREATE_NAMED_ENUM(MECHANIC_SHACKLE),
  99. CREATE_NAMED_ENUM(MECHANIC_MOUNT),
  100. CREATE_NAMED_ENUM(MECHANIC_INFECTED),
  101. CREATE_NAMED_ENUM(MECHANIC_TURN),
  102. CREATE_NAMED_ENUM(MECHANIC_HORROR),
  103. CREATE_NAMED_ENUM(MECHANIC_INVULNERABILITY),
  104. CREATE_NAMED_ENUM(MECHANIC_INTERRUPT),
  105. CREATE_NAMED_ENUM(MECHANIC_DAZE),
  106. CREATE_NAMED_ENUM(MECHANIC_DISCOVERY),
  107. CREATE_NAMED_ENUM(MECHANIC_IMMUNE_SHIELD),
  108. CREATE_NAMED_ENUM(MECHANIC_SAPPED),
  109. CREATE_NAMED_ENUM(MECHANIC_ENRAGED),
  110. CREATE_NAMED_ENUM(MECHANIC_WOUNDED)
  111. };
  112.  
  113. EnumName<UnitFlags> const unitFlags[MAX_UNIT_FLAGS] =
  114. {
  115. CREATE_NAMED_ENUM(UNIT_FLAG_SERVER_CONTROLLED),
  116. CREATE_NAMED_ENUM(UNIT_FLAG_NON_ATTACKABLE),
  117. CREATE_NAMED_ENUM(UNIT_FLAG_DISABLE_MOVE),
  118. CREATE_NAMED_ENUM(UNIT_FLAG_PVP_ATTACKABLE),
  119. CREATE_NAMED_ENUM(UNIT_FLAG_RENAME),
  120. CREATE_NAMED_ENUM(UNIT_FLAG_PREPARATION),
  121. CREATE_NAMED_ENUM(UNIT_FLAG_UNK_6),
  122. CREATE_NAMED_ENUM(UNIT_FLAG_NOT_ATTACKABLE_1),
  123. CREATE_NAMED_ENUM(UNIT_FLAG_IMMUNE_TO_PC),
  124. CREATE_NAMED_ENUM(UNIT_FLAG_IMMUNE_TO_NPC),
  125. CREATE_NAMED_ENUM(UNIT_FLAG_LOOTING),
  126. CREATE_NAMED_ENUM(UNIT_FLAG_PET_IN_COMBAT),
  127. CREATE_NAMED_ENUM(UNIT_FLAG_PVP),
  128. CREATE_NAMED_ENUM(UNIT_FLAG_SILENCED),
  129. CREATE_NAMED_ENUM(UNIT_FLAG_UNK_14),
  130. CREATE_NAMED_ENUM(UNIT_FLAG_UNK_15),
  131. CREATE_NAMED_ENUM(UNIT_FLAG_UNK_16),
  132. CREATE_NAMED_ENUM(UNIT_FLAG_PACIFIED),
  133. CREATE_NAMED_ENUM(UNIT_FLAG_STUNNED),
  134. CREATE_NAMED_ENUM(UNIT_FLAG_IN_COMBAT),
  135. CREATE_NAMED_ENUM(UNIT_FLAG_TAXI_FLIGHT),
  136. CREATE_NAMED_ENUM(UNIT_FLAG_DISARMED),
  137. CREATE_NAMED_ENUM(UNIT_FLAG_CONFUSED),
  138. CREATE_NAMED_ENUM(UNIT_FLAG_FLEEING),
  139. CREATE_NAMED_ENUM(UNIT_FLAG_PLAYER_CONTROLLED),
  140. CREATE_NAMED_ENUM(UNIT_FLAG_NOT_SELECTABLE),
  141. CREATE_NAMED_ENUM(UNIT_FLAG_SKINNABLE),
  142. CREATE_NAMED_ENUM(UNIT_FLAG_MOUNT),
  143. CREATE_NAMED_ENUM(UNIT_FLAG_UNK_28),
  144. CREATE_NAMED_ENUM(UNIT_FLAG_UNK_29),
  145. CREATE_NAMED_ENUM(UNIT_FLAG_SHEATHE),
  146. CREATE_NAMED_ENUM(UNIT_FLAG_UNK_31)
  147. };
  148.  
  149. EnumName<CreatureFlagsExtra> const flagsExtra[FLAGS_EXTRA_COUNT] =
  150. {
  151. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_INSTANCE_BIND),
  152. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_CIVILIAN),
  153. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_PARRY),
  154. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN),
  155. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_BLOCK),
  156. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_CRUSH),
  157. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_XP_AT_KILL),
  158. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_TRIGGER),
  159. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_TAUNT),
  160. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_WORLDEVENT),
  161. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_GUARD),
  162. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_CRIT),
  163. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_SKILLGAIN),
  164. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_TAUNT_DIMINISH),
  165. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_ALL_DIMINISH),
  166. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ),
  167. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_DUNGEON_BOSS),
  168. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING),
  169. CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK)
  170. };
  171.  
  172. class npc_commandscript : public CommandScript
  173. {
  174. public:
  175. npc_commandscript() : CommandScript("npc_commandscript") { }
  176.  
  177. std::vector<ChatCommand> GetCommands() const override
  178. {
  179. static std::vector<ChatCommand> npcAddCommandTable =
  180. {
  181. { "formation", rbac::RBAC_PERM_COMMAND_NPC_ADD_FORMATION, false, &HandleNpcAddFormationCommand, "" },
  182. { "item", rbac::RBAC_PERM_COMMAND_NPC_ADD_ITEM, false, &HandleNpcAddVendorItemCommand, "" },
  183. { "move", rbac::RBAC_PERM_COMMAND_NPC_ADD_MOVE, false, &HandleNpcAddMoveCommand, "" },
  184. { "temp", rbac::RBAC_PERM_COMMAND_NPC_ADD_TEMP, false, &HandleNpcAddTempSpawnCommand, "" },
  185. //{ "weapon", rbac::RBAC_PERM_COMMAND_NPC_ADD_WEAPON, false, &HandleNpcAddWeaponCommand, "" },
  186. { "", rbac::RBAC_PERM_COMMAND_NPC_ADD, false, &HandleNpcAddCommand, "" },
  187. };
  188. static std::vector<ChatCommand> npcDeleteCommandTable =
  189. {
  190. { "item", rbac::RBAC_PERM_COMMAND_NPC_DELETE_ITEM, false, &HandleNpcDeleteVendorItemCommand, "" },
  191. { "", rbac::RBAC_PERM_COMMAND_NPC_DELETE, false, &HandleNpcDeleteCommand, "" },
  192. };
  193. static std::vector<ChatCommand> npcFollowCommandTable =
  194. {
  195. { "stop", rbac::RBAC_PERM_COMMAND_NPC_FOLLOW_STOP, false, &HandleNpcUnFollowCommand, "" },
  196. { "", rbac::RBAC_PERM_COMMAND_NPC_FOLLOW, false, &HandleNpcFollowCommand, "" },
  197. };
  198. static std::vector<ChatCommand> npcSetCommandTable =
  199. {
  200. { "allowmove", rbac::RBAC_PERM_COMMAND_NPC_SET_ALLOWMOVE, false, &HandleNpcSetAllowMovementCommand, "" },
  201. { "entry", rbac::RBAC_PERM_COMMAND_NPC_SET_ENTRY, false, &HandleNpcSetEntryCommand, "" },
  202. { "factionid", rbac::RBAC_PERM_COMMAND_NPC_SET_FACTIONID, false, &HandleNpcSetFactionIdCommand, "" },
  203. { "flag", rbac::RBAC_PERM_COMMAND_NPC_SET_FLAG, false, &HandleNpcSetFlagCommand, "" },
  204. { "level", rbac::RBAC_PERM_COMMAND_NPC_SET_LEVEL, false, &HandleNpcSetLevelCommand, "" },
  205. { "link", rbac::RBAC_PERM_COMMAND_NPC_SET_LINK, false, &HandleNpcSetLinkCommand, "" },
  206. { "model", rbac::RBAC_PERM_COMMAND_NPC_SET_MODEL, false, &HandleNpcSetModelCommand, "" },
  207. { "movetype", rbac::RBAC_PERM_COMMAND_NPC_SET_MOVETYPE, false, &HandleNpcSetMoveTypeCommand, "" },
  208. { "phase", rbac::RBAC_PERM_COMMAND_NPC_SET_PHASE, false, &HandleNpcSetPhaseCommand, "" },
  209. { "phasegroup", rbac::RBAC_PERM_COMMAND_NPC_SET_PHASE, false, &HandleNpcSetPhaseGroup, "" },
  210. { "spawndist", rbac::RBAC_PERM_COMMAND_NPC_SET_SPAWNDIST, false, &HandleNpcSetSpawnDistCommand, "" },
  211. { "spawntime", rbac::RBAC_PERM_COMMAND_NPC_SET_SPAWNTIME, false, &HandleNpcSetSpawnTimeCommand, "" },
  212. { "data", rbac::RBAC_PERM_COMMAND_NPC_SET_DATA, false, &HandleNpcSetDataCommand, "" },
  213. };
  214. static std::vector<ChatCommand> npcCommandTable =
  215. {
  216. { "info", rbac::RBAC_PERM_COMMAND_NPC_INFO, false, &HandleNpcInfoCommand, "" },
  217. { "near", rbac::RBAC_PERM_COMMAND_NPC_NEAR, false, &HandleNpcNearCommand, "" },
  218. { "move", rbac::RBAC_PERM_COMMAND_NPC_MOVE, false, &HandleNpcMoveCommand, "" },
  219. { "playemote", rbac::RBAC_PERM_COMMAND_NPC_PLAYEMOTE, false, &HandleNpcPlayEmoteCommand, "" },
  220. { "say", rbac::RBAC_PERM_COMMAND_NPC_SAY, false, &HandleNpcSayCommand, "" },
  221. { "textemote", rbac::RBAC_PERM_COMMAND_NPC_TEXTEMOTE, false, &HandleNpcTextEmoteCommand, "" },
  222. { "whisper", rbac::RBAC_PERM_COMMAND_NPC_WHISPER, false, &HandleNpcWhisperCommand, "" },
  223. { "yell", rbac::RBAC_PERM_COMMAND_NPC_YELL, false, &HandleNpcYellCommand, "" },
  224. { "tame", rbac::RBAC_PERM_COMMAND_NPC_TAME, false, &HandleNpcTameCommand, "" },
  225. { "add", rbac::RBAC_PERM_COMMAND_NPC_ADD, false, NULL, "", npcAddCommandTable },
  226. { "delete", rbac::RBAC_PERM_COMMAND_NPC_DELETE, false, NULL, "", npcDeleteCommandTable },
  227. { "follow", rbac::RBAC_PERM_COMMAND_NPC_FOLLOW, false, NULL, "", npcFollowCommandTable },
  228. { "set", rbac::RBAC_PERM_COMMAND_NPC_SET, false, NULL, "", npcSetCommandTable },
  229. };
  230. static std::vector<ChatCommand> commandTable =
  231. {
  232. { "npc", rbac::RBAC_PERM_COMMAND_NPC, false, NULL, "", npcCommandTable },
  233. };
  234. return commandTable;
  235. }
  236.  
  237. //add spawn of creature
  238. static bool HandleNpcAddCommand(ChatHandler* handler, char const* args)
  239. {
  240. if (!*args)
  241. return false;
  242.  
  243. char* charID = handler->extractKeyFromLink((char*)args, "Hcreature_entry");
  244. if (!charID)
  245. return false;
  246.  
  247. uint32 id = atoi(charID);
  248. if (!sObjectMgr->GetCreatureTemplate(id))
  249. return false;
  250.  
  251. Player* chr = handler->GetSession()->GetPlayer();
  252. float x = chr->GetPositionX();
  253. float y = chr->GetPositionY();
  254. float z = chr->GetPositionZ();
  255. float o = chr->GetOrientation();
  256. Map* map = chr->GetMap();
  257.  
  258. if (Transport* trans = chr->GetTransport())
  259. {
  260. ObjectGuid::LowType guid = map->GenerateLowGuid<HighGuid::Creature>();
  261. CreatureData& data = sObjectMgr->NewOrExistCreatureData(guid);
  262. data.id = id;
  263. data.phaseMask = chr->GetPhaseMask();
  264. data.posX = chr->GetTransOffsetX();
  265. data.posY = chr->GetTransOffsetY();
  266. data.posZ = chr->GetTransOffsetZ();
  267. data.orientation = chr->GetTransOffsetO();
  268.  
  269. Creature* creature = trans->CreateNPCPassenger(guid, &data);
  270.  
  271. creature->SaveToDB(trans->GetGOInfo()->moTransport.mapID, 1 << map->GetSpawnMode(), chr->GetPhaseMask());
  272.  
  273. sObjectMgr->AddCreatureToGrid(guid, &data);
  274. return true;
  275. }
  276.  
  277. Creature* creature = new Creature();
  278. if (!creature->Create(map->GenerateLowGuid<HighGuid::Creature>(), map, chr->GetPhaseMask(), id, x, y, z, o))
  279. {
  280. delete creature;
  281. return false;
  282. }
  283.  
  284. creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMask());
  285.  
  286. ObjectGuid::LowType db_guid = creature->GetSpawnId();
  287.  
  288. // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells()
  289. // current "creature" variable is deleted and created fresh new, otherwise old values might trigger asserts or cause undefined behavior
  290. creature->CleanupsBeforeDelete();
  291. delete creature;
  292. creature = new Creature();
  293. if (!creature->LoadCreatureFromDB(db_guid, map))
  294. {
  295. delete creature;
  296. return false;
  297. }
  298.  
  299. sObjectMgr->AddCreatureToGrid(db_guid, sObjectMgr->GetCreatureData(db_guid));
  300. return true;
  301. }
  302.  
  303. //add item in vendorlist
  304. static bool HandleNpcAddVendorItemCommand(ChatHandler* handler, char const* args)
  305. {
  306. if (!*args)
  307. return false;
  308.  
  309. const uint8 type = 1; // FIXME: make type (1 item, 2 currency) an argument
  310.  
  311. char* pitem = handler->extractKeyFromLink((char*)args, "Hitem");
  312. if (!pitem)
  313. {
  314. handler->SendSysMessage(LANG_COMMAND_NEEDITEMSEND);
  315. handler->SetSentErrorMessage(true);
  316. return false;
  317. }
  318.  
  319. int32 item_int = atol(pitem);
  320. if (item_int <= 0)
  321. return false;
  322.  
  323. uint32 itemId = item_int;
  324.  
  325. char* fmaxcount = strtok(NULL, " "); //add maxcount, default: 0
  326. uint32 maxcount = 0;
  327. if (fmaxcount)
  328. maxcount = atoul(fmaxcount);
  329.  
  330. char* fincrtime = strtok(NULL, " "); //add incrtime, default: 0
  331. uint32 incrtime = 0;
  332. if (fincrtime)
  333. incrtime = atoul(fincrtime);
  334.  
  335. char* fextendedcost = strtok(NULL, " "); //add ExtendedCost, default: 0
  336. uint32 extendedcost = fextendedcost ? atoul(fextendedcost) : 0;
  337. Creature* vendor = handler->getSelectedCreature();
  338. if (!vendor)
  339. {
  340. handler->SendSysMessage(LANG_SELECT_CREATURE);
  341. handler->SetSentErrorMessage(true);
  342. return false;
  343. }
  344.  
  345. uint32 vendor_entry = vendor->GetEntry();
  346.  
  347. if (!sObjectMgr->IsVendorItemValid(vendor_entry, itemId, maxcount, incrtime, extendedcost, type, handler->GetSession()->GetPlayer()))
  348. {
  349. handler->SetSentErrorMessage(true);
  350. return false;
  351. }
  352.  
  353. sObjectMgr->AddVendorItem(vendor_entry, itemId, maxcount, incrtime, extendedcost, type);
  354.  
  355. ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId);
  356.  
  357. handler->PSendSysMessage(LANG_ITEM_ADDED_TO_LIST, itemId, itemTemplate->GetDefaultLocaleName(), maxcount, incrtime, extendedcost);
  358. return true;
  359. }
  360.  
  361. //add move for creature
  362. static bool HandleNpcAddMoveCommand(ChatHandler* handler, char const* args)
  363. {
  364. if (!*args)
  365. return false;
  366.  
  367. char* guidStr = strtok((char*)args, " ");
  368. char* waitStr = strtok((char*)NULL, " ");
  369.  
  370. ObjectGuid::LowType lowGuid = strtoull(guidStr, nullptr, 10);
  371.  
  372. // attempt check creature existence by DB data
  373. CreatureData const* data = sObjectMgr->GetCreatureData(lowGuid);
  374. if (!data)
  375. {
  376. handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowGuid);
  377. handler->SetSentErrorMessage(true);
  378. return false;
  379. }
  380.  
  381. int wait = waitStr ? atoi(waitStr) : 0;
  382.  
  383. if (wait < 0)
  384. wait = 0;
  385.  
  386. // Update movement type
  387. PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_MOVEMENT_TYPE);
  388.  
  389. stmt->setUInt8(0, uint8(WAYPOINT_MOTION_TYPE));
  390. stmt->setUInt64(1, lowGuid);
  391.  
  392. WorldDatabase.Execute(stmt);
  393.  
  394. handler->SendSysMessage(LANG_WAYPOINT_ADDED);
  395.  
  396. return true;
  397. }
  398.  
  399. static bool HandleNpcSetAllowMovementCommand(ChatHandler* handler, char const* /*args*/)
  400. {
  401. if (sWorld->getAllowMovement())
  402. {
  403. sWorld->SetAllowMovement(false);
  404. handler->SendSysMessage(LANG_CREATURE_MOVE_DISABLED);
  405. }
  406. else
  407. {
  408. sWorld->SetAllowMovement(true);
  409. handler->SendSysMessage(LANG_CREATURE_MOVE_ENABLED);
  410. }
  411. return true;
  412. }
  413.  
  414. static bool HandleNpcSetEntryCommand(ChatHandler* handler, char const* args)
  415. {
  416. if (!*args)
  417. return false;
  418.  
  419. uint32 newEntryNum = atoi(args);
  420. if (!newEntryNum)
  421. return false;
  422.  
  423. Unit* unit = handler->getSelectedUnit();
  424. if (!unit || unit->GetTypeId() != TYPEID_UNIT)
  425. {
  426. handler->SendSysMessage(LANG_SELECT_CREATURE);
  427. handler->SetSentErrorMessage(true);
  428. return false;
  429. }
  430. Creature* creature = unit->ToCreature();
  431. if (creature->UpdateEntry(newEntryNum))
  432. handler->SendSysMessage(LANG_DONE);
  433. else
  434. handler->SendSysMessage(LANG_ERROR);
  435. return true;
  436. }
  437.  
  438. //change level of creature or pet
  439. static bool HandleNpcSetLevelCommand(ChatHandler* handler, char const* args)
  440. {
  441. if (!*args)
  442. return false;
  443.  
  444. uint8 lvl = (uint8) atoi((char*)args);
  445. if (lvl < 1 || lvl > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) + 3)
  446. {
  447. handler->SendSysMessage(LANG_BAD_VALUE);
  448. handler->SetSentErrorMessage(true);
  449. return false;
  450. }
  451.  
  452. Creature* creature = handler->getSelectedCreature();
  453. if (!creature)
  454. {
  455. handler->SendSysMessage(LANG_SELECT_CREATURE);
  456. handler->SetSentErrorMessage(true);
  457. return false;
  458. }
  459.  
  460. if (creature->IsPet())
  461. {
  462. if (((Pet*)creature)->getPetType() == HUNTER_PET)
  463. {
  464. creature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, sObjectMgr->GetXPForLevel(lvl)/4);
  465. creature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
  466. }
  467. ((Pet*)creature)->GivePetLevel(lvl);
  468. }
  469. else
  470. {
  471. creature->SetMaxHealth(100 + 30*lvl);
  472. creature->SetHealth(100 + 30*lvl);
  473. creature->SetLevel(lvl);
  474. creature->SaveToDB();
  475. }
  476.  
  477. return true;
  478. }
  479.  
  480. static bool HandleNpcDeleteCommand(ChatHandler* handler, char const* args)
  481. {
  482. Creature* unit = NULL;
  483.  
  484. if (*args)
  485. {
  486. // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r
  487. char* cId = handler->extractKeyFromLink((char*)args, "Hcreature");
  488. if (!cId)
  489. return false;
  490.  
  491. ObjectGuid::LowType lowguid = strtoull(cId, nullptr, 10);
  492. if (!lowguid)
  493. return false;
  494.  
  495. if (CreatureData const* cr_data = sObjectMgr->GetCreatureData(lowguid))
  496. unit = handler->GetSession()->GetPlayer()->GetMap()->GetCreature(ObjectGuid::Create<HighGuid::Creature>(cr_data->mapid, cr_data->id, lowguid));
  497. }
  498. else
  499. unit = handler->getSelectedCreature();
  500.  
  501. if (!unit || unit->IsPet() || unit->IsTotem())
  502. {
  503. handler->SendSysMessage(LANG_SELECT_CREATURE);
  504. handler->SetSentErrorMessage(true);
  505. return false;
  506. }
  507.  
  508. // Delete the creature
  509. unit->CombatStop();
  510. unit->DeleteFromDB();
  511. unit->AddObjectToRemoveList();
  512.  
  513. handler->SendSysMessage(LANG_COMMAND_DELCREATMESSAGE);
  514.  
  515. return true;
  516. }
  517.  
  518. //del item from vendor list
  519. static bool HandleNpcDeleteVendorItemCommand(ChatHandler* handler, char const* args)
  520. {
  521. if (!*args)
  522. return false;
  523.  
  524. Creature* vendor = handler->getSelectedCreature();
  525. if (!vendor || !vendor->IsVendor())
  526. {
  527. handler->SendSysMessage(LANG_COMMAND_VENDORSELECTION);
  528. handler->SetSentErrorMessage(true);
  529. return false;
  530. }
  531.  
  532. char* pitem = handler->extractKeyFromLink((char*)args, "Hitem");
  533. if (!pitem)
  534. {
  535. handler->SendSysMessage(LANG_COMMAND_NEEDITEMSEND);
  536. handler->SetSentErrorMessage(true);
  537. return false;
  538. }
  539. uint32 itemId = atoul(pitem);
  540.  
  541. const uint8 type = 1; // FIXME: make type (1 item, 2 currency) an argument
  542.  
  543. if (!sObjectMgr->RemoveVendorItem(vendor->GetEntry(), itemId, type))
  544. {
  545. handler->PSendSysMessage(LANG_ITEM_NOT_IN_LIST, itemId);
  546. handler->SetSentErrorMessage(true);
  547. return false;
  548. }
  549.  
  550. ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId);
  551.  
  552. handler->PSendSysMessage(LANG_ITEM_DELETED_FROM_LIST, itemId, itemTemplate->GetDefaultLocaleName());
  553. return true;
  554. }
  555.  
  556. //set faction of creature
  557. static bool HandleNpcSetFactionIdCommand(ChatHandler* handler, char const* args)
  558. {
  559. if (!*args)
  560. return false;
  561.  
  562. uint32 factionId = (uint32) atoi((char*)args);
  563.  
  564. if (!sFactionTemplateStore.LookupEntry(factionId))
  565. {
  566. handler->PSendSysMessage(LANG_WRONG_FACTION, factionId);
  567. handler->SetSentErrorMessage(true);
  568. return false;
  569. }
  570.  
  571. Creature* creature = handler->getSelectedCreature();
  572.  
  573. if (!creature)
  574. {
  575. handler->SendSysMessage(LANG_SELECT_CREATURE);
  576. handler->SetSentErrorMessage(true);
  577. return false;
  578. }
  579.  
  580. creature->setFaction(factionId);
  581.  
  582. // Faction is set in creature_template - not inside creature
  583.  
  584. // Update in memory..
  585. if (CreatureTemplate const* cinfo = creature->GetCreatureTemplate())
  586. const_cast<CreatureTemplate*>(cinfo)->faction = factionId;
  587.  
  588. // ..and DB
  589. PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_FACTION);
  590.  
  591. stmt->setUInt16(0, uint16(factionId));
  592. stmt->setUInt32(1, creature->GetEntry());
  593.  
  594. WorldDatabase.Execute(stmt);
  595.  
  596. return true;
  597. }
  598.  
  599. //set npcflag of creature
  600. static bool HandleNpcSetFlagCommand(ChatHandler* handler, char const* args)
  601. {
  602. if (!*args)
  603. return false;
  604.  
  605. uint64 npcFlags = std::strtoull(args, nullptr, 10);
  606.  
  607. Creature* creature = handler->getSelectedCreature();
  608.  
  609. if (!creature)
  610. {
  611. handler->SendSysMessage(LANG_SELECT_CREATURE);
  612. handler->SetSentErrorMessage(true);
  613. return false;
  614. }
  615.  
  616. creature->SetUInt64Value(UNIT_NPC_FLAGS, npcFlags);
  617.  
  618. PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_NPCFLAG);
  619.  
  620. stmt->setUInt64(0, npcFlags);
  621. stmt->setUInt32(1, creature->GetEntry());
  622.  
  623. WorldDatabase.Execute(stmt);
  624.  
  625. handler->SendSysMessage(LANG_VALUE_SAVED_REJOIN);
  626.  
  627. return true;
  628. }
  629.  
  630. //set data of creature for testing scripting
  631. static bool HandleNpcSetDataCommand(ChatHandler* handler, char const* args)
  632. {
  633. if (!*args)
  634. return false;
  635.  
  636. char* arg1 = strtok((char*)args, " ");
  637. char* arg2 = strtok((char*)NULL, "");
  638.  
  639. if (!arg1 || !arg2)
  640. return false;
  641.  
  642. uint32 data_1 = (uint32)atoi(arg1);
  643. uint32 data_2 = (uint32)atoi(arg2);
  644.  
  645. if (!data_1 || !data_2)
  646. return false;
  647.  
  648. Creature* creature = handler->getSelectedCreature();
  649.  
  650. if (!creature)
  651. {
  652. handler->SendSysMessage(LANG_SELECT_CREATURE);
  653. handler->SetSentErrorMessage(true);
  654. return false;
  655. }
  656.  
  657. creature->AI()->SetData(data_1, data_2);
  658. std::string AIorScript = !creature->GetAIName().empty() ? "AI type: " + creature->GetAIName() : (!creature->GetScriptName().empty() ? "Script Name: " + creature->GetScriptName() : "No AI or Script Name Set");
  659. handler->PSendSysMessage(LANG_NPC_SETDATA, creature->GetGUID().ToString().c_str(), creature->GetName().c_str(), data_1, data_2, AIorScript.c_str());
  660. return true;
  661. }
  662.  
  663. //npc follow handling
  664. static bool HandleNpcFollowCommand(ChatHandler* handler, char const* /*args*/)
  665. {
  666. Player* player = handler->GetSession()->GetPlayer();
  667. Creature* creature = handler->getSelectedCreature();
  668.  
  669. if (!creature)
  670. {
  671. handler->PSendSysMessage(LANG_SELECT_CREATURE);
  672. handler->SetSentErrorMessage(true);
  673. return false;
  674. }
  675.  
  676. // Follow player - Using pet's default dist and angle
  677. creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, creature->GetFollowAngle());
  678.  
  679. handler->PSendSysMessage(LANG_CREATURE_FOLLOW_YOU_NOW, creature->GetName().c_str());
  680. return true;
  681. }
  682.  
  683. static bool HandleNpcInfoCommand(ChatHandler* handler, char const* /*args*/)
  684. {
  685. Creature* target = handler->getSelectedCreature();
  686.  
  687. if (!target)
  688. {
  689. handler->SendSysMessage(LANG_SELECT_CREATURE);
  690. handler->SetSentErrorMessage(true);
  691. return false;
  692. }
  693.  
  694. CreatureTemplate const* cInfo = target->GetCreatureTemplate();
  695.  
  696. uint32 faction = target->getFaction();
  697. uint64 npcflags = target->GetUInt64Value(UNIT_NPC_FLAGS);
  698. uint32 mechanicImmuneMask = cInfo->MechanicImmuneMask;
  699. uint32 displayid = target->GetDisplayId();
  700. uint32 nativeid = target->GetNativeDisplayId();
  701. uint32 Entry = target->GetEntry();
  702.  
  703. int64 curRespawnDelay = target->GetRespawnTimeEx()-time(NULL);
  704. if (curRespawnDelay < 0)
  705. curRespawnDelay = 0;
  706. std::string curRespawnDelayStr = secsToTimeString(uint64(curRespawnDelay), true);
  707. std::string defRespawnDelayStr = secsToTimeString(target->GetRespawnDelay(), true);
  708.  
  709. handler->PSendSysMessage(LANG_NPCINFO_CHAR, target->GetSpawnId(), target->GetGUID().ToString().c_str(), faction, npcflags, Entry, displayid, nativeid);
  710. handler->PSendSysMessage(LANG_NPCINFO_LEVEL, target->getLevel());
  711. handler->PSendSysMessage(LANG_NPCINFO_EQUIPMENT, target->GetCurrentEquipmentId(), target->GetOriginalEquipmentId());
  712. handler->PSendSysMessage(LANG_NPCINFO_HEALTH, target->GetCreateHealth(), target->GetMaxHealth(), target->GetHealth());
  713. handler->PSendSysMessage(LANG_NPCINFO_INHABIT_TYPE, cInfo->InhabitType);
  714.  
  715. handler->PSendSysMessage(LANG_NPCINFO_UNIT_FIELD_FLAGS, target->GetUInt32Value(UNIT_FIELD_FLAGS));
  716. for (uint8 i = 0; i < MAX_UNIT_FLAGS; ++i)
  717. if (target->GetUInt32Value(UNIT_FIELD_FLAGS) & unitFlags[i].Value)
  718. handler->PSendSysMessage("%s (0x%X)", unitFlags[i].Name, unitFlags[i].Value);
  719.  
  720. handler->PSendSysMessage(LANG_NPCINFO_FLAGS, target->GetUInt32Value(UNIT_FIELD_FLAGS_2), target->GetUInt32Value(OBJECT_DYNAMIC_FLAGS), target->getFaction());
  721. handler->PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(), curRespawnDelayStr.c_str());
  722. handler->PSendSysMessage(LANG_NPCINFO_LOOT, cInfo->lootid, cInfo->pickpocketLootId, cInfo->SkinLootId);
  723. handler->PSendSysMessage(LANG_NPCINFO_DUNGEON_ID, target->GetInstanceId());
  724.  
  725. if (CreatureData const* data = sObjectMgr->GetCreatureData(target->GetSpawnId()))
  726. {
  727. handler->PSendSysMessage(LANG_NPCINFO_PHASES, data->phaseid, data->phaseGroup);
  728. if (data->phaseGroup)
  729. {
  730. std::set<uint32> _phases = target->GetPhases();
  731.  
  732. if (!_phases.empty())
  733. {
  734. handler->PSendSysMessage(LANG_NPCINFO_PHASE_IDS);
  735. for (uint32 phaseId : _phases)
  736. handler->PSendSysMessage("%u", phaseId);
  737. }
  738. }
  739. }
  740.  
  741. handler->PSendSysMessage(LANG_NPCINFO_ARMOR, target->GetArmor());
  742. handler->PSendSysMessage(LANG_NPCINFO_POSITION, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ());
  743. handler->PSendSysMessage(LANG_NPCINFO_AIINFO, target->GetAIName().c_str(), target->GetScriptName().c_str());
  744. handler->PSendSysMessage(LANG_NPCINFO_FLAGS_EXTRA, cInfo->flags_extra);
  745. for (uint8 i = 0; i < FLAGS_EXTRA_COUNT; ++i)
  746. if (cInfo->flags_extra & flagsExtra[i].Value)
  747. handler->PSendSysMessage("%s (0x%X)", flagsExtra[i].Name, flagsExtra[i].Value);
  748.  
  749. for (uint8 i = 0; i < NPCFLAG_COUNT; i++)
  750. if (npcflags & npcFlagTexts[i].Value)
  751. handler->PSendSysMessage(npcFlagTexts[i].Name, npcFlagTexts[i].Value);
  752.  
  753. handler->PSendSysMessage(LANG_NPCINFO_MECHANIC_IMMUNE, mechanicImmuneMask);
  754. for (uint8 i = 1; i < MAX_MECHANIC; ++i)
  755. if (mechanicImmuneMask & (1 << (mechanicImmunes[i].Value - 1)))
  756. handler->PSendSysMessage("%s (0x%X)", mechanicImmunes[i].Name, mechanicImmunes[i].Value);
  757.  
  758. return true;
  759. }
  760.  
  761. static bool HandleNpcNearCommand(ChatHandler* handler, char const* args)
  762. {
  763. float distance = (!*args) ? 10.0f : float((atof(args)));
  764. uint32 count = 0;
  765.  
  766. Player* player = handler->GetSession()->GetPlayer();
  767.  
  768. PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_NEAREST);
  769. stmt->setFloat(0, player->GetPositionX());
  770. stmt->setFloat(1, player->GetPositionY());
  771. stmt->setFloat(2, player->GetPositionZ());
  772. stmt->setUInt32(3, player->GetMapId());
  773. stmt->setFloat(4, player->GetPositionX());
  774. stmt->setFloat(5, player->GetPositionY());
  775. stmt->setFloat(6, player->GetPositionZ());
  776. stmt->setFloat(7, distance * distance);
  777. PreparedQueryResult result = WorldDatabase.Query(stmt);
  778.  
  779. if (result)
  780. {
  781. do
  782. {
  783. Field* fields = result->Fetch();
  784. ObjectGuid::LowType guid = fields[0].GetUInt64();
  785. uint32 entry = fields[1].GetUInt32();
  786. float x = fields[2].GetFloat();
  787. float y = fields[3].GetFloat();
  788. float z = fields[4].GetFloat();
  789. uint16 mapId = fields[5].GetUInt16();
  790.  
  791. CreatureTemplate const* creatureTemplate = sObjectMgr->GetCreatureTemplate(entry);
  792. if (!creatureTemplate)
  793. continue;
  794.  
  795. handler->PSendSysMessage(LANG_CREATURE_LIST_CHAT, guid, guid, creatureTemplate->Name.c_str(), x, y, z, mapId);
  796.  
  797. ++count;
  798. }
  799. while (result->NextRow());
  800. }
  801.  
  802. handler->PSendSysMessage(LANG_COMMAND_NEAR_NPC_MESSAGE, distance, count);
  803.  
  804. return true;
  805. }
  806.  
  807. //move selected creature
  808. static bool HandleNpcMoveCommand(ChatHandler* handler, char const* args)
  809. {
  810. ObjectGuid::LowType lowguid = UI64LIT(0);
  811.  
  812. Creature* creature = handler->getSelectedCreature();
  813.  
  814. if (!creature)
  815. {
  816. // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r
  817. char* cId = handler->extractKeyFromLink((char*)args, "Hcreature");
  818. if (!cId)
  819. return false;
  820.  
  821. lowguid = strtoull(cId, nullptr, 10);
  822.  
  823. // Attempting creature load from DB data
  824. CreatureData const* data = sObjectMgr->GetCreatureData(lowguid);
  825. if (!data)
  826. {
  827. handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
  828. handler->SetSentErrorMessage(true);
  829. return false;
  830. }
  831.  
  832. uint32 map_id = data->mapid;
  833.  
  834. if (handler->GetSession()->GetPlayer()->GetMapId() != map_id)
  835. {
  836. handler->PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid);
  837. handler->SetSentErrorMessage(true);
  838. return false;
  839. }
  840. }
  841. else
  842. {
  843. lowguid = creature->GetSpawnId();
  844. }
  845.  
  846. float x = handler->GetSession()->GetPlayer()->GetPositionX();
  847. float y = handler->GetSession()->GetPlayer()->GetPositionY();
  848. float z = handler->GetSession()->GetPlayer()->GetPositionZ();
  849. float o = handler->GetSession()->GetPlayer()->GetOrientation();
  850.  
  851. if (creature)
  852. {
  853. if (CreatureData const* data = sObjectMgr->GetCreatureData(creature->GetSpawnId()))
  854. {
  855. const_cast<CreatureData*>(data)->posX = x;
  856. const_cast<CreatureData*>(data)->posY = y;
  857. const_cast<CreatureData*>(data)->posZ = z;
  858. const_cast<CreatureData*>(data)->orientation = o;
  859. }
  860. creature->SetPosition(x, y, z, o);
  861. creature->GetMotionMaster()->Initialize();
  862. if (creature->IsAlive()) // dead creature will reset movement generator at respawn
  863. {
  864. creature->setDeathState(JUST_DIED);
  865. creature->Respawn();
  866. }
  867. }
  868.  
  869. PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_POSITION);
  870.  
  871. stmt->setFloat(0, x);
  872. stmt->setFloat(1, y);
  873. stmt->setFloat(2, z);
  874. stmt->setFloat(3, o);
  875. stmt->setUInt64(4, lowguid);
  876.  
  877. WorldDatabase.Execute(stmt);
  878.  
  879. handler->PSendSysMessage(LANG_COMMAND_CREATUREMOVED);
  880. return true;
  881. }
  882.  
  883. //play npc emote
  884. static bool HandleNpcPlayEmoteCommand(ChatHandler* handler, char const* args)
  885. {
  886. uint32 emote = atoi((char*)args);
  887.  
  888. Creature* target = handler->getSelectedCreature();
  889. if (!target)
  890. {
  891. handler->SendSysMessage(LANG_SELECT_CREATURE);
  892. handler->SetSentErrorMessage(true);
  893. return false;
  894. }
  895.  
  896. target->SetUInt32Value(UNIT_NPC_EMOTESTATE, emote);
  897.  
  898. return true;
  899. }
  900.  
  901. //set model of creature
  902. static bool HandleNpcSetModelCommand(ChatHandler* handler, char const* args)
  903. {
  904. if (!*args)
  905. return false;
  906.  
  907. uint32 displayId = (uint32) atoi((char*)args);
  908.  
  909. Creature* creature = handler->getSelectedCreature();
  910.  
  911. if (!creature || creature->IsPet())
  912. {
  913. handler->SendSysMessage(LANG_SELECT_CREATURE);
  914. handler->SetSentErrorMessage(true);
  915. return false;
  916. }
  917.  
  918. creature->SetDisplayId(displayId);
  919. creature->SetNativeDisplayId(displayId);
  920.  
  921. creature->SaveToDB();
  922.  
  923. return true;
  924. }
  925.  
  926. /**HandleNpcSetMoveTypeCommand
  927. * Set the movement type for an NPC.<br/>
  928. * <br/>
  929. * Valid movement types are:
  930. * <ul>
  931. * <li> stay - NPC wont move </li>
  932. * <li> random - NPC will move randomly according to the spawndist </li>
  933. * <li> way - NPC will move with given waypoints set </li>
  934. * </ul>
  935. * additional parameter: NODEL - so no waypoints are deleted, if you
  936. * change the movement type
  937. */
  938. static bool HandleNpcSetMoveTypeCommand(ChatHandler* handler, char const* args)
  939. {
  940. if (!*args)
  941. return false;
  942.  
  943. // 3 arguments:
  944. // GUID (optional - you can also select the creature)
  945. // stay|random|way (determines the kind of movement)
  946. // NODEL (optional - tells the system NOT to delete any waypoints)
  947. // this is very handy if you want to do waypoints, that are
  948. // later switched on/off according to special events (like escort
  949. // quests, etc)
  950. char* guid_str = strtok((char*)args, " ");
  951. char* type_str = strtok((char*)NULL, " ");
  952. char* dontdel_str = strtok((char*)NULL, " ");
  953.  
  954. bool doNotDelete = false;
  955.  
  956. if (!guid_str)
  957. return false;
  958.  
  959. ObjectGuid::LowType lowguid = UI64LIT(0);
  960. Creature* creature = NULL;
  961.  
  962. if (dontdel_str)
  963. {
  964. //TC_LOG_ERROR("misc", "DEBUG: All 3 params are set");
  965.  
  966. // All 3 params are set
  967. // GUID
  968. // type
  969. // doNotDEL
  970. if (stricmp(dontdel_str, "NODEL") == 0)
  971. {
  972. //TC_LOG_ERROR("misc", "DEBUG: doNotDelete = true;");
  973. doNotDelete = true;
  974. }
  975. }
  976. else
  977. {
  978. // Only 2 params - but maybe NODEL is set
  979. if (type_str)
  980. {
  981. TC_LOG_ERROR("misc", "DEBUG: Only 2 params ");
  982. if (stricmp(type_str, "NODEL") == 0)
  983. {
  984. //TC_LOG_ERROR("misc", "DEBUG: type_str, NODEL ");
  985. doNotDelete = true;
  986. type_str = NULL;
  987. }
  988. }
  989. }
  990.  
  991. if (!type_str) // case .setmovetype $move_type (with selected creature)
  992. {
  993. type_str = guid_str;
  994. creature = handler->getSelectedCreature();
  995. if (!creature || creature->IsPet())
  996. return false;
  997. lowguid = creature->GetSpawnId();
  998. }
  999. else // case .setmovetype #creature_guid $move_type (with selected creature)
  1000. {
  1001. lowguid = strtoull(guid_str, nullptr, 10);
  1002.  
  1003. /* impossible without entry
  1004. if (lowguid)
  1005. creature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), MAKE_GUID(lowguid, HIGHGUID_UNIT));
  1006. */
  1007.  
  1008. // attempt check creature existence by DB data
  1009. if (!creature)
  1010. {
  1011. CreatureData const* data = sObjectMgr->GetCreatureData(lowguid);
  1012. if (!data)
  1013. {
  1014. handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
  1015. handler->SetSentErrorMessage(true);
  1016. return false;
  1017. }
  1018. }
  1019. else
  1020. {
  1021. lowguid = creature->GetSpawnId();
  1022. }
  1023. }
  1024.  
  1025. // now lowguid is low guid really existed creature
  1026. // and creature point (maybe) to this creature or NULL
  1027.  
  1028. MovementGeneratorType move_type;
  1029.  
  1030. std::string type = type_str;
  1031.  
  1032. if (type == "stay")
  1033. move_type = IDLE_MOTION_TYPE;
  1034. else if (type == "random")
  1035. move_type = RANDOM_MOTION_TYPE;
  1036. else if (type == "way")
  1037. move_type = WAYPOINT_MOTION_TYPE;
  1038. else
  1039. return false;
  1040.  
  1041. // update movement type
  1042. //if (doNotDelete == false)
  1043. // WaypointMgr.DeletePath(lowguid);
  1044.  
  1045. if (creature)
  1046. {
  1047. // update movement type
  1048. if (doNotDelete == false)
  1049. creature->LoadPath(0);
  1050.  
  1051. creature->SetDefaultMovementType(move_type);
  1052. creature->GetMotionMaster()->Initialize();
  1053. if (creature->IsAlive()) // dead creature will reset movement generator at respawn
  1054. {
  1055. creature->setDeathState(JUST_DIED);
  1056. creature->Respawn();
  1057. }
  1058. creature->SaveToDB();
  1059. }
  1060. if (doNotDelete == false)
  1061. {
  1062. handler->PSendSysMessage(LANG_MOVE_TYPE_SET, type_str);
  1063. }
  1064. else
  1065. {
  1066. handler->PSendSysMessage(LANG_MOVE_TYPE_SET_NODEL, type_str);
  1067. }
  1068.  
  1069. return true;
  1070. }
  1071.  
  1072. //npc phase handling
  1073. //change phase of creature
  1074. static bool HandleNpcSetPhaseGroup(ChatHandler* handler, char const* args)
  1075. {
  1076. if (!*args)
  1077. return false;
  1078.  
  1079. uint32 phaseGroupId = (uint32)atoi((char*)args);
  1080.  
  1081. Creature* creature = handler->getSelectedCreature();
  1082. if (!creature || creature->IsPet())
  1083. {
  1084. handler->SendSysMessage(LANG_SELECT_CREATURE);
  1085. handler->SetSentErrorMessage(true);
  1086. return false;
  1087. }
  1088.  
  1089. creature->ClearPhases();
  1090.  
  1091. for (uint32 id : sDB2Manager.GetPhasesForGroup(phaseGroupId))
  1092. creature->SetInPhase(id, false, true); // don't send update here for multiple phases, only send it once after adding all phases
  1093.  
  1094. creature->UpdateObjectVisibility();
  1095. creature->SetDBPhase(-int(phaseGroupId));
  1096.  
  1097. creature->SaveToDB();
  1098.  
  1099. return true;
  1100. }
  1101.  
  1102. //npc phase handling
  1103. //change phase of creature
  1104. static bool HandleNpcSetPhaseCommand(ChatHandler* handler, char const* args)
  1105. {
  1106. if (!*args)
  1107. return false;
  1108.  
  1109. uint32 phase = (uint32) atoi((char*)args);
  1110.  
  1111. Creature* creature = handler->getSelectedCreature();
  1112. if (!creature || creature->IsPet())
  1113. {
  1114. handler->SendSysMessage(LANG_SELECT_CREATURE);
  1115. handler->SetSentErrorMessage(true);
  1116. return false;
  1117. }
  1118.  
  1119. creature->ClearPhases();
  1120. creature->SetInPhase(phase, true, true);
  1121. creature->SetDBPhase(phase);
  1122.  
  1123. creature->SaveToDB();
  1124.  
  1125. return true;
  1126. }
  1127.  
  1128. //set spawn dist of creature
  1129. static bool HandleNpcSetSpawnDistCommand(ChatHandler* handler, char const* args)
  1130. {
  1131. if (!*args)
  1132. return false;
  1133.  
  1134. float option = (float)(atof((char*)args));
  1135. if (option < 0.0f)
  1136. {
  1137. handler->SendSysMessage(LANG_BAD_VALUE);
  1138. return false;
  1139. }
  1140.  
  1141. MovementGeneratorType mtype = IDLE_MOTION_TYPE;
  1142. if (option >0.0f)
  1143. mtype = RANDOM_MOTION_TYPE;
  1144.  
  1145. Creature* creature = handler->getSelectedCreature();
  1146. ObjectGuid::LowType guidLow = UI64LIT(0);
  1147.  
  1148. if (creature)
  1149. guidLow = creature->GetSpawnId();
  1150. else
  1151. return false;
  1152.  
  1153. creature->SetRespawnRadius(option);
  1154. creature->SetDefaultMovementType(mtype);
  1155. creature->GetMotionMaster()->Initialize();
  1156. if (creature->IsAlive()) // dead creature will reset movement generator at respawn
  1157. {
  1158. creature->setDeathState(JUST_DIED);
  1159. creature->Respawn();
  1160. }
  1161.  
  1162. PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_SPAWN_DISTANCE);
  1163.  
  1164. stmt->setFloat(0, option);
  1165. stmt->setUInt8(1, uint8(mtype));
  1166. stmt->setUInt64(2, guidLow);
  1167.  
  1168. WorldDatabase.Execute(stmt);
  1169.  
  1170. handler->PSendSysMessage(LANG_COMMAND_SPAWNDIST, option);
  1171. return true;
  1172. }
  1173.  
  1174. //spawn time handling
  1175. static bool HandleNpcSetSpawnTimeCommand(ChatHandler* handler, char const* args)
  1176. {
  1177. if (!*args)
  1178. return false;
  1179.  
  1180. char* stime = strtok((char*)args, " ");
  1181.  
  1182. if (!stime)
  1183. return false;
  1184.  
  1185. int spawnTime = atoi((char*)stime);
  1186.  
  1187. if (spawnTime < 0)
  1188. {
  1189. handler->SendSysMessage(LANG_BAD_VALUE);
  1190. handler->SetSentErrorMessage(true);
  1191. return false;
  1192. }
  1193.  
  1194. Creature* creature = handler->getSelectedCreature();
  1195. ObjectGuid::LowType guidLow = UI64LIT(0);
  1196.  
  1197. if (creature)
  1198. guidLow = creature->GetSpawnId();
  1199. else
  1200. return false;
  1201.  
  1202. PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_SPAWN_TIME_SECS);
  1203.  
  1204. stmt->setUInt32(0, uint32(spawnTime));
  1205. stmt->setUInt64(1, guidLow);
  1206.  
  1207. WorldDatabase.Execute(stmt);
  1208.  
  1209. creature->SetRespawnDelay((uint32)spawnTime);
  1210. handler->PSendSysMessage(LANG_COMMAND_SPAWNTIME, spawnTime);
  1211.  
  1212. return true;
  1213. }
  1214.  
  1215. static bool HandleNpcSayCommand(ChatHandler* handler, char const* args)
  1216. {
  1217. if (!*args)
  1218. return false;
  1219.  
  1220. Creature* creature = handler->getSelectedCreature();
  1221. if (!creature)
  1222. {
  1223. handler->SendSysMessage(LANG_SELECT_CREATURE);
  1224. handler->SetSentErrorMessage(true);
  1225. return false;
  1226. }
  1227.  
  1228. creature->Say(args, LANG_UNIVERSAL);
  1229.  
  1230. // make some emotes
  1231. char lastchar = args[strlen(args) - 1];
  1232. switch (lastchar)
  1233. {
  1234. case '?': creature->HandleEmoteCommand(EMOTE_ONESHOT_QUESTION); break;
  1235. case '!': creature->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); break;
  1236. default: creature->HandleEmoteCommand(EMOTE_ONESHOT_TALK); break;
  1237. }
  1238.  
  1239. return true;
  1240. }
  1241.  
  1242. //show text emote by creature in chat
  1243. static bool HandleNpcTextEmoteCommand(ChatHandler* handler, char const* args)
  1244. {
  1245. if (!*args)
  1246. return false;
  1247.  
  1248. Creature* creature = handler->getSelectedCreature();
  1249.  
  1250. if (!creature)
  1251. {
  1252. handler->SendSysMessage(LANG_SELECT_CREATURE);
  1253. handler->SetSentErrorMessage(true);
  1254. return false;
  1255. }
  1256.  
  1257. creature->TextEmote(args);
  1258.  
  1259. return true;
  1260. }
  1261.  
  1262. //npc unfollow handling
  1263. static bool HandleNpcUnFollowCommand(ChatHandler* handler, char const* /*args*/)
  1264. {
  1265. Player* player = handler->GetSession()->GetPlayer();
  1266. Creature* creature = handler->getSelectedCreature();
  1267.  
  1268. if (!creature)
  1269. {
  1270. handler->PSendSysMessage(LANG_SELECT_CREATURE);
  1271. handler->SetSentErrorMessage(true);
  1272. return false;
  1273. }
  1274.  
  1275. if (/*creature->GetMotionMaster()->empty() ||*/
  1276. creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != FOLLOW_MOTION_TYPE)
  1277. {
  1278. handler->PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU, creature->GetName().c_str());
  1279. handler->SetSentErrorMessage(true);
  1280. return false;
  1281. }
  1282.  
  1283. FollowMovementGenerator<Creature> const* mgen = static_cast<FollowMovementGenerator<Creature> const*>((creature->GetMotionMaster()->top()));
  1284.  
  1285. if (mgen->GetTarget() != player)
  1286. {
  1287. handler->PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU, creature->GetName().c_str());
  1288. handler->SetSentErrorMessage(true);
  1289. return false;
  1290. }
  1291.  
  1292. // reset movement
  1293. creature->GetMotionMaster()->MovementExpired(true);
  1294.  
  1295. handler->PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU_NOW, creature->GetName().c_str());
  1296. return true;
  1297. }
  1298.  
  1299. // make npc whisper to player
  1300. static bool HandleNpcWhisperCommand(ChatHandler* handler, char const* args)
  1301. {
  1302. if (!*args)
  1303. {
  1304. handler->SendSysMessage(LANG_CMD_SYNTAX);
  1305. handler->SetSentErrorMessage(true);
  1306. return false;
  1307. }
  1308.  
  1309. char* receiver_str = strtok((char*)args, " ");
  1310. char* text = strtok(NULL, "");
  1311.  
  1312. if (!receiver_str || !text)
  1313. {
  1314. handler->SendSysMessage(LANG_CMD_SYNTAX);
  1315. handler->SetSentErrorMessage(true);
  1316. return false;
  1317. }
  1318.  
  1319. Creature* creature = handler->getSelectedCreature();
  1320. if (!creature)
  1321. {
  1322. handler->SendSysMessage(LANG_SELECT_CREATURE);
  1323. handler->SetSentErrorMessage(true);
  1324. return false;
  1325. }
  1326.  
  1327. ObjectGuid receiver_guid = ObjectGuid::Create<HighGuid::Player>(strtoull(receiver_str, nullptr, 10));
  1328.  
  1329. // check online security
  1330. Player* receiver = ObjectAccessor::FindPlayer(receiver_guid);
  1331. if (handler->HasLowerSecurity(receiver, ObjectGuid::Empty))
  1332. return false;
  1333.  
  1334. creature->Whisper(text, LANG_UNIVERSAL, receiver);
  1335. return true;
  1336. }
  1337.  
  1338. static bool HandleNpcYellCommand(ChatHandler* handler, char const* args)
  1339. {
  1340. if (!*args)
  1341. {
  1342. handler->SendSysMessage(LANG_CMD_SYNTAX);
  1343. handler->SetSentErrorMessage(true);
  1344. return false;
  1345. }
  1346.  
  1347. Creature* creature = handler->getSelectedCreature();
  1348. if (!creature)
  1349. {
  1350. handler->SendSysMessage(LANG_SELECT_CREATURE);
  1351. handler->SetSentErrorMessage(true);
  1352. return false;
  1353. }
  1354.  
  1355. creature->Yell(args, LANG_UNIVERSAL);
  1356.  
  1357. // make an emote
  1358. creature->HandleEmoteCommand(EMOTE_ONESHOT_SHOUT);
  1359.  
  1360. return true;
  1361. }
  1362.  
  1363. // add creature, temp only
  1364. static bool HandleNpcAddTempSpawnCommand(ChatHandler* handler, char const* args)
  1365. {
  1366. if (!*args)
  1367. return false;
  1368.  
  1369. char* charID = handler->extractKeyFromLink((char*)args, "Hcreature_entry");
  1370. if (!charID)
  1371. return false;
  1372.  
  1373. Player* chr = handler->GetSession()->GetPlayer();
  1374.  
  1375. uint32 id = atoi(charID);
  1376. if (!id)
  1377. return false;
  1378.  
  1379. if (!sObjectMgr->GetCreatureTemplate(id))
  1380. return false;
  1381.  
  1382. chr->SummonCreature(id, *chr, TEMPSUMMON_CORPSE_DESPAWN, 120);
  1383.  
  1384. return true;
  1385. }
  1386.  
  1387. //npc tame handling
  1388. static bool HandleNpcTameCommand(ChatHandler* handler, char const* /*args*/)
  1389. {
  1390. Creature* creatureTarget = handler->getSelectedCreature();
  1391. if (!creatureTarget || creatureTarget->IsPet())
  1392. {
  1393. handler->PSendSysMessage (LANG_SELECT_CREATURE);
  1394. handler->SetSentErrorMessage (true);
  1395. return false;
  1396. }
  1397.  
  1398. Player* player = handler->GetSession()->GetPlayer();
  1399.  
  1400. if (!player->GetPetGUID().IsEmpty())
  1401. {
  1402. handler->SendSysMessage (LANG_YOU_ALREADY_HAVE_PET);
  1403. handler->SetSentErrorMessage (true);
  1404. return false;
  1405. }
  1406.  
  1407. CreatureTemplate const* cInfo = creatureTarget->GetCreatureTemplate();
  1408.  
  1409. if (!cInfo->IsTameable (player->CanTameExoticPets()))
  1410. {
  1411. handler->PSendSysMessage (LANG_CREATURE_NON_TAMEABLE, cInfo->Entry);
  1412. handler->SetSentErrorMessage (true);
  1413. return false;
  1414. }
  1415.  
  1416. // Everything looks OK, create new pet
  1417. Pet* pet = player->CreateTamedPetFrom(creatureTarget);
  1418. if (!pet)
  1419. {
  1420. handler->PSendSysMessage (LANG_CREATURE_NON_TAMEABLE, cInfo->Entry);
  1421. handler->SetSentErrorMessage (true);
  1422. return false;
  1423. }
  1424.  
  1425. // place pet before player
  1426. float x, y, z;
  1427. player->GetClosePoint (x, y, z, creatureTarget->GetObjectSize(), CONTACT_DISTANCE);
  1428. pet->Relocate(x, y, z, float(M_PI) - player->GetOrientation());
  1429.  
  1430. // set pet to defensive mode by default (some classes can't control controlled pets in fact).
  1431. pet->SetReactState(REACT_DEFENSIVE);
  1432.  
  1433. // calculate proper level
  1434. uint8 level = (creatureTarget->getLevel() < (player->getLevel() - 5)) ? (player->getLevel() - 5) : creatureTarget->getLevel();
  1435.  
  1436. // prepare visual effect for levelup
  1437. pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
  1438.  
  1439. // add to world
  1440. pet->GetMap()->AddToMap(pet->ToCreature());
  1441.  
  1442. // visual effect for levelup
  1443. pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
  1444.  
  1445. // caster have pet now
  1446. player->SetMinion(pet, true);
  1447.  
  1448. pet->SavePetToDB(PET_SAVE_AS_CURRENT);
  1449. player->PetSpellInitialize();
  1450.  
  1451. return true;
  1452. }
  1453.  
  1454. static bool HandleNpcAddFormationCommand(ChatHandler* handler, char const* args)
  1455. {
  1456. if (!*args)
  1457. return false;
  1458.  
  1459. ObjectGuid::LowType leaderGUID = strtoull(args, nullptr, 10);
  1460. Creature* creature = handler->getSelectedCreature();
  1461.  
  1462. if (!creature || !creature->GetSpawnId())
  1463. {
  1464. handler->SendSysMessage(LANG_SELECT_CREATURE);
  1465. handler->SetSentErrorMessage(true);
  1466. return false;
  1467. }
  1468.  
  1469. ObjectGuid::LowType lowguid = creature->GetSpawnId();
  1470. if (creature->GetFormation())
  1471. {
  1472. handler->PSendSysMessage("Selected creature is already member of group " UI64FMTD, creature->GetFormation()->GetId());
  1473. return false;
  1474. }
  1475.  
  1476. if (!lowguid)
  1477. return false;
  1478.  
  1479. Player* chr = handler->GetSession()->GetPlayer();
  1480. FormationInfo* group_member;
  1481.  
  1482. group_member = new FormationInfo;
  1483. group_member->follow_angle = (creature->GetAngle(chr) - chr->GetOrientation()) * 180 / float(M_PI);
  1484. group_member->follow_dist = std::sqrt(std::pow(chr->GetPositionX() - creature->GetPositionX(), 2.f) + std::pow(chr->GetPositionY() - creature->GetPositionY(), 2.f));
  1485. group_member->leaderGUID = leaderGUID;
  1486. group_member->groupAI = 0;
  1487.  
  1488. sFormationMgr->CreatureGroupMap[lowguid] = group_member;
  1489. creature->SearchFormation();
  1490.  
  1491. PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_CREATURE_FORMATION);
  1492.  
  1493. stmt->setUInt64(0, leaderGUID);
  1494. stmt->setUInt64(1, lowguid);
  1495. stmt->setFloat(2, group_member->follow_dist);
  1496. stmt->setFloat(3, group_member->follow_angle);
  1497. stmt->setUInt32(4, uint32(group_member->groupAI));
  1498.  
  1499. WorldDatabase.Execute(stmt);
  1500.  
  1501. handler->PSendSysMessage("Creature " UI64FMTD " added to formation with leader " UI64FMTD, lowguid, leaderGUID);
  1502.  
  1503. return true;
  1504. }
  1505.  
  1506. static bool HandleNpcSetLinkCommand(ChatHandler* handler, char const* args)
  1507. {
  1508. if (!*args)
  1509. return false;
  1510.  
  1511. ObjectGuid::LowType linkguid = strtoull(args, nullptr, 10);
  1512.  
  1513. Creature* creature = handler->getSelectedCreature();
  1514.  
  1515. if (!creature)
  1516. {
  1517. handler->SendSysMessage(LANG_SELECT_CREATURE);
  1518. handler->SetSentErrorMessage(true);
  1519. return false;
  1520. }
  1521.  
  1522. if (!creature->GetSpawnId())
  1523. {
  1524. handler->PSendSysMessage("Selected %s isn't in creature table", creature->GetGUID().ToString().c_str());
  1525. handler->SetSentErrorMessage(true);
  1526. return false;
  1527. }
  1528.  
  1529. if (!sObjectMgr->SetCreatureLinkedRespawn(creature->GetSpawnId(), linkguid))
  1530. {
  1531. handler->PSendSysMessage("Selected creature can't link with guid '" UI64FMTD "'", linkguid);
  1532. handler->SetSentErrorMessage(true);
  1533. return false;
  1534. }
  1535.  
  1536. handler->PSendSysMessage("LinkGUID '" UI64FMTD "' added to creature with DBTableGUID: '" UI64FMTD "'", linkguid, creature->GetSpawnId());
  1537. return true;
  1538. }
  1539.  
  1540. /// @todo NpcCommands that need to be fixed :
  1541. static bool HandleNpcAddWeaponCommand(ChatHandler* /*handler*/, char const* /*args*/)
  1542. {
  1543. /*if (!*args)
  1544. return false;
  1545.  
  1546. uint64 guid = handler->GetSession()->GetPlayer()->GetSelection();
  1547. if (guid == 0)
  1548. {
  1549. handler->SendSysMessage(LANG_NO_SELECTION);
  1550. return true;
  1551. }
  1552.  
  1553. Creature* creature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), guid);
  1554.  
  1555. if (!creature)
  1556. {
  1557. handler->SendSysMessage(LANG_SELECT_CREATURE);
  1558. return true;
  1559. }
  1560.  
  1561. char* pSlotID = strtok((char*)args, " ");
  1562. if (!pSlotID)
  1563. return false;
  1564.  
  1565. char* pItemID = strtok(NULL, " ");
  1566. if (!pItemID)
  1567. return false;
  1568.  
  1569. uint32 ItemID = atoi(pItemID);
  1570. uint32 SlotID = atoi(pSlotID);
  1571.  
  1572. ItemTemplate* tmpItem = sObjectMgr->GetItemTemplate(ItemID);
  1573.  
  1574. bool added = false;
  1575. if (tmpItem)
  1576. {
  1577. switch (SlotID)
  1578. {
  1579. case 1:
  1580. creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, ItemID);
  1581. added = true;
  1582. break;
  1583. case 2:
  1584. creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01, ItemID);
  1585. added = true;
  1586. break;
  1587. case 3:
  1588. creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02, ItemID);
  1589. added = true;
  1590. break;
  1591. default:
  1592. handler->PSendSysMessage(LANG_ITEM_SLOT_NOT_EXIST, SlotID);
  1593. added = false;
  1594. break;
  1595. }
  1596.  
  1597. if (added)
  1598. handler->PSendSysMessage(LANG_ITEM_ADDED_TO_SLOT, ItemID, tmpItem->Name1, SlotID);
  1599. }
  1600. else
  1601. {
  1602. handler->PSendSysMessage(LANG_ITEM_NOT_FOUND, ItemID);
  1603. return true;
  1604. }
  1605. */
  1606. return true;
  1607. }
  1608. };
  1609.  
  1610. void AddSC_npc_commandscript()
  1611. {
  1612. new npc_commandscript();
  1613. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement