home *** CD-ROM | disk | FTP | other *** search
/ Freelog Special Issue 2 / Freelog_HS_3_Setp_Oct_Nov_2000_CD2.mdx / Arcade / Orbit / src / mission.c < prev    next >
C/C++ Source or Header  |  1999-09-19  |  24KB  |  1,197 lines

  1. /*
  2.  
  3. ORBIT, a freeware space combat simulator
  4. Copyright (C) 1999  Steve Belczyk <steve1@genesis.nred.ma.us>
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20. */
  21.  
  22. #include "orbit.h"
  23.  
  24. /* File descriptor stack */
  25. #define NFDS (16)
  26. FILE *fd[NFDS];
  27. int sp;
  28.  
  29. char token[128], tokens[10][128];
  30. int iact;
  31. int planet_index;
  32. int weapon_index;
  33.  
  34. int TAflag;
  35. #define TRIGGER 0
  36. #define ACTION 1
  37.  
  38. ReadMission (msn)
  39. char *msn;
  40. /*
  41.  *  Read a mission file
  42.  */
  43. {
  44.     char fn[128], buf[128];
  45.     int i;
  46.  
  47.     /* Bye if no file name */
  48.     if ( (msn == NULL) || (msn[0] == 0) )
  49.     {
  50.         Mprint ("No mission to load!");
  51.         Log ("ReadMission: No mission to load!");
  52.         return;
  53.     }
  54.  
  55.     /* Construct file name */
  56.     sprintf (fn, "missions/%s", msn);
  57.  
  58.     Log ("ReadMission: reading %s", fn);
  59.  
  60.     /* Init some stuff */
  61.     mission.cursor[0] = mission.cursor[1] = mission.cursor[2] = 0.0;
  62.     mission.verbose = 0;
  63.     strcpy (mission.fn, msn);
  64.     player.score = 0;
  65.     mission.briefing[0] = 0;
  66.     for (i=0; i<10; i++) tokens[i][0] = 0;
  67.     sp = 0;
  68.  
  69.     /* Reset targets, events, weapons and planets, etc; */
  70.     InitTargets();
  71.     ResetEvents();
  72.     InitWeapons();
  73.     ResetPlanets();
  74.     InitWaypoints();
  75.     lock.target = (-1);
  76.  
  77.     /* Open the file */
  78.     if (NULL == (fd[0] = fopen (fn, "r")))
  79.     {
  80.         Log ("ReadMission: Can't open %s", fn);
  81.         sprintf (buf, "Can't open mission file %s", fn);
  82.         Mprint (buf);
  83.         return;
  84.     }
  85.  
  86.     /* Process tokens */
  87.     while (GetToken())
  88.     {
  89.         if (!strcasecmp (token, "cursor")) Cursor();
  90.         else if (!strcasecmp (token, "player")) Player();
  91.         else if (!strcasecmp (token, "waypoint")) Waypoint();
  92.         else if (!strcasecmp (token, "object")) Object();
  93.         else if (!strcasecmp (token, "briefing")) Briefing();
  94.         else if (!strcasecmp (token, "verbose")) mission.verbose = 1;
  95.         else if (!strcasecmp (token, "terse")) mission.verbose = 0;
  96.         else if (!strcasecmp (token, "event")) Event();
  97.         else if (!strcasecmp (token, "planet")) Planet();
  98.         else if (!strcasecmp (token, "weapon")) Weapon();
  99.         else if (!strcasecmp (token, "include")) Include();
  100.         else UnrecognizedToken();
  101.     }
  102.  
  103.     /* Add mission to saved games list */
  104.     AddSave (mission.fn);
  105.  
  106.     /* Show mission briefing */
  107.     Mprint (mission.briefing);
  108.  
  109.     Log ("ReadMission: Done reading mission");
  110. }
  111.  
  112. int GetToken()
  113. /*
  114.  *  Read next token from file
  115.  */
  116. {
  117.     /* Get next token */
  118.     if (1 != fscanf (fd[0], "%s", token))
  119.     {
  120.         fclose (fd[0]);
  121.  
  122.         /* Inside include? */
  123.         if (!PopFD()) return 0;
  124.  
  125.         /* Recurse */
  126.         return (GetToken());
  127.     }
  128.  
  129.     RotateTokens();
  130.  
  131.     /* Start of comment? */
  132.     if (strcasecmp (token, "/*")) return (1);
  133.  
  134.     /* Look for end of comment */
  135.     do
  136.     {
  137.         if (1 != fscanf (fd[0], "%s", token))
  138.         {
  139.             fclose (fd[0]);
  140.  
  141.             /* Inside include? */
  142.             if (!PopFD()) return 0;
  143.         }
  144.         RotateTokens();
  145.     } while (strcasecmp (token, "*/"));
  146.  
  147.     /* Recurse to get next token */
  148.     return (GetToken());        
  149. }
  150.  
  151. RotateTokens()
  152. {
  153.     int i;
  154.  
  155.     for (i=9; i>0; i--) strcpy (tokens[i], tokens[i-1]);
  156.     strcpy (tokens[0], token);
  157. }
  158.  
  159. ShowTokens()
  160. {
  161.     Log ("Recent tokens: %s %s %s %s %s %s %s %s %s %s",
  162.         tokens[9], tokens[8], tokens[7], tokens[6], tokens[5],
  163.         tokens[4], tokens[3], tokens[2], tokens[1], tokens[0]);
  164. }
  165.  
  166. int GetBrace()
  167. /*
  168.  *  Get open brace, error otherwise
  169.  */
  170. {
  171.     if (!GetToken())
  172.     {
  173.         Log ("GetBrace: Unexpected end of file in %s!", mission.fn);
  174.         ShowTokens();
  175.         FinishSound();
  176.         CloseLog();
  177.         exit (0);
  178.     }
  179.  
  180.     if (strcmp (token, "{"))
  181.     {
  182.         Log ("GetBrace: Expected '{', found '%s'", token);
  183.         ShowTokens();
  184.         FinishSound();
  185.         CloseLog();
  186.         exit (0);
  187.     }
  188.  
  189.     return (1);
  190. }
  191.  
  192. int GetRequiredToken()
  193. /*
  194.  *  Get a token, error if EOF
  195.  */
  196. {
  197.     if (!GetToken())
  198.     {
  199.         Log ("GetRequiredToken: Unexpected end of file in %s!", mission.fn);
  200.         ShowTokens();
  201.         FinishSound();
  202.         CloseLog();
  203.         exit (0);
  204.     }
  205. }
  206.  
  207. Cursor()
  208. {
  209.     int xyzflag, relflag;
  210.     double x;
  211.  
  212.     GetBrace();
  213.  
  214.     xyzflag = 0;
  215.  
  216.     while (GetToken())
  217.     {
  218.         if (!strcmp (token, "}")) return;
  219.  
  220.         if ( (token[0] == '+') || (token[0] == '-') ||
  221.              ((token[0] >= '0') && (token[0] <= '9')) )
  222.         {
  223.             /* It's a number */
  224.  
  225.             /* See if abs or relative */
  226.             relflag = 0;
  227.             if (token[0] == '+') relflag = 1;
  228.             if (token[0] == '-') relflag = 1;
  229.  
  230.             sscanf (token, "%lf", &x);
  231.             x = x / KM_TO_UNITS1;
  232.  
  233.             if (relflag)
  234.                 mission.cursor[xyzflag] += x;
  235.             else
  236.                 mission.cursor[xyzflag] = x;
  237.  
  238.             xyzflag = (xyzflag + 1) % 3;
  239.  
  240.             if (mission.verbose)
  241.                 Log ("Set cursor to %lf %lf %lf",
  242.                 mission.cursor[0],
  243.                 mission.cursor[1],
  244.                 mission.cursor[2]);
  245.         }
  246.         else
  247.         {
  248.             /* It's a planet */
  249.             if (!CursorPlanet()) CursorObject();
  250.  
  251.             if (mission.verbose)
  252.             {
  253.                 Log ("Cursor: Setting cursor to %s",
  254.                     token);
  255.                 Log ("Cursor: (Set cursor to %lf %lf %lf)",
  256.                 mission.cursor[0],
  257.                 mission.cursor[1],
  258.                 mission.cursor[2]);
  259.             }
  260.         }
  261.     }
  262. }
  263.  
  264. CursorPlanet()
  265. {
  266.     int p;
  267.  
  268.     for (p=0; p<NPLANETS; p++)
  269.     {
  270.         if (!strcasecmp (token, planet[p].name))
  271.         {
  272.             Vset (mission.cursor, planet[p].pos);
  273.             return 1;
  274.         }
  275.     }
  276.  
  277.     Log ("CursorPlanet: No such planet: %s", token);
  278.     return 0;
  279. }
  280.  
  281. CursorObject()
  282. {
  283.     int t;
  284.  
  285.     for (t=0; t<NTARGETS; t++)
  286.     {
  287.         if (target[t].age > 0.0)
  288.         {
  289.             if (!strcasecmp (token, target[t].name))
  290.             {
  291.                 Vset (mission.cursor, target[t].pos);
  292.                 return 1;
  293.             }
  294.         }
  295.     }
  296.  
  297.     Log ("CursorObject: No such object: %s", token);
  298.     return 0;
  299. }
  300.  
  301. Player()
  302. {
  303.     GetBrace();
  304.  
  305.     mission.player[0] = mission.cursor[0];
  306.     mission.player[1] = mission.cursor[1];
  307.     mission.player[2] = mission.cursor[2];
  308.  
  309.     player.vel[0] = player.vel[1] = player.vel[2] = 0.0;
  310.  
  311.     if (mission.verbose)
  312.         Log ("Player: Set player position to %lf %lf %lf",
  313.         mission.player[0], mission.player[1], mission.player[2]);
  314.  
  315.     Vset (player.pos, mission.player);
  316.  
  317.     while (GetToken())
  318.     {
  319.         if (!strcmp (token, "}")) return;
  320.         else
  321.         {
  322.             UnrecognizedToken();
  323.         }
  324.     }
  325. }
  326.  
  327. Waypoint()
  328. {
  329.     GetBrace();
  330.  
  331.     if (mission.verbose) Log ("Waypoint: Adding waypoint %d", nwaypoints);
  332.     AddWaypoint (mission.cursor);
  333.  
  334.     while (GetToken())
  335.     {
  336.         if (!strcmp (token, "}")) return;
  337.         else
  338.         {
  339.             UnrecognizedToken();
  340.         }
  341.     }
  342. }
  343.  
  344. Briefing()
  345. {
  346.     mission.briefing[0] = 0;
  347.  
  348.     GetBrace();
  349.  
  350.     while (GetToken())
  351.     {
  352.         if (!strcmp (token, "}"))
  353.         {
  354.             if (mission.verbose)
  355.                 Log ("Briefing: %s", mission.briefing);
  356.             return;
  357.         }
  358.         strcat (mission.briefing, " ");
  359.         strcat (mission.briefing, token);
  360.     }
  361. }
  362.  
  363. UnrecognizedToken()
  364. {
  365.     Log ("UnrecognizedToken: Skipping unrecognized token \"%s\" in %s",
  366.         token, mission.fn);
  367.     ShowTokens();
  368. }
  369.  
  370. Object()
  371. {
  372.     int t;
  373.  
  374.     GetBrace();
  375.  
  376.     /* Find an unused target */
  377.     t = FindTarget();
  378.  
  379.     if (mission.verbose) Log ("Object: Creating object %d", t);
  380.  
  381.     /* Set it up */
  382.     Vset (target[t].pos, mission.cursor);
  383.     target[t].age = 0.1;
  384.     target[t].view[0] = 1.0;
  385.     target[t].view[1] = target[t].view[2] = 0.0;
  386.  
  387.     target[t].hidden = 0;
  388.     target[t].invisible = 0;
  389.  
  390.     target[t].up[0] = 0.0;
  391.     target[t].up[1] = 0.0;
  392.     target[t].up[2] = 1.0;
  393.  
  394.     target[t].strategy = STRAT_DONOTHING;
  395.     target[t].friendly = 0;
  396.     target[t].weapon = NPLAYER_WEAPONS;
  397.  
  398.     Crossp (target[t].right, target[t].up, target[t].view);
  399.  
  400.     target[t].vel[0] = target[t].vel[1] = target[t].vel[2] = 0.0;
  401.  
  402.     target[t].move_forward = target[t].move_backward =
  403.         target[t].move_up = target[t].move_down =
  404.         target[t].move_pitchleft = target[t].move_pitchright =
  405.         target[t].move_left = target[t].move_right = 0.0;
  406.  
  407.     target[t].model = 0;
  408.     target[t].list = model[0].list;
  409.     target[t].score = 0;
  410.     strcpy (target[t].name, model[0].name);
  411.  
  412.     target[t].maxshields = 100.0;
  413.     target[t].shieldregen = SHIELD_REGEN;
  414.     target[t].turnrate = 0.3;
  415.     target[t].maxvel = 0.01;
  416.  
  417.     while (GetToken())
  418.     {
  419.         if (!strcmp (token, "}")) return;
  420.  
  421.         if (!strcasecmp (token, "model")) ObjModel (t);
  422.         else if (!strcasecmp (token, "score")) ObjScore (t);
  423.         else if (!strcasecmp (token, "strategy")) ObjStrategy (t);
  424.         else if (!strcasecmp (token, "name")) ObjName (t);
  425.         else if (!strcasecmp (token, "hidden")) ObjHidden (t);
  426.         else if (!strcasecmp (token, "weapon")) ObjWeapon (t);
  427.         else if (!strcasecmp (token, "friendly")) ObjFriendly (t);
  428.         else if (!strcasecmp (token, "maxshields")) ObjMaxshields (t);
  429.         else if (!strcasecmp (token, "shieldregen")) ObjShieldregen (t);
  430.         else if (!strcasecmp (token, "turnrate")) ObjTurnrate (t);
  431.         else if (!strcasecmp (token, "speed")) ObjSpeed (t);
  432.         else if (!strcasecmp (token, "invisible")) ObjInvisible (t);
  433.         else UnrecognizedToken ();
  434.     }
  435. }
  436.  
  437. ObjMaxshields (t)
  438. int t;
  439. {
  440.     GetRequiredToken();
  441.     target[t].maxshields = atof (token);
  442.     target[t].shields = target[t].maxshields;
  443.  
  444.     if (mission.verbose)
  445.         Log ("ObjMaxshields: Object %d shields set to %lf", t, target[t].shields);
  446. }
  447.  
  448. ObjShieldregen (t)
  449. int t;
  450. {
  451.     GetRequiredToken();
  452.     target[t].shieldregen = atof (token);
  453.  
  454.     if (mission.verbose)
  455.         Log ("ObjShieldregen: Object %d regen set to %lf", t, target[t].shieldregen);
  456. }
  457.  
  458. ObjTurnrate (t)
  459. int t;
  460. {
  461.     GetRequiredToken();
  462.     target[t].turnrate = atof (token);
  463.  
  464.     if (mission.verbose)
  465.         Log ("ObjTurnrate: Object %d turnrate set to %lf", t, target[t].turnrate);
  466. }
  467.  
  468. ObjSpeed (t)
  469. int t;
  470. {
  471.     GetRequiredToken();
  472.     target[t].maxvel = atof (token);
  473.  
  474.     if (mission.verbose)
  475.         Log ("ObjSpeed: Object %d speed set to %lf", t, target[t].maxvel);
  476. }
  477.  
  478. ObjModel (t)
  479. int t;
  480. {
  481.     int m;
  482.  
  483.     GetRequiredToken();
  484.  
  485.     m = LoadModel (token);
  486.     target[t].model = m;
  487.     if (m == (-1))
  488.     {
  489.         Log ("ObjModel: Couldn't open model %s", token);
  490.     }
  491.     else
  492.     {
  493.         target[t].list = model[m].list;
  494.     }
  495.  
  496.     if (mission.verbose)
  497.         Log ("ObjModel: Object %d model set to %s", t, model[m].name);
  498. }
  499.  
  500. ObjScore (t)
  501. int t;
  502. {
  503.     GetRequiredToken();
  504.  
  505.     sscanf (token, "%d", &target[t].score);
  506.  
  507.     if (mission.verbose) Log ("ObjScore: Object %d score is %d",
  508.                     t, target[t].score);
  509. }
  510.  
  511. ObjName (t)
  512. {
  513.     GetRequiredToken();
  514.  
  515.     strcpy (target[t].name, token);
  516.  
  517.     if (mission.verbose) Log ("ObjName: Object %d named \"%s\"",
  518.                     t, target[t].name);
  519. }
  520.  
  521. ObjStrategy (t)
  522. int t;
  523. {
  524.     GetRequiredToken();
  525.  
  526.     if (mission.verbose)
  527.         Log ("ObjStrategy: Setting object %d strategy to %s", t, token);
  528.  
  529.     if (!strcasecmp (token, "sit1"))
  530.     {
  531.         target[t].strategy = STRAT_SIT1;
  532.     }
  533.     else if (!strcasecmp (token, "sit2"))
  534.     {
  535.         target[t].strategy = STRAT_SIT2;
  536.     }
  537.     else if (!strcasecmp (token, "sit3"))
  538.     {
  539.         target[t].strategy = STRAT_SIT3;
  540.     }
  541.     else if (!strcasecmp (token, "sit4"))
  542.     {
  543.         target[t].strategy = STRAT_SIT4;
  544.     }
  545.     else if (!strcasecmp (token, "hunt1"))
  546.     {
  547.         target[t].strategy = STRAT_HUNT1;
  548.     }
  549.     else if (!strcasecmp (token, "hunt2"))
  550.     {
  551.         target[t].strategy = STRAT_HUNT2;
  552.     }
  553.     else if (!strcasecmp (token, "hunt3"))
  554.     {
  555.         target[t].strategy = STRAT_HUNT3;
  556.     }
  557.     else if (!strcasecmp (token, "hunt4"))
  558.     {
  559.         target[t].strategy = STRAT_HUNT4;
  560.     }
  561.     else if (!strcasecmp (token, "donothing"))
  562.     {
  563.         target[t].strategy = STRAT_DONOTHING;
  564.     }
  565.     else
  566.     {
  567.         Log ("ObjStrategy: No such strategy: %s", token);
  568.     }
  569. }
  570.  
  571. ObjHidden (t)
  572. int t;
  573. {
  574.     target[t].hidden = 1;
  575.  
  576.     if (mission.verbose)
  577.         Log ("ObjHidden: Object %d is hidden", t);
  578. }
  579.  
  580. ObjInvisible (t)
  581. int t;
  582. {
  583.     target[t].invisible = 1;
  584.  
  585.     if (mission.verbose)
  586.         Log ("ObjInvisible: Object %d is invisible", t);
  587. }
  588.  
  589. ObjFriendly (t)
  590. int t;
  591. {
  592.     target[t].friendly = 1;
  593.  
  594.     if (mission.verbose)
  595.         Log ("ObjFriendly: Object %d is friendly", t);
  596. }
  597.  
  598. ObjWeapon (t)
  599. int t;
  600. {
  601.     GetRequiredToken();
  602.     target[t].weapon = atoi (token);
  603.     if ( (target[t].weapon >= NWEAPONS) ||
  604.          (target[t].weapon < 0) )
  605.         target[t].weapon = 0;
  606.  
  607.     if (mission.verbose)
  608.         Log ("ObjWeapon: Object %d weapon set to %d", t, target[t].weapon);
  609. }
  610.  
  611. Event()
  612. {
  613.     int e, a;
  614.  
  615.     GetBrace();
  616.  
  617.     /* Find an unused event entry */
  618.     e = FindEvent();
  619.  
  620.     if (mission.verbose) Log ("Event: Creating event %d", e);
  621.  
  622.     /* Index to next action */
  623.     iact = (-1);
  624.  
  625.     /* Values for triggers or actions? */
  626.     TAflag = TRIGGER;
  627.  
  628.     /* Set up some stuff */
  629.     event[e].name[0] = 0;
  630.     event[e].enabled = 1;
  631.     event[e].trigger = EVENT_NULL;
  632.     Vset (event[e].pos, mission.cursor);
  633.     event[e].ivalue = 0;
  634.     event[e].fvalue = 0.0;
  635.     for (a=0; a<ACTIONS_PER_EVENT; a++)
  636.     {
  637.         event[e].action[a].active = 0;
  638.         event[e].action[a].action = EVENT_NULL;
  639.         event[e].action[a].ivalue = 0;
  640.         event[e].action[a].fvalue = 0.0;
  641.     }
  642.  
  643.     /* Process rest of event tokens */
  644.     while (1)
  645.     {
  646.         GetRequiredToken();
  647.         if (!strcmp (token, "}"))
  648.         {
  649.             /* Convert units if this is Approach or Depart */
  650.             if ( (event[e].trigger == EVENT_APPROACH) ||
  651.                  (event[e].trigger == EVENT_STOPNEAR) ||
  652.                  (event[e].trigger == EVENT_DEPART) )
  653.             {
  654.                 event[e].fvalue /= KM_TO_UNITS1;
  655.             }
  656.  
  657.             /* Shields is weird, has a text and floating value */
  658.             if (event[e].trigger == EVENT_SHIELDS)
  659.             {
  660.                 sscanf (event[e].cvalue, "%*s %lf", &event[e].fvalue);
  661.                 sscanf (event[e].cvalue, "%s", event[e].cvalue);
  662.                 if (mission.verbose)
  663.                     Log ("Event: EVENT_SHIELDS target %s value %lf",
  664.                         event[e].cvalue, event[e].fvalue);
  665.             }
  666.  
  667.             return;
  668.         }
  669.  
  670.         if (!strcasecmp (token, "trigger")) EvTrigger (e);
  671.         else if (!strcasecmp (token, "name")) EvName (e);
  672.         else if (!strcasecmp (token, "action")) EvAction (e);
  673.         else if (!strcasecmp (token, "value")) EvValue (e);
  674.         else if (!strcasecmp (token, "enabled")) event[e].enabled = 1;
  675.         else if (!strcasecmp (token, "disabled")) event[e].enabled = 0;
  676.         else UnrecognizedToken ();
  677.     }
  678. }
  679.  
  680. EvName (e)
  681. int e;
  682. {
  683.     GetRequiredToken();
  684.     strcpy (event[e].name, token);
  685.  
  686.     if (mission.verbose)
  687.         Log ("EvName: Event %d named %s", e, token);
  688. }
  689.  
  690. EvTrigger (e)
  691. int e;
  692. {
  693.     GetRequiredToken();
  694.  
  695.     TAflag = TRIGGER;
  696.  
  697.     if (mission.verbose)
  698.         Log ("EvTrigger: Setting event %d trigger to %s", e, token);
  699.  
  700.     if (!strcasecmp (token, "approach")) event[e].trigger = EVENT_APPROACH;
  701.     else if (!strcasecmp (token, "depart")) event[e].trigger = EVENT_DEPART;
  702.     else if (!strcasecmp (token, "true")) event[e].trigger = EVENT_TRUE;
  703.     else if (!strcasecmp (token, "score")) event[e].trigger = EVENT_SCORE;
  704.     else if (!strcasecmp (token, "destroy")) event[e].trigger = EVENT_DESTROY;
  705.     else if (!strcasecmp (token, "alarm")) event[e].trigger = EVENT_ALARM;
  706.     else if (!strcasecmp (token, "stopnear")) event[e].trigger = EVENT_STOPNEAR;
  707.     else if (!strcasecmp (token, "shields")) event[e].trigger = EVENT_SHIELDS;
  708.     else UnrecognizedToken();
  709. }
  710.  
  711. EvAction (e)
  712. int e;
  713. {
  714.     /* Bump action index */
  715.     iact++;
  716.     if (iact >= ACTIONS_PER_EVENT)
  717.     {
  718.         Log ("EvAction: Too many actions in event %d!", e);
  719.         iact--;
  720.     }
  721.  
  722.     event[e].action[iact].active = 1;
  723.  
  724.     TAflag = ACTION;
  725.  
  726.     GetRequiredToken();
  727.  
  728.     if (mission.verbose)
  729.         Log ("EvAction: Setting event %d.%d action to %s", e, iact, token);
  730.  
  731.     if (!strcasecmp (token, "message")) event[e].action[iact].action = EVENT_MESSAGE;
  732.     else if (!strcasecmp (token, "hide")) event[e].action[iact].action = EVENT_HIDE;
  733.     else if (!strcasecmp (token, "unhide")) event[e].action[iact].action = EVENT_UNHIDE;
  734.     else if (!strcasecmp (token, "destroy")) event[e].action[iact].action = EVENT_DESTROY;
  735.     else if (!strcasecmp (token, "score")) event[e].action[iact].action = EVENT_SCORE;
  736.     else if (!strcasecmp (token, "enable")) event[e].action[iact].action = EVENT_ENABLE;
  737.     else if (!strcasecmp (token, "disable")) event[e].action[iact].action = EVENT_DISABLE;
  738.     else if (!strcasecmp (token, "loadmission")) event[e].action[iact].action = EVENT_LOADMISSION;
  739.     else if (!strcasecmp (token, "stop")) event[e].action[iact].action = EVENT_STOP;
  740.     else if (!strcasecmp (token, "boom")) event[e].action[iact].action = EVENT_BOOM;
  741.     else if (!strcasecmp (token, "flash")) event[e].action[iact].action = EVENT_FLASH;
  742.     else if (!strcasecmp (token, "moveobject")) event[e].action[iact].action = EVENT_MOVEOBJECT;
  743.     else if (!strcasecmp (token, "moveplayer")) event[e].action[iact].action = EVENT_MOVEPLAYER;
  744.     else if (!strcasecmp (token, "moveplanet")) event[e].action[iact].action = EVENT_MOVEPLANET;
  745.     else if (!strcasecmp (token, "hideplanet")) event[e].action[iact].action = EVENT_HIDEPLANET;
  746.     else if (!strcasecmp (token, "unhideplanet")) event[e].action[iact].action = EVENT_UNHIDEPLANET;
  747.     else if (!strcasecmp (token, "betray")) event[e].action[iact].action = EVENT_BETRAY;
  748.     else UnrecognizedToken();
  749. }
  750.  
  751. EvValue (e)
  752. int e;
  753. {
  754.     char buf[4096];
  755.  
  756.     GetRequiredToken();
  757.  
  758.     buf[0] = 0;
  759.  
  760.     if (strcmp (token, "{"))
  761.     {
  762.         strcpy (buf, token);
  763.     }
  764.     else
  765.     {
  766.         /* Allow text enclosed in braces */
  767.         while (1)
  768.         {
  769.             GetRequiredToken();
  770.             if (!strcmp (token, "}"))
  771.             {
  772.                 break;
  773.             }
  774.  
  775.             /* Add space if not first one */
  776.             if (0 != buf) strcat (buf, " ");
  777.             strcat (buf, token);
  778.         }
  779.     }
  780.     
  781.     /* Figure out what to do with this value */
  782.     if (TAflag == TRIGGER)
  783.     {
  784.         /* It's the trigger's value */
  785.         if (NULL == (event[e].cvalue = (char *) malloc (1+strlen(buf))))
  786.         {
  787.             OutOfMemory();
  788.         }
  789.         strcpy (event[e].cvalue, buf);
  790.         event[e].ivalue = atoi (buf);
  791.         event[e].fvalue = atof (buf);
  792.  
  793.         if (mission.verbose)
  794.             Log ("EvValue: Event %d trigger value set to %s", e, buf);
  795.     }
  796.     else
  797.     {
  798.         /* It's the action's value */
  799.         if (NULL == (event[e].action[iact].cvalue = (char *) malloc (1+strlen(buf))))
  800.         {
  801.             OutOfMemory();
  802.         }
  803.         strcpy (event[e].action[iact].cvalue, buf);
  804.         event[e].action[iact].ivalue = atoi (buf);
  805.         event[e].action[iact].fvalue = atof (buf);
  806.  
  807.         if (mission.verbose)
  808.             Log ("EvValue: Event %d.%d action set to %s", e, iact, buf);
  809.     }
  810. }
  811.  
  812. Weapon()
  813. /*
  814.  *  Handle weapon token
  815.  */
  816. {
  817.     weapon_index = (-1);
  818.  
  819.     GetBrace();
  820.  
  821.     while (GetToken())
  822.     {
  823.         if (!strcmp (token, "}"))
  824.         {
  825.             /* Recompute weapon ranges */
  826.             WeaponRanges();
  827.             return;
  828.         }
  829.  
  830.         if (!strcasecmp (token, "index")) WeaponIndex();
  831.         else if (!strcasecmp (token, "name")) WeaponName();
  832.         else if (!strcasecmp (token, "speed")) WeaponSpeed();
  833.         else if (!strcasecmp (token, "yield")) WeaponYield();
  834.         else if (!strcasecmp (token, "idle")) WeaponIdle();
  835.         else if (!strcasecmp (token, "expire")) WeaponExpire();
  836.         else if (!strcasecmp (token, "renderer")) WeaponRenderer();
  837.         else if (!strcasecmp (token, "color")) WeaponColor();
  838.         else UnrecognizedToken();
  839.     }
  840. }
  841.  
  842. WeaponIndex()
  843. {
  844.     int w;
  845.  
  846.     GetToken();
  847.  
  848.     w = atoi (token);
  849.     if ( (w >= 0) && (w < NWEAPONS) )
  850.     {
  851.         weapon_index = w;
  852.  
  853.         if (mission.verbose)
  854.             Log ("WeaponIndex: Index set to %d", w);
  855.     }
  856. }
  857.  
  858. WeaponName()
  859. {
  860.     GetToken();
  861.  
  862.     if (weapon_index == (-1)) return;
  863.     strcpy (weapon[weapon_index].name, token);
  864.  
  865.     if (mission.verbose)
  866.         Log ("WeaponName: Weapon %d named %s", weapon_index, token);
  867. }
  868.  
  869. WeaponSpeed()
  870. {
  871.     GetToken();
  872.  
  873.     if (weapon_index == (-1)) return;
  874.     weapon[weapon_index].speed = atof (token) / KM_TO_UNITS1;
  875.  
  876.     if (mission.verbose)
  877.         Log ("WeaponSpeed: Weapon %d speed is %lf", weapon_index, weapon[weapon_index].speed);
  878. }
  879.  
  880. WeaponYield()
  881. {
  882.     GetToken();
  883.  
  884.     if (weapon_index == (-1)) return;
  885.     weapon[weapon_index].yield = atof (token);
  886.  
  887.     if (mission.verbose)
  888.         Log ("WeaponYield: Weapon %d yield is %lf", weapon_index, weapon[weapon_index].yield);
  889. }
  890.  
  891. WeaponIdle()
  892. {
  893.     GetToken();
  894.  
  895.     if (weapon_index == (-1)) return;
  896.     weapon[weapon_index].idle = atof (token);
  897.  
  898.     if (mission.verbose)
  899.         Log ("WeaponIdle: Weapon %d idle is %lf", weapon_index, weapon[weapon_index].idle);
  900. }
  901.  
  902. WeaponExpire()
  903. {
  904.     GetToken();
  905.  
  906.     if (weapon_index == (-1)) return;
  907.     weapon[weapon_index].expire = atof (token);
  908.  
  909.     if (mission.verbose)
  910.         Log ("WeaponExpire: Weapon %d expire is %lf", weapon_index, weapon[weapon_index].expire);
  911. }
  912.  
  913. WeaponRenderer()
  914. {
  915.     int r;
  916.  
  917.     GetToken();
  918.  
  919.     if (weapon_index == (-1)) return;
  920.  
  921.     r = atoi (token);
  922.     if ( (r >= 0) && (r < 5) )
  923.     {
  924.         weapon[weapon_index].renderer = r;
  925.  
  926.         if (mission.verbose)
  927.             Log ("WeaponRenderer: Weapon %d renderer set to %d", weapon_index, r);
  928.     }
  929.     else
  930.     {
  931.         Log ("WeaponRenderer: Renderer out of range: %d", r);
  932.     }
  933. }
  934.  
  935. WeaponColor()
  936. {
  937.     int c, r, g, b;
  938.  
  939.     GetToken();
  940.  
  941.     if (weapon_index == (-1)) return;
  942.  
  943.     sscanf (token, "%i", &c);
  944.  
  945.     r = (0xff0000 & c) >> 16;
  946.     g = (0x00ff00 & c) >> 8;
  947.     b = (0x0000ff & c);
  948.     weapon[weapon_index].color[0] = ((float) r) / 256.0;
  949.     weapon[weapon_index].color[1] = ((float) g) / 256.0;
  950.     weapon[weapon_index].color[2] = ((float) b) / 256.0;
  951. }
  952.  
  953. Planet()
  954. /*
  955.  *  Handle the planet token
  956.  */
  957. {
  958.     planet_index = (-1);
  959.  
  960.     GetBrace();
  961.  
  962.     while (GetToken())
  963.     {
  964.         if (!strcmp (token, "}")) return;
  965.  
  966.         if (!strcasecmp (token, "name")) PlanetName();
  967.         else if (!strcasecmp (token, "newname")) PlanetNewname();
  968.         else if (!strcasecmp (token, "reposition")) PlanetReposition();
  969.         else if (!strcasecmp (token, "hidden")) PlanetHidden();
  970.         else if (!strcasecmp (token, "map")) PlanetMap();
  971.         else if (!strcasecmp (token, "oblicity")) PlanetOblicity();
  972.         else if (!strcasecmp (token, "radius")) PlanetRadius();
  973.         else UnrecognizedToken();
  974.     }
  975. }
  976.  
  977. PlanetOblicity()
  978. {
  979.     GetToken();
  980.     if (planet_index == (-1)) return;
  981.  
  982.     planet[planet_index].oblicity = atof (token);
  983.  
  984.     if (mission.verbose)
  985.         Log ("PlanetOblicity: %s oblicity is %lf",
  986.             planet[planet_index].name, planet[planet_index].oblicity);
  987. }
  988.  
  989. PlanetRadius()
  990. {
  991.     int p;
  992.  
  993.     GetToken();
  994.     if (planet_index == (-1)) return;
  995.  
  996.     p = planet_index;
  997.  
  998.     planet[p].radius = atof (token) / KM_TO_UNITS1;
  999.     planet[p].radius2 = planet[p].radius * planet[p].radius;
  1000.     planet[p].mass = planet[p].radius * planet[p].radius2;
  1001.     MakePlanetList (p);
  1002.  
  1003.     if (mission.verbose)
  1004.         Log ("PlanetRadius: %s radius is %lf",
  1005.             planet[planet_index].name, planet[planet_index].radius);
  1006. }
  1007.  
  1008. PlanetMap()
  1009. {
  1010.     GetToken();
  1011.     if (planet_index == (-1)) return;
  1012.  
  1013.     /* Set new texture */
  1014.     strcpy (planet[planet_index].texfname, token);
  1015.     planet[planet_index].custom = 1;
  1016.  
  1017.     /* Define new texture */
  1018.     ReadPlanetTexture (planet_index);
  1019.  
  1020.     if (mission.verbose)
  1021.         Log ("PlanetMap: %s texture map is %s",
  1022.             planet[planet_index].name, planet[planet_index].texfname);
  1023. }
  1024.  
  1025. PlanetHidden()
  1026. {
  1027.     if (planet_index == (-1)) return;
  1028.     planet[planet_index].hidden = 1;
  1029.  
  1030.     if (mission.verbose)
  1031.         Log ("PlanetHidden: %s is hidden", planet[planet_index].name);
  1032. }
  1033.  
  1034. PlanetReposition()
  1035. {
  1036.     if (planet_index == (-1)) return;
  1037.     Vset (planet[planet_index].pos, mission.cursor);
  1038.  
  1039.     if (mission.verbose)
  1040.         Log ("PlanetReposition: %s new position is (%lf,%lf,%lf)",
  1041.             planet[planet_index].name,
  1042.             mission.cursor[0], mission.cursor[1], mission.cursor[2]);
  1043. }
  1044.  
  1045. PlanetName()
  1046. {
  1047.     int p;
  1048.  
  1049.     GetToken();
  1050.  
  1051.     if ((-1) == (p = FindPlanetByName(token)))
  1052.     {
  1053.         Log ("PlanetName: No such planet: %s", token);
  1054.         return;
  1055.     }
  1056.  
  1057.     planet_index = p;
  1058.  
  1059.     if (mission.verbose)
  1060.         Log ("PlanetName: Modifying planet %s (index %d)", token, p);
  1061. }
  1062.  
  1063. PlanetNewname()
  1064. {
  1065.     GetToken();
  1066.     if (planet_index == (-1)) return;
  1067.  
  1068.     strcpy (planet[planet_index].name, token);
  1069.  
  1070.     if (mission.verbose)
  1071.         Log ("PlanetNewname: Planet %d renamed to %s", planet_index, token);
  1072. }
  1073.  
  1074. Include()
  1075. /*
  1076.  *  Open a new include file
  1077.  */
  1078. {
  1079.     char fn[128];
  1080.  
  1081.     GetRequiredToken();
  1082.  
  1083.     Log ("Include: Including file %s", token);
  1084.  
  1085.     /* Construct file name */
  1086.     sprintf (fn, "missions/%s", token);
  1087.  
  1088.     if (!PushFD())
  1089.     {
  1090.         Log ("Include: Can't include file %s", fn);
  1091.         return;
  1092.     }
  1093.  
  1094.     if (NULL == (fd[0] = fopen (fn, "rt")))
  1095.     {
  1096.         Log ("Include: Can't open include file %s", fn);
  1097.         PopFD();
  1098.         return;
  1099.     }
  1100. }
  1101.  
  1102. int PushFD()
  1103. /*
  1104.  *  Push a file descriptor onto the stack
  1105.  */
  1106. {
  1107.     int i;
  1108.  
  1109.     sp++;
  1110.  
  1111.     /* Overflow? */
  1112.     if (sp >= NFDS)
  1113.     {
  1114.         sp--;
  1115.         Log ("PushFD: Include files nested too deeply");
  1116.         return 0;
  1117.     }
  1118.  
  1119.     /* Push stack */
  1120.     for (i=sp; i>0; i--) fd[i] = fd[i-1];
  1121.  
  1122.     return 1;
  1123. }
  1124.  
  1125. int PopFD()
  1126. /*
  1127.  *  Pop and FD off the stack
  1128.  */
  1129. {
  1130.     int i;
  1131.  
  1132.     if (sp == 0) return 0;
  1133.  
  1134.     sp--;
  1135.     for (i=0; i<=sp; i++) fd[i] = fd[i+1];
  1136.  
  1137.     return 1;
  1138. }
  1139.  
  1140. #ifdef WIN32
  1141. int strcasecmp (s1, s2)
  1142. char *s1, *s2;
  1143. {
  1144.     int l1, l2, i;
  1145.     char c1, c2;
  1146.  
  1147.     l1 = strlen (s1);
  1148.     l2 = strlen (s2);
  1149.  
  1150.     if (l1 != l2) return (1);
  1151.     if (l1 == 0) return (0);
  1152.  
  1153.     for (i=0; i<l1; i++)
  1154.     {
  1155.         c1 = tolower (s1[i]);
  1156.         c2 = tolower (s2[i]);
  1157.  
  1158.         if (c1 != c2)
  1159.         {
  1160.             return (1);
  1161.         }
  1162.     }
  1163.  
  1164.     return (0);
  1165. }
  1166.  
  1167. int strncasecmp (s1, s2, n)
  1168. char *s1, *s2;
  1169. int n;
  1170. {
  1171.     int i;
  1172.     char c1, c2;
  1173.  
  1174.     for (i=0; i<n; i++)
  1175.     {
  1176.         c1 = tolower (s1[i]);
  1177.         c2 = tolower (s2[i]);
  1178.  
  1179.         if (c1 != c2)
  1180.         {
  1181.             return (1);
  1182.         }
  1183.     }
  1184.  
  1185.     return (0);
  1186. }
  1187. #endif
  1188.  
  1189. void DoLoad (void)
  1190. /*
  1191.  *  Sparky has typed a mission to load
  1192.  */
  1193. {
  1194.     ReadMission (text.buf);
  1195. }
  1196.  
  1197.