blob: 63c9a841b464ce0d3c56139bc2adeb39b7c021b2 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001RM - HOWTO
2**********
3
4Vorlaeufiges Inhaltsverzeichnis:
5
61) Allgemeines
7 - Fehlerteufel
8 - Logtool
9 - Kommentierung von Aenderungen
10 - eigene Anschluesse
112) Abnahme von Code/Gebieten
12 - Balance/Genehmigungen
13 - Konzeptionelle Eignung
14 - formale Pruefung
15 - Gemeinschaftsarbeiten
163) Verlegung von Dateien
174) Seherhaeuser
18 - Sonderwuensche/Unsichtbarkeit
19 - anderer Befehl zum Betreten
20 - Verweise auf Beispielcode
215) Debuggen von Code
226) besondere Funktionen/Funktionaelitaeten
23 - catch_tell() / ReceiveMsg()
24 - move()
25 - Attack() / Defend()
26 - call_out()
27 - remove() / destruct()
28 - for()-Schleifen
29 - write_file()
30 - Verwalten von charakterbezogenen Daten
31
321) Allgemeines
33==============
34
35o Um stets einen Ueberblick ueber die in Deiner Region (hoffentlich selten)
36 auftretenden Bugs und Warnungen zu behalten, solltest Du einen
37 Fehlerteufel (/obj/tools/fehlerteufel.c) besitzen, bedienen koennen und
38 regelmaessig dessen Listen durchsehen. Deinen Regionsmitarbeitern solltest
39 Du, allein schon, um zusaetzliche Arbeit fuer Dich selbst zu reduzieren,
40 dieses Werkzeug ebenfalls an die Hand geben und sie auffordern, ihren
41 Kram moeglichst umfassend selbst zu reparieren.
42 Neuen Magiern wird dieses Tool uebrigens automatisch von Merlin in die
43 Hand gedrueckt, so dass sie sich vom ersten Tag an daran gewoehnen koennen.
44
45o Es ist empfehlenswert, das Logtool zu besitzen (/obj/tools/logtool.c) und
46 in diesem fuer jedes Repfile eines Regionsmitarbeiters einen Eintrag vor-
47 zusehen. Warum das? Es ist bereits vorgekommen, dass Spieler ernsthaft
48 argumentiert haben, sie duerften einen von ihnen entdeckten Bug ausnutzen,
49 weil sie ihn ja gemeldet haetten (im Repfile!), er aber nicht repariert
50 worden sei (was nicht verwundert, da er im Repfile in der Mehrzahl der
51 Faelle weit unterhalb des Wahrnehmungshorizonts der allermeisten
52 Regionsmagier schwebt).
53
54o Wenn Du in fremdem Code Aenderungen vornehmen musst, die mehr beruehren
55 als nur ein paar Tippfehler in Details oder Infos, dann kommentiere den
56 defekten Code aus und fuege den reparierten mit Kommentar ein. Es reicht
57 an dieser Stelle aus, Deinen Namen und das Datum zu vermerken. In den
58 Header der Datei solltest Du unbedingt ein Changelog einfuegen, in dem
59 das Datum der Aenderung, der Name des Ausfuehrenden (Deiner) sowie die
60 vorgenommene Aenderung mit Begruendung bzw. u.U. Bug-ID aus dem Fehler-
61 teufel einzutragen ist. Wir haben im MG leider keinen wirkungsvollen
62 Debugger und Bugtracker-Mechanismus, so dass wir zur Erhaltung einer
63 gewissen Code-Hygiene Bugfixes mit Hilfe solcher Eintragungen dokumentieren
64 und rueckverfolgen muessen. Insbesondere ist ein solcher Eintrag wichtig,
65 um im Falle von Folge-Bugs die Ursache schneller zu finden.
66
67o Willst Du in Deiner eigenen Region ein Gebiet anschliessen, solltest Du
68 diesen vor Anschluss entweder vom Co-RM oder von einem RM einer anderen
69 Region lesen lassen. Auch wenn Du ein guter Programmierer bist, findet ein
70 zweites Paar Augen oft Dinge, an die man nicht gedacht hat.
71
72
732) Code wird zur Abnahme vorgelegt
74==================================
75
76o Bei Waffen und Ruestungen unbedingt auf Einhaltung der Balance-Vorgaben
77 achten.
78
79o Sofern ein Objekt eine Balance-Genehmigung besitzt, muss die BTOP-Nummer,
80 die die Balance als eindeutige ID fuer jeden Antrag vergibt, im Header
81 des betreffenden Objektes erkennbar eingetragen sein.
82
83o Vor Anschluss sollte man Ruecksprache mit verschiedenen Instanzen halten,
84 um sicherzustellen, dass der Magier alle wesentlichen Punkte
85 beruecksichtigt hat:
86 - liegen alle Balance-Genehmigungen vor?
87 - sind die FP eingetragen?
88 - sind die ZTs eingetragen und getestet?
89 - sind Sonder-EK-Stupse genehmigt und eingetragen?
90
91o Fuer neue Gebiete ist eine grundsaetzliche Pruefung des Konzepts auf
92 Regionstauglichkeit sinnvoll, damit nicht alteingesessene Institutionen
93 oder Orte ploetzlich zur zweiten Wahl abgewertet werden - beispielsweise
94 einen grossen, neuen Hauptort in der Ebene anzuschliessen, der Port Vain
95 voraussehbar den Rang ablaufen wuerde.
96
97o Alle NPCs sollten vor Anschluss einmal gekillt werden, um sie auf
98 grundsaetzliche Kampf-Funktionsfaehigkeit zu pruefen.
99
100o Haben NPCs Namen, sollte ueberlegt werden, diese Namen ggf. zu banishen.
101 (hilfe banish).
102
103o Es existiert ein Shell-Skript, mit dessen Hilfe man offensichtliche
104 Formfehler in einem kompletten Verzeichnis ermitteln kann (Umlaute im
105 Code, zu lange Zeilen etc.), wobei bezueglich der Formalien auch auf
106 den Regionsmitarbeiter-Leitfaden fuer neue Projekte verwiesen werden
107 soll. Das Skript hierzu ist auf Anfrage bei Zesstra erhaeltlich. Der
108 Regionsmagier hat hierbei die Entscheidungsfreiheit, die Berichte dieses
109 Skripts dem Programmierer des neuen Gebiets als Anhaltspunkte zur
110 Verfuegung zu stellen, oder die Abarbeitung der gemeldeten Punkte als
111 Voraussetzung vor dem Anschluss vorzuschreiben, aber auch jede Abstufung
112 dazwischen ist OK. :-)
113 Zusaetzlicher Tip: Das Skript differenziert zwischen eigentlich nicht
114 akzeptablen Konstrukten und zumindest fragwuerdigen, d.h. man kann diese
115 Unterscheidung an den Verantwortlichen mit entsprechenden Forderungen
116 weitergeben.
117 Das Skript ist unter ftp://mg.mud.de/Software/src_check/ erhaeltlich.
118
119o Sollte ein zur Abnahme anstehendes Projekt eine (grundsaetzlich
120 selbstverstaendlich zulaessige) Gemeinschaftsarbeit sein, sollte man
121 als Regionsmagier darauf bestehen, eine sauber getrennte Codebasis
122 in unterschiedlichen Verzeichnissen vorgelegt zu bekommen, oder aber
123 eine Auflistung, welcher Beitrag von welchem Magier stammt.
124 Wenn diese Auflistung sich bis auf Funktionsebene erstrecken sollte
125 (z.B. "DoWield() ist von X, Details von Y, DefendFunc von Z"), ist
126 das unschoen und an sich abzulehnen.
127
128
1293) Verlegung von Dateien
130========================
131
132o Sollte ein Objekt aus einer anderen Region bzw. allgemein aus einem
133 anderen Verzeichnis (z.B. /players) in Deine Region verlegt werden
134 muessen, sind VOR dem Umhaengen folgende Punkte zu beachten:
Arathorn454f1762020-05-01 22:39:30 +0200135 -- Forscherpunkte muessen umgetragen werden
136 -- Quests und Minquests muessen umgetragen werden
137 -- Erstkill-Stufenpunkte muessen umgetragen werden
138 -- Zaubertraenke umtragen lassen
139 -- Seherportal(e) verlegen lassen
140 -- Ruestungen in Padreics Ruestungsskill umtragen lassen
Zesstra299bc492019-08-19 20:09:10 +0200141 -- Waffen in der Liste legendaerer Waffen der Kaempfergilde umtragen
Arathorn454f1762020-05-01 22:39:30 +0200142 (GM Kaempfer oder EM ansprechen)
143 -- im Gebiet vorhandene Seherhaeuser umziehen, an P_SEHERHAUS_ERLAUBT im
144 Zielraum denken
145 -- evtl. im Gebiet vorhandene Kraeuterskill-Kraeuter beruecksichtigen
Arathornae6dbc92020-07-27 23:36:15 +0200146 -- evtl. vorhandene Autoload-Objekte pruefen; in einfachen Faellen kann
147 man ein Wrapper-Objekt erstellen, das das alte beim Clonen durch das
148 neue ersetzt.
MG Mud User88f12472016-06-24 23:31:02 +0200149 -- evtl. Briefempfaenger der Postquest beruecksichtigen,
150 -- ueber die Mudlib greppen lassen, um eventuell in anderen Regionen
151 verwendete Referenzen auf die alten Pfade des umziehenden Codes
152 zu finden und dort umzustellen. Hierbei sind in Ausnahmefaellen von
153 fiesem Code auch in Spielersavefiles gespeicherte Pfade zu
154 beruecksichtigen (*ARGL*).
155
Arathorn454f1762020-05-01 22:39:30 +0200156 Sofern nichts anderes angegeben ist, muss Dir dabei ein EM helfen.
MG Mud User88f12472016-06-24 23:31:02 +0200157
1584) Seherhaeuser
159===============
160
161o Die Erlaubnis zum Bau eines Seherhauses in einem Gebiet haengt einzig und
162 allein von dem verantwortlichen Magier ab. Sollte dieser laenger nicht
163 erreichbar sein (auch nicht ueber externe Mail!), liegt die Entscheidung
164 beim Regionsmagier, der aber in jedem Fall die Eignung des Bauplatzes
165 in der Umgebung bewerten muss.
166
167o Fuer Sonderwuensche bezueglich Unsichtbarkeit von Seherhaeusern oder
168 besonderer Kommandos zum Betreten des Hauses sei auf die Datei
169 /doc/beispiele/misc/seherhaus.c verwiesen, wo die Vorgehensweise
170 erlaeutert wird. Ein Beispiel einer sehr umfangreichen Implementierung
171 findet sich in /d/ebene/room/hp_str8a.c.
172
173o Bei geaenderten Befehlen zum Betreten muss beachtet werden, dass bei einer
174 Standardimplementierung die Erlaube-Liste umgangen wird, d.h. ohne
175 besondere Vorkehrungen u.U. JEDER das Haus ungehindert betreten kann.
176 Es ist hingegen moeglich, die Erlaube-Liste abzufragen und entsprechend
177 zu behandeln, ein Beispiel hierfuer ist in /d/ebene/room/hp_str8a.c
178 nachzulesen (derzeit jedoch auf Spielerwunsch deaktiviert).
179
180
1815) Debuggen von Code
182====================
183
184o Nach dem Reparieren eines Objektes ist es meist erforderlich, das
185 betreffende Objekt neu zu laden. Falls es sich dabei um Objekte handelt,
186 die z.B. in einem Raum mittels AddItem() hinzugefuegt wurden (wie etwa
187 ein NPC), dann ist es am besten, die Datei mit dem Befehl
188 <upd -ad datei.c> zu aktualisieren und somit saemtliche Clones zu
189 zerstoeren. Wenn man mittels <upd -ar datei.c> die bestehenden Clones
190 ersetzen wuerde, wuerden diese aus der Item-Liste des clonenden Raumes
191 ausgetragen, so dass dieser Raum dann im reset() neue Items erzeugt und
192 diese in der Folge doppelt existieren wuerden.
193
194
1956) besondere Funktionen
196=======================
197
198Es kommt haeufig vor, dass Funktionen ueberschrieben werden muessen, und das
199ist auch normalerweise vollkommen normal und nicht beanstandenswert. Jedoch
200sollte man bei bestimmten Funktionen einiges Augenmerk auf die korrekte
201Ausfuehrung richten. Einige Beispiele sind nachfolgend aufgefuehrt:
202
203o catch_tell() / ReceiveMsg()
204 Die Reaktion von Objekten, insbesondere NPCs, auf eingehende Textmeldungen
205 laesst sich nutzen, um schoene und stimmungsvolle Gebiete mit dynamisch
206 reagierenden Bewohnern zu schaffen. Es laesst sich auf der dunklen Seite
207 der Macht hingegen auch verwenden, um ueble Konstrukte zu realisieren,
208 fuer die es seit Ewigkeiten geeignete Implementierungen gibt, und die
209 demzufolge niemals durch eine Endabnahme durch einen RM durchschluepfen
210 duerfen. Ein paar reale NPC-Beispiele aus der Praxis:
211
212 Schnipsel 1)
213
214 if (sscanf(str, " %s greift den Priester %s",name1, dummy) == 2)
215 {
216 pl = find_player(lower_case(name1));
217 if (!pl || !living(pl))
218 return 1;
219 else
220 Kill(pl);
221 }
222 Zweck: Simulation von AddDefender() und InformDefend()/DefendOther()
223 Kommentar: Absolutes No-Go! Mit Echo-Faehigkeiten von Spielern (Gilde oder
224 anderweitig) ist hiermit ein indirekter Playerkill moeglich.
225 Inakzeptable Implementierung.
226
227
228 Schnipsel 2)
229
230 if (sscanf(str, "%s sagt: %s\n", wer,was))
231 {
232 if (lower_case(was)=="ja" )
233 this_player()->move(zielraum, M_TPORT);
234 }
235 Zweck: Ausloesen eines Kommandos, ohne "sage ..." als Befehl
236 ueberschreiben zu muessen.
237 Kommentar: Ausnutzbar als Remote-Fluchtteleport, indem man die Meldung
238 mittels teile-mit an den NPC sendet:
239 "Robert teilt Dir mit: sagt: ja", was ungeprueft ein move()
240 zur Folge hat. Offensichtlich ebenso ungeeignet wie das
241 vorige Beispiel.
242
243
244 Schnipsel 3)
245
246 if (sscanf(lower_case(str),"%s sagt: %sversteck%s",s1,s2,s3))
247 tell_room(environment(),sprintf("Der Fisch sagt: Das ist aber keine "
248 "grosse Hilfe, %s.\n",capitalize(s1)),({TO}));
249
250 sieht erstmal harmlos aus, fuehrt aber mit der Anweisung
251
252 SetChats(8, ({ "Der Fisch sagt: Wo kann ich mich nur verstecken?"}) );
253
254 dazu, dass der NPC dauernd mit sich selber schwatzt. Kein kritischer Bug
255 im eigentlichen Sinn, aber auf jeden Fall der Atmosphaere im Gebiet
256 sehr abtraeglich.
257
258o move()
259 Ueberschreiben von move() ist eine extrem heikle Angelegenheit, bei der
260 beim kleinsten Fehler massive Probleme resultieren koennen, jedoch meist
261 nicht offensichtlich ist, woher das resultiert. Als allgemeine Empfehlung
262 sollte gelten, dass move() NIE ueberschrieben wird, und wenn, dann muss
263 ausfuehrlich und aufmerksam geprueft werden, was da passiert, und ob der
264 gewuenschte Effekt nicht anders sauberer erreicht werden kann.
265 Als zusaetzlicher Hinweis sei auf NotifyMove() und PreventMove() verwiesen,
266 mit deren Hilfe sich die allermeisten Faelle erschlagen lassen, in denen
267 Magier faelschlicherweise glauben, move() ueberschreiben zu muessen.
268
269o Defend()/Attack()
270 hier ist ein beliebter Fehler einfach der, dass man am Ende der Funktion
271 ::Defend() bzw. ::Attack() ruft, aber im Codeblock vorher das Objekt
272 durch eigenen Tod oder anderes schon zerstoert wurde. Dann geht das schief.
273 Einfach mal hinschauen - es ist aber kein wirklich gravierender Fehler,
274 da sowas im Kampf meist ziemlich schnell auffaellt.
275
276o call_out()
277 Hierzu zwei Hinweise: zum einen fuehrt call_out("x",0) seit der Umstellung
278 auf LDmud als Driver nicht mehr implizit zu einem call_out("x",1), wie es
279 zuvor war, sondern tatsaechlich zu einem fast sofortigen Funktionsaufruf der
280 Funktion x() - mit allen Konsequenzen, inklusive eines "too long eval"-
281 Bugs. Wer eine echte Verzoegerung braucht, muss mindestens call_out("x",1)
282 verwenden.
283 Zum anderen wurde mit LDmud die Granularitaet des reset()-Aufrufes auf
284 Heartbeat-Genauigkeit (2 s) verfeinert, so dass man bequem laengere
285 Verzoegerungen auf die Verwendung von reset() umstellen kann.
286
287o Zerstoeren von Objekten mit remove() oder destruct()
288 Man sollte einen sehr kritischen Blick auf Konstrukte werfen, die
289 nach einem remove() noch weiteren Code ausfuehren (Ausnahme: echte efuns
290 und Compiler-Konstrukte wie return).
291 Wenn man Objekte zerstoeren will oder muss, sollte man immer zuerst
292 remove() verwenden. Destruct muss dem absoluten Ausnahmefall vorbehalten
293 bleiben. Man sollte im Hinterkopf behalten, dass Objekte gute Gruende haben
294 koennen, sich einem remove() zu verweigern.
295
296o for()-Schleifen
297 Eigentlich keine Funktion, aber an dieser Stelle doch passend:
298 for()-Schleifen sollten generell durch foreach()-Konstruktionen ersetzt
299 werden, da dies signifikant und messbar schneller ist. Die naechst-
300 schnellere Variante waere etwa folgendes, sofern die Reihenfolge der
301 Abarbeitung unerheblich ist (i ist integer, arr ist ein mixed-Array):
302
303 for ( i=sizeof(arr); i--; ) {
304 tu_etwas_mit(arr[i]);
305 }
306
307o write_file()
308 Benutzung dieser Funktion nur in begruendeten Ausnahmefaellen abnehmen, da
309 keinerlei Begrenzung der Dateigroesse existiert. Insbesondere bei Logfiles
310 entstehen hierdurch im Laufe der Zeit Monsterdateien, die nur Plattenplatz
311 verbrauchen, aber kaum zu ueberschauen sind. Statt write_file() wird in
312 den allermeisten Faellen log_file() mit der Standardgroesse von 50 kB fuer
313 Logfile und eine ggf. vorhandene Altversion (*.OLD) ausreichend sein.
314
315o Verwalten von charakterbezogenen Daten
316 Als Beispiel seien hier Statusdaten fuer den Ablauf von Quests genannt,
317 oder Highscores in irgendwelchen Toplisten. Fuer die Umsetzung dieser
318 Datenerfassung werden typischerweise zwei Techniken eingesetzt. Zum
319 einen kann ein Masterobjekt erstellt werden, das die Daten sammelt und
320 mittels save_object() dauerhaft speichert. Zum anderen kann man auch
321 Daten in einer Property im Spieler ablegen und diese je nach Anwendungs-
322 fall auf SAVE setzen.
323
324 Bei der ersten Variante wird man ueblicherweise die UID oder UUID des
325 Spielers als Indizierungsmerkmal verwenden. Der erste Fallstrick ist nun,
326 dass die UID bei Spielern (nicht Sehern) ggf. nach einer Selbstloeschung
327 neu vergeben werden kann, so dass die Daten inkonsistent werden bzw. der
328 Spieler scheinbar schon in Eurem Master eingetragen ist, obwohl es sich
329 eigentlich um jemand ganz anderes handelt.
330 Als Abhilfemassnahme bietet sich folgendes an:
331 a) UUID verwenden, da diese fuer jeden Spieler eindeutig ist.
332 b) Hinweis: find_player() kann auch mit UUIDs umgehen und das zugehoerige
333 Spielerobjekt ermitteln.
334 c) Man sollte ggf. auf das Mudlib-Event EVT_LIB_PLAYER_DELETION lauschen,
335 um Spieler auszutragen, die sich loeschen, wodurch die zugehoerigen
336 Daten obsolet werden.
337
338 Bei der zweiten Variante muss man verschiedene Dinge beruecksichtigen:
339 a) nicht endlos viele Properties machen, sondern pro Thema (z.B. Quest)
340 einfach eine.
341 b) nur die Properties speichern, bei denen das wirklich noetig ist.
342 c) Speichert man Properties und die Aufgabe wird erledigt, d.h. der
343 Inhalt der Property obsolet, muss die Property wieder geloescht werden.