From dd03042c7045935f3d3903d8c02ce2ca9b149a77 Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Mon, 14 Nov 2011 18:21:40 +0000 Subject: [PATCH] - [+] prevent 'A' (forceattack) behind you - [+] replace: - [+] Something critically savages your body. Your uncursed suit of ring mail protects you. Your suit of ring mail is damaged! - [+] with: - [+] Something critically savages your suit of ring mail. - [+] Your suit of ring mail is damaged! - [+] tremorsense shouldn't see flying creatures - [+] rename blink to "bamf" - [+] add F_containsmeat for non-vegetarian foods - [+] use this in vegetarian checks instead of mt_Flesh - [+] "what goes up" spell - [+] "equal and opposite" spell - [+] why didn't cyborg ninja start with weapon weilded? - [+] getbestwepon - accuracy was counting for too much. have changed calculation. - [+] why is wizard's staff not enchanted??? - [+] elephant race - Pachyon or Mammoan - [+] bonus - [+] Leather skin - [+] str++ - [+] photo mem - [+] high listen skill - [+] good smell - [+] penalty - [+] slow movement - [+] no armour on ears - [+] agi- - [+] low eyesight - [+] vuln to sonic - [+] vegetarian - [+] other - [+] large - [+] throw salt to blind targets - [+] if you learn a new spell school skill while game is in progress, gain a 1st level spell too. - [+] for random roast meat, always use base race - [+] ie. orc, not "elite orc" - [+] (ie. human, not 'town guard') - [+] remove "prepare food" skill. - [+] use "cook" instead - [+] startskill should be a modifier, not absolute. - [+] ie. elf can have sk_ranged, so can hunter. these will now stack. - [+] chance for ai to use a firearm is lowered based on firearm accuracy - [+] bug: massively high amount of skillxp needed for a point - [+] firearms should do more damage at pointblank range. - [+] icicle bugs - getrandomadjcell for knockback failing - [+] still a bug with firearm accuracy updating - [+] 2 squares away, move towards enemy - it doesn't update! - [+] display all valid hits in brown - [+] wear melted wax in ears to reduce sonic damage - [+] ranged skillls - [+] adp - [+] fast reloading - [+] exp - [+] fire through lifeforms! lof_wallstop instead of lof_need - [+] mas - [+] extra dam. - [+] object HP issue: - [+] head: b - an uncursed helmet [AR:3] [110%] - [+] body: c - an uncursed suit of ring mail [AR:6] [173%] - [+] hands: d - an uncursed battered pair of gauntlets [AR:2] [86%] - [+] are objects taking negative damage?? - [+] have put an assertion in to check - [+] wait for it to happen again... - [+] add hitchance to askcoords when throwing/shooting - [+] code it - [+] test for throw - [+] add for telekeniis too - [+] add for guns: - [+] "targetted: something [x%]" - [+] "bow->Target->xxx [x%]" - [+] show gun target on botl - [+] redo throw accuracy: - [+] 100 to hit yourself - [+] apply per-cell penalty based on: - [+] throwing / ranged skill (more) - [+] AGI (lesser) - [+] wetsuit description not showing dtresist cold!! - [+] hunter job - [+] wetsuit (covers multiple body parts), prot from cold - [+] announce bleeding damage from injuries - [+] only mark _weapons_ as 'tried' when weilding them - [+] change random items: - [+] fix wantrr bug - [+] test... - [+] new function: enum RARITY pickrarity() - [+] check for all wantrr = xxx and use pickrarity instead. - [+] give classes a RR_RARITY - [+] common - [+] weapon / armour / money / missile - [+] furniture - [+] misc - [+] rock - [+] uncommon - [+] potion / scroll / food - [+] rare - [+] trap - [+] tech/tool - [+] dfeature (pentagram, vending machine, etc) - [+] vrare - [+] wand - [+] ring - [+] book * [+] rewrite wrappers * [+] marge getrandomobofclass and getrandomob - [+] bug: telling allies to attack something they can't see. need a msg for this. - [+] Norman->Attack->A young hawk [flying, facing NE] - [+] Cancelled. - [+] bug: allies not regaining hp when asleep! fixed. - [+] you can now always 'see' your allies if you have LOH - [+] ie. scannedcell - [+] ie. cansee - [+] player luck should cause better random item creation, and easier monsters - [+] pickrr() needs arg to say what it is for (vault , ob, lf) - [+] meals have special effects. eg: - [+] easy: - [+] mushroom + water = mushroom soup = restore a little stamina - [+] tomato + water = tomato soup = restore a little stamina - [+] apple + stone = fruit juice (don't kill the stone) - [+] cheese + bread = cheese sandwich = restore all food and stamina - [+] rum + chocolate = rum ball = cure pain, restore some hp - [+] med: - [+] corpse + water + salt = jerky - [+] mushroom + water + beef = beef strogonoff = filling, temporary Fitness boost - [+] garlic + bread + clover = garlic bread = produce stench like a trogolodyte - [+] bread + meat + tomato = hot dog = temporary strength - [+] water + sugar + 2 berries = potion of red cordial = speed boost - [+] hard - [+] peanut + stone + salt + bread = peanut butter sandwich = super filling, restore all stamina, temp fitness boost - [+] rum + chocolate + sugar + berry = fruit cake = restores all stamina and hp and mp - [+] implement recipe_t - [+] int ningerdients - [+] enum OBTYPE ingredient[MAXINGREDS] - [+] int count[MAXINGREDS] - [+] int cosumeingredient[MAXINGREDS] (boolean) - [+] makedesc_ob should show the recipe for it, if cooking skill is high enough - [+] cooking skill determines how many ingredients you can use - [+] ie. beginner = you can make recipes which need 2 ingredients - [+] redo "cook" ability. - [+] can combine ingredients using recipes to make meals - [+] ingredients must be known! - [+] chef job - [+] attr - [+] gtaverage agility - [+] low fitnesss - [+] objects: - [+] meat cleaver (slashing, low acc, high crit) - [+] apron (rubber, low protection) - [+] chef hat (cloth, low protection) - [+] butane torch (flambe on adjacent lifeform) - [+] abilities - [+] rage at lv3 * [+] skills - [+] chef job - [+] attr - [+] gtaverage agility - [+] low fitnesss - [+] objects: - [+] meat cleaver (slashing, low acc, high crit) - [+] apron (rubber, low protection) - [+] chef hat (cloth, low protection) - [+] butane torch (flambe on adjacent lifeform) - [+] abilities - [+] rage at lv3 * [+] skills --- Makefile | 3 + ai.c | 57 ++++++++-- ai.h | 2 +- attack.c | 21 +++- data.c | 211 +++++++++++++++++++++++++++-------- data/hiscores.db | Bin 12288 -> 12288 bytes defs.h | 16 ++- flag.c | 1 + io.c | 142 +++++++++++++++++++----- lf.c | 280 +++++++++++++++++++++++++++++++---------------- lf.h | 6 +- map.c | 17 ++- move.c | 4 +- nexus.c | 19 ++++ nexus.h | 1 + objects.c | 247 +++++++++++++++++++++++++++++++---------- objects.h | 10 +- save.c | 4 +- spell.c | 203 +++++++++++++++++++++------------- spell.h | 1 + text.c | 79 ++++++++++++- text.h | 3 + 22 files changed, 994 insertions(+), 333 deletions(-) diff --git a/Makefile b/Makefile index 5d2c22f..f22ded1 100644 --- a/Makefile +++ b/Makefile @@ -3,3 +3,6 @@ nexus: Makefile defs.h nexus.c nexus.h ai.c ai.h attack.c attack.h data.c data.h check: Makefile defs.h nexus.c nexus.h ai.c ai.h attack.c attack.h data.c data.h flag.c flag.h god.c god.h io.c io.h lf.c lf.h map.c map.h move.c move.h objects.c objects.h text.c text.h save.c save.h spell.c spell.h vault.c vault.h splint -onlytrans -nullret -nullstate -branchstate -usedef -type -retvalint -retvalother +posixlib -unrecog -boolops -mustfreefresh -predboolint -unqualifiedtrans -compdef *.c + +dist: + tar zcvf nexus_`date '+%Y%m%d'`.tar.gz --exclude='.svn' *.c *.h data doc vaults Makefile diff --git a/ai.c b/ai.c index 02ba084..e7febde 100644 --- a/ai.c +++ b/ai.c @@ -283,7 +283,7 @@ cell_t *aigetlastknownpos(lifeform_t *lf, lifeform_t *target, int *lastx, int *l return NULL; } -object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra, int *range) { +object_t *aigetrangedattack(lifeform_t *lf, lifeform_t *target, enum RANGEATTACK *ra, int *range) { int db = B_FALSE; enum ATTRBRACKET iqb; object_t *o; @@ -329,11 +329,17 @@ object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra, int *range) { // can we attack by throwing something? if (hasbp(lf, BP_HANDS)) { - o = getbestthrowmissile(lf); + o = getbestthrowmissile(lf, target); if (o) { if (db) dblog(".oO { will throw %s at my target }", o->type->name); if (ra) *ra = RA_THROW; - if (range) *range = getmaxthrowrange(lf, o); + if (range) { + if (hasflag(o->flags, F_POWDER)) { + *range = 1; + } else { + *range = getmaxthrowrange(lf, o); + } + } return o; } } @@ -544,6 +550,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { enum RANGEATTACK rangedattack = RA_NONE; int shootrange = 0; int movefailed = B_FALSE; + int closethrowok = B_FALSE; // pet movement if (ismaster) { @@ -699,13 +706,41 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { // see if we have a ranged attack. if so, adjust wantdist // to maintain distance. - rangedob = aigetrangedattack(lf, &rangedattack, &shootrange); + rangedob = aigetrangedattack(lf, target, &rangedattack, &shootrange); + + // for firearms, chance to fire depends on accuracy. + if (rangedattack == RA_GUN) { + int acc,chance; + acc = getmissileaccuracy(lf, target->cell, getammo(rangedob), rangedob, NULL); + switch (getpctletter(acc,100)) { + case 'S': + case 'A': + chance = 100; break; + case 'B': + chance = 75; break; + case 'C': + chance = 50; break; + default: + chance = 25; break; + } + if (!pctchance(chance)) { + rangedattack = RA_NONE; + rangedob = NULL; + } + } if (rangedattack != RA_NONE) { // ie if we found a ranged attack - // stay out of target's attack range - if (wantdistmin < 2) wantdistmin = 2; - // and stay within range for our ranged attack - if (wantdistmax < wantdistmin) wantdistmax = shootrange; + if ((rangedattack == RA_THROW) && rangedob && hasflag(rangedob->flags, F_POWDER)) { + // don't have to maintain distance to throw powder + closethrowok = B_TRUE; + if (wantdistmin < 1) wantdistmin = 1; + if (wantdistmax < wantdistmin) wantdistmax = shootrange; + } else { + // stay out of target's attack range + if (wantdistmin < 2) wantdistmin = 2; + // and stay within range for our ranged attack + if (wantdistmax < wantdistmin) wantdistmax = shootrange; + } } } // end if attackok @@ -745,9 +780,9 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { // move. if (attackok) { // if not adjacent, check for guns, wands, throwing - if ( (rangedattack != RA_NONE) && + if ( (rangedattack != RA_NONE) && // we have a ranged attack haslof(lf->cell, target->cell, LOF_NEED, NULL) && // and we have line of fire to them - (onein(2) || (getcelldist(lf->cell, target->cell) > 1) )) { // and we're not adjacent to target OR random + (closethrowok || onein(2) || (getcelldist(lf->cell, target->cell) > 1) )) { // and we're not adjacent to target OR random if (rangedattack == RA_GUN) { setguntarget(lf, target); if (!shoot(lf)) { @@ -1473,7 +1508,7 @@ void aiturn(lifeform_t *lf) { } // will usually ignore targets who we can't reach if (!canreach(lf, who, &reachpenalty)) { - if (!aigetrangedattack(lf, NULL, NULL)) { // no ranged attack? + if (!aigetrangedattack(lf, who, NULL, NULL)) { // no ranged attack? // 1 size too small = 53% chance to attack // 1 size too small = 6% chance to attack chance = 100 - (reachpenalty*47); diff --git a/ai.h b/ai.h index 814f251..42fdd10 100644 --- a/ai.h +++ b/ai.h @@ -5,7 +5,7 @@ int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit); enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim); enum OBTYPE aigetfleespell(lifeform_t *lf); cell_t *aigetlastknownpos(lifeform_t *lf, lifeform_t *target, int *lastx, int *lasty, int *lastdir); -object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra, int *range); +object_t *aigetrangedattack(lifeform_t *lf, lifeform_t *target, enum RANGEATTACK *ra, int *range); 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); flag_t *aigoto(lifeform_t *lf, cell_t *c, enum MOVEREASON why, void *data, int timelimit); diff --git a/attack.c b/attack.c index 5c10f12..cae83d3 100644 --- a/attack.c +++ b/attack.c @@ -633,13 +633,23 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) hit = rolltohit(lf, victim, wep, &critical); if (critical) { + object_t *armour; + char noun[BUFLEN]; critpos = getrandomcorebp(victim); + armour = getequippedob(victim->pack, critpos); + if (armour) { + char armname[BUFLEN]; + real_getobname(armour, armname, 1, B_FALSE, B_FALSE, B_TRUE, B_FALSE, B_FALSE); + sprintf(noun, "%s", noprefix(armname)); + } else { + sprintf(noun, "%s", getbodypartname(victim, critpos)); + } // replace victicname to include body part if ((lf == victim) && !isplayer(lf)) { - snprintf(victimbpname, BUFLEN, "its %s", getbodypartname(victim, critpos)); + snprintf(victimbpname, BUFLEN, "its %s", noun); } else { getlfname(victim, buf); - snprintf(victimbpname, BUFLEN, "%s%s %s", buf, getpossessive(buf), getbodypartname(victim, critpos)); + snprintf(victimbpname, BUFLEN, "%s%s %s", buf, getpossessive(buf), noun); } } else { strcpy(victimbpname, ""); @@ -1396,7 +1406,7 @@ enum DAMTYPE basedamagetype(enum DAMTYPE dt) { void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, int dam, enum DAMTYPE damtype) { object_t *o,*armour; int protected = B_FALSE; - char lfname[BUFLEN],victimname[BUFLEN],obname[BUFLEN]; + char lfname[BUFLEN],victimname[BUFLEN]; // replace some dam types if (damtype == DT_UNARMED) damtype = DT_BASH; if (damtype == DT_BITE) damtype = DT_SLASH; @@ -1455,12 +1465,14 @@ void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, int d } moveob(o, victim->cell->obpile, o->amt); } else { + /* if (isplayer(victim)) { msg("Your %s protects you.", noprefix(obname)); } else if (cansee(player, victim)) { getlfname(victim, victimname); msg("%s%s %s protects it.", victimname, getpossessive(victimname), noprefix(obname)); } + */ takedamage(armour, dam, damtype); } } else { @@ -1485,6 +1497,7 @@ void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, int d case BP_LEGS: if (pctchance(70)) fall(victim, lf, B_TRUE); if ((armour = getarmour(victim, BP_LEGS)) != NULL) { + /* getobname(armour, obname, armour->amt); if (isplayer(victim)) { msg("Your %s protects you.", noprefix(obname)); @@ -1492,6 +1505,7 @@ void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, int d getlfname(victim, victimname); msg("%s%s %s protects it.", victimname, getpossessive(victimname), noprefix(obname)); } + */ takedamage(armour, dam, damtype); } else { injure(victim, BP_LEGS, damtype); @@ -1688,6 +1702,7 @@ int getextradamwep(object_t *wep, int *dam, enum DAMTYPE *damtype, int *ndam) { lifeform_t *owner; owner = wep->pile->owner; + // enchanted weapons only deal magic damage if the user has remaining mp. if (owner && owner->mp) { f = hasflag(wep->flags, F_ENCHANTED); if (f) { diff --git a/data.c b/data.c index 4e3d034..39c8509 100644 --- a/data.c +++ b/data.c @@ -64,15 +64,15 @@ 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_COMMS, 'C', "Chat/Communicate with someone."); //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."); - addcommand(CMD_MEMMAGIC, 'M', "Memorise a magic shortcut"); + addcommand(CMD_MEMMAGIC, 'M', "Memorise a hotkey for magic or abilities."); addcommand(CMD_OFFER, 'O', "Offer a sacrifice to the gods."); - addcommand(CMD_OPERATE, 'o', "Operate a tool/wand/device."); + addcommand(CMD_OPERATE, 'o', "Operate a tool/wand/device, or fill a flask."); addcommand(CMD_PICKLOCK, 'p', "Pick a lock."); addcommand(CMD_POUR, 'P', "Pour a potion onto something."); addcommand(CMD_QUAFF, 'q', "Quaff (drink) a potion."); @@ -139,12 +139,14 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 blessed potions of experience"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "ring of miracles"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "ring of control"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "infovisor"); addflag(lastjob->flags, F_STARTSKILL, SK_LORE_ARCANA, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SS_DEATH, PR_MASTER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SS_TRANSLOCATION, PR_MASTER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SS_DIVINATION, PR_MASTER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SS_MENTAL, PR_MASTER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SS_SUMMONING, PR_MASTER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_TECHUSAGE, PR_ADEPT, NA, NULL); //addflag(lastjob->flags, F_HASPET, NA, NA, NA, "young wolf"); for (i = 1; i < MAXSKILLS; i++) { addflag(lastjob->flags, F_CANLEARN, i, NA, NA, NULL); @@ -407,6 +409,54 @@ void initjobs(void) { // 20: tower of iron will // 21: planeshift addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); + + addjob(J_HUNTER, "Hunter", "Hunters eke out a living hunting game in the woods. Their dependance on wild animals for sustenance has made them skilled archers."); + // stats + addflag(lastjob->flags, F_MPDICE, 1, 1, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_STR, 1, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_AGI, 1, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_CON, 1, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_WIS, 2, NA, NULL); + // initial objects + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "hatchet"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "bow"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "50 arrows"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "throwing net"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "cloth trousers"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "pair of leather boots"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "pair of leather gloves"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "sleeping bag"); + // initial skills + addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_AXES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_COOKING, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CLIMBING, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LISTEN, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_NATURE, PR_SKILLED, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_RANGED, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SWIMMING, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_STEALTH, PR_NOVICE, NA, NULL); + // learnable skills + addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_EVASION, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_TECHUSAGE, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_TRAPS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_HUMANOID, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DRAGONS, NA, NA, NULL); + // abilities + addflag(lastjob->flags, F_CANWILL, OT_S_CALMANIMALS, NA, NA, NULL); + addflag(lastjob->flags, F_LEVSKILL, 5, SK_LORE_NATURE, NA, NULL); + addflag(lastjob->flags, F_LEVSKILL, 10, SK_LORE_NATURE, NA, NULL); + addflag(lastjob->flags, F_LEVSKILL, 15, SK_LORE_NATURE, NA, NULL); + addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); + addjob(J_MECHANIC, "Mechanic", "Mechanics, while great at negotiating high hourly rates, are not generally very suited for adventuring. Their spanner and metal-working skills might come in handy though."); // stats addflag(lastjob->flags, F_JOBATTRMOD, A_STR, 1, NA, NULL); @@ -682,7 +732,7 @@ void initjobs(void) { addflag(lastjob->flags, F_JOBATTRMOD, A_IQ, 4, NA, NULL); addflag(lastjob->flags, F_JOBATTRMOD, A_CON, -3, NA, NULL); // initial objects - addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "neophyte staff"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "enchanted neophyte staff"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "wizard hat"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "robe"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 potions of magic"); @@ -704,6 +754,7 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SPEECH, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_STAVES, PR_ADEPT, NA, NULL); // limit + addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SS_AIR, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SS_DEATH, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SS_DIVINATION, NA, NA, NULL); @@ -1755,9 +1806,11 @@ void initobjects(void) { addot(OT_HOTDOG, "hot dog", "A chunk of meat sandwiched between two pieces of bread.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 80, NA, ""); + addflag(lastot->flags, F_ISMEAT, B_TRUE, 80, NA, ""); addot(OT_JERKY, "jerky", "Salted animal flesh. Lightweight and filling.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 90, NA, ""); + addflag(lastot->flags, F_ISMEAT, B_TRUE, 80, NA, ""); addot(OT_MUSHROOMSHI, "shiitake mushroom", "A large brown mushroom.", MT_FOOD, 0.2, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_EDIBLE, B_TRUE, 30, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); @@ -1781,13 +1834,17 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_ISMEAT, B_TRUE, 80, NA, ""); addot(OT_RUMBALL, "rum ball", "A rum-filled ball of chocolate. Cures pain and restores 2-6 hit points.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); // weight normally comes from corpse type addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addot(OT_SALT, "pinch of salt", "A small measure of salt. Used for cooking.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_WHITE, NA, NA, "%"); - addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, ""); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, NULL); + addflag(lastot->flags, F_POWDER, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_MISSILEDAM, 0, NA, NA, ""); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addot(OT_SANDWICHCHEESE, "cheese sandwich", "A tasty cheese sandwich. Filling, and restores all stamina.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_WHITE, NA, NA, "%"); @@ -1807,13 +1864,17 @@ void initobjects(void) { // corpses addot(OT_CORPSE, "corpse", "xxx", MT_FLESH, 1, OC_CORPSE, SZ_TINY); addflag(lastot->flags, F_EDIBLE, B_TRUE, 1, NA, NULL); // will be overridden + addflag(lastot->flags, F_ISMEAT, B_TRUE, 80, NA, ""); addot(OT_HEAD, "head", "xxx", MT_FLESH, 1, OC_CORPSE, SZ_SMALL); addflag(lastot->flags, F_EDIBLE, B_TRUE, 1, NA, NULL); // will be overridden + addflag(lastot->flags, F_ISMEAT, B_TRUE, 80, NA, ""); addot(OT_FLESHCHUNK, "chunk of flesh", "A chunk of flesh from something.", MT_FLESH, 1, OC_FOOD, SZ_SMALL); addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 25, NA, NULL); + addflag(lastot->flags, F_ISMEAT, B_TRUE, 80, NA, ""); addot(OT_FINGER, "severed finger", "The severed finger from some kind of creature.", MT_FLESH, 0.02, OC_CORPSE, SZ_TINY); addflag(lastot->flags, F_EDIBLE, B_TRUE, 1, NA, NULL); + addflag(lastot->flags, F_ISMEAT, B_TRUE, 80, NA, ""); // potions (sorted by rarity) @@ -1902,7 +1963,7 @@ void initobjects(void) { addot(OT_POT_COMPETENCE, "potion of competence", "Permemantly increases the drinker's strength, intelligence or dexterity.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); - addot(OT_POT_GASEOUSFORM, "potion of gaseous form", "Turns the drinker into a cloud of gas.", MT_GLASS, 1, OC_POTION, SZ_TINY); + addot(OT_POT_GASEOUSFORM, "potion of gaseous form", "Turns the drinker into a cloud of gas. Only intended for emergencies, since it will cause you to drop all your items.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL); @@ -2471,7 +2532,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_NORANDOM, B_TRUE, NA, NA, NULL); - addot(OT_S_ICECRUST, "ice crust", "Enrusts your bladed weapon with a layer of ice.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_ICECRUST, "ice crust", "Encrusts your weapon with a layer of sharp ice.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how long the enchantment will remain."); addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL); @@ -2513,7 +2574,7 @@ void initobjects(void) { addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how long the icicle will remain."); addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); - addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL); addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); @@ -2782,8 +2843,12 @@ void initobjects(void) { // l2 addot(OT_S_GRAVLOWER, "lessen gravity", "Causes the caster to fall very slowly.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); + addot(OT_S_WHATGOESUP, "what goes up", "...must come down. Thrown or fired missiles will return to the caster's hands if not destroyed.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); // l3 addot(OT_S_SLOW, "slowness", "Decreases the speed of the target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); @@ -2813,6 +2878,11 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); + addot(OT_S_EQANDOP, "equal and opposite", "Surrounds the caster with a negative gravity field, repelling all missiles in a direct path back to their source.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); // l5 // l6 addot(OT_S_FLIGHT, "fly", "Allows the caster to fly.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); @@ -3123,7 +3193,7 @@ void initobjects(void) { addflag(lastot->flags, F_TARGETTEDSPELL, TT_OBJECT, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // l2 - addot(OT_S_BLINK, "blink", "Teleports the caster to a random location within view.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_BLINK, "bamf", "Teleports the caster to a random location within view.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power VI you can choose where to blink to."); addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); @@ -3288,7 +3358,7 @@ void initobjects(void) { addflag(lastot->flags, F_STAMCOST, 1, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_ANYWHERE, NA, NA, NULL); - addot(OT_A_COOK, "cook", "Combine various foods into a healthy meal.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); + addot(OT_A_COOK, "cook", "Cook a corpse, or combine various foods into a healthy meal.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addot(OT_A_DARKWALK, "darkwalk", "Step between the shadows.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); @@ -3338,8 +3408,6 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_NOANNOUNCE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, 10, NA, NULL); - addot(OT_A_PREPARECORPSE, "prepare corpse", "Prepare and cook a corpse, making it more nutritious.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); - addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addot(OT_A_QUIVERINGPALM, "quivering palm", "A deadly palm strike which knocks the molecules in the target's body out of alignment.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_STAMCOST, 10, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); @@ -3746,7 +3814,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAM, DT_PIERCE, 1, NA, NULL); addflag(lastot->flags, F_ACCURACY, 50, NA, NA, NULL); - addot(OT_SLEEPINGBAG, "sleeping bag", "An insulated bag for sleeping in. Very comfortable.", MT_CLOTH, 4, OC_TECH, SZ_MEDIUM); + addot(OT_SLEEPINGBAG, "sleeping bag", "An insulated bag for sleeping in. Very comfortable.", MT_CLOTH, 2, OC_TECH, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL); addflag(lastot->flags, F_HELPSREST, 15, NA, NA, NULL); @@ -4010,6 +4078,10 @@ void initobjects(void) { addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, NA, NA, NA, ","); addflag(lastot->flags, F_NOMATCONVERT, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_GOESON, BP_EARS, NA, NA, NULL); + addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL); + addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_DTRESIST, DT_SONIC, NA, NULL); addot(OT_SOGGYPAPER, "lump of soggy paper", "A useless lump of soggy paper.", MT_WETPAPER, 0.1, OC_MISC, SZ_TINY); addflag(lastot->flags, F_STACKABLE, NA, NA, NA, NULL); @@ -5228,7 +5300,7 @@ void initobjects(void) { addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 25, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); - addot(OT_NET, "throwing net", "A grid of strong cords, weighted at the edges. Made for throwing over a target.", MT_CLOTH, 3, OC_MISSILE, SZ_MEDIUM); + addot(OT_NET, "throwing net", "A grid of strong cords, weighted at the edges. Made for throwing over a target.", MT_CLOTH, 2, OC_MISSILE, SZ_MEDIUM); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_MISSILEDAM, 0, NA, NA, NULL); @@ -5248,7 +5320,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 3, 3, NA, ""); addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL); - addot(OT_ARROW, "arrow", "A sharp wooden arrow.", MT_WOOD, 0.25, OC_MISSILE, SZ_SMALL); + addot(OT_ARROW, "arrow", "A sharp wooden arrow.", MT_WOOD, 0.1, OC_MISSILE, SZ_SMALL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, ""); addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, ""); @@ -5259,7 +5331,7 @@ void initobjects(void) { 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); + addot(OT_BOLT, "bolt", "A sharp metal spike, meant for firing from a crossbow.", MT_METAL, 0.25, OC_MISSILE, SZ_SMALL); 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, ""); @@ -5639,6 +5711,7 @@ void initobjects(void) { addflag(lastot->flags, F_CRITCHANCE, 8, NA, NA, NULL); addot(OT_WIZARDSTAFF, "neophyte staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, ")"); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_DAM, DT_BASH, 4, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 100, NA, NA, NULL); @@ -5649,6 +5722,7 @@ void initobjects(void) { addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "twisted branch"); addot(OT_WIZARDSTAFF2, "enchanter staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, ")"); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_DAM, DT_BASH, 4, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 100, NA, NA, NULL); @@ -5660,6 +5734,7 @@ void initobjects(void) { addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "twisted branch"); addot(OT_WIZARDSTAFF3, "sorcerer staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, ")"); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_DAM, DT_BASH, 4, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 100, NA, NA, NULL); @@ -5671,6 +5746,7 @@ void initobjects(void) { addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "twisted branch"); addot(OT_WIZARDSTAFF4, "spellbinder staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, ")"); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_VERYRARE, NULL); addflag(lastot->flags, F_DAM, DT_BASH, 4, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 100, NA, NA, NULL); @@ -5682,6 +5758,7 @@ void initobjects(void) { addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "twisted branch"); addot(OT_WIZARDSTAFF5, "warlock staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, ")"); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_VERYRARE, NULL); addflag(lastot->flags, F_DAM, DT_BASH, 4, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 100, NA, NA, NULL); @@ -5693,6 +5770,7 @@ void initobjects(void) { addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "twisted branch"); addot(OT_WIZARDSTAFF6, "archmagi staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, ")"); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_VERYRARE, NULL); addflag(lastot->flags, F_DAM, DT_BASH, 4, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 100, NA, NA, NULL); @@ -5791,34 +5869,31 @@ void initobjects(void) { addflag(lastot->flags, F_RANGE, 5, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_ARROW, NA, NA, NULL); addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL); - addflag(lastot->flags, F_FIRETURNS, 1, NA, NA, NULL); addflag(lastot->flags, F_RELOADTURNS, 1, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); - addot(OT_CROSSBOW, "crossbow", "A standard crossbow. Very powerful, but needs high strength to use.", MT_WOOD, 8, OC_WEAPON, SZ_MEDIUM); + addot(OT_CROSSBOW, "crossbow", "A standard crossbow. Very powerful, but slow to reload and needs high strength to use.", MT_WOOD, 8, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_FIRESPEED, 12, NA, NA, NULL); + addflag(lastot->flags, F_FIRESPEED, 15, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_BOLT, NA, NA, NULL); addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL); - addflag(lastot->flags, F_FIRETURNS, 2, NA, NA, NULL); addflag(lastot->flags, F_RELOADTURNS, 2, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 15, NA, NULL); - addot(OT_CROSSBOWHAND, "hand crossbow", "A small one-handed crossbow. Lightweight, but less powerful than a full-sized one.", MT_WOOD, 3, OC_WEAPON, SZ_SMALL); + addot(OT_CROSSBOWHAND, "hand crossbow", "A small wrist-mounted crossbow. Less powerful and accurate than its full-sized sibling, the hand crossbow's primary strength is its ability to fire multiple shots before reloading.", MT_WOOD, 3, OC_WEAPON, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_FIRESPEED, 6, NA, NA, NULL); + addflag(lastot->flags, F_FIRESPEED, 8, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL); - addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL); + addflag(lastot->flags, F_RANGE, 7, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_BOLT, NA, NA, NULL); - addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL); - addflag(lastot->flags, F_FIRETURNS, 1, NA, NA, NULL); + addflag(lastot->flags, F_AMMOCAPACITY, 3, NA, NA, NULL); addflag(lastot->flags, F_RELOADTURNS, 1, NA, NA, NULL); addot(OT_LONGBOW, "longbow", "A very large (human-sized) bow, capable of firing arrows with great power.", MT_WOOD, 7, OC_WEAPON, SZ_MEDIUM); @@ -5830,7 +5905,6 @@ void initobjects(void) { addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_ARROW, NA, NA, NULL); addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL); - addflag(lastot->flags, F_FIRETURNS, 1, NA, NA, NULL); addflag(lastot->flags, F_RELOADTURNS, 1, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); @@ -5846,7 +5920,6 @@ void initobjects(void) { addflag(lastot->flags, F_AMMOOB, OT_BULLET, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_RUBBERBULLET, NA, NA, NULL); addflag(lastot->flags, F_AMMOCAPACITY, 6, NA, NA, NULL); - addflag(lastot->flags, F_FIRETURNS, 1, NA, NA, NULL); addflag(lastot->flags, F_RELOADTURNS, 2, NA, NA, NULL); addot(OT_SHOTGUN, "shotgun", "Powerful but short-ranged gun.", MT_METAL, 5, OC_WEAPON, SZ_MEDIUM); @@ -5859,7 +5932,6 @@ void initobjects(void) { addflag(lastot->flags, F_RANGE, 3, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_BULLET, NA, NA, NULL); addflag(lastot->flags, F_AMMOCAPACITY, 2, NA, NA, NULL); - addflag(lastot->flags, F_FIRETURNS, 1, NA, NA, NULL); addflag(lastot->flags, F_RELOADTURNS, 3, NA, NA, NULL); addot(OT_SLING, "sling", "Stretchy piece of rubber for launching projectiles.", MT_RUBBER, 0.5, OC_WEAPON, SZ_SMALL); @@ -5871,7 +5943,6 @@ void initobjects(void) { addflag(lastot->flags, F_RANGE, 5, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_STONE, NA, NA, NULL); addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL); - addflag(lastot->flags, F_FIRETURNS, 1, NA, NA, NULL); addflag(lastot->flags, F_RELOADTURNS, 1, NA, NA, NULL); @@ -6074,6 +6145,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 4, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_S_FLIGHT, NA, NA, "pw:1;"); addflag(lastrace->flags, F_VISRANGEMOD, 1, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_EVASION, PR_NOVICE, NA, NULL); // penalties addflag(lastrace->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_ELECTRIC, NA, NA, NULL); @@ -6160,6 +6232,7 @@ void initrace(void) { // bonuses addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_NOVICE, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_METALWORK, PR_NOVICE, NA, NULL); // penalties addflag(lastrace->flags, F_MPMOD, -3, NA, NA, NULL); addflag(lastrace->flags, F_TAMABLE, 35, NA, NA, NULL); @@ -6197,6 +6270,47 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); addflag(lastrace->flags, F_MEDITATES, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MPMOD, 3, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_RANGED, PR_NOVICE, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_STEALTH, PR_NOVICE, NA, NULL); + addflag(lastrace->flags, F_TAMABLE, 25, NA, NA, NULL); + + addrace(R_MAMMOAN, "mammoan", 120, '@', C_GREY, MT_LEATHER, RC_HUMANOID, "Mammoans are huge, elephant-like humanoids. Their have great senses of hearing and smell, a photographic memory, and leather skin which greatly lessens damage. On the other hand they vision is poor, their movement slow, and their digestive system cannot cope with meat."); + addflag(lastrace->flags, F_PLAYABLE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_HIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_VLOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_VLOW, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d3+4"); + addflag(lastrace->flags, F_MOVESPEED, SP_VERYSLOW, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 4, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 65, OC_WEAPON, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_SCROLL, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_SCROLL, NA, NULL); + addflag(lastrace->flags, F_STARTJOB, 75, J_RANDOM, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "roars^a roars"); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); + // bonuses + addflag(lastrace->flags, F_PHOTOMEM, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_ENHANCESMELL, 3, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LISTEN, PR_NOVICE, NA, NULL); + // penalties + addflag(lastrace->flags, F_NOARMOURON, BP_EARS, NA, NA, NULL); + addflag(lastrace->flags, F_NOARMOURON, BP_LEGS, NA, NA, NULL); + addflag(lastrace->flags, F_NOARMOURON, BP_HANDS, NA, NA, NULL); + addflag(lastrace->flags, F_NOARMOURON, BP_FEET, NA, NA, NULL); + addflag(lastrace->flags, F_VISRANGEMOD, -2, NA, NA, NULL); + addflag(lastrace->flags, F_DTVULN, DT_SONIC, NA, NA, NULL); + addflag(lastrace->flags, F_VEGETARIAN, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_TAMABLE, 25, NA, NA, NULL); // human monsters... @@ -7502,6 +7616,7 @@ void initrace(void) { addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, ""); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_SPELLSPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_S_FIREDART, NA, NA, "pw:1;"); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, B_APPENDYOU, "gestures"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 3, NA, NULL); @@ -7526,6 +7641,7 @@ void initrace(void) { addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, ""); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_SPELLSPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_S_FROSTBITE, NA, NA, "pw:1;"); addflag(lastrace->flags, F_CANWILL, OT_S_FREEZEOB, NA, NA, "pw:1;"); addflag(lastrace->flags, F_CANWILL, OT_S_ICICLE, NA, NA, "pw:1;"); @@ -9664,7 +9780,7 @@ void initskills(void) { addskilldesc(SK_CLIMBING, PR_MASTER, "No accuracy penalty or stamina cost to remain climbing.", B_FALSE); addskill(SK_COOKING, "Cooking", "Your ability to combine foods into nutritious meals.", 50); addskilldesc(SK_COOKING, PR_INEPT, " - Note: when cooking, all ingredients must already be recognised.", B_FALSE); - addskilldesc(SK_COOKING, PR_NOVICE, "^gYou can now prepare corpses for consumption.", B_FALSE); + addskilldesc(SK_COOKING, PR_NOVICE, "^gYou can now cook corpses before consumption.", B_TRUE); addskilldesc(SK_COOKING, PR_BEGINNER, "^gYou now recognise bad food.^n", B_TRUE); addskilldesc(SK_COOKING, PR_BEGINNER, "^gYou can now cook recipes using up to 2 ingredients.", B_TRUE); addskilldesc(SK_COOKING, PR_ADEPT, "^gYou can now cook recipes using up to 3 ingredients.", B_TRUE); @@ -9699,12 +9815,16 @@ void initskills(void) { addskilldesc(SK_METALWORK, PR_EXPERT, "^gYou can repair metal items up to 85% condition.^n", B_FALSE); addskilldesc(SK_METALWORK, PR_MASTER, "^gYou can fully repair metal items.^n", B_FALSE); addskill(SK_RANGED, "Ranged Weapons", "Your ability to aim a ranged weapon like a bow or gun.", 50); - addskilldesc(SK_RANGED, PR_NOVICE, "^gYou suffer a -20% accuracy penalty when using ranged weapons.^n", B_FALSE); - addskilldesc(SK_RANGED, PR_BEGINNER, "^gYou suffer a -10% accuracy penalty when using ranged weapons.^n", B_FALSE); - addskilldesc(SK_RANGED, PR_ADEPT, "^gYou no longer suffer a accuracy penalty when using ranged weapons.^n", B_FALSE); - addskilldesc(SK_RANGED, PR_SKILLED, "^gYou gain a +10% accuracy bonus when using ranged weapons.^n", B_FALSE); - addskilldesc(SK_RANGED, PR_EXPERT, "^gYou gain a +20% accuracy bonus when using ranged weapons.^n", B_FALSE); - addskilldesc(SK_RANGED, PR_MASTER, "^gYou gain a +30% accuracy bonus when using ranged weapons.^n", B_FALSE); + addskilldesc(SK_RANGED, PR_INEPT, "^gYour ranged accuracy decreases by 32%% per cell.^n", B_FALSE); + addskilldesc(SK_RANGED, PR_NOVICE, "^gYour ranged accuracy decreases by 22%% per cell.^n", B_FALSE); + addskilldesc(SK_RANGED, PR_BEGINNER, "^gYour ranged accuracy decreases by 16%% per cell.^n", B_FALSE); + addskilldesc(SK_RANGED, PR_ADEPT, "^gYou can now reload ranged weapons instantly.^n", B_TRUE); + addskilldesc(SK_RANGED, PR_ADEPT, "^gYour ranged accuracy decreases by 12%% per cell.^n", B_FALSE); + addskilldesc(SK_RANGED, PR_SKILLED, "^gYour ranged accuracy decreases by 10%% per cell.^n", B_FALSE); + addskilldesc(SK_RANGED, PR_EXPERT, "^gMonsters no longer block your line of fire for ranged weapons.^n", B_TRUE); + addskilldesc(SK_RANGED, PR_EXPERT, "^gYour ranged accuracy decreases by 8%% per cell.^n", B_FALSE); + addskilldesc(SK_RANGED, PR_MASTER, "^gYour ranged attacks now deal 50% more damage.^n", B_TRUE); + addskilldesc(SK_RANGED, PR_MASTER, "^gYour ranged accuracy decreases by 6%% per cell.^n", B_FALSE); addskill(SK_SEWING, "Sewing", "Lets you repair cloth or leather objects.", 100); addskilldesc(SK_SEWING, PR_NOVICE, "^gYou can repair cloth items up to 33% condition.^n", B_FALSE); addskilldesc(SK_SEWING, PR_BEGINNER, "^gYou can repair cloth items up to 50% condition^n", B_FALSE); @@ -9758,12 +9878,13 @@ void initskills(void) { addskilldesc(SK_THIEVERY, PR_EXPERT, "gYou can now steal multiple items.", B_TRUE); addskilldesc(SK_THIEVERY, PR_MASTER, "gYou can now steal equipped items.", B_TRUE); addskill(SK_THROWING, "Throwing", "Your accuracy when throwing objects at things.", 50); - addskilldesc(SK_THROWING, PR_NOVICE, "^gYou suffer a -20% accuracy penalty when throwing items.^n", B_FALSE); - addskilldesc(SK_THROWING, PR_BEGINNER, "^gYou suffer a -10% accuracy penalty when throwing items.^n", B_FALSE); - addskilldesc(SK_THROWING, PR_ADEPT, "^gYou no longer suffer a accuracy penalty when throwing items.^n", B_FALSE); - addskilldesc(SK_THROWING, PR_SKILLED, "^gYou gain a +10% accuracy bonus when throwing items.^n", B_FALSE); - addskilldesc(SK_THROWING, PR_EXPERT, "^gYou gain a +20% accuracy bonus when throwing items.^n", B_FALSE); - addskilldesc(SK_THROWING, PR_MASTER, "^gYou gain a +30% accuracy bonus when throwing items.^n", B_FALSE); + addskilldesc(SK_THROWING, PR_INEPT, "^gYour throw accuracy decreases by 32%% per cell.^n", B_FALSE); + addskilldesc(SK_THROWING, PR_NOVICE, "^gYour throw accuracy decreases by 22%% per cell.^n", B_FALSE); + addskilldesc(SK_THROWING, PR_BEGINNER, "^gYour throw accuracy decreases by 16%% per cell.^n", B_FALSE); + addskilldesc(SK_THROWING, PR_ADEPT, "^gYour throw accuracy decreases by 12%% per cell.^n", B_FALSE); + addskilldesc(SK_THROWING, PR_SKILLED, "^gYour throw accuracy decreases by 10%% per cell.^n", B_FALSE); + addskilldesc(SK_THROWING, PR_EXPERT, "^gYour throw accuracy decreases by 8%% per cell.^n", B_FALSE); + addskilldesc(SK_THROWING, PR_MASTER, "^gYour throw accuracy decreases by 6%% per cell.^n", B_FALSE); addskill(SK_TRAPS, "Traps", "Affects your ability to locate and disarm traps.", 25); addskilldesc(SK_TRAPS, PR_NOVICE, "^gYou gain the 'disarm traps' ability.^n", B_FALSE); addskill(SK_TWOWEAPON, "Dual Weilding", "Allows you to weild two melee weapons at once.", 50); diff --git a/data/hiscores.db b/data/hiscores.db index 98cc6709ed1bec39790ea8b23e78443fbf779e42..0ee52b5293a03d1b6d8a32b0a07ff1dcb5ba774b 100644 GIT binary patch delta 795 zcmZXRT}YEr7{{OIJnuU%Oan|qzJedL&mU8IYG zNH3IgQBVk0I_oBNBqVgvO$Je@6%<4TL03TrT@_gGUMz$-4-cIG|NMXFIh-N)kb871 z{+ccNl4hL;AG(Ns(RX@93-pktXo9ZORk}z66r*mE$xSWPM7w#F_AKXGQ|SlnVmVZR zUTh%N-h3c+np~GFu1SwX|*TRKE+#fZULWyhA-&+Sym9; z0s*!&7l=t)I$}vZY_d`fh!&~`(VQ|%=>!OBdNQ>&Q7ef2WJYiH+jaR~O4iX=MSh=Q zF3Nxe&>Wp1C+XQUc8B#b6Ru#ZA}6?%Ij6k@*U+%t0enJ~1gwIcd@b{`4u3*38n!uz zf70af+gYatb{wq9wJZ(G)q)K4hT4<|-@qVzgn31flZBh7Q9A;66Mj*wpw zx1@ZB!@lkx^@KtZPng#kw-_%(Lf(LEtBjj9zzmi>w4xqzN)5qI=}>PtCP#TiZoy!6 zyfg)|H1?~$V}pM<+z|-NQBO?vN!|g;Bl$ehm=x)hI)k2&Y_rEpRCF!jf6>N3F!(p+ s4F(m7CvGtQn`UFABPz@117W|^5%l!i_@ce`4`N}<1poj5 delta 478 zcmW-cPe>GT6vyA6nc3M{SKM95%#Bu>wVjztbQJ%f9lCUh+76kqMtf*eWG{jRd)uI( zg9nFq35o@c$U_J92ZG(Yv_TMA2?jxd&?zvXlY%xQJU+bdgYO4ky<9IZbmH!6_IIr9 zJ>0`_<^$g2ZT`xiq}A+<-QcS{#=e|4@1QGB%{;El8?%E04&<9T6Vy-2c)YCX3?y&k zQ^`x9mo)~w8$n&P5W9y!ccbL+WzY-Jc8*J6b%)UNQM4n-&BTNBAJ7v~up-2d&p#4{ zY!Y4rukmdj;1qqJm-LWq+{Z6if_=%gteO4bV5Z9lS=4jdkYj)xwmgp0btq!yw9oR( zXqTnrgjP6ffI3VXbi#rP@D@+fJXL4}pJ5e#!n!)uwv48NT4=iv**at=bxTH!no{X& zDF*=3FaY69Ljyh|VLw*F@<%+PD^#Nu+GU%k__=az3uQFdt19^y4F3oFEpasf diff --git a/defs.h b/defs.h index 427af6b..271bba4 100644 --- a/defs.h +++ b/defs.h @@ -806,6 +806,7 @@ enum RACE { R_DWARF, R_ELF, R_HUMAN, + R_MAMMOAN, // human monsters R_BANDITLDR, R_BANDIT, @@ -945,6 +946,7 @@ enum JOB { J_CHEF, J_COMMANDO, J_DRUID, + J_HUNTER, J_MECHANIC, J_MONK, J_NINJA, @@ -1235,6 +1237,7 @@ enum OBTYPE { OT_S_SNOWBALL, OT_S_WALLOFICE, // -- gravity + OT_S_EQANDOP, OT_S_FLIGHT, OT_S_FORCESPHERE, OT_S_GRAVLOWER, @@ -1243,6 +1246,7 @@ enum OBTYPE { OT_S_LEVITATION, OT_S_SLOW, OT_S_TRUESTRIKE, + OT_S_WHATGOESUP, // -- life / cleric OT_S_HEALING, OT_S_HEALINGMIN, @@ -1382,7 +1386,6 @@ enum OBTYPE { OT_A_INSPECT, OT_A_HURRICANESTRIKE, OT_A_POLYREVERT, - OT_A_PREPARECORPSE, OT_A_QUIVERINGPALM, OT_A_STEAL, OT_A_THRUST, // attack up to 2 cells away with a piercing weapon. @@ -1980,6 +1983,8 @@ enum FLAG { // what can you do with this object? F_TAINTED, // will give food poisoning if you eat/drink it F_PREPARED, // raw meat has been prepared using cooking skill + F_ISMEAT, // this food contains meat parts - not suitable for + // vegetarians F_EDIBLE, // you can eat this. val1 = nutrition. 100 = a meal // -1 means "nutrition is weight x abs(val1)" // v2 = nutrition left when partially eaten @@ -2109,7 +2114,6 @@ enum FLAG { F_AMMOOB, // v0 = what object this weapon fires. can have multiple types. F_AMMOCAPACITY, // v0 = max ammo that can be loaded F_RANGE, // range of projectile firing weapon - F_FIRETURNS, // # actions it takes to fire this gun F_RELOADTURNS, // # actions it takes to reload this gun // end gun flags F_FLAMESTRIKE, // causes fires where you hit @@ -2292,6 +2296,11 @@ enum FLAG { F_VISRANGEMOD, // modifications to visrange F_NIGHTVISRANGEMOD, // modifications to nightvisrange F_GUNTARGET, // current projectile weapon target + // v0 is guntarget id. + // text is targetting string (ie. Orc [50%]) + F_THROWING, // set while the player is throwing/firing something + // f->text = obid of what we're throwing + // if f->text is NULL, we're using a firearm. F_CASTINGSPELL, // set while the player is casting a spell // for instant spells: // v0 is spell id @@ -2600,6 +2609,7 @@ enum FLAG { F_RESISTMAG, // immunity to magic effects. v0=amt (1-20) F_MPREGEN, // regenerate MP at val0 per turn F_RAGE, // you are enraged. v0/v1 will be set to player's old hp/maxhp + F_REFLECTION, // missiles are reflected back at thrower F_RETALIATE, // deal damage to anyone who hits you // v0=ndice, v1=dsides, v2=damtype, text=obname // text must have at least TWO words @@ -3183,9 +3193,9 @@ typedef struct lifeform_s { struct race_s *race; int level; int newlevel; - long totskillxp; long xp,skillxp; int skillpoints; + long totskillpoints; int hp,maxhp; int mp,maxmp; float stamina; diff --git a/flag.c b/flag.c index 8f6eab9..4f36834 100644 --- a/flag.c +++ b/flag.c @@ -453,6 +453,7 @@ int flagcausesstatredraw(lifeform_t *lf, enum FLAG fid) { case F_FASTMOVE: case F_FLYING: case F_GRAVBOOSTED: + case F_GUNTARGET: case F_HASNEWLEVEL: case F_HIDING: case F_ICESLIDE: diff --git a/io.c b/io.c index ea8916f..79c4519 100644 --- a/io.c +++ b/io.c @@ -531,6 +531,7 @@ char askchar(char *prompt, char *validchars, char *def, int showchars, int mayca return ch; } +// "func" is a pointer to a function which returns an added description for a highlighted cell cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *srclf, int maxrange, enum LOFTYPE LOFTYPE, int wanttrail) { static int startlf = -1; int finished = B_FALSE; @@ -617,9 +618,15 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src } - wclear(msgwin); - mvwprintw(msgwin, 0, 0, "%s", prompt); - wrefresh(msgwin); + // only show the question if we don't have a starting target + if (c == player->cell) { + wclear(msgwin); + mvwprintw(msgwin, 0, 0, "%s", prompt); + wrefresh(msgwin); + } else { + // force cell description to show + moved = B_TRUE; + } while (!finished) { int dir; @@ -631,6 +638,7 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src drawlevelfor(player); if (moved) { + flag_t *f; int inlof = B_TRUE, inrange = B_TRUE; cell_t *trailtarg = NULL; // show what we are over in msg bar @@ -929,7 +937,7 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src if (srclf && (maxrange != UNLIMITED)) { if (getcelldist(srclf->cell, c) > maxrange) { inrange = B_FALSE; - strcat(buf, " [too-far]"); + strcat(buf, " ^R[too-far]^n"); valid = B_FALSE; } } @@ -939,7 +947,7 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src cell_t *newcell; if (!haslof(srclf->cell, c, LOFTYPE, &newcell)) { inlof = B_FALSE; - strcat(buf, " [no-lof]"); + strcat(buf, " ^B[no-lof]^n"); valid = B_FALSE; } if (newcell) { @@ -947,6 +955,17 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src } } + // throwing hitchance? + + f = lfhasflag(player, F_THROWING); + if (f && valid) { + char throwbuf[BUFLEN]; + makethrowaccstring(player, c, f, throwbuf); + if (strlen(throwbuf)) { + strcat(buf, throwbuf); + } + } + wclear(msgwin); if (subprompt) { @@ -999,6 +1018,7 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src if (c->lf && cansee(player, c->lf)) { startlf = c->lf->id; } + restoregamewindows(); return c; } else if (ch == 'v') { // view // todo: show obpile or view lf @@ -1035,6 +1055,7 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src } clearmsg(); + restoregamewindows(); return NULL; } @@ -1575,6 +1596,10 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { msg("%s enter%s a berzerker rage!", lfname, isplayer(lf) ? "" : "s"); donesomething = B_TRUE; break; + case F_REFLECTION: + msg("^%cA negative gravity field forms around %s!",getlfcol(lf, CC_GOOD), lfname); + donesomething = B_TRUE; + break; case F_RETALIATE: msg("%s appear%s from %s%s skin.", noprefix(f->text), (f->text[strlen(f->text)-1] == 's') ? "" : "s", @@ -2147,6 +2172,10 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { msg("%s %s less angry now.", lfname, isplayer(lf) ? "feel" : "seems"); donesomething = B_TRUE; break; + case F_REFLECTION: + msg("^%cThe negative gravity around %s vanishes!", lfname); + donesomething = B_TRUE; + break; case F_RETALIATE: msg("%s disappear%s from %s%s skin.", noprefix(f->text), (f->text[strlen(f->text)-1] == 's') ? "" : "s", @@ -3393,6 +3422,14 @@ void doattackcell(char dirch) { f->val[2] = dirch; } + + if (getrelativedir(player, dir) != RD_FORWARDS) { + if (!lfhasflag(player, F_AWARENESS)) { + msg("You can't attack behind you!"); + return; + } + } + attackcell(player, c, B_FALSE); } } @@ -4596,11 +4633,8 @@ char *makedesc_ob(object_t *o, char *retbuf) { sprintf(buf, "@It fires at a speed of %d km/h.\n",speedtokph(ff->val[0])); strncat(retbuf, buf, HUGEBUFLEN); } - ff = hasflag(o->flags, F_FIRETURNS); ff2 = hasflag(o->flags, F_RELOADTURNS); - sprintf(buf, "@It takes %d turn%s to fire, and %d turn%s to reload.\n", - ff->val[0], (ff->val[0] == 1) ? "" : "s", - ff2->val[0], (ff2->val[0] == 1) ? "" : "s"); + sprintf(buf, "@It takes %d turn%s to reload.\n", ff2->val[0], (ff2->val[0] == 1) ? "" : "s"); strncat(retbuf, buf, HUGEBUFLEN); } else if (isweapon(o) && isknown(o)) { flag_t *damflag; @@ -5244,6 +5278,18 @@ char *makedesc_ob(object_t *o, char *retbuf) { sprintf(buf2, "%s makes you immune to disease.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; + case F_DTIMMUNE: + sprintf(buf2, "%s makes you immune to %s.\n", buf, getdamnamenoun(f->val[1])); + strncat(retbuf, buf2, HUGEBUFLEN); + break; + case F_DTRESIST: + sprintf(buf2, "%s makes you resistant to %s.\n", buf, getdamnamenoun(f->val[1])); + strncat(retbuf, buf2, HUGEBUFLEN); + break; + case F_DTVULN: + sprintf(buf2, "%s renders you vulnerable to %s.\n", buf, getdamnamenoun(f->val[1])); + strncat(retbuf, buf2, HUGEBUFLEN); + break; case F_DRUNK: sprintf(buf2, "%s makes you tipsy.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); @@ -5380,6 +5426,10 @@ char *makedesc_ob(object_t *o, char *retbuf) { sprintf(buf2, "%s produces light.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; + case F_REFLECTION: + sprintf(buf2, "%s reflects all missiles back to their source.\n", buf); + strncat(retbuf, buf2, HUGEBUFLEN); + break; case F_RETALIATE: sprintf(buf2, "%s protects you with %s.\n", buf, f->text); strncat(retbuf, buf2, HUGEBUFLEN); @@ -6595,9 +6645,12 @@ int doselguntarget(void) { snprintf(buf, BUFLEN, "Aim %s where?",gunname); snprintf(buf2, BUFLEN, "%s->Target->",gunname); - where = askcoords(buf, buf2, TT_MONSTER, player, UNLIMITED, LOF_NEED, B_TRUE); + addflag(player->flags, F_THROWING, B_TRUE, NA, NA, NULL); + where = askcoords(buf, buf2, TT_MONSTER, player, UNLIMITED, getfirearmloftype(player), B_TRUE); + killflagsofid(player->flags, F_THROWING); if (where) { - if (where->lf && haslof(player->cell, where, LOF_NEED, NULL)) { + //if (where->lf && haslof(player->cell, where, LOF_NEED, NULL)) { + if (where->lf) { setguntarget(player, where->lf); } else { setguntarget(player, NULL); @@ -6644,6 +6697,7 @@ int dotakeoff(obpile_t *op) { void dothrow(obpile_t *op) { object_t *o; char buf[BUFLEN],buf2[BUFLEN]; + flag_t *f; if (!hasbp(player, BP_HANDS)) { msg("You have no hands to throw with!"); @@ -6654,9 +6708,8 @@ void dothrow(obpile_t *op) { o = askobject(op, "Throw what", NULL, AO_NONE); if (o) { int maxdist; - char subprompt[BUFLEN]; + char subprompt[BUFLEN],oidbuf[BUFLENSMALL]; cell_t *where; - flag_t *f; getobname(o, buf, 1); f = hasflag(o->flags, F_EQUIPPED); @@ -6671,7 +6724,11 @@ void dothrow(obpile_t *op) { // ask where to throw it snprintf(buf2, BUFLEN, "Throw %s where?",buf); snprintf(subprompt, BUFLEN, "%s->Throw->",buf); + + sprintf(oidbuf, "%ld", o->id); + addflag(player->flags, F_THROWING, B_TRUE, NA, NA, oidbuf); where = askcoords(buf2, subprompt, TT_MONSTER, player, maxdist, LOF_NEED, B_TRUE); + killflagsofid(player->flags, F_THROWING); if (where) { cell_t *newwhere = NULL; @@ -6932,7 +6989,7 @@ void doheadingsmall(WINDOW *win, int y, int x, char *format, char *heading) { void initgfx(void) { int msgwinh = 2; - int statwinh = 2; + int statwinh = 3; setlocale(LC_CTYPE, ""); @@ -7970,7 +8027,7 @@ void handleinput(void) { } break; case 'G': // reload Gun with current ammo - loadfirearmfast(player); + loadfirearmfast(player, B_TRUE); break; case '\'': donextguntarget(); @@ -8290,14 +8347,25 @@ void drawstatus(void) { int myatt[MAXATTS]; int xpleft; - curs_set(0); wclear(statwin); + // FIRST LINE + wmove(statwin, 0, 0); + + // gun target ? + f = hasflag(player->flags, F_GUNTARGET); + if (f) { + wprintw(statwin, "Aim: "); + textwithcol(statwin, f->text); + } + + + // SECOND LINE + wmove(statwin, 1, 0); + //xpleft = getxpforlev(player->level + 1) - player->xp; xpleft = (int) (((float)player->xp / (float)getxpforlev(player->level + 1)) * 100.0); - - wmove(statwin, 0, 0); /* getplayername(pname); wattron(statwin, A_BOLD); wprintw(statwin, "["); wattroff(statwin, A_BOLD); @@ -8612,14 +8680,13 @@ void drawstatus(void) { } - // SECOND LINE - + // THIRD LINE for (a = 0; a < MAXATTS; a++) { myatt[a] = getattr(player, a); } //redraw(); - wmove(statwin, 1, 0); + wmove(statwin, 2, 0); wattron(statwin, A_BOLD); wprintw(statwin, "AR:"); wattroff(statwin, A_BOLD); snprintf(buf, BUFLEN, "%d ", getarmourrating(player, NULL, NULL, NULL)); wprintw(statwin, buf); @@ -8654,6 +8721,7 @@ void drawstatus(void) { capitalise(buf); wprintw(statwin, "%s", buf); unsetcol(statwin, C_BROWN); + } void drawmsg(void) { @@ -9754,6 +9822,10 @@ void showlfstats(lifeform_t *lf, int showall) { strcat(buf, "."); wrapprint(mainwin, &y, &x, "%s ", buf); } + f = lfhasflag(lf, F_REFLECTION); + if (f && (f->known)) { + wrapprint(mainwin, &y, &x, "%s %s surrounded by a negative gravity field.", you(lf), is(lf)); + } f = lfhasflag(lf, F_RETALIATE); if (f && (f->known)) { @@ -9881,16 +9953,20 @@ void showlfstats(lifeform_t *lf, int showall) { if (!dounknown && (slev != PR_INEPT)) { char endbit[BUFLEN]; char basecolour = 'n'; + int max; if (ismaxedskill(lf, sk->id)) { basecolour = 'h'; } // known skill sprintf(thisline, "^%c%-21s^%c[^%d", basecolour, sk->name, basecolour, getskilllevelcolour(slev)); + max = getmaxskilllevel(player, sk->id); for (i = PR_NOVICE; i <= PR_MASTER; i++) { char toadd[BUFLEN]; - if (i > getmaxskilllevel(player, sk->id)) { + if (i == (max+1)) { + sprintf(toadd, "^n]########"); + } else if (i > max) { sprintf(toadd, "^n#########"); } else if (i == slev) { if (i == getmaxskilllevel(player, sk->id)) { @@ -9912,15 +9988,23 @@ void showlfstats(lifeform_t *lf, int showall) { textwithcol(mainwin, thisline); printed = B_TRUE; } else if (dounknown && !slev && lfhasflagval(lf, F_CANLEARN, sk->id, NA, NA, NULL)) { + char toadd[BUFLEN]; + int max; // learnable skill - setcol(mainwin, C_RED); - mvwprintw(mainwin, y, 0, "%-21s", sk->name, " " ); - wprintw(mainwin, "["); - for (i = PR_NOVICE; i < PR_MASTER+1; i++) { - wprintw(mainwin, " "); + sprintf(toadd, "^B%-21s[", sk->name ); + wmove(mainwin, y, 0); + textwithcol(mainwin, toadd); + max = getmaxskilllevel(player, sk->id); + for (i = PR_NOVICE; i <= PR_MASTER; i++) { + if (i == max+1) { + textwithcol(mainwin, "^B]########"); + } else if (i > max) { + textwithcol(mainwin, "^B#########"); + } else { + wprintw(mainwin, " "); + } } - wprintw(mainwin, "]"); - unsetcol(mainwin, C_RED); + textwithcol(mainwin, "^B]^n"); printed = B_TRUE; } diff --git a/lf.c b/lf.c index 96e4d15..c4bd49c 100644 --- a/lf.c +++ b/lf.c @@ -81,6 +81,10 @@ void autoweild(lifeform_t *lf) { pretimespent = lf->timespent; + if (isplayer(lf)) { + dblog("db: calling autoweild for player."); + } + // weild weapons if required bestwep = getbestweapon(lf); if (bestwep) { @@ -688,16 +692,16 @@ int caneat(lifeform_t *lf, object_t *o) { } } - if (lfhasflag(lf, F_VEGETARIAN) && (o->material->id == MT_FLESH)) { + if (lfhasflag(lf, F_VEGETARIAN) && hasflag(o->flags, F_ISMEAT)) { reason = E_VEGETARIAN; return B_FALSE; } - if (lfhasflag(lf, F_CARNIVORE) && (o->material->id != MT_FLESH)) { + if (lfhasflag(lf, F_CARNIVORE) && !hasflag(o->flags, F_ISMEAT)) { reason = E_CARNIVORE; return B_FALSE; } - if (lfhasflag(lf, F_PARTVEGETARIAN) && (o->material->id == MT_FLESH)) { + if (lfhasflag(lf, F_PARTVEGETARIAN) && hasflag(o->flags, F_ISMEAT)) { if (gethungerlevel(gethungerval(player)) < H_PECKISH) { reason = E_PARTVEGETARIAN; return B_FALSE; @@ -1011,7 +1015,7 @@ int cansee_real(lifeform_t *viewer, lifeform_t *viewee, int uselos) { } dist = getcelldist(viewer->cell, viewee->cell); f = lfhasflag(viewer, F_TREMORSENSE); - if (f) { + if (f && !isairborne(viewee)) { if (f->val[0] > 0) { tremordist = f->val[0]; } else { @@ -4302,7 +4306,6 @@ void gainxp(lifeform_t *lf, long amt) { amtneeded = getspforpoint(lf); lf->skillxp += amt; - lf->totskillxp += amt; assert(lf->skillxp >= 0); while (lf->skillxp >= amtneeded) { @@ -4321,6 +4324,7 @@ void gainxp(lifeform_t *lf, long amt) { if (newskillpoints) { lf->skillpoints += newskillpoints; msg("^GYou feel ready to learn a new skill!"); + lf->totskillpoints += newskillpoints; } } @@ -5155,21 +5159,29 @@ int getevasion(lifeform_t *lf) { return ev; } -object_t *getbestthrowmissile(lifeform_t *lf) { +object_t *getbestthrowmissile(lifeform_t *lf, lifeform_t *target) { object_t *bestwep = NULL; int bestdam = -1; object_t *o; for (o = lf->pack->first ; o ; o = o->next) { if (!isequipped(o) && isthrowmissile(o) ) { - int thisdam; - // better than last one? - thisdam = getthrowdam(o) + getshatterdam(o); - if ((bestwep == NULL) || (thisdam > bestdam)) { - bestwep = o; - bestdam = thisdam; + int valid = B_TRUE; + + // powder is only a valid missile if we're adjacent to our target + if (target && hasflag(o->flags, F_POWDER)) { + if (getcelldist(lf->cell,target->cell) > 1) valid = B_FALSE; } + if (valid) { + int thisdam; + // better than last one? + thisdam = getthrowdam(o) + getshatterdam(o); + if ((bestwep == NULL) || (thisdam > bestdam)) { + bestwep = o; + bestdam = thisdam; + } + } } } return bestwep; @@ -5369,6 +5381,13 @@ object_t *getfirearm(lifeform_t *lf) { return NULL; } +enum LOFTYPE getfirearmloftype(lifeform_t *lf) { + if (getskill(lf, SK_RANGED) >= PR_EXPERT) { + return LOF_WALLSTOP; + } + return LOF_NEED; +} + int getfootprinttime(lifeform_t *lf) { int time; @@ -7076,7 +7095,7 @@ race_t *getreallyrandomrace(enum RACECLASS wantrc) { enum SKILL getrandomskill(void) { int sel,count = 0; skill_t *sk; - sel = rnd(0,MAXSKILLS-1); + sel = rnd(1,MAXSKILLS-1); // 0 is SK_NONE for (sk = firstskill ; sk ; sk = sk->next) { if (count == sel) return sk->id; count++; @@ -7177,7 +7196,7 @@ long getspforpoint(lifeform_t *lf) { float mod; long amtneeded; amtneeded = SKILLXPPERPOINT; - amtneeded += (50 * lf->totskillxp); + amtneeded += (50 * lf->totskillpoints); mod = MAXOF(getstatmod(lf, A_IQ), getstatmod(lf, A_WIS)); amtneeded = pctof(100 - mod, amtneeded); return amtneeded; @@ -7958,9 +7977,9 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) { makeknown(OT_POT_JUICE); makeknown(OT_POT_RUM); } - newf = hasflagval(lf->flags, F_CANWILL, OT_A_PREPARECORPSE, NA, NA, NULL); + newf = hasflagval(lf->flags, F_CANWILL, OT_A_COOK, NA, NA, NULL); if (!newf) { - newf = addflag(lf->flags, F_CANWILL, OT_A_PREPARECORPSE, NA, NA, NULL); + newf = addflag(lf->flags, F_CANWILL, OT_A_COOK, NA, NA, NULL); newf->lifetime = FROMSKILL; } } else if (id == SK_LORE_ARCANA) { @@ -7988,6 +8007,23 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) { newf = addflag(lf->flags, F_CANWILL, OT_A_DISARM, NA, NA, NULL); newf->lifetime = FROMSKILL; } + + // learning a new spell school skill will grant you a random first level spell from + // that school. + if (isspellskill(id)) { + enum OBTYPE oid; + int tries = 0; + oid = getrandomspellfromschool(getskillschool(id), 1); + while (cancast(lf, oid, NULL) && (tries < 3)) { + oid = getrandomspellfromschool(getskillschool(id), 1); + tries++; + } + if (oid != OT_NONE) { + addflag(lf->flags, F_CANCAST, oid, NA, NA, NULL); + } + + } + statdirty = B_TRUE; // in case skill changes your stats } @@ -8011,10 +8047,6 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) { newf->lifetime = FROMSKILL; } } else if (id == SK_COOKING) { - if (f->val[1] == PR_BEGINNER) { - newf = addflag(lf->flags, F_CANWILL, OT_A_COOK, NA, NA, NULL); - newf->lifetime = FROMSKILL; - } if (f->val[1] == PR_ADEPT) { if (isplayer(lf)) { makeknown(OT_MUSHROOMSHI); @@ -8397,9 +8429,10 @@ void givestartskills(lifeform_t *lf, flagpile_t *fp) { f = retflag[i]; if (f->id == F_STARTSKILL) { - int wantval; + int wantval,n; wantval = f->val[1]; - while (getskill(lf, f->val[0]) < wantval) { + for (n = 0; n < wantval; n++) { + //while (getskill(lf, f->val[0]) < wantval) { giveskill(lf, f->val[0]); } } @@ -9630,6 +9663,30 @@ int isloreskill(enum SKILL skid) { return B_FALSE; } +int isspellskill(enum SKILL skid) { + switch (skid) { + case SK_SS_ALLOMANCY: + case SK_SS_MENTAL: + case SK_SS_NATURE: + case SK_SS_AIR: + case SK_SS_DEATH: + case SK_SS_DIVINATION: + case SK_SS_ENCHANTMENT: + case SK_SS_FIRE: + case SK_SS_COLD: + case SK_SS_GRAVITY: + case SK_SS_LIFE: + case SK_SS_MODIFICATION: + case SK_SS_SUMMONING: + case SK_SS_TRANSLOCATION: + case SK_SS_WILD: + return B_TRUE; + default: + break; + } + return B_FALSE; +} + int ismadeofice(lifeform_t *lf) { if (lf->material->id == MT_ICE) return B_TRUE; if (lfhasflag(lf, F_FROZEN)) return B_TRUE; @@ -9850,7 +9907,7 @@ lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) { a->level = level; a->newlevel = level; a->xp = getxpforlev(a->level); - a->totskillxp = 0; + a->totskillpoints = 0; a->skillxp = 0; a->skillpoints = 0; a->cell = cell; @@ -10195,7 +10252,7 @@ void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype) { // don't adjust for lifeform material - we inherit all the material's flags. //adjustdammaterial((unsigned int *)amt, damtype, getlfmaterial(lf)); - adjustdamhardness((unsigned int *)amt, damtype, getlfmaterial(lf)); + adjustdamhardness(amt, damtype, getlfmaterial(lf)); if (lfhasflag(lf, F_DRUNK)) { *amt -= rnd(0,3); @@ -10544,23 +10601,24 @@ void autoskill(lifeform_t *lf) { void autotarget(lifeform_t *lf) { object_t *gun; - lifeform_t *targ,*newtarg; + lifeform_t *targ = NULL,*newtarg = NULL; int closest; int i; int gunrange; int targid; gun = getfirearm(lf); - if (!gun) return; - - if (!getammo(gun)) return; - - gunrange = getfirearmrange(gun); - - // already got a target? - targid = getguntargetid(lf); + if (gun && getammo(gun)) { + gunrange = getfirearmrange(gun); + // already got a target? + targid = getguntargetid(lf); + } else { + gunrange = -1; + targid = -1; + } if (targid == -1) { + // no existing target targ = NULL; } else { targ = findlf(NULL, targid); @@ -10569,45 +10627,63 @@ void autotarget(lifeform_t *lf) { if (isdead(targ)) { // clear target ? targ = NULL; - } else if (!haslof(lf->cell, targ->cell, B_FALSE, NULL)) { + } else if (!cansee(lf, targ) || !haslof(lf->cell, targ->cell, getfirearmloftype(lf), NULL)) { // clear target ? targ = NULL; } else { - // already got a valid target. return. + flag_t *f; + + // already got a valid target. just update targetting text. + f = hasflag(lf->flags, F_GUNTARGET); + if (f) { + char targbuf[BUFLEN]; + makegunaimstring(lf, f->val[0], targbuf); + if (!streq(targbuf, f->text)) { + free(f->text); + f->text = strdup(targbuf); + if (isplayer(lf)) { + statdirty = B_TRUE; + drawstatus(); + updatestatus(); + } + } + } return; } } else { - // target no longer exists? - // clear target ? + // target no longer exists + // clear target + targ = NULL; } } - // find new target - newtarg = NULL; - closest = 9999; - for (i = 0; i < lf->nlos; i++) { - cell_t *c; - c = lf->los[i]; - if (c->lf && (c->lf != lf) && cansee(lf, c->lf) && isingunrange(lf, c)) { - int valid = B_TRUE; - if (!areenemies(lf, c->lf)) { - valid = B_FALSE; - } - if (valid) { - int thisdist; - thisdist = getcelldist(lf->cell, c); - if (thisdist < closest) { - newtarg = c->lf; - closest = thisdist; + if (gun && (gunrange != -1)) { + // find new target + newtarg = NULL; + closest = 9999; + for (i = 0; i < lf->nlos; i++) { + cell_t *c; + c = lf->los[i]; + if (c->lf && (c->lf != lf) && cansee(lf, c->lf) && isingunrange(lf, c) && areenemies(lf, c->lf)) { + if (haslof(lf->cell, c, getfirearmloftype(lf), NULL)) { + int thisdist; + thisdist = getcelldist(lf->cell, c); + if (thisdist < closest) { + newtarg = c->lf; + closest = thisdist; + } } } } } - - if (newtarg && (newtarg != targ)) { + if (newtarg != targ) { setguntarget(lf, newtarg); } + + if (!newtarg) { + killflagsofid(lf->flags, F_GUNTARGET); + } } int issmellablelf(lifeform_t *lf) { @@ -10828,13 +10904,16 @@ int loadfirearm(lifeform_t *lf, object_t *gun, object_t *ammo) { // take time if (lf) { - f = hasflag(gun->flags, F_RELOADTURNS); - taketime(lf, getactspeed(lf)*f->val[0]); + if (getskill(lf, SK_RANGED) < PR_ADEPT) { + f = hasflag(gun->flags, F_RELOADTURNS); + taketime(lf, getactspeed(lf)*f->val[0]); + } if (isplayer(lf)) { - char buf[BUFLEN]; - getobname(gun->contents->first, buf, gun->contents->first->amt); - msg("You load %s into your %s.", buf, noprefix(gunname)); + //char buf[BUFLEN]; + //getobname(gun->contents->first, buf, gun->contents->first->amt); + //msg("You load %s into your %s.", buf, noprefix(gunname)); + msg("You reload your %s.", noprefix(gunname)); } else if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); @@ -10847,18 +10926,18 @@ int loadfirearm(lifeform_t *lf, object_t *gun, object_t *ammo) { return B_FALSE; } -int loadfirearmfast(lifeform_t *lf) { +int loadfirearmfast(lifeform_t *lf, int onpurpose) { object_t *gun,*newammo,*curammo; gun = getfirearm(lf); if (!gun) { - if (isplayer(lf)) { + if (isplayer(lf) && onpurpose) { msg("You have no firearm equipped."); } return B_TRUE; } curammo = getammo(gun); if (curammo) { - if (isplayer(lf)) { + if (isplayer(lf) && onpurpose) { char buf[BUFLEN]; getobname(gun, buf, 1); msg("Your %s is already loaded!", noprefix(buf)); @@ -10870,13 +10949,14 @@ int loadfirearmfast(lifeform_t *lf) { if (newammo) { loadfirearm(lf, gun, newammo); } else { - if (isplayer(lf)) { + if (isplayer(lf) && onpurpose) { char buf[BUFLEN]; getobname(gun, buf, 1); msg("You have no ammo for your %s.", noprefix(buf)); } return B_TRUE; } + if ((gamemode == GM_GAMESTARTED) && onpurpose) taketime(lf, getactspeed(lf)); return B_FALSE; } @@ -13115,38 +13195,39 @@ void setfollowdistance(lifeform_t *lf, int min, int max) { } void setguntarget(lifeform_t *lf, lifeform_t *targ) { - flag_t *f; + flag_t *f,*targflag = NULL; + char oldtargbuf[BUFLEN]; + char targbuf[BUFLEN]; + // have an existing target? f = hasflag(lf->flags, F_GUNTARGET); if (f) { + strcpy(oldtargbuf, f->text); killflag(f); + } else { + strcpy(oldtargbuf, ""); } if (targ) { - addflag(lf->flags, F_GUNTARGET, targ->id, NA, NA, NULL); - if (isplayer(lf)) { - // announce - char targname[BUFLEN]; - getlfname(targ, targname); - msg("Targetted: %s.",noprefix(targname)); // remove 'the ' - } else { - if (lfhasflag(lf, F_DEBUG)) { - char lfname[BUFLEN]; - char targname[BUFLEN]; - getlfname(lf, lfname); - getlfname(targ, targname); - dblog("%s targetted %s.",lfname,targname); - } + makegunaimstring(lf, targ->id, targbuf); // fill in the text + f = addflag(lf->flags, F_GUNTARGET, targ->id, NA, NA, targbuf); + } else { + targflag = NULL; + strcpy(targbuf, "nothing"); + } + + // announce if required + if (isplayer(lf)) { + if (!streq(targbuf, oldtargbuf)) { + warn("Targetted: %s", targbuf ); + statdirty = B_TRUE; } } else { - if (isplayer(lf)) { - // announce - msg("Targetted: nothing."); - } else { - if (lfhasflag(lf, F_DEBUG)) { - char lfname[BUFLEN]; - getlfname(lf, lfname); - dblog("%s target set to nothing.",lfname); - } + if (lfhasflag(lf, F_DEBUG)) { + char lfname[BUFLEN]; + char targname[BUFLEN]; + getlfname(lf, lfname); + getlfname(targ, targname); + dblog("%s targetted %s.",lfname,targname); } } } @@ -13480,7 +13561,6 @@ void setstamina(lifeform_t *lf, float howmuch) { int shoot(lifeform_t *lf) { object_t *gun,*ammo; lifeform_t *targ; - flag_t *f; int firespeed; reason = E_OK; @@ -13505,10 +13585,19 @@ int shoot(lifeform_t *lf) { // get fire speed firespeed = getfirearmspeed(gun); - f = hasflag(gun->flags, F_FIRETURNS); - taketime(lf, getactspeed(lf) * f->val[0]); + taketime(lf, getactspeed(lf)); fireat(lf, ammo, 1, targ->cell, firespeed, gun); + if (!getammo(gun)) { + if (loadfirearmfast(lf, B_FALSE)) { + if (isplayer(lf)) { + char obname[BUFLEN]; + getobname(gun, obname, 1); + msg("^bYour %s is now out of ammo!", noprefix(obname)); + } + } + } + return B_FALSE; } @@ -14662,7 +14751,7 @@ void startlfturn(lifeform_t *lf) { getflags(lf->flags, retflag, &nretflags, F_ATTACHEDTO, F_CANWILL, F_CHARMEDBY, F_CLIMBING, F_FLEEFROM, - F_GRABBEDBY, F_GRABBING, F_BOOSTSPELL, F_FEIGNINGDEATH, F_INJURY, + F_GRABBEDBY, F_GRABBING, F_GUNTARGET, 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]; @@ -16327,6 +16416,11 @@ int wear(lifeform_t *lf, object_t *o) { statdirty = B_TRUE; } + if (o->amt > 1) { + // eg. for melted wax in your ears + o = splitob(o); + } + getobname(o, obname, 1); // check if it is already equipped first! diff --git a/lf.h b/lf.h index aeaec6a..0ef6b91 100644 --- a/lf.h +++ b/lf.h @@ -126,7 +126,7 @@ int real_getattr(lifeform_t *lf, enum ATTRIB attr, int ignoreattrset); int getavgdam(lifeform_t *lf, int forxp); float getequippedweight(lifeform_t *lf); int getevasion(lifeform_t *lf); -object_t *getbestthrowmissile(lifeform_t *lf); +object_t *getbestthrowmissile(lifeform_t *lf, lifeform_t *target); object_t *getbestweapon(lifeform_t *lf); object_t *getbestfirearm(lifeform_t *lf); int getbodyparthitchance(enum BODYPART bp); @@ -135,6 +135,7 @@ char *getbodypartequipname(enum BODYPART bp); object_t *getequippedob(obpile_t *op, enum BODYPART bp); int getexposedlimbs(lifeform_t *lf); object_t *getfirearm(lifeform_t *lf); +enum LOFTYPE getfirearmloftype(lifeform_t *lf); int getfootprinttime(lifeform_t *lf); lifeform_t *getguntarget(lifeform_t *lf); int getguntargetid(lifeform_t *lf); @@ -283,6 +284,7 @@ flag_t *isimmuneto(flagpile_t *fp, enum DAMTYPE dt); int isinbattle(lifeform_t *lf); int isingunrange(lifeform_t *lf, cell_t *where); int isloreskill(enum SKILL skid); +int isspellskill(enum SKILL skid); int ismadeofice(lifeform_t *lf); int ismaxedskill(lifeform_t *lf, enum SKILL skid); int ispeaceful(lifeform_t *lf); @@ -309,7 +311,7 @@ void killlf(lifeform_t *lf); void killrace(race_t *race); flag_t *levelabilityready(lifeform_t *lf); int loadfirearm(lifeform_t *lf, object_t *gun, object_t *ammo); -int loadfirearmfast(lifeform_t *lf); +int loadfirearmfast(lifeform_t *lf, int onpurpose); void loseconcentration(lifeform_t *lf); int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc); int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam, object_t *fromob, int retaliate); diff --git a/map.c b/map.c index 38d22e1..916e171 100644 --- a/map.c +++ b/map.c @@ -5530,7 +5530,9 @@ void setcellknown(cell_t *cell, int forcelev) { } } - if (slev == PR_INEPT) { + if (hasflag(player->flags, F_PHOTOMEM)) { + cell->knowntime = PERMENANT; + } else if (slev == PR_INEPT) { cell->knowntime = getattr(player, A_IQ)*5; } else { cell->knowntime = PERMENANT; @@ -5706,12 +5708,17 @@ int unlinkstairsto(map_t *unlinkmap) { void updateknowncells(void) { int x,y; map_t *map; - object_t *wep; - int seenundead = B_FALSE; + //object_t *wep; + //int seenundead = B_FALSE; + // you don't remember cells when you're flying, unless you + // have a magic map or photographic memory. + if (isairborne(player) && !lfhasflag(player, F_PHOTOMEM)) { + return; + } map = player->cell->map; - wep = getweapon(player); + //wep = getweapon(player); for (y = viewy; y < viewy + viewh; y++) { for (x = viewx; x < viewx + vieww; x++) { @@ -5721,9 +5728,11 @@ void updateknowncells(void) { //if ((player->cell == cell) || haslos(player, cell)) { if (haslos(player, cell)) { setcellknown(cell, B_FALSE); + /* if (cell->lf && lfhasflag(cell->lf, F_UNDEAD)) { seenundead = B_TRUE; } + */ } } } diff --git a/move.c b/move.c index 11ba407..8b22b8b 100644 --- a/move.c +++ b/move.c @@ -809,7 +809,7 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc for (i = 0; i < howfar; i++) { if (moveclear(lf, dir, &reason)) { if ((i == 0) && seen && wantannounce) { - msg("%s %s knocked backwards!",lfname,is(lf)); + msg("%s %s knocked %s!",lfname,is(lf), getreldirname(getrelativedir(lf, dir))); } trymove(lf, dir, B_FALSE, B_FALSE); } @@ -1833,7 +1833,7 @@ int opendoor(lifeform_t *lf, object_t *o) { msg("%s bursts open!",obname); } else { char noisebuf[BUFLEN]; - sprintf(noisebuf, "%s bursting open.", obname); + sprintf(noisebuf, "%s bursting open!", obname); noise(doorcell, NULL, NC_OTHER, 4, noisebuf, NULL); } } diff --git a/nexus.c b/nexus.c index b1c2e9c..843598e 100644 --- a/nexus.c +++ b/nexus.c @@ -896,6 +896,25 @@ enum COLOUR getpctcol(float num, float max) { return C_ORANGE; } +char getpctletter(float num, float max) { + float pct; + pct = (num / max) * 100; + if (pct >= 100) { + return 'S'; + } else if (pct >= 85) { + return 'A'; + } else if (pct >= 70) { + return 'B'; + } else if (pct >= 55) { + return 'C'; + } else if (pct >= 40) { + return 'D'; + } else { // ie. < 40% + return 'E'; + } + return '?'; +} + void getrarityrange(int depth, int *min, int *max, int range, int oodok) { int mid; int num; diff --git a/nexus.h b/nexus.h index 4959ce0..ac780f4 100644 --- a/nexus.h +++ b/nexus.h @@ -11,6 +11,7 @@ void dobresnham(int d, int xinc1, int yinc1, int dinc1, int xinc2, int yinc2, in void donextturn(map_t *map); void gethitdicerange(int depth, int *min, int *max, int range, int oodok); enum COLOUR getpctcol(float num, float max); +char getpctletter(float num, float max); void getrarityrange(int depth, int *min, int *max, int range, int oodok); int init(void); void calcbresnham(map_t *m, int x1, int y1, int x2, int y2, cell_t **retcell, int *numpixels); diff --git a/objects.c b/objects.c index 4fa8454..ad1efb1 100644 --- a/objects.c +++ b/objects.c @@ -1308,6 +1308,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes // ie. vending machine, or inside another object/fake cell? corpserace = getrandomcorpserace(NULL); } + if (corpserace->id != corpserace->baseid) corpserace = findrace(corpserace->baseid); } ratio = o->material->weightrating / corpserace->material->weightrating; @@ -1363,6 +1364,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes } else if (o->type->id == OT_JERKY) { if (!corpserace) { corpserace = getrandomcorpserace(NULL); + if (corpserace->id != corpserace->baseid) corpserace = findrace(corpserace->baseid); } addflag(o->flags, F_LINKRACE, corpserace->id, NA, NA, NULL); } else if (o->type->id == OT_ROASTMEAT) { @@ -1371,6 +1373,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes if (!corpserace || hasflag(corpserace->flags, F_NOCORPSE)) { // random one. corpserace = getrandomcorpserace(NULL); + if (corpserace->id != corpserace->baseid) corpserace = findrace(corpserace->baseid); } o->weight = corpserace->weight / 2; @@ -1806,7 +1809,7 @@ recipe_t *addrecipe(enum OBTYPE result, ...) { } -void adjustdamhardness(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL mat) { +void adjustdamhardness(int *dam, enum DAMTYPE damtype, enum MATERIAL mat) { // now check for hardness if (isphysicaldam(damtype)) { *dam -= gethardness(mat); @@ -1820,7 +1823,7 @@ void adjustdamhardness(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL ma } // adjust damage based on material being damaged -void adjustdammaterial(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL mat) { +void adjustdammaterial(int *dam, enum DAMTYPE damtype, enum MATERIAL mat) { // adjust based on material if (mat == MT_MAGIC) { switch (damtype) { @@ -1926,7 +1929,7 @@ void adjustdammaterial(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL ma } -void adjustdamob(object_t *o, unsigned int *dam, enum DAMTYPE damtype) { +void adjustdamob(object_t *o, int *dam, enum DAMTYPE damtype) { // objects can't get hurt the turn they // were created. if (o->birthtime == curtime) { @@ -2410,6 +2413,7 @@ int checkcritprotection(lifeform_t *lf, object_t *o) { if (pctchance(getcritprotection(o))) { char obname[BUFLEN]; getobname(o, obname, o->amt); + /* if (isplayer(lf)) { msg("Your %s protects you.", noprefix(obname)); } else if (cansee(player, lf)) { @@ -2417,6 +2421,7 @@ int checkcritprotection(lifeform_t *lf, object_t *o) { getlfname(lf, lfname); msg("%s%s %s protects it.", lfname, getpossessive(lfname), noprefix(obname)); } + */ return B_TRUE; } return B_FALSE; @@ -3260,6 +3265,8 @@ int getcharges(object_t *o) { return amt; } +// return the base accuracy for the firearm 'wep', or for a throw if wep is null. +// (ie. the accuracy for a range of 0). int getobaccuracy(object_t *wep, lifeform_t *weilder) { int acc; flag_t *f; @@ -3282,25 +3289,6 @@ int getobaccuracy(object_t *wep, lifeform_t *weilder) { acc += (getobbonus(wep, B_FALSE)*10); - if (weilder) { - enum SKILLLEVEL slev; - // modify for weilder's skill - - slev = getweaponskill(weilder, wep); - if (hasflag(wep->flags, F_MASTERWORK)) { - if (slev < PR_ADEPT) slev++; - } - - switch (slev) { - case PR_INEPT: acc -= 35; break; - case PR_NOVICE: acc -= 10; break; - case PR_BEGINNER: acc -= 5; break; - case PR_ADEPT: break; - case PR_SKILLED: acc += 10; break; - case PR_EXPERT: acc += 20; break; - case PR_MASTER: acc += 30; break; - } - } } return acc; } @@ -5938,8 +5926,9 @@ int isbetterwepthan(object_t *a, object_t *b, lifeform_t *owner) { msg("PREACC:a=%s:%d(acc %d), b=%s:%d(acc %d)",namea,dama,(int)acca, nameb, damb,(int)accb); } - dama = pctof(acca, dama); - damb = pctof(accb, damb); + // add on the (acc/2)*damage to each one + dama = dama + pctof(acca/2, dama); + damb = damb + pctof(accb/2, damb); if (db) { msg("POST:a=%s:%d(acc %d), b=%s:%d(acc %d)",namea,dama,(int)acca, nameb, damb,(int)accb); @@ -7663,7 +7652,15 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { snprintf(buf, BUFLEN, "Load %s with what ammo",obname); oo = askobject(lf->pack, buf, NULL, AO_SPECIFIED); if (oo) { - loadfirearm(lf, o, oo); + if (isammofor(oo->type, o)) { + loadfirearm(lf, o, oo); + } else { + if (isplayer(lf)) msg("That can't be used as ammo for %s.", obname); + return B_TRUE; + } + } else { + if (isplayer(lf)) msg("Cancelled."); + return B_TRUE; } } } else if (o->type->obclass->id == OC_WAND) { @@ -8737,7 +8734,7 @@ void quaff(lifeform_t *lf, object_t *o) { // o can be NULL if we're just doing potion EFFECTS, not actually drinking one. void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE potblessed, int *seen) { char lfname[BUFLEN]; - unsigned int dam; + int dam; int i; int first,dir; int amt; @@ -10272,12 +10269,12 @@ object_t *splitob(object_t *o) { return newob; } // returns amount of damage taken -int takedamage(object_t *o, unsigned int howmuch, int damtype) { +int takedamage(object_t *o, int howmuch, int damtype) { return real_takedamage(o, howmuch, damtype, B_TRUE); } // returns amount of damage taken -int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantannounce) { +int real_takedamage(object_t *o, int howmuch, int damtype, int wantannounce) { char predamname[BUFLEN],postdamname[BUFLEN]; char obname[BUFLEN]; flag_t *hpflag, *f; @@ -10405,6 +10402,7 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno } adjustdamob(o, &howmuch, damtype); + assert(howmuch < 1000); // effects which have to happen before damage is applied... @@ -10478,6 +10476,10 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno hpflag->val[0] -= howmuch; } + if (hpflag) { + assert(hpflag->val[0] <= hpflag->val[1]); + } + if (!hpflag || (hpflag->val[0] <= 0)) { // special cases.... if (damtype == DT_FIRE) { @@ -10699,6 +10701,8 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, if (target && isdead(target)) { target = NULL; } + + if (thrower && target && !isprone(target) && !lfhasflag(target, F_CASTINGSPELL)) { if (areallies(thrower, target) && !firearm) { willcatch = B_TRUE; @@ -10727,10 +10731,12 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, // announce it ("xx throws xx" "at yy") if (thrower && isplayer(thrower)) { // player is throwing something - if (target && !hasflag(o->flags, F_POWDER)) { - msg("You %s %s %s %s.", throwverbpres, obname, willcatch ? "to" : "at", targetname); - } else { - msg("You %s %s.",throwverbpres, obname); + if (!firearm) { + if (target && !hasflag(o->flags, F_POWDER)) { + msg("You %s %s %s %s.", throwverbpres, obname, willcatch ? "to" : "at", targetname); + } else { + msg("You %s %s.",throwverbpres, obname); + } } } else if (thrower && haslos(player, srcloc) && (srcloc == thrower->cell)) { char throwstring[BUFLEN]; @@ -10765,21 +10771,6 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, } - // adjust destination location in case something is in the way. - haslof(srcloc, where, LOF_NEED, &newloc); - if (newloc) { - where = newloc; - target = where->lf; - if (target && isdead(target)) { - target = NULL; - } - if (target) { - getlfname(target, targetname); - } - } - - - //taketime(thrower, SPEED_THROW); // some obejcts will die when thrown. @@ -10825,7 +10816,21 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, if (radius > 10) radius = 10; spellcloud(srcloc, radius, '}', C_MAGENTA, OT_S_SLEEP, radius, B_TRUE); - + } else if (o->type->id == OT_SALT) { + if (target && (getcelldist(srcloc, where) <= 1)) { + if (hasbp(target, BP_EYES) && !isblind(target) && !getequippedob(target->pack, BP_EYES)) { + if (cansee(player, target)) { + msg("%s irritates %s%s eyes!", obname, targetname, getpossessive(targetname)); + } + // blind for 5-7 turns + addtempflag(target->flags, F_BLIND, B_TRUE, NA, NA, NULL, rnd(5,10)); + } + } else { + if (haslos(player, srcloc)) { + msg("%s dispers%s into the air.", obname, (amt == 1) ? "es" : "e"); + if (!isknown(o)) makeknown(o->type->id); + } + } } else { if (haslos(player, srcloc)) { msg("%s dispers%s into the air.", obname, (amt == 1) ? "es" : "e"); @@ -10848,6 +10853,20 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, } } + // adjust destination location in case something is in the way. + haslof(srcloc, where, LOF_NEED, &newloc); + if (newloc) { + where = newloc; + target = where->lf; + if (target && isdead(target)) { + target = NULL; + } + if (target) { + getlfname(target, targetname); + } + } + + // do throw animation if (seen) { glyph_t *gl; @@ -10855,6 +10874,27 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, anim(srcloc, where, gl->ch, gl->colour); } + // reflection? + if ( target && lfhasflag(target, F_REFLECTION)) { + if (seen) { + glyph_t *gl; + gl = getglyph(o); + anim(where, srcloc, gl->ch, gl->colour); + msg("%s is reflected away from %s!", obname, targetname); + } + // adjust target + where = srcloc; + target = where->lf; + if (target && isdead(target)) { + target = NULL; + } + if (target) { + getlfname(target, targetname); + } + thrower = NULL; + } + + // find out your chances of hitting if (target) { if (thrower) { @@ -10989,7 +11029,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, if (seen) { if (isplayer(target)) { msg("You dodge %s.", obname); - } else { + } else if (cansee(player, target)) { msg("%s dodges %s.", targetname, obname); } announcedmiss = B_TRUE; @@ -11026,7 +11066,8 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, if (youhit) { if (willcatch) { if (seen) { - msg("%s catch%s %s.", targetname, isplayer(target) ? "" : "es", obname); + msg("^%c%s catch%s %s.", isplayer(target) ? 'g' : 'n', + targetname, isplayer(target) ? "" : "es", obname); } moveob(o, target->pack, amt); return B_FALSE; @@ -11048,8 +11089,21 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, throwdam = getthrowdam(o); + dam = (int)((float)throwdam * multiplier); + // firearms at pointblank range? +50% damage + if (firearm) { + if ((getcelldist(srcloc, where) <= 1)) { + dam = pctof(150, dam); + } + // master marksman ? + if (thrower && (getskill(thrower, SK_RANGED) >= PR_MASTER)) { + dam = pctof(150, dam); + } + } + + // special case if (o->type->id == OT_RUBBERBULLET) { dam = 1; @@ -11086,7 +11140,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, snprintf(damstring, BUFLEN, " [%d dmg]",dam); strcat(buf2, damstring); } - msg("%s", buf2); + msg("^b%s", buf2); } snprintf(damstring, BUFLEN, "%s (%s by %s)",obname,throwverbpast, realthrowernamea); @@ -11192,11 +11246,30 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, } } + if (thrower && hasactivespell(thrower, OT_S_WHATGOESUP)) { + if (newob && !isdeadob(newob)) { + // on the ground? + if ((newob->pile->where == where) && haslof(newob->pile->where, thrower->cell, LOF_NEED, NULL)) { + if (isplayer(thrower)) { + msg("%s returns to you!", obname); + } else if (cansee(player, thrower)) { + msg("%s returns to %s!", obname, throwername); + } else if (haslos(player, newob->pile->where)) { + msg("%s returns to someone!", obname); + } + moveob(newob, thrower->pack, newob->amt); + } + } + } + + + /* if (firearm && outofammo && isplayer(thrower)) { char buf[BUFLEN]; getobname(firearm, buf, 1); msg("Your %s is now out of ammo.", noprefix(buf)); } + */ return B_FALSE; } @@ -12076,12 +12149,8 @@ int validateobs(void) { printf("ERROR in object '%s' - firearms need to have F_AMMOCAPACITY.\n", ot->name); goterror = B_TRUE; } - if (!hasflag(ot->flags, F_FIRETURNS)) { - printf("ERROR in object '%s' - firearms need to have F_AMMOCAPACITY.\n", ot->name); - goterror = B_TRUE; - } if (!hasflag(ot->flags, F_RELOADTURNS)) { - printf("ERROR in object '%s' - firearms need to have F_AMMOCAPACITY.\n", ot->name); + printf("ERROR in object '%s' - firearms need to have F_RELOADTURNS.\n", ot->name); goterror = B_TRUE; } @@ -12385,10 +12454,73 @@ enum MATSTATE getmaterialstate(enum MATERIAL mat) { } int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, object_t *firearm, flag_t *tkthrow) { - int acc,maxrange,howfar; + int acc,howfar,cellpenalty; enum SKILLLEVEL slev; enum SKILL whichskill; enum ATTRIB whichatt; + + // base accuracy of 100% for hitting yourself + // then accuracy goes down for each cell based on skill + agility + if (tkthrow) { + whichatt = tkthrow->val[0]; + whichskill = tkthrow->val[1]; + } else { + whichatt = A_AGI; + if (firearm) { + whichskill = SK_RANGED; + } else { + whichskill = SK_THROWING; + } + } + + // base accuracy to hit your own cell + // (firearm == null) means we are throwing. + acc = getobaccuracy(firearm, thrower); + + // for each cell travelled, lower accuracy, based on skill. + slev = getskill(thrower, whichskill); + + // masterwork firearms? + if (firearm && hasflag(firearm->flags, F_MASTERWORK)) { + if (slev < PR_ADEPT) slev++; + } + + switch (slev) { + case PR_INEPT: cellpenalty = 32; break; + case PR_NOVICE: cellpenalty = 22; break; + case PR_BEGINNER: cellpenalty = 16; break; + case PR_ADEPT: cellpenalty = 12; break; + case PR_SKILLED: cellpenalty = 10; break; + case PR_EXPERT: cellpenalty = 8; break; + case PR_MASTER: cellpenalty = 6; break; + } + + howfar = getcelldist(thrower->cell, where); + + acc -= (cellpenalty*howfar); + + if (whichatt != A_NONE) { + int mod; + mod = getstatmod(thrower, whichatt); // -50 to 50 + mod /= 2; // -25 to +25 + acc += mod; + } + + // penalty for throwing non-missiles + if (missile && !firearm && !isthrowmissile(missile) && !tkthrow) { + acc -= 20; + } + // modify for prone throwers + if (isprone(thrower)) { + acc -= 50; + } + + // modify for prone defenders + if (where->lf && isprone(where->lf)) { + acc -= 30; + } + limit(&acc, 0, NA); +/* // figure out if you miss or not, based on distance and // dexterity // base: @@ -12463,6 +12595,7 @@ int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, ob acc -= 30; } limit(&acc, 0, NA); + */ return acc; } diff --git a/objects.h b/objects.h index c39ad54..18a027a 100644 --- a/objects.h +++ b/objects.h @@ -18,9 +18,9 @@ obpile_t *addobpile(lifeform_t *owner, cell_t *where, object_t *parentob); void addobsinradius(cell_t *centre, int radius, int dirtype, char *name, int allowdupes); objecttype_t *addot(enum OBTYPE id, char *name, char *description, int material, float weight, int obclassid, enum LFSIZE size); recipe_t *addrecipe(enum OBTYPE result, ...); -void adjustdamhardness(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL mat); -void adjustdammaterial(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL mat); -void adjustdamob(object_t *o, unsigned int *dam, enum DAMTYPE damtype); +void adjustdamhardness(int *dam, enum DAMTYPE damtype, enum MATERIAL mat); +void adjustdammaterial(int *dam, enum DAMTYPE damtype, enum MATERIAL mat); +void adjustdamob(object_t *o, int *dam, enum DAMTYPE damtype); int adjustarmourpenalty(lifeform_t *lf, float amt); int adjustshieldpenalty(lifeform_t *lf, float amt); //void adjustprice(objecttype_t *ot, float *price ); @@ -247,8 +247,8 @@ int shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf); void shufflehiddennames(void); int sizetonutrition(enum LFSIZE size); object_t *splitob(object_t *o); -int takedamage(object_t *o, unsigned int howmuch, int damtype); -int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantannounce); +int takedamage(object_t *o, int howmuch, int damtype); +int real_takedamage(object_t *o, int howmuch, int damtype, int wantannounce); int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, object_t *firearm); void timeeffectsob(object_t *o); //void trapeffects(object_t *trapob, enum OBTYPE oid, lifeform_t *lf); diff --git a/save.c b/save.c index cdcf3b8..235bcc7 100644 --- a/save.c +++ b/save.c @@ -200,7 +200,7 @@ lifeform_t *loadlf(FILE *f, cell_t *where) { fscanf(f, "int: %d/%d\n",&l->att[A_IQ],&l->baseatt[A_IQ]); fscanf(f, "xp: %ld\n",&l->xp); fscanf(f, "skillxp: %ld\n",&l->skillxp); - fscanf(f, "totskillxp: %ld\n",&l->totskillxp); + fscanf(f, "totskillpoints: %ld\n",&l->totskillpoints); fscanf(f, "skp: %d\n",&l->skillpoints); fscanf(f, "contr: %d\n",&l->controller); fscanf(f, "hp: %d/%d\n",&l->hp, &l->maxhp); @@ -790,7 +790,7 @@ int savelf(FILE *f, lifeform_t *l) { fprintf(f, "int: %d/%d\n",l->att[A_IQ],l->baseatt[A_IQ]); fprintf(f, "xp: %ld\n",l->xp); fprintf(f, "skillxp: %ld\n",l->skillxp); - fprintf(f, "totskillxp: %ld\n",l->totskillxp); + fprintf(f, "totskillpoints: %ld\n",l->totskillpoints); fprintf(f, "skp: %d\n",l->skillpoints); fprintf(f, "contr: %d\n",l->controller); fprintf(f, "hp: %d/%d\n",l->hp, l->maxhp); diff --git a/spell.c b/spell.c index f81f25d..226a521 100644 --- a/spell.c +++ b/spell.c @@ -580,16 +580,54 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef int i; cell_t fakecell; map_t fakemap; - createfakes(&fakemap, &fakecell); + char obname[BUFLEN]; + int donesomething = B_TRUE; + int ncooked = 0; - if (!isplayer(user)) { - return B_TRUE; - } + if (!isplayer(user)) return B_TRUE; if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) { if (isplayer(user)) msg("You can't cook while swimming!"); return B_TRUE; } + while (donesomething) { + object_t *corpse = NULL; + donesomething = B_FALSE; + // anything here to cook? + for (o = user->cell->obpile->first ; o ; o = o->next) { + if (iscorpse(o) && !hasflag(o->flags, F_PREPARED)) { + char yn; + char ques[BUFLEN]; + getobname(o, obname, o->amt); + sprintf(ques, "There %s %s here. Cook it?", (o->amt == 1) ? "is" : "are",obname); + yn = askchar(ques, "yn","n", B_TRUE, B_FALSE); + if (yn == 'y') { + corpse = o; + break; + } + } + } + + if (corpse) { + preparecorpse(user, corpse); + donesomething = B_TRUE; + ncooked++; + corpse = NULL; + } + } // end while donesomething + + if (ncooked) { + if (ncooked > 1) { + // takes longer + taketime(user, getactspeed(user) * (ncooked-1)); + } + return B_FALSE; + } + + // didn't cook anything from the ground? + // make recipes. + createfakes(&fakemap, &fakecell); + longdesc = malloc(HUGEBUFLEN * sizeof(char)); initprompt(&prompt, "What will you cook (ESC to cancel)?"); for (rec = firstrecipe ; rec ; rec = rec->next ) { @@ -2164,57 +2202,6 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // this call will also remove this ability... setrace(user, f->val[0], B_TRUE); - } else if (abilid == OT_A_PREPARECORPSE) { - object_t *o,*corpse = NULL; - char obname[BUFLEN]; - int donesomething = B_TRUE; - int ncooked = 0; - if (!isplayer(user)) return B_TRUE; - - while (donesomething) { - donesomething = B_FALSE; - // anything here to cook? - for (o = user->cell->obpile->first ; o ; o = o->next) { - if (iscorpse(o) && !hasflag(o->flags, F_PREPARED)) { - char yn; - char ques[BUFLEN]; - getobname(o, obname, o->amt); - sprintf(ques, "There %s %s here. Prepare it?", (o->amt == 1) ? "is" : "are",obname); - yn = askchar(ques, "yn","n", B_TRUE, B_FALSE); - if (yn == 'y') { - corpse = o; - break; - } - } - } - - if (corpse) { - preparecorpse(user, corpse); - donesomething = B_TRUE; - ncooked++; - corpse = NULL; - } - } // end while donesomething - - // didn't cook anything from the ground? - // check inventory. - if (!ncooked) { - initprompt(&prompt, "What will you prepare (ESC to cancel)?"); - for (o = user->pack->first ; o ; o = o->next) { - if (iscorpse(o) && !hasflag(o->flags, F_PREPARED)) { - getobname(o, obname, o->amt); - addchoice(&prompt, o->letter, obname, NULL, o, NULL); - } - } - addchoice(&prompt, '-', "(cancel)", NULL, NULL, NULL); - getchoice(&prompt); - corpse = (object_t *)prompt.result; - if (corpse) preparecorpse(user, corpse); - } - if (ncooked > 1) { - // takes longer - taketime(user, getactspeed(user) * (ncooked-1)); - } } else if (abilid == OT_A_PRAY) { lifeform_t *lf; if (!isplayer(user)) return B_FALSE; @@ -4608,6 +4595,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (haslos(player, targcell)) { if (seenbyplayer) *seenbyplayer = B_TRUE; } + } else if (spellid == OT_S_EQANDOP) { + flag_t *f; + f = addtempflag(caster->flags, F_REFLECTION, B_TRUE, NA, NA, NULL, FROMSPELL); + f->obfrom = spellid; + if (seenbyplayer) *seenbyplayer = B_TRUE; } else if (spellid == OT_S_EVAPORATE) { cell_t *cell[MAXCANDIDATES]; int i,ncells; @@ -5924,24 +5916,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ object_t *o; int donesomething = B_FALSE; - // create icicle - o = addob(targcell->obpile, "huge icicle"); - if (o) { - flag_t *f; - if (haslos(player, targcell)) { - drawscreen(); - msg("A massive icicle rises from the ground!"); - if (seenbyplayer) *seenbyplayer = B_TRUE; - } - f = hasflag(o->flags, F_OBHP); - if (f) { - f->val[0] = 3+power; - f->val[1] = 3+power; - } - addflag(o->flags, F_OBHPDRAIN, 1, DT_MELT, NA, NULL); - - donesomething = B_TRUE; - } + if (haslos(player, targcell)) { + msg("A massive icicle rises from the ground!"); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + // note: we don't actually create the icicle yet, because "getrandomadjcell" will fail + // for cells which contain impassable objects (ie. the icicle). + // knock lfs away if (targcell->lf) { @@ -5957,11 +5938,29 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ getlfname(targcell->lf, lfname); msg("%s is impaled by an icicle!", lfname); } - losehp(targcell->lf, roll("3d6"), DT_PIERCE, caster, "impalement on an icicle"); + losehp(targcell->lf, rolldie(3,power), DT_PIERCE, caster, "impalement on an icicle"); } donesomething = B_TRUE; } + // NOW create the icicle + o = addob(targcell->obpile, "huge icicle"); + if (o) { + flag_t *f; + f = hasflag(o->flags, F_OBHP); + if (f) { + f->val[0] = 3+power; + f->val[1] = 3+power; + } + addflag(o->flags, F_OBHPDRAIN, 1, DT_MELT, NA, NULL); + + donesomething = B_TRUE; + } else { + if (haslos(player, targcell)) { + msg("The icicle vanishes."); + } + } + if (!donesomething) { fizzle(caster); return B_FALSE; @@ -6236,6 +6235,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ fizzle(caster); } } else if (spellid == OT_S_ACCELMETAL) { + char oidbuf[BUFLEN]; + flag_t *f; if (!targob) { // ask for an object targob = askobject(caster->pack, "Fire which object", NULL, AO_NONE); @@ -6253,7 +6254,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_TRUE; } + sprintf(oidbuf, "%ld", targob->id); + f = addflag(caster->flags, F_THROWING, B_TRUE, NA, NA, oidbuf); if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE; + killflagsofid(caster->flags, F_THROWING); // 5 is the same as AT_VHIGH strength // 10 = gun speed @@ -8716,11 +8720,16 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // if no target cell, ask where to throw object if (!targcell) { char obname[BUFLEN],buf2[BUFLEN]; + char oidbuf[BUFLENSMALL]; getobname(targob, obname, 1); snprintf(buf, BUFLEN, "Where will you throw %s to?", obname); // TODO: start trail from the object snprintf(buf2, BUFLEN, "Telekinesis->%s->",obname); + + sprintf(oidbuf, "%ld", targob->id); + addflag(caster->flags, F_THROWING, B_TRUE, NA, NA, oidbuf); targcell = askcoords(buf, buf2,TT_MONSTER | TT_PLAYER, caster, UNLIMITED, LOF_DONTNEED, B_FALSE); + killflagsofid(caster->flags, F_THROWING); } // not liftable? @@ -9246,6 +9255,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } + } else if (spellid == OT_S_WHATGOESUP) { + if (isplayer(caster)) { + msg("A positive gravity field forms around you!"); + } else if (cansee(player, caster)) { + msg("A positive gravity field forms around %s!", castername); + } + if (seenbyplayer) *seenbyplayer = B_TRUE; } else if (spellid == OT_S_WINDSHIELD) { flag_t *f; // always targetted at caster @@ -9737,6 +9753,45 @@ enum SKILL getschoolskill(enum SPELLSCHOOL ss) { return SK_NONE; } +// returns the spellschool associated with the given skill +enum SPELLSCHOOL getskillschool(enum SKILL skid) { + switch (skid) { + case SK_SS_ALLOMANCY: + return SS_ALLOMANCY; + case SK_SS_AIR: + return SS_AIR; + case SK_SS_DEATH: + return SS_DEATH; + case SK_SS_DIVINATION: + return SS_DIVINATION; + case SK_SS_ENCHANTMENT: + return SS_ENCHANTMENT; + case SK_SS_NATURE: + return SS_NATURE; + case SK_SS_FIRE: + return SS_FIRE; + case SK_SS_COLD: + return SS_COLD; + case SK_SS_GRAVITY: + return SS_GRAVITY; + case SK_SS_LIFE: + return SS_LIFE; + case SK_SS_MODIFICATION: + return SS_MODIFICATION; + case SK_SS_MENTAL: + return SS_MENTAL; + case SK_SS_SUMMONING: + return SS_SUMMONING; + case SK_SS_TRANSLOCATION: + return SS_TRANSLOCATION; + case SK_SS_WILD: + return SS_WILD; + default: + break; + } + return SS_NONE; +} + // returns "x MP" or "x-y MP", or "x-y MP, ongoing" ect char *getspellcosttext(lifeform_t *lf, enum OBTYPE spellid, int power, char *buf) { objecttype_t *ot; diff --git a/spell.h b/spell.h index 89fa335..cd75739 100644 --- a/spell.h +++ b/spell.h @@ -16,6 +16,7 @@ enum OBTYPE getrandomspell(int maxlev); enum OBTYPE getrandomspellfromschool(enum SPELLSCHOOL school, int wantlev); enum SPELLSCHOOL getrandomspellschool(void); enum SKILL getschoolskill(enum SPELLSCHOOL ss); +enum SPELLSCHOOL getskillschool(enum SKILL skid); char *getspellcosttext(lifeform_t *lf, enum OBTYPE spellid, int power, char *buf); int getspellduration(int min,int max,int blessed); int getspelllevel(enum OBTYPE spellid); diff --git a/text.c b/text.c index 8bd6ee6..64bb13b 100644 --- a/text.c +++ b/text.c @@ -102,6 +102,8 @@ char *construct_hit_string(lifeform_t *lf, lifeform_t *victim, char *attackernam char withwep[BUFLEN]; char *verb; int needfree = B_FALSE; + int knownnodam = B_FALSE; + int col; strcpy(extradambuf, ""); @@ -116,6 +118,7 @@ char *construct_hit_string(lifeform_t *lf, lifeform_t *victim, char *attackernam if (!victim || getlorelevel(lf, victim->race->raceclass->id)) { //strcpy(extradambuf, " but do no damage"); strcpy(extradambuf, " ineffectually"); + knownnodam = B_TRUE; } } else if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT) ) { snprintf(extradambuf, BUFLEN, " [%d dmg]",dam); @@ -136,7 +139,14 @@ char *construct_hit_string(lifeform_t *lf, lifeform_t *victim, char *attackernam verb = getattackverb(lf, wep, damtype, pctof(10, maxhp), maxhp); } } - snprintf(retbuf, BUFLEN, "^%cYou %s%s %s%s%s%s", fatal ? 'g' : 'n', + if (knownnodam) { + col = C_GREY; + } else if (fatal) { + col = C_GREEN; + } else { + col = C_BROWN; // normal hit + } + snprintf(retbuf, BUFLEN, "^%dYou %s%s %s%s%s%s", col, usecrittext ? "critically " : "", verb, usecrittext ? victimbpname : victimname, withwep,extradambuf, (fatal || backstab) ? "!" : "."); @@ -150,6 +160,7 @@ char *construct_hit_string(lifeform_t *lf, lifeform_t *victim, char *attackernam char attackverb[BUFLEN]; char nodamstr[BUFLEN]; int nodam = B_FALSE; + int col; // capitalise first letter strcpy(buf, attackername); @@ -168,7 +179,13 @@ char *construct_hit_string(lifeform_t *lf, lifeform_t *victim, char *attackernam } else { strcpy(nodamstr, ""); } - snprintf(retbuf, BUFLEN, "^%c%s %s%s%s %s%s%s.", (victim && isplayer(victim) && !nodam) ? 'b' : 'n', buf, + + if (victim && isplayer(victim) && !nodam) { + col = C_YELLOW; + } else { + col = C_GREY; + } + snprintf(retbuf, BUFLEN, "^%d%s %s%s%s %s%s%s.", col, buf, usecrittext ? "critically " : "", attackverb, needses(attackverb) ? "es" : "s", usecrittext ? victimbpname : victimname,withwep, nodamstr); @@ -907,6 +924,19 @@ char *getrarityname(enum RARITY rr) { return "?unknownrarity?"; } +char *getreldirname(int reldir) { + switch (reldir) { + case RD_FORWARDS: + return "forwards"; + case RD_BACKWARDS: + return "backwards"; + case RD_SIDEWAYS: + return "sideways"; + default: break; + } + return "away"; +} + char *getsizetext(enum LFSIZE sz) { switch (sz) { case SZ_MAX: @@ -1042,6 +1072,27 @@ int isvowel (char c) { return B_FALSE; } +// return text for player's F_GUNTARGET flag eg. "goblin [acc:50%]" +void makegunaimstring(lifeform_t *lf, int lfid, char *retbuf) { + char accbuf[BUFLEN]; + char targname[BUFLEN]; + flag_t *f; + lifeform_t *targ; + targ = findlf(lf->cell->map, lfid); + if (!targ) { + strcpy(retbuf, ""); + return; + } + + getlfname(targ, targname); + + f = addflag(lf->flags, F_THROWING, B_TRUE, NA, NA, NULL); + makethrowaccstring(lf, targ->cell, f, accbuf); + killflagsofid(lf->flags, F_THROWING); + + sprintf(retbuf, "%s %s", noprefix(targname), accbuf); +} + char *makekillertext(char *retbuf, char *killverb, char *lastdam, int wantextra) { char *p, *dummy; p = strtok_r(lastdam,"^", &dummy); @@ -1156,6 +1207,30 @@ char *makeplural(char *text) { return newtext; } +// throwflag should be either a F_THROWING or a F_FIRING flag. +char *makethrowaccstring(lifeform_t *lf, cell_t *c, flag_t *throwflag, char *retbuf) { + object_t *o = NULL, *gun = NULL; + int acc = 0; + strcpy(retbuf, ""); + if (strlen(throwflag->text)) { + // get the object being thrown + o = findobbyid(lf->pack, atol(throwflag->text)); + } else { // ie. firing a gun + gun = getfirearm(lf); + if (!gun) return NULL; + o = getammo(gun); + } + if (!o) return NULL; + + acc = getmissileaccuracy(lf, c, o, gun, lfhasflag(player, F_TKTHROW)) ; + if (lfhasflag(lf, F_EXTRAINFO)) { + sprintf(retbuf, "^%d [acc:%d%%]^n", getpctcol(acc,100), acc); + } else { + sprintf(retbuf, "^%d [acc:%c]^n", getpctcol(acc,100), getpctletter(acc,100)); + } + return retbuf; +} + char *makeuppercase(char *text) { if (strlen(text) > 0) { char *p; diff --git a/text.h b/text.h index b6fc851..35e9ce3 100644 --- a/text.h +++ b/text.h @@ -27,6 +27,7 @@ char *getinjuredbpname(enum BODYPART bp); char *getinjuryname(enum DAMTYPE dt); char *getinjurydesc(enum BODYPART bp, enum DAMTYPE dt); char *getrarityname(enum RARITY rr); +char *getreldirname(int reldir); char *getsizetext(enum LFSIZE sz); char *gettimetext(char *retbuf); char *gettimetextfuzzy(char *retbuf, int wantpm); @@ -34,8 +35,10 @@ char *getwaterdepthname(enum DEPTH d); char *getweighttext(float weight, char *buf, int shortfmt); char *is(lifeform_t *lf); int isvowel(char c); +void makegunaimstring(lifeform_t *lf, int lfid, char *retbuf); char *makekillertext(char *retbuf, char *killverb, char *lastdam, int wantextra); char *makeplural(char *text); +char *makethrowaccstring(lifeform_t *lf, cell_t *c, flag_t *throwflag, char *retbuf); char *makeuppercase(char *text); char *makewearstring(lifeform_t *lf, object_t *o, int wantyour, char *posbuf); char *makewearstringsingle(lifeform_t *lf, flag_t *f, char *yourbuf, char *posbuf);