blob: 3d7cb797f3fde934f80f952005455c5c617784a6 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// lepmaster.c -- Master, welcher aus scoremaster, explorationmaster,
4// questmaster und dem Spielerobjekt Informationen
5// ausliest und aus diesen die Levelpunkte des Spieler
6// berechnet
7// Weiters derjenige, der die Seheranforderungen
8// prueft.
9//
10// $Id: lepmaster.c 9168 2015-03-05 00:04:22Z Zesstra $
11
12// Hier kommen Funktionen fuer die Levelpunkte
13#pragma strict_types
14#pragma no_clone
15#pragma no_shadow
16#pragma no_inherit
17#pragma verbose_errors
18#pragma combine_strings
19//#pragma pedantic
20//#pragma range_check
21#pragma warn_deprecated
22
23#include <config.h>
24#include <properties.h>
25#include <new_skills.h>
26#include <exploration.h>
27#include <questmaster.h>
28#include <scoremaster.h>
29#include <wizlevels.h>
30
31#include "lepmaster.h"
32
33// Das Programm zur Foerderung der kleinen Level aktivieren. ;-)
34#define __PFOERKL__ 1
35
36// die ersten 8 Level, d.h. Level 1 bis 8 entsprechen diesen LEPs.
37int *LOW_LEVEL_LEP_LIST = ({100,120,140,180,220,300,360,420}); // 9. Level: 500 LEP
38
39#define REQ_TEXT1 ([0:"unglaublich viel", \
40 1:"unglaublich viel", \
41 2:"enorm viel", \
42 3:"sehr viel", \
43 4:"viel", \
44 5:"einiges", \
45 6:"etwas", \
46 7:"wenig", \
47 8:"sehr wenig", \
48 9:"kaum etwas" ])
49
50#define REQ_TEXT2 ([0:"unglaublich viele", \
51 1:"unglaublich viele", \
52 2:"enorm viele", \
53 3:"sehr viele", \
54 4:"viele", \
55 5:"einige", \
56 6:"ein paar", \
57 7:"wenige", \
58 8:"sehr wenige", \
59 9:"kaum" ])
60
61#define DEBUG(x,y)
62//#define DEBUG(x,y) if (find_player("zook")) tell_object(find_player("zook"),sprintf(x,y))
63
64
65void create()
66{
67 seteuid(getuid());
68}
69
70int QueryLEPForPlayer(object pl)
71{
72 int ret, val, i, l;
73
74 if (extern_call() && !IS_ARCH(geteuid(previous_object())))
75 return -1;
76 if (!pl || !query_once_interactive(pl))
77 return -2;
78
79 // Grundoffset 100, da man mit Level 1 statt 0 startet
80 ret = 100;
81
82 // Beitrag A: Stupse von NPC-Erstkills
83 ret += (int)SCOREMASTER->QueryKillPoints(pl);
84
85 DEBUG("Nach KP: ret = %d\n", ret);
86
87 // Beitrag B: Stupse von geloesten Miniquests
88 ret += (int)QM->QueryMiniQuestPoints(pl);
89
90 DEBUG("Nach MQP: ret = %d\n", ret);
91
92 // Beitrag C: Questpunkte
93 // werden 1:1 uebernommen;
94 ret += (int)pl->QueryProp(P_QP);
95
96 DEBUG("Nach QP: ret = %d\n", ret);
97
98 // Beitrag D: Erfahrungspunkte
99 // Stupse = XPs ^ 0.32
100 val = (int)pl->QueryProp(P_XP);
101
102 if (val<1) l=0;
103 else l=to_int(exp(log(to_float(val))*0.32));
104
105 ret += l;
106
107 DEBUG("Nach XP: ret = %d\n", ret);
108
109 // Beitrag E: Zaubertraenke
110 // Gefundene Traenke geben 5 LEP
111 // Die Heiltraenke geben zusaetzlich 10+20+30+40 LEP
112 i = 80 - (val = sizeof((int *)pl->QueryProp(P_POTIONROOMS)));
113
114 ret += 5*i + ([ 0: 100, 1: 60, 2: 30, 3: 10])[val];
115
116 // Beitrag F: Forscherpunkte
117 // Pro FP gibt es 6 Stufenpunkte
118 ret += 6 * (int)EPMASTER->QueryExplorationPoints(pl);
119
120 DEBUG("Nach FP: ret = %d\n", ret);
121
122 // Beitrag G: Gildeneinstufung
123 // Maximale Gildeneinstufung (10000) entspricht vier Leveln
124 ret += ((int)pl->QueryProp(P_GUILD_RATING))/25;
125
126 DEBUG("Nach GR: ret = %d\n", ret);
127
128 // Ausgabe gibt es nur in 20er-Schritten
129 ret -= ret%20;
130
131 return (ret > 100) ? ret : 100;
132
133}
134
135nomask int QueryLEP()
136{
137 if (!previous_object())
138 return 0;
139 return QueryLEPForPlayer(previous_object());
140}
141
142nomask int QueryLevel(int lep) {
143 if (lep<=0)
144 lep=QueryLEP();
145
146 if (lep<=0)
147 return 0;
148
149#ifdef __PFOERKL__
150 // normale Level alle 100 LEP
151 if (lep >= 500)
152 return lep/100 + 4;
153 else {
154 // level mit weniger LEP am Anfang (1-8)
155 // Level aus der LOW_LEVEL_LEP_LIST raussuchen.
156 int lev = sizeof(LOW_LEVEL_LEP_LIST) - 1;
157 for ( ; lev >= 0; --lev) {
158 if (LOW_LEVEL_LEP_LIST[lev] <= lep)
159 break; // gefunden
160 }
161 return lev+1;
162 }
163#else
164 return lep/100;
165#endif // __PFOERKL__
166 return 0;
167}
168
169// Wieviele LEP fehlen zum naechsten Level?
170nomask int QueryNextLevelLEP(int lvl, int lep) {
171 int needed;
172
173 if (QueryLevel(lep) > lvl)
174 return 0;
175
176#ifdef __PFOERKL__
177 if (lvl < sizeof(LOW_LEVEL_LEP_LIST))
178 needed = LOW_LEVEL_LEP_LIST[lvl];
179 else
180 needed = (lvl-3) * 100; // (lvl + 1 - 4) * 100
181#else
182 needed = (lvl+1) * 100;
183#endif // __PFOERKL__
184
185 // needed sind jetzt die insgesamt benoetigten LEP. Vorhandene abziehen.
186 needed -= lep;
187 // nix < 0 zurueckliefern
188 return max(needed,0);
189}
190
191string QueryForschung()
192{
193 int max, my, avg;
194 string ret;
195
196 if ((my=(int)EPMASTER->QueryExplorationPoints(getuid(previous_object()))) < MIN_EP)
197 return "Du kennst Dich im "MUDNAME" so gut wie gar nicht aus.\n";
198
199 my *= 100;
200 max = my/(int)EPMASTER->QueryMaxEP();
201 avg = my/(int)EPMASTER->QueryAverage();
202
203 ret = "Verglichen mit Deinen Mitspielern, kennst Du Dich im "MUDNAME" ";
204 switch(avg) {
205 case 0..10:
206 ret += "kaum";
207 break;
208 case 11..40:
209 ret += "aeusserst schlecht";
210 break;
211 case 41..56:
212 ret += "sehr schlecht";
213 break;
214 case 57..72:
215 ret += "schlecht";
216 break;
217 case 73..93:
218 ret += "unterdurchschnittlich";
219 break;
220 case 94..109:
221 ret += "durchschnittlich gut";
222 break;
223 case 110..125:
224 ret += "besser als der Durchschnitt";
225 break;
226 case 126..145:
227 ret += "recht gut";
228 break;
229 case 146..170:
230 ret += "ziemlich gut";
231 break;
232 case 171..210:
233 ret += "gut";
234 break;
235 case 211..300:
236 ret += "sehr gut";
237 break;
238 case 301..400:
239 ret += "ausserordentlich gut";
240 break;
241 case 401..500:
242 ret += "unheimlich gut";
243 break;
244 default:
245 ret += "einfach hervorragend";
246 break;
247 }
248 ret += " aus.\nAbsolut gesehen ";
249
250 switch(max) {
251 case 0..5:
252 ret += "kennst Du nur wenig vom "MUDNAME".";
253 break;
254 case 6..10:
255 ret += "solltest Du Dich vielleicht noch genauer umsehen.";
256 break;
257 case 11..17:
258 ret += "bist Du durchaus schon herumgekommen.";
259 break;
260 case 18..25:
261 ret += "hast Du schon einiges gesehen.";
262 break;
263 case 26..35:
264 ret += "bist Du schon weit herumgekommen.";
265 break;
266 case 36..50:
267 ret += "koenntest Du eigentlich einen Reisefuehrer herausbringen.";
268 break;
269 case 51..75:
270 ret += "hast Du schon sehr viel gesehen.";
271 break;
272 default:
273 ret += "besitzt Du eine hervorragende Ortskenntnis.";
274 }
275 return break_string(ret, 78, 0, 1);
276}
277
278
279nomask mixed QueryWizardRequirements(object player)
280{
281 // Diese Funktion gibt ein 2-elementiges Array zurueck, in dem im ersten
282 // Element steht, ob der Spieler Seher werden kann (1) oder
283 // nicht (0) und im zweiten Element steht, was genau ihm noch
284 // fehlt.
285 // Fehlercode ist ({-1, ""})
286
287 // Die Umrechnungsfaktoren wurden einfach aus QueryLEP uebernommen; ggf.
288 // kann man das einmal in Unterfunktionen auslagern.
289
290 mixed ret;
291 string s;
292 int i,z,val;
293
294 ret = ({-1, "Hier ist etwas schief gelaufen. Bitte einen Erzmagier\n"
295 +"benachrichtigen.\n"});
296 s = "";
297 i = 0;
298
299 if(!player || !objectp(player))
300 player=(this_player()?this_player():this_interactive());
301
302 if(!player)
303 return ({-1,""});
304
305 DEBUG("Es geht um: %O\n", player);
306
307 // Abenteuerpunkte
308 DEBUG("Abenteuerpunkte: %d ("+REQ_QP+")\n", player->QueryProp(P_QP));
309 if (player->QueryProp(P_QP) < REQ_QP) {
310 s += sprintf(" * Dir fehlen noch mindestens %d Abenteuerpunkte.\n",
311 REQ_QP - (int)player->QueryProp(P_QP));
312 i--;
313 }
314
315 // Forscherpunkte
316 z = 6 * (int)EPMASTER->QueryExplorationPoints(player);
317 DEBUG("Forscherpunkte: %d ("+REQ_EP+")\n", z);
318 if (z < REQ_EP) {
319 s += sprintf(" * Du kennst Dich im "MUDNAME" noch nicht genug aus, "
320 +"genau genommen\n musst Du Dir noch %s ansehen.\n",
321 REQ_TEXT1[(z*10/REQ_EP)] );
322 i--;
323 }
324
325 // Zaubertraenke
326 z = 80 - (val = sizeof((int*)player->QueryProp(P_POTIONROOMS)));
327 z = z*5 + ([0:100, 1:60, 2:30, 3:10])[val];
328 DEBUG("Zaubertraenke: %d ("+REQ_P+")\n", z);
329 if (z < REQ_P) {
330 s += sprintf(" * Du musst noch einige Zaubertraenke (ca. %d) suchen.\n",
331 (REQ_P - z)/5 );
332 i--;
333 }
334
335 // Erstkills
336 z = (int)SCOREMASTER->QueryKillPoints(player);
337 DEBUG("Erstkills: %d ("+REQ_K+")\n", z);
338 if (z < REQ_K) {
339 s += sprintf(" * Du hast noch nicht genuegend wuerdige Gegner erlegt, genau "
340 +"genommen\n musst Du noch %s wuerdige Monster toeten.\n",
341 REQ_TEXT2[(z*10/REQ_K)] );;
342 i--;
343 }
344
345 int minlevel = QueryLevel(REQ_LEP);
346
347 // Restliche Stufenpunkte
348 DEBUG("Stufenpunkte: %d ("+REQ_LEP+")\n", player->QueryProp(P_LEP));
349 if ((int)(player->QueryProp(P_LEP)) < REQ_LEP) {
350 s += sprintf(" * Du musst mindestens %d Stufenpunkte, entspricht Stufe %d, "
351 "erreichen.\n", REQ_LEP, minlevel);
352 i--;
353 }
354
355 // Demnach mindestens REQ/100-Level
356 DEBUG("Level: %d ("+REQ_LEP/100+")\n", player->QueryProp(P_LEVEL));
357 if ((int)player->QueryProp(P_LEVEL) < minlevel) {
358 s += sprintf(" * Du musst mindestens Stufe %d erreichen.\n", minlevel);
359 i--;
360 }
361
362 if(i<0) {
363 ret = ({-1,
364 sprintf("Du hast noch nicht alle Seher-Anforderungen erfuellt.\n"
365 +"Im einzelnen fehlt Dir folgendes:\n\n%s\n"
366 +break_string("Falls Du Dir nun dennoch unsicher bist, "
367 +"welche Anforderungen Du erfuellen musst, dann "
368 +"schaue bei 'hilfe seher' und 'hilfe stufenpunkte' doch einfach noch "
369 +"einmal nach. Sind dann "
370 +"immer noch Dinge offen oder unklar, so sprich einfach einen "
371 +"der Erzmagier an.", 78,0,1),s) });
372 }
373
374 if (i==0) {
375 ret = ({1, break_string(
376 "Du hast alle Seher-Anforderungen erfuellt. Wende Dich doch "
377 +"einmal an Merlin und frage ihn, ob er Dich befoerdert.",
378 78,0,1) });
379 }
380
381 return ret;
382}
383
384nomask int QueryReadyForWiz(object player)
385{
386 mixed r;
387
388 r = QueryWizardRequirements(player);
389
390 if (!pointerp(r) && sizeof(r)!=2 && !intp(r[0]))
391 return -1;
392
393 return r[0];
394}
395
396nomask string QueryReadyForWizText(object player)
397{
398 mixed r;
399
400 r = QueryWizardRequirements(player);
401
402 if (!pointerp(r) && sizeof(r)!=2 && !stringp(r[1]))
403 return "Hier ist etwas schief gegangen, bitte verstaendige einen "
404 +"Erzmagier.";
405
406 return r[1];
407}
408