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