update
This commit is contained in:
parent
17457b0537
commit
014d591109
4
Makefile
4
Makefile
|
@ -1,2 +1,2 @@
|
|||
nexus: Makefile defs.h nexus.c nexus.h ai.c ai.h attack.c attack.h flag.c flag.h io.c io.h lf.c lf.h map.c map.h move.c move.h objects.c objects.h text.c text.h save.c save.h
|
||||
gcc -g -o nexus nexus.c ai.c attack.c flag.c io.c lf.c map.c move.c objects.c text.c save.c -lncurses
|
||||
nexus: Makefile defs.h nexus.c nexus.h ai.c ai.h attack.c attack.h flag.c flag.h io.c io.h lf.c lf.h map.c map.h move.c move.h objects.c objects.h text.c text.h save.c save.h spell.c spell.h
|
||||
gcc -g -o nexus nexus.c ai.c attack.c flag.c io.c lf.c map.c move.c objects.c text.c save.c spell.c -lncurses
|
||||
|
|
42
ai.c
42
ai.c
|
@ -11,44 +11,77 @@ extern lifeform_t *player;
|
|||
|
||||
void aimove(lifeform_t *lf) {
|
||||
int dir;
|
||||
int db = B_TRUE;
|
||||
int wantdb = B_TRUE;
|
||||
int db = B_FALSE;
|
||||
object_t *curwep,*bestwep;
|
||||
flag_t *f;
|
||||
lifeform_t *target;
|
||||
char buf[BUFLEN];
|
||||
|
||||
|
||||
if (wantdb && haslos(player, lf->cell)) {
|
||||
db = B_TRUE;
|
||||
} else {
|
||||
db = B_FALSE;
|
||||
}
|
||||
|
||||
if (db) dblog("AIMOVE: %s", lf->race->name);
|
||||
|
||||
|
||||
|
||||
// if lifeform isn't alive, skip turn
|
||||
if (isdead(lf)) {
|
||||
if (db) dblog(".oO { i am not alive, skipping turn. }");
|
||||
taketime(lf, SPEED_DEAD);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// do we have a better weapon we could use?
|
||||
curwep = getweapon(lf);
|
||||
bestwep = getbestweapon(lf);
|
||||
|
||||
if (curwep != bestwep) {
|
||||
if (db) dblog(".oO { i have a better weapon than my current one (%s > %s) }",bestwep->type->name, curwep ? curwep->type->name : "nothing");
|
||||
// weild better one
|
||||
weild(lf, bestwep);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// do we already have a target we are attacking?
|
||||
f = hasflag(lf->flags, F_TARGET);
|
||||
if (f) {
|
||||
int targid;
|
||||
if (db) dblog(".oO { i have a target... }");
|
||||
targid = f->val[0];
|
||||
target = findlf(lf->cell->map, targid);
|
||||
if (target) {
|
||||
if (db) dblog(".oO { my target is lfid %d (%s). }", targid, target->race->name);
|
||||
if (haslos(lf, target->cell)) {
|
||||
if (db) dblog(".oO { i can see my target. will move towards it. }");
|
||||
movetowards(lf, target->cell);
|
||||
return;
|
||||
} else {
|
||||
if (db) dblog(".oO { i cannot see my target }");
|
||||
// TODO: move towards last known location
|
||||
|
||||
// just try to move in a random direction
|
||||
dorandommove(lf);
|
||||
if (db) dblog(".oO { will move randomly }");
|
||||
dorandommove(lf, B_NOBADMOVES);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// not attacking anyone in particular
|
||||
|
||||
if (db) dblog(".oO { i do not have a target. }");
|
||||
// TODO: are we hostile? if so, look for a target
|
||||
f = hasflag(lf->flags, F_HOSTILE);
|
||||
if (f) {
|
||||
int x,y;
|
||||
cell_t *c;
|
||||
if (db) dblog(".oO { i am hostile. looking for a target. }");
|
||||
// look around for a target
|
||||
// TODO: use our vis rang einstead of 10!
|
||||
for (y = lf->cell->y - 10; y <= lf->cell->y + 10; y++) {
|
||||
|
@ -58,6 +91,7 @@ void aimove(lifeform_t *lf) {
|
|||
if (c && haslos(lf, c)) {
|
||||
// player there?
|
||||
if (c->lf && c->lf->controller == C_PLAYER) {
|
||||
if (db) dblog(".oO { found a target - lfid %d (%s) ! }",c->lf->id, c->lf->race->name);
|
||||
// target them!
|
||||
addflag(lf->flags, F_TARGET, c->lf->id, -1, -1, "");
|
||||
// tell the player
|
||||
|
@ -67,6 +101,7 @@ void aimove(lifeform_t *lf) {
|
|||
msg("%s sees you!", buf);
|
||||
}
|
||||
// then move towards them...
|
||||
if (db) dblog(".oO { moving towards my new target }");
|
||||
movetowards(lf, c);
|
||||
return;
|
||||
}
|
||||
|
@ -76,7 +111,8 @@ void aimove(lifeform_t *lf) {
|
|||
}
|
||||
|
||||
// just try to move in a random direction
|
||||
dorandommove(lf);
|
||||
if (db) dblog(".oO { default - moving randomly }");
|
||||
dorandommove(lf, B_NOBADMOVES);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
341
attack.c
341
attack.c
|
@ -1,28 +1,136 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "attack.h"
|
||||
#include "defs.h"
|
||||
#include "flag.h"
|
||||
#include "lf.h"
|
||||
#include "objects.h"
|
||||
|
||||
extern lifeform_t *player;
|
||||
|
||||
void doattack(lifeform_t *lf, lifeform_t *victim) {
|
||||
int doattack(lifeform_t *lf, lifeform_t *victim) {
|
||||
int dam;
|
||||
char buf[BUFLEN];
|
||||
char attackername[BUFLEN];
|
||||
char victimname[BUFLEN];
|
||||
int fatal = B_FALSE;
|
||||
flag_t *f;
|
||||
object_t *wep;
|
||||
enum DAMTYPE damtype;
|
||||
obpile_t *op;
|
||||
int attacktime;
|
||||
int acc;
|
||||
int hit = B_FALSE;
|
||||
double dampct;
|
||||
int unarmed = B_FALSE;
|
||||
char wepname[BUFLEN];
|
||||
int ev;
|
||||
|
||||
// depends on weapon, race attackspeed modifier flag, etc
|
||||
taketime(lf, getattackspeed(lf));
|
||||
|
||||
// TODO: figure out if you hit
|
||||
// TODO: figure out if you do damage
|
||||
dam = 1;
|
||||
|
||||
// get names
|
||||
getlfname(lf, attackername);
|
||||
getlfname(victim, victimname);
|
||||
|
||||
losehp(victim, dam, lf, attackername); // TODO: use player name if required
|
||||
|
||||
// get weapon
|
||||
op = addobpile(lf, NULL); // for use if we are unarmed
|
||||
wep = getweapon(lf);
|
||||
if (!wep) {
|
||||
unarmed = B_TRUE;
|
||||
|
||||
// ie. unarmed
|
||||
getunarmedweapon(lf, op);
|
||||
|
||||
if (op->first) {
|
||||
wep = op->first;
|
||||
} else {
|
||||
// cannot attack!
|
||||
if (lf->controller == C_PLAYER) {
|
||||
msg("You cannot attack!");
|
||||
} else if (haslos(player, lf->cell)) {
|
||||
sprintf(buf, "%s",attackername);
|
||||
capitalise(buf);
|
||||
msg("%s looks like it wants to attack!",buf);
|
||||
}
|
||||
|
||||
if (lf->controller != C_PLAYER) {
|
||||
// take some time to avoid infinite loops!
|
||||
taketime(lf, 1);
|
||||
}
|
||||
free(op);
|
||||
return B_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
getobname(wep, wepname, 1);
|
||||
|
||||
|
||||
f = hasflag(wep->flags, F_DAMTYPE);
|
||||
if (f) {
|
||||
damtype = f->val[0];
|
||||
} else {
|
||||
// default - you are just bashing with whatever
|
||||
// you weilded.
|
||||
damtype = DT_BASH;
|
||||
}
|
||||
|
||||
// depends on weapon, race attackspeed modifier flag, etc
|
||||
attacktime = getobattackspeed(wep) + getlfattackspeed(lf);
|
||||
taketime(lf, attacktime);
|
||||
|
||||
// TODO: figure out if you hit
|
||||
|
||||
// TODO: figure out if you do damage, and how much
|
||||
|
||||
acc = 100; // base accuracy of 100%
|
||||
|
||||
// modify for weapon's (lack of) accuracy
|
||||
f = hasflag(wep->flags, F_ACCURACY);
|
||||
if (f) {
|
||||
// ie. accuracy of 100% means no penalty
|
||||
// ie. accuracy of 75% means 25% penalty
|
||||
// etc
|
||||
acc -= (100 - f->val[0]);
|
||||
}
|
||||
|
||||
// modify for defender's evasion
|
||||
ev = getevasion(victim);
|
||||
acc -= ev;
|
||||
|
||||
// modify for attacker's level
|
||||
acc += (lf->level * 2);
|
||||
|
||||
if (acc < 0) acc = 0;
|
||||
if (acc > 100) acc = 100;
|
||||
|
||||
|
||||
// did you hit?
|
||||
if (rnd(1,100) <= acc) {
|
||||
hit = B_TRUE;
|
||||
} else {
|
||||
hit = B_FALSE;
|
||||
}
|
||||
|
||||
|
||||
if (hit) {
|
||||
int reducepct;
|
||||
int ar;
|
||||
int reduceamt;
|
||||
// determine damage
|
||||
dam = getdamroll(wep);
|
||||
|
||||
// modify for attacker's armour
|
||||
ar = getarmour(victim);
|
||||
reducepct = ar * 2;
|
||||
reduceamt = (int)(((float)reducepct / 100.0) * (float)dam);
|
||||
|
||||
dam -= reduceamt;
|
||||
if (dam < 0) dam = 0;
|
||||
|
||||
// TODO: armour gets damaged
|
||||
|
||||
losehp(victim, dam, damtype, lf, attackername);
|
||||
|
||||
if (victim->hp <= 0) {
|
||||
fatal = B_TRUE;
|
||||
|
@ -30,21 +138,230 @@ void doattack(lifeform_t *lf, lifeform_t *victim) {
|
|||
|
||||
// announce it
|
||||
if (lf->controller == C_PLAYER) {
|
||||
msg("You %s %s%s",
|
||||
fatal ? "kill" : "hit",
|
||||
msg("You %s %s%s%s",
|
||||
fatal ? getkillverb(damtype, dam) : getattackverb(damtype, dam),
|
||||
victimname,
|
||||
(dam == 0) ? " but do no damage" : "",
|
||||
fatal ? "!" : ".");
|
||||
|
||||
if (fatal && !hasflag(victim->flags, F_NODEATHANNOUNCE)) {
|
||||
// don't also say "the xx dies"
|
||||
addflag(victim->flags, F_NODEATHANNOUNCE, B_TRUE, -1, -1, "");
|
||||
addflag(victim->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL);
|
||||
}
|
||||
} else {
|
||||
if (haslos(player, lf->cell)) {
|
||||
char withwep[BUFLEN];
|
||||
|
||||
// capitalise first letter
|
||||
sprintf(buf, "%s",attackername);
|
||||
capitalise(buf);
|
||||
|
||||
if (wep && !unarmed) {
|
||||
sprintf(withwep, " with %s", wepname);
|
||||
} else {
|
||||
strcpy(withwep, "");
|
||||
}
|
||||
|
||||
msg("%s %ss %s%s%s.", buf, getattackverb(damtype,dam), victimname,withwep,
|
||||
(dam == 0) ? " but does no damage" : "" );
|
||||
}
|
||||
// TODO: else {if (haslineofhearing() etc
|
||||
}
|
||||
} else { // miss!
|
||||
// announce it
|
||||
if (lf->controller == C_PLAYER) {
|
||||
msg("You miss %s.", victimname);
|
||||
} else {
|
||||
if (haslos(player, lf->cell)) {
|
||||
// capitalise first letter
|
||||
sprintf(buf, "%s",attackername);
|
||||
capitalise(buf);
|
||||
|
||||
msg("%s hits %s.", buf, victimname);
|
||||
msg("%s misses %s.", buf, victimname);
|
||||
}
|
||||
}
|
||||
fightback(victim, lf);
|
||||
}
|
||||
|
||||
// get rid of temp unarmed object
|
||||
if (op->first) {
|
||||
killob(op->first);
|
||||
}
|
||||
free(op);
|
||||
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
char *getattackverb(enum DAMTYPE damtype, int dam) {
|
||||
if (damtype == DT_PROJECTILE) {
|
||||
return "hit";
|
||||
} else if (damtype == DT_HOLY) {
|
||||
return "smite";
|
||||
} else if (damtype == DT_PIERCE) {
|
||||
if (dam == 0) {
|
||||
return "poke";
|
||||
} else if (dam <= 5) {
|
||||
return "nick";
|
||||
} else if (dam <= 10) {
|
||||
return "stab";
|
||||
} else if (dam <= 15) {
|
||||
return "pierce";
|
||||
} else if (dam <= 20) {
|
||||
return "spear";
|
||||
} else {
|
||||
return "deeply stab";
|
||||
}
|
||||
} else if (damtype == DT_CLAW) {
|
||||
if (dam == 0) {
|
||||
return "scratch";
|
||||
} else if (dam <= 5) {
|
||||
return "claw";
|
||||
} else if (dam <= 15) {
|
||||
return "rake";
|
||||
} else if (dam <= 30) {
|
||||
return "gouge";
|
||||
} else {
|
||||
return "eviscerate";
|
||||
}
|
||||
} else if (damtype == DT_SLASH) {
|
||||
if (dam == 0) {
|
||||
return "scratch";
|
||||
} else if (dam <= 10) {
|
||||
return "hit";
|
||||
} else if (dam <= 20) {
|
||||
return "slash";
|
||||
} else {
|
||||
return "slice";
|
||||
}
|
||||
} else if (damtype == DT_CHOP) {
|
||||
if (dam == 0) {
|
||||
return "hit";
|
||||
} else if (dam <= 10) {
|
||||
return "hack";
|
||||
} else {
|
||||
return "chop";
|
||||
}
|
||||
} else if (damtype == DT_BASH) {
|
||||
if (dam == 0) {
|
||||
return "whack";
|
||||
} else if (dam <= 5) {
|
||||
return "hit";
|
||||
} else if (dam <= 10) {
|
||||
return "bash";
|
||||
} else if (dam <= 15) {
|
||||
return "pummel";
|
||||
} else if (dam <= 20) {
|
||||
return "pound";
|
||||
} else {
|
||||
return "flatten";
|
||||
}
|
||||
} else if (damtype == DT_BITE) {
|
||||
if (dam == 0) {
|
||||
return "gnaw";
|
||||
} else if (dam <= 15) {
|
||||
return "bite";
|
||||
} else {
|
||||
return "savage";
|
||||
}
|
||||
}
|
||||
return "hit";
|
||||
}
|
||||
|
||||
char *getkillverb(enum DAMTYPE damtype, int dam) {
|
||||
if (damtype == DT_HOLY) {
|
||||
return "smite";
|
||||
}
|
||||
|
||||
if (dam >= 50) {
|
||||
if (damtype == DT_PIERCE) return "fatally stab";
|
||||
if (damtype == DT_BITE) return "gore";
|
||||
if (damtype == DT_CLAW) return "disembowel";
|
||||
if (damtype == DT_SLASH) return "behead"; // TODO: only if they have a head! otherwise "bisect"
|
||||
}
|
||||
|
||||
return "kill";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// return TRUE if no damage
|
||||
int getdamrange(object_t *o, int *min, int *max) {
|
||||
int mindam,maxdam;
|
||||
flag_t *f;
|
||||
|
||||
f = hasflag(o->flags, F_DAM);
|
||||
if (f) {
|
||||
int mod,ndice,sides;
|
||||
ndice = f->val[0];
|
||||
sides = f->val[1];
|
||||
if (f->val[2] == NA) {
|
||||
mod = 0;
|
||||
} else {
|
||||
mod = f->val[2];
|
||||
}
|
||||
|
||||
mindam = (ndice * 1) + mod;
|
||||
maxdam = (ndice * sides) + mod;
|
||||
} else {
|
||||
mindam = 0;
|
||||
maxdam = 0;
|
||||
}
|
||||
if (min) *min = mindam;
|
||||
if (max) *max = maxdam;
|
||||
}
|
||||
|
||||
|
||||
// roll for damage
|
||||
int getdamroll(object_t *o) {
|
||||
int dam;
|
||||
int ndice, sides, mod;
|
||||
flag_t *f;
|
||||
f = hasflag(o->flags, F_DAM);
|
||||
|
||||
if (f) {
|
||||
ndice = f->val[0];
|
||||
sides = f->val[1];
|
||||
if (f->val[2] != NA) {
|
||||
mod = f->val[2];
|
||||
} else {
|
||||
mod = 0;
|
||||
}
|
||||
dam = rolldie(ndice, sides) + mod;
|
||||
} else {
|
||||
// weapon does no damage
|
||||
dam = 0;
|
||||
}
|
||||
|
||||
return dam;
|
||||
}
|
||||
|
||||
|
||||
// determine attack type for lifeform.
|
||||
// add an object of this kind to the pile 'op'
|
||||
// return its type;
|
||||
objecttype_t *getunarmedweapon(lifeform_t *lf,obpile_t *op) {
|
||||
int nposs;
|
||||
flag_t *f;
|
||||
int sel;
|
||||
char poss[MAXPILEOBS][BUFLEN];
|
||||
|
||||
// pick a random attack type.
|
||||
nposs = 0;
|
||||
for (f = lf->flags->first ; f ; f = f->next) {
|
||||
if (f->id == F_UNARMEDATTACKOB) {
|
||||
strcpy(poss[nposs],f->text);
|
||||
nposs++;
|
||||
}
|
||||
}
|
||||
if (nposs > 0) {
|
||||
sel = rnd(0,nposs-1);
|
||||
addob(op, poss[sel]);
|
||||
}
|
||||
|
||||
if (op->first) {
|
||||
return op->first->type;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
|
7
attack.h
7
attack.h
|
@ -1,3 +1,8 @@
|
|||
#include "defs.h"
|
||||
|
||||
void doattack(lifeform_t *lf, lifeform_t *victim);
|
||||
int doattack(lifeform_t *lf, lifeform_t *victim);
|
||||
char *getattackverb(enum DAMTYPE damtype, int dam);
|
||||
char *getkillverb(enum DAMTYPE damtype, int dam);
|
||||
int getdamrange(object_t *o, int *min, int *max);
|
||||
int getdamroll(object_t *o);
|
||||
objecttype_t *getunarmedweapon(lifeform_t *lf, obpile_t *op);
|
||||
|
|
154
defs.h
154
defs.h
|
@ -7,6 +7,7 @@
|
|||
// save/load
|
||||
#define MAPDIR "data/maps"
|
||||
#define SAVEDIR "data/save"
|
||||
#define DUMMYCELLTYPE 0xabcd
|
||||
|
||||
// SPECIAL NUMBERS/CONSTANTS
|
||||
#define UNLIMITED (-9876)
|
||||
|
@ -32,6 +33,7 @@
|
|||
#define MAXPILEOBS 52
|
||||
|
||||
#define MAXRANDOMOBCANDIDATES 100
|
||||
#define MAXRANDOMLFCANDIDATES 100
|
||||
|
||||
#define MAX_MAPW 80
|
||||
#define MAX_MAPH 50
|
||||
|
@ -58,6 +60,12 @@
|
|||
//
|
||||
#define ANIMDELAY (1000000 / 100) // 1/100 of a second
|
||||
|
||||
|
||||
// askobject options
|
||||
#define AO_NONE 0
|
||||
#define AO_INCLUDENOTHING 1
|
||||
#define AO_ONLYEQUIPPED 2
|
||||
|
||||
// CONTROLLERS
|
||||
#define C_AI 0
|
||||
#define C_PLAYER 1
|
||||
|
@ -70,6 +78,8 @@
|
|||
#define SPEED_PICKUP 5
|
||||
#define SPEED_THROW 10
|
||||
#define SPEED_WAIT 10
|
||||
#define SPEED_READ 10
|
||||
#define SPEED_DRINK 5
|
||||
|
||||
|
||||
// DIRECTION TYPES
|
||||
|
@ -109,6 +119,29 @@
|
|||
#define CT_DOORCLOSED 5
|
||||
#define CT_LOOPCORRIDOR 6
|
||||
|
||||
// damage type
|
||||
enum DAMTYPE {
|
||||
DT_PIERCE,
|
||||
DT_SLASH,
|
||||
DT_CLAW,
|
||||
DT_BASH,
|
||||
DT_BITE,
|
||||
DT_CHOP,
|
||||
DT_PROJECTILE,
|
||||
DT_HOLY,
|
||||
};
|
||||
|
||||
// speeds
|
||||
#define SP_GODLIKE 1
|
||||
#define SP_ULTRAFAST 5
|
||||
#define SP_VERYFAST 10
|
||||
#define SP_FAST 15
|
||||
#define SP_NORMAL 20
|
||||
#define SP_SLOW 25
|
||||
#define SP_VERYSLOW 30
|
||||
#define SP_ULTRASLOW 35
|
||||
#define SP_SLOWEST 40
|
||||
|
||||
// Object Classes
|
||||
enum OBCLASS {
|
||||
OC_MONEY,
|
||||
|
@ -119,6 +152,7 @@ enum OBCLASS {
|
|||
OC_FOOD,
|
||||
OC_ROCK,
|
||||
OC_MISC,
|
||||
OC_SPELL,
|
||||
OC_NULL = -999
|
||||
};
|
||||
|
||||
|
@ -134,6 +168,7 @@ enum HABITAT {
|
|||
};
|
||||
|
||||
enum RARITY {
|
||||
RR_UNIQUE = 7,
|
||||
RR_NEVER = 6,
|
||||
RR_VERYRARE = 5,
|
||||
RR_RARE = 4,
|
||||
|
@ -145,6 +180,7 @@ enum RARITY {
|
|||
|
||||
enum RACE {
|
||||
R_BAT,
|
||||
R_RAT,
|
||||
R_GIANTFLY,
|
||||
R_GIANTBLOWFLY,
|
||||
R_HUMAN,
|
||||
|
@ -153,13 +189,20 @@ enum RACE {
|
|||
|
||||
// Object Materials
|
||||
enum MATERIAL {
|
||||
MT_NOTHING,
|
||||
MT_BONE,
|
||||
MT_STONE,
|
||||
MT_FIRE,
|
||||
MT_PLASTIC,
|
||||
MT_METAL,
|
||||
MT_GLASS,
|
||||
MT_FLESH,
|
||||
MT_WOOD,
|
||||
MT_GOLD
|
||||
MT_GOLD,
|
||||
MT_PAPER,
|
||||
MT_ICE,
|
||||
MT_WATER,
|
||||
MT_LEATHER
|
||||
};
|
||||
|
||||
// Object Types
|
||||
|
@ -172,6 +215,61 @@ enum OBTYPE {
|
|||
OT_CORPSEGOBLIN,
|
||||
OT_CORPSEBAT,
|
||||
OT_CORPSEFLY,
|
||||
// spells
|
||||
OT_S_RNDTELEPORT,
|
||||
OT_S_MAPPING,
|
||||
// potions
|
||||
OT_POT_HEALING,
|
||||
// scrolls
|
||||
OT_MAP,
|
||||
OT_SCR_RNDTELEPORT,
|
||||
OT_SCR_MAPPING,
|
||||
// misc objects
|
||||
OT_EMPTYFLASK,
|
||||
OT_BROKENGLASS,
|
||||
OT_PUDDLEWATER,
|
||||
// armour - feet
|
||||
OT_BOOTSLEATHER,
|
||||
// armour - hands
|
||||
OT_GLOVESLEATHER,
|
||||
// animal weapons
|
||||
OT_TEETHT,
|
||||
OT_CLAWST,
|
||||
OT_CLAWSS,
|
||||
OT_FISTS,
|
||||
// stabbing weapons
|
||||
OT_STEAKKNIFE,
|
||||
OT_DAGGER,
|
||||
OT_RAPIER,
|
||||
OT_TRIDENT,
|
||||
OT_QUICKBLADE,
|
||||
// slashing weapons
|
||||
OT_SCYTHE,
|
||||
OT_SHORTSWORD,
|
||||
OT_SCIMITAR,
|
||||
OT_LONGSWORD,
|
||||
// polearms
|
||||
OT_SPEAR,
|
||||
OT_QUARTERSTAFF,
|
||||
// bashing weapons
|
||||
OT_CLUB,
|
||||
OT_MACE,
|
||||
OT_MORNINGSTAR,
|
||||
OT_GREATCLUB,
|
||||
OT_SICKLE,
|
||||
// holy
|
||||
OT_HANDOFGOD,
|
||||
};
|
||||
|
||||
enum BODYPART {
|
||||
BP_WEAPON,
|
||||
BP_RIGHTHAND,
|
||||
BP_LEFTHAND,
|
||||
BP_HANDS,
|
||||
BP_HEAD,
|
||||
BP_BODY,
|
||||
BP_SHOULDERS,
|
||||
BP_FEET,
|
||||
};
|
||||
|
||||
enum FLAG {
|
||||
|
@ -180,16 +278,40 @@ enum FLAG {
|
|||
F_NO_PLURAL, // this obname doesn't need an 's' for plurals (eg. gold, money)
|
||||
F_NO_A, // this obname doesn't need to start with 'a' for singular (eg. gold)
|
||||
F_EDIBLE, // you can eat this. val2 = nutrition
|
||||
F_EQUIPPED, // val0 = where it is equipped. CLEAR WHEN OB MOVED!
|
||||
F_GOESON, // val0 = where it can be equipped.
|
||||
F_OBATTACKSPEED, // how long weapon takes to attack
|
||||
F_DAMTYPE, // val0 = damage type
|
||||
F_DAM, // val0 = ndice, val1 = nsidesondie, val2 = mod
|
||||
F_ACCURACY, // 100 - val0 = penalty to tohit% (ie. higher is better)
|
||||
F_TWOHANDED, // weapon uses two hands to weild
|
||||
F_UNIQUE, // only one may appear
|
||||
F_GLYPH, // override the glyph with the first char of text
|
||||
F_SHARP, // does damage when you step on it
|
||||
F_NOPICKUP, // cannot pick this up
|
||||
// armour flags
|
||||
F_ARMOURRATING, // val0 * 2 = pct of damage reduced
|
||||
// scroll flags
|
||||
F_LINKSPELL, // val0 = spell this scroll will cast when read
|
||||
// ob identification flags
|
||||
F_HASHIDDENNAME, // whether this object class has a hidden name
|
||||
F_IDENTIFIED, // whether this object is fully identified
|
||||
// lifeform flags
|
||||
F_STARTOB, // val0 = %chance of starting with it, text = ob name
|
||||
F_STARTOBDT, // val0 = %chance of starting with damtype val1
|
||||
F_CORPSETYPE, // text field specifies what corpse obtype to leave
|
||||
F_LFATTACKDELAY, // how long this race takes to attack
|
||||
F_FLYING, // lf is flying
|
||||
F_HOSTILE, // lf will attack anything the player if in sight
|
||||
F_NODEATHANNOUNCE, // don't say 'the xx dies' if this lf dies
|
||||
F_TARGET, // lf will attack this lf id
|
||||
F_ATTACKSPEED, // override default attack speed
|
||||
F_MOVESPEED, // override default move speed
|
||||
F_RARITY, // val[0] = habitat, val[1] = rarity
|
||||
F_NUMAPPEAR, // when randomly appearing, can have > 1. val[0] = min, val[1] = max
|
||||
F_HITDICE, // val0: # d4 to roll for hitdice. val1: +xx
|
||||
// COMBAT
|
||||
F_UNARMEDATTACKOB, // objecttype id to use when attacking unarmed
|
||||
F_EVASION, // % chance of evading an attack
|
||||
//
|
||||
F_NULL = -1
|
||||
};
|
||||
|
@ -204,6 +326,12 @@ enum FLAG {
|
|||
#define B_FALSE (0)
|
||||
#define B_TRUE (-1)
|
||||
|
||||
#define B_UNKNOWN (0)
|
||||
#define B_KNOWN (-1)
|
||||
|
||||
#define B_NOBADMOVES (0)
|
||||
#define B_BADMOVESOK (1)
|
||||
|
||||
#define B_NOSTACK (0)
|
||||
#define B_STACK (-1)
|
||||
#define B_STACKOK (-1)
|
||||
|
@ -225,7 +353,13 @@ enum ERROR {
|
|||
E_OK = 0,
|
||||
E_WALLINWAY = 1,
|
||||
E_LFINWAY = 2,
|
||||
E_NOSPACE = 3
|
||||
E_NOSPACE = 3,
|
||||
E_SELNOTHING = 4,
|
||||
E_ALREADYUSING = 5,
|
||||
E_WEARINGSOMETHINGELSE = 6,
|
||||
E_NOUNARMEDATTACK = 7,
|
||||
E_NOTEQUIPPED = 8,
|
||||
E_NOPICKUP = 9
|
||||
};
|
||||
|
||||
typedef struct map_s {
|
||||
|
@ -281,6 +415,7 @@ typedef struct lifeform_s {
|
|||
int id;
|
||||
int controller;
|
||||
struct race_s *race;
|
||||
int level;
|
||||
int hp,maxhp;
|
||||
int alive;
|
||||
char *lastdam;
|
||||
|
@ -288,6 +423,8 @@ typedef struct lifeform_s {
|
|||
int timespent;
|
||||
int sorted;
|
||||
|
||||
float forgettimer;
|
||||
|
||||
struct obpile_s *pack;
|
||||
|
||||
struct flagpile_s *flags;
|
||||
|
@ -326,15 +463,24 @@ typedef struct flag_s {
|
|||
} flag_t;
|
||||
|
||||
typedef struct material_s {
|
||||
int id;
|
||||
enum MATERIAL id;
|
||||
char *name;
|
||||
struct material_s *next,*prev;
|
||||
} material_t;
|
||||
|
||||
typedef struct knowledge_s {
|
||||
enum OBTYPE id;
|
||||
char *hiddenname;
|
||||
int known;
|
||||
struct knowledge_s *next, *prev;
|
||||
} knowledge_t;
|
||||
|
||||
typedef struct objectclass_s {
|
||||
enum OBCLASS id;
|
||||
char *name;
|
||||
char *desc;
|
||||
char glyph;
|
||||
struct flagpile_s *flags;
|
||||
struct objectclass_s *next, *prev;
|
||||
} objectclass_t;
|
||||
|
||||
|
|
|
@ -6,3 +6,7 @@ In defs.h:
|
|||
In objects.c:
|
||||
define the class with addoc()
|
||||
add the class to sortorder[] at the top
|
||||
findotn() must know how to un-pluralise the name
|
||||
|
||||
In text.c:
|
||||
makeplural() must know about the name
|
||||
|
|
10
flag.c
10
flag.c
|
@ -29,7 +29,7 @@ flag_t *addflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char
|
|||
|
||||
// first blank values
|
||||
for (i = 0; i < 3; i++) {
|
||||
f->val[i] = 0;
|
||||
f->val[i] = NA;
|
||||
}
|
||||
|
||||
f->val[0] = val1;
|
||||
|
@ -39,7 +39,7 @@ flag_t *addflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char
|
|||
f->nvals++;
|
||||
}
|
||||
if (val3 != NA) {
|
||||
f->val[2] = val2;
|
||||
f->val[2] = val3;
|
||||
f->nvals++;
|
||||
}
|
||||
if (text) {
|
||||
|
@ -74,9 +74,9 @@ flag_t *hasflagval(flagpile_t *fp, int id, int val1, int val2, int val3, char *t
|
|||
flag_t *f;
|
||||
for (f = fp->first ; f ; f = f->next) {
|
||||
if (f->id == id) {
|
||||
if ( ((val1 == -1) || (f->val[0] == val1)) &&
|
||||
((val2 == -1) || (f->val[1] == val2)) &&
|
||||
((val3 == -1) || (f->val[2] == val3)) &&
|
||||
if ( ((val1 == NA) || (f->val[0] == val1)) &&
|
||||
((val2 == NA) || (f->val[1] == val2)) &&
|
||||
((val3 == NA) || (f->val[2] == val3)) &&
|
||||
((text == NULL) || strstr(f->text, text))) {
|
||||
return f;
|
||||
}
|
||||
|
|
622
io.c
622
io.c
|
@ -2,8 +2,11 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ncurses.h>
|
||||
#include "attack.h"
|
||||
#include "defs.h"
|
||||
#include "flag.h"
|
||||
#include "io.h"
|
||||
#include "lf.h"
|
||||
#include "map.h"
|
||||
#include "move.h"
|
||||
#include "nexus.h"
|
||||
|
@ -18,6 +21,7 @@ extern enum ERROR reason;
|
|||
|
||||
extern FILE *logfile;
|
||||
extern enum OBCLASS sortorder[];
|
||||
extern knowledge_t *knowledge;
|
||||
|
||||
extern int gamestarted;
|
||||
|
||||
|
@ -169,7 +173,15 @@ cell_t *askcoords(char *prompt) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
object_t *askobject(obpile_t *op, char *prompt, int *count) {
|
||||
object_t *askobject(obpile_t *op, char *prompt, int *count, int opts) {
|
||||
doaskobject(op, prompt, count, opts, OC_NULL);
|
||||
}
|
||||
|
||||
object_t *askobjectofclass(obpile_t *op, char *prompt, int *count, int opts, enum OBCLASS obclass) {
|
||||
doaskobject(op, prompt, count, opts, obclass);
|
||||
}
|
||||
|
||||
object_t *doaskobject(obpile_t *op, char *prompt, int *count, int opts, enum OBCLASS obclass) {
|
||||
int c,i;
|
||||
object_t *mylist[MAXPILEOBS+1];
|
||||
char myletters[MAXPILEOBS+1];
|
||||
|
@ -177,10 +189,16 @@ object_t *askobject(obpile_t *op, char *prompt, int *count) {
|
|||
int firstob = 0;
|
||||
int nextpage = -1;
|
||||
int lastline = SCREENH-2;
|
||||
char buf[BUFLEN];
|
||||
char buf[BUFLEN],buf2[BUFLEN];
|
||||
int finished;
|
||||
char nextlet = 'a';
|
||||
int useobletters;
|
||||
objectclass_t *wantoc;
|
||||
flag_t *f;
|
||||
|
||||
reason = E_OK;
|
||||
|
||||
wantoc = findoc(obclass); // might be null if OC_NULL was passed.
|
||||
|
||||
// if picking form a player's pack, use the object's letters.
|
||||
// otherwise just label them a, b, c, etc.
|
||||
|
@ -195,16 +213,26 @@ object_t *askobject(obpile_t *op, char *prompt, int *count) {
|
|||
i = 0;
|
||||
while (sortorder[c] != OC_NULL) {
|
||||
object_t *o;
|
||||
if (!wantoc || (sortorder[c] == wantoc->id)) {
|
||||
// add all objects of this class
|
||||
for (o = op->first ; o ; o = o->next) {
|
||||
if (o->type->obclass->id == sortorder[c]) {
|
||||
int ok;
|
||||
// can we include this object?
|
||||
ok = B_TRUE;
|
||||
if ((opts & AO_ONLYEQUIPPED) && !hasflag(o->flags, F_EQUIPPED)) {
|
||||
ok = B_FALSE;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
mylist[i] = o;
|
||||
myletters[i] = nextlet;
|
||||
if (++nextlet > 'z') nextlet = 'A';
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
c++;
|
||||
}
|
||||
mylist[i] = NULL;
|
||||
|
@ -219,9 +247,13 @@ object_t *askobject(obpile_t *op, char *prompt, int *count) {
|
|||
int y;
|
||||
int ch;
|
||||
|
||||
|
||||
wclear(mainwin);
|
||||
|
||||
|
||||
// list the objects
|
||||
y = 2;
|
||||
|
||||
for (i = firstob ; (mylist[i] != NULL) && (y < lastline); i++) {
|
||||
if (mylist[i]->type->obclass->id != lastclass) {
|
||||
objectclass_t *oc;
|
||||
|
@ -232,10 +264,23 @@ object_t *askobject(obpile_t *op, char *prompt, int *count) {
|
|||
|
||||
y++;
|
||||
}
|
||||
// print object name
|
||||
getobname(mylist[i], buf,mylist[i]->amt);
|
||||
mvwprintw(mainwin, y, 0, " %c - %s",
|
||||
useobletters ? mylist[i]->letter : myletters[i],
|
||||
sprintf(buf2, " %c - %s", useobletters ? mylist[i]->letter : myletters[i],
|
||||
buf);
|
||||
f = hasflag(mylist[i]->flags,F_EQUIPPED);
|
||||
if (f) {
|
||||
if (f->val[0] == BP_WEAPON) {
|
||||
strcat(buf2, " (weapon)");
|
||||
} else {
|
||||
strcat(buf2, " (");
|
||||
strcat(buf2, getbodypartequipname(f->val[0]));
|
||||
strcat(buf2, " ");
|
||||
strcat(buf2, getbodypartname(f->val[0]));
|
||||
strcat(buf2, ")");
|
||||
}
|
||||
}
|
||||
mvwprintw(mainwin, y, 0, buf2);
|
||||
y++;
|
||||
}
|
||||
if (mylist[i] == NULL) {
|
||||
|
@ -245,9 +290,12 @@ object_t *askobject(obpile_t *op, char *prompt, int *count) {
|
|||
}
|
||||
// draw prompt
|
||||
if (strlen(numstring) > 0) {
|
||||
mvwprintw(mainwin, 0, 0, "%s (ESC to quit) [%s]: ",prompt, numstring);
|
||||
mvwprintw(mainwin, 0, 0, "%s (%sESC to quit) [%s]: ",prompt,
|
||||
(opts & AO_INCLUDENOTHING) ? "- for nothing, " : "",
|
||||
numstring);
|
||||
} else {
|
||||
mvwprintw(mainwin, 0, 0, "%s (ESC to quit): ", prompt);
|
||||
mvwprintw(mainwin, 0, 0, "%s (%sESC to quit): ", prompt,
|
||||
(opts & AO_INCLUDENOTHING) ? "- for nothing, " : "");
|
||||
}
|
||||
if (nextpage != -1) {
|
||||
mvwprintw(mainwin, y, 0, "-- More --");
|
||||
|
@ -269,7 +317,7 @@ object_t *askobject(obpile_t *op, char *prompt, int *count) {
|
|||
} else {
|
||||
firstob = nextpage;
|
||||
}
|
||||
} else if (isalpha(ch)) {
|
||||
} else if (isalpha(ch) || (ch == '$')) {
|
||||
object_t *o;
|
||||
// describe that object
|
||||
if (useobletters) {
|
||||
|
@ -292,20 +340,27 @@ object_t *askobject(obpile_t *op, char *prompt, int *count) {
|
|||
*count = o->amt;
|
||||
}
|
||||
// display game windows again
|
||||
clearmsg();
|
||||
drawscreen();
|
||||
return o;
|
||||
}
|
||||
} else if ((ch == '-') && (opts & AO_INCLUDENOTHING)) { // select nothing
|
||||
reason = E_SELNOTHING;
|
||||
// display game windows again
|
||||
clearmsg();
|
||||
drawscreen();
|
||||
return NULL;
|
||||
} else if (isdigit(ch)) {
|
||||
char temp[2];
|
||||
temp[0] = ch;
|
||||
temp[1] = '\0';
|
||||
strcat(numstring, temp);
|
||||
*count = atoi(numstring);
|
||||
if (count) *count = atoi(numstring);
|
||||
} else if (ch == 8) { // backspace
|
||||
if (strlen(numstring) > 0) {
|
||||
// remove last letter of number string
|
||||
numstring[strlen(numstring)-1] = '\0';
|
||||
*count = atoi(numstring);
|
||||
if (count) *count = atoi(numstring);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -315,6 +370,9 @@ object_t *askobject(obpile_t *op, char *prompt, int *count) {
|
|||
}
|
||||
}
|
||||
|
||||
// clear msg bar
|
||||
clearmsg();
|
||||
|
||||
// display game windows again
|
||||
drawscreen();
|
||||
return NULL;
|
||||
|
@ -397,13 +455,18 @@ void describeob(object_t *o) {
|
|||
char buf[BUFLEN];
|
||||
int y;
|
||||
material_t *m;
|
||||
flag_t *f;
|
||||
|
||||
wclear(mainwin);
|
||||
|
||||
// title
|
||||
getobname(o, buf,o->amt);
|
||||
mvwprintw(mainwin, 0, 0, buf);
|
||||
if (isknown(o)) {
|
||||
mvwprintw(mainwin, 2, 0, o->type->desc);
|
||||
} else {
|
||||
mvwprintw(mainwin, 2, 0, o->type->obclass->desc);
|
||||
}
|
||||
|
||||
// properties
|
||||
y = 4;
|
||||
|
@ -414,6 +477,39 @@ void describeob(object_t *o) {
|
|||
} else {
|
||||
mvwprintw(mainwin, y, 0, "They weigh %0.1fkg (%0.1f each).",(o->weight * o->amt), o->weight);
|
||||
}
|
||||
y++;
|
||||
|
||||
// weapons?
|
||||
if (o->type->obclass->id == OC_WEAPON) {
|
||||
f = hasflag(o->flags, F_DAMTYPE);
|
||||
if (f) {
|
||||
int damtype;
|
||||
int anydam,mindam,maxdam;
|
||||
damtype = f->val[0];
|
||||
getdamrange(o, &mindam, &maxdam);
|
||||
f = hasflag(o->flags, F_DAM);
|
||||
if (f) {
|
||||
if (f->val[2] == NA) {
|
||||
mvwprintw(mainwin, y, 0, "It deals %d-%d %s damage (%dd%d).",mindam,maxdam,
|
||||
getdamname(damtype), f->val[0], f->val[1]);
|
||||
} else {
|
||||
mvwprintw(mainwin, y, 0, "It deals %d-%d %s damage (%dd%d%c%d).",mindam,maxdam,
|
||||
getdamname(damtype), f->val[0], f->val[1], (f->val[2] > 0) ? '+' : '-', abs(f->val[2]));
|
||||
}
|
||||
y++;
|
||||
} else {
|
||||
mvwprintw(mainwin, y, 0, "It deals %s damage.",getdamname(damtype));
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
f = hasflag(o->flags, F_OBATTACKSPEED);
|
||||
if (f) {
|
||||
getspeedname(f->val[0], buf);
|
||||
mvwprintw(mainwin, y, 0, "Its attack rate is %s.",buf);
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
wrefresh(mainwin);
|
||||
|
||||
|
@ -425,7 +521,7 @@ void dodrop(obpile_t *op) {
|
|||
object_t *o;
|
||||
char buf[BUFLEN];
|
||||
int count = ALL;
|
||||
o = askobject(op, "Drop what", &count);
|
||||
o = askobject(op, "Drop what", &count, AO_NONE);
|
||||
if (o) {
|
||||
getobname(o, buf, count);
|
||||
o = moveob(o, op->owner->cell->obpile, count);
|
||||
|
@ -452,7 +548,93 @@ void dodrop(obpile_t *op) {
|
|||
}
|
||||
}
|
||||
|
||||
void dopickup(lifeform_t *lf, obpile_t *op) {
|
||||
int dowear(obpile_t *op) {
|
||||
object_t *o,*oo;
|
||||
char buf[BUFLEN];
|
||||
int count = ALL;
|
||||
int rv;
|
||||
flag_t *f;
|
||||
o = askobjectofclass(op, "Wear what", NULL, AO_NONE, OC_ARMOUR);
|
||||
if (o) {
|
||||
wear(player, o);
|
||||
} else {
|
||||
rv = B_TRUE;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
int doweild(obpile_t *op) {
|
||||
object_t *o,*oo;
|
||||
char buf[BUFLEN];
|
||||
int count = ALL;
|
||||
int rv;
|
||||
flag_t *f;
|
||||
o = askobject(op, "Weild what", &count, AO_INCLUDENOTHING);
|
||||
if (o) {
|
||||
rv = weild(player, o);
|
||||
} else if (reason == E_SELNOTHING) {
|
||||
// ie. unweild
|
||||
rv = weild(player, NULL);
|
||||
} else {
|
||||
rv = B_TRUE;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void doknowledgelist(void) {
|
||||
knowledge_t *k;
|
||||
int y = 0;
|
||||
int numfound = 0;
|
||||
int c;
|
||||
|
||||
wclear(mainwin);
|
||||
mvwprintw(mainwin, y, 0, "Current Knowledge");
|
||||
y++;
|
||||
y++;
|
||||
for (c = 0; sortorder[c] != OC_NULL ; c++) {
|
||||
int first = B_TRUE;
|
||||
for (k = knowledge ; k ; k = k->next) {
|
||||
if (k->known) {
|
||||
objecttype_t *ot;
|
||||
ot = findot(k->id);
|
||||
if (ot->obclass->id == c) {
|
||||
if (first) {
|
||||
mvwprintw(mainwin, y, 0, "%s", ot->obclass->name);
|
||||
y++;
|
||||
|
||||
first = B_FALSE;
|
||||
}
|
||||
|
||||
mvwprintw(mainwin, y, 0, " %-20s (%s)",ot->name, k->hiddenname);
|
||||
y++;
|
||||
|
||||
numfound++;
|
||||
|
||||
if (y >= (SCREENH-1)) {
|
||||
mvwprintw(mainwin, y, 0, "--More--");
|
||||
wrefresh(mainwin);
|
||||
getch();
|
||||
wclear(mainwin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numfound == 0) {
|
||||
mvwprintw(mainwin, y, 0, "You don't know much.");
|
||||
}
|
||||
wrefresh(mainwin);
|
||||
getch();
|
||||
|
||||
clearmsg();
|
||||
drawscreen();
|
||||
}
|
||||
|
||||
int dopickup(obpile_t *op) {
|
||||
int obcount;
|
||||
object_t *o = NULL;
|
||||
int howmany = ALL;
|
||||
|
@ -461,64 +643,94 @@ void dopickup(lifeform_t *lf, obpile_t *op) {
|
|||
obcount = countobs(op);
|
||||
// anything here?
|
||||
if (obcount == 0) {
|
||||
if (lf->controller == C_PLAYER) {
|
||||
msg("There is nothing here to pick up!");
|
||||
}
|
||||
return;
|
||||
return B_TRUE;
|
||||
} else if (obcount == 1) {
|
||||
// just get it
|
||||
o = op->first;
|
||||
howmany = ALL;
|
||||
} else {
|
||||
// prompt which one to pick up
|
||||
o = askobject(op, "Pick up what", &howmany);
|
||||
o = askobject(op, "Pick up what", &howmany, AO_NONE);
|
||||
}
|
||||
|
||||
if (!o) {
|
||||
return;
|
||||
}
|
||||
|
||||
getobname(o, buf, howmany);
|
||||
|
||||
// try to move whatever was selected
|
||||
o = moveob(o, lf->pack, howmany);
|
||||
if (o) { // if pickup was successful...
|
||||
if (lf->controller == C_PLAYER) {
|
||||
msg("You pick up %s.",buf);
|
||||
}
|
||||
taketime(lf, (SPEED_PICKUP * howmany));
|
||||
if (o) {
|
||||
pickup(player, o, howmany);
|
||||
} else {
|
||||
// tell the player why!
|
||||
if (lf->controller == C_PLAYER) {
|
||||
switch (reason) {
|
||||
case E_NOSPACE:
|
||||
msg("Your pack is too full to fit any more objects.");
|
||||
break;
|
||||
default:
|
||||
msg("For some reason, you cannot pick up %s!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return B_TRUE;
|
||||
}
|
||||
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
void doinventory(obpile_t *op) {
|
||||
object_t *o;
|
||||
o = askobject(op, "Select object to describe", NULL);
|
||||
o = askobject(op, "Select object to describe", NULL, AO_NONE);
|
||||
while (o) {
|
||||
// describe it
|
||||
describeob(o);
|
||||
// ask for another one
|
||||
o = askobject(op, "Select object to describe", NULL);
|
||||
o = askobject(op, "Select object to describe", NULL, AO_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
void doquaff(obpile_t *op) {
|
||||
object_t *o;
|
||||
char buf[BUFLEN],buf2[BUFLEN];
|
||||
|
||||
// ask which object to quaff
|
||||
o = askobjectofclass(op, "Quaff what", NULL, AO_NONE, OC_POTION);
|
||||
if (o) {
|
||||
if (isdrinkable(o)) {
|
||||
quaff(player, o);
|
||||
} else {
|
||||
msg("You can't drink that!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void doread(obpile_t *op) {
|
||||
object_t *o;
|
||||
char buf[BUFLEN],buf2[BUFLEN];
|
||||
|
||||
// ask which object to read
|
||||
o = askobjectofclass(op, "Read what", NULL, AO_NONE, OC_SCROLL);
|
||||
if (o) {
|
||||
if (isreadable(o)) {
|
||||
read(player, o);
|
||||
} else {
|
||||
msg("You can't read that!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int dotakeoff(obpile_t *op) {
|
||||
object_t *o;
|
||||
char buf[BUFLEN],buf2[BUFLEN];
|
||||
flag_t *f;
|
||||
int rv;
|
||||
|
||||
// ask which object to read
|
||||
o = askobjectofclass(op, "Take off what", NULL, AO_ONLYEQUIPPED, OC_ARMOUR);
|
||||
if (o) {
|
||||
f = hasflag(o->flags, F_EQUIPPED);
|
||||
if (f) {
|
||||
rv = takeoff(player, o);
|
||||
|
||||
} else {
|
||||
msg("You are not wearing that!");
|
||||
rv = B_TRUE;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void dothrow(obpile_t *op) {
|
||||
object_t *o;
|
||||
char buf[BUFLEN],buf2[BUFLEN];
|
||||
|
||||
// ask which object to throw
|
||||
o = askobject(op, "Throw what", NULL);
|
||||
o = askobject(op, "Throw what", NULL, AO_NONE);
|
||||
if (o) {
|
||||
cell_t *where;
|
||||
getobname(o, buf, 1);
|
||||
|
@ -539,9 +751,27 @@ void dothrow(obpile_t *op) {
|
|||
}
|
||||
}
|
||||
|
||||
// draw a cell which we can't see
|
||||
void drawunviscell(cell_t *cell, int x, int y) {
|
||||
char glyph;
|
||||
if (cell->type->glyph == '.') {
|
||||
glyph = ' ';
|
||||
} else {
|
||||
glyph = cell->type->glyph;
|
||||
}
|
||||
|
||||
mvwprintw(gamewin, y, x, "%c", glyph);
|
||||
|
||||
}
|
||||
|
||||
void drawcell(cell_t *cell, int x, int y) {
|
||||
// draw ground
|
||||
mvwprintw(gamewin, y, x, "%c", cell->type->glyph);
|
||||
}
|
||||
|
||||
void drawcellwithcontents(cell_t *cell, int x, int y) {
|
||||
if (cell->lf) { // lifeform here?
|
||||
// TODO: draw the lf's race glyph
|
||||
// draw the lf's race glyph
|
||||
mvwprintw(gamewin, y, x, "%c", cell->lf->race->glyph);
|
||||
} else if (countobs(cell->obpile) > 0) {
|
||||
object_t *o;
|
||||
|
@ -556,7 +786,7 @@ void drawcell(cell_t *cell, int x, int y) {
|
|||
for (o = cell->obpile->last ; o ; o = o->prev) {
|
||||
if (o->type->obclass->id == sortorder[c]) {
|
||||
// draw it
|
||||
mvwprintw(gamewin, y, x, "%c", o->type->obclass->glyph);
|
||||
mvwprintw(gamewin, y, x, "%c", getglyph(o));
|
||||
drawn = B_TRUE;
|
||||
break;
|
||||
}
|
||||
|
@ -570,8 +800,7 @@ void drawcell(cell_t *cell, int x, int y) {
|
|||
mvwprintw(gamewin, y, x, "%c", cell->obpile->first->type->obclass->glyph);
|
||||
}
|
||||
} else {
|
||||
// draw ground
|
||||
mvwprintw(gamewin, y, x, "%c", cell->type->glyph);
|
||||
drawcell(cell, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -594,7 +823,9 @@ void drawlevelfor(lifeform_t *lf) {
|
|||
cell = getcellat(map, x, y);
|
||||
if (cell) {
|
||||
if (haslos(lf, cell)) {
|
||||
drawcell(cell, x-viewx, y-viewy);
|
||||
drawcellwithcontents(cell, x-viewx, y-viewy);
|
||||
} else if (cell->known) {
|
||||
drawunviscell(cell, x-viewx, y-viewy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -672,15 +903,34 @@ void handleinput(void) {
|
|||
msg("Another thing is about to happen now.");
|
||||
msg("Too many things are happening!");
|
||||
break;
|
||||
// player commands
|
||||
case 'i': // inventory
|
||||
doinventory(player->pack);
|
||||
break;
|
||||
case '\\': // list knowledge
|
||||
doknowledgelist();
|
||||
break;
|
||||
// object functions
|
||||
case 'd': // drop
|
||||
dodrop(player->pack);
|
||||
break;
|
||||
case 'i': // inventory
|
||||
doinventory(player->pack);
|
||||
case 'W': // wear
|
||||
dowear(player->pack);
|
||||
break;
|
||||
case 'w': // weild
|
||||
doweild(player->pack);
|
||||
break;
|
||||
case 'T': // takeoff
|
||||
dotakeoff(player->pack);
|
||||
break;
|
||||
case ',': // pickup
|
||||
dopickup(player, player->cell->obpile);
|
||||
dopickup(player->cell->obpile);
|
||||
break;
|
||||
case 'r': // read
|
||||
doread(player->pack);
|
||||
break;
|
||||
case 'q': // quaff
|
||||
doquaff(player->pack);
|
||||
break;
|
||||
case 't': // throw
|
||||
dothrow(player->pack);
|
||||
|
@ -721,6 +971,88 @@ int keycodetokey(int keycode) {
|
|||
return keystroke;
|
||||
}
|
||||
|
||||
|
||||
int pickup(lifeform_t *lf, object_t *what, int howmany) {
|
||||
char buf[BUFLEN];
|
||||
char obname[BUFLEN];
|
||||
object_t *o;
|
||||
flag_t *f;
|
||||
|
||||
if (!what) {
|
||||
return B_TRUE;
|
||||
}
|
||||
getobname(what, obname, howmany);
|
||||
|
||||
if (howmany == ALL) howmany = o->amt;
|
||||
|
||||
if (!canpickup(lf, what)){
|
||||
// tell the player why!
|
||||
if (lf->controller == C_PLAYER) {
|
||||
switch (reason) {
|
||||
case E_NOSPACE:
|
||||
msg("Your pack is too full to fit any more objects.");
|
||||
break;
|
||||
default:
|
||||
msg("For some reason, you cannot pick up %s!",obname);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return B_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// some checks first...
|
||||
f = hasflag(what->flags, F_SHARP);
|
||||
if (f) {
|
||||
object_t *gloves;
|
||||
gloves = getequippedob(lf->pack, BP_HANDS);
|
||||
if (!gloves) {
|
||||
char *newname;
|
||||
getobname(what, buf, 1);
|
||||
newname = strdup(buf);
|
||||
strrep(newname, "a ", "the ");
|
||||
|
||||
if (lf->controller == C_PLAYER) {
|
||||
msg("Ow! You cut your finger on %s.", newname);
|
||||
}
|
||||
taketime(lf, SPEED_PICKUP);
|
||||
|
||||
sprintf(buf, "stepping on %s", obname);
|
||||
losehp(lf, rnd(1,2), DT_SLASH, NULL, buf);
|
||||
|
||||
return B_TRUE;
|
||||
free(newname);
|
||||
}
|
||||
}
|
||||
|
||||
// try to move whatever was selected
|
||||
o = moveob(what, lf->pack, howmany);
|
||||
if (o) { // if pickup was successful...
|
||||
if (lf->controller == C_PLAYER) {
|
||||
msg("You pick up %c - %s.",o->letter, obname);
|
||||
}
|
||||
/*
|
||||
taketime(lf, (SPEED_PICKUP * howmany));
|
||||
*/
|
||||
taketime(lf, SPEED_PICKUP);
|
||||
} else {
|
||||
// tell the player why!
|
||||
if (lf->controller == C_PLAYER) {
|
||||
switch (reason) {
|
||||
case E_NOSPACE:
|
||||
msg("Your pack is too full to fit any more objects.");
|
||||
break;
|
||||
default:
|
||||
msg("For some reason, you cannot pick up %s!",obname);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return B_TRUE;
|
||||
}
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
|
||||
void dblog(char *format, ... ) {
|
||||
char buf[HUGEBUFLEN];
|
||||
va_list args;
|
||||
|
@ -745,7 +1077,8 @@ void dblog(char *format, ... ) {
|
|||
|
||||
// force a '--more--' prompt
|
||||
void more(void) {
|
||||
msg("%100s"," ");
|
||||
msg("^");
|
||||
drawmsg();
|
||||
}
|
||||
|
||||
void msg(char *format, ... ) {
|
||||
|
@ -768,8 +1101,9 @@ void msg(char *format, ... ) {
|
|||
p = msgbuf;
|
||||
}
|
||||
|
||||
// ie. can we fit the new text + '--more--' ?
|
||||
if (strlen(p) + strlen(buf) + strlen(MORESTRING) >= SCREENW) {
|
||||
// ie. can the message buffer fit:
|
||||
// what is already there + 2 spaces + the new text + '--more--' ?
|
||||
if (strlen(p) + 2 + strlen(buf) + strlen(MORESTRING) >= SCREENW) {
|
||||
strcat(msgbuf, "^");
|
||||
} else {
|
||||
if (strlen(msgbuf) > 0) {
|
||||
|
@ -886,12 +1220,54 @@ int savegame(void) {
|
|||
return B_TRUE;
|
||||
}
|
||||
savelf(f, player);
|
||||
saveknowledge(f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
int takeoff(lifeform_t *lf, object_t *o) {
|
||||
flag_t *f;
|
||||
char obname[BUFLEN];
|
||||
char buf[BUFLEN];
|
||||
|
||||
getobname(o, obname, 1);
|
||||
|
||||
if (!cantakeoff(lf, o)) {
|
||||
switch (reason) {
|
||||
case E_NOTEQUIPPED:
|
||||
if (lf->controller == C_PLAYER) {
|
||||
msg("You are not wearing that!");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (lf->controller == C_PLAYER) {
|
||||
msg("For some reason, you cannot take that off!");
|
||||
}
|
||||
break;
|
||||
}
|
||||
return B_TRUE;
|
||||
}
|
||||
|
||||
// remove the equipped flag
|
||||
f = hasflag(o->flags, F_EQUIPPED);
|
||||
killflag(f);
|
||||
|
||||
taketime(lf, getmovespeed(lf));
|
||||
if (gamestarted) {
|
||||
if (lf->controller == C_PLAYER) {
|
||||
msg("You take off %s.", obname);
|
||||
} else if (haslos(player, lf->cell)) {
|
||||
getlfname(lf, buf);
|
||||
capitalise(buf);
|
||||
msg("%s takes off %s.", buf, obname);
|
||||
}
|
||||
}
|
||||
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
void tombstone(lifeform_t *lf) {
|
||||
// clear screen
|
||||
wclear(mainwin);
|
||||
|
@ -919,3 +1295,141 @@ void tombstone(lifeform_t *lf) {
|
|||
}
|
||||
|
||||
|
||||
int wear(lifeform_t *lf, object_t *o) {
|
||||
int rv = B_FALSE;
|
||||
char buf[BUFLEN],obname[BUFLEN];
|
||||
flag_t *f;
|
||||
int bp;
|
||||
|
||||
getobname(o, obname, 1);
|
||||
|
||||
if (!canwear(lf, o)) {
|
||||
if (gamestarted) {
|
||||
switch (reason) {
|
||||
case E_ALREADYUSING:
|
||||
if (lf->controller == C_PLAYER) {
|
||||
msg("You're already wearing that!");
|
||||
}
|
||||
break;
|
||||
case E_WEARINGSOMETHINGELSE:
|
||||
f = hasflag(o->flags, F_GOESON);
|
||||
if (f) {
|
||||
object_t *inway;
|
||||
// find what else is there
|
||||
inway = getequippedob(lf->pack, f->val[0]);
|
||||
getobname(inway,buf, 1);
|
||||
if (lf->controller == C_PLAYER) {
|
||||
msg("You need to remove your %s first!",buf);
|
||||
}
|
||||
} else {
|
||||
// should never happen
|
||||
msg("You can't wear that!");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (lf->controller == C_PLAYER) {
|
||||
msg("You can't wear that!");
|
||||
}
|
||||
break;
|
||||
}
|
||||
} // end if gamestarted
|
||||
return B_TRUE;
|
||||
} // end if !canwear
|
||||
|
||||
|
||||
// wear it
|
||||
f = hasflag(o->flags, F_GOESON);
|
||||
bp = f->val[0];
|
||||
|
||||
addflag(o->flags, F_EQUIPPED, bp, -1, -1, NULL);
|
||||
taketime(lf, getmovespeed(lf));
|
||||
if (gamestarted) {
|
||||
if (lf->controller == C_PLAYER) {
|
||||
msg("You are now wearing %s.", obname);
|
||||
} else if (haslos(player, lf->cell)) {
|
||||
getlfname(lf, buf);
|
||||
capitalise(lf);
|
||||
msg("%s puts on %s.", buf, obname);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int weild(lifeform_t *lf, object_t *o) {
|
||||
char buf[BUFLEN];
|
||||
flag_t *f;
|
||||
object_t *oo;
|
||||
|
||||
if (o) {
|
||||
getobname(o, buf, o->amt);
|
||||
}
|
||||
|
||||
// TODO: any reason you might not be able to weild it at all?
|
||||
// ie. too big, already have a cursed one, etc?
|
||||
|
||||
if (!canweild(lf, o)) {
|
||||
if (gamestarted) {
|
||||
if (lf->controller == C_PLAYER) {
|
||||
switch (reason) {
|
||||
case E_ALREADYUSING:
|
||||
msg("You are already weilding that!");
|
||||
break;
|
||||
case E_NOUNARMEDATTACK:
|
||||
msg("You cannot fight without a weapon!");
|
||||
break;
|
||||
default:
|
||||
msg("For some reason, you cannot pick up %s!",buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return B_TRUE;
|
||||
}
|
||||
|
||||
// anything else weilded?
|
||||
for (oo = lf->pack->first ; oo ; oo = oo->next) {
|
||||
f = hasflagval(oo->flags, F_EQUIPPED, BP_WEAPON, -1, -1, NULL);
|
||||
if (f) {
|
||||
// unweild it
|
||||
killflag(f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if we asked to just unweild our weapon, exit now
|
||||
// with no error.
|
||||
if (!o) {
|
||||
if (gamestarted) {
|
||||
if (lf->controller == C_PLAYER) {
|
||||
msg("You are now fighting unarmed.");
|
||||
} else if (haslos(player, lf->cell)) {
|
||||
char buf2[BUFLEN];
|
||||
getlfname(lf, buf2);
|
||||
msg("%s is now fighting unarmed.",buf2);
|
||||
}
|
||||
}
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
// now weild this
|
||||
addflag(o->flags, F_EQUIPPED, BP_WEAPON, -1, -1, NULL);
|
||||
taketime(lf, getmovespeed(lf));
|
||||
if (gamestarted) {
|
||||
if (lf->controller == C_PLAYER) {
|
||||
msg("You are now weilding %c - %s.", o->letter, buf);
|
||||
// warn if it won't do any damage
|
||||
f = hasflag(o->flags, F_DAM);
|
||||
if (!f) {
|
||||
msg("You have a feeling that this weapon will not be very effective...");
|
||||
}
|
||||
} else if (haslos(player, lf->cell)) {
|
||||
char buf2[BUFLEN];
|
||||
getlfname(lf, buf2);
|
||||
msg("%s weilds %s.", buf2, buf);
|
||||
|
||||
}
|
||||
}
|
||||
return B_FALSE;
|
||||
}
|
||||
|
|
19
io.h
19
io.h
|
@ -2,7 +2,9 @@
|
|||
#include "defs.h"
|
||||
|
||||
void anim(cell_t *src, cell_t *dst, char ch);
|
||||
object_t *askobject(obpile_t *op, char *title, int *count);
|
||||
object_t *askobject(obpile_t *op, char *title, int *count, int opts);
|
||||
object_t *askobjectofclass(obpile_t *op, char *title, int *count, int opts, enum OBCLASS obclass);
|
||||
object_t *doaskobject(obpile_t *op, char *title, int *count, int opts, enum OBCLASS obclass);
|
||||
cell_t *askcoords(char *prompt);
|
||||
void centre(WINDOW *win, int y, char *format, ... );
|
||||
int chartodir(char ch);
|
||||
|
@ -10,9 +12,16 @@ void clearmsg(void);
|
|||
void describeob(object_t *o);
|
||||
void dodrop(obpile_t *op);
|
||||
void doinventory(obpile_t *op);
|
||||
void dopickup(lifeform_t *lf, obpile_t *op);
|
||||
void doknowledgelist(void);
|
||||
int dopickup(obpile_t *op);
|
||||
void doquaff(obpile_t *op);
|
||||
void doread(obpile_t *op);
|
||||
int dotakeoff(obpile_t *op);
|
||||
void dothrow(obpile_t *op);
|
||||
void drawcell(cell_t *cell, int x, int y);
|
||||
int dowear(obpile_t *op);
|
||||
int doweild(obpile_t *op);
|
||||
void drawunviscell(cell_t *cell, int x, int y);
|
||||
void drawcellwithcontents(cell_t *cell, int x, int y);
|
||||
void drawcursor(void);
|
||||
void drawlevelfor(lifeform_t *lf);
|
||||
void drawmsg(void);
|
||||
|
@ -23,8 +32,12 @@ void handleinput(void);
|
|||
int keycodetokey(int keycode);
|
||||
void more(void);
|
||||
void msg(char *format, ... );
|
||||
int pickup(lifeform_t *lf, object_t *what, int howmany);
|
||||
void dblog(char *format, ... );
|
||||
void redraw(void);
|
||||
int savequit(void);
|
||||
int takeoff(lifeform_t *lf, object_t *o);
|
||||
void tombstone(lifeform_t *lf);
|
||||
void updateviewfor(cell_t *cell);
|
||||
int wear(lifeform_t *lf, object_t *o);
|
||||
int weild(lifeform_t *lf, object_t *o);
|
||||
|
|
593
lf.c
593
lf.c
|
@ -1,3 +1,5 @@
|
|||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -10,13 +12,23 @@
|
|||
extern race_t *firstrace, *lastrace;
|
||||
extern lifeform_t *player;
|
||||
|
||||
extern int gamestarted;
|
||||
|
||||
lifeform_t *addlf(cell_t *cell, enum RACE rid) {
|
||||
extern int loading;
|
||||
|
||||
extern enum ERROR reason;
|
||||
|
||||
lifeform_t *addlf(cell_t *cell, enum RACE rid, int level) {
|
||||
map_t *m;
|
||||
lifeform_t *a;
|
||||
int i;
|
||||
flag_t *f;
|
||||
|
||||
assert(cell);
|
||||
if (cell->type != (celltype_t *) DUMMYCELLTYPE) {
|
||||
assert(!cell->type->solid);
|
||||
}
|
||||
|
||||
m = cell->map;
|
||||
|
||||
// add to the end of the list
|
||||
|
@ -38,13 +50,13 @@ lifeform_t *addlf(cell_t *cell, enum RACE rid) {
|
|||
a->id = m->nextlfid; m->nextlfid++;
|
||||
a->controller = C_AI;
|
||||
a->race = findrace(rid);
|
||||
a->hp = 10; // TODO: fix
|
||||
a->maxhp = 10; // TODO: fix
|
||||
a->level = level;
|
||||
a->cell = cell; // TODO: fix
|
||||
a->alive = B_TRUE;
|
||||
a->lastdam = strdup("nothing");
|
||||
a->timespent = 0;
|
||||
a->sorted = B_FALSE;
|
||||
a->forgettimer = 0;
|
||||
|
||||
a->pack = addobpile(a, NOLOC);
|
||||
|
||||
|
@ -61,8 +73,32 @@ lifeform_t *addlf(cell_t *cell, enum RACE rid) {
|
|||
addflag(a->flags, f->id, f->val[0], f->val[1], f->val[2], f->text);
|
||||
}
|
||||
|
||||
// generate hp/maxhp from hit dice
|
||||
// TODO: take level into account
|
||||
f = hasflag(a->flags, F_HITDICE);
|
||||
if (f) {
|
||||
int hitdice,plus,this;
|
||||
a->maxhp = 0;
|
||||
for (i = 0; i < a->level; i++) {
|
||||
hitdice = f->val[0];
|
||||
plus = f->val[1];
|
||||
this = rolldie(hitdice, 4) + plus;
|
||||
a->maxhp += this;
|
||||
}
|
||||
} else {
|
||||
// default - 0 hit dice + 8
|
||||
a->maxhp = 8 * a->level;
|
||||
}
|
||||
a->hp = a->maxhp;
|
||||
|
||||
// update other things
|
||||
cell->lf = a;
|
||||
|
||||
// give start objetcs
|
||||
if (!loading) {
|
||||
outfitlf(a);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
race_t *addrace(enum RACE id, char *name, char glyph) {
|
||||
|
@ -91,6 +127,110 @@ race_t *addrace(enum RACE id, char *name, char glyph) {
|
|||
a->flags = addflagpile();
|
||||
}
|
||||
|
||||
int canpickup(lifeform_t *lf, object_t *o) {
|
||||
reason = E_OK;
|
||||
if (hasflag(o->flags, F_NOPICKUP)) {
|
||||
reason = E_NOPICKUP;
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
// space in pack?
|
||||
if (countobs(lf->pack) >= MAXPILEOBS) {
|
||||
reason = E_NOSPACE;
|
||||
return B_FALSE;
|
||||
}
|
||||
if (getnextletter(lf->pack, NULL) == '-') {
|
||||
reason = E_NOSPACE;
|
||||
return B_FALSE;
|
||||
}
|
||||
return B_TRUE;
|
||||
}
|
||||
|
||||
int canwear(lifeform_t *lf, object_t *o) {
|
||||
object_t *oo;
|
||||
flag_t *f;
|
||||
enum BODYPART bp;
|
||||
|
||||
reason = E_OK;
|
||||
|
||||
// where is this worn?
|
||||
f = hasflag(o->flags, F_GOESON);
|
||||
if (f) {
|
||||
bp = f->val[0];
|
||||
} else {
|
||||
// can't wear anywhere
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
|
||||
// anything else worn there?
|
||||
for (oo = lf->pack->first ; oo ; oo = oo->next) {
|
||||
f = hasflagval(oo->flags, F_EQUIPPED, bp, -1, -1, NULL);
|
||||
if (f) {
|
||||
if (oo == o) { // already weilding it
|
||||
reason = E_ALREADYUSING;
|
||||
} else {
|
||||
reason = E_WEARINGSOMETHINGELSE;
|
||||
}
|
||||
return B_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// trying to fight unarmed, but no unarmed attack?
|
||||
if (o == NULL) {
|
||||
if (!hasflag(lf->flags, F_UNARMEDATTACKOB)) {
|
||||
reason = E_NOUNARMEDATTACK;
|
||||
return B_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return B_TRUE;
|
||||
}
|
||||
|
||||
int canweild(lifeform_t *lf, object_t *o) {
|
||||
object_t *oo;
|
||||
flag_t *f;
|
||||
|
||||
reason = E_OK;
|
||||
// anything else weilded?
|
||||
for (oo = lf->pack->first ; oo ; oo = oo->next) {
|
||||
f = hasflagval(oo->flags, F_EQUIPPED, BP_WEAPON, -1, -1, NULL);
|
||||
if (f) {
|
||||
if (oo == o) { // already weilding it
|
||||
reason = E_ALREADYUSING;
|
||||
return B_FALSE;
|
||||
} // TODO: else if cursed...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// trying to fight unarmed, but no unarmed attack?
|
||||
if (o == NULL) {
|
||||
if (!hasflag(lf->flags, F_UNARMEDATTACKOB)) {
|
||||
reason = E_NOUNARMEDATTACK;
|
||||
return B_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return B_TRUE;
|
||||
}
|
||||
|
||||
int cantakeoff(lifeform_t *lf, object_t *o) {
|
||||
object_t *oo;
|
||||
flag_t *f;
|
||||
|
||||
reason = E_OK;
|
||||
f = hasflag(o->flags, F_EQUIPPED);
|
||||
if (!f) {
|
||||
reason = E_NOTEQUIPPED;
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
// TODO CURSE
|
||||
|
||||
return B_TRUE;
|
||||
}
|
||||
|
||||
void die(lifeform_t *lf) {
|
||||
char buf[BUFLEN];
|
||||
object_t *o, *nexto;
|
||||
|
@ -133,6 +273,27 @@ void die(lifeform_t *lf) {
|
|||
}
|
||||
}
|
||||
|
||||
void fightback(lifeform_t *lf, lifeform_t *attacker) {
|
||||
// they will now fight back!
|
||||
if (attacker && !isdead(lf)) {
|
||||
if (lf->controller != C_PLAYER) {
|
||||
if (!hasflagval(lf->flags, F_TARGET, attacker->id, NA, NA, NULL)) {
|
||||
addflag(lf->flags, F_TARGET, attacker->id, NA, NA, NULL);
|
||||
// announce
|
||||
if (haslos(player, lf->cell)) {
|
||||
char attackername[BUFLEN];
|
||||
char lfname[BUFLEN];
|
||||
getlfname(attacker, attackername);
|
||||
getlfname(lf, lfname);
|
||||
capitalise(lfname);
|
||||
msg("%s turns to attack %s!", lfname,
|
||||
haslos(player, attacker->cell) ? attackername : "something");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lifeform_t *findlf(map_t *m, int lfid) {
|
||||
lifeform_t *lf;
|
||||
for (lf = m->lf ; lf ; lf = lf->next) {
|
||||
|
@ -152,10 +313,160 @@ race_t *findrace(enum RACE id) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int getattackspeed(lifeform_t *lf) {
|
||||
int speed = SPEED_ATTACK;
|
||||
void gainhp(lifeform_t *lf, int amt) {
|
||||
char buf[BUFLEN];
|
||||
lf->hp += amt;
|
||||
|
||||
if (lf->hp > lf->maxhp) {
|
||||
lf->hp = lf->maxhp;
|
||||
}
|
||||
}
|
||||
|
||||
int getarmour(lifeform_t *lf) {
|
||||
object_t *o;
|
||||
flag_t *f;
|
||||
f = hasflag(lf->flags, F_ATTACKSPEED);
|
||||
int ar = 0;
|
||||
|
||||
for (o = lf->pack->first ; o ; o = o->next) {
|
||||
if (hasflag(o->flags, F_EQUIPPED)) {
|
||||
f = hasflag(o->flags, F_ARMOURRATING);
|
||||
if (f) {
|
||||
ar += f->val[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ar;
|
||||
}
|
||||
|
||||
int getevasion(lifeform_t *lf) {
|
||||
object_t *o;
|
||||
flag_t *f;
|
||||
int ev = 0;
|
||||
// natural evasion
|
||||
f = hasflag(lf->flags, F_EVASION);
|
||||
if (f) {
|
||||
// evasion 10 means -10% penalty to hit you
|
||||
ev += (f->val[0]);
|
||||
if (ev < 0) ev = 0;
|
||||
}
|
||||
|
||||
// minus armour penalties
|
||||
for (o = lf->pack->first ; o ; o = o->next) {
|
||||
f = hasflag(o->flags, F_EVASION);
|
||||
if (f) {
|
||||
ev += (f->val[0]);
|
||||
if (ev < 0) ev = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ev;
|
||||
|
||||
}
|
||||
object_t *getbestweapon(lifeform_t *lf) {
|
||||
obpile_t *op;
|
||||
object_t *curwep,*bestwep = NULL;
|
||||
int bestmaxdam = -999;
|
||||
flag_t *f;
|
||||
object_t *o;
|
||||
|
||||
op = addobpile(lf, NULL); // for use if we are unarmed
|
||||
|
||||
curwep = getweapon(lf);
|
||||
if (!curwep) {
|
||||
getunarmedweapon(lf, op);
|
||||
curwep = op->first;
|
||||
}
|
||||
if (curwep) {
|
||||
f = hasflag(curwep->flags, F_DAM);
|
||||
bestmaxdam = f->val[1];
|
||||
} else {
|
||||
// no current weapon, and no unarmed weapon
|
||||
// anything will be better!
|
||||
bestmaxdam = -999;
|
||||
}
|
||||
|
||||
bestwep = curwep;
|
||||
|
||||
for (o = lf->pack->first ; o ; o = o->next) {
|
||||
f = hasflag(o->flags, F_DAM);
|
||||
// if it does damage and we can weild it...
|
||||
if (f && canweild(lf, o)) {
|
||||
// if its max damage is better...
|
||||
if (f->val[1] > bestmaxdam) {
|
||||
bestmaxdam = f->val[1];
|
||||
bestwep = o;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestwep == op->first) {
|
||||
bestwep = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (op->first) {
|
||||
killob(op->first);
|
||||
}
|
||||
free(op);
|
||||
|
||||
return bestwep;
|
||||
}
|
||||
|
||||
|
||||
char *getbodypartname(enum BODYPART bp) {
|
||||
switch (bp) {
|
||||
case BP_WEAPON:
|
||||
return "weapon";
|
||||
case BP_RIGHTHAND:
|
||||
return "right hand";
|
||||
case BP_LEFTHAND:
|
||||
return "left hand";
|
||||
case BP_HANDS:
|
||||
return "hands";
|
||||
case BP_HEAD:
|
||||
return "head";
|
||||
case BP_BODY:
|
||||
return "body";
|
||||
case BP_SHOULDERS:
|
||||
return "shoulders";
|
||||
case BP_FEET:
|
||||
return "feet";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
char *getbodypartequipname(enum BODYPART bp) {
|
||||
switch (bp) {
|
||||
case BP_WEAPON:
|
||||
return "n/a";
|
||||
case BP_RIGHTHAND:
|
||||
case BP_LEFTHAND:
|
||||
case BP_HANDS:
|
||||
case BP_HEAD:
|
||||
case BP_BODY:
|
||||
case BP_FEET:
|
||||
return "on";
|
||||
case BP_SHOULDERS:
|
||||
return "over";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
object_t *getequippedob(obpile_t *op, enum BODYPART bp) {
|
||||
object_t *o;
|
||||
for (o = op->first; o ; o = o->next) {
|
||||
if (hasflagval(o->flags, F_EQUIPPED, bp, NA, NA, NULL)) {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int getlfattackspeed(lifeform_t *lf) {
|
||||
int speed = 0; // default to taking no time at all - just use weapon delay
|
||||
flag_t *f;
|
||||
f = hasflag(lf->flags, F_LFATTACKDELAY);
|
||||
if (f) {
|
||||
speed = f->val[0];
|
||||
}
|
||||
|
@ -182,6 +493,112 @@ char *getlfname(lifeform_t *lf, char *buf) {
|
|||
return buf;
|
||||
}
|
||||
|
||||
race_t *getrandomlf(map_t *map, int *level) {
|
||||
enum RARITY rarity;
|
||||
race_t *r;
|
||||
int roll;
|
||||
race_t *poss[MAXRANDOMLFCANDIDATES];
|
||||
int nposs = 0;
|
||||
int selidx;
|
||||
int amt;
|
||||
flag_t *f;
|
||||
int db = B_FALSE;
|
||||
|
||||
// determine rarity of lf to generate
|
||||
rarity = RR_FREQUENT;
|
||||
|
||||
// start with 'frequent'ly appearing items
|
||||
// roll a die. 30% chance of getting rarer.
|
||||
// stop when we fail the die roll.
|
||||
roll = rnd(1,100);
|
||||
while (roll < 30) {
|
||||
rarity++;
|
||||
if (rarity == RR_VERYRARE) break;
|
||||
roll = rnd(1,100);
|
||||
}
|
||||
if (db) dblog("adding random lf of rarity %d\n",rarity);
|
||||
|
||||
|
||||
// try to find a lf of this type which will
|
||||
// fit in the map's habitat
|
||||
nposs = 0;
|
||||
while (nposs == 0) {
|
||||
for (r = firstrace ; r ; r = r->next) {
|
||||
if (hasflagval(r->flags, F_RARITY, map->habitat, rarity, NA, NULL) ||
|
||||
hasflagval(r->flags, F_RARITY, H_ALL, rarity, NA, NULL) ) {
|
||||
poss[nposs] = r;
|
||||
nposs++;
|
||||
if (nposs >= MAXRANDOMLFCANDIDATES) break;
|
||||
}
|
||||
}
|
||||
|
||||
// nothing found?
|
||||
if (nposs == 0) {
|
||||
// already at lowest rarity?
|
||||
if (rarity == RR_FREQUENT) {
|
||||
// give up
|
||||
if (db) dblog("no possible lf at all! giving up.");
|
||||
return NULL;
|
||||
} else {
|
||||
// lower rarity and try again
|
||||
rarity--;
|
||||
if (db) dblog("no possible lfs like this. trying again with rarity %d\n",rarity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (db) dblog("got %d possibilities.",nposs);
|
||||
// pick a random lf from our possiblities
|
||||
selidx = rnd(0,nposs-1);
|
||||
r = poss[selidx];
|
||||
/* TODO:
|
||||
// handle lf which appear in multiples (ie. rocks)
|
||||
f = hasflag(ot->flags, F_NUMAPPEAR);
|
||||
if (f) {
|
||||
amt = rnd(f->val[0], f->val[1]);
|
||||
} else {
|
||||
amt = 1;
|
||||
}
|
||||
if (db) sprintf(buf, "%d %s", amt, ot->name);
|
||||
*/
|
||||
|
||||
// TODO: should select a level based on map difficulty/depth
|
||||
if (level) {
|
||||
*level = rnd(1,3);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *getspeedname(int speed, char *buf) {
|
||||
sprintf(buf, "unknownspeed");
|
||||
switch (speed) {
|
||||
case SP_GODLIKE: sprintf(buf, "insanely fast"); break;
|
||||
case SP_ULTRAFAST: sprintf(buf, "extremely fast"); break;
|
||||
case SP_VERYFAST: sprintf(buf, "very fast"); break;
|
||||
case SP_FAST: sprintf(buf, "fast"); break;
|
||||
case SP_NORMAL: sprintf(buf, "normal"); break;
|
||||
case SP_SLOW: sprintf(buf, "slow"); break;
|
||||
case SP_VERYSLOW: sprintf(buf, "very slow"); break;
|
||||
case SP_ULTRASLOW: sprintf(buf, "extremely slow"); break;
|
||||
case SP_SLOWEST: sprintf(buf, "insanely slow"); break;
|
||||
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
object_t *getweapon(lifeform_t *lf) {
|
||||
object_t *o;
|
||||
flag_t *f;
|
||||
for (o = lf->pack->first ; o ; o = o->next) {
|
||||
f = hasflagval(o->flags, F_EQUIPPED, BP_WEAPON, NA, NA, NULL);
|
||||
if (f) {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int haslof(lifeform_t *viewer, cell_t *dest) {
|
||||
int deltax, deltay;
|
||||
int numpixels;
|
||||
|
@ -484,28 +901,61 @@ int haslos(lifeform_t *viewer, cell_t *dest) {
|
|||
|
||||
void initrace(void) {
|
||||
addrace(R_HUMAN, "human", '@');
|
||||
addflag(lastrace->flags, F_CORPSETYPE, -1, -1, -1, "human corpse");
|
||||
addflag(lastrace->flags, F_RARITY, H_DUNGEON, RR_RARE, -1, "");
|
||||
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "human corpse");
|
||||
addflag(lastrace->flags, F_RARITY, H_DUNGEON, RR_RARE, NA, "");
|
||||
addflag(lastrace->flags, F_HITDICE, 1, 4, NA, "");
|
||||
addflag(lastrace->flags, F_EVASION, 0, NA, NA, NULL);
|
||||
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
||||
addflag(lastrace->flags, F_UNARMEDATTACKOB, NA, NA, NA, "fists");
|
||||
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "10 gold coins");
|
||||
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "quickblade");
|
||||
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "leather boots");
|
||||
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "leather gloves");
|
||||
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "3 potions of healing");
|
||||
addflag(lastrace->flags, F_STARTOBDT, 100, DT_PIERCE, NA, NULL);
|
||||
addrace(R_GOBLIN, "goblin", 'g');
|
||||
addflag(lastrace->flags, F_CORPSETYPE, -1, -1, -1, "goblin corpse");
|
||||
addflag(lastrace->flags, F_HOSTILE, B_TRUE, -1, -1, "");
|
||||
addflag(lastrace->flags, F_RARITY, H_DUNGEON, RR_COMMON, -1, "");
|
||||
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "goblin corpse");
|
||||
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
||||
addflag(lastrace->flags, F_RARITY, H_DUNGEON, RR_COMMON, NA, NULL);
|
||||
addflag(lastrace->flags, F_HITDICE, 1, 3, NA, NULL);
|
||||
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
|
||||
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
||||
addflag(lastrace->flags, F_UNARMEDATTACKOB, NA, NA, NA, "small claws");
|
||||
addflag(lastrace->flags, F_STARTOBDT, 50, DT_PIERCE, NA, NULL);
|
||||
addrace(R_BAT, "bat", 'B');
|
||||
addflag(lastrace->flags, F_CORPSETYPE, -1, -1, -1, "bat corpse");
|
||||
addflag(lastrace->flags, F_ATTACKSPEED, 5, -1, -1, "");
|
||||
addflag(lastrace->flags, F_MOVESPEED, 5, -1, -1, "");
|
||||
addflag(lastrace->flags, F_FLYING, B_TRUE, -1, -1, "");
|
||||
addflag(lastrace->flags, F_RARITY, H_DUNGEON, RR_COMMON, -1, "");
|
||||
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "bat corpse");
|
||||
addflag(lastrace->flags, F_LFATTACKDELAY, -3, NA, NA, ""); // extra fast attacks
|
||||
addflag(lastrace->flags, F_MOVESPEED, SP_VERYFAST, NA, NA, "");
|
||||
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
||||
addflag(lastrace->flags, F_RARITY, H_DUNGEON, RR_COMMON, NA, "");
|
||||
addflag(lastrace->flags, F_HITDICE, 0, 2, NA, "");
|
||||
addflag(lastrace->flags, F_UNARMEDATTACKOB, NA, NA, NA, "tiny teeth");
|
||||
addflag(lastrace->flags, F_EVASION, 30, NA, NA, NULL);
|
||||
addrace(R_RAT, "rat", 'r');
|
||||
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "rodent corpse");
|
||||
addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, "");
|
||||
addflag(lastrace->flags, F_MOVESPEED, 5, NA, NA, "");
|
||||
addflag(lastrace->flags, F_RARITY, H_DUNGEON, RR_COMMON, NA, "");
|
||||
addflag(lastrace->flags, F_HITDICE, 0, 1, NA, "");
|
||||
addflag(lastrace->flags, F_UNARMEDATTACKOB, NA, NA, NA, "tiny teeth");
|
||||
addflag(lastrace->flags, F_UNARMEDATTACKOB, NA, NA, NA, "tiny claws");
|
||||
addflag(lastrace->flags, F_EVASION, 20, NA, NA, NULL);
|
||||
addrace(R_GIANTFLY, "giant fly", 'I');
|
||||
addflag(lastrace->flags, F_CORPSETYPE, -1, -1, -1, "giant fly corpse");
|
||||
addflag(lastrace->flags, F_MOVESPEED, 2, -1, -1, "");
|
||||
addflag(lastrace->flags, F_FLYING, B_TRUE, -1, -1, "");
|
||||
addflag(lastrace->flags, F_RARITY, H_DUNGEON, RR_COMMON, -1, "");
|
||||
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "fly corpse");
|
||||
addflag(lastrace->flags, F_MOVESPEED, SP_VERYFAST, NA, NA, "");
|
||||
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
||||
addflag(lastrace->flags, F_RARITY, H_DUNGEON, RR_COMMON, NA, "");
|
||||
addflag(lastrace->flags, F_HITDICE, 0, 2, NA, "");
|
||||
addflag(lastrace->flags, F_EVASION, 40, NA, NA, NULL);
|
||||
addflag(lastrace->flags, F_UNARMEDATTACKOB, NA, NA, NA, "tiny teeth");
|
||||
addrace(R_GIANTBLOWFLY, "giant blowfly", 'I');
|
||||
addflag(lastrace->flags, F_CORPSETYPE, -1, -1, -1, "giant fly corpse");
|
||||
addflag(lastrace->flags, F_MOVESPEED, 2, -1, -1, "");
|
||||
addflag(lastrace->flags, F_FLYING, B_TRUE, -1, -1, "");
|
||||
addflag(lastrace->flags, F_RARITY, H_DUNGEON, RR_UNCOMMON, -1, "");
|
||||
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "fly corpse");
|
||||
addflag(lastrace->flags, F_MOVESPEED, SP_VERYFAST, NA, NA, "");
|
||||
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
||||
addflag(lastrace->flags, F_RARITY, H_DUNGEON, RR_UNCOMMON, NA, "");
|
||||
addflag(lastrace->flags, F_HITDICE, 1, 2, NA, "");
|
||||
addflag(lastrace->flags, F_EVASION, 30, NA, NA, NULL);
|
||||
addflag(lastrace->flags, F_UNARMEDATTACKOB, NA, NA, NA, "tiny teeth");
|
||||
}
|
||||
|
||||
int isdead(lifeform_t *lf) {
|
||||
|
@ -516,14 +966,26 @@ int isdead(lifeform_t *lf) {
|
|||
|
||||
void killlf(lifeform_t *lf) {
|
||||
int i;
|
||||
lifeform_t *nextone, *lastone;
|
||||
lifeform_t *nextone, *lastone, *l;
|
||||
map_t *m;
|
||||
flag_t *f;
|
||||
|
||||
m = lf->cell->map;
|
||||
|
||||
// remove references
|
||||
lf->cell->lf = NULL;
|
||||
|
||||
// check if anyone is targetting us.
|
||||
// if so, stop targetting us now that
|
||||
// we are dead.
|
||||
// TODO: check on all maps?
|
||||
for (l = m->lf ; l ; l = l->next) {
|
||||
f = hasflag(l->flags, F_TARGET);
|
||||
if (f && (f->val[0] == lf->id)) {
|
||||
killflag(f);
|
||||
}
|
||||
}
|
||||
|
||||
// free mem
|
||||
if (lf->lastdam) free(lf->lastdam);
|
||||
|
||||
|
@ -590,7 +1052,7 @@ void killrace(race_t *race) {
|
|||
}
|
||||
|
||||
|
||||
void losehp(lifeform_t *lf, int amt, lifeform_t *fromlf, char *damsrc) {
|
||||
void losehp(lifeform_t *lf, int amt, int damtype, lifeform_t *fromlf, char *damsrc) {
|
||||
char buf[BUFLEN];
|
||||
lf->hp -= amt;
|
||||
if (lf->lastdam) {
|
||||
|
@ -605,35 +1067,74 @@ void losehp(lifeform_t *lf, int amt, lifeform_t *fromlf, char *damsrc) {
|
|||
}
|
||||
lf->lastdam = strdup(buf);
|
||||
|
||||
// they will now fight back!
|
||||
if (fromlf && !isdead(lf)) {
|
||||
if (lf->controller != C_PLAYER) {
|
||||
if (!hasflagval(lf->flags, F_TARGET, fromlf->id, -1, -1, "")) {
|
||||
addflag(lf->flags, F_TARGET, fromlf->id, -1, -1, "");
|
||||
// announce
|
||||
if (haslos(player, lf->cell)) {
|
||||
char fromlfname[BUFLEN];
|
||||
char lfname[BUFLEN];
|
||||
getlfname(fromlf, fromlfname);
|
||||
getlfname(lf, lfname);
|
||||
capitalise(lfname);
|
||||
msg("%s turns to attack %s!", lfname,
|
||||
haslos(player, fromlf->cell) ? fromlfname : "something");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// fight back if required
|
||||
fightback(lf, fromlf);
|
||||
}
|
||||
|
||||
// give initial equiment to a lifeform
|
||||
void outfitlf(lifeform_t *lf) {
|
||||
if (lf->controller == C_PLAYER) {
|
||||
addob(lf->pack, "10 gold");
|
||||
flag_t *f;
|
||||
object_t *bestwep;
|
||||
char buf[BUFLEN];
|
||||
object_t *o;
|
||||
|
||||
// give start objects
|
||||
for (f = lf->flags->first ; f ; f = f->next) {
|
||||
if (f->id == F_STARTOB) {
|
||||
if (rnd(1,100) <= f->val[0]) {
|
||||
addob(lf->pack, f->text);
|
||||
}
|
||||
} else if (f->id == F_STARTOBDT) {
|
||||
if (rnd(1,100) <= f->val[0]) {
|
||||
getrandomobwithdt(NULL, f->val[1], buf);
|
||||
addob(lf->pack, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// weild weapons if required
|
||||
bestwep = getbestweapon(lf);
|
||||
if (bestwep) {
|
||||
weild(lf, bestwep);
|
||||
// make sure it doesn't take any time
|
||||
lf->timespent = 0;
|
||||
}
|
||||
|
||||
// weild armour if required
|
||||
for (o = lf->pack->first ; o ; o = o->next) {
|
||||
if (canwear(lf, o)) {
|
||||
wear(lf, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void taketime(lifeform_t *lf, int howlong) {
|
||||
int db = B_TRUE;
|
||||
|
||||
assert(howlong > 0);
|
||||
|
||||
if (db && gamestarted && haslos(player, lf->cell)) {
|
||||
lifeform_t *l;
|
||||
dblog("lfid %d (%s) spending %d time\n",lf->id,lf->race->name, howlong);
|
||||
}
|
||||
// inc timespent
|
||||
lf->timespent += howlong;
|
||||
// TODO: decrement lifeform's (or their object's) temporary flags
|
||||
|
||||
// if you don't have a map, start forgetting the dungeon
|
||||
if (lf->controller == C_PLAYER) {
|
||||
if (!hasknownob(lf->pack, OT_MAP)) {
|
||||
lf->forgettimer += ((float)howlong / 15.0);
|
||||
if (lf->forgettimer > 1) {
|
||||
int amt;
|
||||
|
||||
// TODO: modify using race memory
|
||||
amt = (int)floor(lf->forgettimer);
|
||||
forgetcells(lf->cell->map, amt);
|
||||
lf->forgettimer -= amt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
21
lf.h
21
lf.h
|
@ -1,19 +1,34 @@
|
|||
#include "defs.h"
|
||||
|
||||
|
||||
lifeform_t *addlf(cell_t *cell, enum RACE rid);
|
||||
lifeform_t *addlf(cell_t *cell, enum RACE rid, int level);
|
||||
race_t *addrace(enum RACE id, char *name, char glyph);
|
||||
int canpickup(lifeform_t *lf, object_t *o);
|
||||
int canwear(lifeform_t *lf, object_t *o);
|
||||
int canweild(lifeform_t *lf, object_t *o);
|
||||
int cantakeoff(lifeform_t *lf, object_t *o);
|
||||
void die(lifeform_t *lf);
|
||||
void fightback(lifeform_t *lf, lifeform_t *attacker);
|
||||
lifeform_t *findlf(map_t *m, int lfid);
|
||||
race_t *findrace(enum RACE id);
|
||||
int getattackspeed(lifeform_t *lf);
|
||||
void gainhp(lifeform_t *lf, int amt);
|
||||
int getarmour(lifeform_t *lf);
|
||||
object_t *getbestweapon(lifeform_t *lf);
|
||||
char *getbodypartname(enum BODYPART bp);
|
||||
char *getbodypartequipname(enum BODYPART bp);
|
||||
object_t *getequippedob(obpile_t *op, enum BODYPART bp);
|
||||
int getlfattackspeed(lifeform_t *lf);
|
||||
int getmovespeed(lifeform_t *lf);
|
||||
char *getlfname(lifeform_t *lf, char *buf);
|
||||
race_t *getrandomlf(map_t *map, int *level);
|
||||
char *getspeedname(int speed, char *buf);
|
||||
object_t *getweapon(lifeform_t *lf);
|
||||
int haslof(lifeform_t *viewer, cell_t *dest);
|
||||
int haslos(lifeform_t *viewer, cell_t *dest);
|
||||
void initrace(void);
|
||||
int isdead(lifeform_t *lf);
|
||||
void killlf(lifeform_t *lf);
|
||||
void killrace(race_t *race);
|
||||
void losehp(lifeform_t *lf, int amt, lifeform_t *fromlf, char *damsrc);
|
||||
void losehp(lifeform_t *lf, int amt, int damtype, lifeform_t *fromlf, char *damsrc);
|
||||
void outfitlf(lifeform_t *lf);
|
||||
void taketime(lifeform_t *lf, int howlong);
|
||||
|
|
81
map.c
81
map.c
|
@ -5,10 +5,13 @@
|
|||
#include <string.h>
|
||||
#include "defs.h"
|
||||
#include "nexus.h"
|
||||
#include "lf.h"
|
||||
#include "map.h"
|
||||
#include "objects.h"
|
||||
|
||||
extern map_t *firstmap,*lastmap;
|
||||
extern int viewx,viewy,vieww,viewh;
|
||||
extern lifeform_t *player;
|
||||
|
||||
cell_t *addcell(map_t *m, int x, int y) {
|
||||
cell_t *cell;
|
||||
|
@ -62,11 +65,24 @@ map_t *addmap(void) {
|
|||
|
||||
void addrandomthing(cell_t *c) {
|
||||
char buf[BUFLEN];
|
||||
// TODO: monsters too
|
||||
int level;
|
||||
race_t *r;
|
||||
|
||||
// if there's already someone there,
|
||||
// then add an object.
|
||||
if (c->lf || (rnd(1,2) == 1)) {
|
||||
// object
|
||||
if (getrandomob(c->map, buf)) {
|
||||
dblog("adding %s to cell %d,%d",buf,c->x,c->y);
|
||||
addob(c->obpile, buf);
|
||||
}
|
||||
} else {
|
||||
r = getrandomlf(c->map, &level);
|
||||
if (r) {
|
||||
dblog("adding %s to cell %d,%d",buf,c->x,c->y);
|
||||
addlf(c, r->id, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cell_t *getcellat(map_t *map, int x, int y) {
|
||||
|
@ -1080,6 +1096,44 @@ map_t *findmap(int mid) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void forgetcells(map_t *map, int amt) {
|
||||
int amtleft;
|
||||
//int totcells;
|
||||
int i;
|
||||
cell_t *poss[MAX_MAPW*MAX_MAPH];
|
||||
cell_t *c;
|
||||
int nposs = 0;
|
||||
// how many cells to forget?
|
||||
//totcells = (map->w * map->h);
|
||||
//amtleft = (int) (((float) pct / 100.0) * (float)totcells);
|
||||
amtleft = amt;
|
||||
|
||||
// get a list of all known cells
|
||||
for (i = 0; i < (map->w*map->h); i++){
|
||||
c = map->cell[i];
|
||||
if (c && c->known && !haslos(player, c)) {
|
||||
poss[nposs] = c;
|
||||
nposs++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (amtleft > nposs) amtleft = nposs;
|
||||
|
||||
// forget cells...
|
||||
for (i = 0; i < amtleft; i++) {
|
||||
int n;
|
||||
int sel;
|
||||
sel = rnd(0,nposs-1);
|
||||
poss[sel]->known = B_FALSE;
|
||||
// shuffle down
|
||||
for (n = i; n < (amtleft-1); n++) {
|
||||
poss[n] = poss[n+1];
|
||||
}
|
||||
nposs--;
|
||||
}
|
||||
}
|
||||
|
||||
cell_t *getcellindir(cell_t *cell, int dir) {
|
||||
cell_t *newcell;
|
||||
int newx,newy;
|
||||
|
@ -1259,12 +1313,11 @@ cell_t *getrandomroomcell(map_t *map, int roomid) {
|
|||
poss = malloc((map->w*map->h) * sizeof(cell_t));
|
||||
|
||||
npossible = 0;
|
||||
// avoid room borders!
|
||||
for (y = 1; y < (map->h-1); y++) {
|
||||
for (x = 1; x < (map->w-1); x++) {
|
||||
for (y = 0; y < map->h; y++) {
|
||||
for (x = 0; x < map->w; x++) {
|
||||
c = getcellat(map, x, y);
|
||||
// is this cell in the correct room?
|
||||
if (c && c->roomid == roomid) {
|
||||
// is this cell in the correct room and not a wall?
|
||||
if (c && !c->type->solid && (c->roomid == roomid)) {
|
||||
poss[npossible] = c;
|
||||
npossible++;
|
||||
}
|
||||
|
@ -1353,3 +1406,19 @@ void setcelltype(cell_t *cell, int id) {
|
|||
}
|
||||
|
||||
|
||||
void updateknowncells(void) {
|
||||
int x,y;
|
||||
map_t *map;
|
||||
|
||||
map = player->cell->map;
|
||||
|
||||
for (y = viewy; y < viewy + viewh; y++) {
|
||||
for (x = viewx; x < viewx + vieww; x++) {
|
||||
cell_t *cell;
|
||||
cell = getcellat(map, x, y);
|
||||
if (cell && !cell->known && haslos(player, cell)) {
|
||||
cell->known = B_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
2
map.h
2
map.h
|
@ -14,6 +14,7 @@ int dirtox(int dt, int dir);
|
|||
int dirtoy(int dt, int dir);
|
||||
void dumpmap(map_t *map);
|
||||
map_t *findmap(int mid);
|
||||
void forgetcells(map_t *map, int amt);
|
||||
cell_t *getcellindir(cell_t *cell, int dir);
|
||||
int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved);
|
||||
int getobchance(int habitat);
|
||||
|
@ -27,3 +28,4 @@ int isonmap(map_t *map, int x, int y);
|
|||
int iswallindir(cell_t *cell, int dir);
|
||||
void makedoor(cell_t *cell);
|
||||
void setcelltype(cell_t *cell, int id);
|
||||
void updateknowncells(void);
|
||||
|
|
99
move.c
99
move.c
|
@ -1,7 +1,11 @@
|
|||
#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;
|
||||
|
||||
|
@ -10,7 +14,8 @@ int canmove(lifeform_t *lf, int dir, enum ERROR *error) {
|
|||
|
||||
cell = getcellindir(lf->cell, dir);
|
||||
|
||||
if (cell->type->solid) {
|
||||
|
||||
if (!cell || cell->type->solid) {
|
||||
if (error) *error = E_WALLINWAY;
|
||||
return B_FALSE;
|
||||
}
|
||||
|
@ -22,25 +27,58 @@ int canmove(lifeform_t *lf, int dir, enum ERROR *error) {
|
|||
return B_TRUE;
|
||||
}
|
||||
|
||||
void dorandommove(lifeform_t *lf) {
|
||||
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);
|
||||
while (trymove(lf, dir)) {
|
||||
|
||||
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;
|
||||
|
||||
|
@ -50,6 +88,59 @@ void movelf(lifeform_t *lf, cell_t *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
|
||||
|
@ -61,7 +152,7 @@ int moveto(lifeform_t *lf, cell_t *newcell) {
|
|||
movelf(lf, newcell);
|
||||
|
||||
// tell player about things
|
||||
if (lf->controller == C_PLAYER) {
|
||||
if (!isdead(lf) && (lf->controller == C_PLAYER)) {
|
||||
int numobs;
|
||||
char buf[BUFLEN];
|
||||
numobs = countobs(newcell->obpile);
|
||||
|
|
2
move.h
2
move.h
|
@ -1,7 +1,7 @@
|
|||
#include "defs.h"
|
||||
|
||||
int canmove(lifeform_t *lf, int dir, enum ERROR *error);
|
||||
void dorandommove(lifeform_t *lf);
|
||||
void dorandommove(lifeform_t *lf, int badmovesok);
|
||||
int dowait(lifeform_t *lf);
|
||||
void movelf(lifeform_t *lf, cell_t *newcell);
|
||||
int moveto(lifeform_t *lf, cell_t *newcell);
|
||||
|
|
40
nexus.c
40
nexus.c
|
@ -15,6 +15,7 @@ objecttype_t *objecttype = NULL,*lastobjecttype = NULL;
|
|||
celltype_t *firstcelltype = NULL,*lastcelltype = NULL;
|
||||
race_t *firstrace = NULL,*lastrace = NULL;
|
||||
map_t *firstmap = NULL,*lastmap = NULL;
|
||||
knowledge_t *knowledge = NULL, *lastknowledge = NULL;
|
||||
|
||||
FILE *logfile;
|
||||
|
||||
|
@ -46,15 +47,24 @@ int main(char **argv, int argc) {
|
|||
createmap(firstmap, H_DUNGEON);
|
||||
}
|
||||
|
||||
// if no player, add them
|
||||
if (!knowledge) {
|
||||
// populate scroll names
|
||||
genhiddennames();
|
||||
}
|
||||
|
||||
// if no player (ie. didn't load a game), add them
|
||||
if (!player) {
|
||||
// add player
|
||||
player = addlf(getrandomcelloftype(firstmap, CT_ROOM), R_HUMAN, 1);
|
||||
player->controller = C_PLAYER;
|
||||
drawscreen();
|
||||
msg("Welcome to %snexus!", newworld ? "the new " : "");
|
||||
more();
|
||||
player = addlf(getrandomcelloftype(firstmap, CT_ROOM), R_HUMAN);
|
||||
player->controller = C_PLAYER;
|
||||
outfitlf(player);
|
||||
addlf(getcellindir(player->cell, D_N), R_BAT);
|
||||
// XXX testing
|
||||
//addlf(getcellindir(player->cell, D_N), R_GOBLIN, 1);
|
||||
|
||||
} else {
|
||||
drawscreen();
|
||||
msg("Welcome back!");
|
||||
more();
|
||||
}
|
||||
|
@ -219,33 +229,47 @@ int init(void) {
|
|||
}
|
||||
|
||||
int isplayerturn(void) {
|
||||
if (!player) return B_FALSE;
|
||||
|
||||
if (player->cell->map->lf->controller == C_PLAYER) {
|
||||
return B_TRUE;
|
||||
}
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
// get a random number
|
||||
// get a random number between min and max
|
||||
int rnd(int min, int max) {
|
||||
int res;
|
||||
res = (rand() % (max - min + 1)) + min;
|
||||
return res;
|
||||
}
|
||||
// get a random number
|
||||
int rolldie(int ndice, int sides) {
|
||||
int i;
|
||||
int res = 0;
|
||||
for (i = 0; i < ndice; i++) {
|
||||
res += rnd(1,sides);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// sort map's lifeform list by time spent
|
||||
void sortlf(map_t *map) {
|
||||
int donesomething;
|
||||
lifeform_t *l;
|
||||
int adjustby;
|
||||
int db = B_FALSE;
|
||||
int db = B_TRUE;
|
||||
|
||||
// bubblesort
|
||||
/*
|
||||
if (db) {
|
||||
dblog("BEFORE sortlf():");
|
||||
for (l = map->lf ; l ; l = l->next) {
|
||||
dblog("- %s (timespent= %d) (sorted=%d)", (l == player) ? "player" : l->race->name, l->timespent,l->sorted);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
donesomething = B_TRUE;
|
||||
while (donesomething) {
|
||||
|
@ -283,9 +307,11 @@ void sortlf(map_t *map) {
|
|||
if (db) {
|
||||
dblog("AFTER SORT:");
|
||||
for (l = map->lf ; l ; l = l->next) {
|
||||
if (haslos(player, l->cell)) {
|
||||
dblog("- %s (timespent= %d) (sorted=%d)", (l == player) ? "player" : l->race->name, l->timespent,l->sorted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now go through the list and make the first element be 0
|
||||
adjustby = map->lf->timespent;
|
||||
|
|
1
nexus.h
1
nexus.h
|
@ -10,4 +10,5 @@ char *getdirname(int dir);
|
|||
int init(void);
|
||||
int isplayerturn(void);
|
||||
int rnd(int min, int max);
|
||||
int rolldie(int ndice, int sides);
|
||||
void sortlf(map_t *map);
|
||||
|
|
25
objects.h
25
objects.h
|
@ -2,8 +2,9 @@
|
|||
#define __OBJECTS_H
|
||||
#include "defs.h"
|
||||
|
||||
knowledge_t *addknowledge(enum OBCLASS id, char *hiddenname, int known);
|
||||
material_t *addmaterial(enum MATERIAL id, char *name);
|
||||
objectclass_t *addoc(enum OBCLASS id, char *name, char glyph);
|
||||
objectclass_t *addoc(enum OBCLASS id, char *name, char *desc, char glyph);
|
||||
object_t *addob(obpile_t *where, char *name);
|
||||
object_t *addobject(obpile_t *where, char *name, int canstack);
|
||||
obpile_t *addobpile(lifeform_t *owner, cell_t *where);
|
||||
|
@ -11,27 +12,47 @@ objecttype_t *addot(int id, char *name, char *description, int material, float w
|
|||
object_t *canstackob(obpile_t *op, object_t *match);
|
||||
object_t *canstacknewot(obpile_t *op, objecttype_t *match);
|
||||
void copyobprops(object_t *dst, object_t *src);
|
||||
int countnames(char **list);
|
||||
int countobs(obpile_t *op);
|
||||
material_t *findmaterial(int id);
|
||||
objectclass_t *findoc(int id);
|
||||
object_t *findobl(obpile_t *op, char let); // find object by letter
|
||||
objecttype_t *findot(int id);
|
||||
objecttype_t *findot(enum OBTYPE id);
|
||||
objecttype_t *findotn(char *name); // find objecttype by name
|
||||
void genhiddennames(void);
|
||||
char *getdamname(enum DAMTYPE damtype);
|
||||
char getglyph(object_t *o);
|
||||
char *genhiddenname(enum OBCLASS id);
|
||||
char *gethiddenname(object_t *o);
|
||||
int getobattackspeed(object_t *o);
|
||||
int getletindex(char let);
|
||||
char getnextletter(obpile_t *op, char *wantletter);
|
||||
char *getobname(object_t *o, char *buf, int count);
|
||||
char *getrandomob(map_t *map, char *buf);
|
||||
char *getrandomobwithdt(map_t *map, enum DAMTYPE damtype, char *buf);
|
||||
object_t *hasknownob(obpile_t *op, enum OBTYPE oid);
|
||||
object_t *hasob(obpile_t *op, enum OBTYPE oid);
|
||||
object_t *hasobid(obpile_t *op, int id);
|
||||
void initobjects(void);
|
||||
int isdrinkable(object_t *o);
|
||||
int isknown(object_t *o);
|
||||
int isplainob(object_t *o);
|
||||
int isreadable(object_t *o);
|
||||
void killmaterial(material_t *m);
|
||||
void killob(object_t *o);
|
||||
void killoc(objectclass_t *oc);
|
||||
void killot(objecttype_t *ot);
|
||||
void makeknown(enum OBTYPE otid);
|
||||
object_t *moveob(object_t *src, obpile_t *dst, int howmany);
|
||||
object_t *obexists(enum OBTYPE obid);
|
||||
int obfits(object_t *o, obpile_t *op);
|
||||
int obpropsmatch(object_t *a, object_t *b);
|
||||
int pilehasletter(obpile_t *op, char let);
|
||||
void quaff(lifeform_t *lf, object_t *o);
|
||||
void read(lifeform_t *lf, object_t *o);
|
||||
int removeob(object_t *o, int howmany);
|
||||
object_t *relinkob(object_t *src, obpile_t *dst);
|
||||
void throwat(lifeform_t *thrower, object_t *o, cell_t *where);
|
||||
int willshatter(enum MATERIAL mat);
|
||||
#endif
|
||||
|
||||
|
|
121
save.c
121
save.c
|
@ -1,3 +1,4 @@
|
|||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -12,6 +13,9 @@
|
|||
|
||||
extern lifeform_t *player;
|
||||
extern map_t *firstmap;
|
||||
extern knowledge_t *knowledge;
|
||||
|
||||
int loading = B_FALSE;
|
||||
|
||||
int loadall(void) {
|
||||
DIR *dir;
|
||||
|
@ -19,6 +23,8 @@ int loadall(void) {
|
|||
char *filename;
|
||||
FILE *f;
|
||||
|
||||
loading = B_TRUE;
|
||||
|
||||
dir = opendir(MAPDIR);
|
||||
if (!dir) {
|
||||
dblog("Could not open map directory '%s'",MAPDIR);
|
||||
|
@ -41,10 +47,32 @@ int loadall(void) {
|
|||
|
||||
loadsavegame();
|
||||
|
||||
loading = B_FALSE;
|
||||
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
int loadknowledge(FILE *f) {
|
||||
int db = B_FALSE;
|
||||
char buf[BUFLEN];
|
||||
int otid,known;
|
||||
char hiddenname[BUFLEN];
|
||||
if (db) dblog("--> Loading knowledge...\n");
|
||||
fscanf(f, "startknowledge\n");
|
||||
|
||||
fgets(buf, BUFLEN, f);
|
||||
buf[strlen(buf)-1] = '\0'; // strip newline
|
||||
|
||||
while (strcmp(buf, "endknowledge")) {
|
||||
sscanf(buf, "%d^%s^%d",&otid, hiddenname, &known);
|
||||
addknowledge(otid, hiddenname, known);
|
||||
// get next line
|
||||
fgets(buf, BUFLEN, f);
|
||||
buf[strlen(buf)-1] = '\0'; // strip newline
|
||||
}
|
||||
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
// load and allocate one lifeform from given file
|
||||
lifeform_t *loadlf(FILE *f, cell_t *where) {
|
||||
|
@ -57,7 +85,7 @@ lifeform_t *loadlf(FILE *f, cell_t *where) {
|
|||
int obcount;
|
||||
int mapid;
|
||||
map_t *m;
|
||||
int x,y;
|
||||
int x,y,level;
|
||||
int db = B_TRUE;
|
||||
|
||||
if (db) dblog("--> Loading lifeform...\n");
|
||||
|
@ -67,6 +95,7 @@ lifeform_t *loadlf(FILE *f, cell_t *where) {
|
|||
fscanf(f, "race: %d\n",&lfraceid);
|
||||
fscanf(f, "map: %d\n",&mapid);
|
||||
fscanf(f, "pos: %d,%d\n",&x, &y);
|
||||
fscanf(f, "level: %d\n",&level);
|
||||
|
||||
// find the map
|
||||
m = findmap(mapid);
|
||||
|
@ -82,7 +111,7 @@ lifeform_t *loadlf(FILE *f, cell_t *where) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
l = addlf(where, lfraceid);
|
||||
l = addlf(where, lfraceid,level);
|
||||
l->id = lfid;
|
||||
l->x = x;
|
||||
l->y = y;
|
||||
|
@ -99,6 +128,7 @@ lifeform_t *loadlf(FILE *f, cell_t *where) {
|
|||
fscanf(f, "timespent: %d\n",&l->timespent);
|
||||
|
||||
fscanf(f, "sorted: %d\n",&l->sorted);
|
||||
fscanf(f, "forgettimer: %f\n",&l->forgettimer);
|
||||
|
||||
if (db) dblog("--> Got hp=%d/%d. timespend=%d. sorted=%d. Now loading ob list.",l->hp,l->maxhp,l->timespent,l->sorted);
|
||||
|
||||
|
@ -118,14 +148,17 @@ lifeform_t *loadlf(FILE *f, cell_t *where) {
|
|||
}
|
||||
if (db) dblog("--> Finished oblist. Found %d objects.",obcount);
|
||||
|
||||
// now load load object defs!
|
||||
// now load load object defs for this player!
|
||||
fscanf(f, "obdefs\n");
|
||||
for (i = 0; i < obcount; i++) {
|
||||
long thisid;
|
||||
if (db) dblog("--> Creating ob #%d for lf.",i);
|
||||
//if (db) dblog("-----> ob %d/%d...\n",i+1,obcount);
|
||||
if (loadob(f, l->pack)) {
|
||||
if (loadob(f, l->pack, &thisid)) {
|
||||
dblog("Error - can't create object %d/%d!\n",i+1,obcount);
|
||||
exit(1);
|
||||
}
|
||||
if (db) dblog("----> done (id=%ld)",thisid);
|
||||
}
|
||||
|
||||
// is this the player?
|
||||
|
@ -154,14 +187,12 @@ map_t *loadmap(char *basefile) {
|
|||
sprintf(filename, "%s/%s",MAPDIR,basefile);
|
||||
f = fopen(filename, "rt");
|
||||
|
||||
|
||||
|
||||
// create map
|
||||
m = addmap();
|
||||
dummycell = malloc(sizeof(cell_t));
|
||||
dummycell->obpile = addobpile(NULL, dummycell);
|
||||
dummycell->map = m;
|
||||
dummycell->type = (celltype_t *)0xabcde; // for debugging
|
||||
dummycell->type = (celltype_t *)DUMMYCELLTYPE; // for debugging
|
||||
|
||||
if (!m) {
|
||||
dblog("Error creating map while loading file '%s'",filename);
|
||||
|
@ -255,14 +286,23 @@ map_t *loadmap(char *basefile) {
|
|||
|
||||
// create all objects in a dummy cell
|
||||
for (i = 0; i < obcount; i++) {
|
||||
if (db) dblog("-----> ob %d/%d...\n",i+1,obcount);
|
||||
if (loadob(f, dummycell->obpile)) {
|
||||
int n;
|
||||
long thisid;
|
||||
if (db) dblog("-----> loading into dummycell: mapob %d/%d...\n",i+1,obcount);
|
||||
if (loadob(f, dummycell->obpile, &thisid)) {
|
||||
dblog("Error - can't create object %d/%d!\n",i+1,obcount);
|
||||
exit(1);
|
||||
}
|
||||
if (db) dblog("----------> got obid %ld\n",thisid);
|
||||
// check!
|
||||
if (!hasobid(dummycell->obpile, thisid)) {
|
||||
dblog("Error: after loading obid %ld, can't find it in dummycell!\n",thisid);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// hand out the objects to lifeforms...
|
||||
/*
|
||||
for (l = m->lf ; l ; l = l->next) {
|
||||
int curob = 0;
|
||||
long obid;
|
||||
|
@ -279,7 +319,7 @@ map_t *loadmap(char *basefile) {
|
|||
}
|
||||
}
|
||||
if (!found) {
|
||||
dblog("Error loading obs - lf %d should have obid %ld but can't find it.\n",l->id, obid);
|
||||
dblog("Error loading obs - lf %d should have obid %ld but can't find it in dummycell.\n",l->id, obid);
|
||||
exit(1);
|
||||
}
|
||||
// next one
|
||||
|
@ -293,6 +333,7 @@ map_t *loadmap(char *basefile) {
|
|||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
// hand out objects to cells
|
||||
for (y = 0; y < m->h; y++) {
|
||||
|
@ -303,23 +344,21 @@ map_t *loadmap(char *basefile) {
|
|||
c = m->cell[y * m->w + x];
|
||||
|
||||
obid = c->obpile->oblist[curob];
|
||||
dblog("Handing out objects to cell %d,%d\n",x,y);
|
||||
while (obid != -1) {
|
||||
int found = B_FALSE;
|
||||
dblog(" Looking for obid %ld in dummycell...",obid);
|
||||
// find this ob id in the dummycell
|
||||
for (o = dummycell->obpile->first ; o ; o = nexto) {
|
||||
nexto = o->next;
|
||||
if (o->id == obid) {
|
||||
o = hasobid(dummycell->obpile, obid);
|
||||
if (o) {
|
||||
dblog(" Got it.");
|
||||
relinkob(o, c->obpile);
|
||||
found = B_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
dblog("Error loading obs - cell %d,%d should have obid %ld but can't find it.\n",x,y, obid);
|
||||
} else {
|
||||
dblog(" Error loading obs - cell %d,%d should have obid %ld but can't find it.\n",x,y, obid);
|
||||
exit(1);
|
||||
}
|
||||
// next one
|
||||
curob++;
|
||||
obid = c->obpile->oblist[curob];
|
||||
}
|
||||
// clear the oblist
|
||||
for (i = 0; i < MAXPILEOBS; i++) {
|
||||
|
@ -345,11 +384,14 @@ map_t *loadmap(char *basefile) {
|
|||
|
||||
free(dummycell);
|
||||
|
||||
// successful load - kill the map now
|
||||
unlink(filename);
|
||||
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
int loadob(FILE *f, obpile_t *op) {
|
||||
int loadob(FILE *f, obpile_t *op, long *id) {
|
||||
objecttype_t *ot;
|
||||
object_t *o;
|
||||
material_t *mat;
|
||||
|
@ -359,17 +401,23 @@ int loadob(FILE *f, obpile_t *op) {
|
|||
int flagid;
|
||||
flag_t tempflag;
|
||||
int rv;
|
||||
int db = B_TRUE;
|
||||
|
||||
fscanf(f, "id:%ld\n",&obid);
|
||||
fscanf(f, "type:%d\n",&otid);
|
||||
|
||||
if (db) dblog("... loading object id %ld",obid);
|
||||
if (id) {
|
||||
*id = obid;
|
||||
}
|
||||
|
||||
ot = findot(otid);
|
||||
if (!ot) {
|
||||
dblog("ERROR loading objects - can't find obtype id %ld\n",obid);
|
||||
return B_TRUE;
|
||||
}
|
||||
// create the object
|
||||
o = addob(op, ot->name);
|
||||
o = addobject(op, ot->name, B_NOSTACK); // no stacking!
|
||||
|
||||
// overwrite ob parameters
|
||||
o->id = obid;
|
||||
|
@ -397,15 +445,16 @@ int loadob(FILE *f, obpile_t *op) {
|
|||
|
||||
fscanf(f, "flags:\n");
|
||||
|
||||
dblog("About to start loading object flags...");
|
||||
rv = fscanf(f, "%d,%d,%d,%d,%d\n",
|
||||
&tempflag.id, &tempflag.nvals, &tempflag.val[0], &tempflag.val[1], &tempflag.val[2]);
|
||||
|
||||
while (tempflag.id != -1) {
|
||||
dblog("got flag id=%d\n",tempflag.id);
|
||||
// get flag text
|
||||
fgets(buf, BUFLEN, f);
|
||||
buf[strlen(buf)-1] = '\0'; // strip newline
|
||||
|
||||
while (tempflag.id != -1) {
|
||||
dblog("got flag id=%d\n",tempflag.id);
|
||||
|
||||
addflag(o->flags, tempflag.id,
|
||||
tempflag.val[0],
|
||||
|
@ -451,6 +500,10 @@ int loadsavegame(void) {
|
|||
printf("Error loading savegame from file '%s'",ent->d_name);
|
||||
exit(1);
|
||||
}
|
||||
if (loadknowledge(f)) {
|
||||
printf("Error loading knowledge from file '%s'",ent->d_name);
|
||||
exit(1);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
// successful load - kill the savegame now
|
||||
|
@ -462,6 +515,23 @@ int loadsavegame(void) {
|
|||
return B_FALSE;
|
||||
}
|
||||
|
||||
int saveknowledge(FILE *f) {
|
||||
int db = B_FALSE;
|
||||
char buf[BUFLEN];
|
||||
int otid,known;
|
||||
char hiddenname[BUFLEN];
|
||||
knowledge_t *k;
|
||||
if (db) dblog("--> Saving knowledge...\n");
|
||||
fprintf(f, "startknowledge\n");
|
||||
|
||||
for (k = knowledge; k ; k = k->next) {
|
||||
fprintf(f, "%d^%s^%d\n",k->id, k->hiddenname, k->known);
|
||||
}
|
||||
fprintf(f, "endknowledge\n");
|
||||
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
int savelf(FILE *f, lifeform_t *l) {
|
||||
object_t *o;
|
||||
int obcount = 0;
|
||||
|
@ -471,12 +541,15 @@ int savelf(FILE *f, lifeform_t *l) {
|
|||
fprintf(f, "race: %d\n",l->race->id);
|
||||
fprintf(f, "map: %d\n",l->cell->map->id);
|
||||
fprintf(f, "pos: %d,%d\n",l->cell->x, l->cell->y);
|
||||
fprintf(f, "level: %d\n",l->level);
|
||||
// liefform will be cfeated after loading the above.
|
||||
fprintf(f, "contr: %d\n",l->controller);
|
||||
fprintf(f, "hp: %d/%d\n",l->hp, l->maxhp);
|
||||
fprintf(f, "alive: %d\n",l->alive);
|
||||
fprintf(f, "lastdam: %s\n",l->lastdam);
|
||||
fprintf(f, "timespent: %d\n",l->timespent);
|
||||
fprintf(f, "sorted: %d\n",l->sorted);
|
||||
fprintf(f, "forgettimer: %f\n",l->forgettimer);
|
||||
// lifeform objects
|
||||
obcount = 0;
|
||||
for (o = l->pack->first ; o ; o = o->next) {
|
||||
|
|
4
save.h
4
save.h
|
@ -1,10 +1,12 @@
|
|||
#include "defs.h"
|
||||
|
||||
int loadall(void);
|
||||
int loadknowledge(FILE *f);
|
||||
lifeform_t *loadlf(FILE *f, cell_t *where);
|
||||
map_t *loadmap(char *basefile);
|
||||
int loadob(FILE *f, obpile_t *op);
|
||||
int loadob(FILE *f, obpile_t *op, long *id);
|
||||
int loadsavegame(void);
|
||||
int saveknowledge(FILE *f);
|
||||
int savelf(FILE *f, lifeform_t *l);
|
||||
int savemap(map_t *m);
|
||||
int saveob(FILE *f, object_t *o);
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "defs.h"
|
||||
#include "flag.h"
|
||||
#include "map.h"
|
||||
#include "objects.h"
|
||||
#include "text.h"
|
||||
|
||||
extern lifeform_t *player;
|
||||
|
||||
void dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target) {
|
||||
char buf[BUFLEN];
|
||||
if (spellid == OT_S_RNDTELEPORT) {
|
||||
cell_t *c = NULL;
|
||||
while (!c || c->type->solid) {
|
||||
c = getrandomcell(target->cell->map);
|
||||
}
|
||||
if ((target->controller != C_PLAYER) && haslos(player, target->cell)) {
|
||||
getlfname(target, buf);
|
||||
capitalise(buf);
|
||||
msg("%s disappears in a puff of smoke!", buf);
|
||||
}
|
||||
// TODO: add smoke
|
||||
movelf(target, c);
|
||||
// TODO: add more smoke
|
||||
if (target->controller == C_PLAYER) {
|
||||
msg("Suddenly, your surroundings appear different!");
|
||||
} else if (haslos(player, target->cell)) {
|
||||
getlfname(target, buf);
|
||||
capitalise(buf);
|
||||
msg("%s appears in a puff of smoke!", buf);
|
||||
}
|
||||
} else if (spellid == OT_S_MAPPING) {
|
||||
int x,y;
|
||||
map_t *m;
|
||||
m = caster->cell->map;
|
||||
// reveal map
|
||||
for (y = 0; y < m->h; y++) {
|
||||
for (x = 0; x < m->w; x++) {
|
||||
cell_t *c;
|
||||
c = getcellat(m, x, y);
|
||||
c->known = B_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (target->controller == C_PLAYER) {
|
||||
msg("An image of your surroundings appears in your mind!");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef __SPELLS_H
|
||||
#define __SPELLS_H
|
||||
#include "defs.h"
|
||||
|
||||
void dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target);
|
||||
|
||||
#endif
|
||||
|
63
text.c
63
text.c
|
@ -24,9 +24,25 @@ int isvowel (char c) {
|
|||
// allocates and returns new string
|
||||
char *makeplural(char *text) {
|
||||
int newlen;
|
||||
char *newtext;
|
||||
char lastlet;
|
||||
char *newtext;
|
||||
char *p;
|
||||
int rv;
|
||||
|
||||
newtext = strdup(text);
|
||||
|
||||
// scrolls
|
||||
rv = strrep(newtext, "scroll ", "scrolls ");
|
||||
if (rv) return newtext;
|
||||
rv = strrep(newtext, "potion ", "potions ");
|
||||
if (rv) return newtext;
|
||||
rv = strrep(newtext, "piece ", "pieces ");
|
||||
if (rv) return newtext;
|
||||
|
||||
rv = strrep(newtext, "pair ", "pairs ");
|
||||
// don't return
|
||||
|
||||
// default
|
||||
lastlet = text[strlen(text)-1];
|
||||
switch (lastlet) {
|
||||
case 's':
|
||||
|
@ -39,3 +55,48 @@ char *makeplural(char *text) {
|
|||
}
|
||||
return newtext;
|
||||
}
|
||||
|
||||
int strrep(char *text, char *oldtok, char *newtok) {
|
||||
char *temp;
|
||||
int rv;
|
||||
temp = strdup(" ");
|
||||
rv = dostrrep(text, &temp, oldtok, newtok);
|
||||
// swap
|
||||
text = realloc(text, strlen(temp));
|
||||
strcpy(text, temp);
|
||||
free(temp);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// returns TRUE if any replacements made
|
||||
int dostrrep(char* in, char** out, char* oldtok, char* newtok) {
|
||||
char *temp;
|
||||
char *found = strstr(in, oldtok);
|
||||
int idx;
|
||||
if(!found) {
|
||||
*out = realloc(*out, strlen(in) + 1);
|
||||
strcpy(*out, in);
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
idx = found - in;
|
||||
|
||||
*out = realloc(*out, strlen(in) - strlen(oldtok) + strlen(newtok) + 1);
|
||||
strncpy(*out, in, idx);
|
||||
strcpy(*out + idx, newtok);
|
||||
strcpy(*out + idx + strlen(newtok), in + idx + strlen(oldtok));
|
||||
|
||||
temp = malloc(idx+strlen(newtok)+1);
|
||||
strncpy(temp,*out,idx+strlen(newtok));
|
||||
temp[idx + strlen(newtok)] = '\0';
|
||||
|
||||
dostrrep(found + strlen(oldtok), out, oldtok, newtok);
|
||||
temp = realloc(temp, strlen(temp) + strlen(*out) + 1);
|
||||
strcat(temp,*out);
|
||||
free(*out);
|
||||
*out = temp;
|
||||
|
||||
return B_TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue