History

implement xp. gain maxhp when you get a level. various cleanup.

mischief committed 11 years ago

Commit cca5e331 parent 0ca63d011 files · +408 −125Browse files

Unified · Split

11 files
  1. ai.c +7 −1
  2. alg.c +41 −0
  3. alg.h +4 −0
  4. algtest.c +33 −0
  5. dat.h +23 −7
  6. hack9.c +19 −3
  7. level.c +130 −65
  8. monst.c +70 −12
  9. monstdata.c +22 −10
  10. path.c +14 −13
  11. ui.c +45 −14
ai.c+7−1
@@ -172,6 +172,7 @@ typedef struct walktodata walktodata; · 171 unmodified lines
172struct walktodata172struct walktodata
173{173{
174 Point dst;174 Point dst;
175 Point last;
175 int npath;176 int npath;
176 int next;177 int next;
177 Point *path;178 Point *path;
@@ -188,7 +189,9 @@ walktoinner(AIState *a) · 10 unmodified lines
188 d = a->aux;189 d = a->aux;
189 m = a->m;190 m = a->m;
190 191
191 if(d->blocked > d->wait){192 /* d->last might not equal m->pt if some other
193 * state pre-empted us, like attack */
194 if(!eqpt(d->last, m->pt) || d->blocked > d->wait){
192 goto cleanup;195 goto cleanup;
193 }196 }
194 197
@@ -228,6 +231,7 @@ walktoinner(AIState *a) · 33 unmodified lines
228 d->next++;231 d->next++;
229 232
230 maction(m, MMOVE, p);233 maction(m, MMOVE, p);
234 d->last = p;
231 return 0;235 return 0;
232cleanup:236cleanup:
233 free(d->path);237 free(d->path);
@@ -267,6 +271,7 @@ walkto(Monster *m, Point p, int wait) · 33 unmodified lines
267 AIState *i;271 AIState *i;
268 d = mallocz(sizeof(*d), 1);272 d = mallocz(sizeof(*d), 1);
269 d->dst = p;273 d->dst = p;
274 d->last = m->pt;
270 d->wait = wait;275 d->wait = wait;
271 assert(d != nil);276 assert(d != nil);
272 i = mkstate("walk", m, d, nil, walktoexec, walktoexit);277 i = mkstate("walk", m, d, nil, walktoexec, walktoexit);
@@ -313,6 +318,7 @@ attackexec(AIState *a) · 40 unmodified lines
313 d->wd->dst = mt->pt;318 d->wd->dst = mt->pt;
314 }319 }
315 d->wd->wait = 2;320 d->wd->wait = 2;
321 d->wd->last = m->pt;
316 if(walktoinner(d->w) < 0){322 if(walktoinner(d->w) < 0){
317 a = mpopstate(m);323 a = mpopstate(m);
318 freestate(a);324 freestate(a);
alg.c+41−0
@@ -1,5 +1,6 @@
1#include <u.h>1#include <u.h>
2#include <libc.h>2#include <libc.h>
3#include <draw.h>
3#include "alg.h"4#include "alg.h"
4 5
5Priq*6Priq*
@@ -94,3 +95,43 @@ priqhas(Priq *q, void *val) · 88 unmodified lines
94 return 0;95 return 0;
95}96}
96 97
98/* von neumann neighborhood */
99Point*
100neighbor(Rectangle in, Point p, int *n)
101{
102 int i, count;
103 Point *neigh, p2, diff[] = { {1, 0}, {0, -1}, {-1, 0}, {0, 1} };
104
105 count = 0;
106 neigh = mallocz(sizeof(Point) * nelem(diff), 1);
107
108 for(i = 0; i < nelem(diff); i++){
109 p2 = addpt(p, diff[i]);
110 if(ptinrect(p2, in)){
111 neigh[count++] = p2;
112 }
113 }
114
115 *n = count;
116 return neigh;
117}
118
119/* fisher-yates shuffle */
120void
121shuffle(void *base, long nel, long width)
122{
123 unsigned char *b, *swap1, *swap2;
124 long i, j, k;
125 b = base;
126 for(i = nel - 1; i > 0; i--){
127 j = nrand(i);
128 swap1 = &b[i*width];
129 swap2 = &b[j*width];
130 for(k = 0; k < width; k++){
131 *swap1 ^= *swap2;
132 *swap2 ^= *swap1;
133 *swap1++ ^= *swap2++;
134 }
135 }
136}
137
alg.h+4−0
@@ -6,6 +6,7 @@ struct Priq · 5 unmodified lines
6 int alloc;6 int alloc;
7};7};
8 8
9/* alg.c */
9typedef int (*pricmp)(void *v1, void *v2);10typedef int (*pricmp)(void *v1, void *v2);
10Priq *priqnew(int size);11Priq *priqnew(int size);
11void priqfree(Priq *q);12void priqfree(Priq *q);
@@ -14,3 +15,6 @@ void *priqpop(Priq *q, pricmp cmp); · 2 unmodified lines
14void *priqtop(Priq *q);15void *priqtop(Priq *q);
15int priqhas(Priq *q, void *val);16int priqhas(Priq *q, void *val);
16 17
18Point *neighbor(Rectangle in, Point p, int *n);
19void shuffle(void *base, long nel, long width);
20
algtest.c+33−0
@@ -1,5 +1,6 @@
1#include <u.h>1#include <u.h>
2#include <libc.h>2#include <libc.h>
3#include <draw.h>
3 4
4#include "alg.h"5#include "alg.h"
5 6
@@ -37,11 +38,43 @@ testpriq(void) · 31 unmodified lines
37 return 0;38 return 0;
38}39}
39 40
41int
42testshuffle(void)
43{
44 int arr[] = {1, 3, 5, 7, 9, 11, 13, 17};
45 Point pt[] = {{0,0}, {1, 1}, {2, 2}, {3, 3}};
46 long i, sz;
47
48 fmtinstall('P', Pfmt);
49
50 sz = sizeof(arr)/sizeof(arr[0]);
51
52 print("\n");
53 for(i=0;i<sz;i++)
54 print("%d ", arr[i]);
55 print("\n");
56 shuffle(arr, sz, sizeof(arr[0]));
57 for(i=0;i<sz;i++)
58 print("%d ", arr[i]);
59 print("\n");
60
61 sz = sizeof(pt)/sizeof(pt[0]);
62 for(i=0;i<sz;i++)
63 print("%P ", pt[i]);
64 print("\n");
65 shuffle(pt, sz, sizeof(pt[0]));
66 for(i=0;i<sz;i++)
67 print("%P ", pt[i]);
68 print("\n");
69 return 0;
70}
71
40struct {72struct {
41 char *n;73 char *n;
42 tfun f;74 tfun f;
43} tfuns[] = {75} tfuns[] = {
44 {"priq", testpriq},76 {"priq", testpriq},
77 {"shuffle", testshuffle},
45 {nil, nil},78 {nil, nil},
46};79};
47 80
dat.h+23−7
@@ -10,15 +10,13 @@ typedef struct Camera Camera; · 9 unmodified lines
10 10
11/* hack9.c */11/* hack9.c */
12extern int debug;12extern int debug;
13extern int farmsg;
13extern Monster *player;14extern Monster *player;
14extern char *user;15extern char *user;
15extern char *home;16extern char *home;
16extern long turn;17extern long turn;
17void msg(char *fmt, ...);18int isyou(Monster *m);
18void good(char *fmt, ...);19int nearyou(Point p);
19void warn(char *fmt, ...);
20void bad(char *fmt, ...);
21void dbg(char *fmt, ...);
22 20
23typedef void (*AIFun)(AIState *);21typedef void (*AIFun)(AIState *);
24 22
@@ -65,12 +63,13 @@ void drawtile(Tileset *t, Image *dst, Point p, int i); · 40 unmodified lines
65struct MonsterData63struct MonsterData
66{64{
67 char *name;65 char *name;
66 uint basexpl;
68 char align;67 char align;
69 uint mvr;68 uint mvr;
70 uint maxhp;69 uint maxhp;
71 long def;70 long def;
72 uint atk;
73 uint rolls;71 uint rolls;
72 uint atk;
74};73};
75 74
76extern MonsterData monstdata[1200];75extern MonsterData monstdata[1200];
@@ -114,6 +113,8 @@ struct Monster · 37 unmodified lines
114 113
115 /* current hp */114 /* current hp */
116 double hp;115 double hp;
116 /* maximum hp */
117 double maxhp;
117 118
118 /* armor class */119 /* armor class */
119 long ac;120 long ac;
@@ -121,6 +122,11 @@ struct Monster · 1 unmodified line
121 /* kill count */122 /* kill count */
122 long kills;123 long kills;
123 124
125 /* experience level */
126 long xpl;
127 /* experience gained */
128 long xp;
129
124 /* flags */130 /* flags */
125 u32int flags;131 u32int flags;
126 132
@@ -139,13 +145,17 @@ int mupdate(Monster *m); · 12 unmodified lines
139void mpushstate(Monster *m, AIState *a);145void mpushstate(Monster *m, AIState *a);
140AIState *mpopstate(Monster *m);146AIState *mpopstate(Monster *m);
141int maction(Monster *m, int what, Point where);147int maction(Monster *m, int what, Point where);
148long xpcalc(long level);
142 149
143/* well known tiles, also indexes into monstdata */150/* well known tiles, also indexes into monstdata */
144enum151enum
145{152{
146 /* monsters */153 /* monsters */
147 TLARGECAT = 39,154 TLARGECAT = 39,
155 TGNOME = 166,
156 TGNOMELORD = 167,
148 TGWIZARD = 168,157 TGWIZARD = 168,
158 TGNOMEKING = 169,
149 TLICH = 185,159 TLICH = 185,
150 TSOLDIER = 280,160 TSOLDIER = 280,
151 TSERGEANT = 281,161 TSERGEANT = 281,
@@ -168,6 +178,7 @@ enum · 16 unmodified lines
168 178
169struct Portal179struct Portal
170{180{
181 char name[32];
171 /* where it takes us to */182 /* where it takes us to */
172 Level *to;183 Level *to;
173 /* location in to */184 /* location in to */
@@ -237,6 +248,7 @@ struct Level · 63 unmodified lines
237 Spawn spawns[10];248 Spawn spawns[10];
238};249};
239 250
251/* level.c */
240Level *genlevel(int width, int height, int type);252Level *genlevel(int width, int height, int type);
241void freelevel(Level *l);253void freelevel(Level *l);
242Tile *tileat(Level *l, Point p);254Tile *tileat(Level *l, Point p);
@@ -244,7 +256,6 @@ Tile *tileat(Level *l, Point p); · 1 unmodified line
244#define hasflagat(l, p, F) (*(l->flags+(p.y*l->width)+p.x) & (F))256#define hasflagat(l, p, F) (*(l->flags+(p.y*l->width)+p.x) & (F))
245#define setflagat(l, p, F) (*(l->flags+(p.y*l->width)+p.x) |= (F))257#define setflagat(l, p, F) (*(l->flags+(p.y*l->width)+p.x) |= (F))
246#define clrflagat(l, p, F) (*(l->flags+(p.y*l->width)+p.x) &= ~(F))258#define clrflagat(l, p, F) (*(l->flags+(p.y*l->width)+p.x) &= ~(F))
247Point *lneighbor(Level *l, Point p, int *n);
248 259
249struct Camera260struct Camera
250{261{
@@ -267,6 +278,11 @@ int manhattan(Point cur, Point targ); · 16 unmodified lines
267int pathfind(Level *l, Point start, Point end, Point **path, int not);278int pathfind(Level *l, Point start, Point end, Point **path, int not);
268 279
269/* ui.c */280/* ui.c */
281void msg(char *fmt, ...);
282void good(char *fmt, ...);
283void warn(char *fmt, ...);
284void bad(char *fmt, ...);
285void dbg(char *fmt, ...);
270void uiinit(char *name);286void uiinit(char *name);
271void uiexec(AIState *ai);287void uiexec(AIState *ai);
272void uiredraw(int justui);288void uiredraw(int justui);
hack9.c+19−3
@@ -12,11 +12,26 @@ enum · 11 unmodified lines
12};12};
13 13
14int debug;14int debug;
15int farmsg = 0;
15Monster *player;16Monster *player;
16char *user;17char *user;
17char *home;18char *home;
18long turn = 0;19long turn = 0;
19 20
21int
22isyou(Monster *m)
23{
24 return m == player;
25}
26
27int
28nearyou(Point p)
29{
30 if(farmsg)
31 return 1;
32 return manhattan(player->pt, p) < ORTHOCOST*5;
33}
34
20/*35/*
21 * sort monsters for movement order.36 * sort monsters for movement order.
22 * player comes first, followed by monsters,37 * player comes first, followed by monsters,
@@ -40,7 +55,7 @@ monsort(void *a, void *b) · 17 unmodified lines
40 return sa < sb;55 return sa < sb;
41}56}
42 57
43void58static void
44movemons(void)59movemons(void)
45{60{
46 Point p;61 Point p;
@@ -81,7 +96,8 @@ movemons(void) · 34 unmodified lines
81 96
82 priqfree(tomove);97 priqfree(tomove);
83}98}
84void99
100static void
85usage(void)101usage(void)
86{102{
87 fprint(2, "usage: %s [-d]", argv0);103 fprint(2, "usage: %s [-d]", argv0);
@@ -142,7 +158,7 @@ threadmain(int argc, char *argv[]) · 54 unmodified lines
142 158
143 if(debug > 0){159 if(debug > 0){
144 player->hp = 500;160 player->hp = 500;
145 player->md->maxhp = 500;161 player->maxhp = 500;
146 }162 }
147 163
148 uiredraw(0);164 uiredraw(0);
level.c+130−65
@@ -4,6 +4,7 @@ · 3 unmodified lines
4#include <thread.h>4#include <thread.h>
5 5
6#include "dat.h"6#include "dat.h"
7#include "alg.h"
7 8
8/* clear removes all monsters/features near p. */9/* clear removes all monsters/features near p. */
9static void10static void
@@ -71,13 +72,16 @@ drunk1(Level *l, Point p, uint count, uint sbias) · 61 unmodified lines
71static int72static int
72drunken(Level *l, int type, int howmuch, int s1, int s2)73drunken(Level *l, int type, int howmuch, int s1, int s2)
73{74{
74 int cnt, npath;75 int cnt, npath, redos;
75 Point p, *path;76 Point p, *path;
76 Tile *t;77 Tile *t;
77 78
78 cnt = ((l->width * l->height) / howmuch); //* 2;79 cnt = ((l->width * l->height) / howmuch); //* 2;
80 redos = 0;
79 81
80redo:82redo:
83 if(redos++ > 10)
84 return 0;
81 /* fill */85 /* fill */
82 for(p.x = 0; p.x < l->width; p.x++){86 for(p.x = 0; p.x < l->width; p.x++){
83 for(p.y = 0; p.y < l->height; p.y++){87 for(p.y = 0; p.y < l->height; p.y++){
@@ -149,14 +153,14 @@ several(Level *l, Point *p, int count, int type, int r) · 65 unmodified lines
149 Point *neigh;153 Point *neigh;
150 Tile *t;154 Tile *t;
151 for(i = 0; i < count; i++){155 for(i = 0; i < count; i++){
152 if(!hasflagat(l, p[i], Fhasmonster)){156 if(!hasflagat(l, p[i], Fhasmonster|Fblocked)){
153 t = tileat(l, p[i]);157 t = tileat(l, p[i]);
154 t->unit = type;158 t->unit = type;
155 t->monst = mkmons(l, p[i], type);159 t->monst = mkmons(l, p[i], type);
156 setflagat(l, p[i], Fhasmonster);160 setflagat(l, p[i], Fhasmonster);
157 }161 }
158 if(r > 0){162 if(r > 0){
159 neigh = lneighbor(l, p[i], &n);163 neigh = neighbor(l->r, p[i], &n);
160 for(j = 0; j < n; j++){164 for(j = 0; j < n; j++){
161 several(l, neigh, n, type, r-1);165 several(l, neigh, n, type, r-1);
162 }166 }
@@ -174,26 +178,55 @@ static void addspawn(Level *l, Point p, int what, int freq) · 11 unmodified lines
174static void178static void
175levelexec(AIState *a)179levelexec(AIState *a)
176{180{
177 int i;181 int i, j, n;
182 Point p, np, *neigh;
178 Level *l;183 Level *l;
184 Tile *t;
185 MonsterData *md;
186 Monster *m;
187
179 l = a->aux;188 l = a->aux;
180 189
190 assert(l > (void*)0x1000);
191
192 assert(l != nil);
193
181 for(i = 0; i < l->nspawns; i++){194 for(i = 0; i < l->nspawns; i++){
182 if(turn % l->spawns[i].freq == 0){195 if(turn % l->spawns[i].freq == 0){
183 several(l, &l->spawns[i].pt, 1, l->spawns[i].what, 0);196 p = l->spawns[i].pt;
197
198 /* le trap */
199 neigh = neighbor(l->r, p, &n);
200 for(j = 0; j < n; j++){
201 np = neigh[j];
202 if(hasflagat(l, np, Fhasmonster)){
203 t = tileat(l, np);
204 m = t->monst;
205 md = &monstdata[l->spawns[i].what];
206 if(m->type != l->spawns[i].what && abs(m->align - md->align) > 15){
207 several(l, &np, 1, l->spawns[i].what, 1);
208 }
209 }
210 }
211
212 free(neigh);
213 several(l, &p, 1, l->spawns[i].what, 0);
184 }214 }
185 }215 }
186}216}
187 217
188static void218static int
189gen(Level *l, int type)219gen(Level *l, int type)
190{220{
191 int space, npath;221 int space, npath, try;
192 Point pup, pdown, p, *path;222 Point pup, pdown, p, p2, *path;
223 Rectangle in;
193 Tile *t;224 Tile *t;
194 225
195 space = 0;226 space = 0;
227 try = 0;
196 228
229 in = insetrect(l->r, 3);
197 pup = ZP;230 pup = ZP;
198 pdown = ZP;231 pdown = ZP;
199 232
@@ -202,13 +235,13 @@ gen(Level *l, int type) · 2 unmodified lines
202 flagat(l, pup) = 0;235 flagat(l, pup) = 0;
203 do{236 do{
204 pup = (Point){nrand(l->width), nrand(l->height)};237 pup = (Point){nrand(l->width), nrand(l->height)};
205 }while(!ptinrect(pup, insetrect(l->r, 3)));238 }while(!ptinrect(pup, in));
206 239
207 if(!eqpt(pdown, ZP))240 if(!eqpt(pdown, ZP))
208 flagat(l, pup) = 0;241 flagat(l, pup) = 0;
209 do{242 do{
210 pdown = (Point){nrand(l->width), nrand(l->height)};243 pdown = (Point){nrand(l->width), nrand(l->height)};
211 }while(!ptinrect(pdown, insetrect(l->r, 3)));244 }while(!ptinrect(pdown, in));
212 245
213 /* already upstair? */246 /* already upstair? */
214 if(flagat(l, pdown) & Fportal)247 if(flagat(l, pdown) & Fportal)
@@ -225,50 +258,89 @@ gen(Level *l, int type) · 10 unmodified lines
225 t = tileat(l, pup);258 t = tileat(l, pup);
226 t->feat = TUPSTAIR;259 t->feat = TUPSTAIR;
227 t->portal = mallocz(sizeof(Portal), 1);260 t->portal = mallocz(sizeof(Portal), 1);
261 strcpy(t->portal->name, "staircase upstairs");
228 l->up = pup;262 l->up = pup;
229 263
230 setflagat(l, pdown, Fhasfeature|Fportal);264 setflagat(l, pdown, Fhasfeature|Fportal);
231 t = tileat(l, pdown);265 t = tileat(l, pdown);
232 t->feat = TDOWNSTAIR;266 t->feat = TDOWNSTAIR;
233 t->portal = mallocz(sizeof(Portal), 1);267 t->portal = mallocz(sizeof(Portal), 1);
268 strcpy(t->portal->name, "staircase downstairs");
234 l->down = pdown;269 l->down = pdown;
235 break;270 break;
236 }271 }
237 272
273 enum { DIST = ORTHOCOST*10, };
274
238 switch(type){275 switch(type){
239 case 0:276 case 0:
240 drunken(l, TTREE, 3, 3, 3);277 drunken(l, TTREE, 3, 3, 3);
241 clear(l, pup, 1);278 clear(l, pup, 1);
242 clear(l, pdown, 1);279 clear(l, pdown, 1);
243 //several(l, &l->down, 1, TLICH, 0);280 several(l, &l->down, 1, TLICH, 1);
244 several(l, &l->down, 1, TGWIZARD, 1);281 several(l, &l->down, 1, TGWIZARD, 1);
245 //several(l, &l->up, 1, TGWIZARD, 0);
246 break;282 break;
247 break;283 break;
248 case 1:284 case 1:
249 space += drunken(l, TTREE, 2, 0, 0);285 space += drunken(l, TTREE, 2, 0, 0);
250 clear(l, pup, 1);286 clear(l, pup, 1);
251 clear(l, pdown, 1);287 clear(l, pdown, 1);
252 genmonsters(l, TGWIZARD, space/128);288 do{
253 genmonsters(l, TSOLDIER, space/64);289 p = (Point){nrand(l->width), nrand(l->height)};
290 if(try++ > 10)
291 return -1;
292 }while(!ptinrect(p, in) || manhattan(p, l->down) < DIST || manhattan(p, l->up) < DIST || hasflagat(l, p, Fblocked|Fhasmonster|Fhasfeature));
293 clear(l, p, 2);
294 several(l, &p, 1, TCAPTAIN, 0);
295 several(l, &p, 1, TLIEUTENANT, 1);
296 addspawn(l, p, TSOLDIER, 37);
297 addspawn(l, p, TSERGEANT, 51);
298 addspawn(l, p, TLIEUTENANT, 97);
299 addspawn(l, p, TCAPTAIN, 131);
300 do{
301 p2 = (Point){nrand(l->width), nrand(l->height)};
302 if(try++ > 10)
303 return -1;
304 }while(!ptinrect(p2, in) || manhattan(p, p2) < DIST || manhattan(p, p2) > DIST*2 || manhattan(p2, l->down) < DIST || manhattan(p2, l->up) < DIST || hasflagat(l, p2, Fblocked|Fhasmonster|Fhasfeature));
305 clear(l, p2, 2);
306 several(l, &p2, 1, TGNOMEKING, 0);
307 several(l, &p2, 1, TGWIZARD, 1);
308 addspawn(l, p2, TGNOME, 11);
309 addspawn(l, p2, TGNOMELORD, 25);
310 addspawn(l, p2, TGWIZARD, 73);
311 addspawn(l, p2, TGNOMEKING, 131);
312
313 /* don't start empty */
314 genmonsters(l, TGNOMELORD, space/128);
254 genmonsters(l, TSERGEANT, space/128);315 genmonsters(l, TSERGEANT, space/128);
255 several(l, &l->down, 1, TCAPTAIN, 0);
256 several(l, &l->down, 1, TLIEUTENANT, 1);
257 addspawn(l, l->down, TSOLDIER, 20);
258 addspawn(l, l->down, TSERGEANT, 40);
259 addspawn(l, l->up, TGWIZARD, 20);
260 break;316 break;
261 case 2:317 case 2:
262 space += drunken(l, TGRAVE, 2, 4, 4);318 space += drunken(l, TGRAVE, 2, 4, 4);
263 clear(l, l->up, 2);319 clear(l, l->up, 2);
264 clear(l, l->down, 2);320 clear(l, l->down, 2);
265 genmonsters(l, TGWIZARD, space/48);321 do{
322 p = (Point){nrand(l->width), nrand(l->height)};
323 if(try++ > 10)
324 return -1;
325 }while(!ptinrect(p, in) || manhattan(p, l->down) < DIST || manhattan(p, l->up) < DIST || hasflagat(l, p, Fblocked|Fhasmonster|Fhasfeature));
326 clear(l, p, 2);
327 addspawn(l, p, TLICH, 31);
328 addspawn(l, p, TGHOST, 5);
329 do{
330 p2 = (Point){nrand(l->width), nrand(l->height)};
331 if(try++ > 10)
332 return -1;
333 }while(!ptinrect(p2, in) || manhattan(p, p2) < DIST*3 || manhattan(p2, l->down) < DIST || manhattan(p2, l->up) < DIST || hasflagat(l, p2, Fblocked|Fhasmonster|Fhasfeature));
334 clear(l, p2, 2);
335 several(l, &p2, 1, TGNOMEKING, 0);
336 several(l, &p2, 1, TGWIZARD, 1);
337 addspawn(l, p2, TGNOME, 11);
338 addspawn(l, p2, TGNOMELORD, 25);
339 addspawn(l, p2, TGWIZARD, 73);
340 addspawn(l, p2, TGNOMEKING, 131);
341
266 genmonsters(l, TGHOST, space/64);342 genmonsters(l, TGHOST, space/64);
267 several(l, &l->down, 1, TLICH, 2);343 genmonsters(l, TGNOME, space/64);
268 clear(l, pdown, 1);
269 addspawn(l, l->up, TGWIZARD, 11);
270 addspawn(l, l->down, TLICH, 61);
271 addspawn(l, l->down, TGHOST, 31);
272 break;344 break;
273 case 3:345 case 3:
274 drunken(l, TLAVA, 2, 1, 1);346 drunken(l, TLAVA, 2, 1, 1);
@@ -294,6 +366,8 @@ gen(Level *l, int type) · 19 unmodified lines
294 }366 }
295 367
296 l->ai = mkstate("level", nil, l, nil, levelexec, nil);368 l->ai = mkstate("level", nil, l, nil, levelexec, nil);
369
370 return 0;
297}371}
298 372
299Level*373Level*
@@ -302,29 +376,34 @@ genlevel(int width, int height, int type) · 2 unmodified lines
302 int x, y;376 int x, y;
303 Level *l;377 Level *l;
304 378
305 l = mallocz(sizeof(Level), 1);379 l = nil;
306 if(l == nil)
307 return nil;
308 380
309 l->width = width;381 do {
310 l->height = height;382 if(l != nil)
311 l->r = Rect(0, 0, width, height);383 freelevel(l);
312 384
313 l->tiles = mallocz(sizeof(Tile) * width * height, 1);385 l = mallocz(sizeof(Level), 1);
314 if(l->tiles == nil)386 if(l == nil)
315 goto err0;387 return nil;
316 388
317 l->flags = mallocz(sizeof(int) * width * height, 1);389 l->width = width;
318 if(l->flags == nil)390 l->height = height;
319 goto err1;391 l->r = Rect(0, 0, width, height);
320 392
321 for(x = 0; x < width; x++){393 l->tiles = mallocz(sizeof(Tile) * width * height, 1);
322 for(y = 0; y < height; y++){394 if(l->tiles == nil)
323 tileat(l, Pt(x, y))->terrain = TFLOOR;395 goto err0;
324 }
325 }
326 396
327 gen(l, type);397 l->flags = mallocz(sizeof(int) * width * height, 1);
398 if(l->flags == nil)
399 goto err1;
400
401 for(x = 0; x < width; x++){
402 for(y = 0; y < height; y++){
403 tileat(l, Pt(x, y))->terrain = TFLOOR;
404 }
405 }
406 } while(gen(l, type) < 0);
328 407
329 return l;408 return l;
330 409
@@ -340,16 +419,23 @@ freelevel(Level *l) · 9 unmodified lines
340{419{
341 int x, y;420 int x, y;
342 Point p;421 Point p;
422 Tile *t;
343 423
344 for(x = 0; x < l->width; x++){424 for(x = 0; x < l->width; x++){
345 for(y = 0; y < l->height; y++){425 for(y = 0; y < l->height; y++){
346 p = (Point){x, y};426 p = (Point){x, y};
427 t = tileat(l, p);
347 if(hasflagat(l, p, Fhasmonster))428 if(hasflagat(l, p, Fhasmonster))
348 mfree(tileat(l, Pt(x, y))->monst);429 mfree(t->monst);
430 if(hasflagat(l, p, Fhasmonster))
431 free(t->portal);
349 }432 }
350 }433 }
351 434
352 free(l->tiles);435 free(l->tiles);
436 free(l->flags);
437 if(l->ai != nil)
438 freestate(l->ai);
353 free(l);439 free(l);
354}440}
355 441
@@ -359,24 +445,3 @@ tileat(Level *l, Point p) · 3 unmodified lines
359 return l->tiles+(p.y*l->width)+p.x;445 return l->tiles+(p.y*l->width)+p.x;
360}446}
361 447
362/* von neumann neighborhood */
363Point*
364lneighbor(Level *l, Point p, int *n)
365{
366 int i, count;
367 Point *neigh, p2, diff[] = { {1, 0}, {0, -1}, {-1, 0}, {0, 1} };
368
369 count = 0;
370 neigh = mallocz(sizeof(Point) * nelem(diff), 1);
371
372 for(i = 0; i < nelem(diff); i++){
373 p2 = addpt(p, diff[i]);
374 if(ptinrect(p2, l->r)){ // && !hasflagat(l, p2, Fblocked)){ //|| hasflagat(l, p2, Fhasmonster))){
375 neigh[count++] = p2;
376 }
377 }
378
379 *n = count;
380 return neigh;
381}
382
monst.c+70−12
@@ -27,7 +27,9 @@ monst(int idx) · 26 unmodified lines
27 m->mvr = md->mvr;27 m->mvr = md->mvr;
28 m->mvp = nrand(m->mvr);28 m->mvp = nrand(m->mvr);
29 m->hp = md->maxhp;29 m->hp = md->maxhp;
30 m->maxhp = md->maxhp;
30 m->ac = md->def;31 m->ac = md->def;
32 m->xpl = md->basexpl;
31 m->md = md;33 m->md = md;
32 34
33 incref(&m->ref);35 incref(&m->ref);
@@ -80,10 +82,14 @@ mupdate(Monster *m) · 46 unmodified lines
80 82
81 /* gain some hp if you aren't dead. */83 /* gain some hp if you aren't dead. */
82 if((m->flags & Mdead) == 0)84 if((m->flags & Mdead) == 0)
83 if(m->hp < m->md->maxhp){85 if(m->hp < m->maxhp){
84 m->hp += (double)m->md->maxhp/100.0;86 /* below half, 2%. above, 0.5%. */
85 if(m->hp > m->md->maxhp)87 if(m->hp < m->maxhp/2)
86 m->hp = m->md->maxhp;88 m->hp += 1.0 + (double)m->maxhp/50.0;
89 else
90 m->hp += (double)m->maxhp/200.0;
91 if(m->hp > m->maxhp)
92 m->hp = m->maxhp;
87 }93 }
88 }94 }
89 95
@@ -116,17 +122,40 @@ mpopstate(Monster *m) · 26 unmodified lines
116 return a;122 return a;
117}123}
118 124
125/* determines what happens when a monster gets some xp */
126static void
127maddxp(Monster *m, long xp)
128{
129 long hpgain, last;
130
131 dbg("%s get %ld xp total %ld next %ld", m->md->name, xp, m->xp, xpcalc(m->xpl));
132
133 last = m->xpl;
134 m->xp += xp;
135 while(m->xp >= xpcalc(m->xpl)){
136 m->xpl++;
137 hpgain = 1 + roll(1, 8);
138 m->maxhp += hpgain;
139 m->hp += hpgain*2;
140 }
141
142 if(m->xpl > last)
143 if(nearyou(m->pt))
144 good("the %s becomes level %d!", m->md->name, m->xpl);
145}
146
119static int147static int
120mattack(Monster *m, Monster *mt)148mattack(Monster *m, Monster *mt)
121{149{
122 int hit, crit, dmg;150 int hit, crit, dmg, xp;
123 hit = roll(1, 100);151 hit = roll(1, 100);
124 if(hit < 10+abs(mt->ac-10)*2){152 if(hit < 10+abs(mt->ac-10)*2){
125 warn("the %s misses the %s!", m->md->name, mt->md->name);153 if(nearyou(m->pt))
154 warn("the %s misses the %s!", m->md->name, mt->md->name);
126 return 0;155 return 0;
127 }156 }
128 157
129 dmg = roll(m->md->atk, m->md->rolls);158 dmg = roll(m->md->rolls, m->md->atk);
130 159
131 if(dmg && mt->ac < 0){160 if(dmg && mt->ac < 0){
132 dmg -= 1+nrand(-mt->ac);161 dmg -= 1+nrand(-mt->ac);
@@ -137,9 +166,11 @@ mattack(Monster *m, Monster *mt) · 4 unmodified lines
137 crit = roll(1, 5);166 crit = roll(1, 5);
138 if(crit == 1){167 if(crit == 1){
139 dmg *= 2;168 dmg *= 2;
140 warn("the %s critically strikes the %s for %d!", m->md->name, mt->md->name, dmg);169 if(nearyou(m->pt))
170 warn("the %s critically strikes the %s for %d!", m->md->name, mt->md->name, dmg);
141 } else {171 } else {
142 warn("the %s hits the %s for %d!", m->md->name, mt->md->name, dmg);172 if(nearyou(m->pt))
173 msg("the %s hits the %s for %d.", m->md->name, mt->md->name, dmg);
143 }174 }
144 175
145 mt->hp -= dmg;176 mt->hp -= dmg;
@@ -148,7 +179,22 @@ mattack(Monster *m, Monster *mt) · 2 unmodified lines
148 mt->hp = 0;179 mt->hp = 0;
149 mt->flags = Mdead;180 mt->flags = Mdead;
150 m->kills++;181 m->kills++;
151 bad("the %s kills the %s!", m->md->name, mt->md->name);182
183 xp = 10+10*pow(mt->xpl, 1.75);
184
185 if(nearyou(m->pt))
186 bad("the %s kills the %s, and gains %ld xp.", m->md->name, mt->md->name, xp);
187
188 /* gain some xp */
189 maddxp(m, xp);
190
191 /* gain 1/4 your target's max hp */
192 if(m->hp < m->maxhp){
193 m->hp += (double)mt->maxhp/4.0;
194 if(m->hp > m->maxhp)
195 m->hp = m->maxhp;
196 }
197
152 return 1;198 return 1;
153 }199 }
154 200
@@ -179,7 +225,7 @@ maction(Monster *m, int what, Point where) · 24 unmodified lines
179 targ->unit = 0;225 targ->unit = 0;
180 }226 }
181 return 0;227 return 0;
182 } else if(!hasflagat(m->l, where, Fblocked)){228 } else if(!hasflagat(m->l, where, Fblocked|Fhasmonster)){
183 /* move */229 /* move */
184 cur = tileat(m->l, m->pt);230 cur = tileat(m->l, m->pt);
185 setflagat(m->l, where, (Fhasmonster));231 setflagat(m->l, where, (Fhasmonster));
@@ -190,6 +236,11 @@ maction(Monster *m, int what, Point where) · 4 unmodified lines
190 cur->monst = nil;236 cur->monst = nil;
191 237
192 m->pt = where;238 m->pt = where;
239
240 if(isyou(m) && hasflagat(m->l, where, Fportal)){
241 warn("you see a %s here.", targ->portal->name);
242 }
243
193 return 1;244 return 1;
194 }245 }
195 break;246 break;
@@ -202,7 +253,7 @@ maction(Monster *m, int what, Point where) · 6 unmodified lines
202 m = cur->monst;253 m = cur->monst;
203 cur->monst = nil;254 cur->monst = nil;
204 if(cur->portal->to == nil){255 if(cur->portal->to == nil){
205 if((cur->portal->to = genlevel(nrand(20)+20, nrand(20)+20, nrand(3)+1)) == nil)256 if((cur->portal->to = genlevel(nrand(20)+50, nrand(20)+10, nrand(3)+1)) == nil)
206 sysfatal("genlevel: %r");257 sysfatal("genlevel: %r");
207 258
208 cur->portal->pt = cur->portal->to->up;259 cur->portal->pt = cur->portal->to->up;
@@ -231,3 +282,10 @@ maction(Monster *m, int what, Point where) · 22 unmodified lines
231 return -1;282 return -1;
232}283}
233 284
285/* return the amount of xp required to gain a level */
286long
287xpcalc(long level)
288{
289 return 20 + (10 * (2*level) * (level+pow(0.95, level)));
290}
291
monstdata.c+22−10
@@ -5,16 +5,28 @@ · 4 unmodified lines
5 5
6#include "dat.h"6#include "dat.h"
7 7
8enum
9{
10 UNALIGNED = 0,
11 GNOME = 50,
12 UNDEAD = -50,
13 HUMAN = -20,
14
15};
16
8MonsterData monstdata[1200] = {17MonsterData monstdata[1200] = {
9 /* name, align, mvr, hp, ac, atk, rolls */18 /* name, xpl,align, mvr, hp, ac, rolls, atk */
10[TLARGECAT] {"large cat", 1, 16, 16, 8, 2, 2},19[TLARGECAT] {"large cat", 0, UNALIGNED, 16, 16, 8, 1, 3},
11[TGWIZARD] {"gnomish wizard", 50, 10, 16, 6, 2, 2},20[TGNOME] {"gnome", 1, GNOME, 6, 16, 10, 1, 6},
12[TLICH] {"lich", -50, 16, 32, -1, 2, 3},21[TGNOMELORD] {"gnome lord", 3, GNOME, 8, 32, 10, 1, 8},
13[TSOLDIER] {"soldier", -20, 12, 8, 8, 2, 2},22[TGWIZARD] {"gnome wizard", 3, GNOME, 10, 32, 4, 1, 6},
14[TSERGEANT] {"sergeant", -20, 12, 16, 6, 5, 1},23[TGNOMEKING] {"gnome king", 5, GNOME, 10, 48, 10, 2, 6},
15[TLIEUTENANT] {"lieutenant", -20, 12, 32, 4, 3, 2},24[TLICH] {"lich", 2, UNDEAD, 6, 32, 3, 3, 2},
16[TCAPTAIN] {"captain", -20, 15, 64, 2, 3, 3},25[TSOLDIER] {"soldier", 6, HUMAN, 10, 16, 10, 1, 8},
17[TGHOST] {"ghost", -50, 6, 8, -10, 2, 1},26[TSERGEANT] {"sergeant", 8, HUMAN, 10, 16, 10, 2, 6},
18[TWIZARD] {"wizard", 20, 16, 64, -1, 2, 4},27[TLIEUTENANT] {"lieutenant", 10, HUMAN, 10, 32, 10, 3, 4},
28[TCAPTAIN] {"captain", 12, HUMAN, 10, 48, 10, 4, 4},
29[TGHOST] {"ghost", 1, UNDEAD, 6, 16, -5, 1, 4},
30[TWIZARD] {"wizard", 0, 127, 14, 64, 5, 2, 3},
19};31};
20 32
path.c+14−13
@@ -45,7 +45,7 @@ pathfind(Level *l, Point start, Point end, Point **path, int not) · 44 unmodified lines
45{45{
46 int i, nneigh, npath;46 int i, nneigh, npath;
47 Point *neighborp, pt;47 Point *neighborp, pt;
48 PNode *nodes, *p, *neighbor, *head, *tmp, *rev;48 PNode *nodes, *p, *neigh, *head, *tmp, *rev;
49 Priq *q;49 Priq *q;
50 50
51 npath = -1;51 npath = -1;
@@ -72,21 +72,22 @@ pathfind(Level *l, Point start, Point end, Point **path, int not) · 20 unmodified lines
72 if(eqpt(p->pt, end))72 if(eqpt(p->pt, end))
73 break;73 break;
74 74
75 neighborp = lneighbor(l, p->pt, &nneigh);75 neighborp = neighbor(l->r, p->pt, &nneigh);
76 shuffle(neighborp, nneigh, sizeof(Point));
76 for(i = 0; i < nneigh; i++){77 for(i = 0; i < nneigh; i++){
77 pt = neighborp[i];78 pt = neighborp[i];
78 neighbor = &nodes[pt.y*l->width + pt.x];79 neigh = &nodes[pt.y*l->width + pt.x];
79 if(eqpt(pt, end) || (flagat(l, pt) & not) == 0)80 if(eqpt(pt, end) || (flagat(l, pt) & not) == 0)
80 if(!neighbor->closed){81 if(!neigh->closed){
81 if(!priqhas(q, neighbor)){82 if(!priqhas(q, neigh)){
82 neighbor->pt = pt;83 neigh->pt = pt;
83 neighbor->G = p->G + ORTHOCOST;84 neigh->G = p->G + ORTHOCOST;
84 neighbor->H = manhattan(pt, end);85 neigh->H = manhattan(pt, end);
85 priqpush(q, neighbor, pnodecmp);86 priqpush(q, neigh, pnodecmp);
86 neighbor->parent = p;87 neigh->parent = p;
87 } else if(p->G + ORTHOCOST < neighbor->G){88 } else if(p->G + ORTHOCOST < neigh->G){
88 neighbor->G = p->G + ORTHOCOST;89 neigh->G = p->G + ORTHOCOST;
89 neighbor->parent = p;90 neigh->parent = p;
90 }91 }
91 }92 }
92 }93 }
ui.c+45−14
@@ -44,20 +44,40 @@ struct Msg · 43 unmodified lines
44typedef struct UI UI;44typedef struct UI UI;
45struct UI45struct UI
46{46{
47 /* current ui size */
47 int uisz;48 int uisz;
49
50 /* colors */
48 Image **cols;51 Image **cols;
52
53 /* mouse, keyboard */
49 Mousectl *mc;54 Mousectl *mc;
50 Keyboardctl *kc;55 Keyboardctl *kc;
56
57 /* log chan */
51 Channel *msgc;58 Channel *msgc;
59
60 /* linked list of current msgs */
52 Msg *msg;61 Msg *msg;
53 int nmsg;62 int nmsg;
63
64 /* tileset */
54 Tileset *tiles;65 Tileset *tiles;
66
67 /* level view rectangle, in tiles */
55 Rectangle viewr;68 Rectangle viewr;
69 /* ui rectangle, in pixels */
56 Rectangle uir;70 Rectangle uir;
57 Point camp;71 Point camp;
58 int autoidle;72
73 /* timer tick, see /^tickproc */
59 Channel *tickcmd;74 Channel *tickcmd;
60 Channel *tick;75 Channel *tick;
76
77 /* should auto-move? */
78 int autoidle;
79 /* show far away messages? */
80 int farmsg;
61} ui;81} ui;
62 82
63 83
@@ -115,7 +135,7 @@ uiinit(char *name) · 51 unmodified lines
115 135
116 proccreate(tickproc, nil, 4096);136 proccreate(tickproc, nil, 4096);
117 137
118 if((ui.msgc = chancreate(sizeof(Msg*), 100)) == nil)138 if((ui.msgc = chancreate(sizeof(Msg*), 1000)) == nil)
119 sysfatal("chancreate: %r");139 sysfatal("chancreate: %r");
120 140
121 tileset = getenv("tileset");141 tileset = getenv("tileset");
@@ -223,8 +243,7 @@ static void · 101 unmodified lines
223drawlevel(Level *l, Tileset *ts, Rectangle r)243drawlevel(Level *l, Tileset *ts, Rectangle r)
224{244{
225 int what;245 int what;
226 ulong maxhp;246 double hp, maxhp;
227 double hp;
228 char buf[16];247 char buf[16];
229 Point p, p2, sp, bot;248 Point p, p2, sp, bot;
230 Image *c;249 Image *c;
@@ -249,10 +268,10 @@ drawlevel(Level *l, Tileset *ts, Rectangle r) · 18 unmodified lines
249 else if(t->feat)268 else if(t->feat)
250 what = t->feat;269 what = t->feat;
251 drawtile(ts, screen, sp, what);270 drawtile(ts, screen, sp, what);
252 if(t->monst != nil && t->monst != player){271 if(t->monst != nil){
253 m = t->monst;272 m = t->monst;
254 hp = m->hp, maxhp = m->md->maxhp;273 hp = m->hp, maxhp = m->maxhp;
255 snprint(buf, sizeof(buf), "%.0f/%lud HP", hp, maxhp);274 snprint(buf, sizeof(buf), "%.0f/%.0f HP", hp, maxhp);
256 if(hp > (maxhp/4)*3)275 if(hp > (maxhp/4)*3)
257 c = ui.cols[CGREEN];276 c = ui.cols[CGREEN];
258 else if(hp > maxhp/2)277 else if(hp > maxhp/2)
@@ -263,6 +282,9 @@ drawlevel(Level *l, Tileset *ts, Rectangle r) · 4 unmodified lines
263 c = ui.cols[CRED];282 c = ui.cols[CRED];
264 p2 = addpt(sp, bot);283 p2 = addpt(sp, bot);
265 string(screen, p2, c, ZP, smallfont, buf);284 string(screen, p2, c, ZP, smallfont, buf);
285 p2.y -= smallfont->height;
286 snprint(buf, sizeof(buf), "L%ld", m->xpl);
287 string(screen, p2, display->white, ZP, smallfont, buf);
266 /* debugging the ai state */288 /* debugging the ai state */
267 if(debug){289 if(debug){
268 if(m->ai != nil){290 if(m->ai != nil){
@@ -281,8 +303,7 @@ static void · 12 unmodified lines
281drawui(Rectangle r)303drawui(Rectangle r)
282{304{
283 int i, logline, sw;305 int i, logline, sw;
284 ulong maxhp;306 double hp, maxhp;
285 double hp;
286 Point p;307 Point p;
287 Image *c;308 Image *c;
288 char buf[256];309 char buf[256];
@@ -322,8 +343,12 @@ drawui(Rectangle r) · 33 unmodified lines
322 p = string(screen, p, display->white, ZP, font, buf);343 p = string(screen, p, display->white, ZP, font, buf);
323 p.x += sw;344 p.x += sw;
324 345
325 hp = player->hp, maxhp = player->md->maxhp;346 snprint(buf, sizeof(buf), "L:%ld XP:%ld/%ld", player->xpl, player->xp, xpcalc(player->xpl));
326 snprint(buf, sizeof(buf), "%.0f/%lud HP", hp, maxhp);347 p = string(screen, p, display->white, ZP, font, buf);
348 p.x += sw;
349
350 hp = player->hp, maxhp = player->maxhp;
351 snprint(buf, sizeof(buf), "HP:%.0f/%.0f", hp, maxhp);
327 if(hp > (maxhp/4)*3)352 if(hp > (maxhp/4)*3)
328 c = ui.cols[CGREEN];353 c = ui.cols[CGREEN];
329 else if(hp > maxhp/2)354 else if(hp > maxhp/2)
@@ -335,7 +360,7 @@ drawui(Rectangle r) · 5 unmodified lines
335 p = string(screen, p, c, ZP, font, buf);360 p = string(screen, p, c, ZP, font, buf);
336 p.x += sw;361 p.x += sw;
337 362
338 snprint(buf, sizeof(buf), "%ld AC", player->ac);363 snprint(buf, sizeof(buf), "AC:%ld", player->ac);
339 p = string(screen, p, display->white, ZP, font, buf);364 p = string(screen, p, display->white, ZP, font, buf);
340 p.x += sw;365 p.x += sw;
341 366
@@ -405,6 +430,9 @@ dbgmenu(int idx, char **s) · 63 unmodified lines
405 case 1:430 case 1:
406 *s = "revive and gain max hp";431 *s = "revive and gain max hp";
407 return 'r';432 return 'r';
433 case 2:
434 *s = "toggle far messages";
435 return 'f';
408 }436 }
409 return Runemax;437 return Runemax;
410}438}
@@ -483,7 +511,7 @@ uiexec(AIState *ai) · 72 unmodified lines
483 if(c == 0x7f)511 if(c == 0x7f)
484 threadexitsall(nil);512 threadexitsall(nil);
485 513
486 if(gameover > 0){514 if(gameover > 0 && gameover++ < 2){
487 bad("you are dead. game over, man.");515 bad("you are dead. game over, man.");
488 }516 }
489 517
@@ -515,12 +543,15 @@ uiexec(AIState *ai) · 25 unmodified lines
515 543
516 incref(&player->ref);544 incref(&player->ref);
517 player->flags &= ~Mdead;545 player->flags &= ~Mdead;
518 player->hp = player->md->maxhp;546 player->hp = player->maxhp;
519 setflagat(player->l, player->pt, Fhasmonster);547 setflagat(player->l, player->pt, Fhasmonster);
520 tileat(player->l, player->pt)->monst = player;548 tileat(player->l, player->pt)->monst = player;
521 tileat(player->l, player->pt)->unit = player->type;549 tileat(player->l, player->pt)->unit = player->type;
522 gameover = 0;550 gameover = 0;
523 break;551 break;
552 case 2:
553 farmsg = !farmsg;
554 break;
524 }555 }
525 redraw(&ui, 0, 0);556 redraw(&ui, 0, 0);
526 continue; 557 continue;