| // MorgenGrauen MUDlib |
| // |
| // player/quests.c -- quest handler |
| // |
| // $Id: quests.c 9142 2015-02-04 22:17:29Z Zesstra $ |
| |
| // Dieses Modul enhaelt die Quest-spezifischen Teile der Playerobjekte. |
| #pragma strong_types |
| #pragma save_types |
| #pragma range_check |
| #pragma no_clone |
| #pragma pedantic |
| |
| #define NEED_PROTOTYPES |
| #include <player/life.h> |
| #include <player/quest.h> |
| #include <thing/properties.h> |
| #include <player/base.h> |
| #include <living/life.h> |
| #undef NEED_PROTOTYPES |
| |
| #include "/secure/questmaster.h" |
| #include <wizlevels.h> |
| #include <daemon.h> |
| #include <language.h> |
| #include <mail.h> |
| #include <defines.h> |
| #include <new_skills.h> |
| #include <properties.h> |
| #include <events.h> |
| |
| mixed quests; |
| |
| int QueryQuest(string questname); |
| // local properties prototype |
| static mixed _query_quests(); |
| static int _query_questpoints(); |
| |
| protected void create() { |
| Set(P_QUESTS, NOSETMETHOD, F_SET_METHOD); |
| Set(P_QUESTS, quests = ([]), F_VALUE); |
| Set(P_QUESTS, SECURED, F_MODE); |
| Set(P_QP, SAVE, F_MODE); |
| Set(P_QP, SECURED, F_MODE); |
| } |
| |
| varargs int GiveQuest(string questname, string message) { |
| mixed *quest = QM->QueryQuest(questname); |
| |
| // Questname ungueltig |
| if (!quest||!pointerp(quest)||quest==({})) |
| return GQ_KEY_INVALID; |
| // Unbefugter Zugriff auf deaktivierte Quest |
| if (!quest[6]&&!IS_ARCH(this_interactive())) |
| return GQ_IS_INACTIVE; |
| // Unbefugter Zugriff |
| if (member(quest[2], load_name(previous_object()))==-1 && |
| !IS_ARCH(this_interactive())) |
| return GQ_ILLEGAL_OBJ; |
| |
| // Gilde wird in jedem Fall informiert. |
| string guild=GUILD_DIR+QueryProp(P_GUILD); |
| if (find_object(guild) || file_size(guild+".c")>-1) |
| catch( call_other(guild, "NotifyGiveQuest", ME, questname);publish ); |
| |
| // Quest bereits gesetzt |
| if (QueryQuest(questname)) |
| return GQ_ALREADY_SET; |
| AddExp(quest[1]); |
| quests += ([ questname : quest[0]; time() ]); |
| force_save(); |
| // Event ausloesen |
| EVENTD->TriggerEvent(EVT_LIB_QUEST_SOLVED,([ |
| E_OBJECT: ME, |
| E_PLNAME: getuid(ME), |
| E_ENVIRONMENT: environment(), |
| E_QUESTNAME: questname, |
| E_QP_GRANTED: quest[0] ]) ); |
| |
| if (message && message!="") { |
| if (message!="__silent__") { |
| message=implode(explode(message,"@@name@@"), |
| capitalize(query_real_name())); |
| } |
| else { |
| message=""; |
| } |
| } |
| else |
| message=capitalize(query_real_name()) |
| +" hat gerade ein Abenteuer bestanden: "+ questname+"\n"; |
| if(message!="") |
| catch(QM->Channel(message);publish); |
| catch(QM->SendMail(questname, quest, ME);publish); |
| return OK; |
| } |
| |
| int DeleteQuest(string questname) { |
| // Quest ist nicht gesetzt |
| if(!QueryQuest(questname)) |
| return DQ_NOT_SET; |
| |
| mixed *quest = QM->QueryQuest(questname); |
| // Questname ungueltig |
| if (!quest||!pointerp(quest)||quest==({})) |
| return DQ_KEY_INVALID; |
| // Unbefugter Zugriff |
| if (!IS_ARCH(this_interactive())) |
| return DQ_ILLEGAL_OBJ; |
| AddExp(-quest[1]); |
| m_delete(quests, questname); |
| force_save(); |
| return OK; |
| } |
| |
| int QueryQuest(string questname) { |
| int dummy; |
| |
| // Gaeste haben keine Quests. |
| if( sscanf( getuid(), "gast%d", dummy ) == 1 ) |
| return QQ_GUEST; |
| // Uebergebener Parameter "questname" ungueltig oder leer? |
| if(!questname || !stringp(questname) || questname == "") |
| return QQ_KEY_INVALID; |
| // Questname ist tatsaechlich in der Questliste enthalten? Alles klar! |
| if ( member(quests, questname) ) |
| return OK; |
| // Ansonsten war der Name wohl ungueltig. |
| return QQ_KEY_INVALID; |
| } |
| |
| int ModifyQuestTime(string qname, int when) { |
| if ( process_call() ) |
| return -1; |
| |
| // Nur EM+ oder der Tagebuchmaster duerfen die Werte aendern. |
| if ( !IS_ARCH(this_interactive()) && |
| load_name(previous_object())!="/d/wald/leusel/quest/objs/tagebuch-master") |
| return -1; |
| |
| // Questliste ist unerwartet kein Mapping. |
| if ( !mappingp(quests) ) |
| return -2; |
| |
| // Kein Questname angegeben, oder Spieler hat diese Quest ueberhaupt nicht |
| // geloest. |
| if ( !stringp(qname) || !member(quests, qname) ) |
| return -3; |
| |
| // Der Tagebuchmaster setzt Eintraege ggf. auf 0, wenn er keine Daten |
| // findet, und EM+ wollen Eintraege auf -1 setzen koennen, um das Einlesen |
| // der Daten noch einmal zu ermoeglichen, d.h. diese Werte sind zusaetzlich |
| // zu gueltigen Zeitwerten erlaubt. |
| if ( !intp(when) || when < -1 || when > time() ) |
| return -4; |
| |
| // Neuen Wert eintragen. |
| quests[qname,1] = when; |
| return 1; |
| } |
| |
| int QueryQuestTime(string qname) { |
| return quests[qname,1]; |
| } |
| |
| // Konvertiert Datenstruktur von quests in ein Mapping mit folgendem Aufbau: |
| // quests = ([ "questname" : Abenteuerpunkte; Zeit_des_Questabschlusses, ]) |
| protected void updates_after_restore(mixed newflag) { |
| // Ganz frischer Spieler? Dann keine Behandlung erforderlich. |
| if ( newflag ) |
| return; |
| // Wenn die Questliste noch kein Mapping ist, Konvertierung anstossen. |
| if ( !mappingp(quests) ) { |
| // Wenn noch keine Quests eingetragen sind, Leermapping eintragen. |
| if ( !sizeof(quests) ) { |
| quests = ([:2]); |
| return; |
| } |
| // Vorsichtshalber Leereintraege rausziehen. |
| quests -= ({({})}); |
| // Liste der Questzeiten aus dem Spieler auslesen. Wenn nicht vorhanden, |
| // Array mit -1-Elementen passender Laenge erzeugen. |
| // -1 an allen Stellen eintragen, wo bisher keine Daten vorliegen. |
| // Diese werden dann vom Questtagebuch durch die Daten ersetzt. |
| int *qtimes = QueryProp("questtime")||allocate(sizeof(quests), -1); |
| // Falls die Questliste laenger ist als die Zeitenliste, wird letztere |
| // um die fehlende Laenge in Form von -1-eintraegen ergaenzt, unter der |
| // Annahme, dass die fehlenden Eintraege bisher lediglich nicht |
| // eingelesen wurden. Im umgekehrten Fall werden alle Zeiten verworfen, |
| // da dieser Fall eintritt, wenn einem Spieler eine Quest ausgetragen |
| // wurde und die Listen in der Vergangenheit nicht synchron gehalten |
| // wurden. |
| if ( sizeof(qtimes) < sizeof(quests) ) { |
| qtimes += allocate(sizeof(quests)-sizeof(qtimes), -1); |
| } |
| if ( sizeof(qtimes) > sizeof(quests) ) { |
| qtimes = allocate(sizeof(quests), -1); |
| } |
| // Questdaten und Questzeiten zusammenpferchen. Ergibt folg. Mapping: |
| // temp = ([ ({Questname1, QP1}) : Questzeit, ... ]) |
| mapping temp = mkmapping(quests, qtimes); |
| quests = m_allocate(sizeof(quests),2); |
| foreach(mixed qdata, int qtime : temp) { |
| quests += ([ qdata[0] : qdata[1]; qtime ]); |
| } |
| if (QueryProp("questtime")) { |
| SetProp("questtime",0); |
| Set("questtime", SAVE, F_MODE_AD); |
| } |
| } |
| } |
| |
| // **** local property methods |
| static int _query_questpoints() { |
| int qp; |
| |
| if ( !mappingp(quests) || !sizeof(quests) ) { |
| return 0; |
| } |
| |
| closure qqp = symbol_function("QueryQuestPoints", QM); |
| // Die aktuell gueltigen Abenteuerpunkte aus dem Questmaster holen und |
| // die Questliste damit aktualisieren. qp wird als Referenz mit uebergeben |
| // damit das Additionsergebnis auch nach dem Durchlauf ausserhalb der |
| // Closure verfuegbar ist. |
| // Falls Abenteuerpunkte < 0 existieren, wird die entsprechende Quest |
| // aus der Liste ausgetragen. |
| walk_mapping(quests, |
| function void (string qname, int qpoints, int qtime, int sum) |
| { |
| qpoints = funcall(qqp, qname); |
| if (qpoints<0) |
| m_delete(quests,qname); |
| else |
| sum += qpoints; |
| }, &qp); |
| |
| Set(P_QP, qp); |
| return qp; |
| } |
| |
| static mixed _query_quests() { |
| return copy(quests); |
| } |