FS2_Open
Open source remastering of the Freespace 2 engine
missionlog.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 
13 #include "globalincs/alphacolors.h"
14 #include "graphics/font.h"
15 #include "iff_defs/iff_defs.h"
16 #include "localization/localize.h"
17 #include "mission/missiongoals.h"
18 #include "mission/missionlog.h"
19 #include "mission/missionparse.h"
20 #include "network/multi.h"
21 #include "network/multimsgs.h"
22 #include "network/multiutil.h"
23 #include "parse/parselo.h"
24 #include "playerman/player.h"
25 #include "ship/ship.h"
26 
27 
28 
29 #define MAX_LOG_ENTRIES 700
30 #define MAX_LOG_LINES 1000
31 
32 // used for high water mark for culling out log entries
33 #define LOG_CULL_MARK ((int)(MAX_LOG_ENTRIES * 0.95f))
34 #define LOG_CULL_DOORDIE_MARK ((int)(MAX_LOG_ENTRIES * 0.99f))
35 #define LOG_LAST_DITCH_CULL_NUM ((int)(MAX_LOG_ENTRIES * 0.20f))
36 #define LOG_HALFWAY_REPORT_NUM ((int)(MAX_LOG_ENTRIES * 0.50f))
37 
38 #define EMPTY_LOG_NAME ""
39 
40 // defines for X position offsets of different items for mission log
41 #define TIME_X 10
42 #define OBJECT_X 75
43 #define ACTION_X 250
44 
45 #define LOG_COLOR_NORMAL 0
46 #define LOG_COLOR_BRIGHT 1
47 #define LOG_COLOR_OTHER 2
48 #define NUM_LOG_COLORS 3
49 
50 // defines for log flags
51 #define LOG_FLAG_GOAL_FAILED (1<<0)
52 #define LOG_FLAG_GOAL_TRUE (1<<1)
53 
54 typedef struct log_text_seg {
55  log_text_seg *next; // linked list
56  char *text; // the text
57  int color; // color text should be displayed in
58  int x; // x offset to display text at
59  int flags; // used to possibly print special characters when displaying the log
60 } log_text_seg;
61 
63 static int X, P_width;
64 
65 // Log_lines is used for scrollback display purposes.
66 static log_text_seg *Log_lines[MAX_LOG_LINES];
67 static fix Log_line_timestamps[MAX_LOG_LINES];
68 
69 log_entry log_entries[MAX_LOG_ENTRIES]; // static array because John says....
71 
73 {
74  last_entry = 0;
75 
76  // zero out all the memory so we don't get bogus information when playing across missions!
77  memset( log_entries, 0, sizeof(log_entries) );
78 }
79 
80 // returns the number of entries in the mission log
82 {
83  return last_entry;
84 }
85 
86 // function to clean up the mission log removing obsolete entries. Entries might get marked obsolete
87 // in several ways -- having to recycle entries, a ship's subsystem destroyed entries when a ship is
88 // fully destroyed, etc.
90 {
91  int i, index;
92 
93  nprintf(("missionlog", "culling obsolete entries. starting last entry %d.\n", last_entry));
94  // find the first obsolete entry
95  for (i = 0; i < last_entry; i++ )
96  if ( log_entries[i].flags & MLF_OBSOLETE )
97  break;
98 
99  // nothing to do if next if statement is true
100  if ( i == last_entry )
101  return;
102 
103  // compact the log array, removing the obsolete entries.
104  index = i; // index is the first obsolete entry
105 
106  // 'index' should always point to the next element in the list
107  // which is getting compacted. 'i' points to the next array
108  // element to be replaced.
109  do {
110  // get to the next non-obsolete entry. The obsolete entry must not be essential either!
111  while ( (log_entries[index].flags & MLF_OBSOLETE) && !(log_entries[index].flags & MLF_ESSENTIAL) ) {
112  index++;
113  last_entry--;
114  }
115 
116  log_entries[i++] = log_entries[index++];
117  } while ( i < last_entry );
118 
119 #ifndef NDEBUG
120  nprintf(("missionlog", "Ending entry: %d.\n", last_entry));
121 #endif
122 }
123 
124 // function to mark entries as obsolete. Passed is the type of entry that is getting added
125 // to the log. Some entries might get marked obsolete as a result of this type
127 {
128  int i;
129  log_entry *entry = NULL;
130 
131  // before adding this entry, check to see if the entry type is a ship destroyed or destructed entry.
132  // If so, we can remove any subsystem destroyed entries from the log for this ship.
133  if ( type == LOG_SHIP_DESTROYED || type == LOG_SELF_DESTRUCTED ) {
134  for (i = 0; i < last_entry; i++) {
135  entry = &log_entries[i];
136 
137  // check to see if the type is a subsystem destroyed entry, and that it belongs to the
138  // ship passed into this routine. If it matches, mark as obsolete. We'll clean up
139  // the log when it starts to get full
140  if ( !stricmp( pname, entry->pname ) ) {
141  if ( (entry->type == LOG_SHIP_SUBSYS_DESTROYED) || (entry->type == LOG_SHIP_DISARMED) || (entry->type == LOG_SHIP_DISABLED) )
142  entry->flags |= MLF_OBSOLETE;
143  }
144  }
145  }
146 
147  // check to see if we are getting to about 80% of our log capacity. If so, cull the log.
148  if ( last_entry > LOG_CULL_MARK ) {
150 
151  // if we culled the entries, and we are still low on space, we need to take more drastic measures.
152  // these include removing all non-essential entries from the log. These entries are entries
153  // which has not been asked for by mission_log_get_time
154  if ( last_entry > LOG_CULL_MARK ) {
155  nprintf(("missionlog", "marking the first %d non-essential log entries as obsolete\n", LOG_LAST_DITCH_CULL_NUM));
156  for (i = 0; i < LOG_LAST_DITCH_CULL_NUM; i++ ) {
157  entry = &log_entries[i];
158  if ( !(entry->flags & MLF_ESSENTIAL) ){
159  entry->flags |= MLF_OBSOLETE;
160  }
161  }
162 
163  // cull the obsolete entries again
165 
166  // if we get to this point, and there are no entries left -- we are in big trouble. We will simply
167  // mark the first 20% of the log as obsolete and compress. Don't do this unless we are *really*
168  // in trouble
170  nprintf(("missionlog", "removing the first %d entries in the mission log!!!!\n", LOG_LAST_DITCH_CULL_NUM));
171  for (i = 0; i < LOG_LAST_DITCH_CULL_NUM; i++ ){
172  entry->flags |= MLF_OBSOLETE;
173  }
174 
176  }
177  }
178  }
179 }
180 
181 // following function adds an entry into the mission log.
182 // pass a type and a string which indicates the object
183 // that this event is for. Don't add entries with this function for multiplayer
184 void mission_log_add_entry(int type, char *pname, char *sname, int info_index)
185 {
186  int last_entry_save;
187  log_entry *entry;
188 
189  // multiplayer clients don't use this function to add log entries -- they will get
190  // all their info from the host
191  if ( MULTIPLAYER_CLIENT ){
192  return;
193  }
194 
195  last_entry_save = last_entry;
196 
197  // mark any entries as obsolete. Part of the pruning is done based on the type (and name) passed
198  // for a new entry
199  mission_log_obsolete_entries(type, pname);
200 
201  entry = &log_entries[last_entry];
202 
203  if ( last_entry == MAX_LOG_ENTRIES ){
204  return;
205  }
206 
207  entry->type = type;
208  if ( pname ) {
209  Assert (strlen(pname) < NAME_LENGTH);
210  strcpy_s(entry->pname, pname);
211  } else
212  strcpy_s( entry->pname, EMPTY_LOG_NAME );
213 
214  if ( sname ) {
215  Assert (strlen(sname) < NAME_LENGTH);
216  strcpy_s(entry->sname, sname);
217  } else
218  strcpy_s( entry->sname, EMPTY_LOG_NAME );
219 
220  entry->index = info_index;
221  entry->flags = 0;
222  entry->primary_team = -1;
223  entry->secondary_team = -1;
224 
225  // determine the contents of the flags member based on the type of entry we added. We need to store things
226  // like team for the primary and (possibly) secondary object for this entry.
227  switch ( type ) {
228  int index;
229 
230  case LOG_SHIP_DESTROYED:
231  case LOG_SHIP_ARRIVED:
232  case LOG_SHIP_DEPARTED:
233  case LOG_SHIP_DOCKED:
235  case LOG_SHIP_UNDOCKED:
236  case LOG_SHIP_DISABLED:
237  case LOG_SHIP_DISARMED:
238  case LOG_SELF_DESTRUCTED:
239  // multiplayer. callsign is passed in for ship destroyed and self destruct
240  if((Game_mode & GM_MULTIPLAYER) && (multi_find_player_by_callsign(pname) >= 0)){
241  int np_index = multi_find_player_by_callsign(pname);
242  index = multi_get_player_ship( np_index );
243  } else {
244  index = ship_name_lookup( pname );
245  }
246 
247  Assert (index >= 0);
248  entry->primary_team = Ships[index].team;
249 
250  // some of the entries have a secondary component. Figure out what is up with them.
251  if ( (type == LOG_SHIP_DOCKED) || (type == LOG_SHIP_UNDOCKED)) {
252  if ( sname ) {
253  index = ship_name_lookup( sname );
254  Assert (index >= 0);
255  entry->secondary_team = Ships[index].team;
256  }
257  } else if ( type == LOG_SHIP_DESTROYED ) {
258  if ( sname ) {
259  int team;
260 
261  // multiplayer, player name will possibly be sent in
262  if((Game_mode & GM_MULTIPLAYER) && (multi_find_player_by_callsign(sname) >= 0)) {
263  // get the player's ship
264  int np_index = multi_find_player_by_callsign(sname);
265  int np_ship = multi_get_player_ship(np_index);
266 
267  if(np_ship < 0)
268  {
269  // argh. badness
270  Int3();
271  team = Player_ship->team;
272  }
273  else
274  {
275  team = Ships[Objects[Net_players[np_index].m_player->objnum].instance].team;
276  }
277  }
278  else
279  {
280  index = ship_name_lookup( sname );
281  // no ship, then it probably exited -- check the exited
282  if ( index == -1 ) {
283  index = ship_find_exited_ship_by_name( sname );
284  if ( index == -1 ) {
285  break;
286  }
287  team = Ships_exited[index].team;
288  } else {
289  team = Ships[index].team;
290  }
291  }
292 
293  entry->secondary_team = team;
294  } else {
295  nprintf(("missionlog", "No secondary name for ship destroyed log entry!\n"));
296  }
297  } else if ( (type == LOG_SHIP_SUBSYS_DESTROYED) && (Ship_info[Ships[index].ship_info_index].flags & SIF_SMALL_SHIP) ) {
298  // make subsystem destroyed entries for small ships hidden
299  entry->flags |= MLF_HIDDEN;
300  } else if ( (type == LOG_SHIP_ARRIVED) && (Ships[index].wingnum != -1 ) ) {
301  // arrival of ships in wings don't display
302  entry->flags |= MLF_HIDDEN;
303  }
304  break;
305 
306  case LOG_WING_DESTROYED:
307  case LOG_WING_DEPARTED:
308  case LOG_WING_ARRIVED:
309  index = wing_name_lookup(pname, 1);
310  Assert(index != -1);
311  Assert(info_index != -1); // this is the team value
312 
313  // get the team value for this wing. Departed or destroyed wings will pass the team
314  // value in info_index parameter. For arriving wings, get the team value from the
315  // first ship in the list because the info_index contains the wave count
316  if ( type == LOG_WING_ARRIVED ) {
317  int i, si = -1;
318 
319  // Goober5000 - get the team value from any ship in the list, because
320  // ships that arrive initially docked could be created in random order
321  for (i = 0; i < MAX_SHIPS_PER_WING; ++i) {
322  // get first valid ship
323  si = Wings[index].ship_index[i];
324  if (si >= 0) {
325  break;
326  }
327  }
328  Assert( si != -1 );
329  entry->primary_team = Ships[si].team;
330  } else {
331  entry->primary_team = info_index;
332  }
333 
334 #ifndef NDEBUG
335  // MWA 2/25/98. debug code to try to find any ships in this wing that have departed.
336  // scan through all log entries and find at least one ship_depart entry for a ship
337  // that was in this wing.
338  if ( type == LOG_WING_DEPARTED ) {
339  int i;
340 
341  // if all were destroyed, then don't do this debug code.
342  if ( (Wings[index].total_destroyed + Wings[index].total_vanished) == Wings[index].total_arrived_count ){
343  break;
344  }
345 
346  for ( i = 0; i < last_entry; i++ ) {
347  if ( log_entries[i].type != LOG_SHIP_DEPARTED ){
348  continue;
349  }
350  if( log_entries[i].index == index ){
351  break;
352  }
353  }
354  if ( i == last_entry ){
355  Int3(); // get Allender -- cannot find any departed ships from wing that supposedly departed.
356  }
357  }
358 #endif
359 
360  break;
361 
362  // don't display waypoint done entries
363  case LOG_WAYPOINTS_DONE:
364  entry->flags |= MLF_HIDDEN;
365  break;
366 
367  default:
368  break;
369  }
370 
371  entry->timestamp = Missiontime;
372 
373  // if in multiplayer and I am the master, send this log entry to everyone
374  if ( MULTIPLAYER_MASTER ){
376  }
377 
378  last_entry++;
379 
380 #ifndef NDEBUG
381  if ( !(last_entry % 10) ) {
382  if ( (last_entry > LOG_HALFWAY_REPORT_NUM) && (last_entry > last_entry_save) ){
383  nprintf(("missionlog", "new highwater point reached for mission log (%d entries).\n", last_entry));
384  }
385  }
386 #endif
387 
388 }
389 
390 // function, used in multiplayer only, which adds an entry sent by the host of the game, into
391 // the mission log. The index of the log entry is passed as one of the parameters in addition to
392 // the normal parameters used for adding an entry to the log
393 void mission_log_add_entry_multi( int type, char *pname, char *sname, int index, fix timestamp, int flags )
394 {
395  log_entry *entry;
396 
397  // we'd better be in multiplayer and not the master of the game
400 
401  // mark any entries as obsolete. Part of the pruning is done based on the type (and name) passed
402  // for a new entry
403  mission_log_obsolete_entries(type, pname);
404 
405  entry = &log_entries[last_entry];
406 
407  if ( last_entry == MAX_LOG_ENTRIES ){
408  return;
409  }
410 
411  last_entry++;
412 
413  entry->type = type;
414  if ( pname ) {
415  Assert (strlen(pname) < NAME_LENGTH);
416  strcpy_s(entry->pname, pname);
417  }
418  if ( sname ) {
419  Assert (strlen(sname) < NAME_LENGTH);
420  strcpy_s(entry->sname, sname);
421  }
422  entry->index = index;
423 
424  entry->flags = flags;
425  entry->timestamp = timestamp;
426 }
427 
428 // function to determine is the given event has taken place count number of times.
429 
430 int mission_log_get_time_indexed( int type, char *pname, char *sname, int count, fix *time)
431 {
432  int i, found;
433  log_entry *entry;
434 
435  entry = &log_entries[0];
436 
437  for (i = 0; i < last_entry; i++, entry++) {
438  found = 0;
439 
440  if ( entry->type == type ) {
441  // if we are looking for a dock/undock entry, then we don't care about the order in which the names
442  // were passed into this function. Count the entry as found if either name matches both in the other
443  // set.
444  if ( (type == LOG_SHIP_DOCKED) || (type == LOG_SHIP_UNDOCKED) ) {
445  if (sname == NULL) {
446  Int3();
447  return 0;
448  }
449 
450  if ( (!stricmp(entry->pname, pname) && !stricmp(entry->sname, sname)) || (!stricmp(entry->pname, sname) && !stricmp(entry->sname, pname)) ) {
451  found = 1;
452  }
453  } else {
454  // for non dock/undock goals, then the names are important!
455  if (pname == NULL) {
456  Int3();
457  return 0;
458  }
459 
460  if ( stricmp(entry->pname, pname) ) {
461  continue;
462  }
463 
464  // if we are looking for a subsystem entry, the subsystem names must be compared
465  if ((type == LOG_SHIP_SUBSYS_DESTROYED || type == LOG_CAP_SUBSYS_CARGO_REVEALED)) {
466  if ( (sname == NULL) || !subsystem_stricmp(sname, entry->sname) ) {
467  found = 1;
468  }
469  } else {
470  if ( (sname == NULL) || !stricmp(sname, entry->sname) ) {
471  found = 1;
472  }
473  }
474  }
475 
476  if ( found ) {
477  count--;
478 
479  if ( !count ) {
480  entry->flags |= MLF_ESSENTIAL; // since the goal code asked for this entry, mark it as essential
481 
482  if (time) {
483  *time = entry->timestamp;
484  }
485 
486  return 1;
487  }
488  }
489  }
490  }
491 
492  return 0;
493 }
494 
495 // this function determines if the given type of event on the specified
496 // object has taken place yet. If not, it returns 0. If it has, the
497 // timestamp that the event happened is returned in the time parameter
498 int mission_log_get_time( int type, char *pname, char *sname, fix *time )
499 {
500  return mission_log_get_time_indexed( type, pname, sname, 1, time );
501 }
502 
503 // determines the number of times the given type of event takes place
504 
505 int mission_log_get_count( int type, char *pname, char *sname )
506 {
507  int i;
508  log_entry *entry;
509  int count = 0;
510 
511  entry = &log_entries[0];
512 
513  for (i = 0; i < last_entry; i++, entry++) {
514 
515  if ( entry->type == type ) {
516  // if we are looking for a dock/undock entry, then we don't care about the order in which the names
517  // were passed into this function. Count the entry as found if either name matches both in the other
518  // set.
519  if ( (type == LOG_SHIP_DOCKED) || (type == LOG_SHIP_UNDOCKED) ) {
520  if (sname == NULL) {
521  Int3();
522  return 0;
523  }
524 
525  if ( (!stricmp(entry->pname, pname) && !stricmp(entry->sname, sname)) || (!stricmp(entry->pname, sname) && !stricmp(entry->sname, pname)) ) {
526  count++;
527  }
528  } else {
529  // for non dock/undock goals, then the names are important!
530  if (pname == NULL) {
531  Int3();
532  return 0;
533  }
534 
535  if ( stricmp(entry->pname, pname) ) {
536  continue;
537  }
538 
539  if ( (sname == NULL) || !stricmp(sname, entry->sname) ) {
540  count++;
541  }
542  }
543  }
544  }
545 
546  return count;
547 }
548 
549 
550 void message_log_add_seg(int n, int x, int msg_color, const char *text, int flags = 0)
551 {
552  log_text_seg *seg, **parent;
553 
554  if ((n < 0) || (n >= MAX_LOG_LINES))
555  return;
556 
557  parent = &Log_lines[n];
558  while (*parent)
559  parent = &((*parent)->next);
560 
561  seg = (log_text_seg *) vm_malloc(sizeof(log_text_seg));
562  Assert(seg);
563  seg->text = vm_strdup(text);
564  seg->color = msg_color;
565  seg->x = x;
566  seg->flags = flags;
567  seg->next = NULL;
568  *parent = seg;
569 }
570 
571 void message_log_add_segs(const char *source_string, int msg_color, int flags = 0)
572 {
573  if (!source_string) {
574  mprintf(("Why are you passing a NULL pointer to message_log_add_segs?\n"));
575  return;
576  }
577  if (!*source_string) {
578  return;
579  }
580 
581  int w;
582 
583  // duplicate the string so that we can split it without modifying the source
584  char *dup_string = vm_strdup(source_string);
585  char *str = dup_string;
586  char *split = NULL;
587 
588  while (true) {
589  if (X == ACTION_X) {
590  while (is_white_space(*str))
591  str++;
592  }
593 
594  if (P_width - X < 1)
595  split = str;
596  else
597  split = split_str_once(str, P_width - X);
598 
599  if (split != str)
600  message_log_add_seg(Num_log_lines, X, msg_color, str, flags);
601 
602  if (!split) {
603  gr_get_string_size(&w, NULL, str);
604  X += w;
605  break;
606  }
607 
608  Num_log_lines++;
609  X = ACTION_X;
610  str = split;
611  }
612 
613  // free the buffer
614  vm_free(dup_string);
615 }
616 
618 {
619  log_text_seg *ptr, *ptr2;
620 
621  if ((n < 0) || (n >= MAX_LOG_LINES))
622  return;
623 
624  ptr = Log_lines[n];
625  while (ptr) {
626  ptr2 = ptr->next;
627  vm_free(ptr);
628  ptr = ptr2;
629  }
630 
631  Log_lines[n] = NULL;
632 }
633 
634 int message_log_color_get_team(int msg_color)
635 {
636  return msg_color - NUM_LOG_COLORS;
637 }
638 
640 {
641  return NUM_LOG_COLORS + team;
642 }
643 
644 // pw = total pixel width
646 {
647  char text[256];
648  log_entry *entry;
649  int i, c, kill, type;
650 
651  P_width = pw;
652  mission_log_cull_obsolete_entries(); // compact array so we don't have gaps
653 
654  // initialize the log lines data
655  Num_log_lines = 0;
656  for (i=0; i<MAX_LOG_LINES; i++) {
657  Log_lines[i] = NULL;
658  Log_line_timestamps[i] = 0;
659  }
660 
661  for (i=0; i<last_entry; i++) {
662  entry = &log_entries[i];
663 
664  if (entry->flags & MLF_HIDDEN)
665  continue;
666 
667  // track time of event (normal timestamp milliseconds format)
668  Log_line_timestamps[Num_log_lines] = entry->timestamp;
669 
670  // Goober5000
671  if ((entry->type == LOG_GOAL_SATISFIED) || (entry->type == LOG_GOAL_FAILED))
672  c = LOG_COLOR_BRIGHT;
673  else if (entry->primary_team >= 0)
675  else
676  c = LOG_COLOR_OTHER;
677 
678  if ( (Lcl_gr) && ((entry->type == LOG_GOAL_FAILED) || (entry->type == LOG_GOAL_SATISFIED)) ) {
679  // in german goal events, just say "objective" instead of objective name
680  // this is cuz we can't translate objective names
681  message_log_add_seg(Num_log_lines, OBJECT_X, c, "Einsatzziel");
682  } else if ( (Lcl_pl) && ((entry->type == LOG_GOAL_FAILED) || (entry->type == LOG_GOAL_SATISFIED)) ) {
683  // same thing for polish
684  message_log_add_seg(Num_log_lines, OBJECT_X, c, "Cel misji");
685  } else {
687  }
688 
689  // now on to the actual message itself
690  X = ACTION_X;
691  kill = 0;
692 
693  // Goober5000
694  if (entry->secondary_team >= 0)
696  else
697  c = LOG_COLOR_NORMAL;
698 
699  switch (entry->type) {
700  case LOG_SHIP_DESTROYED:
701  message_log_add_segs(XSTR( "Destroyed", 404), LOG_COLOR_NORMAL);
702  if (strlen(entry->sname)) {
703  message_log_add_segs(XSTR( " Kill: ", 405), LOG_COLOR_NORMAL);
704  message_log_add_segs(entry->sname, c);
705  if (entry->index >= 0) {
706  sprintf(text, NOX(" (%d%%)"), entry->index);
708  }
709  }
710  break;
711 
712  case LOG_SELF_DESTRUCTED:
713  message_log_add_segs(XSTR( "Self Destructed", 1476), LOG_COLOR_NORMAL);
714  break;
715 
716  case LOG_WING_DESTROYED:
717  message_log_add_segs(XSTR( "Destroyed", 404), LOG_COLOR_NORMAL);
718  break;
719 
720  case LOG_SHIP_ARRIVED:
721  message_log_add_segs(XSTR( "Arrived", 406), LOG_COLOR_NORMAL);
722  break;
723 
724  case LOG_WING_ARRIVED:
725  if (entry->index > 1){
726  sprintf(text, XSTR( "Arrived (wave %d)", 407), entry->index);
727  } else {
728  strcpy_s(text, XSTR( "Arrived", 406));
729  }
731  break;
732 
733  case LOG_SHIP_DEPARTED:
734  message_log_add_segs(XSTR( "Departed", 408), LOG_COLOR_NORMAL);
735  break;
736 
737  case LOG_WING_DEPARTED:
738  message_log_add_segs(XSTR( "Departed", 408), LOG_COLOR_NORMAL);
739  break;
740 
741  case LOG_SHIP_DOCKED:
742  message_log_add_segs(XSTR( "Docked with ", 409), LOG_COLOR_NORMAL);
743  message_log_add_segs(entry->sname, c);
744  break;
745 
747  int si_index, model_index;
748 
749  si_index = (int)((entry->index >> 16) & 0xffff);
750  model_index = (int)(entry->index & 0xffff);
751 
752  message_log_add_segs(XSTR( "Subsystem ", 410), LOG_COLOR_NORMAL);
753  //message_log_add_segs(entry->sname, LOG_COLOR_BRIGHT);
754  const char *subsys_name = Ship_info[si_index].subsystems[model_index].subobj_name;
755  if (Ship_info[si_index].subsystems[model_index].type == SUBSYSTEM_TURRET) {
756  subsys_name = XSTR("Turret", 1487);
757  }
759  message_log_add_segs(XSTR( " destroyed", 411), LOG_COLOR_NORMAL);
760  break;
761  }
762 
763  case LOG_SHIP_UNDOCKED:
764  message_log_add_segs(XSTR( "Undocked with ", 412), LOG_COLOR_NORMAL);
765  message_log_add_segs(entry->sname, c);
766  break;
767 
768  case LOG_SHIP_DISABLED:
769  message_log_add_segs(XSTR( "Disabled", 413), LOG_COLOR_NORMAL);
770  break;
771 
772  case LOG_SHIP_DISARMED:
773  message_log_add_segs(XSTR( "Disarmed", 414), LOG_COLOR_NORMAL);
774  break;
775 
777  message_log_add_segs(XSTR( " called for rearm", 415), LOG_COLOR_NORMAL);
778  break;
779 
781  message_log_add_segs(XSTR( " aborted rearm", 416), LOG_COLOR_NORMAL);
782  break;
783 
785  message_log_add_segs(XSTR( "Called in as reinforcement", 417), LOG_COLOR_NORMAL);
786  break;
787 
788  case LOG_CARGO_REVEALED:
789  Assert( entry->index >= 0 );
790  Assert(!(entry->index & CARGO_NO_DEPLETE));
791 
792  message_log_add_segs(XSTR( "Cargo revealed: ", 418), LOG_COLOR_NORMAL);
793  strncpy(text, Cargo_names[entry->index], sizeof(text) - 1);
795  break;
796 
798  Assert( entry->index >= 0 );
799  Assert(!(entry->index & CARGO_NO_DEPLETE));
800 
802  message_log_add_segs(XSTR( " subsystem cargo revealed: ", 1488), LOG_COLOR_NORMAL);
803  strncpy(text, Cargo_names[entry->index], sizeof(text) - 1);
805  break;
806 
807 
808  case LOG_GOAL_SATISFIED:
809  case LOG_GOAL_FAILED: {
810  type = Mission_goals[entry->index].type & GOAL_TYPE_MASK;
811 
812  // don't display failed bonus goals
813  if ( (type == BONUS_GOAL) && (entry->type == LOG_GOAL_FAILED) ) {
814  kill = 1;
815  break; // don't display this line
816  }
817 
818  sprintf( text, XSTR( "%s objective ", 419), Goal_type_text(type) );
819  if ( entry->type == LOG_GOAL_SATISFIED )
820  strcat_s(text, XSTR( "satisfied.", 420));
821  else
822  strcat_s(text, XSTR( "failed.", 421));
823 
825  break;
826  } // matches case statement!
827  }
828 
829  if (kill) {
831 
832  } else {
833  if (Num_log_lines < MAX_LOG_LINES-1)
834  Num_log_lines++;
835  }
836  }
837 }
838 
840 {
841  int i;
842 
843  for (i=0; i<MAX_LOG_LINES; i++)
845 
846  Num_log_lines = 0;
847 }
848 
849 // message_log_scrollback displays the contents of the mesasge log currently much like the HUD
850 // message scrollback system. I'm sure this system will be overhauled.
851 void mission_log_scrollback(int line, int list_x, int list_y, int list_w, int list_h)
852 {
853  char buf[256];
854  int y;
855  int font_h = gr_get_font_height();
856  log_text_seg *seg;
857 
858  y = 0;
859  while (y + font_h <= list_h) {
860  if (line >= Num_log_lines)
861  break;
862 
863  if (Log_line_timestamps[line]) {
865  gr_print_timestamp(list_x + TIME_X, list_y + y, Log_line_timestamps[line], GR_RESIZE_MENU);
866  }
867 
868  seg = Log_lines[line];
869  while (seg) {
870  switch (seg->color) {
871  case LOG_COLOR_BRIGHT:
873  break;
874 
875  case LOG_COLOR_OTHER:
877  break;
878 
879  default:
880  {
882  if (team < 0)
884  else
886 
887  break;
888  }
889  }
890 
891  strcpy_s(buf, seg->text);
892  if (seg->x < ACTION_X)
893  gr_force_fit_string(buf, 256, ACTION_X - OBJECT_X - 8);
894  else
895  gr_force_fit_string(buf, 256, list_w - seg->x);
896 
898  gr_string(list_x + seg->x, list_y + y, buf, GR_RESIZE_MENU);
899 
900  // possibly "print" some symbols for interesting log entries
901  if ( (seg->flags & LOG_FLAG_GOAL_TRUE) || (seg->flags & LOG_FLAG_GOAL_FAILED) ) {
902  int i;
903 
904  if ( seg->flags & LOG_FLAG_GOAL_FAILED )
906  else
908 
909  i = list_y + y + font_h / 2 - 1;
910  gr_circle(list_x + TIME_X - 6, i, 5, GR_RESIZE_MENU);
911 
913  gr_line(list_x + TIME_X - 10, i, list_x + TIME_X - 8, i, GR_RESIZE_MENU);
914  gr_line(list_x + TIME_X - 6, i - 4, list_x + TIME_X - 6, i - 2, GR_RESIZE_MENU);
915  gr_line(list_x + TIME_X - 4, i, list_x + TIME_X - 2, i, GR_RESIZE_MENU);
916  gr_line(list_x + TIME_X - 6, i + 2, list_x + TIME_X - 6, i + 4, GR_RESIZE_MENU);
917  }
918 
919  seg = seg->next;
920  }
921 
922  y += font_h;
923  line++;
924  }
925 }
int timestamp(int delta_ms)
Definition: timer.cpp:226
wing Wings[MAX_WINGS]
Definition: ship.cpp:128
#define MULTIPLAYER_CLIENT
Definition: multi.h:132
int i
Definition: multi_pxo.cpp:466
fix Missiontime
Definition: systemvars.cpp:19
#define vm_free(ptr)
Definition: pstypes.h:548
#define LOG_COLOR_OTHER
Definition: missionlog.cpp:47
#define LOG_CULL_DOORDIE_MARK
Definition: missionlog.cpp:34
#define BONUS_GOAL
Definition: missiongoals.h:30
#define LOG_PLAYER_CALLED_FOR_REARM
Definition: missionlog.h:31
int team
Definition: ship.h:606
void mission_log_add_entry(int type, char *pname, char *sname, int info_index)
Definition: missionlog.cpp:184
int last_entry
Definition: missionlog.cpp:70
int Game_mode
Definition: systemvars.cpp:24
#define EMPTY_LOG_NAME
Definition: missionlog.cpp:38
color * iff_get_color_by_team(int team, int seen_from_team, int is_bright)
Definition: iff_defs.cpp:644
int primary_team
Definition: missionlog.h:56
#define MAX_LOG_LINES
Definition: missionlog.cpp:30
#define GR_RESIZE_MENU
Definition: 2d.h:684
net_player * Net_player
Definition: multi.cpp:94
struct log_text_seg log_text_seg
#define LOG_SHIP_SUBSYS_DESTROYED
Definition: missionlog.h:27
GLuint index
Definition: Glext.h:5608
player * m_player
Definition: multi.h:459
int index
Definition: missionlog.h:53
int flags
Definition: missionlog.h:49
__inline void gr_circle(int xc, int yc, int d, int resize_mode=GR_RESIZE_FULL)
Definition: 2d.h:774
#define LOG_SHIP_ARRIVED
Definition: missionlog.h:22
int message_log_color_get_team(int msg_color)
Definition: missionlog.cpp:634
#define LOG_GOAL_FAILED
Definition: missionlog.h:34
void message_log_init_scrollback(int pw)
Definition: missionlog.cpp:645
void mission_log_cull_obsolete_entries()
Definition: missionlog.cpp:89
Assert(pm!=NULL)
#define mprintf(args)
Definition: pstypes.h:238
#define MAX_LOG_ENTRIES
Definition: missionlog.cpp:29
__inline void gr_string(int x, int y, const char *string, int resize_mode=GR_RESIZE_FULL)
Definition: 2d.h:769
int subsystem_stricmp(const char *str1, const char *str2)
Definition: parselo.cpp:3648
#define LOG_WING_DEPARTED
Definition: missionlog.h:25
#define LOG_SHIP_UNDOCKED
Definition: missionlog.h:28
int Lcl_pl
Definition: localize.cpp:49
CButton * team
#define NUM_LOG_COLORS
Definition: missionlog.cpp:48
#define LOG_SHIP_DEPARTED
Definition: missionlog.h:24
void message_log_shutdown_scrollback()
Definition: missionlog.cpp:839
#define LOG_LAST_DITCH_CULL_NUM
Definition: missionlog.cpp:35
void mission_log_add_entry_multi(int type, char *pname, char *sname, int index, fix timestamp, int flags)
Definition: missionlog.cpp:393
int ship_find_exited_ship_by_name(char *name)
Definition: ship.cpp:5338
void gr_print_timestamp(int x, int y, fix timestamp, int resize_mode)
Definition: font.cpp:143
void gr_set_color_fast(color *dst)
Definition: 2d.cpp:1197
#define MAX_SHIPS_PER_WING
Definition: globals.h:52
int flags
Definition: multi.h:463
void mission_log_obsolete_entries(int type, char *pname)
Definition: missionlog.cpp:126
log_entry log_entries[MAX_LOG_ENTRIES]
Definition: missionlog.cpp:69
#define Int3()
Definition: pstypes.h:292
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: Glext.h:7308
mission_goal Mission_goals[MAX_GOALS]
#define LOG_WING_ARRIVED
Definition: missionlog.h:23
Container & split(Container &result, const typename Container::value_type &s, const typename Container::value_type &delimiters, split_struct::empties_t empties=split_struct::empties_ok)
GLenum type
Definition: Gl.h:1492
#define MLF_HIDDEN
Definition: missionlog.h:45
int type
Definition: missionlog.h:48
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
int instance
Definition: object.h:150
#define LOG_FLAG_GOAL_FAILED
Definition: missionlog.cpp:51
char pname[NAME_LENGTH]
Definition: missionlog.h:51
#define NETINFO_FLAG_AM_MASTER
Definition: multi.h:599
color Color_bright
Definition: alphacolors.cpp:28
int mission_log_get_time(int type, char *pname, char *sname, fix *time)
Definition: missionlog.cpp:498
#define LOG_WING_DESTROYED
Definition: missionlog.h:21
#define LOG_SHIP_DISABLED
Definition: missionlog.h:29
GLenum pname
Definition: Gl.h:1517
int mission_log_get_time_indexed(int type, char *pname, char *sname, int count, fix *time)
Definition: missionlog.cpp:430
color Color_bright_green
Definition: alphacolors.cpp:31
#define LOG_GOAL_SATISFIED
Definition: missionlog.h:33
#define nprintf(args)
Definition: pstypes.h:239
#define GM_MULTIPLAYER
Definition: systemvars.h:18
#define ACTION_X
Definition: missionlog.cpp:43
int mission_log_query_scrollback_size()
Definition: missionlog.cpp:81
#define SIF_SMALL_SHIP
Definition: ship.h:943
#define w(p)
Definition: modelsinc.h:68
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
#define SUBSYSTEM_TURRET
Definition: model.h:54
#define vm_strdup(ptr)
Definition: pstypes.h:549
#define MLF_ESSENTIAL
Definition: missionlog.h:43
#define LOG_CAP_SUBSYS_CARGO_REVEALED
Definition: missionlog.h:38
int Num_log_lines
Definition: missionlog.cpp:62
#define LOG_CULL_MARK
Definition: missionlog.cpp:33
char sname[NAME_LENGTH]
Definition: missionlog.h:52
#define TIME_X
Definition: missionlog.cpp:41
int multi_find_player_by_callsign(const char *callsign)
Definition: multiutil.cpp:1291
GLint GLint GLint GLint GLint x
Definition: Glext.h:5182
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
long fix
Definition: pstypes.h:54
GLclampd n
Definition: Glext.h:7286
#define GOAL_TYPE_MASK
Definition: missiongoals.h:34
const char * XSTR(const char *str, int index)
Definition: localize.cpp:851
int objnum
Definition: player.h:124
ship * Player_ship
Definition: ship.cpp:124
int message_log_team_get_color(int team)
Definition: missionlog.cpp:639
color Color_bright_red
Definition: alphacolors.cpp:34
#define LOG_SHIP_DESTROYED
Definition: missionlog.h:20
#define LOG_SHIP_DOCKED
Definition: missionlog.h:26
#define NOX(s)
Definition: pstypes.h:473
bool end_string_at_first_hash_symbol(char *src)
Definition: parselo.cpp:3833
GLbitfield flags
Definition: Glext.h:6722
#define vm_malloc(size)
Definition: pstypes.h:547
int wing_name_lookup(const char *name, int ignore_count)
Definition: ship.cpp:12706
__inline void gr_line(int x1, int y1, int x2, int y2, int resize_mode=GR_RESIZE_FULL)
Definition: 2d.h:791
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
void mission_log_scrollback(int line, int list_x, int list_y, int list_w, int list_h)
Definition: missionlog.cpp:851
int mission_log_get_count(int type, char *pname, char *sname)
Definition: missionlog.cpp:505
fix timestamp
Definition: missionlog.h:50
int secondary_team
Definition: missionlog.h:57
void message_log_add_seg(int n, int x, int msg_color, const char *text, int flags=0)
Definition: missionlog.cpp:550
#define LOG_PLAYER_CALLED_FOR_REINFORCEMENT
Definition: missionlog.h:32
#define strcat_s(...)
Definition: safe_strings.h:68
#define NAME_LENGTH
Definition: globals.h:15
#define LOG_HALFWAY_REPORT_NUM
Definition: missionlog.cpp:36
int gr_force_fit_string(char *str, int max_str, int max_width)
Definition: font.cpp:48
#define MLF_OBSOLETE
Definition: missionlog.h:44
void mission_log_init()
Definition: missionlog.cpp:72
#define LOG_FLAG_GOAL_TRUE
Definition: missionlog.cpp:52
void gr_get_string_size(int *w, int *h, const char *text, int len=9999)
Definition: font.cpp:196
char * split_str_once(char *src, int max_pixel_w)
Definition: parselo.cpp:3330
#define CARGO_NO_DEPLETE
Definition: missionparse.h:221
void message_log_remove_segs(int n)
Definition: missionlog.cpp:617
int gr_get_font_height()
Definition: font.cpp:187
#define MULTIPLAYER_MASTER
Definition: multi.h:130
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
int multi_get_player_ship(int np_index)
Definition: multiutil.cpp:599
#define LOG_CARGO_REVEALED
Definition: missionlog.h:37
SCP_vector< exited_ship > Ships_exited
Definition: ship.cpp:152
Definition: missionlog.h:47
color Color_normal
Definition: alphacolors.cpp:28
const char * Goal_type_text(int n)
GLint GLsizei count
Definition: Gl.h:1491
void send_mission_log_packet(int num)
Definition: multimsgs.cpp:3348
color Color_text_normal
Definition: alphacolors.cpp:26
#define LOG_COLOR_BRIGHT
Definition: missionlog.cpp:46
int ship_index[MAX_SHIPS_PER_WING]
Definition: ship.h:1531
#define LOG_COLOR_NORMAL
Definition: missionlog.cpp:45
#define OBJECT_X
Definition: missionlog.cpp:42
int is_white_space(char ch)
Definition: parselo.cpp:59
#define LOG_WAYPOINTS_DONE
Definition: missionlog.h:36
void message_log_add_segs(const char *source_string, int msg_color, int flags=0)
Definition: missionlog.cpp:571
int ship_name_lookup(const char *name, int inc_players)
Definition: ship.cpp:12900
char * Cargo_names[]
net_player Net_players[MAX_PLAYERS]
Definition: multi.cpp:93
log_text_seg * next
Definition: missionlog.cpp:55
#define stricmp(s1, s2)
Definition: config.h:271
#define LOG_SHIP_DISARMED
Definition: missionlog.h:30
#define LOG_PLAYER_ABORTED_REARM
Definition: missionlog.h:35
const GLubyte * c
Definition: Glext.h:8376
int Lcl_gr
Definition: localize.cpp:48
#define LOG_SELF_DESTRUCTED
Definition: missionlog.h:39
GLint y
Definition: Gl.h:1505
#define strcpy_s(...)
Definition: safe_strings.h:67