Advertisement
Guest User

Untitled

a guest
Jan 19th, 2017
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.97 KB | None | 0 0
  1. ////////////////////////////////////////////////////////////////////////
  2. // OpenTibia - an opensource roleplaying game
  3. ////////////////////////////////////////////////////////////////////////
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. ////////////////////////////////////////////////////////////////////////
  17. #include "otpch.h"
  18. #include <libxml/xmlmemory.h>
  19. #include <libxml/parser.h>
  20.  
  21. #include "spawn.h"
  22. #include "tools.h"
  23.  
  24. #include "player.h"
  25. #include "npc.h"
  26.  
  27. #include "configmanager.h"
  28. #include "game.h"
  29.  
  30. extern ConfigManager g_config;
  31. extern Monsters g_monsters;
  32. extern Game g_game;
  33.  
  34. #define MINSPAWN_INTERVAL 1000
  35. #define DEFAULTSPAWN_INTERVAL 60000
  36.  
  37. Spawns::Spawns()
  38. {
  39. loaded = started = false;
  40. }
  41.  
  42. Spawns::~Spawns()
  43. {
  44. if(started)
  45. clear();
  46. }
  47.  
  48. bool Spawns::loadFromXml(const std::string& _filename)
  49. {
  50. if(isLoaded())
  51. return true;
  52.  
  53. filename = _filename;
  54. xmlDocPtr doc = xmlParseFile(filename.c_str());
  55. if(!doc)
  56. {
  57. std::clog << "[Warning - Spawns::loadFromXml] Cannot open spawns file." << std::endl;
  58. std::clog << getLastXMLError() << std::endl;
  59. return false;
  60. }
  61.  
  62. xmlNodePtr spawnNode, root = xmlDocGetRootElement(doc);
  63. if(xmlStrcmp(root->name,(const xmlChar*)"spawns"))
  64. {
  65. std::clog << "[Error - Spawns::loadFromXml] Malformed spawns file." << std::endl;
  66. xmlFreeDoc(doc);
  67. return false;
  68. }
  69.  
  70. for(spawnNode = root->children; spawnNode; spawnNode = spawnNode->next)
  71. parseSpawnNode(spawnNode, false);
  72.  
  73. xmlFreeDoc(doc);
  74. loaded = true;
  75. return true;
  76. }
  77.  
  78. bool Spawns::parseSpawnNode(xmlNodePtr p, bool checkDuplicate)
  79. {
  80. if(xmlStrcmp(p->name, (const xmlChar*)"spawn"))
  81. return false;
  82.  
  83. int32_t intValue;
  84. std::string strValue;
  85.  
  86. Position centerPos;
  87. if(!readXMLString(p, "centerpos", strValue))
  88. {
  89. if(!readXMLInteger(p, "centerx", intValue))
  90. return false;
  91.  
  92. centerPos.x = intValue;
  93. if(!readXMLInteger(p, "centery", intValue))
  94. return false;
  95.  
  96. centerPos.y = intValue;
  97. if(!readXMLInteger(p, "centerz", intValue))
  98. return false;
  99.  
  100. centerPos.z = intValue;
  101. }
  102. else
  103. {
  104. IntegerVec posVec = vectorAtoi(explodeString(strValue, ","));
  105. if(posVec.size() < 3)
  106. return false;
  107.  
  108. centerPos = Position(posVec[0], posVec[1], posVec[2]);
  109. }
  110.  
  111. if(!readXMLInteger(p, "radius", intValue))
  112. return false;
  113.  
  114. int32_t radius = intValue;
  115. Spawn* spawn = new Spawn(centerPos, radius);
  116. if(checkDuplicate)
  117. {
  118. for(SpawnList::iterator it = spawnList.begin(); it != spawnList.end(); ++it)
  119. {
  120. if((*it)->getPosition() == centerPos)
  121. delete *it;
  122. }
  123. }
  124.  
  125. spawnList.push_back(spawn);
  126. for(xmlNodePtr tmpNode = p->children; tmpNode; tmpNode = tmpNode->next)
  127. {
  128. if(!xmlStrcmp(tmpNode->name, (const xmlChar*)"monster"))
  129. {
  130. if(!readXMLString(tmpNode, "name", strValue))
  131. continue;
  132.  
  133. std::string name = strValue;
  134. int32_t interval = MINSPAWN_INTERVAL / 1000;
  135. if(readXMLInteger(tmpNode, "spawntime", intValue) || readXMLInteger(tmpNode, "interval", intValue))
  136. {
  137. if(intValue <= interval)
  138. {
  139. std::clog << "[Warning - Spawns::loadFromXml] " << name << " " << centerPos << " spawntime cannot"
  140. << " be less than " << interval << " seconds." << std::endl;
  141. continue;
  142. }
  143.  
  144. interval = intValue;
  145. }
  146.  
  147. interval *= 1000;
  148. Position placePos = centerPos;
  149. if(readXMLInteger(tmpNode, "x", intValue))
  150. placePos.x += intValue;
  151.  
  152. if(readXMLInteger(tmpNode, "y", intValue))
  153. placePos.y += intValue;
  154.  
  155. if(readXMLInteger(tmpNode, "z", intValue))
  156. placePos.z /*+*/= intValue;
  157.  
  158. Direction direction = NORTH;
  159. if(readXMLInteger(tmpNode, "direction", intValue) && direction >= EAST && direction <= WEST)
  160. direction = (Direction)intValue;
  161.  
  162. spawn->addMonster(name, placePos, direction, interval);
  163. }
  164. else if(!xmlStrcmp(tmpNode->name, (const xmlChar*)"npc"))
  165. {
  166. if(!readXMLString(tmpNode, "name", strValue))
  167. continue;
  168.  
  169. std::string name = strValue;
  170. Position placePos = centerPos;
  171. if(readXMLInteger(tmpNode, "x", intValue))
  172. placePos.x += intValue;
  173.  
  174. if(readXMLInteger(tmpNode, "y", intValue))
  175. placePos.y += intValue;
  176.  
  177. if(readXMLInteger(tmpNode, "z", intValue))
  178. placePos.z /*+*/= intValue;
  179.  
  180. Direction direction = NORTH;
  181. if(readXMLInteger(tmpNode, "direction", intValue) && direction >= EAST && direction <= WEST)
  182. direction = (Direction)intValue;
  183.  
  184. Npc* npc = Npc::createNpc(name);
  185. if(!npc)
  186. continue;
  187.  
  188. npc->setMasterPosition(placePos, radius);
  189. npc->setDirection(direction);
  190. npcList.push_back(npc);
  191. }
  192. }
  193.  
  194. return true;
  195. }
  196.  
  197. void Spawns::startup()
  198. {
  199. if(!isLoaded() || isStarted())
  200. return;
  201.  
  202. for(NpcList::iterator it = npcList.begin(); it != npcList.end(); ++it)
  203. g_game.placeCreature((*it), (*it)->getMasterPosition(), false, true);
  204.  
  205. npcList.clear();
  206. for(SpawnList::iterator it = spawnList.begin(); it != spawnList.end(); ++it)
  207. (*it)->startup();
  208.  
  209. started = true;
  210. }
  211.  
  212. void Spawns::clear()
  213. {
  214. started = false;
  215. for(SpawnList::iterator it = spawnList.begin(); it != spawnList.end(); ++it)
  216. delete (*it);
  217.  
  218. spawnList.clear();
  219. loaded = false;
  220. filename = std::string();
  221. }
  222.  
  223. bool Spawns::isInZone(const Position& centerPos, int32_t radius, const Position& pos)
  224. {
  225. if(radius == -1)
  226. return true;
  227.  
  228. return ((pos.x >= centerPos.x - radius) && (pos.x <= centerPos.x + radius) &&
  229. (pos.y >= centerPos.y - radius) && (pos.y <= centerPos.y + radius));
  230. }
  231.  
  232. void Spawn::startEvent()
  233. {
  234. if(!checkSpawnEvent)
  235. checkSpawnEvent = Scheduler::getInstance().addEvent(createSchedulerTask(getInterval(), boost::bind(&Spawn::checkSpawn, this)));
  236. }
  237.  
  238. Spawn::Spawn(const Position& _pos, int32_t _radius)
  239. {
  240. centerPos = _pos;
  241. radius = _radius;
  242. interval = DEFAULTSPAWN_INTERVAL;
  243. checkSpawnEvent = 0;
  244. }
  245.  
  246. Spawn::~Spawn()
  247. {
  248. stopEvent();
  249. Monster* monster = NULL;
  250. for(SpawnedMap::iterator it = spawnedMap.begin(); it != spawnedMap.end(); ++it)
  251. {
  252. if(!(monster = it->second))
  253. continue;
  254.  
  255. monster->setSpawn(NULL);
  256. if(!monster->isRemoved())
  257. g_game.freeThing(monster);
  258. }
  259.  
  260. spawnedMap.clear();
  261. spawnMap.clear();
  262. }
  263.  
  264. bool Spawn::findPlayer(const Position& pos)
  265. {
  266. SpectatorVec list;
  267. g_game.getSpectators(list, pos);
  268.  
  269. Player* tmpPlayer = NULL;
  270. for(SpectatorVec::iterator it = list.begin(); it != list.end(); ++it)
  271. {
  272. if((tmpPlayer = (*it)->getPlayer()) && !tmpPlayer->hasFlag(PlayerFlag_IgnoredByMonsters))
  273. return true;
  274. }
  275.  
  276. return false;
  277. }
  278.  
  279. bool Spawn::spawnMonster(uint32_t spawnId, MonsterType* mType, const Position& pos, Direction dir, int16_t t,
  280. bool startup /*= false*/)
  281. {
  282. Monster* monster = Monster::createMonster(mType);
  283. if(!monster)
  284. return false;
  285.  
  286. if(startup)
  287. {
  288. //No need to send out events to the surrounding since there is no one out there to listen!
  289. if(!g_game.internalPlaceCreature(monster, pos, false, true))
  290. {
  291. delete monster;
  292. return false;
  293. }
  294. }
  295. else if (t == 0)
  296. {
  297. if (!g_game.placeCreature(monster, pos, false, true))
  298. {
  299. delete monster;
  300. return false;
  301. }
  302. }
  303. else {
  304. g_game.addMagicEffect(pos, MAGIC_EFFECT_TELEPORT);
  305. Scheduler::getInstance().addEvent(createSchedulerTask(
  306. 1400, boost::bind(&Spawn::spawnMonster, this, spawnId, mType, pos, dir, t - 1400,false)));
  307. return true;
  308. }
  309.  
  310. monster->setSpawn(this);
  311. monster->setMasterPosition(pos, radius);
  312. monster->setDirection(dir);
  313.  
  314. monster->addRef();
  315. spawnedMap.insert(SpawnedPair(spawnId, monster));
  316. spawnMap[spawnId].lastSpawn = OTSYS_TIME();
  317.  
  318. return true;
  319. }
  320.  
  321. void Spawn::startup()
  322. {
  323. for(SpawnMap::iterator it = spawnMap.begin(); it != spawnMap.end(); ++it)
  324. {
  325. spawnBlock_t& sb = it->second;
  326. spawnMonster(it->first, sb.mType, sb.pos, sb.direction, true);
  327. }
  328. }
  329.  
  330. void Spawn::checkSpawn()
  331. {
  332. #ifdef __DEBUG_SPAWN__
  333. std::clog << "[Notice] Spawn::checkSpawn " << this << std::endl;
  334. #endif
  335. Monster* monster;
  336. uint32_t spawnId;
  337.  
  338. checkSpawnEvent = 0;
  339. for(SpawnedMap::iterator it = spawnedMap.begin(); it != spawnedMap.end();)
  340. {
  341. spawnId = it->first;
  342. monster = it->second;
  343. if(monster->isRemoved())
  344. {
  345. if(spawnId)
  346. spawnMap[spawnId].lastSpawn = OTSYS_TIME();
  347.  
  348. monster->unRef();
  349. spawnedMap.erase(it++);
  350. }
  351. else
  352. {
  353. /*if(spawnId && !isInSpawnZone(monster->getPosition()) && monster->getIdleStatus())
  354. g_game.internalTeleport(monster, monster->getMasterPosition(), true);
  355.  
  356. */++it;
  357. }
  358. }
  359.  
  360. uint32_t spawnCount = 0;
  361. for(SpawnMap::iterator it = spawnMap.begin(); it != spawnMap.end(); ++it)
  362. {
  363. spawnId = it->first;
  364. spawnBlock_t& sb = it->second;
  365. if(spawnedMap.count(spawnId))
  366. continue;
  367.  
  368. if(OTSYS_TIME() < sb.lastSpawn + sb.interval)
  369. continue;
  370.  
  371. if(findPlayer(sb.pos))
  372. {
  373. sb.lastSpawn = OTSYS_TIME();
  374. continue;
  375. }
  376.  
  377. spawnMonster(spawnId, sb.mType, sb.pos, sb.direction);
  378. ++spawnCount;
  379. if(spawnCount >= (uint32_t)g_config.getNumber(ConfigManager::RATE_SPAWN))
  380. break;
  381. }
  382.  
  383. if(spawnedMap.size() < spawnMap.size())
  384. checkSpawnEvent = Scheduler::getInstance().addEvent(createSchedulerTask(getInterval(), boost::bind(&Spawn::checkSpawn, this)));
  385. #ifdef __DEBUG_SPAWN__
  386. else
  387. std::clog << "[Notice] Spawn::checkSpawn stopped " << this << std::endl;
  388. #endif
  389. }
  390.  
  391. bool Spawn::addMonster(const std::string& _name, const Position& _pos, Direction _dir, uint32_t _interval)
  392. {
  393. if(!g_game.getTile(_pos))
  394. {
  395. std::clog << "[Spawn::addMonster] NULL tile at spawn position (" << _pos << ")" << std::endl;
  396. return false;
  397. }
  398.  
  399. MonsterType* mType = g_monsters.getMonsterType(_name);
  400. if(!mType)
  401. {
  402. std::clog << "[Spawn::addMonster] Cannot find \"" << _name << "\"" << std::endl;
  403. return false;
  404. }
  405.  
  406. if(_interval < interval)
  407. interval = _interval;
  408.  
  409. spawnBlock_t sb;
  410. sb.mType = mType;
  411. sb.pos = _pos;
  412. sb.direction = _dir;
  413. sb.interval = _interval;
  414. sb.lastSpawn = 0;
  415.  
  416. uint32_t spawnId = (int32_t)spawnMap.size() + 1;
  417. spawnMap[spawnId] = sb;
  418. return true;
  419. }
  420.  
  421. void Spawn::removeMonster(Monster* monster)
  422. {
  423. for(SpawnedMap::iterator it = spawnedMap.begin(); it != spawnedMap.end(); ++it)
  424. {
  425. if(it->second != monster)
  426. continue;
  427.  
  428. monster->unRef();
  429. spawnedMap.erase(it);
  430. break;
  431. }
  432. }
  433.  
  434. void Spawn::stopEvent()
  435. {
  436. if(!checkSpawnEvent)
  437. return;
  438.  
  439. Scheduler::getInstance().stopEvent(checkSpawnEvent);
  440. checkSpawnEvent = 0;
  441. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement