1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5
6 #include "../include/string.h"
7
8 #include "obj.h"
9 #include "objutils.h"
10 #include "messages.h"
11 #include "mission.h"
12 #include "missionio.h"
13 #include "simutils.h"
14 #include "sar.h"
15 #include "config.h"
16
17
18 #ifdef __MSW__
19 static double rint(double x);
20 #endif /* __MSW__ */
21 static sar_mission_objective_struct *SARMissionObjectiveGetCurrentPtr(
22 sar_mission_struct *mission
23 );
24 static int SARMissionGetObjectPassengers(
25 sar_core_struct *core_ptr, sar_object_struct *obj_ptr
26 );
27 static Boolean SARMissionGroundContactMatchName(
28 sar_core_struct *core_ptr, sar_scene_struct *scene,
29 sar_object_struct **ptr, int total,
30 const int *ground_contact, int total_ground_contacts,
31 const char *name
32 );
33
34 sar_mission_struct *SARMissionNew(void);
35 void SARMissionDelete(sar_mission_struct *mission);
36
37 void SARMissionPrintStats(
38 sar_core_struct *core_ptr,
39 sar_scene_struct *scene,
40 sar_mission_struct *mission,
41 sar_object_struct *obj_ptr
42 );
43
44 static int SARMissionDoObjectiveSuccess(
45 sar_mission_struct *mission, sar_scene_struct *scene
46 );
47 static int SARMissionDoObjectiveFailed(
48 sar_mission_struct *mission, sar_scene_struct *scene
49 );
50
51 void SARMissionDestroyNotify(
52 sar_core_struct *core_ptr, sar_object_struct *obj_ptr
53 );
54 void SARMissionHoistInNotify(
55 sar_core_struct *core_ptr, sar_object_struct *obj_ptr,
56 int hoisted_in /* Number of humans hoisted in */
57 );
58 void SARMissionPassengersEnterNotify(
59 sar_core_struct *core_ptr, sar_object_struct *obj_ptr,
60 int passengers_entered /* Number of passengers entered */
61 );
62 void SARMissionPassengersLeaveNotify(
63 sar_core_struct *core_ptr, sar_object_struct *obj_ptr,
64 int passengers_left /* Number of passengers that left */
65 );
66 void SARMissionLandNotify(
67 sar_core_struct *core_ptr, sar_object_struct *obj_ptr,
68 const int *ground_contact, int total_ground_contacts
69 );
70
71 static void SARMissionObjectiveManage(
72 sar_core_struct *core_ptr, sar_mission_struct *mission,
73 sar_mission_objective_struct *objective
74 );
75 int SARMissionManage(sar_core_struct *core_ptr);
76
77
78 #define ATOI(s) (((s) != NULL) ? atoi(s) : 0)
79 #define ATOL(s) (((s) != NULL) ? atol(s) : 0)
80 #define ATOF(s) (((s) != NULL) ? atof(s) : 0.0f)
81 #define STRDUP(s) (((s) != NULL) ? strdup(s) : NULL)
82
83 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
84 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
85 #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h)))
86 #define STRLEN(s) (((s) != NULL) ? ((int)strlen(s)) : 0)
87
88 #define ISCOMMENT(c) ((c) == SAR_COMMENT_CHAR)
89 #define ISCR(c) (((c) == '\n') || ((c) == '\r'))
90
91
92 /*
93 * Interval between mission end check and leaving simulation to
94 * go back to the menus (in milliseconds):
95 */
96 #define DEF_MISSION_END_INT 5000
97
98
99
100 #ifdef __MSW__
rint(double x)101 static double rint(double x)
102 {
103 if((double)((double)x - (int)x) > (double)0.5)
104 return((double)((int)x + (int)1));
105 else
106 return((double)((int)x));
107 }
108 #endif /* __MSW__ */
109
110
111 /*
112 * Returns the pointer to the current mission objective structure on
113 * the given mission structure. Can return NULL on error.
114 */
SARMissionObjectiveGetCurrentPtr(sar_mission_struct * mission)115 static sar_mission_objective_struct *SARMissionObjectiveGetCurrentPtr(
116 sar_mission_struct *mission
117 )
118 {
119 int i;
120
121 if(mission == NULL)
122 return(NULL);
123
124 i = mission->cur_objective;
125 if((i < 0) || (i >= mission->total_objectives))
126 return(NULL);
127 else
128 return(&mission->objective[i]);
129 }
130
131 /*
132 * Returns the number of passengers on the object, depending on the
133 * object type it may not have any objects. Does not include crew
134 * or any fixed on-board `individuals'.
135 *
136 * For any object that has a hoist and rescue basket, any passengers
137 * in the rescue basket are NOT counted.
138 *
139 * The object is assumed valid.
140 */
SARMissionGetObjectPassengers(sar_core_struct * core_ptr,sar_object_struct * obj_ptr)141 static int SARMissionGetObjectPassengers(
142 sar_core_struct *core_ptr, sar_object_struct *obj_ptr
143 )
144 {
145 int *passengers;
146
147 if(obj_ptr == NULL)
148 return(0);
149
150 if(SARObjGetOnBoardPtr(
151 obj_ptr,
152 NULL, &passengers, NULL,
153 NULL,
154 NULL, NULL
155 ))
156 return(0);
157
158 if(passengers != NULL)
159 return(MAX(*passengers, 0));
160 else
161 return(0);
162 }
163
164 /*
165 * Checks for all objects in the given objects list who's name
166 * matches the given name and who's index is found on the given
167 * ground_contact list.
168 *
169 * Any special object numbers in the given ground_contact list will
170 * be ignored.
171 *
172 * Returns True on match or False on no match or error.
173 */
SARMissionGroundContactMatchName(sar_core_struct * core_ptr,sar_scene_struct * scene,sar_object_struct ** ptr,int total,const int * ground_contact,int total_ground_contacts,const char * name)174 static Boolean SARMissionGroundContactMatchName(
175 sar_core_struct *core_ptr, sar_scene_struct *scene,
176 sar_object_struct **ptr, int total,
177 const int *ground_contact, int total_ground_contacts,
178 const char *name
179 )
180 {
181 int i, obj_num;
182 sar_object_struct *obj_ptr;
183
184
185 if((name == NULL) || (ground_contact == NULL) || (ptr == NULL))
186 return(False);
187
188 /* Check if landed at right place, iterate through list of
189 * ground contact objects for matching name
190 */
191 for(i = 0; i < total_ground_contacts; i++)
192 {
193 obj_num = ground_contact[i];
194 obj_ptr = SARObjGetPtr(ptr, total, obj_num);
195 if((obj_ptr == NULL) ? 1 : (obj_ptr->name == NULL))
196 continue;
197
198 /* Names match? */
199 if(!strcasecmp(obj_ptr->name, name))
200 break;
201 }
202 /* No match? */
203 if(i >= total_ground_contacts)
204 return(False);
205 else
206 return(True);
207 }
208
209
210 /*
211 * Allocates a new mission structure with all its members
212 * reset.
213 */
SARMissionNew(void)214 sar_mission_struct *SARMissionNew(void)
215 {
216 return(
217 (sar_mission_struct *)calloc(1, sizeof(sar_mission_struct))
218 );
219 }
220
221 /*
222 * Deletes the given mission structure and all its substructures,
223 * including the mission structure itself.
224 */
SARMissionDelete(sar_mission_struct * mission)225 void SARMissionDelete(sar_mission_struct *mission)
226 {
227 if(mission == NULL)
228 return;
229
230 /* Need to delete objective(s)? */
231 if(mission->objective != NULL)
232 {
233 int i;
234 sar_mission_objective_struct *objective;
235
236 /* Iterate through each objective and delete its members */
237 for(i = mission->total_objectives - 1; i >= 0; i--)
238 {
239 objective = &mission->objective[i];
240
241 free(objective->arrive_at_name);
242 free(objective->message_success);
243 free(objective->message_fail);
244 }
245
246 /* Delete all objectives */
247 free(mission->objective);
248 mission->objective = NULL;
249 mission->total_objectives = 0;
250 }
251
252 /* Delete the rest of the mission structure */
253 free(mission->title);
254 free(mission->description);
255
256 free(mission->start_location_name);
257
258 free(mission->scene_file);
259 free(mission->player_model_file);
260 free(mission->player_stats_file);
261
262 free(mission->objective);
263
264 free(mission);
265 }
266
267
268 /*
269 * Prints mission stats to the scene's message output with respect
270 * to the given object and mission structures.
271 */
SARMissionPrintStats(sar_core_struct * core_ptr,sar_scene_struct * scene,sar_mission_struct * mission,sar_object_struct * obj_ptr)272 void SARMissionPrintStats(
273 sar_core_struct *core_ptr, sar_scene_struct *scene,
274 sar_mission_struct *mission,
275 sar_object_struct *obj_ptr
276 )
277 {
278 int *passengers = NULL,
279 *passengers_max = NULL;
280 char text[1024];
281
282
283 /* First print object statistics if object is valid */
284 SARObjGetOnBoardPtr(
285 obj_ptr,
286 NULL, &passengers, &passengers_max,
287 NULL,
288 NULL, NULL
289 );
290
291 /* Format passengers on board string */
292 sprintf(
293 text,
294 "%s: %i(%i)",
295 SAR_MESG_PASSENGERS,
296 (passengers != NULL) ? *passengers : 0,
297 (passengers_max != NULL) ? *passengers_max : 0
298 );
299 SARMessageAdd(scene, text);
300
301 /* Valid mission structure given? */
302 if(mission != NULL)
303 {
304 sar_mission_objective_struct *objective = SARMissionObjectiveGetCurrentPtr(mission);
305
306 /* Is there a current mission objective? */
307 if(objective != NULL)
308 {
309 #define tmp_name_len 80
310 char tmp_name[tmp_name_len];
311
312 /* Handle by mission objective type */
313 switch(objective->type)
314 {
315 case SAR_MISSION_OBJECTIVE_ARRIVE_AT:
316 strncpy(
317 tmp_name,
318 (objective->arrive_at_name != NULL) ?
319 objective->arrive_at_name : "(null)",
320 tmp_name_len
321 );
322 tmp_name[tmp_name_len - 1] = '\0';
323
324 /* Print arrive mission status */
325 sprintf(
326 text,
327 "%s %s",
328 SAR_MESG_MISSION_IN_PROGRESS_ENROUTE, tmp_name
329 );
330 SARMessageAdd(scene, text);
331
332 /* Is there a time limit? */
333 if(objective->time_left > 0.0)
334 {
335 sprintf(text,
336 "%s %s",
337 SAR_MESG_TIME_LEFT,
338 SARDeltaTimeString(
339 core_ptr,
340 (time_t)objective->time_left
341 )
342 );
343 SARMessageAdd(scene, text);
344 }
345 break;
346
347 case SAR_MISSION_OBJECTIVE_PICK_UP:
348 case SAR_MISSION_OBJECTIVE_PICK_UP_ARRIVE_AT:
349 /* Print how many more we need to find */
350 if(objective->humans_need_rescue > 0)
351 sprintf(
352 text,
353 "%s, %i %s",
354 SAR_MESG_MISSION_RESCUE_IN_PROGRESS,
355 objective->humans_need_rescue,
356 SAR_MESG_MISSION_MORE_TO_FIND
357 );
358 else
359 sprintf(
360 text,
361 "%s, %s",
362 SAR_MESG_MISSION_RESCUE_IN_PROGRESS,
363 SAR_MESG_MISSION_ALL_FOUND
364 );
365 SARMessageAdd(scene, text);
366
367 /* Is there a time limit? */
368 if(objective->time_left > 0.0)
369 {
370 /* Need to check objective type again */
371 switch(objective->type)
372 {
373 /* Pick up all and get them to safety */
374 case SAR_MISSION_OBJECTIVE_PICK_UP_ARRIVE_AT:
375 sprintf(
376 text,
377 "%s %s %s",
378 SAR_MESG_TIME_LEFT,
379 SARDeltaTimeString(
380 core_ptr,
381 (time_t)objective->time_left
382 ),
383 SAR_MESG_MISSION_TO_GET_ALL_TO_SAFETY
384 );
385 SARMessageAdd(scene, text);
386 break;
387
388 /* Just pick up all */
389 case SAR_MISSION_OBJECTIVE_PICK_UP:
390 sprintf(
391 text,
392 "%s %s %s",
393 SAR_MESG_TIME_LEFT,
394 SARDeltaTimeString(
395 core_ptr,
396 (time_t)objective->time_left
397 ),
398 SAR_MESG_MISSION_TO_PICK_UP_ALL
399 );
400 SARMessageAdd(scene, text);
401 break;
402 }
403 }
404 break;
405 }
406
407 #undef tmp_name_len
408 } /* Is there a current mission objective? */
409 else
410 {
411 /* No current mission objective, implying mission is
412 * completed or failed. Check master mission state.
413 */
414 switch(mission->state)
415 {
416 case MISSION_STATE_IN_PROGRESS:
417 /* Still in progress but no current objectives? Must be
418 * a delay in the updates (hopefully), print a standby
419 * message.
420 */
421 SARMessageAdd(scene, SAR_MESG_MISSION_STANDBY);
422 break;
423
424 case MISSION_STATE_FAILED:
425 /* Print generic mission objectives failed message */
426 SARMessageAdd(scene, SAR_MESG_MISSION_FAILED);
427 break;
428
429 case MISSION_STATE_ACCOMPLISHED:
430 /* Print generic mission accomplished message */
431 SARMessageAdd(scene, SAR_MESG_MISSION_RESCUE_COMPLETE);
432 break;
433 }
434 }
435 } /* Valid mission structure given? */
436 }
437
438
439 /*
440 * Procedure to mark current objective on the given mission structure
441 * as success and go on to the next objective. If there are no more
442 * objectives then the entire mission has been accomplished.
443 *
444 * Returns:
445 *
446 * -1 General error
447 * 0 Went on to next objective
448 * 1 All objectives completed, mission accomplished
449 */
SARMissionDoObjectiveSuccess(sar_mission_struct * mission,sar_scene_struct * scene)450 static int SARMissionDoObjectiveSuccess(
451 sar_mission_struct *mission, sar_scene_struct *scene
452 )
453 {
454 int player_obj_num;
455 sar_object_struct *player_obj_ptr;
456 sar_mission_objective_struct *objective;
457
458 if((mission == NULL) || (scene == NULL))
459 return(-1);
460
461 /* Get player object references from scene structure */
462 player_obj_num = scene->player_obj_num;
463 player_obj_ptr = scene->player_obj_ptr;
464
465 /* Get current mission objective */
466 objective = SARMissionObjectiveGetCurrentPtr(mission);
467 if(objective != NULL)
468 {
469 sar_object_aircraft_struct *obj_aircraft_ptr;
470 const char *mesg_ptr = objective->message_success;
471
472 /* Mark current objective as success */
473 objective->state = SAR_MISSION_OBJECTIVE_STATE_SUCCESS;
474
475 /* Print success message? */
476 if(mesg_ptr != NULL)
477 SARMessageAdd(scene, mesg_ptr);
478
479 /* Update way point on player object */
480 obj_aircraft_ptr = SAR_OBJ_GET_AIRCRAFT(player_obj_ptr);
481 if(obj_aircraft_ptr != NULL)
482 {
483 obj_aircraft_ptr->cur_intercept++;
484 if(obj_aircraft_ptr->cur_intercept >= obj_aircraft_ptr->total_intercepts)
485 obj_aircraft_ptr->cur_intercept = obj_aircraft_ptr->total_intercepts - 1;
486 }
487
488 /* Increment to next objective */
489 mission->cur_objective++;
490 }
491
492 /* All objectives completed? */
493 if((mission->cur_objective >= mission->total_objectives) ||
494 (objective == NULL)
495 )
496 {
497 /* Mark mission progress state as accomplished */
498 mission->state = MISSION_STATE_ACCOMPLISHED;
499
500 /* Set mission accomplished banner */
501 SARBannerMessageAppend(scene, NULL);
502 SARBannerMessageAppend(scene,
503 SAR_MESG_MISSION_ACCOMPLISHED_BANNER
504 );
505 #if 0
506 SARBannerMessageAppend(
507 scene,
508 ((mesg_ptr != NULL) ? mesg_ptr :
509 SAR_MESG_MISSION_ARRIVE_COMPLETE
510 )
511 );
512 #endif
513
514 /* Do not set continue banner message for mission accomplished */
515
516 /* Schedual next mission check in 5 seconds which will
517 * detect acomplished state
518 */
519 mission->next_check = cur_millitime + DEF_MISSION_END_INT;
520
521 /* Return indicating all objectives completed, mission
522 * accomplished
523 */
524 return(1);
525 }
526 else
527 {
528 /* Return indicating went on to next objective */
529 return(0);
530 }
531 }
532
533 /*
534 * Procedure to mark current objective on the given mission structure
535 * as failed and mark the entire mission as failed.
536 *
537 * Returns:
538 *
539 * -1 General error
540 * 0 Went on to next objective
541 * 1 Entire mission failed
542 */
SARMissionDoObjectiveFailed(sar_mission_struct * mission,sar_scene_struct * scene)543 static int SARMissionDoObjectiveFailed(
544 sar_mission_struct *mission, sar_scene_struct *scene
545 )
546 {
547 sar_mission_objective_struct *objective;
548
549 if((mission == NULL) || (scene == NULL))
550 return(-1);
551
552 /* Get current mission objective */
553 objective = SARMissionObjectiveGetCurrentPtr(mission);
554 if(objective != NULL)
555 {
556 const char *mesg_ptr = objective->message_fail;
557
558 /* Mark current objective as failed */
559 objective->state = SAR_MISSION_OBJECTIVE_STATE_FAILED;
560
561 /* Print failed message? */
562 if(mesg_ptr != NULL)
563 SARMessageAdd(scene, mesg_ptr);
564
565 /* For now, set current objective to reffer past the
566 * highest objective
567 */
568 /* This might change later, some objectives might allow fail in
569 * the future, thus allowing the next objective to be playable and
570 * not have the entire mission fail
571 *
572 * Check if player has crashed on the scene structure?
573 */
574 mission->cur_objective = mission->total_objectives;
575 }
576
577 /* All objectives failed? */
578 if((mission->cur_objective >= mission->total_objectives) ||
579 (objective == NULL)
580 )
581 {
582 /* Mark mission progress state as failed */
583 mission->state = MISSION_STATE_FAILED;
584
585 /* Set mission failed banner */
586 SARBannerMessageAppend(scene, NULL);
587 SARBannerMessageAppend(scene,
588 SAR_MESG_MISSION_FAILED_BANNER
589 );
590 #if 0
591 SARBannerMessageAppend(
592 scene,
593 (mesg_ptr != NULL) ? mesg_ptr :
594 SAR_MESG_MISSION_ARRIVE_FAILED_TIME
595 );
596 #endif
597
598 /* Set continue message */
599 SARBannerMessageAppend(
600 scene,
601 SAR_MESG_MISSION_POST_FAILED_BANNER
602 );
603
604 /* Schedual next mission check in 5 seconds which will
605 * detect failed state.
606 */
607 mission->next_check = cur_millitime + DEF_MISSION_END_INT;
608
609 /* Return indicating entire mission failed */
610 return(1);
611 }
612 else
613 {
614 /* Return indicating went on to next objective */
615 return(0);
616 }
617 }
618
619
620 /*
621 * Destroy notify. This function should be called whenever an
622 * object is *about* to be destroyed.
623 */
SARMissionDestroyNotify(sar_core_struct * core_ptr,sar_object_struct * obj_ptr)624 void SARMissionDestroyNotify(
625 sar_core_struct *core_ptr, sar_object_struct *obj_ptr
626 )
627 {
628 int player_obj_num;
629 sar_object_struct *player_obj_ptr;
630 sar_mission_objective_struct *objective;
631 sar_mission_struct *mission = core_ptr->mission;
632 sar_scene_struct *scene = core_ptr->scene;
633 const sar_option_struct *opt = &core_ptr->option;
634 if((scene == NULL) || (mission == NULL) || (obj_ptr == NULL))
635 return;
636
637 if(opt->runtime_debug)
638 printf(
639 "SARMissionDestroyNotify():\
640 Got destroy notify for object \"%s\".\n",
641 obj_ptr->name
642 );
643
644 /* Get references to player object */
645 player_obj_num = scene->player_obj_num;
646 player_obj_ptr = scene->player_obj_ptr;
647
648 /* Get current mission objective, return if there isn't one */
649 objective = SARMissionObjectiveGetCurrentPtr(mission);
650 if(objective == NULL)
651 return;
652
653 /* Log object crash event */
654 if(True)
655 {
656 char *s;
657 const char *name = obj_ptr->name;
658
659 /* If this is the player object then get player's name */
660 if(player_obj_ptr == obj_ptr)
661 {
662 sar_player_stat_struct *pstat = SARPlayerStatCurrent(
663 core_ptr, NULL
664 );
665 if(pstat != NULL)
666 {
667 pstat->crashes++;
668 name = pstat->name;
669 }
670 }
671
672 s = (char *)malloc(
673 (80 + STRLEN(name)) * sizeof(char)
674 );
675 sprintf(
676 s,
677 "%s crashed",
678 name
679 );
680 SARMissionLogEvent(
681 core_ptr, mission,
682 SAR_MISSION_LOG_EVENT_CRASH,
683 -1.0,
684 &obj_ptr->pos,
685 NULL, 0,
686 s,
687 fname.mission_log
688 );
689 free(s);
690 }
691
692
693 /* Handle by current objective type */
694 switch(objective->type)
695 {
696 case SAR_MISSION_OBJECTIVE_ARRIVE_AT:
697 case SAR_MISSION_OBJECTIVE_PICK_UP:
698 case SAR_MISSION_OBJECTIVE_PICK_UP_ARRIVE_AT:
699 /* Is the player object the object that was destroyed? */
700 if(player_obj_ptr == obj_ptr)
701 {
702 /* Player object has been destroyed, this means that for
703 * this type of objective the objective has failed.
704 * Mark this objective as failed and go on to the next
705 * objective or possibly fail the entire mission
706 */
707 SARMissionDoObjectiveFailed(mission, scene);
708 }
709 break;
710 }
711 }
712
713 /*
714 * Hoist in notify, this function should be called whenever a number
715 * of human objects have been deleted because they were hoisted
716 * into the object specified by obj_ptr.
717 *
718 * Note that for events of humans entering an object, should call
719 * the notify function SARMissionPassengerEnterNotify().
720 */
SARMissionHoistInNotify(sar_core_struct * core_ptr,sar_object_struct * obj_ptr,int hoisted_in)721 void SARMissionHoistInNotify(
722 sar_core_struct *core_ptr, sar_object_struct *obj_ptr,
723 int hoisted_in /* Number of humans hoisted in */
724 )
725 {
726 char *s;
727 const char *name;
728 sar_mission_objective_struct *objective;
729 sar_mission_struct *mission = core_ptr->mission;
730 sar_scene_struct *scene = core_ptr->scene;
731 const sar_option_struct *opt = &core_ptr->option;
732 if((scene == NULL) || (mission == NULL) || (obj_ptr == NULL) ||
733 (hoisted_in <= 0)
734 )
735 return;
736
737 if(opt->runtime_debug)
738 printf(
739 "SARMissionHoistInNotify(): Got hoist in notify for object \"%s\" for %i humans.\n",
740 obj_ptr->name, hoisted_in
741 );
742
743 /* Get current mission objective, return if there isn't one */
744 objective = SARMissionObjectiveGetCurrentPtr(mission);
745 if(objective == NULL)
746 return;
747
748 name = obj_ptr->name;
749
750 /* If this is the player then add score */
751 if(scene->player_obj_ptr == obj_ptr)
752 {
753 sar_player_stat_struct *pstat = SARPlayerStatCurrent(
754 core_ptr, NULL
755 );
756 if(pstat != NULL)
757 {
758 pstat->score += SAR_POINTS_VICTIM_PICKED_UP * hoisted_in;
759 name = pstat->name;
760 }
761 }
762
763 /* Log human picked up event */
764 s = (char *)malloc((80 + STRLEN(name)) * sizeof(char));
765 sprintf(
766 s,
767 "%s picked up %i passenger%s",
768 name,
769 hoisted_in,
770 (hoisted_in == 1) ? "" : "s"
771 );
772 SARMissionLogEvent(
773 core_ptr, mission,
774 SAR_MISSION_LOG_EVENT_PICKUP,
775 -1.0,
776 &obj_ptr->pos,
777 NULL, 0,
778 s,
779 fname.mission_log
780 );
781 free(s);
782
783 /* Handle by current objective type */
784 switch(objective->type)
785 {
786 /* Only need to check for objectives of type
787 * SAR_MISSION_OBJECTIVE_PICK_UP since they get passed the
788 * instant all humans have been picked up.
789 */
790 case SAR_MISSION_OBJECTIVE_PICK_UP:
791 /* Reduce number of humans that still need rescue, note that
792 * we do not care which object hoisted in these humans.
793 */
794 objective->humans_need_rescue -= hoisted_in;
795
796 /* All humans picked up? */
797 if(objective->humans_need_rescue <= 0)
798 {
799 /* This objective has been passed with success, call
800 * procedure to go on to the next objective.
801 */
802 SARMissionDoObjectiveSuccess(mission, scene);
803 }
804 break;
805 }
806 }
807
808 /*
809 * Passengers enter notify, this function should be called
810 * whenever a number of people have volentarly (not hoisted in)
811 * entered the object specified by obj_ptr.
812 *
813 * The value passengers_entered indicates how many passengers
814 * entered the given object (since the object's current passenger
815 * count is not checked).
816 */
SARMissionPassengersEnterNotify(sar_core_struct * core_ptr,sar_object_struct * obj_ptr,int passengers_entered)817 void SARMissionPassengersEnterNotify(
818 sar_core_struct *core_ptr, sar_object_struct *obj_ptr,
819 int passengers_entered /* Number of passengers entered */
820 )
821 {
822 char *s;
823 const char *name;
824 sar_mission_objective_struct *objective;
825 sar_mission_struct *mission = core_ptr->mission;
826 sar_scene_struct *scene = core_ptr->scene;
827 const sar_option_struct *opt = &core_ptr->option;
828 if((scene == NULL) || (mission == NULL) || (obj_ptr == NULL) ||
829 (passengers_entered <= 0)
830 )
831 return;
832
833 if(opt->runtime_debug)
834 printf(
835 "SARMissionPassengersEnterNotify(): Got enter notify for object \"%s\" for %i humans.\n",
836 obj_ptr->name, passengers_entered
837 );
838
839 /* Get current mission objective, return if there isn't one */
840 objective = SARMissionObjectiveGetCurrentPtr(mission);
841 if(objective == NULL)
842 return;
843
844 name = obj_ptr->name;
845
846 /* If this is the player then add score */
847 if(scene->player_obj_ptr == obj_ptr)
848 {
849 sar_player_stat_struct *pstat = SARPlayerStatCurrent(
850 core_ptr, NULL
851 );
852 if(pstat != NULL)
853 {
854 pstat->score += SAR_POINTS_VICTIM_PICKED_UP * passengers_entered;
855 name = pstat->name;
856 }
857 }
858
859 /* Log human enter event */
860 s = (char *)malloc((80 + STRLEN(name)) * sizeof(char));
861 sprintf(
862 s,
863 "%s picked up %i passenger%s",
864 name,
865 passengers_entered,
866 (passengers_entered == 1) ? "" : "s"
867 );
868 SARMissionLogEvent(
869 core_ptr, mission,
870 SAR_MISSION_LOG_EVENT_PICKUP,
871 -1.0,
872 &obj_ptr->pos,
873 NULL, 0,
874 s,
875 fname.mission_log
876 );
877 free(s);
878
879 /* Handle by current objective type */
880 switch(objective->type)
881 {
882 /* Only need to check for objectives of type
883 * SAR_MISSION_OBJECTIVE_PICK_UP since they get passed the
884 * instant all humans have been picked up.
885 */
886 case SAR_MISSION_OBJECTIVE_PICK_UP:
887 /* Reduce number of humans that still need rescue, note that
888 * we do not care which object hoisted in these humans.
889 */
890 objective->humans_need_rescue -= passengers_entered;
891
892 /* All humans picked up? */
893 if(objective->humans_need_rescue <= 0)
894 {
895 /* This objective has been passed with success, call
896 * procedure to go on to the next objective.
897 */
898 SARMissionDoObjectiveSuccess(mission, scene);
899 }
900 break;
901 }
902 }
903
904 /*
905 * Passengers leave notify, this function should be called
906 * whenever the given object safely lets off passengers.
907 *
908 * The value passengers_left indicates how many passengers
909 * left the given object (since the object's current passenger
910 * count is not checked).
911 */
SARMissionPassengersLeaveNotify(sar_core_struct * core_ptr,sar_object_struct * obj_ptr,int passengers_left)912 void SARMissionPassengersLeaveNotify(
913 sar_core_struct *core_ptr, sar_object_struct *obj_ptr,
914 int passengers_left /* Number of passengers that left */
915 )
916 {
917 sar_mission_struct *mission = core_ptr->mission;
918 if((mission == NULL) || (obj_ptr == NULL))
919 return;
920
921 /* This is not implemented yet, when it does however it will check if
922 * the number of passengers let off meets the mission requirements
923 * (if this is a rescue mission) and in which case then mark the
924 * mission as successfully ended.
925 */
926
927 }
928
929 /*
930 * Land notify callback, this function should be called whenever an
931 * object specified by obj_ptr has landed.
932 *
933 * The ground_contact is an array of object indices that are the
934 * indices of objects that the given object has landed on. This value
935 * can be NULL if there are no objects that the given object has
936 * landed on.
937 */
SARMissionLandNotify(sar_core_struct * core_ptr,sar_object_struct * obj_ptr,const int * ground_contact,int total_ground_contacts)938 void SARMissionLandNotify(
939 sar_core_struct *core_ptr, sar_object_struct *obj_ptr,
940 const int *ground_contact, int total_ground_contacts
941 )
942 {
943 int passengers_unloaded;
944 sar_mission_objective_struct *objective;
945 sar_mission_struct *mission = core_ptr->mission;
946 sar_scene_struct *scene = core_ptr->scene;
947 const sar_option_struct *opt = &core_ptr->option;
948 if((scene == NULL) || (mission == NULL) || (obj_ptr == NULL))
949 return;
950
951 if(opt->runtime_debug)
952 printf(
953 "SARMissionLandNotify(): Got land notify for object \"%s\".\n",
954 obj_ptr->name
955 );
956
957 /* Get current mission objective, return if there isn't one */
958 objective = SARMissionObjectiveGetCurrentPtr(mission);
959 if(objective == NULL)
960 return;
961
962 #define ACCOUNT_PASSENGERS_DROPPED(i) \
963 { if(obj_ptr != NULL) { \
964 char *s; \
965 const char *name = obj_ptr->name; \
966 \
967 /* Add score if this is the player */ \
968 if(scene->player_obj_ptr == obj_ptr) \
969 { \
970 sar_player_stat_struct *pstat = SARPlayerStatCurrent(core_ptr, NULL); \
971 if(pstat != NULL) \
972 { \
973 pstat->rescues += i; \
974 pstat->score += SAR_POINTS_VICTIM_RESCUED * i; \
975 name = pstat->name; \
976 } \
977 } \
978 \
979 /* Log the number of passengers dropped */ \
980 s = (char *)malloc( \
981 (256 + STRLEN(obj_ptr->name)) * sizeof(char) \
982 ); \
983 sprintf( \
984 s, \
985 "%s dropped off %i passenger%s", \
986 name, i, (i == 1) ? "" : "s" \
987 ); \
988 SARMissionLogEvent( \
989 core_ptr, mission, \
990 SAR_MISSION_LOG_EVENT_DROPOFF, \
991 -1.0f, \
992 (obj_ptr != NULL) ? &obj_ptr->pos : NULL, \
993 NULL, 0, \
994 s, \
995 fname.mission_log \
996 ); \
997 free(s); \
998 } }
999
1000 /* Handle by current objective type */
1001 switch(objective->type)
1002 {
1003 case SAR_MISSION_OBJECTIVE_ARRIVE_AT:
1004 /* Not landed at right place? */
1005 if(!SARMissionGroundContactMatchName(
1006 core_ptr, scene,
1007 core_ptr->object, core_ptr->total_objects,
1008 ground_contact, total_ground_contacts,
1009 objective->arrive_at_name
1010 ))
1011 break;
1012
1013 /* Unload passengers */
1014 /* We may need to do a more prettier unload and also check for when
1015 * exactly the passengers are actually unloaded
1016 */
1017 passengers_unloaded = SARSimOpPassengersUnloadAll(
1018 scene, obj_ptr
1019 );
1020 if(passengers_unloaded > 0)
1021 {
1022 ACCOUNT_PASSENGERS_DROPPED(passengers_unloaded);
1023 }
1024
1025 /* Is the given object the player object? */
1026 if((scene->player_obj_ptr == obj_ptr) &&
1027 (objective->state == SAR_MISSION_OBJECTIVE_STATE_INCOMPLETE) &&
1028 (mission->state == MISSION_STATE_IN_PROGRESS)
1029 )
1030 {
1031 /* This objective has been passed with success, call
1032 * procedure to go on to the next objective.
1033 */
1034 SARMissionDoObjectiveSuccess(mission, scene);
1035 }
1036 break;
1037
1038 case SAR_MISSION_OBJECTIVE_PICK_UP:
1039 /* Skip this case, since it has no arrive at object there
1040 * is no way to check if landed at the correct place.
1041 * Do not unload passengers either.
1042 */
1043 break;
1044
1045 case SAR_MISSION_OBJECTIVE_PICK_UP_ARRIVE_AT:
1046 /* Landed at the right place? */
1047 if(SARMissionGroundContactMatchName(
1048 core_ptr, scene,
1049 core_ptr->object, core_ptr->total_objects,
1050 ground_contact, total_ground_contacts,
1051 objective->arrive_at_name
1052 ))
1053 {
1054 int *passengers = NULL,
1055 *total_passengers = NULL;
1056 int passengers_onboard;
1057
1058 /* Get number of passengers on board the given object,
1059 * note that the given object may not be the player object
1060 * but it is okay because any object is accepted to unload
1061 * passengers for this kind of objective
1062 */
1063 SARObjGetOnBoardPtr(
1064 obj_ptr,
1065 NULL, &passengers, &total_passengers,
1066 NULL,
1067 NULL, NULL
1068 );
1069 passengers_onboard = ((passengers != NULL) ?
1070 *passengers : 0
1071 );
1072
1073 /* Unload passengers */
1074 /* We may need to do a more prettier unload, letting passengers leave
1075 * and also check for *when* passengers have all left (but not in this
1076 * land notify function)
1077 */
1078 passengers_unloaded = SARSimOpPassengersUnloadAll(
1079 scene, obj_ptr
1080 );
1081 if(passengers_unloaded > 0)
1082 {
1083 ACCOUNT_PASSENGERS_DROPPED(passengers_unloaded);
1084 }
1085
1086 /* Reduce number of humans that need rescue on the
1087 * objective structure
1088 */
1089 objective->humans_need_rescue -= passengers_onboard;
1090
1091 /* If no more humans need rescue then this objective is
1092 * done and will be marked as success
1093 */
1094 if((objective->humans_need_rescue <= 0) &&
1095 (objective->state == SAR_MISSION_OBJECTIVE_STATE_INCOMPLETE) &&
1096 (mission->state == MISSION_STATE_IN_PROGRESS)
1097 )
1098 {
1099 /* This objective has been passed with success, call
1100 * procedure to go on to the next objective.
1101 */
1102 SARMissionDoObjectiveSuccess(mission, scene);
1103 }
1104 }
1105 break;
1106
1107 } /* Handle by current objective type */
1108
1109 #undef ACCOUNT_PASSENGERS_DROPPED
1110 }
1111
1112
1113 /*
1114 * Manages the given mission objective. This function should be
1115 * called from SARMissionManage().
1116 */
SARMissionObjectiveManage(sar_core_struct * core_ptr,sar_mission_struct * mission,sar_mission_objective_struct * objective)1117 static void SARMissionObjectiveManage(
1118 sar_core_struct *core_ptr, sar_mission_struct *mission,
1119 sar_mission_objective_struct *objective
1120 )
1121 {
1122 int player_obj_num;
1123 sar_object_struct *player_obj_ptr;
1124 sar_scene_struct *scene = core_ptr->scene;
1125 const sar_option_struct *opt = &core_ptr->option;
1126 if((scene == NULL) || (mission == NULL) || (objective == NULL))
1127 return;
1128
1129 /* Get pointer to player object */
1130 player_obj_num = scene->player_obj_num;
1131 player_obj_ptr = scene->player_obj_ptr;
1132
1133 /* Handle by objective type */
1134 switch(objective->type)
1135 {
1136 case SAR_MISSION_OBJECTIVE_ARRIVE_AT:
1137 /* Is there a time limit? */
1138 if(objective->time_left > 0.0f)
1139 {
1140 /* Reduce time left */
1141 objective->time_left -= (float)lapsed_millitime *
1142 time_compression / 1000.0f;
1143
1144 /* Time limit exceeded? */
1145 if(objective->time_left <= 0.0f)
1146 {
1147 if(opt->runtime_debug)
1148 printf(
1149 "SARMissionObjectiveManage(): Mission objective time expired to arrive.\n"
1150 );
1151
1152 /* Time limit exceeded and did not reach arrive at
1153 * object. Mark this objective as failed and go on to
1154 * the next objective or possibly fail entire mission.
1155 */
1156 SARMissionDoObjectiveFailed(mission, scene);
1157 }
1158 }
1159 break;
1160
1161 case SAR_MISSION_OBJECTIVE_PICK_UP:
1162 /* Is there a time limit? */
1163 if(objective->time_left > 0.0f)
1164 {
1165 /* Reduce time left */
1166 objective->time_left -= (float)lapsed_millitime *
1167 time_compression / 1000.0f;
1168
1169 /* Time limit exceeded? */
1170 if(objective->time_left <= 0.0f)
1171 {
1172 /* Time limit has exceeded, check if all humans that
1173 * still need to be brought to safety are in the
1174 * player object.
1175 */
1176 int passengers = SARMissionGetObjectPassengers(
1177 core_ptr, player_obj_ptr
1178 );
1179 if((objective->humans_need_rescue - passengers) > 0)
1180 {
1181 if(opt->runtime_debug)
1182 printf(
1183 "SARMissionObjectiveManage(): Mission objective time expired to pick up.\n"
1184 );
1185
1186 /* There are still more unpicked up humans out
1187 * there. Mark this objective as failed and go on
1188 * to the next objective or possibly fail entire
1189 * mission.
1190 */
1191 SARMissionDoObjectiveFailed(mission, scene);
1192 }
1193 }
1194 }
1195 break;
1196
1197 case SAR_MISSION_OBJECTIVE_PICK_UP_ARRIVE_AT:
1198 /* Is there a time limit? */
1199 if(objective->time_left > 0.0f)
1200 {
1201 /* Reduce time left */
1202 objective->time_left -= (float)lapsed_millitime *
1203 time_compression / 1000.0f;
1204
1205 /* Time limit exceeded? */
1206 if(objective->time_left <= 0.0f)
1207 {
1208 if(opt->runtime_debug)
1209 printf(
1210 "SARMissionObjectiveManage(): Mission objective time expired to pick up and arrive.\n"
1211 );
1212
1213 /* Time limit exceeded and not all have been rescued
1214 * and brought to safety. Mark this objective as
1215 * failed and go on to the next objective or possibly
1216 * fail entire mission.
1217 */
1218 SARMissionDoObjectiveFailed(mission, scene);
1219 }
1220 }
1221 break;
1222 }
1223 }
1224
1225 /*
1226 * Manages mission, this function should be called once per loop.
1227 *
1228 * Return codes are as follows:
1229 *
1230 * -1 Error.
1231 * 0 Nothing happened or not time to manage.
1232 * 1 Mission end success.
1233 * 2 Mission end failure.
1234 */
SARMissionManage(sar_core_struct * core_ptr)1235 int SARMissionManage(sar_core_struct *core_ptr)
1236 {
1237 sar_mission_struct *mission = core_ptr->mission;
1238 sar_mission_objective_struct *objective;
1239 if(mission == NULL)
1240 return(-1);
1241
1242 /* Update time spent on mission */
1243 mission->time_spent += (float)lapsed_millitime *
1244 time_compression / 1000.0f;
1245
1246 /* Not time to manage mission yet? */
1247 if(mission->next_check > cur_millitime)
1248 {
1249 /* Skip and return success */
1250 return(0);
1251 }
1252 else
1253 {
1254 /* Yes its time to check mission status */
1255
1256 /* Schedual next time to check mission.
1257 *
1258 * Note that mission->next_check may be modified again by
1259 * one of the mission manage handler functions farther
1260 * below.
1261 */
1262 mission->next_check = cur_millitime + mission->check_int;
1263 }
1264
1265 /* Get current mission objective */
1266 objective = SARMissionObjectiveGetCurrentPtr(mission);
1267
1268
1269 /* Mission no longer in progress? */
1270 if((mission->state != MISSION_STATE_IN_PROGRESS) ||
1271 (objective == NULL)
1272 )
1273 {
1274 /* Check the resulting state of the mission */
1275 switch(mission->state)
1276 {
1277 case MISSION_STATE_ACCOMPLISHED:
1278 return(1);
1279 break;
1280
1281 case MISSION_STATE_FAILED:
1282 return(2);
1283 break;
1284
1285 default:
1286 /* Unsupported mission state, return error */
1287 fprintf(
1288 stderr,
1289 "SARMissionManage(): Unsupported mission state %i, returning as error.\n",
1290 mission->state
1291 );
1292 return(-1);
1293 break;
1294 }
1295 }
1296
1297 /* Mission still in progress, manage current mission objective */
1298 SARMissionObjectiveManage(core_ptr, mission, objective);
1299
1300 return(0);
1301 }
1302