973 lines
28 KiB
C
973 lines
28 KiB
C
|
/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */
|
||
|
/* aux1.c */
|
||
|
/* auxiliary functions for those in com.c, also see aux2.c and aux3.c */
|
||
|
|
||
|
#include "glob.h"
|
||
|
|
||
|
|
||
|
|
||
|
/* check to see if too much tunneling has been done in this level */
|
||
|
void tunnelcheck(void)
|
||
|
{
|
||
|
if ((Level->depth == 0 && Current_Environment != E_DLAIR) ||
|
||
|
Current_Environment == E_ASTRAL)
|
||
|
return;
|
||
|
Level->tunnelled++;
|
||
|
if ((Level->tunnelled) > (Level->level_length)/4)
|
||
|
mprint("Dust and stone fragments fall on you from overhead.");
|
||
|
if ((Level->tunnelled) >(Level->level_length)/2)
|
||
|
mprint("You hear groaning and creaking noises.");
|
||
|
if ((Level->tunnelled) > (3*(Level->level_length))/4)
|
||
|
mprint("The floor trembles and you hear a loud grinding screech.");
|
||
|
if ((Level->tunnelled) > Level->level_length) {
|
||
|
mprint("With a scream of tortured stone, the entire dungeon caves in!!!");
|
||
|
gain_experience(5000);
|
||
|
if (Player.status[SHADOWFORM]) {
|
||
|
change_environment(E_COUNTRYSIDE);
|
||
|
switch (Country[Player.x][Player.y].base_terrain_type)
|
||
|
{
|
||
|
case CASTLE:
|
||
|
case STARPEAK:
|
||
|
case CAVES:
|
||
|
case VOLCANO:
|
||
|
Country[Player.x][Player.y].current_terrain_type = MOUNTAINS;
|
||
|
break;
|
||
|
case DRAGONLAIR:
|
||
|
Country[Player.x][Player.y].current_terrain_type = DESERT;
|
||
|
break;
|
||
|
case MAGIC_ISLE:
|
||
|
Country[Player.x][Player.y].current_terrain_type = CHAOS_SEA;
|
||
|
break;
|
||
|
case PALACE:
|
||
|
Country[Player.x][Player.y].current_terrain_type = JUNGLE;
|
||
|
break;
|
||
|
}
|
||
|
Country[Player.x][Player.y].base_terrain_type =
|
||
|
Country[Player.x][Player.y].current_terrain_type;
|
||
|
c_set(Player.x, Player.y, CHANGED);
|
||
|
print1("In your shadowy state, you float back up to the surface.");
|
||
|
return;
|
||
|
}
|
||
|
mprint("You are flattened into an unpleasant jellylike substance.");
|
||
|
p_death("dungeon cave-in");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* displays a room's name */
|
||
|
void showroom(int i)
|
||
|
{
|
||
|
strcpy(Str1,"");
|
||
|
strcpy(Str2,"");
|
||
|
switch(Current_Environment) {
|
||
|
case E_MANSION:
|
||
|
strcpy(Str2,"A luxurious mansion: ");
|
||
|
break;
|
||
|
case E_HOUSE:
|
||
|
strcpy(Str2,"A house: ");
|
||
|
break;
|
||
|
case E_HOVEL:
|
||
|
strcpy(Str2,"A hovel: ");
|
||
|
break;
|
||
|
case E_CITY:
|
||
|
strcpy(Str2,"The City of Rampart");
|
||
|
break;
|
||
|
case E_VILLAGE:
|
||
|
switch(Villagenum) {
|
||
|
case 1: strcpy(Str2,"The Village of Star View"); break;
|
||
|
case 2: strcpy(Str2,"The Village of Woodmere"); break;
|
||
|
case 3: strcpy(Str2,"The Village of Stormwatch"); break;
|
||
|
case 4: strcpy(Str2,"The Village of Thaumaris"); break;
|
||
|
case 5: strcpy(Str2,"The Village of Skorch"); break;
|
||
|
case 6: strcpy(Str2,"The Village of Whorfen"); break;
|
||
|
}
|
||
|
break;
|
||
|
case E_CAVES:
|
||
|
strcpy(Str2,"The Goblin Caves: ");
|
||
|
break;
|
||
|
case E_CASTLE:
|
||
|
strcpy(Str2,"The Archmage's Castle: ");
|
||
|
break;
|
||
|
case E_ASTRAL:
|
||
|
strcpy(Str2,"The Astral Plane: ");
|
||
|
break;
|
||
|
case E_VOLCANO:
|
||
|
strcpy(Str2,"The Volcano: ");
|
||
|
break;
|
||
|
case E_PALACE:
|
||
|
strcpy(Str2,"The Palace Dungeons: ");
|
||
|
break;
|
||
|
case E_SEWERS:
|
||
|
strcpy(Str2,"The Sewers: ");
|
||
|
break;
|
||
|
case E_TACTICAL_MAP:
|
||
|
strcpy(Str2,"The Tactical Map ");
|
||
|
break;
|
||
|
default:
|
||
|
strcpy(Str2,"");
|
||
|
break;
|
||
|
}
|
||
|
if (Current_Environment == Current_Dungeon) {
|
||
|
strcpy(Str1,"Level ");
|
||
|
if (Level->depth < 10) {
|
||
|
Str1[6] = Level->depth + '0';
|
||
|
Str1[7] = 0;
|
||
|
}
|
||
|
else {
|
||
|
Str1[6] = (Level->depth / 10) + '0';
|
||
|
Str1[7] = (Level->depth % 10) + '0';
|
||
|
Str1[8] = 0;
|
||
|
}
|
||
|
strcat(Str1," (");
|
||
|
strcat(Str1,roomname(i));
|
||
|
strcat(Str1,")");
|
||
|
}
|
||
|
else if (strlen(Str2) == 0 || Current_Environment == E_MANSION ||
|
||
|
Current_Environment == E_HOUSE || Current_Environment == E_HOVEL)
|
||
|
strcpy(Str1,roomname(i));
|
||
|
strcat(Str2,Str1);
|
||
|
locprint(Str2);
|
||
|
}
|
||
|
|
||
|
|
||
|
int player_on_sanctuary(void)
|
||
|
{
|
||
|
if ((Player.x==Player.sx) &&
|
||
|
(Player.y==Player.sy))
|
||
|
return(TRUE);
|
||
|
else {
|
||
|
if (Player.patron) {
|
||
|
if ((Level->site[Player.x][Player.y].locchar == ALTAR) &&
|
||
|
(Level->site[Player.x][Player.y].aux == Player.patron))
|
||
|
return(TRUE);
|
||
|
else return(FALSE);
|
||
|
}
|
||
|
else return(FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* check a move attempt, maybe attack something, return TRUE if ok to move. */
|
||
|
/* x y is the proposed place to move to */
|
||
|
int p_moveable(int x, int y)
|
||
|
{
|
||
|
setgamestatus(SKIP_MONSTERS);
|
||
|
if (! inbounds(x,y)) return (FALSE);
|
||
|
else if (Player.status[SHADOWFORM]) {
|
||
|
switch(Level->site[x][y].p_locf) {
|
||
|
case L_CHAOS: case L_ABYSS: case L_VOID:
|
||
|
return cinema_confirm("That looks dangerous.") == 'y';
|
||
|
default:
|
||
|
resetgamestatus(SKIP_MONSTERS);
|
||
|
return(TRUE);
|
||
|
}
|
||
|
}
|
||
|
else if (loc_statusp(x,y,SECRET)) {
|
||
|
if (!gamestatusp(FAST_MOVE)) print3("Ouch!");
|
||
|
return(FALSE);
|
||
|
}
|
||
|
else if (Level->site[x][y].creature != NULL) {
|
||
|
if (! gamestatusp(FAST_MOVE)) {
|
||
|
fight_monster(Level->site[x][y].creature);
|
||
|
resetgamestatus(SKIP_MONSTERS);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
else return(FALSE);
|
||
|
}
|
||
|
else if ((Level->site[x][y].locchar == WALL) ||
|
||
|
(Level->site[x][y].locchar == STATUE) ||
|
||
|
(Level->site[x][y].locchar == PORTCULLIS) ||
|
||
|
(Level->site[x][y].locchar == CLOSED_DOOR) ||
|
||
|
(gamestatusp(FAST_MOVE) &&
|
||
|
((Level->site[x][y].locchar == HEDGE) ||
|
||
|
(Level->site[x][y].locchar == LAVA) ||
|
||
|
(Level->site[x][y].locchar == ABYSS) ||
|
||
|
(Level->site[x][y].locchar == VOID_CHAR) ||
|
||
|
(Level->site[x][y].locchar == FIRE) ||
|
||
|
(Level->site[x][y].locchar == WHIRLWIND) ||
|
||
|
(Level->site[x][y].locchar == WATER) ||
|
||
|
(Level->site[x][y].locchar == LIFT) ||
|
||
|
(Level->site[x][y].locchar == TRAP)))) {
|
||
|
if (! gamestatusp(FAST_MOVE)) print3("Ouch!");
|
||
|
return(FALSE);
|
||
|
}
|
||
|
else if (optionp(CONFIRM)) {
|
||
|
if ((Level->site[x][y].locchar == HEDGE) ||
|
||
|
(Level->site[x][y].locchar == LAVA) ||
|
||
|
(Level->site[x][y].locchar == FIRE) ||
|
||
|
(Level->site[x][y].locchar == WHIRLWIND) ||
|
||
|
(Level->site[x][y].locchar == ABYSS) ||
|
||
|
(Level->site[x][y].locchar == VOID_CHAR) ||
|
||
|
(Level->site[x][y].locchar == WATER) ||
|
||
|
(Level->site[x][y].locchar == RUBBLE) ||
|
||
|
(Level->site[x][y].locchar == LIFT) ||
|
||
|
(Level->site[x][y].locchar == TRAP)) {
|
||
|
/* horses WILL go into water... */
|
||
|
if (gamestatusp(MOUNTED)) {
|
||
|
if (Level->site[x][y].locchar != WATER ||
|
||
|
Level->site[x][y].p_locf != L_WATER) {
|
||
|
print1("You can't convince your steed to continue.");
|
||
|
setgamestatus(SKIP_MONSTERS);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
else return(TRUE);
|
||
|
}
|
||
|
else if (cinema_confirm("Look where you're about to step!") == 'y') resetgamestatus(SKIP_MONSTERS);
|
||
|
else setgamestatus(SKIP_MONSTERS);
|
||
|
return(!gamestatusp(SKIP_MONSTERS));
|
||
|
}
|
||
|
else {
|
||
|
resetgamestatus(SKIP_MONSTERS);
|
||
|
return(TRUE);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
resetgamestatus(SKIP_MONSTERS);
|
||
|
return(TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* check a move attempt in the countryside */
|
||
|
int p_country_moveable(int x, int y)
|
||
|
{
|
||
|
if (! inbounds(x,y)) return (FALSE);
|
||
|
else if (optionp(CONFIRM)) {
|
||
|
if ((Country[x][y].current_terrain_type == CHAOS_SEA) ||
|
||
|
(Country[x][y].current_terrain_type == MOUNTAINS))
|
||
|
return(cinema_confirm("That's dangerous terrain, and slow going.")=='y');
|
||
|
else return(TRUE);
|
||
|
}
|
||
|
else return(TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* search once particular spot */
|
||
|
void searchat(int x, int y)
|
||
|
{
|
||
|
int i;
|
||
|
if (inbounds(x,y) && (random_range(3) || Player.status[ALERT])) {
|
||
|
if (loc_statusp(x,y,SECRET)) {
|
||
|
lreset(x,y,SECRET);
|
||
|
lset(x, y, CHANGED);
|
||
|
if ((Level->site[x][y].locchar==OPEN_DOOR) ||
|
||
|
(Level->site[x][y].locchar==CLOSED_DOOR)) {
|
||
|
mprint("You find a secret door!");
|
||
|
for(i=0;i<=8;i++) { /* FIXED! 12/25/98 */
|
||
|
lset(x+Dirs[0][i],y+Dirs[1][i],STOPS);
|
||
|
lset(x+Dirs[0][i], y+Dirs[1][i], CHANGED);
|
||
|
}
|
||
|
}
|
||
|
else mprint("You find a secret passage!");
|
||
|
drawvision(Player.x,Player.y);
|
||
|
}
|
||
|
if ((Level->site[x][y].p_locf >= TRAP_BASE) &&
|
||
|
(Level->site[x][y].locchar != TRAP) &&
|
||
|
(Level->site[x][y].p_locf <= TRAP_BASE+NUMTRAPS)) {
|
||
|
Level->site[x][y].locchar = TRAP;
|
||
|
lset(x, y, CHANGED);
|
||
|
mprint("You find a trap!");
|
||
|
drawvision(Player.x,Player.y);
|
||
|
resetgamestatus(FAST_MOVE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* This is to be called whenever anything might change player performance in
|
||
|
melee, such as changing weapon, statistics, etc. */
|
||
|
void calc_melee(void)
|
||
|
{
|
||
|
calc_weight();
|
||
|
|
||
|
Player.maxweight = (Player.str * Player.agi * 10);
|
||
|
Player.absorption = Player.status[PROTECTION];
|
||
|
Player.defense = 2 * statmod(Player.agi)+(Player.level/2);
|
||
|
Player.hit = Player.level + statmod(Player.dex)+1;
|
||
|
Player.dmg = statmod(Player.str)+3;
|
||
|
Player.speed = 5 - min(4,(statmod(Player.agi)/2));
|
||
|
if (Player.status[HASTED] > 0) Player.speed = Player.speed / 2;
|
||
|
if (Player.status[SLOWED] > 0) Player.speed = Player.speed * 2;
|
||
|
if (Player.itemweight > 0)
|
||
|
switch(Player.maxweight / Player.itemweight) {
|
||
|
case 0: Player.speed+=6; break;
|
||
|
case 1: Player.speed+=3; break;
|
||
|
case 2: Player.speed+=2; break;
|
||
|
case 3: Player.speed+=1; break;
|
||
|
}
|
||
|
|
||
|
if (Player.status[ACCURATE]) Player.hit+=20;
|
||
|
if (Player.status[HERO]) Player.hit+=Player.dex;
|
||
|
if (Player.status[HERO]) Player.dmg+=Player.str;
|
||
|
if (Player.status[HERO]) Player.defense+=Player.agi;
|
||
|
if (Player.status[HERO]) Player.speed=Player.speed / 2;
|
||
|
|
||
|
Player.speed = max(1,min(25,Player.speed));
|
||
|
|
||
|
if (gamestatusp(MOUNTED)) {
|
||
|
Player.speed = 3;
|
||
|
Player.hit += 10;
|
||
|
Player.dmg += 10;
|
||
|
}
|
||
|
#ifdef INCLUDE_MONKS
|
||
|
else if (Player.rank[MONKS] > 0)
|
||
|
{
|
||
|
/* monks are faster when not in armor or on horseback */
|
||
|
if (Player.possessions[O_ARMOR] == NULL) {
|
||
|
Player.speed += (min(0,(Player.rank[MONKS] -1)));
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
/* weapon */
|
||
|
/* have to check for used since it could be a 2h weapon just carried
|
||
|
in one hand */
|
||
|
if (Player.possessions[O_WEAPON_HAND] != NULL)
|
||
|
if (Player.possessions[O_WEAPON_HAND]->used &&
|
||
|
((Player.possessions[O_WEAPON_HAND]->objchar==WEAPON)||
|
||
|
(Player.possessions[O_WEAPON_HAND]->objchar==MISSILEWEAPON))) {
|
||
|
Player.hit +=
|
||
|
Player.possessions[O_WEAPON_HAND]->hit +
|
||
|
Player.possessions[O_WEAPON_HAND]->plus;
|
||
|
Player.dmg +=
|
||
|
Player.possessions[O_WEAPON_HAND]->dmg +
|
||
|
Player.possessions[O_WEAPON_HAND]->plus;
|
||
|
}
|
||
|
|
||
|
#ifdef INCLUDE_MONKS
|
||
|
if (Player.rank[MONKS] > 0)
|
||
|
{
|
||
|
/* monks */
|
||
|
/* aren't monks just obscene? PGM */
|
||
|
if (Player.possessions[O_WEAPON_HAND] == NULL) /*barehanded*/
|
||
|
{
|
||
|
/* all monks get a bonus in unarmed combat */
|
||
|
Player.hit += ( Player.rank[MONKS] * Player.level );
|
||
|
Player.dmg += ( Player.rank[MONKS] * Player.level );
|
||
|
Player.defense += ( Player.rank[MONKS] * Player.level );
|
||
|
|
||
|
if (Player.rank[MONKS] == MONK_GRANDMASTER)
|
||
|
{
|
||
|
/* Grandmaster does 3x damage in unarmed combat. */
|
||
|
Player.dmg *= 3;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* shield or defensive weapon */
|
||
|
if (Player.possessions[O_SHIELD] != NULL) {
|
||
|
Player.defense +=
|
||
|
Player.possessions[O_SHIELD]->aux +
|
||
|
Player.possessions[O_SHIELD]->plus;
|
||
|
}
|
||
|
|
||
|
/* armor */
|
||
|
if (Player.possessions[O_ARMOR] != NULL) {
|
||
|
Player.absorption += Player.possessions[O_ARMOR]->dmg;
|
||
|
Player.defense +=
|
||
|
Player.possessions[O_ARMOR]->plus -
|
||
|
Player.possessions[O_ARMOR]->aux;
|
||
|
}
|
||
|
|
||
|
if (strlen(Player.meleestr) > 2*maneuvers())
|
||
|
default_maneuvers();
|
||
|
comwinprint();
|
||
|
showflags();
|
||
|
dataprint();
|
||
|
}
|
||
|
|
||
|
|
||
|
/* player attacks monster m */
|
||
|
void fight_monster(struct monster *m)
|
||
|
{
|
||
|
int hitmod = 0;
|
||
|
int reallyfight = TRUE;
|
||
|
|
||
|
if (Player.status[AFRAID]) {
|
||
|
print3("You are much too afraid to fight!");
|
||
|
reallyfight = FALSE;
|
||
|
}
|
||
|
else if (player_on_sanctuary()) {
|
||
|
print3("You restrain yourself from desecrating this holy place.");
|
||
|
reallyfight = FALSE;
|
||
|
}
|
||
|
else if (Player.status[SHADOWFORM]) {
|
||
|
print3("Your attack has no effect in your shadowy state.");
|
||
|
reallyfight = FALSE;
|
||
|
}
|
||
|
else if ((Player.status[BERSERK]<1) && (! m_statusp(m,HOSTILE))) {
|
||
|
if (optionp(BELLICOSE)) reallyfight = TRUE;
|
||
|
else reallyfight = 'y'==cinema_confirm("You're attacking without provokation.");
|
||
|
}
|
||
|
else reallyfight = TRUE;
|
||
|
|
||
|
if (reallyfight) {
|
||
|
|
||
|
if (Lunarity == 1) hitmod += Player.level;
|
||
|
else if (Lunarity == -1) hitmod -= (Player.level / 2);
|
||
|
|
||
|
if (! m->attacked) Player.alignment -= 2; /* chaotic action */
|
||
|
m_status_set(m,AWAKE);
|
||
|
m_status_set(m,HOSTILE);
|
||
|
m->attacked = TRUE;
|
||
|
Player.hit += hitmod;
|
||
|
tacplayer(m);
|
||
|
Player.hit -= hitmod;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* Attempt to break an object o */
|
||
|
int damage_item(pob o)
|
||
|
{
|
||
|
/* special case -- break star gem */
|
||
|
if (o->id == OB_STARGEM) {
|
||
|
print1("The Star Gem shatters into a million glistening shards....");
|
||
|
if (Current_Environment == E_STARPEAK) {
|
||
|
if (! gamestatusp(KILLED_LAWBRINGER))
|
||
|
print2("You hear an agonizing scream of anguish and despair.");
|
||
|
morewait();
|
||
|
print1("A raging torrent of energy escapes in an explosion of magic!");
|
||
|
print2("The energy flows to the apex of Star Peak where there is");
|
||
|
morewait();
|
||
|
clearmsg();
|
||
|
print1("an enormous explosion!");
|
||
|
morewait();
|
||
|
annihilate(1);
|
||
|
print3("You seem to gain strength in the chaotic glare of magic!");
|
||
|
Player.str = max(Player.str, Player.maxstr + 5); /* FIXED! 12/25/98 */
|
||
|
Player.pow = max(Player.pow, Player.maxpow + 5); /* ditto */
|
||
|
Player.alignment -= 200;
|
||
|
dispose_lost_objects(1,o);
|
||
|
}
|
||
|
else {
|
||
|
morewait();
|
||
|
print1("The shards coalesce back together again, and vanish");
|
||
|
print2("with a muted giggle.");
|
||
|
dispose_lost_objects(1,o);
|
||
|
Objects[o->id].uniqueness = UNIQUE_UNMADE; /* FIXED! 12/30/98 */
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
else {
|
||
|
if (o->fragility < random_range(30)) {
|
||
|
if (o->objchar == STICK && o->charge > 0) {
|
||
|
strcpy(Str1,"Your ");
|
||
|
strcat(Str1,(o->blessing >= 0 ? o->truename : o->cursestr));
|
||
|
strcat(Str1," explodes!");
|
||
|
print1(Str1);
|
||
|
morewait();
|
||
|
nprint1(" Ka-Blamm!!!");
|
||
|
/* general case. Some sticks will eventually do special things */
|
||
|
morewait();
|
||
|
manastorm(Player.x, Player.y, o->charge*o->level*10);
|
||
|
dispose_lost_objects(1,o);
|
||
|
return 1;
|
||
|
}
|
||
|
else if ((o->blessing > 0) && (o->level > random_range(10))) {
|
||
|
strcpy(Str1,"Your ");
|
||
|
strcat(Str1,itemid(o));
|
||
|
strcat(Str1," glows strongly.");
|
||
|
print1(Str1);
|
||
|
return 0;
|
||
|
}
|
||
|
else if ((o->blessing < -1) && (o->level > random_range(10))) {
|
||
|
strcpy(Str1,"You hear an evil giggle from your ");
|
||
|
strcat(Str1,itemid(o));
|
||
|
print1(Str1);
|
||
|
return 0;
|
||
|
}
|
||
|
else if (o->plus > 0) {
|
||
|
strcpy(Str1,"Your ");
|
||
|
strcat(Str1,itemid(o));
|
||
|
strcat(Str1," glows and then fades.");
|
||
|
print1(Str1);
|
||
|
o->plus--;
|
||
|
return 0;
|
||
|
}
|
||
|
else {
|
||
|
if (o->blessing > 0) print1("You hear a faint despairing cry!");
|
||
|
else if (o->blessing < 0) print1("You hear an agonized scream!");
|
||
|
strcpy(Str1,"Your ");
|
||
|
strcat(Str1,itemid(o));
|
||
|
strcat(Str1," shatters in a thousand lost fragments!");
|
||
|
print2(Str1);
|
||
|
morewait();
|
||
|
dispose_lost_objects(1,o);
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* do dmg points of damage of type dtype, from source fromstring */
|
||
|
void p_damage(int dmg, int dtype, char *fromstring)
|
||
|
{
|
||
|
if (gamestatusp(FAST_MOVE)) {
|
||
|
drawvision(Player.x,Player.y);
|
||
|
resetgamestatus(FAST_MOVE);
|
||
|
}
|
||
|
if (! p_immune(dtype)) {
|
||
|
if (dtype == NORMAL_DAMAGE) Player.hp -= max(1,(dmg-Player.absorption));
|
||
|
else Player.hp -= dmg;
|
||
|
if (Player.hp < 1) p_death(fromstring);
|
||
|
}
|
||
|
else mprint("You resist the effects!");
|
||
|
dataprint();
|
||
|
}
|
||
|
|
||
|
/* game over, you lose! */
|
||
|
void p_death(char *fromstring)
|
||
|
{
|
||
|
Player.hp = -1;
|
||
|
print3("You died!");
|
||
|
morewait();
|
||
|
display_death(fromstring);
|
||
|
player_dump();
|
||
|
#ifdef SAVE_LEVELS
|
||
|
kill_all_levels();
|
||
|
#endif
|
||
|
endgraf();
|
||
|
exit(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* move the cursor around, like for firing a wand, sets x and y to target */
|
||
|
void setspot(int *x, int *y)
|
||
|
{
|
||
|
char c = ' ';
|
||
|
mprint("Targeting.... ? for help");
|
||
|
omshowcursor(*x,*y);
|
||
|
while ((c != '.') && (c != ESCAPE)) {
|
||
|
c = lgetc();
|
||
|
switch(c) {
|
||
|
case 'h':case '4': movecursor(x,y,-1,0); break;
|
||
|
case 'j':case '2': movecursor(x,y,0,1); break;
|
||
|
case 'k':case '8': movecursor(x,y,0,-1); break;
|
||
|
case 'l':case '6': movecursor(x,y,1,0); break;
|
||
|
case 'b':case '1': movecursor(x,y,-1,1); break;
|
||
|
case 'n':case '3': movecursor(x,y,1,1); break;
|
||
|
case 'y':case '7': movecursor(x,y,-1,-1); break;
|
||
|
case 'u':case '9': movecursor(x,y,1,-1); break;
|
||
|
case '?':
|
||
|
clearmsg();
|
||
|
mprint("Use vi keys or numeric keypad to move cursor to target.");
|
||
|
mprint("Hit the '.' key when done, or ESCAPE to abort.");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (c==ESCAPE) *x = *y= ABORT;
|
||
|
screencheck(Player.x,Player.y);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* get a direction: return index into Dirs array corresponding to direction */
|
||
|
int getdir(void)
|
||
|
{
|
||
|
while (1) {
|
||
|
mprint("Select direction [hjklyubn, ESCAPE to quit]: ");
|
||
|
switch (mgetc()) {
|
||
|
case '4':
|
||
|
case 'h':
|
||
|
case 'H': return(5);
|
||
|
case '2':
|
||
|
case 'j':
|
||
|
case 'J': return(6);
|
||
|
case '8':
|
||
|
case 'k':
|
||
|
case 'K': return(7);
|
||
|
case '6':
|
||
|
case 'l':
|
||
|
case 'L': return(4);
|
||
|
case '7':
|
||
|
case 'y':
|
||
|
case 'Y': return(3);
|
||
|
case '9':
|
||
|
case 'u':
|
||
|
case 'U': return(1);
|
||
|
case '1':
|
||
|
case 'b':
|
||
|
case 'B': return(2);
|
||
|
case '3':
|
||
|
case 'n':
|
||
|
case 'N': return(0);
|
||
|
case ESCAPE: return(ABORT);
|
||
|
default: print3("That's not a direction! ");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* functions describes monster m's state for examine function */
|
||
|
char *mstatus_string(struct monster *m)
|
||
|
{
|
||
|
if (m_statusp(m, M_INVISIBLE) && !Player.status[TRUESIGHT])
|
||
|
strcpy(Str2, "Some invisible creature");
|
||
|
else if (m->uniqueness == COMMON) {
|
||
|
if (m->hp < Monsters[m->id].hp / 3)
|
||
|
strcpy(Str2,"a grievously injured ");
|
||
|
else if (m->hp < Monsters[m->id].hp / 2)
|
||
|
strcpy(Str2,"a severely injured ");
|
||
|
else if (m->hp < Monsters[m->id].hp)
|
||
|
strcpy(Str2,"an injured ");
|
||
|
else strcpy(Str2,getarticle(m->monstring));
|
||
|
if (m->level > Monsters[m->id].level) {
|
||
|
strcat(Str2," (level ");
|
||
|
strcat(Str2,wordnum(m->level+1-Monsters[m->id].level));
|
||
|
strcat(Str2,") ");
|
||
|
}
|
||
|
strcat(Str2,m->monstring);
|
||
|
}
|
||
|
else {
|
||
|
strcpy(Str2,m->monstring);
|
||
|
if (m->hp < Monsters[m->id].hp / 3)
|
||
|
strcat(Str2," who is grievously injured ");
|
||
|
else if (m->hp < Monsters[m->id].hp / 2)
|
||
|
strcat(Str2," who is severely injured ");
|
||
|
else if (m->hp < Monsters[m->id].hp)
|
||
|
strcat(Str2," who is injured ");
|
||
|
}
|
||
|
return(Str2);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* for the examine function */
|
||
|
void describe_player(void)
|
||
|
{
|
||
|
if (Player.hp < (Player.maxhp /5))
|
||
|
print1("A grievously injured ");
|
||
|
else if (Player.hp < (Player.maxhp /2))
|
||
|
print1("A seriously wounded ");
|
||
|
else if (Player.hp < Player.maxhp)
|
||
|
print1("A somewhat bruised ");
|
||
|
else print1("A fit ");
|
||
|
|
||
|
if (Player.status[SHADOWFORM])
|
||
|
nprint1("shadow");
|
||
|
else
|
||
|
nprint1(levelname(Player.level));
|
||
|
nprint1(" named ");
|
||
|
nprint1(Player.name);
|
||
|
if (gamestatusp(MOUNTED))
|
||
|
nprint1(" (riding a horse.)");
|
||
|
}
|
||
|
|
||
|
|
||
|
/* access to player experience... */
|
||
|
/* share out experience among guild memberships */
|
||
|
void gain_experience(int amount)
|
||
|
{
|
||
|
int i,count=0,share;
|
||
|
Player.xp += (long) amount;
|
||
|
gain_level(); /* actually, check to see if should gain level */
|
||
|
for(i=0;i<NUMRANKS;i++)
|
||
|
if (Player.guildxp[i] > 0) count++;
|
||
|
share = amount/(max(count,1));
|
||
|
for(i=0;i<NUMRANKS;i++)
|
||
|
if (Player.guildxp[i] > 0) Player.guildxp[i]+=share;
|
||
|
}
|
||
|
|
||
|
/* try to hit a monster in an adjacent space. If there are none
|
||
|
return FALSE. Note if you're berserk you get to attack ALL
|
||
|
adjacent monsters! */
|
||
|
int goberserk(void)
|
||
|
{
|
||
|
int wentberserk=FALSE,i;
|
||
|
char meleestr[80];
|
||
|
strcpy(meleestr,Player.meleestr);
|
||
|
strcpy(Player.meleestr,"lLlClH");
|
||
|
for(i=0;i<8;i++)
|
||
|
if (Level->site[Player.x+Dirs[0][i]][Player.y+Dirs[1][i]].creature
|
||
|
!= NULL) {
|
||
|
wentberserk=TRUE;
|
||
|
fight_monster(Level->site[Player.x+Dirs[0][i]][Player.y+Dirs[1][i]].creature);
|
||
|
morewait();
|
||
|
}
|
||
|
strcpy(Player.meleestr,meleestr);
|
||
|
return(wentberserk);
|
||
|
}
|
||
|
|
||
|
/* identifies a trap for examine() by its aux value */
|
||
|
char *trapid(int trapno)
|
||
|
{
|
||
|
switch (trapno) {
|
||
|
case L_TRAP_SIREN:return("A siren trap");
|
||
|
case L_TRAP_DART:return("A dart trap");
|
||
|
case L_TRAP_PIT:return("A pit");
|
||
|
case L_TRAP_SNARE:return("A snare");
|
||
|
case L_TRAP_BLADE:return("A blade trap");
|
||
|
case L_TRAP_FIRE:return("A fire trap");
|
||
|
case L_TRAP_TELEPORT:return("A teleport trap");
|
||
|
case L_TRAP_DISINTEGRATE:return("A disintegration trap");
|
||
|
case L_TRAP_DOOR:return("A trap door");
|
||
|
case L_TRAP_MANADRAIN:return("A manadrain trap");
|
||
|
case L_TRAP_ACID:return("An acid shower trap");
|
||
|
case L_TRAP_SLEEP_GAS:return("A sleep gas trap");
|
||
|
case L_TRAP_ABYSS:return("A concealed entrance to the abyss");
|
||
|
default: return("A completely inoperative trap.");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* checks current food status of player, every hour, and when food is eaten */
|
||
|
void foodcheck(void)
|
||
|
{
|
||
|
if (Player.food > 48) {
|
||
|
print3("You vomit up your huge meal.");
|
||
|
Player.food = 12;
|
||
|
}
|
||
|
else if (Player.food == 30)
|
||
|
print3("Time for a smackerel of something.");
|
||
|
else if (Player.food == 20)
|
||
|
print3("You feel hungry.");
|
||
|
else if (Player.food == 12)
|
||
|
print3("You are ravenously hungry.");
|
||
|
else if (Player.food == 3) {
|
||
|
print3("You feel weak.");
|
||
|
if (gamestatusp(FAST_MOVE)) {
|
||
|
drawvision(Player.x,Player.y);
|
||
|
resetgamestatus(FAST_MOVE);
|
||
|
}
|
||
|
}
|
||
|
else if (Player.food < 0) {
|
||
|
if (gamestatusp(FAST_MOVE)) {
|
||
|
drawvision(Player.x,Player.y);
|
||
|
resetgamestatus(FAST_MOVE);
|
||
|
}
|
||
|
print3("You're starving!");
|
||
|
p_damage(-5*Player.food,UNSTOPPABLE,"starvation");
|
||
|
}
|
||
|
showflags();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* see whether room should be illuminated */
|
||
|
void roomcheck(void)
|
||
|
{
|
||
|
static int oldroomno = -1;
|
||
|
#ifdef MSDOS_SUPPORTED_ANTIQUE
|
||
|
static int oldlevel = -1;
|
||
|
#else
|
||
|
static plv oldlevel = NULL;
|
||
|
#endif
|
||
|
int roomno = Level->site[Player.x][Player.y].roomnumber;
|
||
|
|
||
|
if ((roomno == RS_CAVERN) ||
|
||
|
(roomno == RS_SEWER_DUCT) ||
|
||
|
(roomno == RS_KITCHEN) ||
|
||
|
(roomno == RS_BATHROOM) ||
|
||
|
(roomno == RS_BEDROOM) ||
|
||
|
(roomno == RS_DININGROOM) ||
|
||
|
(roomno == RS_CLOSET) ||
|
||
|
(roomno > ROOMBASE))
|
||
|
if ((! loc_statusp(Player.x,Player.y,LIT)) &&
|
||
|
(! Player.status[BLINDED]) &&
|
||
|
(Player.status[ILLUMINATION] || (difficulty() < 6))) {
|
||
|
showroom(Level->site[Player.x][Player.y].roomnumber);
|
||
|
spreadroomlight(Player.x,Player.y,roomno);
|
||
|
levelrefresh();
|
||
|
}
|
||
|
if ((oldroomno != roomno) ||
|
||
|
#ifdef MSDOS_SUPPORTED_ANTIQUE
|
||
|
(oldlevel != Level->depth)) {
|
||
|
#else
|
||
|
(oldlevel != Level)) {
|
||
|
#endif
|
||
|
showroom(roomno);
|
||
|
oldroomno = roomno;
|
||
|
#ifdef MSDOS_SUPPORTED_ANTIQUE
|
||
|
oldlevel = Level->depth;
|
||
|
#else
|
||
|
oldlevel = Level;
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ask for mercy */
|
||
|
void surrender(struct monster *m)
|
||
|
{
|
||
|
int i;
|
||
|
long bestitem,bestvalue;
|
||
|
|
||
|
switch(random_range(4)) {
|
||
|
case 0: print1("You grovel at the monster's feet..."); break;
|
||
|
case 1: print1("You cry 'uncle'!"); break;
|
||
|
case 2: print1("You beg for mercy."); break;
|
||
|
case 3: print1("You yield to the monster."); break;
|
||
|
}
|
||
|
if (m->id == GUARD) {
|
||
|
if (m_statusp(m,HOSTILE))
|
||
|
monster_talk(m);
|
||
|
else {
|
||
|
print2("The guard (bored): Have you broken a law? [yn] ");
|
||
|
if (ynq2() == 'y') {
|
||
|
print2("The guard grabs you, and drags you to court.");
|
||
|
morewait();
|
||
|
send_to_jail();
|
||
|
}
|
||
|
else print2("Then don't bother me. Scat!");
|
||
|
}
|
||
|
}
|
||
|
else if ((m->talkf==M_NO_OP) ||
|
||
|
(m->talkf==M_TALK_STUPID))
|
||
|
print3("Your plea is ignored.");
|
||
|
else {
|
||
|
morewait();
|
||
|
print1("Your surrender is accepted.");
|
||
|
if (Player.cash > 0) nprint1(" All your gold is taken....");
|
||
|
Player.cash = 0;
|
||
|
bestvalue = 0;
|
||
|
bestitem = ABORT;
|
||
|
for (i=1;i<MAXITEMS;i++)
|
||
|
if (Player.possessions[i] != NULL)
|
||
|
if (bestvalue < true_item_value(Player.possessions[i])) {
|
||
|
bestitem = i;
|
||
|
bestvalue = true_item_value(Player.possessions[i]);
|
||
|
}
|
||
|
if (bestitem != ABORT) {
|
||
|
print2("You also give away your best item... ");
|
||
|
nprint2(itemid(Player.possessions[bestitem]));
|
||
|
nprint2(".");
|
||
|
morewait();
|
||
|
givemonster(m,Player.possessions[bestitem]);
|
||
|
morewait(); /* msgs come from givemonster */
|
||
|
conform_unused_object(Player.possessions[bestitem]);
|
||
|
Player.possessions[bestitem] = NULL;
|
||
|
}
|
||
|
print2("You feel less experienced... ");
|
||
|
Player.xp = max(0,Player.xp - m->xpv);
|
||
|
nprint2("The monster seems more experienced!");
|
||
|
m->level = (min(10,m->level+1));
|
||
|
m->hp += m->level*20;
|
||
|
m->hit += m->level;
|
||
|
m->dmg += m->level;
|
||
|
m->ac += m->level;
|
||
|
m->xpv += m->level*10;
|
||
|
morewait();
|
||
|
clearmsg();
|
||
|
if ((m->talkf == M_TALK_EVIL) && random_range(10)) {
|
||
|
print1("It continues to attack you, laughing evilly!");
|
||
|
m_status_set(m,HOSTILE);
|
||
|
m_status_reset(m,GREEDY);
|
||
|
}
|
||
|
else if (m->id == HORNET || m->id == GUARD)
|
||
|
print1("It continues to attack you. ");
|
||
|
else {
|
||
|
print1("The monster leaves, chuckling to itself....");
|
||
|
m_teleport(m);
|
||
|
}
|
||
|
}
|
||
|
dataprint();
|
||
|
}
|
||
|
|
||
|
|
||
|
/* threaten a monster */
|
||
|
void threaten(struct monster *m)
|
||
|
{
|
||
|
char response;
|
||
|
switch(random_range(4)) {
|
||
|
case 0:mprint("You demand that your opponent surrender!"); break;
|
||
|
case 1:mprint("You threaten to do bodily harm to it."); break;
|
||
|
case 2:mprint("You attempt to bluster it into submission."); break;
|
||
|
case 3:mprint("You try to cow it with your awesome presence."); break;
|
||
|
}
|
||
|
morewait(); /* FIXED! 12/25/98 */
|
||
|
if (! m_statusp(m,HOSTILE)) {
|
||
|
print3("You only annoy it with your futile demand.");
|
||
|
m_status_set(m,HOSTILE);
|
||
|
}
|
||
|
else if (((m->level*2 > Player.level) && (m->hp > Player.dmg)) ||
|
||
|
(m->uniqueness != COMMON))
|
||
|
print1("It sneers contemptuously at you.");
|
||
|
else if ((m->talkf != M_TALK_GREEDY) &&
|
||
|
(m->talkf != M_TALK_HUNGRY) &&
|
||
|
(m->talkf != M_TALK_EVIL) &&
|
||
|
(m->talkf != M_TALK_MAN) &&
|
||
|
(m->talkf != M_TALK_BEG) &&
|
||
|
(m->talkf != M_TALK_THIEF) &&
|
||
|
(m->talkf != M_TALK_MERCHANT) &&
|
||
|
(m->talkf != M_TALK_IM))
|
||
|
print1("Your demand is ignored");
|
||
|
else {
|
||
|
print1("It yields to your mercy.");
|
||
|
Player.alignment+=3;
|
||
|
print2("Kill it, rob it, or free it? [krf] ");
|
||
|
do response = (char) mcigetc();
|
||
|
while ((response != 'k')&&(response != 'r')&&(response !='f'));
|
||
|
if (response == 'k') {
|
||
|
m_death(m);
|
||
|
print2("You treacherous rogue!");
|
||
|
Player.alignment -= 13;
|
||
|
}
|
||
|
else if (response == 'r') {
|
||
|
Player.alignment-=2;
|
||
|
print2("It drops its treasure and flees.");
|
||
|
m_dropstuff(m);
|
||
|
m_remove( m );
|
||
|
}
|
||
|
else {
|
||
|
Player.alignment+=2;
|
||
|
print2("'If you love something set it free ... '");
|
||
|
if (random_range(100)==13) {
|
||
|
morewait();
|
||
|
print2("'...If it doesn't come back, hunt it down and kill it.'");
|
||
|
}
|
||
|
print3("It departs with a renewed sense of its own mortality.");
|
||
|
m_remove( m );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* name of the player's experience level */
|
||
|
char *levelname(int level)
|
||
|
{
|
||
|
switch(level) {
|
||
|
case 0:strcpy(Str3,"neophyte");break;
|
||
|
case 1:strcpy(Str3,"beginner");break;
|
||
|
case 2:strcpy(Str3,"tourist");break;
|
||
|
case 3:strcpy(Str3,"traveller");break;
|
||
|
case 4:strcpy(Str3,"wayfarer");break;
|
||
|
case 5:strcpy(Str3,"peregrinator");break;
|
||
|
case 6:strcpy(Str3,"wanderer");break;
|
||
|
case 7:strcpy(Str3,"hunter");break;
|
||
|
case 8:strcpy(Str3,"scout");break;
|
||
|
case 9:strcpy(Str3,"trailblazer");break;
|
||
|
case 10:strcpy(Str3,"discoverer");break;
|
||
|
case 11:strcpy(Str3,"explorer");break;
|
||
|
case 12:strcpy(Str3,"senior explorer");break;
|
||
|
case 13:strcpy(Str3,"ranger");break;
|
||
|
case 14:strcpy(Str3,"ranger captain");break;
|
||
|
case 15:strcpy(Str3,"ranger knight");break;
|
||
|
case 16:strcpy(Str3,"adventurer");break;
|
||
|
case 17:strcpy(Str3,"experienced adventurer");break;
|
||
|
case 18:strcpy(Str3,"skilled adventurer");break;
|
||
|
case 19:strcpy(Str3,"master adventurer");break;
|
||
|
case 20:strcpy(Str3,"hero");break;
|
||
|
case 21:strcpy(Str3,"superhero");break;
|
||
|
case 22:strcpy(Str3,"demigod");break;
|
||
|
default:
|
||
|
if (level < 100) {
|
||
|
strcpy(Str3,"Order ");
|
||
|
Str3[6] = ((level/10)-2) + '0';
|
||
|
Str3[7] = 0;
|
||
|
strcat(Str3," Master of Omega");
|
||
|
}
|
||
|
else strcpy(Str3,"Ultimate Master of Omega");
|
||
|
break;
|
||
|
}
|
||
|
return(Str3);
|
||
|
}
|