Unified · Split
| @@ -4,6 +4,7 @@ · 3 unmodified lines | ||
| 4 | 4 | #include <thread.h> |
| 5 | 5 | |
| 6 | 6 | #include "dat.h" |
| 7 | +#include "alg.h" | |
| 7 | 8 | |
| 8 | 9 | AIState* |
| 9 | 10 | mkstate(char *name, Monster *m, void *aux, AIFun enter, AIFun exec, AIFun exit) |
| @@ -87,6 +88,7 @@ idleexec(AIState *a) · 77 unmodified lines | ||
| 87 | 88 | ys = c.y - yd; |
| 88 | 89 | |
| 89 | 90 | Point pts[] = { p, Pt(p.x, ys), Pt(xs, p.y), Pt(xs, ys) }; |
| 91 | + shuffle(pts, 4, sizeof(Point)); | |
| 90 | 92 | for(i = 0; i < 4; i++){ |
| 91 | 93 | s = pts[i]; |
| 92 | 94 | if(!ptinrect(s, m->l->r)) |
| @@ -8,6 +8,12 @@ typedef struct MonsterData MonsterData; · 7 unmodified lines | ||
| 8 | 8 | typedef struct Monster Monster; |
| 9 | 9 | typedef struct Camera Camera; |
| 10 | 10 | |
| 11 | +/* sizes */ | |
| 12 | +enum | |
| 13 | +{ | |
| 14 | + SZMONNAME = 32, | |
| 15 | +}; | |
| 16 | + | |
| 11 | 17 | /* hack9.c */ |
| 12 | 18 | extern int debug; |
| 13 | 19 | extern int farmsg; |
| @@ -62,18 +68,20 @@ void drawtile(Tileset *t, Image *dst, Point p, int i); · 48 unmodified lines | ||
| 62 | 68 | |
| 63 | 69 | struct MonsterData |
| 64 | 70 | { |
| 65 | − char *name; | |
| 66 | − uint basexpl; | |
| 71 | + char name[SZMONNAME]; | |
| 72 | + /* offset into tileset */ | |
| 73 | + int tile; | |
| 74 | + | |
| 75 | + /* base experience level */ | |
| 76 | + int basexpl; | |
| 67 | 77 | char align; |
| 68 | − uint mvr; | |
| 69 | − uint maxhp; | |
| 70 | − long def; | |
| 71 | − uint rolls; | |
| 72 | − uint atk; | |
| 78 | + int mvr; | |
| 79 | + int maxhp; | |
| 80 | + int def; | |
| 81 | + int rolls; | |
| 82 | + int atk; | |
| 73 | 83 | }; |
| 74 | 84 | |
| 75 | −extern MonsterData monstdata[1200]; | |
| 76 | − | |
| 77 | 85 | /* possible moves */ |
| 78 | 86 | enum |
| 79 | 87 | { |
| @@ -93,8 +101,6 @@ struct Monster · 13 unmodified lines | ||
| 93 | 101 | { |
| 94 | 102 | /* references */ |
| 95 | 103 | Ref ref; |
| 96 | − /* type */ | |
| 97 | − int type; | |
| 98 | 104 | |
| 99 | 105 | /* current level */ |
| 100 | 106 | Level *l; |
| @@ -105,11 +111,11 @@ struct Monster · 4 unmodified lines | ||
| 105 | 111 | char align; |
| 106 | 112 | |
| 107 | 113 | /* move rate */ |
| 108 | − long mvr; | |
| 114 | + int mvr; | |
| 109 | 115 | /* move points */ |
| 110 | − long mvp; | |
| 116 | + int mvp; | |
| 111 | 117 | /* turn counter */ |
| 112 | − long turns; | |
| 118 | + int turns; | |
| 113 | 119 | |
| 114 | 120 | /* current hp */ |
| 115 | 121 | double hp; |
| @@ -117,15 +123,15 @@ struct Monster · 1 unmodified line | ||
| 117 | 123 | double maxhp; |
| 118 | 124 | |
| 119 | 125 | /* armor class */ |
| 120 | − long ac; | |
| 126 | + int ac; | |
| 121 | 127 | |
| 122 | 128 | /* kill count */ |
| 123 | − long kills; | |
| 129 | + int kills; | |
| 124 | 130 | |
| 125 | 131 | /* experience level */ |
| 126 | − long xpl; | |
| 132 | + int xpl; | |
| 127 | 133 | /* experience gained */ |
| 128 | − long xp; | |
| 134 | + int xp; | |
| 129 | 135 | |
| 130 | 136 | /* flags */ |
| 131 | 137 | u32int flags; |
| @@ -139,15 +145,17 @@ struct Monster · 7 unmodified lines | ||
| 139 | 145 | }; |
| 140 | 146 | |
| 141 | 147 | /* monst.c */ |
| 142 | −Monster *monst(int idx); | |
| 148 | +int monstdbopen(char *file); | |
| 149 | +MonsterData *mdbyname(char *monster); | |
| 150 | +Monster *mbyname(char *monster); | |
| 143 | 151 | void mfree(Monster *m); |
| 144 | 152 | int mupdate(Monster *m); |
| 145 | 153 | void mpushstate(Monster *m, AIState *a); |
| 146 | 154 | AIState *mpopstate(Monster *m); |
| 147 | 155 | int maction(Monster *m, int what, Point where); |
| 148 | −long xpcalc(long level); | |
| 156 | +int xpcalc(int level); | |
| 149 | 157 | |
| 150 | −/* well known tiles, also indexes into monstdata */ | |
| 158 | +/* well known tiles, indexes into tileset */ | |
| 151 | 159 | enum |
| 152 | 160 | { |
| 153 | 161 | /* monsters */ |
| @@ -173,6 +181,7 @@ enum · 19 unmodified lines | ||
| 173 | 181 | TWATER = 860, |
| 174 | 182 | TICE = 861, |
| 175 | 183 | TLAVA = 862, |
| 184 | + TSPAWN = 888, | |
| 176 | 185 | TPORTAL = 891, |
| 177 | 186 | }; |
| 178 | 187 | |
| @@ -190,7 +199,7 @@ struct Spawn · 11 unmodified lines | ||
| 190 | 199 | /* where spawn occurs */ |
| 191 | 200 | Point pt; |
| 192 | 201 | /* what to spawn */ |
| 193 | − int what; | |
| 202 | + char what[SZMONNAME]; | |
| 194 | 203 | /* frequency of spawn, modulo turns */ |
| 195 | 204 | int freq; |
| 196 | 205 | }; |
| @@ -300,6 +309,7 @@ enum · 103 unmodified lines | ||
| 300 | 309 | |
| 301 | 310 | extern Point cardinals[]; |
| 302 | 311 | int roll(int count, int sides); |
| 312 | +int parseroll(char *str, int *count, int *sides); | |
| 303 | 313 | int min(int a, int b); |
| 304 | 314 | int max(int a, int b); |
| 305 | 315 | |
| @@ -107,6 +107,7 @@ usage(void) · 106 unmodified lines | ||
| 107 | 107 | void |
| 108 | 108 | threadmain(int argc, char *argv[]) |
| 109 | 109 | { |
| 110 | + char buf[256]; | |
| 110 | 111 | /* of viewport, in size of tiles */ |
| 111 | 112 | Tile *t; |
| 112 | 113 | Level *level; |
| @@ -129,6 +130,11 @@ threadmain(int argc, char *argv[]) · 16 unmodified lines | ||
| 129 | 130 | |
| 130 | 131 | uiinit(argv0); |
| 131 | 132 | |
| 133 | + snprint(buf, sizeof(buf), "%s/lib/hack9/%s", home, "monster.ndb"); | |
| 134 | + if(monstdbopen(buf) < 0) | |
| 135 | + if(monstdbopen("monster.ndb") < 0) | |
| 136 | + sysfatal("monstdbopen: %r"); | |
| 137 | + | |
| 132 | 138 | /* initial level */ |
| 133 | 139 | if(debug > 0){ |
| 134 | 140 | if((level = genlevel(11, 11, 0)) == nil) |
| @@ -139,7 +145,7 @@ threadmain(int argc, char *argv[]) · 4 unmodified lines | ||
| 139 | 145 | } |
| 140 | 146 | |
| 141 | 147 | /* the player */ |
| 142 | − player = monst(TWIZARD); | |
| 148 | + player = mbyname("wizard"); | |
| 143 | 149 | if(player == nil) |
| 144 | 150 | sysfatal("monst: %r"); |
| 145 | 151 | |
| @@ -108,10 +108,12 @@ redo: · 107 unmodified lines | ||
| 108 | 108 | |
| 109 | 109 | /* create a monster in the idle state */ |
| 110 | 110 | static Monster* |
| 111 | −mkmons(Level *l, Point p, int type) | |
| 111 | +mkmons(Level *l, Point p, char *type) | |
| 112 | 112 | { |
| 113 | 113 | Monster *m; |
| 114 | − m = monst(type); | |
| 114 | + m = mbyname(type); | |
| 115 | + if(m == nil) | |
| 116 | + sysfatal("monstbyname: %r"); | |
| 115 | 117 | m->l = l; |
| 116 | 118 | m->pt = p; |
| 117 | 119 | /* setup ai state */ |
| @@ -121,7 +123,7 @@ mkmons(Level *l, Point p, int type) · 3 unmodified lines | ||
| 121 | 123 | |
| 122 | 124 | /* genmonsters spawns count of type monsters at random places on l. */ |
| 123 | 125 | static void |
| 124 | −genmonsters(Level *l, int type, int count) | |
| 126 | +genmonsters(Level *l, char *type, int count) | |
| 125 | 127 | { |
| 126 | 128 | int i; |
| 127 | 129 | Point p; |
| @@ -133,8 +135,8 @@ genmonsters(Level *l, int type, int count) · 5 unmodified lines | ||
| 133 | 135 | }while(hasflagat(l, p, Fhasmonster|Fhasfeature|Fblocked)); |
| 134 | 136 | |
| 135 | 137 | t = tileat(l, p); |
| 136 | − t->unit = type; | |
| 137 | 138 | t->monst = mkmons(l, p, type); |
| 139 | + t->unit = t->monst->md->tile; | |
| 138 | 140 | setflagat(l, p, Fhasmonster); |
| 139 | 141 | } |
| 140 | 142 | } |
| @@ -147,7 +149,7 @@ genmonsters(Level *l, int type, int count) · 6 unmodified lines | ||
| 147 | 149 | * spawns 13 ghosts centered at p on l. |
| 148 | 150 | */ |
| 149 | 151 | static void |
| 150 | −several(Level *l, Point *p, int count, int type, int r) | |
| 152 | +several(Level *l, Point *p, int count, char *type, int r) | |
| 151 | 153 | { |
| 152 | 154 | int i, j, n; |
| 153 | 155 | Point *neigh; |
| @@ -155,8 +157,8 @@ several(Level *l, Point *p, int count, int type, int r) · 1 unmodified line | ||
| 155 | 157 | for(i = 0; i < count; i++){ |
| 156 | 158 | if(!hasflagat(l, p[i], Fhasmonster|Fblocked)){ |
| 157 | 159 | t = tileat(l, p[i]); |
| 158 | − t->unit = type; | |
| 159 | 160 | t->monst = mkmons(l, p[i], type); |
| 161 | + t->unit = t->monst->md->tile; | |
| 160 | 162 | setflagat(l, p[i], Fhasmonster); |
| 161 | 163 | } |
| 162 | 164 | if(r > 0){ |
| @@ -169,10 +171,18 @@ several(Level *l, Point *p, int count, int type, int r) · 6 unmodified lines | ||
| 169 | 171 | } |
| 170 | 172 | } |
| 171 | 173 | |
| 172 | −static void addspawn(Level *l, Point p, int what, int freq) | |
| 174 | +static void addspawn(Level *l, Point p, char *what, int freq) | |
| 173 | 175 | { |
| 174 | − if(l->nspawns < nelem(l->spawns)-1) | |
| 175 | − l->spawns[l->nspawns++] = (Spawn){p, what, freq}; | |
| 176 | + Spawn sp; | |
| 177 | + | |
| 178 | + if(l->nspawns < nelem(l->spawns)-1){ | |
| 179 | + sp.pt = p; | |
| 180 | + strcpy(sp.what, what); | |
| 181 | + sp.freq = freq; | |
| 182 | + l->spawns[l->nspawns++] = sp; | |
| 183 | + tileat(l, p)->feat = TSPAWN; | |
| 184 | + setflagat(l, p, Fhasfeature); | |
| 185 | + } | |
| 176 | 186 | } |
| 177 | 187 | |
| 178 | 188 | static void |
| @@ -198,9 +208,9 @@ levelexec(AIState *a) · 19 unmodified lines | ||
| 198 | 208 | if(hasflagat(l, np, Fhasmonster)){ |
| 199 | 209 | t = tileat(l, np); |
| 200 | 210 | m = t->monst; |
| 201 | − md = &monstdata[l->spawns[i].what]; | |
| 202 | − if(m->type != l->spawns[i].what && abs(m->align - md->align) > 15){ | |
| 203 | − several(l, &np, 1, l->spawns[i].what, 1); | |
| 211 | + md = mdbyname(l->spawns[i].what); | |
| 212 | + if(strcmp(m->md->name, l->spawns[i].what) != 0 && abs(m->align - md->align) > 15){ | |
| 213 | + several(l, &p, 1, l->spawns[i].what, 2); | |
| 204 | 214 | } |
| 205 | 215 | } |
| 206 | 216 | } |
| @@ -273,8 +283,8 @@ gen(Level *l, int type) · 66 unmodified lines | ||
| 273 | 283 | drunken(l, TTREE, 3, 3, 3); |
| 274 | 284 | clear(l, pup, 1); |
| 275 | 285 | clear(l, pdown, 1); |
| 276 | − several(l, &l->down, 1, TLICH, 1); | |
| 277 | − several(l, &l->down, 1, TGWIZARD, 1); | |
| 286 | + several(l, &l->down, 1, "lich", 1); | |
| 287 | + several(l, &l->down, 1, "gnome wizard", 1); | |
| 278 | 288 | break; |
| 279 | 289 | break; |
| 280 | 290 | case 1: |
| @@ -287,28 +297,28 @@ gen(Level *l, int type) · 6 unmodified lines | ||
| 287 | 297 | return -1; |
| 288 | 298 | }while(!ptinrect(p, in) || manhattan(p, l->down) < DIST || manhattan(p, l->up) < DIST || hasflagat(l, p, Fblocked|Fhasmonster|Fhasfeature)); |
| 289 | 299 | clear(l, p, 2); |
| 290 | − several(l, &p, 1, TCAPTAIN, 0); | |
| 291 | − several(l, &p, 1, TLIEUTENANT, 1); | |
| 292 | − addspawn(l, p, TSOLDIER, 37); | |
| 293 | − addspawn(l, p, TSERGEANT, 51); | |
| 294 | − addspawn(l, p, TLIEUTENANT, 97); | |
| 295 | − addspawn(l, p, TCAPTAIN, 131); | |
| 300 | + several(l, &p, 1, "captain", 0); | |
| 301 | + several(l, &p, 1, "lieutenant", 1); | |
| 302 | + addspawn(l, p, "soldier", 37); | |
| 303 | + addspawn(l, p, "sergeant", 51); | |
| 304 | + addspawn(l, p, "lieutenant", 97); | |
| 305 | + addspawn(l, p, "captain", 131); | |
| 296 | 306 | do{ |
| 297 | 307 | p2 = (Point){nrand(l->width), nrand(l->height)}; |
| 298 | 308 | if(try++ > 10) |
| 299 | 309 | return -1; |
| 300 | 310 | }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)); |
| 301 | 311 | clear(l, p2, 2); |
| 302 | − several(l, &p2, 1, TGNOMEKING, 0); | |
| 303 | − several(l, &p2, 1, TGWIZARD, 1); | |
| 304 | − addspawn(l, p2, TGNOME, 11); | |
| 305 | − addspawn(l, p2, TGNOMELORD, 25); | |
| 306 | − addspawn(l, p2, TGWIZARD, 73); | |
| 307 | − addspawn(l, p2, TGNOMEKING, 131); | |
| 312 | + several(l, &p2, 1, "gnome king", 0); | |
| 313 | + several(l, &p2, 1, "gnome wizard", 1); | |
| 314 | + addspawn(l, p2, "gnome", 11); | |
| 315 | + addspawn(l, p2, "gnome lord", 25); | |
| 316 | + addspawn(l, p2, "gnome wizard", 73); | |
| 317 | + addspawn(l, p2, "gnome king", 131); | |
| 308 | 318 | |
| 309 | 319 | /* don't start empty */ |
| 310 | − genmonsters(l, TGNOMELORD, space/128); | |
| 311 | − genmonsters(l, TSERGEANT, space/128); | |
| 320 | + genmonsters(l, "gnome lord", space/128); | |
| 321 | + genmonsters(l, "sergeant", space/128); | |
| 312 | 322 | break; |
| 313 | 323 | case 2: |
| 314 | 324 | space += drunken(l, TGRAVE, 2, 4, 4); |
| @@ -320,44 +330,41 @@ gen(Level *l, int type) · 5 unmodified lines | ||
| 320 | 330 | return -1; |
| 321 | 331 | }while(!ptinrect(p, in) || manhattan(p, l->down) < DIST || manhattan(p, l->up) < DIST || hasflagat(l, p, Fblocked|Fhasmonster|Fhasfeature)); |
| 322 | 332 | clear(l, p, 2); |
| 323 | − addspawn(l, p, TLICH, 31); | |
| 324 | − addspawn(l, p, TGHOST, 5); | |
| 333 | + addspawn(l, p, "lich", 31); | |
| 334 | + addspawn(l, p, "ghost", 5); | |
| 325 | 335 | do{ |
| 326 | 336 | p2 = (Point){nrand(l->width), nrand(l->height)}; |
| 327 | 337 | if(try++ > 10) |
| 328 | 338 | return -1; |
| 329 | 339 | }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)); |
| 330 | 340 | clear(l, p2, 2); |
| 331 | − several(l, &p2, 1, TGNOMEKING, 0); | |
| 332 | − several(l, &p2, 1, TGWIZARD, 1); | |
| 333 | − addspawn(l, p2, TGNOME, 11); | |
| 334 | − addspawn(l, p2, TGNOMELORD, 25); | |
| 335 | − addspawn(l, p2, TGWIZARD, 73); | |
| 336 | − addspawn(l, p2, TGNOMEKING, 131); | |
| 337 | − | |
| 338 | − genmonsters(l, TGHOST, space/64); | |
| 339 | − genmonsters(l, TGNOME, space/64); | |
| 341 | + several(l, &p2, 1, "gnome king", 0); | |
| 342 | + several(l, &p2, 1, "gnome wizard", 1); | |
| 343 | + addspawn(l, p2, "gnome", 11); | |
| 344 | + addspawn(l, p2, "gnome lord", 25); | |
| 345 | + addspawn(l, p2, "gnome wizard", 37); | |
| 346 | + addspawn(l, p2, "gnome king", 53); | |
| 347 | + | |
| 348 | + genmonsters(l, "ghost", space/64); | |
| 349 | + genmonsters(l, "gnome", space/64); | |
| 340 | 350 | break; |
| 341 | 351 | case 3: |
| 342 | − drunken(l, TLAVA, 2, 1, 1); | |
| 352 | + space += drunken(l, TLAVA, 2, 1, 1); | |
| 343 | 353 | clear(l, pup, 2); |
| 344 | 354 | clear(l, pdown, 2); |
| 345 | 355 | do{ |
| 346 | 356 | p = (Point){nrand(l->width), nrand(l->height)}; |
| 347 | − }while(hasflagat(l, p, Fblocked|Fhasfeature)); | |
| 348 | − addspawn(l, p, TLARGECAT, 11); | |
| 349 | − do{ | |
| 350 | − p = (Point){nrand(l->width), nrand(l->height)}; | |
| 351 | − }while(hasflagat(l, p, Fblocked|Fhasfeature)); | |
| 352 | − addspawn(l, p, TLARGECAT, 13); | |
| 353 | − do{ | |
| 354 | − p = (Point){nrand(l->width), nrand(l->height)}; | |
| 355 | − }while(hasflagat(l, p, Fblocked|Fhasfeature)); | |
| 356 | − addspawn(l, p, TGWIZARD, 9); | |
| 357 | + }while(!ptinrect(p, in) || hasflagat(l, p, Fblocked|Fhasfeature)); | |
| 358 | + clear(l, p, 2); | |
| 359 | + addspawn(l, p, "large cat", 67); | |
| 357 | 360 | do{ |
| 358 | 361 | p = (Point){nrand(l->width), nrand(l->height)}; |
| 359 | − }while(hasflagat(l, p, Fblocked|Fhasfeature)); | |
| 360 | − addspawn(l, p, TGWIZARD, 15); | |
| 362 | + }while(!ptinrect(p, in) || hasflagat(l, p, Fblocked|Fhasfeature)); | |
| 363 | + clear(l, p, 2); | |
| 364 | + addspawn(l, p, "gnome lord", 27); | |
| 365 | + | |
| 366 | + genmonsters(l, "large cat", space/64); | |
| 367 | + genmonsters(l, "gnome lord", space/64); | |
| 361 | 368 | break; |
| 362 | 369 | } |
| 363 | 370 | |
| @@ -11,7 +11,6 @@ OFILES=\ · 10 unmodified lines | ||
| 11 | 11 | hack9.$O\ |
| 12 | 12 | level.$O\ |
| 13 | 13 | monst.$O\ |
| 14 | − monstdata.$O\ | |
| 15 | 14 | path.$O\ |
| 16 | 15 | tile.$O\ |
| 17 | 16 | ui.$O\ |
| @@ -7,7 +7,9 @@ BIN=$home/bin/$objtype · 6 unmodified lines | ||
| 7 | 7 | </sys/src/cmd/mkone |
| 8 | 8 | |
| 9 | 9 | install:V: $BIN/$TARG |
| 10 | − cp nethack.32x32 $home/lib/ | |
| 10 | + mkdir $home/lib/hack9 | |
| 11 | + cp nethack.32x32 $home/lib/hack9 | |
| 12 | + cp monster.ndb $home/lib/hack9 | |
| 11 | 13 | |
| 12 | 14 | $O.alg: algtest.$O alg.$O |
| 13 | 15 | $LD -o $target $prereq |
| @@ -2,27 +2,157 @@ · 1 unmodified line | ||
| 2 | 2 | #include <libc.h> |
| 3 | 3 | #include <draw.h> |
| 4 | 4 | #include <thread.h> |
| 5 | +#include <bio.h> | |
| 6 | +#include <ndb.h> | |
| 5 | 7 | |
| 6 | 8 | #include "dat.h" |
| 7 | 9 | |
| 8 | −Monster* | |
| 9 | −monst(int idx) | |
| 10 | +enum | |
| 11 | +{ | |
| 12 | + MONNAME = 0, | |
| 13 | + MONTILE, | |
| 14 | + MONXPL, | |
| 15 | + MONALIGN, | |
| 16 | + MONMVRATE, | |
| 17 | + MONHP, | |
| 18 | + MONAC, | |
| 19 | + MONATK, | |
| 20 | +}; | |
| 21 | + | |
| 22 | +static char *monstdbcmd[] = { | |
| 23 | +[MONNAME] "monster", | |
| 24 | +[MONTILE] "tile", | |
| 25 | +[MONXPL] "xpl", | |
| 26 | +[MONALIGN] "align", | |
| 27 | +[MONMVRATE] "mvr", | |
| 28 | +[MONHP] "hp", | |
| 29 | +[MONAC] "ac", | |
| 30 | +[MONATK] "atk", | |
| 31 | +}; | |
| 32 | + | |
| 33 | +static Ndb *monstdb; | |
| 34 | + | |
| 35 | +int | |
| 36 | +monstdbopen(char *file) | |
| 37 | +{ | |
| 38 | + monstdb = ndbopen(file); | |
| 39 | + if(monstdb == nil) | |
| 40 | + return 0; | |
| 41 | + return 1; | |
| 42 | +} | |
| 43 | + | |
| 44 | +typedef struct mdcache mdcache; | |
| 45 | +struct mdcache | |
| 10 | 46 | { |
| 11 | − Monster *m; | |
| 12 | 47 | MonsterData *md; |
| 48 | + mdcache *next; | |
| 49 | +}; | |
| 13 | 50 | |
| 14 | − if(idx < 0 || idx > nelem(monstdata)) | |
| 15 | − goto missing; | |
| 51 | +static mdcache *monstcache = nil; | |
| 52 | + | |
| 53 | +/* TODO: sanity checks */ | |
| 54 | +static int | |
| 55 | +mdaddattr(MonsterData *md, int type, char *attr) | |
| 56 | +{ | |
| 57 | + switch(type){ | |
| 58 | + case MONNAME: | |
| 59 | + strncpy(md->name, attr, sizeof(md->name)-1); | |
| 60 | + md->name[sizeof(md->name)-1] = 0; | |
| 61 | + break; | |
| 62 | + case MONTILE: | |
| 63 | + md->tile = atol(attr); | |
| 64 | + case MONXPL: | |
| 65 | + md->basexpl = atol(attr); | |
| 66 | + break; | |
| 67 | + case MONALIGN: | |
| 68 | + md->align = (char)atol(attr); | |
| 69 | + break; | |
| 70 | + case MONMVRATE: | |
| 71 | + md->mvr = atol(attr); | |
| 72 | + break; | |
| 73 | + case MONHP: | |
| 74 | + md->maxhp = atol(attr); | |
| 75 | + break; | |
| 76 | + case MONAC: | |
| 77 | + md->def = atol(attr); | |
| 78 | + break; | |
| 79 | + case MONATK: | |
| 80 | + if(!parseroll(attr, &md->atk, &md->rolls)){ | |
| 81 | + werrstr("bad roll '%s'", attr); | |
| 82 | + return 0; | |
| 83 | + } | |
| 84 | + break; | |
| 85 | + default: | |
| 86 | + return 0; | |
| 87 | + } | |
| 88 | + | |
| 89 | + return 1; | |
| 90 | +} | |
| 91 | + | |
| 92 | +MonsterData* | |
| 93 | +mdbyname(char *monster) | |
| 94 | +{ | |
| 95 | + int i; | |
| 96 | + Ndbtuple *t, *nt; | |
| 97 | + Ndbs search; | |
| 98 | + MonsterData *md; | |
| 99 | + mdcache *mdc; | |
| 100 | + | |
| 101 | + /* cached? */ | |
| 102 | + for(mdc = monstcache; mdc != nil; mdc = mdc->next){ | |
| 103 | + if(strcmp(monster, mdc->md->name) == 0){ | |
| 104 | + return mdc->md; | |
| 105 | + } | |
| 106 | + } | |
| 107 | + | |
| 108 | + t = ndbsearch(monstdb, &search, "monster", monster); | |
| 109 | + if(t == nil) | |
| 110 | + return nil; | |
| 111 | + | |
| 112 | + md = mallocz(sizeof(MonsterData), 1); | |
| 113 | + assert(md != nil); | |
| 114 | + | |
| 115 | + for(nt = t; nt != nil; nt = nt->entry){ | |
| 116 | + for(i = 0; i < nelem(monstdbcmd); i++){ | |
| 117 | + if(strcmp(nt->attr, monstdbcmd[i]) == 0){ | |
| 118 | + if(!mdaddattr(md, i, nt->val)) | |
| 119 | + sysfatal("bad monster value '%s=%s': %r", nt->attr, nt->val); | |
| 120 | + goto okattr; | |
| 121 | + } | |
| 122 | + } | |
| 123 | + sysfatal("unknown monster attribute '%s'", nt->attr); | |
| 124 | +okattr: | |
| 125 | + continue; | |
| 126 | + } | |
| 127 | + | |
| 128 | + mdc = mallocz(sizeof(mdcache), 1); | |
| 129 | + assert(mdc != nil); | |
| 130 | + | |
| 131 | + if(monstcache == nil){ | |
| 132 | + monstcache = mdc; | |
| 133 | + monstcache->md = md; | |
| 134 | + } else { | |
| 135 | + mdc->md = md; | |
| 136 | + mdc->next = monstcache; | |
| 137 | + monstcache = mdc; | |
| 138 | + } | |
| 139 | + | |
| 140 | + return md; | |
| 141 | +} | |
| 142 | + | |
| 143 | +Monster* | |
| 144 | +mbyname(char *monster) | |
| 145 | +{ | |
| 146 | + MonsterData *md; | |
| 147 | + Monster *m; | |
| 16 | 148 | |
| 17 | − md = &monstdata[idx]; | |
| 18 | − if(md->name == nil) | |
| 149 | + md = mdbyname(monster); | |
| 150 | + if(md == nil) | |
| 19 | 151 | goto missing; |
| 20 | 152 | |
| 21 | 153 | m = mallocz(sizeof(Monster), 1); |
| 22 | − if(m == nil) | |
| 23 | − return nil; | |
| 154 | + assert(m != nil); | |
| 24 | 155 | |
| 25 | − m->type = idx; | |
| 26 | 156 | m->align = md->align; |
| 27 | 157 | m->mvr = md->mvr; |
| 28 | 158 | m->mvp = nrand(m->mvr); |
| @@ -30,13 +160,14 @@ monst(int idx) · 1 unmodified line | ||
| 30 | 160 | m->maxhp = md->maxhp; |
| 31 | 161 | m->ac = md->def; |
| 32 | 162 | m->xpl = md->basexpl; |
| 163 | + | |
| 33 | 164 | m->md = md; |
| 34 | 165 | |
| 35 | 166 | incref(&m->ref); |
| 36 | − return m; | |
| 37 | 167 | |
| 168 | + return m; | |
| 38 | 169 | missing: |
| 39 | − werrstr("missing monster %d", idx); | |
| 170 | + werrstr("no data for monster '%s'", monster); | |
| 40 | 171 | return nil; |
| 41 | 172 | } |
| 42 | 173 | |
| @@ -124,9 +255,9 @@ mpopstate(Monster *m) · 81 unmodified lines | ||
| 124 | 255 | |
| 125 | 256 | /* determines what happens when a monster gets some xp */ |
| 126 | 257 | static void |
| 127 | −maddxp(Monster *m, long xp) | |
| 258 | +maddxp(Monster *m, int xp) | |
| 128 | 259 | { |
| 129 | − long hpgain, last; | |
| 260 | + int hpgain, last; | |
| 130 | 261 | |
| 131 | 262 | dbg("%s get %ld xp total %ld next %ld", m->md->name, xp, m->xp, xpcalc(m->xpl)); |
| 132 | 263 | |
| @@ -283,8 +414,8 @@ maction(Monster *m, int what, Point where) · 150 unmodified lines | ||
| 283 | 414 | } |
| 284 | 415 | |
| 285 | 416 | /* return the amount of xp required to gain a level */ |
| 286 | −long | |
| 287 | −xpcalc(long level) | |
| 417 | +int | |
| 418 | +xpcalc(int level) | |
| 288 | 419 | { |
| 289 | 420 | return 20 + (10 * (2*level) * (level+pow(0.95, level))); |
| 290 | 421 | } |
| @@ -1,32 +0,0 @@ | ||
| 1 | −#include <u.h> | |
| 2 | −#include <libc.h> | |
| 3 | −#include <draw.h> | |
| 4 | −#include <thread.h> | |
| 5 | − | |
| 6 | −#include "dat.h" | |
| 7 | − | |
| 8 | −enum | |
| 9 | −{ | |
| 10 | − UNALIGNED = 0, | |
| 11 | − GNOME = 50, | |
| 12 | − UNDEAD = -50, | |
| 13 | − HUMAN = -20, | |
| 14 | − | |
| 15 | −}; | |
| 16 | − | |
| 17 | −MonsterData monstdata[1200] = { | |
| 18 | − /* name, xpl,align, mvr, hp, ac, rolls, atk */ | |
| 19 | −[TLARGECAT] {"large cat", 0, UNALIGNED, 16, 16, 8, 1, 3}, | |
| 20 | −[TGNOME] {"gnome", 1, GNOME, 6, 16, 10, 1, 6}, | |
| 21 | −[TGNOMELORD] {"gnome lord", 3, GNOME, 8, 32, 10, 1, 8}, | |
| 22 | −[TGWIZARD] {"gnome wizard", 3, GNOME, 10, 32, 4, 1, 6}, | |
| 23 | −[TGNOMEKING] {"gnome king", 5, GNOME, 10, 48, 10, 2, 6}, | |
| 24 | −[TLICH] {"lich", 2, UNDEAD, 6, 32, 3, 3, 2}, | |
| 25 | −[TSOLDIER] {"soldier", 6, HUMAN, 10, 16, 10, 1, 8}, | |
| 26 | −[TSERGEANT] {"sergeant", 8, HUMAN, 10, 16, 10, 2, 6}, | |
| 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}, | |
| 31 | −}; | |
| 32 | − | |
| @@ -0,0 +1,35 @@ | ||
| 1 | +# monster database | |
| 2 | + | |
| 3 | +monster="large cat" | |
| 4 | + tile=39 xpl=6 align=0 mvr=15 hp=16 ac=4 atk=2d4 | |
| 5 | + | |
| 6 | +# gnomes | |
| 7 | +monster="gnome" | |
| 8 | + tile=166 xpl=1 align=50 mvr=6 hp=16 ac=10 atk=1d6 | |
| 9 | +monster="gnome lord" | |
| 10 | + tile=167 xpl=3 align=50 mvr=8 hp=32 ac=10 atk=1d8 | |
| 11 | +monster="gnome wizard" | |
| 12 | + tile=168 xpl=3 align=50 mvr=10 hp=32 ac=4 atk=1d6 | |
| 13 | +monster="gnome king" | |
| 14 | + tile=169 xpl=5 align=50 mvr=10 hp=48 ac=10 atk=2d6 | |
| 15 | + | |
| 16 | +# undead | |
| 17 | +monster="lich" | |
| 18 | + tile=185 xpl=2 align=-50 mvr=6 hp=32 ac=3 atk=3d2 | |
| 19 | +monster="ghost" | |
| 20 | + tile=290 xpl=1 align=-50 mvr=6 hp=16 ac=-5 atk=1d4 | |
| 21 | + | |
| 22 | +# military | |
| 23 | +monster="soldier" | |
| 24 | + tile=280 xpl=6 align=-20 mvr=10 hp=16 ac=10 atk=1d8 | |
| 25 | +monster="sergeant" | |
| 26 | + tile=281 xpl=8 align=-20 mvr=10 hp=16 ac=10 atk=2d6 | |
| 27 | +monster="lieutenant" | |
| 28 | + tile=282 xpl=10 align=-20 mvr=10 hp=32 ac=10 atk=3d4 | |
| 29 | +monster="captain" | |
| 30 | + tile=283 xpl=12 align=-20 mvr=10 hp=48 ac=10 atk=4d4 | |
| 31 | + | |
| 32 | +# player | |
| 33 | +monster="wizard" | |
| 34 | + tile=349 xpl=0 align=127 mvr=14 hp=64 ac=5 atk=2d3 | |
| 35 | + | |
| @@ -142,9 +142,9 @@ uiinit(char *name) · 141 unmodified lines | ||
| 142 | 142 | if(tileset == nil) |
| 143 | 143 | tileset = strdup("nethack.32x32"); |
| 144 | 144 | |
| 145 | − snprint(buf, sizeof(buf), "%s/lib/%s", home, tileset); | |
| 146 | − if((ui.tiles = opentile("nethack.32x32", 32, 32)) == nil) | |
| 147 | − if((ui.tiles = opentile(buf, 32, 32)) == nil) | |
| 145 | + snprint(buf, sizeof(buf), "%s/lib/hack9/%s", home, tileset); | |
| 146 | + if((ui.tiles = opentile(buf, 32, 32)) == nil) | |
| 147 | + if((ui.tiles = opentile("nethack.32x32", 32, 32)) == nil) | |
| 148 | 148 | sysfatal("opentile: %r"); |
| 149 | 149 | free(tileset); |
| 150 | 150 | |
| @@ -283,7 +283,7 @@ drawlevel(Level *l, Tileset *ts, Rectangle r) · 132 unmodified lines | ||
| 283 | 283 | p2 = addpt(sp, bot); |
| 284 | 284 | string(screen, p2, c, ZP, smallfont, buf); |
| 285 | 285 | p2.y -= smallfont->height; |
| 286 | − snprint(buf, sizeof(buf), "L%ld", m->xpl); | |
| 286 | + snprint(buf, sizeof(buf), "L%d", m->xpl); | |
| 287 | 287 | string(screen, p2, display->white, ZP, smallfont, buf); |
| 288 | 288 | /* debugging the ai state */ |
| 289 | 289 | if(debug){ |
| @@ -334,7 +334,7 @@ drawui(Rectangle r) · 44 unmodified lines | ||
| 334 | 334 | p = string(screen, p, display->white, ZP, font, buf); |
| 335 | 335 | p.x += sw*2; |
| 336 | 336 | |
| 337 | − snprint(buf, sizeof(buf), "%ld kills", player->kills); | |
| 337 | + snprint(buf, sizeof(buf), "%d kills", player->kills); | |
| 338 | 338 | p = string(screen, p, display->white, ZP, font, buf); |
| 339 | 339 | |
| 340 | 340 | p.x = r.min.x; |
| @@ -343,7 +343,7 @@ drawui(Rectangle r) · 2 unmodified lines | ||
| 343 | 343 | p = string(screen, p, display->white, ZP, font, buf); |
| 344 | 344 | p.x += sw; |
| 345 | 345 | |
| 346 | − snprint(buf, sizeof(buf), "L:%ld XP:%ld/%ld", player->xpl, player->xp, xpcalc(player->xpl)); | |
| 346 | + snprint(buf, sizeof(buf), "L:%d XP:%d/%d", player->xpl, player->xp, xpcalc(player->xpl)); | |
| 347 | 347 | p = string(screen, p, display->white, ZP, font, buf); |
| 348 | 348 | p.x += sw; |
| 349 | 349 | |
| @@ -360,7 +360,7 @@ drawui(Rectangle r) · 10 unmodified lines | ||
| 360 | 360 | p = string(screen, p, c, ZP, font, buf); |
| 361 | 361 | p.x += sw; |
| 362 | 362 | |
| 363 | − snprint(buf, sizeof(buf), "AC:%ld", player->ac); | |
| 363 | + snprint(buf, sizeof(buf), "AC:%d", player->ac); | |
| 364 | 364 | p = string(screen, p, display->white, ZP, font, buf); |
| 365 | 365 | p.x += sw; |
| 366 | 366 | |
| @@ -546,7 +546,7 @@ uiexec(AIState *ai) · 179 unmodified lines | ||
| 546 | 546 | player->hp = player->maxhp; |
| 547 | 547 | setflagat(player->l, player->pt, Fhasmonster); |
| 548 | 548 | tileat(player->l, player->pt)->monst = player; |
| 549 | − tileat(player->l, player->pt)->unit = player->type; | |
| 549 | + tileat(player->l, player->pt)->unit = player->md->tile; | |
| 550 | 550 | gameover = 0; |
| 551 | 551 | break; |
| 552 | 552 | case 2: |
| @@ -19,10 +19,28 @@ roll(int count, int sides) · 18 unmodified lines | ||
| 19 | 19 | int d; |
| 20 | 20 | d = 0; |
| 21 | 21 | while(count--> 0) |
| 22 | − d += 1+nrand(sides); | |
| 22 | + d += 1+lnrand(sides); | |
| 23 | 23 | return d; |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | +int | |
| 27 | +parseroll(char *str, int *count, int *sides) | |
| 28 | +{ | |
| 29 | + int i; | |
| 30 | + char *f[2]; | |
| 31 | + | |
| 32 | + if(str == nil || count == nil || sides == nil) | |
| 33 | + return 0; | |
| 34 | + | |
| 35 | + i = gettokens(str, f, 2, "d"); | |
| 36 | + if(i != 2) | |
| 37 | + return 0; | |
| 38 | + | |
| 39 | + *count = atoi(f[0]); | |
| 40 | + *sides = atoi(f[1]); | |
| 41 | + return 1; | |
| 42 | +} | |
| 43 | + | |
| 26 | 44 | int |
| 27 | 45 | min(int a, int b) |
| 28 | 46 | { |