1 #include "repairCrew.h"
2
3 const static int16_t CMD_SET_TARGET_POSITION = 0x0000;
4
5 PVector<RepairCrew> repairCrewList;
6
7 REGISTER_MULTIPLAYER_CLASS(RepairCrew, "RepairCrew");
RepairCrew()8 RepairCrew::RepairCrew()
9 : MultiplayerObject("RepairCrew")
10 {
11 ship_id = -1;
12 position.x = -1;
13 action = RC_Idle;
14 direction = ERepairCrewDirection(irandom(RC_Up, RC_Right + 1));
15
16 selected = false;
17
18 registerMemberReplication(&ship_id);
19 registerMemberReplication(&position, 1.0);
20 registerMemberReplication(&target_position);
21
22 repairCrewList.push_back(this);
23 }
24
25 //due to a suspected compiler bug this deconstructor needs to be explicitly defined
~RepairCrew()26 RepairCrew::~RepairCrew()
27 {
28 }
29
30 /* struct PathNode
31 {
32 ERepairCrewDirection arrive_direction;
33 bool right, down;
34 };
35 */
36
37 class PathMap {
38 class PathNode {
39 public:
40 ERepairCrewDirection arrive_direction;
41 bool right, down;
PathNode()42 PathNode() : arrive_direction(RC_None), right(false), down(false) { };
43 };
44 private:
45 std::vector<PathNode> pathMap;
46 public:
47 int width;
48 int height;
49
PathMap(const sf::Vector2i & size)50 PathMap(const sf::Vector2i &size) : pathMap(size.x*size.y), width(size.x), height(size.y) {
51 // init all interior down/right doors (not right or bottom edge)
52 for (int x = 0; x < width-1; x++) {
53 for (int y = 0; y < height-1; y++) {
54 Node(x, y).down = true;
55 Node(x, y).right = true;
56 }
57 }
58 }
59
Node(int x,int y)60 inline PathNode& Node(int x, int y) {
61 assert(x >= 0 && x < width && y >= 0 && y < height);
62 return pathMap[y*width + x];
63 }
64 };
65
pathFind(sf::Vector2i start_pos,sf::Vector2i target_pos,P<ShipTemplate> t)66 ERepairCrewDirection pathFind(sf::Vector2i start_pos, sf::Vector2i target_pos, P<ShipTemplate> t)
67 {
68 PathMap map(t->interiorSize());
69
70 for(unsigned int n=0; n<t->rooms.size(); n++)
71 {
72 const ShipRoomTemplate &room = t->rooms[n];
73 for(int x=0; x<room.size.x; x++)
74 {
75 map.Node(room.position.x + x,room.position.y - 1).down = false;
76 map.Node(room.position.x + x,room.position.y + room.size.y - 1).down = false;
77 }
78 for(int y=0; y<room.size.y; y++)
79 {
80 map.Node(room.position.x - 1,room.position.y + y).right = false;
81 map.Node(room.position.x + room.size.x - 1,room.position.y + y).right = false;
82 }
83 }
84 for(unsigned int n=0; n<t->doors.size(); n++)
85 {
86 const ShipDoorTemplate &door = t->doors[n];
87 if (door.horizontal)
88 {
89 map.Node(door.position.x,door.position.y - 1).down = true;
90 }else{
91 map.Node(door.position.x - 1,door.position.y).right = true;
92 }
93 }
94
95 std::vector<sf::Vector2i> search_points;
96 search_points.push_back(start_pos);
97 while(search_points.size() > 0)
98 {
99 sf::Vector2i pos = search_points[0];
100 if (pos == target_pos)
101 return map.Node(pos.x,pos.y).arrive_direction;
102 search_points.erase(search_points.begin());
103
104 if (map.Node(pos.x,pos.y).right && map.Node(pos.x + 1,pos.y).arrive_direction == RC_None)
105 {
106 map.Node(pos.x + 1,pos.y).arrive_direction = map.Node(pos.x,pos.y).arrive_direction;
107 if (map.Node(pos.x + 1,pos.y).arrive_direction == RC_None) map.Node(pos.x + 1,pos.y).arrive_direction = RC_Right;
108 search_points.push_back(sf::Vector2i(pos.x + 1, pos.y));
109 }
110 if (pos.x > 0 && map.Node(pos.x - 1,pos.y).right && map.Node(pos.x - 1,pos.y).arrive_direction == RC_None)
111 {
112 map.Node(pos.x - 1,pos.y).arrive_direction = map.Node(pos.x,pos.y).arrive_direction;
113 if (map.Node(pos.x - 1,pos.y).arrive_direction == RC_None) map.Node(pos.x - 1,pos.y).arrive_direction = RC_Left;
114 search_points.push_back(sf::Vector2i(pos.x - 1, pos.y));
115 }
116 if (map.Node(pos.x,pos.y).down && map.Node(pos.x,pos.y + 1).arrive_direction == RC_None)
117 {
118 map.Node(pos.x,pos.y + 1).arrive_direction = map.Node(pos.x,pos.y).arrive_direction;
119 if (map.Node(pos.x,pos.y + 1).arrive_direction == RC_None) map.Node(pos.x,pos.y + 1).arrive_direction = RC_Down;
120 search_points.push_back(sf::Vector2i(pos.x, pos.y + 1));
121 }
122 if (pos.y > 0 && map.Node(pos.x,pos.y - 1).down && map.Node(pos.x,pos.y - 1).arrive_direction == RC_None)
123 {
124 map.Node(pos.x,pos.y - 1).arrive_direction = map.Node(pos.x,pos.y).arrive_direction;
125 if (map.Node(pos.x,pos.y - 1).arrive_direction == RC_None) map.Node(pos.x,pos.y - 1).arrive_direction = RC_Up;
126 search_points.push_back(sf::Vector2i(pos.x, pos.y - 1));
127 }
128 }
129
130 return RC_None;
131 }
132
update(float delta)133 void RepairCrew::update(float delta)
134 {
135 P<PlayerSpaceship> ship;
136 if (game_server)
137 ship = game_server->getObjectById(ship_id);
138 else if (game_client)
139 ship = game_client->getObjectById(ship_id);
140 else
141 {
142 destroy();
143 return;
144 }
145
146
147 if (game_server && !ship)
148 {
149 destroy();
150 return;
151 }
152 if (!ship || !ship->ship_template)
153 return;
154
155 if (ship->ship_template->rooms.size() == 0)
156 {
157 destroy();
158 return;
159 }
160
161 if (position.x < -0.5)
162 {
163 ship->ship_template->interiorSize();
164 int n=irandom(0, ship->ship_template->rooms.size() - 1);
165 position = sf::Vector2f(ship->ship_template->rooms[n].position + sf::Vector2i(irandom(0, ship->ship_template->rooms[n].size.x - 1), irandom(0, ship->ship_template->rooms[n].size.y - 1)));
166 target_position = sf::Vector2i(position);
167 }
168
169 action_delay -= delta;
170 sf::Vector2i pos = sf::Vector2i(position + sf::Vector2f(0.5, 0.5));
171 switch(action)
172 {
173 case RC_Idle:
174 {
175 action_delay = 1.0 / move_speed;
176 if (pos != target_position)
177 {
178 ERepairCrewDirection new_direction = pathFind(pos, target_position, ship->ship_template);
179 if (new_direction != RC_None)
180 {
181 action = RC_Move;
182 direction = new_direction;
183 }
184 }
185 position = sf::Vector2f(pos);
186
187 ESystem system = ship->ship_template->getSystemAtRoom(pos);
188 if (system != SYS_None)
189 {
190 ship->systems[system].health += repair_per_second * delta;
191 if (ship->systems[system].health > 1.0)
192 ship->systems[system].health = 1.0;
193 ship->systems[system].hacked_level -= repair_per_second * delta;
194 if (ship->systems[system].hacked_level < 0.0)
195 ship->systems[system].hacked_level = 0.0;
196 }
197 if (ship->auto_repair_enabled && pos == target_position && (system == SYS_None || !ship->hasSystem(system) || ship->systems[system].health == 1.0))
198 {
199 int n=irandom(0, SYS_COUNT - 1);
200
201 if (ship->hasSystem(ESystem(n)) && ship->systems[n].health < 1.0)
202 {
203 for(unsigned int idx=0; idx<ship->ship_template->rooms.size(); idx++)
204 {
205 if (ship->ship_template->rooms[idx].system == ESystem(n))
206 {
207 target_position = ship->ship_template->rooms[idx].position + sf::Vector2i(irandom(0, ship->ship_template->rooms[idx].size.x - 1), irandom(0, ship->ship_template->rooms[idx].size.y - 1));
208 }
209 }
210 }
211 }
212 }
213 break;
214 case RC_Move:
215 switch(direction)
216 {
217 case RC_None: break;
218 case RC_Left: position.x -= delta * move_speed; break;
219 case RC_Right: position.x += delta * move_speed; break;
220 case RC_Up: position.y -= delta * move_speed; break;
221 case RC_Down: position.y += delta * move_speed; break;
222 }
223 if (action_delay < 0.0)
224 action = RC_Idle;
225 break;
226 }
227 }
228
onReceiveClientCommand(int32_t client_id,sf::Packet & packet)229 void RepairCrew::onReceiveClientCommand(int32_t client_id, sf::Packet& packet)
230 {
231 int16_t command;
232 packet >> command;
233 switch(command)
234 {
235 case CMD_SET_TARGET_POSITION:
236 {
237 sf::Vector2i pos;
238 packet >> pos;
239 if (!isTargetPositionTaken(pos))
240 {
241 target_position = pos;
242 }
243 }
244 break;
245 }
246 }
247
commandSetTargetPosition(sf::Vector2i position)248 void RepairCrew::commandSetTargetPosition(sf::Vector2i position)
249 {
250 sf::Packet packet;
251 packet << CMD_SET_TARGET_POSITION << position;
252 sendClientCommand(packet);
253 }
254
isTargetPositionTaken(sf::Vector2i pos)255 bool RepairCrew::isTargetPositionTaken(sf::Vector2i pos)
256 {
257 foreach(RepairCrew, c, repairCrewList)
258 {
259 if (c->ship_id == ship_id && c->target_position == pos)
260 return true;
261 }
262 return false;
263 }
264
getRepairCrewFor(P<PlayerSpaceship> ship)265 PVector<RepairCrew> getRepairCrewFor(P<PlayerSpaceship> ship)
266 {
267 PVector<RepairCrew> ret;
268 if (!ship)
269 return ret;
270
271 foreach(RepairCrew, c, repairCrewList)
272 if (c->ship_id == ship->getMultiplayerId())
273 ret.push_back(c);
274 return ret;
275 }
276