- [+] climbing
- [+] climb "into"walls - [+] stopclimbing(int onpurpose) - [+] can we move forwards? - [+] if not: - [+] if onpurpose, fail - [+] otherwise fall onto whoever is there??? or they block you from falling?? - [+] move forwards - [+] kill f_climbing flag - [+] startclimbing() - [+] move onto the wall - [+] set your facing to face away from the wall. - [+] add F_CLIMBING - [+] must pass a CLIMB check first or you fail to climb! - [+] can't climb if burdened - [+] once climbing: - [+] can't cast spells - [+] cannot change facing - [+] always strafe if you go sideways - [+] change los functions to let you see out! - [+] different move verb ("climb" instead of move/fly) - [+] different canmove() code - [+] you can only move sideways (along the wall) or forwards (off the wall) - [+] ie. cellindir(lf, lf->facing) == newcell (forwards) - [+] OR - [+] ie. cellindir(lf, lf->facing + 2 (wrapped)) == newcell (right) - [+] OR - [+] ie. cellindir(lf, lf->facing - 2 (wrapped)) == newcell (left) - [+] AND you can only move sidways if: - [+] the new cell is a wall - [+] the cell in (lf->facing) of the new cell is NOT a wall - [+] if you climb off a wall, tell the player that they stopped climbing - [+] moving while climbing: - [+] must pass a sc_climb skill check to move - [+] costs 1 stamina to move - [+] warn before climbing if your stam == 1 - [+] attacking - [+] large penalty to hit the climber (higher for smaller monstesr) - [+] if monsters miss you and you are climbing, chance they'll give up. - [+] attacking FROM a wall gets a big penalty unless you are very skilled at climbing - [+] startlfturn - [+] lose stam each turn. - [+] if stam drops to 0, you fall off or stop climbing - [+] you fall if burdened - [+] don't regen stam while climing - [+] ai: - [+] monsters won't start targeting lfs who are climbing - [+] monsters don't pay stamina to move while climb - [+] make monsters be able to climb when fleeing - [+] let you climb down holes instead of falling
This commit is contained in:
parent
1222ee9550
commit
06cf19e7c9
39
ai.c
39
ai.c
|
@ -286,7 +286,7 @@ object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra, int *range) {
|
|||
// animal and lower intelligence won't use ranged
|
||||
// attacks.
|
||||
if (db) dblog(".oO { no ranged attack due to low iq. }");
|
||||
*ra = RA_NONE;
|
||||
if (ra) *ra = RA_NONE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -297,8 +297,8 @@ object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra, int *range) {
|
|||
getobname(o, gunname, o->amt);
|
||||
if (db) dblog(".oO { will fire my gun (%s) at target. }",gunname);
|
||||
}
|
||||
*ra = RA_GUN;
|
||||
*range = getfirearmrange(o);
|
||||
if (ra) *ra = RA_GUN;
|
||||
if (range) *range = getfirearmrange(o);
|
||||
return o;
|
||||
}
|
||||
|
||||
|
@ -313,8 +313,8 @@ object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra, int *range) {
|
|||
|
||||
if (db) dblog(".oO { will zap %s instead of moving }", o->type->name);
|
||||
|
||||
*ra = RA_WAND;
|
||||
*range = getvisrange(lf, B_TRUE); // ie unlimited
|
||||
if (ra) *ra = RA_WAND;
|
||||
if (range) *range = getvisrange(lf, B_TRUE); // ie unlimited
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
@ -324,15 +324,15 @@ object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra, int *range) {
|
|||
o = getbestthrowmissile(lf);
|
||||
if (o) {
|
||||
if (db) dblog(".oO { will throw %s at my target }", o->type->name);
|
||||
*ra = RA_THROW;
|
||||
*range = getmaxthrowrange(lf, o);
|
||||
if (ra) *ra = RA_THROW;
|
||||
if (range) *range = getmaxthrowrange(lf, o);
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
if (db) dblog(".oO { found no ranged attack. }");
|
||||
*ra = RA_NONE;
|
||||
*range = 0;
|
||||
if (ra) *ra = RA_NONE;
|
||||
if (range) *range = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1442,15 +1442,27 @@ void aiturn(lifeform_t *lf) {
|
|||
if (lf->los[n] != lf->cell) { // not ourself
|
||||
who = lf->los[n]->lf;
|
||||
if (who && !isdead(who) && !isunconscious(who) && cansee(lf, who)) {
|
||||
int chance = 100;
|
||||
int chance = 100; // chance that we ('lf') will attack 'who'
|
||||
int reachpenalty;
|
||||
// targets sleeping in a tent will probably be ignored
|
||||
if (isresting(lf)) {
|
||||
if (isresting(who)) {
|
||||
object_t *restob;
|
||||
restob = getrestob(who);
|
||||
if (restob && (restob->type->id == OT_TENT)) {
|
||||
chance = 5;
|
||||
}
|
||||
}
|
||||
// will usually ignore targets who we can't reach
|
||||
if (!canreach(lf, who, &reachpenalty)) {
|
||||
if (!aigetrangedattack(lf, NULL, NULL)) { // no ranged attack?
|
||||
// 1 size to small = 53% chance to attack
|
||||
// 1 size to small = 6% chance to attack
|
||||
chance = 100 - (reachpenalty*47);
|
||||
if (db) dblog(".oO { target %d (%s) is %d sizes out of reach. %d%% chance to ignore }",who->id, who->race->name,
|
||||
reachpenalty, reachpenalty*47);
|
||||
}
|
||||
}
|
||||
|
||||
if (pctchance(chance)) {
|
||||
if (lfhasflagval(lf, F_HATESRACE, who->race->id, NA, NA, NULL) ||
|
||||
lfhasflagval(lf, F_HATESRACE, who->race->baseid, NA, NA, NULL) ) {
|
||||
|
@ -1778,6 +1790,11 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
|
|||
if ((ot->id == OT_S_BLINDNESS) && isblind(victim)) {
|
||||
specificcheckok = B_FALSE;
|
||||
}
|
||||
if (ot->id == OT_A_CLIMB) {
|
||||
if (!canclimb(lf, NULL)) {
|
||||
specificcheckok = B_FALSE;
|
||||
}
|
||||
}
|
||||
if (ot->id == OT_A_DISARM) {
|
||||
if (!getweapon(victim)) {
|
||||
specificcheckok = B_FALSE;
|
||||
|
|
41
attack.c
41
attack.c
|
@ -3,6 +3,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "ai.h"
|
||||
#include "attack.h"
|
||||
#include "defs.h"
|
||||
#include "flag.h"
|
||||
|
@ -1146,6 +1147,13 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
// chance that ai will give up if we can't reach the victim
|
||||
if (!isplayer(lf) && !canreach(lf, victim, NULL)) {
|
||||
if (pctchance(90)) {
|
||||
loseaitargets(lf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1956,7 +1964,7 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical)
|
|||
} else if (critical && *critical) {
|
||||
gothit = B_TRUE;
|
||||
} else {
|
||||
enum LFSIZE sizetoreach = SZ_ANY;
|
||||
int reachpenalty = 0;
|
||||
// actually roll...
|
||||
acc = getlfaccuracy(lf, wep);
|
||||
|
||||
|
@ -1977,22 +1985,9 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical)
|
|||
acc += 30;
|
||||
}
|
||||
|
||||
// harder to hit flying/levitating enemies, unless you are
|
||||
// large (ie. tall) enough to reach them.
|
||||
// if you are smaller than "sizetoreach", you get a penalty
|
||||
switch (isairborne(victim)) {
|
||||
case F_FLYING:
|
||||
sizetoreach = SZ_HUGE;
|
||||
break;
|
||||
case F_LEVITATING:
|
||||
sizetoreach = SZ_HUMAN;
|
||||
break;
|
||||
default: sizetoreach = SZ_ANY; break;
|
||||
if (!canreach(lf, victim, &reachpenalty)) {
|
||||
acc -= (15*reachpenalty);
|
||||
}
|
||||
if (sizetoreach != SZ_ANY) {
|
||||
acc -= (15*(sizetoreach - getlfsize(lf)));
|
||||
}
|
||||
|
||||
|
||||
// modify for defender's evasion
|
||||
if (isprone(victim) || !cansee(victim, lf)) {
|
||||
|
@ -2012,6 +2007,20 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical)
|
|||
// modify for lore level
|
||||
if (lorelev != PR_INEPT) lorelev += (lorelev*10);
|
||||
|
||||
// modify for attacking while climbing
|
||||
if (isclimbing(lf)) {
|
||||
switch (getskill(lf, SK_CLIMBING)) {
|
||||
case PR_INEPT: acc -= 100; break;
|
||||
case PR_NOVICE: acc -= 100; break;
|
||||
case PR_BEGINNER: acc -= 75; break;
|
||||
case PR_ADEPT: acc -= 50; break;
|
||||
case PR_SKILLED: acc -= 25; break;
|
||||
case PR_EXPERT: acc -= 10; break;
|
||||
default:
|
||||
case PR_MASTER: break;
|
||||
}
|
||||
}
|
||||
|
||||
limit(&acc, 0, 100);
|
||||
|
||||
//if (aidb) dblog(".oO { my modified chance to hit is %d %% }", acc);
|
||||
|
|
19
data.c
19
data.c
|
@ -164,6 +164,7 @@ void initjobs(void) {
|
|||
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 gold coins");
|
||||
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "3 potions of healing");
|
||||
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 bananas");
|
||||
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "rope");
|
||||
// initial skills
|
||||
addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_NOVICE, NA, NULL);
|
||||
addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_SKILLED, NA, NULL);
|
||||
|
@ -1897,7 +1898,7 @@ void initobjects(void) {
|
|||
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
|
||||
|
||||
///////////////////
|
||||
// death / ncromancy
|
||||
// death / necromancy
|
||||
///////////////////
|
||||
// l1
|
||||
addot(OT_S_STENCH, "stench", "Nauseates the target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
|
||||
|
@ -3082,9 +3083,10 @@ void initobjects(void) {
|
|||
addflag(lastot->flags, F_NEEDSGRAB, B_TRUE, NA, NA, NULL);
|
||||
addot(OT_A_CHECKSTAIRS, "check stairs", "Attempt to determine what lies on the other end of a staircase.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
|
||||
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
|
||||
addot(OT_A_CLIMB, "climb wall", "Climb up a wall to escape your enemies.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
|
||||
addflag(lastot->flags, F_STAMCOST, 2, NA, NA, NULL);
|
||||
addot(OT_A_CLIMB, "climb", "Climb up or down whatever is in front of you (walls or pits).", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
|
||||
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 food and water into a healthy meals.", 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);
|
||||
|
@ -8197,6 +8199,7 @@ void initrace(void) {
|
|||
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL);
|
||||
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
||||
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting
|
||||
addflag(lastrace->flags, F_STARTSKILL, SK_CLIMBING, PR_MASTER, NA, NULL);
|
||||
addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:1;range:4;");
|
||||
addflag(lastrace->flags, F_CASTCHANCE, 60, NA, NA, NULL);
|
||||
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
||||
|
@ -8217,6 +8220,7 @@ void initrace(void) {
|
|||
addflag(lastrace->flags, F_STARTATT, A_AGI, AT_GTAVERAGE, NA, NULL);
|
||||
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
||||
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
||||
addflag(lastrace->flags, F_STARTSKILL, SK_CLIMBING, PR_MASTER, NA, NULL);
|
||||
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
||||
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "5d4+1");
|
||||
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 4, NA, NULL);
|
||||
|
@ -8247,6 +8251,7 @@ void initrace(void) {
|
|||
addflag(lastrace->flags, F_STARTATT, A_AGI, AT_GTAVERAGE, NA, NULL);
|
||||
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
||||
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
||||
addflag(lastrace->flags, F_STARTSKILL, SK_CLIMBING, PR_MASTER, NA, NULL);
|
||||
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
||||
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "4d4+1");
|
||||
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 4, NA, NULL);
|
||||
|
@ -8904,7 +8909,13 @@ void initskills(void) {
|
|||
addskilldesc(SK_CHANNELING, PR_EXPERT, "^gThe power level of wands and scrolls is increased by 8.^n", B_FALSE);
|
||||
addskilldesc(SK_CHANNELING, PR_MASTER, "^gThe power level of wands and scrolls is increased by 10.^n", B_FALSE);
|
||||
addskill(SK_CLIMBING, "Climbing", "Helps you to climb walls, mountains or other terrain.", 50);
|
||||
addskilldesc(SK_CLIMBING, PR_INEPT, "- Increases you chances of successfully climbing by 10% per level.", B_FALSE);
|
||||
addskilldesc(SK_CLIMBING, PR_INEPT, "Increases your chances of successfully climbing by 10% per level.", B_FALSE);
|
||||
addskilldesc(SK_CLIMBING, PR_NOVICE, "You gain the 'climb walls' ability. Cannot attack while climbing.", B_FALSE);
|
||||
addskilldesc(SK_CLIMBING, PR_BEGINNER, "-75% accuracy penalty while climbing.", B_FALSE);
|
||||
addskilldesc(SK_CLIMBING, PR_ADEPT, "-50% accuracy penalty while climbing.", B_FALSE);
|
||||
addskilldesc(SK_CLIMBING, PR_SKILLED, "-25% accuracy penalty while climbing.", B_FALSE);
|
||||
addskilldesc(SK_CLIMBING, PR_EXPERT, "-10% accuracy penalty while climbing.", B_FALSE);
|
||||
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_NOVICE, "^gYou now recognise water and rotting food.^n", B_TRUE);
|
||||
addskilldesc(SK_COOKING, PR_BEGINNER, "^gYou can now recognise all kinds of bad food.^n", B_TRUE);
|
||||
|
|
3
defs.h
3
defs.h
|
@ -2735,6 +2735,8 @@ enum ERROR {
|
|||
E_WALLINWAY = 1,
|
||||
E_LFINWAY,
|
||||
E_NOSPACE,
|
||||
E_BADCLIMBDIR,
|
||||
E_STOPCLIMBING,
|
||||
E_SELNOTHING,
|
||||
E_ALREADYUSING,
|
||||
E_WEARINGSOMETHINGELSE,
|
||||
|
@ -2797,6 +2799,7 @@ enum ERROR {
|
|||
E_PRONE,
|
||||
E_PENTAGRAM,
|
||||
E_SWIMMING,
|
||||
E_CLIMBING,
|
||||
E_DANGEROUS,
|
||||
E_INJURED,
|
||||
};
|
||||
|
|
1
flag.c
1
flag.c
|
@ -420,6 +420,7 @@ int flagcausesstatredraw(lifeform_t *lf, enum FLAG fid) {
|
|||
case F_ASLEEP:
|
||||
case F_ATTRMOD:
|
||||
case F_BLIND:
|
||||
case F_CLIMBING:
|
||||
case F_CONFUSED:
|
||||
case F_DRUNK:
|
||||
case F_EATING:
|
||||
|
|
29
io.c
29
io.c
|
@ -735,7 +735,8 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src
|
|||
|
||||
if (lfhasflag(c->lf, F_CLIMBING)) {
|
||||
if (strlen(extrainfo)) strcat(extrainfo, ", ");
|
||||
strcat(extrainfo, "climbing");
|
||||
strcat(extrainfo, "climbing ");
|
||||
strcat(extrainfo, c->type->name);
|
||||
}
|
||||
|
||||
f = lfhasflag(c->lf, F_ATTACHEDTO);
|
||||
|
@ -5488,16 +5489,17 @@ char *makedesc_skill(enum SKILL skid, char *retbuf, enum SKILLLEVEL levhilite) {
|
|||
for (i = 0; i < sk->nskilldesc; i++) {
|
||||
if (sk->skilldesclev[i] == slev) {
|
||||
if (slev == PR_INEPT) {
|
||||
snprintf(buf, BUFLEN, "%s\n",sk->skilldesctext[i]);
|
||||
// extra blank line after this one
|
||||
snprintf(buf, BUFLEN, "%s\n\n",sk->skilldesctext[i]);
|
||||
} else {
|
||||
int hilitethis = B_FALSE;
|
||||
char atxlevel[BUFLEN];
|
||||
if ((levhilite != PR_INEPT) && (slev == levhilite)) {
|
||||
hilitethis = B_TRUE;
|
||||
}
|
||||
snprintf(buf, BUFLEN, "%sAt %s level%s: %s\n",
|
||||
hilitethis ? "^w" : "",
|
||||
getskilllevelname(sk->skilldesclev[i]),
|
||||
hilitethis ? "^n" : "",
|
||||
snprintf(atxlevel, BUFLEN, "At %s level", getskilllevelname(sk->skilldesclev[i]));
|
||||
snprintf(buf, BUFLEN, "%s%-18s%s: %s\n", // right-align "at xx level"
|
||||
hilitethis ? "^w" : "", atxlevel, hilitethis ? "^n" : "",
|
||||
sk->skilldesctext[i]);
|
||||
}
|
||||
strncat(retbuf, buf, HUGEBUFLEN);
|
||||
|
@ -6055,7 +6057,7 @@ void doenter(lifeform_t *lf) {
|
|||
if (isplayer(lf)) {
|
||||
enterob = hasob(lf->cell->obpile, OT_PORTAL);
|
||||
if (enterob) {
|
||||
usestairs(lf, enterob, B_TRUE);
|
||||
usestairs(lf, enterob, B_TRUE, B_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -6487,7 +6489,7 @@ void dostairs(int dir) {
|
|||
object_t *o;
|
||||
o = hasobwithflagval(player->cell->obpile, F_CLIMBABLE, dir, NA, NA, NULL);
|
||||
if (o) {
|
||||
usestairs(player, o, B_TRUE);
|
||||
usestairs(player, o, B_TRUE, B_FALSE);
|
||||
} else {
|
||||
msg("There are no stairs going %s here!", getdirname(dir));
|
||||
}
|
||||
|
@ -8262,6 +8264,11 @@ void drawstatus(void) {
|
|||
wprintw(statwin, " Swim");
|
||||
unsetcol(statwin, C_BOLDBLUE);
|
||||
}
|
||||
if (isclimbing(player)) {
|
||||
setcol(statwin, C_BOLDBLUE);
|
||||
wprintw(statwin, " Climb");
|
||||
unsetcol(statwin, C_BOLDBLUE);
|
||||
}
|
||||
|
||||
if (isairborne(player)) {
|
||||
if (lfhasflag(player, F_FLYING)) {
|
||||
|
@ -9478,6 +9485,12 @@ void showlfstats(lifeform_t *lf, int showall) {
|
|||
if (f && (f->known)) {
|
||||
wrapprint(mainwin, &y, &x, "%s %s flying. ", you(lf), is(lf));
|
||||
}
|
||||
if (isswimming(lf)) {
|
||||
wrapprint(mainwin, &y, &x, "%s %s swimming. ", you(lf), is(lf));
|
||||
}
|
||||
if (isclimbing(lf)) {
|
||||
wrapprint(mainwin, &y, &x, "%s %s currently climbing. ", you(lf), is(lf));
|
||||
}
|
||||
f = lfhasknownflag(lf, F_PRONE);
|
||||
if (f && (f->known)) {
|
||||
wrapprint(mainwin, &y, &x, "%s %s lying on the ground. ", you(lf), is(lf));
|
||||
|
|
241
lf.c
241
lf.c
|
@ -515,6 +515,10 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) {
|
|||
reason = E_SWIMMING;
|
||||
return B_FALSE;
|
||||
}
|
||||
if (isclimbing(lf)) {
|
||||
reason = E_CLIMBING;
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
reason = E_OK;
|
||||
|
||||
|
@ -586,6 +590,38 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) {
|
|||
return castable;
|
||||
}
|
||||
|
||||
int canclimb(lifeform_t *lf, enum ERROR *reason) {
|
||||
cell_t *cc;
|
||||
cc = getcellindir(lf->cell, lf->facing);
|
||||
if (isclimbing(lf)) {
|
||||
if (reason) *reason = E_CLIMBING;
|
||||
return B_FALSE;
|
||||
} else if (!cc) {
|
||||
if (reason) *reason = E_BADCLIMBDIR;
|
||||
return B_FALSE;
|
||||
} else if (!cc->type->solid) {
|
||||
if (hasobwithflagval(cc->obpile, F_PIT, D_DOWN, NA, NA, NULL)) {
|
||||
// ok
|
||||
} else {
|
||||
if (reason) *reason = E_BADCLIMBDIR;
|
||||
return B_FALSE;
|
||||
}
|
||||
} else if (cc->lf) {
|
||||
if (reason) *reason = E_LFINWAY;
|
||||
return B_FALSE;
|
||||
} else if (isswimming(lf)) {
|
||||
if (reason) *reason = E_SWIMMING;
|
||||
return B_FALSE;
|
||||
} else if (isimmobile(lf)) {
|
||||
if (reason) *reason = E_CANTMOVE;
|
||||
return B_FALSE;
|
||||
} else if (isburdened(lf) || lfhasflag(lf, F_GRAVBOOSTED)) {
|
||||
if (reason) *reason = E_TOOHEAVY;
|
||||
return B_FALSE;
|
||||
}
|
||||
return B_TRUE;
|
||||
}
|
||||
|
||||
int candrink(lifeform_t *lf, object_t *o) {
|
||||
// undead won't drink
|
||||
if (getraceclass(lf) == RC_UNDEAD) {
|
||||
|
@ -869,6 +905,11 @@ int canpush(lifeform_t *lf, object_t *o, int dir) {
|
|||
reason = E_FAILED;
|
||||
return B_FALSE;
|
||||
}
|
||||
if (isswimming(lf) || isclimbing(lf)) {
|
||||
reason = E_FAILED;
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
return B_TRUE;
|
||||
|
||||
}
|
||||
|
@ -887,6 +928,40 @@ int canquaff(lifeform_t *lf, object_t *o) {
|
|||
return B_TRUE;
|
||||
}
|
||||
|
||||
int canreach(lifeform_t *lf, lifeform_t *victim, int *reachpenalty) {
|
||||
enum LFSIZE sizetoreach = SZ_ANY;
|
||||
// harder to hit flying/levitating enemies, unless you are
|
||||
// large (ie. tall) enough to reach them.
|
||||
// if you are smaller than "sizetoreach", you get a penalty
|
||||
if (!isairborne(lf)) {
|
||||
switch (isairborne(victim)) {
|
||||
case F_FLYING:
|
||||
sizetoreach = SZ_HUGE;
|
||||
break;
|
||||
case F_LEVITATING:
|
||||
sizetoreach = SZ_HUMAN;
|
||||
break;
|
||||
default: sizetoreach = SZ_ANY; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sizetoreach == SZ_ANY) {
|
||||
// harder to hit something which is climbing above you
|
||||
if (isclimbing(victim) && !isclimbing(lf)) {
|
||||
if (getskill(lf, SK_CLIMBING) != PR_MASTER) {
|
||||
sizetoreach = SZ_LARGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sizetoreach == SZ_ANY) {
|
||||
if (reachpenalty) *reachpenalty = 0;
|
||||
return B_TRUE;
|
||||
}
|
||||
if (reachpenalty) *reachpenalty = (sizetoreach - getlfsize(lf));
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
int cansee(lifeform_t *viewer, lifeform_t *viewee) {
|
||||
return cansee_real(viewer, viewee, B_TRUE);
|
||||
}
|
||||
|
@ -1264,6 +1339,9 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
|
|||
case E_PRONE:
|
||||
msg("You can't cast spells while prone.");
|
||||
break;
|
||||
case E_CLIMBING:
|
||||
msg("You can't cast spells while climbing.");
|
||||
break;
|
||||
case E_SWIMMING:
|
||||
msg("You can't cast spells while swimming.");
|
||||
break;
|
||||
|
@ -3863,7 +3941,7 @@ int flee(lifeform_t *lf) {
|
|||
// can we flee via stairs?
|
||||
stairs = hasobwithflag(lf->cell->obpile, F_CLIMBABLE);
|
||||
if (stairs) {
|
||||
if (!usestairs(lf, stairs, B_TRUE)) {
|
||||
if (!usestairs(lf, stairs, B_TRUE, B_TRUE)) {
|
||||
if (db) dblog("%s - fleeing via %s", stairs->type->name);
|
||||
return B_TRUE;
|
||||
}
|
||||
|
@ -6229,6 +6307,9 @@ int getmovespeed(lifeform_t *lf) {
|
|||
}
|
||||
|
||||
char *getmoveverb(lifeform_t *lf) {
|
||||
if (lfhasflag(lf, F_CLIMBING)) {
|
||||
return "climb";
|
||||
}
|
||||
if (lfhasflag(lf, F_FLYING)) {
|
||||
return "fly";
|
||||
} else if (lfhasflag(lf, F_LEVITATING)) {
|
||||
|
@ -6244,6 +6325,9 @@ char *getmoveverb(lifeform_t *lf) {
|
|||
}
|
||||
|
||||
char *getmoveverbother(lifeform_t *lf) {
|
||||
if (lfhasflag(lf, F_CLIMBING)) {
|
||||
return "climbs";
|
||||
}
|
||||
if (lfhasflag(lf, F_FLYING)) {
|
||||
return "flies";
|
||||
} else if (lfhasflag(lf, F_LEVITATING)) {
|
||||
|
@ -6276,14 +6360,19 @@ lifeform_t *getnearbypeaceful(lifeform_t *lf) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
char *getpitverb(lifeform_t *lf, int dir, int onpurpose) {
|
||||
char *getpitverb(lifeform_t *lf, int dir, int onpurpose, int climb) {
|
||||
if (lfhasflag(lf, F_FLYING)) {
|
||||
if (isplayer(lf)) return "fly";
|
||||
else return "flies";
|
||||
} else if (onpurpose) { // TODO: check if we are using a rope
|
||||
} else if (onpurpose) {
|
||||
if (dir == D_DOWN) {
|
||||
if (isplayer(lf)) return "jump";
|
||||
else return "jumps";
|
||||
if (climb) {
|
||||
if (isplayer(lf)) return "climb";
|
||||
else return "climbs";
|
||||
} else {
|
||||
if (isplayer(lf)) return "jump";
|
||||
else return "jumps";
|
||||
}
|
||||
} else {
|
||||
if (isplayer(lf)) return "climb";
|
||||
else return "climbs";
|
||||
|
@ -8787,11 +8876,20 @@ int haslof(cell_t *src, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest) {
|
|||
if (newdest) *newdest = cell;
|
||||
}
|
||||
|
||||
// solid cells stop lof
|
||||
// solid cells stop lof UNLESS
|
||||
// - this is our source cell
|
||||
// - there is a lf there and this is our target cell
|
||||
|
||||
if (loftype & LOF_WALLSTOP) {
|
||||
if (cell->type->solid) {
|
||||
reason = E_NOLOF;
|
||||
return B_FALSE;
|
||||
if (i == 0) {
|
||||
// ok
|
||||
} else if (cell->lf && (i == (numpixels-1)) ) {
|
||||
// ok
|
||||
} else {
|
||||
reason = E_NOLOF;
|
||||
return B_FALSE;
|
||||
}
|
||||
}
|
||||
// certain objects block lof
|
||||
blockob = hasobwithflag(cell->obpile, F_BLOCKSLOF);
|
||||
|
@ -8812,10 +8910,12 @@ int haslof(cell_t *src, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest) {
|
|||
}
|
||||
// if lifeforms don't stop lof, this is now a valid cell.
|
||||
// if (!(loftype & LOF_LFSSTOP)) {
|
||||
if (newdest) *newdest = cell;
|
||||
if (newdest) *newdest = cell;
|
||||
// }
|
||||
|
||||
// lifeforms block lof unless they're in our destination
|
||||
// lifeforms block lof unless:
|
||||
// - they're in the first cell (ie the one doing the throwing/firing/shooting/etc)
|
||||
// - they're in our destination
|
||||
if (cell->lf && (!isprone(cell->lf)) && (loftype & LOF_LFSSTOP)) {
|
||||
// if not in first cell...
|
||||
if (i != 0) {
|
||||
|
@ -12278,12 +12378,78 @@ void relinklf(lifeform_t *src, map_t *dst) {
|
|||
sortlf(dst, src);
|
||||
}
|
||||
|
||||
int startclimbing(lifeform_t *lf, cell_t *where) {
|
||||
int dir;
|
||||
dir = getdirtowards(lf->cell, where, lf, B_FALSE, DT_ORTH);
|
||||
movelf(lf, where);
|
||||
setfacing(lf, diropposite(dir));
|
||||
addflag(lf->flags, F_CLIMBING, B_TRUE, NA, NA, NULL);
|
||||
int startclimbing(lifeform_t *lf) {
|
||||
cell_t *where;
|
||||
char lfname[BUFLEN];
|
||||
object_t *pit = NULL;
|
||||
char pitname[BUFLEN];
|
||||
|
||||
getlfname(lf, lfname);
|
||||
|
||||
where = getcellindir(lf->cell, lf->facing);
|
||||
pit = hasobwithflagval(where->obpile, F_PIT, D_DOWN, NA, NA, NULL);
|
||||
if (pit) {
|
||||
getobname(pit, pitname, 1);
|
||||
} else {
|
||||
strcpy(pitname, "");
|
||||
}
|
||||
|
||||
if (pit && isplayer(lf)) {
|
||||
char ques[BUFLEN], ch;
|
||||
sprintf(ques, "Climb down %s?",pitname);
|
||||
|
||||
ch = askchar(ques, "yn","n", B_TRUE, B_FALSE);
|
||||
if (ch != 'y') {
|
||||
msg("Cancelled.");
|
||||
return B_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
taketime(lf, getmovespeed(lf));
|
||||
|
||||
// climbing down a pit?
|
||||
if (pit) {
|
||||
int mod;
|
||||
// move there.
|
||||
movelf(lf, where);
|
||||
// make a skill check.
|
||||
mod = (countadjwalls(where)+1)/2;
|
||||
if (skillcheck(lf, SC_CLIMB, 20, mod)) {
|
||||
// if you pass, safely move down the pit.
|
||||
// usestairs() will announce this.
|
||||
usestairs(lf, pit, B_TRUE, B_TRUE);
|
||||
} else {
|
||||
// you will fall...
|
||||
if (isplayer(lf)) {
|
||||
msg("You lose your footing!");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (skillcheck(lf, SC_CLIMB, getcellclimbdifficulty(where), 0)) {
|
||||
// announce
|
||||
if (isplayer(lf)) {
|
||||
msg("You climb onto %s %s.", needan(where->type->name) ? "an" : "a", where->type->name);
|
||||
} else if (cansee(player, lf)) {
|
||||
if (haslos(player, where)) {
|
||||
msg("%s climbs onto %s %s.", lfname, needan(where->type->name) ? "an" : "a", where->type->name);
|
||||
} else {
|
||||
msg("%s climbs out of view.", lfname);
|
||||
}
|
||||
}
|
||||
// change facing BEFORE moving, so that we don't reveal cells on the other
|
||||
// side of the wall
|
||||
setfacing(lf, diropposite(lf->facing));
|
||||
movelf(lf, where);
|
||||
addflag(lf->flags, F_CLIMBING, B_TRUE, NA, NA, NULL);
|
||||
} else {
|
||||
if (isplayer(lf)) {
|
||||
msg("You try to climb onto %s, but fail.", where->type->name);
|
||||
} else if (cansee(player, lf)) {
|
||||
msg("%s tries to start climbing, but fails.", lfname);
|
||||
}
|
||||
return B_TRUE;
|
||||
}
|
||||
}
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
|
@ -13680,9 +13846,10 @@ void startlfturn(lifeform_t *lf) {
|
|||
// either use up stamina, or gain it
|
||||
if (lfhasflag(lf, F_SPRINTING)) {
|
||||
modstamina(lf, -1.5);
|
||||
} else if (isswimming(lf)) {
|
||||
} else if (isswimming(lf) && isplayer(lf)) {
|
||||
int lossamt;
|
||||
// lose stamina based on swimming skill
|
||||
// players lose stamina based on swimming skill
|
||||
// monsters don't.
|
||||
switch (getskill(lf, SK_SWIMMING)) {
|
||||
case PR_INEPT: lossamt = 3; break;
|
||||
case PR_NOVICE: lossamt = 1; break;
|
||||
|
@ -13693,6 +13860,19 @@ void startlfturn(lifeform_t *lf) {
|
|||
case PR_MASTER: lossamt = 0; break;
|
||||
}
|
||||
if (lossamt) modstamina(lf, -lossamt);
|
||||
} else if (isclimbing(lf) && isplayer(lf)) {
|
||||
int lossamt;
|
||||
// players lose stamina based on climbing skill
|
||||
// monsters don't lose stamina to climb.
|
||||
switch (getskill(lf, SK_CLIMBING)) {
|
||||
case PR_INEPT: lossamt = 2; break;
|
||||
case PR_NOVICE: lossamt = 1; break;
|
||||
case PR_BEGINNER: lossamt = 1; break;
|
||||
case PR_MASTER: lossamt = 0; break;
|
||||
default:
|
||||
lossamt = 0.5; break;
|
||||
}
|
||||
if (lossamt) modstamina(lf, -lossamt);
|
||||
} else {
|
||||
// if we didn't move last turn, regenerate stamina.
|
||||
if (!killflagsofid(lf->flags, F_MOVED)) {
|
||||
|
@ -14040,6 +14220,16 @@ void startlfturn(lifeform_t *lf) {
|
|||
// IMPORTANT: any potentially damaging effects have to go after here...
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// if you run out of stamina while climbing, you fall
|
||||
if (isclimbing(lf)) {
|
||||
if ((getstamina(lf) <= 0) || isburdened(lf) || lfhasflag(lf, F_GRAVBOOSTED)) {
|
||||
stopclimbing(lf, B_FALSE);
|
||||
if (isdead(lf)) return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
f = hasflag(lf->flags, F_POISONED);
|
||||
if (f) {
|
||||
// chance of fighting it off - gets easier over time.
|
||||
|
@ -14531,7 +14721,10 @@ int stopclimbing(lifeform_t *lf, int onpurpose) {
|
|||
}
|
||||
movelf(lf, c);
|
||||
killflagsofid(lf->flags, F_CLIMBING);
|
||||
if (!onpurpose) {
|
||||
if (onpurpose) {
|
||||
if (isplayer(lf)) msg("You drop down to the ground.");
|
||||
taketime(lf, getmovespeed(lf));
|
||||
} else {
|
||||
fall(lf, NULL, B_TRUE);
|
||||
}
|
||||
return B_FALSE;
|
||||
|
@ -14855,7 +15048,7 @@ void timeeffectslf(lifeform_t *lf) {
|
|||
}
|
||||
|
||||
if (willfall) {
|
||||
usestairs(lf, o, B_FALSE);
|
||||
usestairs(lf, o, B_FALSE, B_FALSE);
|
||||
donesomething = B_TRUE;
|
||||
o = hasobwithflagval(lf->cell->obpile, F_PIT, dir, NA, NA, NULL);
|
||||
}
|
||||
|
@ -14893,7 +15086,6 @@ int tryclimb(lifeform_t *lf, cell_t *where, char *towhat) {
|
|||
// train climbing
|
||||
practice(lf, SK_CLIMBING, 1);
|
||||
// continue...
|
||||
|
||||
} else {
|
||||
// you fall.
|
||||
if (isplayer(lf)) {
|
||||
|
@ -15182,7 +15374,7 @@ int useability(lifeform_t *lf, enum OBTYPE aid, lifeform_t *who, cell_t *where)
|
|||
}
|
||||
|
||||
|
||||
int usestairs(lifeform_t *lf, object_t *o, int onpurpose) {
|
||||
int usestairs(lifeform_t *lf, object_t *o, int onpurpose, int climb) {
|
||||
flag_t *f;
|
||||
map_t *curmap;
|
||||
map_t *newmap;
|
||||
|
@ -15261,6 +15453,9 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose) {
|
|||
if (tryclimb(lf, obcell, buf)) {
|
||||
// failed
|
||||
return B_TRUE;
|
||||
} else {
|
||||
// success
|
||||
climb = B_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15280,7 +15475,7 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose) {
|
|||
f = hasflag(o->flags, F_PIT);
|
||||
|
||||
if (isplayer(lf) || cansee(player, lf)) {
|
||||
msg("%s %s %s the %s...", lfname, getpitverb(lf, dir,onpurpose), getdirname(dir), noprefix(obname));
|
||||
msg("%s %s %s the %s...", lfname, getpitverb(lf, dir,onpurpose, climb), getdirname(dir), noprefix(obname));
|
||||
// move cursor to msgwindow while we create the new level...
|
||||
if (isplayer(lf)) wrefresh(msgwin);
|
||||
}
|
||||
|
|
8
lf.h
8
lf.h
|
@ -31,6 +31,7 @@ int calcxprace(enum RACE rid);
|
|||
void callguards(lifeform_t *caller, lifeform_t *victim);
|
||||
int canattack(lifeform_t *lf);
|
||||
int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost);
|
||||
int canclimb(lifeform_t *lf, enum ERROR *reason);
|
||||
int candrink(lifeform_t *lf, object_t *o);
|
||||
int caneat(lifeform_t *lf, object_t *o);
|
||||
int canhear(lifeform_t *lf, cell_t *c, int volume);
|
||||
|
@ -40,6 +41,7 @@ int canpickup(lifeform_t *lf, object_t *o, int amt);
|
|||
int canpolymorphto(enum RACE rid);
|
||||
int canpush(lifeform_t *lf, object_t *o, int dir);
|
||||
int canquaff(lifeform_t *lf, object_t *o);
|
||||
int canreach(lifeform_t *lf, lifeform_t *victim, int *reachpenalty);
|
||||
int cansee(lifeform_t *viewer, lifeform_t *viewee);
|
||||
int cansee_real(lifeform_t *viewer, lifeform_t *viewee, int uselos);
|
||||
int cansleep(lifeform_t *lf);
|
||||
|
@ -179,7 +181,7 @@ int getmovespeed(lifeform_t *lf);
|
|||
char *getmoveverb(lifeform_t *lf);
|
||||
char *getmoveverbother(lifeform_t *lf);
|
||||
lifeform_t *getnearbypeaceful(lifeform_t *lf);
|
||||
char *getpitverb(lifeform_t *lf, int dir, int onpurpose);
|
||||
char *getpitverb(lifeform_t *lf, int dir, int onpurpose, int climb);
|
||||
char *getlfname(lifeform_t *lf, char *buf);
|
||||
char *real_getlfname(lifeform_t *lf, char *buf, int usevis);
|
||||
char *getlfnamea(lifeform_t *lf, char *buf);
|
||||
|
@ -340,7 +342,7 @@ int recruit(lifeform_t *lf);
|
|||
void refreshlevelabilities(lifeform_t *lf);
|
||||
void relinklf(lifeform_t *src, map_t *dst);
|
||||
int rest(lifeform_t *lf, int onpurpose);
|
||||
int startclimbing(lifeform_t *lf, cell_t *where);
|
||||
int startclimbing(lifeform_t *lf);
|
||||
int startresting(lifeform_t *lf, int willtrain);
|
||||
int rollattr(enum ATTRBRACKET bracket);
|
||||
int rollstat(lifeform_t *lf, enum ATTRIB attr);
|
||||
|
@ -389,7 +391,7 @@ void unsummon(lifeform_t *lf, int vanishobs);
|
|||
int unweild(lifeform_t *lf, object_t *o);
|
||||
int useability(lifeform_t *lf, enum OBTYPE aid, lifeform_t *who, cell_t *where);
|
||||
int useringofmiracles(lifeform_t *lf, int charges);
|
||||
int usestairs(lifeform_t *lf, object_t *o, int onpurpose);
|
||||
int usestairs(lifeform_t *lf, object_t *o, int onpurpose, int climb);
|
||||
int validateraces(void);
|
||||
int wear(lifeform_t *lf, object_t *o);
|
||||
int weild(lifeform_t *lf, object_t *o);
|
||||
|
|
14
map.c
14
map.c
|
@ -1288,6 +1288,20 @@ cell_t *getcellat(map_t *map, int x, int y) {
|
|||
return map->cell[y*map->w + x];
|
||||
}
|
||||
|
||||
int getcellclimbdifficulty(cell_t *c) {
|
||||
int diff = 12;
|
||||
switch (c->type->material->id) {
|
||||
case MT_GLASS: diff = 26; break;
|
||||
case MT_DRAGONWOOD: diff = 20; break;
|
||||
case MT_METAL: diff = 20; break;
|
||||
case MT_WAX: diff = 10; break;
|
||||
case MT_WOOD: diff = 8; break;
|
||||
case MT_PLANT: diff = 8; break;
|
||||
default: diff = 12; break;
|
||||
}
|
||||
return diff;
|
||||
}
|
||||
|
||||
int getcelldist(cell_t *src, cell_t *dst) {
|
||||
double xd,yd;
|
||||
// use pythag
|
||||
|
|
1
map.h
1
map.h
|
@ -21,6 +21,7 @@ int fix_reachability(map_t *m);
|
|||
int fix_unreachable_cell(cell_t *badcell);
|
||||
void floodfill(cell_t *startcell);
|
||||
cell_t *getcellat(map_t *map, int x, int y);
|
||||
int getcellclimbdifficulty(cell_t *c);
|
||||
int getcelldist(cell_t *src, cell_t *dst);
|
||||
int getcelldistorth(cell_t *src, cell_t *dst);
|
||||
void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer);
|
||||
|
|
197
move.c
197
move.c
|
@ -291,19 +291,75 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) {
|
|||
if (error) *error = E_OFFMAP;
|
||||
return B_FALSE;
|
||||
}
|
||||
if (cell->type->solid) {
|
||||
// mover is noncorporeal?
|
||||
if (lf && lfhasflag(lf, F_NONCORPOREAL)) {
|
||||
if (error) *error = E_WALLINWAY; // ok but still set reason
|
||||
// ok
|
||||
} else if (cell->lf && (cell->lf != lf)) { // someone (else) in the wall?
|
||||
if (error) *error = E_LFINWAY; // ok but still set reason
|
||||
//return B_FALSE;
|
||||
// ok
|
||||
} else {
|
||||
if (error) *error = E_WALLINWAY;
|
||||
if (lf && isclimbing(lf)) {
|
||||
cell_t *rightcell,*leftcell,*frontcell;
|
||||
int rightdir,leftdir,i;
|
||||
// climbing rules: you can climb into a cell if:
|
||||
// - it is directly to your side
|
||||
// - the target cell (beside you) is a wall
|
||||
// - the cell in FRONT (ie. dir you are facing) of the target cell
|
||||
// is NOT a wall
|
||||
// OR
|
||||
// - it is straight forward (ie. off the wall)
|
||||
rightdir = lf->facing;
|
||||
leftdir = lf->facing;
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (++rightdir > DC_NW) rightdir = DC_N;
|
||||
if (--leftdir < DC_N) leftdir = DC_NW;
|
||||
}
|
||||
rightcell = getcellindir(lf->cell, rightdir);
|
||||
leftcell = getcellindir(lf->cell, leftdir);
|
||||
frontcell = getcellindir(lf->cell, lf->facing);
|
||||
if ((cell != rightcell) && (cell != leftcell) && (cell != frontcell)) {
|
||||
// not left/right/front
|
||||
if (error) *error = E_BADCLIMBDIR;
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
if (cell == frontcell) {
|
||||
// in front
|
||||
if (cell->type->solid) {
|
||||
if (error) *error = E_BADCLIMBDIR;
|
||||
return B_FALSE;
|
||||
} else if (!cell->lf) {
|
||||
// in front and not solid, and no lf there
|
||||
if (error) *error = E_STOPCLIMBING;
|
||||
return B_TRUE;
|
||||
}
|
||||
} else {
|
||||
// to the side
|
||||
if (cell->type->solid) {
|
||||
cell_t *sidefrontcell;
|
||||
sidefrontcell = getcellindir(cell, lf->facing);
|
||||
if (!sidefrontcell || sidefrontcell->type->solid) {
|
||||
// cell in front of target cell is solid
|
||||
if (error) *error = E_BADCLIMBDIR;
|
||||
return B_FALSE;
|
||||
}
|
||||
} else {
|
||||
// to the side and not solid
|
||||
if (error) *error = E_BADCLIMBDIR;
|
||||
return B_FALSE;
|
||||
}
|
||||
}
|
||||
// if okay, now drop through to below code which checks
|
||||
// whether there are any lfs or objects in the way
|
||||
} else {
|
||||
// not climbing
|
||||
if (cell->type->solid) {
|
||||
// mover is noncorporeal?
|
||||
if (lf && lfhasflag(lf, F_NONCORPOREAL)) {
|
||||
if (error) *error = E_WALLINWAY; // ok but still set reason
|
||||
// ok
|
||||
} else if (cell->lf && (cell->lf != lf)) { // someone (else) in the wall?
|
||||
if (error) *error = E_LFINWAY; // ok but still set reason
|
||||
//return B_FALSE;
|
||||
// ok
|
||||
} else {
|
||||
if (error) *error = E_WALLINWAY;
|
||||
return B_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// must check for lf before checking for impassable objects,
|
||||
|
@ -321,6 +377,7 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) {
|
|||
if (error) *error = E_LFINWAY;
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
for (o = cell->obpile->first ; o ; o = o->next) {
|
||||
if (isimpassableob(o, lf)) {
|
||||
if (lf) {
|
||||
|
@ -1395,7 +1452,9 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) {
|
|||
// this is the equivilant of losing the same amount of stamina which we
|
||||
// would regenerate, only it avoids constantly redrawing the status
|
||||
// bar every single move.
|
||||
if (isplayer(lf)) addflag(lf->flags, F_MOVED, B_TRUE, NA, NA, NULL);
|
||||
if (isplayer(lf)) {
|
||||
addflag(lf->flags, F_MOVED, B_TRUE, NA, NA, NULL);
|
||||
}
|
||||
|
||||
if (!onpurpose || !isplayer(lf)) {
|
||||
dontclearmsg = B_TRUE;
|
||||
|
@ -1608,19 +1667,17 @@ int opendoor(lifeform_t *lf, object_t *o) {
|
|||
return B_TRUE;
|
||||
}
|
||||
|
||||
if (!canopendoors(lf)) {
|
||||
if (isplayer(lf)) {
|
||||
msg("You have no hands with which to open the door!");
|
||||
} else {
|
||||
// ai will try to break down doors
|
||||
if (gettargetlf(lf)) {
|
||||
attackcell(lf, doorcell, B_TRUE);
|
||||
return B_FALSE;
|
||||
}
|
||||
if (lf) {
|
||||
if (isclimbing(lf)) {
|
||||
if (isplayer(lf)) msg("You can't open doors while climbing!");
|
||||
return B_TRUE;
|
||||
} else if (isswimming(lf)) {
|
||||
if (isplayer(lf)) msg("You can't open doors while swimming!");
|
||||
return B_TRUE;
|
||||
}
|
||||
return B_TRUE;
|
||||
}
|
||||
|
||||
|
||||
f = hasflag(o->flags, F_OPEN);
|
||||
if (f) {
|
||||
if (lf && isplayer(lf)) {
|
||||
|
@ -1629,6 +1686,19 @@ int opendoor(lifeform_t *lf, object_t *o) {
|
|||
return B_TRUE;
|
||||
} else {
|
||||
if (lf) {
|
||||
if (!canopendoors(lf)) {
|
||||
if (isplayer(lf)) {
|
||||
msg("You have no hands with which to open the door!");
|
||||
} else {
|
||||
// ai will try to break down doors
|
||||
if (gettargetlf(lf)) {
|
||||
attackcell(lf, doorcell, B_TRUE);
|
||||
return B_FALSE;
|
||||
}
|
||||
}
|
||||
return B_TRUE;
|
||||
}
|
||||
|
||||
if (isplayer(lf)) {
|
||||
int dir;
|
||||
cell_t *pastdoorcell;
|
||||
|
@ -1985,6 +2055,28 @@ int initiatemove(lifeform_t *lf, cell_t *cell, int *didmsg) {
|
|||
|
||||
if (cell && cell->lf && !canswapwith(lf, cell->lf)) attacking = B_TRUE;
|
||||
|
||||
// climbing along a wall?
|
||||
if (isplayer(lf) && isclimbing(lf)) {
|
||||
if (cell != getcellindir(lf->cell, lf->facing)) { // not dropping off the wall
|
||||
if (!getstamina(lf)) {
|
||||
// this shouldn't be able to happen, since if you run out
|
||||
// of stamina while on a wall you'll fall off during startlfturn().
|
||||
msg("You are too tired to climb!");
|
||||
reason = E_OK;
|
||||
return B_TRUE;
|
||||
} else {
|
||||
// must pass a skill check to keep climbing!
|
||||
if (!skillcheck(lf, SC_CLIMB, getcellclimbdifficulty(cell), 0)) {
|
||||
msg("You lose your footing!");
|
||||
stopclimbing(lf, B_FALSE);
|
||||
reason = E_OK;
|
||||
return B_TRUE;
|
||||
}
|
||||
modstamina(lf, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// too tired? (if we're attacking, leave the 'too tired' message to
|
||||
// the attack code)
|
||||
if (!attacking && !getstamina(lf)) {
|
||||
|
@ -2391,9 +2483,9 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
|
|||
|
||||
// warn before moving onto dangerous cells
|
||||
if (onpurpose && isplayer(lf) && !lfhasflag(lf, F_SNEAK)) {
|
||||
char ques[BUFLEN];
|
||||
char ch;
|
||||
if (cell && celldangerous(lf, cell, B_TRUE, &errcode)) {
|
||||
char ques[BUFLEN];
|
||||
char ch;
|
||||
if ((errcode == E_AVOIDOB) && rdata) {
|
||||
char obname[BUFLEN];
|
||||
object_t *avoidob;
|
||||
|
@ -2408,6 +2500,13 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
|
|||
return B_TRUE;
|
||||
}
|
||||
}
|
||||
if (isclimbing(lf) && (cell != getcellindir(lf->cell, lf->facing)) && (getstamina(lf) - 1 <= 0)) {
|
||||
snprintf(ques, BUFLEN, "Climbing further will exhaust you - continue?");
|
||||
ch = askchar(ques, "yn","n", B_TRUE, B_FALSE);
|
||||
if (ch != 'y') {
|
||||
return B_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
moveok = B_FALSE;
|
||||
|
@ -2456,29 +2555,33 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
|
|||
}
|
||||
}
|
||||
|
||||
// now move to new cell
|
||||
moveto(lf, cell, rndmove ? B_FALSE : onpurpose, dontclearmsg);
|
||||
if (errcode == E_STOPCLIMBING) {
|
||||
stopclimbing(lf, B_TRUE);
|
||||
} else {
|
||||
// now move to new cell
|
||||
moveto(lf, cell, rndmove ? B_FALSE : onpurpose, dontclearmsg);
|
||||
|
||||
// take some time
|
||||
if (onpurpose) {
|
||||
// strafing sideways/backwards takes longer
|
||||
if (strafe && !lfhasflag(lf, F_AWARENESS)) {
|
||||
switch (reldir) {
|
||||
case RD_SIDEWAYS: howlong = pctof(125, howlong); break;
|
||||
case RD_BACKWARDS: howlong = pctof(150, howlong); break;
|
||||
case RD_FORWARDS:
|
||||
if (hasactivespell(lf, OT_S_TAILWIND)) {
|
||||
// faster
|
||||
howlong = pctof(75, howlong);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
// take some time
|
||||
if (onpurpose) {
|
||||
// strafing sideways/backwards takes longer
|
||||
if (strafe && !lfhasflag(lf, F_AWARENESS)) {
|
||||
switch (reldir) {
|
||||
case RD_SIDEWAYS: howlong = pctof(125, howlong); break;
|
||||
case RD_BACKWARDS: howlong = pctof(150, howlong); break;
|
||||
case RD_FORWARDS:
|
||||
if (hasactivespell(lf, OT_S_TAILWIND)) {
|
||||
// faster
|
||||
howlong = pctof(75, howlong);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
limit(&howlong, SP_GODLIKE, NA);
|
||||
taketime(lf, howlong);
|
||||
if (!rndmove && !strafe) setfacing(lf, dir); // face the way we moved
|
||||
}
|
||||
limit(&howlong, SP_GODLIKE, NA);
|
||||
taketime(lf, howlong);
|
||||
if (!rndmove && !strafe) setfacing(lf, dir); // face the way we moved
|
||||
}
|
||||
|
||||
// attached lfs or lfs you have grabbed will move the same direction if they can
|
||||
|
@ -2534,12 +2637,17 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
|
|||
// train
|
||||
if (isswimming(lf)) {
|
||||
practice(lf, SK_SWIMMING, 1);
|
||||
} else if (isclimbing(lf)) {
|
||||
practice(lf, SK_CLIMBING, 1);
|
||||
}
|
||||
} else { // ie !moveok
|
||||
object_t *inway = NULL;
|
||||
int door, dooropen;
|
||||
reason = errcode;
|
||||
switch (errcode) {
|
||||
case E_BADCLIMBDIR:
|
||||
if (isplayer(lf)) msg("You can't climb in that direction.");
|
||||
break;
|
||||
case E_OFFMAP:
|
||||
if (lf->cell->map->region->rtype->id == RG_WORLDMAP) {
|
||||
// cope with nonorthogonal!
|
||||
|
@ -2586,6 +2694,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
|
|||
}
|
||||
break;
|
||||
case E_DOORINWAY:
|
||||
// can't open doors while climbing
|
||||
inway = (object_t *)rdata;
|
||||
door = isdoor(inway, &dooropen);
|
||||
if (door && !dooropen) {
|
||||
|
|
53
spell.c
53
spell.c
|
@ -555,48 +555,23 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
|
|||
|
||||
taketime(user, getactspeed(user)*2);
|
||||
} else if (abilid == OT_A_CLIMB) {
|
||||
if (lfhasflag(user, F_CLIMBING)) {
|
||||
// stop climbing
|
||||
stopclimbing(user, B_TRUE);
|
||||
taketime(user, getmovespeed(user));
|
||||
return B_FALSE;
|
||||
}
|
||||
|
||||
if (isprone(user)) {
|
||||
if (isplayer(user)) msg("You will need to stand up first!");
|
||||
return B_TRUE;
|
||||
}
|
||||
// ask for direction
|
||||
if (!targcell) {
|
||||
int dirch,dir;
|
||||
dirch = askchar("Climb wall in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE);
|
||||
if ((dirch == '-') || !dirch) {
|
||||
if (isplayer(user)) msg("Cancelled.");
|
||||
return B_TRUE;
|
||||
}
|
||||
dir = chartodir(dirch);
|
||||
if (dir == D_NONE) {
|
||||
targcell = user->cell;
|
||||
} else {
|
||||
targcell = getcellindir(user->cell, dir);
|
||||
enum ERROR why;
|
||||
if (!canclimb(user, &why)) {
|
||||
if (isplayer(user)){
|
||||
switch (why) {
|
||||
case E_CLIMBING: msg("You are already climbing!"); break;
|
||||
case E_CANTMOVE: msg("You can't move!"); break;
|
||||
case E_BADCLIMBDIR: msg("There is no wall to climb in front of you!"); break;
|
||||
case E_LFINWAY: msg("Something is in the way!"); break;
|
||||
case E_SWIMMING: msg("You can't climb while swimming!"); break;
|
||||
case E_TOOHEAVY: msg("Your load is too heavy to climb with!"); break;
|
||||
default: msg("For some reason, you can't climb."); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!targcell) {
|
||||
if (isplayer(user)) msg("Cancelled.");
|
||||
return B_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!targcell->type->solid) {
|
||||
if (isplayer(user)) msg("There is no wall there!");
|
||||
return B_TRUE;
|
||||
}
|
||||
if (targcell->lf) {
|
||||
if (isplayer(user)) msg("There is no wall there!");
|
||||
return B_TRUE;
|
||||
}
|
||||
|
||||
startclimbing(user, targcell);
|
||||
taketime(user, getmovespeed(user));
|
||||
startclimbing(user);
|
||||
} else if (abilid == OT_A_COOK) {
|
||||
object_t *water,*o;
|
||||
race_t *r = NULL;
|
||||
|
|
Loading…
Reference in New Issue