This commit is contained in:
Rob Pearce 2010-12-07 07:34:26 +00:00
parent 17457b0537
commit 014d591109
26 changed files with 17654 additions and 1105 deletions

View File

@ -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
View File

@ -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
View File

@ -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;
}
}

View File

@ -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
View File

@ -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;

View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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);

15428
log.txt

File diff suppressed because it is too large Load Diff

81
map.c
View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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;

View File

@ -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);

925
objects.c

File diff suppressed because it is too large Load Diff

View File

@ -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

119
save.c
View File

@ -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) {
} 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
View File

@ -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);

53
spell.c Normal file
View File

@ -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!");
}
}
}

8
spell.h Normal file
View File

@ -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
View File

@ -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;
}

2
text.h
View File

@ -4,3 +4,5 @@ char *capitalise(char *text);
int isvowel(char c);
char *makeplural(char *text);
int strrep(char *text, char *oldtok, char *newtok);
int dostrrep(char* in, char** out, char* oldtok, char* newtok);