/* * modify.c * (adapted, more or less, from option.c) */ #include "copyright.h" #include #include #include #include #include #include "Wlib.h" #include "defs.h" #include "xsg_defs.h" #include "struct.h" #include "localdata.h" static int notdone; /* not done flag */ static int mode; /* 0=player, 1=planet */ static int nummodify; /* either NUMPMODIFY or NUMPLMODIFY */ static struct player *mpp; /* pointer to player being modified */ static struct planet *mplp; /* pointer to planet being modified */ static struct player pl; /* local copy of player */ static struct planet pln; /* local copy of planet */ static modifyrefresh(); static char *ship_classes[] = { "Ship class: Scout (SC)", "Ship class: Destroyer (DD)", "Ship class: Cruiser (CA)", "Ship class: Battleship (BB)", "Ship class: Assault (AS)", "Ship class: Starbase (SB)", #ifdef SGALAXY "Ship class: Galaxy (GA)", #endif #ifdef ATT "Ship class: AT&T", #endif ""}; static char *team_names[] = { "Team: Independent", "Team: Federation", "Team: Romulan", "Team: Klingon", "Team: Orion", ""}; static short p_team, pl_team; /* I don't know if this is the best way to implement this, but it's easy */ /* (assumes PLREPAIR=0x10, PLFUEL=0x20, PLAGRI=0x40) */ static char *planet_features[] = { "Features: None", /* 000 */ "Features: REPAIR", /* 001 */ "Features: FUEL", /* 010 */ "Features: REPAIR FUEL", /* 011 */ "Features: AGRI", /* 100 */ "Features: REPAIR AGRI", /* 101 */ "Features: FUEL AGRI", /* 110 */ "Features: REPAIR FUEL AGRI", /* 111 */ ""}; static unsigned short pl_flags; typedef enum MOD_TYPE_T { M_MULTI, M_ACTION, M_STRING } MOD_TYPE; struct modify { int num; MOD_TYPE type; char *text; void *status; }; /* only the M_ACTION ones really need constants */ #define PMOD_NAME 0 #define PMOD_TEAM 1 #define PMOD_CLASS 2 #define PMOD_HEAL 3 #define PMOD_HELP 4 #define PMOD_HARM 5 #define PMOD_HOSE 6 #define PMOD_COOL 7 /* TSH 2/93 */ #define PMOD_PLKILLS 8 #define PMOD_MIKILLS 9 #define PMOD_TOGSHLD 10 #define PMOD_TOGCLOAK 11 /* TSH 4/93 */ #define PMOD_NUKE 12 #define PMOD_EJECT 13 #define PMOD_NOORBIT 14 #define PMOD_PACIFY 15 #define PMOD_GHOSTBUST 16 /* TSH 2/93 */ #define PMOD_FREE 17 /* TSH 2/93 */ #define PMOD_DONE 18 #ifndef GHOSTTIME #define GHOSTTIME (30 * 1000000 / UPDATE) /* 30 secs, TSH 2/93 */ #endif static struct modify pmodify[] = { { PMOD_NAME, M_STRING, "Player name", (void *) pl.p_name }, { PMOD_TEAM, M_MULTI, (char *) team_names, (void *) &p_team }, { PMOD_CLASS, M_MULTI, (char *) ship_classes, (void *) &(pl.p_ship.s_type) }, { PMOD_HEAL, M_ACTION, "Heal", NULL }, { PMOD_HELP, M_ACTION, "Help", NULL }, { PMOD_HARM, M_ACTION, "Harm", NULL }, { PMOD_HOSE, M_ACTION, "Hose", NULL }, { PMOD_COOL, M_ACTION, "Cool weapons", NULL }, { PMOD_PLKILLS, M_ACTION, "Kills +1", NULL }, { PMOD_MIKILLS, M_ACTION, "Kills -1", NULL }, { PMOD_TOGSHLD, M_ACTION, "Toggle shields", NULL }, { PMOD_TOGCLOAK, M_ACTION, "Toggle cloak", NULL }, { PMOD_NUKE, M_ACTION, "Nuke", NULL }, { PMOD_EJECT, M_ACTION, "EJECT PLAYER", NULL }, { PMOD_NOORBIT, M_ACTION, "Knock out of orbit", NULL }, { PMOD_PACIFY, M_ACTION, "Make peaceful", NULL }, { PMOD_GHOSTBUST, M_ACTION, "GHOSTBUST", NULL }, { PMOD_FREE, M_ACTION, "FREE SLOT", NULL }, { PMOD_DONE, M_ACTION, "Done", NULL }, { -1, -1, NULL, NULL } }; #define NUMPMODIFY ((sizeof(pmodify)/sizeof(pmodify[0]))-1) #define PLMOD_NAME 0 #define PLMOD_TEAM 1 #define PLMOD_FEATURES 2 #define PLMOD_PLARM 3 #define PLMOD_MIARM 4 #define PLMOD_DESTROY 5 #define PLMOD_DONE 6 static struct modify plmodify[] = { { PLMOD_NAME, M_STRING, "Planet name", (void *) pln.pl_name }, { PLMOD_TEAM, M_MULTI, (char *) team_names, (void *) &pl_team }, { PLMOD_FEATURES, M_MULTI, (char *) planet_features, (void *) &pl_flags }, { PLMOD_PLARM, M_ACTION, "Armies +5", NULL }, { PLMOD_MIARM, M_ACTION, "Armies -5", NULL }, { PLMOD_DESTROY, M_ACTION, "Destroy", NULL }, { PLMOD_DONE, M_ACTION, "Done", NULL }, { -1, -1, NULL, NULL } }; #define NUMPLMODIFY ((sizeof(plmodify)/sizeof(plmodify[0]))-1) #define MAXSTRING 15 /* only strings are player & planet names */ #define MODIFYBORDER 2 #define MODIFYLEN 35 /* Set up the modify window */ modifywindow(target) struct obtype *target; { register int i; char buf[BUFSIZ]; /* Init not done flag */ notdone = 1; /* locate the player's struct */ if (target->o_type == PLAYERTYPE) { mode = 0; nummodify = NUMPMODIFY; mpp = &players[target->o_num]; sprintf(buf, "Modifying player %s (%s)", mpp->p_name, mpp->p_mapchars); warning(buf); MCOPY(mpp, &pl, sizeof(struct player)); p_team = 0; switch (mpp->p_team) { case ORI: p_team++; case KLI: p_team++; case ROM: p_team++; case FED: p_team++; case NOBODY: break; default: fprintf(stderr,"Internal error: mpp->p_team is from mars (%x)\n", mpp->p_team); } } else { mode = 1; nummodify = NUMPLMODIFY; mplp = &planets[target->o_num]; sprintf(buf, "Modifying planet %s", mplp->pl_name); warning(buf); MCOPY(mplp, &pln, sizeof(struct planet)); pl_team = 0; switch (mplp->pl_owner) { case ORI: pl_team++; case KLI: pl_team++; case ROM: pl_team++; case FED: pl_team++; case NOBODY: break; default: fprintf(stderr,"Internal error: mplp->pl_owner is from mars (%x)\n", mplp->pl_owner); } pl_flags = (mplp->pl_flags & (PLREPAIR|PLFUEL|PLAGRI)) >> 4; } /* Create window big enough to hold modify windows */ if (modifyWin==NULL) { modifyWin = W_MakeMenu("modify", WINSIDE+10, -BORDER+10, MODIFYLEN, MAX(NUMPMODIFY,NUMPLMODIFY), baseWin, MODIFYBORDER); } if(mode == 0) /* player modify */ W_ResizeMenu(modifyWin, MODIFYLEN, NUMPMODIFY); else /* planet modify */ W_ResizeMenu(modifyWin, MODIFYLEN, NUMPLMODIFY); for (i=0; i< (mode ? NUMPLMODIFY : NUMPMODIFY); i++) { if (i >= nummodify) W_WriteText(modifyWin, 0, i, textColor, "", 0, 0); /* blank */ else modifyrefresh(mode ? &(plmodify[i]) : &(pmodify[i])); } /* Map window */ W_MapWindow(modifyWin); } /* Refresh the modify window given by the modify struct */ static modifyrefresh(op) register struct modify *op; { char buf[BUFSIZ]; switch (op->type) { case M_MULTI: /* note I expect to index on a short, not an int */ sprintf(buf, "%s", ((char **) op->text)[*((short *) op->status)]); break; case M_ACTION: sprintf(buf, "%s", op->text); break; case M_STRING: sprintf(buf, "%s: %s_", op->text, (char *) op->status); break; default: fprintf(stderr, "Internal error: bad op->type\n"); } W_WriteText(modifyWin, 0, op->num, textColor, buf, strlen(buf), 0); } modifyaction(data) W_Event *data; { register struct modify *op; char buf[BUFSIZ]; int i; register char *cp; if (data->y >= nummodify) return(0); op= (mode ? &(plmodify[data->y]) : &(pmodify[data->y])); switch (op->type) { case M_STRING: if (data->type == W_EV_BUTTON) return(0); switch (data->key) { case '\b': case '\177': cp = (char *) op->status; i = strlen(cp); if (i > 0) { cp += i - 1; *cp = '\0'; } break; case '\027': /* word erase */ cp = (char *) op->status; i = strlen(cp); /* back up over blanks */ while (--i >= 0 && isspace(cp[i])) ; i++; /* back up over non-blanks */ while (--i >= 0 && !isspace(cp[i])) ; i++; cp[i] = '\0'; break; case '\025': case '\030': ((char *) op->status)[0] = '\0'; break; default: if (data->key < 32 || data->key > 127) break; cp = (char *) op->status; i = strlen(cp); if (i < MAXSTRING && !iscntrl(data->key)) { cp += i; cp[1] = '\0'; cp[0] = data->key; } else W_Beep(); break; } break; case M_MULTI: if (data->type == W_EV_KEY) return(0); #define IDX *((short *) op->status) ( IDX )++; if (( *((char **) op->text)[IDX] ) == '\0') ( IDX ) = 0; #undef IDX break; case M_ACTION: if (data->type == W_EV_KEY) return(0); if (!mode) { switch (op->num) { case PMOD_HEAL: pl.p_shield = mpp->p_shield = mpp->p_ship.s_maxshield; pl.p_damage = mpp->p_damage = 0; pl.p_fuel = mpp->p_fuel = mpp->p_ship.s_maxfuel; mpp->p_wtemp = mpp->p_etemp = 0; mpp->p_wtime = mpp->p_etime = 0; break; case PMOD_HELP: pl.p_shield += pl.p_ship.s_maxshield / 10; if (pl.p_shield > pl.p_ship.s_maxshield) pl.p_shield = pl.p_ship.s_maxshield; mpp->p_shield = pl.p_shield; pl.p_damage -= pl.p_ship.s_maxshield / 10; if (pl.p_damage < 0) pl.p_damage = 0; mpp->p_damage = pl.p_damage; pl.p_fuel += pl.p_ship.s_maxfuel / 10; if (pl.p_fuel > pl.p_ship.s_maxfuel) pl.p_fuel = pl.p_ship.s_maxfuel; mpp->p_fuel = pl.p_fuel; break; case PMOD_COOL: /* TSH 2/93 */ mpp->p_wtemp = 0; break; case PMOD_HARM: pl.p_shield -= pl.p_ship.s_maxshield / 10; if (pl.p_shield < 0) pl.p_shield = 0; mpp->p_shield = pl.p_shield; pl.p_damage += pl.p_ship.s_maxshield / 10; if (pl.p_damage > pl.p_ship.s_maxshield) pl.p_damage = pl.p_ship.s_maxshield; mpp->p_damage = pl.p_damage; pl.p_fuel -= pl.p_ship.s_maxfuel / 10; if (pl.p_fuel < 0) pl.p_fuel = 0; mpp->p_fuel = pl.p_fuel; break; case PMOD_HOSE: pl.p_shield = mpp->p_shield = 0; pl.p_damage = mpp->p_damage = mpp->p_ship.s_maxdamage; pl.p_fuel = mpp->p_fuel = 0; break; case PMOD_NUKE: /* from xtkill.c */ mpp->p_ship.s_type = STARBASE; sprintf(buf, "%s (%2s) was utterly obliterated.", mpp->p_name, mpp->p_mapchars); pmessage(buf, 0, MALL); mpp->p_explode=10; mpp->p_status=PEXPLODE; mpp->p_whydead=KPROVIDENCE; mpp->p_whodead=0; notdone = 0; /* he's dead, stop editing */ break; case PMOD_EJECT: mpp->p_ship.s_type = STARBASE; sprintf(buf, "%s (%2s) was ejected from the game.", mpp->p_name, mpp->p_mapchars); pmessage(buf, 0, MALL); mpp->p_explode=10; mpp->p_status=PEXPLODE; mpp->p_whydead=KQUIT; /* make him self destruct */ mpp->p_whodead=0; notdone = 0; /* he's history, stop editing */ break; case PMOD_PLKILLS: mpp->p_kills++; break; case PMOD_MIKILLS: mpp->p_kills--; if (mpp->p_kills < 0) mpp->p_kills = 0; break; case PMOD_TOGSHLD: if (mpp->p_flags & PFSHIELD) { mpp->p_flags &= ~PFSHIELD; pl.p_flags &= ~PFSHIELD; } else { mpp->p_flags |= PFSHIELD; pl.p_flags |= PFSHIELD; } break; case PMOD_TOGCLOAK: if (mpp->p_flags & PFCLOAK) { mpp->p_flags &= ~PFCLOAK; pl.p_flags &= ~PFCLOAK; } else { mpp->p_flags |= PFCLOAK; pl.p_flags |= PFCLOAK; } break; case PMOD_NOORBIT: mpp->p_flags &= ~PFORBIT; pl.p_flags &= ~PFORBIT; break; case PMOD_PACIFY: mpp->p_war = mpp->p_hostile = mpp->p_swar = 0; pl.p_war = pl.p_hostile = pl.p_swar = 0; break; case PMOD_GHOSTBUST: if(mpp->p_status != PFREE) mpp->p_ghostbuster = GHOSTTIME; break; case PMOD_FREE: if (mpp->p_process != 0) { ERROR(1,("xtkilling player %i, process %i\n",mpp->p_no,mpp->p_process)); if (kill(mpp->p_process, SIGTERM) < 0) freeslot(mpp); } else { freeslot(mpp); } break; case PMOD_DONE: notdone = 0; break; default: fprintf(stderr, "Internal error: unknown p action item\n"); } } else { switch (op->num) { case PLMOD_PLARM: mplp->pl_armies += 5; break; case PLMOD_MIARM: mplp->pl_armies -= 5; if (mplp->pl_armies < 1) mplp->pl_armies = 1; break; case PLMOD_DESTROY: mplp->pl_armies = 0; mplp->pl_owner = NOBODY; pl_team = 0; modifyrefresh(&(plmodify[PLMOD_TEAM])); /* could this cause genocide? */ break; case PLMOD_DONE: notdone = 0; break; default: fprintf(stderr, "Internal error: unknown pl action item\n"); } } break; default: fprintf(stderr, "Internal error: bad type %d\n", op->type); } if (!notdone) modifydone(); else modifyrefresh(op); } modifydone() { /* Unmap window */ W_UnmapWindow(modifyWin); if (mode) { /* update non-action items (planet name, team, flags) */ strcpy(mplp->pl_name, pln.pl_name); mplp->pl_namelen = strlen(mplp->pl_name); if (!pl_team) mplp->pl_owner = NOBODY; else mplp->pl_owner = 1 << (pl_team-1); mplp->pl_flags &= ~(PLREPAIR|PLFUEL|PLAGRI); mplp->pl_flags |= (pl_flags << 4); } else { /* * Now, update any non-action items (player name, ship type, etc). * * Note that the shield/damage/fuel is scaled proportionately at the * time that "done" is clicked. The "action items" must therefore * affect pl * and mpp at the time they are pressed; otherwise you * could heal somebody * and then have the effect reversed when you * pressed "done". */ strcpy(mpp->p_name, pl.p_name); /* mpp->p_flags = pl.p_flags; /* transfer flags */ if (pl.p_ship.s_type != mpp->p_ship.s_type) { /*this can be bad if the guy dies and comes back as something else*/ getship(&(mpp->p_ship), pl.p_ship.s_type); if ((pl.p_ship.s_type != STARBASE) && (pl.p_ship.s_type != ATT) && mpp->p_kills < (float) plkills) { mpp->p_ship.s_plasmacost = -1; } /* give proportionate shield/damage */ mpp->p_shield = (int) ( (double) mpp->p_ship.s_maxshield * (double) mpp->p_shield / (double) pl.p_ship.s_maxshield ); mpp->p_damage = (int) ( (double) mpp->p_ship.s_maxdamage * (double) mpp->p_damage / (double) pl.p_ship.s_maxdamage ); mpp->p_fuel = (int) ( (double) mpp->p_ship.s_maxfuel * (double) mpp->p_fuel / (double) pl.p_ship.s_maxfuel ); /* reduce speed, if necessary */ if (mpp->p_speed > mpp->p_ship.s_maxspeed) mpp->p_speed = mpp->p_ship.s_maxspeed; /* preserve certain optional robot features */ if (mpp->p_flags & PFROBOT) { if (!pl.p_ship.s_phasercost) mpp->p_ship.s_phasercost = 0; if (!pl.p_ship.s_torpcost) mpp->p_ship.s_torpcost = 0; if (!pl.p_ship.s_cloakcost) mpp->p_ship.s_cloakcost = 0; mpp->p_ship.s_torpturns = pl.p_ship.s_torpturns; } } if (!p_team) mpp->p_team = NOBODY; else mpp->p_team = 1 << (p_team-1); } }