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 "creatureaction/CreatureActionSearchJob.h"
19
20 #include "creatureaction/CreatureActionGetFee.h"
21 #include "creatureaction/CreatureActionSearchFood.h"
22 #include "creatureaction/CreatureActionSleep.h"
23 #include "creatureaction/CreatureActionUseRoom.h"
24 #include "creatureaction/CreatureActionWalkToTile.h"
25 #include "creaturemood/CreatureMood.h"
26 #include "entities/Creature.h"
27 #include "entities/CreatureDefinition.h"
28 #include "entities/Tile.h"
29 #include "game/Seat.h"
30 #include "gamemap/GameMap.h"
31 #include "rooms/Room.h"
32 #include "rooms/RoomType.h"
33 #include "utils/Helper.h"
34 #include "utils/LogManager.h"
35 #include "utils/MakeUnique.h"
36 #include "utils/Random.h"
37
action()38 std::function<bool()> CreatureActionSearchJob::action()
39 {
40 return std::bind(&CreatureActionSearchJob::handleSearchJob,
41 std::ref(mCreature), mForced);
42 }
43
handleSearchJob(Creature & creature,bool forced)44 bool CreatureActionSearchJob::handleSearchJob(Creature& creature, bool forced)
45 {
46 // Current creature tile position
47 Tile* myTile = creature.getPositionTile();
48 if (myTile == nullptr)
49 {
50 creature.popAction();
51 return false;
52 }
53
54 // If we are unhappy, we do not want to work
55 switch(creature.getMoodValue())
56 {
57 case CreatureMoodLevel::Upset:
58 {
59 // 20% chances of not working
60 if(Random::Int(0, 100) < 20)
61 {
62 creature.popAction();
63 return true;
64 }
65 break;
66 }
67 case CreatureMoodLevel::Angry:
68 case CreatureMoodLevel::Furious:
69 {
70 // We don't work
71 creature.popAction();
72 return true;
73 }
74 default:
75 // We can work
76 break;
77 }
78
79 if(!creature.hasSlapEffect())
80 {
81 // The creature should look for gold after payday if the keeper is not broke
82 if((creature.getGoldFee() > 0) &&
83 (!creature.hasActionBeenTried(CreatureActionType::getFee)) &&
84 (creature.getSeat()->getGold() > 0))
85 {
86 creature.pushAction(Utils::make_unique<CreatureActionGetFee>(creature));
87 return true;
88 }
89
90 // If we are sleepy, we go to bed unless we have been slapped
91 if (Random::Double(20.0, 30.0) > creature.getWakefulness())
92 {
93 creature.popAction();
94 creature.pushAction(Utils::make_unique<CreatureActionSleep>(creature));
95 return true;
96 }
97
98 // If we are hungry, we try to find food unless we have been slapped
99 if (Random::Double(70.0, 80.0) < creature.getHunger())
100 {
101 creature.popAction();
102 creature.pushAction(Utils::make_unique<CreatureActionSearchFood>(creature, false));
103 return true;
104 }
105 }
106
107 if(forced)
108 {
109 // We check if we can work in the given room
110 Room* room = myTile->getCoveringRoom();
111 for(const CreatureRoomAffinity& affinity : creature.getDefinition()->getRoomAffinity())
112 {
113 if(room == nullptr)
114 continue;
115 if(room->getType() != affinity.getRoomType())
116 continue;
117 if(affinity.getEfficiency() <= 0)
118 continue;
119 if(!creature.getSeat()->canOwnedCreatureUseRoomFrom(room->getSeat()))
120 continue;
121
122 // It is the room responsibility to test if the creature is suited for working in it
123 if(room->hasOpenCreatureSpot(&creature))
124 {
125 creature.pushAction(Utils::make_unique<CreatureActionUseRoom>(creature, *room, forced));
126 return false;
127 }
128 break;
129 }
130
131 // If we couldn't work on the room we were forced to, we stop trying
132 creature.popAction();
133 return true;
134 }
135
136 // We get the room we like the most. If we are on such a room, we start working if we can
137 for(const CreatureRoomAffinity& affinity : creature.getDefinition()->getRoomAffinity())
138 {
139 // If likeness = 0, we don't consider working here
140 if(affinity.getLikeness() <= 0)
141 continue;
142
143 // See if we are in the room we like the most. If yes and we can work, we stay. If no,
144 // We check if there is such a room somewhere else where we can go
145 if((myTile->getCoveringRoom() != nullptr) &&
146 (myTile->getCoveringRoom()->getType() == affinity.getRoomType()) &&
147 (creature.getSeat()->canOwnedCreatureUseRoomFrom(myTile->getCoveringRoom()->getSeat())))
148 {
149 Room* room = myTile->getCoveringRoom();
150 // If the efficiency is 0 or the room is a hatchery, we only wander in the room
151 if((affinity.getEfficiency() <= 0) ||
152 (room->getType() == RoomType::hatchery))
153 {
154 int index = Random::Int(0, room->numCoveredTiles() - 1);
155 Tile* tileDest = room->getCoveredTile(index);
156 creature.setDestination(tileDest);
157 return false;
158 }
159
160 // It is the room responsibility to test if the creature is suited for working in it
161 if(room->hasOpenCreatureSpot(&creature))
162 {
163 creature.pushAction(Utils::make_unique<CreatureActionUseRoom>(creature, *room, forced));
164 return true;
165 }
166 }
167
168 // We are not in a room of the good type or we couldn't use it. We check if there is a reachable room
169 // of the good type
170 std::vector<Tile*> rooms;
171 for(Room* room : creature.getGameMap()->getRooms())
172 {
173 if(room->getSeat() != creature.getSeat())
174 continue;
175
176 if(room->numCoveredTiles() <= 0)
177 continue;
178
179 if(room->getType() != affinity.getRoomType())
180 continue;
181
182 // If efficiency is 0, we just want to wander so no need to check if the room is available
183 if((affinity.getEfficiency() > 0) && !room->hasOpenCreatureSpot(&creature))
184 continue;
185
186 Tile* tile = room->getCoveredTile(0);
187 if(!creature.getGameMap()->pathExists(&creature, myTile, tile))
188 continue;
189
190 rooms.push_back(tile);
191 }
192
193 if(rooms.empty())
194 continue;
195
196 Tile* chosenTile = nullptr;
197 std::list<Tile*> tilePath = creature.getGameMap()->findBestPath(&creature, myTile, rooms, chosenTile);
198
199 if(tilePath.empty() || (chosenTile == nullptr))
200 continue;
201
202 std::vector<Ogre::Vector3> vectorPath;
203 creature.tileToVector3(tilePath, vectorPath, true, 0.0);
204 creature.setWalkPath(EntityAnimation::walk_anim, EntityAnimation::idle_anim, true, true, vectorPath);
205 creature.pushAction(Utils::make_unique<CreatureActionWalkToTile>(creature));
206 return false;
207 }
208
209 // Default action
210 creature.popAction();
211 return true;
212 }
213