blob: d73ebed431630166975aad282bfd503e4c955ba5 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// inpc/select.c -- Beste Ausruestung suchen
4//
5// $Id: select.c 6998 2008-08-24 17:17:46Z Zesstra $
6#pragma strong_types
7#pragma save_types
8#pragma range_check
9#pragma no_clone
10#pragma pedantic
11
12#define NEED_PROTOTYPES
13
14#include <thing.h>
15#include <living.h>
16#include <inpc.h>
17#include <properties.h>
18#include <combat.h>
19#include <language.h>
20
21#define ME this_object()
22
23mapping scan_objects(mixed src) {
24 // Ermittelt zu jedem Typ (Waffe, Ruestungstyp...) alle Objekte diesen Typs
25 // Gesucht wird: - Im Inventory, falls Objekt angegeben
26 // - Im Array, falls Array angegeben
27 object *obs;
28 mapping res;
29 mixed x;
30 int i,cost,cost_limit;
31
32 if (mappingp(src))
33 return src;
34 res=([]);
35 if (objectp(src))
36 src=all_inventory(src);
37 if (!pointerp(src))
38 src=({src});
39
40 cost_limit = get_eval_cost()/3;
41 foreach(object ob: src)
42 {
43 if ( (cost=get_eval_cost()) < cost_limit )
44 {
45 log_file("rochus/raeuber_eval",
46 ctime()+"select::scan_objects(). Rest "+to_string(cost)+
47 ", i="+to_string(i)+", Size "+to_string(sizeof(src))+".\n");
48 return res;
49 break;
50 }
51 if (!objectp(ob))
52 continue;
53 if (x=ob->QueryProp(P_ARMOUR_TYPE))
54 ;
55 else if (ob->QueryProp(P_WEAPON_TYPE))
56 x=OT_WEAPON;
57 else if (ob->QueryProp(P_COMBATCMDS))
58 x=OT_COMBAT_OBJECT;
59 else
60 x=OT_MISC;
61 if (!pointerp(obs=res[x]))
62 obs=({});
63 obs+=({ob});
64 res[x]=obs;
65 }
66 return res;
67}
68
69mixed *find_object_by_type(mixed from, mixed typ) {
70 // Findet all Objekte eines Typs, z.B. alle Waffen im Monster
71 // <from> kann auch ein Mapping sein, das schon die mit scan_objects
72 // erstellt Klassifikation enthaelt, damit diese nicht mehrfach
73 // erstellt werden muss.
74 mixed res;
75
76 if (!mappingp(from))
77 from=scan_objects(from);
78 if (!mappingp(from) ||
79 !pointerp(res=from[typ]))
80 return ({});
81 return res;
82}
83
84int eval_weapon(object ob) {
85 return ob->QueryProp(P_WC);
86}
87
88object find_best_weapon(mixed from) {
89 // Findet die beste Waffe
90 int i,wc,bwc,cost,cost_limit;
91 object *res,bob;
92
93 if (!pointerp(res=find_object_by_type(from, OT_WEAPON)))
94 return 0;
95 bwc=-1;bob=0;
96
97 cost_limit = get_eval_cost()/3;
98 for (i=sizeof(res);i--;)
99 foreach(object ob: res)
100 {
101 if (!objectp(ob)) continue;
102 wc=eval_weapon(ob);
103 if (wc>bwc)
104 {
105 bob=ob;
106 bwc=wc;
107 }
108
109 if ( (cost=get_eval_cost()) < cost_limit )
110 {
111 log_file("rochus/raeuber_eval",
112 "Break in select::find_best_weapon(). Rest-Ticks "+to_string(cost)+
113 ", i = "+to_string(i)+", Size "+to_string(sizeof(res))+".\n");
114 return bob; // zurueckgeben, was bisher drinsteht.
115 break;
116 }
117 }
118 return bob;
119}
120
121varargs int wield_best_weapon(mixed from) {
122 // Zueckt die beste Waffe.
123 // Sollte mit command("zuecke_beste_waffe") aufgerufen werden,
124 // damit this_player() richtig gesetzt wird.
125 object ob,old;
126
127 // Einige NPC moegen keine Waffen. Zum Beispiel Karate-Gilden-NPC
128 // Durch Setzen von INPC_DONT_WIELD_WEAPONS kann man das Zuecken verhindern
129 if(QueryProp(INPC_DONT_WIELD_WEAPONS)) return 0;
130
131 if (!from)
132 from=ME;
133
134 if (!objectp(ob=find_best_weapon(from)))
135 return 0;
136 if (objectp(old=QueryProp(P_WEAPON)) && old!=ob) {
137 old->RemoveId(INPC_BEST_WEAPON_ID);
138 old->DoUnwield();
139 }
140 if (!ob->id(INPC_BEST_WEAPON_ID))
141 ob->AddId(INPC_BEST_WEAPON_ID);
142
143 return ob->DoWield();
144}
145
146int eval_armour(object ob) {
147 return ob->QueryProp(P_AC);
148}
149
150object find_best_armour(mixed from, mixed typ) {
151 // Findet die beste Ruestung eines Typs
152 int i,ac,bac;
153 object *res,bob;
154
155 if (!pointerp(res=find_object_by_type(from, typ)))
156 return 0;
157 bac=-1;
158 bob=0;
159 foreach(object ob: res)
160 {
161 if (!objectp(ob)) continue;
162 ac=eval_armour(ob);
163 if (ac>bac)
164 {
165 bob=ob;
166 bac=ac;
167 }
168 }
169 return bob;
170}
171
172object *find_best_armours(mixed from) {
173 // Findet die besten Ruestungen, die gleichzeitig getragen werden koennen
174 mapping ol;
175 object *res,ob;
176 mixed *types;
177 int i;
178
179 if (!mappingp(ol=scan_objects(from)))
180 return ({});
181 if (!pointerp(res=ol[AT_MISC]))
182 res=({});
183 types=m_indices(ol);
184 foreach(object typ: types)
185 {
186 if (VALID_ARMOUR_CLASS[typ]) // anderer Armour-Typ ausser AT_MISC?
187 {
188 ob=find_best_armour(from,typ);
189 if (objectp(ob))
190 res+=({ob});
191 }
192 }
193 return res;
194}
195
196varargs int wear_best_armours(mixed from) {
197 // Die besten Ruestungen werden angezogen
198 // Sollte mit command("trage_beste_ruestungen") aufgerufen werden,
199 // damit this_player() richtig gesetzt wird.
200 object *na,*oa,*diff;
201 int i,cost,cost_limit;
202
203 if (!from)
204 from=ME;
205 if (!pointerp(na=find_best_armours(from)))
206 return 0;
207 if (!pointerp(oa=QueryProp(P_ARMOURS)))
208 oa=({});
209 diff=oa-na;
210 cost_limit = get_eval_cost()/3;
211 foreach(object di: diff)
212 {
213 di->RemoveId(INPC_BEST_SHIELD_ID);
214 di->DoUnwear();
215 if ( (cost=get_eval_cost()) < cost_limit )
216 {
217 log_file("rochus/raeuber_eval",
218 ctime()+"Break 1 in select::wear_best_armours(). Rest "+
219 to_string(cost)+", i="+to_string(i)+", Size "+
220 to_string(sizeof(diff))+".\n");
221 return 1; // zurueckgeben, was bisher drinsteht.
222 break;
223 }
224 }
225 diff=na-oa;
226 cost_limit = get_eval_cost()/3;
227 foreach(object di: diff)
228 {
229 if ( di->QueryProp(P_ARMOUR_TYPE)==AT_SHIELD
230 && !di->id(INPC_BEST_SHIELD_ID))
231 di->AddId(INPC_BEST_SHIELD_ID);
232 di->do_wear("alles");
233 if ( (cost=get_eval_cost()) < cost_limit )
234 {
235 log_file("rochus/raeuber_eval",
236 ctime()+"Break 2 in select::wear_best_armours(). Rest "+
237 to_string(cost)+", i="+to_string(i)+", Size "+
238 to_string(sizeof(diff))+".\n");
239 return 1; // zurueckgeben, was bisher drinsteht.
240 break;
241 }
242 }
243 return 1;
244}
245
246int eval_combat_object(object ob, mapping vals, object enemy) {
247 return 0;
248}
249
250varargs string
251find_best_combat_command(mixed from, object enemy, mapping pref) {
252 // Sucht den guenstigsten Befehl zur Benutzung einer Sonderwaffe heraus
253 object *obs;
254 mixed *ind,y,vul;
255 mapping x;
256 string best;
257 int i,j,max,val,mhp;
258
259 if (!from)
260 from=ME;
261 if (!enemy)
262 enemy=SelectEnemy();
263 if (!mappingp(pref)) // bevorzugte Eigenschaften
264 pref=([C_MIN:5,
265 C_AVG:10,
266 C_MAX:2,
267 C_HEAL:10
268 ]);
269 best=0;max=-1;
270 if (!pointerp(obs=find_object_by_type(from,OT_COMBAT_OBJECT)))
271 return best;
272 mhp=QueryProp(P_MAX_HP)-QueryProp(P_HP);
273 if (objectp(enemy))
274 vul=enemy->QueryProp(P_RESISTANCE_STRENGTHS);
275 if (mhp<0) mhp=0;
276 foreach(object ob: obs)
277 {
278 if (!objectp(ob))
279 continue;
280 if (!mappingp(x=ob->QueryProp(P_COMBATCMDS)))
281 continue;
282 ind=m_indices(x);
283 for (j=sizeof(ind)-1;j>=0;j--)
284 {
285 if (!stringp(ind[j])) continue;
286 y=x[ind[j]];
287 if (mappingp(y))
288 {
289 if (val=y[C_HEAL])
290 {
291 if (val>mhp) val=mhp; // Nur MOEGLICHE Heilung beruecksichtigen
292 val*=pref[C_HEAL];
293 }
294 else
295 {
296 val=y[C_MIN]*pref[C_MIN]
297 + y[C_AVG]*pref[C_AVG]
298 + y[C_MAX]*pref[C_MAX];
299 // auskommentiert, da eval_resistance() bisher nicht implementiert
300 // ist. Zesstra, 06.08.2007
301 //if (y[C_DTYPES] && vul) // Vulnerability des Gegners bedenken...
302 // val=(int)(((float)val)*(1.0+eval_resistance(y[C_DTYPES],vul)));
303 }
304 }
305 else
306 {
307 val=1;
308 }
309 val+=eval_combat_object(obs[i],y,enemy);
310 if (val<max) continue;
311 max=val;
312 if (mappingp(y) && y[C_HEAL]>0)
313 best=sprintf(ind[j],name(RAW)); // Heilung auf sich selbst
314 else if (objectp(enemy))
315 best=sprintf(ind[j],enemy->name(RAW)); // Schaden auf Gegner
316 }
317 }
318
319 return best;
320}
321
322varargs int use_best_combat_command(mixed enemy, mixed from, mapping pref) {
323 // Fuehrt moeglichst guten Kampfeinsatz mit einer Sonderwaffe aus
324 string str;
325
326 if (stringp(enemy) && environment())
327 enemy=present(enemy,environment());
328 if (str=find_best_combat_command(from,enemy,pref))
329 return command(str);
330 return 0;
331}
332
333void add_select_commands() {
334 add_action("wield_best_weapon","zuecke_beste_waffe");
335 add_action("wear_best_armours","trage_beste_ruestungen");
336 add_action("use_best_combat_command","benutze_beste_sonderwaffe");
337}