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