blob: d73ebed431630166975aad282bfd503e4c955ba5 [file] [log] [blame]
// MorgenGrauen MUDlib
//
// inpc/select.c -- Beste Ausruestung suchen
//
// $Id: select.c 6998 2008-08-24 17:17:46Z Zesstra $
#pragma strong_types
#pragma save_types
#pragma range_check
#pragma no_clone
#pragma pedantic
#define NEED_PROTOTYPES
#include <thing.h>
#include <living.h>
#include <inpc.h>
#include <properties.h>
#include <combat.h>
#include <language.h>
#define ME this_object()
mapping scan_objects(mixed src) {
// Ermittelt zu jedem Typ (Waffe, Ruestungstyp...) alle Objekte diesen Typs
// Gesucht wird: - Im Inventory, falls Objekt angegeben
// - Im Array, falls Array angegeben
object *obs;
mapping res;
mixed x;
int i,cost,cost_limit;
if (mappingp(src))
return src;
res=([]);
if (objectp(src))
src=all_inventory(src);
if (!pointerp(src))
src=({src});
cost_limit = get_eval_cost()/3;
foreach(object ob: src)
{
if ( (cost=get_eval_cost()) < cost_limit )
{
log_file("rochus/raeuber_eval",
ctime()+"select::scan_objects(). Rest "+to_string(cost)+
", i="+to_string(i)+", Size "+to_string(sizeof(src))+".\n");
return res;
break;
}
if (!objectp(ob))
continue;
if (x=ob->QueryProp(P_ARMOUR_TYPE))
;
else if (ob->QueryProp(P_WEAPON_TYPE))
x=OT_WEAPON;
else if (ob->QueryProp(P_COMBATCMDS))
x=OT_COMBAT_OBJECT;
else
x=OT_MISC;
if (!pointerp(obs=res[x]))
obs=({});
obs+=({ob});
res[x]=obs;
}
return res;
}
mixed *find_object_by_type(mixed from, mixed typ) {
// Findet all Objekte eines Typs, z.B. alle Waffen im Monster
// <from> kann auch ein Mapping sein, das schon die mit scan_objects
// erstellt Klassifikation enthaelt, damit diese nicht mehrfach
// erstellt werden muss.
mixed res;
if (!mappingp(from))
from=scan_objects(from);
if (!mappingp(from) ||
!pointerp(res=from[typ]))
return ({});
return res;
}
int eval_weapon(object ob) {
return ob->QueryProp(P_WC);
}
object find_best_weapon(mixed from) {
// Findet die beste Waffe
int i,wc,bwc,cost,cost_limit;
object *res,bob;
if (!pointerp(res=find_object_by_type(from, OT_WEAPON)))
return 0;
bwc=-1;bob=0;
cost_limit = get_eval_cost()/3;
for (i=sizeof(res);i--;)
foreach(object ob: res)
{
if (!objectp(ob)) continue;
wc=eval_weapon(ob);
if (wc>bwc)
{
bob=ob;
bwc=wc;
}
if ( (cost=get_eval_cost()) < cost_limit )
{
log_file("rochus/raeuber_eval",
"Break in select::find_best_weapon(). Rest-Ticks "+to_string(cost)+
", i = "+to_string(i)+", Size "+to_string(sizeof(res))+".\n");
return bob; // zurueckgeben, was bisher drinsteht.
break;
}
}
return bob;
}
varargs int wield_best_weapon(mixed from) {
// Zueckt die beste Waffe.
// Sollte mit command("zuecke_beste_waffe") aufgerufen werden,
// damit this_player() richtig gesetzt wird.
object ob,old;
// Einige NPC moegen keine Waffen. Zum Beispiel Karate-Gilden-NPC
// Durch Setzen von INPC_DONT_WIELD_WEAPONS kann man das Zuecken verhindern
if(QueryProp(INPC_DONT_WIELD_WEAPONS)) return 0;
if (!from)
from=ME;
if (!objectp(ob=find_best_weapon(from)))
return 0;
if (objectp(old=QueryProp(P_WEAPON)) && old!=ob) {
old->RemoveId(INPC_BEST_WEAPON_ID);
old->DoUnwield();
}
if (!ob->id(INPC_BEST_WEAPON_ID))
ob->AddId(INPC_BEST_WEAPON_ID);
return ob->DoWield();
}
int eval_armour(object ob) {
return ob->QueryProp(P_AC);
}
object find_best_armour(mixed from, mixed typ) {
// Findet die beste Ruestung eines Typs
int i,ac,bac;
object *res,bob;
if (!pointerp(res=find_object_by_type(from, typ)))
return 0;
bac=-1;
bob=0;
foreach(object ob: res)
{
if (!objectp(ob)) continue;
ac=eval_armour(ob);
if (ac>bac)
{
bob=ob;
bac=ac;
}
}
return bob;
}
object *find_best_armours(mixed from) {
// Findet die besten Ruestungen, die gleichzeitig getragen werden koennen
mapping ol;
object *res,ob;
mixed *types;
int i;
if (!mappingp(ol=scan_objects(from)))
return ({});
if (!pointerp(res=ol[AT_MISC]))
res=({});
types=m_indices(ol);
foreach(object typ: types)
{
if (VALID_ARMOUR_CLASS[typ]) // anderer Armour-Typ ausser AT_MISC?
{
ob=find_best_armour(from,typ);
if (objectp(ob))
res+=({ob});
}
}
return res;
}
varargs int wear_best_armours(mixed from) {
// Die besten Ruestungen werden angezogen
// Sollte mit command("trage_beste_ruestungen") aufgerufen werden,
// damit this_player() richtig gesetzt wird.
object *na,*oa,*diff;
int i,cost,cost_limit;
if (!from)
from=ME;
if (!pointerp(na=find_best_armours(from)))
return 0;
if (!pointerp(oa=QueryProp(P_ARMOURS)))
oa=({});
diff=oa-na;
cost_limit = get_eval_cost()/3;
foreach(object di: diff)
{
di->RemoveId(INPC_BEST_SHIELD_ID);
di->DoUnwear();
if ( (cost=get_eval_cost()) < cost_limit )
{
log_file("rochus/raeuber_eval",
ctime()+"Break 1 in select::wear_best_armours(). Rest "+
to_string(cost)+", i="+to_string(i)+", Size "+
to_string(sizeof(diff))+".\n");
return 1; // zurueckgeben, was bisher drinsteht.
break;
}
}
diff=na-oa;
cost_limit = get_eval_cost()/3;
foreach(object di: diff)
{
if ( di->QueryProp(P_ARMOUR_TYPE)==AT_SHIELD
&& !di->id(INPC_BEST_SHIELD_ID))
di->AddId(INPC_BEST_SHIELD_ID);
di->do_wear("alles");
if ( (cost=get_eval_cost()) < cost_limit )
{
log_file("rochus/raeuber_eval",
ctime()+"Break 2 in select::wear_best_armours(). Rest "+
to_string(cost)+", i="+to_string(i)+", Size "+
to_string(sizeof(diff))+".\n");
return 1; // zurueckgeben, was bisher drinsteht.
break;
}
}
return 1;
}
int eval_combat_object(object ob, mapping vals, object enemy) {
return 0;
}
varargs string
find_best_combat_command(mixed from, object enemy, mapping pref) {
// Sucht den guenstigsten Befehl zur Benutzung einer Sonderwaffe heraus
object *obs;
mixed *ind,y,vul;
mapping x;
string best;
int i,j,max,val,mhp;
if (!from)
from=ME;
if (!enemy)
enemy=SelectEnemy();
if (!mappingp(pref)) // bevorzugte Eigenschaften
pref=([C_MIN:5,
C_AVG:10,
C_MAX:2,
C_HEAL:10
]);
best=0;max=-1;
if (!pointerp(obs=find_object_by_type(from,OT_COMBAT_OBJECT)))
return best;
mhp=QueryProp(P_MAX_HP)-QueryProp(P_HP);
if (objectp(enemy))
vul=enemy->QueryProp(P_RESISTANCE_STRENGTHS);
if (mhp<0) mhp=0;
foreach(object ob: obs)
{
if (!objectp(ob))
continue;
if (!mappingp(x=ob->QueryProp(P_COMBATCMDS)))
continue;
ind=m_indices(x);
for (j=sizeof(ind)-1;j>=0;j--)
{
if (!stringp(ind[j])) continue;
y=x[ind[j]];
if (mappingp(y))
{
if (val=y[C_HEAL])
{
if (val>mhp) val=mhp; // Nur MOEGLICHE Heilung beruecksichtigen
val*=pref[C_HEAL];
}
else
{
val=y[C_MIN]*pref[C_MIN]
+ y[C_AVG]*pref[C_AVG]
+ y[C_MAX]*pref[C_MAX];
// auskommentiert, da eval_resistance() bisher nicht implementiert
// ist. Zesstra, 06.08.2007
//if (y[C_DTYPES] && vul) // Vulnerability des Gegners bedenken...
// val=(int)(((float)val)*(1.0+eval_resistance(y[C_DTYPES],vul)));
}
}
else
{
val=1;
}
val+=eval_combat_object(obs[i],y,enemy);
if (val<max) continue;
max=val;
if (mappingp(y) && y[C_HEAL]>0)
best=sprintf(ind[j],name(RAW)); // Heilung auf sich selbst
else if (objectp(enemy))
best=sprintf(ind[j],enemy->name(RAW)); // Schaden auf Gegner
}
}
return best;
}
varargs int use_best_combat_command(mixed enemy, mixed from, mapping pref) {
// Fuehrt moeglichst guten Kampfeinsatz mit einer Sonderwaffe aus
string str;
if (stringp(enemy) && environment())
enemy=present(enemy,environment());
if (str=find_best_combat_command(from,enemy,pref))
return command(str);
return 0;
}
void add_select_commands() {
add_action("wield_best_weapon","zuecke_beste_waffe");
add_action("wear_best_armours","trage_beste_ruestungen");
add_action("use_best_combat_command","benutze_beste_sonderwaffe");
}