1 /*
2 * Copyright (C) 2011-2016 OpenDungeons Team
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
18 #include "traps/TrapBoulder.h"
19
20 #include "entities/Tile.h"
21 #include "entities/MissileBoulder.h"
22 #include "entities/TrapEntity.h"
23 #include "game/Player.h"
24 #include "gamemap/GameMap.h"
25 #include "network/ODPacket.h"
26 #include "traps/TrapManager.h"
27 #include "utils/ConfigManager.h"
28 #include "utils/Random.h"
29 #include "utils/LogManager.h"
30
31 const std::string TrapBoulderName = "Boulder";
32 const std::string TrapBoulderNameDisplay = "Boulder trap";
33 const TrapType TrapBoulder::mTrapType = TrapType::boulder;
34
35 namespace
36 {
37 class TrapBoulderFactory : public TrapFactory
38 {
getTrapType() const39 TrapType getTrapType() const override
40 { return TrapBoulder::mTrapType; }
41
getName() const42 const std::string& getName() const override
43 { return TrapBoulderName; }
44
getNameReadable() const45 const std::string& getNameReadable() const override
46 { return TrapBoulderNameDisplay; }
47
getCostPerTile() const48 int getCostPerTile() const override
49 { return ConfigManager::getSingleton().getTrapConfigInt32("BoulderCostPerTile"); }
50
getMeshName() const51 const std::string& getMeshName() const override
52 {
53 static const std::string meshName = "Boulder";
54 return meshName;
55 }
56
checkBuildTrap(GameMap * gameMap,const InputManager & inputManager,InputCommand & inputCommand) const57 void checkBuildTrap(GameMap* gameMap, const InputManager& inputManager, InputCommand& inputCommand) const override
58 {
59 checkBuildTrapDefault(gameMap, TrapType::boulder, inputManager, inputCommand);
60 }
61
buildTrap(GameMap * gameMap,Player * player,ODPacket & packet) const62 bool buildTrap(GameMap* gameMap, Player* player, ODPacket& packet) const override
63 {
64 std::vector<Tile*> tiles;
65 if(!getTrapTilesDefault(tiles, gameMap, player, packet))
66 return false;
67
68 int32_t pricePerTarget = TrapManager::costPerTile(TrapType::boulder);
69 int32_t price = static_cast<int32_t>(tiles.size()) * pricePerTarget;
70 if(!gameMap->withdrawFromTreasuries(price, player->getSeat()))
71 return false;
72
73 TrapBoulder* trap = new TrapBoulder(gameMap);
74 return buildTrapDefault(gameMap, trap, player->getSeat(), tiles);
75 }
76
checkBuildTrapEditor(GameMap * gameMap,const InputManager & inputManager,InputCommand & inputCommand) const77 void checkBuildTrapEditor(GameMap* gameMap, const InputManager& inputManager, InputCommand& inputCommand) const override
78 {
79 checkBuildTrapDefaultEditor(gameMap, TrapType::boulder, inputManager, inputCommand);
80 }
81
buildTrapEditor(GameMap * gameMap,ODPacket & packet) const82 bool buildTrapEditor(GameMap* gameMap, ODPacket& packet) const override
83 {
84 TrapBoulder* trap = new TrapBoulder(gameMap);
85 return buildTrapDefaultEditor(gameMap, trap, packet);
86 }
87
getTrapFromStream(GameMap * gameMap,std::istream & is) const88 Trap* getTrapFromStream(GameMap* gameMap, std::istream& is) const override
89 {
90 TrapBoulder* trap = new TrapBoulder(gameMap);
91 if(!Trap::importTrapFromStream(*trap, is))
92 {
93 OD_LOG_ERR("Error while building a trap from the stream");
94 }
95 return trap;
96 }
97
buildTrapOnTiles(GameMap * gameMap,Player * player,const std::vector<Tile * > & tiles) const98 bool buildTrapOnTiles(GameMap* gameMap, Player* player, const std::vector<Tile*>& tiles) const override
99 {
100 int32_t pricePerTarget = TrapManager::costPerTile(TrapType::boulder);
101 int32_t price = static_cast<int32_t>(tiles.size()) * pricePerTarget;
102 if(!gameMap->withdrawFromTreasuries(price, player->getSeat()))
103 return false;
104
105 TrapBoulder* trap = new TrapBoulder(gameMap);
106 return buildTrapDefault(gameMap, trap, player->getSeat(), tiles);
107 }
108 };
109
110 // Register the factory
111 static TrapRegister reg(new TrapBoulderFactory);
112 }
113
TrapBoulder(GameMap * gameMap)114 TrapBoulder::TrapBoulder(GameMap* gameMap) :
115 Trap(gameMap)
116 {
117 mReloadTime = ConfigManager::getSingleton().getTrapConfigUInt32("BoulderReloadTurns");
118 mMinDamage = ConfigManager::getSingleton().getTrapConfigDouble("BoulderDamagePerHitMin");
119 mMaxDamage = ConfigManager::getSingleton().getTrapConfigDouble("BoulderDamagePerHitMax");
120 mNbShootsBeforeDeactivation = ConfigManager::getSingleton().getTrapConfigUInt32("BoulderNbShootsBeforeDeactivation");
121 setMeshName("");
122 }
123
shoot(Tile * tile)124 bool TrapBoulder::shoot(Tile* tile)
125 {
126 std::vector<Tile*> tiles = tile->getAllNeighbors();
127 for(std::vector<Tile*>::iterator it = tiles.begin(); it != tiles.end();)
128 {
129 Tile* tmpTile = *it;
130 std::vector<Tile*> vecTile;
131 vecTile.push_back(tmpTile);
132
133 if(getGameMap()->getVisibleCreatures(vecTile, getSeat(), true).empty())
134 it = tiles.erase(it);
135 else
136 ++it;
137 }
138 if(tiles.empty())
139 return false;
140
141 // We take a random tile and launch boulder it
142 Tile* tileChosen = tiles[Random::Uint(0, tiles.size() - 1)];
143 // We launch the boulder
144 Ogre::Vector3 direction(static_cast<Ogre::Real>(tileChosen->getX() - tile->getX()),
145 static_cast<Ogre::Real>(tileChosen->getY() - tile->getY()),
146 0);
147 Ogre::Vector3 position;
148 position.x = static_cast<Ogre::Real>(tile->getX());
149 position.y = static_cast<Ogre::Real>(tile->getY());
150 position.z = 0;
151 direction.normalise();
152 MissileBoulder* missile = new MissileBoulder(getGameMap(), getSeat(), getName(), "Boulder",
153 direction, ConfigManager::getSingleton().getTrapConfigDouble("BoulderSpeed"),
154 Random::Double(mMinDamage, mMaxDamage), nullptr, true);
155 missile->addToGameMap();
156 missile->createMesh();
157 missile->setPosition(position);
158 // We don't want the missile to stay idle for 1 turn. Because we are in a doUpkeep context,
159 // we can safely call the missile doUpkeep as we know the engine will not call it the turn
160 // it has been added
161 missile->doUpkeep();
162 missile->setAnimationState("Triggered", true);
163
164 return true;
165 }
166
getTrapEntity(Tile * tile)167 TrapEntity* TrapBoulder::getTrapEntity(Tile* tile)
168 {
169 return new TrapEntity(getGameMap(), *this, reg.getTrapFactory()->getMeshName(), tile, 0.0, false, isActivated(tile) ? 1.0f : 0.5f);
170 }
171