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