From 6199c829bbce98e87d7ca826be71753dbac410fc Mon Sep 17 00:00:00 2001 From: rob Date: Tue, 30 Aug 2022 19:21:52 +1000 Subject: [PATCH 1/7] "cause" of death (rather than "method") buffer size isue on levelup text fix pluralisation of single-word objects (eg "leaf") --- io.c | 2 +- lf.c | 2 +- text.c | 8 +++++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/io.c b/io.c index 137d975..04282d5 100755 --- a/io.c +++ b/io.c @@ -15413,7 +15413,7 @@ void tombstone(lifeform_t *lf) { wattroff(mainwin, A_BOLD); wattron(mainwin, A_BOLD); mvwprintw(mainwin, y, 0, HISCOREFORMAT, "Pos", "Score", "Name", "Job"); - wprintw(mainwin, "Method of death"); y++; + wprintw(mainwin, "Cause of death"); y++; wmove(mainwin, y, 0); wattroff(mainwin, A_BOLD); diff --git a/lf.c b/lf.c index 303a0d7..9f19e88 100755 --- a/lf.c +++ b/lf.c @@ -5783,7 +5783,7 @@ void enhanceskills(lifeform_t *lf) { for (i = 0; i < nposs; i++) { char this[2]; - snprintf(this, 1, "%c", getattrletter(poss[i])); + snprintf(this, 2, "%c", getattrletter(poss[i])); if (isalpha(this[0])) { if (i == 0) { snprintf(ques, BUFLEN, "Increase your %s", getattrname(poss[i])); diff --git a/text.c b/text.c index 78d06b6..cca1999 100755 --- a/text.c +++ b/text.c @@ -2373,7 +2373,9 @@ char *makeplural(char **text) { len = strlen(*text); assert(len > 0); - newtext = strdup(*text); // make copy + //newtext = strdup(*text); // make copy + // make copy with trailing space + asprintf(&newtext, "%s ", *text); for (pl = firstplural ; pl ; pl = pl->next) { strrep(&newtext, pl->singular, pl->plural, &rv); @@ -2382,6 +2384,10 @@ char *makeplural(char **text) { break; } } + // now remove trailing space + if ( newtext[strlen(newtext)-1] == ' ') { + newtext[strlen(newtext)-1] = '\0'; + } if (!done) { // default From 072cc96e4f8e8262346371cdbff0ea16c376ebd6 Mon Sep 17 00:00:00 2001 From: rob Date: Tue, 30 Aug 2022 20:19:48 +1000 Subject: [PATCH 2/7] Fix description of OT_TREEDOWN If you visit a new branch before taking the regular stairs in your current branch DON'T update nextmap[dir] to point at the new branch. --- data.c | 2 +- map.c | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/data.c b/data.c index f91090f..7800436 100755 --- a/data.c +++ b/data.c @@ -2398,7 +2398,7 @@ void initobjects(void) { addflag(lastot->flags, F_ONEPERCELL, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_IMPORTANT, B_TRUE, NA, NA, NULL); - addot(OT_TREEDOWN, "hollow tree leading down", "A huge hollow tree containing an ascending staircase.", MT_DRAGONWOOD, 3000, OC_DFEATURE, SZ_HUGE); + addot(OT_TREEDOWN, "hollow tree leading down", "A huge hollow tree containing a descending staircase.", MT_DRAGONWOOD, 3000, OC_DFEATURE, SZ_HUGE); addflag(lastot->flags, F_GLYPH, C_WOOD, '>', NA, NULL); addflag(lastot->flags, F_STAIRS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CLIMBABLE, D_DOWN, NA, NA, "hollow tree"); diff --git a/map.c b/map.c index 99c1ac8..a39ff95 100755 --- a/map.c +++ b/map.c @@ -4717,14 +4717,21 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging - // did we come from a previous map in the same region? if (parentmap && (exitdir != D_NONE)) { - if ((parentmap->region->id == map->region->id) || - (map->region->rtype->majorbranch)) { - if (db) dblog(" linking to parentmap %s in dir %s", parentmap->name, getdirname(diropposite(exitdir))); + if (parentmap->region->id == map->region->id) { + // we came from a previous map in the same region + if (db) dblog(" linking to same region parentmap %s in dir %s", parentmap->name, getdirname(diropposite(exitdir))); + // ONLY change parent map's nextmap if it's + // in the same region. parentmap->nextmap[exitdir] = map->id; - assert(exitdir >= 0); map->nextmap[diropposite(exitdir)] = parentmap->id; + } else if (map->region->rtype->majorbranch) { + // we just arrived at the first map of a new region + if (db) dblog(" linking to diff region parentmap %s in dir %s", parentmap->name, getdirname(diropposite(exitdir))); + map->nextmap[diropposite(exitdir)] = parentmap->id; + // don't update parent map's nextmap[] since we + // want it to go to maps of the parent's + // region. } } //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging From 4f3375c58b2f35d389fdb2fd53737837399bd938 Mon Sep 17 00:00:00 2001 From: rob Date: Tue, 30 Aug 2022 22:03:11 +1000 Subject: [PATCH 3/7] Reduce weapon stamina cost based on proficiency. add assertion to catch when too many skill abilities/descriptions are added fix duplicate description on some weapon skills --- attack.c | 7 ++++--- data.c | 3 +-- defs.h | 7 ++++--- io.c | 10 ++++++---- lf.c | 23 +++++++++++++++++++++-- lf.h | 1 + 6 files changed, 37 insertions(+), 14 deletions(-) diff --git a/attack.c b/attack.c index b0a9f29..8d09b56 100755 --- a/attack.c +++ b/attack.c @@ -834,11 +834,12 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { } if (dostamloss) { object_t *priwep; + float loss; priwep = getweapon(lf); - // lose a bit of stamina - modstamina(lf, -getattackstamloss(priwep)); + loss = getattackstamlosslf(lf, priwep); + // lose a bit of stamina + modstamina(lf, -loss); } - //} // stop sprinting stopsprinting(lf); diff --git a/data.c b/data.c index 7800436..0b28b68 100755 --- a/data.c +++ b/data.c @@ -21201,7 +21201,7 @@ void initskills(void) { if (isweaponskill(sk->id) || (sk->id == SK_UNARMED)) { addskilldesc(sk->id, PR_INEPT, "This skill increases your accuracy and damage when using matching weapons.", B_FALSE); - if (sk->id == SK_CLUBS) addskilldesc(sk->id, PR_NOVICE, "^gYou gain the 'merciful fighting' ability.^n", B_FALSE); + addskilldesc(sk->id, PR_INEPT, "Each skill level also decreases stamina usage of matching weapons by 10%.", B_FALSE); addskilldesc(sk->id, PR_NOVICE, "^gYou can now recognise the quality of matching weapons.^n", B_FALSE); addskilldesc(sk->id, PR_NOVICE, "^gEliminates accuracy penalties with matching weapons.^n", B_FALSE); addskilldesc(sk->id, PR_BEGINNER, "^g+1 accuracy.^n", B_FALSE); @@ -21220,7 +21220,6 @@ void initskills(void) { addskilldesc(sk->id, PR_SKILLED, "^gYou can now block certain attacks with this kind of weapon.^n", B_FALSE); } addskilldesc(sk->id, PR_EXPERT, "^g+4 accuracy, +30% damage bonus.^n", B_FALSE); - if (sk->id == SK_UNARMED) addskilldesc(sk->id, PR_EXPERT, "^gYou gain the 'flip' ability.^n", B_FALSE); addskilldesc(sk->id, PR_MASTER, "^g+6 accuracy, +40%% damage bonus, combination strike ability.^n", B_FALSE); if (sk->id != SK_UNARMED) { diff --git a/defs.h b/defs.h index 2852c25..a92bb8f 100755 --- a/defs.h +++ b/defs.h @@ -975,6 +975,7 @@ enum SKILLLEVEL { PR_MASTER = 6, }; #define MAXSKILLLEVEL 7 +#define MAXSKILLDESC (MAXSKILLLEVEL*3) #define MAXSKILLWILLS (MAXSKILLLEVEL*5) @@ -5371,9 +5372,9 @@ typedef struct skill_s { char *name; char *shortname; char *desc; - enum SKILLLEVEL skilldesclev[MAXSKILLLEVEL*2]; - char *skilldesctext[MAXSKILLLEVEL*2]; - int skilldescmsg[MAXSKILLLEVEL*2]; + enum SKILLLEVEL skilldesclev[MAXSKILLDESC]; + char *skilldesctext[MAXSKILLDESC]; + int skilldescmsg[MAXSKILLDESC]; int nskilldesc; struct skillwill_s { diff --git a/io.c b/io.c index 04282d5..3ba3c52 100755 --- a/io.c +++ b/io.c @@ -6700,12 +6700,12 @@ char *makedesc_ob(object_t *o, char *retbuf) { } } - stamcost = getattackstamloss(o); - snprintf(buf2, BUFLEN, ", and Stamina cost is %0.2f",stamcost); + stamcost = getattackstamlosslf(player, o); + snprintf(buf2, BUFLEN, ", and Stamina cost for you is %0.2f",stamcost); strcat(buf, buf2); if (compareob) { float cstamcost,diff; - cstamcost = getattackstamloss(compareob); + cstamcost = getattackstamlosslf(player, compareob); diff = stamcost - cstamcost; if (diff == 0) { strcat(buf, " (=)"); @@ -7811,9 +7811,11 @@ char *makedesc_ob(object_t *o, char *retbuf) { sprintf(buf, " - %s", contentname); if ((o->type->id == OT_SPELLBOOK) || (o->type->id == OT_GRIMOIRE)) { char lbuf[BUFLEN]; + char kbuf[BUFLEN]; + sprintf(kbuf, " ^%d[known]^n", C_GREEN); sprintf(lbuf, " (Lv %d %s)%s", getspelllevel(oo->type->id), getschoolname(getspellschool(oo->type->id)), lfhasflagval(player, F_CANCAST, oo->type->id, NA, NA, NULL) ? - " [known]" : ""); + kbuf : ""); strcat(buf, lbuf); } strcat(buf, "\n"); diff --git a/lf.c b/lf.c index 9f19e88..a969024 100755 --- a/lf.c +++ b/lf.c @@ -8014,6 +8014,25 @@ int getattackspeed(lifeform_t *lf) { return (int)speed; } +float getattackstamlosslf(lifeform_t *lf, object_t *wep) { + float loss; + loss = getattackstamloss(wep); // base loss + if (wep && loss > 0) { + flag_t *f; + // modify based on proficiency + f = hasflag(wep->flags, F_USESSKILL); + if (f && (f->val[0] != SK_NONE)) { + enum SKILLLEVEL slev; + slev = getskill(lf, f->val[0]); + if (slev >= PR_NOVICE) { + loss *= ((float)slev/10); + limitf(&loss, 0, NA); + } + } + } + return loss; +} + float getattackstamloss(object_t *wep) { float loss; loss = STAMTOATTACK; @@ -16020,6 +16039,7 @@ void addskillabil(enum SKILL id, enum SKILLLEVEL lev, enum OBTYPE abilid, int ti skill_t *sk; sk = findskill(id); assert(sk); + assert(sk->nskillwills < MAXSKILLWILLS); if (announce) { objecttype_t *ot; @@ -16039,8 +16059,6 @@ void addskillabil(enum SKILL id, enum SKILLLEVEL lev, enum OBTYPE abilid, int ti sk->skillwill[sk->nskillwills].text = NULL; } sk->nskillwills++; - - } // rid is optional, can be R_NONE @@ -16238,6 +16256,7 @@ void addskilldesc(enum SKILL id, enum SKILLLEVEL lev, char *text, int wantmsg) { skill_t *sk; sk = findskill(id); assert(sk); + assert(sk->nskilldesc < MAXSKILLDESC); sk->skilldesclev[sk->nskilldesc] = lev; sk->skilldesctext[sk->nskilldesc] = strdup(text); sk->skilldescmsg[sk->nskilldesc] = wantmsg; diff --git a/lf.h b/lf.h index 32a7c13..3300187 100755 --- a/lf.h +++ b/lf.h @@ -170,6 +170,7 @@ int getarmournoise(lifeform_t *lf); int getarmourrating(lifeform_t *lf, object_t **hitob, int *hitchance, enum BODYPART *hitbp, int *narms); int getattackspeed(lifeform_t *lf); float getattackstamloss(object_t *wep); +float getattackstamlosslf(lifeform_t *lf, object_t *wep); int getattpoints(lifeform_t *lf); int getattr(lifeform_t *lf, enum ATTRIB attr); enum ATTRBRACKET getattrbracket(int attrval, enum ATTRIB whichatt, /*@null@*/char *buf); From d331bfad550ba4b76be9c4813631abf9f8c16b1c Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 1 Sep 2022 20:32:18 +1000 Subject: [PATCH 4/7] charisma gives chance of monsters being peaceful --- lf.c | 2 +- map.c | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lf.c b/lf.c index a969024..dadd4ed 100755 --- a/lf.c +++ b/lf.c @@ -23295,7 +23295,7 @@ int skillcheckvs(lifeform_t *lf1, enum CHECKTYPE ct1, int mod1, lifeform_t *lf2, mod2 += 5; } - // ignore the difficult, we just want the modified roll. + // ignore the difficulty, we just want the modified roll. real_skillcheck(lf1, ct1, 0, mod1, &roll1); real_skillcheck(lf2, ct2, 0, mod2, &roll2); diff --git a/map.c b/map.c index a39ff95..a299420 100755 --- a/map.c +++ b/map.c @@ -435,6 +435,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok } else if ((player->race->id == R_MAMMOAN) && (lf->race->id == R_ELEPHANT)) { killflagsofid(lf->flags, F_HOSTILE); } else { + int mayoverride = B_TRUE; // adjust hostility based on player's alignment switch (getalignment(player)) { case AL_GOOD: @@ -442,18 +443,30 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok killflagsofid(lf->flags, F_HOSTILE); } else if (getalignment(lf) == AL_EVIL) { if (!lfhasflag(lf, F_HOSTILE)) addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + mayoverride = B_FALSE; } break; case AL_EVIL: if (getalignment(lf) == AL_GOOD) { - if (!lfhasflag(lf, F_HOSTILE)) { - addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); - } + if (!lfhasflag(lf, F_HOSTILE)) addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + mayoverride = B_FALSE; } break; default: break; } + + if ( getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) > IQ_ANIMAL) { + int mod=0; + if (lf->race->id == player-> race->id) { + mod += 15; + } + if (skillcheckvs(player, SC_CHA, mod, lf, SC_CHA, 0)) { + killflagsofid(lf->flags, F_HOSTILE); + } else { + if (!lfhasflag(lf, F_HOSTILE)) addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + } + } } } // end if hasequipped amu_victimisation } From 47e0e1fce80eec9969b9acc55106d50a4f550cc9 Mon Sep 17 00:00:00 2001 From: rob Date: Mon, 12 Sep 2022 21:25:58 +1000 Subject: [PATCH 5/7] fire god gifts should be fireproof --- god.c | 7 ++++++- io.c | 2 +- objects.c | 11 ++++++++--- objects.h | 1 + 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/god.c b/god.c index d155f29..864134e 100755 --- a/god.c +++ b/god.c @@ -1593,7 +1593,6 @@ int godgiftmaybe(enum RACE rid, int fromtemple, int announce) { f->obfrom = god->race->id; } break; - } } } @@ -1672,6 +1671,12 @@ int godgiftmaybe(enum RACE rid, int fromtemple, int announce) { } else { msg("You hear something hitting the ground."); } + + + // fire god's gifts are always fireproof + if (rid == R_GODFIRE) { + makefireproof(o); + } } } diff --git a/io.c b/io.c index 3ba3c52..dc2f325 100755 --- a/io.c +++ b/io.c @@ -8547,7 +8547,7 @@ char *makedesc_spell(objecttype_t *ot, char *retbuf) { return retbuf; } -// if wantunknown is set, lsit spells we DONT know. +// if wantunknown is set, list 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 wantlowmp, int wanttoohard, int mpcutoff) { diff --git a/objects.c b/objects.c index db38bc2..ce454b0 100755 --- a/objects.c +++ b/objects.c @@ -2273,9 +2273,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum switch (wantom[n]->id) { case OM_FLAMING: // flaming weapons are immune to fire if (o->type->obclass->id == OC_WEAPON) { - if (!isimmuneto(o->flags, DT_FIRE, B_FALSE)) { - addflag(o->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); - } + makefireproof(o); } break; case OM_FROZEN: @@ -9270,6 +9268,13 @@ int makedullermaybe(object_t *o, int howmuch) { return B_FALSE; } +flag_t *makefireproof(object_t *o) { + if (!o) return NULL; + + if (isimmuneto(o->flags, DT_FIRE, B_FALSE)) return NULL; + return addflag(o->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); +} + void makeunequipped(lifeform_t *lf, object_t *o) { // remove the equipped flag killflagsofid(o->flags, F_EQUIPPED); diff --git a/objects.h b/objects.h index ce5b019..0617a75 100755 --- a/objects.h +++ b/objects.h @@ -265,6 +265,7 @@ lifeform_t *makeanimated(lifeform_t *lf, object_t *o, int level); void makecool(object_t *o, int howmuch, int howlong); int makeduller(object_t *o, int howmuch); int makedullermaybe(object_t *o, int howmuch); +flag_t *makefireproof(object_t *o); void makeunequipped(lifeform_t *lf, object_t *o); void makehot(object_t *o, int howmuch, int howlong); void makeknown(enum OBTYPE otid); From e1507aa7d67b8efc2981a6ecea7482cc9d275ad9 Mon Sep 17 00:00:00 2001 From: rob Date: Sat, 17 Sep 2022 10:15:17 +1000 Subject: [PATCH 6/7] change reload command to v --- data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data.c b/data.c index 0b28b68..27bd798 100755 --- a/data.c +++ b/data.c @@ -203,7 +203,7 @@ void initcommands(void) { addcommand(CMD_FIRE, 'f', "Fire your firearm/bow at your current target."); addcommand(CMD_FIRENEW, 'F', "Fire your firearm/bow at a new target."); addcommand(CMD_AIM, 'a', "Aim your current firearm/bow at a new target."); - addcommand(CMD_GUNRELOAD, 'a', "Reload current firearm/bow with current ammo."); + addcommand(CMD_GUNRELOAD, 'v', "Reload (quiVer) firearm/bow with current ammo."); addcommand(CMD_NEXTTARGET, '\'', "Cycle to next firearm target."); // Information addcommand(CMD_HELP, '?', "Display this text."); From 3f162673cf0da716f59908b9d53030fa27c28027 Mon Sep 17 00:00:00 2001 From: rob Date: Sun, 18 Sep 2022 17:24:50 +1000 Subject: [PATCH 7/7] Add script to check for unused command letters WIP: autoexplore code --- data.c | 4 +- defs.h | 6 ++- find_unused_letters.sh | 2 + io.c | 41 ++++++++++++++++++- io.h | 1 + lf.c | 9 +++++ map.c | 91 ++++++++++++++++++++++++++++++++++++++++++ map.h | 3 ++ nexus.c | 12 +++++- 9 files changed, 164 insertions(+), 5 deletions(-) create mode 100755 find_unused_letters.sh diff --git a/data.c b/data.c index 27bd798..8854f12 100755 --- a/data.c +++ b/data.c @@ -174,8 +174,10 @@ void initcommands(void) { addcommand(CMD_UP, '<', "Go up stairs."); addcommand(CMD_DOWN, '>', "Go down stairs, enter a shop/portal."); addcommand(CMD_GO, 'G', "Go to a set position (pathfind)."); + addcommand(CMD_EXPLORE, 'z', "Auto-explore the current level"); // Actions - addcommand(CMD_AGAIN, 'g', "Repeat last action."); + addcommand(CMD_AGAIN, 'g', "Repeat last action (do aGain)."); + addcommand(CMD_REPEATSPELL, 'p', "RePeat last spell/ability."); addcommand(CMD_REST, '.', "Rest once."); addcommand(CMD_PICKUP, ',', "Pick up something from the ground."); addcommand(CMD_COMMS, 'c', "Chat/Communicate with someone."); diff --git a/defs.h b/defs.h index a92bb8f..b33c43a 100755 --- a/defs.h +++ b/defs.h @@ -3748,6 +3748,7 @@ enum FLAG { F_CAREFULMOVE, // moving slowly on purpose to avoid slipping. F_AUTOCMD, // val0 = how many times to repeat this F_LASTCMD, // text[0] = last command performed, v0/1 = x/y of cell, v2=various + F_LASTSPELL, // val0=id of last spell cast, for player only F_WILLTHROW, // this lf will treat obid v0 as a thrown missile. F_CANSTUDY, // lf can study spells from school v0 F_CANLEARN, // lf is able to learn skill val0 @@ -4373,8 +4374,9 @@ enum FLAG { F_XRAYVIS, //val0=num of walls we can see through F_CANSEETHROUGHMAT, //val0=kind of material you can see through F_CANSEETHROUGHLF, // larger lifeforms don't block los for us - F_PATHFINDING, // you are following a path via 'G' + F_PATHFINDING, // you are following a path via 'G' or 'z' // to coords v0,v1 on mapid v2 + // str = G or z F_SPRINTING, // you are sprinting. F_WOUNDING, // increase all damage done by this lf by v0 F_WINDSHIELD,// has a windshield protecting against missiles of speed @@ -4752,6 +4754,7 @@ enum COMMAND { CMD_DROP, CMD_DROPMULTI, CMD_EAT, + CMD_EXPLORE, CMD_FIRE, CMD_FIRENEW, CMD_FORCEATTACK, @@ -4778,6 +4781,7 @@ enum COMMAND { CMD_QUAFF, CMD_QUIT, CMD_READ, + CMD_REPEATSPELL, CMD_REST, CMD_RESTFULL, CMD_SAVEQUIT, diff --git a/find_unused_letters.sh b/find_unused_letters.sh new file mode 100755 index 0000000..81d7d36 --- /dev/null +++ b/find_unused_letters.sh @@ -0,0 +1,2 @@ +#!/bin/bash +echo {a..z} {A..Z} | tr ' ' '\n' | egrep -v $(grep addcom *.c | grep -v '//' | grep -v \\\\ | awk -F\' '{print $2}' | egrep "[a-zA-Z]" | tr '\n' '|' | sed 's/^|//;s/|$//') diff --git a/io.c b/io.c index dc2f325..8264ff1 100755 --- a/io.c +++ b/io.c @@ -11272,6 +11272,9 @@ void handleinput(void) { case CMD_GO: // go somewhere (pathfind) startpathfind(); break; + case CMD_EXPLORE: // autoexplore + startexplore(B_TRUE); + break; case CMD_HELP: // help dohelp('?'); break; @@ -11313,6 +11316,14 @@ void handleinput(void) { case CMD_MEMMAGIC: // 'M'emorise magic/ability shortcut domemmagic(); break; + case CMD_REPEATSPELL: // 're'p'eat last spell/ability + f = hasflag(player->flags, F_LASTSPELL); + if (f) { + domagic(f->val[0], NA, NA); + } else { + msg("There is no previous spell to repeat."); + } + break; case CMD_UP: // go up if (isprone(player)) { standup(player); @@ -15262,6 +15273,33 @@ void showpath(lifeform_t *lf) { restoregamewindows(); } + +// TODO: not quite working. sometimes seems to flip back and forth between 2 positions +int startexplore(int announce) { + cell_t *c; + c = get_explore_target(player); + if (!c) { + msg("Can't find any unknown cells to explore."); + return B_TRUE; + } + killflagsofid(player->flags, F_PATHFINDING); + + if (ai_createpathto(player, c)) { + addflag(player->flags, F_PATHFINDING, c->x, c->y, player->cell->map->id, "z"); + //msg("Going from %d,%d to unexplored %d,%d", player->cell->x, player->cell->y, c->x, c->y); + if (announce) { + msg("Starting auto-explore."); + } else { + msg("Continuing auto-explore."); + } + } else { + msg("Pathfind failed from %d,%d to unexplored %d,%d", player->cell->x, player->cell->y, c->x, c->y); + } + + + return B_FALSE; +} + void startpathfind(void) { cell_t *c = NULL; c = askcoords("Go to where?", "Goto->", TT_NONE, player, UNLIMITED, LOF_DONTNEED, B_FALSE); @@ -15274,11 +15312,10 @@ void startpathfind(void) { (haslos(player, c) && !cellwalkable(player, c, NULL))) { msg("You don't know how to get there."); return; - } // try to find path. if (ai_createpathto(player, c)) { - addflag(player->flags, F_PATHFINDING, c->x, c->y, player->cell->map->id, NULL); + addflag(player->flags, F_PATHFINDING, c->x, c->y, player->cell->map->id, "G"); } else { msg("You don't know how to get there."); } diff --git a/io.h b/io.h index ce224f7..8ff43c5 100755 --- a/io.h +++ b/io.h @@ -158,6 +158,7 @@ int showhiscoreline(void *hilitescore, int ncols, char **argv, char **colname); void showlfarmour(lifeform_t *lf); void showlfstats(lifeform_t *lf, int showall); void showpath(lifeform_t *lf); +int startexplore(int announce); void startpathfind(void); void textwithcol(WINDOW *win, char *buf); void textwithcol_real(WINDOW *win, char *buf, int resetcolatend); diff --git a/lf.c b/lf.c index dadd4ed..3dd2043 100755 --- a/lf.c +++ b/lf.c @@ -2156,6 +2156,11 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar // lose mp losemp(lf, cost); + // remember spell for rePeat command + if (isplayer(lf)) { + modflag(lf->flags, F_LASTSPELL, sid, NA, NA, NULL); + } + // spell fails? // miscast chance? if (isplayer(lf) && !hasjob(lf, J_GOD)) { @@ -26512,6 +26517,10 @@ int useability(lifeform_t *lf, enum OBTYPE aid, lifeform_t *who, cell_t *where) cwflag = lfhasflagval(lf, F_CANWILL, aid, NA, NA, NULL); rv = abilityeffects(lf, aid, where, who, cwflag); + // remember ability for rePeat command + if (isplayer(lf)) { + modflag(lf->flags, F_LASTSPELL, aid, NA, NA, NULL); + } if (!rv) { flag_t *f; diff --git a/map.c b/map.c index a299420..5641d82 100755 --- a/map.c +++ b/map.c @@ -5,6 +5,7 @@ #include #include #include +#include "ai.h" #include "astar.h" #include "attack.h" #include "defs.h" @@ -3044,6 +3045,62 @@ cell_t *get_closest_adjcell(cell_t *src, cell_t *dst) { return NULL; } +// find the closest known & walkable cell, with an adjacent unknown one +// note: only works when lf == player at the moment +cell_t *get_explore_target(lifeform_t *lf) { + int i; + int maxdist = MAXOF(MAX_MAPW, MAX_MAPH); + cell_t *src, **poss, *sel = NULL; + int x,y; + int nposs; + if (!lf) return NULL; + src = lf->cell; + for (i = 1;(i< maxdist && !sel); i++) { + int nok = 0; + nposs = 0; + poss = malloc(sizeof(cell_t *)*(i+2)*4); + //msg("player is %d,%d, dist %d.", lf->cell->x, lf->cell->y, i); + //msg("Box is %d,%d to %d, %d.", lf->cell->x - i, lf->cell->y - i, + // lf->cell->x + i, lf->cell->y + i); + for (y = lf->cell->y - i; y <= lf->cell->y + i; y++) { + for (x = lf->cell->x - i; x <= lf->cell->x + i; ) { + cell_t *newcell = NULL; + + //msg("Checking %d,%d.",x, y); + newcell = getcellat(lf->cell->map,x,y); + if (newcell) { + nok++; + if (newcell->known != KG_UNKNOWN && + cellwalkable(lf, newcell, NULL) && + countadjcellsknown(newcell, B_FALSE, DT_COMPASS)) { + poss[nposs] = newcell; + nposs++; + } + } + + + // change x based on where we are in te square of + // possible cells + if (y == lf->cell->y - i || y== lf->cell->y + i) { + x++; + } else { + x += (i*2); + } + } + } + //msg("%d/%d possible cells at distance %d.",nposs, nok, i); + if (nposs) { + sel = poss[rnd(0,nposs-1)]; + } + free(poss); + if (nok == 0) { + // no valid cells + break; + } + } + return sel; +} + int getdoorlockdiff(int depth) { return 70 + (depth*3); } @@ -3456,6 +3513,31 @@ int countadjcellswithflag(cell_t *cell, enum FLAG fid, int dirtype) { return count; } +int countadjcellsknown(cell_t *cell, int wantknown, int dirtype) { + int d; + int count = 0; + int start,end; + cell_t *newcell; + if (dirtype == DT_ORTH) { + start = D_N; + end = D_W; + } else { // ie. DT_COMPASS + start = DC_N; + end = DC_NW; + } + for (d = start; d <= end; d++) { + newcell = getcellindir(cell, d); + if (newcell) { + if (wantknown && (newcell->known != KG_UNKNOWN)) { + count++; + } else if (!wantknown && (newcell->known == KG_UNKNOWN)) { + count++; + } + } + } + return count; +} + int countadjcellsoftype(cell_t *cell, enum CELLTYPE id, int dirtype) { int d; int count = 0; @@ -7963,6 +8045,15 @@ void forgetcells(map_t *map, int amt) { } } +cell_t *getcellindirdist(cell_t *src, int dir, int dist) { + cell_t *c = src; + int i; + for (i = 0; (i < dist && c); i++) { + c = getcellindir(c,dir); + } + return c; +} + cell_t *getcellindir(cell_t *cell, int dir) { cell_t *newcell; int newx,newy; diff --git a/map.h b/map.h index 82f92fd..22707f2 100755 --- a/map.h +++ b/map.h @@ -72,6 +72,7 @@ object_t *gettopobject(cell_t *where, int forglyph); //void calclight(map_t *map); int calcroompos(map_t *map, int w, int h, int xmargin, int ymargin, int *bx, int *by, int force, int stayclose); int compassdir(int orthdir); +int countadjcellsknown(cell_t *cell, int wantknown, int dirtype); int countadjcellsoftype(cell_t *cell, enum CELLTYPE id, int dirtype); int countadjrooms(cell_t *cell, int dirtype); int countadjcellswithflag(cell_t *cell, enum FLAG fid, int dirtype); @@ -141,8 +142,10 @@ room_t *findroom(map_t *m, int roomid); map_t *findsurfaceexitmap(map_t *m); void forgetcells(map_t *map, int amt); cell_t *getcellindir(cell_t *cell, int dir); +cell_t *getcellindirdist(cell_t *src, int dir, int dist); enum TEMPERATURE getcelltemp(cell_t *c, int *actualtemp); vault_t *getcellvault(cell_t *c); +cell_t *get_explore_target(lifeform_t *lf); cell_t *getclosestroomcell(lifeform_t *lf, int roomid); int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved); int getobchance(int habitat); diff --git a/nexus.c b/nexus.c index 160afaf..d35fa40 100755 --- a/nexus.c +++ b/nexus.c @@ -1145,7 +1145,9 @@ void donextturn(map_t *map) { // pathfinding? if (donormalmove && isplayer(who)) { - if (lfhasflag(who, F_PATHFINDING)) { + flag_t *pff; + pff = lfhasflag(who, F_PATHFINDING); + if (pff) { cell_t *c; // follow..... c = ai_getnextcellinpath(who); @@ -1175,8 +1177,16 @@ void donextturn(map_t *map) { } } } else { + int keepgoing = B_FALSE; msg("Arrived at destination."); + if (streq(pff->text, "z")) { + keepgoing = B_TRUE; + } stoppathfinding(who); + if (keepgoing) { + startexplore(B_FALSE); + } + } } }