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}
};
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}
};
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));
}
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-"));
}
}
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);
}
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;
}
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);
}
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);
}
}
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;
}
}
}
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;
}
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)--;
}
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);
}
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;
}
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
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>
NAME
getReturnAddress
FUNCTION
Extract the return address from a players email.
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;
}
}
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\
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);
}
}
}
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");
}