MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame^] | 1 | // MorgenGrauen MUDlib |
| 2 | /** \file /file.c |
| 3 | * merkt sich Syntaxen und deren Erfolg |
| 4 | * Kommt gar nicht mit geschachtelten Befehlen klar... |
| 5 | * \author Zesstra |
| 6 | */ |
| 7 | |
| 8 | #pragma strong_types,save_types,rtt_checks |
| 9 | #pragma no_clone,no_inherit,no_shadow |
| 10 | #pragma pedantic, range_check |
| 11 | |
| 12 | #include <defines.h> |
| 13 | #include <events.h> |
| 14 | #include <wizlevels.h> |
| 15 | #include <player/base.h> |
| 16 | #include <userinfo.h> |
| 17 | #include <driver_info.h> |
| 18 | #include <regexp.h> |
| 19 | |
| 20 | #define HOME(x) (__PATH__(0)+x) |
| 21 | #define ZDEBUG(x) tell_room("/players/zesstra/workroom",\ |
| 22 | sprintf("syntax: %O\n",x)); |
| 23 | |
| 24 | mapping blacklist; |
| 25 | |
| 26 | struct cmd_s { |
| 27 | string verb; |
| 28 | string cmd; |
| 29 | string uid; |
| 30 | int success; |
| 31 | int fp; |
| 32 | int evalno; |
| 33 | string tp_uid; |
| 34 | int finished; |
| 35 | }; |
| 36 | |
| 37 | // LIste der letzten Kommandos, Queue zum speichern in die DB. |
| 38 | // Das letzte Element ist das letzte Kommando (ggf. noch nicht abgeschlossen) |
| 39 | private struct cmd_s *commands = ({}); |
| 40 | |
| 41 | protected void create() |
| 42 | { |
| 43 | seteuid(getuid()); |
| 44 | if (sl_open(HOME("ARCH/syntaxen.sqlite")) != 1) |
| 45 | { |
| 46 | raise_error("Datenbank konnte nicht geoeffnet werden.\n"); |
| 47 | } |
| 48 | // Tabellen und Indices anlegen, falls die nicht existieren. |
| 49 | sl_exec("CREATE TABLE IF NOT EXISTS syntaxen(" |
| 50 | "cmd TEXT UNIQUE, " |
| 51 | "verb TEXT NOT NULL, envuid TEXT NOT NULL, " |
| 52 | "success INTEGER, count INTEGER, fp INTEGER);"); |
| 53 | sl_exec("CREATE INDEX IF NOT EXISTS idx_verb ON syntaxen(verb);"); |
| 54 | // dieses Objekt darf nur per hand (mit this_player()) geladen werden, weil |
| 55 | // da ein Teil der Blacklist herkommt... Man beachte, dass dies auch das |
| 56 | // ist, was die ueblichen Kommunikationsbefehle ausfiltert. |
| 57 | string *tmp = map(this_player()->QueryProp(P_LOCALCMDS), |
| 58 | function string (mixed val) |
| 59 | {return val[0];} |
| 60 | ); |
| 61 | blacklist = mkmapping(tmp |
| 62 | - ({ "toete","schnupper", "schnuppere", "suche","such", |
| 63 | "unt", "untersuche","untersuch", "riech", |
| 64 | "rieche", "lausch", "lausche", "taste", |
| 65 | "fuehl", "fuehle, beruehre", "schau", "schaue", |
| 66 | "les", "lies", "betrachte", "betr", "betracht", |
| 67 | "teile" // wird per regexp gefiltert! |
| 68 | }) |
| 69 | + ({"mail","frage","frag", "xload", "xeval", "xcall", |
| 70 | "gruppe", "g", "team", "frufe", "fruf", "fwer", |
| 71 | "femote", "rknuddel", "knuddel", "nick", "nicke", |
| 72 | "rnick", "rnicke", "knuddel", "knuddele", |
| 73 | "rknuddel", "rknuddele","denke","denk", |
| 74 | "ffix","fnotiz","fuebertrage", "chaoskontrolle", |
| 75 | "kreis", // Matrixkristall |
| 76 | }) |
| 77 | ); |
| 78 | } |
| 79 | |
| 80 | private void write_db() |
| 81 | { |
| 82 | foreach(struct cmd_s c : commands) |
| 83 | { |
| 84 | int** row=sl_exec("SELECT rowid, success, count, fp from syntaxen " |
| 85 | "WHERE cmd=?1;", |
| 86 | c->cmd); |
| 87 | if (row) |
| 88 | { |
| 89 | sl_exec("UPDATE syntaxen SET success=?2, count=?3, fp=?4" |
| 90 | "WHERE rowid=?1;", row[0][0], |
| 91 | c->success || row[0][1], |
| 92 | ++row[0][2], c->fp || row[0][3] ); |
| 93 | } |
| 94 | else |
| 95 | { |
| 96 | sl_exec("INSERT INTO syntaxen(verb, cmd, envuid, success, count, fp) " |
| 97 | "VALUES(?1,?2,?3,?4,?5,?6);", |
| 98 | c->verb, c->cmd, c->uid, c->success, 1, c->fp); |
| 99 | } |
| 100 | } |
| 101 | commands = ({}); |
| 102 | } |
| 103 | |
| 104 | // Beendet ein Kommando, wird nur intern gerufen |
| 105 | private void commit(struct cmd_s c) |
| 106 | { |
| 107 | c->finished = 1; |
| 108 | //printf("Kommando abgeschlossen: %O\n", c); |
| 109 | if (get_eval_cost() > 1000000 |
| 110 | && sizeof(commands) > 5 |
| 111 | && find_call_out(#'write_db) == -1) |
| 112 | { |
| 113 | // In DB wegschreiben |
| 114 | call_out(#'write_db, 1); |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | public varargs int remove(int silent) |
| 119 | { |
| 120 | write_db(); |
| 121 | destruct(this_object()); |
| 122 | return 1; |
| 123 | } |
| 124 | |
| 125 | // gerufen, wenn ein Spieler ein Kommando eingetippt hat, aus modify_command() |
| 126 | // heraus. Nach Parsen und Kommandoblock, aber vor allem anderen. |
| 127 | // ACHTUNG: wenn ein Kommando erfolgreich ist, wird KEIN end_cmd() von aussen |
| 128 | // gerufen... |
| 129 | public void start_cmd(string cmdstr) |
| 130 | { |
| 131 | if (!interactive(previous_object())) |
| 132 | return; |
| 133 | cmdstr = lower_case(cmdstr); |
| 134 | // letztes Kommando notfalls abschliessen |
| 135 | struct cmd_s cmd; |
| 136 | if (sizeof(commands)) |
| 137 | { |
| 138 | cmd = commands[<1]; |
| 139 | if (!cmd->finished) |
| 140 | { |
| 141 | // wir betrachten es uebrigens als erfolgreich! |
| 142 | commit(cmd); |
| 143 | } |
| 144 | } |
| 145 | // teile- mit und Ebenen und alle Kommandos, die nur aus verb und einem Wort |
| 146 | // bestehen, sind auch unnuetz. |
| 147 | //printf("%O\n",cmdstr); |
| 148 | if (sizeof(explode(cmdstr, " ")) < 3 |
| 149 | || sizeof(cmdstr) > 100 |
| 150 | || regmatch(cmdstr,"^teile.*mit",RE_PCRE) |
| 151 | || regmatch(cmdstr,"^-[[:alpha:]-]*[' :]{1}",RE_PCRE) |
| 152 | || regmatch(cmdstr,"^[.']", RE_PCRE) |
| 153 | ) |
| 154 | { |
| 155 | return; |
| 156 | } |
| 157 | cmd = (<cmd_s> verb: explode(cmdstr, " ")[0], |
| 158 | cmd: cmdstr, |
| 159 | uid: getuid(environment(this_player())), |
| 160 | evalno: driver_info(DI_EVAL_NUMBER), |
| 161 | success: 1, |
| 162 | tp_uid: getuid(previous_object()), |
| 163 | ); |
| 164 | // sonstige Blacklist |
| 165 | if (member(blacklist, cmd->verb)) |
| 166 | return; |
| 167 | |
| 168 | commands += ({cmd}); |
| 169 | //printf("Kommandostart: %O\n", cmd); |
| 170 | } |
| 171 | |
| 172 | // gerufen von _auswerten() im Spielerobjekt - das kommt ziemlich am Ende der |
| 173 | // Kommandoverarbeitung - wenn es noch gerufen wird und uns ruft, betrachten |
| 174 | // wir das Kommando als NICHT erfolgreich. |
| 175 | public void cmd_unsuccessful() |
| 176 | { |
| 177 | if (!sizeof(commands)) |
| 178 | return; |
| 179 | struct cmd_s cmd = commands[<1]; |
| 180 | // Darf nur vom Spielerobjekt gerufen werden, welches das letzte Kommando |
| 181 | // angefangen hat. |
| 182 | if (cmd->tp_uid != getuid(previous_object())) |
| 183 | return; |
| 184 | // und dies gehoert nur zum letzten Kommando, wenn Verb und Eval-No |
| 185 | // uebereinstimmen. |
| 186 | if (cmd->verb == query_verb() |
| 187 | || cmd->evalno == driver_info(DI_EVAL_NUMBER)) |
| 188 | { |
| 189 | cmd->success = 0; |
| 190 | //printf("Kommando nicht erfolgreich: %O\n", cmd); |
| 191 | commit(cmd); |
| 192 | } |
| 193 | // Wenn nicht, war das letzte Kommando offenbar doch erfolgreich. Aus |
| 194 | // irgendnem Grund haben wir aber den Start des neuen Kommandos verpasst. |
| 195 | // Daher verwerfen wir das jetzt. Das alte Kommando war aber offenbar |
| 196 | // erfolgreich, daher wird es jetzt abgeschlossen. |
| 197 | else |
| 198 | { |
| 199 | commit(cmd); |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | public void LogEP(int type) |
| 204 | { |
| 205 | if (!sizeof(commands)) |
| 206 | return; |
| 207 | struct cmd_s cmd = commands[<1]; |
| 208 | // Darf nur vom Spielerobjekt gerufen werden, welches das letzte Kommando |
| 209 | // angefangen hat. |
| 210 | if (cmd->tp_uid != getuid(previous_object())) |
| 211 | return; |
| 212 | //printf("FP gefunden: %O\n", cmd); |
| 213 | // und dies gehoert nur zum letzten Kommando, wenn Verb und Eval-No |
| 214 | // uebereinstimmen. |
| 215 | if (cmd->verb == query_verb() |
| 216 | || cmd->evalno == driver_info(DI_EVAL_NUMBER)) |
| 217 | { |
| 218 | cmd->fp = type+1; |
| 219 | // Und wenn es nen FP gab, ist das Kommando auch erfolgreich. |
| 220 | commit(cmd); |
| 221 | } |
| 222 | } |
| 223 | |