blob: 6cc4f602bdc67e9b6770892ae1b05354363507c8 [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
Arathornd5c9c022020-01-08 22:04:28 +010083 ret += ({int})SCOREMASTER->QueryKillPoints(pl);
MG Mud User88f12472016-06-24 23:31:02 +020084
85 DEBUG("Nach KP: ret = %d\n", ret);
86
87 // Beitrag B: Stupse von geloesten Miniquests
Arathornd5c9c022020-01-08 22:04:28 +010088 ret += ({int})QM->QueryMiniQuestPoints(pl);
MG Mud User88f12472016-06-24 23:31:02 +020089
90 DEBUG("Nach MQP: ret = %d\n", ret);
91
92 // Beitrag C: Questpunkte
93 // werden 1:1 uebernommen;
Arathornd5c9c022020-01-08 22:04:28 +010094 ret += ({int})pl->QueryProp(P_QP);
MG Mud User88f12472016-06-24 23:31:02 +020095
96 DEBUG("Nach QP: ret = %d\n", ret);
97
98 // Beitrag D: Erfahrungspunkte
99 // Stupse = XPs ^ 0.32
Arathornd5c9c022020-01-08 22:04:28 +0100100 val = ({int})pl->QueryProp(P_XP);
MG Mud User88f12472016-06-24 23:31:02 +0200101
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
Arathornd5c9c022020-01-08 22:04:28 +0100112 i = 80 - (val = sizeof(({int *})pl->QueryProp(P_POTIONROOMS)));
MG Mud User88f12472016-06-24 23:31:02 +0200113
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
Arathornd5c9c022020-01-08 22:04:28 +0100118 ret += 6 * ({int})EPMASTER->QueryExplorationPoints(pl);
MG Mud User88f12472016-06-24 23:31:02 +0200119
120 DEBUG("Nach FP: ret = %d\n", ret);
121
122 // Beitrag G: Gildeneinstufung
123 // Maximale Gildeneinstufung (10000) entspricht vier Leveln
Arathornd5c9c022020-01-08 22:04:28 +0100124 ret += (({int})pl->QueryProp(P_GUILD_RATING))/25;
MG Mud User88f12472016-06-24 23:31:02 +0200125
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__
MG Mud User88f12472016-06-24 23:31:02 +0200166}
167
168// Wieviele LEP fehlen zum naechsten Level?
169nomask int QueryNextLevelLEP(int lvl, int lep) {
170 int needed;
171
172 if (QueryLevel(lep) > lvl)
173 return 0;
174
175#ifdef __PFOERKL__
176 if (lvl < sizeof(LOW_LEVEL_LEP_LIST))
177 needed = LOW_LEVEL_LEP_LIST[lvl];
178 else
179 needed = (lvl-3) * 100; // (lvl + 1 - 4) * 100
180#else
181 needed = (lvl+1) * 100;
182#endif // __PFOERKL__
183
184 // needed sind jetzt die insgesamt benoetigten LEP. Vorhandene abziehen.
185 needed -= lep;
186 // nix < 0 zurueckliefern
187 return max(needed,0);
188}
189
190string QueryForschung()
191{
192 int max, my, avg;
193 string ret;
194
Arathornd5c9c022020-01-08 22:04:28 +0100195 if ((my=({int})EPMASTER->QueryExplorationPoints(getuid(previous_object()))) < MIN_EP)
MG Mud User88f12472016-06-24 23:31:02 +0200196 return "Du kennst Dich im "MUDNAME" so gut wie gar nicht aus.\n";
197
198 my *= 100;
Arathornd5c9c022020-01-08 22:04:28 +0100199 max = my/({int})EPMASTER->QueryMaxEP();
200 avg = my/({int})EPMASTER->QueryAverage();
MG Mud User88f12472016-06-24 23:31:02 +0200201
202 ret = "Verglichen mit Deinen Mitspielern, kennst Du Dich im "MUDNAME" ";
203 switch(avg) {
204 case 0..10:
205 ret += "kaum";
206 break;
207 case 11..40:
208 ret += "aeusserst schlecht";
209 break;
210 case 41..56:
211 ret += "sehr schlecht";
212 break;
213 case 57..72:
214 ret += "schlecht";
215 break;
216 case 73..93:
217 ret += "unterdurchschnittlich";
218 break;
219 case 94..109:
220 ret += "durchschnittlich gut";
221 break;
222 case 110..125:
223 ret += "besser als der Durchschnitt";
224 break;
225 case 126..145:
226 ret += "recht gut";
227 break;
228 case 146..170:
229 ret += "ziemlich gut";
230 break;
231 case 171..210:
232 ret += "gut";
233 break;
234 case 211..300:
235 ret += "sehr gut";
236 break;
237 case 301..400:
238 ret += "ausserordentlich gut";
239 break;
240 case 401..500:
241 ret += "unheimlich gut";
242 break;
243 default:
244 ret += "einfach hervorragend";
245 break;
246 }
247 ret += " aus.\nAbsolut gesehen ";
248
249 switch(max) {
250 case 0..5:
251 ret += "kennst Du nur wenig vom "MUDNAME".";
252 break;
253 case 6..10:
254 ret += "solltest Du Dich vielleicht noch genauer umsehen.";
255 break;
256 case 11..17:
257 ret += "bist Du durchaus schon herumgekommen.";
258 break;
259 case 18..25:
260 ret += "hast Du schon einiges gesehen.";
261 break;
262 case 26..35:
263 ret += "bist Du schon weit herumgekommen.";
264 break;
265 case 36..50:
266 ret += "koenntest Du eigentlich einen Reisefuehrer herausbringen.";
267 break;
268 case 51..75:
269 ret += "hast Du schon sehr viel gesehen.";
270 break;
271 default:
272 ret += "besitzt Du eine hervorragende Ortskenntnis.";
273 }
274 return break_string(ret, 78, 0, 1);
275}
276
277
278nomask mixed QueryWizardRequirements(object player)
279{
280 // Diese Funktion gibt ein 2-elementiges Array zurueck, in dem im ersten
281 // Element steht, ob der Spieler Seher werden kann (1) oder
282 // nicht (0) und im zweiten Element steht, was genau ihm noch
283 // fehlt.
284 // Fehlercode ist ({-1, ""})
285
286 // Die Umrechnungsfaktoren wurden einfach aus QueryLEP uebernommen; ggf.
287 // kann man das einmal in Unterfunktionen auslagern.
288
289 mixed ret;
290 string s;
291 int i,z,val;
292
293 ret = ({-1, "Hier ist etwas schief gelaufen. Bitte einen Erzmagier\n"
294 +"benachrichtigen.\n"});
295 s = "";
296 i = 0;
297
298 if(!player || !objectp(player))
299 player=(this_player()?this_player():this_interactive());
300
301 if(!player)
302 return ({-1,""});
303
304 DEBUG("Es geht um: %O\n", player);
305
306 // Abenteuerpunkte
bugfixd94d0932020-04-08 11:27:13 +0200307 DEBUG("Abenteuerpunkte: %d ("+REQ_QP+")\n", ({int})player->QueryProp(P_QP));
308 if (({int})player->QueryProp(P_QP) < REQ_QP) {
MG Mud User88f12472016-06-24 23:31:02 +0200309 s += sprintf(" * Dir fehlen noch mindestens %d Abenteuerpunkte.\n",
Arathornd5c9c022020-01-08 22:04:28 +0100310 REQ_QP - ({int})player->QueryProp(P_QP));
MG Mud User88f12472016-06-24 23:31:02 +0200311 i--;
312 }
313
314 // Forscherpunkte
Arathornd5c9c022020-01-08 22:04:28 +0100315 z = 6 * ({int})EPMASTER->QueryExplorationPoints(player);
MG Mud User88f12472016-06-24 23:31:02 +0200316 DEBUG("Forscherpunkte: %d ("+REQ_EP+")\n", z);
317 if (z < REQ_EP) {
318 s += sprintf(" * Du kennst Dich im "MUDNAME" noch nicht genug aus, "
319 +"genau genommen\n musst Du Dir noch %s ansehen.\n",
320 REQ_TEXT1[(z*10/REQ_EP)] );
321 i--;
322 }
323
324 // Zaubertraenke
Arathornd5c9c022020-01-08 22:04:28 +0100325 z = 80 - (val = sizeof(({int*})player->QueryProp(P_POTIONROOMS)));
MG Mud User88f12472016-06-24 23:31:02 +0200326 z = z*5 + ([0:100, 1:60, 2:30, 3:10])[val];
327 DEBUG("Zaubertraenke: %d ("+REQ_P+")\n", z);
328 if (z < REQ_P) {
329 s += sprintf(" * Du musst noch einige Zaubertraenke (ca. %d) suchen.\n",
330 (REQ_P - z)/5 );
331 i--;
332 }
333
334 // Erstkills
Arathornd5c9c022020-01-08 22:04:28 +0100335 z = ({int})SCOREMASTER->QueryKillPoints(player);
MG Mud User88f12472016-06-24 23:31:02 +0200336 DEBUG("Erstkills: %d ("+REQ_K+")\n", z);
337 if (z < REQ_K) {
338 s += sprintf(" * Du hast noch nicht genuegend wuerdige Gegner erlegt, genau "
339 +"genommen\n musst Du noch %s wuerdige Monster toeten.\n",
340 REQ_TEXT2[(z*10/REQ_K)] );;
341 i--;
342 }
343
344 int minlevel = QueryLevel(REQ_LEP);
345
346 // Restliche Stufenpunkte
bugfixd94d0932020-04-08 11:27:13 +0200347 DEBUG("Stufenpunkte: %d ("+REQ_LEP+")\n", ({int})player->QueryProp(P_LEP));
Arathornd5c9c022020-01-08 22:04:28 +0100348 if (({int})(player->QueryProp(P_LEP)) < REQ_LEP) {
MG Mud User88f12472016-06-24 23:31:02 +0200349 s += sprintf(" * Du musst mindestens %d Stufenpunkte, entspricht Stufe %d, "
350 "erreichen.\n", REQ_LEP, minlevel);
351 i--;
352 }
353
354 // Demnach mindestens REQ/100-Level
bugfixd94d0932020-04-08 11:27:13 +0200355 DEBUG("Level: %d ("+REQ_LEP/100+")\n", ({int})player->QueryProp(P_LEVEL));
Arathornd5c9c022020-01-08 22:04:28 +0100356 if (({int})player->QueryProp(P_LEVEL) < minlevel) {
MG Mud User88f12472016-06-24 23:31:02 +0200357 s += sprintf(" * Du musst mindestens Stufe %d erreichen.\n", minlevel);
358 i--;
359 }
360
361 if(i<0) {
362 ret = ({-1,
363 sprintf("Du hast noch nicht alle Seher-Anforderungen erfuellt.\n"
364 +"Im einzelnen fehlt Dir folgendes:\n\n%s\n"
365 +break_string("Falls Du Dir nun dennoch unsicher bist, "
366 +"welche Anforderungen Du erfuellen musst, dann "
367 +"schaue bei 'hilfe seher' und 'hilfe stufenpunkte' doch einfach noch "
368 +"einmal nach. Sind dann "
369 +"immer noch Dinge offen oder unklar, so sprich einfach einen "
370 +"der Erzmagier an.", 78,0,1),s) });
371 }
372
373 if (i==0) {
374 ret = ({1, break_string(
375 "Du hast alle Seher-Anforderungen erfuellt. Wende Dich doch "
376 +"einmal an Merlin und frage ihn, ob er Dich befoerdert.",
377 78,0,1) });
378 }
379
380 return ret;
381}
382
383nomask int QueryReadyForWiz(object player)
384{
385 mixed r;
386
387 r = QueryWizardRequirements(player);
388
389 if (!pointerp(r) && sizeof(r)!=2 && !intp(r[0]))
390 return -1;
391
392 return r[0];
393}
394
395nomask string QueryReadyForWizText(object player)
396{
397 mixed r;
398
399 r = QueryWizardRequirements(player);
400
401 if (!pointerp(r) && sizeof(r)!=2 && !stringp(r[1]))
402 return "Hier ist etwas schief gegangen, bitte verstaendige einen "
403 +"Erzmagier.";
404
405 return r[1];
406}
407