1: <?php
2:
3: namespace Budabot\User\Modules;
4:
5: use stdClass;
6:
7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66:
67: class TowerController {
68:
69: 70: 71: 72:
73: public $moduleName;
74:
75:
76: public $playfieldController;
77:
78:
79: public $playerManager;
80:
81:
82: public $text;
83:
84:
85: public $settingManager;
86:
87:
88: public $chatBot;
89:
90:
91: public $db;
92:
93:
94: public $util;
95:
96:
97: public $levelController;
98:
99:
100: public $logger;
101:
102: protected $attackListeners = array();
103:
104: 105: 106: 107: 108: 109: 110: 111: 112:
113: public $defaultTowerAttackSpam = "1";
114:
115: 116: 117: 118: 119: 120: 121: 122:
123: public $defaultTowerPageSize = "15";
124:
125: 126: 127: 128: 129: 130: 131: 132: 133:
134: public $defaultCheckCloseTimeOnScout = "1";
135:
136: 137: 138: 139: 140: 141: 142: 143: 144:
145: public $defaultCheckGuildNameOnScout = "1";
146:
147: 148: 149:
150: public function registerAttackListener($callback, $data = null) {
151: if (!is_callable($callback)) {
152: $this->logger->log('ERROR', 'Given callback is not valid.');
153: return;
154: }
155: $listener = new stdClass();
156: $listener->callback = $callback;
157: $listener->data = $data;
158: $this->attackListeners []= $listener;
159: }
160:
161: 162: 163: 164:
165: public function setup() {
166: $this->db->loadSQLFile($this->moduleName, 'tower_attack');
167: $this->db->loadSQLFile($this->moduleName, 'scout_info');
168: $this->db->loadSQLFile($this->moduleName, 'tower_site');
169: }
170:
171: 172: 173: 174: 175: 176: 177:
178: public function attacksCommand($message, $channel, $sender, $sendto, $args) {
179: $this->attacksCommandHandler($args[1], '', '', $sendto);
180: }
181:
182: 183: 184: 185: 186: 187: 188: 189:
190: public function attacks2Command($message, $channel, $sender, $sendto, $args) {
191: $playfield = $this->playfieldController->getPlayfieldByName($args[1]);
192: if ($playfield === null) {
193: $msg = "Please enter a valid playfield.";
194: $sendto->reply($msg);
195: return;
196: }
197:
198: $tower_info = $this->getTowerInfo($playfield->id, $args[2]);
199: if ($tower_info === null) {
200: $msg = "Invalid site number.";
201: $sendto->reply($msg);
202: return;
203: }
204:
205: $cmd = "$args[1] $args[2] ";
206: $search = "WHERE a.`playfield_id` = {$tower_info->playfield_id} AND a.`site_number` = {$tower_info->site_number}";
207: $this->attacksCommandHandler($args[3], $search, $cmd, $sendto);
208: }
209:
210: 211: 212: 213: 214: 215: 216: 217:
218: public function attacksOrgCommand($message, $channel, $sender, $sendto, $args) {
219: $cmd = "org $args[1] ";
220: $value = str_replace("'", "''", $args[1]);
221: $search = "WHERE a.`att_guild_name` LIKE '$value' OR a.`def_guild_name` LIKE '$value'";
222: $this->attacksCommandHandler($args[2], $search, $cmd, $sendto);
223: }
224:
225: 226: 227: 228: 229: 230: 231: 232:
233: public function attacksPlayerCommand($message, $channel, $sender, $sendto, $args) {
234: $cmd = "player $args[1] ";
235: $value = str_replace("'", "''", $args[1]);
236: $search = "WHERE a.`att_player` LIKE '$value'";
237: $this->attacksCommandHandler($args[2], $search, $cmd, $sendto);
238: }
239:
240: 241: 242: 243: 244: 245:
246: public function lcCommand($message, $channel, $sender, $sendto, $args) {
247: $sql = "SELECT * FROM playfields WHERE `id` IN (SELECT DISTINCT `playfield_id` FROM tower_site) ORDER BY `short_name`";
248: $data = $this->db->query($sql);
249:
250: $blob = '';
251: forEach ($data as $row) {
252: $baseLink = $this->text->makeChatcmd($row->long_name, "/tell <myname> lc $row->short_name");
253: $blob .= "$baseLink <highlight>($row->short_name)<end>\n";
254: }
255: $msg = $this->text->makeBlob('Land Control Index', $blob);
256: $sendto->reply($msg);
257: }
258:
259: 260: 261: 262: 263: 264:
265: public function lc2Command($message, $channel, $sender, $sendto, $args) {
266: $playfield_name = strtoupper($args[1]);
267: $playfield = $this->playfieldController->getPlayfieldByName($playfield_name);
268: if ($playfield === null) {
269: $msg = "Playfield '$playfield_name' could not be found.";
270: $sendto->reply($msg);
271: return;
272: }
273:
274: $sql = "SELECT *, t1.playfield_id, t1.site_number FROM tower_site t1
275: JOIN playfields p ON (t1.playfield_id = p.id)
276: WHERE t1.playfield_id = ?";
277:
278: $data = $this->db->query($sql, $playfield->id);
279: if (count($data)) {
280: $blob = '';
281: forEach ($data as $row) {
282: $blob .= "<pagebreak>" . $this->formatSiteInfo($row) . "\n\n";
283: }
284:
285: $msg = $this->text->makeBlob("All Bases in $playfield->long_name", $blob);
286: } else {
287: $msg = "Playfield <highlight>$playfield->long_name<end> does not have any tower sites.";
288: }
289:
290: $sendto->reply($msg);
291: }
292:
293: 294: 295: 296: 297: 298:
299: public function lc3Command($message, $channel, $sender, $sendto, $args) {
300: $playfield_name = strtoupper($args[1]);
301: $playfield = $this->playfieldController->getPlayfieldByName($playfield_name);
302: if ($playfield === null) {
303: $msg = "Playfield '$playfield_name' could not be found.";
304: $sendto->reply($msg);
305: return;
306: }
307:
308: $site_number = $args[2];
309: $sql = "SELECT *, t1.playfield_id, t1.site_number FROM tower_site t1
310: JOIN playfields p ON (t1.playfield_id = p.id)
311: WHERE t1.playfield_id = ? AND t1.site_number = ?";
312:
313: $row = $this->db->queryRow($sql, $playfield->id, $site_number);
314: if ($row !== null) {
315: $blob = $this->formatSiteInfo($row) . "\n\n";
316:
317:
318: $sql = "
319: SELECT
320: a.*,
321: v.*,
322: COALESCE(v.time, a.time) dt
323: FROM
324: tower_attack_<myname> a
325: LEFT JOIN tower_victory_<myname> v
326: ON v.attack_id = a.id
327: WHERE
328: a.playfield_id = ?
329: AND a.site_number = ?
330: ORDER BY
331: dt DESC
332: LIMIT 10";
333: $data = $this->db->query($sql, $playfield->id, $site_number);
334: forEach ($data as $row) {
335: if (empty($row->attack_id)) {
336:
337: if (!empty($row->att_guild_name)) {
338: $name = $row->att_guild_name;
339: } else {
340: $name = $row->att_player;
341: }
342: $blob .= "<$row->att_faction>$name<end> attacked <$row->def_faction>$row->def_guild_name<end>\n";
343: } else {
344:
345: $blob .= "<$row->win_faction>$row->win_guild_name<end> won against <$row->lose_faction>$row->lose_guild_name<end>\n";
346: }
347: }
348:
349: $msg = $this->text->makeBlob("$playfield->short_name $site_number", $blob);
350: } else {
351: $msg = "Invalid site number.";
352: }
353:
354: $sendto->reply($msg);
355: }
356:
357: 358: 359: 360:
361: public function opentimesCommand($message, $channel, $sender, $sendto, $args) {
362: $sql = "
363: SELECT
364: guild_name,
365: sum(ct_ql) AS total_ql
366: FROM
367: scout_info
368: GROUP BY
369: guild_name
370: ORDER BY
371: guild_name ASC";
372: $data = $this->db->query($sql);
373: $contractQls = array();
374: forEach ($data as $row) {
375: $contractQls[$row->guild_name] = $row->total_ql;
376: }
377:
378: $sql = "
379: SELECT
380: *
381: FROM
382: tower_site t
383: JOIN scout_info s ON (t.playfield_id = s.playfield_id AND s.site_number = t.site_number)
384: JOIN playfields p ON (t.playfield_id = p.id)
385: ORDER BY
386: guild_name ASC,
387: ct_ql DESC";
388: $data = $this->db->query($sql);
389:
390: if (count($data) > 0) {
391: $blob = '';
392: $currentGuildName = '';
393: forEach ($data as $row) {
394: if ($row->guild_name != $currentGuildName) {
395: $contractQl = $contractQls[$row->guild_name];
396: $contractQl = ($contractQl * 2);
397: $faction = strtolower($row->faction);
398:
399: $blob .= "\n<u><$faction>$row->guild_name<end></u> (Total Contract QL: $contractQl)\n";
400: $currentGuildName = $row->guild_name;
401: }
402: $gas_level = $this->getGasLevel($row->close_time);
403: $gas_change_string = "$gas_level->color $gas_level->gas_level - $gas_level->next_state in " . gmdate('H:i:s', $gas_level->gas_change) . "<end>";
404:
405: $site_link = $this->text->makeChatcmd("$row->short_name $row->site_number", "/tell <myname> lc $row->short_name $row->site_number");
406: $open_time = $row->close_time - (3600 * 6);
407: if ($open_time < 0) {
408: $open_time += 86400;
409: }
410:
411: $blob .= "$site_link - {$row->min_ql}-{$row->max_ql}, $row->ct_ql CT, $gas_change_string [by $row->scouted_by]\n";
412: }
413:
414: $msg = $this->text->makeBlob("Scouted Bases", $blob);
415: } else {
416: $msg = "No sites currently scouted.";
417: }
418: $sendto->reply($msg);
419: }
420:
421: 422: 423: 424: 425: 426: 427:
428: public function penaltyCommand($message, $channel, $sender, $sendto, $args) {
429: if (count($args) == 2) {
430: $budatime = $args[1];
431: } else {
432: $budatime = '2h';
433: }
434:
435: $time = $this->util->parseTime($budatime);
436: if ($time < 1) {
437: $msg = "You must enter a valid time parameter.";
438: $sendto->reply($msg);
439: return;
440: }
441:
442: $penaltyTimeString = $this->util->unixtimeToReadable($time, false);
443:
444: $data = $this->getSitesInPenalty(time() - $time);
445:
446: if (count($data) > 0) {
447: $blob = '';
448: $current_faction = '';
449: forEach ($data as $row) {
450: if ($current_faction != $row->att_faction) {
451: $blob .= "\n<header2>{$row->att_faction}<end>\n";
452: $current_faction = $row->att_faction;
453: }
454: $timeString = $this->util->unixtimeToReadable(time() - $row->penalty_time, false);
455: $blob .= "<{$row->att_faction}>{$row->att_guild_name}<end> - $timeString ago\n";
456: }
457: $msg = $this->text->makeBlob("Orgs in penalty ($penaltyTimeString)", $blob);
458: } else {
459: $msg = "There are no orgs who have attacked or won battles in the past $penaltyTimeString.";
460: }
461: $sendto->reply($msg);
462: }
463:
464: 465: 466: 467: 468: 469:
470: public function remscoutCommand($message, $channel, $sender, $sendto, $args) {
471: $playfield_name = $args[1];
472: $site_number = $args[2];
473:
474: $playfield = $this->playfieldController->getPlayfieldByName($playfield_name);
475: if ($playfield === null) {
476: $msg = "Invalid playfield.";
477: $sendto->reply($msg);
478: return;
479: }
480:
481: $tower_info = $this->getTowerInfo($playfield->id, $site_number);
482: if ($tower_info === null) {
483: $msg = "Invalid site number.";
484: $sendto->reply($msg);
485: return;
486: }
487:
488: $num_rows = $this->remScoutSite($playfield->id, $site_number);
489:
490: if ($num_rows == 0) {
491: $msg = "Could not find a scout record for {$playfield->short_name} {$site_number}.";
492: } else {
493: $msg = "{$playfield->short_name} {$site_number} removed successfully.";
494: }
495: $sendto->reply($msg);
496: }
497:
498: 499: 500: 501: 502:
503: public function scoutCommand($message, $channel, $sender, $sendto, $args) {
504: $skip_checks = false;
505:
506: if (count($args) == 7) {
507: $playfield_name = $args[1];
508: $site_number = $args[2];
509: $closing_time = $args[3];
510: $ct_ql = $args[4];
511: $faction = $this->getFaction($args[5]);
512: $guild_name = $args[6];
513: } else {
514: $pattern = "@Control Tower - ([^ ]+) Level: (\d+) Danger level: (.+) Alignment: ([^ ]+) Organization: (.+) Created at UTC: ([^ ]+) ([^ ]+)@si";
515: if (preg_match($pattern, $args[3], $arr)) {
516: $playfield_name = $args[1];
517: $site_number = $args[2];
518: $closing_time = $arr[7];
519: $ct_ql = $arr[2];
520: $faction = $this->getFaction($arr[1]);
521: $guild_name = $arr[5];
522: } else {
523:
524: return false;
525: }
526: }
527:
528: $msg = $this->addScoutInfo($sender, $playfield_name, $site_number, $closing_time, $ct_ql, $faction, $guild_name, $skip_checks);
529: $sendto->reply($msg);
530: }
531:
532: 533: 534: 535: 536:
537: public function forcescoutCommand($message, $channel, $sender, $sendto, $args) {
538: $skip_checks = true;
539:
540: if (count($args) == 7) {
541: $playfield_name = $args[1];
542: $site_number = $args[2];
543: $closing_time = $args[3];
544: $ct_ql = $args[4];
545: $faction = $this->getFaction($args[5]);
546: $guild_name = $args[6];
547: } else {
548: $pattern = "@Control Tower - ([^ ]+) Level: (\d+) Danger level: (.+) Alignment: ([^ ]+) Organization: (.+) Created at UTC: ([^ ]+) ([^ ]+)@si";
549: if (preg_match($pattern, $args[3], $arr)) {
550: $playfield_name = $args[1];
551: $site_number = $args[2];
552: $closing_time = $arr[7];
553: $ct_ql = $arr[2];
554: $faction = $this->getFaction($arr[1]);
555: $guild_name = $arr[5];
556: } else {
557:
558: return false;
559: }
560: }
561:
562: $msg = $this->addScoutInfo($sender, $playfield_name, $site_number, $closing_time, $ct_ql, $faction, $guild_name, $skip_checks);
563: $sendto->reply($msg);
564: }
565:
566: public function addScoutInfo($sender, $playfield_name, $site_number, $closing_time, $ct_ql, $faction, $guild_name, $skip_checks) {
567: if ($faction != 'Omni' && $faction != 'Neutral' && $faction != 'Clan') {
568: return "Valid values for faction are: 'Omni', 'Neutral', and 'Clan'.";
569: }
570:
571: $playfield = $this->playfieldController->getPlayfieldByName($playfield_name);
572: if ($playfield === null) {
573: return "Invalid playfield.";
574: }
575:
576: $tower_info = $this->getTowerInfo($playfield->id, $site_number);
577: if ($tower_info === null) {
578: return "Invalid site number.";
579: }
580:
581: if ($ct_ql < $tower_info->min_ql || $ct_ql > $tower_info->max_ql) {
582: return "$playfield->short_name $tower_info->site_number can only accept Control Tower of ql {$tower_info->min_ql}-{$tower_info->max_ql}.";
583: }
584:
585: $closing_time_array = explode(':', $closing_time);
586: $closing_time_seconds = $closing_time_array[0] * 3600 + $closing_time_array[1] * 60 + $closing_time_array[2];
587:
588: if (!$skip_checks && $this->settingManager->get('check_close_time_on_scout') == 1) {
589: $last_victory = $this->getLastVictory($tower_info->playfield_id, $tower_info->site_number);
590: if ($last_victory !== null) {
591: $victory_time_of_day = $last_attack->time % 86400;
592: if ($victory_time_of_day > $closing_time_seconds) {
593: $victory_time_of_day -= 86400;
594: }
595:
596: if ($closing_time_seconds - $victory_time_of_day > 3600) {
597: $check_blob .= "- <green>Closing time<end> The closing time you have specified is more than 1 hour after the site was destroyed.";
598: $check_blob .= " Please verify that you are using the closing time and not the gas change time and that the closing time is correct.\n\n";
599: }
600: }
601: }
602:
603: if (!$skip_checks && $this->settingManager->get('check_guild_name_on_scout') == 1) {
604: if (!$this->checkGuildName($guild_name)) {
605: $check_blob .= "- <green>Org name<end> The org name you entered has never attacked or been attacked.\n\n";
606: }
607: }
608:
609: if ($check_blob) {
610: $forceCmd = "forcescout $playfield->short_name $site_number $closing_time $ct_ql $faction $guild_name";
611: $forcescoutLink = $this->text->makeChatcmd("<symbol>$forceCmd", "/tell <myname> $forceCmd");
612: $check_blob .= "Please correct these errors, or, if you are sure the values you entered are correct, use !forcescout to bypass these checks.\n\n";
613: $check_blob .= $forcescoutLink;
614:
615: return $this->text->makeBlob("Scouting problems for $playfield->short_name $site_number", $check_blob);
616: } else {
617: $this->addScoutSite($playfield->id, $site_number, $closing_time_seconds, $ct_ql, $faction, $guild_name, $sender);
618: return "Scout info for <highlight>$playfield->short_name $site_number<end> has been updated.";
619: }
620: }
621:
622: 623: 624: 625: 626:
627: public function towerStatsCommand($message, $channel, $sender, $sendto, $args) {
628: if (count($args) == 2) {
629: $budatime = $args[1];
630: } else {
631: $budatime = "1d";
632: }
633:
634: $time = $this->util->parseTime($budatime);
635: if ($time < 1) {
636: $msg = "You must enter a valid time parameter.";
637: $sendto->reply($msg);
638: return;
639: }
640:
641: $timeString = $this->util->unixtimeToReadable($time);
642:
643: $blob = '';
644:
645: $sql = "SELECT
646: att_faction,
647: COUNT(att_faction) AS num
648: FROM
649: tower_attack_<myname>
650: WHERE
651: `time` >= ?
652: GROUP BY
653: att_faction
654: ORDER BY
655: num DESC";
656:
657: $data = $this->db->query($sql, time() - $time);
658: forEach ($data as $row) {
659: $blob .= "<{$row->att_faction}>{$row->att_faction}<end> have attacked <highlight>{$row->num}<end> times.\n";
660: }
661: if (count($data) > 0) {
662: $blob .= "\n";
663: }
664:
665: $sql = "SELECT
666: lose_faction,
667: COUNT(lose_faction) AS num
668: FROM
669: tower_victory_<myname>
670: WHERE
671: `time` >= ?
672: GROUP BY
673: lose_faction
674: ORDER BY
675: num DESC";
676:
677: $data = $this->db->query($sql, time() - $time);
678: forEach ($data as $row) {
679: $blob .= "<{$row->lose_faction}>{$row->lose_faction}<end> have lost <highlight>{$row->num}<end> tower sites.\n";
680: }
681:
682: if ($blob == '') {
683: $msg = "No tower attacks or victories have been recorded.";
684: } else {
685: $msg = $this->text->makeBlob("Tower Stats for the Last $timeString", $blob);
686: }
687: $sendto->reply($msg);
688: }
689:
690: 691: 692: 693: 694: 695: 696:
697: public function victoryCommand($message, $channel, $sender, $sendto, $args) {
698: $this->victoryCommandHandler($args[1], $search, "", $sendto);
699: }
700:
701: 702: 703: 704: 705: 706: 707:
708: public function victory2Command($message, $channel, $sender, $sendto, $args) {
709: $playfield = $this->playfieldController->getPlayfieldByName($args[1]);
710: if ($playfield === null) {
711: $msg = "Invalid playfield.";
712: $sendto->reply($msg);
713: return;
714: }
715:
716: $tower_info = $this->getTowerInfo($playfield->id, $args[2]);
717: if ($tower_info === null) {
718: $msg = "Invalid site number.";
719: $sendto->reply($msg);
720: return;
721: }
722:
723: $cmd = "$args[1] $args[2] ";
724: $search = "WHERE a.`playfield_id` = {$tower_info->playfield_id} AND a.`site_number` = {$tower_info->site_number}";
725: $this->victoryCommandHandler($args[3], $search, $cmd, $sendto);
726: }
727:
728: 729: 730: 731: 732: 733: 734:
735: public function victoryOrgCommand($message, $channel, $sender, $sendto, $args) {
736: $cmd = "org $args[1] ";
737: $value = str_replace("'", "''", $args[1]);
738: $search = "WHERE v.`win_guild_name` LIKE '$value' OR v.`lose_guild_name` LIKE '$value'";
739: $this->victoryCommandHandler($args[2], $search, $cmd, $sendto);
740: }
741:
742: 743: 744: 745: 746: 747: 748:
749: public function victoryPlayerCommand($message, $channel, $sender, $sendto, $args) {
750: $cmd = "player $args[1] ";
751: $value = str_replace("'", "''", $args[1]);
752: $search = "WHERE a.`att_player` LIKE '$value'";
753: $this->victoryCommandHandler($args[2], $search, $cmd, $sendto);
754: }
755:
756: 757: 758: 759: 760: 761:
762: public function attackMessagesEvent($eventObj) {
763: if (preg_match("/^The (Clan|Neutral|Omni) organization (.+) just entered a state of war! (.+) attacked the (Clan|Neutral|Omni) organization (.+)'s tower in (.+) at location \\((\\d+),(\\d+)\\)\\.$/i", $eventObj->message, $arr)) {
764: $att_side = ucfirst(strtolower($arr[1]));
765: $att_guild = $arr[2];
766: $att_player = $arr[3];
767: $def_side = ucfirst(strtolower($arr[4]));
768: $def_guild = $arr[5];
769: $playfield_name = $arr[6];
770: $x_coords = $arr[7];
771: $y_coords = $arr[8];
772: } else if (preg_match("/^(.+) just attacked the (Clan|Neutral|Omni) organization (.+)'s tower in (.+) at location \(([0-9]+), ([0-9]+)\).(.*)$/i", $eventObj->message, $arr)) {
773: $att_player = $arr[1];
774: $def_side = ucfirst(strtolower($arr[2]));
775: $def_guild = $arr[3];
776: $playfield_name = $arr[4];
777: $x_coords = $arr[5];
778: $y_coords = $arr[6];
779: } else {
780: return;
781: }
782:
783:
784:
785: $whois = $this->playerManager->getByName($att_player);
786: if ($whois === null) {
787: $whois = new stdClass;
788: $whois->type = 'npc';
789:
790:
791: $whois->name = $att_player;
792: $whois->faction = 'Neutral';
793: }
794: if (isset($att_side)) {
795: $whois->faction = $att_side;
796: }
797: if (isset($att_guild)) {
798: $whois->guild = $att_guild;
799: }
800:
801: $playfield = $this->playfieldController->getPlayfieldByName($playfield_name);
802: $closest_site = $this->getClosestSite($playfield->id, $x_coords, $y_coords);
803:
804: $defender = new stdClass();
805: $defender->faction = $def_side;
806: $defender->guild = $def_guild;
807: $defender->playfield = $playfield;
808: $defender->site = $closest_site;
809:
810: forEach ($this->attackListeners as $listener) {
811: call_user_func($listener->callback, $whois, $defender, $listener->data);
812: }
813:
814: if ($closest_site === null) {
815: $this->logger->log('error', "ERROR! Could not find closest site: ({$playfield_name}) '{$playfield->id}' '{$x_coords}' '{$y_coords}'");
816: $more = "[<red>UNKNOWN AREA!<end>]";
817: } else {
818:
819: $this->recordAttack($whois, $def_side, $def_guild, $x_coords, $y_coords, $closest_site);
820: $this->logger->log('debug', "Site being attacked: ({$playfield_name}) '{$closest_site->playfield_id}' '{$closest_site->site_number}'");
821:
822:
823: $link = "Attacker: <highlight>";
824: if ($whois->firstname) {
825: $link .= $whois->firstname . " ";
826: }
827:
828: $link .= '"' . $att_player . '"';
829: if ($whois->lastname) {
830: $link .= " " . $whois->lastname;
831: }
832: $link .= "<end>\n";
833:
834: if ($whois->breed) {
835: $link .= "Breed: <highlight>$whois->breed<end>\n";
836: }
837: if ($whois->gender) {
838: $link .= "Gender: <highlight>$whois->gender<end>\n";
839: }
840:
841: if ($whois->profession) {
842: $link .= "Profession: <highlight>$whois->profession<end>\n";
843: }
844: if ($whois->level) {
845: $level_info = $this->levelController->getLevelInfo($whois->level);
846: $link .= "Level: <highlight>{$whois->level}/<green>{$whois->ai_level}<end> ({$level_info->pvpMin}-{$level_info->pvpMax})<end>\n";
847: }
848:
849: $link .= "Alignment: <highlight>$whois->faction<end>\n";
850:
851: if ($whois->guild) {
852: $link .= "Organization: <highlight>$whois->guild<end>\n";
853: if ($whois->guild_rank) {
854: $link .= "Organization Rank: <highlight>$whois->guild_rank<end>\n";
855: }
856: }
857:
858: $link .= "\n";
859:
860: $link .= "Defender: <highlight>$def_guild<end>\n";
861: $link .= "Alignment: <highlight>$def_side<end>\n\n";
862:
863: $base_link = $this->text->makeChatcmd("{$playfield->short_name} {$closest_site->site_number}", "/tell <myname> lc {$playfield->short_name} {$closest_site->site_number}");
864: $attack_waypoint = $this->text->makeChatcmd("{$x_coords}x{$y_coords}", "/waypoint {$x_coords} {$y_coords} {$playfield->id}");
865: $link .= "Playfield: <highlight>{$base_link} ({$closest_site->min_ql}-{$closest_site->max_ql})<end>\n";
866: $link .= "Location: <highlight>{$closest_site->site_name} ({$attack_waypoint})<end>\n";
867:
868: $more = $this->text->makeBlob("{$playfield->short_name} {$closest_site->site_number}", $link, 'Advanced Tower Info');
869: }
870:
871: $targetorg = "<".strtolower($def_side).">".$def_guild."<end>";
872:
873:
874: $msg .= "";
875:
876:
877: if ($this->settingManager->get("tower_attack_spam") >= 2) {
878:
879: if ($whois->profession == "") {
880: $msg .= "<".strtolower($whois->faction).">$att_player<end> (Unknown";
881: } else {
882: if (!$whois->guild){
883: $msg .= "<".strtolower($whois->faction).">$att_player<end>";
884: } else {
885: $msg .= "<font color=#AAAAAA>$att_player<end>";
886: }
887: $msg .= " (<font color=#AAAAAA>$whois->level<end>";
888: if ($whois->ai_level) {
889: $msg .= "/<green>$whois->ai_level<end>";
890: }
891: $msg .= ", $whois->breed <font color=#AAAAAA>$whois->profession<end>";
892: }
893:
894: if (!$whois->guild) {
895: $msg .= ")";
896: } else if (!$whois->guild_rank) {
897: $msg .= "<".strtolower($whois->faction).">$whois->guild<end>)";
898: } else {
899: $msg .= ", $whois->guild_rank of <".strtolower($whois->faction).">$whois->guild<end>)";
900: }
901:
902: } else if ($whois->guild) {
903: $msg .= "<".strtolower($whois->faction).">$whois->guild<end>";
904: } else {
905: $msg .= "<".strtolower($whois->faction).">$att_player<end>";
906: }
907:
908: $msg .= " attacked $targetorg [$more]";
909:
910: $s = $this->settingManager->get("tower_attack_spam");
911:
912: if ($s > 0) {
913: $this->chatBot->sendGuild($msg, true);
914: }
915: }
916:
917: 918: 919: 920: 921: 922:
923: public function victoryMessagesEvent($eventObj) {
924: if (preg_match("/^The (Clan|Neutral|Omni) organization (.+) attacked the (Clan|Neutral|Omni) (.+) at their base in (.+). The attackers won!!$/i", $eventObj->message, $arr)) {
925: $win_faction = $arr[1];
926: $win_guild_name = $arr[2];
927: $lose_faction = $arr[3];
928: $lose_guild_name = $arr[4];
929: $playfield_name = $arr[5];
930: } else if (preg_match("/^Notum Wars Update: The (clan|neutral|omni) organization (.+) lost their base in (.+).$/i", $eventObj->message, $arr)) {
931: $win_faction = '';
932: $win_guild_name = '';
933: $lose_faction = ucfirst($arr[1]);
934: $lose_guild_name = $arr[2];
935: $playfield_name = $arr[3];
936: } else {
937: return;
938: }
939:
940: $playfield = $this->playfieldController->getPlayfieldByName($playfield_name);
941: if ($playfield === null) {
942: $this->logger->log('error', "Could not find playfield for name '$playfield_name'");
943: return;
944: }
945:
946: $last_attack = $this->getLastAttack($win_faction, $win_guild_name, $lose_faction, $lose_guild_name, $playfield->id);
947: if ($last_attack !== null) {
948: $this->remScoutSite($last_attack->playfield_id, $last_attack->site_number);
949: } else {
950: $last_attack = new stdClass;
951: $last_attack->att_guild_name = $win_guild_name;
952: $last_attack->def_guild_name = $lose_guild_name;
953: $last_attack->att_faction = $win_faction;
954: $last_attack->def_faction = $lose_faction;
955: $last_attack->playfield_id = $playfield->id;
956: $last_attack->id = '-1';
957: }
958:
959: $this->recordVictory($last_attack);
960: }
961:
962: protected function attacksCommandHandler($page_label, $search, $cmd, $sendto) {
963: if (is_numeric($page_label) == false) {
964: $page_label = 1;
965: } else if ($page_label < 1) {
966: $msg = "You must choose a page number greater than 0";
967: $sendto->reply($msg);
968: return;
969: }
970:
971: $page_size = $this->settingManager->get('tower_page_size');
972: $start_row = ($page_label - 1) * $page_size;
973:
974: $sql =
975: "SELECT
976: *
977: FROM
978: tower_attack_<myname> a
979: LEFT JOIN playfields p ON (a.playfield_id = p.id)
980: LEFT JOIN tower_site s ON (a.playfield_id = s.playfield_id AND a.site_number = s.site_number)
981: $search
982: ORDER BY
983: a.`time` DESC
984: LIMIT
985: ?, ?";
986:
987: $data = $this->db->query($sql, intval($start_row), intval($page_size));
988: if (count($data) == 0) {
989: $msg = "No tower attacks found.";
990: } else {
991: $links = array();
992: if ($page_label > 1) {
993: $links['Previous Page'] = '/tell <myname> attacks ' . ($page_label - 1);
994: }
995: $links['Next Page'] = "/tell <myname> attacks {$cmd}" . ($page_label + 1);
996:
997: $blob = "The last $page_size Tower Attacks (page $page_label)\n\n";
998: $blob .= $this->text->makeHeaderLinks($links) . "\n\n";
999:
1000: forEach ($data as $row) {
1001: $timeString = $this->util->unixtimeToReadable(time() - $row->time);
1002: $blob .= "Time: " . $this->util->date($row->time) . " (<highlight>$timeString<end> ago)\n";
1003: if ($row->att_faction == '') {
1004: $att_faction = "unknown";
1005: } else {
1006: $att_faction = strtolower($row->att_faction);
1007: }
1008:
1009: if ($row->def_faction == '') {
1010: $def_faction = "unknown";
1011: } else {
1012: $def_faction = strtolower($row->def_faction);
1013: }
1014:
1015: if ($row->att_profession == 'Unknown') {
1016: $blob .= "Attacker: <{$att_faction}>{$row->att_player}<end> ({$row->att_faction})\n";
1017: } else if ($row->att_guild_name == '') {
1018: $blob .= "Attacker: <{$att_faction}>{$row->att_player}<end> ({$row->att_level}/<green>{$row->att_ai_level}<end> {$row->att_profession}) ({$row->att_faction})\n";
1019: } else {
1020: $blob .= "Attacker: {$row->att_player} ({$row->att_level}/<green>{$row->att_ai_level}<end> {$row->att_profession}) <{$att_faction}>{$row->att_guild_name}<end> ({$row->att_faction})\n";
1021: }
1022:
1023: $base = $this->text->makeChatcmd("{$row->short_name} {$row->site_number}", "/tell <myname> lc {$row->short_name} {$row->site_number}");
1024: $base .= " ({$row->min_ql}-{$row->max_ql})";
1025:
1026: $blob .= "Defender: <{$def_faction}>{$row->def_guild_name}<end> ({$row->def_faction})\n";
1027: $blob .= "Site: $base\n\n";
1028: }
1029: $msg = $this->text->makeBlob("Tower Attacks", $blob);
1030: }
1031:
1032: $sendto->reply($msg);
1033: }
1034:
1035: protected function victoryCommandHandler($page_label, $search, $cmd, $sendto) {
1036: if (is_numeric($page_label) == false) {
1037: $page_label = 1;
1038: } else if ($page_label < 1) {
1039: $msg = "You must choose a page number greater than 0";
1040: $sendto->reply($msg);
1041: return;
1042: }
1043:
1044: $page_size = $this->settingManager->get('tower_page_size');
1045: $start_row = ($page_label - 1) * $page_size;
1046:
1047: $sql = "
1048: SELECT
1049: *,
1050: v.time AS victory_time,
1051: a.time AS attack_time
1052: FROM
1053: tower_victory_<myname> v
1054: LEFT JOIN tower_attack_<myname> a ON (v.attack_id = a.id)
1055: LEFT JOIN playfields p ON (a.playfield_id = p.id)
1056: LEFT JOIN tower_site s ON (a.playfield_id = s.playfield_id AND a.site_number = s.site_number)
1057: {$search}
1058: ORDER BY
1059: `victory_time` DESC
1060: LIMIT
1061: ?, ?";
1062:
1063: $data = $this->db->query($sql, intval($start_row), intval($page_size));
1064: if (count($data) == 0) {
1065: $msg = "No Tower results found.";
1066: } else {
1067: $links = array();
1068: if ($page_label > 1) {
1069: $links['Previous Page'] = '/tell <myname> victory ' . ($page_label - 1);
1070: }
1071: $links['Next Page'] = "/tell <myname> victory {$cmd}" . ($page_label + 1);
1072:
1073: $blob = "The last $page_size Tower Results (page $page_label)\n\n";
1074: $blob .= $this->text->makeHeaderLinks($links) . "\n\n";
1075: forEach ($data as $row) {
1076: $timeString = $this->util->unixtimeToReadable(time() - $row->victory_time);
1077: $blob .= "Time: " . $this->util->date($row->victory_time) . " (<highlight>$timeString<end> ago)\n";
1078:
1079: if (!$win_side = strtolower($row->win_faction)) {
1080: $win_side = "unknown";
1081: }
1082: if (!$lose_side = strtolower($row->lose_faction)) {
1083: $lose_side = "unknown";
1084: }
1085:
1086: if ($row->playfield_id != '' && $row->site_number != '') {
1087: $base = $this->text->makeChatcmd("{$row->short_name} {$row->site_number}", "/tell <myname> lc {$row->short_name} {$row->site_number}");
1088: $base .= " ({$row->min_ql}-{$row->max_ql})";
1089: } else {
1090: $base = "Unknown";
1091: }
1092:
1093: $blob .= "Winner: <{$win_side}>{$row->win_guild_name}<end> (".ucfirst($win_side).")\n";
1094: $blob .= "Loser: <{$lose_side}>{$row->lose_guild_name}<end> (".ucfirst($lose_side).")\n";
1095: $blob .= "Site: $base\n\n";
1096: }
1097: $msg = $this->text->makeBlob("Tower Victories", $blob);
1098: }
1099:
1100: $sendto->reply($msg);
1101: }
1102:
1103: public function getTowerInfo($playfield_id, $site_number) {
1104: $sql = "
1105: SELECT
1106: *
1107: FROM
1108: tower_site t
1109: WHERE
1110: `playfield_id` = ?
1111: AND `site_number` = ?
1112: LIMIT 1";
1113:
1114: return $this->db->queryRow($sql, $playfield_id, $site_number);
1115: }
1116:
1117: protected function findSitesInPlayfield($playfield_id) {
1118: $sql = "SELECT * FROM tower_site WHERE `playfield_id` = ?";
1119:
1120: return $this->db->query($sql, $playfield_id);
1121: }
1122:
1123: protected function getClosestSite($playfield_id, $x_coords, $y_coords) {
1124: $sql = "
1125: SELECT
1126: *,
1127: ((x_distance * x_distance) + (y_distance * y_distance)) radius
1128: FROM
1129: (SELECT
1130: playfield_id,
1131: site_number,
1132: min_ql,
1133: max_ql,
1134: x_coord,
1135: y_coord,
1136: site_name,
1137: (x_coord - {$x_coords}) as x_distance,
1138: (y_coord - {$y_coords}) as y_distance
1139: FROM
1140: tower_site
1141: WHERE
1142: playfield_id = ?) t
1143: ORDER BY
1144: radius ASC
1145: LIMIT 1";
1146:
1147: return $this->db->queryRow($sql, $playfield_id);
1148: }
1149:
1150: protected function getLastAttack($att_faction, $att_guild_name, $def_faction, $def_guild_name, $playfield_id) {
1151: $time = time() - (7 * 3600);
1152:
1153: $sql = "
1154: SELECT
1155: *
1156: FROM
1157: tower_attack_<myname>
1158: WHERE
1159: `att_guild_name` = ?
1160: AND `att_faction` = ?
1161: AND `def_guild_name` = ?
1162: AND `def_faction` = ?
1163: AND `playfield_id` = ?
1164: AND `time` >= ?
1165: ORDER BY
1166: `time` DESC
1167: LIMIT 1";
1168:
1169: return $this->db->queryRow($sql, $att_guild_name, $att_faction, $def_guild_name, $def_faction, $playfield_id, $time);
1170: }
1171:
1172: protected function recordAttack($whois, $def_faction, $def_guild_name, $x_coords, $y_coords, $closest_site) {
1173: $sql = "
1174: INSERT INTO tower_attack_<myname> (
1175: `time`,
1176: `att_guild_name`,
1177: `att_faction`,
1178: `att_player`,
1179: `att_level`,
1180: `att_ai_level`,
1181: `att_profession`,
1182: `def_guild_name`,
1183: `def_faction`,
1184: `playfield_id`,
1185: `site_number`,
1186: `x_coords`,
1187: `y_coords`
1188: ) VALUES (
1189: ?,
1190: ?,
1191: ?,
1192: ?,
1193: ?,
1194: ?,
1195: ?,
1196: ?,
1197: ?,
1198: ?,
1199: ?,
1200: ?,
1201: ?
1202: )";
1203:
1204: return $this->db->exec($sql, time(), $whois->guild, $whois->faction, $whois->name, $whois->level, $whois->ai_level, $whois->profession,
1205: $def_guild_name, $def_faction, $closest_site->playfield_id, $closest_site->site_number, $x_coords, $y_coords);
1206: }
1207:
1208: protected function findAllScoutedSites() {
1209: $sql =
1210: "SELECT
1211: *
1212: FROM
1213: scout_info s
1214: JOIN tower_site t
1215: ON (s.playfield_id = t.playfield_id AND s.site_number = t.site_number)
1216: JOIN playfields p
1217: ON (s.playfield_id = p.id)
1218: ORDER BY
1219: guild_name, ct_ql";
1220:
1221: return $this->db->query($sql);
1222: }
1223:
1224: protected function getLastVictory($playfield_id, $site_number) {
1225: $sql = "
1226: SELECT
1227: *
1228: FROM
1229: tower_victory_<myname> v
1230: JOIN tower_attack_<myname> a ON (v.attack_id = a.id)
1231: WHERE
1232: a.`playfield_id` = ?
1233: AND a.`site_number` >= ?
1234: ORDER BY
1235: v.`time` DESC
1236: LIMIT 1";
1237:
1238: return $this->db->queryRow($sql, $playfield_id, $site_number);
1239: }
1240:
1241: protected function recordVictory($last_attack) {
1242: $sql = "
1243: INSERT INTO tower_victory_<myname> (
1244: `time`,
1245: `win_guild_name`,
1246: `win_faction`,
1247: `lose_guild_name`,
1248: `lose_faction`,
1249: `attack_id`
1250: ) VALUES (
1251: ?,
1252: ?,
1253: ?,
1254: ?,
1255: ?,
1256: ?
1257: )";
1258:
1259: return $this->db->exec($sql, time(), $last_attack->att_guild_name, $last_attack->att_faction, $last_attack->def_guild_name, $last_attack->def_faction, $last_attack->id);
1260: }
1261:
1262: protected function addScoutSite($playfield_id, $site_number, $close_time, $ct_ql, $faction, $guild_name, $scouted_by) {
1263: $this->db->exec("DELETE FROM scout_info WHERE `playfield_id` = ? AND `site_number` = ?", $playfield_id, $site_number);
1264:
1265: $sql = "
1266: INSERT INTO scout_info (
1267: `playfield_id`,
1268: `site_number`,
1269: `scouted_on`,
1270: `scouted_by`,
1271: `ct_ql`,
1272: `guild_name`,
1273: `faction`,
1274: `close_time`
1275: ) VALUES (
1276: ?,
1277: ?,
1278: ?,
1279: ?,
1280: ?,
1281: ?,
1282: ?,
1283: ?
1284: )";
1285:
1286: $numrows = $this->db->exec($sql, $playfield_id, $site_number, time(), $scouted_by, $ct_ql, $guild_name, $faction, $close_time);
1287:
1288: return $numrows;
1289: }
1290:
1291: protected function remScoutSite($playfield_id, $site_number) {
1292: $sql = "DELETE FROM scout_info WHERE `playfield_id` = ? AND `site_number` = ?";
1293:
1294: return $this->db->exec($sql, $playfield_id, $site_number);
1295: }
1296:
1297: protected function checkGuildName($guild_name) {
1298: $sql = "SELECT * FROM tower_attack_<myname> WHERE `att_guild_name` LIKE ? OR `def_guild_name` LIKE ? LIMIT 1";
1299:
1300: $data = $this->db->query($sql, $guild_name, $guild_name);
1301: if (count($data) === 0) {
1302: return false;
1303: } else {
1304: return true;
1305: }
1306: }
1307:
1308: protected function getSitesInPenalty($time) {
1309: $sql = "
1310: SELECT att_guild_name, att_faction, MAX(IFNULL(t2.time, t1.time)) AS penalty_time
1311: FROM tower_attack_<myname> t1
1312: LEFT JOIN tower_victory_<myname> t2 ON t1.id = t2.attack_id
1313: WHERE
1314: att_guild_name <> ''
1315: AND (t2.time IS NULL AND t1.time > ?)
1316: OR t2.time > ?
1317: GROUP BY att_guild_name, att_faction
1318: ORDER BY att_faction ASC, penalty_time DESC";
1319: return $this->db->query($sql, $time, $time);
1320: }
1321:
1322: protected function getGasLevel($close_time) {
1323: $current_time = time() % 86400;
1324:
1325: $site = new stdClass();
1326: $site->current_time = $current_time;
1327: $site->close_time = $close_time;
1328:
1329: if ($close_time < $current_time) {
1330: $close_time += 86400;
1331: }
1332:
1333: $time_until_close_time = $close_time - $current_time;
1334: $site->time_until_close_time = $time_until_close_time;
1335:
1336: if ($time_until_close_time < 3600 * 1) {
1337: $site->gas_change = $time_until_close_time;
1338: $site->gas_level = '5%';
1339: $site->next_state = 'closes';
1340: $site->color = "<orange>";
1341: } else if ($time_until_close_time < 3600 * 6) {
1342: $site->gas_change = $time_until_close_time;
1343: $site->gas_level = '25%';
1344: $site->next_state = 'closes';
1345: $site->color = "<green>";
1346: } else {
1347: $site->gas_change = $time_until_close_time - (3600 * 6);
1348: $site->gas_level = '75%';
1349: $site->next_state = 'opens';
1350: $site->color = "<red>";
1351: }
1352:
1353: return $site;
1354: }
1355:
1356: protected function formatSiteInfo($row) {
1357: $waypointLink = $this->text->makeChatcmd($row->x_coord . "x" . $row->y_coord, "/waypoint {$row->x_coord} {$row->y_coord} {$row->playfield_id}");
1358: $attacksLink = $this->text->makeChatcmd("Recent attacks", "/tell <myname> attacks {$row->short_name} {$row->site_number}");
1359: $victoryLink = $this->text->makeChatcmd("Recent victories", "/tell <myname> victory {$row->short_name} {$row->site_number}");
1360:
1361: $blob = "Short name: <highlight>{$row->short_name} {$row->site_number}<end>\n";
1362: $blob .= "Long name: <highlight>{$row->site_name}, {$row->long_name}<end>\n";
1363: $blob .= "Level range: <highlight>{$row->min_ql}-{$row->max_ql}<end>\n";
1364: $blob .= "Center coordinates: $waypointLink\n";
1365: $blob .= $attacksLink . "\n";
1366: $blob .= $victoryLink;
1367:
1368: return $blob;
1369: }
1370:
1371: public function getFaction($input) {
1372: $faction = ucfirst(strtolower($input));
1373: if ($faction == "Neut") {
1374: $faction = "Neutral";
1375: }
1376: return $faction;
1377: }
1378: }
1379: