home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Games Extra 1996 May
/
Amiga_Games_Extra_CD_5-96.bin
/
spiele
/
publicdomain
/
amsrc
/
combat
/
fight.m
< prev
next >
Wrap
Text File
|
1996-02-19
|
46KB
|
1,720 lines
/*
* Amiga MUD
*
* Copyright (c) 1996 by Chris Gray
*/
/*
* fight.m - add player stats, fighting, etc. to the starter dungeon.
*/
private tp_fight CreateTable().
use tp_fight
/*
* NOTE: there is a direct dependency on r_arrivals, to send killed
* players there.
*/
define t_fight STEPS_PER_REGAINED_HIT_POINT 25.
define t_fight BLUTOS_AFTER_DYING 25.
define t_fight RANDOM_MONSTER_LIFE 100.
define t_fight FOREVER_LIFE -1.
/* first, the new player properties. Note: these are all the effective values,
which may include modifications from armour, weapons, spells, etc. */
define t_fight p_pInited CreateBoolProp(). /* player has been set up */
define t_fight p_pFightTerse CreateBoolProp().
define t_fight p_pFightSuperTerse CreateBoolProp().
define t_fight p_pHitMax CreateIntProp(). /* max hit points */
define t_fight p_pHitNow CreateIntProp(). /* current hit points */
define t_fight p_pHitCount CreateIntProp(). /* part count for healing */
define t_fight p_pExperience CreateIntProp(). /* experience */
define t_fight p_pLevel CreateIntProp(). /* current level */
define t_fight p_pStrength CreateIntProp(). /* strength */
define t_fight p_pSpeed CreateIntProp(). /* speed/dexterity */
define t_fight p_pProtection CreateIntProp(). /* current armour class */
define t_fight p_pWeapon CreateThingProp(). /* current weapon */
define t_fight p_pShield CreateThingProp(). /* current shield */
define t_fight p_pArmour CreateThingProp(). /* current armour */
define t_fight p_pCurrentTarget CreateThingProp(). /* current opponent */
define t_fight p_pDieNotifyList CreateActionListProp().
define t_fight p_pNewMonster CreateThingProp(). /* temp during creation */
define t_fight p_pWieldChecker CreateActionProp(). /* allow player check */
/* monster-only properties */
define t_fight p_mActions CreateStringProp(). /* single string of actions */
define t_fight p_mActionIndexes CreateIntListProp(). /* indices of them */
define t_fight p_mMovesUntilVanish CreateIntProp(). /* when it leaves */
define t_fight p_mInitAction CreateActionProp(). /* startup action */
define t_fight p_mMoveAction CreateActionProp(). /* step action */
define t_fight p_mAfterMoveAction CreateActionProp(). /* on enter new room */
define t_fight p_mFightAction CreateActionProp(). /* fight action */
define t_fight p_mSpecialAction CreateActionProp(). /* action to do */
define t_fight p_mKillAction CreateActionProp(). /* action on kill */
define t_fight p_mCreateAction CreateActionProp(). /* something new */
define t_fight p_mArriveAction CreateActionProp(). /* something comes */
define t_fight p_mArrivedAction CreateActionProp(). /* check new loc */
define t_fight p_mExpired CreateBoolProp(). /* it has "died" */
define t_fight p_mBlocker CreateBoolProp(). /* it can block */
define t_fight p_mHunting CreateBoolProp(). /* look for target */
/* properties for weapons/shield/armour */
define t_fight p_oHitBonus CreateIntProp(). /* hitpoints bonus */
define t_fight p_oStrBonus CreateIntProp(). /* strength bonus */
define t_fight p_oSpeedBonus CreateIntProp(). /* speed bonus */
define t_fight p_oArmourProt CreateIntProp(). /* armour protection bonus */
define t_fight p_oShieldProt CreateIntProp(). /* shield protection bonus */
define t_fight p_oAccuracy CreateIntProp(). /* base accuracy level */
define t_fight p_oDamage CreateIntProp(). /* base damage level */
define t_fight p_oHealing CreateIntProp(). /* strength of heal */
define t_fight p_oWieldChecker CreateActionProp(). /* when wield a weapon */
/* properties on rooms */
define t_fight p_rNoGenerateMonsters CreateBoolProp()./* no new baddies */
define t_fight p_rMonsterList CreateThingListProp(). /* what might turn up */
define t_fight p_rMonsterChance CreateIntListProp(). /* diff per person */
define t_fight p_rMonsterTotal CreateIntProp(). /* total of the chances */
define t_fight p_rKillAction CreateActionProp(). /* when monster killed */
/* this is an ancestor of all generic monsters */
define t_fight GenericMonster CreateThing(nil).
/*
* fighterDesc - return additional description for a fighter.
*/
define tp_fight proc fighterDesc()string:
thing it, weapon, shield, armour;
string name, s, shieldName, armourName;
it := It();
s := "";
name := Capitalize(CharacterNameS(it));
weapon := it@p_pWeapon;
shield := it@p_pShield;
if shield ~= nil then
shieldName := FormatName(shield@p_oName);
fi;
armour := it@p_pArmour;
if armour ~= nil then
armourName := FormatName(armour@p_oName);
fi;
if weapon = nil then
if shield = nil then
if armour ~= nil then
s := name + " is wearing " + armourName;
fi;
else
s := name + AAn(" is using", shieldName);
if armour ~= nil then
s := s + " and wearing " + armourName;
fi;
fi;
else
s := name + AAn(" is wielding", FormatName(weapon@p_oName));
if shield = nil then
if armour ~= nil then
s := s + " and wearing " + armourName;
fi;
else
if armour ~= nil then
s := s + AAn(", using", shieldName);
s := s + " and wearing " + armourName;
else
s := s + AAn(" and using", shieldName);
fi;
fi;
fi;
if s ~= "" then
s := " " + s + ".";
fi;
s
corp;
/*
* AddFighterDesc - add the description about weapons, etc. to the list
* of extra descriptions on the passed character, if it is not
* already there.
*/
define t_fight proc AddFighterDesc(thing theCharacter)void:
list action la;
la := theCharacter@p_pDescMore;
if la = nil then
la := CreateActionList();
theCharacter@p_pDescMore := la;
fi;
if FindElement(la, fighterDesc) = -1 then
AddTail(la, fighterDesc);
fi;
corp;
/*
* useItem - start using the given item.
*/
define tp_fight proc useItem(thing th)void:
thing me;
list action la;
me := Me();
me@p_pHitMax := me@p_pHitMax + th@p_oHitBonus;
me@p_pStrength := me@p_pStrength + th@p_oStrBonus;
me@p_pSpeed := me@p_pSpeed + th@p_oSpeedBonus;
me@p_pProtection := me@p_pProtection + th@p_oArmourProt + th@p_oShieldProt;
AddFighterDesc(me);
corp;
/*
* unUseItem - stop using the given item.
*/
define tp_fight proc unUseItem(thing th, theCharacter)void:
theCharacter@p_pHitMax := theCharacter@p_pHitMax - th@p_oHitBonus;
theCharacter@p_pStrength := theCharacter@p_pStrength - th@p_oStrBonus;
theCharacter@p_pSpeed := theCharacter@p_pSpeed - th@p_oSpeedBonus;
theCharacter@p_pProtection := theCharacter@p_pProtection -
th@p_oArmourProt - th@p_oShieldProt;
corp;
/* the wear/use/wield routines for armour/shields/weapons */
define tp_fight proc armourDrop(thing th)status:
thing theCharacter;
theCharacter := th@p_oCarryer;
if theCharacter ~= nil then
unUseItem(th, theCharacter);
theCharacter -- p_pArmour;
th -- p_oUnGetChecker;
fi;
continue
corp;
define tp_fight proc shieldDrop(thing th)status:
thing theCharacter;
theCharacter := th@p_oCarryer;
if theCharacter ~= nil then
unUseItem(th, theCharacter);
theCharacter -- p_pShield;
th -- p_oUnGetChecker;
fi;
continue
corp;
define tp_fight proc weaponDrop(thing th)status:
thing theCharacter;
theCharacter := th@p_oCarryer;
if theCharacter ~= nil then
unUseItem(th, theCharacter);
theCharacter -- p_pWeapon;
th -- p_oUnGetChecker;
fi;
continue
corp;
define tp_fight proc armourWear()status:
thing th, me, oldArmour;
th := It();
me := Me();
if me@p_pWeapon = th then
ignore weaponDrop(th);
fi;
if me@p_pShield = th then
ignore shieldDrop(th);
fi;
oldArmour := me@p_pArmour;
if oldArmour ~= nil then
unUseItem(oldArmour, me);
oldArmour -- p_oUnGetChecker;
fi;
useItem(th);
th@p_oUnGetChecker := armourDrop;
me@p_pArmour := th;
Print("You are now wearing the " + FormatName(th@p_oName) + ".\n");
succeed
corp;
define tp_fight proc shieldUse()status:
thing th, me, oldShield;
th := It();
me := Me();
if me@p_pWeapon = th then
ignore weaponDrop(th);
fi;
if me@p_pArmour = th then
ignore armourDrop(th);
fi;
oldShield := me@p_pShield;
if oldShield ~= nil then
unUseItem(oldShield, me);
oldShield -- p_oUnGetChecker;
fi;
useItem(th);
th@p_oUnGetChecker := shieldDrop;
me@p_pShield := th;
Print("You are now using the " + FormatName(th@p_oName) + ".\n");
succeed
corp;
define tp_fight proc weaponWield()status:
thing th, me, oldWeapon;
th := It();
me := Me();
if me@p_pShield = th then
ignore shieldDrop(th);
fi;
if me@p_pArmour = th then
ignore armourDrop(th);
fi;
oldWeapon := me@p_pWeapon;
if oldWeapon ~= nil then
unUseItem(oldWeapon, me);
oldWeapon -- p_oUnGetChecker;
fi;
useItem(th);
th@p_oUnGetChecker := weaponDrop;
me@p_pWeapon := th;
Print("You are now wielding the " + FormatName(th@p_oName) + ".\n");
succeed
corp;
/*
* SetupWeapon - set up a model object as a weapon.
*/
define t_fight proc public SetupWeapon(thing theModel; int hitBonus, strBonus,
speedBonus, armourProt, shieldProt, accuracy, damage)void:
if hitBonus ~= 0 then
theModel@p_oHitBonus := hitBonus;
fi;
if strBonus ~= 0 then
theModel@p_oStrBonus := strBonus;
fi;
if speedBonus ~= 0 then
theModel@p_oSpeedBonus := speedBonus;
fi;
if armourProt ~= 0 then
theModel@p_oArmourProt := armourProt;
theModel@p_oWearChecker := armourWear;
fi;
if shieldProt ~= 0 then
theModel@p_oShieldProt := shieldProt;
theModel@p_oUseChecker := shieldUse;
fi;
if accuracy ~= 0 then
theModel@p_oAccuracy := accuracy;
fi;
if damage ~= 0 then
theModel@p_oDamage := damage;
theModel@p_oWieldChecker := weaponWield;
fi;
corp;
/*
* WeaponSell - companion routine - set up what is for sale.
*/
define t_fight proc public WeaponSell(thing room; string name, desc;
int price, hitBonus, strBonus, speedBonus,
armourProt, shieldProt, accuracy, damage
)thing:
thing theModel;
theModel := AddForSale(room, name, desc, price, nil);
SetupWeapon(theModel, hitBonus, strBonus, speedBonus, armourProt,
shieldProt, accuracy, damage);
theModel
corp;
define tp_fight proc healBuy()status:
thing th, me;
int n, hits, delta;
th := It();
me := Me();
n := th@p_oHealing;
n := n / 2 + Random(n / 2);
hits := me@p_pHitNow;
delta := me@p_pHitMax - hits;
if delta = 0 then
Print("You didn't need healing. Oh well - easy come, easy go!\n");
else
if n > delta then
n := delta;
fi;
me@p_pHitNow := hits + n;
if n = 1 then
Print("You are healed for one point.\n");
else
Print("You are healed for " + IntToString(n) + " points.\n");
fi;
fi;
if not me@p_pHidden then
OPrint(Capitalize(CharacterNameG(me)) + " makes a purchase.\n");
fi;
/* Tell 'StoreBuy' to destroy the copy, do not add it to our inventory,
and print no messages, but charge us for it. */
succeed
corp;
/*
* HealSell - set up a healing "object".
*/
define t_fight proc public HealSell(thing room; string name;
int cost, healing)void:
thing theModel;
theModel := AddForSale(room, name, "", cost, healBuy);
theModel@p_oHealing := healing;
corp;
/*
* showStats - show the statistics of the given thing (monster or player)
*/
define tp_fight proc showStats(thing theCharacter; bool forceLong)void:
string name;
int ac;
thing th;
name := theCharacter@p_pName;
if not theCharacter@p_pStandard then
name := FormatName(name);
fi;
Print(name);
Print(": Hit: ");
IPrint(theCharacter@p_pHitNow);
Print("/");
IPrint(theCharacter@p_pHitMax);
Print(" Exp: ");
IPrint(theCharacter@p_pExperience);
Print(" Lvl: ");
IPrint(theCharacter@p_pLevel);
Print(" Str: ");
IPrint(theCharacter@p_pStrength);
Print(" Spd: ");
IPrint(theCharacter@p_pSpeed);
Print(" AC: ");
ac := theCharacter@p_pProtection;
if ac > 0 then
Print("+");
fi;
IPrint(ac);
Print(" Bl: ");
IPrint(theCharacter@p_pMoney);
Print("\n");
if forceLong or not theCharacter@p_pFightTerse or theCharacter ~= Me() then
th := theCharacter@p_pWeapon;
if th ~= nil then
Print("Weapon: ");
Print(FormatName(th@p_oName));
Print("\n");
fi;
th := theCharacter@p_pShield;
if th ~= nil then
Print("Shield: ");
Print(FormatName(th@p_oName));
Print("\n");
fi;
th := theCharacter@p_pArmour;
if th ~= nil then
Print("Armour: ");
Print(FormatName(th@p_oName));
Print("\n");
fi;
fi;
corp;
/**************************************************************************\
* *
* Code, etc. for monsters *
* *
\**************************************************************************/
/* NOTE: each monster points at the player it is currently attacking, which
is usually the player which caused it to come into being, but can be
another, if that other attacked the monster. Players point at the monster
they most recently created or attacked, but those pointers are subject
to testing before they are used, since the monsters can leave. */
/* the fighting code */
/*
* AddExperience - do all needed on an experience gain or loss.
*/
define t_fight proc public AddExperience(thing thePlayer; int n)void:
int level, value;
n := n + thePlayer@p_pExperience;
thePlayer@p_pExperience := n;
level := 0;
value := 10;
while value <= n do
value := value * 10;
level := level + 1;
od;
value := thePlayer@p_pLevel;
if level ~= value then
thePlayer@p_pLevel := level;
if level > value then
SPrint(thePlayer, "You have gained a level!\n");
if Random(2) = 0 then
SPrint(thePlayer, "You gain speed.\n");
thePlayer@p_pSpeed := thePlayer@p_pSpeed + 1;
else
SPrint(thePlayer, "You gain strength.\n");
thePlayer@p_pStrength := thePlayer@p_pStrength + 1;
fi;
thePlayer@p_pHitMax := thePlayer@p_pHitMax + 8 + Random(5);
else
SPrint(thePlayer, "You have lost a level!\n");
if thePlayer@p_pSpeed > thePlayer@p_pStrength or
thePlayer@p_pSpeed = thePlayer@p_pStrength and Random(2) = 0
then
SPrint(thePlayer, "You lose speed.\n");
thePlayer@p_pSpeed := thePlayer@p_pSpeed - 1;
else
SPrint(thePlayer, "You lose strength.\n");
thePlayer@p_pStrength := thePlayer@p_pStrength - 1;
fi;
n := thePlayer@p_pHitMax - 8 - Random(5);
if n < 10 then
n := 10;
fi;
thePlayer@p_pHitMax := n;
fi;
fi;
corp;
/*
* FindLoot - the player finds loot from a kill.
*/
define t_fight proc public FindLoot(int amount)void:
thing theCharacter;
if amount = 0 then
amount := 1;
fi;
if amount = 1 then
Print("You found one bluto of loot.\n");
else
Print("You found ");
IPrint(amount);
Print(" blutos of loot.\n");
fi;
theCharacter := Me();
theCharacter@p_pMoney := theCharacter@p_pMoney + amount;
corp;
/*
* part of KillPlayer.
*/
define tp_fight proc showAndLook()status:
ShowIcon();
ignore ShowRoomToMe(true);
continue
corp;
/*
* KillPlayer - general routine for killing a player. Send him back to the
* arrivals room with no belongings and 25 blutos.
* NOTE: if a player tells Packrat to go into the proving grounds, she
* will be set up to fight, just as if she were a player. Then, if
* someone kills her, this routine will be called by her!
*/
define t_fight proc public KillPlayer(thing theVictim, theKiller)void:
list action la;
list thing lt;
int count, i;
action a;
thing here, item, killerLoc;
string victimName;
la := theVictim@p_pDieNotifyList;
count := Count(la);
i := 0;
while i ~= count do
a := la[i];
if call(a, bool)(theVictim) then
DelElement(la, a);
count := count - 1;
else
i := i + 1;
fi;
od;
here := AgentLocation(theVictim);
lt := theVictim@p_pCarrying;
count := Count(lt);
i := 0;
while i < count do
item := lt[i];
if DoDrop(here, theVictim, item) = continue then
count := count - 1;
else
i := i + 1;
fi;
od;
/* this makes for a non-obvious cheat, but I want it disabled anyway */
victimName := theVictim@p_pName;
if victimName ~= "Packrat" then
theVictim@p_pMoney := BLUTOS_AFTER_DYING;
fi;
theVictim@p_pHitNow := 10;
theVictim@p_pExperience := theVictim@p_pExperience / 2;
AddExperience(theVictim, 0);
if theVictim@p_pHidden then
theVictim@p_pHidden := false;
ABPrint(here, theVictim, theVictim,
"Something fades into view. It is the corpse of " + victimName +
"!\n");
fi;
ABPrint(here, theVictim, theVictim,
"The corpse just fades away, but you catch a glimpse from the corner "
"of your eye of a pale cloud floating off.\n");
ignore ForceAction(theVictim, DoUnShowIcon);
SetAgentLocation(theVictim, r_arrivals);
SPrint(theVictim,
"You feel an abrupt tearing of the local continuum as your essence "
"departs from your ravaged body. Looking down, you see your corpse fade "
"away to nothing, leaving little sign of your recent presence. A feeling "
"of lightness pervades your being, and you begin to float away from the "
"scene. The floating quickens and the world becomes a blur of motion. Soon "
"you can again make out your surroundings.\n");
ABPrint(r_arrivals, theVictim, theVictim, "From the corner of your eye "
"you see a pale cloud float into view, which then solidifies into " +
victimName + ".\n");
ignore ForceAction(theVictim, showAndLook);
/* did the killer kill off the only light source? */
if theKiller ~= theVictim and not LightAt(here) then
/* it may have gotten dark there */
killerLoc := AgentLocation(theKiller);
if killerLoc ~= here or not HasLight(theKiller) then
ForEachAgent(here, UnShowRoomFromAgent);
if killerLoc = here then
if theKiller = Me() then
UnShowRoomFromMe();
else
UnShowRoomFromAgent(theKiller);
fi;
fi;
fi;
fi;
corp;
/*
* MonsterHitPlayer - have the monster hit the player.
* Note: this can be executed by the player or by the monster!
* Return 'true' if the player is still alive.
*/
define t_fight proc public MonsterHitPlayer(
thing theMonster, thePlayer, where)bool:
string monsterName, playerName;
int n, hits;
bool alive;
if thePlayer@p_pCurrentTarget = nil then
thePlayer@p_pCurrentTarget := theMonster;
fi;
alive := true;
n := theMonster@p_oAccuracy;
if n ~= 0 and Here()@p_rMonsterList ~= nil then
/* Special case - if accuracy = 0, the monster never attacks.
Also, don't let monsters attack in a non-combat area, since
the player can't hit back! */
monsterName := Capitalize(CharacterNameG(theMonster));
playerName := thePlayer@p_pName;
if thePlayer@p_pHidden then
ABPrint(where, thePlayer, thePlayer,
monsterName + " attacks something.\n");
else
ABPrint(where, thePlayer, thePlayer,
monsterName + " attacks " + playerName + ".\n");
fi;
/* first, does the attack hit? Note: 5 is "standard". */
n := n * 3 + theMonster@p_pSpeed - 5;
if n ~= 0 then
n := Random(60 / n);
else
n := 1;
fi;
if n = 0 then
/* A hit. Get basic damage done by monster */
n := (theMonster@p_oDamage + 1) * 4;
n := (n / 2 + Random(n / 2 + 3)) / 4;
/* Modify by player armour class */
n := n + thePlayer@p_pProtection - 9;
/* and for excessive player strength */
n := n - (thePlayer@p_pStrength - 3) / 5;
if n > 0 then
hits := thePlayer@p_pHitNow;
hits := hits - n;
SPrint(thePlayer, monsterName + " hits for " +
if n = 1 then
"one point"
else
IntToString(n) + " points"
fi +
". [" + IntToString(hits) + "/" +
IntToString(thePlayer@p_pHitMax) + "]\n");
if hits <= 0 then
SPrint(thePlayer, "You are killed!\n");
if not thePlayer@p_pHidden then
ABPrint(where, thePlayer, thePlayer,
monsterName + " kills " + playerName + "!\n");
fi;
KillPlayer(thePlayer, theMonster);
alive := false;
else
thePlayer@p_pHitNow := hits;
fi;
else
if not thePlayer@p_pFightSuperTerse then
SPrint(thePlayer,
monsterName + " hits but does no damage.\n");
fi;
fi;
else
if not thePlayer@p_pFightTerse then
SPrint(thePlayer, monsterName + " attacks but misses.\n");
fi;
fi;
fi;
alive
corp;
/*
* KillMonster - normal stuff for killing a monster.
*/
define t_fight proc KillMonster(thing theMonster)void:
string monsterName;
thing theKiller, here;
list thing lt;
int i;
theKiller := Me();
monsterName := CharacterNameS(theMonster);
Print(Capitalize(monsterName) + " is killed!\n");
if theKiller@p_pHidden then
OPrint(Capitalize(monsterName) + " is killed!\n");
else
OPrint(Capitalize(theKiller@p_pName) + " kills " + monsterName +"!\n");
fi;
theKiller -- p_pCurrentTarget;
lt := theMonster@p_pCarrying;
if lt ~= nil then
here := Here();
i := Count(lt);
while i ~= 0 do
i := i - 1;
ignore DoDrop(here, theMonster, lt[i]);
od;
fi;
if theMonster ~= theKiller then
i := theMonster@p_pMoney;
if i ~= 0 then
FindLoot((i + 1) / 2 + Random((i + 1) / 2));
fi;
fi;
ignore ForceAction(theMonster, DoUnShowIcon);
corp;
/*
* PlayerHitMonster - the player is attacking the monster.
* Return 'true' if the monster is still alive.
* Note: this is only ever executed by the player.
*/
define t_fight proc public PlayerHitMonster(thing thePlayer, theMonster)bool:
thing weapon, here, theModel;
string monsterName;
int n, hits;
list thing lt;
bool alive;
action a;
alive := true;
theMonster@p_mMovesUntilVanish := RANDOM_MONSTER_LIFE;
thePlayer@p_pCurrentTarget := theMonster;
if theMonster@p_pCurrentTarget ~= thePlayer then
/* if multiple people are bashing on a monster, it randomly
targets one of them */
if theMonster@p_pCurrentTarget = nil or Random(2) = 0 then
theMonster@p_pCurrentTarget := thePlayer;
fi;
fi;
weapon := thePlayer@p_pWeapon;
monsterName := CharacterNameG(theMonster);
if thePlayer@p_pHidden then
OPrint(Capitalize(monsterName) + " is attacked.\n");
else
OPrint(Capitalize(thePlayer@p_pName) + " attacks " +
monsterName + ".\n");
fi;
/* first, does the attack hit? Note: 5 is "standard". */
if weapon = nil then
n := 5;
else
n := weapon@p_oAccuracy;
fi;
n := (n + thePlayer@p_pLevel) * 3 + thePlayer@p_pSpeed - 5;
/* weaponless level 0 character has one chance in 4 of hitting */
/* weaponless level 1 - 4 character has one chance in 3 of hitting */
/* weaponless level 5 - 10 character has one chance in 2 of hitting */
/* weaponless level 11 and up character always hits */
if n ~= 0 then
n := Random(60 / n);
else
n := 1;
fi;
if n = 0 then
/* A hit! How much damage? */
if weapon = nil then
n := 3;
else
n := weapon@p_oDamage;
fi;
n := (n + thePlayer@p_pStrength) * 2;
n := (n / 2 + Random(n / 2 + 3)) / 4;
/* Modify by monster armour class */
n := n + theMonster@p_pProtection - 9;
if n > 0 then
Print("You hit for " + IntToString(n) +
if n = 1 then " point.\n" else " points.\n" fi);
hits := theMonster@p_pHitNow;
if n >= hits then
/* it is killed */
theModel := Parent(theMonster);
a := theMonster@p_mKillAction;
if a ~= nil then
alive := call(a, bool)(thePlayer, theMonster);
else
alive := false;
KillMonster(theMonster);
DestroyMachine(theMonster);
AddExperience(thePlayer, hits);
fi;
a := Here()@p_rKillAction;
if a ~= nil then
call(a, void)(thePlayer, theModel);
fi;
else
theMonster@p_pHitNow := hits - n;
AddExperience(thePlayer, n);
fi;
else
if not thePlayer@p_pFightSuperTerse then
Print("You hit " + monsterName + " but do no damage.\n");
fi;
fi;
else
if not thePlayer@p_pFightTerse then
Print("You attack " + monsterName + " but miss.\n");
fi;
fi;
alive
corp;
/*
* PlayerHitPlayer - the current player is attacking the given player.
*/
define t_fight proc public PlayerHitPlayer(thing theTarget)void:
thing here, theAttacker, weapon;
string attackerName, targetName, points;
int n, hits;
here := Here();
theAttacker := Me();
attackerName := Capitalize(theAttacker@p_pName);
targetName := theTarget@p_pName;
if theTarget@p_pInited then
if not theAttacker@p_pHidden and not theTarget@p_pHidden then
ABPrint(here, theTarget, theAttacker,
attackerName + " attacks " + targetName + ".\n");
fi;
weapon := theAttacker@p_pWeapon;
/* first, does the attack hit? Note: 5 is "standard". */
if weapon = nil then
n := 5;
else
n := weapon@p_oAccuracy;
fi;
n := n + theAttacker@p_pLevel;
if n ~= 0 then
n := (Random(200 / n) + 5) / 10;
else
n := 1;
fi;
if n = 0 then
/* A hit! How much damage? */
if weapon = nil then
n := 5;
else
n := weapon@p_oDamage;
fi;
n := n + theAttacker@p_pStrength / 5;
n := n / 2 + Random(n / 2) + 1;
/* Modify by target armour class */
n := n + theTarget@p_pProtection - 9;
/* and for excessive player strength */
n := n - theTarget@p_pStrength / 5;
if n > 0 then
hits := theTarget@p_pHitNow;
SPrint(theTarget, attackerName +
" attacks you and hits for " +
if n = 1 then
"one point"
else
IntToString(n) + " points"
fi + ". [" + IntToString(hits - n) + "/" +
IntToString(hits) + "]\n");
Print("You hit for " + if n = 1 then "one point" else
IntToString(n) + " points" fi + ".\n");
if n >= hits then
/* target is killed */
n := hits;
if not theAttacker@p_pHidden and not theTarget@p_pHidden
then
ABPrint(here, theTarget, theAttacker,
attackerName + " kills " + targetName + "!\n");
fi;
SPrint(theTarget, attackerName + " has killed you!\n");
Print(Capitalize(targetName) + " is killed!\n");
if theTarget@p_pMoney ~= 0 then
FindLoot(theTarget@p_pMoney);
fi;
KillPlayer(theTarget, theAttacker);
else
theTarget@p_pHitNow := hits - n;
fi;
AddExperience(theAttacker, n);
else
if not theTarget@p_pFightSuperTerse then
SPrint(theTarget, attackerName +
" attacks you and hits, but does no damage.\n");
fi;
if not theAttacker@p_pFightSuperTerse then
Print("You hit " + targetName + " but do no damage.\n");
fi;
fi;
else
if not theTarget@p_pFightTerse then
SPrint(theTarget, attackerName + " attacks you but misses.\n");
fi;
if not theAttacker@p_pFightTerse then
Print("You attack " + targetName + " but miss.\n");
fi;
fi;
else
Print(Capitalize(targetName) + " is not set up for fighting.\n");
fi;
corp;
/*
* InitMonsterModels - clear a room for a new opponent set.
*/
define t_fight proc public InitMonsterModels(thing room; int initTotal)void:
room@p_rMonsterList := CreateThingList();
room@p_rMonsterChance := CreateIntList();
room@p_rMonsterTotal := initTotal;
corp;
/*
* AddPossibleMonster - add a monster to a room's opponent list.
*/
define t_fight proc public AddPossibleMonster(thing room, theMonster;
int likelihood)void:
AddTail(room@p_rMonsterList, theMonster);
AddTail(room@p_rMonsterChance, likelihood);
room@p_rMonsterTotal := room@p_rMonsterTotal + likelihood;
corp;
define t_fight proc public MonsterMove(thing theMonster; int dir)bool:
false
corp;
/*
* doRunAway - part of RunAwaySoon, and hence of RunAway.
*/
define tp_fight proc doRunAway()void:
int dir;
dir := Random(12);
if MonsterMove(Me(), dir) then
After(1, doRunAway);
fi;
corp;
/*
* RunAwaySoon - the current monster panics and tries hard to leave this
* location. This routine returns a 'status', so that it can be called
* via 'ForceAction'.
*/
define t_fight proc public RunAwaySoon()status:
OPrint(Capitalize(CharacterNameG(Me())) + " panics!\n");
After(0, doRunAway);
continue
corp;
/*
* RunAway - something has happened to cause a monster to want to run away.
* Arrange for it to try to do so. This routine is not normally called
* by the monster that wants to run away, so we use ForceAction and
* After to make it work out right.
*/
define t_fight proc public RunAway(thing theCoward)void:
ignore ForceAction(theCoward, RunAwaySoon);
corp;
/*
* MonsterAction - a monster does one of its random "actions".
*/
define t_fight proc public MonsterAction(thing theMonster)void:
list int li;
string monsterName, s;
int pos, n;
if LightAt(Here()) then
li := theMonster@p_mActionIndexes;
monsterName := Capitalize(CharacterNameG(theMonster));
if li = nil then
OPrint(monsterName + " runs around.\n");
else
s := theMonster@p_mActions;
n := Random(Count(li));
if n = 0 then
pos := 0;
else
pos := li[n - 1];
fi;
n := li[n];
s := SubString(s, pos, n - pos);
OPrint(monsterName + " " + s + ".\n");
fi;
else
OPrint("You hear a noise.\n");
fi;
corp;
/*
* checkMonsterArrival - a monster has moved somewhere - inform each other
* monster that cares.
*/
define tp_fight proc checkMonsterArrival(thing theTarget)void:
action a;
a := theTarget@p_mArriveAction;
if a ~= nil then
call(a, void)(theTarget, Me());
fi;
corp;
/*
* PickNewTarget - the monster has no target here. Randomly pick one.
*/
define tp_fight proc huntTarget(thing theTarget)void:
thing me;
me := Me();
if me@p_mHunting and theTarget@p_pStandard then
me -- p_mHunting;
me@p_pCurrentTarget := theTarget;
ignore MonsterHitPlayer(me, theTarget, Here());
fi;
corp;
define t_fight proc public PickNewTarget()void:
Me()@p_mHunting := true;
ForEachAgent(Here(), huntTarget);
corp;
/*
* MonsterMove - try to move in given direction and fight attacker.
*/
replace MonsterMove(thing theMonster; int dir)bool:
thing theTarget, here;
action a;
if TryToMove(dir) then
MachineMove(dir);
a := theMonster@p_mArrivedAction;
if a ~= nil then
call(a, void)();
fi;
here := Here();
ForEachAgent(here, checkMonsterArrival);
theTarget := theMonster@p_pCurrentTarget;
/* if our current target is here - attack! */
if theTarget ~= nil and AgentLocation(theTarget) = here then
if LightAt(here) then
ignore MonsterHitPlayer(theMonster, theTarget, here);
else
OPrint("You hear a noise.\n");
fi;
elif Random(5) = 0 then
PickNewTarget();
fi;
true
else
false
fi
corp;
/*
* DoMonsterMove - attack target, move in random direction or do "action"
*/
define t_fight proc public DoMonsterMove(thing theMonster)void:
thing theTarget, here;
action a;
here := Here();
if Random(3) = 0 then
theTarget := theMonster@p_pCurrentTarget;
if theTarget ~= nil and AgentLocation(theTarget) = here then
if LightAt(here) then
ignore MonsterHitPlayer(theMonster, theTarget, here);
else
OPrint("You hear a noise.\n");
fi;
elif Random(5) = 0 then
PickNewTarget();
fi;
else
if MonsterMove(theMonster, Random(12)) then
a := theMonster@p_mAfterMoveAction;
if a ~= nil then
call(a, void)();
fi;
else
MonsterAction(theMonster);
fi;
fi;
corp;
/*
* MonsterStillMoving - see if monster leaves, and if so, nuke it.
*/
define t_fight proc public MonsterStillMoving(thing theMonster;
action dieAction)bool:
thing obj, theTarget;
int n, count;
list thing lt;
n := theMonster@p_mMovesUntilVanish;
if n = FOREVER_LIFE then
true
elif n <= 0 then
theMonster@p_mExpired := true;
if dieAction ~= nil then
call(dieAction, void)(theMonster);
fi;
if LightAt(Here()) then
OPrint(Capitalize(CharacterNameG(theMonster)) + " leaves.\n");
ForEachAgent(Here(), UnShowIconOnce);
fi;
theTarget := theMonster@p_pCurrentTarget;
if theTarget ~= nil then
if theTarget@p_pCurrentTarget = theMonster then
theTarget -- p_pCurrentTarget;
fi;
fi;
lt := theMonster@p_pCarrying;
if lt ~= nil then
count := Count(lt);
while count ~= 0 do
count := count - 1;
obj := lt[count];
ZapObject(obj);
DelElement(lt, obj);
od;
fi;
/* After this point, the monster has no properties */
DestroyMachine(theMonster);
/* At this point, the monster does not exist, so this routine must
do nothing but exit. In particular, OPrint is a no-no. */
/* NOTE: because of a possible reference from a player who attacked
the monster and therefore has a reference to its thing as that
player's p_pCurrentTarget, the thing, although emptied out,
will not go away until all such players delete their reference. */
false
else
theMonster@p_mMovesUntilVanish := n - 1;
true
fi
corp;
/*
* MonsterReschedule - setup to do his step again.
*/
define t_fight proc public MonsterReschedule(thing theMonster)void:
int n;
n := theMonster@p_pSpeed;
if n = 0 then
n := 100;
else
n := 100 / n;
fi;
After(Random(n) + 1, theMonster@p_mMoveAction);
corp;
/*
* DummyMonsterInit - init routine that just does the Reschedule.
*/
define t_fight proc public DummyMonsterInit()void:
MonsterReschedule(Me());
corp;
/*
* MonsterInit - initialization of a random moving monster.
*/
define t_fight proc public MonsterInit()void:
thing theMonster;
theMonster := Me();
ignore SetMachineActive(theMonster, theMonster@p_mMoveAction);
if LightAt(Here()) then
OPrint(Capitalize(CharacterNameG(theMonster)) + " has appeared.\n");
ForEachAgent(Here(), ShowIconOnce);
fi;
MonsterReschedule(theMonster);
corp;
/*
* MonsterNoNo - standard monster response to many actions.
*/
define t_fight proc public MonsterNoNo()status:
Print("You don't want to do that!\n");
fail
corp;
GenericMonster@p_pName := "MONSTER;GENERIC".
GenericMonster@p_oTouchChecker := MonsterNoNo.
GenericMonster@p_oSmellChecker := MonsterNoNo.
GenericMonster@p_oPushChecker := MonsterNoNo.
GenericMonster@p_oPullChecker := MonsterNoNo.
GenericMonster@p_oTurnChecker := MonsterNoNo.
GenericMonster@p_oLiftChecker := MonsterNoNo.
GenericMonster@p_oLowerChecker := MonsterNoNo.
GenericMonster@p_oEatChecker := MonsterNoNo.
SetThingStatus(GenericMonster, ts_readonly).
/*
* CreateMonsterModel - create a new model monster.
*/
define t_fight proc public CreateMonsterModel(string name, desc;
action initAction, moveAction;
int hits, speed, protection, accuracy, damage, money)thing:
thing theModel;
theModel := CreateThing(GenericMonster);
SetThingStatus(theModel, ts_readonly);
theModel@p_pName := name;
if desc ~= "" then
theModel@p_pDesc := desc;
else
theModel@p_pDesc := "This is an ordinary " + FormatName(name) + ".";
fi;
if initAction ~= nil then
theModel@p_mInitAction := initAction;
fi;
theModel@p_mMoveAction := moveAction;
theModel@p_pHitMax := hits;
theModel@p_pSpeed := speed;
theModel@p_pProtection := protection;
theModel@p_oAccuracy := accuracy;
theModel@p_oDamage := damage;
if money ~= 0 then
theModel@p_pMoney := money;
fi;
/* Note that we put this extra description on the model, rather than
on the individual monsters. This saves time and space, but can mess
up if some code ends up wanting to add description stuff to
monsters created this way. */
AddFighterDesc(theModel);
theModel
corp;
/*
* AddModelAction - add a 'moves around' action to a model monster.
* Note: keep in mind that these messages are seen by both the player
* involved and by any bystanders. (So don't use 'you'!).
*/
define t_fight proc public AddModelAction(thing theModel; string a)void:
list int li;
int len;
li := theModel@p_mActionIndexes;
if li = nil then
li := CreateIntList();
theModel@p_mActionIndexes := li;
theModel@p_mActions := a;
else
a := theModel@p_mActions + a;
theModel@p_mActions := a;
fi;
AddTail(li, Length(a));
corp;
/*
* checkMonsterCreation - a new monster has arrived. Tell all who care.
*/
define tp_fight proc checkMonsterCreation(thing theOther)void:
action a;
a := theOther@p_mCreateAction;
if a ~= nil then
call(a, void)(theOther, Me()@p_pNewMonster);
fi;
corp;
/*
* CreateMonster - create a new monster with random hitpoints.
* Note: this routine assumes it is called by a player.
*/
define t_fight proc public CreateMonster(thing theCreator,theModel,where)thing:
thing theMonster;
int hits;
theMonster := CreateThing(theModel);
SetupMachine(theMonster);
hits := theModel@p_pHitMax;
hits := hits / 2 + Random(hits / 2) + 1;
theMonster@p_pHitMax := hits;
theMonster@p_pHitNow := hits;
theMonster@p_mMovesUntilVanish := RANDOM_MONSTER_LIFE;
theMonster@p_pCurrentTarget := theCreator;
theMonster@p_mExpired := false;
CreateMachine(theModel@p_pName, theMonster, where, theModel@p_mInitAction);
theCreator@p_pCurrentTarget := theMonster;
Me()@p_pNewMonster := theMonster;
ForEachAgent(where, checkMonsterCreation);
Me() -- p_pNewMonster;
theMonster
corp;
/*
* CreateSpecificMonster - create a copy of a model monster.
*/
define t_fight proc public CreateSpecificMonster(
thing theCreator, theModel, where)thing:
thing theMonster;
theMonster := CreateThing(theModel);
SetupMachine(theMonster);
theMonster@p_pHitNow := theModel@p_pHitMax;
theMonster@p_mMovesUntilVanish := RANDOM_MONSTER_LIFE;
theMonster@p_pCurrentTarget := theCreator;
CreateMachine(theModel@p_pName, theMonster, where, theModel@p_mInitAction);
theCreator@p_pCurrentTarget := theMonster;
Me()@p_pNewMonster := theMonster;
ForEachAgent(where, checkMonsterCreation);
Me() -- p_pNewMonster;
theMonster
corp;
/*
* PickNewMonster - pick a new monster for the player to fight.
* Return the thing of the generated monster, if any.
*/
define t_fight proc public PickNewMonster(thing theCreator, where)thing:
list thing lt;
list int li;
int choice, count;
lt := where@p_rMonsterList;
if lt ~= nil then
li := where@p_rMonsterChance;
choice := Random(where@p_rMonsterTotal);
count := Count(li);
while count ~= 0 and choice >= li[count - 1] do
choice := choice - li[count - 1];
count := count - 1;
od;
if count ~= 0 then
CreateMonster(theCreator, lt[count - 1], where)
else
nil
fi
else
nil
fi
corp;
/* a 'checker' for healing and generating random monsters */
define tp_fight proc monsterEnterCheck()status:
thing me, theMonster;
int i;
me := Me();
i := me@p_pHitCount;
i := i + 1;
if i = STEPS_PER_REGAINED_HIT_POINT then
i := me@p_pHitNow;
if i < me@p_pHitMax then
me@p_pHitNow := i + 1;
fi;
i := 0;
fi;
me@p_pHitCount := i;
theMonster := me@p_pCurrentTarget;
if theMonster = nil and not Here()@p_rNoGenerateMonsters then
theMonster := PickNewMonster(me, Here());
fi;
continue
corp;
/* a 'checker' to let monsters try to hit fleeing players */
define tp_fight proc monsterLeaveCheck(int dir)status:
thing me, theMonster, here;
int n;
status result;
result := continue;
me := Me();
theMonster := me@p_pCurrentTarget;
if theMonster ~= nil then
here := Here();
if AgentLocation(theMonster) = here then
/* the monster I was fighting is still here with me */
n := Random(3);
if n = 0 and theMonster@p_mBlocker then
if LightAt(here) then
Print(Capitalize(CharacterNameG(theMonster)) +
" blocks you.\n");
else
Print("Something blocks you.\n");
fi;
result := fail;
else
if n = 1 and LightAt(here) then
if not MonsterHitPlayer(theMonster, me, here) then
/* player has died - fail the move */
result := fail;
fi;
fi;
me -- p_pCurrentTarget;
fi;
else
me -- p_pCurrentTarget;
fi;
fi;
result
corp;
/*
* StandardAttack - standard code for player attack something.
*/
define t_fight proc public StandardAttack(
thing thePlayer, theTarget, where)void:
int mSpeed;
if theTarget@p_pStandard then
/* a monster set up like a player, e.g. Packrat after being forced
into the proving grounds */
if theTarget@p_pInited then
PlayerHitPlayer(theTarget);
else
Print(Capitalize(CharacterNameS(theTarget)) +
" is not set up for fighting.\n");
fi;
else
mSpeed := theTarget@p_pSpeed;
if Random(thePlayer@p_pSpeed + mSpeed) < mSpeed then
/* monster hits first */
if MonsterHitPlayer(theTarget, thePlayer, where) then
ignore PlayerHitMonster(thePlayer, theTarget);
fi;
else
/* player hits first */
if PlayerHitMonster(thePlayer, theTarget) then
ignore MonsterHitPlayer(theTarget, thePlayer, where);
fi;
fi;
fi;
corp;
/*
* InitFighter - set up a player for fighting. Can be called repeatedly,
* since it checks for duplicates.
*/
define t_fight proc public InitFighter(thing fighter)void:
if not fighter@p_pInited then
fighter@p_pInited := true;
fighter@p_pHitMax := 10;
fighter@p_pHitNow := 10;
fighter@p_pHitCount := 0;
fighter@p_pExperience := 0;
fighter@p_pStrength := 5; /* "standard" strength */
fighter@p_pSpeed := 5; /* "standard" speed */
fighter@p_pProtection := 9; /* armour class +9 */
fighter@p_pLevel := 0;
fighter@p_pDieNotifyList := CreateActionList();
AddPlayerEnterChecker(fighter, monsterEnterCheck, false);
AddPlayerLeaveChecker(fighter, monsterLeaveCheck, false);
SPrint(fighter, "\nCombat initialized!\n\n");
fi;
corp;
/*
* LeaveFighting - utility to call when leaving a fighting area. It returns
* 'fail' for monsters, to keep them in, 'succeed' for players. Is
* suitable for a regular move checker.
*/
define t_fight proc public LeaveFighting()status:
thing fighter;
fighter := Me();
if fighter@p_pInited then
/* a player or someone like Packrat */
continue
else
/* must be a monster - don't let them out */
fail
fi
corp;
/*
* HealingBuy - routine to buy healing at a healer.
*/
define t_fight proc public HealingBuy(string what)bool:
thing me;
me := Me();
if me@p_pHitNow >= me@p_pHitMax then
Print("The proprietor looks at you for a moment, and then frowns "
"in puzzlement and says: 'But you are in perfect health!'\n");
false
else
StoreBuy(what)
fi
corp;
/************************\
* *
* The new commands added *
* *
\************************/
define tp_fight proc v_status(string who)bool:
thing me;
me := Me();
if who == "full" then
if me@p_pInited then
showStats(me, true);
true
else
Print("There is no combat status to show you.\n");
false
fi
elif who ~= "" and IsWizard() then
me := FindAgent(who);
if me ~= nil then
showStats(me, true);
true
else
Print("There is no " + who + " here.\n");
false
fi
else
if me@p_pInited then
showStats(me, false);
true
else
Print("There is no combat status to show you.\n");
false
fi
fi
corp;
define tp_fight proc v_wield(string what)bool:
VerbCarry("wield", nil, p_oWieldChecker, p_pWieldChecker,
"You cannot wield", what)
corp;
/*
* v_hit - the basic attacking verb.
*/
define tp_fight proc v_hit(string what)bool:
thing me, theTarget, here;
action a;
me := Me();
here := Here();
if what = "" then
Print("You must specify who or what you want to attack.\n");
false
elif not me@p_pInited then
Print("You are not yet set up for fighting.\n");
false
elif not CanSee(here, me) then
Print("You can't see to fight.\n");
false
elif here@p_rMonsterList = nil then
Print("This is a non-combat area.\n");
false
else
theTarget := FindAgent(what);
if theTarget = nil then
if FindName(here@p_rContents, p_oName, what) ~= fail or
FindName(me@p_pCarrying, p_oName, what) ~= fail or
MatchName(here@p_rScenery, what) ~= -1
then
Print("You can only attack players or monsters.\n");
else
Print(IsAre("There", "no", FormatName(what), "here.\n"));
fi;
false
else
if ThingCharacter(theTarget) ~= nil then
if theTarget = me then
Print("Masochism is not implemented.\n");
else
/* attacking another player */
PlayerHitPlayer(theTarget);
fi;
else
/* attacking a monster */
a := theTarget@p_mFightAction;
if a ~= nil then
call(a, void)(theTarget);
else
StandardAttack(me, theTarget, here);
fi;
fi;
true
fi
fi
corp;
/*
* verbs to allow briefer output during combat.
*/
define tp_fight proc v_fightterse()bool:
thing me;
me := Me();
if me@p_pFightTerse and not me@p_pFightSuperTerse then
Print("You are already in fightterse mode.\n");
false
else
me -- p_pFightSuperTerse;
me@p_pFightTerse := true;
Print("fightterse mode set.\n");
true
fi
corp;
define tp_fight proc v_fightsuperterse()bool:
thing me;
me := Me();
if me@p_pFightSuperTerse then
Print("You are already in fightsuperterse mode.\n");
false
else
me@p_pFightTerse := true;
me@p_pFightSuperTerse := true;
Print("fightsuperterse mode set.\n");
true
fi
corp;
define tp_fight proc v_fightverbose()bool:
thing me;
me := Me();
if not me@p_pFightTerse then
Print("You are already in fightverbose mode.\n");
false
else
me -- p_pFightTerse;
me -- p_pFightSuperTerse;
Print("fightverbose mode set.\n");
true
fi
corp;
Verb1(G, "status", 0, v_status).
Synonym(G, "status", "st").
Verb1(G, "wield", 0, v_wield).
Verb1(G, "hit", 0, v_hit).
Synonym(G, "hit", "fight").
Synonym(G, "hit", "attack").
Synonym(G, "hit", "kill").
Synonym(G, "hit", "h").
Synonym(G, "hit", "k").
Verb0(G, "fightterse", 0, v_fightterse).
Synonym(G, "fightterse", "fightbrief").
Verb0(G, "fightsuperterse", 0, v_fightsuperterse).
Synonym(G, "fightsuperterse", "fightsuperbrief").
Verb0(G, "fightverbose", 0, v_fightverbose).
unuse tp_fight