initial checkin

This commit is contained in:
Rob Pearce 2010-12-02 01:17:54 +00:00
commit 19d30819ae
30 changed files with 6773 additions and 0 deletions

2
Makefile Normal file
View File

@ -0,0 +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

124
ai.c Normal file
View File

@ -0,0 +1,124 @@
#include <stdio.h>
#include <stdlib.h>
#include "ai.h"
#include "defs.h"
#include "flag.h"
#include "lf.h"
#include "map.h"
#include "objects.h"
extern lifeform_t *player;
void aimove(lifeform_t *lf) {
int dir;
int db = B_TRUE;
flag_t *f;
lifeform_t *target;
char buf[BUFLEN];
if (db) dblog("AIMOVE: %s", lf->race->name);
// if lifeform isn't alive, skip turn
if (isdead(lf)) {
taketime(lf, SPEED_DEAD);
return;
}
f = hasflag(lf->flags, F_TARGET);
if (f) {
int targid;
targid = f->val[0];
target = findlf(lf->cell->map, targid);
if (target) {
if (haslos(lf, target->cell)) {
movetowards(lf, target->cell);
return;
} else {
// TODO: move towards last known location
// just try to move in a random direction
dorandommove(lf);
return;
}
}
} else {
// not attacking anyone in particular
// TODO: are we hostile? if so, look for a target
f = hasflag(lf->flags, F_HOSTILE);
if (f) {
int x,y;
cell_t *c;
// 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++) {
for (x = lf->cell->x - 10; x <= lf->cell->x + 10; x++) {
c = getcellat(lf->cell->map, x, y);
// cell exists and we can see it?
if (c && haslos(lf, c)) {
// player there?
if (c->lf && c->lf->controller == C_PLAYER) {
// target them!
addflag(lf->flags, F_TARGET, c->lf->id, -1, -1, "");
// tell the player
if (haslos(player, lf->cell)) {
getlfname(lf, buf);
capitalise(buf);
msg("%s sees you!", buf);
}
// then move towards them...
movetowards(lf, c);
return;
}
}
}
}
}
// just try to move in a random direction
dorandommove(lf);
return;
}
// if we get this far, just wait
dowait(lf);
}
int getdirtowards(lifeform_t *lf, cell_t *dst) {
int d;
cell_t *c;
int mindist=9999,bestdir=D_NONE;
for (d = DC_N; d <= DC_NW; d++) {
c = getcellindir(lf->cell, d);
if (!c) continue;
if (c == dst) {
// destination is adjacent!
bestdir = d;
break;
}
if (canmove(lf, d)) {
int thisdist;
thisdist = getcelldist(c, dst);
if (thisdist < mindist) {
mindist = thisdist;
bestdir = d;
}
}
}
// TODO: handle ties
return bestdir;
}
void movetowards(lifeform_t *lf, cell_t *dst) {
int dir;
// move towards them
dir = getdirtowards(lf, dst);
if (dir != D_NONE) {
trymove(lf, dir);
}
}

5
ai.h Normal file
View File

@ -0,0 +1,5 @@
#include "defs.h"
void aimove(lifeform_t *lf);
int getdirtowards(lifeform_t *lf, cell_t *dst);
void movetowards(lifeform_t *lf, cell_t *dst);

50
attack.c Normal file
View File

@ -0,0 +1,50 @@
#include <stdio.h>
#include <stdlib.h>
#include "attack.h"
#include "defs.h"
extern lifeform_t *player;
void doattack(lifeform_t *lf, lifeform_t *victim) {
int dam;
char buf[BUFLEN];
char attackername[BUFLEN];
char victimname[BUFLEN];
int fatal = B_FALSE;
// 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;
getlfname(lf, attackername);
getlfname(victim, victimname);
losehp(victim, dam, lf, attackername); // TODO: use player name if required
if (victim->hp <= 0) {
fatal = B_TRUE;
}
// announce it
if (lf->controller == C_PLAYER) {
msg("You %s %s%s",
fatal ? "kill" : "hit",
victimname,
fatal ? "!" : ".");
// don't also say "the xx dies"
addflag(victim->flags, F_NODEATHANNOUNCE, B_TRUE, -1, -1, "");
} else {
if (haslos(player, lf->cell)) {
// capitalise first letter
sprintf(buf, "%s",attackername);
capitalise(buf);
msg("%s hits %s.", buf, victimname);
}
}
}

3
attack.h Normal file
View File

@ -0,0 +1,3 @@
#include "defs.h"
void doattack(lifeform_t *lf, lifeform_t *victim);

374
defs.h Normal file
View File

@ -0,0 +1,374 @@
#ifndef __DEFS_H
#define __DEFS_H
// MACROS
#define MAXOF(a,b) (a > b ? a : b)
// save/load
#define MAPDIR "data/maps"
#define SAVEDIR "data/save"
// SPECIAL NUMBERS/CONSTANTS
#define UNLIMITED (-9876)
#define ALL (-9875)
#define NA (-9874)
// STRINGS
#define BUFLENSMALL 64
#define BUFLEN 128
#define HUGEBUFLEN 1024
#define MORESTRING "--More--"
// LIMITS
#define SCREENW 80
#define SCREENH 24
#define MAXPILEOBS 52
#define MAXRANDOMOBCANDIDATES 100
#define MAX_MAPW 80
#define MAX_MAPH 50
//#define MAX_MAPROOMS 10
#define MIN_ROOMH 4
#define MIN_ROOMW 4
#define MAX_ROOMW (MAX_MAPW / 5)
#define MAX_ROOMH (MAX_MAPH / 5)
#define MAXDIR_ORTH 4
#define MAXDIR_COMPASS 8
// MAP BUILDING
#define DEF_TURNPCT 40
#define DEF_SPARSENESS 14
//#define DEF_SPARSENESS 0
#define DEF_LOOPPCT 70
//#define DEF_LOOPPCT 0
#define MINROOMS 15
#define MAXROOMS 25
#define DEF_WINDOWPCT 5
//
#define ANIMDELAY (1000000 / 100) // 1/100 of a second
// CONTROLLERS
#define C_AI 0
#define C_PLAYER 1
// speed settings (lower is faster)
#define SPEED_ATTACK 10
#define SPEED_DEAD 50
#define SPEED_MOVE 10
#define SPEED_DROP 5
#define SPEED_PICKUP 5
#define SPEED_THROW 10
#define SPEED_WAIT 10
// DIRECTION TYPES
#define DT_ORTH 0
#define DT_COMPASS 1
// DIRECTIONS
#define D_NONE -1
#define D_UNKNOWN -2
// Orthogonal directions
#define D_N 0
#define D_E 1
#define D_S 2
#define D_W 3
// Compass directions
#define DC_N 4
#define DC_NE 5
#define DC_E 6
#define DC_SE 7
#define DC_S 8
#define DC_SW 9
#define DC_W 10
#define DC_NW 11
// Cell types
#define CT_WALL 0
#define CT_ROOMWALL 1
#define CT_CORRIDOR 2
#define CT_ROOM 3
#define CT_DOOROPEN 4
#define CT_DOORCLOSED 5
#define CT_LOOPCORRIDOR 6
// Object Classes
enum OBCLASS {
OC_MONEY,
OC_WEAPON,
OC_ARMOUR,
OC_SCROLL,
OC_POTION,
OC_FOOD,
OC_ROCK,
OC_MISC,
OC_NULL = -999
};
enum BLESSTYPE {
B_UNCURSED = 0,
B_BLESSED = 1,
B_CURSED = -1
};
enum HABITAT {
H_DUNGEON = 1,
H_ALL = 999
};
enum RARITY {
RR_NEVER = 6,
RR_VERYRARE = 5,
RR_RARE = 4,
RR_UNCOMMON = 3,
RR_COMMON = 2,
RR_FREQUENT = 1,
};
enum RACE {
R_BAT,
R_GIANTFLY,
R_GIANTBLOWFLY,
R_HUMAN,
R_GOBLIN,
};
// Object Materials
enum MATERIAL {
MT_STONE,
MT_FIRE,
MT_PLASTIC,
MT_METAL,
MT_FLESH,
MT_WOOD,
MT_GOLD
};
// Object Types
enum OBTYPE {
// rocks
OT_GOLD,
OT_STONE,
// corpses
OT_CORPSEHUMAN,
OT_CORPSEGOBLIN,
OT_CORPSEBAT,
OT_CORPSEFLY,
};
enum FLAG {
// object flags
F_STACKABLE, // can stack multiple objects togethr
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
// lifeform flags
F_CORPSETYPE, // text field specifies what corpse obtype to leave
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_NULL = -1
};
// probabilities
//#define CH_DEADENDOB 35
//#define CH_EMPTYCELLOB 3
#define CH_PILLAR 5
// Booleans
#define B_FALSE (0)
#define B_TRUE (-1)
#define B_NOSTACK (0)
#define B_STACK (-1)
#define B_STACKOK (-1)
#define NOOWNER (NULL)
#define NOLOC (NULL)
#define B_NOTSOLID (0)
#define B_EMPTY (0)
#define B_SOLID (-1)
#define B_OPAQUE (0)
#define B_TRANSPARENT (-1)
#define B_TRANS (-1)
// errors
enum ERROR {
E_OK = 0,
E_WALLINWAY = 1,
E_LFINWAY = 2,
E_NOSPACE = 3
};
typedef struct map_s {
int id;
char *name; // name of this map
enum HABITAT habitat; // eg. dungeon, forest, etc
unsigned int seed;
int w,h; // width/height of this map
struct cell_s *cell[MAX_MAPW*MAX_MAPH]; // list of cells in this map
int nextmap[MAXDIR_ORTH]; // which map is in each direction
long nextlfid;
struct lifeform_s *lf,*lastlf;
struct map_s *next, *prev;
} map_t; //////////////// remember to modify save/load for new props!!
typedef struct cell_s {
map_t *map; // pointer back to map
int x,y; // map coords
int roomid;
struct celltype_s *type;
struct obpile_s *obpile;
// lifeform pile
struct lifeform_s *lf;
// known to player?
int known;
// FOR CONSTRUCTION
int visited;
} cell_t;
typedef struct celltype_s {
int id; // eg. dungeonfloor, wall, door
char glyph; // how to display it
int solid; // can you walk through it?
int transparent; // can you see through it?
struct celltype_s *next, *prev;
} celltype_t;
typedef struct race_s {
enum RACE id;
char *name;
char glyph;
struct flagpile_s *flags;
// speed modifiers
// hit dice
struct race_s *next, *prev;
} race_t;
typedef struct lifeform_s {
int id;
int controller;
struct race_s *race;
int hp,maxhp;
int alive;
char *lastdam;
int timespent;
int sorted;
struct obpile_s *pack;
struct flagpile_s *flags;
// for loading
long oblist[MAXPILEOBS];
int x,y;
struct cell_s *cell;
struct lifeform_s *next, *prev;
} lifeform_t;
typedef struct obpile_s {
lifeform_t *owner;// } Only one of these
cell_t *where; // } should be filled in
struct object_s *first,*last;
// for loading
long oblist[MAXPILEOBS];
} obpile_t;
typedef struct flagpile_s {
struct flag_s *first,*last;
} flagpile_t;
typedef struct flag_s {
enum FLAG id;
int nvals;
int val[3];
char *text;
struct flagpile_s *pile;
struct flag_s *next, *prev;
} flag_t;
typedef struct material_s {
int id;
char *name;
struct material_s *next,*prev;
} material_t;
typedef struct objectclass_s {
enum OBCLASS id;
char *name;
char glyph;
struct objectclass_s *next, *prev;
} objectclass_t;
typedef struct objecttype_s {
enum OBTYPE id;
char *name;
char *desc;
struct objectclass_s *obclass;
material_t *material;
float weight; // in kilograms
struct flagpile_s *flags;
struct objecttype_s *next, *prev;
} objecttype_t;
typedef struct object_s {
long id; // unique for every ob in the game!
struct objecttype_s *type;
struct obpile_s *pile; // reverse pointer back to pile
// these variables are initially
// inherited from objecttype:
material_t *material;
float weight; // in kilograms
// flags
// these variables are NOT inherited
char *inscription;
char letter;
enum BLESSTYPE blessed;
int blessknown;
int amt; // for stackable objects
flagpile_t *flags;
struct object_s *next, *prev;
} object_t;
#endif

8
doc/add_obclass.txt Normal file
View File

@ -0,0 +1,8 @@
when adding a new obejct class:
In defs.h:
add its OC_ enum
In objects.c:
define the class with addoc()
add the class to sortorder[] at the top

11
doc/add_race.txt Normal file
View File

@ -0,0 +1,11 @@
defs.h:
add RACE enum (R_xx)
add OT_CORPSExxx obtype
lf.c:
addrace(R_xx)
+ flagso
objects.c:
addot(OTCORPSE)

120
flag.c Normal file
View File

@ -0,0 +1,120 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "defs.h"
#include "flag.h"
#include "text.h"
flag_t *addflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text) {
flag_t *f;
int i;
if (fp->first == NULL) {
fp->first = malloc(sizeof(flag_t));
f = fp->first;
f->prev = NULL;
} else {
// go to end of list
f = fp->last;
f->next = malloc(sizeof(flag_t));
f->next->prev = f;
f = f->next;
}
fp->last = f;
f->next = NULL;
// fill in props
f->id = id; // increment next ob id
// first blank values
for (i = 0; i < 3; i++) {
f->val[i] = 0;
}
f->val[0] = val1;
f->nvals = 1;
if (val2 != NA) {
f->val[1] = val2;
f->nvals++;
}
if (val3 != NA) {
f->val[2] = val2;
f->nvals++;
}
if (text) {
f->text = strdup(text);
} else {
f->text = strdup("");
}
f->pile = fp;
return f;
}
flagpile_t *addflagpile(void) {
flagpile_t *fp;
fp = malloc(sizeof(flagpile_t));
fp->first = NULL;
fp->last = NULL;
return fp;
}
flag_t *hasflag(flagpile_t *fp, int id) {
flag_t *f;
for (f = fp->first ; f ; f = f->next) {
if (f->id == id) return f;
}
return NULL;
}
flag_t *hasflagval(flagpile_t *fp, int id, int val1, int val2, int val3, char *text) {
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)) &&
((text == NULL) || strstr(f->text, text))) {
return f;
}
}
}
return NULL;
}
void killflag(flag_t *f) {
int i;
flag_t *nextone, *lastone;
// free mem
// remove from list
nextone = f->next;
if (nextone != NULL) {
nextone->prev = f->prev;
} else { /* last */
f->pile->last = f->prev;
}
if (f->prev == NULL) {
/* first */
nextone = f->next;
f->pile->first = nextone;
free(f);
} else {
lastone = f->prev;
free (lastone->next );
lastone->next = nextone;
}
}
void killflagpile(flagpile_t *fp) {
while (fp->first) {
killflag(fp->first);
}
free(fp);
}

10
flag.h Normal file
View File

@ -0,0 +1,10 @@
#include "defs.h"
// functions
flag_t *addflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text);
flagpile_t *addflagpile(void);
flag_t *hasflag(flagpile_t *fp, int id);
flag_t *hasflagval(flagpile_t *fp, int id, int val1, int val2, int val3, char *text);
void killflag(flag_t *f);
void killflagpile(flagpile_t *fp);

921
io.c Normal file
View File

@ -0,0 +1,921 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ncurses.h>
#include "defs.h"
#include "io.h"
#include "map.h"
#include "move.h"
#include "nexus.h"
#include "objects.h"
WINDOW *mainwin;
WINDOW *gamewin;
WINDOW *msgwin;
WINDOW *statwin;
extern enum ERROR reason;
extern FILE *logfile;
extern enum OBCLASS sortorder[];
extern int gamestarted;
char msgbuf[HUGEBUFLEN];
extern lifeform_t *player;
extern map_t *firstmap;
int viewx = -9999,viewy = -9999;
int vieww,viewh;
void anim(cell_t *src, cell_t *dst, char ch) {
int deltax, deltay;
int numpixels;
int d;
int dinc1,dinc2,xinc1,xinc2,yinc1,yinc2;
int xinc,yinc,dinc;
int i;
int x1,y1,dir;
int x;
int y;
int maxvisrange;
int modmaxvisrange;
int xray = B_FALSE;
int wentuphill = B_FALSE;
int origheight;
int shopwall;
int x2,y2;
// just in case
if (src->map != dst->map) return;
x1 = src->x;
y1 = src->y;
x2 = dst->x;
y2 = dst->y;
deltax = (x2 - x1);
if (deltax < 0) deltax = -deltax;
deltay = (y2 - y1);
if (deltay < 0) deltay = -deltay;
// going nowhere
if ((deltax == 0) && (deltay == 0)) {
return;
}
if (deltax >= deltay) {
numpixels = deltax + 1;
d = (deltay*2) - deltax;
dinc1 = deltay << 1;
dinc2 = (deltay-deltax) << 1;
xinc1 = 1;
xinc2 = 1;
yinc1 = 0;
yinc2 = 1;
} else {
numpixels = deltay + 1;
d = (deltax*2) - deltay;
dinc1 = deltax << 1;
dinc2 = (deltax - deltay) << 1;
xinc1 = 0;
xinc2 = 1;
yinc1 = 1;
yinc2 = 1;
}
if (x1 > x2) {
xinc1 = - xinc1;
xinc2 = - xinc2;
}
if (y1 > y2) {
yinc1 = - yinc1;
yinc2 = - yinc2;
}
x = x1; y = y1;
for (i = 0; i < numpixels ; i++) {
cell_t *cell;
// get current cell
cell = getcellat(src->map, x, y);
// update screen
updateviewfor(cell);
drawlevelfor(player);
// draw char & cursor at its current pos...
mvwprintw(gamewin, cell->y - viewy, cell->x - viewx, "%c", ch);
wmove(gamewin, cell->y - viewy, cell->x - viewx);
wrefresh(gamewin);
usleep(ANIMDELAY);
// move to next cell
if (d < 0) {
xinc = xinc1;
yinc = yinc1;
dinc = dinc1;
} else {
xinc = xinc2;
yinc = yinc2;
dinc = dinc2;
}
d += dinc;
x += xinc;
y += yinc;
}
}
cell_t *askcoords(char *prompt) {
int finished = B_FALSE;
cell_t *c,*newcell;
c = player->cell;
wclear(msgwin);
mvwprintw(msgwin, 0, 0, "%s", prompt);
wrefresh(msgwin);
while (!finished) {
int dir;
char ch;
drawstatus();
updateviewfor(c);
drawlevelfor(player);
// move cursor selected position
wmove(gamewin, c->y - viewy, c->x - viewx);
redraw();
// get input
ch = getch();
if (ch == '.') {
return c;
} else if (ch == 27) { // ESC - cancel
finished = B_TRUE;
} else {
dir = chartodir(ch);
if (dir != D_NONE) {
newcell = getcellindir(c, dir);
if (newcell) c = newcell;
}
}
}
return NULL;
}
object_t *askobject(obpile_t *op, char *prompt, int *count) {
int c,i;
object_t *mylist[MAXPILEOBS+1];
char myletters[MAXPILEOBS+1];
char numstring[BUFLEN];
int firstob = 0;
int nextpage = -1;
int lastline = SCREENH-2;
char buf[BUFLEN];
int finished;
char nextlet = 'a';
int useobletters;
// if picking form a player's pack, use the object's letters.
// otherwise just label them a, b, c, etc.
if (op->owner && (op->owner->controller == C_PLAYER)) {
useobletters = B_TRUE;
} else {
useobletters = B_FALSE;
}
// construct a list of objects
c = 0;
i = 0;
while (sortorder[c] != OC_NULL) {
object_t *o;
// add all objects of this class
for (o = op->first ; o ; o = o->next) {
if (o->type->obclass->id == sortorder[c]) {
mylist[i] = o;
myletters[i] = nextlet;
if (++nextlet > 'z') nextlet = 'A';
i++;
}
}
c++;
}
mylist[i] = NULL;
// start displaying from the first one
firstob = 0;
nextpage = -1;
finished = B_FALSE;
strcpy(numstring, "");
while (!finished) {
int lastclass = OC_NULL;
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;
// print class heading
mvwprintw(mainwin, y, 0, "%s", mylist[i]->type->obclass->name);
lastclass = mylist[i]->type->obclass->id;
y++;
}
getobname(mylist[i], buf,mylist[i]->amt);
mvwprintw(mainwin, y, 0, " %c - %s",
useobletters ? mylist[i]->letter : myletters[i],
buf);
y++;
}
if (mylist[i] == NULL) {
nextpage = -1;
} else {
nextpage = i;
}
// draw prompt
if (strlen(numstring) > 0) {
mvwprintw(mainwin, 0, 0, "%s (ESC to quit) [%s]: ",prompt, numstring);
} else {
mvwprintw(mainwin, 0, 0, "%s (ESC to quit): ", prompt);
}
if (nextpage != -1) {
mvwprintw(mainwin, y, 0, "-- More --");
}
// update screen
wrefresh(mainwin);
// wait for keypess
ch = getch();
if (ch == 27) { // ESCAPE
finished = B_TRUE;
break;
}
// otherwise look for shift key etc..
ch = keycodetokey(ch);
// then handle input
if (ch == ' ') { // next page
if (nextpage == -1) { // go to first page
firstob = 0;
} else {
firstob = nextpage;
}
} else if (isalpha(ch)) {
object_t *o;
// describe that object
if (useobletters) {
o = findobl(op, ch);
} else {
o = NULL;
for (i = firstob ; (mylist[i] != NULL) && (y < lastline); i++) {
if (myletters[i] == ch) {
o = mylist[i];
break;
}
}
}
if (o) {
// make sure count is okay...
if (count && *count > o->amt) {
*count = o->amt;
}
if (count && (*count == ALL)) {
*count = o->amt;
}
// display game windows again
drawscreen();
return o;
}
} else if (isdigit(ch)) {
char temp[2];
temp[0] = ch;
temp[1] = '\0';
strcat(numstring, temp);
*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);
}
}
// sanity check count...
if (count && (*count == 0)) {
strcpy(numstring, "");
}
}
// display game windows again
drawscreen();
return NULL;
}
void centre(WINDOW *win, int y, char *format, ... ) {
int w;
char buf[BUFLEN];
va_list args;
va_start(args, format);
vsprintf( buf, format, args );
va_end(args);
w = getmaxx(win);
mvwprintw(win, y, (w/2) - (strlen(buf)/2), buf);
}
int chartodir(char c) {
switch (tolower(c)) {
case 'h': return D_W;
case 'j': return D_S;
case 'k': return D_N;
case 'l': return D_E;
case 'y': return DC_NW;
case 'u': return DC_NE;
case 'b': return DC_SW;
case 'n': return DC_SE;
}
return D_NONE;
}
void clearmsg(void) {
wclear(msgwin);
wrefresh(msgwin);
}
int cleanupgfx(void) {
curs_set(1);
endwin();
return B_FALSE;
}
void updateviewfor(cell_t *cell) {
// calculate viewport if required
if ((viewx == -9999) || (viewy == -9999)) {
// try to centre player
viewx = cell->x - (SCREENW/2);
viewy = cell->y - (SCREENH/2);
}
while ((cell->x - viewx) >= ((SCREENW / 3)*2)) {
viewx++;
}
while ((cell->y - viewy) >= ((SCREENH / 3)*2)) {
viewy++;
}
while ((cell->x - viewx) <= (SCREENW/3)) {
viewx--;
}
while ((cell->y - viewy) <= (SCREENH/3)) {
viewy--;
}
}
void drawscreen(void) {
drawstatus();
updateviewfor(player->cell);
drawlevelfor(player);
drawcursor();
redraw();
}
void describeob(object_t *o) {
char buf[BUFLEN];
int y;
material_t *m;
wclear(mainwin);
// title
getobname(o, buf,o->amt);
mvwprintw(mainwin, 0, 0, buf);
mvwprintw(mainwin, 2, 0, o->type->desc);
// properties
y = 4;
mvwprintw(mainwin, y, 0, "%s made from %s.",(o->amt == 1) ? "It is" : "They are", o->material->name); y++;
if (o->amt == 1) {
mvwprintw(mainwin, y, 0, "It weighs %0.1fkg.",o->weight);
} else {
mvwprintw(mainwin, y, 0, "They weigh %0.1fkg (%0.1f each).",(o->weight * o->amt), o->weight);
}
wrefresh(mainwin);
// wait for key
getch();
}
void dodrop(obpile_t *op) {
object_t *o;
char buf[BUFLEN];
int count = ALL;
o = askobject(op, "Drop what", &count);
if (o) {
getobname(o, buf, count);
o = moveob(o, op->owner->cell->obpile, count);
if (o) { // if drop was successful...
if (op->owner) {
if (op->owner->controller == C_PLAYER) {
msg("You drop %s.",buf);
}
taketime(op->owner, (SPEED_DROP * count));
}
} else {
// tell the player why!
if (op->owner->controller == C_PLAYER) {
switch (reason) {
case E_NOSPACE:
msg("There is no space here for any more objects!");
break;
default:
msg("For some reason, you cannot drop %s!");
break;
}
}
}
}
}
void dopickup(lifeform_t *lf, obpile_t *op) {
int obcount;
object_t *o = NULL;
int howmany = ALL;
char buf[BUFLEN];
obcount = countobs(op);
// anything here?
if (obcount == 0) {
if (lf->controller == C_PLAYER) {
msg("There is nothing here to pick up!");
}
return;
} 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);
}
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));
} 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;
}
}
}
}
void doinventory(obpile_t *op) {
object_t *o;
o = askobject(op, "Select object to describe", NULL);
while (o) {
// describe it
describeob(o);
// ask for another one
o = askobject(op, "Select object to describe", NULL);
}
}
void dothrow(obpile_t *op) {
object_t *o;
char buf[BUFLEN],buf2[BUFLEN];
// ask which object to throw
o = askobject(op, "Throw what", NULL);
if (o) {
cell_t *where;
getobname(o, buf, 1);
// TODO: calculate throw range
// ask where to throw it
sprintf(buf2, "Throw %s where?",buf);
where = askcoords(buf2);
if (where) {
if (haslof(player, where)) {
throwat(player, o, where);
} else {
msg("You don't have a clear line of fire to there.");
}
}
}
}
void drawcell(cell_t *cell, int x, int y) {
if (cell->lf) { // lifeform here?
// TODO: draw the lf's race glyph
mvwprintw(gamewin, y, x, "%c", cell->lf->race->glyph);
} else if (countobs(cell->obpile) > 0) {
object_t *o;
int c;
int drawn = B_FALSE;
// draw highest object in sort order
c = 0;
while ((sortorder[c] != OC_NULL) && (!drawn)) {
// check each object against this ob class
// count backwards so more recently dropped objects
// appear first.
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);
drawn = B_TRUE;
break;
}
}
c++;
}
if (!drawn) {
// should never happen. if it does, just show the
// first object
dblog("Warn: sorted object glyph drawing matching nothing!");
mvwprintw(gamewin, y, x, "%c", cell->obpile->first->type->obclass->glyph);
}
} else {
// draw ground
mvwprintw(gamewin, y, x, "%c", cell->type->glyph);
}
}
void drawcursor(void) {
// move cursor to player position
wmove(gamewin, player->cell->y - viewy, player->cell->x - viewx);
wrefresh(gamewin);
}
void drawlevelfor(lifeform_t *lf) {
int x,y;
int cx,cy;
cell_t *cell;
map_t *map;
map = lf->cell->map;
wclear(gamewin);
for (y = viewy; y < viewy + viewh; y++) {
for (x = viewx; x < viewx + vieww; x++) {
cell = getcellat(map, x, y);
if (cell) {
if (haslos(lf, cell)) {
drawcell(cell, x-viewx, y-viewy);
}
}
}
}
}
void initgfx(void) {
mainwin = initscr();
if (!has_colors()) {
printf("Terminal does not support colour.\n");
exit(1);
}
start_color();
noecho();
cbreak();
nodelay(mainwin, FALSE);
// determine window sizes
vieww = SCREENW;
viewh = SCREENH - 4;
// create windows
msgwin = newwin(1, vieww, 0, 0);
gamewin = newwin(viewh, vieww, 1, 0);
statwin = newwin(2, vieww, 2 + viewh,0);
redraw();
refresh();
// init message buffer
strcpy(msgbuf, "");
}
int getkey(void) {
int key_code=0;
key_code = getch();
return keycodetokey(key_code);
}
void handleinput(void) {
int ch;
ch = getkey();
switch (ch) {
// movement
case 'h':
case 'j':
case 'k':
case 'l':
case 'y':
case 'u':
case 'b':
case 'n':
trymove(player, chartodir(ch));
break;
case 'H':
case 'J':
case 'K':
case 'L':
case 'Y':
case 'U':
case 'B':
case 'N':
tryrun(player, chartodir(ch));
break;
case '.': // wait
dowait(player);
break;
// testing
case '1':
msg("Something happens.");
msg("Something else happens.");
msg("Another thing is about to happen now.");
msg("Too many things are happening!");
break;
// object functions
case 'd': // drop
dodrop(player->pack);
break;
case 'i': // inventory
doinventory(player->pack);
break;
case ',': // pickup
dopickup(player, player->cell->obpile);
break;
case 't': // throw
dothrow(player->pack);
break;
// GAME FUNCTIONS
case 'S': // save + quit
if (savegame()) {
msg("Save failed.");
drawmsg();
} else {
msg("Saved successfully. See you later...");
more();
drawmsg();
exit(0);
}
break;
}
}
int keycodetokey(int keycode) {
int keystroke = 0;
if (keycode == -1) return -1;
if (keycode == 27) { // an esc sequence
keycode=getch();
keystroke=keycode;
keycode=getch();
keystroke=keystroke | (keycode<<8);
keycode=getch();
keystroke=keystroke | (keycode<<16);
} else {
// regular keypress
return (int)keycode;
}
return keystroke;
}
void dblog(char *format, ... ) {
char buf[HUGEBUFLEN];
va_list args;
char *p;
va_start(args, format);
vsprintf( buf, format, args );
va_end(args);
/*
if (gamestarted) {
fprintf(logfile, "%s\n", buf);
fflush(logfile);
} else {
printf("%s\n", buf);
fflush(stdout);
}
*/
fprintf(logfile, "%s\n", buf);
fflush(logfile);
}
// force a '--more--' prompt
void more(void) {
msg("%100s"," ");
}
void msg(char *format, ... ) {
char buf[BUFLEN];
va_list args;
char *p;
int db = B_FALSE;
va_start(args, format);
vsprintf( buf, format, args );
va_end(args);
if (db) dblog("adding to msgbuf: [%s]",buf);
// Move to just after the last '^' in the message buffer...
p = strrchr(msgbuf, '^');
if (p) {
p++;
} else {
p = msgbuf;
}
// ie. can we fit the new text + '--more--' ?
if (strlen(p) + strlen(buf) + strlen(MORESTRING) >= SCREENW) {
strcat(msgbuf, "^");
} else {
if (strlen(msgbuf) > 0) {
strcat(msgbuf, " ");
}
}
strcat(msgbuf, buf);
if (db) dblog(" msgbuf is now: [%s]",msgbuf);
}
void drawstatus(void) {
char buf[BUFLEN];
wclear(statwin);
sprintf(buf, "[%-12s] HP: %d/%d","Player", player->hp,player->maxhp);
mvwprintw(statwin, 0, 0, buf);
//redraw();
}
void drawmsg(void) {
char *tok,*nexttok;
int db = B_FALSE;
// no messages to display?
if (!strcmp(msgbuf, "")) {
return;
}
// TODO: if it's a monster's turn, always do a more?
nexttok = strstr(msgbuf, "^");
if (!nexttok) {
// just update msg with current text
wclear(msgwin);
mvwprintw(msgwin, 0, 0, "%s", msgbuf);
wrefresh(msgwin);
} else {
while (nexttok) {
char thistok[BUFLEN];
int thistoklen;
// print up to just before the "^" current token
// remember this token
thistoklen = nexttok - msgbuf;
strncpy(thistok, msgbuf, thistoklen);
thistok[thistoklen] = '\0';
if (db) dblog("drawmsg: thistok is [%s]",thistok);
// is there another token?
nexttok = strstr(msgbuf, "^");
if (nexttok) {
char *p;
nexttok++; // go forward past the ^
if (db) dblog("drawmsg: nexttok is [%s]",nexttok);
// print with '--more--' added to the end
if (db) dblog("drawmsg: displaying thistok [%s]",thistok);
wclear(msgwin);
mvwprintw(msgwin, 0, 0, "%s%s", thistok,MORESTRING);
wrefresh(msgwin);
// ...wait for spacebar before showing next bit...
while (getch() != ' ');
if (db) dblog("prompting for --more--");
// now clear msgstring up to end of where
// 'thistok' appears!
strcpy(msgbuf, nexttok);
if (db) dblog(" reduced msgbuf to: [%s]",msgbuf);
} else {
if (db) dblog("drawmsg: no nexttok");
// just print this bit
wclear(msgwin);
mvwprintw(msgwin, 0, 0, "%s", thistok);
wrefresh(msgwin);
}
}
}
// clear message buffer
if (isplayerturn()) {
strcpy(msgbuf, "");
if (db) dblog("clearing msg buf");
}
}
void redraw(void) {
//wrefresh(msgwin);
wrefresh(statwin);
wrefresh(gamewin);
}
int savegame(void) {
map_t *m;
FILE *f;
char buf[BUFLEN];
int rv;
for (m = firstmap; m ; m = m->next) {
// save world
rv = savemap(m);
if (rv) {
msg("Could not save map '%s'",m->name);
return B_TRUE;
}
// save player + their objects
sprintf(buf, "%s/game.sav",SAVEDIR);
f = fopen(buf, "wt");
if (!f) {
msg("Could not open save file!");
return B_TRUE;
}
savelf(f, player);
fclose(f);
}
return B_FALSE;
}
void tombstone(lifeform_t *lf) {
// clear screen
wclear(mainwin);
centre(mainwin, 1, "R.I.P.\n");
//printf("%s\n",lf->name);
centre(mainwin, 2, "Player\n");// TODO: use player name here
centre(mainwin, 3, "Killed by %s.\n",lf->lastdam);
wrefresh(mainwin);
// wait for key...
getch();
// close down graphics ready to quit
// clear windows
delwin(gamewin);
delwin(statwin);
delwin(msgwin);
// clear screen
wclear(mainwin);
// close down curses
curs_set(1);
endwin();
}

30
io.h Normal file
View File

@ -0,0 +1,30 @@
#include <ncurses.h>
#include "defs.h"
void anim(cell_t *src, cell_t *dst, char ch);
object_t *askobject(obpile_t *op, char *title, int *count);
cell_t *askcoords(char *prompt);
void centre(WINDOW *win, int y, char *format, ... );
int chartodir(char ch);
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 dothrow(obpile_t *op);
void drawcell(cell_t *cell, int x, int y);
void drawcursor(void);
void drawlevelfor(lifeform_t *lf);
void drawmsg(void);
void drawscreen(void);
void drawstatus(void);
int getkey(void);
void handleinput(void);
int keycodetokey(int keycode);
void more(void);
void msg(char *format, ... );
void dblog(char *format, ... );
void redraw(void);
int savequit(void);
void tombstone(lifeform_t *lf);
void updateviewfor(cell_t *cell);

639
lf.c Normal file
View File

@ -0,0 +1,639 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "defs.h"
#include "flag.h"
#include "lf.h"
#include "map.h"
#include "objects.h"
extern race_t *firstrace, *lastrace;
extern lifeform_t *player;
lifeform_t *addlf(cell_t *cell, enum RACE rid) {
map_t *m;
lifeform_t *a;
int i;
flag_t *f;
m = cell->map;
// add to the end of the list
if (m->lf == NULL) {
m->lf = malloc(sizeof(lifeform_t));
a = m->lf;
a->prev = NULL;
} else {
// go to end of list
a = m->lastlf;
a->next = malloc(sizeof(lifeform_t));
a->next->prev = a;
a = a->next;
}
m->lastlf = a;
a->next = NULL;
// props
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->cell = cell; // TODO: fix
a->alive = B_TRUE;
a->lastdam = strdup("nothing");
a->timespent = 0;
a->sorted = B_FALSE;
a->pack = addobpile(a, NOLOC);
// clear laoding variables
for (i = 0; i < MAXPILEOBS; i++) {
a->oblist[i] = -1;
}
a->x = -1;
a->y = -1;
// inherit flags from race
a->flags = addflagpile();
for (f = a->race->flags->first ; f ; f = f->next) {
addflag(a->flags, f->id, f->val[0], f->val[1], f->val[2], f->text);
}
// update other things
cell->lf = a;
}
race_t *addrace(enum RACE id, char *name, char glyph) {
race_t *a;
// add to the end of the list
if (firstrace == NULL) {
firstrace = malloc(sizeof(race_t));
a = firstrace;
a->prev = NULL;
} else {
// go to end of list
a = lastrace;
a->next = malloc(sizeof(race_t));
a->next->prev = a;
a = a->next;
}
lastrace = a;
a->next = NULL;
// props
a->id = id;
a->name = strdup(name);
a->glyph = glyph;
a->flags = addflagpile();
}
void die(lifeform_t *lf) {
char buf[BUFLEN];
object_t *o, *nexto;
flag_t *f;
lf->alive = B_FALSE;
if (lf->controller == C_PLAYER) {
// forec screen redraw so you see your hp = 0
drawscreen();
msg("You die.");
more();
// force msg redraw!
drawmsg();
} else {
if (!hasflag(lf->flags, F_NODEATHANNOUNCE)) {
if (haslos(player, lf->cell)) {
getlfname(lf, buf);
capitalise(buf);
msg("%s dies.",buf);
}
}
}
// drop all objects
while (lf->pack->first) {
if (!moveob(lf->pack->first, lf->cell->obpile, ALL)) {
killob(lf->pack->first);
}
}
// drop corpse
f = hasflag(lf->flags, F_CORPSETYPE);
if (f) {
addob(lf->cell->obpile, f->text);
}
if (lf->controller != C_PLAYER) {
// kill lifeform
killlf(lf);
}
}
lifeform_t *findlf(map_t *m, int lfid) {
lifeform_t *lf;
for (lf = m->lf ; lf ; lf = lf->next) {
if (lf->id == lfid) return lf;
}
return NULL;
}
race_t *findrace(enum RACE id) {
race_t *r;
for (r = firstrace; r ; r = r->next) {
if (r->id == id) {
return r;
}
}
return NULL;
}
int getattackspeed(lifeform_t *lf) {
int speed = SPEED_ATTACK;
flag_t *f;
f = hasflag(lf->flags, F_ATTACKSPEED);
if (f) {
speed = f->val[0];
}
return speed;
}
int getmovespeed(lifeform_t *lf) {
int speed = SPEED_MOVE;
flag_t *f;
f = hasflag(lf->flags, F_MOVESPEED);
if (f) {
speed = f->val[0];
}
return speed;
}
char *getlfname(lifeform_t *lf, char *buf) {
if (lf == player) {
sprintf(buf, "you");
} else {
sprintf(buf, "the %s",lf->race->name);
}
return buf;
}
int haslof(lifeform_t *viewer, cell_t *dest) {
int deltax, deltay;
int numpixels;
int d;
int dinc1,dinc2,xinc1,xinc2,yinc1,yinc2;
int xinc,yinc,dinc;
int i;
int x1,y1,dir;
int x;
int y;
int maxvisrange;
int modmaxvisrange;
int xray = B_FALSE;
int wentuphill = B_FALSE;
int origheight;
int shopwall;
int x2,y2;
map_t *map;
// must have line of sight to fire...
if (!haslos(viewer, dest)) return B_FALSE;
if (viewer->cell->map != dest->map) return B_FALSE;
map = dest->map;
x1 = viewer->cell->x;
y1 = viewer->cell->y;
x2 = dest->x;
y2 = dest->y;
deltax = (x2 - x1);
if (deltax < 0) deltax = -deltax;
deltay = (y2 - y1);
if (deltay < 0) deltay = -deltay;
// can always fire at your own cell
if ((deltax == 0) && (deltay == 0)) {
return B_TRUE;
}
if (deltax >= deltay) {
numpixels = deltax + 1;
d = (deltay*2) - deltax;
dinc1 = deltay << 1;
dinc2 = (deltay-deltax) << 1;
xinc1 = 1;
xinc2 = 1;
yinc1 = 0;
yinc2 = 1;
} else {
numpixels = deltay + 1;
d = (deltax*2) - deltay;
dinc1 = deltax << 1;
dinc2 = (deltax - deltay) << 1;
xinc1 = 0;
xinc2 = 1;
yinc1 = 1;
yinc2 = 1;
}
if (x1 > x2) {
xinc1 = - xinc1;
xinc2 = - xinc2;
}
if (y1 > y2) {
yinc1 = - yinc1;
yinc2 = - yinc2;
}
x = x1; y = y1;
for (i = 0; i < numpixels ; i++) {
cell_t *cell;
// don't need to move out of the last one
if ((x == x2) && (y == y2)) {
break;
}
if (d < 0) {
xinc = xinc1;
yinc = yinc1;
dinc = dinc1;
} else {
xinc = xinc2;
yinc = yinc2;
dinc = dinc2;
}
// solid cells stop lof
cell = getcellat(map, x, y);
if (cell->type->solid) {
return B_FALSE;
}
// move to next cell
d += dinc;
x += xinc;
y += yinc;
}
// made it to the target cell!
return B_TRUE;
}
int haslos(lifeform_t *viewer, cell_t *dest) {
int deltax, deltay;
int numpixels;
int d;
int dinc1,dinc2,xinc1,xinc2,yinc1,yinc2;
int xinc,yinc,dinc;
int i;
int x1,y1,dir;
int x;
int y;
int maxvisrange;
int modmaxvisrange;
int xray = B_FALSE;
int wentuphill = B_FALSE;
int origheight;
int shopwall;
int x2,y2;
map_t *map;
if (viewer->cell->map != dest->map) return B_FALSE;
map = dest->map;
x1 = viewer->cell->x;
y1 = viewer->cell->y;
x2 = dest->x;
y2 = dest->y;
/*
if (hasproplf(viewer, P_XRAYVISION)) {
xray = getproplf(viewer, P_XRAYVISION);
}
*/
deltax = (x2 - x1);
if (deltax < 0) deltax = -deltax;
deltay = (y2 - y1);
if (deltay < 0) deltay = -deltay;
// can always see your own cell
if ((deltax == 0) && (deltay == 0)) {
//if (viewer->controller == C_HUMAN) wreck->mazelev[z].maze[y2*MAZEW+x2].known = B_PERM;
return B_TRUE;
}
/*
if (hasproplf(viewer, P_BLINDED)) {
return B_FALSE;
}
*/
if (deltax >= deltay) {
numpixels = deltax + 1;
d = (deltay*2) - deltax;
dinc1 = deltay << 1;
dinc2 = (deltay-deltax) << 1;
xinc1 = 1;
xinc2 = 1;
yinc1 = 0;
yinc2 = 1;
} else {
numpixels = deltay + 1;
d = (deltax*2) - deltay;
dinc1 = deltax << 1;
dinc2 = (deltax - deltay) << 1;
xinc1 = 0;
xinc2 = 1;
yinc1 = 1;
yinc2 = 1;
}
if (x1 > x2) {
xinc1 = - xinc1;
xinc2 = - xinc2;
}
if (y1 > y2) {
yinc1 = - yinc1;
yinc2 = - yinc2;
}
x = x1; y = y1;
//maxvisrange = getvisrange(viewer, B_LIGHTDOESNTMATTER);
maxvisrange = UNLIMITED;
/*
if (hasproplf(viewer, P_SEEINDARK) || wreck->mazelev[viewer->z].lightlevel >= 100) {
modmaxvisrange = maxvisrange;
} else {
modmaxvisrange = getvisrange(viewer, B_LIGHTMATTERS);
}
*/
//origheight = getheight(x1,y1,z);
// too far away
if (maxvisrange != UNLIMITED) {
if (getcelldist(viewer->cell, dest) > maxvisrange) {
return B_FALSE;
}
}
// outside our modified vision range, and not lit
/*
if (modmaxvisrange != UNLIMITED) {
if (getdistance(x1,y1,x2,y2) > modmaxvisrange) {
if (!xyislit(x2,y2,viewer->z)) {
return B_FALSE;
}
}
}
*/
//shopwall = B_FALSE;
for (i = 0; i < numpixels ; i++) {
cell_t *cell;
// if we went uphill, stop here
/*
if (wentuphill) {
return B_FALSE;
}
*/
// don't need to move out of the last one
if ((x == x2) && (y == y2)) {
break;
}
if (d < 0) {
xinc = xinc1;
yinc = yinc1;
dinc = dinc1;
} else {
xinc = xinc2;
yinc = yinc2;
dinc = dinc2;
}
/*
if (debug) {
printf("checking LOS at %d,%d going (%d,%d)\n",x,y,xinc,yinc);
fflush(stdout);
}
*/
// solid cells stop los
cell = getcellat(map, x, y);
if (!cell->type->transparent) {
if (xray) xray--;
else return B_FALSE;
}
/*
// check for smoke
if ((x != x1) || (y != y1)) { // if not in first cell
if (hasopaqueobject(viewer, x,y,z) && (getheight(x,y,z) >= origheight)) {
if (!hasproplf(viewer, P_SEEINSMOKE)) {
return B_FALSE;
}
}
}
*/
// xray vision decreases by one
if (xray) xray--;
// if you went uphill, can't see any further
/*
if (getheight(x,y,z) > origheight) {
wentuphill = B_TRUE;
}
*/
// move to next cell
d += dinc;
x += xinc;
y += yinc;
}
// made it to the target cell!
/*
if (viewer->controller == C_HUMAN) wreck->mazelev[z].maze[y2*MAZEW+x2].known = B_PERM;
if (viewer->controller == C_HUMAN) wreck->mazelev[z].maze[y2*MAZEW+x2].known = B_PERM;
*/
return B_TRUE;
}
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, "");
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, "");
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, "");
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, "");
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, "");
}
int isdead(lifeform_t *lf) {
if (!lf->alive) return B_TRUE;
if (lf->hp <= 0) return B_TRUE;
return B_FALSE;
}
void killlf(lifeform_t *lf) {
int i;
lifeform_t *nextone, *lastone;
map_t *m;
m = lf->cell->map;
// remove references
lf->cell->lf = NULL;
// free mem
if (lf->lastdam) free(lf->lastdam);
// kill any remaining obs
while (lf->pack->first) {
killob(lf->pack->first);
}
// kill object pile
free(lf->pack);
// kill flags
while (lf->flags->first) {
killflag(lf->flags->first);
}
killflagpile(lf->flags);
// remove from list
nextone = lf->next;
if (nextone != NULL) {
nextone->prev = lf->prev;
} else { /* last */
m->lastlf = lf->prev;
}
if (lf->prev == NULL) {
/* first */
nextone = lf->next;
free(m->lf);
m->lf = nextone;
} else {
lastone = lf->prev;
free (lastone->next );
lastone->next = nextone;
}
}
void killrace(race_t *race) {
int i;
race_t *nextone, *lastone;
// free mem
free(race->name);
// remove from list
nextone = race->next;
if (nextone != NULL) {
nextone->prev = race->prev;
} else { /* last */
lastrace = race->prev;
}
if (race->prev == NULL) {
/* first */
nextone = race->next;
free(race);
race = nextone;
} else {
lastone = race->prev;
free (lastone->next );
lastone->next = nextone;
}
}
void losehp(lifeform_t *lf, int amt, lifeform_t *fromlf, char *damsrc) {
char buf[BUFLEN];
lf->hp -= amt;
if (lf->lastdam) {
free(lf->lastdam);
}
// replace 'the' at start of damsrc with 'a'
if (strstr(damsrc, "the ") == damsrc) {
sprintf(buf, "a %s", (damsrc+4));
} else {
strcpy(buf, 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");
}
}
}
}
}
// give initial equiment to a lifeform
void outfitlf(lifeform_t *lf) {
if (lf->controller == C_PLAYER) {
addob(lf->pack, "10 gold");
}
}
void taketime(lifeform_t *lf, int howlong) {
// inc timespent
lf->timespent += howlong;
// TODO: decrement lifeform's (or their object's) temporary flags
}

19
lf.h Normal file
View File

@ -0,0 +1,19 @@
#include "defs.h"
lifeform_t *addlf(cell_t *cell, enum RACE rid);
race_t *addrace(enum RACE id, char *name, char glyph);
void die(lifeform_t *lf);
lifeform_t *findlf(map_t *m, int lfid);
race_t *findrace(enum RACE id);
int getattackspeed(lifeform_t *lf);
int getmovespeed(lifeform_t *lf);
char *getlfname(lifeform_t *lf, char *buf);
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 taketime(lifeform_t *lf, int howlong);

939
log.txt Normal file
View File

@ -0,0 +1,939 @@
====== NEW LOGFILE ====
adding random object of rarity 1
got 2 possibilities.
adding 9 stone to cell 38,2
adding random object of rarity 1
got 2 possibilities.
adding 3 stone to cell 25,3
adding random object of rarity 1
got 2 possibilities.
adding 9 stone to cell 51,4
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 21 gold coin to cell 5,5
adding random object of rarity 1
got 2 possibilities.
adding 56 gold coin to cell 5,6
adding random object of rarity 1
got 2 possibilities.
adding 79 gold coin to cell 23,6
adding random object of rarity 3
no possible objects like this. trying again with rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 2 stone to cell 50,6
adding random object of rarity 1
got 2 possibilities.
adding 8 stone to cell 39,7
adding random object of rarity 1
got 2 possibilities.
adding 4 stone to cell 9,8
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 65 gold coin to cell 12,9
adding random object of rarity 1
got 2 possibilities.
adding 16 gold coin to cell 12,10
adding random object of rarity 1
got 2 possibilities.
adding 99 gold coin to cell 37,10
adding random object of rarity 1
got 2 possibilities.
adding 17 gold coin to cell 49,11
adding random object of rarity 1
got 2 possibilities.
adding 79 gold coin to cell 51,11
adding random object of rarity 3
no possible objects like this. trying again with rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 31 gold coin to cell 2,12
adding random object of rarity 1
got 2 possibilities.
adding 8 stone to cell 31,12
adding random object of rarity 1
got 2 possibilities.
adding 4 stone to cell 35,15
adding random object of rarity 1
got 2 possibilities.
adding 22 gold coin to cell 60,15
adding random object of rarity 1
got 2 possibilities.
adding 42 gold coin to cell 39,17
adding random object of rarity 1
got 2 possibilities.
adding 7 stone to cell 10,18
adding random object of rarity 1
got 2 possibilities.
adding 37 gold coin to cell 14,18
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 3 stone to cell 34,18
adding random object of rarity 1
got 2 possibilities.
adding 95 gold coin to cell 55,18
adding random object of rarity 3
no possible objects like this. trying again with rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 2 stone to cell 23,20
adding random object of rarity 1
got 2 possibilities.
adding 46 gold coin to cell 39,20
adding random object of rarity 1
got 2 possibilities.
adding 4 stone to cell 52,21
adding random object of rarity 1
got 2 possibilities.
adding 92 gold coin to cell 21,24
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 10 stone to cell 20,25
adding random object of rarity 1
got 2 possibilities.
adding 54 gold coin to cell 6,26
adding random object of rarity 1
got 2 possibilities.
adding 29 gold coin to cell 44,26
adding random object of rarity 1
got 2 possibilities.
adding 77 gold coin to cell 52,27
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 40 gold coin to cell 48,31
adding random object of rarity 1
got 2 possibilities.
adding 44 gold coin to cell 24,33
adding random object of rarity 1
got 2 possibilities.
adding 6 stone to cell 3,35
adding random object of rarity 1
got 2 possibilities.
adding 62 gold coin to cell 24,35
adding random object of rarity 1
got 2 possibilities.
adding 14 gold coin to cell 21,36
adding random object of rarity 1
got 2 possibilities.
adding 1 stone to cell 46,38
adding random object of rarity 1
got 2 possibilities.
adding 3 stone to cell 2,39
adding random object of rarity 1
got 2 possibilities.
adding 7 stone to cell 44,40
adding random object of rarity 1
got 2 possibilities.
adding 71 gold coin to cell 11,41
adding random object of rarity 1
got 2 possibilities.
adding 11 gold coin to cell 12,41
adding random object of rarity 1
got 2 possibilities.
adding 5 stone to cell 28,41
adding random object of rarity 1
got 2 possibilities.
adding 1 stone to cell 10,42
adding random object of rarity 1
got 2 possibilities.
adding 28 gold coin to cell 30,46
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 13 gold coin to cell 7,47
adding random object of rarity 1
got 2 possibilities.
adding 44 gold coin to cell 15,47
--> Will add 9 objects to room 0 (of 23)
adding random object of rarity 1
got 2 possibilities.
adding 7 stone to cell 21,17
adding random object of rarity 1
got 2 possibilities.
adding 17 gold coin to cell 24,3
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 88 gold coin to cell 12,27
adding random object of rarity 1
got 2 possibilities.
adding 2 stone to cell 25,21
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 33 gold coin to cell 25,26
adding random object of rarity 3
no possible objects like this. trying again with rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 86 gold coin to cell 20,9
adding random object of rarity 1
got 2 possibilities.
adding 90 gold coin to cell 1,47
adding random object of rarity 1
got 2 possibilities.
adding 31 gold coin to cell 48,9
adding random object of rarity 1
got 2 possibilities.
adding 91 gold coin to cell 7,1
--> Will add 12 objects to room 1 (of 23)
adding random object of rarity 4
no possible objects like this. trying again with rarity 3
no possible objects like this. trying again with rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 94 gold coin to cell 53,16
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 6 stone to cell 57,19
adding random object of rarity 1
got 2 possibilities.
adding 2 stone to cell 54,16
adding random object of rarity 1
got 2 possibilities.
adding 5 stone to cell 49,16
adding random object of rarity 1
got 2 possibilities.
adding 1 stone to cell 61,16
adding random object of rarity 1
got 2 possibilities.
adding 8 stone to cell 52,20
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 4 stone to cell 50,20
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 5 stone to cell 55,19
adding random object of rarity 1
got 2 possibilities.
adding 10 stone to cell 58,21
adding random object of rarity 1
got 2 possibilities.
adding 3 stone to cell 60,14
adding random object of rarity 1
got 2 possibilities.
adding 6 stone to cell 59,20
adding random object of rarity 1
got 2 possibilities.
adding 3 stone to cell 50,16
--> Will add 3 pillars
--> Will add 10 objects to room 2 (of 23)
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 7 stone to cell 6,7
adding random object of rarity 3
no possible objects like this. trying again with rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 9 stone to cell 3,5
adding random object of rarity 1
got 2 possibilities.
adding 94 gold coin to cell 6,1
adding random object of rarity 1
got 2 possibilities.
adding 3 stone to cell 3,8
adding random object of rarity 3
no possible objects like this. trying again with rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 5 stone to cell 3,7
adding random object of rarity 1
got 2 possibilities.
adding 5 stone to cell 4,2
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 71 gold coin to cell 2,4
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 31 gold coin to cell 1,9
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 4 stone to cell 5,1
adding random object of rarity 1
got 2 possibilities.
adding 10 stone to cell 6,2
--> Will add 4 objects to room 3 (of 23)
adding random object of rarity 3
no possible objects like this. trying again with rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 53 gold coin to cell 24,29
adding random object of rarity 1
got 2 possibilities.
adding 6 stone to cell 27,30
adding random object of rarity 1
got 2 possibilities.
adding 58 gold coin to cell 30,28
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 35 gold coin to cell 35,29
--> Will add 5 objects to room 4 (of 23)
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 7 stone to cell 4,37
adding random object of rarity 1
got 2 possibilities.
adding 8 stone to cell 2,35
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 5 stone to cell 1,37
adding random object of rarity 1
got 2 possibilities.
adding 35 gold coin to cell 5,38
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 10 stone to cell 3,38
--> Will add 3 objects to room 5 (of 23)
adding random object of rarity 1
got 2 possibilities.
adding 9 stone to cell 50,41
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 21 gold coin to cell 50,39
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 1 stone to cell 42,40
--> Will add 5 objects to room 6 (of 23)
adding random object of rarity 1
got 2 possibilities.
adding 2 stone to cell 50,29
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 6 stone to cell 43,25
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 10 stone to cell 45,32
adding random object of rarity 1
got 2 possibilities.
adding 56 gold coin to cell 47,29
adding random object of rarity 1
got 2 possibilities.
adding 1 stone to cell 46,29
--> Will add 1 objects to room 7 (of 23)
adding random object of rarity 1
got 2 possibilities.
adding 9 stone to cell 38,4
--> Will add 9 objects to room 8 (of 23)
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 37 gold coin to cell 14,43
adding random object of rarity 1
got 2 possibilities.
adding 1 stone to cell 17,44
adding random object of rarity 1
got 2 possibilities.
adding 73 gold coin to cell 11,42
adding random object of rarity 1
got 2 possibilities.
adding 4 stone to cell 18,47
adding random object of rarity 1
got 2 possibilities.
adding 3 stone to cell 20,46
adding random object of rarity 1
got 2 possibilities.
adding 10 stone to cell 15,40
adding random object of rarity 1
got 2 possibilities.
adding 84 gold coin to cell 11,46
adding random object of rarity 1
got 2 possibilities.
adding 3 stone to cell 19,48
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 9 stone to cell 9,44
--> Will add 7 objects to room 9 (of 23)
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 3 stone to cell 42,46
adding random object of rarity 3
no possible objects like this. trying again with rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 5 stone to cell 37,47
adding random object of rarity 1
got 2 possibilities.
adding 99 gold coin to cell 44,43
adding random object of rarity 1
got 2 possibilities.
adding 9 stone to cell 45,43
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 1 gold coin to cell 37,45
adding random object of rarity 1
got 2 possibilities.
adding 3 stone to cell 35,43
adding random object of rarity 3
no possible objects like this. trying again with rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 5 stone to cell 43,47
--> Will add 2 objects to room 10 (of 23)
adding random object of rarity 1
got 2 possibilities.
adding 7 stone to cell 41,8
adding random object of rarity 1
got 2 possibilities.
adding 8 gold coin to cell 40,9
--> Will add 4 objects to room 11 (of 23)
adding random object of rarity 1
got 2 possibilities.
adding 3 stone to cell 18,7
adding random object of rarity 1
got 2 possibilities.
adding 13 gold coin to cell 30,4
adding random object of rarity 1
got 2 possibilities.
adding 6 stone to cell 32,5
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 1 gold coin to cell 29,6
--> Will add 5 objects to room 12 (of 23)
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 66 gold coin to cell 18,36
adding random object of rarity 1
got 2 possibilities.
adding 7 stone to cell 17,39
adding random object of rarity 1
got 2 possibilities.
adding 14 gold coin to cell 17,37
adding random object of rarity 1
got 2 possibilities.
adding 9 stone to cell 14,37
adding random object of rarity 4
no possible objects like this. trying again with rarity 3
no possible objects like this. trying again with rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 25 gold coin to cell 18,38
--> Will add 7 objects to room 13 (of 23)
adding random object of rarity 1
got 2 possibilities.
adding 50 gold coin to cell 28,46
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 7 gold coin to cell 27,45
adding random object of rarity 1
got 2 possibilities.
adding 4 stone to cell 29,43
adding random object of rarity 1
got 2 possibilities.
adding 26 gold coin to cell 26,46
adding random object of rarity 1
got 2 possibilities.
adding 34 gold coin to cell 25,47
adding random object of rarity 1
got 2 possibilities.
adding 1 stone to cell 26,42
adding random object of rarity 1
got 2 possibilities.
adding 4 stone to cell 22,45
--> Will add 5 objects to room 14 (of 23)
adding random object of rarity 1
got 2 possibilities.
adding 32 gold coin to cell 9,23
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 7 stone to cell 19,20
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 1 stone to cell 17,17
adding random object of rarity 1
got 2 possibilities.
adding 2 stone to cell 17,18
adding random object of rarity 1
got 2 possibilities.
adding 24 gold coin to cell 14,19
--> Will add 11 objects to room 15 (of 23)
adding random object of rarity 1
got 2 possibilities.
adding 57 gold coin to cell 33,38
adding random object of rarity 1
got 2 possibilities.
adding 2 stone to cell 39,38
adding random object of rarity 3
no possible objects like this. trying again with rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 30 gold coin to cell 40,41
adding random object of rarity 1
got 2 possibilities.
adding 16 gold coin to cell 34,39
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 71 gold coin to cell 31,39
adding random object of rarity 1
got 2 possibilities.
adding 10 stone to cell 41,39
adding random object of rarity 1
got 2 possibilities.
adding 39 gold coin to cell 39,39
adding random object of rarity 1
got 2 possibilities.
adding 7 stone to cell 40,40
adding random object of rarity 1
got 2 possibilities.
adding 2 stone to cell 30,41
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 2 stone to cell 31,40
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 3 stone to cell 34,41
--> Will add 0 objects to room 16 (of 23)
--> Will add 2 pillars
--> Will add 10 objects to room 17 (of 23)
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 50 gold coin to cell 1,31
adding random object of rarity 1
got 2 possibilities.
adding 1 stone to cell 2,30
adding random object of rarity 1
got 2 possibilities.
adding 74 gold coin to cell 4,24
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 96 gold coin to cell 4,25
adding random object of rarity 1
got 2 possibilities.
adding 84 gold coin to cell 1,23
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 5 stone to cell 2,29
adding random object of rarity 1
got 2 possibilities.
adding 4 stone to cell 2,23
adding random object of rarity 1
got 2 possibilities.
adding 52 gold coin to cell 4,31
adding random object of rarity 1
got 2 possibilities.
adding 32 gold coin to cell 3,22
adding random object of rarity 1
got 2 possibilities.
adding 7 stone to cell 1,28
--> Will add 7 objects to room 18 (of 23)
adding random object of rarity 1
got 2 possibilities.
adding 41 gold coin to cell 7,8
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 55 gold coin to cell 17,10
adding random object of rarity 1
got 2 possibilities.
adding 7 stone to cell 15,10
adding random object of rarity 1
got 2 possibilities.
adding 2 stone to cell 15,13
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 87 gold coin to cell 17,7
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 9 stone to cell 14,6
adding random object of rarity 3
no possible objects like this. trying again with rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 46 gold coin to cell 8,12
--> Will add 2 objects to room 19 (of 23)
adding random object of rarity 1
got 2 possibilities.
adding 28 gold coin to cell 23,12
adding random object of rarity 1
got 2 possibilities.
adding 65 gold coin to cell 28,13
--> Will add 7 objects to room 20 (of 23)
adding random object of rarity 1
got 2 possibilities.
adding 5 gold coin to cell 1,17
adding random object of rarity 1
got 2 possibilities.
adding 57 gold coin to cell 3,16
adding random object of rarity 1
got 2 possibilities.
adding 1 stone to cell 2,19
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 28 gold coin to cell 2,16
adding random object of rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 32 gold coin to cell 4,14
adding random object of rarity 1
got 2 possibilities.
adding 5 gold coin to cell 4,16
adding random object of rarity 1
got 2 possibilities.
adding 51 gold coin to cell 3,15
--> Will add 1 objects to room 21 (of 23)
adding random object of rarity 1
got 2 possibilities.
adding 56 gold coin to cell 43,21
--> Will add 15 objects to room 22 (of 23)
adding random object of rarity 1
got 2 possibilities.
adding 44 gold coin to cell 22,3
adding random object of rarity 1
got 2 possibilities.
adding 57 gold coin to cell 12,2
adding random object of rarity 1
got 2 possibilities.
adding 86 gold coin to cell 18,3
adding random object of rarity 3
no possible objects like this. trying again with rarity 2
no possible objects like this. trying again with rarity 1
got 2 possibilities.
adding 7 stone to cell 15,1
adding random object of rarity 1
got 2 possibilities.
adding 39 gold coin to cell 10,3
adding random object of rarity 1
got 2 possibilities.
adding 9 stone to cell 18,1
adding random object of rarity 1
got 2 possibilities.
adding 60 gold coin to cell 14,1
adding random object of rarity 1
got 2 possibilities.
adding 39 gold coin to cell 20,2
adding random object of rarity 1
got 2 possibilities.
adding 8 stone to cell 11,1
adding random object of rarity 1
got 2 possibilities.
adding 4 stone to cell 15,2
adding random object of rarity 1
got 2 possibilities.
adding 93 gold coin to cell 17,3
adding random object of rarity 1
got 2 possibilities.
adding 83 gold coin to cell 19,1
adding random object of rarity 1
got 2 possibilities.
adding 7 stone to cell 12,1
adding random object of rarity 1
got 2 possibilities.
adding 9 stone to cell 23,2
adding random object of rarity 1
got 2 possibilities.
adding 18 gold coin to cell 21,2
Finished adding objects.
AIMOVE: bat
AIMOVE: bat
AIMOVE: bat
AIMOVE: bat
AIMOVE: bat
AIMOVE: bat
AIMOVE: bat
AIMOVE: bat
AIMOVE: bat
AIMOVE: bat
AIMOVE: bat
AIMOVE: bat
AIMOVE: bat
AIMOVE: bat
AIMOVE: bat

1355
map.c Normal file

File diff suppressed because it is too large Load Diff

29
map.h Normal file
View File

@ -0,0 +1,29 @@
#include "defs.h"
cell_t *addcell(map_t *map, int x, int y);
map_t *addmap(void);
void addrandomthing(cell_t *c);
cell_t *getcellat(map_t *map, int x, int y);
int getcelldist(cell_t *src, cell_t *dst);
int calcroompos(map_t *map, int w, int h, int *bx, int *by);
int countadjcellsoftype(cell_t *cell, int id);
int countcellexits(cell_t *cell);
void createmap(map_t *map, int habitat);
void createroom(map_t *map, int minx, int miny, int w, int h, int roomid);
int dirtox(int dt, int dir);
int dirtoy(int dt, int dir);
void dumpmap(map_t *map);
map_t *findmap(int mid);
cell_t *getcellindir(cell_t *cell, int dir);
int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved);
int getobchance(int habitat);
cell_t *getrandomcell(map_t *map);
cell_t *getrandomcelloftype(map_t *map, int id);
int getrandomdir(int dirtype);
cell_t *getrandomroomcell(map_t *map, int roomid);
int isloopdirok(cell_t *cell, int dir);
int isnewcellok(cell_t *cell, char *err);
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);

5
mod_ob.txt Normal file
View File

@ -0,0 +1,5 @@
When modifying the object_t structure:
- update obpropsmatch()
- update isplainob()
- update addobject()

146
move.c Normal file
View File

@ -0,0 +1,146 @@
#include <stdio.h>
#include "attack.h"
#include "defs.h"
#include "map.h"
extern lifeform_t *player;
int canmove(lifeform_t *lf, int dir, enum ERROR *error) {
cell_t *cell;
cell = getcellindir(lf->cell, dir);
if (cell->type->solid) {
if (error) *error = E_WALLINWAY;
return B_FALSE;
}
if (cell->lf) {
if (error) *error = E_LFINWAY;
return B_FALSE;
}
return B_TRUE;
}
void dorandommove(lifeform_t *lf) {
int dir;
int tries = 0;
dir = getrandomdir(DT_COMPASS);
while (trymove(lf, dir)) {
if (++dir > DC_NW) dir = DC_N;
if (++tries >= MAXDIR_COMPASS) {
dowait(lf);
return;
}
}
}
int dowait(lifeform_t *lf) {
taketime(lf, SPEED_WAIT);
return B_FALSE;
}
void movelf(lifeform_t *lf, cell_t *newcell) {
// update current cell
lf->cell->lf = NULL;
// update lifeform
lf->cell = newcell;
// update new cell
newcell->lf = lf;
}
// basically this is a warpper for 'movelf' which
// does other game things like telling the player
// what is here.
int moveto(lifeform_t *lf, cell_t *newcell) {
// actually do the move
movelf(lf, newcell);
// tell player about things
if (lf->controller == C_PLAYER) {
int numobs;
char buf[BUFLEN];
numobs = countobs(newcell->obpile);
if (numobs == 1) {
getobname(newcell->obpile->first, buf, newcell->obpile->first->amt);
msg("You see %s here.", buf);
} else if ((numobs > 1) && (numobs <= 3)) {
msg("You see a few objects here.");
} else if ((numobs > 3) && (numobs <= 6)) {
msg("You see some objects here.");
} else if (numobs > 6) {
msg("You see many objects here.");
} else {
// just clear the message buffer
clearmsg();
}
}
}
int opendoor(lifeform_t *lf, cell_t *cell) {
char buf[BUFLEN];
if (cell->type->id == CT_DOORCLOSED) {
// open it
setcelltype(cell, CT_DOOROPEN);
if (lf->controller == C_PLAYER) {
msg("You open a door.");
} else {
// TODO: only announce if player can see it
if (haslos(player, cell)) {
getlfname(lf, buf);
capitalise(buf);
msg("%s opens a door.",buf);
}
}
taketime(lf, getmovespeed(lf));
} else {
return B_TRUE;
}
return B_FALSE;
}
int tryrun(lifeform_t *lf, int dir) {
// continue moving until we fail
while (canmove(lf, dir, NULL)) {
trymove(lf,dir);
}
}
int trymove(lifeform_t *lf, int dir) {
cell_t *cell;
enum ERROR errcode;
char buf[BUFLEN], buf2[BUFLEN];
cell = getcellindir(lf->cell, dir);
if (canmove(lf, dir, &errcode)) {
moveto(lf, cell);
taketime(lf, getmovespeed(lf));
} else {
switch (errcode) {
case E_WALLINWAY:
// is it a door in the way?
if (cell->type->id == CT_DOORCLOSED) {
// try to open it
opendoor(lf, cell);
} else {
if (lf->controller == C_PLAYER) {
msg("Ouch! You walk into a wall.");
}
}
break;
case E_LFINWAY:
// attack!
doattack(lf, cell->lf);
break;
}
return B_TRUE;
}
return B_FALSE;
}

8
move.h Normal file
View File

@ -0,0 +1,8 @@
#include "defs.h"
int canmove(lifeform_t *lf, int dir, enum ERROR *error);
void dorandommove(lifeform_t *lf);
int dowait(lifeform_t *lf);
void movelf(lifeform_t *lf, cell_t *newcell);
int moveto(lifeform_t *lf, cell_t *newcell);
int trymove(lifeform_t *lf, int dir);

297
nexus.c Normal file
View File

@ -0,0 +1,297 @@
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "io.h"
#include "lf.h"
#include "map.h"
#include "nexus.h"
#include "objects.h"
#include "save.h"
material_t *material = NULL,*lastmaterial = NULL;
objectclass_t *objectclass = NULL,*lastobjectclass = NULL;
objecttype_t *objecttype = NULL,*lastobjecttype = NULL;
celltype_t *firstcelltype = NULL,*lastcelltype = NULL;
race_t *firstrace = NULL,*lastrace = NULL;
map_t *firstmap = NULL,*lastmap = NULL;
FILE *logfile;
enum ERROR reason; // global for returning errors
lifeform_t *player = NULL;
int gameover;
int gamestarted = B_FALSE;
int main(char **argv, int argc) {
int newworld = B_FALSE;
atexit(cleanup);
// init params
init();
// load whatever maps are available
loadall();
// init graphics
initgfx();
// if no maps, make the initial level
if (!firstmap) {
newworld = B_TRUE;
addmap();
createmap(firstmap, H_DUNGEON);
}
// if no player, add them
if (!player) {
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);
} else {
msg("Welcome back!");
more();
}
// start game - this will cause debug messages to now
// go to the log file instead of stdout.
gamestarted = B_TRUE;
// show level
drawscreen();
// MAIN LOOP
gameover = B_FALSE;
while (!gameover) {
// someone has a turn
donextturn(player->cell->map);
// update lifeform structue to figure out who goes next
sortlf(player->cell->map);
// TODO: monsters move etc
// check for death etc
doeffects();
// show level
drawscreen();
// check end of game
checkendgame();
}
// print tombstone
tombstone(player);
}
celltype_t *addcelltype(int id, char glyph, int solid, int transparent) {
celltype_t *a;
// add to the end of the list
if (firstcelltype == NULL) {
firstcelltype = malloc(sizeof(celltype_t));
a = firstcelltype;
a->prev = NULL;
} else {
// go to end of list
a = lastcelltype;
a->next = malloc(sizeof(celltype_t));
a->next->prev = a;
a = a->next;
}
lastcelltype = a;
a->next = NULL;
// set props
a->id = id;
a->glyph = glyph;
a->solid = solid;
a->transparent = transparent;
}
void checkendgame(void) {
if (!player->alive) {
gameover = B_TRUE;
}
}
void cleanup(void) {
fclose(logfile);
cleanupgfx();
}
void doeffects(void) {
lifeform_t *lf;
// check for death
for (lf = player->cell->map->lf; lf ; lf = lf->next) {
if (lf->hp <= 0) {
// die!
die(lf);
}
}
}
void donextturn(map_t *map) {
lifeform_t *who;
// show messages to plaeyr
drawmsg();
who = map->lf;
if (who->controller == C_PLAYER) {
drawcursor();
// find out what player wants to do
handleinput();
} else {
// TODO: do ai move
aimove(who);
}
// everyone else's time goes down by 1
for (who = map->lf->next ; who ; who = who->next ){
if (who->timespent > 0) who->timespent--;
}
}
celltype_t *findcelltype(int id) {
celltype_t *ct;
for (ct = firstcelltype; ct ; ct = ct->next) {
if (ct->id == id) {
return ct;
}
}
return NULL;
}
char *getdirname(int dir) {
switch (dir) {
case D_N:
return "North";
case D_E:
return "East";
case D_S:
return "South";
case D_W:
return "West";
case D_UNKNOWN:
return "D_UNKNOWN";
case D_NONE:
return "D_NONE";
}
return "?errordir?";
}
int init(void) {
// random numbers
srand(time(NULL));
// open log file
logfile = fopen("log.txt","wt");
fprintf(logfile, "\n\n\n====== NEW LOGFILE ====\n");
// cell types
addcelltype(CT_WALL, '#', B_SOLID, B_OPAQUE);
addcelltype(CT_ROOMWALL, '#', B_SOLID, B_OPAQUE);
addcelltype(CT_CORRIDOR, '.', B_EMPTY, B_TRANS);
addcelltype(CT_LOOPCORRIDOR, 'L', B_EMPTY, B_TRANS);
addcelltype(CT_ROOM, '.', B_EMPTY, B_TRANS);
addcelltype(CT_DOOROPEN, '-', B_EMPTY, B_TRANS);
addcelltype(CT_DOORCLOSED, '+', B_SOLID, B_OPAQUE);
initobjects();
initrace();
return B_FALSE;
}
int isplayerturn(void) {
if (player->cell->map->lf->controller == C_PLAYER) {
return B_TRUE;
}
return B_FALSE;
}
// get a random number
int rnd(int min, int max) {
int res;
res = (rand() % (max - min + 1)) + min;
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;
// 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) {
donesomething = B_FALSE;
for (l = map->lf ; l ; l = l->next) {
if (!l->sorted && l->next && (l->timespent > l->next->timespent) ) {
lifeform_t *temp;
// remember next element
temp = l->next;
// remove this element from list
if (l->prev == NULL) {
// first
map->lf = l->next;
} else {
// not first
l->prev->next = l->next;
}
// don't bother checking for next - we know ther eis one.
l->next->prev = l->prev;
// re-add element afterwards
l->next = temp->next;
l->prev = temp;
temp->next = l;
if (l->next == NULL) map->lastlf = l;
donesomething = B_TRUE;
} else {
l->sorted = B_TRUE;
}
}
}
if (db) {
dblog("AFTER SORT:");
for (l = map->lf ; l ; l = l->next) {
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;
for (l = map->lf ; l ; l = l->next) {
l->timespent -= adjustby;
l->sorted = B_FALSE;
}
}

13
nexus.h Normal file
View File

@ -0,0 +1,13 @@
#include "defs.h"
celltype_t *addcelltype(int id, char glyph, int solid, int transparent);
void checkendgame(void);
void cleanup(void);
void doeffects(void);
void donextturn(map_t *map);
celltype_t *findcelltype(int id);
char *getdirname(int dir);
int init(void);
int isplayerturn(void);
int rnd(int min, int max);
void sortlf(map_t *map);

0
object.h Normal file
View File

940
objects.c Normal file
View File

@ -0,0 +1,940 @@
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "defs.h"
#include "flag.h"
#include "objects.h"
#include "text.h"
extern objecttype_t *objecttype,*lastobjecttype;
extern objectclass_t *objectclass,*lastobjectclass;
extern material_t *material,*lastmaterial;
extern lifeform_t *player;
extern int reason;
char letorder[MAXPILEOBS] = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
};
objecttype_t *lastot = NULL;
enum OBCLASS sortorder[] = {
OC_MONEY,
OC_WEAPON,
OC_ARMOUR,
OC_SCROLL,
OC_POTION,
OC_FOOD,
OC_ROCK,
OC_MISC,
OC_NULL
};
long nextoid = 0;
material_t *addmaterial(enum MATERIAL id, char *name) {
material_t *a;
// add to the end of the list
if (material == NULL) {
material = malloc(sizeof(material_t));
a = material;
a->prev = NULL;
} else {
// go to end of list
a = lastmaterial;
a->next = malloc(sizeof(material_t));
a->next->prev = a;
a = a->next;
}
lastmaterial = a;
a->next = NULL;
// props
a->id = id;
a->name = strdup(name);
}
objectclass_t *addoc(enum OBCLASS id, char *name, char glyph) {
objectclass_t *a;
// add to the end of the list
if (objectclass == NULL) {
objectclass = malloc(sizeof(objectclass_t));
a = objectclass;
a->prev = NULL;
} else {
// go to end of list
a = lastobjectclass;
a->next = malloc(sizeof(objectclass_t));
a->next->prev = a;
a = a->next;
}
lastobjectclass = a;
a->next = NULL;
// props
a->id = id;
a->name = strdup(name);
a->glyph = glyph;
}
// create a new obkejct, stacking ok
object_t *addob(obpile_t *where, char *name) {
addobject(where, name, B_TRUE);
}
// create a new object
// if canstack is true, we are allwoed
// to join similar objects together instead of
// creating new obejct entries.
object_t *addobject(obpile_t *where, char *name, int canstack) {
objecttype_t *ot;
object_t *o;
char *p,*nsp;
char numstring[BUFLEN];
int howmany = 1;
int i;
int db = B_FALSE;
flag_t *f;
// parse name string
nsp = numstring;
for (p = name ; isdigit(*p) ; p++) {
*nsp = *p;
nsp++;
}
*nsp = '\0';
// are we giving multiple objects?
if (strlen(numstring) > 0) {
// first increment name string pointer
// past any spaces
while (!isalpha(*p)) p++;
// now figure out how many
howmany = atoi(numstring);
} else {
howmany = 1;
}
// make sure we can find the requested object type
ot = findotn(p);
if (!ot) {
if (db) dblog("DB: No match for object name '%s'", p );
return NULL;
}
if (db) dblog("DB: '%s' -> adding %d x %s",name, howmany, ot->name);
for (i = 0; i < howmany; i++) {
int added = B_FALSE;
if (canstack) {
object_t *existob;
if (db) dblog("DB: Looking for stacks...");
// TODO: if object is stackable
// TODO: if (hasflag(ob,stackable) && hasobject(where, ot)) {
// does the pile already contain one?
existob = canstacknewot(where, ot);
if (existob) {
if (db) dblog("DB: STACK FOUND. Adding %d obs to existing stack.",howmany);
existob->amt++;
added = B_TRUE;
}
if (db) dblog("DB: No stacks found.");
}
if (!added) {
if (db) dblog("DB: Creating new object.");
// otherwise add to list
if (where->first == NULL) {
where->first = malloc(sizeof(object_t));
o = where->first;
o->prev = NULL;
} else {
// go to end of list
o = where->last;
o->next = malloc(sizeof(object_t));
o->next->prev = o;
o = o->next;
}
where->last = o;
o->next = NULL;
// fill in props
o->id = nextoid++; // increment next ob id
o->type = ot;
o->pile = where;
// inherit from objecttype
o->material = ot->material;
o->weight = ot->weight;
o->flags = addflagpile();
for (f = ot->flags->first ; f ; f = f->next) {
addflag(o->flags, f->id, f->val[0], f->val[1], f->val[2], f->text);
}
// non-inherited:
o->inscription = NULL;
// if adding to a player...
if (where->owner) {
o->letter = getnextletter(where, NULL);
} else {
// new object - has no letter yet.
o->letter = ' ';
}
o->amt = 1;
o->blessed = B_UNCURSED;
o->blessknown = B_FALSE; // TODO: change to false
}
}
// return the last object given
return o;
}
obpile_t *addobpile(lifeform_t *owner, cell_t *where) {
obpile_t *op;
op = malloc(sizeof(obpile_t));
op->first = NULL;
op->last = NULL;
op->owner = owner;
op->where = where;
return op;
}
objecttype_t *addot(int id, char *name, char *description, int material, float weight, int obclassid) {
objecttype_t *a;
// add to the end of the list
if (objecttype == NULL) {
objecttype = malloc(sizeof(objecttype_t));
a = objecttype;
a->prev = NULL;
} else {
// go to end of list
a = lastobjecttype;
a->next = malloc(sizeof(objecttype_t));
a->next->prev = a;
a = a->next;
}
lastobjecttype = a;
a->next = NULL;
// props
a->id = id;
a->name = strdup(name);
a->desc = strdup(description);
a->material = findmaterial(material);
a->weight = weight;
a->obclass = findoc(obclassid);
a->flags = addflagpile();
// for easy addition of flags
lastot = a;
}
// does the pile "op" have an object we can
// stack "o" with
object_t *canstackob(obpile_t *op, object_t *match) {
object_t *o;
if (!hasflag(match->flags, F_STACKABLE)) {
return NULL;
}
for (o = op->first ; o ; o = o->next) {
if (obpropsmatch(o, match)) return o;
}
return NULL;
}
// does the pile "op" have an object we can
// stack a new object of type "ot" with
object_t *canstacknewot(obpile_t *op, objecttype_t *match) {
object_t *o;
if (!hasflag(match->flags, F_STACKABLE)) {
return NULL;
}
for (o = op->first ; o ; o = o->next) {
if (o->type == match) {
if (isplainob(o)) return o;
}
}
return NULL;
}
void copyobprops(object_t *dst, object_t *src) {
dst->material = src->material;
dst->weight = src->weight;
// TODO: copy flags
if (src->inscription) {
dst->inscription = strdup(src->inscription);
}
}
int countobs(obpile_t *op) {
object_t *o;
int count = 0;
for (o = op->first ; o ; o = o->next) {
count++;
}
return count;
}
material_t *findmaterial(int id) {
material_t *m;
for (m = material ; m ; m = m->next) {
if (m->id == id) return m;
}
return NULL;
}
objectclass_t *findoc(int id) {
objectclass_t *oc;
for (oc = objectclass ; oc ; oc = oc->next) {
if (oc->id == id) return oc;
}
return NULL;
}
object_t *findobl(obpile_t *op, char let) {
object_t *o;
for (o = op->first; o ; o = o->next) {
if (o->letter == let) return o;
}
return NULL;
}
objecttype_t *findot(int id) {
objecttype_t *ot;
for (ot = objecttype ; ot ; ot = ot->next) {
if (ot->id == id) return ot;
}
return NULL;
}
objecttype_t *findotn(char *name) {
objecttype_t *ot;
char *searchfor;
searchfor = strdup(name);
for (ot = objecttype ; ot ; ot = ot->next) {
if (strstr(ot->name, searchfor)) {
free(searchfor);
return ot;
}
}
// haven't found it yet - check for plurals
// search for words ending in "es" (eg. tomatoes)
if ((searchfor[strlen(searchfor)-1] == 's') &&
(searchfor[strlen(searchfor)-2] == 'e') ) {
// remove trailing 'es'
searchfor[strlen(searchfor)-1] = '\0';
searchfor[strlen(searchfor)-2] = '\0';
// search again
for (ot = objecttype ; ot ; ot = ot->next) {
if (strstr(ot->name, searchfor)) {
free(searchfor);
return ot;
}
}
}
// reset back to inital word
free(searchfor);
searchfor = strdup(name);
// search for words ending in "s" (eg. "swords")
if (searchfor[strlen(searchfor)-1] == 's') {
// remove trailing 's'
searchfor[strlen(searchfor)-1] = '\0';
searchfor[strlen(searchfor)-2] = '\0';
// search again
for (ot = objecttype ; ot ; ot = ot->next) {
if (strstr(ot->name, searchfor)) {
free(searchfor);
return ot;
}
}
}
return NULL;
}
int getletidx(char let) {
int i;
for (i = 0; i < MAXPILEOBS; i++) {
if (letorder[i] == let) return i;
}
return -1;
}
// select lowest possible letter
char getnextletter(obpile_t *op, char *wantletter) {
object_t *o;
int curidx = -1, thisidx;
char let;
int db = B_FALSE;
// try 'wantletter' first
if (wantletter) {
if (!pilehasletter(op, *wantletter)) {
return *wantletter;
}
}
curidx = 0; // ie 'a'
for (curidx = 0; curidx < MAXPILEOBS; curidx++) {
// does any other object in the pile have this letter?
let = letorder[curidx];
if (!pilehasletter(op, let)) {
// if we didn't find it, this letter is okay.
return let;
}
}
return '-';
}
// buf must already be allocated
char *getobname(object_t *o, char *buf, int count) {
char *pluralname;
char prefix[BUFLEN];
// handle ALL
if (count == ALL) {
count = o->amt;
}
// figure out prefix
if ((count == 1) && !hasflag(o->flags, F_NO_A)) {
pluralname = strdup(o->type->name);
if (o->blessknown) {
if (o->blessed == B_UNCURSED) {
strcpy(prefix, "an");
} else {
strcpy(prefix, "a");
}
} else {
if (isvowel(o->type->name[0])) {
strcpy(prefix, "an");
} else {
strcpy(prefix, "a");
}
}
} else {
// multiple objects?
if (hasflag(o->flags, F_NO_PLURAL)) {
pluralname = strdup(o->type->name);
} else {
pluralname = makeplural(o->type->name);
}
sprintf(prefix, "%d",count);
}
sprintf(buf, "%s ", prefix);
// blessed status
if (o->blessknown) {
switch (o->blessed) {
case B_BLESSED:
strcat(buf, "blessed ");
break;
case B_UNCURSED:
strcat(buf, "uncursed ");
break;
case B_CURSED:
strcat(buf, "cursed ");
break;
}
}
// object name
strcat(buf, pluralname);
free(pluralname);
return buf;
}
char *getrandomob(map_t *map, char *buf) {
enum RARITY rarity;
objecttype_t *ot;
int roll;
objecttype_t *poss[MAXRANDOMOBCANDIDATES];
int nposs = 0;
int selidx;
int amt;
flag_t *f;
int db = B_FALSE;
// determine rarity of object 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 object of rarity %d\n",rarity);
// try to find an object of this type which will
// fit in the map's habitat
nposs = 0;
while (nposs == 0) {
for (ot = objecttype ; ot ; ot = ot->next) {
if (hasflagval(ot->flags, F_RARITY, map->habitat, rarity, -1, "") ||
hasflagval(ot->flags, F_RARITY, H_ALL, rarity, -1, "") ) {
poss[nposs] = ot;
nposs++;
if (nposs >= MAXRANDOMOBCANDIDATES) break;
}
}
// nothing found?
if (nposs == 0) {
// already at lowest rarity?
if (rarity == RR_FREQUENT) {
// give up
sprintf(buf, "");
if (db) dblog("no possible objects at all! giving up.");
return NULL;
} else {
// lower rarity and try again
rarity--;
if (db) dblog("no possible objects like this. trying again with rarity %d\n",rarity);
}
}
}
if (db) dblog("got %d possibilities.",nposs);
// pick a random object from our possiblities
selidx = rnd(0,nposs-1);
ot = poss[selidx];
// handle objects 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);
return buf;
}
object_t *hasob(obpile_t *op, enum OBTYPE oid) {
object_t *o;
for (o = op->first ; o ; o = o->next) {
if (o->type->id == oid) return o;
}
return NULL;
}
void initobjects(void) {
// materials
addmaterial(MT_STONE, "stone");
addmaterial(MT_FIRE, "fire");
addmaterial(MT_PLASTIC, "plastic");
addmaterial(MT_METAL, "metal");
addmaterial(MT_WOOD, "wood");
addmaterial(MT_FLESH, "flesh");
addmaterial(MT_GOLD, "gold");
// object classes
addoc(OC_MONEY, "Money", '$');
addoc(OC_SCROLL, "Scrolls", '?');
addoc(OC_POTION, "Potions", '!');
addoc(OC_WEAPON, "Weapons", '\\');
addoc(OC_ARMOUR, "Armour", ']');
addoc(OC_ROCK, "Rocks/Gems", '*');
addoc(OC_FOOD, "Food", '%');
addoc(OC_MISC, "Miscellaneous", '"');
// object types
addot(OT_GOLD, "gold coin", "Sparkling nuggets of gold, the standard currency of Nexus.", MT_GOLD, 0.1, OC_MONEY);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_ALL, RR_COMMON, -1, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 100, -1, "");
addot(OT_STONE, "stone", "A medium-sized roundish stone.", MT_STONE, 0.5, OC_ROCK);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, RR_FREQUENT, -1, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 10, -1, "");
// corpses
addot(OT_CORPSEHUMAN, "human corpse", "The dead body of a human.", MT_FLESH, 50, OC_FOOD);
addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, "");
addot(OT_CORPSEGOBLIN, "goblin corpse", "The dead body of a goblin.", MT_FLESH, 20, OC_FOOD);
addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, "");
addot(OT_CORPSEBAT, "bat corpse", "The dead body of a bat.", MT_FLESH, 5, OC_FOOD);
addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, "");
addot(OT_CORPSEBAT, "fly corpse", "The dead body of a giant flying insect.", MT_FLESH, 5, OC_FOOD);
addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, "");
}
// has this object changed proerties from its
// parent objecttype?
int isplainob(object_t *o) {
if (o->material != o->type->material) return B_FALSE;
if (o->weight != o->type->weight) return B_FALSE;
if (o->inscription) return B_FALSE;
if (o->blessed != B_UNCURSED) return B_FALSE;
if (o->blessknown) return B_FALSE;
return B_TRUE;
}
void killmaterial(material_t *m) {
int i;
material_t *nextone, *lastone;
// free mem
free(m->name);
// remove from list
nextone = m->next;
if (nextone != NULL) {
nextone->prev = m->prev;
} else { /* last */
lastmaterial = m->prev;
}
if (m->prev == NULL) {
/* first */
nextone = m->next;
free(material);
material = nextone;
} else {
lastone = m->prev;
free (lastone->next );
lastone->next = nextone;
}
}
void killob(object_t *o) {
int i;
object_t *nextone, *lastone;
// free mem
if (o->inscription) free(o->inscription);
// remove from list
nextone = o->next;
if (nextone != NULL) {
nextone->prev = o->prev;
} else { /* last */
o->pile->last = o->prev;
}
if (o->prev == NULL) {
/* first */
nextone = o->next;
o->pile->first = nextone;
free(o);
} else {
lastone = o->prev;
free (lastone->next );
lastone->next = nextone;
}
}
void killoc(objectclass_t *oc) {
int i;
objectclass_t *nextone, *lastone;
// free mem
free(oc->name);
// remove from list
nextone = oc->next;
if (nextone != NULL) {
nextone->prev = oc->prev;
} else { /* last */
lastobjectclass = oc->prev;
}
if (oc->prev == NULL) {
/* first */
nextone = oc->next;
free(objectclass);
objectclass = nextone;
} else {
lastone = oc->prev;
free (lastone->next );
lastone->next = nextone;
}
}
void killot(objecttype_t *ot) {
int i;
objecttype_t *nextone, *lastone;
// free mem
free(ot->name);
free(ot->desc);
if (ot->flags) killflagpile(ot->flags);
// remove from list
nextone = ot->next;
if (nextone != NULL) {
nextone->prev = ot->prev;
} else { /* last */
lastobjecttype = ot->prev;
}
if (ot->prev == NULL) {
/* first */
nextone = ot->next;
free(objecttype);
objecttype = nextone;
} else {
lastone = ot->prev;
free (lastone->next );
lastone->next = nextone;
}
}
object_t *moveob(object_t *src, obpile_t *dst, int howmany) {
object_t *o, *oo, *existob;
int i;
int db = B_FALSE;
reason = E_OK;
if (db) dblog("DB: moveob() - moving %d x %s",howmany, src->type->name);
existob = canstackob(dst, src);
if (existob) {
if (db) dblog("DB: moveob() - found stack to join");
if (howmany == ALL) howmany = src->amt;
existob->amt += howmany;
src->amt -= howmany;
if (src->amt == 0) {
killob(src);
}
return existob;
} else {
if (db) dblog("DB: moveob() - no stack to join");
// space in destination pile?
if (getnextletter(dst, NULL) == '-') {
reason = E_NOSPACE;
return NULL;
}
// no similar objects in the dest pile.
if ((howmany == ALL) || (howmany == src->amt)) {
if (db) dblog("DB: dropping ALL - relinking object to new pile");
// just move the whole object to the new pile
o = relinkob(src, dst);
} else {
obpile_t *tempop;
if (db) dblog("DB: moving only some of a stack.");
// create temporary object pile
tempop = addobpile(NULL, NULL);
// add new object to the temporary pile
o = addob(tempop, src->type->name);
// copy props from original object
copyobprops(o, src);
// just move some of them
for (i = 0; i < howmany; i++ ) {
// the first one is already there!
if (i != 0) {
// inc counter in temp pile
o->amt++;
}
// dec counter on original
src->amt--;
}
if (src->amt <= 0) {
killob(src);
}
// now move the object entry from the temporary pile to the
// real destination pile.
while (tempop->first) {
o = relinkob(tempop->first, dst);
}
free(tempop);
}
}
return o;
}
int obfits(object_t *o, obpile_t *op) {
if (countobs(op) >= MAXPILEOBS) {
return B_FALSE;
}
return B_TRUE;
}
// has this object changed proerties from its
// parent objecttype?
int obpropsmatch(object_t *a, object_t *b) {
if (a->type != b->type) return B_FALSE;
if (a->material != b->material) return B_FALSE;
if (a->weight != b->weight) return B_FALSE;
if (a->inscription || b->inscription) return B_FALSE;
if (a->blessed != b->blessed) return B_FALSE;
if (a->blessknown != b->blessknown) return B_FALSE;
return B_TRUE;
}
int pilehasletter(obpile_t *op, char let) {
object_t *o;
int found = B_FALSE;
for (o = op->first ; o ; o = o->next) {
if (o->letter == let) {
found = B_TRUE;
break;
}
}
return found;
}
object_t *relinkob(object_t *src, obpile_t *dst) {
if (!obfits(src, dst)) return NULL;
// unlink this object from the current list
if (src->prev == NULL) {
// first
src->pile->first = src->next;
} else {
// not first
src->prev->next = src->next;
}
if (src->next == NULL) {
// last
src->pile->last = src->prev;
} else {
// not last
src->next->prev = src->prev;
}
// add this object to the end of the list for the new pile
if (dst->first == NULL) {
// first element in new list
dst->first = src;
src->prev = NULL;
} else {
object_t *aa;
// go to end of list
aa = dst->last;
// not first in new list
src->prev = aa;
aa->next = src;
}
dst->last = src;
src->pile = dst;
src->next = NULL;
// adjust letter if going to player
if (dst->owner && (dst->owner->controller == C_PLAYER)) {
src->letter = getnextletter(dst, &src->letter);
}
return src;
}
void throwat(lifeform_t *thrower, object_t *o, cell_t *where) {
char throwername[BUFLEN];
char obname[BUFLEN];
char targetname[BUFLEN];
char buf[BUFLEN];
lifeform_t *target;
getlfname(thrower, throwername);
target = where->lf;
if (target) {
getlfname(target, targetname);
}
// announce it ("xx throws xx" "at yy")
getobname(o, obname, 1);
if (thrower->controller == C_PLAYER) {
if (target) {
msg("You throw %s at %s.", obname, targetname);
} else {
msg("You throw %s.",obname);
}
} else {
}
if (haslos(player, thrower->cell)) {
char throwstring[BUFLEN];
char *throwercaps;
throwercaps = strdup(throwername);
capitalise(throwercaps);
sprintf(throwstring, "%s throw%s %s",throwercaps,
(thrower->controller == C_PLAYER) ? "" : "s",
obname);
if (target && haslos(player, where)) {
strcat(throwstring, " at");
strcat(throwstring, targetname);
}
strcat(throwstring, ".");
free(throwercaps);
}
taketime(thrower, SPEED_THROW);
// TODO: figure out if you miss or not, based on distance
// do throw animation
anim(thrower->cell, where, o->type->obclass->glyph);
// if someone is there, they take damage and the object might die
if (target) {
int dam;
char damstring[BUFLEN];
// damage is kilograms / 5.
// ie. 5 kg object does 1 damage
// ie. 100 kg object does 20 damage (person)
// ie. 1 tonne object does 200 damage (car)
dam = (int)ceil((double)o->weight / 5.0);
// announce
if (haslos(player, where)) {
char *obcaps;
obcaps = strdup(obname);
capitalise(obcaps);
msg("%s hits %s.",obcaps,targetname);
free(obcaps);
}
sprintf(damstring, "%s (thrown by %s)",obname,throwername);
losehp(target, dam, thrower, damstring);
}
// either remove or move the object
moveob(o, where->obpile, 1);
}

37
objects.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef __OBJECTS_H
#define __OBJECTS_H
#include "defs.h"
material_t *addmaterial(enum MATERIAL id, char *name);
objectclass_t *addoc(enum OBCLASS id, char *name, 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);
objecttype_t *addot(int id, char *name, char *description, int material, float weight, int obclassid);
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 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 *findotn(char *name); // find objecttype by name
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);
object_t *hasob(obpile_t *op, enum OBTYPE oid);
void initobjects(void);
int isplainob(object_t *o);
void killmaterial(material_t *m);
void killob(object_t *o);
void killoc(objectclass_t *oc);
void killot(objecttype_t *ot);
object_t *moveob(object_t *src, obpile_t *dst, int howmany);
int obfits(object_t *o, obpile_t *op);
int obpropsmatch(object_t *a, object_t *b);
int pilehasletter(obpile_t *op, char let);
object_t *relinkob(object_t *src, obpile_t *dst);
void throwat(lifeform_t *thrower, object_t *o, cell_t *where);
#endif

594
save.c Normal file
View File

@ -0,0 +1,594 @@
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "defs.h"
#include "lf.h"
#include "map.h"
#include "move.h"
#include "nexus.h"
#include "objects.h"
#include "save.h"
extern lifeform_t *player;
extern map_t *firstmap;
int loadall(void) {
DIR *dir;
struct dirent *ent;
char *filename;
FILE *f;
dir = opendir(MAPDIR);
if (!dir) {
dblog("Could not open map directory '%s'",MAPDIR);
return B_TRUE;
}
// for each map file in directory
while ((ent = readdir(dir)) != NULL) {
char *p;
// ie. start of 4 char prefix
p = ent->d_name + strlen(ent->d_name) - 4;
// load this map
if (!strcmp(p, ".map") ) {
if (!loadmap(ent->d_name)) {
printf("Error loading map from file '%s'",ent->d_name);
exit(1);
}
}
}
closedir(dir);
loadsavegame();
return B_FALSE;
}
// load and allocate one lifeform from given file
lifeform_t *loadlf(FILE *f, cell_t *where) {
lifeform_t *l;
int lfid, lfraceid;
long obid;
int rv;
int i;
char buf[BUFLEN];
int obcount;
int mapid;
map_t *m;
int x,y;
int db = B_TRUE;
if (db) dblog("--> Loading lifeform...\n");
fscanf(f, "startlf\n");
fscanf(f, "lfid: %d\n",&lfid);
fscanf(f, "race: %d\n",&lfraceid);
fscanf(f, "map: %d\n",&mapid);
fscanf(f, "pos: %d,%d\n",&x, &y);
// find the map
m = findmap(mapid);
if (!m) {
dblog("ERROR loading lf id %d: can't find map id %d\n",lfid,mapid);
exit(1);
}
if (where == NULL) {
where = getcellat(m, x, y);
}
if (!m) {
dblog("ERROR loading lf id %d: can't find cell at %d,%d on map id %d\n",lfid,x,y,mapid);
exit(1);
}
l = addlf(where, lfraceid);
l->id = lfid;
l->x = x;
l->y = y;
// load rest of this lf
fscanf(f, "contr: %d\n",&l->controller);
fscanf(f, "hp: %d/%d\n",&l->hp, &l->maxhp);
fscanf(f, "alive: %d\n",&l->alive);
fgets(buf, BUFLEN, f); // lastdam
buf[strlen(buf)-1] = '\0'; // strip newline
l->lastdam = strdup(buf + 9); // after 'lastdam: '
fscanf(f, "timespent: %d\n",&l->timespent);
fscanf(f, "sorted: %d\n",&l->sorted);
if (db) dblog("--> Got hp=%d/%d. timespend=%d. sorted=%d. Now loading ob list.",l->hp,l->maxhp,l->timespent,l->sorted);
// load object list
obcount = 0;
obid = 9999; // for testing
rv = fscanf(f, "ob:%ld\n",&obid);
while (obid != -1) {
if (db) dblog("--> Load ob id %d into list...",obid);
l->pack->oblist[obcount] = obid;
obcount++;
fscanf(f, "ob:%ld\n",&obid);
}
// terminate with -1s!
for (i = obcount ; i < MAXPILEOBS; i++) {
l->pack->oblist[i] = -1;
}
if (db) dblog("--> Finished oblist. Found %d objects.",obcount);
// now load load object defs!
fscanf(f, "obdefs\n");
for (i = 0; i < obcount; i++) {
//if (db) dblog("-----> ob %d/%d...\n",i+1,obcount);
if (loadob(f, l->pack)) {
dblog("Error - can't create object %d/%d!\n",i+1,obcount);
exit(1);
}
}
// is this the player?
if (l->controller == C_PLAYER) {
player = l;
}
}
map_t *loadmap(char *basefile) {
FILE *f;
char filename[BUFLEN];
char buf[BUFLEN];
char buf2[BUFLEN];
int obcount;
int i;
int x,y;
int db = B_TRUE;
lifeform_t *l;
object_t *o,*nexto;
map_t *m;
cell_t *dummycell;
if (db) dblog("Loading map from %s...",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
if (!m) {
dblog("Error creating map while loading file '%s'",filename);
return NULL;
}
// load map info
if (db) dblog("--> Loading map info...\n");
fscanf(f, "id:%d\n",&m->id); // map id
fgets(buf, BUFLEN, f); // map name
buf[strlen(buf)-1] = '\0'; // strip newline
m->name = strdup(buf + 5); // after 'name:'
fscanf(f, "habitat:%d\n",(int *)&m->habitat); // habitat
fscanf(f, "seed:%d\n",&m->seed); // seed
fscanf(f, "dims:%d,%d\n",&m->w, &m->h); // map dimensons
fscanf(f, "nextlfid:%ld\n",&m->nextlfid);
fscanf(f, "nextmaps:\n");
for (i = 0; i < MAXDIR_ORTH; i++) {
fscanf(f, "%d\n",&m->nextmap[i]); // map dimensons
}
if (db) dblog("--> Finished map info. name='%s', dims=%d x %d\n",m->name, m->w, m->h);
fscanf(f, "id:%d\n",&m->id); // map id
// load lifeforms
if (db) dblog("--> Loading lifeforms...\n");
fscanf(f, "lifeforms:\n");
fscanf(f, "%s\n",buf);
while (!strcmp(buf ,"startlf")) {
loadlf(f, dummycell);
// check for more lifeforms...
fscanf(f, "%s\n",buf);
}
// load cells
if (db) dblog("--> Loading map cells...\n");
fscanf(f, "cells:\n");
for (y = 0; y < m->h; y++) {
for (x = 0; x < m->w; x++) {
cell_t *c;
celltype_t *ct;
int celltypeid;
long obid;
//if (db) dblog("cell %d,%d...",x,y);
// allocate this cell
c = addcell(m, x, y);
/*
c = m->cell[y * m->w + x];
c->map = m;
c->obpile = addobpile(NULL, c);
c->lf = NULL;
c->x = x;
c->y = y;
c->roomid = -1;
*/
// cell info
fscanf(f, "%d,%d,%d,%d\n",
&c->roomid, &celltypeid, &c->known, &c->visited);
ct = findcelltype(celltypeid);
if (ct) {
c->type = ct;
} else {
dblog("ERROR loading map cells - can't find celltype id %ld\n",celltypeid);
exit(1);
}
// cell objects
obcount = 0;
fscanf(f, "ob:%ld\n",&obid);
while (obid != -1) {
c->obpile->oblist[obcount] = obid;
obcount++;
fscanf(f, "ob:%ld\n",&obid);
}
// terminate with -1s!
for (i = obcount ; i < MAXPILEOBS; i++) {
c->obpile->oblist[i] = -1;
}
}
}
// load object definitions
if (db) dblog("--> Loading object definitions for map obs...\n");
fscanf(f, "MAPOBS:%d\n",&obcount); // how many obs?
// 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)) {
dblog("Error - can't create object %d/%d!\n",i+1,obcount);
exit(1);
}
}
// hand out the objects to lifeforms...
for (l = m->lf ; l ; l = l->next) {
int curob = 0;
long obid;
obid = l->pack->oblist[curob];
while (obid != -1) {
int found = B_FALSE;
// find this ob id in the dummycell
for (o = dummycell->obpile->first ; o ; o = nexto) {
nexto = o->next;
if (o->id == obid) {
relinkob(o, l->pack);
found = B_TRUE;
break;
}
}
if (!found) {
dblog("Error loading obs - lf %d should have obid %ld but can't find it.\n",l->id, obid);
exit(1);
}
// next one
curob++;
obid = l->pack->oblist[curob];
}
// clear the oblist
for (i = 0; i < MAXPILEOBS; i++) {
l->pack->oblist[i] = -1;
}
}
// hand out objects to cells
for (y = 0; y < m->h; y++) {
for (x = 0; x < m->w; x++) {
cell_t *c;
long obid;
int curob = 0;
c = m->cell[y * m->w + x];
obid = c->obpile->oblist[curob];
while (obid != -1) {
int found = B_FALSE;
// find this ob id in the dummycell
for (o = dummycell->obpile->first ; o ; o = nexto) {
nexto = o->next;
if (o->id == obid) {
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);
exit(1);
}
// next one
curob++;
}
// clear the oblist
for (i = 0; i < MAXPILEOBS; i++) {
c->obpile->oblist[i] = -1;
}
}
}
fclose(f);
// move lifeforms to their proper locations
for (l = m->lf ; l ; l = l->next) {
cell_t *c;
c = getcellat(m, l->x, l->y);
if (!c) {
dblog("Error loading map - Can't find cell at %d,%d to place lifeform id %d.\n",
l->x, l->y, l->id);
exit(1);
}
movelf(l, c);
//dblog("Moving lf %d to %d,%d\n",l->id, l->x, l->y);
}
free(dummycell);
return m;
}
int loadob(FILE *f, obpile_t *op) {
objecttype_t *ot;
object_t *o;
material_t *mat;
long obid;
int otid,matid;
char buf[BUFLEN];
int flagid;
flag_t tempflag;
int rv;
fscanf(f, "id:%ld\n",&obid);
fscanf(f, "type:%d\n",&otid);
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);
// overwrite ob parameters
o->id = obid;
fscanf(f, "material:%d\n",&matid);
mat = findmaterial(matid);
if (!mat) {
dblog("ERROR loading objects - can't find material %d\n",matid);
return B_TRUE;
}
o->material = mat;
fscanf(f, "weight:%f\n",&o->weight);
fgets(buf, BUFLEN, f); // inscription
buf[strlen(buf)-1] = '\0'; // strip newline
o->inscription = strdup(buf + 6); // after 'inscr:'
if (!strcmp(o->inscription, "^^^")) { // ie. if equal to ^^^...
free(o->inscription);
o->inscription = NULL;
}
fscanf(f, "letter:%c\n",&o->letter);
fscanf(f, "bless:%d\n",&o->blessed);
fscanf(f, "blessknown:%d\n",&o->blessknown);
fscanf(f, "amt:%d\n",&o->amt);
fscanf(f, "flags:\n");
rv = fscanf(f, "%d,%d,%d,%d,%d\n",
&tempflag.id, &tempflag.nvals, &tempflag.val[0], &tempflag.val[1], &tempflag.val[2]);
// 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],
tempflag.val[1],
tempflag.val[2], strcmp(buf, "^^^") ? buf : NULL);
// load next one
rv = fscanf(f, "%d,%d,%d,%d,%d\n",
&tempflag.id, &tempflag.nvals, &tempflag.val[0], &tempflag.val[1], &tempflag.val[2]);
//dblog("fscanf returned %d\n",rv);
}
fscanf(f, "endob\n");
return B_FALSE;
}
int loadsavegame(void) {
DIR *dir;
struct dirent *ent;
char filename[BUFLEN];
FILE *f;
// now see if there is a savegame...
dir = opendir(SAVEDIR);
if (!dir) {
dblog("Could not open savegame directory '%s'",SAVEDIR);
return B_TRUE;
}
ent = readdir(dir);
while ((ent = readdir(dir)) != NULL) {
char *p;
// ie. start of 4 char prefix
p = ent->d_name + strlen(ent->d_name) - 4;
// load this savegame
if (!strcmp(p, ".sav") ) {
sprintf(filename, "%s/%s",SAVEDIR,ent->d_name);
dblog("Trying to load from %s\n",filename);
f = fopen(filename, "rt");
if (!f) {
printf("Error opening savegame file '%s'",ent->d_name);
exit(1);
}
if (!loadlf(f, NULL)) {
printf("Error loading savegame from file '%s'",ent->d_name);
exit(1);
}
fclose(f);
// successful load - kill the savegame now
unlink(filename);
break;
}
}
closedir(dir);
return B_FALSE;
}
int savelf(FILE *f, lifeform_t *l) {
object_t *o;
int obcount = 0;
// save this lf
fprintf(f, "startlf\n");
fprintf(f, "lfid: %d\n",l->id);
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, "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);
// lifeform objects
obcount = 0;
for (o = l->pack->first ; o ; o = o->next) {
fprintf(f, "ob:%ld\n",o->id);
obcount++;
}
fprintf(f, "ob:-1\n");
fprintf(f, "obdefs\n");
// now save our object definitions
for (o = l->pack->first ; o ; o = o->next) {
saveob(f, o);
}
return B_FALSE;
}
int savemap(map_t *m) {
FILE *f;
char filename[BUFLEN];
int i;
object_t *o;
lifeform_t *l;
int x,y;
int obcount = 0;
// TODO: check that map dir exists
sprintf(filename, "%s/map%d.map",MAPDIR, m->id);
f = fopen(filename, "wt");
// save map info
fprintf(f, "id:%d\n",m->id); // map id
fprintf(f, "name:%s\n",m->name); // map name
fprintf(f, "habitat:%d\n",m->habitat); // habitat
fprintf(f, "seed:%d\n",m->seed); // seed
fprintf(f, "dims:%d,%d\n",m->w, m->h); // map dimensons
fprintf(f, "nextlfid:%ld\n",m->nextlfid);
fprintf(f, "nextmaps:\n");
for (i = 0; i < MAXDIR_ORTH; i++) {
fprintf(f, "%d\n",m->nextmap[i] ); // map dimensons
}
// save all non-player lifeforms (includes their objects)
fprintf(f, "lifeforms:\n");
for (l = m->lf ; l ; l = l->next) {
if (l->controller != C_PLAYER) { // don't save the player!
savelf(f, l);
}
}
fprintf(f, "endlifeforms\n");
// cells
fprintf(f, "cells:\n");
for (y = 0; y < m->h; y++) {
for (x = 0; x < m->w; x++) {
cell_t *c;
c = getcellat(m, x, y);
// cell info
fprintf(f, "%d,%d,%d,%d\n",
c->roomid, c->type->id, c->known, c->visited);
// cell objects
for (o = c->obpile->first ; o ; o = o->next) {
fprintf(f, "ob:%ld\n",o->id);
obcount++;
}
fprintf(f, "ob:-1\n");
}
}
// save object definitions from map cells
fprintf(f, "MAPOBS:%d\n",obcount);
for (y = 0; y < m->h; y++) {
for (x = 0; x < m->w; x++) {
cell_t *c;
c = getcellat(m, x, y);
// cell objects
for (o = c->obpile->first ; o ; o = o->next) {
saveob(f, o);
}
}
}
fclose(f);
return B_FALSE;
}
int saveob(FILE *f, object_t *o) {
flag_t *fl;
fprintf(f, "id:%ld\n",o->id);
fprintf(f, "type:%d\n",o->type->id);
fprintf(f, "material:%d\n",o->material->id);
fprintf(f, "weight:%f\n",o->weight);
fprintf(f, "inscr:%s\n",o->inscription ? o->inscription : "^^^");
fprintf(f, "letter:%c\n",o->letter);
fprintf(f, "bless:%d\n",o->blessed);
fprintf(f, "blessknown:%d\n",o->blessknown);
fprintf(f, "amt:%d\n",o->amt);
fprintf(f, "flags:\n");
for (fl = o->flags->first ; fl ; fl = fl->next) {
fprintf(f, "%d,%d,%d,%d,%d\n",
fl->id, fl->nvals, fl->val[0], fl->val[1], fl->val[2]);
if (!fl->text || !strcmp(fl->text, "")) {
fprintf(f, "%s\n","^^^");
} else {
fprintf(f, "%s\n",fl->text);
}
}
fprintf(f, "-1,-1,-1,-1,-1\n");
fprintf(f, "endob\n");
return B_FALSE;
}

10
save.h Normal file
View File

@ -0,0 +1,10 @@
#include "defs.h"
int loadall(void);
lifeform_t *loadlf(FILE *f, cell_t *where);
map_t *loadmap(char *basefile);
int loadob(FILE *f, obpile_t *op);
int loadsavegame(void);
int savelf(FILE *f, lifeform_t *l);
int savemap(map_t *m);
int saveob(FILE *f, object_t *o);

37
svn-commit.tmp Normal file
View File

@ -0,0 +1,37 @@
Initial checkin
--This line, and those below, will be ignored--
A objects.h
A ai.h
A save.c
A lf.c
A nexus.c
A save.h
A move.c
A lf.h
A attack.c
A io.c
A nexus.h
A flag.c
A object.h
A move.h
A io.h
A attack.h
A map.c
A log.txt
A flag.h
A map.h
A doc
A doc/add_race.txt
A doc/add_obclass.txt
A text.c
A defs.h
A data
A data/maps
A data/save
A ai.c
A objects.c
A text.h
A Makefile
A mod_ob.txt

41
text.c Normal file
View File

@ -0,0 +1,41 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "defs.h"
#include "objects.h"
char *capitalise(char *text) {
text[0] = toupper(text[0]);
return text;
}
int isvowel (char c) {
switch (c) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
return B_TRUE;
}
return B_FALSE;
}
// allocates and returns new string
char *makeplural(char *text) {
int newlen;
char *newtext;
char lastlet;
lastlet = text[strlen(text)-1];
switch (lastlet) {
case 's':
case 'o': // append "es"
asprintf(&newtext, "%ses",text);
break;
default: // append "s"
asprintf(&newtext, "%ss",text);
break;
}
return newtext;
}

6
text.h Normal file
View File

@ -0,0 +1,6 @@
#include "defs.h"
char *capitalise(char *text);
int isvowel(char c);
char *makeplural(char *text);