diff --git a/ai.c b/ai.c index 415fd6f..078500e 100644 --- a/ai.c +++ b/ai.c @@ -19,6 +19,45 @@ extern enum ERROR reason; int wantdb = B_TRUE; +void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) { + int db = B_FALSE; + + if (lfhasflag(lf, F_DEBUG)) { + db = B_TRUE; + } + + if (db) { + char lfname[BUFLEN],vicname[BUFLEN]; + getlfname(lf, lfname); + getlfname(victim, vicname); + dblog(".oO { %s settings new target: %s }", lfname, vicname); + } + + killflagsofid(lf->flags, F_TARGET); + killflagsofid(lf->flags, F_TARGETCELL); + + + if ((timelimit == PERMENANT) || (timelimit == UNLIMITED)) { + addflag(lf->flags, F_TARGET, victim->id, victim->cell->x, victim->cell->y, NULL); + } else { + addtempflag(lf->flags, F_TARGET, victim->id , victim->cell->x , victim->cell->y, NULL,timelimit); + } + // tell the player + if (cansee(player, lf)) { + makenoise(lf, N_GETANGRY); + } + + + // change allegience ? + if (!areenemies(lf, victim)) { + if (getallegiance(victim) == AL_FRIENDLY) { + if (!hasflag(lf->flags, F_HOSTILE)) { + addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + } + } + } + +} enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim) { flag_t *f; @@ -199,6 +238,30 @@ object_t *aigetwand(lifeform_t *lf, enum FLAG purpose) { return NULL; } +void aigoto(lifeform_t *lf, cell_t *c, int timelimit) { + int db = B_FALSE; + + if (lfhasflag(lf, F_DEBUG)) { + db = B_TRUE; + } + + if (db) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + dblog(".oO { %s going to targecell: %d, %d }", lfname, c->x, c->y); + } + + killflagsofid(lf->flags, F_TARGET); + killflagsofid(lf->flags, F_TARGETCELL); + + + if ((timelimit == PERMENANT) || (timelimit == UNLIMITED)) { + addflag(lf->flags, F_TARGETCELL, c->x, c->y, NA, NULL); + } else { + addtempflag(lf->flags, F_TARGETCELL, c->x, c->y, NA, NULL,timelimit); + } +} + void aimove(lifeform_t *lf) { int db = B_FALSE; object_t *curwep,*bestwep, *o; @@ -231,7 +294,7 @@ void aimove(lifeform_t *lf) { if (db) { char lfname[BUFLEN]; - getlfname(lf, lfname); + real_getlfname(lf, lfname, B_FALSE); dblog("AIMOVE: %s", lfname); } @@ -408,7 +471,7 @@ void aimove(lifeform_t *lf) { } } if (spellfailed) { - if (db) dblog(".oO { cast spell/ability tried but failed (2)! }"); + if (db) dblog(".oO { cast spell/ability tried but failed (2)! reason = %d }", reason); } else { // spell succesful return; @@ -503,13 +566,17 @@ void aimove(lifeform_t *lf) { } } } else { + cell_t *targcell; if (db) dblog(".oO { i cannot see my target. moving to last known loc %d/%d }",lastx,lasty); // can't see target. // move towards their last known location instead - addflag(lf->flags, F_TARGETCELL, lastx, lasty, NA, NULL); - // remove f_target - killflag(f); + targcell = getcellat(lf->cell->map, lastx, lasty); + if (targcell) { + aigoto(lf, targcell, PERMENANT); + } else { + if (db) dblog(".oO { go to target's last known loc failed! }"); + } /* // just try to move in a random direction @@ -540,7 +607,7 @@ void aimove(lifeform_t *lf) { // remember NOT to target this one. lf->ignorecell = c; } else { - if (db) dblog(".oO { successfully walked towards f_targetcell. }"); + if (db) dblog(".oO { successfully walked towards f_targetcell. arrived at %d,%d }",lf->cell->x, lf->cell->y); // moved towards it. // reset lifetime f->lifetime = AI_FOLLOWTIME; @@ -586,12 +653,8 @@ void aimove(lifeform_t *lf) { if (c->lf && cansee(lf, c->lf)) { if (isplayer(c->lf)) { // TODO: change to if isenemy ? if (db) dblog(".oO { found a target - lfid %d (%s) ! }",c->lf->id, c->lf->race->name); - // target them! - addtempflag(lf->flags, F_TARGET, c->lf->id, c->x, c->y, NULL, AI_FOLLOWTIME); - // tell the player - if (cansee(player, lf)) { - makenoise(lf, N_GETANGRY); - } + + aiattack(lf, c->lf, AI_FOLLOWTIME); // then move towards them... if (db) dblog(".oO { moving towards my new target }"); @@ -1064,9 +1127,7 @@ int lookforobs(lifeform_t *lf, int covetsonly) { if (gothere) { // start walking towards target cell - addtempflag(lf->flags, F_TARGETCELL, c->x, c->y, NA, NULL, AI_FOLLOWTIME); - // forget about people we are attacking - killflagsofid(lf->flags, F_TARGET); + aigoto(lf, c, AI_FOLLOWTIME); return B_TRUE; } } diff --git a/ai.h b/ai.h index e9cf252..ac1798c 100644 --- a/ai.h +++ b/ai.h @@ -1,9 +1,11 @@ #include "defs.h" +void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit); enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim); enum OBTYPE aigetfleespell(lifeform_t *lf); void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim, lifeform_t **spelllf, cell_t **spellcell, object_t **spellob, enum FLAG purpose); object_t * aigetwand(lifeform_t *lf, enum FLAG purpose); +void aigoto(lifeform_t *lf, cell_t *c, int timelimit); void aimove(lifeform_t *lf); int aipickup(lifeform_t *lf, object_t *o); int aiobok(lifeform_t *lf, object_t *o, lifeform_t *target); diff --git a/defs.h b/defs.h index 578abdc..1b62811 100644 --- a/defs.h +++ b/defs.h @@ -24,6 +24,7 @@ enum GAMEMODE { GM_LOADING, GM_LOADED, GM_GAMESTARTED, + GM_GAMEOVER, }; enum ATTRIB { @@ -1075,6 +1076,7 @@ enum FLAG { F_NONE, // dummy flag // object flags F_DEAD, // object will be removed + F_CREATEDBY, // object was made by lf id v0, text=real lfname F_ENCHANTABLE, // object can get +1/-1 ect F_STACKABLE, // can stack multiple objects togethr F_NO_PLURAL, // this obname doesn't need an 's' for plurals (eg. gold, money) @@ -1573,6 +1575,7 @@ enum ERROR { enum COMMAND { CMD_AIM, CMD_CLOSE, + CMD_COMMS, CMD_DOWN, CMD_DROP, CMD_DROPMULTI, @@ -1601,6 +1604,7 @@ enum COMMAND { CMD_RESTFULL, CMD_SAVEQUIT, CMD_TAKEOFF, + CMD_THROW, CMD_UP, CMD_WEAR, CMD_WEILD, diff --git a/flag.c b/flag.c index c4d4b4e..062f5f5 100644 --- a/flag.c +++ b/flag.c @@ -307,7 +307,16 @@ void killflag(flag_t *f) { if ((gamemode == GM_GAMESTARTED)) { if (f->pile->owner) { if (announceflagloss(f->pile->owner, f)) { - interrupt(f->pile->owner); + // don't include flags which interrupt will kill! + switch (f->id) { + case F_RESTING: + case F_RUNNING: + case F_AUTOCMD: + break; + default: + interrupt(f->pile->owner); + break; + } } } else if (f->pile->ob) { announceobflagloss(f->pile->ob, f); diff --git a/io.c b/io.c index 70b5aea..090f129 100644 --- a/io.c +++ b/io.c @@ -5,6 +5,7 @@ #include #include #include +#include "ai.h" #include "attack.h" #include "defs.h" #include "flag.h" @@ -2227,7 +2228,9 @@ void describeob(object_t *o) { f = hasflag(o->flags, F_ACCURACY); if (f) { - mvwprintw(mainwin, y, 0, "It has %s accuracy.",getaccuracyname(f->val[0])); + int acc; + acc = getobaccuracy(o, NULL); + mvwprintw(mainwin, y, 0, "It has %s accuracy.",getaccuracyname(acc)); y++; } @@ -2236,7 +2239,7 @@ void describeob(object_t *o) { if (isarmour(o)) { f = hasflag(o->flags, F_ARMOURRATING); if (f) { - mvwprintw(mainwin, y, 0, "It has an Armour Rating of %d.",f->val[0]); + mvwprintw(mainwin, y, 0, "It has an Armour Rating of %d.",f->val[0] + getobbonus(o)); y++; } f = hasflag(o->flags, F_GOESON); @@ -2690,15 +2693,134 @@ void doclose(void) { } } -void dodrop(obpile_t *op, int wantmulti) { +void docomms(void) { + lifeform_t *lf = NULL; + cell_t *where; + char buf[BUFLEN]; + char lfname[BUFLEN]; + char ch; + + where = askcoords("Talk to who?", TT_MONSTER); + if (where && where->lf && cansee(player, where->lf)) { + lf = where->lf; + } + if (!lf) { + msg("Cancelled."); + return; + } + getlfname(lf, lfname); + + sprintf(buf, "What will you say to %s?",lfname); + initprompt(&prompt, buf); + prompt.maycancel = B_TRUE; + // are they friendly? + if (areallies(player, lf)) { + addchoice(&prompt, 'a', "Attack something", NULL, NULL); + if (!isadjacent(lf->cell, player->cell)) { + addchoice(&prompt, 'c', "Come here", NULL, NULL); + } + if (isadjacent(lf->cell, player->cell)) { + addchoice(&prompt, 't', "Trade items with me", NULL, NULL); + } + } else { + addchoice(&prompt, 'y', "Yeeeeeaaaargh!", NULL, NULL); + } + addchoice(&prompt, 'n', "(nothing)", NULL, NULL); + + ch = getchoice(&prompt); + switch (ch) { + cell_t *c; + lifeform_t *lf2 = NULL; + char lfname2[BUFLEN]; + case 'a': + sprintf(buf, "Tell %s to attack who?",lfname); + c = askcoords(buf, TT_MONSTER); + if (c && c->lf && cansee(player, c->lf)) { + lf2 = c->lf; + + } + if (!lf2) { + msg("Cancelled."); + return; + } + getlfname(lf2, lfname2); + msg("You say \"Attack %s!\" to %s.",lfname2, lfname); + aiattack(lf, lf2, AI_FOLLOWTIME); + break; + case 'c': + msg("You say \"Come here!\" to %s.",lfname); + // find adjacent cell + c = getrandomadjcell(player->cell, WE_NOTSOLID); + if (c) { + aigoto(lf, c, AI_FOLLOWTIME); + } + break; + case 'n': + msg("Cancelled."); + return; + case 't': + // ask whtehr to give/take + initprompt(&prompt, "How will you trade?"); + sprintf(buf, "Give items to %s",lfname); + addchoice(&prompt, 'i', buf, NULL, NULL); + sprintf(buf, "Take items from %s",lfname); + addchoice(&prompt, 'o', buf, NULL, NULL); + sprintf(buf, "Both"); + addchoice(&prompt, 'b', buf, NULL, NULL); + sprintf(buf, "Neither"); + addchoice(&prompt, 'n', buf, NULL, NULL); + ch = getchoice(&prompt); + switch (ch) { + case 'i': + dodrop(player->pack, B_MULTIPLE, lf->pack); + break; + case 'o': + dopickup(lf->pack); + break; + case 'b': + dodrop(player->pack, B_MULTIPLE, lf->pack); + dopickup(lf->pack); + break; + case 'n': + msg("Cancelled."); + return; + } + break; + case 'y': + msg("You shout at %s!", lfname); + noise(where, player, "someone shouting!", NULL); + break; + } + taketime(player, getactspeed(player)); +} + +void dodrop(obpile_t *op, int wantmulti, obpile_t *dst) { object_t *o; char buf[BUFLEN]; int count = ALL; int i; - if (wantmulti) { - askobjectmulti(op, "Drop what", AO_NONE); + lifeform_t *tolf = NULL; + char lfname[BUFLEN]; + + + // where is destination? + if (dst->owner) { + tolf = dst->owner; + getlfname(tolf, lfname); } else { - o = askobject(op, "Drop what", &count, AO_NONE); + // on ground + } + + if (tolf) { + sprintf(buf, "Give what to %s",lfname); + } else { + strcpy(buf, "Drop what"); + } + + if (wantmulti) { + askobjectmulti(op, buf, AO_NONE); + } else { + o = askobject(op, buf, &count, AO_NONE); if (o) { retobs[0] = o; retobscount[0] = count; @@ -2726,7 +2848,13 @@ void dodrop(obpile_t *op, int wantmulti) { if (f->val[0] == BP_WEAPON) { // first try to unweild it if (unweild(player, o)) { - if (nretobs > 1) msg("Not dropping %s.",buf); more(); + if (nretobs > 1) { + if (tolf) { + msg("Not giving %s to %s.",buf, lfname); more(); + } else { + msg("Not dropping %s.",buf); more(); + } + } continue; } } else { // armour @@ -2738,12 +2866,24 @@ void dodrop(obpile_t *op, int wantmulti) { if (ch == 'y') { if (takeoff(player, o)) { // failed to take it off - can't drop it. - if (nretobs > 1) msg("Not dropping %s.",buf); more(); + if (nretobs > 1) { + if (tolf) { + msg("Not giving %s to %s.",buf, lfname); more(); + } else { + msg("Not dropping %s.",buf); more(); + } + } continue; } } else { - if (nretobs > 1) msg("Not dropping %s.",buf); more(); + if (nretobs > 1) { + if (tolf) { + msg("Not giving %s to %s.",buf, lfname); more(); + } else { + msg("Not dropping %s.",buf); more(); + } + } continue; } } @@ -2751,7 +2891,17 @@ void dodrop(obpile_t *op, int wantmulti) { if (count == ALL) count = o->amt; - drop(o, count); + if (tolf) { + o = moveob(o, dst, count); + if (o) { + getobname(o, buf, o->amt); + msg("%s takes %s from you.",lfname, buf); + } else { + msg("%s can't carry that.",lfname); + } + } else { + drop(o, count); + } } } @@ -3364,21 +3514,39 @@ int dopickup(obpile_t *op) { //object_t *o = NULL; int howmany = ALL; int i; + lifeform_t *fromlf = NULL; + char lfname[BUFLEN]; + char buf[BUFLEN]; + + if (op->owner) { + fromlf = op->owner; + getlfname(fromlf, lfname); + } + obcount = countobs(op); // anything here? if (obcount == 0) { - msg("There is nothing here to pick up!"); + if (fromlf) { + msg("%s is not carrying anything!", lfname); + } else { + msg("There is nothing here to pick up!"); + } return B_TRUE; - } else if ((obcount == 1) && (op->first->amt == 1)) { + } else if (!fromlf && (obcount == 1) && (op->first->amt == 1)) { // just get it howmany = ALL; retobs[0] = op->first; retobscount[0] = op->first->amt; nretobs = 1; } else { + if (fromlf) { + sprintf(buf, "Take what from %s",lfname); + } else { + strcpy(buf, "Pick up what"); + } // prompt which one to pick up - askobjectmulti(op, "Pick up what", AO_NONE); + askobjectmulti(op, buf, AO_NONE); } if (nretobs <= 0) { @@ -4771,14 +4939,17 @@ void handleinput(void) { addflag(player->flags, F_LASTCMD, NA, NA, NA, temp); doclose(); break; + case 'C': // communicate + docomms(); + break; case 'e': // eat doeat(player->pack); break; case 'd': // drop - dodrop(player->pack, B_SINGLE); + dodrop(player->pack, B_SINGLE, player->cell->obpile); break; case 'D': // drop multiple things - dodrop(player->pack, B_MULTIPLE); + dodrop(player->pack, B_MULTIPLE, player->cell->obpile); break; case 'W': // wear dowear(player->pack); @@ -6403,6 +6574,9 @@ void tombstone(lifeform_t *lf) { int y; char *p, *dummy; + + gamemode = GM_GAMEOVER; + getplayernamefull(pname); // clear screen diff --git a/io.h b/io.h index eebc78d..ccac7aa 100644 --- a/io.h +++ b/io.h @@ -31,7 +31,8 @@ int contains(enum OBCLASS *array, int nargs, enum OBCLASS want); void describeob(object_t *o); void doattackcell(char dirch); void doclose(void); -void dodrop(obpile_t *op, int wantmulti); +void docomms(void); +void dodrop(obpile_t *op, int wantmulti, obpile_t *dst); void doeat(obpile_t *op); void doenter(lifeform_t *lf); void doexplain(void); diff --git a/lf.c b/lf.c index 0a79d00..900157c 100644 --- a/lf.c +++ b/lf.c @@ -394,24 +394,33 @@ int areallies(lifeform_t *lf1, lifeform_t *lf2) { return B_FALSE; } -// make sure player has at least novice skill in their start weapon +// make sure player has at least novice skill in all their start weapons void autoskill(lifeform_t *lf) { - object_t *wep; skill_t *sk; - wep = getweapon(lf); - if (wep) { - sk = getobskill(wep); + object_t *o; + enum SKILLLEVEL slev; + int nweps = 0; + + if (isplayer(lf)) { + slev = PR_NOVICE; } else { - sk = findskill(SK_UNARMED); + slev = PR_ADEPT; } - if (sk) { - if (isplayer(lf)) { - giveskilllev(lf, sk->id, PR_NOVICE); - } else { - giveskilllev(lf, sk->id, PR_ADEPT); + for (o = lf->pack->first ; o ; o = o->next) { + if (isweapon(o) && canweild(lf, o)) { + sk = getobskill(o); + if (sk) { + giveskilllev(lf, sk->id, slev); + } + nweps++; } } + + if (!nweps) { + giveskilllev(lf, SK_UNARMED, slev); + } + } void autotarget(lifeform_t *lf) { @@ -523,9 +532,6 @@ void autoweild(lifeform_t *lf) { // make sure it doesn't take any time lf->timespent = pretimespent; - - // make sure we are skilled in this. - autoskill(lf); } int appearsrandomly(enum RACE rid) { @@ -1750,7 +1756,7 @@ void fightback(lifeform_t *lf, lifeform_t *attacker) { } else { lifeform_t *l; - setlftarget(lf, attacker); + aiattack(lf, attacker, AI_FOLLOWTIME); // any nearby monsters which will help out? if (getallegiance(lf) != AL_FRIENDLY) { @@ -1758,7 +1764,7 @@ void fightback(lifeform_t *lf, lifeform_t *attacker) { if (l->race->baseid == lf->race->baseid) { if (!isdead(l) && areallies(l,lf)) { if (cansee(l, attacker)) { - setlftarget(l, attacker); + aiattack(l, attacker, AI_FOLLOWTIME); } } } @@ -2589,52 +2595,26 @@ int getlfaccuracy(lifeform_t *lf) { // get weapon wep = getweapon(lf); if (wep) { - acc = getobaccuracy(wep); + acc = getobaccuracy(wep, lf); } else { // ie. unarmed op = getunarmedweapon(lf, NULL); if (op->first) { wep = op->first; - acc = getobaccuracy(wep); + acc = getobaccuracy(wep, lf); } else { // cannot attack acc = 0; } } - // modify for skill level - if (wep) { - skill_t *sk; - sk = getobskill(wep); - if (sk) { - switch (getskill(lf, sk->id)) { - case PR_INEPT: - acc -= 75; - break; - case PR_NOVICE: - acc -= 25; - break; - case PR_BEGINNER: - acc -= 5; - break; - case PR_ADEPT: - break; - case PR_SKILLED: - acc += 25; - break; - case PR_EXPERT: - acc += 50; - break; - case PR_MASTER: - acc += 75; - break; - } - } - } - if (op) killobpile(op); + // modify for weilder's level + acc += (lf->level * 2); + + // modify with dexterity acc += getstatmod(lf, A_DEX); @@ -3014,11 +2994,15 @@ char *real_getlfname(lifeform_t *lf, char *buf, int usevis) { } char *getlfnamea(lifeform_t *lf, char *buf) { + return real_getlfnamea(lf, buf, B_TRUE); +} + +char *real_getlfnamea(lifeform_t *lf, char *buf, int usevis) { if (lf == player) { sprintf(buf, "you"); } else { char buf2[BUFLEN]; - getlfname(lf, buf2); + real_getlfname(lf, buf2, usevis); sprintf(buf, "%s %s", isvowel(lf->race->name[0]) ? "an" : "a", noprefix(buf2)); @@ -3662,6 +3646,7 @@ void givejob(lifeform_t *lf, enum JOB jobid) { // now give start obs/skills from it givestartobs(lf, lf->flags); givestartskills(lf, lf->flags); + autoskill(lf); // override hp/mp from race @@ -4255,6 +4240,7 @@ int haslof(lifeform_t *viewer, cell_t *dest, enum LOFTYPE loftype, cell_t **newd cell_t *retcell[MAXRETCELLS]; reason = E_OK; + if (newdest) *newdest = viewer->cell; if (!viewer) return B_FALSE; if (!viewer->cell) return B_FALSE; @@ -4279,8 +4265,6 @@ int haslof(lifeform_t *viewer, cell_t *dest, enum LOFTYPE loftype, cell_t **newd calcbresnham(map, x1, y1, x2, y2, retcell, &numpixels); - if (newdest) *newdest = viewer->cell; - for (i = 0; i < numpixels ; i++) { cell_t *cell; object_t *blockob; @@ -4512,6 +4496,9 @@ void initjobs(void) { } } addjob(J_ADVENTURER, "Adventurer"); + addflag(lastjob->flags, F_STARTATT, A_STR, ST_AVERAGE, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "short sword"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 bananas"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour"); @@ -6548,6 +6535,7 @@ void noise(cell_t *c, lifeform_t *noisemaker, char *text, char *seetext) { void outfitlf(lifeform_t *lf) { givestartobs(lf, lf->flags); givestartskills(lf, lf->flags); + autoskill(lf); // weild/wear stuff autoweild(lf); @@ -7346,6 +7334,8 @@ void interrupt(lifeform_t *lf) { stoprunning(lf); killflagsofid(lf->flags, F_AUTOCMD); } + +/*j void setlftarget(lifeform_t *lf, lifeform_t *victim) { // first remove existing targets killflagsofid(lf->flags, F_TARGET); @@ -7362,6 +7352,7 @@ void setlftarget(lifeform_t *lf, lifeform_t *victim) { } } } +*/ int shoot(lifeform_t *lf) { object_t *gun,*ammo; @@ -7562,6 +7553,10 @@ int slipon(lifeform_t *lf, object_t *o) { moveob(o, new->obpile, 1); } } + // stop sprinting + killflagsofid(lf->flags, F_SPRINTING); + // boost spells end + stopallspells(lf); return B_FALSE; } @@ -8061,9 +8056,22 @@ void turneffectslf(lifeform_t *lf) { f = hasflag(o->flags, F_WALKDAM); if (f) { int dam; + flag_t *fromlfflag; + lifeform_t *fromlf = NULL; + char damstring[BUFLEN]; + dam = roll(f->text); getobname(o, buf, o->amt); - dam = losehp(lf, dam, f->val[0], NULL, buf); + + fromlfflag = hasflag(o->flags, F_CREATEDBY); + if (fromlfflag) { + sprintf(damstring, "%s^created by %s",buf, fromlfflag->text); + } else { + strcpy(damstring, buf); + } + + + dam = losehp(lf, dam, f->val[0], fromlf, damstring); if (dam > 0) { if (f->val[0] == DT_POISONGAS) { if (isplayer(lf) || cansee(player, lf)) { diff --git a/lf.h b/lf.h index f325c32..5ab3beb 100644 --- a/lf.h +++ b/lf.h @@ -94,6 +94,7 @@ lifeform_t *getnearbypeaceful(lifeform_t *lf); char *getlfname(lifeform_t *lf, char *buf); char *real_getlfname(lifeform_t *lf, char *buf, int usevis); char *getlfnamea(lifeform_t *lf, char *buf); +char *real_getlfnamea(lifeform_t *lf, char *buf, int usevis); enum LFSIZE getlfsize(lifeform_t *lf); float getlfweight(lifeform_t *lf, int withobs); int getspellspeed(lifeform_t *lf); @@ -188,7 +189,7 @@ void setattr(lifeform_t *lf, enum ATTRIB attr, int val); void setguntarget(lifeform_t *lf, lifeform_t *targ); void setrace(lifeform_t *lf, enum RACE rid); void setlastdam(lifeform_t *lf, char *buf); -void setlftarget(lifeform_t *lf, lifeform_t *victim); +//void setlftarget(lifeform_t *lf, lifeform_t *victim); 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); diff --git a/log.txt b/log.txt index b362097..6dc257c 100644 --- a/log.txt +++ b/log.txt @@ -7,7 +7,6 @@ xxx xxx xxx xxx -xxx finding random lf with rarity val 85-100 -> possibility: goblin, rarity=85 @@ -116,3 +115,183 @@ finding random lf with rarity val 85-100 -> possibility: giant fly, rarity=85 -> possibility: glowbug, rarity=85 got 9 possibilities. +finding random lf with rarity val 85-100 + +-> possibility: goblin, rarity=85 +-> possibility: xat, rarity=90 +-> possibility: giant bat, rarity=90 +-> possibility: giant worker ant, rarity=85 +-> possibility: giant newt, rarity=100 +-> possibility: giant rat, rarity=90 +-> possibility: brown snake, rarity=85 +-> possibility: giant fly, rarity=85 +-> possibility: glowbug, rarity=85 +got 9 possibilities. +finding random lf with rarity val 85-100 + +-> possibility: goblin, rarity=85 +-> possibility: xat, rarity=90 +-> possibility: giant bat, rarity=90 +-> possibility: giant worker ant, rarity=85 +-> possibility: giant newt, rarity=100 +-> possibility: giant rat, rarity=90 +-> possibility: brown snake, rarity=85 +-> possibility: giant fly, rarity=85 +-> possibility: glowbug, rarity=85 +got 9 possibilities. +finding random lf with rarity val 85-100 + +-> possibility: goblin, rarity=85 +-> possibility: xat, rarity=90 +-> possibility: giant bat, rarity=90 +-> possibility: giant worker ant, rarity=85 +-> possibility: giant newt, rarity=100 +-> possibility: giant rat, rarity=90 +-> possibility: brown snake, rarity=85 +-> possibility: giant fly, rarity=85 +-> possibility: glowbug, rarity=85 +got 9 possibilities. +finding random lf with rarity val 85-100 + +-> possibility: goblin, rarity=85 +-> possibility: xat, rarity=90 +-> possibility: giant bat, rarity=90 +-> possibility: giant worker ant, rarity=85 +-> possibility: giant newt, rarity=100 +-> possibility: giant rat, rarity=90 +-> possibility: brown snake, rarity=85 +-> possibility: giant fly, rarity=85 +-> possibility: glowbug, rarity=85 +got 9 possibilities. +finding random lf with rarity val 85-100 + +-> possibility: goblin, rarity=85 +-> possibility: xat, rarity=90 +-> possibility: giant bat, rarity=90 +-> possibility: giant worker ant, rarity=85 +-> possibility: giant newt, rarity=100 +-> possibility: giant rat, rarity=90 +-> possibility: brown snake, rarity=85 +-> possibility: giant fly, rarity=85 +-> possibility: glowbug, rarity=85 +got 9 possibilities. +rollhitdice() - rolling 2d4 + 2 +rollhitdice() - mod is +-5% +rollhitdice() ---- die 1/2 == 5 +rollhitdice() ---- die 2/2 == 6 +TOTAL: 11 + -> modified to: 11 +givejob() starting. + +processing normal flag: 186 +processing normal flag: 145 +processing normal flag: 145 +processing normal flag: 145 +processing normal flag: 145 +processing normal flag: 145 +processing normal flag: 145 +processing normal flag: 145 +processing normal flag: 145 +processing normal flag: 145 +processing normal flag: 145 +processing normal flag: 145 +processing normal flag: 145 +processing normal flag: 146 +processing normal flag: 146 +processing normal flag: 146 +processing normal flag: 146 +processing normal flag: 146 +processing normal flag: 213 +processing normal flag: 213 +processing normal flag: 213 +processing normal flag: 213 +processing normal flag: 213 +processing normal flag: 213 +processing normal flag: 213 +processing normal flag: 213 +processing normal flag: 213 +processing normal flag: 213 +processing normal flag: 213 +processing normal flag: 213 +processing normal flag: 213 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +processing normal flag: 212 +fireat(): dam = throwdam(2) * speed(2) = 4 +AIMOVE: something +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i have a target... } +.oO { my target is lfid 31 (human). } +.oO { i cannot see my target. moving to last known loc 12/15 } +.oO { something going to targecell: 12, 15 } +.oO { walking from 12,17 towards f_targetcell (12,15) ... } +.oO { successfully walked towards f_targetcell. } +AIMOVE: something +.oO { looking for covetted objects... } +.oO { didn't find any obs i want } +.oO { walking from 11,18 towards f_targetcell (12,15) ... } +.oO { successfully walked towards f_targetcell. } diff --git a/map.c b/map.c index aa37ce4..0bd95b8 100644 --- a/map.c +++ b/map.c @@ -167,6 +167,19 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt) { } free(moncell); } + + // sometimes give the lf random objects (extra monsters through + // 'numappears' don't get them. + if (!lfhasflag(lf, F_NOPACK)) { + if (rnd(1,3) == 1) { + int nobs = rnd(1,3); + char buf[BUFLEN]; + int i; + for (i = 0; i < nobs; i++) { + if (getrandomob(c->map, buf)) addob(lf->pack, buf); + } + } + } lf->born = B_TRUE; } // end if lf } diff --git a/move.c b/move.c index f07675a..49ffe34 100644 --- a/move.c +++ b/move.c @@ -81,24 +81,53 @@ int canmove(lifeform_t *lf, int dir, enum ERROR *error) { } +// lf is the one moving, lf2 is the one who is being forced to swap +int canswapwith(lifeform_t *lf, lifeform_t *lf2) { + // player can never be forced to swap + if (isplayer(lf2)) { + return B_FALSE; + } + // cannot swap if lf's cell is dangerous to lf2 + if (celldangerous(lf2, lf->cell, B_FALSE, NULL)) { + return B_FALSE; + } + + // allies can always swap + if (areallies(lf, lf2)) { + return B_TRUE; + } + if (isplayer(lf) && !areenemies(lf, lf2)) { + // player can swap with peaceful lgs + // if they are a lot smaller + if (getlfsize(lf) - getlfsize(lf2) >= 2) { + return B_TRUE; + } + } + return B_FALSE; +} + // will populate rdata -int celldangerous(lifeform_t *lf, cell_t *cell, enum ERROR *error) { +// onlyifknown = true means "check for _known_ dangerous objects" +// onlyifknown = false means "check for _any dangerous objects, doesn't matter if we know about them" +int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *error) { enum IQBRACKET iq; + int include_nonobvious = B_FALSE; + flag_t *f; + object_t *o; + // default if (error) { *error = E_OK; rdata = NULL; } - // check for _known_ dangerous objects - iq = getiqname(getattr(lf, A_IQ), NULL); - if ((iq >= IQ_AVERAGE) && !isblind(lf)) { - flag_t *f; - object_t *o; + // obvious things that you can see + if (!onlyifknown || haslos(lf, cell)) { for (o = cell->obpile->first ; o ; o = o->next) { - // don't walk on sharp objects without boots - if (hasflag(o->flags, F_SHARP)) { - if (!getequippedob(lf->pack, BP_FEET)) { + f = hasflag(o->flags, F_WALKDAM); + if (f) { + // are we immune to this? + if (!lfhasflagval(lf, F_DTIMMUNE, f->val[0], NA, NA, NULL)) { if (error) { *error = E_AVOIDOB; rdata = o; @@ -106,10 +135,23 @@ int celldangerous(lifeform_t *lf, cell_t *cell, enum ERROR *error) { return B_TRUE; } } - f = hasflag(o->flags, F_WALKDAM); - if (f) { - // are we immune to this? - if (!lfhasflagval(lf, F_DTIMMUNE, f->val[0], NA, NA, NULL)) { + } + } + + // non-obvious things - only include these if we are smart enough + if (!onlyifknown) { + include_nonobvious = B_TRUE; + } else { + iq = getiqname(getattr(lf, A_IQ), NULL); + if ((iq >= IQ_AVERAGE) && haslos(lf, cell)) { + include_nonobvious = B_TRUE; + } + } + if (include_nonobvious) { + for (o = cell->obpile->first ; o ; o = o->next) { + // don't walk on sharp objects without boots + if (hasflag(o->flags, F_SHARP)) { + if (!getequippedob(lf->pack, BP_FEET)) { if (error) { *error = E_AVOIDOB; rdata = o; @@ -616,7 +658,6 @@ int movelf(lifeform_t *lf, cell_t *newcell) { if (haslos(l, newcell)) { int dointerrupt = B_FALSE; - if (isplayer(l)) { if (areenemies(lf, l)) { if (lfhasflag(l, F_RUNNING) || lfhasflag(l, F_RESTING)) { @@ -1213,31 +1254,31 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { } break; case E_LFINWAY: - if (areallies(lf, cell->lf)) { - // if it's the player in the way... - if (isplayer(cell->lf)) { - return attacklf(lf, cell->lf); - } else { - lifeform_t *lfinway; - cell_t *oldcell; - // otherwise swap locations. - - // make lf who is there vanish temporarily... - lfinway = cell->lf; - cell->lf = NULL; - lfinway->cell = NULL; + if (canswapwith(lf, cell->lf)) { + lifeform_t *lfinway; + cell_t *oldcell; + // otherwise swap locations. + + // make lf who is there vanish temporarily... + lfinway = cell->lf; + cell->lf = NULL; + lfinway->cell = NULL; - // remember your cell - oldcell = lf->cell; + // remember your cell + oldcell = lf->cell; - // move you.. - moveto(lf, cell, onpurpose); - taketime(lf, getmovespeed(lf)); + // move you.. + moveto(lf, cell, onpurpose); + taketime(lf, getmovespeed(lf)); - // move them... - lfinway->cell = oldcell; - oldcell->lf = lfinway; - reason = E_OK; + // move them... + lfinway->cell = oldcell; + oldcell->lf = lfinway; + reason = E_OK; + if (isplayer(lf)) { + char lfname[BUFLEN]; + getlfname(lfinway, lfname); + msg("You swap places with %s.", lfname); } } else { // attack! @@ -1315,7 +1356,7 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) { } cell = getcellindir(lf->cell, dir); - if (celldangerous(lf, cell, error)) { + if (celldangerous(lf, cell, B_TRUE, error)) { return B_FALSE; } diff --git a/move.h b/move.h index 9868e6a..1c054a8 100644 --- a/move.h +++ b/move.h @@ -2,7 +2,8 @@ int canandwillmove(lifeform_t *lf, int dir, enum ERROR *error); int canmove(lifeform_t *lf, int dir, enum ERROR *error); -int celldangerous(lifeform_t *lf, cell_t *cell, enum ERROR *error); +int canswapwith(lifeform_t *lf, lifeform_t *lf2); +int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *error); int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error); int closedoorat(lifeform_t *lf, cell_t *c); int closedoor(lifeform_t *lf, object_t *o); diff --git a/nexus.c b/nexus.c index 48a2cd4..dd7e3ef 100644 --- a/nexus.c +++ b/nexus.c @@ -631,6 +631,7 @@ void initcommands(void) { addcommand(CMD_REST, '.', "Rest once."); 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_EAT, 'e', "Eat something."); @@ -643,6 +644,7 @@ void initcommands(void) { addcommand(CMD_QUAFF, 'q', "Quaff (drink) a potion."); addcommand(CMD_READ, 'r', "Read a scroll/book."); addcommand(CMD_RESTFULL, 'R', "Rest until healed, or train your skills."); + addcommand(CMD_THROW, 't', "Throw an object."); addcommand(CMD_TAKEOFF, 'T', "Take off an item of clothing/jewelery."); addcommand(CMD_WEILD, 'w', "Weild a weapon."); addcommand(CMD_WEAR, 'W', "Wear an item of clothing/jewelery."); diff --git a/objects.c b/objects.c index d68b675..5a5d50b 100644 --- a/objects.c +++ b/objects.c @@ -975,7 +975,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack) { // add objects in a circle // returns # added. -int addobburst(cell_t *where, int range, int dirtype, char *name) { +int addobburst(cell_t *where, int range, int dirtype, char *name, lifeform_t *fromlf) { int (*distfunc)(cell_t *, cell_t *); int x,y; cell_t *c; @@ -994,7 +994,12 @@ int addobburst(cell_t *where, int range, int dirtype, char *name) { c = getcellat(where->map, x,y); if (distfunc(where, c) <= range) { if (!c->type->solid) { - if (addob(c->obpile, name)) nadded++; + object_t *o; + o = addob(c->obpile, name); + if (o) { + if (fromlf) setobcreatedby(o, fromlf); + nadded++; + } } } } @@ -1245,6 +1250,7 @@ void adjustdamob(object_t *o, unsigned int *dam, enum DAMTYPE damtype) { } o->blessknown = B_TRUE; } + *dam = 0; return; } } else if (o->blessed == B_CURSED) { @@ -2044,7 +2050,7 @@ int getcharges(object_t *o) { return amt; } -int getobaccuracy(object_t *wep) { +int getobaccuracy(object_t *wep, lifeform_t *weilder) { int acc; flag_t *f; @@ -2063,6 +2069,36 @@ int getobaccuracy(object_t *wep) { acc = f->val[0]; } + if (weilder) { + skill_t *sk; + // modify for weilder's skill + sk = getobskill(wep); + if (sk) { + switch (getskill(weilder, sk->id)) { + case PR_INEPT: + acc -= 75; + break; + case PR_NOVICE: + acc -= 25; + break; + case PR_BEGINNER: + acc -= 5; + break; + case PR_ADEPT: + break; + case PR_SKILLED: + acc += 25; + break; + case PR_EXPERT: + acc += 50; + break; + case PR_MASTER: + acc += 75; + break; + } + } + } + // modify for attacker's level if (wep->pile->owner) { acc += (wep->pile->owner->level * 2); @@ -4400,7 +4436,7 @@ void initobjects(void) { addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL); addot(OT_SCR_REMOVECURSE, "scroll of remove curse", "Removes curses from all weilded equipment.", MT_PAPER, 0.5, OC_SCROLL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addot(OT_SCR_TURNUNDEAD, "scroll of turn undead", "Instills fear in undead creatures.", MT_PAPER, 0.5, OC_SCROLL); addflag(lastot->flags, F_LINKSPELL, OT_S_TURNUNDEAD, NA, NA, NULL); @@ -4583,7 +4619,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); // l6 - addot(OT_S_FLIGHT, "flight", "Allows the caster to fly.", MT_NOTHING, 0, OC_SPELL); + addot(OT_S_FLIGHT, "fly", "Allows the caster to fly.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); @@ -4844,7 +4880,7 @@ void initobjects(void) { addflag(lastot->flags, F_MANUALOF, SK_SS_GRAVITY, NA, NA, NULL); addot(OT_MAN_SS_LIFE, "manual of life magic", "Teaches you the skill 'life magic'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_SS_LIFE, NA, NA, NULL); - addot(OT_MAN_SS_MODIFICATION, "manual of modification", "Teaches you the skill 'modification'.", MT_PAPER, 3, OC_BOOK); + addot(OT_MAN_SS_MODIFICATION, "manual of modification magic", "Teaches you the skill 'modification magic'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_SS_MODIFICATION, NA, NA, NULL); addot(OT_MAN_SS_MENTAL, "manual of psionics", "Teaches you the skill 'psionics'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_SS_MENTAL, NA, NA, NULL); @@ -4901,7 +4937,7 @@ void initobjects(void) { addflag(lastot->flags, F_LINKSPELL, OT_S_GRAVLOWER, NA, NA, NULL); addot(OT_SB_GRAVBOOST, "spellbook of boost gravity", "Teaches the spell 'boost gravity'.", MT_PAPER, 1.5, OC_BOOK); addflag(lastot->flags, F_LINKSPELL, OT_S_GRAVBOOST, NA, NA, NULL); - addot(OT_SB_FLIGHT, "spellbook of flight", "Teaches the spell 'flight'.", MT_PAPER, 1.5, OC_BOOK); + addot(OT_SB_FLIGHT, "spellbook of fly", "Teaches the spell 'fly'.", MT_PAPER, 1.5, OC_BOOK); addflag(lastot->flags, F_LINKSPELL, OT_S_FLIGHT, NA, NA, NULL); addot(OT_SB_HASTE, "spellbook of haste", "Teaches the spell 'haste'.", MT_PAPER, 1.5, OC_BOOK); addflag(lastot->flags, F_LINKSPELL, OT_S_HASTE, NA, NA, NULL); @@ -6348,33 +6384,63 @@ int isbetterarmourthan(object_t *a, object_t *b) { // compare weapons using max damage int isbetterwepthan(object_t *a, object_t *b) { - flag_t *f; + //flag_t *f; int dama,damb; + float acca,accb; + int db = B_FALSE; + char namea[BUFLEN]; + char nameb[BUFLEN]; if (!a) return B_FALSE; if (!b) return B_TRUE; - f = hasflag(a->flags, F_DAM); - if (f) { - dama = (f->val[0] * f->val[1]) + f->val[2]; - } else { - dama = 0; + /* if (a->pile->owner && lfhasflag(a->pile->owner, F_DEBUG)) { + db = B_TRUE; + } + if (b->pile->owner && lfhasflag(b->pile->owner, F_DEBUG)) { + db = B_TRUE; + } */ + + + if (db) { + getobname(a, namea, a->amt); + getobname(b, nameb, b->amt); } - f = hasflag(b->flags, F_DAM); - if (f) { - damb = (f->val[0] * f->val[1]) + f->val[2]; - } else { - damb = 0; - } + getdamrange(a->flags, NULL, &dama); + getdamrange(b->flags, NULL, &damb); // modify based on extra props if (hasflag(a->flags, F_HASBRAND)) { dama *= 3; } + if (hasflag(a->flags, F_ONFIRE)) { + dama += 8; + } + + if (hasflag(b->flags, F_HASBRAND)) { damb *= 3; } + if (hasflag(b->flags, F_ONFIRE)) { + damb += 8; + } + + // modify with accuracy + acca = getobaccuracy(a, a->pile->owner); + accb = getobaccuracy(b, b->pile->owner); + + + if (db) { + msg("PREACC:a=%s:%d(acc %d), b=%s:%d(acc %d)",namea,dama,(int)acca, nameb, damb,(int)accb); + } + + dama = (int)((float)dama * (acca/100)); + damb = (int)((float)damb * (accb/100)); + + if (db) { + msg("POST:a=%s:%d(acc %d), b=%s:%d(acc %d)",namea,dama,(int)acca, nameb, damb,(int)accb); + } if (dama > damb) return B_TRUE; return B_FALSE; @@ -8972,6 +9038,15 @@ void setinscription(object_t *o, char *text) { o->inscription = strdup(text); } +void setobcreatedby(object_t *o, lifeform_t *lf) { + char lfname[BUFLEN]; + if (!lf) { + return; + } + real_getlfnamea(lf, lfname, B_FALSE); + addflag(o->flags, F_CREATEDBY, lf->id, NA, NA, lfname); +} + // randomizes hidden names void shufflehiddennames(void) { int i,n; @@ -9240,6 +9315,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, object_t *newob; cell_t *newloc; int db = B_TRUE; + int willcatch = B_FALSE; reason = E_OK; @@ -9333,6 +9409,9 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, } if (target) { getlfname(target, targetname); + if (areallies(thrower, target) && !firearm) { + willcatch = B_TRUE; + } } // touch effects @@ -9346,7 +9425,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, if (thrower && isplayer(thrower)) { // player is throwing something if (target) { - msg("You %s %s at %s.", throwverbpres, obname, targetname); + msg("You %s %s %s %s.", throwverbpres, obname, willcatch ? "to" : "at", targetname); } else { msg("You %s %s.",throwverbpres, obname); } @@ -9358,7 +9437,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, obname); if (target && haslos(player, where)) { - strcat(throwstring, " at "); + strcat(throwstring, willcatch ? " to " : " at "); strcat(throwstring, targetname); } strcat(throwstring, "."); @@ -9430,7 +9509,11 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, // find out your chances of hitting if (target) { if (thrower) { - acc = getmissileaccuracy(thrower, where, o, firearm, A_DEX); + if (willcatch) { + acc = 100; + } else { + acc = getmissileaccuracy(thrower, where, o, firearm, A_DEX); + } } else { // purely based on saving throw... acc = 100; @@ -9450,7 +9533,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, } // saving throw - if (youhit) { + if (youhit && !willcatch) { if (skillcheck(target, SC_DODGE, 20, 0)) { youhit = B_FALSE; } @@ -9462,77 +9545,87 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, msg("%s recoils in fear!", targetname); } o->blessknown = B_TRUE; + // ... but undead won't catch blessed things + willcatch = B_FALSE; } // if someone is there, they take damage and the object might die // this should be "if target && youhit" if (youhit) { - int dam = 0,shatterdam = 0; - char damstring[BUFLEN]; - int reduceamt = 0; - int throwdam; - - throwdam = getthrowdam(o); - dam = throwdam * speed; - if (db) dblog("fireat(): dam = throwdam(%d) * speed(%d) = %d",throwdam, speed, dam); - - // special case - if (o->type->id == OT_RUBBERBULLET) { - dam = 1; - } - - // deal extra cutting damage afterwards? - shatterdam = getshatterdam(o); - if (shatterdam > 0) { - shattered = B_TRUE; - } - - // announce - if (seen) { - char buf2[BUFLEN]; - sprintf(buf2, "%s hit%s %s%s",obname,(amt == 1) ? "s" : "", targetname, - (willshatter(o->material->id)) ? " and shatters!" : "." - ); - if (lfhasflag(player, F_EXTRAINFO)) { - char damstring[BUFLEN]; - sprintf(damstring, " [%d dmg]",dam); - strcat(buf2, damstring); - } - msg("%s", buf2); - } else { - if (willshatter(o->material->id)) { - noise(where, NULL, "shattering glass.", NULL); - } - } - sprintf(damstring, "%s (%s by %s)",obname,throwverbpast, realthrowernamea); - - reduceamt = getarmourdamreduction(target, o, dam, DT_PROJECTILE); - - applyarmourdamreduction(target, o, reduceamt, &dam, DT_PROJECTILE); - - if (dam > 0) { - lifeform_t *whogetsxp = NULL; - // TODO: at the moment you won't get experience if you telekenetically - // throw an object at something. is this okay? - if (thrower && (thrower->cell == srcloc)) { - whogetsxp = thrower; - } - losehp(target, dam, DT_PROJECTILE, whogetsxp, damstring); - } - - if (reduceamt && (speed >= 3)) { - applyarmourdamage(target, o, reduceamt, DT_PROJECTILE); - } - - if (shatterdam && !isdead(target)) { - // extra glass damage + if (willcatch) { if (seen) { - msg("%s %s showered in glass shards!", targetname, isplayer(target) ? "are" : "is"); + msg("%s catches %s.", targetname, obname); + } + moveob(o, target->pack, amt); + return B_FALSE; + } else { + int dam = 0,shatterdam = 0; + char damstring[BUFLEN]; + int reduceamt = 0; + int throwdam; + + throwdam = getthrowdam(o); + dam = throwdam * speed; + if (db) dblog("fireat(): dam = throwdam(%d) * speed(%d) = %d",throwdam, speed, dam); + + // special case + if (o->type->id == OT_RUBBERBULLET) { + dam = 1; + } + + // deal extra cutting damage afterwards? + shatterdam = getshatterdam(o); + if (shatterdam > 0) { + shattered = B_TRUE; + } + + // announce + if (seen) { + char buf2[BUFLEN]; + sprintf(buf2, "%s hit%s %s%s",obname,(amt == 1) ? "s" : "", targetname, + (willshatter(o->material->id)) ? " and shatters!" : "." + ); + if (lfhasflag(player, F_EXTRAINFO)) { + char damstring[BUFLEN]; + sprintf(damstring, " [%d dmg]",dam); + strcat(buf2, damstring); + } + msg("%s", buf2); + } else { + if (willshatter(o->material->id)) { + noise(where, NULL, "shattering glass.", NULL); + } } sprintf(damstring, "%s (%s by %s)",obname,throwverbpast, realthrowernamea); - losehp(target, shatterdam, DT_SLASH, thrower, damstring); - } + + reduceamt = getarmourdamreduction(target, o, dam, DT_PROJECTILE); + + applyarmourdamreduction(target, o, reduceamt, &dam, DT_PROJECTILE); + + if (dam > 0) { + lifeform_t *whogetsxp = NULL; + // TODO: at the moment you won't get experience if you telekenetically + // throw an object at something. is this okay? + if (thrower && (thrower->cell == srcloc)) { + whogetsxp = thrower; + } + losehp(target, dam, DT_PROJECTILE, whogetsxp, damstring); + } + + if (reduceamt && (speed >= 3)) { + applyarmourdamage(target, o, reduceamt, DT_PROJECTILE); + } + + if (shatterdam && !isdead(target)) { + // extra glass damage + if (seen) { + msg("%s %s showered in glass shards!", targetname, isplayer(target) ? "are" : "is"); + } + sprintf(damstring, "%s (%s by %s)",obname,throwverbpast, realthrowernamea); + losehp(target, shatterdam, DT_SLASH, thrower, damstring); + } + } } else { if (isplayer(thrower)) { msg("Your %s misses %s.", noprefix(obname), targetname); @@ -10298,7 +10391,7 @@ int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, ob // base accuracy if (firearm) { - acc = getobaccuracy(firearm); + acc = getobaccuracy(firearm, thrower); } else { acc = 50; } diff --git a/objects.h b/objects.h index 080de43..b17d84a 100644 --- a/objects.h +++ b/objects.h @@ -10,7 +10,7 @@ material_t *addmaterial(enum MATERIAL id, char *name, float weightrating); objectclass_t *addoc(enum OBCLASS id, char *name, char *desc, char glyph); object_t *addob(obpile_t *where, char *name); object_t *addobject(obpile_t *where, char *name, int canstack); -int addobburst(cell_t *where, int range, int dirtype, char *name); +int addobburst(cell_t *where, int range, int dirtype, char *name, lifeform_t *fromlf); obmod_t *addobmod(enum OBMOD id, char *prefix); obpile_t *addobpile(lifeform_t *owner, cell_t *where); objecttype_t *addot(int id, char *name, char *description, int material, float weight, int obclassid); @@ -49,7 +49,7 @@ int geteffecttime(int min, int max, enum BLESSTYPE isblessed); objecttype_t *getlinkspell(object_t *o); enum MATSTATE getmaterialstate(enum MATERIAL mat); int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, object_t *firearm, enum ATTRIB whichatt); -int getobaccuracy(object_t *wep); +int getobaccuracy(object_t *wep, lifeform_t *weilder); int getobbonus(object_t *o); skill_t *getobskill(object_t *o); int getobvalue(object_t *o); @@ -170,6 +170,7 @@ int removeob(object_t *o, int howmany); object_t *relinkob(object_t *src, obpile_t *dst); void setblessed(object_t *o, enum BLESSTYPE wantbless); void setinscription(object_t *o, char *text); +void setobcreatedby(object_t *o, lifeform_t *lf); void shufflehiddennames(void); object_t *splitob(object_t *o); int takedamage(object_t *o, unsigned int howmuch, int damtype); diff --git a/spell.c b/spell.c index 107672e..cf78890 100644 --- a/spell.c +++ b/spell.c @@ -19,6 +19,8 @@ extern lifeform_t *player; extern skill_t *firstskill, *lastskill; +extern int needredraw; + extern prompt_t prompt; extern WINDOW *msgwin; @@ -830,7 +832,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int tries = 0,maxtries = 10; // pick a random location targcell = NULL; - while (!targcell || !cellwalkable(caster, targcell, NULL) || celldangerous(caster, targcell, NULL)) { + while (!targcell || !cellwalkable(caster, targcell, NULL) || celldangerous(caster, targcell, B_FALSE, NULL)) { int i; i = rnd(0,caster->nlos-1); targcell = caster->los[i]; @@ -858,19 +860,31 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // don't set caster's cell on fire! for (i = 1; i < nretcell; i++) { cell_t *c; + object_t *o; c = retcell[i]; // set on fire - addob(c->obpile, "medium fire"); - if (c->lf) { - char buf[BUFLEN]; - getlfname(c->lf,buf); - if (!isimmuneto(c->lf->flags, DT_FIRE)) { - msg("%s burn%s!",buf,isplayer(c->lf) ? "" : "s"); + o = addob(c->obpile, "medium fire"); + + if (o) { + setobcreatedby(o, caster); + if (c->lf) { + char buf[BUFLEN]; + char damstring[BUFLEN]; + char realcname[BUFLEN]; + getlfname(c->lf,buf); + if (!isimmuneto(c->lf->flags, DT_FIRE)) { + msg("%s burn%s!",buf,isplayer(c->lf) ? "" : "s"); + } + real_getlfname(caster, realcname, B_FALSE); + sprintf(damstring, "%s%s wave of fire", realcname, getpossessive(realcname)); + losehp(c->lf, rolldie(2,10), DT_FIRE, caster, damstring); } - losehp(c->lf, rolldie(2,10), DT_FIRE, caster, "a wave of fire"); } } + if (cansee(player, caster)) { + needredraw = B_TRUE; + } } else if (spellid == OT_S_CLOUDKILL) { if (!validatespellcell(caster, &targcell, TT_MONSTER, B_FALSE, LOF_NEED, spellid, power)) return B_TRUE; @@ -880,7 +894,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_FALSE; } - addobburst(targcell, (power/3), DT_COMPASS, "cloud of gas"); + addobburst(targcell, (power/3), DT_COMPASS, "cloud of gas", caster); if (haslos(player, targcell)) { msg("A cloud of poison gas appears!"); @@ -1331,6 +1345,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (!targcell->type->solid || hasflag(targcell->type->material->flags, F_FLAMMABLE)) { int dir; cell_t *c; + object_t *o; // centre fireball here... if (isplayer(caster)) { msg("You launch an enormous ball of fire!"); @@ -1356,14 +1371,20 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ for (dir = D_N; dir <= D_W; dir++) { c = getcellindir(targcell, dir); if (c && (!c->type->solid || hasflag(c->type->material->flags, F_FLAMMABLE)) ) { - addob(c->obpile, "large fire"); + o = addob(c->obpile, "large fire"); + if (o) { + setobcreatedby(o, caster); + } } } for (dir = DC_NE; dir <= DC_NW; dir += 2) { cell_t *c; c = getcellindir(targcell, dir); if (c && (!c->type->solid || hasflag(c->type->material->flags, F_FLAMMABLE)) ) { - addob(c->obpile, "medium fire"); + o = addob(c->obpile, "medium fire"); + if (o) { + setobcreatedby(o, caster); + } } } for (dir = D_N; dir <= D_W; dir++) { @@ -1372,7 +1393,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (c) { c = getcellindir(c, dir); if (c && (!c->type->solid || hasflag(c->type->material->flags, F_FLAMMABLE)) ) { - addob(c->obpile, "small fire"); + o = addob(c->obpile, "small fire"); + if (o) { + setobcreatedby(o, caster); + } } } } @@ -1476,6 +1500,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ f->val[0] += power; f->val[1] += power; } + setobcreatedby(o, caster); } else { failed = B_TRUE; } @@ -1659,7 +1684,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (seenbyplayer) *seenbyplayer = B_TRUE; } - if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (getmr(target) && skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { if (isplayer(target) || haslos(player, target->cell)) { getlfname(target, buf); msg("%s blur%s for a moment.",buf, isplayer(target) ? "" : "s"); @@ -1819,7 +1844,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (seenbyplayer) *seenbyplayer = B_TRUE; } } else { - losehp(l, 9999, DT_DIRECT, NULL, "an infinite death spell"); + char dambuf[BUFLEN]; + char cname[BUFLEN]; + real_getlfname(caster, cname, B_FALSE); + sprintf(dambuf, "%s%s infinite death spell", cname, getpossessive(cname)); + losehp(l, 9999, DT_DIRECT, NULL, dambuf); } } } @@ -2303,6 +2332,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // create the source portal srcportal = addob(srccell->obpile, "magic portal"); + setobcreatedby(srcportal, caster); // announce, because we might have a delay creating the level... if (isplayer(caster)) { @@ -2327,6 +2357,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // add the dst portal dstportal = addob(newcell->obpile, "magic portal"); + setobcreatedby(dstportal, caster); // link the dst portal addflag_real(dstportal->flags, F_MAPLINK, caster->cell->map->id, srccell->x, srccell->y, NULL, PERMENANT, B_FALSE, -1); @@ -3367,6 +3398,8 @@ cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, i maxrange = getspellrange(spellid, power); + if (*targcell) where = *targcell; + while (!done) { if (where) { cell_t *newwhere = NULL;