added some debug code & fixed compiler warning
[NeonServV5.git] / src / modules / funcmd.mod / cmd_funcmds_bomb.c
1 /* cmd_funcmds_bomb.c - NeonServ v5.6
2  * Copyright (C) 2011-2012  Philipp Kreil (pk910)
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17
18 static void funcmd_bomb_plant(struct funcmd_header_info *header, struct Event *event, char **argv, int argc, int kick_bomb);
19 static USERAUTH_CALLBACK(funcmd_bomb_plant_nick_lookup);
20 static void funcmd_bomb_plant_async1(struct funcmd_header_info *header, struct Event *event, struct UserNode *user, int wires, int kick_bomb);
21 static void funcmd_bomb_plant_async2(struct funcmd_header_info *header, struct Event *event, struct UserNode *user, int wires, int kick_bomb);
22 static void funcmd_bomb_defuse(struct funcmd_header_info *header, struct Event *event, char **argv, int argc);
23 static void funcmd_bomb_return(struct funcmd_header_info *header, struct Event *event, char **argv, int argc);
24 static TIMEQ_CALLBACK(funcmd_bomb_timeout);
25
26 struct funcmd_bomb_plant_cache {
27     struct funcmd_header_info header;
28     struct Event *event;
29     int wires : 4;
30     int kick_bomb : 4;
31 };
32
33 struct funcmd_bomb_bomb {
34     struct funcmd_header_info header;
35     struct UserNode *owner, *target;
36     struct timeq_entry *timer;
37     char wires[FUNCMD_BOMB_WIRES_MAX];
38     int right_wire : 4;
39     int kick_bomb : 4;
40     struct funcmd_bomb_bomb *next;
41 };
42
43 static struct funcmd_bomb_bomb *funcmd_bomb_bombs = NULL;
44
45 static int funcmd_bomb_freeuser(struct UserNode *user) {
46     struct funcmd_bomb_bomb *bomb, *next_bomb, *prev_bomb = NULL;
47     for(bomb = funcmd_bomb_bombs; bomb; bomb = next_bomb) {
48         next_bomb = bomb->next;
49         if(bomb->owner == user)
50             bomb->owner = NULL;
51         if(bomb->target == user) {
52             timeq_del(bomb->timer);
53             free(bomb);
54             if(prev_bomb)
55                 prev_bomb->next = next_bomb;
56             else
57                 funcmd_bomb_bombs = next_bomb;
58         } else
59             prev_bomb = bomb;
60     }
61     return 1;
62 }
63
64 static int funcmd_bomb_freechan(struct ChanNode *chan) {
65     struct funcmd_bomb_bomb *bomb, *next_bomb, *prev_bomb = NULL;
66     for(bomb = funcmd_bomb_bombs; bomb; bomb = next_bomb) {
67         next_bomb = bomb->next;
68         if(bomb->header.chan == chan) {
69             timeq_del(bomb->timer);
70             free(bomb);
71             if(prev_bomb)
72                 prev_bomb->next = next_bomb;
73             else
74                 funcmd_bomb_bombs = next_bomb;
75         } else
76             prev_bomb = bomb;
77     }
78     return 1;
79 }
80
81 static void funcmd_bomb_freeclient(struct ClientSocket *client) {
82     struct funcmd_bomb_bomb *bomb, *next_bomb, *prev_bomb = NULL;
83     for(bomb = funcmd_bomb_bombs; bomb; bomb = next_bomb) {
84         next_bomb = bomb->next;
85         if(bomb->header.client == client) {
86             timeq_del(bomb->timer);
87             free(bomb);
88             if(prev_bomb)
89                 prev_bomb->next = next_bomb;
90             else
91                 funcmd_bomb_bombs = next_bomb;
92         } else
93             prev_bomb = bomb;
94     }
95 }
96
97 CMD_BIND(funcmd_bomb) {
98     FUNCMD_HEADER;
99     if(argc) {
100         char *subcmd = argv[0];
101         argv++;
102         argc--;
103         if(!stricmp(subcmd, "plant"))
104             funcmd_bomb_plant(header, event, argv, argc, 0);
105         else if(!stricmp(subcmd, "kplant"))
106             funcmd_bomb_plant(header, event, argv, argc, 1);
107         else if(!stricmp(subcmd, "defuse"))
108             funcmd_bomb_defuse(header, event, argv, argc);
109         else if(!stricmp(subcmd, "return"))
110             funcmd_bomb_return(header, event, argv, argc);
111         else {
112             char tmp[MAXLEN];
113             sprintf(tmp, "%s %s", event->command->cmd, subcmd);
114             reply(header->client, header->user, "MODCMD_UNKNOWN", tmp);
115         }
116     } else {
117         reply(header->client, header->user, "FUN_BOMB_MENU");
118         reply(header->client, header->user, "FUN_BOMB_MENU_PLANT", event->command->cmd, FUNCMD_BOMB_WIRES_DEFAULT);
119         reply(header->client, header->user, "FUN_BOMB_MENU_KPLANT", event->command->cmd, FUNCMD_BOMB_WIRES_DEFAULT);
120         reply(header->client, header->user, "FUN_BOMB_MENU_DEFUSE", event->command->cmd);
121         //reply(header->client, header->user, "FUN_BOMB_MENU_RETURN", event->command->cmd);
122     }
123     FUNCMD_FOOTER;
124 }
125
126 static void funcmd_bomb_plant(struct funcmd_header_info *header, struct Event *event, char **argv, int argc, int kick_bomb) {
127     if(!argc) {
128         reply(header->client, header->user, "MODCMD_LESS_PARAM_COUNT");
129         return;
130     }
131     struct UserNode *user;
132     int wires = FUNCMD_BOMB_WIRES_DEFAULT;
133     if(!(user = getUserByNick(argv[0]))) {
134         reply(header->client, header->user, "NS_USER_UNKNOWN", argv[0]);
135         return;
136     }
137     if(isNetworkService(user)) {
138         reply(header->client, header->user, "FUN_BOMB_PLANT_SERVICE");
139         return;
140     }
141     if(user == header->user) {
142         reply(header->client, header->user, "FUN_BOMB_SELF");
143         return;
144     }
145     if(argc > 1) {
146         wires = atoi(argv[1]);
147         if(wires < FUNCMD_BOMB_WIRES_MIN || wires > FUNCMD_BOMB_WIRES_MAX) {
148             reply(header->client, header->user, "FUN_BOMB_PLANT_MAXWIRES", FUNCMD_BOMB_WIRES_MIN, FUNCMD_BOMB_WIRES_MAX);
149             return;
150         }
151     }
152     if(kick_bomb == 1) { /* protect shit... */
153         if(user->flags & USERFLAG_ISAUTHED) {
154             funcmd_bomb_plant_async1(header, event, user, wires, kick_bomb);
155         } else {
156             struct funcmd_bomb_plant_cache *cache = malloc(sizeof(*cache));
157             memcpy(&cache->header, header, sizeof(*header));
158             cache->event = event;
159             cache->wires = wires;
160             cache->kick_bomb = kick_bomb;
161             get_userauth(user, module_id, funcmd_bomb_plant_nick_lookup, cache);
162         }
163     } else
164         funcmd_bomb_plant_async2(header, event, user, wires, kick_bomb);
165 }
166
167 static USERAUTH_CALLBACK(funcmd_bomb_plant_nick_lookup) {
168     struct funcmd_bomb_plant_cache *cache = data;
169     if(!user) {
170         reply(cache->header.client, cache->header.user, "NS_USER_UNKNOWN", "*");
171     } else {
172         funcmd_bomb_plant_async1(&cache->header, cache->event, user, cache->wires, cache->kick_bomb);
173     }
174     free(cache);
175 }
176
177 static void funcmd_bomb_plant_async1(struct funcmd_header_info *header, struct Event *event, struct UserNode *user, int wires, int kick_bomb) {
178     if(kick_bomb == 1) { /* protect shit... */
179         if(isUserProtected(header->chan, user, header->user)) {
180             reply(header->client, header->user, "FUN_BOMB_PLANT_PROTECTED");
181             return;
182         }
183     }
184     funcmd_bomb_plant_async2(header, event, user, wires, kick_bomb);
185 }
186
187 static void funcmd_bomb_defuse_strip_color(char *buffer) {
188     int i, j;
189     j = 0;
190     for(i = 0; buffer[i]; i++) {
191         if(buffer[i] == '\003') {
192             i++;
193             if(!buffer[i]) break;
194             if(isdigit(buffer[i])) {
195                 i++;
196                 if(!buffer[i]) break;
197             }
198             if(isdigit(buffer[i])) {
199                 i++;
200                 if(!buffer[i]) break;
201             }
202         }
203         buffer[j++] = buffer[i];
204     }
205     buffer[j] = 0;
206 }
207
208 static int funcmd_bomb_defuse_get_wire_id(char *wire, struct UserNode *user) {
209     char *wires = get_language_string(user, "FUN_BOMB_WIRES");
210     char *cwire = wires;
211     char tmp[MAXLEN];
212     int found = 0, cindex = 0;
213     do {
214         wires = strchr(cwire, '|');
215         if(wires) {
216             *wires = '\0';
217         }
218         cindex++;
219         strcpy(tmp, cwire);
220         funcmd_bomb_defuse_strip_color(tmp);
221         if(!stricmp(wire, tmp))
222             found = cindex;
223         if(wires) {
224             *wires = '|';
225             cwire = wires + 1;
226         } else
227             cwire = NULL;
228     } while(!found && cwire);
229     return found;
230 }
231
232 static int funcmd_bomb_defuse_get_wire_name(int wire_id, char *buffer, char *wires, struct UserNode *user) {
233     if(!wires)
234         wires = get_language_string(user, "FUN_BOMB_WIRES");
235     char *cwire = wires;
236     int cindex = 0, chars = 0;
237     buffer[0] = 0;
238     do {
239         wires = strchr(cwire, '|');
240         if(wires) {
241             *wires = '\0';
242         }
243         cindex++;
244         if(cindex == wire_id)
245             chars = sprintf(buffer, "%s", cwire);
246         if(wires) {
247             *wires = '|';
248             cwire = wires + 1;
249         }
250     } while(!chars && cwire);
251     return chars;
252 }
253
254 static void funcmd_bomb_plant_async2(struct funcmd_header_info *header, struct Event *event, struct UserNode *user, int wires, int kick_bomb) {
255     //everything should be checked now... plant the bomb :)
256     struct funcmd_bomb_bomb *bomb;
257     for(bomb = funcmd_bomb_bombs; bomb; bomb = bomb->next) {
258         if(bomb->target == user) {
259             reply(header->client, header->user, "FUN_BOMB_TARGET_ACTIVE", user->nick);
260             return;
261         }
262         if(bomb->owner == header->user) {
263             reply(header->client, header->user, "FUN_BOMB_OWNER_ACTIVE");
264             return;
265         }
266     }
267     bomb = malloc(sizeof(*bomb));
268     memcpy(&bomb->header, header, sizeof(*header));
269     bomb->target = user;
270     bomb->owner = header->user;
271     bomb->kick_bomb = kick_bomb;
272     bomb->timer = timeq_add(FUNCMD_BOMB_TIME, module_id, funcmd_bomb_timeout, bomb);
273     bomb->next = funcmd_bomb_bombs;
274     funcmd_bomb_bombs = bomb;
275     int i, j, k, l;
276     int pool[FUNCMD_BOMB_WIRES_MAX+1];
277     for(i = 0; i < FUNCMD_BOMB_WIRES_MAX; i++) {
278         pool[i] = i+1;
279     }
280     pool[i] = 0;
281     for(i = 0; i < FUNCMD_BOMB_WIRES_MAX; i++) {
282         if(i < wires) {
283             j = (rand() % (FUNCMD_BOMB_WIRES_MAX - i));
284             bomb->wires[i] = pool[j];
285             l = 0;
286             for(k = 0; k < (FUNCMD_BOMB_WIRES_MAX - i); k++) {
287                 if(k == j)
288                     l = 1;
289                 pool[k] = pool[k+l];
290             }
291         } else
292             bomb->wires[i] = 0;
293     }
294     bomb->right_wire = bomb->wires[(rand() % wires)];
295     char *wires_lang_str_a = get_language_string(header->user, "FUN_BOMB_WIRES");
296     char *wires_lang_str_b = get_language_string(user, "FUN_BOMB_WIRES");
297     if(!header->send_notice && wires_lang_str_a != wires_lang_str_b) {
298         wires_lang_str_a = get_language_string(NULL, "FUN_BOMB_WIRES");
299         header->null_language = 1;
300         bomb->header.null_language = 1;
301     }
302     char wires_str[MAXLEN];
303     j = 0;
304     for(i = 0; i < wires; i++) {
305         if(i) {
306             wires_str[j++] = ',';
307             wires_str[j++] = ' ';
308         }
309         j += funcmd_bomb_defuse_get_wire_name(bomb->wires[i], wires_str+j, wires_lang_str_a, NULL);
310     }
311     wires_str[j] = '\0';
312     if(header->send_notice) {
313         reply(header->client, header->user, (kick_bomb ? "FUN_BOMB_KPLANTED" : "FUN_BOMB_PLANTED"), header->user->nick, user->nick, FUNCMD_BOMB_TIME, wires_str, event->command->cmd);
314         j = 0;
315         for(i = 0; i < wires; i++) {
316             if(i) {
317                 wires_str[j++] = ',';
318                 wires_str[j++] = ' ';
319             }
320             j += funcmd_bomb_defuse_get_wire_name(bomb->wires[i], wires_str+j, wires_lang_str_b, NULL);
321         }
322         wires_str[j] = '\0';
323         reply(header->client, user, (kick_bomb ? "FUN_BOMB_KPLANTED" : "FUN_BOMB_PLANTED"), header->user->nick, user->nick, FUNCMD_BOMB_TIME, wires_str, event->command->cmd);
324     } else
325         funcmd_reply(header, (kick_bomb ? "FUN_BOMB_KPLANTED" : "FUN_BOMB_PLANTED"), REPLYTYPE_NORMAL, header->user->nick, user->nick, FUNCMD_BOMB_TIME, wires_str, event->command->cmd);
326 }
327
328 static void funcmd_bomb_detonate(struct funcmd_bomb_bomb *bomb) {
329     char *ptr;
330     int user_count = ((ptr = getSetting(bomb->target, bomb->header.chan, "bombs")) ? atoi(ptr) : 0);
331     int total_count = ((ptr = getSetting(bomb->target, NULL, "bombs")) ? atoi(ptr) : 0);
332     int detonated_count = ((ptr = getSetting(bomb->target, NULL, "bombs_detonated")) ? atoi(ptr) : 0);
333     user_count++;
334     total_count++;
335     detonated_count++;
336     char buf[10];
337     sprintf(buf, "%d", user_count);
338     setSetting(bomb->target, bomb->header.chan, "bombs", buf);
339     sprintf(buf, "%d", total_count);
340     setSetting(bomb->target, NULL, "bombs", buf);
341     sprintf(buf, "%d", detonated_count);
342     setSetting(bomb->target, NULL, "bombs_detonated", buf);
343     char *wires = get_language_string(NULL, "FUN_BOMB_WIRES");
344     char *cwire = wires;
345     char tmp[MAXLEN];
346     int cindex = 0;
347     tmp[0] = 0;
348     do {
349         wires = strchr(cwire, '|');
350         if(wires) {
351             *wires = '\0';
352         }
353         cindex++;
354         if(cindex == bomb->right_wire)
355             strcpy(tmp, cwire);
356         if(wires) {
357             *wires = '|';
358             cwire = wires + 1;
359         } else
360             cwire = NULL;
361     } while(!tmp[0] && cwire);
362     if(bomb->header.send_notice)
363         reply(bomb->header.client, bomb->owner, "FUN_BOMB_DETONATED", REPLYTYPE_NORMAL, bomb->target->nick, tmp, total_count, user_count);
364     funcmd_reply(&bomb->header, "FUN_BOMB_DETONATED", REPLYTYPE_NORMAL, bomb->target->nick, tmp, total_count, user_count);
365     if(bomb->kick_bomb) {
366         putsock(bomb->header.client, "KICK %s %s :[BOMB] *BOOOOOOM*", bomb->header.chan->name, bomb->target->nick);
367     }
368 }
369
370 static void funcmd_bomb_defuse(struct funcmd_header_info *header, struct Event *event, char **argv, int argc) {
371     if(!argc) {
372         reply(header->client, header->user, "MODCMD_LESS_PARAM_COUNT");
373         return;
374     }
375     struct funcmd_bomb_bomb *bomb, *prev_bomb = NULL;
376     for(bomb = funcmd_bomb_bombs; bomb; bomb = bomb->next) {
377         if(bomb->target == header->user)
378             break;
379         else
380             prev_bomb = bomb;
381     }
382     if(!bomb) {
383         reply(header->client, header->user, "FUN_BOMB_NOBOMB");
384         return;
385     }
386     funcmd_bomb_defuse_strip_color(argv[0]);
387     int cut_wire = funcmd_bomb_defuse_get_wire_id(argv[0], header->user);
388     if(!cut_wire)
389         cut_wire = funcmd_bomb_defuse_get_wire_id(argv[0], NULL);
390     if(!cut_wire) {
391         reply(header->client, header->user, "FUN_BOMB_UNKNOWN_WIRE", argv[0]);
392         return;
393     }
394     if(bomb->right_wire == cut_wire) {
395         char *tmp;
396         int user_count = ((tmp = getSetting(header->user, header->chan, "bombs")) ? atoi(tmp) : 0);
397         int total_count = ((tmp = getSetting(header->user, NULL, "bombs")) ? atoi(tmp) : 0);
398         int defused_count = ((tmp = getSetting(header->user, NULL, "bombs_defused")) ? atoi(tmp) : 0);
399         user_count++;
400         total_count++;
401         defused_count++;
402         char buf[10];
403         sprintf(buf, "%d", user_count);
404         setSetting(header->user, header->chan, "bombs", buf);
405         sprintf(buf, "%d", total_count);
406         setSetting(header->user, NULL, "bombs", buf);
407         sprintf(buf, "%d", defused_count);
408         setSetting(header->user, NULL, "bombs_defused", buf);
409         
410         if(header->send_notice)
411             reply(header->client, bomb->owner, "FUN_BOMB_DEFUSED", REPLYTYPE_NORMAL, header->user->nick, total_count, user_count, defused_count);
412         funcmd_reply(header, "FUN_BOMB_DEFUSED", REPLYTYPE_NORMAL, header->user->nick, total_count, user_count, defused_count);
413     } else {
414         funcmd_bomb_detonate(bomb);
415     }
416     timeq_del(bomb->timer);
417     if(prev_bomb)
418         prev_bomb->next = bomb->next;
419     else
420         funcmd_bomb_bombs = bomb->next;
421     free(bomb);
422 }
423
424 static void funcmd_bomb_return(struct funcmd_header_info *header, struct Event *event, char **argv, int argc) {
425     if(!argc) {
426         reply(header->client, header->user, "MODCMD_LESS_PARAM_COUNT");
427         return;
428     }
429     //following ;)
430 }
431
432 static TIMEQ_CALLBACK(funcmd_bomb_timeout) {
433     struct funcmd_bomb_bomb *cbomb = data;
434     struct funcmd_bomb_bomb *bomb, *prev_bomb = NULL;
435     for(bomb = funcmd_bomb_bombs; bomb; bomb = bomb->next) {
436         if(cbomb == bomb) {
437             cbomb = NULL;
438             break;
439         } else
440             prev_bomb = bomb;
441     }
442     if(cbomb) return;
443     funcmd_bomb_detonate(bomb);
444     if(prev_bomb)
445         prev_bomb->next = bomb->next;
446     else
447         funcmd_bomb_bombs = bomb->next;
448     free(bomb);
449 }