Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
NetGameClient.cpp
Go to the documentation of this file.
1 /* Project Starshatter 4.5
2  Destroyer Studios LLC
3  Copyright (C) 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: Stars.exe
6  FILE: NetGameClient.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Network Game Manager class
13 */
14 
15 #include "MemDebug.h"
16 #include "NetGameClient.h"
17 #include "NetClientConfig.h"
18 #include "NetLobby.h"
19 #include "NetPlayer.h"
20 #include "NetData.h"
21 #include "NetUtil.h"
22 #include "Ship.h"
23 #include "ShipDesign.h"
24 #include "Shield.h"
25 #include "Shot.h"
26 #include "Sim.h"
27 #include "SimEvent.h"
28 #include "Weapon.h"
29 #include "Element.h"
30 #include "Explosion.h"
31 #include "HUDView.h"
32 #include "RadioView.h"
33 #include "Instruction.h"
34 #include "Hangar.h"
35 #include "FlightDeck.h"
36 #include "Mission.h"
37 
38 #include "NetMsg.h"
39 #include "NetHost.h"
40 #include "NetLayer.h"
41 #include "NetPeer.h"
42 
43 #include "Game.h"
44 #include "Light.h"
45 
46 // +--------------------------------------------------------------------+
47 
48 const int MAX_NET_FPS = 20;
49 const int MIN_NET_FRAME = 1000 / MAX_NET_FPS;
50 
51 const char* FormatGameTime();
52 
53 // +--------------------------------------------------------------------+
54 
56 : server_id(0), join_req_time(0)
57 {
58  Print("Constructing NetGameClient\n");
59 
60  NetHost me;
61  Text server_name;
62  WORD port = 11101;
63 
65  if (ncc) {
66  NetServerInfo* info = ncc->GetSelectedServer();
67 
68  if (info) {
69  server_name = info->hostname;
70  port = info->gameport;
71  }
72  }
73 
74  if (server_name.length() && port > 0) {
75  Print(" '%s' is a client of '%s'\n", me.Name(), server_name.data());
76  link = new(__FILE__,__LINE__) NetLink;
77  server_id = link->AddPeer(NetAddr(server_name, port));
79  }
80  else if (port == 0) {
81  Print(" '%s' invalid game port number %d\n", me.Name(), port);
82  }
83  else {
84  Print(" '%s' is a client without a server\n", me.Name());
85  }
86 }
87 
89 {
91 
92  // wait for message to be delivered before shutting down the link:
93  Sleep(500);
94 
96 }
97 
98 // +--------------------------------------------------------------------+
99 
100 void
102 {
103  if ((NetLayer::GetTime() - join_req_time) < 5000)
104  return;
105 
107  Print(" sending join request - name: '%s' elem: '%s' index: %d\n",
108  player_name.data(),
111 
112  NetJoinRequest join_req;
113  join_req.SetName(player_name);
114  join_req.SetPassword(player_pass);
115  join_req.SetElement(local_player->GetElement()->Name());
116  join_req.SetIndex(local_player->GetElementIndex());
117 
120 
122  }
123 }
124 
125 // +--------------------------------------------------------------------+
126 
127 void
129 {
130  if (!msg) return;
131 
132  NetJoinRequest join_req;
133  if (join_req.Unpack(msg->Data())) {
134  Print("Client received Join Request from '%s'\n", join_req.GetName());
135  }
136 }
137 
138 void
140 {
141  if (!msg) return;
142 
143  Sim* sim = Sim::GetSim();
144  if (!sim) return;
145 
146  NetJoinAnnounce* join_ann = new(__FILE__,__LINE__) NetJoinAnnounce;
147  bool saved = false;
148 
149  if (join_ann->Unpack(msg->Data())) {
150  DWORD nid = msg->NetID();
151  DWORD oid = join_ann->GetObjID();
152  Text name = join_ann->GetName();
153  Text elem_name = join_ann->GetElement();
154  Text region = join_ann->GetRegion();
155  Point loc = join_ann->GetLocation();
156  Point velocity = join_ann->GetVelocity();
157  int index = join_ann->GetIndex();
158  int shld_lvl = join_ann->GetShield();
159  join_ann->SetNetID(nid);
160  Ship* ship = 0;
161  char ship_name[128];
162 
163  strcpy_s(ship_name, Game::GetText("NetGameClient.no-ship").data());
164 
165  if (local_player && player_name == name) {
166  HUDView::Message(Game::GetText("NetGameClient.local-accept"), name.data(), local_player->Name());
167 
168  objid = oid;
169  netid = nid;
170  local_player->SetObjID(oid);
173 
174  SimRegion* rgn = local_player->GetRegion();
175  if (rgn && region != rgn->Name()) {
176  SimRegion* dst = sim->FindRegion(region);
177  if (dst) dst->InsertObject(local_player);
178  }
179 
180  local_player->MoveTo(loc);
181  local_player->SetVelocity(velocity);
182 
183  Shield* shield = local_player->GetShield();
184  if (shield)
185  shield->SetNetShieldLevel(shld_lvl);
186  }
187  else {
188  NetPlayer* remote_player = FindPlayerByObjID(oid);
189  if (remote_player) {
190  remote_player->SetName(name);
191  remote_player->SetObjID(oid);
192 
193  if (index > 0)
194  sprintf_s(ship_name, "%s %d", elem_name.data(), index);
195  else
196  sprintf_s(ship_name, "%s", elem_name.data());
197  }
198  else {
199  Element* element = sim->FindElement(elem_name);
200 
201  if (element) {
202  ship = element->GetShip(index);
203  }
204  else {
205  Print("NetGameClient::DoJoinAnnounce() could not find elem %s for player '%s' objid %d\n",
206  elem_name.data(), name.data(), oid);
207 
208  NetUtil::SendElemRequest(elem_name.data());
209  }
210 
211  if (!ship) {
212  // save it for later:
213  join_backlog.append(join_ann);
214  saved = true;
215  }
216  else {
217  strcpy_s(ship_name, ship->Name());
218 
219  SimRegion* rgn = ship->GetRegion();
220  if (rgn && region != rgn->Name()) {
221  SimRegion* dst = sim->FindRegion(region);
222  if (dst) dst->InsertObject(ship);
223  }
224 
225  ship->MoveTo(loc);
226  ship->SetVelocity(velocity);
227 
228  Shield* shield = ship->GetShield();
229  if (shield)
230  shield->SetNetShieldLevel(shld_lvl);
231 
232  NetPlayer* remote_player = new(__FILE__,__LINE__) NetPlayer(nid);
233  remote_player->SetName(name);
234  remote_player->SetObjID(oid);
235  remote_player->SetShip(ship);
236 
237  players.append(remote_player);
238 
239  if (name == "Server A.I. Ship") {
240  Print("Remote Player '%s' has joined as '%s' with ID %d\n", name.data(), ship_name, oid);
241  }
242  else {
243  HUDView::Message(Game::GetText("NetGameClient.remote-join").data(), name.data(), ship_name);
244  }
245  }
246  }
247  }
248  }
249 
250  if (!saved)
251  delete join_ann;
252 }
253 
254 bool
256 {
257  bool finished = false;
258 
259  if (!join_ann)
260  return finished;
261 
262  Sim* sim = Sim::GetSim();
263  if (!sim)
264  return finished;
265 
266  DWORD nid = join_ann->GetNetID();
267  DWORD oid = join_ann->GetObjID();
268  Text name = join_ann->GetName();
269  Text elem_name = join_ann->GetElement();
270  Text region = join_ann->GetRegion();
271  Point loc = join_ann->GetLocation();
272  Point velocity = join_ann->GetVelocity();
273  int index = join_ann->GetIndex();
274  int shld_lvl = join_ann->GetShield();
275  Ship* ship = 0;
276  char ship_name[128];
277 
278  strcpy_s(ship_name, Game::GetText("NetGameClient.no-ship").data());
279 
280  if (nid && oid) {
281  NetPlayer* remote_player = FindPlayerByObjID(oid);
282  if (remote_player) {
283  remote_player->SetName(name);
284  remote_player->SetObjID(oid);
285 
286  if (index > 0)
287  sprintf_s(ship_name, "%s %d", elem_name.data(), index);
288  else
289  sprintf_s(ship_name, "%s", elem_name.data());
290  }
291  else {
292  Element* element = sim->FindElement(elem_name);
293 
294  if (element) {
295  ship = element->GetShip(index);
296  }
297 
298  if (ship) {
299  strcpy_s(ship_name, ship->Name());
300 
301  SimRegion* rgn = ship->GetRegion();
302  if (rgn && region != rgn->Name()) {
303  SimRegion* dst = sim->FindRegion(region);
304  if (dst) dst->InsertObject(ship);
305  }
306 
307  ship->MoveTo(loc);
308  ship->SetVelocity(velocity);
309 
310  Shield* shield = ship->GetShield();
311  if (shield)
312  shield->SetNetShieldLevel(shld_lvl);
313 
314  NetPlayer* remote_player = new(__FILE__,__LINE__) NetPlayer(nid);
315  remote_player->SetName(name);
316  remote_player->SetObjID(oid);
317  remote_player->SetShip(ship);
318 
319  players.append(remote_player);
320  finished = true;
321 
322  if (name == "Server A.I. Ship") {
323  Print("NetGameClient::DoJoinBacklog() Remote Player '%s' has joined as '%s' with ID %d\n", name.data(), ship_name, oid);
324  }
325  else {
326  HUDView::Message(Game::GetText("NetGameClient.remote-join").data(), name.data(), ship_name);
327  }
328  }
329  }
330  }
331 
332  return finished;
333 }
334 
335 
336 void
338 {
339  if (!msg) return;
340 
341  Print("Client received Quit Request from NetID: %08X\n", msg->NetID());
342 }
343 
344 void
346 {
347  if (!msg) return;
348 
349  NetQuitAnnounce quit_ann;
350  quit_ann.Unpack(msg->Data());
351 
352  NetPlayer* player = FindPlayerByObjID(quit_ann.GetObjID());
353 
354  if (player) {
355  NetPlayer* zombie = players.remove(player);
356 
357  // return remote ship to ship pool:
358  Ship* s = zombie->GetShip();
359  if (s) {
360  s->SetNetworkControl(0);
361  zombie->SetShip(0);
362  }
363 
364  if (quit_ann.GetDisconnected())
365  HUDView::Message(Game::GetText("NetGameClient.remote-discon").data(), zombie->Name());
366  else
367  HUDView::Message(Game::GetText("NetGameClient.remote-quit").data(), zombie->Name());
368  delete zombie;
369  }
370  else {
371  Print("Quit Announce for unknown player %08X disconnected = %d\n", msg->NetID(), quit_ann.GetDisconnected());
372  }
373 }
374 
375 void
377 {
378  if (!msg) return;
379 
380  HUDView::Message(Game::GetText("NetGameClient.game-over").data());
381  players.destroy();
382  active = false;
383 }
384 
385 void
387 {
388  if (!msg) return;
389 
390  HUDView::Message(Game::GetText("NetGameClient.discon-detect").data());
391  HUDView::Message(Game::GetText("NetGameClient.please-exit").data());
392  players.destroy();
393  active = false;
394 }
395 
396 void
398 {
399  if (!msg) return;
400 
401  NetObjLoc obj_loc;
402  obj_loc.Unpack(msg->Data());
403 
404  NetPlayer* player = FindPlayerByObjID(obj_loc.GetObjID());
405  if (player)
406  player->DoObjLoc(&obj_loc);
407 }
408 
409 void
411 {
412  if (!msg) return;
413 
414  NetObjDamage obj_damage;
415  obj_damage.Unpack(msg->Data());
416 
417  Ship* ship = FindShipByObjID(obj_damage.GetObjID());
418  if (ship) {
419  Sim* sim = Sim::GetSim();
420  Shot* shot = FindShotByObjID(obj_damage.GetShotID());
421  const Ship* owner = 0;
422  const char* owner_name = "[NET]";
423 
424  ship->InflictNetDamage(obj_damage.GetDamage(), shot);
425 
426  if (shot && sim) {
427  if (shot->Owner()) {
428  owner = shot->Owner();
429  owner_name = owner->Name();
430  }
431 
432  if (shot->IsMissile()) {
433  SimRegion* region = ship->GetRegion();
434  float scale = ship->Design()->explosion_scale;
435 
436  if (scale <= 0)
437  scale = ship->Design()->scale;
438 
439  if (owner) {
440  const ShipDesign* owner_design = owner->Design();
441  if (owner_design && owner_design->scale < scale)
442  scale = (float) owner_design->scale;
443  }
444 
445  sim->CreateExplosion(shot->Location(), Point(), Explosion::SHOT_BLAST, 20.0f * scale, scale, region);
446  }
447 
448  if (!shot->IsBeam()) {
449  if (owner) {
450  ShipStats* stats = ShipStats::Find(owner_name);
451 
452  if (stats) {
453  if (shot->IsPrimary())
454  stats->AddGunHit();
455  else if (shot->Damage() > 0)
456  stats->AddMissileHit();
457  }
458  }
459 
460  shot->Destroy();
461  }
462  }
463  }
464 }
465 
466 void
468 {
469  if (!msg) return;
470 
471  NetObjKill obj_kill;
472  obj_kill.Unpack(msg->Data());
473 
474  Ship* ship = FindShipByObjID(obj_kill.GetObjID());
475  if (ship) {
476  Ship* killer = FindShipByObjID(obj_kill.GetKillerID());
477  Text killer_name = Game::GetText("NetGameClient.unknown");
478 
479  if (killer)
480  killer_name = killer->Name();
481 
482  // log the kill:
483  switch (obj_kill.GetKillType()) {
484  default:
486  Print("Ship '%s' destroyed (misc) (%s)\n", ship->Name(), FormatGameTime());
487  break;
488 
491  Print("Ship '%s' killed by '%s' (%s)\n", ship->Name(), killer_name.data(), FormatGameTime());
492  break;
493 
495  Print("Ship '%s' killed in collision with '%s' (%s)\n", ship->Name(), killer_name.data(), FormatGameTime());
496  break;
497 
499  Print("Ship '%s' destroyed (crash) (%s)\n", ship->Name(), FormatGameTime());
500 
502  Print("Ship '%s' docked (%s)\n", ship->Name(), FormatGameTime());
503  }
504 
505  // record the kill in the stats:
506  if (killer && obj_kill.GetKillType() != NetObjKill::KILL_DOCK) {
507  ShipStats* kstats = ShipStats::Find(killer->Name());
508  if (kstats) {
509  if (obj_kill.GetKillType() == NetObjKill::KILL_PRIMARY)
510  kstats->AddEvent(SimEvent::GUNS_KILL, ship->Name());
511 
512  else if (obj_kill.GetKillType() == NetObjKill::KILL_SECONDARY)
513  kstats->AddEvent(SimEvent::MISSILE_KILL, ship->Name());
514  }
515 
516  if (killer && killer->GetIFF() != ship->GetIFF()) {
517  if (ship->GetIFF() > 0 || killer->GetIFF() > 1)
518  kstats->AddPoints(ship->Value());
519  }
520  }
521 
522  ShipStats* killee = ShipStats::Find(ship->Name());
523  if (killee) {
524  if (obj_kill.GetKillType() == NetObjKill::KILL_DOCK)
525  killee->AddEvent(SimEvent::DOCK, killer_name);
526  else
527  killee->AddEvent(SimEvent::DESTROYED, killer_name);
528  }
529 
530  if (obj_kill.GetKillType() == NetObjKill::KILL_DOCK) {
531  FlightDeck* deck = killer->GetFlightDeck(obj_kill.GetFlightDeck());
532  sim->NetDockShip(ship, killer, deck);
533  }
534  else {
535  ship->InflictNetDamage(ship->Integrity());
536  ship->DeathSpiral();
537 
538  if (!obj_kill.GetRespawn())
539  ship->SetRespawnCount(0);
540  else
541  ship->SetRespawnLoc(obj_kill.GetRespawnLoc());
542  }
543  }
544 
545  // this shouldn't happen in practice,
546  // but if it does, this is what should be done:
547  else {
548  Shot* shot = FindShotByObjID(obj_kill.GetObjID());
549 
550  if (shot) {
551  ::Print("NetGameClient::DoObjKill destroying shot '%s'\n", shot->Name());
552  shot->Destroy();
553  }
554  }
555 }
556 
557 void
559 {
560 }
561 
562 void
564 {
565  if (!msg) return;
566  Print("Client received OBJ HYPER from NetID: %08x\n", msg->NetID());
567 
568  NetObjHyper obj_hyper;
569  obj_hyper.Unpack(msg->Data());
570 
571  NetPlayer* player = FindPlayerByObjID(obj_hyper.GetObjID());
572  if (player && player->GetShip())
573  player->DoObjHyper(&obj_hyper);
574 }
575 
576 void
578 {
579  if (!msg) return;
580 
581  NetObjTarget obj_target;
582  obj_target.Unpack(msg->Data());
583 
584  NetPlayer* player = FindPlayerByObjID(obj_target.GetObjID());
585  if (player)
586  player->DoObjTarget(&obj_target);
587 }
588 
589 void
591 {
592  if (!msg) return;
593 
594  NetObjEmcon obj_emcon;
595  obj_emcon.Unpack(msg->Data());
596 
597  NetPlayer* player = FindPlayerByObjID(obj_emcon.GetObjID());
598  if (player)
599  player->DoObjEmcon(&obj_emcon);
600 }
601 
602 // +--------------------------------------------------------------------+
603 
604 void
606 {
607  if (!msg) return;
608 
609  NetSysDamage sys_damage;
610  sys_damage.Unpack(msg->Data());
611 
612  NetPlayer* player = FindPlayerByObjID(sys_damage.GetObjID());
613  if (player && player->GetShip())
614  player->DoSysDamage(&sys_damage);
615 }
616 
617 void
619 {
620  if (!msg) return;
621 
622  NetSysStatus sys_status;
623  sys_status.Unpack(msg->Data());
624 
625  NetPlayer* player = FindPlayerByObjID(sys_status.GetObjID());
626  if (player && player->GetShip())
627  player->DoSysStatus(&sys_status);
628 }
629 
630 // +--------------------------------------------------------------------+
631 
632 void
634 {
635  if (!msg) return;
636 
637  NetElemCreate elem_create;
638  elem_create.Unpack(msg->Data());
639 
640  const char* elem_name = elem_create.GetName().data();
641 
642  ::Print("NetGameClient::DoElemCreate name: %s iff: %d type %s\n",
643  elem_name,
644  elem_create.GetIFF(),
645  Mission::RoleName(elem_create.GetType()));
646 
647  Sim* sim = Sim::GetSim();
648  Element* elem = sim->FindElement(elem_name);
649  if (elem) {
650  ::Print(" element '%' already exists - ignored\n", elem_name);
651  return;
652  }
653 
654  elem = sim->CreateElement(elem_name,
655  elem_create.GetIFF(),
656  elem_create.GetType());
657 
658  int* load = elem_create.GetLoadout();
659  int* slots = elem_create.GetSlots();
660  int squadron = elem_create.GetSquadron();
661  int code = elem_create.GetObjCode();
662  Text target = elem_create.GetObjective();
663  bool alert = elem_create.GetAlert();
664  bool active = elem_create.GetInFlight();
665 
666  elem->SetIntelLevel(elem_create.GetIntel());
667  elem->SetLoadout(load);
668 
669  if (code > Instruction::RTB || target.length() > 0) {
670  Instruction* obj = new(__FILE__,__LINE__) Instruction(code, target);
671  elem->AddObjective(obj);
672  }
673 
674  Ship* carrier = sim->FindShip(elem_create.GetCarrier());
675  if (carrier) {
676  elem->SetCarrier(carrier);
677 
678  Hangar* hangar = carrier->GetHangar();
679  if (hangar) {
680  Text squadron_name = hangar->SquadronName(squadron);
681  elem->SetSquadron(squadron_name);
682 
683  if (active) {
684  for (int i = 0; i < 4; i++) {
685  int slot = slots[i];
686  if (slot > -1) {
687  hangar->GotoActiveFlight(squadron, slot, elem, load);
688  }
689  }
690  }
691 
692  else {
693  FlightDeck* deck = 0;
694  int queue = 1000;
695 
696  for (int i = 0; i < carrier->NumFlightDecks(); i++) {
697  FlightDeck* d = carrier->GetFlightDeck(i);
698 
699  if (d && d->IsLaunchDeck()) {
700  int dq = hangar->PreflightQueue(d);
701 
702  if (dq < queue) {
703  queue = dq;
704  deck = d;
705  }
706  }
707  }
708 
709  for (int i = 0; i < 4; i++) {
710  int slot = slots[i];
711  if (slot > -1) {
712  hangar->GotoAlert(squadron, slot, deck, elem, load, !alert);
713  }
714  }
715  }
716  }
717  }
718 }
719 
720 void
722 {
723  if (!msg) return;
724 
725  NetShipLaunch ship_launch;
726  ship_launch.Unpack(msg->Data());
727 
728  Sim* sim = Sim::GetSim();
729  int squadron = ship_launch.GetSquadron();
730  int slot = ship_launch.GetSlot();
731 
732  Ship* carrier = FindShipByObjID(ship_launch.GetObjID());
733 
734  if (carrier) {
735  Hangar* hangar = carrier->GetHangar();
736 
737  if (hangar) {
738  hangar->Launch(squadron, slot);
739  }
740  }
741 }
742 
743 void
745 {
746  if (!msg) return;
747 
748  NetWepTrigger trigger;
749  trigger.Unpack(msg->Data());
750 
751  NetPlayer* player = FindPlayerByObjID(trigger.GetObjID());
752  if (player)
753  player->DoWepTrigger(&trigger);
754 }
755 
756 void
758 {
759  if (!msg) return;
760 
761  NetWepRelease release;
762  release.Unpack(msg->Data());
763 
764  NetPlayer* player = FindPlayerByObjID(release.GetObjID());
765  if (player) {
766  player->DoWepRelease(&release);
767  }
768 
769  else {
770  Ship* shooter = FindShipByObjID(release.GetObjID());
771  if (shooter) {
772  int index = release.GetIndex();
773  DWORD tgtid = release.GetTgtID();
774  DWORD wepid = release.GetWepID();
775  int subid = release.GetSubtarget();
776  bool decoy = release.GetDecoy();
777  bool probe = release.GetProbe();
778 
779  Weapon* w = 0;
780 
781  if (decoy) w = shooter->GetDecoy();
782  else if (probe) w = shooter->GetProbeLauncher();
783  else w = shooter->GetWeaponByIndex(index);
784 
785  if (w && !w->IsPrimary()) {
786  SimObject* target = FindShipByObjID(tgtid);
787  System* subtgt = 0;
788 
789  if (target) {
790  if (subid >= 0) {
791  Ship* tgt_ship = (Ship*) target;
792  subtgt = tgt_ship->Systems().at(subid);
793  }
794  }
795  else {
796  target = FindShotByObjID(tgtid);
797  }
798 
799  Shot* shot = w->NetFireSecondary(target, subtgt, wepid);
800 
801  if (shot && shot->IsDrone()) {
802  if (probe)
803  shooter->SetProbe((Drone*) shot);
804 
805  else if (decoy)
806  shooter->AddActiveDecoy((Drone*) shot);
807  }
808  }
809  }
810  }
811 }
812 
813 void
815 {
816  if (!msg) return;
817 
818  NetNavData nav_data;
819  nav_data.Unpack(msg->Data());
820 
821  Element* elem = sim->FindElement(nav_data.GetElem());
822  Ship* ship = FindShipByObjID(nav_data.GetObjID());
823 
824  if (elem) {
825  if (nav_data.IsAdd()) {
826  Instruction* navpt = new(__FILE__,__LINE__) Instruction(*nav_data.GetNavPoint());
827  Instruction* after = 0;
828  int index = nav_data.GetIndex();
829 
830  if (index >= 0 && index < elem->GetFlightPlan().size())
831  after = elem->GetFlightPlan().at(index);
832 
833  elem->AddNavPoint(navpt, after, false);
834  }
835 
836  else {
837  Instruction* navpt = nav_data.GetNavPoint();
838  Instruction* exist = 0;
839  int index = nav_data.GetIndex();
840 
841  if (navpt && index >= 0 && index < elem->GetFlightPlan().size()) {
842  exist = elem->GetFlightPlan().at(index);
843 
844  *exist = *navpt;
845  }
846  }
847  }
848 }
849 
850 void
852 {
853  if (!msg) return;
854 
855  NetNavDelete nav_delete;
856  nav_delete.Unpack(msg->Data());
857 
858  Element* elem = sim->FindElement(nav_delete.GetElem());
859  Ship* ship = FindShipByObjID(nav_delete.GetObjID());
860 
861  if (elem) {
862  int index = nav_delete.GetIndex();
863 
864  if (index < 0) {
865  elem->ClearFlightPlan(false);
866  }
867 
868  else if (index < elem->FlightPlanLength()) {
869  Instruction* npt = elem->GetFlightPlan().at(index);
870  elem->DelNavPoint(npt, false);
871  }
872  }
873 }
874 
875 void
877 {
878  if (!msg) return;
879 
880  NetWepDestroy destroy;
881  destroy.Unpack(msg->Data());
882 
883  Shot* shot = FindShotByObjID(destroy.GetObjID());
884  if (shot) {
885  if (shot->IsBeam())
886  ::Print("NetGameClient::DoWepDestroy shot '%s'\n", shot->Name());
887 
888  shot->Destroy();
889  }
890 }
891 
892 void
894 {
895  if (!msg) return;
896 
897  NetCommMsg comm_msg;
898  comm_msg.Unpack(msg->Data());
899 
900  NetPlayer* player = FindPlayerByObjID(comm_msg.GetObjID());
901  if (player)
902  player->DoCommMessage(&comm_msg);
903 }
904 
905 void
907 {
908  if (!msg) return;
909 
910  NetChatMsg chat_msg;
911  chat_msg.Unpack(msg->Data());
912 
913  Text name = chat_msg.GetName();
914  if (name.length() < 1)
915  name = Game::GetText("NetGameClient.chat.unknown");
916 
917  HUDView::Message("%s> %s", name.data(), chat_msg.GetText().data());
918 }
919 
920 void
922 {
923  if (!msg) return;
924 
925  NetSelfDestruct self_destruct;
926  self_destruct.Unpack(msg->Data());
927 
928  Ship* ship = FindShipByObjID(self_destruct.GetObjID());
929  if (ship) {
930  ship->InflictNetDamage(self_destruct.GetDamage());
931  }
932 }
933 
934 // +--------------------------------------------------------------------+
935 
936 void
938 {
939  DWORD time = Game::GameTime();
940 
941  // don't flood the network...
942  if (time - last_send_time < MIN_NET_FRAME)
943  return;
944 
945  last_send_time = time;
946 
947  if (local_player && objid && server_id) {
948  double r, p, y;
950 
951  NetObjLoc obj_loc;
952 
953  obj_loc.SetObjID(objid);
954  obj_loc.SetLocation(local_player->Location());
955  obj_loc.SetVelocity(local_player->Velocity());
956  obj_loc.SetOrientation(Point(r,p,y));
957  obj_loc.SetThrottle(local_player->Throttle() > 10);
958  obj_loc.SetAugmenter(local_player->Augmenter());
959  obj_loc.SetGearDown(local_player->IsGearDown());
960 
961  Shield* shield = local_player->GetShield();
962  if (shield)
963  obj_loc.SetShield((int) shield->GetPowerLevel());
964  else
965  obj_loc.SetShield(0);
966 
967  BYTE* obj_loc_data = obj_loc.Pack();
968 
969  link->SendMessage(server_id, obj_loc_data, NetObjLoc::SIZE);
970  }
971 }
972 
973 // +--------------------------------------------------------------------+
974 
975 void
977 {
978  if (!net_data || !server_id)
979  return;
980 
981  if (local_player || net_data->Type() < 0x20) {
982  BYTE* data = net_data->Pack();
983  BYTE flags = 0;
984 
985  if (net_data->Type() >= 0x10)
986  flags |= NetMsg::RELIABLE;
987 
988  link->SendMessage(server_id, data, net_data->Length(), flags);
989  }
990 }
991 
992 // +--------------------------------------------------------------------+
993 
994 void
996 {
997  if (local_player) {
998  if (local_player->GetObjID() == 0) {
999  SendJoinRequest();
1000  }
1001 
1002  else if (active) {
1003  // check health of server:
1004  NetPeer* server_peer = link->FindPeer(server_id);
1005  if (server_peer && (NetLayer::GetUTC() - server_peer->LastReceiveTime() > 15)) {
1006  NetMsg net_disco(0, NET_DISCONNECT, 0, 0, 0);
1007  DoDisconnect(&net_disco);
1008  }
1009 
1010  // if server is still there,
1011  else if (server_peer) {
1012 
1013  // check if any old join announcements still need to be processed:
1015  while (++iter) {
1016  NetJoinAnnounce* join_ann = iter.value();
1017 
1018  if (DoJoinBacklog(join_ann)) {
1019  iter.removeItem();
1020  delete join_ann;
1021  }
1022  }
1023  }
1024  }
1025  }
1026 
1028 }
1029 
1030 // +--------------------------------------------------------------------+
1031 
1032 bool
1034 {
1035  if (obj->Type() == SimObject::SIM_SHIP) {
1036  Ship* s = (Ship*) obj;
1037  if (local_player == s)
1038  local_player = 0;
1039  }
1040 
1041  return SimObserver::Update(obj);
1042 }
1043 
1044 const char*
1046 {
1047  return "NetGameClient";
1048 }
1049 
1050 // +--------------------------------------------------------------------+
1051 
1052 void
1053 NetGameClient::Respawn(DWORD oid, Ship* spawn)
1054 {
1055  if (!oid || !spawn) return;
1056 
1057  Print("NetGameClient::Respawn(%d, %s)\n", oid, spawn->Name());
1058  spawn->SetObjID(oid);
1059  Observe(spawn);
1060 
1061  NetPlayer* p = FindPlayerByObjID(oid);
1062  if (p)
1063  p->SetShip(spawn);
1064 
1065  if (objid == oid) {
1066  Print(" RESPAWN LOCAL PLAYER\n\n");
1067  local_player = spawn;
1068  }
1069 }