/* /lib/npc.c * from the Dead Souls LPC Library * the standard non-player character object * created by Descartes of Borg 950323 * Version: @(#) npc.c 1.11@(#) * Last Modified: 96/12/21 */ #include <lib.h> #include <daemons.h> #include <position.h> #include <armour_types.h> #include <message_class.h> #include "include/npc.h" inherit LIB_CHAT; inherit LIB_COMMAND; inherit LIB_CONTAINER; inherit LIB_LIVING; inherit LIB_MESSAGES; inherit LIB_MOVE; inherit LIB_OBJECT; private int ActionChance, CombatActionChance; private mixed Encounter; private string *EnemyNames; private static int Level, Unique; private static mixed Die, Action, CombatAction; private static mapping Inventory; static void create() { AddSave( ({ "CarriedMass" }) ); SetSaveRecurse(1); chat::create(); command::create(); living::create(); messages::create(); object::create(); Setup(); SetPK(1); SetOpacity(0); EnemyNames = ({}); Encounter = 0; ActionChance = 0; Unique = 0; Inventory = ([]); } static void init() { string *enemies; if( !query_heart_beat() ) { eventCheckHealing(); set_heart_beat( GetHeartRate() ); } if( sizeof(enemies = GetEnemyNames()) ) { if( member_array((string)this_player()->GetKeyName(),enemies) != -1 ) { eventExecuteAttack(this_player()); return; } } if( Encounter ) { int x = 0; if( functionp(Encounter) ) { x = (int)evaluate(Encounter, this_player()); } else if( arrayp(Encounter) ) { if( member_array(this_player()->GetKeyName(), Encounter) > -1 ) { x = 1; } else { x = 1; } } else if( (int)this_player()->GetStatLevel("charisma") < Encounter ) { x = 1; } if( x ) { SetAttack(this_player()); } } } static void heart_beat() { int position; living::heart_beat(); if( !ContinueHeart() ) { set_heart_beat(0); return; } position = GetPosition(); if( position == POSITION_LYING || position == POSITION_SITTING ) { eventForce("stand up"); } if( !GetInCombat() && ActionChance > random(100) ) { int x; if( functionp(Action) ) evaluate(Action); else if( pointerp(Action) && (x = sizeof(Action)) ) { string act; act = Action[random(x)]; if( act && act != "" && act[0] == '!' && act != "!" ) { act = act[1..]; eventForce(act); } else message("other_action", act, environment()); } } else if( GetInCombat() && CombatActionChance > random(100) ) { int x; if( functionp(CombatAction) ) evaluate(CombatAction); else if( pointerp(CombatAction) && (x = sizeof(CombatAction)) ) { string act; act = CombatAction[random(x)]; if( act && act != "" && act[0] == '!' && act != "!" ) { act = act[1..]; eventForce(act); } else message("other_action", act, environment()); } } } void receive_message(string cl, string msg) { catch_tell(msg); } void catch_tell(string msg) { } static int Destruct() { if( GetParty() ) PARTY_D->eventLeaveParty(this_object()); living::Destruct(); return object::Destruct(); } void eventReconnect() { } /* *************** /lib/npc.c command functions ************** */ static int cmdAll(string arg) { object env; string verb; verb = query_verb(); env = environment(); if( chat::chat_command(verb + " " + arg) == "" ) return 1; return command::cmdAll(arg); } /* *************** /lib/npc.c events *************** */ int eventCompleteMove(mixed dest) { mixed val; string file; int x; if( environment() ) return move::eventMove(dest); else x = move::eventMove(dest); if( !x ) return x; foreach(file, val in Inventory) { object ob; if( intp(val) ) { if( val < 0 ) { ob = unique(file, -val); if( ob ) ob->eventMove(this_object()); } else while(val--) if( ob = new(file) ) ob->eventMove(this_object()); } else if( stringp(val) ) { if( !(ob = new(file)) ) continue; if( ob->eventMove(this_object()) ) eventForce(val); } else if( functionp(val) ) { if( !(ob = new(file)) ) continue; if( ob->eventMove(this_object()) ) evaluate(val); } } return x; } int eventDestruct() { chat::eventDestruct(); object::eventDestruct(); } varargs int eventDie(object agent) { int x; if( (x = living::eventDie(agent)) != 1 ) return x; if( stringp(Die) ) { message("other_action", Die, environment(), ({ this_object() })); if( agent) message("my_action", "You kill " + GetName() + ".", agent); } else if( functionp(Die) && !evaluate(Die, agent) ) return 0; else { message("other_action", "%^BOLD%^%^RED%^"+ GetName() + " drops dead.", environment(), ({ this_object() }) ); if( agent ) message("my_action", "You kill " + GetName() + ".", agent); } set_heart_beat(0); call_out( (: Destruct :), 0); return 1; } mixed eventTurn(object who) { if( !living::eventTurn(who) ) { return 0; } all_inventory()->eventDestruct(); call_out((: Destruct :), 0); return 1; } void eventEnemyDied(object ob) { living::eventEnemyDied(ob); EnemyNames -= ({ (string)ob->GetKeyName() }); } int eventMove(mixed dest) { int ret; ret = eventCompleteMove(dest); eventMoveFollowers(environment(this_object())); return ret; } varargs int eventMoveLiving(mixed dest, string omsg, string imsg) { object *inv; object prev, env; string msgclass; if( prev = environment() ) { if( stringp(dest) ) { if(dest[0] != '/') { string *arr; arr = explode(file_name(prev), "/"); dest = "/"+implode(arr[0..sizeof(arr)-2], "/")+"/"+dest; } } if( !eventCompleteMove(dest) ) { eventPrint("You remain where you are."); return 0; } inv = filter(all_inventory(prev), (: (!GetInvis($1) && living($1) && ($1 != this_object())) :)); if( !omsg || omsg == "" ) omsg = GetMessage("telout"); else omsg = GetMessage("leave", omsg); inv->eventPrint(omsg, MSG_ENV); } else if( !eventCompleteMove(dest) ) { eventPrint("You remain where you are."); return 0; } inv = filter(all_inventory(environment()), (: (!GetInvis($1) && living($1) && ($1 != this_object())) :)); if( (!imsg || imsg == "") && (!omsg || omsg == "") ) imsg = GetMessage(msgclass = "telin"); else if( !imsg || imsg == "" ) imsg = GetMessage(msgclass = "come", imsg); else imsg = replace_string(imsg, "$N", GetName()); inv->eventPrint(imsg, MSG_ENV); eventMoveFollowers(environment(this_player())); return 1; } varargs int eventPrint(string msg, mixed arg2, mixed arg3) { return 1; } int eventReceiveObject() { object ob; ob = previous_object(); if( !ob || !container::eventReceiveObject() ) return 0; AddCarriedMass((int)ob->GetMass()); return 1; } int eventReleaseObject() { object ob; ob = previous_object(); if( !ob || !container::eventReleaseObject() ) return 0; AddCarriedMass( -((int)ob->GetMass()) ); return 1; } varargs int eventShow(object who, string str) { if( !living::eventShow(who, str) ) return 0; eventPrint((string)this_player()->GetName() + " looks you over."); return 1; } /* *************** /lib/npc.c modal functions *************** */ int CanCarry(int amount) { return living::CanCarry(amount); } mixed CanGet(object who) { return GetName() + " is a living being!"; } int CanReceive(object ob) { return CanCarry((int)ob->GetMass()); } /* *************** /lib/npc.c lfuns *************** */ static int ContinueHeart() { object env; if( !(env = environment()) ) return 0; if( !sizeof(filter(all_inventory(env), (: userp :))) ) return 0; return 1; } /* *************** /lib/npc.c data functions *************** */ mapping SetInventory(mapping mp ) { return (Inventory = mp); } varargs string SetRace(string race, mixed extra) { race = living::SetRace(race, extra); eventCompleteHeal(GetMaxHealthPoints()); return race; } string SetClass(string cls) { string *skills; int x, i; cls = living::SetClass(cls); x = Level; i = sizeof(skills = GetSkills()); while(i--) { int y; y = (GetSkillClass(skills[i]) || 5); SetSkill(skills[i], (3*x)/y, y); } return cls; } int SetLevel(int x) { string *tmp; int i; Level = x; i = sizeof(tmp = GetSkills()); while(i--) { int y; y = (GetSkillClass(tmp[i]) || 5); SetSkill(tmp[i], (3*x)/y, y); } i = sizeof(tmp = GetStats()); while(i--) { int y; y = (GetStatClass(tmp[i]) || 5); SetStat(tmp[i], ((5-y)*10) + (3*x)/y, y); } eventCompleteHeal(GetMaxHealthPoints()); return Level; } int GetLevel() { return Level; } int SetHealthPoints(int x) { if( x > GetMaxHealthPoints() ) SetStat("durability", (x-50)/10, GetStatClass("durability")); AddHealthPoints( x - GetHealthPoints() ); return GetHealthPoints(); } int SetMaxHealthPoints(int x) { SetStat("durability", to_int((x-50)/10), GetStatClass("durability")); return GetMaxHealthPoints(); } int SetMagicPoints(int x) { if( x > GetMaxMagicPoints() ) SetStat("intelligence", (x-50)/10, GetStatClass("intelligence")); AddMagicPoints( x - GetMagicPoints() ); return GetMagicPoints(); } int SetMaxMagicPoints(int x) { SetStat("intelligence", (x-50)/10, GetStatClass("intelligence")); return GetMaxMagicPoints(); } float SetStaminaPoints(float x) { if( x > GetMaxStaminaPoints() ) SetStat("agility", to_int((x-50.0)/10.0), GetStatClass("agility")); AddStaminaPoints( x - GetStaminaPoints() ); return to_float(GetStaminaPoints()); } float SetMaxStaminaPoints(float x) { SetStat("agility", (x-50.0)/10.0, GetStatClass("agility")); return GetMaxStaminaPoints(); } varargs void SetCurrency(mixed val, int amount) { if( stringp(val) ) AddCurrency(val, amount - GetCurrency(val)); else if( mapp(val) ) { string *currs; int i; i = sizeof(currs = keys(val)); while(i--) AddCurrency(currs[i], val[currs[i]]-GetCurrency(currs[i])); } else error("Bad argument 1 to SetCurrency()."); } mixed SetEncounter(mixed val) { return (Encounter = val); } string *AddEncounter(string nom) { if( !stringp(nom) ) error("Bad argument 1 to AddEncounter()\n"); if( Encounter && !pointerp(Encounter) ) return 0; else Encounter += ({ convert_name(nom) }); return Encounter; } string *RemoveEncounter(string nom) { if( !stringp(nom) ) error("Bad argument 1 to RemoveEncounter()\n"); if( Encounter && !pointerp(Encounter) ) return 0; else Encounter -= ({ convert_name(nom) }); return Encounter; } mixed GetEncounter() { return Encounter; } mixed SetDie(mixed val) { return (Die = val); } mixed GetDie() { return Die; } string SetKeyName(string nom) { set_living_name(nom = object::SetKeyName(nom)); return nom; } string GetName() { return object::GetName(); } string GetCapName() { return object::GetCapName(); } string GetShort() { return object::GetShort(); } varargs string GetLong(string str) { mapping counts; string item, what; float h; str = object::GetLong() + "\n"; what = "The "+GetGender()+" "+GetRace(); str += living::GetLong(what); foreach(item in map(all_inventory(), (: (string)$1->GetAffectLong(this_object()) :))) if( item ) str += item + "\n"; counts = ([]); foreach(item in map(all_inventory(),(: (string)$1->GetEquippedShort() :))) if( item ) counts[item]++; if( sizeof(counts) ) str += GetCapName() + " is carrying:\n"; foreach(item in keys(counts)) str += capitalize(consolidate(counts[item], item)) + "\n"; return str; } void SetAction(int chance, mixed val) { ActionChance = chance; if( stringp(val) ) val = ({ val }); else if( !functionp(val) && !pointerp(val) ) error("Bad argument 2 to SetAction()\n"); Action = val; } mixed GetAction() { return Action; } void SetCombatAction(int chance, mixed val) { CombatActionChance = chance; if( stringp(val) ) val = ({ val }); else if( !functionp(val) && !pointerp(val) ) error("Bad argument 2 to SetCombatAction()\n"); CombatAction = val; } mixed GetCombatAction() { return CombatAction; } int AddCarriedMass(int x) { return living::AddCarriedMass(x); } mixed *GetCommands() { return commands(); } int SetUnique(int x) { Unique = x; if( Unique ) UNIQUE_D->eventTouchObject(); return Unique; } int GetUnique() { return Unique; } string GetCommandFail() { return "What?"; } int AddEnemy(object ob) { string tmp; if( !living::AddEnemy(ob) ) return 0; if( member_array(tmp = (string)ob->GetKeyName(), EnemyNames) == -1 ) EnemyNames += ({ tmp }); return 1; } string *GetEnemyNames() { return EnemyNames; } int GetRadiantLight(int ambient) { return (object::GetRadiantLight(ambient) + container::GetRadiantLight(ambient)); } int *GetScreen() { return ({ 80, 24 }); }