238 lines
5.0 KiB
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;
|
|
}
|
|
|
|
|