Generated from /home/galaxyng/NG/Source/process.c with ROBODoc v4.0.18 on Mon Jan 05 22:26:08 2004

TABLE OF CONTENTS


GalaxyNG/phase1orders

NAME

   phase1orders -- map of all phase 1 orders.

FUNCTION

   A map that maps an order name to the corresponding function
   that executes the order.  

SOURCE

    orderinfo       phase1orders[] = {
      {"@", &at_order},
      {"=", &eq_order},             /* FS 1999/12 set real name */
      {"a", &a_order},
      {"b", &b_order},
      {"d", &d_order},
      {"e", &e_order},
      {"f", &f_order},
      {"h", &h_order},              /* CB-19980923, to recall (halt) a group */
      {"i", &i_order},
      {"j", &j_order},
      {"l", &l_order},
      {"m", &m_order},
      {"o", &o_order},
      {"p", &p_order},
      {"q", &q_order},
      {"r", &r_order},
      {"s", &s_order},
      {"u", &u_order},
      {"v", &v_order},
      {"w", &w_order},
      {"x", &x_order},
      {"y", &y_order},
      {"z", &z_order},
      {NULL, NULL}
    };
    

GalaxyNG/phase2orders

NAME

   phase2orders -- map of all phase 2 orders.

FUNCTION

   A map that maps an order name to the corresponding function
   that executes the order.  

SOURCE

    orderinfo       phase2orders[] = {
      {"c", &c_order},
      {"g", &g_order},
      {"n", &n_order},
      {"t", &t_order},
      {NULL, NULL}
    };
    

GalaxyNG/mistake

NAME

   mistake -- generate an error message about an order.

FUNCTION

   Dynamically generate an error message and add it to
   the list of mistakes of a player.

SOURCE

    void
    mistake(player *P, enum error_type elevel, strlist *s, char *format, ...)
    {
      int             n;
      va_list         ap;
      char* lformat;
    
      va_start(ap, format);
    
      lformat = (char*)malloc(strlen(format)+4);
    
      switch(elevel) {
      case INFO:
        sprintf(lformat, "+I %s", format);
        break;
    
      case WARNING:
        sprintf(lformat, "+W %s", format);
        break;
    
      case ERROR:
        sprintf(lformat, "+E %s", format);
        break;
      }
    
    #ifdef WIN32
      vsprintf(lineBuffer, format, ap);
    #else
      n = vsnprintf(lineBuffer, LINE_BUFFER_SIZE, lformat, ap);
      assert(n != -1);
    #endif
    
      free(lformat);
    
      va_end(ap);
    
      insertList(&P->orders, s, makestrlist(lineBuffer));
    }
    

GalaxyNG/at_order

NAME

   at_order -- write message to a nation

SOURCE

    void
    at_order(game *aGame, player *P, strlist **s)
    {
      char           *ns;
      alliance       *a;
      alliance       *plist;
      player         *P2;
    
      pdebug(DFULL, "at_order\n");
      ns = getstr(0);               /* for whom is the message */
      if (ns[0]) {
        for (plist = NULL; ns[0]; ns = getstr(0)) {
          if ((P2 = findElement(player, aGame->players, ns))) {
            a = allocStruct(alliance);
    
            a->who = P2;
            addList(&plist, a);
          }
          else
            mistake(P, INFO, *s, "Nation not recognized");
        }
        for (a = plist; a; a = a->next)
          addList(&a->who->messages, makestrlist("-message starts-"));
    
        for (*s = (*s)->next; (*s) && ((*s)->str[0] != '@'); *s = (*s)->next) {
          for (a = plist; a; a = a->next)
            addList(&a->who->messages, makestrlist((*s)->str));
        }
        for (a = plist; a; a = a->next)
          addList(&a->who->messages, makestrlist("-message ends-"));
        freelist(plist);
      }
      else {                        /* Message is global */
        addList(&(aGame->messages), makestrlist("-message starts-"));
    
        for (*s = (*s)->next; (*s) && ((*s)->str[0] != '@'); *s = (*s)->next) {
          addList(&(aGame->messages), makestrlist((*s)->str));
        }
        addList(&(aGame->messages), makestrlist("-message ends-"));
      }
    }
    

GalaxyNG/eq_order

NAME

   eq_order -- set real name

SOURCE

    void
    eq_order(game *aGame, player *P, strlist **s)
    {
      char           *ns;
    
      pdebug(DFULL, "eq_order\n");
      ns = getstr(0);
      if (!ns[0]) {
        mistake(P, INFO, *s, "No name provided.");
        return;
      }
      if (P->realName)
        free(P->realName);
      P->realName = strdup(ns);
    }
    

GalaxyNG/l_order

NAME

   l_order -- load cargo onto a group of ships.

FUNCTION

SOURCE

    void
    l_order(game *aGame, player *P, strlist **s)
    {
      group          *g;
      group          *g2;
      double          x, amount;
      double          y;
      int             amountFlag;
      planet         *p;
      int             numberOfShips;
      int             typeOfCargo;
      char           *ns;
    
      amountFlag = FALSE;
    
      pdebug(DFULL, "l_order\n");
      g = findgroup(P, getstr(0));
      if (!g) {
        mistake(P, ERROR, *s, "Group not recognized.");
        return;
      }
      p = g->where;
    
      typeOfCargo = nametocargotype(getstr(0));
      if (g->type->cargo == 0) {
        mistake(P, ERROR, *s, "Group cannot carry cargo.");
        return;
      }
      if (g->dist) {
        mistake(P, ERROR, *s, "Group is in hyperspace.");
        return;
      }
      if (cargospace(g) <= g->load) {
        /* '<=' is used cause we deal with doubles here */
        mistake(P, ERROR, *s, "Group is fully loaded.");
        return;
      }
      if (typeOfCargo < 0 || typeOfCargo > 2) {
        mistake(P, ERROR, *s, "Cargo type not recognized.");
        return;
      }
      if (g->load && g->loadtype != typeOfCargo) {
        mistake(P, ERROR, *s, "Group is already carrying a different load.");
        return;
      }
      /* Determine the number of ships to load the cargo on */
    
      numberOfShips = g->ships;     /* Start-off with using all ships */
      ns = getstr(0);
      if ((ns[0] != '\0') &&
          (noCaseStrcmp("amount", ns) != 0) && (isdigit(ns[0]))) {
        numberOfShips = atoi(ns);
        if (numberOfShips != 0) {
          if (numberOfShips > g->ships) {
            mistake(P, ERROR, *s, "Not enough ships, all available used.");
            numberOfShips = g->ships;
          }
          if (numberOfShips <= 0) { /* KDW July 1999 */
            mistake(P, ERROR, *s, "You must specify > 0 ships, all available used.");
            numberOfShips = g->ships;
          }
        }
        ns = getstr(0);
      }
      /* Determine the amount of cargo to be loaded per ship */
      if (ns[0] != '\0') {
        if (noCaseStrcmp("amount", ns) == 0) {
          ns = getstr(0);
          if (ns[0] != '\0') {
            amount = atof(ns);
            if (amount > (cargospace(g) - g->load)) {
              mistake(P, ERROR, *s,
                      "Not enough cargo space available to carry this amount.");
              return;
            }
          }
          else {
            mistake(P, ERROR, *s, "Keyword AMOUNT should be followed by a number.");
            return;
          }
        }
        else {
          mistake(P, ERROR, *s, "Expected the keyword AMOUNT.");
          return;
        }
        amountFlag = TRUE;
      }
      else {
        amount = cargospace(g) - g->load;
      }
    
      if (amount < AMOUNTMIN) {
        mistake(P, ERROR, *s,
                "You should load at least %f per ship,"
                " you are trying to loading %f.", AMOUNTMIN, amount);
        return;
      }
      /* Check if the planet has enough of the goods requested. */
    
      switch (typeOfCargo) {
      case CG_CAP:
        y = p->cap;
        break;
      case CG_MAT:
        y = p->mat;
        break;
      case CG_COL:
        y = p->col;
        break;
      }
    
      /* Total amount that has to be uploaded */
      x = amount * numberOfShips;
      if (y == 0.0) {
        mistake(P, ERROR, *s, "No cargo of this type available on \"%s\".", p->name);
        return;
      }
      if (y / numberOfShips < AMOUNTMIN) {
        mistake(P, ERROR, *s,
                "Not enough cargo available on \"%s\" to"
                " load at least %f per ship.", p->name, AMOUNTMIN);
        return;
      }
      if (y < x) {
        if (amountFlag) {
          mistake(P, ERROR, *s,
                  "Not enough cargo available on \"%s\" to"
                  " load %.2f per ship,\nloading %.2f per ship.",
                  p->name, amount, y / numberOfShips);
        }
        amount = y / numberOfShips;
      }
      /* Everything is OK, break of a group, and load cargo */
    
      if (numberOfShips != g->ships) {
        g2 = allocStruct(group);
    
        *g2 = *g;
        g2->next = NULL;
        numberGroup(P, g2);
        g2->name = (char*)malloc(8);
        sprintf(g2->name, "%d", g2->number);
        addList(&P->groups, g2);
        assert(numberOfShips < g->ships);
        g->ships -= numberOfShips;
        g2->ships = numberOfShips;
        g = g2;
      }
      switch (typeOfCargo) {
      case CG_CAP:
        if (y > x)
          y = x;
        g->load += y / g->ships;
        p->cap -= y;
        break;
      case CG_MAT:
        if (y > x)
          y = x;
        g->load += y / g->ships;
        p->mat -= y;
        break;
      case CG_COL:
        if (y > x)
          y = x;
        g->load += y / g->ships;
        p->col -= y;
        break;
      }
      g->loadtype = typeOfCargo;
    }
    

GalaxyNG/u_order

NAME

   u_order -- unload cargo

SOURCE

    void
    u_order(game *aGame, player *P, strlist **s)
    {
      group          *g;
      group          *g2;
      int             numberOfShips;
      double          amount;
      char           *ns;
    
      pdebug(DFULL, "u_order\n");
    
      g = findgroup(P, getstr(0));
      if (!g) {
        mistake(P, ERROR, *s, "Group not recognized.");
        return;
      }
      if (g->loadtype == CG_EMPTY) {
        mistake(P, ERROR, *s, "No cargo on board.");
        return;
      }
      if (g->dist) {
        mistake(P, ERROR, *s, "Group is in hyperspace.");
        return;
      }
      /* Determine how many ships are unloaded */
      numberOfShips = g->ships;     /* Start-of with all ships */
      ns = getstr(0);
      if ((ns[0] != '\0') &&
          (noCaseStrcmp("amount", ns) != 0) && (isdigit(ns[0]))) {
        numberOfShips = atoi(ns);
        if (numberOfShips != 0) {
          if (numberOfShips > g->ships) {
            mistake(P, ERROR, *s, "Not enough ships, all available used.");
            numberOfShips = g->ships;
          }
          if (numberOfShips <= 0) { /* KDW July 1999 */
            mistake(P, ERROR, *s, "You must specify > 0 ships, all available used.");
            numberOfShips = g->ships;
          }
        }
        ns = getstr(0);
      }
      /* Determine the amount of cargo to be unloaded per ship */
      if (ns[0] != '\0') {
        if (noCaseStrcmp("amount", ns) == 0) {
          ns = getstr(0);
          if (ns[0] != '\0') {
            amount = atof(ns);
            if (amount > g->load) {
              amount = g->load;
              mistake(P, ERROR, *s,
                      "Group does not carry that much cargo, using amount=%.2f",
                      amount);
            }
            if (amount < AMOUNTMIN) {
              mistake(P, ERROR, *s, "Unload atleast %.2f per ship.", AMOUNTMIN);
              return;
            }
          }
          else {
            mistake(P, ERROR, *s, "Keyword AMOUNT should be followed by a number.");
            return;
          }
        }
        else {
          mistake(P, ERROR, *s, "Expected the keyword AMOUNT.");
          return;
        }
      }
      else {
        amount = g->load;
      }
    
      if (numberOfShips != g->ships) {
        g2 = allocStruct(group);
    
        *g2 = *g;
        g2->next = NULL;
        numberGroup(P, g2);
        g2->name = (char*)malloc(8);
        sprintf(g2->name, "%d", g2->number);
        addList(&P->groups, g2);
        assert(numberOfShips < g->ships);
        g->ships -= numberOfShips;
        g2->ships = numberOfShips;
        g = g2;
      }
      unloadgroup(g, P, amount);
    }
    

GalaxyNG/v_order

NAME

   v_order -- claim a planet.

SOURCE

    void
    v_order(game *aGame, player *P, strlist **s)
    {
      planet         *p;
      planet_claim   *pclaim;
    
      pdebug(DFULL, "v_order\n");
    
      p = findPlanet(aGame, getstr(0));
      if (!p) {
        mistake(P, ERROR, *s, "Planet not recognized.");
      }
      else {
        plog(LFULL, "Nation %s claims planet %s\n", P->name, p->name);
        pclaim = allocStruct(planet_claim);
    
        pclaim->planet_claimed = p;
        pclaim->next = NULL;
        addList(&(P->claimed_planets), pclaim);
      }
    }
    

GalaxyNG/w_order

NAME

   w_order -- declare war on another nation.

SOURCE

    void
    w_order(game *aGame, player *P, strlist **s)
    {
      player         *P2;
      alliance       *a;
    
      pdebug(DFULL, "w_order\n");
    
      P2 = findElement(player, aGame->players, getstr(0));
    
      if (!P2) {
        mistake(P, ERROR, *s, "Nation not recognized.");
        return;
      }
      for (a = P->allies; a; a = a->next) {
        if (a->who == P2) {
          remList(&P->allies, a);
          return;
        }
      }
    }
    

GalaxyNG/runTurn

NAME

   runTurn -- run a turn.

SYNOPSIS

   int runTurn(game *, char *)
   result = runTurn(aGame, ordersFileName)

FUNCTION

   Move one turn forward in time. All orders sent in by the nations
   are executed and the different phases are executed.  
   Nations that did not sent in orders for a number of consecutive
   turns are removed from the game.
   Although we can assume all the orders are correct, since they
   have been processed by checkorders(), we stil do some sanity
   checks.

INPUTS

   aGame --
   ordersFileName -- name of the file that contains the orders
                     of _all_ the nations.
 RESULTS
   aGame->turn is increased by one.
   aGame       contains the new situation, including battles,
               bombings and messages.
   result 
     FALSE -- Error occured during turn processing
     TRUE  -- All OK
 NOTE
   The turn is not saved and no reports are generated, this is handled
   by seperate functions.  This function should be split in parts.

SOURCE

    int
    runTurn(game *aGame, char *ordersFileName)
    {
      player         *P;
      char           *oGameName;
      char           *nationName;
      char           *password;
      FILE           *ordersFile;
    
      plog(LPART, "Reading orders from file %s\n", ordersFileName);
    
      ordersFile = Fopen(ordersFileName, "r");
    
      getLine(ordersFile);
      for (; !feof(ordersFile);) {
        if (noCaseStrncmp("#GALAXY", lineBuffer, 7) == 0) {
          player         *aPlayer;
    
          getstr(lineBuffer);
          oGameName = strdup(getstr(NULL));
          nationName = strdup(getstr(NULL));
          password = strdup(getstr(NULL));
          if (noCaseStrcmp(oGameName, aGame->name) == 0) {
            aPlayer = findElement(player, aGame->players, nationName);
    
            if (aPlayer) {
              aPlayer->lastorders = aGame->turn + 1;
              if (noCaseStrcmp(aPlayer->pswd, password) == 0) {
                aPlayer->orders = NULL;
                getLine(ordersFile);
                for (; !feof(ordersFile) &&
                     noCaseStrncmp("#GALAXY", lineBuffer, 7) &&
                     noCaseStrncmp("#END", lineBuffer, 4);) {
                  strlist        *s;
    
                  if ((s = makestrlist(lineBuffer)) != NULL)
                    addList(&(aPlayer->orders), s);
                  getLine(ordersFile);
                }
              }
              else {
                plog(LPART, "Password Incorrect.\n");
              }
            }
            else {
              plog(LPART, "Unrecognized player %s.\n", nationName);
            }
          }
          else {
            plog(LPART, "Orders are not for game %s.\n", aGame->name);
          }
          free(oGameName);
          free(nationName);
          free(password);
        }
        getLine(ordersFile);
      }
      fclose(ordersFile);
    
      (aGame->turn)++;
    
      if (!checkIntegrity(aGame))
        return FALSE;
    
      plog(LPART, "Orders read, processing...\n");
      plog(LFULL, "# Phase 1 Orders\n");
      for (P = aGame->players; P; P = P->next) {
        doOrders(aGame, P, phase1orders, 1);
      }
    
      if (!checkIntegrity(aGame))
        return FALSE;
    
      plog(LFULL, "# Phase 2 Orders\n");
      for (P = aGame->players; P; P = P->next) {
        doOrders(aGame, P, phase2orders, 2);
      }
    
      if (!checkIntegrity(aGame))
        return FALSE;
    
      plog(LFULL, "# joinphase I\n");
      joinphase(aGame);
      preComputeGroupData(aGame);
      plog(LFULL, "# fightphase I\n");
      fightphase(aGame, GF_INBATTLE1);
      plog(LFULL, "# bombphase I\n");
      bombphase(aGame);
      plog(LFULL, "# loadphase\n");
      loadphase(aGame);
      plog(LFULL, "# fleetphase I \n");
      fleetphase(aGame);
      if (!checkIntegrity(aGame))
        return FALSE;
      plog(LFULL, "# interceptphase\n");
      interceptphase(aGame);
      plog(LFULL, "# movephase\n");
      movephase(aGame);
      plog(LFULL, "# joinphase II\n");
      joinphase(aGame);
      preComputeGroupData(aGame);
      plog(LFULL, "# fightphase II\n");
      fightphase(aGame, GF_INBATTLE2);
      plog(LFULL, "# bombphase II\n");
      bombphase(aGame);
      plog(LFULL, "# producephase\n");
      producephase(aGame);
      plog(LFULL, "# unloadphase\n");
      unloadphase(aGame);
      plog(LFULL, "# joinphase III\n");
      joinphase(aGame);
      plog(LFULL, "# fleetphase II\n");
      fleetphase(aGame);
      if (!checkIntegrity(aGame))
        return FALSE;
      preComputeGroupData(aGame);
      sortphase(aGame);
    
      if (!(aGame->gameOptions.gameOptions & GAME_NODROP))
        removeDeadPlayer(aGame);
      nationStatus(aGame);
    
      return TRUE;
    }
    

GalaxyNG/checkOrders

NAME

   checkOrders --  check orders

SYNOPSIS

   int checkOrders(char *ordersFileName)
   resNumber = checkOrders(ordersFileName)

FUNCTION

   Checks a file with orders and prints a report with a forecast and 
   any errors found in the orders to stdout.
   It is checked that the orders contain a valid game name, nation
   name and password.
   A copy of the orders is stored in the directory orders/<gameName>. 

   If the orders start with #REPORT instead of #GALAXY a copy
   of the previous turn report is send to stdout.

INPUTS

   ordersFileName - name of the file with the orders.

RESULT

   resNumber -- return code:
      RES_NO_ORDERS - no line containing "#GALAXY" or #REPORT was found.
      RES_PASSWORD  - password was incorrect.
      RES_PLAYER    - no such player (Nation) exists.
      RES_NO_GAME   - no such game exists.
      RES_TURNRAN   - orders are for a turn that already ran.
      RES_OK        - everything was OK.

BUGS

   Does not handle machine reports or xml reports.

SEE ALSO

   areValidOrders(), copyOrders() 

SOURCE

    void
    checkOrders(game *aGame, char *nationName, FILE * forecast, int kind)
    {
      player         *aPlayer;
      struct fielddef fields;
    
      /* blatant attempt to avoid doing orders more than once if more than 
         one report type is being generated */
      static int orders_done = 0;
    
      pdebug(DFULL, "check orders\n");
      aPlayer = findElement(player, aGame->players, nationName);
    
      fields.destination = forecast;
      tagVisiblePlanets(aGame->planets, aPlayer);
    
      checkIntegrity(aGame);
    
      if (orders_done == 0) {
        orders_done = 1;
    
        doOrders(aGame, aPlayer, phase1orders, 1);
        doOrders(aGame, aPlayer, phase2orders, 2);
    
        joinphase(aGame);
        loadphase(aGame);
        fleetphase(aGame);
        checkIntegrity(aGame);
        interceptphase(aGame);
        movephase(aGame);
        joinphase(aGame);
        producephase(aGame);
        unloadphase(aGame);
        joinphase(aGame);
        fleetphase(aGame);
        
        preComputeGroupData(aGame);
        sortphase(aGame);
        checkIntegrity(aGame);
      }
    
      (aGame->turn)++;
      if (kind == F_XMLREPORT) {
        report_xml(aGame, aPlayer, forecast, Forecast);
      }
      else {
        nationStatus(aGame);
        reportGlobalMessages(aGame->messages, &fields);
        reportMessages(aPlayer, &fields);
        reportOrders(aPlayer, &fields);
        reportMistakes(aPlayer, &fields);
        yourStatusForecast(aGame->planets, aPlayer, &fields);
        if (aPlayer->flags & F_SHIPTYPEFORECAST) {
          reportYourShipTypes(aPlayer, &fields);
        }
        if (aPlayer->flags & F_PLANETFORECAST) {
          yourPlanetsForecast(aGame->planets, aPlayer, &fields);
          reportProdTable(aGame->planets, aPlayer, &fields);
        }
        if (aPlayer->flags & F_ROUTESFORECAST) {
          reportRoutes(aGame->planets, aPlayer, &fields);
        }
        if (aPlayer->flags & F_GROUPFORECAST) {
          reportYourGroups(aGame->planets, aPlayer, &fields);
          reportFleets(aPlayer, &fields);
        }
      }
      (aGame->turn)--;
    }
    

GalaxyNG/copyOrders

NAME

   copyOrders -- copy incoming orders to file.

SYNOPSIS

 void copyOrders(game *aGame, FILE *orders, char *nationName, 
                 char *password, int theTurnNumber)

FUNCTION

   Copy the orders to a file called 
     GAMEHOME/orders/<game name>/<nation name>.<turn number>
   If and #END line is missing one is generated.

INPUTS

   orderFile      - should point to the line after the #GALAXY line.
   aGame 
   nationName
   password
   theTurnNumber

SOURCE

    void
    copyOrders(game *aGame,
               FILE * orders,
               char *nationName, char *password, int theTurnNumber)
    {
      strlist        *s;
      char           *copyFileName;
      FILE           *copyFile;
      player         *aPlayer;
    
      aPlayer = findElement(player, aGame->players, nationName);
    
      aPlayer->orders = NULL;
      copyFileName = alloc(strlen(aGame->name) + strlen(aPlayer->name) +
                           strlen(galaxynghome) + strlen("/orders//") + 20);
      sprintf(copyFileName, "%s/orders/%s/%s.%d",
              galaxynghome, aGame->name, aPlayer->name, theTurnNumber);
    
      copyFile = Fopen(copyFileName, "w");
      savefprintf(copyFile, "#GALAXY %s %s %s\n",
                  aGame->name, nationName, password);
      getLine(orders);
      for (; !feof(orders) && noCaseStrncmp("#END", lineBuffer, 4);) {
        savefprintf(copyFile, "%s", lineBuffer);
        s = makestrlist(lineBuffer);
        addList(&(aPlayer->orders), s);
        getLine(orders);
      }
      if (feof(orders))
        savefprintf(copyFile, "#END\n");
      else
        savefprintf(copyFile, "%s\n", lineBuffer);
    
      free(copyFileName);
    }
    

GalaxyNG/areValidOrders

NAME

   areValidOrders -- check if orders are valid and load game.

SYNOPSIS

   int areValidOrders(FILE *ordersFile, 
                      char **command, game **game, 
                      char **nationName, char **password)

FUNCTION

   Scans through a file with orders until a line that starts
   with "#" is found.  The the rest of the line is then
   used to determine the name of the game, the nation the orders
   are for, and the password for the nation.
   The given game is loaded.  It is checked that the given
   player exists in this game, and that the given password
   is equal to the stored password.

INPUTS

   ordersFile     - pointer to a opened file with orders.
   theTurnNumber  - turn number the orders are supposed to be for.

RESULT

   result      - return code:
      RES_NO_ORDERS - no line containing "#GALAXY" was found.
      RES_PASSWORD  - password was incorrect.
      RES_PLAYER    - no such player (Nation) exists.
      RES_NO_GAME   - no such game exists.
      RES_TURNRAN   - orders are for a turn that already ran.
      RES_OK        - everything was OK.
   aGame       - game Structure loaded from disk
   nationName  - name of the nation the orders are for.
   password    - given password of the nation.

   ordersFile  - points to the line after the #GALAXY line.
   
   If the result is RES_OK then the game and its configuration
   file are loaded from disk.

SEE ALSO

   CMD_report(), CMD_check(), CMD_relay()

SOURCE

    int
    areValidOrders(FILE * ordersFile,
                   game **aGame,
                   char **nationName, char **password, int theTurnNumber)
    {
      int             resNumber, foundOrders;
      char           *gameName, *isRead;
    
      gameName = NULL;
    
      foundOrders = FALSE;
      for (isRead = fgets(lineBuffer, LINE_BUFFER_SIZE, ordersFile);
           isRead; isRead = fgets(lineBuffer, LINE_BUFFER_SIZE, ordersFile)) {
        if (noCaseStrncmp("#GALAXY", lineBuffer, 7) == 0) {
          foundOrders = TRUE;
          break;
        }
      }
    
      if (foundOrders) {
        getstr(lineBuffer);
        gameName = strdup(getstr(NULL));
        *nationName = strdup(getstr(NULL));
        *password = strdup(getstr(NULL));
        plog(LPART, "%s %s %s\n", gameName, *nationName, *password);
        if ((*aGame = loadgame(gameName, LG_CURRENT_TURN))) {
          player         *aPlayer;
    
          loadConfig(*aGame);
          aPlayer = findElement(player, (*aGame)->players, *nationName);
    
          if (aPlayer) {
            if (noCaseStrcmp(aPlayer->pswd, *password) eq 0) {
              if ((theTurnNumber >= (*aGame)->turn + 1) ||
                  (theTurnNumber eq LG_CURRENT_TURN)) {
                resNumber = RES_OK;
              }
              else {
                resNumber = RES_TURNRAN;
              }
            }
            else {
              resNumber = RES_PASSWORD;
            }
          }
          else {
            resNumber = RES_PLAYER;
          }
        }
        else {
          resNumber = RES_NO_GAME;
        }
      }
      else {
        resNumber = RES_NO_ORDERS;
      }
    
      if ((resNumber == RES_NO_GAME) || (resNumber == RES_NO_ORDERS)) {
        *aGame = allocStruct(game);
    
        setName(*aGame, "UnknownGame");
        loadConfig(*aGame);
        if (gameName)
          setName(*aGame, gameName);
      }
      return resNumber;
    }
    

GalaxyNG/getTurnNumber

NAME

   getTurnNumber -- get the turn number

FUNCTION

   Scans an incomming email for the From: line.
   If it is found it looks for the word "order" or "report"
   It then looks if there is a number after this word.
   If there is this number is returned.
   If no From: line was found the program aborts.
 RESULTS
   >= 0             -- the turn number
   LG_CURRENT_TURN  -- no turn number was specified

GalaxyNG/getDestination

NAME

   getDestination -- get Destination for the message

FUNCTION

   Extract the destination of a relay message from a players
   email.
 NOTE
   The message should contain the line
      Subject:   relay <nation name>

GalaxyNG/getReturnAddress

NAME

   getReturnAddress

FUNCTION

   Extract the return address from a players email.

GalaxyNG/doOrders

NAME

   doOrders -- carry out all orders.

SYNOPSIS

   void doOrders(game *aGame, player *aPlayer, 
                 orderinfo *orderInfo, int phase)

FUNCTION

   Carry out all orders for one player. 

SOURCE

    void
    doOrders(game *aGame, player *aPlayer, orderinfo *orderInfo, int phase)
    {
      strlist        *s;
      orderinfo      *op;
    
      plog(LFULL, "doOrders: Phase %d Nation %s\n", phase, aPlayer->name);
    
      pdebug(DFULL, "doOrders\n");
      pdebug(DFULL2, "  Phase %d Nation %s\n", phase, aPlayer->name);
      for (s = aPlayer->orders; s;) {
        char           *order;
    
        pdebug(DFULL2, "  Order %s\n", s->str);
        for (order = getstr(s->str); (s) && (phase eq 2) && (*order eq '@');) {
          plog(LFULL, "order: %s phase:%d\n", order, phase);
          for (s = s->next; s; s = s->next) {
            order = getstr(s->str);
            if (*order eq '@')
              break;
          }
          if (s) {
            s = s->next;
            if (s)
              order = getstr(s->str);
          }
        }
    
        if (s) {
          order = getstr(s->str);
          for (op = orderInfo; op->name != 0; op++) {
            if (noCaseStrncmp(op->name, order, ORDER_SIZE) == 0) {
              (*(op->func)) (aGame, aPlayer, &s);
              break;
            }
          }
        }
        if (s)
          s = s->next;
      }
    }
    

GalaxyNG/removeDeadPlayer

NAME

   removeDeadPlayer -- Removes idle players 

FUNCTION

   Check if a player last sent-in orders, and if this was too
   long ago the player is removed from the game. 

SOURCE

    void
    removeDeadPlayer(game *aGame)
    {
      player         *P;
      player         *P3;
      int             allowedOrderGap;
    
      pdebug(DFULL, "removeDeadPlayer\n");
      allowedOrderGap = (aGame->turn < ENDPHASE1TURN) ? ORDERGAP1 : ORDERGAP2;
      for (P = aGame->players; P; P = P3) {
        P3 = P->next;
        if (P->addr[0]) {
          int             idleTurns;
    
          idleTurns = (P->lastorders) ? aGame->turn - P->lastorders :
              allowedOrderGap + 1;
          plog(LFULL, "Player %s idle turns %d\n", P->name, idleTurns);
          if (idleTurns != 0) {
            if (idleTurns < allowedOrderGap) {
              int gap = allowedOrderGap - idleTurns;
              sprintf(lineBuffer, "\n\

GalaxyNG/preComputeGroupData

NAME

   preComputeGroupData -- precompute some frequently used values.

FUNCTION

   This is a very nasty function that precomputes some properties of
   groups.  This speeds up turn processing but also creates some
   serious problems when the function is not called at the right
   time.  A very nice case of premature optimization.

SOURCE

    void
    preComputeGroupData(game *aGame)
    {
      player         *aPlayer;
      group          *aGroup;
    
      for (aPlayer = aGame->players; aPlayer; aPlayer = aPlayer->next) {
        for (aGroup = aPlayer->groups; aGroup; aGroup = aGroup->next) {
          aGroup->attack = groupAttack(aGroup);
          aGroup->defense = groupDefense(aGroup);
          aGroup->location = groupLocation(aGame, aGroup);
        }
      }
    }
    

GalaxyNG/generateErrorMessage

NAME

   generateErrorMessage -- create error message for faulty orders.

FUNCTION

   

INPUTS

    resNumber -- The kind of error.
    forecast  -- file to write the message to.

SOURCE

    void
    generateErrorMessage(int resNumber, game *aGame,
                         char *nationName, int theTurnNumber, FILE * forecast)
    {
      switch (resNumber) {
      case RES_NO_ORDERS:
        fprintf(forecast,
                "O wise leader your mail did not contain any orders.\n"
                "Remember orders start with,\n"
                " #GALAXY <Galaxy Name> <Nation Name> <Password>\n"
                "and end with,\n #END\n");
        break;
      case RES_ERR_GALAXY:
        fprintf(forecast,
                "O wise leader you must supply your nation name and galaxy name.\n"
                "Remember orders start with,\n"
                " #GALAXY <Galaxy Name> <Nation Name> <Password>\n"
                "and end with,\n #END\n");
        break;
      case RES_NO_GAME:
        fprintf(forecast,
                "O wise leader there is no galaxy called %s.\n"
                "This probably means that you mispelled the galaxy name "
                "in your orders\n", aGame->name);
        break;
      case RES_PASSWORD:
        fprintf(forecast,
                "O wise leader the password you gave is incorrect.\n");
        break;
      case RES_PLAYER:
        fprintf(forecast,
                "O wise leader there is no nation called %s.\n"
                "This probably means that you mispelled your nation name.\n",
                nationName);
        break;
      case RES_TURNRAN:
        fprintf(forecast,
                "O wise leader you sent in orders for turn %d, that turn already ran.\n",
                theTurnNumber);
        break;
      case RES_DESTINATION:
        fprintf(forecast,
                "O wise leader the recipient of the message you sent does not exist.\n");
        break;
      case RES_NODESTINATION:
        fprintf(forecast,
                "O wise leader you failed to give a destination for your message.\n");
      }
      fprintf(forecast,
              "\nYour orders have been discarded!\n"
              "Please correct the mistake and retransmit your orders.\n");
    }