Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Player.cpp
Go to the documentation of this file.
1 /* Project Starshatter 4.5
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: Stars.exe
6  FILE: Player.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Player / Logbook class
13 */
14 
15 
16 #include "MemDebug.h"
17 #include "Player.h"
18 #include "NetLobbyServer.h"
19 #include "NetLayer.h"
20 #include "Ship.h"
21 #include "SimEvent.h"
22 #include "Campaign.h"
23 #include "CampaignSaveGame.h"
24 #include "Random.h"
25 #include "HUDView.h"
26 #include "MFD.h"
27 
28 #include "DataLoader.h"
29 #include "Encrypt.h"
30 #include "ParseUtil.h"
31 #include "FormatUtil.h"
32 #include "Bitmap.h"
33 #include "Game.h"
34 
35 // +-------------------------------------------------------------------+
36 
37 class AwardInfo
38 {
39 public:
40  static const char* TYPENAME() { return "AwardInfo"; }
41 
42  AwardInfo() :
43  type(RANK),
44  id(0),
45  large_insignia(0),
46  small_insignia(0),
48  total_points(0),
49  mission_points(0),
50  total_missions(0),
51  kills(0),
52  lost(0),
53  collision(0),
54  campaign_id(0),
55  campaign_complete(false),
56  dynamic_campaign(false),
57  ceremony(true),
58  required_awards(0),
59  lottery(0),
60  min_rank(0),
61  max_rank((int) 1e9),
62  min_ship_class(0),
63  max_ship_class((int) 1e9)
64  { }
65  ~AwardInfo() { }
66 
67  enum TYPE { RANK, MEDAL };
68 
69  int type;
70  int id;
80 
84  int kills;
85  int lost;
86  int collision;
90  bool ceremony;
91 
93  int lottery;
94  int min_rank;
95  int max_rank;
98 };
99 
100 static List<AwardInfo> rank_table;
101 static List<AwardInfo> medal_table;
102 static bool config_exists = false;
103 
104 // +-------------------------------------------------------------------+
105 
106 Player::Player(const char* n)
107 : uid(0), name(n), create_date(0), points(0), medals(0), flight_time(0),
108 missions(0), kills(0), losses(0), campaigns(0), trained(0),
109 flight_model(0), flying_start(0), landing_model(0),
110 ai_level(1), hud_mode(0), hud_color(1),
111 ff_level(4), grid(1), gunsight(0), award(0)
112 {
113  name.setSensitive(false);
114 
115  mfd[0] = -1;
116  mfd[1] = -1;
117  mfd[2] = -1;
118  mfd[3] = -1;
119 }
120 
122 : uid(0), create_date(0), points(0), medals(0), flight_time(0),
123 missions(0), kills(0), losses(0), campaigns(0), trained(0),
124 flight_model(0), flying_start(0), landing_model(0),
125 ai_level(1), hud_mode(0), hud_color(1),
126 ff_level(4), grid(1), gunsight(0), award(0)
127 {
128  name.setSensitive(false);
129 
130  mfd[0] = -1;
131  mfd[1] = -1;
132  mfd[2] = -1;
133  mfd[3] = -1;
134 }
135 
137 { }
138 
139 // +-------------------------------------------------------------------+
140 
141 void
142 Player::SetName(const char* n)
143 {
144  if (n && *n)
145  name = n;
146 }
147 
148 void
149 Player::SetPassword(const char* p)
150 {
151  if (p && *p) {
152  pass = p;
153 
154  if (pass.length() > 16)
155  pass = pass.substring(0, 16);
156  }
157 }
158 
159 void
160 Player::SetSquadron(const char* s)
161 {
162  if (s && *s)
163  squadron = s;
164 }
165 
166 void
167 Player::SetSignature(const char* s)
168 {
169  if (s && *s)
170  signature = s;
171 }
172 
173 const Text&
174 Player::ChatMacro(int n) const
175 {
176  if (n >= 0 && n < 10)
177  return chat_macros[n];
178 
179  return chat_macros[0];
180 }
181 
182 void
183 Player::SetChatMacro(int n, const char* m)
184 {
185  if (n >= 0 && n < 10 && m && *m)
186  chat_macros[n] = m;
187 }
188 
189 void
191 {
192  if (p >= 0)
193  points = p;
194 }
195 
196 void
198 {
199  medals = m;
200 }
201 
202 void
204 {
205  campaigns = n;
206 }
207 
208 void
210 {
211  if (n == 0)
212  trained = 0;
213 
214  else if (n > 0 && n <= 20)
215  trained = trained | (1 << (n-1));
216 
217  else if (n > 20)
218  trained = n;
219 }
220 
221 bool
222 Player::HasTrained(int n) const
223 {
224  if (n > 0 && n <= 20)
225  return (trained & (1 << (n-1))) ? true : false;
226 
227  return false;
228 }
229 
230 bool
232 {
233  if (id > 0 && id < 30)
234  return (campaigns & (1 << id)) ? true : false;
235 
236  return false;
237 }
238 
239 void
241 {
242  if (id > 0 && id < 30) {
243  campaigns = campaigns | (1 << id);
244  Save();
245  }
246 }
247 
248 void
250 {
251  if (d >= 0)
252  create_date = d;
253 }
254 
255 void
257 {
258  if (t >= 0)
259  flight_time = t;
260 }
261 
262 void
264 {
265  if (m >= 0)
266  missions = m;
267 }
268 
269 void
271 {
272  if (k >= 0)
273  kills = k;
274 }
275 
276 void
278 {
279  if (l >= 0)
280  losses = l;
281 }
282 
283 // +-------------------------------------------------------------------+
284 
285 void
287 {
288  if (t > 0)
289  flight_time += t;
290 }
291 
292 void
294 {
295  if (p > 0)
296  points += p;
297 }
298 
299 void
301 {
302  if (m > 0)
303  missions += m;
304 }
305 
306 void
308 {
309  if (k > 0)
310  kills += k;
311 }
312 
313 void
315 {
316  if (l > 0)
317  losses += l;
318 }
319 
320 // +-------------------------------------------------------------------+
321 
322 void
324 {
325  if (n >= Ship::FM_STANDARD && n <= Ship::FM_ARCADE) {
326  flight_model = n;
328  }
329 }
330 
331 void
333 {
334  flying_start = n;
335 }
336 
337 void
339 {
340  if (n >= Ship::LM_STANDARD && n <= Ship::LM_EASIER) {
341  landing_model = n;
343  }
344 }
345 
346 void
348 {
349  ai_level = n;
350 }
351 
352 void
354 {
355  hud_mode = n;
356  HUDView::SetArcade(n > 0);
357 }
358 
359 void
361 {
362  hud_color = n;
364 }
365 
366 void
368 {
369  if (n >= 0 && n <= 4) {
370  ff_level = n;
372  }
373 }
374 
375 void
377 {
378  if (n >= 0 && n <= 1) {
379  grid = n;
380  }
381 }
382 
383 void
385 {
386  if (n >= 0 && n <= 1) {
387  gunsight = n;
388  }
389 }
390 
391 void
393 {
394  award = 0;
395 }
396 
397 Text
399 {
400  if (award)
401  return award->name;
402 
403  return Text();
404 }
405 
406 Text
408 {
409  if (award)
410  return award->grant;
411 
412  return Text();
413 }
414 
415 Bitmap*
417 {
418  if (award)
419  return award->large_insignia;
420 
421  return 0;
422 }
423 
424 Sound*
426 {
427  if (award && award->grant_sound.length()) {
428  DataLoader* loader = DataLoader::GetLoader();
429  Sound* result = 0;
430 
431  loader->LoadSound(award->grant_sound, result);
432  return result;
433  }
434 
435  return 0;
436 }
437 
438 // +-------------------------------------------------------------------+
439 
440 const char*
442 {
443  ListIter<AwardInfo> iter = rank_table;
444  while (++iter) {
445  AwardInfo* award = iter.value();
446  if (award->id == rank)
447  return award->name;
448  }
449 
450  return "Conscript";
451 }
452 
453 const char*
455 {
456  ListIter<AwardInfo> iter = rank_table;
457  while (++iter) {
458  AwardInfo* award = iter.value();
459  if (award->id == rank)
460  return award->abrv;
461  }
462 
463  return "";
464 }
465 
466 Bitmap*
467 Player::RankInsignia(int rank, int size)
468 {
469  ListIter<AwardInfo> iter = rank_table;
470  while (++iter) {
471  AwardInfo* award = iter.value();
472  if (award->id == rank) {
473  if (size == 0)
474  return award->small_insignia;
475 
476  if (size == 1)
477  return award->large_insignia;
478  }
479  }
480 
481  return 0;
482 }
483 
484 const char*
486 {
487  ListIter<AwardInfo> iter = rank_table;
488  while (++iter) {
489  AwardInfo* award = iter.value();
490  if (award->id == rank)
491  return award->desc;
492  }
493 
494  return "";
495 }
496 
497 int
498 Player::RankFromName(const char* name)
499 {
500  ListIter<AwardInfo> iter = rank_table;
501  while (++iter) {
502  AwardInfo* award = iter.value();
503  if (award->name == name)
504  return award->id;
505  }
506 
507  return 0;
508 }
509 
510 int
512 {
513  for (int i = rank_table.size()-1; i >= 0; i--) {
514  AwardInfo* award = rank_table[i];
515  if (points >= award->total_points)
516  return award->id;
517  }
518 
519  return 0;
520 }
521 
522 void
524 {
525  ListIter<AwardInfo> iter = rank_table;
526  while (++iter) {
527  AwardInfo* award = iter.value();
528  if (r == award->id)
529  points = award->total_points;
530  }
531 }
532 
533 int
534 Player::Medal(int n) const
535 {
536  if (n < 0)
537  return 0;
538 
539  for (int i = 0; i < 16; i++) {
540  int selector = 1 << (15-i);
541 
542  // found a medal:
543  if (medals & selector) {
544 
545  // and it's the nth medal!
546  if (n == 0) {
547  return selector;
548  }
549 
550  n--;
551  }
552  }
553 
554  return 0;
555 }
556 
557 // +-------------------------------------------------------------------+
558 
559 const char*
561 {
562  ListIter<AwardInfo> iter = medal_table;
563  while (++iter) {
564  AwardInfo* award = iter.value();
565  if (award->id == medal)
566  return award->name;
567  }
568 
569  return "";
570 }
571 
572 Bitmap*
573 Player::MedalInsignia(int medal, int size)
574 {
575  ListIter<AwardInfo> iter = medal_table;
576  while (++iter) {
577  AwardInfo* award = iter.value();
578  if (award->id == medal) {
579  if (size == 0)
580  return award->small_insignia;
581 
582  if (size == 1)
583  return award->large_insignia;
584  }
585  }
586 
587  return 0;
588 }
589 
590 const char*
592 {
593  ListIter<AwardInfo> iter = medal_table;
594  while (++iter) {
595  AwardInfo* award = iter.value();
596  if (award->id == medal)
597  return award->desc;
598  }
599 
600  return "";
601 }
602 
603 // +-------------------------------------------------------------------+
604 
605 bool
606 Player::CanCommand(int ship_class)
607 {
608  if (ship_class <= Ship::ATTACK)
609  return true;
610 
611  for (int i = rank_table.size()-1; i >= 0; i--) {
612  AwardInfo* award = rank_table[i];
613  if (points > award->total_points) {
614  return (ship_class & award->granted_ship_classes) != 0;
615  }
616  }
617 
618  return false;
619 }
620 
621 int
623 {
624  for (int i = 0; i < rank_table.size(); i++) {
625  AwardInfo* award = rank_table[i];
626  if ((ship_class & award->granted_ship_classes) != 0) {
627  return i;
628  }
629  }
630 
631  return rank_table.size()-1;
632 }
633 
634 // +-------------------------------------------------------------------+
635 
636 int
637 Player::GetMissionPoints(ShipStats* s, DWORD start_time)
638 {
639  int result = 0;
640 
641  if (s) {
642  result = s->GetPoints();
643 
644  int flight_time = (Game::GameTime() - start_time) / 1000;
645 
646  // if player survived mission, award one experience point
647  // for each minute of action, in ten point blocks:
648  if (!s->GetDeaths() && !s->GetColls()) {
649  int minutes = flight_time / 60;
650  minutes /= 10;
651  minutes *= 10;
652  result += minutes;
653 
654  if (s->HasEvent(SimEvent::DOCK))
655  result += 100;
656  }
657  else {
658  result -= (int) (2.5 * Ship::Value(s->GetShipClass()));
659  }
660 
661  if (result < 0)
662  result = 0;
663  }
664 
665  return result;
666 }
667 
668 // +-------------------------------------------------------------------+
669 
670 void
671 Player::ProcessStats(ShipStats* s, DWORD start_time)
672 {
673  if (!s) return;
674 
675  int old_rank = Rank();
676  int pts = GetMissionPoints(s, start_time);
677 
678  AddPoints(pts);
680  AddKills(s->GetGunKills());
682  AddLosses(s->GetDeaths());
683  AddLosses(s->GetColls());
684  AddMissions(1);
685  AddFlightTime((Game::GameTime() - start_time) / 1000);
686 
687  int rank = Rank();
688 
689  // did the player earn a promotion?
690  if (old_rank != rank) {
691  ListIter<AwardInfo> iter = rank_table;
692  while (++iter) {
693  AwardInfo* a = iter.value();
694  if (rank == a->id) {
695  award = a;
696  }
697  }
698  }
699 
700  // if not, did the player earn a medal?
701  else {
702  ListIter<AwardInfo> iter = medal_table;
703  while (++iter) {
704  AwardInfo* a = iter.value();
705 
706  if (EarnedAward(a, s) && a->ceremony) {
707  award = a;
708  break;
709  }
710  }
711  }
712 
713  // persist all stats, promotions, and medals:
714  Save();
715 }
716 
717 bool
719 {
720  if (!a || !s)
721  return false;
722 
723  // already earned this medal?
724  if (a->id & medals)
725  return false;
726 
727  // eligible for this medal?
728  int rank = Rank();
729  if (a->min_rank > rank || a->max_rank < rank)
730  return false;
731 
732  if ((a->required_awards & medals) < a->required_awards)
733  return false;
734 
735  if (a->min_ship_class > s->GetShipClass() || a->max_ship_class < s->GetShipClass())
736  return false;
737 
738  if (a->total_points > points)
739  return false;
740 
741  if (a->total_missions > missions)
742  return false;
743 
744  if (a->campaign_id && a->campaign_complete) {
746  return false;
747  }
748 
749  else {
750  // campaign related requirements
752 
753  if (c) {
754  if (a->dynamic_campaign && !c->IsDynamic())
755  return false;
756  }
757  }
758 
759  // sufficient merit for this medal?
760  if (a->mission_points > s->GetPoints())
761  return false;
762 
763  if (a->kills > s->GetGunKills() + s->GetMissileKills())
764  return false;
765 
766  if (a->mission_points > s->GetPoints())
767  return false;
768 
769  // player must survive mission if lost = -1
770  if (a->lost < 0 && (s->GetDeaths() || s->GetColls()))
771  return false;
772 
773  // do we need to be wounded in battle?
774  if (a->lost > s->GetDeaths() || a->collision > s->GetColls())
775  return false;
776 
777  // final lottery check:
778  if (a->lottery < 2 || RandomChance(1, a->lottery)) {
779  medals |= a->id;
780  return true;
781  }
782 
783  // what do we have for the losers, judge?
784  return false;
785 }
786 
787 // +-------------------------------------------------------------------+
788 
789 static List<Player> player_roster;
790 static Player* current_player = 0;
791 
794 {
795  return player_roster;
796 }
797 
798 Player*
800 {
801  return current_player;
802 }
803 
804 void
806 {
807  HUDView* hud = HUDView::GetInstance();
808 
809  if (current_player && current_player != p) {
810  if (hud) {
811  for (int i = 0; i < 3; i++) {
812  MFD* mfd = hud->GetMFD(i);
813 
814  if (mfd)
815  current_player->mfd[i] = mfd->GetMode();
816  }
817  }
818  }
819 
820  if (player_roster.contains(p)) {
821  current_player = p;
822 
827 
828  if (hud) {
829  for (int i = 0; i < 3; i++) {
830  if (p->mfd[i] >= 0) {
831  MFD* mfd = hud->GetMFD(i);
832 
833  if (mfd)
834  mfd->SetMode(p->mfd[i]);
835  }
836  }
837  }
838  }
839 }
840 
841 Player*
842 Player::Find(const char* name)
843 {
844  for (int i = 0; i < player_roster.size(); i++) {
845  Player* p = player_roster.at(i);
846  if (p->Name() == name)
847  return p;
848  }
849 
850  return 0;
851 }
852 
853 Player*
854 Player::Create(const char* name)
855 {
856  if (name && *name) {
857  // check for existence:
858  if (Find(name))
859  return 0;
860 
861  Player* newbie = new(__FILE__,__LINE__) Player(name);
862  newbie->SetCreateDate(NetLayer::GetUTC());
863 
864  player_roster.append(newbie);
865  newbie->CreateUniqueID();
866  return newbie;
867  }
868 
869  return 0;
870 }
871 
872 void
874 {
875  if (p) {
876  player_roster.remove(p);
877 
878  if (p == current_player) {
879  current_player = 0;
880 
881  if (player_roster.size())
882  current_player = player_roster.at(0);
883  }
884 
886  delete p;
887  }
888 }
889 
890 // +-------------------------------------------------------------------+
891 
892 void
894 {
895  LoadAwardTables();
896  Load();
897 
898  if (!current_player) {
899  if (!player_roster.size()) {
900  Create("Pilot");
901  }
902 
903  SelectPlayer(player_roster.at(0));
904  }
905 }
906 
907 void
909 {
910  if (current_player && !player_roster.contains(current_player))
911  delete current_player;
912 
913  player_roster.destroy();
914  current_player = 0;
915 
916  rank_table.destroy();
917  medal_table.destroy();
918 }
919 
920 // +-------------------------------------------------------------------+
921 
922 bool
924 {
925  return config_exists;
926 }
927 
928 // +-------------------------------------------------------------------+
929 
930 #define GET_DEF_BOOL(x) if(pdef->name()->value()==(#x))GetDefBool(player->x,pdef,filename)
931 #define GET_DEF_TEXT(x) if(pdef->name()->value()==(#x))GetDefText(player->x,pdef,filename)
932 #define GET_DEF_NUM(x) if(pdef->name()->value()==(#x))GetDefNumber(player->x,pdef,filename)
933 
934 void
936 {
937  config_exists = false;
938 
939  // read the config file:
940  BYTE* block = 0;
941  int blocklen = 0;
942 
943  char filename[64];
944  strcpy_s(filename, "player.cfg");
945 
946  FILE* f;
947  ::fopen_s(&f, filename, "rb");
948 
949  if (f) {
950  config_exists = true;
951 
952  ::fseek(f, 0, SEEK_END);
953  blocklen = ftell(f);
954  ::fseek(f, 0, SEEK_SET);
955 
956  block = new(__FILE__,__LINE__) BYTE[blocklen+1];
957  block[blocklen] = 0;
958 
959  ::fread(block, blocklen, 1, f);
960  ::fclose(f);
961  }
962 
963  if (blocklen == 0)
964  return;
965 
966  Parser parser(new(__FILE__,__LINE__) BlockReader((const char*) block, blocklen));
967  Term* term = parser.ParseTerm();
968 
969  if (!term) {
970  Print("ERROR: could not parse '%s'.\n", filename);
971  return;
972  }
973  else {
974  TermText* file_type = term->isText();
975  if (!file_type || file_type->value() != "PLAYER_CONFIG") {
976  Print("WARNING: invalid '%s' file. Using defaults\n", filename);
977  return;
978  }
979  }
980 
981  if (current_player && !player_roster.contains(current_player))
982  delete current_player;
983  player_roster.destroy();
984  current_player = 0;
985 
986  do {
987  delete term;
988 
989  term = parser.ParseTerm();
990 
991  if (term) {
992  TermDef* def = term->isDef();
993  if (def) {
994  if (def->name()->value() == "player") {
995 
996  if (!def->term() || !def->term()->isStruct()) {
997  Print("WARNING: player structure missing in '%s'\n", filename);
998  }
999  else {
1000  Player* player = new(__FILE__,__LINE__) Player;
1001  bool current = false;
1002  TermStruct* val = def->term()->isStruct();
1003 
1004  for (int i = 0; i < val->elements()->size(); i++) {
1005  TermDef* pdef = val->elements()->at(i)->isDef();
1006  if (pdef) {
1007  GET_DEF_TEXT(name);
1008  else GET_DEF_TEXT(squadron);
1009  else GET_DEF_TEXT(signature);
1010 
1011  else GET_DEF_NUM(uid);
1012  else GET_DEF_NUM(flight_model);
1013  else GET_DEF_NUM(flying_start);
1014  else GET_DEF_NUM(landing_model);
1015  else GET_DEF_NUM(ai_level);
1016  else GET_DEF_NUM(hud_mode);
1017  else GET_DEF_NUM(hud_color);
1018  else GET_DEF_NUM(ff_level);
1019  else GET_DEF_NUM(grid);
1020  else GET_DEF_NUM(gunsight);
1021 
1022  else if (pdef->name()->value() == ("chat_0"))
1023  GetDefText(player->chat_macros[0], pdef, filename);
1024 
1025  else if (pdef->name()->value() == ("chat_1"))
1026  GetDefText(player->chat_macros[1], pdef, filename);
1027 
1028  else if (pdef->name()->value() == ("chat_2"))
1029  GetDefText(player->chat_macros[2], pdef, filename);
1030 
1031  else if (pdef->name()->value() == ("chat_3"))
1032  GetDefText(player->chat_macros[3], pdef, filename);
1033 
1034  else if (pdef->name()->value() == ("chat_4"))
1035  GetDefText(player->chat_macros[4], pdef, filename);
1036 
1037  else if (pdef->name()->value() == ("chat_5"))
1038  GetDefText(player->chat_macros[5], pdef, filename);
1039 
1040  else if (pdef->name()->value() == ("chat_6"))
1041  GetDefText(player->chat_macros[6], pdef, filename);
1042 
1043  else if (pdef->name()->value() == ("chat_7"))
1044  GetDefText(player->chat_macros[7], pdef, filename);
1045 
1046  else if (pdef->name()->value() == ("chat_8"))
1047  GetDefText(player->chat_macros[8], pdef, filename);
1048 
1049  else if (pdef->name()->value() == ("chat_9"))
1050  GetDefText(player->chat_macros[9], pdef, filename);
1051 
1052  else if (pdef->name()->value() == ("mfd0"))
1053  GetDefNumber(player->mfd[0], pdef, filename);
1054 
1055  else if (pdef->name()->value() == ("mfd1"))
1056  GetDefNumber(player->mfd[1], pdef, filename);
1057 
1058  else if (pdef->name()->value() == ("mfd2"))
1059  GetDefNumber(player->mfd[2], pdef, filename);
1060 
1061  else if (pdef->name()->value() == ("current"))
1062  GetDefBool(current, pdef, filename);
1063 
1064  else if (pdef->name()->value() == ("trained"))
1065  GetDefNumber(player->trained, pdef, filename);
1066 
1067  else if (pdef->name()->value() == ("stats")) {
1068  Text stats;
1069  GetDefText(stats, pdef, filename);
1070  player->DecodeStats(stats);
1071  }
1072 
1073  else if (pdef->name()->value().indexOf("XXX_CHEAT_A1B2C3_") == 0) {
1074  if (pdef->name()->value().contains("points"))
1075  GetDefNumber(player->points, pdef, filename);
1076 
1077  else if (pdef->name()->value().contains("rank")) {
1078  int rank=0;
1079  GetDefNumber(rank, pdef, filename);
1080  player->SetRank(rank);
1081  }
1082 
1083  else if (pdef->name()->value().contains("medals"))
1084  GetDefNumber(player->medals, pdef, filename);
1085 
1086  else if (pdef->name()->value().contains("campaigns"))
1087  GetDefNumber(player->campaigns, pdef, filename);
1088 
1089  else if (pdef->name()->value().contains("missions"))
1090  GetDefNumber(player->missions, pdef, filename);
1091 
1092  else if (pdef->name()->value().contains("kills"))
1093  GetDefNumber(player->kills, pdef, filename);
1094 
1095  else if (pdef->name()->value().contains("losses"))
1096  GetDefNumber(player->losses, pdef, filename);
1097 
1098  else if (pdef->name()->value().contains("flight_time"))
1099  GetDefNumber(player->flight_time, pdef, filename);
1100  }
1101  }
1102  }
1103 
1104  player_roster.append(player);
1105  player->CreateUniqueID();
1106 
1107  if (current)
1108  SelectPlayer(player);
1109  }
1110 
1111  }
1112  else {
1113  Print("WARNING: unknown label '%s' in '%s'\n",
1114  def->name()->value().data(), filename);
1115  }
1116  }
1117  else {
1118  Print("WARNING: term ignored in '%s'\n", filename);
1119  term->print();
1120  }
1121  }
1122  }
1123  while (term);
1124 
1125  delete [] block;
1126 }
1127 
1128 // +-------------------------------------------------------------------+
1129 
1130 void
1132 {
1133  HUDView* hud = HUDView::GetInstance();
1134  if (hud && current_player) {
1135  for (int i = 0; i < 3; i++) {
1136  MFD* mfd = hud->GetMFD(i);
1137 
1138  if (mfd)
1139  current_player->mfd[i] = mfd->GetMode();
1140  }
1141  }
1142 
1143  FILE* f;
1144  fopen_s(&f, "player.cfg", "w");
1145  if (f) {
1146  fprintf(f, "PLAYER_CONFIG\n\n");
1147 
1148  ListIter<Player> iter = player_roster;
1149  while (++iter) {
1150  Player* p = iter.value();
1151 
1152  fprintf(f, "player: {\n");
1153  fprintf(f, " uid: %d,\n", p->uid);
1154  fprintf(f, " name: \"%s\",\n", SafeQuotes(p->name.data()));
1155  fprintf(f, " squadron: \"%s\",\n", SafeQuotes(p->squadron.data()));
1156  fprintf(f, " signature: \"%s\",\n", SafeQuotes(p->signature.data()));
1157 
1158  Text stat_data = p->EncodeStats();
1159 
1160  if (stat_data.length() > 32) {
1161  char tmp[64];
1162  int len = stat_data.length();
1163 
1164  for (int n = 0; n < len; n += 32) {
1165  ZeroMemory(tmp, sizeof(tmp));
1166  const char* p = stat_data.data() + n;
1167  strncpy(tmp, p, 32);
1168 
1169  if (n == 0)
1170  fprintf(f, " stats: \"%s\"\n", tmp);
1171  else if (n < len-32)
1172  fprintf(f, " \"%s\"\n", tmp);
1173  else
1174  fprintf(f, " \"%s\",\n", tmp);
1175  }
1176  }
1177 
1178  if (p == current_player)
1179  fprintf(f, " current: true,\n");
1180  else
1181  fprintf(f, " current: false,\n");
1182 
1183  fprintf(f, " trained: %d,\n", p->trained);
1184  fprintf(f, " flight_model: %d,\n", p->flight_model);
1185  fprintf(f, " flying_start: %d,\n", p->flying_start);
1186  fprintf(f, " landing_model: %d,\n", p->landing_model);
1187  fprintf(f, " ai_level: %d,\n", p->ai_level);
1188  fprintf(f, " hud_mode: %d,\n", p->hud_mode);
1189  fprintf(f, " hud_color: %d,\n", p->hud_color);
1190  fprintf(f, " ff_level: %d,\n", p->ff_level);
1191  fprintf(f, " grid: %d,\n", p->grid);
1192  fprintf(f, " gunsight: %d,\n", p->gunsight);
1193 
1194  for (int i = 0; i < 10; i++) {
1195  fprintf(f, " chat_%d: \"%s\",\n", i, SafeQuotes(p->chat_macros[i].data()));
1196  }
1197 
1198  for (int i = 0; i < 3; i++) {
1199  if (p->mfd[i] >= 0) {
1200  fprintf(f, " mfd%d: %d,\n", i, p->mfd[i]);
1201  }
1202  }
1203 
1204  fprintf(f, "}\n\n");
1205  }
1206 
1207  fclose(f);
1208 
1209  config_exists = true;
1210  }
1211 }
1212 
1213 // +-------------------------------------------------------------------+
1214 
1215 static char stat_buf[280];
1216 static char code_buf[280];
1217 
1218 Text
1220 {
1221  ZeroMemory(stat_buf, 280);
1222  ZeroMemory(code_buf, 280);
1223 
1224  sprintf_s(stat_buf, "%-16s%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
1225  pass.data(),
1226  create_date,
1227  points,
1228  flight_time,
1229  missions,
1230  kills,
1231  losses,
1232  medals,
1233  campaigns,
1234  11, 12, 13, 14, 15, 16,
1235  17, 18, 19, 20, 21, 22, 23, 24,
1236  25, 26, 27, 28, 29, 30, 31, 32);
1237 
1238  for (int i = 0; i < 16; i++)
1239  for (int j = 0; j < 16; j++)
1240  code_buf[i*16 + j] = stat_buf[j*16 + i];
1241 
1242  return Encryption::Encode(Encryption::Encrypt(code_buf));
1243 }
1244 
1245 void
1246 Player::DecodeStats(const char* stats)
1247 {
1248  ZeroMemory(stat_buf, 280);
1249  ZeroMemory(code_buf, 280);
1250 
1251  if (!stats || !*stats) {
1252  Print("Player::DecodeStats() invalid or missing stats\n");
1254  return;
1255  }
1256 
1258 
1259  if (plain.length() == 64) {
1260  for (int i = 0; i < 8; i++)
1261  for (int j = 0; j < 8; j++)
1262  stat_buf[j*8 + i] = plain[i*8 +j];
1263  }
1264 
1265  else if (plain.length() == 256) {
1266  for (int i = 0; i < 16; i++)
1267  for (int j = 0; j < 16; j++)
1268  stat_buf[j*16 + i] = plain[i*16 +j];
1269  }
1270 
1271  else {
1272  Print("Player::DecodeStats() invalid plain text length %d\n", plain.length());
1274  return;
1275  }
1276 
1277  char work[32];
1278  ZeroMemory(work, 32);
1279  CopyMemory(work, stat_buf, 16);
1280  for (int i = 15; i > 0; i--)
1281  if (work[i] == ' ') work[i] = 0;
1282  else break;
1283  pass = work;
1284 
1285  ZeroMemory(work, 16);
1286  CopyMemory(work, stat_buf+16, 8);
1287  sscanf_s(work, "%x", &create_date);
1288 
1289  ZeroMemory(work, 16);
1290  CopyMemory(work, stat_buf+24, 8);
1291  sscanf_s(work, "%x", &points);
1292  if (points < 0) points = 0;
1293 
1294  ZeroMemory(work, 16);
1295  CopyMemory(work, stat_buf+32, 8);
1296  sscanf_s(work, "%x", &flight_time);
1297  if (flight_time < 0) flight_time = 0;
1298 
1299  ZeroMemory(work, 16);
1300  CopyMemory(work, stat_buf+40, 8);
1301  sscanf_s(work, "%x", &missions);
1302  if (missions < 0) missions = 0;
1303 
1304  ZeroMemory(work, 16);
1305  CopyMemory(work, stat_buf+48, 8);
1306  sscanf_s(work, "%x", &kills);
1307  if (kills < 0) kills = 0;
1308 
1309  ZeroMemory(work, 16);
1310  CopyMemory(work, stat_buf+56, 8);
1311  sscanf_s(work, "%x", &losses);
1312  if (losses < 0) losses = 0;
1313 
1314  if (plain.length() > 64) {
1315  ZeroMemory(work, 16);
1316  CopyMemory(work, stat_buf+64, 8);
1317  sscanf_s(work, "%x", &medals);
1318 
1319  ZeroMemory(work, 16);
1320  CopyMemory(work, stat_buf+72, 8);
1321  sscanf_s(work, "%x", &campaigns);
1322  }
1323 
1324  if (create_date == 0) {
1325  ::Print("WARNING - loaded player with zero stats '%s'\n", name.data());
1327  }
1328 }
1329 
1330 // +-------------------------------------------------------------------+
1331 
1332 void
1334 {
1335  DataLoader* loader = DataLoader::GetLoader();
1336 
1337  if (!loader) return;
1338 
1339  BYTE* block = 0;
1340  const char* filename = "awards.def";
1341 
1342  loader->SetDataPath("Awards/");
1343  loader->LoadBuffer(filename, block, true);
1344  Parser parser(new(__FILE__,__LINE__) BlockReader((const char*) block));
1345 
1346  Term* term = parser.ParseTerm();
1347 
1348  if (!term) {
1349  return;
1350  }
1351  else {
1352  TermText* file_type = term->isText();
1353  if (!file_type || file_type->value() != "AWARDS") {
1354  return;
1355  }
1356  }
1357 
1358  rank_table.destroy();
1359  medal_table.destroy();
1360 
1361  ::Print("Loading Ranks and Medals\n");
1362 
1363  do {
1364  delete term; term = 0;
1365  term = parser.ParseTerm();
1366 
1367  if (term) {
1368  TermDef* def = term->isDef();
1369  if (def) {
1370  if (def->name()->value() == "award") {
1371 
1372  if (!def->term() || !def->term()->isStruct()) {
1373  Print("WARNING: award structure missing in '%s'\n", filename);
1374  }
1375  else {
1376  AwardInfo* award = new(__FILE__,__LINE__) AwardInfo;
1377  TermStruct* val = def->term()->isStruct();
1378 
1379  for (int i = 0; i < val->elements()->size(); i++) {
1380  TermDef* pdef = val->elements()->at(i)->isDef();
1381  if (pdef) {
1382  if (pdef->name()->value() == ("name")) {
1383  GetDefText(award->name, pdef, filename);
1384  award->name = Game::GetText(award->name);
1385  }
1386 
1387  else if (pdef->name()->value() == ("abrv")) {
1388  GetDefText(award->abrv, pdef, filename);
1389  award->abrv = Game::GetText(award->abrv);
1390  }
1391 
1392  else if (pdef->name()->value() == ("desc")) {
1393  GetDefText(award->desc, pdef, filename);
1394  if (award->desc.length() <= 40)
1395  award->desc = Game::GetText(award->desc);
1396  }
1397 
1398  else if (pdef->name()->value() == ("award")) {
1399  GetDefText(award->grant, pdef, filename);
1400  if (award->grant.length() <= 40)
1401  award->grant = Game::GetText(award->grant);
1402  }
1403 
1404  else if (pdef->name()->value() == ("desc_sound"))
1405  GetDefText(award->desc_sound, pdef, filename);
1406 
1407  else if (pdef->name()->value() == ("award_sound"))
1408  GetDefText(award->grant_sound, pdef, filename);
1409 
1410  else if (pdef->name()->value().indexOf("large") == 0) {
1411  Text txt;
1412  GetDefText(txt, pdef, filename);
1413  txt.setSensitive(false);
1414 
1415  if (!txt.contains(".pcx"))
1416  txt.append(".pcx");
1417 
1418  loader->CacheBitmap(txt, award->large_insignia);
1419  }
1420 
1421  else if (pdef->name()->value().indexOf("small") == 0) {
1422  Text txt;
1423  GetDefText(txt, pdef, filename);
1424  txt.setSensitive(false);
1425 
1426  if (!txt.contains(".pcx"))
1427  txt.append(".pcx");
1428 
1429  loader->CacheBitmap(txt, award->small_insignia);
1430 
1431  if (award->small_insignia)
1432  award->small_insignia->AutoMask();
1433  }
1434 
1435  else if (pdef->name()->value() == ("type")) {
1436  Text txt;
1437  GetDefText(txt, pdef, filename);
1438  txt.setSensitive(false);
1439 
1440  if (txt == "rank")
1441  award->type = AwardInfo::RANK;
1442 
1443  else if (txt == "medal")
1444  award->type = AwardInfo::MEDAL;
1445  }
1446 
1447  else if (pdef->name()->value() == ("id"))
1448  GetDefNumber(award->id, pdef, filename);
1449 
1450  else if (pdef->name()->value() == ("total_points"))
1451  GetDefNumber(award->total_points, pdef, filename);
1452 
1453  else if (pdef->name()->value() == ("mission_points"))
1454  GetDefNumber(award->mission_points, pdef, filename);
1455 
1456  else if (pdef->name()->value() == ("total_missions"))
1457  GetDefNumber(award->total_missions, pdef, filename);
1458 
1459  else if (pdef->name()->value() == ("kills"))
1460  GetDefNumber(award->kills, pdef, filename);
1461 
1462  else if (pdef->name()->value() == ("lost"))
1463  GetDefNumber(award->lost, pdef, filename);
1464 
1465  else if (pdef->name()->value() == ("collision"))
1466  GetDefNumber(award->collision, pdef, filename);
1467 
1468  else if (pdef->name()->value() == ("campaign_id"))
1469  GetDefNumber(award->campaign_id, pdef, filename);
1470 
1471  else if (pdef->name()->value() == ("campaign_complete"))
1472  GetDefBool(award->campaign_complete, pdef, filename);
1473 
1474  else if (pdef->name()->value() == ("dynamic_campaign"))
1475  GetDefBool(award->dynamic_campaign, pdef, filename);
1476 
1477  else if (pdef->name()->value() == ("ceremony"))
1478  GetDefBool(award->ceremony, pdef, filename);
1479 
1480  else if (pdef->name()->value() == ("required_awards"))
1481  GetDefNumber(award->required_awards, pdef, filename);
1482 
1483  else if (pdef->name()->value() == ("lottery"))
1484  GetDefNumber(award->lottery, pdef, filename);
1485 
1486  else if (pdef->name()->value() == ("min_rank"))
1487  GetDefNumber(award->min_rank, pdef, filename);
1488 
1489  else if (pdef->name()->value() == ("max_rank"))
1490  GetDefNumber(award->max_rank, pdef, filename);
1491 
1492  else if (pdef->name()->value() == ("min_ship_class")) {
1493  Text classname;
1494  GetDefText(classname, pdef, filename);
1495  award->min_ship_class = Ship::ClassForName(classname);
1496  }
1497 
1498  else if (pdef->name()->value() == ("max_ship_class")) {
1499  Text classname;
1500  GetDefText(classname, pdef, filename);
1501  award->max_ship_class = Ship::ClassForName(classname);
1502  }
1503 
1504  else if (pdef->name()->value().indexOf("grant") == 0)
1505  GetDefNumber(award->granted_ship_classes, pdef, filename);
1506  }
1507  }
1508 
1509  if (award->type == AwardInfo::RANK) {
1510  rank_table.append(award);
1511  }
1512 
1513  else if (award->type == AwardInfo::MEDAL) {
1514  medal_table.append(award);
1515  }
1516 
1517  else {
1518  delete award;
1519  }
1520  }
1521  }
1522  else {
1523  Print("WARNING: unknown label '%s' in '%s'\n",
1524  def->name()->value().data(), filename);
1525  }
1526  }
1527  else {
1528  Print("WARNING: term ignored in '%s'\n", filename);
1529  term->print();
1530  }
1531  }
1532  }
1533  while (term);
1534 
1535  loader->ReleaseBuffer(block);
1536  loader->SetDataPath(0);
1537 }
1538 
1539 // +-------------------------------------------------------------------+
1540 
1541 void
1543 {
1544  ListIter<Player> iter = player_roster;
1545  while (++iter) {
1546  Player* p = iter.value();
1547 
1548  if (p != this && p->uid >= uid)
1549  uid = p->uid + 1;
1550  }
1551 
1552  if (uid < 1)
1553  uid = 1;
1554 }