nexus/move.c

238 lines
5.0 KiB
C

#include <stdio.h>
#include <string.h>
#include "attack.h"
#include "defs.h"
#include "lf.h"
#include "map.h"
#include "objects.h"
#include "text.h"
extern lifeform_t *player;
int canmove(lifeform_t *lf, int dir, enum ERROR *error) {
cell_t *cell;
cell = getcellindir(lf->cell, dir);
if (!cell || cell->type->solid) {
if (error) *error = E_WALLINWAY;
return B_FALSE;
}
if (cell->lf) {
if (error) *error = E_LFINWAY;
return B_FALSE;
}
return B_TRUE;
}
void dorandommove(lifeform_t *lf, int badmovesok) {
int dir;
int tries = 0;
int moveok;
enum ERROR why;
// find a valid direction
dir = getrandomdir(DT_COMPASS);
moveok = canmove(lf, dir, &why);
if (!moveok && badmovesok) {
switch (why) {
case E_WALLINWAY:
case E_LFINWAY:
moveok = B_TRUE;
break;
}
}
while (!moveok) {
// try next direction...
if (++dir > DC_NW) dir = DC_N;
if (++tries >= MAXDIR_COMPASS) {
dowait(lf);
return;
}
// check this direction...
moveok = canmove(lf, dir, &why);
if (!moveok && badmovesok) {
switch (why) {
case E_WALLINWAY:
case E_LFINWAY:
moveok = B_TRUE;
break;
}
}
}
trymove(lf, dir);
}
int dowait(lifeform_t *lf) {
taketime(lf, SPEED_WAIT);
if (lf->controller == C_PLAYER) {
// clear msg bar
clearmsg();
}
return B_FALSE;
}
void movelf(lifeform_t *lf, cell_t *newcell) {
object_t *o,*nexto;
char obname[BUFLEN],lfname[BUFLEN],buf[BUFLEN];
// update current cell
lf->cell->lf = NULL;
// update lifeform
lf->cell = newcell;
// update new cell
newcell->lf = lf;
// check ground objects
if (!hasflag(lf->flags, F_FLYING)) {
for (o = newcell->obpile->first ; o ; o = nexto ) {
nexto = o->next;
if (hasflag(o->flags, F_SHARP)) {
object_t *boots;
// has boots on?
boots = getequippedob(lf->pack, BP_FEET);
if (boots) {
// crunch the broken glass
getobname(o, obname, 1);
if (o->amt > 1) {
char *newname;
// we want 'xx steps on some pieces of broken glass'
// not 'xx steps on 5 pieces of broken glass'
newname = makeplural(obname);
strrep(newname, "a ", "some ");
strcpy(obname, newname);
free(newname);
}
if (lf->controller == C_PLAYER) {
msg("You crush %s underfoot.",obname);
} else if (haslos(player, newcell)) {
getlfname(lf, lfname);
capitalise(lfname);
msg("%s crushes %s.",lfname, obname);
}
// kill object
removeob(o, o->amt);
} else {
// take damage
getobname(o, obname, 1);
if (lf->controller == C_PLAYER) {
msg("Ow - you step on %s!",obname);
} else if (haslos(player, newcell)) {
getlfname(lf, lfname);
capitalise(lfname);
msg("%s steps on %s!",lfname, obname);
}
sprintf(buf, "stepping on %s", obname);
losehp(lf, rnd(1,2), DT_SLASH, NULL, buf);
}
}
} // end foreach object in cell
} // end if !flying
// update where player knows
// (but without a map you will then slowly forget it)
if (lf->controller == C_PLAYER) {
updateknowncells();
}
}
// basically this is a warpper for 'movelf' which
// does other game things like telling the player
// what is here.
int moveto(lifeform_t *lf, cell_t *newcell) {
// actually do the move
movelf(lf, newcell);
// tell player about things
if (!isdead(lf) && (lf->controller == C_PLAYER)) {
int numobs;
char buf[BUFLEN];
numobs = countobs(newcell->obpile);
if (numobs == 1) {
getobname(newcell->obpile->first, buf, newcell->obpile->first->amt);
msg("You see %s here.", buf);
} else if ((numobs > 1) && (numobs <= 3)) {
msg("You see a few objects here.");
} else if ((numobs > 3) && (numobs <= 6)) {
msg("You see some objects here.");
} else if (numobs > 6) {
msg("You see many objects here.");
} else {
// just clear the message buffer
clearmsg();
}
}
}
int opendoor(lifeform_t *lf, cell_t *cell) {
char buf[BUFLEN];
if (cell->type->id == CT_DOORCLOSED) {
// open it
setcelltype(cell, CT_DOOROPEN);
if (lf->controller == C_PLAYER) {
msg("You open a door.");
} else {
// TODO: only announce if player can see it
if (haslos(player, cell)) {
getlfname(lf, buf);
capitalise(buf);
msg("%s opens a door.",buf);
}
}
taketime(lf, getmovespeed(lf));
} else {
return B_TRUE;
}
return B_FALSE;
}
int tryrun(lifeform_t *lf, int dir) {
// continue moving until we fail
while (canmove(lf, dir, NULL)) {
trymove(lf,dir);
}
}
int trymove(lifeform_t *lf, int dir) {
cell_t *cell;
enum ERROR errcode;
char buf[BUFLEN], buf2[BUFLEN];
cell = getcellindir(lf->cell, dir);
if (canmove(lf, dir, &errcode)) {
moveto(lf, cell);
taketime(lf, getmovespeed(lf));
} else {
switch (errcode) {
case E_WALLINWAY:
// is it a door in the way?
if (cell->type->id == CT_DOORCLOSED) {
// try to open it
opendoor(lf, cell);
} else {
if (lf->controller == C_PLAYER) {
msg("Ouch! You walk into a wall.");
}
}
break;
case E_LFINWAY:
// attack!
doattack(lf, cell->lf);
break;
}
return B_TRUE;
}
return B_FALSE;
}