1216 lines
33 KiB
C
1216 lines
33 KiB
C
/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */
|
|
/* aux2.c */
|
|
/* some functions called by ocom.c, also see aux1.c and aux3.c*/
|
|
/* This is a real grab bag file. It contains functions used by
|
|
aux1.c and omega.c, as well as elsewhere. It is mainly here so aux1.c
|
|
and aux3.c are not huge */
|
|
|
|
#include "glob.h"
|
|
|
|
/* Player stats like str, agi, etc give modifications to various abilities
|
|
chances to do things, etc. Positive is good, negative bad. */
|
|
int statmod(int stat)
|
|
{
|
|
return((stat-10)/2);
|
|
}
|
|
|
|
|
|
/* effects of hitting */
|
|
void p_hit (struct monster *m,int dmg,int dtype)
|
|
{
|
|
int dmult = 0;
|
|
|
|
/* chance for critical hit..., 3/10 */
|
|
switch (random_range(10)) {
|
|
case 0:
|
|
if (random_range(100) < (Player.level
|
|
#ifdef INCLUDE_MONKS
|
|
+ Player.rank[MONKS]
|
|
#endif
|
|
)) {
|
|
strcpy(Str3,"You annihilate ");
|
|
dmult = 1000;
|
|
}
|
|
else {
|
|
strcpy(Str3,"You blast ");
|
|
dmult=5;
|
|
}
|
|
break;
|
|
case 1:
|
|
case 2:
|
|
strcpy(Str3,"You smash ");
|
|
dmult=2; break;
|
|
|
|
default:
|
|
dmult=1;
|
|
if (random_range(10)) strcpy(Str3,"You hit ");
|
|
#ifdef NEW_QUOTES
|
|
else switch(random_range(12)) {
|
|
#else
|
|
else switch(random_range(4)) {
|
|
#endif
|
|
case 0: strcpy(Str3,"You damage "); break;
|
|
case 1: strcpy(Str3,"You inflict bodily harm on "); break;
|
|
case 2: strcpy(Str3,"You injure "); break;
|
|
case 3: strcpy(Str3,"You molest "); break;
|
|
case 4: strcpy(Str3,"You tweak "); break;
|
|
case 5: strcpy(Str3,"You smush "); break;
|
|
case 6: strcpy(Str3,"You smurf "); break;
|
|
case 7: strcpy(Str3,"You grind "); break;
|
|
case 8: strcpy(Str3,"You hurt "); break;
|
|
case 9: strcpy(Str3,"You bring pain to "); break;
|
|
case 10: strcpy(Str3,"You recite nasty poetry at "); break;
|
|
case 11: strcpy(Str3,"You smack "); break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (Lunarity == 1) dmult = dmult * 2;
|
|
else if (Lunarity == -1) dmult = dmult / 2;
|
|
if (m->uniqueness == COMMON) strcat(Str3,"the ");
|
|
strcat(Str3,m->monstring);
|
|
strcat(Str3,". ");
|
|
if (Verbosity != TERSE) mprint(Str3);
|
|
else mprint("You hit it.");
|
|
|
|
#ifdef INCLUDE_MONKS
|
|
if (Player.possessions[O_WEAPON_HAND] == NULL) { /*barehanded*/
|
|
if (Player.rank[MONKS] > MONK_MASTER_SIGHS) {
|
|
/* high level monks do unstoppable hand damage */
|
|
dtype = UNSTOPPABLE;
|
|
}
|
|
}
|
|
#endif
|
|
m_damage(m,dmult * random_range(dmg),dtype);
|
|
if ((Verbosity != TERSE) && (random_range(10)==3) && (m->hp > 0))
|
|
mprint("It laughs at the injury and fights on!");
|
|
}
|
|
|
|
/* and effects of missing */
|
|
void player_miss(struct monster *m,int dtype)
|
|
{
|
|
if (random_range(30)==1) /* fumble 1 in 30 */
|
|
p_fumble(dtype);
|
|
else {
|
|
if (Verbosity != TERSE) {
|
|
if (random_range(10))
|
|
strcpy(Str3,"You miss ");
|
|
else switch(random_range(4)) {
|
|
case 0: strcpy(Str3,"You flail lamely at "); break;
|
|
case 1: strcpy(Str3,"You only amuse "); break;
|
|
case 2: strcpy(Str3,"You fail to even come close to "); break;
|
|
case 3: strcpy(Str3,"You totally avoid contact with "); break;
|
|
}
|
|
if (m->uniqueness == COMMON) strcat(Str3,"the ");
|
|
strcat(Str3,m->monstring);
|
|
strcat(Str3,". ");
|
|
mprint(Str3);
|
|
}
|
|
else mprint("You missed it.");
|
|
}
|
|
}
|
|
|
|
/* oh nooooo, a fumble.... */
|
|
void p_fumble(int dtype)
|
|
{
|
|
mprint("Ooops! You fumbled....");
|
|
switch(random_range(10)) {
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5: drop_weapon(); break;
|
|
case 6:
|
|
case 7:
|
|
case 8: break_weapon(); break;
|
|
case 9: mprint("Oh No! You hit yourself!");
|
|
p_damage(Player.dmg,dtype,"stupidity");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* try to drop a weapon (from fumbling) */
|
|
void drop_weapon(void)
|
|
{
|
|
if (Player.possessions[O_WEAPON_HAND] != NULL) {
|
|
strcpy(Str1,"You dropped your ");
|
|
strcat(Str1,Player.possessions[O_WEAPON_HAND]->objstr);
|
|
mprint(Str1);
|
|
morewait();
|
|
p_drop_at(Player.x,Player.y,1,Player.possessions[O_WEAPON_HAND]);
|
|
conform_lost_objects(1,Player.possessions[O_WEAPON_HAND]);
|
|
}
|
|
else mprint("You feel fortunate.");
|
|
}
|
|
|
|
|
|
/* try to break a weapon (from fumbling) */
|
|
void break_weapon(void)
|
|
{
|
|
if (Player.possessions[O_WEAPON_HAND] != NULL) {
|
|
strcpy(Str1,"Your ");
|
|
strcat(Str1,itemid(Player.possessions[O_WEAPON_HAND]));
|
|
strcat(Str1," vibrates in your hand....");
|
|
mprint(Str1);
|
|
(void) damage_item(Player.possessions[O_WEAPON_HAND]);
|
|
morewait();
|
|
}
|
|
}
|
|
|
|
|
|
/* hooray */
|
|
void p_win(void)
|
|
{
|
|
morewait();
|
|
clearmsg();
|
|
print1("You won!");
|
|
morewait();
|
|
display_win();
|
|
endgraf();
|
|
exit(0);
|
|
}
|
|
|
|
|
|
/* handle a h,j,k,l, etc., to change x and y by dx and dy */
|
|
/* for targeting in dungeon */
|
|
void movecursor(int *x, int *y, int dx, int dy)
|
|
{
|
|
if (inbounds(*x+dx,*y+dy)) {
|
|
*x += dx;
|
|
*y += dy;
|
|
screencheck(*x,*y);
|
|
}
|
|
omshowcursor(*x,*y);
|
|
}
|
|
|
|
|
|
/* is Player immune to damage type dtype */
|
|
int p_immune(int dtype)
|
|
{
|
|
return(Player.immunity[dtype]>0);
|
|
}
|
|
|
|
|
|
/* deal with each possible stati -- values are per move */
|
|
/* this function is executed every move */
|
|
/* A value over 1000 indicates a permanent effect */
|
|
void minute_status_check(void)
|
|
{
|
|
int i;
|
|
|
|
if (Player.status[HASTED]>0) {
|
|
if (Player.status[HASTED] < 1000) {
|
|
Player.status[HASTED]--;
|
|
if (Player.status[HASTED]==0) {
|
|
mprint("The world speeds up.");
|
|
calc_melee();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (Player.status[POISONED]>0) {
|
|
Player.status[POISONED]--;
|
|
p_damage(3,POISON,"poison");
|
|
if (Player.status[POISONED] == 0) {
|
|
showflags();
|
|
mprint("You feel better now.");
|
|
}
|
|
}
|
|
|
|
|
|
if (Player.immunity[UNSTOPPABLE]>0) {
|
|
for(i=0;i<NUMIMMUNITIES;i++)
|
|
Player.immunity[i]--;
|
|
if (Player.immunity[UNSTOPPABLE]==1)
|
|
mprint("You feel vincible again.");
|
|
}
|
|
|
|
|
|
if (Player.status[IMMOBILE]>0) {
|
|
Player.status[IMMOBILE]--;
|
|
if (Player.status[IMMOBILE] == 0)
|
|
mprint("You can move again.");
|
|
}
|
|
|
|
|
|
if (Player.status[SLEPT]>0) {
|
|
Player.status[SLEPT]--;
|
|
if (Player.status[SLEPT] == 0) {
|
|
mprint("You woke up.");
|
|
}
|
|
}
|
|
|
|
if (Player.status[REGENERATING]>0) {
|
|
if ((Player.hp < Player.maxhp) && (Player.mana > 0)){
|
|
Player.hp++;
|
|
Player.mana--;
|
|
dataprint();
|
|
}
|
|
if (Player.status[REGENERATING] < 1000) {
|
|
Player.status[REGENERATING]--;
|
|
if (Player.status[REGENERATING] == 0) {
|
|
mprint("You feel less homeostatic.");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Player.status[SLOWED]>0) {
|
|
if (Player.status[SLOWED] < 1000) {
|
|
Player.status[SLOWED]--;
|
|
if (Player.status[SLOWED] == 0) {
|
|
mprint("You feel quicker now.");
|
|
calc_melee();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Player.status[RETURNING]>0) {
|
|
Player.status[RETURNING]--;
|
|
if (Player.status[RETURNING] == 10)
|
|
mprint("Your return spell slowly hums towards activation...");
|
|
else if (Player.status[RETURNING] == 8)
|
|
mprint("There is an electric tension in the air!");
|
|
else if (Player.status[RETURNING] == 5)
|
|
mprint("A vortex of mana begins to form around you!");
|
|
else if (Player.status[RETURNING] == 1)
|
|
mprint("Your surroundings start to warp and fade!");
|
|
if (Player.status[RETURNING] == 0)
|
|
level_return();
|
|
}
|
|
|
|
if (Player.status[AFRAID]>0) {
|
|
if (Player.status[AFRAID] < 1000) {
|
|
Player.status[AFRAID]--;
|
|
if (Player.status[AFRAID] == 0) {
|
|
mprint("You feel bolder now.");
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* effect of gamma ray radiation... */
|
|
void moon_check(void)
|
|
{
|
|
/* 24 day lunar cycle */
|
|
Phase = (Phase+1)%24;
|
|
phaseprint();
|
|
Lunarity = 0;
|
|
if (((Player.patron == DRUID) && ((Phase/2 == 3) || (Phase/2 == 9))) ||
|
|
((Player.alignment > 10) && (Phase/2 == 6)) ||
|
|
((Player.alignment < -10) && (Phase/2 == 0))) {
|
|
mprint("As the moon rises you feel unusually vital!");
|
|
Lunarity = 1;
|
|
}
|
|
else
|
|
if (((Player.patron == DRUID) && ((Phase/2 == 0) || (Phase/2 == 6))) ||
|
|
((Player.alignment > 10) && (Phase/2 == 0)) ||
|
|
((Player.alignment < -10) && (Phase/2 == 6))) {
|
|
mprint("The rise of the moon tokens a strange enervation!");
|
|
Lunarity = -1;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check 1/hour for torch to burn out if used */
|
|
void torch_check(void)
|
|
{
|
|
int i;
|
|
for(i=O_READY_HAND;i<=O_WEAPON_HAND;i++) {
|
|
if (Player.possessions[i]!=NULL)
|
|
if ((Player.possessions[i]->id == OB_TORCH) && /*torch */
|
|
(Player.possessions[i]->aux > 0)) {
|
|
Player.possessions[i]->aux--;
|
|
if (Player.possessions[i]->aux==0) {
|
|
mprint("Your torch goes out!!!");
|
|
conform_unused_object(Player.possessions[i]);
|
|
if (Player.possessions[i]->number > 1) {
|
|
Player.possessions[i]->number--;
|
|
Player.possessions[i]->aux = 6;
|
|
}
|
|
else {
|
|
Player.possessions[i]->usef = I_NO_OP;
|
|
Player.possessions[i]->cursestr =
|
|
Player.possessions[i]->truename =
|
|
Player.possessions[i]->objstr = "burnt-out torch";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* values are in multiples of ten minutes */
|
|
/* values over 1000 indicate a permanent effect */
|
|
void tenminute_status_check(void)
|
|
{
|
|
if ((Player.status[SHADOWFORM]>0) && (Player.status[SHADOWFORM]<1000)) {
|
|
Player.status[SHADOWFORM]--;
|
|
if (Player.status[SHADOWFORM] == 0) {
|
|
Player.immunity[NORMAL_DAMAGE]--;
|
|
Player.immunity[ACID]--;
|
|
Player.immunity[THEFT]--;
|
|
Player.immunity[INFECTION]--;
|
|
mprint("You feel less shadowy now.");
|
|
}
|
|
}
|
|
|
|
if ((Player.status[ILLUMINATION]>0) && (Player.status[ILLUMINATION]<1000)) {
|
|
Player.status[ILLUMINATION]--;
|
|
if (Player.status[ILLUMINATION] == 0) {
|
|
mprint("Your light goes out!");
|
|
}
|
|
}
|
|
|
|
|
|
if ((Player.status[VULNERABLE]>0) && (Player.status[VULNERABLE]<1000)){
|
|
Player.status[VULNERABLE]--;
|
|
if (Player.status[VULNERABLE] == 0)
|
|
mprint("You feel less endangered.");
|
|
}
|
|
|
|
|
|
if ((Player.status[DEFLECTION]>0) && (Player.status[DEFLECTION]<1000)){
|
|
Player.status[DEFLECTION]--;
|
|
if (Player.status[DEFLECTION] == 0)
|
|
mprint("You feel less well defended.");
|
|
}
|
|
|
|
if ((Player.status[ACCURATE]>0) && (Player.status[ACCURACY]<1000)){
|
|
Player.status[ACCURATE]--;
|
|
if (Player.status[ACCURATE] == 0) {
|
|
calc_melee();
|
|
mprint("The bulls' eyes go away.");
|
|
}
|
|
}
|
|
if ((Player.status[HERO]>0) && (Player.status[HERO]<1000)){
|
|
Player.status[HERO]--;
|
|
if (Player.status[HERO] == 0) {
|
|
calc_melee();
|
|
mprint("You feel less than super.");
|
|
}
|
|
}
|
|
|
|
if ((Player.status[LEVITATING]>0) && (Player.status[LEVITATING]<1000)){
|
|
Player.status[LEVITATING]--;
|
|
if (Player.status[LEVITATING] == 0)
|
|
mprint("You're no longer walking on air.");
|
|
}
|
|
|
|
if (Player.status[DISEASED]>0) {
|
|
Player.status[DISEASED]--;
|
|
if (Player.status[DISEASED] == 0) {
|
|
showflags();
|
|
mprint("You feel better now.");
|
|
}
|
|
}
|
|
|
|
|
|
if ((Player.status[INVISIBLE] > 0) && (Player.status[INVISIBLE]<1000)){
|
|
Player.status[INVISIBLE]--;
|
|
if (Player.status[INVISIBLE] == 0)
|
|
mprint("You feel more opaque now.");
|
|
}
|
|
|
|
if ((Player.status[BLINDED]>0) && (Player.status[BLINDED]<1000)) {
|
|
Player.status[BLINDED]--;
|
|
if (Player.status[BLINDED] == 0)
|
|
mprint("You can see again.");
|
|
}
|
|
|
|
if ((Player.status[TRUESIGHT]>0) && (Player.status[TRUESIGHT]<1000)) {
|
|
Player.status[TRUESIGHT]--;
|
|
if (Player.status[TRUESIGHT] == 0)
|
|
mprint("You feel less keen now.");
|
|
}
|
|
|
|
if ((Player.status[BERSERK]>0) && (Player.status[BERSERK]<1000)) {
|
|
Player.status[BERSERK]--;
|
|
if (Player.status[BERSERK] == 0)
|
|
mprint("You stop foaming at the mouth.");
|
|
}
|
|
|
|
if ((Player.status[ALERT]>0) && (Player.status[ALERT] < 1000)) {
|
|
Player.status[ALERT]--;
|
|
if (Player.status[ALERT] == 0)
|
|
mprint("You feel less alert now.");
|
|
}
|
|
|
|
if ((Player.status[BREATHING]>0) && (Player.status[BREATHING] < 1000)) {
|
|
Player.status[BREATHING]--;
|
|
if (Player.status[BREATHING] == 0)
|
|
mprint("You feel somewhat congested.");
|
|
}
|
|
|
|
if ((Player.status[DISPLACED]>0) && (Player.status[DISPLACED] < 1000)) {
|
|
Player.status[DISPLACED]--;
|
|
if (Player.status[DISPLACED]==0)
|
|
mprint("You feel a sense of position.");
|
|
}
|
|
timeprint();
|
|
dataprint();
|
|
}
|
|
|
|
|
|
|
|
/* Increase in level at appropriate experience gain */
|
|
void gain_level(void)
|
|
{
|
|
int gained=FALSE;
|
|
int hp_gain; /* FIXED! 12/30/98 */
|
|
|
|
if (gamestatusp(SUPPRESS_PRINTING))
|
|
return;
|
|
while (expval(Player.level+1) <= Player.xp) {
|
|
if (!gained)
|
|
morewait();
|
|
gained = TRUE;
|
|
Player.level++;
|
|
print1("You have attained a new experience level!");
|
|
print2("You are now ");
|
|
nprint2(getarticle(levelname(Player.level)));
|
|
nprint2(levelname(Player.level));
|
|
hp_gain = random_range(Player.con)+1; /* start fix 12/30/98 */
|
|
if (Player.hp < Player.maxhp )
|
|
Player.hp += hp_gain*Player.hp/Player.maxhp;
|
|
else if (Player.hp < Player.maxhp + hp_gain)
|
|
Player.hp = Player.maxhp + hp_gain;
|
|
/* else leave current hp alone */
|
|
Player.maxhp += hp_gain;
|
|
Player.maxmana = calcmana();
|
|
/* If the character was given a bonus, let him keep it. Otherwise
|
|
* recharge him. */
|
|
Player.mana = max(Player.mana, Player.maxmana); /* end fix 12/30/98 */
|
|
morewait();
|
|
}
|
|
if (gained) clearmsg();
|
|
calc_melee();
|
|
}
|
|
|
|
/* experience requirements */
|
|
long expval(plevel)
|
|
int plevel;
|
|
{
|
|
switch(plevel) {
|
|
case 0:return(0L);
|
|
case 1:return(20L);
|
|
case 2:return(50L);
|
|
case 3:return(200L);
|
|
case 4:return(500L);
|
|
case 5:return(1000L);
|
|
case 6:return(2000L);
|
|
case 7:return(3000L);
|
|
case 8:return(5000L);
|
|
case 9:return(7000L);
|
|
case 10:return(10000L);
|
|
default:
|
|
if (plevel < 20)
|
|
return((plevel-9) * 10000L);
|
|
else
|
|
return((plevel-9) * 10000L +
|
|
(plevel-19)*(plevel-19)*500);
|
|
}
|
|
}
|
|
|
|
/* If an item is unidentified, it isn't worth much to those who would buy it */
|
|
long item_value(pob item)
|
|
{
|
|
if (item->known == 0) {
|
|
if (item->objchar == THING) return(1);
|
|
else return(true_item_value(item) / 10);
|
|
}
|
|
else if (item->known == 1) {
|
|
if (item->objchar == THING) return(item->basevalue);
|
|
else return(item->basevalue / 2);
|
|
}
|
|
else return(true_item_value(item));
|
|
}
|
|
|
|
|
|
/* figures value based on item base-value, charge, plus, and blessing */
|
|
long true_item_value(pob item)
|
|
{
|
|
long value = item->basevalue;
|
|
|
|
if (item->objchar == THING) return(item->basevalue);
|
|
else {
|
|
if (item->objchar == STICK) value += value*item->charge/20;
|
|
if (item->plus > -1) value += value*item->plus/4;
|
|
else value /= -item->plus;
|
|
if (item->blessing > 0) value *= 2;
|
|
return((long) value);
|
|
}
|
|
}
|
|
|
|
/* kill off player if he isn't got the "breathing" status */
|
|
void p_drown(void)
|
|
{
|
|
int attempts = 3, i;
|
|
|
|
if (Player.status[BREATHING] > 0)
|
|
mprint("Your breathing is unaffected!");
|
|
else while (Player.possessions[O_ARMOR] ||
|
|
Player.itemweight > ((int) (Player.maxweight / 2))) {
|
|
menuclear();
|
|
switch (attempts--) {
|
|
case 3: print3("You try to hold your breath..."); break;
|
|
case 2: print3("You try to hold your breath... You choke..."); break;
|
|
case 1: print3("You try to hold your breath... You choke... Your lungs fill..."); break;
|
|
case 0: p_death("drowning");
|
|
}
|
|
morewait();
|
|
menuprint("a: Drop an item.\n");
|
|
menuprint("b: Bash an item.\n");
|
|
menuprint("c: Drop your whole pack.\n");
|
|
showmenu();
|
|
switch(menugetc()) {
|
|
case 'a':
|
|
drop();
|
|
if (Level->site[Player.x][Player.y].p_locf == L_WATER && Level->site[Player.x][Player.y].things)
|
|
{
|
|
mprint("It sinks without a trace.");
|
|
free_objlist(Level->site[Player.x][Player.y].things);
|
|
Level->site[Player.x][Player.y].things = NULL;
|
|
}
|
|
break;
|
|
case 'b':
|
|
bash_item();
|
|
break;
|
|
case 'c':
|
|
setgamestatus(SUPPRESS_PRINTING);
|
|
for(i=0;i<MAXPACK;i++) {
|
|
if (Player.pack[i] != NULL) {
|
|
if (Level->site[Player.x][Player.y].p_locf != L_WATER)
|
|
{
|
|
p_drop_at(Player.x,Player.y,Player.pack[i]->number,Player.pack[i]);
|
|
free_obj( Player.pack[i], TRUE );
|
|
} else
|
|
free_obj( Player.pack[i], TRUE );
|
|
}
|
|
Player.pack[i] = NULL;
|
|
}
|
|
if (Level->site[Player.x][Player.y].p_locf == L_WATER)
|
|
mprint("It sinks without a trace.");
|
|
Player.packptr = 0;
|
|
resetgamestatus(SUPPRESS_PRINTING);
|
|
calc_melee();
|
|
break;
|
|
}
|
|
}
|
|
show_screen();
|
|
return;
|
|
}
|
|
|
|
|
|
/* the effect of some weapon on monster m, with dmgmod a bonus to damage */
|
|
void weapon_use(int dmgmod, pob weapon, struct monster *m)
|
|
{
|
|
int aux = (weapon==NULL ? -2 : weapon->aux); /* bare hands */
|
|
switch(aux) {
|
|
case -2: weapon_bare_hands(dmgmod,m); break;
|
|
default:
|
|
case I_NO_OP: weapon_normal_hit(dmgmod,weapon,m); break;
|
|
case I_ACIDWHIP: weapon_acidwhip(dmgmod,weapon,m); break;
|
|
case I_TANGLE: weapon_tangle(dmgmod,weapon,m); break;
|
|
case I_ARROW: weapon_arrow(dmgmod,weapon,m); break;
|
|
case I_BOLT: weapon_bolt(dmgmod,weapon,m); break;
|
|
case I_DEMONBLADE: weapon_demonblade(dmgmod,weapon,m); break;
|
|
case I_LIGHTSABRE: weapon_lightsabre(dmgmod,weapon,m); break;
|
|
case I_MACE_DISRUPT: weapon_mace_disrupt(dmgmod,weapon,m); break;
|
|
case I_VORPAL: weapon_vorpal(dmgmod,weapon,m); break;
|
|
case I_DESECRATE: weapon_desecrate(dmgmod,weapon,m); break;
|
|
case I_FIRESTAR: weapon_firestar(dmgmod,weapon,m); break;
|
|
case I_DEFEND: weapon_defend(dmgmod,weapon,m); break;
|
|
case I_VICTRIX: weapon_victrix(dmgmod,weapon,m); break;
|
|
case I_SCYTHE: weapon_scythe(dmgmod,weapon,m); break;
|
|
}
|
|
}
|
|
|
|
|
|
/* for printing actions in printactions above */
|
|
char *actionlocstr(char dir)
|
|
{
|
|
switch(dir) {
|
|
case 'L': strcpy(Str3,"low."); break;
|
|
case 'C': strcpy(Str3,"center."); break;
|
|
case 'H': strcpy(Str3,"high."); break;
|
|
default: strcpy(Str3,"wildly."); break;
|
|
}
|
|
return(Str3);
|
|
}
|
|
|
|
|
|
/* execute player combat actions versus monster m */
|
|
void tacplayer(struct monster *m)
|
|
{
|
|
int i=0;
|
|
|
|
while (i < strlen(Player.meleestr)) {
|
|
if (m->hp > 0) {
|
|
switch(Player.meleestr[i]) {
|
|
case 't': case 'T':
|
|
if (Player.possessions[O_WEAPON_HAND] == NULL)
|
|
strcpy(Str1,"You punch ");
|
|
else strcpy(Str1,"You thrust ");
|
|
strcat(Str1,actionlocstr(Player.meleestr[i+1]));
|
|
if (Verbosity == VERBOSE) mprint(Str1);
|
|
if (player_hit(2*statmod(Player.dex),Player.meleestr[i+1],m))
|
|
weapon_use(0,Player.possessions[O_WEAPON_HAND],m);
|
|
else player_miss(m,NORMAL_DAMAGE);
|
|
break;
|
|
case 'c': case 'C':
|
|
if (Player.possessions[O_WEAPON_HAND] == NULL)
|
|
strcpy(Str1,"You punch ");
|
|
else if (Player.possessions[O_WEAPON_HAND]->type == CUTTING)
|
|
strcpy(Str1,"You cut ");
|
|
else if (Player.possessions[O_WEAPON_HAND]->type == STRIKING)
|
|
strcpy(Str1,"You strike ");
|
|
else strcpy(Str1,"You attack ");
|
|
strcat(Str1,actionlocstr(Player.meleestr[i+1]));
|
|
if (Verbosity == VERBOSE) mprint(Str1);
|
|
if (player_hit(0,Player.meleestr[i+1],m))
|
|
weapon_use(2*statmod(Player.str),
|
|
Player.possessions[O_WEAPON_HAND],
|
|
m);
|
|
else player_miss(m,NORMAL_DAMAGE);
|
|
break;
|
|
case 'l': case 'L':
|
|
strcpy(Str1,"You lunge ");
|
|
strcat(Str1,actionlocstr(Player.meleestr[i+1]));
|
|
if (Verbosity == VERBOSE) mprint(Str1);
|
|
if (player_hit(Player.level+Player.dex,Player.meleestr[i+1],m))
|
|
weapon_use(Player.level,Player.possessions[O_WEAPON_HAND],m);
|
|
else player_miss(m,NORMAL_DAMAGE);
|
|
break;
|
|
}
|
|
}
|
|
i+=2;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/* checks to see if player hits with hitmod vs. monster m at location hitloc */
|
|
int player_hit(int hitmod, char hitloc, struct monster *m)
|
|
{
|
|
int i=0,blocks=FALSE,goodblocks=0,hit;
|
|
if (m->hp < 1) {
|
|
mprint("Unfortunately, your opponent is already dead!");
|
|
return(FALSE);
|
|
}
|
|
else {
|
|
if (hitloc == 'X') hitloc = random_loc();
|
|
|
|
transcribe_monster_actions(m);
|
|
|
|
while (i<strlen(m->meleestr)) {
|
|
if ((m->meleestr[i] == 'B') || (m->meleestr[i] == 'R')) {
|
|
blocks = TRUE;
|
|
if (hitloc == m->meleestr[i+1])
|
|
goodblocks++;
|
|
}
|
|
i+=2;
|
|
}
|
|
|
|
if (! blocks) goodblocks = -1;
|
|
hit = hitp(Player.hit+hitmod,m->ac+goodblocks*10);
|
|
if ((! hit) && (goodblocks > 0)) {
|
|
if (m->uniqueness == COMMON) {
|
|
strcpy(Str1,"The ");
|
|
strcat(Str1,m->monstring);
|
|
}
|
|
else strcpy(Str1,m->monstring);
|
|
strcat(Str1," blocks it!");
|
|
if (Verbosity == VERBOSE) mprint(Str1);
|
|
}
|
|
return(hit);
|
|
}
|
|
}
|
|
|
|
|
|
/* This function is used to undo all items temporarily, should
|
|
always be used in pairs with on being TRUE and FALSE, and may cause
|
|
anomalous stats and item-usage if used indiscriminately */
|
|
|
|
void toggle_item_use(int on)
|
|
{
|
|
static int used[MAXITEMS];
|
|
int i;
|
|
setgamestatus(SUPPRESS_PRINTING);
|
|
if (on)
|
|
for(i=0;i<MAXITEMS;i++) {
|
|
used[i] = FALSE;
|
|
if (Player.possessions[i] != NULL) {
|
|
if ((used[i] = Player.possessions[i]->used) == TRUE) {
|
|
Player.possessions[i]->used = FALSE;
|
|
item_use(Player.possessions[i]);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for(i=1;i<MAXITEMS;i++)
|
|
if (used[i]) {
|
|
Player.possessions[i]->used = TRUE;
|
|
item_use(Player.possessions[i]);
|
|
}
|
|
calc_melee();
|
|
showflags();
|
|
dataprint();
|
|
timeprint();
|
|
}
|
|
resetgamestatus(SUPPRESS_PRINTING);
|
|
}
|
|
|
|
|
|
void enter_site(Symbol site)
|
|
{
|
|
switch(site) {
|
|
case CITY: change_environment(E_CITY); break;
|
|
case VILLAGE: change_environment(E_VILLAGE); break;
|
|
case CAVES: change_environment(E_CAVES); break;
|
|
case CASTLE: change_environment(E_CASTLE); break;
|
|
case VOLCANO: change_environment(E_VOLCANO); break;
|
|
case TEMPLE: change_environment(E_TEMPLE); break;
|
|
case DRAGONLAIR: change_environment(E_DLAIR); break;
|
|
case STARPEAK: change_environment(E_STARPEAK); break;
|
|
case MAGIC_ISLE: change_environment(E_MAGIC_ISLE); break;
|
|
case PALACE: change_environment(E_PALACE); break;
|
|
default:print3("There's nothing to enter here!"); break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Switches context dungeon/countryside/city, etc */
|
|
void change_environment(char new_environment)
|
|
{
|
|
int i, emerging = FALSE;
|
|
|
|
Player.sx = -1;
|
|
Player.sy = -1; /* reset sanctuary if there was one */
|
|
|
|
/* missing message if gets lost on site... */
|
|
if (gamestatusp(LOST))
|
|
{
|
|
resetgamestatus(LOST); /* in case the player gets lost _on_ a site */
|
|
mprint("You know where you are now."); /* but didn't inform player... DAG */
|
|
}
|
|
|
|
resetgamestatus(FAST_MOVE);
|
|
|
|
Last_Environment = Current_Environment;
|
|
if (Last_Environment == E_COUNTRYSIDE)
|
|
{
|
|
LastCountryLocX = Player.x;
|
|
LastCountryLocY = Player.y;
|
|
}
|
|
|
|
if (((Last_Environment == E_CITY) ||
|
|
(Last_Environment == E_VILLAGE)) &&
|
|
((new_environment == E_MANSION) ||
|
|
(new_environment == E_HOUSE) ||
|
|
(new_environment == E_HOVEL) ||
|
|
(new_environment == E_SEWERS) ||
|
|
(new_environment == E_ARENA)))
|
|
{
|
|
LastTownLocX = Player.x;
|
|
LastTownLocY = Player.y;
|
|
}
|
|
|
|
else if (((Last_Environment == E_MANSION) ||
|
|
(Last_Environment == E_HOUSE) ||
|
|
(Last_Environment == E_HOVEL) ||
|
|
(Last_Environment == E_SEWERS) ||
|
|
(Last_Environment == E_ARENA)) &&
|
|
((new_environment == E_CITY) ||
|
|
(new_environment == E_VILLAGE)))
|
|
{
|
|
setPlayerXY( LastTownLocX, LastTownLocY);
|
|
emerging = TRUE;
|
|
}
|
|
|
|
Current_Environment = new_environment;
|
|
switch (new_environment)
|
|
{
|
|
case E_ARENA:
|
|
setPlayerXY(5, 7);
|
|
setgamestatus(ARENA_MODE);
|
|
load_arena();
|
|
ScreenOffset = 0;
|
|
ScreenXOffset = 0;
|
|
show_screen();
|
|
break;
|
|
|
|
case E_ABYSS:
|
|
setPlayerXY(32, 15);
|
|
load_abyss();
|
|
abyss_file();
|
|
lose_all_items();
|
|
ScreenOffset = 0;
|
|
ScreenXOffset = 0;
|
|
show_screen();
|
|
break;
|
|
|
|
case E_CIRCLE:
|
|
setPlayerXY(32, 14);
|
|
load_circle(TRUE);
|
|
if (Objects[OB_STARGEM].uniqueness == UNIQUE_TAKEN)
|
|
{
|
|
print1("A bemused voice says:");
|
|
print2("'Why are you here? You already have the Star Gem!'");
|
|
morewait();
|
|
}
|
|
else if (Player.rank[CIRCLE] > 0)
|
|
{
|
|
print1("You hear the voice of the Prime Sorceror:");
|
|
print2("'Congratulations on your attainment of the Circle's Demesne.'");
|
|
morewait();
|
|
print1("For the honor of the Circle, you may take the Star Gem");
|
|
print2("and destroy it on the acme of Star Peak.");
|
|
morewait();
|
|
print1("Beware the foul LawBringer who resides there...");
|
|
print2("By the way, some of the members of the Circle seem to");
|
|
morewait();
|
|
print1("have become a bit jealous of your success --");
|
|
print2("I'd watch out for them too if I were you.");
|
|
morewait();
|
|
}
|
|
else if (Player.alignment > 0)
|
|
{
|
|
print1("A mysterious ghostly image materializes in front of you.");
|
|
print2("It speaks: 'Greetings, fellow abider in Law. I am called");
|
|
morewait();
|
|
print1("The LawBringer. If you wish to advance our cause, obtain");
|
|
print2("the mystic Star Gem and return it to me on Star Peak.");
|
|
morewait();
|
|
print1("Beware the power of the evil Circle of Sorcerors and the");
|
|
print2("forces of Chaos which guard the gem.'");
|
|
morewait();
|
|
print1("The strange form fades slowly.");
|
|
morewait();
|
|
}
|
|
ScreenOffset = 0;
|
|
ScreenXOffset = 0;
|
|
show_screen();
|
|
break;
|
|
|
|
case E_COURT:
|
|
setPlayerXY(32, 2);
|
|
LastCountryLocX = 6;
|
|
LastCountryLocY = 1;
|
|
load_court(TRUE);
|
|
ScreenOffset = 0;
|
|
ScreenXOffset = 0;
|
|
show_screen();
|
|
break;
|
|
|
|
case E_MANSION:
|
|
load_house(E_MANSION, TRUE);
|
|
setPlayerXY(2, 8);
|
|
ScreenOffset = 0;
|
|
ScreenXOffset = 0;
|
|
show_screen();
|
|
break;
|
|
|
|
case E_HOUSE:
|
|
load_house(E_HOUSE, TRUE);
|
|
setPlayerXY(2, 13);
|
|
ScreenOffset = 0;
|
|
ScreenXOffset = 0;
|
|
show_screen();
|
|
break;
|
|
|
|
case E_HOVEL:
|
|
load_house(E_HOVEL, TRUE);
|
|
setPlayerXY(2, 9);
|
|
ScreenOffset = 0;
|
|
ScreenXOffset = 0;
|
|
show_screen();
|
|
break;
|
|
|
|
case E_DLAIR:
|
|
setPlayerXY(0, 8);
|
|
load_dlair(gamestatusp(KILLED_DRAGONLORD), TRUE);
|
|
ScreenOffset = 0;
|
|
ScreenXOffset = 0;
|
|
show_screen();
|
|
break;
|
|
|
|
case E_STARPEAK:
|
|
setPlayerXY(2, 9);
|
|
load_speak(gamestatusp(KILLED_LAWBRINGER), TRUE);
|
|
ScreenOffset = 0;
|
|
ScreenXOffset = 0;
|
|
show_screen();
|
|
break;
|
|
|
|
case E_MAGIC_ISLE:
|
|
setPlayerXY(62, 14);
|
|
load_misle(gamestatusp(KILLED_EATER), TRUE);
|
|
ScreenOffset = 0;
|
|
ScreenXOffset = 0;
|
|
show_screen();
|
|
break;
|
|
|
|
case E_TEMPLE:
|
|
load_temple(Country[Player.x][Player.y].aux, TRUE);
|
|
setPlayerXY(32, 15);
|
|
ScreenOffset = 0;
|
|
ScreenXOffset = 0;
|
|
show_screen();
|
|
break;
|
|
|
|
case E_CITY:
|
|
if (emerging) {
|
|
print1("You emerge onto the street.");
|
|
emerging = FALSE;
|
|
}
|
|
else {
|
|
print1("You pass through the massive gates of Rampart, the city.");
|
|
setPlayerXY(62, 20);
|
|
}
|
|
if (City == NULL) load_city(TRUE);
|
|
#ifdef SAVE_LEVELS
|
|
else
|
|
msdos_changelevel(Level,new_environment,0);
|
|
#endif
|
|
Level = City;
|
|
ScreenOffset = Player.y - (ScreenLength/2);
|
|
ScreenXOffset =Player.x - (ScreenWidth/2);
|
|
screencheck(Player.x, Player.y);
|
|
show_screen();
|
|
break;
|
|
case E_VILLAGE:
|
|
if (!emerging) {
|
|
/* different villages per different locations */
|
|
switch(Country[Player.x][Player.y].aux) {
|
|
case VIL_STARVIEW:
|
|
setPlayerXY( 0, 6 );
|
|
Villagenum = VIL_STARVIEW;
|
|
break;
|
|
default:
|
|
print3("Very strange, a nonexistent village.");
|
|
case VIL_WOODMERE:
|
|
setPlayerXY( 39, 15 );
|
|
Villagenum = VIL_WOODMERE;
|
|
break;
|
|
case VIL_STORMWAT:
|
|
setPlayerXY( 63, 8 );
|
|
Villagenum = VIL_STORMWAT;
|
|
break;
|
|
case VIL_THAUMARI:
|
|
setPlayerXY( 32, 15 );
|
|
Villagenum = VIL_THAUMARI;
|
|
break;
|
|
case VIL_SKORCH:
|
|
setPlayerXY( 2, 8 );
|
|
Villagenum = VIL_SKORCH;
|
|
break;
|
|
case VIL_WHORFEN:
|
|
setPlayerXY( 2, 2 );
|
|
Villagenum = VIL_WHORFEN;
|
|
break;
|
|
}
|
|
}
|
|
if ((! emerging) || (TempLevel == NULL)) load_village(Villagenum, TRUE);
|
|
else if (TempLevel->environment != E_VILLAGE) load_village(Villagenum, TRUE);
|
|
#ifndef SAVE_LEVELS
|
|
else Level = TempLevel;
|
|
#else
|
|
else {
|
|
msdos_changelevel(Level,new_environment,0);
|
|
Level = TempLevel;
|
|
}
|
|
#endif
|
|
if (emerging) {
|
|
print1("You emerge onto the street.");
|
|
emerging = FALSE;
|
|
}
|
|
else
|
|
print1("You enter a small rural village.");
|
|
ScreenOffset = 0;
|
|
ScreenXOffset = 0;
|
|
show_screen();
|
|
break;
|
|
case E_CAVES:
|
|
print1("You enter a dark cleft in a hillside;");
|
|
print2("You note signs of recent passage in the dirt nearby.");
|
|
if (gamestatusp(MOUNTED)) {
|
|
morewait();
|
|
print1("Seeing as you might not be coming back, you feel compelled");
|
|
print2("to let your horse go, rather than keep him hobbled outside.");
|
|
resetgamestatus(MOUNTED);
|
|
calc_melee();
|
|
}
|
|
MaxDungeonLevels = CAVELEVELS;
|
|
if (Current_Dungeon != E_CAVES) {
|
|
#ifdef SAVE_LEVELS
|
|
msdos_changelevel(Level,0,-1);
|
|
#endif
|
|
free_dungeon();
|
|
Dungeon = NULL;
|
|
Level = NULL;
|
|
Current_Dungeon = E_CAVES;
|
|
}
|
|
change_level(0,1,FALSE);
|
|
break;
|
|
case E_VOLCANO:
|
|
print1("You pass down through the glowing crater.");
|
|
if (gamestatusp(MOUNTED)) {
|
|
morewait();
|
|
print1("Seeing as you might not be coming back, you feel compelled");
|
|
print2("to let your horse go, rather than keep him hobbled outside.");
|
|
resetgamestatus(MOUNTED);
|
|
calc_melee();
|
|
}
|
|
MaxDungeonLevels = VOLCANOLEVELS;
|
|
if (Current_Dungeon != E_VOLCANO) {
|
|
#ifdef SAVE_LEVELS
|
|
msdos_changelevel(Level,0,-1);
|
|
#endif
|
|
free_dungeon();
|
|
Dungeon = NULL;
|
|
Level = NULL;
|
|
Current_Dungeon = E_VOLCANO;
|
|
}
|
|
change_level(0,1,FALSE);
|
|
break;
|
|
case E_ASTRAL:
|
|
print1("You are in a weird flickery maze.");
|
|
if (gamestatusp(MOUNTED)) {
|
|
print2("Your horse doesn't seem to have made it....");
|
|
resetgamestatus(MOUNTED);
|
|
calc_melee();
|
|
}
|
|
MaxDungeonLevels = ASTRALLEVELS;
|
|
if (Current_Dungeon != E_ASTRAL) {
|
|
#ifdef SAVE_LEVELS
|
|
msdos_changelevel(Level,0,-1);
|
|
#endif
|
|
free_dungeon();
|
|
Dungeon = NULL;
|
|
Level = NULL;
|
|
Current_Dungeon = E_ASTRAL;
|
|
}
|
|
change_level(0,1,FALSE);
|
|
break;
|
|
case E_CASTLE:
|
|
print1("You cross the drawbridge. Strange forms move beneath the water.");
|
|
if (gamestatusp(MOUNTED)) {
|
|
morewait();
|
|
print1("Seeing as you might not be coming back, you feel compelled");
|
|
print2("to let your horse go, rather than keep him hobbled outside.");
|
|
resetgamestatus(MOUNTED);
|
|
}
|
|
MaxDungeonLevels = CASTLELEVELS;
|
|
if (Current_Dungeon != E_CASTLE) {
|
|
#ifdef SAVE_LEVELS
|
|
msdos_changelevel(Level,0,-1);
|
|
#endif
|
|
free_dungeon();
|
|
Dungeon = NULL;
|
|
Level = NULL;
|
|
Current_Dungeon = E_CASTLE;
|
|
}
|
|
change_level(0,1,FALSE);
|
|
break;
|
|
case E_SEWERS:
|
|
print1("You pry open a manhole and descend into the sewers below.");
|
|
if (gamestatusp(MOUNTED)) {
|
|
print2("You horse waits patiently outside the sewer entrance....");
|
|
dismount_steed();
|
|
}
|
|
MaxDungeonLevels = SEWERLEVELS;
|
|
if (Current_Dungeon != E_SEWERS) {
|
|
#ifdef SAVE_LEVELS
|
|
msdos_changelevel(Level,0,-1);
|
|
#endif
|
|
free_dungeon();
|
|
Dungeon = NULL;
|
|
Level = NULL;
|
|
Current_Dungeon = E_SEWERS;
|
|
}
|
|
change_level(0,1,FALSE);
|
|
break;
|
|
case E_COUNTRYSIDE:
|
|
print1("You return to the fresh air of the open countryside.");
|
|
if (Last_Environment == E_CITY) {
|
|
setPlayerXY(27,19);
|
|
}
|
|
else {
|
|
setPlayerXY(LastCountryLocX,LastCountryLocY);
|
|
}
|
|
for(i=0;i<9;i++)
|
|
c_set(Player.x+Dirs[0][i], Player.y+Dirs[1][i], SEEN);
|
|
ScreenOffset = Player.y - (ScreenLength/2);
|
|
/* ScreenXOffset = Player.x - (ScreenWidth/2); PGM*/
|
|
show_screen();
|
|
break;
|
|
case E_TACTICAL_MAP:
|
|
print1("You are now on the tactical screen; exit off any side to leave");
|
|
make_country_screen(Country[Player.x][Player.y].current_terrain_type);
|
|
make_country_monsters(Country[Player.x][Player.y].current_terrain_type);
|
|
setPlayerXY( Level->level_width/2, Level->level_length/2 );
|
|
|
|
/* This should be altered to use setPlayerXY(x,y) PGM */
|
|
|
|
while (Level->site[Player.x][Player.y].locchar == WATER) {
|
|
if (Player.y < Level->level_length/2 + 5)
|
|
Player.y++;
|
|
else if (Player.x > Level->level_width/2 - 10) {
|
|
Player.x--;
|
|
Player.y = Level->level_length/2 - 5;
|
|
}
|
|
else {
|
|
Level->site[Player.x][Player.y].locchar =
|
|
Level->site[Player.x][Player.y].showchar = FLOOR;
|
|
Level->site[Player.x][Player.y].p_locf = L_NO_OP;
|
|
}
|
|
}
|
|
ScreenOffset = 0;
|
|
ScreenXOffset = 0;
|
|
show_screen();
|
|
break;
|
|
case E_PALACE:
|
|
print1("You enter the dungeons of the ruined palace.");
|
|
if (gamestatusp(MOUNTED)) {
|
|
morewait();
|
|
print1("Seeing as you might not be coming back, you feel compelled");
|
|
print2("to let your horse go, rather than keep him hobbled outside.");
|
|
resetgamestatus(MOUNTED);
|
|
}
|
|
MaxDungeonLevels = PALACELEVELS;
|
|
if (Current_Dungeon != E_PALACE) {
|
|
#ifdef SAVE_LEVELS
|
|
msdos_changelevel(Level,0,-1);
|
|
#endif
|
|
free_dungeon();
|
|
Dungeon = NULL;
|
|
Level = NULL;
|
|
Current_Dungeon = E_PALACE;
|
|
}
|
|
change_level(0,1,FALSE);
|
|
break;
|
|
case E_NEVER_NEVER_LAND: default:
|
|
print1("There must be some mistake. You don't look like Peter Pan.");
|
|
print2("(But here you are in Never-Never Land)");
|
|
ScreenOffset = Player.y - (ScreenLength/2);
|
|
ScreenXOffset = Player.x - (ScreenWidth/2);
|
|
show_screen();
|
|
break;
|
|
}
|
|
setlastxy(Player.x, Player.y);
|
|
if (Current_Environment != E_COUNTRYSIDE)
|
|
showroom(Level->site[Player.x][Player.y].roomnumber);
|
|
else
|
|
terrain_check(FALSE);
|
|
}
|