From bcced3608bdd120315d4ed1d9b9478f7caa4a2f1 Mon Sep 17 00:00:00 2001 From: jtc Date: Fri, 21 Oct 1994 21:19:39 +0000 Subject: phantasia(6), from 44lite --- phantasia/fight.c | 1688 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1688 insertions(+) create mode 100644 phantasia/fight.c (limited to 'phantasia/fight.c') diff --git a/phantasia/fight.c b/phantasia/fight.c new file mode 100644 index 00000000..4038d1db --- /dev/null +++ b/phantasia/fight.c @@ -0,0 +1,1688 @@ +/* + * fight.c Phantasia monster fighting routines + */ + +#include "include.h" + +/************************************************************************ +/ +/ FUNCTION NAME: encounter() +/ +/ FUNCTION: monster battle routine +/ +/ AUTHOR: E. A. Estes, 2/20/86 +/ +/ ARGUMENTS: +/ int particular - particular monster to fight if >= 0 +/ +/ RETURN VALUE: none +/ +/ MODULES CALLED: monsthits(), playerhits(), readmessage(), callmonster(), +/ writerecord(), pickmonster(), displaystats(), pow(), cancelmonster(), +/ awardtreasure(), more(), death(), wmove(), setjmp(), drandom(), printw(), +/ longjmp(), wrefresh(), mvprintw(), wclrtobot() +/ +/ GLOBAL INPUTS: Curmonster, Whichmonster, LINES, Lines, Circle, Shield, +/ Player, *stdscr, Fileloc, Fightenv[], *Enemyname +/ +/ GLOBAL OUTPUTS: Curmonster, Whichmonster, Lines, Shield, Player, Luckout +/ +/ DESCRIPTION: +/ Choose a monster and check against some special types. +/ Arbitrate between monster and player. Watch for either +/ dying. +/ +/************************************************************************/ + +encounter(particular) +int particular; +{ +bool firsthit = Player.p_blessing; /* set if player gets the first hit */ +int flockcnt = 1; /* how many time flocked */ + + /* let others know what we are doing */ + Player.p_status = S_MONSTER; + writerecord(&Player, Fileloc); + +#ifdef SYS5 + flushinp(); +#endif + + Shield = 0.0; /* no shield up yet */ + + if (particular >= 0) + /* monster is specified */ + Whichmonster = particular; + else + /* pick random monster */ + Whichmonster = pickmonster(); + + setjmp(Fightenv); /* this is to enable changing fight state */ + + move(6, 0); + clrtobot(); /* clear bottom area of screen */ + + Lines = 9; + callmonster(Whichmonster); /* set up monster to fight */ + + Luckout = FALSE; /* haven't tried to luckout yet */ + + if (Curmonster.m_type == SM_MORGOTH) + mvprintw(4, 0, "You've encountered %s, Bane of the Council and Valar.\n", + Enemyname); + + if (Curmonster.m_type == SM_UNICORN) + { + if (Player.p_virgin) + { + printw("You just subdued %s, thanks to the virgin.\n", Enemyname); + Player.p_virgin = FALSE; + } + else + { + printw("You just saw %s running away!\n", Enemyname); + Curmonster.m_experience = 0.0; + Curmonster.m_treasuretype = 0; + } + } + else + /* not a special monster */ + for (;;) + /* print header, and arbitrate between player and monster */ + { + mvprintw(6, 0, "You are being attacked by %s, EXP: %.0f (Size: %.0f)\n", + Enemyname, Curmonster.m_experience, Circle); + + displaystats(); + mvprintw(1, 26, "%20.0f", Player.p_energy + Shield); /* overprint energy */ + readmessage(); + + if (Curmonster.m_type == SM_DARKLORD + && Player.p_blessing + && Player.p_charms > 0) + /* overpower Dark Lord with blessing and charm */ + { + mvprintw(7, 0, "You just overpowered %s!", Enemyname); + Lines = 8; + Player.p_blessing = FALSE; + --Player.p_charms; + break; + } + + /* allow paralyzed monster to wake up */ + Curmonster.m_speed = MIN(Curmonster.m_speed + 1.0, Curmonster.m_maxspeed); + + if (drandom() * Curmonster.m_speed > drandom() * Player.p_speed + /* monster is faster */ + && Curmonster.m_type != SM_DARKLORD + /* not D. L. */ + && Curmonster.m_type != SM_SHRIEKER + /* not mimic */ + && !firsthit) + /* monster gets a hit */ + monsthits(); + else + /* player gets a hit */ + { + firsthit = FALSE; + playerhits(); + } + + refresh(); + + if (Lines > LINES - 2) + /* near bottom of screen - pause */ + { + more(Lines); + move(Lines = 8, 0); + clrtobot(); + } + + if (Player.p_energy <= 0.0) + /* player died */ + { + more(Lines); + death(Enemyname); + cancelmonster(); + break; /* fight ends if the player is saved from death */ + } + + if (Curmonster.m_energy <= 0.0) + /* monster died */ + break; + } + + /* give player credit for killing monster */ + Player.p_experience += Curmonster.m_experience; + + if (drandom() < Curmonster.m_flock / 100.0) + /* monster flocks */ + { + more(Lines); + ++flockcnt; + longjmp(Fightenv, 0); + /*NOTREACHED*/ + } + else if (Circle > 1.0 + && Curmonster.m_treasuretype > 0 + && drandom() > 0.2 + pow(0.4, (double) (flockcnt / 3 + Circle / 3.0))) + /* monster has treasure; this takes # of flocks and size into account */ + { + more(Lines); + awardtreasure(); + } + + /* pause before returning */ + getyx(stdscr, Lines, flockcnt); + more(Lines + 1); + + Player.p_ring.ring_inuse = FALSE; /* not using ring */ + + /* clean up the screen */ + move(4, 0); + clrtobot(); +} +/* */ +/************************************************************************ +/ +/ FUNCTION NAME: pickmonster() +/ +/ FUNCTION: choose a monster based upon where we are +/ +/ AUTHOR: E. A. Estes, 2/20/86 +/ +/ ARGUMENTS: none +/ +/ RETURN VALUE: monster number to call +/ +/ MODULES CALLED: floor(), drandom() +/ +/ GLOBAL INPUTS: Marsh, Circle, Player +/ +/ GLOBAL OUTPUTS: none +/ +/ DESCRIPTION: +/ Certain monsters can be found in certain areas of the grid. +/ We take care of rolling them here. +/ Unfortunately, this routine assumes that the monster data +/ base is arranged in a particular order. If the data base +/ is altered (to add monsters, or make them tougher), this +/ routine may also need to be changed. +/ +/************************************************************************/ + +pickmonster() +{ + if (Player.p_specialtype == SC_VALAR) + /* even chance of any monster */ + return((int) ROLL(0.0, 100.0)); + + if (Marsh) + /* water monsters */ + return((int) ROLL(0.0, 15.0)); + + else if (Circle > 24) + /* even chance of all non-water monsters */ + return((int) ROLL(14.0, 86.0)); + + else if (Circle > 15) + /* chance of all non-water monsters, weighted toward middle */ + return((int) (ROLL(0.0, 50.0) + ROLL(14.0, 37.0))); + + else if (Circle > 8) + /* not all non-water monsters, weighted toward middle */ + return((int) (ROLL(0.0, 50.0) + ROLL(14.0, 26.0))); + + else if (Circle > 3) + /* even chance of some tamer non-water monsters */ + return((int) ROLL(14.0, 50.0)); + + else + /* even chance of some of the tamest non-water monsters */ + return((int) ROLL(14.0, 25.0)); +} +/* */ +/************************************************************************ +/ +/ FUNCTION NAME: playerhits() +/ +/ FUNCTION: prompt player for action in monster battle, and process +/ +/ AUTHOR: E. A. Estes, 12/4/85 +/ +/ ARGUMENTS: none +/ +/ RETURN VALUE: none +/ +/ MODULES CALLED: hitmonster(), throwspell(), inputoption(), cancelmonster(), +/ floor(), wmove(), drandom(), altercoordinates(), waddstr(), mvprintw(), +/ wclrtoeol(), wclrtobot() +/ +/ GLOBAL INPUTS: Curmonster, Lines, Player, *stdscr, Luckout, *Enemyname +/ +/ GLOBAL OUTPUTS: Curmonster, Lines, Player, Luckout +/ +/ DESCRIPTION: +/ Process all monster battle options. +/ +/************************************************************************/ + +playerhits() +{ +double inflict; /* damage inflicted */ +int ch; /* input */ + + mvaddstr(7, 0, "1:Melee 2:Skirmish 3:Evade 4:Spell 5:Nick "); + + if (!Luckout) + /* haven't tried to luckout yet */ + if (Curmonster.m_type == SM_MORGOTH) + /* cannot luckout against Morgoth */ + addstr("6:Ally "); + else + addstr("6:Luckout "); + + if (Player.p_ring.ring_type != R_NONE) + /* player has a ring */ + addstr("7:Use Ring "); + else + clrtoeol(); + + ch = inputoption(); + + move(8, 0); + clrtobot(); /* clear any messages from before */ + Lines = 9; + mvaddstr(4, 0, "\n\n"); /* clear status area */ + + switch (ch) + { + case 'T': /* timeout; lose turn */ + break; + + case ' ': + case '1': /* melee */ + /* melee affects monster's energy and strength */ + inflict = ROLL(Player.p_might / 2.0 + 5.0, 1.3 * Player.p_might) + + (Player.p_ring.ring_inuse ? Player.p_might : 0.0); + + Curmonster.m_melee += inflict; + Curmonster.m_strength = Curmonster.m_o_strength + - Curmonster.m_melee / Curmonster.m_o_energy + * Curmonster.m_o_strength / 4.0; + hitmonster(inflict); + break; + + case '2': /* skirmish */ + /* skirmish affects monter's energy and speed */ + inflict = ROLL(Player.p_might / 3.0 + 3.0, 1.1 * Player.p_might) + + (Player.p_ring.ring_inuse ? Player.p_might : 0.0); + + Curmonster.m_skirmish += inflict; + Curmonster.m_maxspeed = Curmonster.m_o_speed + - Curmonster.m_skirmish / Curmonster.m_o_energy + * Curmonster.m_o_speed / 4.0; + hitmonster(inflict); + break; + + case '3': /* evade */ + /* use brains and speed to try to evade */ + if ((Curmonster.m_type == SM_DARKLORD + || Curmonster.m_type == SM_SHRIEKER + /* can always run from D. L. and shrieker */ + || drandom() * Player.p_speed * Player.p_brains + > drandom() * Curmonster.m_speed * Curmonster.m_brains) + && (Curmonster.m_type != SM_MIMIC)) + /* cannot run from mimic */ + { + mvaddstr(Lines++, 0, "You got away!"); + cancelmonster(); + altercoordinates(0.0, 0.0, A_NEAR); + } + else + mvprintw(Lines++, 0, "%s is still after you!", Enemyname); + + break; + + case 'M': + case '4': /* magic spell */ + throwspell(); + break; + + case '5': /* nick */ + /* hit 1 plus sword; give some experience */ + inflict = 1.0 + Player.p_sword; + Player.p_experience += floor(Curmonster.m_experience / 10.0); + Curmonster.m_experience *= 0.92; + /* monster gets meaner */ + Curmonster.m_maxspeed += 2.0; + Curmonster.m_speed = (Curmonster.m_speed < 0.0) ? 0.0 : Curmonster.m_speed + 2.0; + if (Curmonster.m_type == SM_DARKLORD) + /* Dark Lord; doesn't like to be nicked */ + { + mvprintw(Lines++, 0, + "You hit %s %.0f times, and made him mad!", Enemyname, inflict); + Player.p_quickness /= 2.0; + altercoordinates(0.0, 0.0, A_FAR); + cancelmonster(); + } + else + hitmonster(inflict); + break; + + case 'B': + case '6': /* luckout */ + if (Luckout) + mvaddstr(Lines++, 0, "You already tried that."); + else + { + Luckout = TRUE; + if (Curmonster.m_type == SM_MORGOTH) + /* Morgoth; ally */ + { + if (drandom() < Player.p_sin / 100.0) + { + mvprintw(Lines++, 0, "%s accepted!", Enemyname); + cancelmonster(); + } + else + mvaddstr(Lines++, 0, "Nope, he's not interested."); + } + else + /* normal monster; use brains for success */ + { + if ((drandom() + 0.333) * Player.p_brains + < (drandom() + 0.333) * Curmonster.m_brains) + mvprintw(Lines++, 0, "You blew it, %s.", Player.p_name); + else + { + mvaddstr(Lines++, 0, "You made it!"); + Curmonster.m_energy = 0.0; + } + } + } + break; + + case '7': /* use ring */ + if (Player.p_ring.ring_type != R_NONE) + { + mvaddstr(Lines++, 0, "Now using ring."); + Player.p_ring.ring_inuse = TRUE; + if (Player.p_ring.ring_type != R_DLREG) + /* age ring */ + --Player.p_ring.ring_duration; + } + break; + } + +} +/* */ +/************************************************************************ +/ +/ FUNCTION NAME: monsthits() +/ +/ FUNCTION: process a monster hitting the player +/ +/ AUTHOR: E. A. Estes, 12/4/85 +/ +/ ARGUMENTS: none +/ +/ RETURN VALUE: none +/ +/ MODULES CALLED: cancelmonster(), scramblestats(), more(), floor(), wmove(), +/ drandom(), altercoordinates(), longjmp(), waddstr(), mvprintw(), +/ getanswer() +/ +/ GLOBAL INPUTS: Curmonster, Lines, Circle, Shield, Player, *stdscr, +/ Fightenv[], *Enemyname +/ +/ GLOBAL OUTPUTS: Curmonster, Whichmonster, Lines, Shield, Player, +/ *Enemyname +/ +/ DESCRIPTION: +/ Handle all special monsters here. If the monster is not a special +/ one, simply roll a hit against the player. +/ +/************************************************************************/ + +monsthits() +{ +double inflict; /* damage inflicted */ +int ch; /* input */ + + switch (Curmonster.m_type) + /* may be a special monster */ + { + case SM_DARKLORD: + /* hits just enough to kill player */ + inflict = (Player.p_energy + Shield) * 1.02; + goto SPECIALHIT; + + case SM_SHRIEKER: + /* call a big monster */ + mvaddstr(Lines++, 0, + "Shrieeeek!! You scared it, and it called one of its friends."); + more(Lines); + Whichmonster = (int) ROLL(70.0, 30.0); + longjmp(Fightenv, 0); + /*NOTREACHED*/ + + case SM_BALROG: + /* take experience away */ + inflict = ROLL(10.0, Curmonster.m_strength); + inflict = MIN(Player.p_experience, inflict); + mvprintw(Lines++, 0, + "%s took away %.0f experience points.", Enemyname, inflict); + Player.p_experience -= inflict; + return; + + case SM_FAERIES: + if (Player.p_holywater > 0) + /* holy water kills when monster tries to hit */ + { + mvprintw(Lines++, 0, "Your holy water killed it!"); + --Player.p_holywater; + Curmonster.m_energy = 0.0; + return; + } + break; + + case SM_NONE: + /* normal hit */ + break; + + default: + if (drandom() > 0.2) + /* normal hit */ + break; + + /* else special things */ + switch (Curmonster.m_type) + { + case SM_LEANAN: + /* takes some of the player's strength */ + inflict = ROLL(1.0, (Circle - 1.0) / 2.0); + inflict = MIN(Player.p_strength, inflict); + mvprintw(Lines++, 0, "%s sapped %0.f of your strength!", + Enemyname, inflict); + Player.p_strength -= inflict; + Player.p_might -= inflict; + break; + + case SM_SARUMAN: + if (Player.p_palantir) + /* take away palantir */ + { + mvprintw(Lines++, 0, "Wormtongue stole your palantir!"); + Player.p_palantir = FALSE; + } + else if (drandom() > 0.5) + /* gems turn to gold */ + { + mvprintw(Lines++, 0, + "%s transformed your gems into gold!", Enemyname); + Player.p_gold += Player.p_gems; + Player.p_gems = 0.0; + } + else + /* scramble some stats */ + { + mvprintw(Lines++, 0, "%s scrambled your stats!", Enemyname); + scramblestats(); + } + break; + + case SM_THAUMATURG: + /* transport player */ + mvprintw(Lines++, 0, "%s transported you!", Enemyname); + altercoordinates(0.0, 0.0, A_FAR); + cancelmonster(); + break; + + case SM_VORTEX: + /* suck up some mana */ + inflict = ROLL(0, 7.5 * Circle); + inflict = MIN(Player.p_mana, floor(inflict)); + mvprintw(Lines++, 0, + "%s sucked up %.0f of your mana!", Enemyname, inflict); + Player.p_mana -= inflict; + break; + + case SM_NAZGUL: + /* try to take ring if player has one */ + if (Player.p_ring.ring_type != R_NONE) + /* player has a ring */ + { + mvaddstr(Lines++, 0, "Will you relinguish your ring ? "); + ch = getanswer("YN", FALSE); + if (ch == 'Y') + /* take ring away */ + { + Player.p_ring.ring_type = R_NONE; + Player.p_ring.ring_inuse = FALSE; + cancelmonster(); + break; + } + } + + /* otherwise, take some brains */ + mvprintw(Lines++, 0, + "%s neutralized 1/5 of your brain!", Enemyname); + Player.p_brains *= 0.8; + break; + + case SM_TIAMAT: + /* take some gold and gems */ + mvprintw(Lines++, 0, + "%s took half your gold and gems and flew off.", Enemyname); + Player.p_gold /= 2.0; + Player.p_gems /= 2.0; + cancelmonster(); + break; + + case SM_KOBOLD: + /* steal a gold piece and run */ + mvprintw(Lines++, 0, + "%s stole one gold piece and ran away.", Enemyname); + Player.p_gold = MAX(0.0, Player.p_gold - 1.0); + cancelmonster(); + break; + + case SM_SHELOB: + /* bite and (medium) poison */ + mvprintw(Lines++, 0, + "%s has bitten and poisoned you!", Enemyname); + Player.p_poison -= 1.0; + break; + + case SM_LAMPREY: + /* bite and (small) poison */ + mvprintw(Lines++, 0, "%s bit and poisoned you!", Enemyname); + Player.p_poison += 0.25; + break; + + case SM_BONNACON: + /* fart and run */ + mvprintw(Lines++, 0, "%s farted and scampered off.", Enemyname); + Player.p_energy /= 2.0; /* damage from fumes */ + cancelmonster(); + break; + + case SM_SMEAGOL: + if (Player.p_ring.ring_type != R_NONE) + /* try to steal ring */ + { + mvprintw(Lines++, 0, + "%s tried to steal your ring, ", Enemyname); + if (drandom() > 0.1) + addstr("but was unsuccessful."); + else + { + addstr("and ran away with it!"); + Player.p_ring.ring_type = R_NONE; + cancelmonster(); + } + } + break; + + case SM_SUCCUBUS: + /* inflict damage through shield */ + inflict = ROLL(15.0, Circle * 10.0); + inflict = MIN(inflict, Player.p_energy); + mvprintw(Lines++, 0, "%s sapped %.0f of your energy.", + Enemyname, inflict); + Player.p_energy -= inflict; + break; + + case SM_CERBERUS: + /* take all metal treasures */ + mvprintw(Lines++, 0, + "%s took all your metal treasures!", Enemyname); + Player.p_crowns = 0; + Player.p_sword = + Player.p_shield = + Player.p_gold = 0.0; + cancelmonster(); + break; + + case SM_UNGOLIANT: + /* (large) poison and take a quickness */ + mvprintw(Lines++, 0, + "%s poisoned you, and took one quik.", Enemyname); + Player.p_poison += 5.0; + Player.p_quickness -= 1.0; + break; + + case SM_JABBERWOCK: + /* fly away, and leave either a Jubjub bird or Bonnacon */ + mvprintw(Lines++, 0, + "%s flew away, and left you to contend with one of its friends.", + Enemyname); + Whichmonster = 55 + (drandom() > 0.5) ? 22 : 0; + longjmp(Fightenv, 0); + /*NOTREACHED*/ + + case SM_TROLL: + /* partially regenerate monster */ + mvprintw(Lines++, 0, + "%s partially regenerated his energy.!", Enemyname); + Curmonster.m_energy += + floor((Curmonster.m_o_energy - Curmonster.m_energy) / 2.0); + Curmonster.m_strength = Curmonster.m_o_strength; + Curmonster.m_melee = Curmonster.m_skirmish = 0.0; + Curmonster.m_maxspeed = Curmonster.m_o_speed; + break; + + case SM_WRAITH: + if (!Player.p_blindness) + /* make blind */ + { + mvprintw(Lines++, 0, "%s blinded you!", Enemyname); + Player.p_blindness = TRUE; + Enemyname = "A monster"; + } + break; + } + return; + } + + /* fall through to here if monster inflicts a normal hit */ + inflict = drandom() * Curmonster.m_strength + 0.5; +SPECIALHIT: + mvprintw(Lines++, 0, "%s hit you %.0f times!", Enemyname, inflict); + + if ((Shield -= inflict) < 0) + { + Player.p_energy += Shield; + Shield = 0.0; + } +} +/* */ +/************************************************************************ +/ +/ FUNCTION NAME: cancelmonster() +/ +/ FUNCTION: mark current monster as no longer active +/ +/ AUTHOR: E. A. Estes, 12/4/85 +/ +/ ARGUMENTS: none +/ +/ RETURN VALUE: none +/ +/ MODULES CALLED: none +/ +/ GLOBAL INPUTS: none +/ +/ GLOBAL OUTPUTS: Curmonster +/ +/ DESCRIPTION: +/ Clear current monster's energy, experience, treasure type, and +/ flock. This is the same as having the monster run away. +/ +/************************************************************************/ + +cancelmonster() +{ + Curmonster.m_energy = 0.0; + Curmonster.m_experience = 0.0; + Curmonster.m_treasuretype = 0; + Curmonster.m_flock = 0.0; +} +/* */ +/************************************************************************ +/ +/ FUNCTION NAME: hitmonster() +/ +/ FUNCTION: inflict damage upon current monster +/ +/ AUTHOR: E. A. Estes, 12/4/85 +/ +/ ARGUMENTS: +/ double inflict - damage to inflict upon monster +/ +/ RETURN VALUE: none +/ +/ MODULES CALLED: monsthits(), wmove(), strcmp(), waddstr(), mvprintw() +/ +/ GLOBAL INPUTS: Curmonster, Lines, Player, *stdscr, *Enemyname +/ +/ GLOBAL OUTPUTS: Curmonster, Lines +/ +/ DESCRIPTION: +/ Hit monster specified number of times. Handle when monster dies, +/ and a few special monsters. +/ +/************************************************************************/ + +hitmonster(inflict) +double inflict; +{ + mvprintw(Lines++, 0, "You hit %s %.0f times!", Enemyname, inflict); + Curmonster.m_energy -= inflict; + if (Curmonster.m_energy > 0.0) + { + if (Curmonster.m_type == SM_DARKLORD || Curmonster.m_type == SM_SHRIEKER) + /* special monster didn't die */ + monsthits(); + } + else + /* monster died. print message. */ + { + if (Curmonster.m_type == SM_MORGOTH) + mvaddstr(Lines++, 0, "You have defeated Morgoth, but he may return. . ."); + else + /* all other types of monsters */ + { + mvprintw(Lines++, 0, "You killed it. Good work, %s.", Player.p_name); + + if (Curmonster.m_type == SM_MIMIC + && strcmp(Curmonster.m_name, "A Mimic") != 0 + && !Player.p_blindness) + mvaddstr(Lines++, 0, "The body slowly changes into the form of a mimic."); + } + } +} +/* */ +/************************************************************************ +/ +/ FUNCTION NAME: throwspell() +/ +/ FUNCTION: throw a magic spell +/ +/ AUTHOR: E. A. Estes, 12/4/85 +/ +/ ARGUMENTS: none +/ +/ RETURN VALUE: none +/ +/ MODULES CALLED: hitmonster(), cancelmonster(), sqrt(), floor(), wmove(), +/ drandom(), altercoordinates(), longjmp(), infloat(), waddstr(), mvprintw(), +/ getanswer() +/ +/ GLOBAL INPUTS: Curmonster, Whichmonster, Nomana[], Player, *stdscr, +/ Fightenv[], Illspell[], *Enemyname +/ +/ GLOBAL OUTPUTS: Curmonster, Whichmonster, Shield, Player +/ +/ DESCRIPTION: +/ Prompt player and process magic spells. +/ +/************************************************************************/ + +throwspell() +{ +double inflict; /* damage inflicted */ +double dtemp; /* for dtemporary calculations */ +int ch; /* input */ + + mvaddstr(7, 0, "\n\n"); /* clear menu area */ + + if (Player.p_magiclvl >= ML_ALLORNOTHING) + mvaddstr(7, 0, "1:All or Nothing "); + if (Player.p_magiclvl >= ML_MAGICBOLT) + addstr("2:Magic Bolt "); + if (Player.p_magiclvl >= ML_FORCEFIELD) + addstr("3:Force Field "); + if (Player.p_magiclvl >= ML_XFORM) + addstr("4:Transform "); + if (Player.p_magiclvl >= ML_INCRMIGHT) + addstr("5:Increase Might\n"); + if (Player.p_magiclvl >= ML_INVISIBLE) + mvaddstr(8, 0, "6:Invisibility "); + if (Player.p_magiclvl >= ML_XPORT) + addstr("7:Transport "); + if (Player.p_magiclvl >= ML_PARALYZE) + addstr("8:Paralyze "); + if (Player.p_specialtype >= SC_COUNCIL) + addstr("9:Specify"); + mvaddstr(4, 0, "Spell ? "); + + ch = getanswer(" ", TRUE); + + mvaddstr(7, 0, "\n\n"); /* clear menu area */ + + if (Curmonster.m_type == SM_MORGOTH && ch != '3') + /* can only throw force field against Morgoth */ + ILLSPELL(); + else + switch (ch) + { + case '1': /* all or nothing */ + if (drandom() < 0.25) + /* success */ + { + inflict = Curmonster.m_energy * 1.01 + 1.0; + + if (Curmonster.m_type == SM_DARKLORD) + /* all or nothing doesn't quite work against D. L. */ + inflict *= 0.9; + } + else + /* failure -- monster gets stronger and quicker */ + { + Curmonster.m_o_strength = Curmonster.m_strength *= 2.0; + Curmonster.m_maxspeed *= 2.0; + Curmonster.m_o_speed *= 2.0; + + /* paralyzed monsters wake up a bit */ + Curmonster.m_speed = MAX(1.0, Curmonster.m_speed * 2.0); + } + + if (Player.p_mana >= MM_ALLORNOTHING) + /* take a mana if player has one */ + Player.p_mana -= MM_ALLORNOTHING; + + hitmonster(inflict); + break; + + case '2': /* magic bolt */ + if (Player.p_magiclvl < ML_MAGICBOLT) + ILLSPELL(); + else + { + do + /* prompt for amount to expend */ + { + mvaddstr(4, 0, "How much mana for bolt? "); + dtemp = floor(infloat()); + } + while (dtemp < 0.0 || dtemp > Player.p_mana); + + Player.p_mana -= dtemp; + + if (Curmonster.m_type == SM_DARKLORD) + /* magic bolts don't work against D. L. */ + inflict = 0.0; + else + inflict = dtemp * ROLL(15.0, sqrt(Player.p_magiclvl / 3.0 + 1.0)); + mvaddstr(5, 0, "Magic Bolt fired!\n"); + hitmonster(inflict); + } + break; + + case '3': /* force field */ + if (Player.p_magiclvl < ML_FORCEFIELD) + ILLSPELL(); + else if (Player.p_mana < MM_FORCEFIELD) + NOMANA(); + else + { + Player.p_mana -= MM_FORCEFIELD; + Shield = (Player.p_maxenergy + Player.p_shield) * 4.2 + 45.0; + mvaddstr(5, 0, "Force Field up.\n"); + } + break; + + case '4': /* transform */ + if (Player.p_magiclvl < ML_XFORM) + ILLSPELL(); + else if (Player.p_mana < MM_XFORM) + NOMANA(); + else + { + Player.p_mana -= MM_XFORM; + Whichmonster = (int) ROLL(0.0, 100.0); + longjmp(Fightenv, 0); + /*NOTREACHED*/ + } + break; + + case '5': /* increase might */ + if (Player.p_magiclvl < ML_INCRMIGHT) + ILLSPELL(); + else if (Player.p_mana < MM_INCRMIGHT) + NOMANA(); + else + { + Player.p_mana -= MM_INCRMIGHT; + Player.p_might += + (1.2 * (Player.p_strength + Player.p_sword) + + 5.0 - Player.p_might) / 2.0; + mvprintw(5, 0, "New strength: %.0f\n", Player.p_might); + } + break; + + case '6': /* invisible */ + if (Player.p_magiclvl < ML_INVISIBLE) + ILLSPELL(); + else if (Player.p_mana < MM_INVISIBLE) + NOMANA(); + else + { + Player.p_mana -= MM_INVISIBLE; + Player.p_speed += + (1.2 * (Player.p_quickness + Player.p_quksilver) + + 5.0 - Player.p_speed) / 2.0; + mvprintw(5, 0, "New quickness: %.0f\n", Player.p_speed); + } + break; + + case '7': /* transport */ + if (Player.p_magiclvl < ML_XPORT) + ILLSPELL(); + else if (Player.p_mana < MM_XPORT) + NOMANA(); + else + { + Player.p_mana -= MM_XPORT; + if (Player.p_brains + Player.p_magiclvl + < Curmonster.m_experience / 200.0 * drandom()) + { + mvaddstr(5, 0, "Transport backfired!\n"); + altercoordinates(0.0, 0.0, A_FAR); + cancelmonster(); + } + else + { + mvprintw(5, 0, "%s is transported.\n", Enemyname); + if (drandom() < 0.3) + /* monster didn't drop its treasure */ + Curmonster.m_treasuretype = 0; + + Curmonster.m_energy = 0.0; + } + } + break; + + case '8': /* paralyze */ + if (Player.p_magiclvl < ML_PARALYZE) + ILLSPELL(); + else if (Player.p_mana < MM_PARALYZE) + NOMANA(); + else + { + Player.p_mana -= MM_PARALYZE; + if (Player.p_magiclvl > + Curmonster.m_experience / 1000.0 * drandom()) + { + mvprintw(5, 0, "%s is held.\n", Enemyname); + Curmonster.m_speed = -2.0; + } + else + mvaddstr(5, 0, "Monster unaffected.\n"); + } + break; + + case '9': /* specify */ + if (Player.p_specialtype < SC_COUNCIL) + ILLSPELL(); + else if (Player.p_mana < MM_SPECIFY) + NOMANA(); + else + { + Player.p_mana -= MM_SPECIFY; + mvaddstr(5, 0, "Which monster do you want [0-99] ? "); + Whichmonster = (int) infloat(); + Whichmonster = MAX(0, MIN(99, Whichmonster)); + longjmp(Fightenv, 0); + /*NOTREACHED*/ + } + break; + } +} +/* */ +/************************************************************************ +/ +/ FUNCTION NAME: callmonster() +/ +/ FUNCTION: read monster from file, and fill structure +/ +/ AUTHOR: E. A. Estes, 2/25/86 +/ +/ ARGUMENTS: +/ int which - which monster to call +/ +/ RETURN VALUE: none +/ +/ MODULES CALLED: truncstring(), fread(), fseek(), floor(), drandom(), +/ strcpy() +/ +/ GLOBAL INPUTS: Curmonster, Circle, Player, *Monstfp +/ +/ GLOBAL OUTPUTS: Curmonster, Player, *Enemyname +/ +/ DESCRIPTION: +/ Read specified monster from monster database and fill up +/ current monster structure. +/ Adjust statistics based upon current size. +/ Handle some special monsters. +/ +/************************************************************************/ + +callmonster(which) +int which; +{ +struct monster Othermonster; /* to find a name for mimics */ + + which = MIN(which, 99); /* make sure within range */ + + /* fill structure */ + fseek(Monstfp, (long) which * (long) SZ_MONSTERSTRUCT, 0); + fread((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp); + + /* handle some special monsters */ + if (Curmonster.m_type == SM_MODNAR) + { + if (Player.p_specialtype < SC_COUNCIL) + /* randomize some stats */ + { + Curmonster.m_strength *= drandom() + 0.5; + Curmonster.m_brains *= drandom() + 0.5; + Curmonster.m_speed *= drandom() + 0.5; + Curmonster.m_energy *= drandom() + 0.5; + Curmonster.m_experience *= drandom() + 0.5; + Curmonster.m_treasuretype = + (int) ROLL(0.0, (double) Curmonster.m_treasuretype); + } + else + /* make Modnar into Morgoth */ + { + strcpy(Curmonster.m_name, "Morgoth"); + Curmonster.m_strength = drandom() * (Player.p_maxenergy + Player.p_shield) / 1.4 + + drandom() * (Player.p_maxenergy + Player.p_shield) / 1.5; + Curmonster.m_brains = Player.p_brains; + Curmonster.m_energy = Player.p_might * 30.0; + Curmonster.m_type = SM_MORGOTH; + Curmonster.m_speed = Player.p_speed * 1.1 + + (Player.p_specialtype == SC_EXVALAR) ? Player.p_speed : 0.0; + Curmonster.m_flock = 0.0; + Curmonster.m_treasuretype = 0; + Curmonster.m_experience = 0.0; + } + } + else if (Curmonster.m_type == SM_MIMIC) + /* pick another name */ + { + which = (int) ROLL(0.0, 100.0); + fseek(Monstfp, (long) which * (long) SZ_MONSTERSTRUCT, 0); + fread(&Othermonster, SZ_MONSTERSTRUCT, 1, Monstfp); + strcpy(Curmonster.m_name, Othermonster.m_name); + } + + truncstring(Curmonster.m_name); + + if (Curmonster.m_type != SM_MORGOTH) + /* adjust stats based on which circle player is in */ + { + Curmonster.m_strength *= (1.0 + Circle / 2.0); + Curmonster.m_brains *= Circle; + Curmonster.m_speed += Circle * 1.e-9; + Curmonster.m_energy *= Circle; + Curmonster.m_experience *= Circle; + } + + if (Player.p_blindness) + /* cannot see monster if blind */ + Enemyname = "A monster"; + else + Enemyname = Curmonster.m_name; + + if (Player.p_speed <= 0.0) + /* make Player.p_speed positive */ + { + Curmonster.m_speed += -Player.p_speed; + Player.p_speed = 1.0; + } + + /* fill up the rest of the structure */ + Curmonster.m_o_strength = Curmonster.m_strength; + Curmonster.m_o_speed = Curmonster.m_maxspeed = Curmonster.m_speed; + Curmonster.m_o_energy = Curmonster.m_energy; + Curmonster.m_melee = Curmonster.m_skirmish = 0.0; +} +/* */ +/************************************************************************ +/ +/ FUNCTION NAME: awardtreasure() +/ +/ FUNCTION: select a treasure +/ +/ AUTHOR: E. A. Estes, 12/4/85 +/ +/ ARGUMENTS: none +/ +/ RETURN VALUE: none +/ +/ MODULES CALLED: pickmonster(), collecttaxes(), more(), cursedtreasure(), +/ floor(), wmove(), drandom(), sscanf(), printw(), altercoordinates(), +/ longjmp(), infloat(), waddstr(), getanswer(), getstring(), wclrtobot() +/ +/ GLOBAL INPUTS: Somebetter[], Curmonster, Whichmonster, Circle, Player, +/ *stdscr, Databuf[], *Statptr, Fightenv[] +/ +/ GLOBAL OUTPUTS: Whichmonster, Shield, Player +/ +/ DESCRIPTION: +/ Roll up a treasure based upon monster type and size, and +/ certain player statistics. +/ Handle cursed treasure. +/ +/************************************************************************/ + +awardtreasure() +{ +register int whichtreasure; /* calculated treasure to grant */ +int temp; /* temporary */ +int ch; /* input */ +double treasuretype; /* monster's treasure type */ +double gold = 0.0; /* gold awarded */ +double gems = 0.0; /* gems awarded */ +double dtemp; /* for temporary calculations */ + + whichtreasure = (int) ROLL(1.0, 3.0); /* pick a treasure */ + treasuretype = (double) Curmonster.m_treasuretype; + + move(4, 0); + clrtobot(); + move(6, 0); + + if (drandom() > 0.65) + /* gold and gems */ + { + if (Curmonster.m_treasuretype > 7) + /* gems */ + { + gems = ROLL(1.0, (treasuretype - 7.0) + * (treasuretype - 7.0) * (Circle - 1.0) / 4.0); + printw("You have discovered %.0f gems!", gems); + } + else + /* gold */ + { + gold = ROLL(treasuretype * 10.0, treasuretype + * treasuretype * 10.0 * (Circle - 1.0)); + printw("You have found %.0f gold pieces.", gold); + } + + addstr(" Do you want to pick them up ? "); + ch = getanswer("NY", FALSE); + addstr("\n\n"); + + if (ch == 'Y') + if (drandom() < treasuretype / 35.0 + 0.04) + /* cursed */ + { + addstr("They were cursed!\n"); + cursedtreasure(); + } + else + collecttaxes(gold, gems); + + return; + } + else + /* other treasures */ + { + addstr("You have found some treasure. Do you want to inspect it ? "); + ch = getanswer("NY", FALSE); + addstr("\n\n"); + + if (ch != 'Y') + return; + else + if (drandom() < 0.08 && Curmonster.m_treasuretype != 4) + { + addstr("It was cursed!\n"); + cursedtreasure(); + return; + } + else + switch (Curmonster.m_treasuretype) + { + case 1: /* treasure type 1 */ + switch (whichtreasure) + { + case 1: + addstr("You've discovered a power booster!\n"); + Player.p_mana += ROLL(Circle * 4.0, Circle * 30.0); + break; + + case 2: + addstr("You have encountered a druid.\n"); + Player.p_experience += + ROLL(0.0, 2000.0 + Circle * 400.0); + break; + + case 3: + addstr("You have found a holy orb.\n"); + Player.p_sin = MAX(0.0, Player.p_sin - 0.25); + break; + } + break; + /* end treasure type 1 */ + + case 2: /* treasure type 2 */ + switch (whichtreasure) + { + case 1: + addstr("You have found an amulet.\n"); + ++Player.p_amulets; + break; + + case 2: + addstr("You've found some holy water!\n"); + ++Player.p_holywater; + break; + + case 3: + addstr("You've met a hermit!\n"); + Player.p_sin *= 0.75; + Player.p_mana += 12.0 * Circle; + break; + } + break; + /* end treasure type 2 */ + + case 3: /* treasure type 3 */ + switch (whichtreasure) + { + case 1: + dtemp = ROLL(7.0, 30.0 + Circle / 10.0); + printw("You've found a +%.0f shield!\n", dtemp); + if (dtemp >= Player.p_shield) + Player.p_shield = dtemp; + else + SOMEBETTER(); + break; + + case 2: + addstr("You have rescued a virgin. Will you be honorable ? "); + ch = getanswer("NY", FALSE); + addstr("\n\n"); + if (ch == 'Y') + Player.p_virgin = TRUE; + else + { + Player.p_experience += 2000.0 * Circle; + ++Player.p_sin; + } + break; + + case 3: + addstr("You've discovered some athelas!\n"); + --Player.p_poison; + break; + } + break; + /* end treasure type 3 */ + + case 4: /* treasure type 4 */ + addstr("You've found a scroll. Will you read it ? "); + ch = getanswer("NY", FALSE); + addstr("\n\n"); + + if (ch == 'Y') + switch ((int) ROLL(1, 6)) + { + case 1: + addstr("It throws up a shield for you next monster.\n"); + getyx(stdscr, whichtreasure, ch); + more(whichtreasure); + Shield = + (Player.p_maxenergy + Player.p_energy) * 5.5 + Circle * 50.0; + Whichmonster = pickmonster(); + longjmp(Fightenv, 0); + /*NOTREACHED*/ + + case 2: + addstr("It makes you invisible for you next monster.\n"); + getyx(stdscr, whichtreasure, ch); + more(whichtreasure); + Player.p_speed = 1e6; + Whichmonster = pickmonster(); + longjmp(Fightenv, 0); + /*NOTREACHED*/ + + case 3: + addstr("It increases your strength ten fold to fight your next monster.\n"); + getyx(stdscr, whichtreasure, ch); + more(whichtreasure); + Player.p_might *= 10.0; + Whichmonster = pickmonster(); + longjmp(Fightenv, 0); + /*NOTREACHED*/ + + case 4: + addstr("It is a general knowledge scroll.\n"); + Player.p_brains += ROLL(2.0, Circle); + Player.p_magiclvl += ROLL(1.0, Circle / 2.0); + break; + + case 5: + addstr("It tells you how to pick your next monster.\n"); + addstr("Which monster do you want [0-99] ? "); + Whichmonster = (int) infloat(); + Whichmonster = MIN(99, MAX(0, Whichmonster)); + longjmp(Fightenv, 0); + + case 6: + addstr("It was cursed!\n"); + cursedtreasure(); + break; + } + break; + /* end treasure type 4 */ + + case 5: /* treasure type 5 */ + switch (whichtreasure) + { + case 1: + dtemp = ROLL(Circle / 4.0 + 5.0, Circle / 2.0 + 9.0); + printw("You've discovered a +%.0f dagger.\n", dtemp); + if (dtemp >= Player.p_sword) + Player.p_sword = dtemp; + else + SOMEBETTER(); + break; + + case 2: + dtemp = ROLL(7.5 + Circle * 3.0, Circle * 2.0 + 160.0); + printw("You have found some +%.0f armour!\n", dtemp); + if (dtemp >= Player.p_shield) + Player.p_shield = dtemp; + else + SOMEBETTER(); + break; + + case 3: + addstr("You've found a tablet.\n"); + Player.p_brains += 4.5 * Circle; + break; + } + break; + /* end treasure type 5 */ + + case 6: /* treasure type 6 */ + switch (whichtreasure) + { + case 1: + addstr("You've found a priest.\n"); + Player.p_energy = Player.p_maxenergy + Player.p_shield; + Player.p_sin /= 2.0; + Player.p_mana += 24.0 * Circle; + Player.p_brains += Circle; + break; + + case 2: + addstr("You have come upon Robin Hood!\n"); + Player.p_shield += Circle * 2.0; + Player.p_strength += Circle / 2.5 + 1.0; + break; + + case 3: + dtemp = ROLL(2.0 + Circle / 4.0, Circle / 1.2 + 10.0); + printw("You have found a +%.0f axe!\n", dtemp); + if (dtemp >= Player.p_sword) + Player.p_sword = dtemp; + else + SOMEBETTER(); + break; + } + break; + /* end treasure type 6 */ + + case 7: /* treasure type 7 */ + switch (whichtreasure) + { + case 1: + addstr("You've discovered a charm!\n"); + ++Player.p_charms; + break; + + case 2: + addstr("You have encountered Merlyn!\n"); + Player.p_brains += Circle + 5.0; + Player.p_magiclvl += Circle / 3.0 + 5.0; + Player.p_mana += Circle * 10.0; + break; + + case 3: + dtemp = ROLL(5.0 + Circle / 3.0, Circle / 1.5 + 20.0); + printw("You have found a +%.0f war hammer!\n", dtemp); + if (dtemp >= Player.p_sword) + Player.p_sword = dtemp; + else + SOMEBETTER(); + break; + } + break; + /* end treasure type 7 */ + + case 8: /* treasure type 8 */ + switch (whichtreasure) + { + case 1: + addstr("You have found a healing potion.\n"); + Player.p_poison = MIN(-2.0, Player.p_poison - 2.0); + break; + + case 2: + addstr("You have discovered a transporter. Do you wish to go anywhere ? "); + ch = getanswer("NY", FALSE); + addstr("\n\n"); + if (ch == 'Y') + { + double x, y; + + addstr("X Y Coordinates ? "); + getstring(Databuf, SZ_DATABUF); + sscanf(Databuf, "%lf %lf", &x, &y); + altercoordinates(x, y, A_FORCED); + } + break; + + case 3: + dtemp = ROLL(10.0 + Circle / 1.2, Circle * 3.0 + 30.0); + printw("You've found a +%.0f sword!\n", dtemp); + if (dtemp >= Player.p_sword) + Player.p_sword = dtemp; + else + SOMEBETTER(); + break; + } + break; + /* end treasure type 8 */ + + case 10: + case 11: + case 12: + case 13: /* treasure types 10 - 13 */ + if (drandom() < 0.33) + { + if (Curmonster.m_treasuretype == 10) + { + addstr("You've found a pair of elven boots!\n"); + Player.p_quickness += 2.0; + break; + } + else if (Curmonster.m_treasuretype == 11 + && !Player.p_palantir) + { + addstr("You've acquired Saruman's palantir.\n"); + Player.p_palantir = TRUE; + break; + } + else if (Player.p_ring.ring_type == R_NONE + && Player.p_specialtype < SC_COUNCIL + && (Curmonster.m_treasuretype == 12 + || Curmonster.m_treasuretype == 13)) + /* roll up a ring */ + { + if (drandom() < 0.8) + /* regular rings */ + { + if (Curmonster.m_treasuretype == 12) + { + whichtreasure = R_NAZREG; + temp = 35; + } + else + { + whichtreasure = R_DLREG; + temp = 0; + } + } + else + /* bad rings */ + { + whichtreasure = R_BAD; + temp = 15 + Statptr->c_ringduration + (int) ROLL(0,5); + } + + addstr("You've discovered a ring. Will you pick it up ? "); + ch = getanswer("NY", FALSE); + addstr("\n\n"); + + if (ch == 'Y') + { + Player.p_ring.ring_type = whichtreasure; + Player.p_ring.ring_duration = temp; + } + + break; + } + } + /* end treasure types 10 - 13 */ + /* fall through to treasure type 9 if no treasure from above */ + + case 9: /* treasure type 9 */ + switch (whichtreasure) + { + case 1: + if (Player.p_level <= 1000.0 + && Player.p_crowns <= 3 + && Player.p_level >= 10.0) + { + addstr("You have found a golden crown!\n"); + ++Player.p_crowns; + break; + } + /* fall through otherwise */ + + case 2: + addstr("You've been blessed!\n"); + Player.p_blessing = TRUE; + Player.p_sin /= 3.0; + Player.p_energy = Player.p_maxenergy + Player.p_shield; + Player.p_mana += 100.0 * Circle; + break; + + case 3: + dtemp = ROLL(1.0, Circle / 5.0 + 5.0); + dtemp = MIN(dtemp, 99.0); + printw("You have discovered some +%.0f quicksilver!\n",dtemp); + if (dtemp >= Player.p_quksilver) + Player.p_quksilver = dtemp; + else + SOMEBETTER(); + break; + } + break; + /* end treasure type 9 */ + } + } +} +/* */ +/************************************************************************ +/ +/ FUNCTION NAME: cursedtreasure() +/ +/ FUNCTION: take care of cursed treasure +/ +/ AUTHOR: E. A. Estes, 12/4/85 +/ +/ ARGUMENTS: none +/ +/ RETURN VALUE: none +/ +/ MODULES CALLED: waddstr() +/ +/ GLOBAL INPUTS: Player, *stdscr +/ +/ GLOBAL OUTPUTS: Player +/ +/ DESCRIPTION: +/ Handle cursed treasure. Look for amulets and charms to save +/ the player from the curse. +/ +/************************************************************************/ + +cursedtreasure() +{ + if (Player.p_charms > 0) + { + addstr("But your charm saved you!\n"); + --Player.p_charms; + } + else if (Player.p_amulets > 0) + { + addstr("But your amulet saved you!\n"); + --Player.p_amulets; + } + else + { + Player.p_energy = (Player.p_maxenergy + Player.p_shield) / 10.0; + Player.p_poison += 0.25; + } +} +/* */ +/************************************************************************ +/ +/ FUNCTION NAME: scramblestats() +/ +/ FUNCTION: scramble some selected statistics +/ +/ AUTHOR: E. A. Estes, 12/4/85 +/ +/ ARGUMENTS: none +/ +/ RETURN VALUE: none +/ +/ MODULES CALLED: floor(), drandom() +/ +/ GLOBAL INPUTS: Player +/ +/ GLOBAL OUTPUTS: Player +/ +/ DESCRIPTION: +/ Swap a few player statistics randomly. +/ +/************************************************************************/ + +scramblestats() +{ +double dbuf[6]; /* to put statistic in */ +double dtemp1, dtemp2; /* for swapping values */ +register int first, second; /* indices for swapping */ +register double *dptr; /* pointer for filling and emptying buf[] */ + + /* fill buffer */ + dptr = &dbuf[0]; + *dptr++ = Player.p_strength; + *dptr++ = Player.p_mana; + *dptr++ = Player.p_brains; + *dptr++ = Player.p_magiclvl; + *dptr++ = Player.p_energy; + *dptr = Player.p_sin; + + /* pick values to swap */ + first = (int) ROLL(0, 5); + second = (int) ROLL(0, 5); + + /* swap values */ + dptr = &dbuf[0]; + dtemp1 = dptr[first]; + /* this expression is split to prevent a compiler loop on some compilers */ + dtemp2 = dptr[second]; + dptr[first] = dtemp2; + dptr[second] = dtemp1; + + /* empty buffer */ + Player.p_strength = *dptr++; + Player.p_mana = *dptr++; + Player.p_brains = *dptr++; + Player.p_magiclvl = *dptr++; + Player.p_energy = *dptr++; + Player.p_sin = *dptr; +} -- cgit v1.2.3-56-ge451