'cname', 'label' => 'Character name', 'maxlength' => 16], ['name' => 'class', 'label' => 'Class', 'type' => 'select', 'options' => ['fighter' => 'Fighter (+ATK/HP)', 'mage' => 'Mage (+ATK)', 'thief' => 'Thief (+DEF/HP)']], ], 'Enter the world', ['csrf' => csrf_token()]); p_link('/games.php', 'Back to games'); page_end(); exit; } } mud_respawn(); $msg = []; // ---- command handling ---- if (isset($_GET['cmd'])) { $raw = strtolower(trim($_GET['cmd'])); $parts = explode(' ', $raw, 2); $cmd = $parts[0]; $arg = trim($parts[1] ?? ($_GET['arg'] ?? '')); } elseif ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['cmd'])) { require_csrf(); $parts = explode(' ', trim($_POST['cmd']), 2); $cmd = strtolower($parts[0]); $arg = $parts[1] ?? ''; } else { $cmd = ''; $arg = ''; } switch ($cmd) { case 'n': case 'north': case 's': case 'south': case 'e': case 'east': case 'w': case 'west': case 'u': case 'up': case 'd': case 'down': $dir = $cmd[0]; $room = mud_room($c['room_id']); if (!empty($room['exits'][$dir])) { $c['room_id'] = $room['exits'][$dir]; db()->prepare("UPDATE mud_chars SET room_id=?,last_cmd_at=? WHERE id=?") ->execute([$c['room_id'], time(), $c['id']]); mud_echo("{$c['name']} heads {$dir}.", $c['room_id']); } else { $msg[] = "You can't go that way."; } break; case 'look': case 'l': $msg[] = 'You take in your surroundings.'; break; case 'k': case 'kill': case 'attack': if (!$arg) { $msg[] = 'Kill what?'; break; } $spawns = mud_alive_spawns($c['room_id']); $hit = null; foreach ($spawns as $sp) { if (strpos($sp['key_name'], $arg) === 0 || strpos($sp['name'], $arg) !== false) { $hit = $sp; break; } } if ($hit) $msg = array_merge($msg, mud_fight($hit['id'], $c)); else $msg[] = "There is no '$arg' here to fight."; break; case 'take': case 'get': if (!$arg) { $msg[] = 'Take what?'; break; } $ground = mud_ground_items($c['room_id']); $got = null; foreach ($ground as $g) if (strpos($g['key_name'], $arg) === 0) { $got = $g; break; } if ($got) { db()->prepare("DELETE FROM mud_ground WHERE id=?")->execute([$got['id']]); $inv = json_decode($c['inv'], true); $inv[] = $got['key_name']; $inv = json_encode($inv); db()->prepare("UPDATE mud_chars SET inv=? WHERE id=?")->execute([$inv, $c['id']]); $c['inv'] = $inv; mud_echo("{$c['name']} takes {$got['name']}.", $c['room_id']); $msg[] = "You take {$got['name']}."; } else $msg[] = "There is no '$arg' here."; break; case 'wear': case 'wield': if (!$arg) { $msg[] = 'Wear what?'; break; } $inv = json_decode($c['inv'], true); $it = null; foreach ($inv as $k) { if (strpos($k, $arg) === 0) { $it = mud_item($k); break; } } if (!$it) { $msg[] = "You don't have that."; break; } if ($it['slot'] === 'weapon') { $c['weapon'] = $it['key_name']; db()->prepare("UPDATE mud_chars SET weapon=? WHERE id=?")->execute([$it['key_name'], $c['id']]); $msg[] = "You wield {$it['name']}."; } elseif ($it['slot'] === 'armor') { $c['armor'] = $it['key_name']; db()->prepare("UPDATE mud_chars SET armor=? WHERE id=?")->execute([$it['key_name'], $c['id']]); $msg[] = "You don {$it['name']}."; } else { $msg[] = "You can't wear that."; } break; case 'drink': case 'quaff': if (!$arg) { $msg[] = 'Drink what?'; break; } $inv = json_decode($c['inv'], true); $it = null; $idx = null; foreach ($inv as $i => $k) { if (strpos($k, $arg) === 0) { $it = mud_item($k); $idx = $i; break; } } if (!$it) { $msg[] = "You don't have that."; break; } if ($it['slot'] !== 'potion') { $msg[] = "That's not a potion."; break; } $heal = $it['heal']; $c['hp'] = min($c['max_hp'], $c['hp'] + $heal); unset($inv[$idx]); $inv = json_encode(array_values($inv)); db()->prepare("UPDATE mud_chars SET hp=?,inv=? WHERE id=?")->execute([$c['hp'], $inv, $c['id']]); $c['inv'] = $inv; $msg[] = "You drink {$it['name']} and recover $heal hp."; break; case 'inv': case 'i': case 'inventory': $inv = json_decode($c['inv'], true); $msg[] = $inv ? "You carry: " . implode(', ', array_map(fn($k) => mud_item($k)['name'], $inv)) : "Your pack is empty."; break; case 'score': case 'stats': $msg[] = "Level {$c['level']} | HP {$c['hp']}/{$c['max_hp']} | ATK {$c['atk']} | DEF {$c['def']} | XP {$c['xp']} | Gold {$c['gold']} | Bank {$c['bank']} | Kills {$c['kills']} | Deaths {$c['deaths']}"; break; case 'attack': case 'a': if (!$arg) { $msg[] = 'Attack who?'; break; } $v = mud_find_player_in_room($c['room_id'], $arg); if ($v) { if ($v['id'] == $c['id']) $msg[] = "You can't attack yourself."; else $msg = array_merge($msg, mud_pvp($c, $v)); } else { $here = array_values(array_filter(mud_players_in_room($c['room_id']), fn($p) => $p['id'] != $c['id'])); $who = $here ? implode(', ', array_map(fn($p) => $p['name'], $here)) : 'nobody'; $msg[] = "There is no '$arg' here to fight. Adventurers present: $who."; } break; case 'buy': case 'b': if (!$arg) { $msg[] = 'Buy what? (e.g. buy steel_sword)'; break; } $msg = array_merge($msg, mud_buy($c, $arg)); break; case 'bank': if (!$arg) { $msg[] = 'bank to deposit, or bank - to withdraw.'; break; } if ($arg[0] === '-') $msg = array_merge($msg, mud_withdraw($c, (int)substr($arg,1))); else $msg = array_merge($msg, mud_deposit($c, (int)$arg)); break; case 'tax': $msg = array_merge($msg, mud_tax($c)); break; case 'bounty': $bp = explode(' ', $arg, 2); if (count($bp) < 2 || !is_numeric($bp[1])) { $msg[] = 'bounty '; break; } $v = mud_find_player_in_room($c['room_id'], $bp[0]); if ($v) { if ($v['id'] == $c['id']) $msg[] = "You can't bounty yourself."; else $msg = array_merge($msg, mud_set_bounty($c, $v, (int)$bp[1])); } else $msg[] = "There is no '$bp[0]' here to bounty."; break; case 'board': case 'top': $lb = mud_leaderboard(10); $msg[] = 'Adventurers of renown:'; foreach ($lb as $i => $r) { $cn = $GLOBALS['MUD_CLASSES'][$r['class']]['name'] ?? $r['class']; $msg[] = sprintf(" %d. %s (%s) L%d G%d K%d/D%d", $i+1, $r['name'], $cn, $r['level'], $r['gold'], $r['kills'], $r['deaths']); } break; case 'help': case 'h': case '': $msg[] = "Commands: n/s/e/w/u/d (move), look, kill , attack , take , " . "wear/wield , drink , buy , bank <+/->amt, tax, " . "bounty , board (leaderboard), inv, score, help. " . "Also play live on the telnet BBS (port 12300)."; break; default: $msg[] = "Unknown command: $cmd (try 'help')."; } // ---- render room ---- $room = mud_room($c['room_id']); $spawns = mud_alive_spawns($c['room_id']); $ground = mud_ground_items($c['room_id']); $others = mud_players_in_room($c['room_id']); $ev_st = db()->prepare("SELECT text FROM mud_events WHERE room_id=? ORDER BY id DESC LIMIT 5"); $ev_st->execute([$c['room_id']]); $events = $ev_st->fetchAll(PDO::FETCH_COLUMN); page_start('MUD - ' . $c['name']); if ($msg) foreach ($msg as $m) p_para($m); p_rule(); p_para($room['name']); p_para($room['descr']); if ($spawns) { p_para('Here:'); foreach ($spawns as $sp) p_para(' ' . $sp['descr'] . ' (' . $sp['hp'] . ' hp)'); } // other players present $people = array_filter($others, fn($p) => $p['id'] != $c['id']); if ($people) { p_para('Adventurers here:'); foreach ($people as $p) { $cn = $GLOBALS['MUD_CLASSES'][$p['class']]['name'] ?? $p['class']; p_para(' ' . $p['name'] . ' (' . $cn . ', L' . $p['level'] . (($p['bounty']>0)?', bounty '.$p['bounty'].'g':'') . ')'); } } if ($ground) { p_para('On the ground:'); foreach ($ground as $g) p_para(' ' . $g['name']); } if ($events) { p_para('You see:'); foreach (array_reverse($events) as $ev) p_para(' ' . $ev); } p_rule(); p_para("HP {$c['hp']}/{$c['max_hp']} Lvl {$c['level']} XP {$c['xp']} Gold {$c['gold']} Bank {$c['bank']}"); // movement links + command form $links = []; foreach ($room['exits'] as $dir => $to) { $labels = ['n'=>'North','s'=>'South','e'=>'East','w'=>'West','u'=>'Up','d'=>'Down']; $links[] = ['/mud.php', $labels[$dir], ['cmd' => $dir]]; } p_links($links); // action quick links $acts = []; if ($spawns) $acts[] = ['/mud.php', 'Attack', ['cmd' => 'kill', 'arg' => substr($spawns[0]['key_name'],0,3)]]; if ($room['id'] == 9) { foreach (mud_shop_list() as $it) $acts[] = ['/mud.php', 'Buy '.$it['name'].' ('.$it['price'].'g)', ['cmd' => 'buy', 'arg' => $it['key_name']]]; } if ($room['id'] == 10) { $acts[] = ['/mud.php', 'Deposit 10g', ['cmd' => 'bank', 'arg' => '10']]; $acts[] = ['/mud.php', 'Withdraw 10g', ['cmd' => 'bank', 'arg' => '-10']]; } if ($room['id'] == 11) { $acts[] = ['/mud.php', 'Pay the Taxman', ['cmd' => 'tax']]; } if ($people) $acts[] = ['/mud.php', 'Attack ' . $people[array_key_first($people)]['name'], ['cmd' => 'attack', 'arg' => substr($people[array_key_first($people)]['name'],0,4)]]; $acts[] = ['/mud.php', 'Look', ['cmd' => 'look']]; $acts[] = ['/mud.php', 'Inventory', ['cmd' => 'inv']]; $acts[] = ['/mud.php', 'Score', ['cmd' => 'score']]; $acts[] = ['/mud.php', 'Leaderboard', ['cmd' => 'board']]; $acts[] = ['/mud.php', 'Help', ['cmd' => 'help']]; p_links($acts); p_para('Or type a command:'); p_form('/mud.php', [ ['name' => 'cmd', 'label' => '', 'maxlength' => 48], ], 'Go', ['csrf' => csrf_token()]); p_link('/games.php', 'Back to games'); page_end();