From d51dfa11f9c61fc52ecd681cb0e028dca1b3b643 Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Fri, 9 Sep 2011 23:03:32 +0000 Subject: [PATCH] - [+] make "fear" be used to flee, not attack - [+] CRASH in linkexit() - [+] make most monsters either have sk_perception at least novice. - [+] show success rate when studying scrolls - [+] bug: unable to drink from fountains anymore - [+] always use multidrop - this will free up 'D' - [+] forest tree cluster maps are not working - only a single tree in each cluster! - [+] crash - ghost adding footprint to solid cell! - [+] amberon's wrath for attacking peaceful should happen once per ATTACK, not once per HIT - [+] show cells outside LOS as blue or darkgrey - [+] Don't place normal rooms next to the edge of the map either!! - [+] getradiuscells(scatter) needs an option to include density - [+] then make absolute zero have high density * [+] summoning spells on pentagram will summon a demon instead - [+] "confusion" / "baffle" mental spell - l2 - [+] add 'concussion' injury (head bash) - confusion effect. - [+] iswoozy checks for this. - [+] severed limbs -"frominjury" so taht you can heal them - [+] linkexit() needs to be able to handle making THREE turns: - [+] when looking for turnpos, remember each up/down celll - [+] if we don't find one ("annot find a way to link up") , go through each up/down cell and look left/right - [+] fix is in place. - [+] tested. - [+] bug: doors being placed on top of rock walls!!! think this is related to fix_deadends. - [+] assert statement added. * [+] bug: no up stairs generated on first dungeon map! was being removed by clearcell() for overlapping rooms. - [+] mass stun spell - l4. stuns all in los ? * [+] make "stun" / massstun durations be 2-4 depending on power - [+] "restricted" jobs/races? - [+] don't put shopkeepers in pubs - [+] make a per-map maxvisrange. the deeper you go, the lower this gets (ie . it is darker, less ambientlight) - [+] limit getvisrange(lf) by getmapmaxvisrange() - [+] map->habitat->maxvisrange. set this during createhabitat() - [+] reduce maxvisrange - [+] reduce it to 6 - [+] why can i still see 1 cell? - [+] why can i still always see my own cell? - [+] when in pitch black for a certain amount of time, your vision adjusts to maxrange=1 - [+] ie. getnightvisrange(lf) should be modified by lf->eyeadjustment - [+] reset if you can ever see a lit cell. - [+] when this happens to the player: - [+] msgs about this - [+] also force light recalc - [+] only recalc light when dirty - [+] if we call "haslos()" for a lf and they have losdirty, precalclos first. - [+] vis range problems - [+] sunglasses/footballhelm visrangereduce isn't working anymore - [+] it's reducing maxvisrange(lf). - [+] BUT - my maxvisrange is 5, which is still higher than the ambient range. - [+] need to apply reductions AFTER ambient light - [+] NOW eyeadjustment isn't working. because cell lit is l_temp, not l_notlit. - [+] but if this is the case, why can't i see? anwer: because my visrange has been reduced to 0 due to no ambient light! - [+] so.... how do i make lightt sources override this? - [+] maybe say: if a cell is lit, i can see it, even if it's outside my ambient light. - [+] falling over isn't reducing your visrange anymore - [+] why doesn't eyeadjust make the screen update? - [+] is regular "haslos" code ever used anymore???? - [+] now i can't see lit cells in the darkness again....fixed - [+] after you calm something, give it xpval0 - [+] show message when calm animals fails - [+] check all spell sc_resistmag oskillcheck difficulties - [+] diff should be 20 + (spelllev*2) + power - [+] l1 spell should be diff 20 - [+] l2 should be diff 24 - [+] ... - [+] l7 should be diff 34 - [+] bleeding injuries should make armour "bloodstained" (5% chance per turn) - [+] msgs for "the sun is starting to set" and "the sun is starting to rise" - [+] make 6am, 18pm be constants - [+] add crushed windpipe - lower Fitness, cannot sprint * [+] CRASH when going down stairs! another overlapping room bug i think. - [+] cockatrices and chickens should cluck - [+] canwill param: race:xxx; - [+] define it - [+] use this in "createmonster" - [+] use this in "polymorph" when on self - [+] then remove f_forcepoly - [+] TEST - [+] make playerstart vaults able to appear randomly (just don't place the the "playerstart" object) - [+] redo texttospellopts() to make it more friendly - [+] give a list of what we want as args, rather than passing lots of nulls - [+] "pw:", &localpowervar etc - [+] make "n_lowhp" noisetext happen at END of lf turn - NOT during losehp. - [+] rename turneffectslf() to startlfturn() - [+] show hunger level as a bar in @@ - [+] warn before becoming burdened. - [+] warn when you ARE burdened. at the end of moveob() - [+] l6 - absolute zero (turn everyone around you to ice, freeze all obs, turn ground to ice) - [+] some monsters leave non-meat food behind? - [+] cactus -> cactus juice/fruit - [+] dreamfungus -> sleeping powerder - [+] silver weapons (5% chance on eligible weapons) - [+] hurt vampires - [+] vulnerable to mat??? - then use fromob in losehp() - [+] f_matvuln mt_xxx multiplier - [+] add some silver weapons - [+] f_canbediffmat mt_silver 10% - [+] if f_canbediffmat is true, sometimes change material to this on creation - [+] getobname - if material is differnet, show this - [+] dagger - [+] sword - [+] arrow - [+] bolt - [+] dart - [+] addob should accept 'wantdiffmat' --- ai.c | 4 +- attack.c | 99 ++- data/hiscores.db | Bin 5120 -> 5120 bytes defs.h | 28 +- flag.c | 23 +- io.c | 174 +++- io.h | 2 +- lf.c | 1566 +++++++++++++++++++++--------------- lf.h | 11 +- map.c | 250 ++++-- map.h | 6 +- move.c | 32 +- nexus.c | 35 +- objects.c | 182 +++-- objects.h | 3 +- save.c | 2 + spell.c | 347 +++++--- spell.h | 2 + text.c | 97 ++- text.h | 5 +- vaults/monsterzoo.disabled | 21 + vaults/playerstart1.vlt | 13 +- vaults/playerstart2.vlt | 15 +- vaults/playerstart3.vlt | 1 - vaults/playerstart4.vlt | 1 - vaults/playerstart5.vlt | 21 + vaults/playerstart6.vlt | 23 + vaults/playerstart7.vlt | 26 + 28 files changed, 1961 insertions(+), 1028 deletions(-) create mode 100644 vaults/monsterzoo.disabled create mode 100644 vaults/playerstart5.vlt create mode 100644 vaults/playerstart6.vlt create mode 100644 vaults/playerstart7.vlt diff --git a/ai.c b/ai.c index 2a100c4..0a18937 100644 --- a/ai.c +++ b/ai.c @@ -299,7 +299,7 @@ object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra, int *range) { if (db) dblog(".oO { will zap %s instead of moving }", o->type->name); *ra = RA_WAND; - *range = getvisrange(lf); // ie unlimited + *range = getvisrange(lf, B_TRUE); // ie unlimited return o; } } @@ -1764,7 +1764,7 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG willflag = lfhasflagval(lf, F_CANWILL, ot->id, NA, NA, NULL); if (willflag) { - texttospellopts(f->text, NULL, NULL, NULL, &srange); + texttospellopts(f->text, "range:", &srange, NULL); if (!srange) srange = 5; } // override... diff --git a/attack.c b/attack.c index ed60dd1..744b249 100644 --- a/attack.c +++ b/attack.c @@ -167,6 +167,9 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { int saysorry = B_FALSE; flag_t *retflag[MAXCANDIDATES]; int nretflags = 0; + int attackedhelpless = B_FALSE; + int attackedfriend = B_FALSE; + int attackedpeaceful = B_FALSE; // anyone there? if so just attack. if (c->lf) { @@ -191,10 +194,14 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { // cancel. return B_TRUE; } + attackedpeaceful = B_TRUE; } attacktype = AT_LF; attacktarget = c->lf; + + if (areallies(lf, attacktarget)) attackedfriend = B_TRUE; + if (!cansee(attacktarget, lf) || isfleeing(attacktarget)) attackedhelpless = B_TRUE; } else { object_t *o; // has an impassable object? @@ -429,6 +436,51 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { losehp(lf, 1, DT_DIRECT, NULL, "blood loss"); } + // god effects... + if (attacktype == AT_LF) { + if (attackedfriend) { + angergodmaybe(R_GODMERCY, 100); + angergodmaybe(R_GODPURITY, 100); + switch (getalignment(attacktarget)) { + case AL_EVIL: + angergodmaybe(R_GODDEATH, 20); // even more + break; + case AL_GOOD: + angergodmaybe(R_GODPURITY, 20); // even more + break; + default: + break; + } + } else if (attackedpeaceful) { + angergodmaybe(R_GODMERCY, 50); + angergodmaybe(R_GODPURITY, 50); + switch (getalignment(attacktarget)) { + case AL_EVIL: + angergodmaybe(R_GODDEATH, 20); // even more + break; + case AL_GOOD: + angergodmaybe(R_GODPURITY, 20); // even more + break; + default: + break; + } + } else if (attackedhelpless) { + angergodmaybe(R_GODMERCY, 100); + angergodmaybe(R_GODPURITY, 100); + if (getalignment(attacktarget) != AL_EVIL) { + pleasegodmaybe(R_GODTHIEVES, 5); + pleasegodmaybe(R_GODDEATH, 10); + } + } + if (lfhasflag(lf, F_USEDPOISON)) { + killflagsofid(lf->flags, F_USEDPOISON); + angergodmaybe(R_GODPURITY, 100); + angergodmaybe(R_GODMERCY, 50); + pleasegodmaybe(R_GODDEATH, 3); + } + } + + return B_FALSE; } @@ -444,8 +496,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) int deflected = B_FALSE; int weppassthrough = B_FALSE; int firstisbackstab = B_FALSE; - int attackedhelpless = B_FALSE; - int attackedfriend = B_FALSE; int hit = B_FALSE; int critical = 0; char wepname[BUFLEN]; @@ -656,17 +706,10 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) addflag(victim->flags, F_STABBEDBY, lf->id, NA, NA, NULL); dam[0] *= (getskill(lf, SK_BACKSTAB)); firstisbackstab = B_TRUE; - attackedhelpless = B_TRUE; } } } - if (!cansee(victim, lf)) { - attackedhelpless = B_TRUE; - } - if (areallies(lf, victim)) { - attackedfriend = B_TRUE; - } // extra damage for being skilled? if (wepsk) { slev = getskill(lf, wepsk->id); @@ -929,7 +972,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } else { strcpy(buf, attackername2); } - losehp_real(victim, dam[i], damtype[i], lf, buf, B_FALSE, NULL, B_FALSE); + losehp_real(victim, dam[i], damtype[i], lf, buf, B_FALSE, wep, B_FALSE); // victim's armour loses hp if (reduceamt && !critical) { @@ -1158,38 +1201,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } } - if (isplayer(lf)) { - if (attackedfriend) { - angergodmaybe(R_GODMERCY, 100); - angergodmaybe(R_GODPURITY, 100); - switch (getalignment(victim)) { - case AL_EVIL: - angergodmaybe(R_GODDEATH, 20); // even more - break; - case AL_GOOD: - angergodmaybe(R_GODPURITY, 20); // even more - break; - default: - break; - } - } - if (attackedhelpless) { - angergodmaybe(R_GODMERCY, 100); - angergodmaybe(R_GODPURITY, 100); - if (getalignment(victim) != AL_EVIL) { - pleasegodmaybe(R_GODTHIEVES, 5); - pleasegodmaybe(R_GODDEATH, 10); - } - } - if (lfhasflag(lf, F_USEDPOISON)) { - killflagsofid(lf->flags, F_USEDPOISON); - angergodmaybe(R_GODPURITY, 100); - angergodmaybe(R_GODMERCY, 50); - pleasegodmaybe(R_GODDEATH, 3); - } - - } - if (aidb) dblog(".oO { doattack about to return B_FALSE }"); return B_FALSE; } @@ -1347,7 +1358,7 @@ void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, enum break; case BP_HEAD: if (pctchance(80)) fall(victim, lf, B_TRUE); - stun(victim, 2); + stun(victim, 1); // chance of your helmet falling off o = getarmour(victim, BP_HEAD); if (o) { @@ -2061,7 +2072,7 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical) } limit(&critroll, 1, 100); - if (critroll <= getcritchance(lf, wep)) *critical = 1; + if (critroll <= getcritchance(lf, wep,victim)) *critical = 1; } f = lfhasflag(lf, F_TRUESTRIKE); diff --git a/data/hiscores.db b/data/hiscores.db index f2b2d2c88504a2a8b91b93e2d4d0dd1185eab67b..63fddadab0fffb0aa1a85124b0084d62430a0ffe 100644 GIT binary patch delta 676 zcmZqBXwaA-&FjK|1U72iVCG{53NSMN1_`q;|DMdpBB@}&$i{G=VH-m~Ln?zEP+Uuj zje$v6QB{nMfl*l2m~-+2HgT)${G|Mx6g>@5kesYJLr+nDl24hDf^U9aws&SuPHKum zQl&ytPJVuhLQZ~hv7V|3L^~Hqy8u+Xx-eMK+yW$MS)84klUkCWr>80eQ5%WX&_o58 z<$_>kmW&|X!sUrY3K{vOc`15U0$}l2HjubXN@99?YLS9QNk&nAc^=4BFatF8Hs`SR zGw}fZ$STGKBqf+THnVfIGEZK>Eh!+(!py)Z1R?}Mguvvj+}=FAKvhi4n;4jHFmKw- z!?TPzR7C<50`j^H^P!G)DJsoOK?FgfLPcVUo|-twN%F>gU`2)s7>b}?0+}zyU^kha RMFArofKnhZOygk+698YVs2KnN delta 231 zcmZqBXwaA-&1=m70W3g@X`{vsWO8KDn{x!GFtKxi zB$>BvX6I;S7LZ|KW?+;C5mF#Ra&iZ^?Bt!??mQ4985n^y>t-IFWz3V8u*!1j^RO{6 z39DN(9G$#|Pg){RA+@3)C%-r|KTi*2Clm8x2Ifo5i#I!RxHC^|2(Z+Z0jXEEX3{Cj zPx2` #include #include #include @@ -252,7 +253,8 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, lifeform_t *l; for (l = where->map->lf ; l ; l = l->next) { if (haslos(l, where)) { - precalclos(l); + setlosdirty(l); + //precalclos(l); if (isplayer(l)) { redrawscreenatend = B_TRUE; } @@ -288,7 +290,8 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, //dblog("CALCINGLIGHT from flag\n"); redrawscreenatend = B_TRUE; calclight(redolight); - precalclos(player); + setlosdirty(player); + //precalclos(player); } //dblog("DRAWINGSCREEN from flag\n"); @@ -355,7 +358,11 @@ int flagcausesloscalc(enum FLAG fid) { case F_ASLEEP: case F_BLIND: case F_BLOCKSVIEW: + case F_NIGHTVISRANGEMOD: case F_PRONE: + case F_SEEINDARK: + case F_VISRANGE: + case F_VISRANGEMOD: return B_TRUE; default: break; } @@ -411,6 +418,7 @@ int flagcausesstatredraw(lifeform_t *lf, enum FLAG fid) { case F_ASLEEP: case F_ATTRMOD: case F_BLIND: + case F_CONFUSED: case F_EATING: case F_FASTMOVE: case F_FLYING: @@ -831,14 +839,16 @@ void killflag(flag_t *f) { // - if it was an object flag, then everyone who can see // its cell recalcs their los. if (f->pile->owner) { - precalclos(f->pile->owner); + setlosdirty(f->pile->owner); + //precalclos(f->pile->owner); if (isplayer(f->pile->owner)) redoscreen = B_TRUE; } else { // everyone who can see this cell recalcs their los lifeform_t *l; for (l = redolos->map->lf ; l ; l = l->next) { if (haslos(l, redolos)) { - precalclos(l); + setlosdirty(l); + //precalclos(l); if (isplayer(l)) redoscreen = B_TRUE; } } @@ -846,7 +856,8 @@ void killflag(flag_t *f) { } if (redolight) { calclight(redolight); - precalclos(player); + setlosdirty(player); + //precalclos(player); needredraw = B_TRUE; } if (redoscreen) { @@ -1123,6 +1134,8 @@ int getflags(flagpile_t *fp, flag_t **retflag, int *nretflags, ... ) { } va_end(flags); + assert(nwantflags < MAXCANDIDATES); + // now populate retflag[] with matches flags *nretflags = 0; for (i = 0; i < nwantflags; i++) { diff --git a/io.c b/io.c index 44b4d02..1f9ca9c 100644 --- a/io.c +++ b/io.c @@ -42,6 +42,8 @@ extern enum ERROR reason; extern char msghist[MAXHISTORY][BUFLEN]; extern int nmsghist; +extern void (*precalclos)(lifeform_t *); + extern lifeform_t *godlf[]; extern int ngodlfs; @@ -675,7 +677,7 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src } // need a certain amount of iq to recognise drunkenness - f = isdrunk(c->lf); + f = lfhasflag(c->lf, F_DRUNK); if (f && (iqb >= AT_LTAVERAGE)) { if (strlen(extrainfo)) strcat(extrainfo, ", "); strcat(extrainfo, getdrunktext(f)); @@ -1240,6 +1242,14 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_CONFUSED: + if (isplayer(lf)) { + msg("^WYou feel woozy..."); + } else { + msg("^%c%s looks woozy...", lfname, getlfcol(lf, CC_BAD)); + } + donesomething = B_TRUE; + break; case F_DEAF: if (isplayer(lf)) { msg("^WYou cannot hear anything!"); @@ -1786,6 +1796,14 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_CONFUSED: + if (isplayer(lf)) { + msg("You feel more steady now."); + } else { + msg("%s looks more steady.", lfname); + } + donesomething = B_TRUE; + break; case F_DEAF: if (isplayer(lf)) { msg("Your hearing returns."); @@ -2595,6 +2613,7 @@ int askobjectmulti(obpile_t *op, char *prompt, long opts) { int selcount[MAXPILEOBS+1]; char myletters[MAXPILEOBS+1]; char numstring[BUFLEN]; + char pbuf[BUFLEN]; int firstob = 0; int nextpage = -1; int lastline = SCREENH-4; @@ -2669,8 +2688,8 @@ int askobjectmulti(obpile_t *op, char *prompt, long opts) { finished = B_FALSE; strcpy(numstring, ""); while (!finished) { - int y; - int ch; + int y,n,ch,nselected = 0; + float selweight = 0; cls(); @@ -2684,18 +2703,43 @@ int askobjectmulti(obpile_t *op, char *prompt, long opts) { } else { nextpage = i; } + + // count selected items + for (n = 0 ; (mylist[n] != NULL) ; n++) { + if (selected[n]) { + int thiscount; + nselected++; + if (selcount[n] == ALL) thiscount = mylist[n]->amt; + else thiscount = selcount[n]; + selweight += (getobunitweight(mylist[n]) * thiscount); + } + } // draw prompt if (nextpage != -1) { mvwprintw(mainwin, y, 0, MORESTRING); } if (strlen(numstring) > 0) { - mvwprintw(mainwin, 0, 0, "%s (%s','=all, ESC to quit) [%s]: ",prompt, + snprintf(pbuf, BUFLEN,"%s (%s','=all, ESC to quit) [%s]: ",prompt, (opts & AO_INCLUDENOTHING) ? "- for nothing, " : "", numstring); } else { - mvwprintw(mainwin, 0, 0, "%s (%sESC to quit): ", prompt, + snprintf(pbuf, BUFLEN,"%s (%sESC to quit): ", prompt, (opts & AO_INCLUDENOTHING) ? "- for nothing, " : ""); } + + // show how many items we've picked, and how much they weigh + if (nselected) { + char wbuf[BUFLEN]; + char selbuf[BUFLEN]; + getweighttext(selweight, wbuf, B_TRUE); + sprintf(selbuf, " (%d ob%s, ", nselected, (nselected > 1) ? "s" : ""); + strcat(selbuf, wbuf); + strcat(selbuf, ")"); + strcat(pbuf, selbuf); + } + + mvwprintw(mainwin, 0, 0, "%s", pbuf); + // update screen wrefresh(mainwin); // wait for keypess @@ -2742,7 +2786,7 @@ int askobjectmulti(obpile_t *op, char *prompt, long opts) { selected[i] = val; if (val == B_TRUE) { selcount[i] = count; - if (selcount[i] > mylist[i]->amt) selcount[i] = ALL; + if (selcount[i] > mylist[i]->amt) selcount[i] = mylist[i]->amt; } else { selcount[i] = 0; } @@ -3102,14 +3146,14 @@ void describeob(object_t *o) { if (o->amt == 1) { char wbuf[BUFLEN]; - getweighttext(getobweight(o), wbuf); + getweighttext(getobweight(o), wbuf, B_FALSE); snprintf(buf2, BUFLEN, "and weighs %s.",wbuf); strcat(buf, buf2); } else { char wbuf[BUFLEN]; char wbuf2[BUFLEN]; - getweighttext(getobweight(o), wbuf); - getweighttext(getobunitweight(o), wbuf2); + getweighttext(getobweight(o), wbuf, B_FALSE); + getweighttext(getobunitweight(o), wbuf2, B_FALSE); snprintf(buf2, BUFLEN, "and weigh %s (%s each).",wbuf, wbuf2); strcat(buf, buf2); } @@ -3277,7 +3321,7 @@ void describeob(object_t *o) { mvwprintw(mainwin, y, 0, " Its attack delay is %d%%.",delay - 100); y++; - critchance = getcritchance(player, o); + critchance = getcritchance(player, o, NULL); if (critchance > 0) { mvwprintw(mainwin, y, 0, " You have a %d%% critical hit chance with it.", critchance); y++; @@ -4938,7 +4982,7 @@ void dolook(cell_t *where, int onpurpose) { // if wantunknown is set, lsit spells we DONT know. // otherwise list spells we DO know. // only include spells which cost <= mpcutoff -void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2, enum SPELLSCHOOL wantschool, int wantunknown, int wantinvalid, int mpcutoff) { +void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2, enum SPELLSCHOOL wantschool, int wantunknown, int wantlowmp, int wanttoohard, int mpcutoff) { char ch; flag_t *f; char buf[BUFLEN]; @@ -4948,6 +4992,7 @@ void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2, int mpcost[MAXCANDIDATES]; char mpdesc[MAXCANDIDATES][BUFLEN]; int validspell[MAXCANDIDATES]; + int err[MAXCANDIDATES]; // will be e_ok, e_notready, e_toopowerful, e_nomp int deactspell[MAXCANDIDATES]; int nposs = 0; int i,n,lev; @@ -4979,13 +5024,16 @@ void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2, if (f->val[2] == NA) { snprintf(mpdesc[nposs], BUFLEN, "(ready)"); validspell[nposs] = B_TRUE; + err[nposs] = E_OK; } else { if (f->val[1] == f->val[2]) { snprintf(mpdesc[nposs], BUFLEN, "(ready)"); validspell[nposs] = B_TRUE; + err[nposs] = E_OK; } else { snprintf(mpdesc[nposs], BUFLEN, "(%d/%d)",f->val[1],f->val[2]); validspell[nposs] = B_FALSE; + err[nposs] = E_TOOPOWERFUL; } } @@ -5039,12 +5087,15 @@ void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2, } if (mpcost[nposs] <= mpcutoff) { validspell[nposs] = B_TRUE; + err[nposs] = E_OK; } else { validspell[nposs] = B_FALSE; + err[nposs] = E_NOMP; } } else { snprintf(mpdesc[nposs], BUFLEN, "(too hard)"); validspell[nposs] = B_FALSE; + err[nposs] = E_TOOPOWERFUL; } nposs++; } @@ -5070,6 +5121,7 @@ void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2, lastschool = SS_LAST; for (i = 0; i < nposs; i++) { + int addit = B_FALSE; int power; enum SPELLSCHOOL thisschool = SS_NONE; ot = findot(poss[i]); @@ -5099,7 +5151,15 @@ void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2, strcat(costbuf, mpdesc[i]); snprintf(buf, BUFLEN, "%-30s%s", buf2, costbuf); - if (wantinvalid || validspell[i]) { + if (validspell[i]) { + addit = B_TRUE; + } else if ((err[i] == E_NOMP) && wantlowmp) { + addit = B_TRUE; + } else if ((err[i] == E_TOOPOWERFUL) && wanttoohard) { + addit = B_TRUE; + } + + if (addit) { // letter doesn't matter addchoice(pr, 'a', buf2, buf, ot); } @@ -5113,7 +5173,7 @@ void domagic(enum OBTYPE spellid, int cellx, int celly) { // init the prompt if required. if (spellid == OT_NONE) { - makespellchoicelist(&prompt, player, "Use which spell/ability:","Describe which spell/ability:", SS_NONE, B_FALSE, B_TRUE, player->mp); + makespellchoicelist(&prompt, player, "Use which spell/ability:","Describe which spell/ability:", SS_NONE, B_FALSE, B_TRUE, B_FALSE, player->mp); } finished = B_FALSE; @@ -5181,7 +5241,7 @@ void domemmagic(void) { char ch; int slot; objecttype_t *ot; - makespellchoicelist(&prompt, player, "Memorise which spell/ability:","Describe which spell/ability",SS_NONE, B_FALSE, B_TRUE, player->maxmp); + makespellchoicelist(&prompt, player, "Memorise which spell/ability:","Describe which spell/ability",SS_NONE, B_FALSE, B_TRUE, B_TRUE, player->maxmp); if (prompt.nchoices <= 0) { msg("You don't have any spells or abilities!"); return; @@ -5327,7 +5387,9 @@ int dopickup(obpile_t *op, int forceask) { } for (i = 0; i < nretobs; i++) { - pickup(player, retobs[i],retobscount[i], B_TRUE, B_TRUE); + if (pickup(player, retobs[i],retobscount[i], B_TRUE, B_TRUE)) { + break; + } } /* @@ -5515,9 +5577,9 @@ void doinventory(obpile_t *op) { void doquaff(obpile_t *op) { object_t *o,*liquid = NULL; - // quaffable objects here? + // quaffable objects here? (don't need to be able to pick them up) for (o = player->cell->obpile->first; o ; o = o->next) { - if (isdrinkable(o) && canquaff(player, o) && canpickup(player, o, 1)) { + if (isdrinkable(o) && canquaff(player, o) ) { char obname[BUFLEN]; char buf[BUFLEN]; char ch; @@ -6023,6 +6085,10 @@ void drawlevelfor(lifeform_t *lf) { return; } + if ((gamemode == GM_GAMESTARTED) && isplayer(lf) && lf->losdirty) { + precalclos(player); + } + //dbtimestart("drawscreen"); map = lf->cell->map; @@ -6136,6 +6202,7 @@ void initgfx(void) { init_pair(C_BOLDMAGENTA, COLOR_MAGENTA, COLOR_BLACK); init_pair(C_BOLDGREEN, COLOR_GREEN, COLOR_BLACK); init_pair(C_ORANGE, COLOR_RED, COLOR_BLACK); + init_pair(C_DARKGREY, COLOR_BLACK, COLOR_BLACK); init_pair(BLUEBG+C_BLACK, COLOR_BLACK, COLOR_BLUE); @@ -7033,10 +7100,8 @@ void handleinput(void) { case 'e': // eat doeat(player->pack); break; - case 'd': // drop - dodrop(player->pack, B_SINGLE, player->cell->obpile); - break; - case 'D': // drop multiple things + case 'd': // drop multiple things + //dodrop(player->pack, B_SINGLE, player->cell->obpile); dodrop(player->pack, B_MULTIPLE, player->cell->obpile); break; case 'W': // wear @@ -7296,6 +7361,7 @@ int needsbold(enum COLOUR col) { case C_BOLDMAGENTA: case C_BOLDGREEN: case C_ORANGE: + case C_DARKGREY: return B_TRUE; default: break; @@ -7418,6 +7484,12 @@ void drawstatus(void) { } } + if (iswoozy(player)) { + setcol(statwin, C_YELLOW); + wprintw(statwin, " Woozy"); + unsetcol(statwin, C_YELLOW); + } + // paralysed somehow? if (isresting(player)) { setcol(statwin, C_CYAN); @@ -7515,7 +7587,7 @@ void drawstatus(void) { } // show certain flags - f = isdrunk(player); + f = lfhasflag(player, F_DRUNK); if (f) { char dstring[BUFLEN]; strcpy(dstring, getdrunktext(f)); @@ -7987,7 +8059,7 @@ void showlfstats(lifeform_t *lf, int showall) { float w; w = getlfweight(lf, B_NOOBS); doheadingsmall(mainwin, y, 0, ftext, "Weight"); - getweighttext(w, buf); + getweighttext(w, buf, B_FALSE); wprintw(mainwin, buf, w); y++; } @@ -8340,11 +8412,35 @@ void showlfstats(lifeform_t *lf, int showall) { if (showall) { f = hasflag(lf->flags, F_HUNGER); if (f) { + int i; + char hungerbar[10]; + float pct; + enum COLOUR col; doheadingsmall(mainwin, y2, x2, ftext, "Hunger"); - gethungername(lf, gethungerlevel(f->val[0]), buf); + // select colour for hungerbar + // hunger can be from -(const*2) up to (const*5) + pct = (((float)f->val[0] + (float)(HUNGERCONST*2)) / ((float)HUNGERCONST*7.0)) * 100; + limitf(&pct, 0, 100); + pct = 100 - pct; + col = gethungercol(gethungerlevel(f->val[0])); + // construct hungerbar + for (i = 0; i < 10; i++) { + if (pct >= (i*10)) { + hungerbar[i] = '*'; + } else { + hungerbar[i] = '.'; + } + } + + //gethungername(lf, gethungerlevel(f->val[0]), buf); capitalise(buf); - wprintw(mainwin, "%-14s", buf); y2++; + wprintw(mainwin, "["); + setcol(mainwin, col); + wprintw(mainwin, "%s", hungerbar); + unsetcol(mainwin, col); + wprintw(mainwin, "]"); + y2++; /* if (showall) { wprintw(mainwin, "%-14s (%d)", buf, f->val[0]); y++; @@ -8731,7 +8827,6 @@ void showlfstats(lifeform_t *lf, int showall) { wrapprint(mainwin, &y, &x, buf); } } - } else if (mode == 'a') { centre(mainwin, C_WHITE, 0, "ABILITIES"); y = 2; @@ -8741,7 +8836,7 @@ void showlfstats(lifeform_t *lf, int showall) { f = lfhasknownflagval(lf, F_CANWILL, ot->id, NA, NA, NULL); if (f && (f->known)) { char expirebuf[BUFLEN]; - char eb2[BUFLEN]; + char eb2[BUFLEN],racestr[BUFLEN]; int needgrab = B_FALSE; int range; @@ -8753,7 +8848,7 @@ void showlfstats(lifeform_t *lf, int showall) { } // extra options? - texttospellopts(f->text, NULL, NULL, &needgrab, &range); + texttospellopts(f->text, "needgrab:", &needgrab, "range:", &range, "race:", racestr, NULL); if (needgrab) { strcat(expirebuf, ",after grab"); } @@ -8762,6 +8857,11 @@ void showlfstats(lifeform_t *lf, int showall) { snprintf(rbuf, BUFLEN, ",range:%d",range); strcat(expirebuf, rbuf); } + if (strlen(racestr)) { + char rbuf[BUFLEN]; + snprintf(rbuf, BUFLEN, ",race:%s",racestr); + strcat(expirebuf, rbuf); + } if (strlen(expirebuf)) { snprintf(eb2, BUFLEN,"(%s)",expirebuf); @@ -9066,6 +9166,11 @@ void showlfstats(lifeform_t *lf, int showall) { mvwprintw(mainwin, y, 0, "%s can control teleportation and polymorphic effects.", you(lf)); y++; } + f = lfhasknownflag(lf, F_CONFUSED); + if (f) { + mvwprintw(mainwin, y, 0, "%s %s confused.", you(lf), is(lf)); + y++; + } f = lfhasknownflag(lf, F_DEAF); if (f) { mvwprintw(mainwin, y, 0, "%s %s deaf.", you(lf), is(lf)); @@ -9301,7 +9406,7 @@ void showlfstats(lifeform_t *lf, int showall) { f = lfhasflag(lf, F_PAIN); if (f && (f->known)) { - if (isdrunk(lf)) { + if (lfhasflag(lf, F_DRUNK)) { mvwprintw(mainwin, y, 0, "%s %s in extreme pain, somewhat mitigated by %s inebriation.", you(lf), is(lf), isplayer(lf) ? "your" : "its"); } else { mvwprintw(mainwin, y, 0, "%s %s in extreme pain, and movement will cause %s damage.", you(lf), is(lf), isplayer(lf) ? "you" : "it"); @@ -9426,6 +9531,17 @@ void showlfstats(lifeform_t *lf, int showall) { y++; } } + + // material vulnerbilities + getflags(lf->flags, retflag, &nretflags, F_MATVULN, F_NONE); + for (i = 0; i < nretflags; i++) { + material_t *mt; + mt = findmaterial(retflag[i]->val[0]); + + sprintf(buf, "%s take%s %d%% damage from weapons made of %s.", you(lf), + isplayer(lf) ? "" : "s", retflag[i]->val[1], mt->name); + mvwprintw(mainwin, y, 0, buf); y++; + } } else if (mode == 'i') { object_t *o; cls(); diff --git a/io.h b/io.h index db32fba..6a46a49 100644 --- a/io.h +++ b/io.h @@ -92,7 +92,7 @@ void initgfx(void); void initprompt(prompt_t *p, char *q1); int keycodetokey(int keycode); void listobs(WINDOW *win, object_t **mylist, int *sellist, int *selcount, int firstob, int *counter, int lastline, int *y, char *myletters, int forpickup, int showpoints); -void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2, enum SPELLSCHOOL wantschool, int wantunknown, int wantinvalid, int mpcutoff); +void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2, enum SPELLSCHOOL wantschool, int wantunknown, int wantlowmp, int wanttoohard,int mpcutoff); void more(void); void warn(char *format, ... ); void msg(char *format, ... ); diff --git a/lf.c b/lf.c index 48b9d8f..4661078 100644 --- a/lf.c +++ b/lf.c @@ -371,7 +371,7 @@ int calcxp(lifeform_t *lf) { break; } // get dam from text - texttospellopts(f->text, NULL, damstr, &needgrab, NULL); + texttospellopts(f->text, "dam:", damstr, "needgrab:", &needgrab, NULL ); if (strlen(damstr)) { int dice,sides,mod,min,max; float thisavg; @@ -495,7 +495,7 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) { int needgrab = B_FALSE; // get canwill opts - texttospellopts(f->text, NULL, NULL, &needgrab, NULL); + texttospellopts(f->text, "needgrab:", &needgrab, NULL); // no mp cost. if (mpcost) *mpcost = 0; @@ -1376,19 +1376,32 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar } int celllitfor(lifeform_t *lf, cell_t *c, int maxvisrange, int nightvisrange) { + int dist; + //int ambientvis; + dist = getcelldist(lf->cell, c); // too far away if (maxvisrange != UNLIMITED) { - if (getcelldist(lf->cell, c) > maxvisrange) { - return B_FALSE; + if (dist > maxvisrange) { + // if it's lit and within our non-ambient-adjusted visrange, it's still ok + if (islit(c) && (dist <= getvisrange(lf, B_FALSE))) return B_TRUE; + else return B_FALSE; } } + // outside ambient light range and beyond nightvis range + /* + ambientvis = getmapmaxvisrange(c->map); + if ((ambientvis == 0) || (dist > ambientvis)) { + if (dist >= nightvisrange) { + return B_FALSE; + } + } + */ + // outside the range of our light, and not lit - if (nightvisrange != UNLIMITED) { - if (getcelldist(lf->cell, c) > nightvisrange) { - if (!islit(c)) { - return B_FALSE; - } + if ((nightvisrange != UNLIMITED) && !islit(c)) { + if (dist > nightvisrange) { + return B_FALSE; } else { // inside our nightvis range and magically dark if (c->lit == L_PERMDARK) { @@ -1631,6 +1644,17 @@ float comparelfs(lifeform_t *lf1, lifeform_t *lf2) { return ratio; } +int confuse(lifeform_t *lf, int howlong) { + flag_t *f; + f = lfhasflag(lf, F_CONFUSED); + if (f) { + if (f->lifetime > 0) f->lifetime += howlong; + } else { + addtempflag(lf->flags, F_CONFUSED, B_TRUE, NA, NA, NULL, howlong); + } + return B_FALSE; +} + int countinnateattacks(lifeform_t *lf) { int count = 0,i; flag_t *f; @@ -2362,6 +2386,47 @@ int digup(lifeform_t *lf, object_t *o) { return B_FALSE; } +void do_eyesight_adjust(lifeform_t *lf) { + int i,nlitcells = 0; + int preea; + + if (isplayer(lf)) { + dblog("x"); + } + + // any lit cells within los? + for (i = 0; i < lf->nlos; i++) { + if (lf->los[i]->lit) { + nlitcells++; + } + } + + preea = lf->eyeadjustment; + if (nlitcells) { + // if you could see any lit cells, you lose your eyeadjustment for nightvision + if (lf->eyeadjustment/10) { + lf->eyeadjustment = 0; + if (isplayer(lf)) msg("The light causes you to lose your natural night sight."); + setlosdirty(lf); + //precalclos(lf); + } + } else { + if ((lf->cell->lit == L_NOTLIT) && (lf->eyeadjustment < MAX_EYEADJ)) { + // your eyes start to adjust... + lf->eyeadjustment++; + if (isplayer(lf) && (lf->eyeadjustment/10) > (preea/10)) { + if (preea/10) { + msg("Your eyes have fully adjusted to the darkness."); + } else { + msg("Your eyes are starting to adjust to the darkness."); + } + } + setlosdirty(lf); + //precalclos(lf); + } + } +} + // dump which level random things will appear at void dumplev(void) { int i; @@ -2378,7 +2443,7 @@ void dumplev(void) { fprintf(logfile, "Dlev %d (rar >= %d): ",i,min); for (r = firstrace ; r; r = r->next) { int rarity = 0; - f = hasflag(r->flags, F_RARITY); + f = hasflagval(r->flags, F_RARITY, H_DUNGEON, NA, NA, NULL); if (f) { rarity = f->val[1]; // ok this lev? @@ -2415,7 +2480,7 @@ void dumplev(void) { fprintf(logfile, "Dlev %d (rar >= %d): ",i,min); for (ot = objecttype ; ot; ot = ot->next) { int rarity = 0; - f = hasflag(ot->flags, F_RARITY); + f = hasflagval(ot->flags, F_RARITY, H_DUNGEON, NA, NA, NULL); if (f) { rarity = f->val[1]; // ok this lev? @@ -2741,6 +2806,26 @@ int eat(lifeform_t *lf, object_t *o) { return B_FALSE; } + +// end of turn effects +void endlfturn(lifeform_t *lf) { + // lf will complain if in pain + if (isbleeding(lf) && onein(3)) { + // TODO: replace 4 + if (ispetof(lf, player) && !canhear(player, lf->cell, 4)) { + char realname[BUFLEN]; + real_getlfname(lf, realname, B_FALSE); + warn("You feel worried about your %s.", noprefix(realname)); + } else { + makenoise(lf, N_LOWHP); + } + if (ispetof(lf, player)) { + more(); + } + } +} + + void enhancerandomskill(lifeform_t *lf) { flag_t *f; enum SKILL poss[MAXSKILLS]; @@ -3010,7 +3095,7 @@ void enhanceskills(lifeform_t *lf) { if (isplayer(lf)) { int done = B_FALSE; while (!done) { - makespellchoicelist(&prompt, player, "Learn which new spell:","Describe which spell:", f->val[1], B_TRUE, B_FALSE, player->maxmp); + makespellchoicelist(&prompt, player, "Learn which new spell:","Describe which spell:", f->val[1], B_TRUE, B_FALSE, B_FALSE, player->maxmp); if (prompt.nchoices > 0) { objecttype_t *ot; getchoicestr(&prompt, B_TRUE, B_TRUE); @@ -3030,7 +3115,7 @@ void enhanceskills(lifeform_t *lf) { } } else { // monster gets random spell - makespellchoicelist(&prompt, lf, "xx","xx:", f->val[1], B_TRUE, B_FALSE, lf->maxmp); + makespellchoicelist(&prompt, lf, "xx","xx:", f->val[1], B_TRUE, B_FALSE, B_FALSE, lf->maxmp); if (prompt.nchoices > 0) { objecttype_t *ot; // pick one randomly @@ -3144,7 +3229,7 @@ void enhanceskills(lifeform_t *lf) { slev = getskill(lf, SK_SS_MENTAL); if (pctchance(slev*10)) { // construct list of castable mental spells - makespellchoicelist(&prompt, lf, "Learn which new psionic power:","Describe which psionic power:", SS_MENTAL, B_TRUE, B_FALSE, player->maxmp); + makespellchoicelist(&prompt, lf, "Learn which new psionic power:","Describe which psionic power:", SS_MENTAL, B_TRUE, B_FALSE, B_FALSE, player->maxmp); if (prompt.nchoices > 0) { objecttype_t *ot; msg("Your brain has unlocked a new psionic power!"); more(); @@ -3390,7 +3475,6 @@ race_t *findracebyname(char *name) { } } - // ...then partial matches in names for (r = firstrace; r ; r = r->next) { if (strstr(r->name, name)) { @@ -4158,14 +4242,17 @@ int real_getattr(lifeform_t *lf, enum ATTRIB attr, int ignoreattrset) { if (!ignoreattrset) { f = lfhasflagval(lf, F_ATTRSET, attr, NA, NA, NULL); if (f) { - return f->val[1]; + val = f->val[1]; + } else { + val = lf->att[attr]; } + } else { + // base attribute + val = lf->att[attr]; } - // base attribute - val = lf->att[attr]; // modified? - getflags(lf->flags, retflag, &nretflags, F_ATTRMOD, F_DRUNK, F_NONE); + getflags(lf->flags, retflag, &nretflags, F_ATTRMOD, F_DRUNK, F_INJURY, F_NONE); for (i = 0; i < nretflags; i++) { f = retflag[i]; if ((f->id == F_ATTRMOD) && (f->val[0] == attr)) { @@ -4182,6 +4269,9 @@ int real_getattr(lifeform_t *lf, enum ATTRIB attr, int ignoreattrset) { val -= f->val[0]; } } + if ((f->id == F_INJURY) && (f->val[0] == IJ_WINDPIPECRUSHED) && (attr == A_CON)) { + val -= 6; + } } if (val < 0) val = 0; @@ -4389,7 +4479,7 @@ int getevasion(lifeform_t *lf) { ev += level_ev; // dexterity mod - ev += (getstatmod(lf, A_DEX) / 10); + ev += getattr(lf, A_DEX); // you are easier to hit if you're glowing if (hasflag(lf->flags, F_PRODUCESLIGHT)) { @@ -4737,6 +4827,20 @@ int gethppct(lifeform_t *lf) { return pct; } +enum COLOUR gethungercol(enum HUNGER hlev) { + enum COLOUR col = C_GREY; + switch (hlev) { + case H_STUFFED: col = C_BOLDBLUE; break; + case H_FULL: col = C_BOLDGREEN; break; + case H_NONE: col = C_GREEN; break; + case H_PECKISH: col = C_GREY; break; + case H_HUNGRY: col = C_BROWN; break; + case H_VHUNGRY: col = C_YELLOW; break; + default: case H_STARVING: col = C_RED; break; + } + return col; +} + enum HUNGER gethungerlevel(int hunger) { int thresh = HUNGERCONST; if (hunger < -thresh) { @@ -4790,7 +4894,7 @@ char *gethungername(lifeform_t *lf, enum HUNGER hunger, char *buf) { if (lf && (lf->race->id == R_VAMPIRE)) { strcpy(buf, "very thirsty"); } else { - strcpy(buf, "very hungry"); + strcpy(buf, "ravenous"); } break; case H_STARVING: @@ -4927,7 +5031,7 @@ int getlfaccuracy(lifeform_t *lf, object_t *wep) { } // modify for drunkenness - f = isdrunk(lf); + f = lfhasflag(lf, F_DRUNK); if (f) { int amt; amt = (f->lifetime/TM_DRUNKTIME)+1; @@ -5049,15 +5153,15 @@ int getminions(lifeform_t *lf, lifeform_t **minion, int *nminions) { } int getnightvisrange(lifeform_t *lf) { - int range = 1,i; // default + int range = 0; // default flag_t *f; flag_t *retflag[MAXCANDIDATES]; - int nretflags; + int nretflags,i; f = lfhasflag(lf, F_SEEINDARK); if (f && !isblind(lf)) { if (f->val[0] == UNLIMITED) { - range = getvisrange(lf); + range = MAXVISRANGE; } else { range = f->val[0]; } @@ -5065,6 +5169,9 @@ int getnightvisrange(lifeform_t *lf) { f = lfhasflag(lf, F_TREMORSENSE); if (f) { return f->val[0]; + } else { + // depends how much your eyes have adjusted + range = (lf->eyeadjustment / 10); } } // modifications? @@ -5076,7 +5183,7 @@ int getnightvisrange(lifeform_t *lf) { } } - if (range < 0) range = 0; + limit(&range, 0, MAXVISRANGE); return range; } @@ -5348,7 +5455,8 @@ int getmr(lifeform_t *lf) { } -int getvisrange(lifeform_t *lf) { +// get maximum vision range for a lf +int getvisrange(lifeform_t *lf, int useambient) { int range,i; flag_t *f; flag_t *retflag[MAXCANDIDATES]; @@ -5362,9 +5470,27 @@ int getvisrange(lifeform_t *lf) { if (f) { range = f->val[0]; } else { - range = MAXVISRANGE; + range = DEF_VISRANGE; } + if (useambient) { + if ((gamemode == GM_GAMESTARTED) && (lf->cell)) { + int maxrange; + maxrange = getmapmaxvisrange(lf->cell->map); + limit(&range, NA, MAXOF(maxrange, getnightvisrange(lf))); + } + } + + // positive modifiers + getflags(lf->flags, retflag, &nretflags, F_VISRANGEMOD, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; + if (f->id == F_VISRANGEMOD) { + range += f->val[0]; + } + } + + //negative modifiers getflags(lf->flags, retflag, &nretflags, F_INJURY, F_NONE); for (i = 0; i < nretflags; i++) { switch (retflag[i]->val[0]) { @@ -5374,41 +5500,10 @@ int getvisrange(lifeform_t *lf) { break; } } - - // can't see as far if you're on the ground - if (isprone(lf)) { + if (isprone(lf) && (range >= 2)) { + // can't see as far if you're on the ground range /= 2; } - - // modify for darkness outside ? - if ((range > 0) && isoutdoors(lf->cell->map)) { - int hours,mins,secs; - float pct; - splittime(&hours,&mins,&secs); - pct = ((float)mins/59.0) * 100.0; - if (hours == 6) { // ie. 6am - 7am - // getting lighter. as minutes approach 59, - // visrange gets closer to maximum. - range = pctof( pct, range); - limit(&range, 1, NA); - } else if (hours == 18) { // ie. 6pm-7pm - // getting darker. as minutes approach 59, - // visrange gets closer to zero. - range = pctof( 100 - pct, range); - limit(&range, 1, NA); - } - } - - - // other modifications? - getflags(lf->flags, retflag, &nretflags, F_VISRANGEMOD, F_NONE); - for (i = 0; i < nretflags; i++) { - f = retflag[i]; - if (f->id == F_VISRANGEMOD) { - range += f->val[0]; - } - } - limit(&range, 0, MAXVISRANGE); return range; } @@ -7330,11 +7425,23 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) { } break; case BP_HEAD: - if (!eyesshaded(lf)) { - inj = IJ_BLACKEYE; - desc = strdup("eye is bruised^vision range halved"); + switch (rnd(1,3)) { + case 1: + if (!eyesshaded(lf)) { + inj = IJ_BLACKEYE; + desc = strdup("eye is bruised^vision range halved"); + } + break; + case 2: + inj = IJ_CONCUSSION; + desc = strdup("brain is concussed^random movement"); + break; + case 3: + inj = IJ_WINDPIPECRUSHED; + desc = strdup("windpipe is crushed^fitness penalty, cannot sprint"); + break; } - break; // maybe move this to an 'eye' injury? + break; case BP_LEGS: if (onein(3)) { inj = IJ_LEGBROKEN; @@ -7382,7 +7489,7 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) { char buf[BUFLEN]; addob(lf->cell->obpile, "severed finger"); o = getequippedob(lf->pack, bp2); - addflag(lf->flags, F_NOBODYPART, bp2, NA, NA, NULL); + addflag(lf->flags, F_NOBODYPART, bp2, B_FROMINJURY, NA, NULL); inj = IJ_FINGERMISSING; sprintf(buf, "%s is severed^cannot wear rings on this hand", getbodypartname(bp2)); desc = strdup(buf); @@ -7461,6 +7568,9 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) { wep = getweapon(lf); if (wep) drop(wep, wep->amt); break; + case IJ_WINDPIPECRUSHED: + stopsprinting(lf); + break; default: break; } @@ -7997,6 +8107,7 @@ int haslos(lifeform_t *viewer, cell_t *dest) { int x2,y2; map_t *map; int currange; + int nvrange; cell_t *retcell[MAXRETCELLS]; if (!viewer) return B_FALSE; @@ -8009,6 +8120,11 @@ int haslos(lifeform_t *viewer, cell_t *dest) { if (isdead(viewer) && !isplayer(viewer)) return B_FALSE; + if (viewer->losdirty) { + precalclos(viewer); + viewer->losdirty = B_FALSE; + } + // can we use pre-calced los? // //if ((viewer->cell->map->lf == viewer) && viewer->los) { @@ -8035,9 +8151,11 @@ int haslos(lifeform_t *viewer, cell_t *dest) { return B_FALSE; } - maxvisrange = getvisrange(viewer); + maxvisrange = getvisrange(viewer, B_TRUE); - if (!celllitfor(viewer, dest, maxvisrange, getnightvisrange(viewer))) { + nvrange = getnightvisrange(viewer); + limit(&nvrange, NA, maxvisrange); + if (!celllitfor(viewer, dest, maxvisrange, nvrange)) { return B_FALSE; } @@ -8108,6 +8226,12 @@ void initjobs(void) { // NOTE: try to always make the job's primary weapon be the first object defined. // this will make sure that they have the letter 'a'. addjob(J_GOD, "Diety"); + addflag(lastjob->flags, F_STARTATT, A_STR, AT_EXHIGH, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_DEX, AT_EXHIGH, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_IQ, AT_EXHIGH, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_CON, AT_EXHIGH, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_WIS, AT_EXHIGH, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_CHA, AT_EXHIGH, NA, NULL); //addflag(lastjob->flags, F_OMNIPOTENT, B_TRUE, NA, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_IQ, AT_VHIGH, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_CHA, AT_EXHIGH, NA, NULL); @@ -8283,6 +8407,7 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_RANGED, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, PR_ADEPT, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_TECHUSAGE, PR_ADEPT, NA, NULL); // abilities mayusespellschool(lastjob->flags, SS_NATURE, F_CANCAST); addflag(lastjob->flags, F_HASPET, NA, NA, NA, "young wolf"); @@ -8625,7 +8750,7 @@ void initjobs(void) { // non-player jobs addjob(J_SHOPKEEPER, "Shopkeeper"); - addflag(lastjob->flags, F_NOPLAYER, B_TRUE, AT_AVERAGE, NA, NULL); + addflag(lastjob->flags, F_NOPLAYER, B_TRUE, NA, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_IQ, AT_AVERAGE, NA, NULL); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "100-1000 gold coins"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "shotgun"); @@ -8732,6 +8857,7 @@ void initrace(void) { addflag(lastrace->flags, F_WANTSBETTERARM, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MINIONS, 100, 1, 3, "bandit"); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); addrace(R_BANDIT, "bandit", 75, '@', C_GREY, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, NULL); @@ -8757,6 +8883,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOJOBTEXT, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTJOB, 15, J_WIZARD, NA, NULL); addflag(lastrace->flags, F_STARTJOB, 50, J_ROGUE, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); addrace(R_BEGGAR, "beggar", 50, '@', C_BROWN, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_RARITY, H_VILLAGE, 80, NA, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 70, NA, NULL); @@ -8804,6 +8931,7 @@ void initrace(void) { addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ISPRISONER, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HIREPRICE, 0, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); addrace(R_TOWNGUARD, "town guard", 100, '@', C_GREY, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LTAVERAGE, NA, NULL); @@ -8830,6 +8958,7 @@ void initrace(void) { addflag(lastrace->flags, F_WANTSBETTERARM, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); // gods - kep sorted alphabetically addrace(R_GODPURITY, "Amberon", 90, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD); @@ -8852,6 +8981,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_SS_LIFE, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_FIRSTAID, PR_SKILLED, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_SPELLCASTING, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, B_APPENDYOU, "gestures imperiously"); // god abilities addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Purity"); @@ -8902,6 +9032,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_BACKSTAB, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_THROWING, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_CLIMBING, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, B_APPENDYOU, "waves his hand"); // god abilities addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Thieves"); @@ -8941,6 +9072,7 @@ void initrace(void) { //addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_SPELLCASTING, PR_EXPERT, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_SS_DEATH, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "extends a skeletal finger"); // god abilities addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Death"); @@ -8982,6 +9114,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "10 blessed vials of ambrosia"); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "2 rings of regeneration"); addflag(lastrace->flags, F_STARTSKILL, SK_FIRSTAID, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "raises her hand"); // god abilities addflag(lastrace->flags, F_GODOF, B_FEMALE, NA, NA, "Mercy"); @@ -9031,7 +9164,8 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_EXPERT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SPELLCASTING, PR_EXPERT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_EXPERT, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); @@ -9054,6 +9188,7 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_HEAVYBLOW, 2, 2, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); addflag(lastrace->flags, F_MINIONS, 50, 1, 3, "goblin"); addflag(lastrace->flags, F_MINIONS, 20, 1, 3, "goblin warrior"); @@ -9066,6 +9201,7 @@ void initrace(void) { addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "7d4+0"); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 8, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 2, NA, "^clucking."); addflag(lastrace->flags, F_MOVESPEED, SP_VERYSLOW, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); @@ -9130,6 +9266,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, "0d6+5"); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); @@ -9160,7 +9297,8 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_EXPERT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SPELLCASTING, PR_EXPERT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^flapping wings"); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); @@ -9194,7 +9332,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_HEAVYBLOW, NA, NA, NULL); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); addrace(R_GIANTFIRE, "fire giant", 160, 'H', C_RED, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -9225,7 +9363,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "bellows^a bellow"); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); addrace(R_GIANTFIREFC, "fire giant forgecaller", 160, 'H', C_RED, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_GIANTFIRE; @@ -9259,10 +9397,10 @@ void initrace(void) { addflag(lastrace->flags, F_CANCAST, OT_S_FIREDART, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_FLAMEPILLAR, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_S_FLAMEBURST, 4, 4, "pw:4;"); - addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_ADEPT, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_SS_FIRE, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SPELLCASTING, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SS_FIRE, PR_ADEPT, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); addrace(R_GIANTFIRETITAN, "fire titan", 160, 'H', C_RED, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -9291,7 +9429,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_S_BURNINGWAVE, 3, 3, "pw:6;"); addflag(lastrace->flags, F_DTRESIST, DT_FIRE, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); // TODO: storm giant // TODO: storm titan @@ -9320,6 +9458,7 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); addflag(lastrace->flags, F_PACKATTACK, 3, NA, 2, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); addrace(R_GNOLLHM, "gnoll huntmaster", 130, 'h', C_BROWN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_GNOLL; @@ -9349,7 +9488,7 @@ void initrace(void) { addflag(lastrace->flags, F_PACKATTACK, 3, NA, 2, NULL); addflag(lastrace->flags, F_MINIONS, 75, 1, 2, "gnoll"); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); addrace(R_GNOLLMR, "gnoll marauder", 130, 'h', C_BROWN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_GNOLL; @@ -9378,6 +9517,7 @@ void initrace(void) { addflag(lastrace->flags, F_PACKATTACK, 3, NA, 2, NULL); addflag(lastrace->flags, F_MINIONS, 75, 1, 2, "gnoll"); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); addrace(R_GOBLIN, "goblin", 20, 'g', C_BROWN, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -9406,6 +9546,7 @@ void initrace(void) { addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTJOB, 25, J_ROGUE, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); addrace(R_GOBLINWAR, "goblin warrior", 30, 'g', C_BROWN, MT_FLESH, RC_HUMANOID); @@ -9434,7 +9575,7 @@ void initrace(void) { addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); addflag(lastrace->flags, F_MINIONS, 90, 1, 2, "goblin"); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); addrace(R_GOBLINSHOOTER, "goblin sharpshooter", 20, 'g', C_BROWN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_GOBLIN; @@ -9465,7 +9606,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL); addflag(lastrace->flags, F_STARTHIDDENPCT, 75, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); addrace(R_GOBLINHEXER, "goblin hexer", 20, 'g', C_BROWN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_GOBLIN; @@ -9493,7 +9634,8 @@ void initrace(void) { addflag(lastrace->flags, F_MPREGEN, 3, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_BLINDNESS, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_PAIN, NA, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SPELLCASTING, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MINIONS, 90, 1, 2, "goblin"); @@ -9526,6 +9668,7 @@ void initrace(void) { addflag(lastrace->flags, F_PHALANX, 5, NA, 1, "hobgoblin"); addflag(lastrace->flags, F_MINIONS, 50, 1, 2, "goblin"); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); addrace(R_HOBGOBLINWAR, "hobgoblin warrior", 90, 'g', C_GREEN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_HOBGOBLIN; @@ -9558,6 +9701,7 @@ void initrace(void) { addflag(lastrace->flags, F_MINIONS, 50, 1, 4, "goblin"); addflag(lastrace->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); // TODO: hobgoblin archer // TODO: hobgoblin warcaster @@ -9635,7 +9779,7 @@ void initrace(void) { addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, B_APPENDYOU, "spits"); addflag(lastrace->flags, F_CANWILL, OT_S_POISONBOLT, 5, 5, "pw:5;"); - addflag(lastrace->flags, F_HASSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); addrace(R_MINOTAUR, "minotaur", 130, 'H', C_BROWN, MT_FLESH, RC_HUMANOID); @@ -9659,7 +9803,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "+2 heavy flail"); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "greataxe"); addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_PERCEPTION, PR_EXPERT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_EXPERT, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:5;"); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "roars^a roar"); @@ -9696,6 +9840,7 @@ void initrace(void) { addflag(lastrace->flags, F_MINIONS, 50, 1, 5, "orc"); addflag(lastrace->flags, F_MINIONS, 20, 1, 2, "orc warrior"); addflag(lastrace->flags, F_MORALE, 20, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); addrace(R_OGRESAVAGE, "ogre savage", 160, 'O', C_BROWN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_OGRE; @@ -9725,7 +9870,7 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 20, NA, NA, NULL); addflag(lastrace->flags, F_MINIONS, 50, 1, 5, "orc"); addflag(lastrace->flags, F_MINIONS, 50, 1, 3, "orc warrior"); - addflag(lastrace->flags, F_HASSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); addrace(R_OGREWARHULK, "ogre warhulk", 160, 'O', C_BROWN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_OGRE; @@ -9756,6 +9901,7 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_MINIONS, 25, 1, 8, "orc"); addflag(lastrace->flags, F_MINIONS, 25, 1, 2, "orc warrior"); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); addrace(R_ORC, "orc", 90, 'o', C_BROWN, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -9785,6 +9931,7 @@ void initrace(void) { //addflag(lastrace->flags, F_STARTJOB, 20, J_WIZARD, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, 5, 5, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); addrace(R_ORCWARRIOR, "orc warrior", 90, 'o', C_BROWN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_ORC; @@ -9816,6 +9963,7 @@ void initrace(void) { //addflag(lastrace->flags, F_STARTJOB, 20, J_WIZARD, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); addrace(R_ORK, "ork", 90, 'o', C_BROWN, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "orc corpse"); @@ -9843,6 +9991,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); addrace(R_PEGASUS, "pegasus", 130, 'Q', C_GREY, MT_FLESH, RC_MAGIC); addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL); @@ -9870,7 +10019,7 @@ void initrace(void) { addflag(lastrace->flags, F_RESISTMAG, 5, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 25, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); addrace(R_POLTERGEIST, "poltergeist", 50, 'p', C_GREEN, MT_FLESH, RC_UNDEAD); // sPirit addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -9896,7 +10045,8 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_SS_MENTAL, PR_EXPERT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SS_MENTAL, PR_EXPERT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_XPMULTIPLY, 2, NA, NA, NULL); @@ -9926,11 +10076,12 @@ void initrace(void) { addflag(lastrace->flags, F_CANCAST, OT_S_CHARM, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_SLEEP, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_FEAR, NA, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_ADEPT, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_SS_MENTAL, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SPELLCASTING, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SS_MENTAL, PR_ADEPT, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL); addflag(lastrace->flags, F_STARTHIDDENPCT, 60, NA, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); addrace(R_SHADOWCAT, "shadowcat", 5, 'f', C_BLUE, MT_FLESH, RC_MAGIC); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -9997,8 +10148,9 @@ void initrace(void) { addflag(lastrace->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^crackling flames"); - addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_NOVICE, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_SS_FIRE, PR_BEGINNER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SPELLCASTING, PR_NOVICE, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SS_FIRE, PR_BEGINNER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); @@ -10022,8 +10174,9 @@ void initrace(void) { addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, B_APPENDYOU, "gestures"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3"); addflag(lastrace->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_NOVICE, NA, NULL); - addflag(lastrace->flags, F_HASSKILL, SK_SS_COLD, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SPELLCASTING, PR_NOVICE, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SS_COLD, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); @@ -10044,6 +10197,7 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); addrace(R_XAT, "xat", 2, 'x', C_BROWN, MT_FLESH, RC_ANIMAL); @@ -10168,7 +10322,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL); addflag(lastrace->flags, F_RETALIATE, 1, 4, DT_PIERCE, "sharp spines"); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); - addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "cactus fruit"); addflag(lastrace->flags, F_DOESNTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "4d4"); @@ -10192,7 +10346,7 @@ void initrace(void) { addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); - addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "pile of sleeping powder"); addflag(lastrace->flags, F_DOESNTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4"); @@ -10280,7 +10434,9 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); + addflag(lastrace->flags, F_MATVULN, MT_SILVER, 200, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^flapping wings"); + addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addrace(R_BEAR, "black bear", 150, 'q', C_BLUE, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, NULL); @@ -10369,6 +10525,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling"); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addrace(R_ANTS, "giant soldier ant", 25, 'a', C_BROWN, MT_FLESH, RC_ANIMAL); lastrace->baseid = R_ANT; addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -10392,6 +10549,7 @@ void initrace(void) { addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling"); addflag(lastrace->flags, F_MINIONS, 50, 1, 3, "giant worker ant"); + addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addrace(R_ANTLION, "giant antlion", 30, 'a', C_YELLOW, MT_FLESH, RC_ANIMAL); lastrace->baseid = R_ANT; addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -10415,6 +10573,7 @@ void initrace(void) { addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling"); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "roars^a roars"); + addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addrace(R_CHICKEN, "chicken", 0.5, 'c', C_BROWN, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); @@ -10430,7 +10589,8 @@ void initrace(void) { addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); addflag(lastrace->flags, F_VEGETARIAN, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 1, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 1, NA, "clucks^clucking"); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "squarks^squarking"); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^clucking."); addrace(R_DOG, "dog", 35, 'd', C_BROWN, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_RNDHOSTILE, 10, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); @@ -10668,6 +10828,7 @@ void initrace(void) { addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:4;"); addflag(lastrace->flags, F_CANWILL, OT_A_SUCKBLOOD, NA, NA, "dam:0d1+4;"); + addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addrace(R_NEWT, "giant newt", 4, ':', C_BROWN, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL); @@ -11165,23 +11326,20 @@ void initrace(void) { addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d8+4"); - addflag(lastrace->flags, F_ARMOURRATING, 16, NA, NA, NULL); + addflag(lastrace->flags, F_ARMOURRATING, 18, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LOW, NA, NULL); - addflag(lastrace->flags, F_MAXATTACKS, 3, 3, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6+1"); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d4"); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 10, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_ELECTRIC, NA, NA, NULL); + addflag(lastrace->flags, F_DETECTLIFE, 10, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); addflag(lastrace->flags, F_DTRESIST, DT_ACID, NA, NA, NULL); addflag(lastrace->flags, F_DTRESIST, DT_COLD, NA, NA, NULL); addflag(lastrace->flags, F_DTRESIST, DT_FIRE, NA, NA, NULL); - addflag(lastrace->flags, F_DETECTLIFE, 10, NA, NA, NULL); - addflag(lastrace->flags, F_CANWILL, OT_S_FEAR, 20, 20, "pw:3;"); - addflag(lastrace->flags, F_CANWILL, OT_S_CLOUDKILL, 20, 20, "pw:3;"); + addflag(lastrace->flags, F_CANWILL, OT_S_FEAR, 20, 20, "pw:1;"); + addflag(lastrace->flags, F_CANWILL, OT_S_CLOUDKILL, 20, 20, "pw:1;"); addflag(lastrace->flags, F_CANWILL, OT_S_SUMMONDEMON, 20, 20, "pw:3;"); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "narrows its eyes"); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "roars^an other-wordly roar"); @@ -11217,26 +11375,26 @@ void initrace(void) { addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "3d8"); + addflag(lastrace->flags, F_REGENERATES, 2, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 18, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_LTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_DEX, AT_HIGH, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LOW, NA, NULL); - addflag(lastrace->flags, F_MAXATTACKS, 3, 3, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6+1"); - addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d4"); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3-1"); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d4-1"); + addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 28, "3-5"); + addflag(lastrace->flags, F_HITCONFERVALS, P_VENOM, 2, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 10, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_ELECTRIC, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); - addflag(lastrace->flags, F_DTRESIST, DT_ACID, NA, NA, NULL); - addflag(lastrace->flags, F_DTRESIST, DT_COLD, NA, NA, NULL); addflag(lastrace->flags, F_DTRESIST, DT_FIRE, NA, NA, NULL); - addflag(lastrace->flags, F_DETECTLIFE, 10, NA, NA, NULL); - addflag(lastrace->flags, F_CANWILL, OT_S_FEAR, 20, 20, "pw:3;"); - addflag(lastrace->flags, F_CANWILL, OT_S_CLOUDKILL, 20, 20, "pw:3;"); - addflag(lastrace->flags, F_CANWILL, OT_S_SUMMONDEMON, 20, 20, "pw:3;"); + addflag(lastrace->flags, F_DETECTMAGIC, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_STEALTH, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_S_FEAR, 20, 20, "pw:1;"); + addflag(lastrace->flags, F_CANWILL, OT_S_INVISIBILITY, 20, 20, "pw:1;"); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "narrows its eyes"); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "roars^an other-wordly roar"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "screechs^an other-wordly screech"); // undead addrace(R_ZOMBIE, "zombie", 50, 'Z', C_BLUE, MT_FLESH, RC_UNDEAD); @@ -11308,6 +11466,7 @@ void initrace(void) { addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL); addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, ""); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 72, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "4d4+2"); @@ -11359,6 +11518,7 @@ void initrace(void) { addflag(lastrace->flags, F_VAMPIRIC, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, "3d6"); + addflag(lastrace->flags, F_MATVULN, MT_SILVER, 200, NA, NULL); addflag(lastrace->flags, F_SEEINVIS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 8, NA, NA, NULL); addflag(lastrace->flags, F_AVOIDOBTYPE, OT_GARLIC, B_TRUE, NA, NULL); @@ -11375,8 +11535,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_S_CHARM, 3, 3, "pw:6;"); addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, 5, 5, "range:3;"); addflag(lastrace->flags, F_CANWILL, OT_S_STUN, 5, 5, "pw:1;"); - addflag(lastrace->flags, F_CANWILL, OT_S_POLYMORPH, 3, 3, "pw:1;"); - addflag(lastrace->flags, F_FORCEPOLY, R_BATVAMPIRE, 20, 20, "pw:3;"); + addflag(lastrace->flags, F_CANWILL, OT_S_POLYMORPH, 3, 3, "pw:1;race:vampire bat;"); addflag(lastrace->flags, F_DETECTOBS, 10, OT_COFFIN, NA, NULL); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "pile of ash"); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "gestures"); @@ -11475,6 +11634,7 @@ void initrace(void) { addflag(r->flags, F_DTIMMUNE, DT_WATER, NA, NA, NULL); } else if (r->raceclass->id == RC_DEMON) { addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); + addflag(r->flags, F_MATVULN, MT_SILVER, 200, NA, NULL); } else if (r->raceclass->id == RC_GOD) { addflag(r->flags, F_PIETY, 100, NA, NA, NULL); addflag(r->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); @@ -11686,10 +11846,6 @@ void killlf(lifeform_t *lf) { } } -flag_t *isdrunk(lifeform_t *lf) { - return lfhasflag(lf, F_DRUNK); -} - // returns second weapon if you are dual weilding object_t *isdualweilding(lifeform_t *lf) { object_t *priwep,*secwep; @@ -12057,12 +12213,15 @@ lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) { a->polyrevert = B_FALSE; // for precalcing line of sight + a->losdirty = B_TRUE; a->nlos = 0; //a->los = malloc(sizeof(cell_t *) * MAXVISRANGE); a->los = malloc( sizeof(cell_t *) * ((MAXVISRANGE*2+1)*(MAXVISRANGE*2+1))); //a->viscell = NULL; a->viscell = malloc( sizeof(int) * ((MAXVISRANGE*2+1)*(MAXVISRANGE*2+1))); + a->eyeadjustment = 0; + // for ai // avoid messages when equipping initial obs @@ -12230,7 +12389,7 @@ void addtrail(lifeform_t *lf, int dir) { return; } // footprints first - if (!isairborne(lf)) { + if (!isairborne(lf) && !lfhasflag(lf, F_NONCORPOREAL)) { int fpdir; enum SKILLLEVEL slev; @@ -12363,7 +12522,7 @@ void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype) { //adjustdammaterial((unsigned int *)amt, damtype, getlfmaterial(lf)); adjustdamhardness((unsigned int *)amt, damtype, getlfmaterial(lf)); - if (isdrunk(lf)) { + if (lfhasflag(lf, F_DRUNK)) { *amt -= rnd(0,3); } @@ -12391,6 +12550,8 @@ void makepeaceful(lifeform_t *who) { } } + addflag(who->flags, F_XPVAL, 0, NA, NA, NULL); + killflagsofid(who->flags, F_HOSTILE); killflagsofid(who->flags, F_TARGETLF); // stop targetting anyone @@ -12518,6 +12679,8 @@ int areenemies(lifeform_t *lf1, lifeform_t *lf2) { } void age(lifeform_t *lf, int pct) { + if (hasjob(lf, J_GOD)) return; + lf->maxhp -= pctof(pct,lf->maxhp); limit(&lf->maxhp, 0, NA); limit(&lf->hp, NA, lf->maxhp); @@ -12802,6 +12965,14 @@ int isweaponskill(enum SKILL skid) { return B_FALSE; } +enum FLAG iswoozy(lifeform_t *lf) { + if (lfhasflag(lf, F_DRUNK)) return B_TRUE; + if (lfhasflag(lf, F_CONFUSED)) return B_TRUE; + if (lfhasflagval(lf, F_INJURY, IJ_CONCUSSION, NA, NA, NULL)) return B_TRUE; + + return F_NONE; +} + void killjob(job_t *job) { job_t *nextone, *lastone; @@ -13079,6 +13250,28 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml } + // adjust for source object's material + if (fromob) { + if (lfhasflagval(lf, F_MATIMMUNE, fromob->material->id, NA, NA, NULL)) { + amt = 0; + } else { + f = lfhasflagval(lf, F_MATVULN, fromob->material->id, NA, NA, NULL); + if (f) { + // will always do some damage + if (!amt) amt = 1; + amt = pctof(f->val[1], amt); + // announce + if (isplayer(lf)) { + msg("The touch of %s sears you!", fromob->material->name); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("The touch of %s sears %s!", fromob->material->name, lfname); + } + } + } + } + // adjust damage! if (reducedam) { adjustdamlf(lf, &amt, damtype); @@ -13206,18 +13399,6 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml warn("*** LOW HITPOINT WARNING ***"); more(); } - } else if (prebleed != postbleed) { - // TODO: replace 4 - if (ispetof(lf, player) && !canhear(player, lf->cell, 4)) { - char realname[BUFLEN]; - real_getlfname(lf, realname, B_FALSE); - warn("You feel worried about your %s.", noprefix(realname)); - } else { - makenoise(lf, N_LOWHP); - } - if (ispetof(lf, player)) { - more(); - } } } @@ -13688,6 +13869,9 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha lifeform_t *l; int sounddist; int rv = B_FALSE; + + assert(text); + if (gamemode != GM_GAMESTARTED) { return B_FALSE; } @@ -13811,10 +13995,12 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha msg("You hear %s%s%c", textnopunc, distbuf, punc); rv = B_TRUE; } else { + assert(text); msg("You hear %s", text); rv = B_TRUE; } } else { + assert(text); msg("You hear %s", text); rv = B_TRUE; } @@ -13847,6 +14033,7 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha // wake up! if (isplayer(l)) { char wakenoise[BUFLEN]; + assert(text); strcpy(wakenoise, text); wakenoise[strlen(wakenoise)-1] = '\0'; // omit punctuation //msg("A nearby noise awakens you!"); @@ -13922,8 +14109,7 @@ int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground, int want } } - - if (!canpickup(lf, what,howmany)){ + if (!canpickup(lf, what,howmany)) { // tell the player why! if (isplayer(lf)) { switch (reason) { @@ -13957,6 +14143,18 @@ int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground, int want } if (!failed) { + // warn if it is too heavy + if (isplayer(lf) && !isburdened(lf) && + (getobpileweight(lf->pack) + (getobunitweight(what)*howmany) > getmaxcarryweight(lf)) ) { + char ch,buf[BUFLEN]; + snprintf(buf, BUFLEN, "Picking up %s will burden you. Continue", obname); + ch = askchar(buf, "yn","n", B_TRUE); + if (ch != 'y') { + msg("Cancelled."); + return B_TRUE; + } + } + if (touch(lf, what)) { taketime(lf, SPEED_PICKUP); return B_TRUE; @@ -14175,7 +14373,7 @@ void precalclos_new(lifeform_t *lf) { free(lf->los); lf->los = NULL; } - maxvisrange = getvisrange(lf); + maxvisrange = getvisrange(lf, B_FALSE); nightvisrange = getnightvisrange(lf); // find all cells at max fov @@ -14291,10 +14489,11 @@ void precalclos_new(lifeform_t *lf) { } } if (!found) { - // can we see it? - if (!celllitfor(lf, c, maxvisrange, nightvisrange)) { - keepgoing = B_FALSE; - } + int litforus; + // is the cell lit? if it isn't, then still keep going, + // as there might be a light-producing object further on. + litforus = celllitfor(lf, c, maxvisrange, nightvisrange); + if (!celltransparentfor(lf, c, &xray, &rangemod)) { keepgoing = B_FALSE; } @@ -14303,9 +14502,12 @@ void precalclos_new(lifeform_t *lf) { // if keepgoing was false, still count it // BUT then stop looking. - los[nlos] = c; - blocker[nlos] = keepgoing ? B_FALSE : B_TRUE; - nlos++; + if (litforus) { + los[nlos] = c; + blocker[nlos] = keepgoing ? B_FALSE : B_TRUE; + nlos++; + } + // TODO: remember if we saw any _lit_ cells } } else { // ie. if !c keepgoing = B_FALSE; @@ -14324,6 +14526,10 @@ void precalclos_new(lifeform_t *lf) { free(los); free(blocker); + + if (isplayer(lf) && (gamemode == GM_GAMESTARTED)) { + needredraw = B_TRUE; + } } int push(lifeform_t *lf, object_t *o, int dir) { @@ -15535,6 +15741,14 @@ int setlfmaterial(lifeform_t *lf, enum MATERIAL id) { return B_FALSE; } +void setlosdirty(lifeform_t *lf) { + lf->losdirty = B_TRUE; + if (isplayer(lf)) { + needredraw = B_TRUE; + drawscreen(); + } +} + int shoot(lifeform_t *lf) { object_t *gun,*ammo; lifeform_t *targ; @@ -15973,527 +16187,12 @@ void sortlf(map_t *map, lifeform_t *lf) { } } -// returns TRUE on failure (ie. nothing to steal) -int steal(lifeform_t *lf, obpile_t *op, enum FLAG wantflag) { - enum SKILLLEVEL slev; - object_t *o; - int i,nsteals; - int numgot = 0; - int fromground; - char letter = 'a'; - slev = getskill(lf, SK_THIEVERY); - - if (op->owner) { - fromground = B_FALSE; - } else { - fromground = B_TRUE; - } - // - if (slev >= PR_EXPERT) { - nsteals = 2; - } else { - nsteals = 1; - } - - // what do we steal? - for (i = 0; i < nsteals; i++) { - char buf[BUFLEN]; - snprintf(buf, BUFLEN, "Steal what (%d of %d)?", i+1, nsteals); - initprompt(&prompt, buf); - for (o = op->first ; o ; o = o->next) { - int ok = B_TRUE; - if ((slev < PR_SKILLED) && (getobunitweight(o) >= 3)) { - // too heavy to steal - ok = B_FALSE; - } else if ((slev < PR_MASTER) && isequipped(o)) { - // equipped - ok = B_FALSE; - } else if (!canpickup(lf, o, 1)) { - // can't pick it up - ok = B_FALSE; - } else if ((wantflag != F_NONE) && !hasflag(o->flags, wantflag)) { - // don't have the right flag - ok = B_FALSE; - } - if (ok) { - getobname(o, buf, 1); - addchoice(&prompt, fromground ? letter++ : o->letter, buf, NULL, o); - } - } - if (prompt.nchoices > 1) { - if (isplayer(lf) && (slev >= PR_ADEPT)) { - addchoice(&prompt, '-', "Nothing", NULL, NULL); - // pick what you want - getchoice(&prompt); - o = (object_t *)prompt.result; - } else { - // random - o = (object_t *)prompt.choice[rnd(0,prompt.nchoices-1)].data; - } - if (o) { - killflagsofid(o->flags, F_SHOPITEM); - o = moveob(o, lf->pack, 1); - if (o) { - char obname[BUFLEN]; - char lfname[BUFLEN]; - char targname[BUFLEN]; - getlfname(lf, lfname); - getobname(o, obname, 1); - if (op->owner) { - getlfname(op->owner, targname); - if (isplayer(lf)) { - msg("You steal %s from %s!", getlfcol(op->owner, CC_BAD), obname, targname); - } else if (cansee(player, lf)) { - msg("^%c%s steals %s from %s!", getlfcol(op->owner, CC_BAD), lfname, obname, targname); - } - } else { - if (isplayer(lf)) { - msg("You steal %s!", obname); - } else if (cansee(player, lf)) { - msg("%s steals %s!", lfname, obname); - } - } - numgot++; - } - } - } else { - // nothing left to steal - - if (numgot == 0) { - return B_TRUE; - } - break; - } - } // end foreach steal - - if (isplayer(lf)) pleasegodmaybe(R_GODTHIEVES, 5+numgot); - - return B_FALSE; -} - - -int stone(lifeform_t *lf) { - char lfname[BUFLEN]; - char statname[BUFLEN]; - int failed = B_FALSE; - - if (!lfcanbestoned(lf)) { - failed = B_TRUE; - } - if (failed) { - return B_TRUE; - } - - getlfname(lf, lfname); - - - snprintf(statname, BUFLEN, "statue of a %s", lf->race->name); - addob(lf->cell->obpile, statname); - - // kill lifeform - addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); - addflag(lf->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); - - if (cansee(player, lf)) { - msg("^%c%s %s to stone!", getlfcol(lf, CC_VBAD), lfname, isplayer(lf) ? "turn" : "turns"); - } - setlastdam(lf, "petrification"); - die(lf); - return B_FALSE; -} - -void stopeating(lifeform_t *lf) { - flag_t *f; - f = lfhasflag(lf, F_EATING); - if (f) { - if (isplayer(lf)){ - msg("You stop eating."); - } - killflagsofid(lf->flags, F_EATING); - } - -} - -void stopresting(lifeform_t *lf) { - flag_t *f; - - // stop training - f = hasflag(lf->flags, F_TRAINING); - if (f) { - killflag(f); - if (isplayer(lf)) { - msg("Your training is interrupted!"); - } else if (cansee(player, lf)) { - char buf[BUFLEN]; - getlfname(lf, buf); - capitalise(buf); - msg("%s stops training.",buf); - } - statdirty = B_TRUE; - } - // stop resting! - f = isresting(lf); - if (f) { - killflag(f); - if (isplayer(lf)) { - msg("Your rest is interrupted!"); - } else if (cansee(player, lf)) { - char buf[BUFLEN]; - getlfname(lf, buf); - msg("%s stops resting.",buf); - } - statdirty = B_TRUE; - } -} - -void stoprunning(lifeform_t *lf) { - flag_t *f; - f = hasflag(lf->flags, F_RUNNING); - if (f) { - killflag(f); - } - -} - -void stopsprinting(lifeform_t *lf) { - flag_t *f; - f = lfhasflag(lf, F_SPRINTING); - if (f && f->val[0]) { - killflag(f); - } - -} - -int stun(lifeform_t *lf, int nturns) { - if (lfhasflag(lf, F_ASLEEP)) { - return B_TRUE; - } - if (isplayer(lf)) { - msg("You are stunned!"); - } else if (cansee(player, lf)) { - char buf[BUFLEN]; - getlfname(lf, buf); - msg("%s is stunned!", buf); - } - taketime(lf, getactspeed(lf)*nturns); - return B_FALSE; -} - -// wrapper for addmonster(), but announce that it appears -// and make it worth zero xp. -// -// for unique monsters, they move from their current position. -lifeform_t *summonmonster(lifeform_t *caster, cell_t *c, enum RACE rid, char *racename, int lifetime, int wantfriendly) { - lifeform_t *newlf = NULL; - char buf[BUFLEN]; - - newlf = addmonster(c, rid, racename, B_FALSE, 1, B_FALSE, NULL); - if (newlf) { - if (haslos(player, c)) { - //char *newbuf; - getlfnamea(newlf, buf); - capitalise(buf); - msg("%s appears!", buf); - } - - if (!hasflag(newlf->flags, F_UNIQUE)) { - // summoned - if (caster) { - addflag(newlf->flags, F_SUMMONEDBY, caster->id, lifetime, NA, NULL); - if (wantfriendly) { - addflag(newlf->flags, F_PETOF, caster->id, NA, NA, NULL); - if (areallies(player, caster)) { - makefriendly(newlf, PERMENANT); - } - } - } - // not worth any xp - killflagsofid(newlf->flags, F_XPVAL); - addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL); - } - } - return newlf; -} - - -int takeoff(lifeform_t *lf, object_t *o) { - flag_t *f; - char obname[BUFLEN]; - char buf[BUFLEN]; - - if (!isarmour(o)) { - return unweild(lf, o); - } - - getobname(o, obname, 1); - - if (!cantakeoff(lf, o)) { - switch (reason) { - case E_CURSED: - if (isplayer(lf)) { - msg("Your %s appears to be stuck to you!", noprefix(obname)); - o->blessknown = B_TRUE; - } - // still take time - taketime(lf, getactspeed(lf)); - break; - case E_NOTEQUIPPED: - if (isplayer(lf)) { - msg("You are not wearing that!"); - } - break; - default: - if (isplayer(lf)) { - msg("For some reason, you cannot remove your %s!", noprefix(obname)); - } - // still take time - taketime(lf, getactspeed(lf)); - break; - } - return B_TRUE; - } - - // remove the equipped flag - f = hasflag(o->flags, F_EQUIPPED); - killflag(f); - - taketime(lf, getactspeed(lf)); - if ((gamemode == GM_GAMESTARTED)) { - if (isplayer(lf)) { - msg("You take off %s.", obname); - statdirty = B_TRUE; - } else if (cansee(player, lf)) { - getlfname(lf, buf); - capitalise(buf); - msg("%s takes off %s.", buf, obname); - } - - } - - // lose flags - loseobflags(lf, o, F_EQUIPCONFER); - - f = hasflag(o->flags, F_CREATEDBYSPELL); - if (f) stopspell(lf, f->val[0]); - - if (obproduceslight(o)) { - calclight((getoblocation(o))->map); - precalclos(lf); - drawscreen(); - } - - return B_FALSE; -} - -void taketime(lifeform_t *lf, long howlong) { - int db = B_FALSE; - map_t *map; - - if (notime || lfhasflag(lf, F_NOTIME)) { - return; - } - - /* - if (isplayer(lf)) { - statdirty = B_TRUE; - } - */ - - map = lf->cell->map; - - assert(howlong > 0); - - if (db && (gamemode == GM_GAMESTARTED) && cansee(player, lf)) { - dblog("lfid %d (%s) spending %d time\n",lf->id,lf->race->name, howlong); - } - // inc timespent - lf->timespent += howlong; - assert(lf->timespent >= 0); - - // time-based effects on lifeforms (eg hp regeneration) go here... - - // TODO: decrement lifeform's (or their object's) temporary flags - - - // if you don't have a map, start forgetting the dungeon - if (isplayer(lf)) { - if (!lfhasflag(lf, F_PHOTOMEM) && (getskill(lf, SK_CARTOGRAPHY) < PR_SKILLED)) { - lf->forgettimer += ((float)howlong / 500.0); - if (lf->forgettimer > 1) { - int amt; - - // TODO: modify using race memory - amt = (int)floor(lf->forgettimer); - forgetcells(lf->cell->map, amt); - lf->forgettimer -= amt; - } - } - } - - // now move player up in linked list... - sortlf(map, lf); -} - -int throwat(lifeform_t *thrower, object_t *o, cell_t *where) { - if (!hasbp(thrower, BP_HANDS)) { - if (isplayer(thrower)) msg("You have no hands to throw with!"); - return B_TRUE; - } - taketime(thrower, getactspeed(thrower)); - return fireat(thrower, o, 1, where, getthrowspeed(getattr(thrower, A_STR)), NULL); -} - -// lf effects which happen every xx ticks -// IMPORTANT - don't call taketime() during this function. -void timeeffectslf(lifeform_t *lf) { - object_t *o, *nexto; - flag_t *f,*nextf; - int dir; - - // make SURE we don't take any time! - notime = B_TRUE; - - // decrement flags - timeeffectsflags(lf->flags); - - // remove effects from expired poison - for (f = lf->flags->first ; f; f = nextf) { - nextf = f->next; - if (f->lifetime == FROMPOISON) { - if (!lfhasflagval(lf, F_POISONED, f->obfrom, NA, NA, NULL)) { - killflag(f); - } - } - } - - if (lfhasflag(lf, F_INTERRUPTED)) { - interrupt(lf); - killflagsofid(lf->flags, F_INTERRUPTED); - } - - if (isdead(lf)) { - killflagsofid(lf->flags, F_NOTIME); - return; - } - - // revert to original form if a polymorph just expired - if (lf->polyrevert) { - enum RACE rid = R_NONE; - race_t *r; - flag_t *ff; - // change back - ff = lfhasflag(lf, F_ORIGRACE); - if (ff) { - rid = ff->val[0]; - } else { - rid = R_NONE; // should never happen! - } - r = findrace(rid); - if (r) { - setrace(lf, r->id, B_TRUE); - } else { - if (isplayer(lf)) { - msg("For some reason, you are unable to revert to your original form!"); - } - } - lf->polyrevert = B_FALSE; - } - - - // time effects on lifeform's objects - for (o = lf->pack->first ; o ; o = nexto) { - nexto = o->next; - - f = hasflag(o->flags, F_CREATEDBYSPELL); - if (f && !hasactivespell(lf, f->val[0])) { - killob(o); - continue; - } - - timeeffectsob(o); - } - - // holes in the floor/roof - for (dir = D_UP; dir <= D_DOWN; dir++) { - int donesomething = B_TRUE; - o = hasobwithflagval(lf->cell->obpile, F_PIT, dir, NA, NA, NULL); - while (o && donesomething) { - int willfall = B_FALSE; - donesomething = B_FALSE; - if ((dir == D_DOWN) && !isairborne(lf)) { - willfall = B_TRUE; - } else if ((dir == D_UP) && lfhasflag(lf, F_LEVITATING)) { - willfall = B_TRUE; - } - - if (willfall) { - usestairs(lf, o, B_FALSE); - donesomething = B_TRUE; - o = hasobwithflagval(lf->cell->obpile, F_PIT, dir, NA, NA, NULL); - } - } - } - - notime = B_FALSE; -} - -// return B_TRUE on failure. -int tryclimb(lifeform_t *lf, cell_t *where, char *towhat) { - // if you have a rope or there's an adjacent wall, you can try - // to climb up - int adjwalls; - char lfname[BUFLEN]; - getlfname(lf, lfname); - adjwalls = countadjwalls(where); - if (adjwalls || hasobwithflag(lf->pack, F_HELPSCLIMB)) { - if (isplayer(lf)) { - msg("You start climbing..."); - } else if (cansee(player, lf)) { - msg("%s starts climbing...", lfname); - } - - taketime(lf, getactspeed(lf)); - - // base difficulty of 20 - if (skillcheck(lf, SC_CLIMB, 20, (countadjwalls(where)+1)/2)) { - // you made it! - if (isplayer(lf)) { - msg("You reach %s.", towhat); - } else if (cansee(player, lf)) { - msg("%s reaches %s.", towhat); - } - // train climbing - practice(lf, SK_CLIMBING, 1); - // continue... - - } else { - // you fall. - if (isplayer(lf)) { - msg("You fall to the ground!"); - } else if (cansee(player, lf)) { - msg("%s falls to the ground!", lfname); - } - fall(lf, NULL, B_FALSE); // this will take some time. - losehp(lf, roll("1d6"), DT_FALL, NULL, "a fall while climbing"); - return B_TRUE; - } - } else { // no rope or adjacent walls - if (isplayer(lf)) { - msg("You can't reach the roof!"); - } - return B_TRUE; - } - - // success - return B_FALSE; -} - ////////////////////////////////// // effects which happen before every TURN // (ie. the faster the player is, the faster they happen) // eg. damage from walking on things ////////////////////////////////// -void turneffectslf(lifeform_t *lf) { +void startlfturn(lifeform_t *lf) { int db = B_FALSE; map_t *map; enum ERROR error; @@ -16510,9 +16209,9 @@ void turneffectslf(lifeform_t *lf) { map = lf->cell->map; - if (db) dblog("starting turneffectslf for lf id %d %s", lf->id, lf->race->name); + if (db) dblog("startlfturn for lf id %d %s", lf->id, lf->race->name); - if (isplayer(lf) && isdrunk(lf)) statdirty = B_TRUE; + if (isplayer(lf) && lfhasflag(lf, F_DRUNK)) statdirty = B_TRUE; // clear one-turn-only flags killflagsofid(lf->flags, F_DONELISTEN); @@ -17016,7 +16715,7 @@ void turneffectslf(lifeform_t *lf) { } else if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("^b%s melts a little.",getlfcol(lf, CC_BAD), lfname); + msg("^%c%s melts a little.",getlfcol(lf, CC_BAD), lfname); } } } @@ -17096,7 +16795,8 @@ void turneffectslf(lifeform_t *lf) { if (isdead(lf)) return; - getflags(lf->flags, retflag, &nretflags, F_ATTACHEDTO, F_CANWILL, F_CHARMEDBY, F_FLEEFROM, F_GRABBEDBY, F_GRABBING, F_BOOSTSPELL, F_FEIGNINGDEATH, + getflags(lf->flags, retflag, &nretflags, F_ATTACHEDTO, F_CANWILL, F_CHARMEDBY, F_FLEEFROM, + F_GRABBEDBY, F_GRABBING, F_BOOSTSPELL, F_FEIGNINGDEATH, F_INJURY, F_NOFLEEFROM, F_PETOF, F_SPOTTED, F_STABBEDBY, F_TARGETCELL, F_TARGETLF, F_NONE); for (i = 0; i < nretflags; i++) { f = retflag[i]; @@ -17146,6 +16846,14 @@ void turneffectslf(lifeform_t *lf) { continue; } } + + // bleeding injuries can stain armour + if ((f->id == F_INJURY) && (f->val[2] == DT_SLASH)) { + object_t *arm; + arm = getequippedob(lf->pack, f->val[1]); + if (arm && !hasobmod(arm, OM_BLOODSTAINED) && pctchance(5)) applyobmod(arm, OM_BLOODSTAINED); + } + if (f->id == F_STABBEDBY) { lifeform_t *lf2; lf2 = findlf(NULL, f->val[0]); @@ -17210,9 +16918,525 @@ void turneffectslf(lifeform_t *lf) { } } // end if f_target or f_targetcell } // end loop through lf flags - } +// returns TRUE on failure (ie. nothing to steal) +int steal(lifeform_t *lf, obpile_t *op, enum FLAG wantflag) { + enum SKILLLEVEL slev; + object_t *o; + int i,nsteals; + int numgot = 0; + int fromground; + char letter = 'a'; + slev = getskill(lf, SK_THIEVERY); + + if (op->owner) { + fromground = B_FALSE; + } else { + fromground = B_TRUE; + } + // + if (slev >= PR_EXPERT) { + nsteals = 2; + } else { + nsteals = 1; + } + + // what do we steal? + for (i = 0; i < nsteals; i++) { + char buf[BUFLEN]; + snprintf(buf, BUFLEN, "Steal what (%d of %d)?", i+1, nsteals); + initprompt(&prompt, buf); + for (o = op->first ; o ; o = o->next) { + int ok = B_TRUE; + if ((slev < PR_SKILLED) && (getobunitweight(o) >= 3)) { + // too heavy to steal + ok = B_FALSE; + } else if ((slev < PR_MASTER) && isequipped(o)) { + // equipped + ok = B_FALSE; + } else if (!canpickup(lf, o, 1)) { + // can't pick it up + ok = B_FALSE; + } else if ((wantflag != F_NONE) && !hasflag(o->flags, wantflag)) { + // don't have the right flag + ok = B_FALSE; + } + if (ok) { + getobname(o, buf, 1); + addchoice(&prompt, fromground ? letter++ : o->letter, buf, NULL, o); + } + } + if (prompt.nchoices > 1) { + if (isplayer(lf) && (slev >= PR_ADEPT)) { + addchoice(&prompt, '-', "Nothing", NULL, NULL); + // pick what you want + getchoice(&prompt); + o = (object_t *)prompt.result; + } else { + // random + o = (object_t *)prompt.choice[rnd(0,prompt.nchoices-1)].data; + } + if (o) { + killflagsofid(o->flags, F_SHOPITEM); + o = moveob(o, lf->pack, 1); + if (o) { + char obname[BUFLEN]; + char lfname[BUFLEN]; + char targname[BUFLEN]; + getlfname(lf, lfname); + getobname(o, obname, 1); + if (op->owner) { + getlfname(op->owner, targname); + if (isplayer(lf)) { + msg("You steal %s from %s!", getlfcol(op->owner, CC_BAD), obname, targname); + } else if (cansee(player, lf)) { + msg("^%c%s steals %s from %s!", getlfcol(op->owner, CC_BAD), lfname, obname, targname); + } + } else { + if (isplayer(lf)) { + msg("You steal %s!", obname); + } else if (cansee(player, lf)) { + msg("%s steals %s!", lfname, obname); + } + } + numgot++; + } + } + } else { + // nothing left to steal + + if (numgot == 0) { + return B_TRUE; + } + break; + } + } // end foreach steal + + if (isplayer(lf)) pleasegodmaybe(R_GODTHIEVES, 5+numgot); + + return B_FALSE; +} + + +int stone(lifeform_t *lf) { + char lfname[BUFLEN]; + char statname[BUFLEN]; + int failed = B_FALSE; + + if (!lfcanbestoned(lf)) { + failed = B_TRUE; + } + if (failed) { + return B_TRUE; + } + + getlfname(lf, lfname); + + + snprintf(statname, BUFLEN, "statue of a %s", lf->race->name); + addob(lf->cell->obpile, statname); + + // kill lifeform + addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); + addflag(lf->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); + + if (cansee(player, lf)) { + msg("^%c%s %s to stone!", getlfcol(lf, CC_VBAD), lfname, isplayer(lf) ? "turn" : "turns"); + } + setlastdam(lf, "petrification"); + die(lf); + return B_FALSE; +} + +void stopeating(lifeform_t *lf) { + flag_t *f; + f = lfhasflag(lf, F_EATING); + if (f) { + if (isplayer(lf)){ + msg("You stop eating."); + } + killflagsofid(lf->flags, F_EATING); + } + +} + +void stopresting(lifeform_t *lf) { + flag_t *f; + + // stop training + f = hasflag(lf->flags, F_TRAINING); + if (f) { + killflag(f); + if (isplayer(lf)) { + msg("Your training is interrupted!"); + } else if (cansee(player, lf)) { + char buf[BUFLEN]; + getlfname(lf, buf); + capitalise(buf); + msg("%s stops training.",buf); + } + statdirty = B_TRUE; + } + // stop resting! + f = isresting(lf); + if (f) { + killflag(f); + if (isplayer(lf)) { + msg("Your rest is interrupted!"); + } else if (cansee(player, lf)) { + char buf[BUFLEN]; + getlfname(lf, buf); + msg("%s stops resting.",buf); + } + statdirty = B_TRUE; + } +} + +void stoprunning(lifeform_t *lf) { + flag_t *f; + f = hasflag(lf->flags, F_RUNNING); + if (f) { + killflag(f); + } + +} + +void stopsprinting(lifeform_t *lf) { + flag_t *f; + f = lfhasflag(lf, F_SPRINTING); + if (f && f->val[0]) { + killflag(f); + } + +} + +int stun(lifeform_t *lf, int nturns) { + if (lfhasflag(lf, F_ASLEEP)) { + return B_TRUE; + } + if (isplayer(lf)) { + msg("You are stunned!"); + } else if (cansee(player, lf)) { + char buf[BUFLEN]; + getlfname(lf, buf); + msg("%s is stunned!", buf); + } + taketime(lf, getactspeed(lf)*nturns); + return B_FALSE; +} + +// wrapper for addmonster(), but announce that it appears +// and make it worth zero xp. +// +// for unique monsters, they move from their current position. +lifeform_t *summonmonster(lifeform_t *caster, cell_t *c, enum RACE rid, char *racename, int lifetime, int wantfriendly) { + lifeform_t *newlf = NULL; + char buf[BUFLEN]; + + newlf = addmonster(c, rid, racename, B_FALSE, 1, B_FALSE, NULL); + if (newlf) { + if (haslos(player, c)) { + //char *newbuf; + getlfnamea(newlf, buf); + capitalise(buf); + msg("%s appears!", buf); + } + + if (!hasflag(newlf->flags, F_UNIQUE)) { + // summoned + if (caster) { + addflag(newlf->flags, F_SUMMONEDBY, caster->id, lifetime, NA, NULL); + if (wantfriendly) { + addflag(newlf->flags, F_PETOF, caster->id, NA, NA, NULL); + if (areallies(player, caster)) { + makefriendly(newlf, PERMENANT); + } + } + } + // not worth any xp + killflagsofid(newlf->flags, F_XPVAL); + addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL); + } + } + return newlf; +} + + +int takeoff(lifeform_t *lf, object_t *o) { + flag_t *f; + char obname[BUFLEN]; + char buf[BUFLEN]; + + if (!isarmour(o)) { + return unweild(lf, o); + } + + getobname(o, obname, 1); + + if (!cantakeoff(lf, o)) { + switch (reason) { + case E_CURSED: + if (isplayer(lf)) { + msg("Your %s appears to be stuck to you!", noprefix(obname)); + o->blessknown = B_TRUE; + } + // still take time + taketime(lf, getactspeed(lf)); + break; + case E_NOTEQUIPPED: + if (isplayer(lf)) { + msg("You are not wearing that!"); + } + break; + default: + if (isplayer(lf)) { + msg("For some reason, you cannot remove your %s!", noprefix(obname)); + } + // still take time + taketime(lf, getactspeed(lf)); + break; + } + return B_TRUE; + } + + // remove the equipped flag + f = hasflag(o->flags, F_EQUIPPED); + killflag(f); + + taketime(lf, getactspeed(lf)); + if ((gamemode == GM_GAMESTARTED)) { + if (isplayer(lf)) { + msg("You take off %s.", obname); + statdirty = B_TRUE; + } else if (cansee(player, lf)) { + getlfname(lf, buf); + capitalise(buf); + msg("%s takes off %s.", buf, obname); + } + + } + + // lose flags + loseobflags(lf, o, F_EQUIPCONFER); + + f = hasflag(o->flags, F_CREATEDBYSPELL); + if (f) stopspell(lf, f->val[0]); + + if (obproduceslight(o)) { + calclight((getoblocation(o))->map); + setlosdirty(lf); + //precalclos(lf); + drawscreen(); + } + + return B_FALSE; +} + +void taketime(lifeform_t *lf, long howlong) { + int db = B_FALSE; + map_t *map; + + if (notime || lfhasflag(lf, F_NOTIME)) { + return; + } + + /* + if (isplayer(lf)) { + statdirty = B_TRUE; + } + */ + + map = lf->cell->map; + + assert(howlong > 0); + + if (db && (gamemode == GM_GAMESTARTED) && cansee(player, lf)) { + dblog("lfid %d (%s) spending %d time\n",lf->id,lf->race->name, howlong); + } + // inc timespent + lf->timespent += howlong; + assert(lf->timespent >= 0); + + // time-based effects on lifeforms (eg hp regeneration) go here... + + // TODO: decrement lifeform's (or their object's) temporary flags + + + // if you don't have a map, start forgetting the dungeon + if (isplayer(lf)) { + if (!lfhasflag(lf, F_PHOTOMEM) && (getskill(lf, SK_CARTOGRAPHY) < PR_SKILLED)) { + lf->forgettimer += ((float)howlong / 500.0); + if (lf->forgettimer > 1) { + int amt; + + // TODO: modify using race memory + amt = (int)floor(lf->forgettimer); + forgetcells(lf->cell->map, amt); + lf->forgettimer -= amt; + } + } + } + + // now move player up in linked list... + sortlf(map, lf); +} + +int throwat(lifeform_t *thrower, object_t *o, cell_t *where) { + if (!hasbp(thrower, BP_HANDS)) { + if (isplayer(thrower)) msg("You have no hands to throw with!"); + return B_TRUE; + } + taketime(thrower, getactspeed(thrower)); + return fireat(thrower, o, 1, where, getthrowspeed(getattr(thrower, A_STR)), NULL); +} + +// lf effects which happen every xx ticks +// IMPORTANT - don't call taketime() during this function. +void timeeffectslf(lifeform_t *lf) { + object_t *o, *nexto; + flag_t *f,*nextf; + int dir; + + // make SURE we don't take any time! + notime = B_TRUE; + + // decrement flags + timeeffectsflags(lf->flags); + + // remove effects from expired poison + for (f = lf->flags->first ; f; f = nextf) { + nextf = f->next; + if (f->lifetime == FROMPOISON) { + if (!lfhasflagval(lf, F_POISONED, f->obfrom, NA, NA, NULL)) { + killflag(f); + } + } + } + + if (lfhasflag(lf, F_INTERRUPTED)) { + interrupt(lf); + killflagsofid(lf->flags, F_INTERRUPTED); + } + + if (isdead(lf)) { + killflagsofid(lf->flags, F_NOTIME); + return; + } + + // revert to original form if a polymorph just expired + if (lf->polyrevert) { + enum RACE rid = R_NONE; + race_t *r; + flag_t *ff; + // change back + ff = lfhasflag(lf, F_ORIGRACE); + if (ff) { + rid = ff->val[0]; + } else { + rid = R_NONE; // should never happen! + } + r = findrace(rid); + if (r) { + setrace(lf, r->id, B_TRUE); + } else { + if (isplayer(lf)) { + msg("For some reason, you are unable to revert to your original form!"); + } + } + lf->polyrevert = B_FALSE; + } + + + // time effects on lifeform's objects + for (o = lf->pack->first ; o ; o = nexto) { + nexto = o->next; + + f = hasflag(o->flags, F_CREATEDBYSPELL); + if (f && !hasactivespell(lf, f->val[0])) { + killob(o); + continue; + } + + timeeffectsob(o); + } + + // holes in the floor/roof + for (dir = D_UP; dir <= D_DOWN; dir++) { + int donesomething = B_TRUE; + o = hasobwithflagval(lf->cell->obpile, F_PIT, dir, NA, NA, NULL); + while (o && donesomething) { + int willfall = B_FALSE; + donesomething = B_FALSE; + if ((dir == D_DOWN) && !isairborne(lf)) { + willfall = B_TRUE; + } else if ((dir == D_UP) && lfhasflag(lf, F_LEVITATING)) { + willfall = B_TRUE; + } + + if (willfall) { + usestairs(lf, o, B_FALSE); + donesomething = B_TRUE; + o = hasobwithflagval(lf->cell->obpile, F_PIT, dir, NA, NA, NULL); + } + } + } + + notime = B_FALSE; +} + +// return B_TRUE on failure. +int tryclimb(lifeform_t *lf, cell_t *where, char *towhat) { + // if you have a rope or there's an adjacent wall, you can try + // to climb up + int adjwalls; + char lfname[BUFLEN]; + getlfname(lf, lfname); + adjwalls = countadjwalls(where); + if (adjwalls || hasobwithflag(lf->pack, F_HELPSCLIMB)) { + if (isplayer(lf)) { + msg("You start climbing..."); + } else if (cansee(player, lf)) { + msg("%s starts climbing...", lfname); + } + + taketime(lf, getactspeed(lf)); + + // base difficulty of 20 + if (skillcheck(lf, SC_CLIMB, 20, (countadjwalls(where)+1)/2)) { + // you made it! + if (isplayer(lf)) { + msg("You reach %s.", towhat); + } else if (cansee(player, lf)) { + msg("%s reaches %s.", towhat); + } + // train climbing + practice(lf, SK_CLIMBING, 1); + // continue... + + } else { + // you fall. + if (isplayer(lf)) { + msg("You fall to the ground!"); + } else if (cansee(player, lf)) { + msg("%s falls to the ground!", lfname); + } + fall(lf, NULL, B_FALSE); // this will take some time. + losehp(lf, roll("1d6"), DT_FALL, NULL, "a fall while climbing"); + return B_TRUE; + } + } else { // no rope or adjacent walls + if (isplayer(lf)) { + msg("You can't reach the roof!"); + } + return B_TRUE; + } + + // success + return B_FALSE; +} + + // returns B_TRUE if the action which involved touching this should fail int touch(lifeform_t *lf, object_t *o) { flag_t *f; @@ -17409,7 +17633,8 @@ int unweild(lifeform_t *lf, object_t *o) { if (obproduceslight(o)) { calclight((getoblocation(o))->map); - precalclos(lf); + setlosdirty(lf); + //precalclos(lf); drawscreen(); } @@ -17736,8 +17961,9 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose) { if (isplayer(lf)) { statdirty = B_TRUE; needredraw = B_TRUE; - calclight(player->cell->map); - precalclos(lf); + calclight(lf->cell->map); + setlosdirty(lf); + //precalclos(lf); drawscreen(); } @@ -17806,6 +18032,7 @@ int validateraces(void) { // add a fake lf lf = addlf(&fakecell, r->id, 1); + givestartskills(lf, lf->flags); if (!hasflag(r->flags, F_SIZE)) { printf("ERROR in race '%s' - missing F_SIZE.\n", r->name); @@ -17840,6 +18067,7 @@ int validateraces(void) { if (sp->obclass->id == OC_SPELL) { if ((f->id == F_CANWILL) || hasflagval(r->flags, F_HASSKILL, SK_SPELLCASTING, NA, NA, NULL) || + hasflagval(r->flags, F_STARTSKILL, SK_SPELLCASTING, NA, NA, NULL) || (school == SS_ALLOMANCY) || (school == SS_MENTAL) ) { int power; diff --git a/lf.h b/lf.h index 9718c5e..c948092 100644 --- a/lf.h +++ b/lf.h @@ -50,6 +50,7 @@ int checkfordrowning(lifeform_t *lf, object_t *o); int check_rest_ok(lifeform_t *lf); //void checkxp(enum RACE rid); float comparelfs(lifeform_t *lf1, lifeform_t *lf2); +int confuse(lifeform_t *lf, int howlong); int countinnateattacks(lifeform_t *lf); int countmoney(lifeform_t *lf); int countnearbyallies(lifeform_t *lf); @@ -61,10 +62,12 @@ void die(lifeform_t *lf); int digcell(lifeform_t *lf, cell_t *c, object_t *o); int digdown(lifeform_t *lf, object_t *o); int digup(lifeform_t *lf, object_t *o); +void do_eyesight_adjust(lifeform_t *lf); void dumplev(void); void dumplf(void); void dumpxp(void); int eat(lifeform_t *lf, object_t *o); +void endlfturn(lifeform_t *lf); void enhancerandomskill(lifeform_t *lf); void enhanceskills(lifeform_t *lf); void extinguishlf(lifeform_t *lf); @@ -125,6 +128,7 @@ int gethearingrange(lifeform_t *lf); int gethidemodifier(lifeform_t *lf); int gethitdice(lifeform_t *lf); int gethppct(lifeform_t *lf); +enum COLOUR gethungercol(enum HUNGER hlev); enum HUNGER gethungerlevel(int hunger); char *gethungername(lifeform_t *lf, enum HUNGER hunger, char *buf); int gethungerval(lifeform_t *lf); @@ -150,7 +154,7 @@ float getmaxliftweight(lifeform_t *lf); int getmaxmp(lifeform_t *lf); float getmaxpushweight(lifeform_t *lf); int getmr(lifeform_t *lf); -int getvisrange(lifeform_t *lf); +int getvisrange(lifeform_t *lf, int useambient); void idxtoxy(lifeform_t *lf, int idx, int *x, int *y); void setviscell(lifeform_t *lf, cell_t *cell, int how); int getviscell(lifeform_t *lf, cell_t *cell); @@ -235,7 +239,6 @@ int isblind(lifeform_t *lf); enum BURDENED isburdened(lifeform_t *lf); int ischarmable(lifeform_t *lf); int isdead(lifeform_t *lf); -flag_t *isdrunk(lifeform_t *lf); object_t *isdualweilding(lifeform_t *lf); int isfleeing(lifeform_t *lf); int isfreebp(lifeform_t *lf, enum BODYPART bp); @@ -264,6 +267,7 @@ int isswimming(lifeform_t *lf); int isundead(lifeform_t *lf); flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt); int isweaponskill(enum SKILL skid); +enum FLAG iswoozy(lifeform_t *lf); void killjob(job_t *job); void killlf(lifeform_t *lf); void killrace(race_t *race); @@ -316,12 +320,14 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph); void setlastdam(lifeform_t *lf, char *buf); //void setlftarget(lifeform_t *lf, lifeform_t *victim); int setlfmaterial(lifeform_t *lf, enum MATERIAL id); +void setlosdirty(lifeform_t *lf); int shoot(lifeform_t *lf); int skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod); int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *result); int skillcheckvs(lifeform_t *lf1, enum CHECKTYPE ct1, int mod1, lifeform_t *lf2, enum CHECKTYPE ct2, int mod2); int slipon(lifeform_t *lf, object_t *o); void sortlf(map_t *map, lifeform_t *lf); +void startlfturn(lifeform_t *lf); int steal(lifeform_t *lf, obpile_t *op, enum FLAG wantflag); int stone(lifeform_t *lf); void stopeating(lifeform_t *lf); @@ -336,7 +342,6 @@ void taketime(lifeform_t *lf, long howlong); int throwat(lifeform_t *thrower, object_t *o, cell_t *where); void timeeffectslf(lifeform_t *lf); int tryclimb(lifeform_t *lf, cell_t *where, char *towhat); -void turneffectslf(lifeform_t *lf); int touch(lifeform_t *lf, object_t *o); void unpoison(lifeform_t *lf); void unsummon(lifeform_t *lf, int vanishobs); diff --git a/map.c b/map.c index eb9fb4f..dc19aa8 100644 --- a/map.c +++ b/map.c @@ -50,8 +50,8 @@ cell_t *addcell(map_t *m, int x, int y) { cell->x = x; cell->y = y; cell->habitat = m->habitat; - setcelltype(cell, cell->habitat->solidcelltype); cell->obpile = addobpile(NOOWNER, cell, NOOB); + setcelltype(cell, cell->habitat->solidcelltype); cell->lf = NULL; cell->room = NULL; cell->lit = L_NOTLIT; @@ -67,7 +67,7 @@ cell_t *addcell(map_t *m, int x, int y) { return cell; } -habitat_t *addhabitat(enum HABITAT id, char *name, enum CELLTYPE emptycell, enum CELLTYPE solidcell, int thingchance, int obchance, int vaultchance) { +habitat_t *addhabitat(enum HABITAT id, char *name, enum CELLTYPE emptycell, enum CELLTYPE solidcell, int thingchance, int obchance, int vaultchance, int maxvisrange) { habitat_t *a; // add to the end of the list if (firsthabitat == NULL) { @@ -92,6 +92,7 @@ habitat_t *addhabitat(enum HABITAT id, char *name, enum CELLTYPE emptycell, enum a->randthingpct = thingchance; a->randobpct = obchance; a->randvaultpct = vaultchance; + a->maxvisrange = maxvisrange; return a; } @@ -472,8 +473,43 @@ map_t *getmapindir(map_t *src, int dir) { return other; } +// +int getmapmaxvisrange(map_t *m) { + int maxrange; + + maxrange = m->habitat->maxvisrange; + + // modify for darkness outside ? + if (isoutdoors(m)) { + int hours,mins,secs; + float pct; + splittime(&hours,&mins,&secs); + pct = ((float)mins/59.0) * 100.0; + if (hours == 6) { // ie. 6am - 7am + // getting lighter. as minutes approach 59, + // visrange gets closer to maximum. + maxrange = pctof( pct, maxrange); + limit(&maxrange, 1, NA); + } else if (hours == 18) { // ie. 6pm-7pm + // getting darker. as minutes approach 59, + // visrange gets closer to zero. + maxrange = pctof( 100 - pct, maxrange); + limit(&maxrange, 1, NA); + } + } else if (m->habitat->id == H_DUNGEON) { + // in dungeon, reduce distance based on depth (ie. ambient light) + maxrange -= m->depth; + } + + limit(&maxrange, 0, MAXVISRANGE); + + return maxrange; +} + // populates retcell[] with all cells within given radius of centre -void getradiuscells(cell_t *centre, int radius, int dirtype, enum LOFTYPE needlof, int wantcentre, cell_t **retcell, int *ncells) { +// if 'scatter' is >0, then not all cells will be returned - as you approach the edge of the radius, +// chances of getting the cells are lowered +void getradiuscells(cell_t *centre, int radius, int dirtype, enum LOFTYPE needlof, int wantcentre, cell_t **retcell, int *ncells, int scatterdensity) { int (*distfunc)(cell_t *, cell_t *); int x,y; cell_t *c; @@ -491,10 +527,22 @@ void getradiuscells(cell_t *centre, int radius, int dirtype, enum LOFTYPE needlo for (y = centre->y - radius; y <= centre->y + radius; y++) { for (x = centre->x - radius; x <= centre->x + radius; x++) { c = getcellat(centre->map, x,y); - if (c && haslof(centre, c, needlof, NULL) && (distfunc(centre, c) <= radius) && - (wantcentre || (c != centre)) ) { - retcell[*ncells] = c; - (*ncells)++; + if (c) { + int distance; + distance = distfunc(centre, c); + if (haslof(centre, c, needlof, NULL) && (distance <= radius) && + (wantcentre || (c != centre)) ) { + int chance; + if (scatterdensity) { + chance = 100 - (((float)distance / (float)radius) * scatterdensity); + } else { + chance = 100; + } + if (pctchance(chance)) { + retcell[*ncells] = c; + (*ncells)++; + } + } } } } @@ -939,6 +987,42 @@ void clearcell(cell_t *c) { c->knownglyph.colour = C_GREY; } } +void clearcell_exceptflags(cell_t *c, ... ) { + va_list args; + enum FLAG exception[MAXCANDIDATES]; + int nexceptions = 0,i; + object_t *o,*nexto; + va_start(args, c); + exception[nexceptions] = va_arg(args, enum FLAG); + while (exception[nexceptions] != F_NONE) { + nexceptions++; + exception[nexceptions] = va_arg(args, enum FLAG); + } + va_end(args); + assert(nexceptions < MAXCANDIDATES); + + if (c->lf && !isplayer(c->lf)) { + killlf(c->lf); + } + + for (o = c->obpile->first ; o ; o = nexto) { + int exclude = B_FALSE; + nexto = o->next; + for (i = 0; i < nexceptions; i++) { + if (hasflag(o->flags, exception[i])) { + exclude = B_TRUE; + break; + } + } + if (!exclude) killob(o); + } + + if (gamemode == GM_GAMESTARTED) { + c->known = B_FALSE; + c->knownglyph.ch = ' '; + c->knownglyph.colour = C_GREY; + } +} // returns true if something happened int dowaterspread(cell_t *c) { @@ -1199,6 +1283,9 @@ void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer) { if (g->ch == '.') { g->ch = ' '; } + // out of LOS - show as dark + // TODO: if terminal supports it, use C_DARKGREY instead. + g->colour = C_BLUE; } break; } @@ -1827,7 +1914,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ if (!roomvault[i]) { int rx,ry; // just do a normal room - createroom(map, i, NA, NA, 0, 0, &rx, &ry, &roomw[i],&roomh[i], 50, B_FALSE); + createroom(map, i, NA, NA, DEF_VAULTMARGIN, DEF_VAULTMARGIN, &rx, &ry, &roomw[i],&roomh[i], 50, B_FALSE); roomvault[i] = B_FALSE; } } @@ -2006,6 +2093,8 @@ void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t int density; cell_t *c; char buf[BUFLEN]; + cell_t *retcell[MAXCANDIDATES]; + int nretcells; //object_t *o; // fill entire maze with emptiness @@ -2035,62 +2124,39 @@ void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t } // clearings for (i = 0; i < nclearings; i++) { - int w; + int w,n; c = getrandomcell(map); w = rnd(MINCLEARINGRADIUS,MAXCLEARINGRADIUS); - for (y = c->y - w; y <= c->y + w; y++) { - for (x = c->x - w; x <= c->x + w; x++) { - cell_t *newc; - int dist = 999; - newc = getcellat(map, x, y); - if (newc) { - dist = getcelldistorth(newc, c); - if (dist <= w) { - int dirtchance; - // kill all obs here - while (newc->obpile->first) killob(newc->obpile->first); - - // change it into dirt. - // ie. at centre (dist=0) dirt chance is 100% - // ie. at max distance, dirt chance is 30% - dirtchance = 100 - (((float)dist / (float)w) * 70); - if (rnd(1,100) <= dirtchance) { - setcelltype(newc, CT_DIRT); - } - } - } - } + // clear obs in all clearing cells + getradiuscells(c, w, DT_ORTH, LOF_DONTNEED, B_TRUE, retcell, &nretcells, B_FALSE); + for (n = 0; n < nretcells; n++) { + // kill all obs here + while (retcell[n]->obpile->first) killob(retcell[n]->obpile->first); + } + + // fill some cells with dirt + getradiuscells(c, w, DT_ORTH, LOF_DONTNEED, B_TRUE, retcell, &nretcells, 70); + for (n = 0; n < nretcells; n++) { + setcelltype(retcell[n], CT_DIRT); } } break; case 2: // add clusters of trees nclearings = rnd(5,10); for (i = 0; i < nclearings; i++) { - int w; + int w,n; c = getrandomcell(map); while (c->lf) c = getrandomcell(map); w = rnd(MINCLEARINGRADIUS,MAXCLEARINGRADIUS); - for (y = c->y - w; y <= c->y + w; y++) { - for (x = c->x - w; x <= c->x + w; x++) { - cell_t *newc; - int dist = 999; - newc = getcellat(map, x, y); - if (newc) { - dist = getcelldistorth(newc, c); - if (dist <= w) { - int treechance; - treechance = 100 - (((float)dist / (float)w) * 70); - if (rnd(1,100) <= treechance) { - switch (rnd(0,1)) { - default: case 0: strcpy(buf, "tree"); break; - case 1: strcpy(buf, "shrub"); break; - } - addob(c->obpile, buf); - } - } - } + + getradiuscells(c, w, DT_ORTH, LOF_DONTNEED, B_TRUE, retcell, &nretcells, 80); + for (n = 0; n < nretcells; n++) { + switch (rnd(0,1)) { + default: case 0: strcpy(buf, "tree"); break; + case 1: strcpy(buf, "shrub"); break; } + addob(retcell[n]->obpile, buf); } } break; @@ -2798,7 +2864,7 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { // if we hit a cell of this roomid, mark this dir as invalid. for (d = D_N; d <= D_W; d++) { dist[d] = 0; - hitsedge[d] = B_TRUE; + hitsedge[d] = B_FALSE; sameroom[d] = B_FALSE; c = getcellindir(startcell, d); while (c) { @@ -2820,7 +2886,6 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { } else if (cellwalkable(NULL, c, NULL)) { if (!wantfilled || c->filled) { // walkable and not in this vault. finished. - hitsedge[d] = B_FALSE; directendcell[d] = c; if (db) dblog(" can make %s path (hits empty cell at dist %d)", getdirname(d), dist[d]); break; @@ -2839,7 +2904,6 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { cellwalkable(NULL, pcell, NULL)) { if (!wantfilled || c->filled) { // finished. - hitsedge[d] = B_FALSE; directendcell[d] = c; if (db) dblog(" can make %s path (hits adjacent empty cell at dist %d)", getdirname(d), dist[d]); break; @@ -2851,8 +2915,14 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { // check next cell c = getcellindir(c, d); // getting the same cell! } + if (!c) { + if (db) dblog(" going %s hits edge of map.", getdirname(d)); + hitsedge[d] = B_TRUE; + } if (dist[d] != 999) { - if (dist[d] < mindist) mindist = dist[d]; + if (!hitsedge[d]) { + if (dist[d] < mindist) mindist = dist[d]; + } if (dist[d] > maxdist) maxdist = dist[d]; } } @@ -2911,14 +2981,17 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { int turndist = 0; c2 = getcellindir(c, perpdir[n]); - perpcell[nperpcells] = c2; // this will be used if we need to make 2 turns - perpturncell1[nperpcells] = c; - perpturndir1[nperpcells] = perpdir[n]; - nperpcells++; while (c2) { int gotsolution = B_FALSE; turndist++; + + + perpcell[nperpcells] = c2; // this will be used if we need to make 2 turns + perpturncell1[nperpcells] = c; + perpturndir1[nperpcells] = perpdir[n]; + nperpcells++; + if ((roomid >= 0) && (getroomid(c2) == roomid)) { if (wantfilled && c2->type->solid) { // see EXCEPTION above. @@ -2991,21 +3064,28 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { c = getcellindir(c, turndir); } } else { - // We need to make 3 turns. + // We need to make 2 turns. // for each perpcell[], look in startdir + diropposite(startdir) int dir3[2],i,n; cell_t *turncell2 = NULL; int turndir2; dir3[0] = startdir; dir3[1] = diropposite(startdir); + if (db) dblog(" Need to make two turns. Searching %s and %s from each perpcell.", getdirname(dir3[0]), + getdirname(dir3[1])); for (i = 0; i < nperpcells; i++) { - for (n = 0; n < 1; n++) { + for (n = 0; n < 2; n++) { cell_t *c2; int turndist = 0; + + if (db) dblog_nocr("looking %s from %d,%d: ", getdirname(dir3[n]), + perpcell[i]->x, perpcell[i]->y); + c2 = getcellindir(perpcell[i], dir3[n]); while (c2) { int gotsolution = B_FALSE; turndist++; + if (db) dblog_nocr("(%d,%d)",c2->x,c2->y); if ((roomid >= 0) && (getroomid(c2) == roomid)) { if (wantfilled && c2->type->solid) { // see EXCEPTION above. @@ -3040,29 +3120,27 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { } } if (gotsolution) { - if (db) dblog(" Solution found: Walk %d %s, then %d %s.", - startdist, getdirname(startdir), - turndist, getdirname(perpdir[n])); + turncell = perpturncell1[i]; + turndir = perpturndir1[i]; + turncell2 = perpcell[i]; + turndir2 = dir3[n]; - turncell = perpturncell1[i]; - turndir = perpturndir1[i]; - turncell2 = perpcell[i]; - turndir2 = dir3[n]; - - endcell = c2; + endcell = c2; break; } // check next cell - c2 = getcellindir(c2, perpdir[n]); + c2 = getcellindir(c2, dir3[n]); } // end while c2 if (turncell2) break; + + if (db) dblog(""); } // end for n=1-2 if (turncell2) break; } // end foreach perpcell // TODO: if we find a solution, fill in turncell2 and make path. if (turncell2) { - if (db) dblog(" 2turn Solution found: Walk %s, then %s, then %s.", + if (db) dblog(" Twoturn solution found: Walk %s, then %s, then %s.", getdirname(startdir), getdirname(turndir), getdirname(turndir2)); // make a path up to the turn point. @@ -3094,6 +3172,7 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { } } else { if (db) dblog(" Cannot find a way to link up."); + assert(0 == 1); // for debugging } return B_TRUE; } @@ -3189,6 +3268,13 @@ int linkexits(map_t *m, int roomid) { // part of this room for (i = 0; i < nposs; i++) { int ncorridors = 0,d; + + // if exit is solid and COMPLETELY surrounded by solid, ignore it. + if (c->type->solid && (countcellexits(c) == 0)){ + if (db) dblog("cell is solid and surrounded by solids. ignoring."); + continue; + } + if (db) dblog("linking exit #%d",i); for (d = D_N; d <= D_W; d++) { @@ -3316,8 +3402,8 @@ int createroom(map_t *map, int roomid, int overrideminw, int overrideminh, int x for (x = minx; x <= maxx; x++) { cell = getcellat(map, x, y); if (cell) { - // kill contents - clearcell(cell); + // kill contents, EXCEPT for staircases! + clearcell_exceptflags(cell, F_CLIMBABLE, F_NONE); // make it a border or room if ((y == miny) || (y == maxy) || (x == minx) || (x == maxx)) { @@ -4321,11 +4407,11 @@ void initmap(void) { int vx[4],vy[4],i; // habitats // thingchance, obchance, vaultchance - addhabitat(H_DUNGEON, "dungeon", CT_CORRIDOR, CT_WALL, 3, 50, 30); - addhabitat(H_FOREST, "forest", CT_GRASS, CT_WALL, 3, 75, 0); - addhabitat(H_HEAVEN, "heaven", CT_CORRIDOR, CT_WALL, 0, 0, 0); - addhabitat(H_PIT, "pit", CT_CORRIDOR, CT_WALL, 0, 0, 0); - addhabitat(H_VILLAGE, "village", CT_GRASS, CT_WALL, 3, 70, 0); + addhabitat(H_DUNGEON, "dungeon", CT_CORRIDOR, CT_WALL, 3, 50, 30, 6); + addhabitat(H_FOREST, "forest", CT_GRASS, CT_WALL, 3, 75, 0, MAXVISRANGE); + addhabitat(H_HEAVEN, "heaven", CT_CORRIDOR, CT_WALL, 0, 0, 0, MAXVISRANGE); + addhabitat(H_PIT, "pit", CT_CORRIDOR, CT_WALL, 0, 0, 0, 5); + addhabitat(H_VILLAGE, "village", CT_GRASS, CT_WALL, 3, 70, 0, MAXVISRANGE); // cell types addcelltype(CT_WALL, "rock wall", '#', C_GREY, B_SOLID, B_OPAQUE, MT_STONE, 0); @@ -4992,6 +5078,7 @@ int remove_deadends(map_t *m, int howmuch) { c = m->cell[n]; if (countcellexits(c) == 1) { // erase this cell + clearcell(c); setcelltype(c, solidcell); count++; } @@ -5050,7 +5137,7 @@ void setcellknown(cell_t *cell, int forcelev) { void setcellknownradius(cell_t *centre, int forcelev, int radius, int dirtype) { cell_t *cell[MAXCANDIDATES]; int ncells,i; - getradiuscells(centre, radius, dirtype, LOF_DONTNEED, B_TRUE, cell, &ncells); + getradiuscells(centre, radius, dirtype, LOF_DONTNEED, B_TRUE, cell, &ncells, B_FALSE); for (i = 0; i < ncells; i++) { cell_t *c; c = cell[i]; @@ -5062,6 +5149,9 @@ void setcelltype(cell_t *cell, enum CELLTYPE id) { assert(cell); cell->type = findcelltype(id); assert(cell->type); + if (cell->type->solid) { + assert(!cell->obpile->first); + } if ((gamemode == GM_GAMESTARTED) && haslos(player, cell)) { needredraw = B_TRUE; } diff --git a/map.h b/map.h index 5c78a38..4270272 100644 --- a/map.h +++ b/map.h @@ -1,7 +1,7 @@ #include "defs.h" cell_t *addcell(map_t *map, int x, int y); -habitat_t *addhabitat(enum HABITAT id, char *name, enum CELLTYPE emptycell, enum CELLTYPE solidcell, int thingchance, int obchance, int vaultchance); +habitat_t *addhabitat(enum HABITAT id, char *name, enum CELLTYPE emptycell, enum CELLTYPE solidcell, int thingchance, int obchance, int vaultchance, int maxvisrange); void addhomeobs(lifeform_t *lf); map_t *addmap(void); lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int amt, int autogen, int *nadded); @@ -14,6 +14,7 @@ regiontype_t *addregiontype(enum REGIONTYPE id, char *name, enum HABITAT default int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, int doorpct, int dooropenchance); int cellhaslos(cell_t *c1, cell_t *dest); void clearcell(cell_t *c); +void clearcell_exceptflags(cell_t *c, ...); int dowaterspread(cell_t *c); void fix_reachability(map_t *m); int fix_unreachable_cell(cell_t *badcell); @@ -28,7 +29,8 @@ int getdoorsecretdiff(int depth); flag_t *getmapcoords(map_t *m, int *x, int *y); int getmapdifficulty(map_t *m); map_t *getmapindir(map_t *src, int dir); -void getradiuscells(cell_t *centre, int radius, int dirtype, enum LOFTYPE needlof, int wantcentre, cell_t **retcell, int *ncells); +int getmapmaxvisrange(map_t *m); +void getradiuscells(cell_t *centre, int radius, int dirtype, enum LOFTYPE needlof, int wantcentre, cell_t **retcell, int *ncells, int scatterdensity); int getroomid(cell_t *c); void getroomedge(map_t *m, int roomid, int minx, int miny, int maxx, int maxy, int whichside, cell_t **retcell, int *ncells, int onlywantsolid); object_t *gettopobject(cell_t *where, int forglyph); diff --git a/move.c b/move.c index 42fe517..d98ab71 100644 --- a/move.c +++ b/move.c @@ -897,7 +897,7 @@ int moveeffects(lifeform_t *lf) { f = lfhasflag(lf, F_PAIN); if (f) { - if (!isdrunk(lf)) { + if (!lfhasflag(lf, F_DRUNK)) { int dam; if (isplayer(lf)) { msg("Your body is wracked with pain!"); @@ -1022,7 +1022,8 @@ int movelf(lifeform_t *lf, cell_t *newcell) { if (lfproduceslight(lf)) { calclight(lf->cell->map); } - precalclos(lf); + setlosdirty(lf); + //precalclos(lf); if (isplayer(lf) || cansee(player, lf)) { needredraw = B_TRUE; @@ -1221,7 +1222,8 @@ int movelf(lifeform_t *lf, cell_t *newcell) { // much larger creatures moving will cause our los to be recalculated if (getlfsize(lf) - getlfsize(l) >= 2) { - precalclos(l); + setlosdirty(l); + //precalclos(l); } if (isplayer(l)) { @@ -2133,18 +2135,23 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { char buf[BUFLEN]; int dontclearmsg = B_FALSE; int moveok; - int drunk = B_FALSE; + int rndmove = B_FALSE; flag_t *f; - f = isdrunk(lf); + f = lfhasflag(lf, F_DRUNK); if (f) { if (!hasjob(lf, J_PIRATE)) { if (rnd(1,6) <= ((f->lifetime/TM_DRUNKTIME)+1)) { // randomize move - dir = rnd(DC_N, DC_NW); - drunk = B_TRUE; // ie. you can walk into walls now. + rndmove = B_TRUE; // ie. you can walk into walls now. } } + } else if (iswoozy(lf)) { + rndmove = B_TRUE; + } + + if (rndmove) { + dir = rnd(DC_N, DC_NW); } cell = getcellindir(lf->cell, dir); @@ -2215,7 +2222,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { } // now move to new cell - moveto(lf, cell, drunk ? B_FALSE : onpurpose, dontclearmsg); + moveto(lf, cell, rndmove ? B_FALSE : onpurpose, dontclearmsg); if (onpurpose) { taketime(lf, getmovespeed(lf)); } @@ -2305,7 +2312,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { if (!cell || !haslos(lf, cell)) { if (isplayer(lf)) { // only take damage if we didn't know about this - if ((cell && !cell->known) || isdrunk(lf)) { + if ((cell && !cell->known) || iswoozy(lf)) { snprintf(buf, BUFLEN, "%sing into a %s", getmoveverb(lf), cell ? cell->type->name : "wall"); losehp(lf, 1, DT_BASH, NULL, buf); @@ -2568,8 +2575,9 @@ int walkoffmap(lifeform_t *lf, int dir, int onpurpose) { if (isplayer(lf)) { statdirty = B_TRUE; needredraw = B_TRUE; - calclight(player->cell->map); - precalclos(lf); + calclight(lf->cell->map); + setlosdirty(lf); + //precalclos(lf); drawscreen(); } @@ -2592,7 +2600,7 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) { rdata = NULL; } - if (isdrunk(lf)) { + if (iswoozy(lf)) { return B_TRUE; } diff --git a/nexus.c b/nexus.c index 1bf34b3..4cb73df 100644 --- a/nexus.c +++ b/nexus.c @@ -325,7 +325,8 @@ int main(int argc, char **argv) { // calculate initial light calclight(player->cell->map); // pre-calc line-of-sight for player - precalclos(player); + //precalclos(player); + setlosdirty(player); // don't want any mosnters starting within los/lof of player for (y = 0; y < player->cell->map->h; y++) { @@ -360,7 +361,7 @@ int main(int argc, char **argv) { // basic flow is: // // donextturn() - process a turn for a lifeform - // turneffectslf() Rest effects, Damage from floor objects, etc + // startlfturn() Rest effects, Damage from floor objects, etc // lifeform takes action // checkdeath() - check for object/player death. remove dead things. // timeeffectsworld() Fires burn out, ice melts, etc @@ -567,12 +568,14 @@ void donextturn(map_t *map) { assert(who->timespent == 0); - turneffectslf(who); + startlfturn(who); // calculate light calclight(map); // pre-calculate line of sight for this lifeform - precalclos(who); + //precalclos(who); + // cope with eyesight adjusting to the dark + do_eyesight_adjust(who); // update gun targets autotarget(who); @@ -743,7 +746,10 @@ void donextturn(map_t *map) { if (hasflag(player->flags, F_ASLEEP)) { needredraw = B_FALSE; } - } + + if (!isdead(who)) endlfturn(who); + } // end 'if who' + // check for death etc checkdeath(); @@ -820,9 +826,9 @@ enum COLOUR getpctcol(float num, float max) { } else if (pct >= 50) { return C_BROWN; } else if (pct >= 25) { - return C_RED; + return C_YELLOW; } else { // ie. < 25% - return C_ORANGE; + return C_RED; } return C_ORANGE; } @@ -971,8 +977,8 @@ void initcommands(void) { addcommand(CMD_PICKUP, ',', "Pick up something from the ground."); addcommand(CMD_CLOSE, 'c', "Close a door."); addcommand(CMD_COMMS, 'C', "Communicate with an ally."); - addcommand(CMD_DROP, 'd', "Drop an item."); - addcommand(CMD_DROPMULTI, 'D', "Drop multiple items."); + //addcommand(CMD_DROP, 'd', "Drop an item."); + addcommand(CMD_DROPMULTI, 'd', "Drop one or more items."); addcommand(CMD_EAT, 'e', "Eat something."); addcommand(CMD_EAT, 'E', "Enhance your skills."); addcommand(CMD_MAGIC, 'm', "Use magic or abilities."); @@ -1534,6 +1540,17 @@ void timeeffectsworld(map_t *map, int updategametime) { gamedays++; } } + + // if it's the player's turn, announce sun set/rise + if (isplayer(map->lf) && isoutdoors(map)) { + int h,m,s; + splittime(&h, &m, &s); + if (h == 6) { + msg("The sun is rising."); + } else if (h == 18) { + msg("The sun is setting."); + } + } if (db) dblog("cur time is %ld\n",curtime); } diff --git a/objects.c b/objects.c index 09cd902..52010fa 100644 --- a/objects.c +++ b/objects.c @@ -439,6 +439,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes int wantlit = B_FALSE; int wantrarity = RR_NONE; int wantgoodness = G_NA; + enum MATERIAL wantdiffmat = MT_NOTHING; map_t *targetmap = NULL; // for portals cell_t *targetcell = NULL; // for portals int donesomething; @@ -449,6 +450,8 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes int ndoorflags = 0; char *signtext = NULL; int trapchance = 0; + flag_t *retflag[MAXCANDIDATES]; + int nretflags = 0; // just in case we don't add any addedob[0] = NULL; @@ -619,6 +622,11 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes wantlit = B_TRUE; p += strlen("lit "); donesomething = B_TRUE; + // different materials + } else if (strstarts(p, "silver ")) { + wantdiffmat = MT_SILVER; + p += strlen("silver "); + donesomething = B_TRUE; // rarity } else if (strstarts(p, "common ")) { wantrarity = RR_COMMON; @@ -890,6 +898,22 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes howmany = 1; } + + // we asked for a different material. is this possible? + if ((wantdiffmat != MT_NOTHING) && !hasflagval(ot->flags, F_CANBEDIFFMAT, wantdiffmat, NA, NA, NULL)) { + wantdiffmat = MT_NOTHING; + } + + // chance of being a different material baesd on ob flags + if (wantdiffmat == MT_NOTHING) { + getflags(ot->flags, retflag, &nretflags, F_CANBEDIFFMAT, F_NONE); + for (i = 0; i < nretflags; i++) { + if (pctchance(retflag[i]->val[1])) { + wantdiffmat = retflag[i]->val[0]; break; + } + } + } + if (db) dblog("DB: '%s' -> adding %d x %s",name, howmany, ot->name); @@ -1035,6 +1059,11 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes o = addedob[i]; obloc = getoblocation(o); + + if (wantdiffmat != MT_NOTHING) { + changemat(o, wantdiffmat); + } + // fill in sign text if (signtext) { addflag(o->flags, F_SIGNTEXT, NA, NA, NA, signtext); @@ -1329,7 +1358,6 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes f->val[0] = wantdepth; } } - // chance of masterwork based on wantgoodness switch (wantgoodness) { case G_GREAT: @@ -1587,7 +1615,7 @@ int addobburst(cell_t *where, int range, int dirtype, char *name, lifeform_t *fr redrawpause(); - getradiuscells(where, range, dirtype, needlof, B_TRUE, cell, &ncells); + getradiuscells(where, range, dirtype, needlof, B_TRUE, cell, &ncells, B_FALSE); for (i = 0; i < ncells; i++) { cell_t *c; c = cell[i]; @@ -2194,6 +2222,7 @@ int canseeob(lifeform_t *lf, object_t *o) { enum SKILLLEVEL slev; int cutoffpct; int cutoff; + slev = getskill(lf, SK_PERCEPTION); switch (slev) { case PR_NOVICE: cutoffpct = 80; break; @@ -2279,7 +2308,6 @@ int changemat(object_t *o, enum MATERIAL mat) { material_t *m; flag_t *f, *nextf; - m = findmaterial(mat); if (!m) { return E_FAILED; @@ -2325,14 +2353,13 @@ int changemat(object_t *o, enum MATERIAL mat) { om = findobmod(OM_FROZEN); applyobmod(o, om); } - return B_FALSE; + return B_FALSE; } int checkobnames(char *haystack, char *needle) { char *pluralname; int db = B_FALSE; - // search for exact match if (!strcmp(haystack, needle)) { // found it! @@ -3753,8 +3780,9 @@ int getmaterialvalue(enum MATERIAL mat) { case MT_RUBBER: case MT_GLASS: case MT_SILK: - return 5; case MT_METAL: + return 5; + case MT_SILVER: return 6; case MT_GOLD: return 7; @@ -4104,7 +4132,6 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan int venditem = B_FALSE; flag_t *f; brand_t *br; - obmod_t *om; int hasunknownmod = B_FALSE; cell_t *where; int no_a = B_FALSE; @@ -4388,7 +4415,6 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan } } - // blessed status if (!hasflag(o->flags, F_NOBLESS) && wantblesscurse) { if (showall || isblessknown(o)) { @@ -4429,26 +4455,22 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan case MT_WOOD: strcat(localbuf, "wooden "); break; + case MT_ICE: // we'll use the 'frozen' obmod instead + break; default: - // strcat(localbuf, o->material->name); - // strcat(localbuf, " "); + strcat(localbuf, o->material->name); + strcat(localbuf, " "); break; } } // include mods (ie. a flaming sword) if (wantpremods) { + obmod_t *om; for (om = firstobmod ; om; om = om->next) { - flag_t *omf; - int found = B_FALSE; - for (omf = om->flags->first ; omf ; omf = omf->next){ - if (hasflagval(o->flags, omf->id, omf->val[0], omf->val[1], omf->val[2], NULL)) { - found = B_TRUE; - } - } - if (found) { + if (hasobmod(o, om)) { strcat(localbuf, om->prefix); - } + } } } @@ -4959,15 +4981,15 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth pluralname = strdup(ot->name); } - // blessed or cursed? + // blessed or cursed? 15% chance each way strcpy(cursestr, ""); if (!hasflag(ot->flags, F_NOBLESS)) { int num; num = rnd(1,100); if (num <= 15) { - strcpy(cursestr, "blessed "); - } else if (num <= 30) { strcpy(cursestr, "cursed "); + } else if (num >= 85) { + strcpy(cursestr, "blessed "); } } @@ -5377,6 +5399,18 @@ object_t *hasobofclass(obpile_t *op, enum OBCLASS cid) { return NULL; } +int hasobmod(object_t *o, obmod_t *om) { + flag_t *omf; + int found = B_TRUE; + for (omf = om->flags->first ; omf ; omf = omf->next){ + if (!hasflagval(o->flags, omf->id, omf->val[0], omf->val[1], omf->val[2], NULL)) { + found = B_FALSE; + break; + } + } + return found; +} + object_t *hasobmulti(obpile_t *op, enum OBTYPE *oid, int noids) { object_t *o; int n; @@ -5736,6 +5770,8 @@ void initobjects(void) { addflag(lastmaterial->flags, F_DTIMMUNE, DT_SLASH, NA, NA, NULL); addflag(lastmaterial->flags, F_DTRESIST, DT_CHOP, NA, NA, NULL); addflag(lastmaterial->flags, F_DTRESIST, DT_PROJECTILE, NA, NA, NULL); + addmaterial(MT_SILVER, "silver", 11); + addflag(lastmaterial->flags, F_HARDNESS, 2, NA, NA, NULL); addmaterial(MT_METAL, "metal", 13); addflag(lastmaterial->flags, F_HARDNESS, 5, NA, NA, NULL); addflag(lastmaterial->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); @@ -5748,8 +5784,7 @@ void initobjects(void) { addflag(lastmaterial->flags, F_DTVULN, DT_BASH, NA, NA, NULL); addflag(lastmaterial->flags, F_DTVULN, DT_COLD, NA, NA, NULL); addmaterial(MT_GOLD, "gold", 16); - addflag(lastmaterial->flags, F_HARDNESS, 4, NA, NA, NULL); - //addmaterial(MT_GOLD, "gold", 16); + addflag(lastmaterial->flags, F_HARDNESS, 3, NA, NA, NULL); // object classes addoc(OC_DFEATURE, "Dungeon Features", "Doors, etc.", '\\', C_GREY); @@ -6332,6 +6367,10 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL); addflag(lastot->flags, F_NUMAPPEAR, 1, 15, NA, ""); + addot(OT_CACFRUIT, "cactus fruit", "The nutritous fruit from a cactus plant.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); + addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL); addot(OT_GARLIC, "clove of garlic", "A very pungent clove of raw garlic. ", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, ""); @@ -6683,7 +6722,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); - addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_SMITEGOOD, "smite good", "Instantly deals 1-^bpower*2^n damage to good creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); @@ -7049,6 +7088,12 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 1, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); + // l6 + addot(OT_S_ABSOLUTEZERO, "absolute zero", "Instantly freezes everything around the caster - creatures, objects, even the ground itself.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); /////////////////// // nature /////////////////// @@ -7331,6 +7376,13 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); // l4 + addot(OT_S_HEALINGMAJ, "major healing", "Restores 20-30 health to the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell heals an extra 2 damage per power level."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_CUREPOISON, "cure poison", "Cures the target of all poisons.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); @@ -7348,7 +7400,6 @@ void initobjects(void) { addot(OT_S_STUN, "stun", "Stuns the target, preventing them from taking action for a few seconds.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); - addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); // l2 @@ -7365,6 +7416,13 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL); + addot(OT_S_BAFFLE, "baffle", "Confuses the target, causing them to lose control of their movement.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The target will be confused for ^bpower^n*4 turns."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); // l3 addot(OT_S_PSYARMOUR, "psychic armour", "Mentally block incoming attacks.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The psychic armour's Armour Rating is ^bpower*4^n."); @@ -7387,6 +7445,11 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // l4 + addot(OT_S_STUNMASS, "mass stun", "Stuns all creatures within sight.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addot(OT_S_SLEEP, "sleep", "Puts the target creature to sleep.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how long the sleep effect will last."); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); @@ -7394,13 +7457,6 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); - addot(OT_S_HEALINGMAJ, "major healing", "Restores 20-30 health to the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell heals an extra 2 damage per power level."); - addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); - addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); - addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); - addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // l5 addot(OT_S_CHARM, "charm", "Causes another lifeform to temporary become friendly.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability and duration."); @@ -9018,7 +9074,7 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACYMOD, -10, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_POISONGAS, NA, NULL); - addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -5, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -2, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addot(OT_HELM, "helmet", "A plain metal helmet.", MT_METAL, 2, OC_ARMOUR, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); @@ -9031,7 +9087,7 @@ void initobjects(void) { addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_ACCURACYMOD, -10, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); - addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -4, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -1, NA, NULL); addot(OT_GOLDCROWN, "golden crown", "A heavy gold crown, encrusted with jewels.", MT_GOLD, 5, OC_ARMOUR, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 25, RR_RARE, NULL); addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL); @@ -9060,8 +9116,8 @@ void initobjects(void) { addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); - addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -2, NA, NULL); - addflag(lastot->flags, F_EQUIPCONFER, F_NIGHTVISRANGEMOD, -2, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -1, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_NIGHTVISRANGEMOD, -1, NA, NULL); addflag(lastot->flags, F_TINTED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addot(OT_EYEPATCH, "eyepatch", "A small patch of black material which covers one eye. Scary looking.", MT_CLOTH, 0.01, OC_ARMOUR, SZ_SMALL); @@ -9303,6 +9359,7 @@ void initobjects(void) { addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, ""); addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 15, NA, NULL); addot(OT_NANODART, "nanodart", "A metal dart with a laser-sharpened point.", MT_METAL, 0.5, OC_MISSILE, SZ_TINY); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); @@ -9340,6 +9397,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 15, NA, NULL); addot(OT_BOLT, "bolt", "A sharp metal spike, meant for firing from a crossbow.", MT_METAL, 0.5, OC_MISSILE, SZ_SMALL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); @@ -9347,6 +9405,7 @@ void initobjects(void) { addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, ""); addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL); + addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 20, NA, NULL); addot(OT_BULLET, "bullet", "A regular gun bullet.", MT_METAL, 0.1, OC_MISSILE, SZ_MINI); @@ -9357,8 +9416,9 @@ void initobjects(void) { addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL); addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 10, NA, NULL); - addot(OT_RUBBERBULLET, "rubber bullet", "A rubber gun bullet - does not do much damage.", MT_STONE, 0.05, OC_MISSILE, SZ_MINI); + addot(OT_RUBBERBULLET, "rubber bullet", "A rubber gun bullet - does not do much damage.", MT_RUBBER, 0.05, OC_MISSILE, SZ_MINI); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, ""); addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, ""); @@ -9427,6 +9487,7 @@ void initobjects(void) { addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 2, NA, NA, NULL); + addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 10, NA, NULL); addot(OT_KNIFE, "knife", "A moderately sharp stabbing tool.", MT_METAL, 0.5, OC_WEAPON, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d3"); @@ -9472,6 +9533,7 @@ void initobjects(void) { addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 6, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); + addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 5, NA, NULL); addot(OT_SICKLE, "sickle", "A hand-held agricultural tool with a curved blade.", MT_METAL, 1, OC_WEAPON, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d6"); @@ -9511,6 +9573,7 @@ void initobjects(void) { addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 10, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); + addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 5, NA, NULL); addot(OT_ORNSWORD, "ornamental sword", "A gleaming (but quite blunt) blade.", MT_METAL, 6, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastot->flags, F_SHINY, B_TRUE, NA, NA, NULL); @@ -10269,8 +10332,9 @@ int ismetal(enum MATERIAL mat) { int metal = B_FALSE; switch (mat) { case MT_METAL: - case MT_WIRE: case MT_GOLD: + case MT_SILVER: + case MT_WIRE: metal = B_TRUE; break; default: @@ -10469,6 +10533,12 @@ void killmaterial(material_t *m) { void killob(object_t *o) { object_t *nextone, *lastone; + // debugging + if (o->type->id == OT_STAIRSUP) { + msg("warning: removing an up staircase!"); + dblog("warning: removing an up staircase!"); + } + // remove flags conferred by this object if (o->pile->owner) { loseobflags(o->pile->owner, o, ALLCONFERRED); @@ -10831,7 +10901,7 @@ object_t *moveob(object_t *src, obpile_t *dst, int howmany) { object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { object_t *o, *existob; - int i; + int i,preburdened = B_FALSE; int db = B_FALSE; flag_t *f; @@ -10861,6 +10931,8 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { dst = newcell->obpile; } } + } else if (dst->owner) { + preburdened = isburdened(dst->owner); } if (db) dblog("DB: moveob() - moving %d x %s",howmany, src->type->name); @@ -10982,6 +11054,17 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { } } + // did this make us burdened? + if (isplayer(dst->owner)) { + if (isburdened(dst->owner) != preburdened) { + if (preburdened == BR_NONE) { + msg("^wThe weight of your possessions is burdening you!"); + } else { + msg("^wThe weight of your possessions is burdening you even more!"); + } + } + } + // in case you picked up money, something which changes your AR, etc if (isplayer(dst->owner)) { statdirty = B_TRUE; @@ -12031,7 +12114,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { if ((m->region->rtype->id == RG_FIRSTDUNGEON) && (m->depth == 1)) { cell_t *cell[MAXCANDIDATES]; int ncells,i; - getradiuscells(lf->cell, 1, DT_COMPASS, B_FALSE, B_TRUE, cell, &ncells); + getradiuscells(lf->cell, 1, DT_COMPASS, B_FALSE, B_TRUE, cell, &ncells, B_FALSE); for (i = 0; i < ncells; i++) { if (hasob(cell[i]->obpile, OT_STAIRSUP)) { object_t *o; @@ -13637,7 +13720,8 @@ object_t *relinkob(object_t *src, obpile_t *dst) { if (obproduceslight(src)) { calclight((getoblocation(src))->map); if (gamemode == GM_GAMESTARTED) { - precalclos(player); + setlosdirty(player); + //precalclos(player); } drawscreen(); } @@ -14891,7 +14975,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, if (thrower && (thrower->cell == srcloc)) { whogetsxp = thrower; } - losehp(target, dam, DT_PROJECTILE, whogetsxp, damstring); + losehp_real(target, dam, DT_PROJECTILE, whogetsxp, damstring, B_TRUE, o, B_TRUE); } if (reduceamt && (speed >= 3)) { @@ -15060,7 +15144,8 @@ void timeeffectsob(object_t *o) { if (!o->blessknown) o->blessknown = B_TRUE; } calclight(ourcell->map); - precalclos(player); + setlosdirty(player); + //precalclos(player); } } else { // not near undead if (glowflag) { @@ -15974,7 +16059,7 @@ int willshatter(enum MATERIAL mat) { return B_FALSE; } -int getcritchance(lifeform_t *lf, object_t *o) { +int getcritchance(lifeform_t *lf, object_t *o, lifeform_t *victim) { flag_t *f; int chance = 0; if (!o) return 0; @@ -15996,6 +16081,11 @@ int getcritchance(lifeform_t *lf, object_t *o) { } } + // double crit chance if victim is vulnerable to this weapon + if (victim && lfhasflagval(victim, F_MATVULN, o->material->id, NA, NA, NULL)) { + chance *= 2; + } + return chance; } @@ -16123,7 +16213,7 @@ int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, ob maxrange = getmaxthrowrange(thrower, missile); } } else { - maxrange = getvisrange(thrower); + maxrange = getvisrange(thrower, B_TRUE); } howfar = getcelldist(thrower->cell, where); diff --git a/objects.h b/objects.h index 464353c..f840b00 100644 --- a/objects.h +++ b/objects.h @@ -59,7 +59,7 @@ void genhiddennames(void); object_t *getbestcontainer(obpile_t *op); int getchargeinfo(object_t *o, int *cur, int *max); int getcharges(object_t *o); -int getcritchance(lifeform_t *lf, object_t *o); +int getcritchance(lifeform_t *lf, object_t *o, lifeform_t *victim); int geteffecttime(int min, int max, enum BLESSTYPE isblessed); objecttype_t *getlinkspell(object_t *o); enum COLOUR getmaterialcolour(enum MATERIAL mat ); @@ -136,6 +136,7 @@ object_t *hasknownob(obpile_t *op, enum OBTYPE oid); object_t *hasob(obpile_t *op, enum OBTYPE oid); object_t *hasobletter(obpile_t *op, char letter); object_t *hasobofclass(obpile_t *op, enum OBCLASS cid); +int hasobmod(object_t *o, obmod_t *om); object_t *hasobmulti(obpile_t *op, enum OBTYPE *oid, int noids); object_t *hasobwithflag(obpile_t *op, enum FLAG flagid); object_t *hasobwithflagval(obpile_t *op, enum FLAG flagid, int val0, int val1, int val2, char *text); diff --git a/save.c b/save.c index cc3152f..5aa0189 100644 --- a/save.c +++ b/save.c @@ -217,6 +217,7 @@ lifeform_t *loadlf(FILE *f, cell_t *where) { fscanf(f, "sorted: %d\n",&l->sorted); fscanf(f, "polyrevert: %d\n",&l->polyrevert); fscanf(f, "forgettimer: %f\n",&l->forgettimer); + fscanf(f, "eyeadj: %d\n",&l->eyeadjustment); if (db) dblog("--> Got hp=%d/%d. timespend=%d. sorted=%d. Now loading flags.",l->hp,l->maxhp,l->timespent,l->sorted); @@ -797,6 +798,7 @@ int savelf(FILE *f, lifeform_t *l) { fprintf(f, "sorted: %d\n",l->sorted); fprintf(f, "polyrevert: %d\n",l->polyrevert); fprintf(f, "forgettimer: %f\n",l->forgettimer); + fprintf(f, "eyeadj: %d\n",l->eyeadjustment); // lf flags saveflagpile(f, l->flags); diff --git a/spell.c b/spell.c index cb784fc..00d23f6 100644 --- a/spell.c +++ b/spell.c @@ -54,7 +54,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef char targetname[BUFLEN]; char buf[BUFLEN]; int power = 0,needgrab = B_FALSE, range = 0; - char damstr[BUFLEN]; + char damstr[BUFLEN],racestr[BUFLEN]; objecttype_t *ot; flag_t *f; @@ -67,7 +67,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef needgrab = B_FALSE; if (cwflag && strlen(cwflag->text)) { - texttospellopts(cwflag->text, &power, damstr, &needgrab, &range); + texttospellopts(cwflag->text, "pw:", &power, "dam:", damstr, "needgrab:", &needgrab, "range:", &range, "range:", racestr, NULL); } // get more options from ablity itself... @@ -925,6 +925,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef int howlong; int slev; flag_t *f; + if (lfhasflagval(user, F_INJURY, IJ_WINDPIPECRUSHED, NA, NA, NULL)) { + if (isplayer(user)) msg("You can't sprint with a crushed windpipe."); + return B_TRUE; + } if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) { if (isplayer(user)) msg("You can't sprint while swimming!"); @@ -1015,7 +1019,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if ((o->type->obclass->id == OC_SCROLL) && isknown(o)) { f = hasflag(o->flags, F_LINKSPELL); if (f && !cancast(user, f->val[0], NULL)) { + char buf2[BUFLEN]; getobname(o, buf, o->amt); + difficulty = 20 + (getspelllevel(f->val[0])*3); + sprintf(buf2, "%s (%d%% success chance)", buf, difficulty); addchoice(&prompt, o->letter, buf, NULL, f); } } @@ -2059,8 +2066,52 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } + + // special case: summoning spell on a pentagram + if (caster && hasob(caster->cell->obpile, OT_PENTAGRAM) && hasflagval(sp->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL) && + (sp->id != OT_S_SUMMONDEMON)) { + if (haslos(player, caster->cell)) { + msg("The pentagram pulses red."); + } + if (summonlfs(caster, caster->cell, RC_DEMON, SZ_ANY, AL_NONE, 1, PERMENANT, B_FALSE)) { + if (isplayer(caster) || cansee(player, caster)) { + msg("An other-worldly demon appears!"); + } + } + return B_FALSE; + } + + + // switch based on spell effects... - if (spellid == OT_S_ABSORBMETAL) { + if (spellid == OT_S_ABSOLUTEZERO) { + cell_t *retcell[MAXCANDIDATES]; + int nretcells,i; + if (isplayer(caster)) { + msg("You unleash a freezing blast!"); + } else if (cansee(player, caster)) { + msg("%s unleashes a freezing blast!", castername, getpossessive(castername)); + } + // freeze lfs, obs in most cells + getradiuscells(caster->cell, 7, DT_ORTH, LOF_WALLSTOP, B_FALSE, retcell, &nretcells, 90); + for (i = 0; i < nretcells; i++) { + object_t *o, *nexto; + if (retcell[i]->lf) { + for (o = retcell[i]->lf->pack->first ; o ; o = nexto) { + nexto = o->next; + changemat(o, MT_ICE); + } + freezelf(retcell[i]->lf, caster, PERMENANT); + } + for (o = retcell[i]->obpile->first ; o ; o = nexto) { + nexto = o->next; + changemat(o, MT_ICE); + } + o = addobfast(retcell[i]->obpile, OT_ICESHEET); + if (o) killflagsofid(o->flags, F_OBHPDRAIN); + } + + } else if (spellid == OT_S_ABSORBMETAL) { int i; float totalmass = 0; object_t *o; @@ -2102,7 +2153,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ removedeadobs(targcell->obpile); - if (targcell->lf && !skillcheck(targcell->lf, SC_RESISTMAG, 20 + power, 0)) { + if (targcell->lf && !skillcheck(targcell->lf, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { // destroy only WORN metal objects, not CARRIED ones for (o = targcell->lf->pack->first ; o ; o = o->next) { if (isequipped(o) && ismetal(o->material->id)) { @@ -2263,6 +2314,31 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else { fizzle(caster); } + } else if (spellid == OT_S_BAFFLE) { + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE; + target = targcell->lf; + + if (lfhasflag(target, F_ASLEEP) || !ischarmable(target)) { + fizzle(caster); + return B_TRUE; + } + + if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { + if (isplayer(target)) { + msg("You shrug off a mental attack."); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } else if (haslos(player, target->cell)) { + getlfname(target, buf); + msg("%s shrugs off %s mental attack.", buf, isplayer(caster) ? "your" : "a"); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + return B_FALSE; + } else { + confuse(target, power*4); + if (isplayer(target) || cansee(player, target)) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + } } else if (spellid == OT_S_BARKSKIN) { flag_t *f; // always targetted at caster @@ -2315,7 +2391,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_FALSE; } - if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { failed = B_TRUE; } @@ -2600,8 +2676,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ powerleft = power; for (i = 0; i < caster->nlos; i++) { c = caster->los[i]; - if (c->lf && (c->lf != caster) && (c->lf->race->raceclass->id == RC_ANIMAL) && (gethitdice(c->lf) <= powerleft)) { - if (lfhasflag(c->lf, F_HOSTILE)) { + if (c->lf && (c->lf != caster) && (c->lf->race->raceclass->id == RC_ANIMAL) && lfhasflag(c->lf, F_HOSTILE)) { + if (gethitdice(c->lf) <= powerleft) { powerleft -= gethitdice(c->lf); makepeaceful(c->lf); @@ -2618,6 +2694,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (seenbyplayer) *seenbyplayer = B_TRUE; } donesomething++; + } else { + if (isplayer(caster)) { + char lfname[BUFLEN]; + getlfname(c->lf, lfname); + msg("%s is not affected.", lfname); + } } } if (powerleft <= 0) break; @@ -2788,7 +2870,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_FALSE; } - if (skillcheck(targcell->lf, SC_RESISTMAG, 20 + power, 0)) { + if (skillcheck(targcell->lf, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isplayer(caster) || cansee(player, target)) { msg("%s resists.",targetname); if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -3007,7 +3089,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // saving throw - if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isplayer(caster) || cansee(player, target)) { char tname[BUFLEN]; getlfname(target, tname); @@ -3054,7 +3136,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // determine type of mosnter - if ((power >= 7) && isplayer(caster)) { + if (getforcedspellrace(caster, spellid, buf)) { + } else if ((power >= 7) && isplayer(caster)) { // ask what kind of monster askstring("Create what kind of monster", '?', buf, BUFLEN, NULL); } else { @@ -3497,7 +3580,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // don't need line of fire! if (!validatespellcell(caster, &targcell, TT_OBJECT, spellid, power, frompot)) return B_TRUE; - getradiuscells(targcell, power, DT_ORTH, LOF_NEED, B_TRUE, cell, &ncells); + getradiuscells(targcell, power, DT_ORTH, LOF_NEED, B_TRUE, cell, &ncells, B_FALSE); for (i = 0; i < ncells; i++) { object_t *o,*nexto; for (o = cell[i]->obpile->first ; o ; o = nexto) { @@ -3579,11 +3662,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // flag. // other people get a check anyway. if (targcell->lf == caster) { - if (getmr(targcell->lf) && skillcheck(targcell->lf, SC_RESISTMAG, 20 + power, 0)) { + if (getmr(targcell->lf) && skillcheck(targcell->lf, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { resisted = B_TRUE; } } else { - if (skillcheck(targcell->lf, SC_RESISTMAG, 20 + power, 0)) { + if (skillcheck(targcell->lf, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { resisted = B_TRUE; } } @@ -3750,7 +3833,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE; target = targcell->lf; - if ((getattr(target, A_IQ) <= 3) || skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if ((getattr(target, A_IQ) <= 3) || skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (cansee(player, target)) { getlfname(target, buf); msg("%s %s momentarily foolish.", buf, isplayer(target) ? "feel" : "looks"); @@ -4317,7 +4400,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_GASEOUSFORM) { if (!target) target = caster; - if (getmr(target) && (target->race->id != R_VAMPIRE) && skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (getmr(target) && (target->race->id != R_VAMPIRE) && skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isplayer(target)) { msg("You feel momentarily insubstantial."); if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -4444,7 +4527,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (seenbyplayer) *seenbyplayer = B_TRUE; } - if (getmr(target) && skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (getmr(target) && skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isplayer(target) || haslos(player, target->cell)) { getlfname(target, buf); msg("%s blur%s for a moment.",buf, isplayer(target) ? "" : "s"); @@ -4455,7 +4538,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ addtempflag(target->flags, F_FASTACTMOVE, 10, NA, NA, NULL, howlong); } } else if ((spellid == OT_S_HEALING) || (spellid == OT_S_HEALINGMIN) || (spellid == OT_S_HEALINGMAJ)) { - int donesomething = B_FALSE; + int donesomething = B_FALSE,i; + flag_t *retflag[MAXCANDIDATES]; + int nretflags; if (!validatespellcell(caster, &targcell,TT_ALLY, spellid, power, frompot)) return B_TRUE; target = targcell->lf; if (!target) { @@ -4471,6 +4556,23 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ donesomething = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE; } + getflags(target->flags, retflag, &nretflags, F_NOBODYPART, F_NONE); + for (i = 0; i < nretflags; i++) { + if (retflag[i]->val[1] == B_FROMINJURY) { + if (isplayer(target)) { + msg("Your %s grows back!", getbodypartname(retflag[0]->val[0])); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } else if (cansee(player, target)) { + char targname[BUFLEN]; + getlfname(target, targname); + msg("%s%s %s grows back!", targname, getpossessive(targname), + getbodypartname(retflag[0]->val[0])); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + killflag(retflag[i]); + donesomething = B_TRUE; + } + } if ((spellid == OT_S_HEALINGMIN) && donesomething) { // minor healing will stop here @@ -4577,20 +4679,21 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ fizzle(caster); return B_FALSE; } + if (isplayer(target)) { - // make more hungry - modhunger(target, HUNGERCONST); + msg("A sudden hunger comes over you!"); if (seenbyplayer) *seenbyplayer = B_TRUE; + } else if (cansee(player, target)) { + char lfname[BUFLEN]; + getlfname(target, lfname); + msg("%s looks more hungry.", lfname); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + + if (lfhasflag(target, F_HUNGER)) { + modhunger(target, HUNGERCONST); // make more hungry } else { - if (cansee(player, target)) { - if (lfhasflag(target, F_HUNGER)) { - modhunger(target, HUNGERCONST); // make more hungry - } else { - // ie. "hungry" - addflag(target->flags, F_HUNGER, HUNGERCONST*2, NA, NA, NULL); - } - if (seenbyplayer) *seenbyplayer = B_TRUE; - } + addflag(target->flags, F_HUNGER, HUNGERCONST*2, NA, NA, NULL); } } else if (spellid == OT_S_HOLYAURA) { flag_t *f; @@ -4723,7 +4826,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } for (l = caster->cell->map->lf ; l ; l = l->next) { if (l != caster) { - if (isimmuneto(l->flags, DT_NECROTIC) || skillcheck(l, SC_RESISTMAG, 20 + power, 0)) { + if (isimmuneto(l->flags, DT_NECROTIC) || skillcheck(l, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isplayer(l)) { msg("Luckily, the evil doesn't seem to harm you."); if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -4739,7 +4842,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // now hit the caster! - if (isimmuneto(caster->flags, DT_NECROTIC) || skillcheck(caster, SC_RESISTMAG, 20 + power, 0)) { + if (isimmuneto(caster->flags, DT_NECROTIC) || skillcheck(caster, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isplayer(caster)) { msg("Luckily, the evil doesn't seem to harm you."); if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -4888,7 +4991,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // destroy objects right away removedeadobs(targcell->obpile); - if (targcell->lf && !skillcheck(targcell->lf, SC_RESISTMAG, 20 + power, 0)) { + if (targcell->lf && !skillcheck(targcell->lf, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { // destroy only WORN metal objects, not CARRIED ones for (o = targcell->lf->pack->first ; o ; o = o->next) { if (isequipped(o) && ismetal(o->material->id)) { @@ -4921,7 +5024,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ lifeform_t *oldplayer; // calc view - precalclos(targcell->lf); + setlosdirty(targcell->lf); + //precalclos(targcell->lf); // temporarily change player pointer... oldplayer = player; @@ -5027,7 +5131,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } - if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { saved = B_TRUE; } else if (skillcheck(target, SC_STR, 20 + power, 0)) { saved = B_TRUE; @@ -5062,7 +5166,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // make this a constitution skill check ? - if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { failed = B_TRUE; } else if (skillcheck(target, SC_CON, 20 + power, 0)) { failed = B_TRUE; @@ -5102,7 +5206,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // savingthrow - if (skillcheck(target, SC_RESISTMAG, 20 + power, 0) || skillcheck(target, SC_CON, 30 + power, 0)) { + if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0) || skillcheck(target, SC_CON, 30 + power, 0)) { if (haslos(player, target->cell)) { char lfname[BUFLEN]; getlfname(target, lfname); @@ -5198,7 +5302,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // saving throw.... - if (skillcheck(target, SC_RESISTMAG, 16 + power*2, 0)) { + if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isplayer(caster) && cansee(player, target)) { msg("%s%s mind fights off your intrusion!", targname, getpossessive(targname)); } @@ -5883,7 +5987,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_FALSE; } - if (lfhasflag(target, F_GRAVBOOSTED) || skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (lfhasflag(target, F_GRAVBOOSTED) || skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isplayer(target)) { msg("You feel momentarily heavier."); } else if (cansee(player, target)) { @@ -6103,7 +6207,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ getlfname(target, targetname); - if (skillcheck(targcell->lf, SC_RESISTMAG, 30 + power, 0)) { + if (skillcheck(targcell->lf, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isplayer(caster) || cansee(player, target)) { msg("%s resists.",targetname); if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -6145,7 +6249,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ breakgrabs(target, B_TRUE, B_TRUE); } else if (spellid == OT_S_POLYMORPH) { race_t *r = NULL; - flag_t *f; if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE; target = targcell->lf; @@ -6155,7 +6258,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_TRUE; } - if ((target != caster) && skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if ((target != caster) && skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isplayer(target)) { msg("You feel momentarily different."); if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -6167,9 +6270,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_FALSE; } - f = lfhasflag(target, F_FORCEPOLY); - if (f) { - r = findrace(f->val[0]); + if ((caster == target) && getforcedspellrace(caster, spellid, buf)) { + r = findracebyname(buf); } else { if (lfhasflag(caster, F_CONTROL)) { if (power < 5) { @@ -6550,7 +6652,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_TRUE; } - if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isplayer(target)) { msg("You yawn."); if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -6616,7 +6718,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE; target = targcell->lf; - if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isplayer(target)) { msg("You feel momentarily slower."); if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -6660,7 +6762,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE; target = haslf(targcell); if (target) { - if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isplayer(caster) || cansee(player, target)) { char tname[BUFLEN]; getlfname(target, tname); @@ -6857,7 +6959,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_TRUE; } - if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isplayer(target)) { msg("You feel momentarily nauseated."); if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -7013,7 +7115,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_TRUE; } - if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isplayer(target)) { msg("You shrug off a mental attack."); if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -7024,11 +7126,49 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } return B_FALSE; } else { - stun(target, 2); + stun(target, (power/5)+2); if (isplayer(target) || cansee(player, target)) { if (seenbyplayer) *seenbyplayer = B_TRUE; } } + } else if (spellid == OT_S_STUNMASS) { + int i; + int donesomething = B_FALSE; + target = caster; + // stun everyone within los of caster + for (i = 0; i < target->nlos; i++) { + lifeform_t *thistarg; + + targcell = target->los[i]; + thistarg = targcell->lf; + if (thistarg && (thistarg != caster)) { + if (lfhasflag(thistarg, F_ASLEEP) || !ischarmable(thistarg)) { + fizzle(caster); + return B_TRUE; + } + if (skillcheck(thistarg, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { + donesomething = B_TRUE; + if (isplayer(thistarg)) { + msg("You shrug off a mental attack."); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } else if (haslos(player, thistarg->cell)) { + getlfname(thistarg, buf); + msg("%s shrugs off %s mental attack.", buf, isplayer(caster) ? "your" : "a"); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + } else { + donesomething = B_TRUE; + stun(thistarg, (power/5)+2); + if (isplayer(thistarg) || cansee(player, thistarg)) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + } + } + } + + if (!donesomething) { + fizzle(caster); + } } else if (spellid == OT_S_SUCK) { if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE; @@ -7037,7 +7177,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (target) { int failed = B_FALSE; - if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { failed = B_TRUE; } else { // they get pulled towards caster @@ -7069,7 +7209,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ target = caster; - if (getmr(target) && skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (getmr(target) && skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isplayer(target)) { msg("You flicker."); if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -7420,7 +7560,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int friendly; lifetime = (power * 9) + rnd(1,power*2); - switch (spellid) { case OT_S_SUMMONDEMON: wantrc = RC_DEMON; @@ -7747,7 +7886,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE; target = targcell->lf; - if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (cansee(player, target)) { getlfname(target, buf); msg("%s %s momentarily weaker.", buf, isplayer(target) ? "feel" : "looks"); @@ -8132,6 +8271,56 @@ void fizzle(lifeform_t *caster) { } } +char *getforcedspellrace(lifeform_t *lf, enum OBTYPE spellid, char *racestr) { + flag_t *f; + // forced? + f = lfhasflagval(lf, F_CANWILL, spellid, NA, NA, NULL); + if (f) { + texttospellopts(f->text, "race:", racestr, NULL); + if (strlen(racestr)) { + return racestr; + } + } + return NULL; +} + +int getmpcost(lifeform_t *lf, enum OBTYPE oid) { + flag_t *f; + objecttype_t *ot; + int cost = 0; + ot = findot(oid); + if (!ot) { + return 0; + } + + if (lf) { + if (lfhasflagval(lf, F_BOOSTSPELL, oid, NA, NA, NULL)) { + return 0; // ie. deactivating it + } + if (lfhasflagval(lf, F_CANWILL, oid, NA, NA, NULL)) { + return 0; // ie. deactivating it + } + } + + f = hasflag(ot->flags, F_MPCOST); + if (f) { + cost = f->val[0]; + } else { + f = hasflag(ot->flags, F_SPELLLEVEL); + if (f) { + cost = f->val[0] * f->val[0]; + } + } + return cost; +} + +int getmrdiff(enum OBTYPE spellid, int power) { + int lev,diff; + lev = getspelllevel(spellid); + diff = 20 + (lev*2) + power; + return diff; +} + // maxlev <= 0 means 'any lev' enum OBTYPE getrandomspell(int maxlev) { @@ -8346,7 +8535,7 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) { // spellpower f = lfhasflagval(lf, F_CANWILL, spellid, NA, NA, NULL); if (f && strlen(f->text)) { - texttospellopts(f->text, &power, NULL, NULL, NULL); + texttospellopts(f->text, "pw:", &power, NULL ); if (power > 0) { if (db) { dblog("-->power = %d (from canwill)", power); @@ -8367,12 +8556,11 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) { // // this check doesn't apply for monsters. if (isplayer(lf)) { + int maxspelllevel = MAXSPELLLEV; if (hasjob(lf, J_DRUID) && (school == SS_NATURE)) { - // always okay } else if ((school == SS_ALLOMANCY) || (school == SS_MENTAL)) { // dont need spellcasting skill for mental/allomancy } else { - int maxspelllevel; usesorcery = B_TRUE; switch (schoolskill) { case PR_INEPT: maxspelllevel = 0; break; @@ -8383,16 +8571,13 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) { case PR_EXPERT: maxspelllevel = 8; break; case PR_MASTER: maxspelllevel = 9; break; } + } + // player can only ever cast spells up to your level. + if (!hasjob(lf, J_GOD)) limit(&maxspelllevel, NA, lf->level); - // player can only ever cast spells up to your level. - if (!hasjob(lf, J_GOD)) { - limit(&maxspelllevel, NA, lf->level); - } - - if (spelllev > maxspelllevel) { - if (db) dblog("-->power = 0 (no skilled enough in spell school)"); - return 0; - } + if (spelllev > maxspelllevel) { + if (db) dblog("-->power = 0 (no skilled enough in spell school)"); + return 0; } } @@ -8533,7 +8718,7 @@ int getspellrange(lifeform_t *lf, enum OBTYPE spellid, int power) { flag_t *f; f = lfhasflagval(lf, F_CANWILL, spellid, NA, NA, NULL); if (f && strlen(f->text)) { - texttospellopts(f->text, NULL, NULL, NULL, &newrange); + texttospellopts(f->text, "range:", &newrange, NULL); if (newrange > 0) { return newrange; } @@ -9101,34 +9286,4 @@ int getiqreq(enum OBTYPE oid) { } */ -int getmpcost(lifeform_t *lf, enum OBTYPE oid) { - flag_t *f; - objecttype_t *ot; - int cost = 0; - ot = findot(oid); - if (!ot) { - return 0; - } - - if (lf) { - if (lfhasflagval(lf, F_BOOSTSPELL, oid, NA, NA, NULL)) { - return 0; // ie. deactivating it - } - if (lfhasflagval(lf, F_CANWILL, oid, NA, NA, NULL)) { - return 0; // ie. deactivating it - } - } - - f = hasflag(ot->flags, F_MPCOST); - if (f) { - cost = f->val[0]; - } else { - f = hasflag(ot->flags, F_SPELLLEVEL); - if (f) { - cost = f->val[0] * f->val[0]; - } - } - return cost; -} - diff --git a/spell.h b/spell.h index 272b095..3dba847 100644 --- a/spell.h +++ b/spell.h @@ -7,7 +7,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ objecttype_t *findspelln(char *buf); void fizzle(lifeform_t *caster); //int getiqreq(enum OBTYPE oid); +char *getforcedspellrace(lifeform_t *lf, enum OBTYPE spellid, char *racestr); int getmpcost(lifeform_t *lf, enum OBTYPE oid); +int getmrdiff(enum OBTYPE spellid, int power); enum OBTYPE getrandomspell(int maxlev); enum SKILL getschoolskill(enum SPELLSCHOOL ss); char *getspellcosttext(lifeform_t *lf, enum OBTYPE spellid, int power, char *buf); diff --git a/text.c b/text.c index 2d83f6d..d56c425 100644 --- a/text.c +++ b/text.c @@ -1,5 +1,7 @@ +#include #include #include +#include #include #include #include "defs.h" @@ -402,17 +404,18 @@ char *getwaterdepthname(enum DEPTH d) { return "?unknowndepth?"; } -char *getweighttext(float weight, char *buf) { +char *getweighttext(float weight, char *buf, int shortfmt) { if (weight == 0) { - snprintf(buf, BUFLEN, "nothing"); + if (shortfmt) snprintf(buf, BUFLEN, "0kg"); + else snprintf(buf, BUFLEN, "nothing"); } else if (weight >= 1) { if ((int)weight == weight) { // ie. is weight an integer? - snprintf(buf, BUFLEN, "%0.0f kg",weight); + snprintf(buf, BUFLEN, "%0.0f%skg",weight, shortfmt ? "" : " "); } else { - snprintf(buf, BUFLEN, "%0.1f kg",weight); + snprintf(buf, BUFLEN, "%0.1f%skg",weight, shortfmt ? "" : " "); } } else { - snprintf(buf, BUFLEN, "%0.0f grams", weight * 1000); + snprintf(buf, BUFLEN, "%0.0f%s", weight * 1000, shortfmt ? "g" : " grams"); } return buf; } @@ -854,7 +857,8 @@ int texttodice(char *text, int *ndice, int *nsides, int *bonus) { return B_FALSE; } -void texttospellopts(char *text, int *power, char *damstr, int *needgrab, int *range) { +/* +void texttospellopts(char *text, int *power, char *damstr, int *needgrab, int *range, char *racestr) { char *p; int n; char *argname[] = { @@ -862,6 +866,7 @@ void texttospellopts(char *text, int *power, char *damstr, int *needgrab, int *r "dam:", "needgrab:", "range:", + "race:", NULL, }; void *argval[] = { @@ -869,6 +874,7 @@ void texttospellopts(char *text, int *power, char *damstr, int *needgrab, int *r damstr, needgrab, range, + racestr, NULL, }; char argtype[] = { @@ -876,6 +882,7 @@ void texttospellopts(char *text, int *power, char *damstr, int *needgrab, int *r 's', 'b', 'i', + 's', '\0', }; @@ -884,6 +891,7 @@ void texttospellopts(char *text, int *power, char *damstr, int *needgrab, int *r if (damstr) strcpy(damstr, ""); if (needgrab) *needgrab = B_FALSE; if (range) *range = 0; + if (racestr) strcpy(racestr, ""); if (!strlen(text)) { return; @@ -915,7 +923,84 @@ void texttospellopts(char *text, int *power, char *damstr, int *needgrab, int *r } } } +*/ +void texttospellopts(char *text, ... ) { + char *p; + va_list args; + char *validname[] = { + "pw:", + "dam:", + "needgrab:", + "range:", + "race:", + NULL, + }; + char argtype[] = { + 'i', + 's', + 'b', + 'i', + 's', + '\0', + }; + char *wantname = NULL; + void *writeto = NULL; + + va_start(args, text); + wantname = va_arg(args, char *); + if (wantname) writeto = va_arg(args, void *); + while (wantname) { + int foundidx = -1,i; + // process this one + + // validate 'wantname' - must match one of 'validname[]' + for (i = 0; validname[i]; i++) { + if (streq(validname[i], wantname)) { + foundidx = i; + break; + } + } + assert(foundidx != -1); + + // look for 'wantname' within 'text' + for (p = text ; *p ; p++) { + if (!strncmp(p, wantname, strlen(wantname)) ) { // found it! + char localval[BUFLEN]; + char *valfull; + + // blank our dest buffer + if (argtype[foundidx] == 'i') { + *((int *)writeto) = 0; + } else if (argtype[foundidx] == 'b') { + *((int *)writeto) = B_FALSE; + } else if (argtype[foundidx] == 's') { + strcpy((char *)writeto, ""); + } + + // extract value from text + // p will point to "pw:xxx;" + strcpy(localval, p + strlen(wantname)); // localval is "xxx;" + valfull = strtok(localval, ";"); // valfull is "xxx" + if (valfull) { + // if it's there, write the value into 'writeto' + if (argtype[foundidx] == 'i') { + *((int *)writeto) = atoi(valfull); + } else if (argtype[foundidx] == 'b') { + *((int *)writeto) = atoi(valfull) ? B_TRUE : B_FALSE; + } else if (argtype[foundidx] == 's') { + strcpy((char *)writeto, valfull); + } + } + } + } + + // get next one + wantname = va_arg(args, char *); + if (wantname) writeto = va_arg(args, void *); + } + va_end(args); +} char *you(lifeform_t *lf) { if (isplayer(lf)) { diff --git a/text.h b/text.h index f1e7baf..c545887 100644 --- a/text.h +++ b/text.h @@ -19,7 +19,7 @@ char *getsizetext(enum LFSIZE sz); char *gettimetext(char *retbuf); char *gettimetextfuzzy(char *retbuf, int wantpm); char *getwaterdepthname(enum DEPTH d); -char *getweighttext(float weight, char *buf); +char *getweighttext(float weight, char *buf, int shortfmt); char *is(lifeform_t *lf); int isvowel(char c); char *makekillertext(char *retbuf, char *lastdam, int wantextra); @@ -39,7 +39,8 @@ char *strends(char *a, char *suffix); char *strstarts(char *a, char *prefix); int strpixmatch(char *haystack, char *needle); int texttodice(char *text, int *ndice, int *nsides, int *bonus); -void texttospellopts(char *text, int *power, char *damstr, int *needgrab, int *range); +void texttospellopts(char *text, ... ); +//void texttospellopts(char *text, int *power, char *damstr, int *needgrab, int *range, char *racestr); char *you(lifeform_t *lf); char *you_l(lifeform_t *lf); char *your(lifeform_t *lf); diff --git a/vaults/monsterzoo.disabled b/vaults/monsterzoo.disabled new file mode 100644 index 0000000..b95edf0 --- /dev/null +++ b/vaults/monsterzoo.disabled @@ -0,0 +1,21 @@ +! filled with random monsters +@id:monsterzoo +@map +random(3,3,5,5) +@end + +@legend +@end + +@flags +autodoors:100 +goesin:dungeon +! every cell in here has 1-3 objects and a monster +scatter(1,1,-2,-2) mon:random:100% +scatter(1,1,-2,-2) ob:random:100% +scatter(1,1,-2,-2) ob:random:100% +scatter(1,1,-2,-2) ob:random:100%:50 +scatter(1,1,-2,-2) ob:random:100%:50 +rarity:rare +@end + diff --git a/vaults/playerstart1.vlt b/vaults/playerstart1.vlt index 4b8eb3d..afbb180 100644 --- a/vaults/playerstart1.vlt +++ b/vaults/playerstart1.vlt @@ -1,11 +1,11 @@ @id:playerstart_1 @map ########## -#...c..|,# -#...-/-### +#......|,# +#..c...### +......|,# -#.-/-..### -#...c..|,# +#..c...### +#......|,# ########## @end @legend @@ -14,16 +14,11 @@ ,:ob:1-4 bones:50 +:ob:wooden door +:exit -/:ob:wooden table --:ob:wooden footstool @end @flags goesin:dungeon playerstart -norandom atoneof(8,1)(8,3)(8,5) ob:playerstart -scatter(1,1,-2,-2) ob:wooden footstool:0-3 -scatter(1,1,-2,-2) ob:random food:0-2 mayrotate @end diff --git a/vaults/playerstart2.vlt b/vaults/playerstart2.vlt index f66c192..d85b3d9 100644 --- a/vaults/playerstart2.vlt +++ b/vaults/playerstart2.vlt @@ -1,25 +1,26 @@ @id:playerstart_2 @map ###x### -#.|.|.# +#m|.|m# ###.### -#.|.|.# +#m|.-p# ###.### -#.|.|.# +#m|.|m# ###.### -#.|.|.# +#m|.|m# ###x### @end @legend #:cell:rock wall -|:ob:iron gate +|:ob:locked iron gate +-:ob:iron gate +p:ob:playerstart +m:mon:humanoid x:exit @end @flags goesin:dungeon playerstart -norandom -atoneof(1,1)(1,3)(1,5)(1,7)(5,1)(5,3)(5,5)(5,7) ob:playerstart mayrotate @end diff --git a/vaults/playerstart3.vlt b/vaults/playerstart3.vlt index 1bd33cf..f7bdda9 100644 --- a/vaults/playerstart3.vlt +++ b/vaults/playerstart3.vlt @@ -20,7 +20,6 @@ p:ob:playerstart goesin:dungeon autodoors:50 playerstart -norandom mayrotate @end diff --git a/vaults/playerstart4.vlt b/vaults/playerstart4.vlt index a9bf7c1..6937c42 100644 --- a/vaults/playerstart4.vlt +++ b/vaults/playerstart4.vlt @@ -19,7 +19,6 @@ x:exit @flags goesin:dungeon playerstart -norandom mayrotate @end diff --git a/vaults/playerstart5.vlt b/vaults/playerstart5.vlt new file mode 100644 index 0000000..a81893c --- /dev/null +++ b/vaults/playerstart5.vlt @@ -0,0 +1,21 @@ +@id:playerstart_5 +@map +####### +##...## +#.....# +#..p..x +#.....# +##...## +####### +@end +@legend +#:cell:rock wall +p:ob:playerstart +x:exit +@end +@flags +goesin:dungeon +playerstart +mayrotate +@end + diff --git a/vaults/playerstart6.vlt b/vaults/playerstart6.vlt new file mode 100644 index 0000000..218412d --- /dev/null +++ b/vaults/playerstart6.vlt @@ -0,0 +1,23 @@ +@id:playerstart_6 +@map +###### +####.# +###..x +##...# +#..p.# +##...# +###..x +####.# +###### +@end +@legend +#:cell:rock wall +p:ob:playerstart +x:exit +@end +@flags +goesin:dungeon +playerstart +mayrotate +@end + diff --git a/vaults/playerstart7.vlt b/vaults/playerstart7.vlt new file mode 100644 index 0000000..b92cf76 --- /dev/null +++ b/vaults/playerstart7.vlt @@ -0,0 +1,26 @@ +@id:playerstart_7 +@map +##+###+## +#...#...# ++.p.|.f.+ +#...#...# +##|###|## +#...#...# ++.f.|.f.+ +#...#...# +##+###+## +@end +@legend +#:cell:rock wall +p:ob:playerstart +p:ob:fountain +f:ob:fountain ++:ob:wooden door +|:ob:iron gate +@end +@flags +goesin:dungeon +playerstart +mayrotate +@end +