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