form('/fight', 'Fights\fight'); $r->get('/victory', 'Fights\victory'); $r->form('/drop', 'Fights\drop'); $r->get('/dead', 'Fights\dead'); return $r; } /** * One big long public static function that determines the outcome of the fight. */ public static function fight() { if (user()->currentaction !== 'Fighting') { exit('Cheat attempt detected.

Get a life, loser.'); } $page = ['magiclist' => '', 'yourturn' => '', 'monsterturn' => '', 'monsterhp' => '', 'command' => '']; $playerisdead = 0; // Generate spell list $user_spells = user()->spells(); if (! empty($user_spells)) { $page['magiclist'] = '

'; } // Determine initial combat parameters $chancetoswingfirst = rand(1, 10) + (int) ceil(sqrt(user()->dexterity)); if (user()->currentfight === 1) { $maxlevel = (int) floor(max(abs(user()->latitude) + 5, abs(user()->longitude) + 5) / 5); $minlevel = max(1, $maxlevel - 2); $monster = db()->query('SELECT * FROM monsters WHERE level >= ? AND level <= ? ORDER BY RANDOM() LIMIT 1;', [ $minlevel, $maxlevel, ])->fetchArray(SQLITE3_ASSOC); user()->currentmonster = $monster['id']; user()->currentmonsterhp = rand((int) (($monster['maxhp'] / 5) * 4), $monster['maxhp']); user()->currentmonstersleep = 0; user()->currentmonsterimmune = $monster['immune']; $chancetoswingfirst = ($chancetoswingfirst > (rand(1, 7) + (int) ceil(sqrt($monster['maxdam'])))) ? 1 : 0; } // Get monster statistics $monster = get_monster(user()->currentmonster); $page['monstername'] = $monster['name']; // Run action if (isset($_POST['run'])) { $chancetorun = rand(4, 10) + (int) ceil(sqrt(user()->dexterity)); if ($chancetorun <= (rand(1, 5) + (int) ceil(sqrt($monster['maxdam'])))) { $page['yourturn'] = 'You tried to run away, but were blocked in front!

'; $page['monsterhp'] = "Monster's HP: ".user()->currentmonsterhp.'

'; // Monster turn logic (similar to original public static function) $page['monsterturn'] = self::handleMonsterTurn($userrow, $monster); user()->currentaction = 'Exploring'; user()->save(); redirect('/'); } } // Fight action if (isset($_POST['fight'])) { // Player's attack $min = (int) (user()->attackpower * 0.75); $max = (int) (user()->attackpower / 3); $tohit = (int) ceil(mt_rand(min($min, $max), max($min, $max))); $toexcellent = rand(1, 150); if ($toexcellent <= sqrt(user()->strength)) { $tohit *= 2; $page['yourturn'] .= 'Excellent hit!
'; } $min = (int) ($monster['armor'] * 0.75); $max = (int) $monster['armor']; $toblock = (int) ceil(rand(min($min, $max), max($min, $max)) / 3); $tododge = rand(1, 100); $monsterdamage = max(1, $tohit - $toblock); if ($tododge <= sqrt($monster['armor'])) { $monsterdamage = 0; $page['yourturn'] .= 'The monster is dodging. No damage has been scored.
'; } if (user()->currentuberdamage != 0) { $monsterdamage += (int) ceil($monsterdamage * (user()->currentuberdamage / 100)); } user()->currentmonsterhp -= $monsterdamage; $page['yourturn'] .= "You attack the monster for $monsterdamage damage.

"; $page['monsterhp'] = "Monster's HP: ".user()->currentmonsterhp.'

'; // Check for monster defeat if (user()->currentmonsterhp <= 0) { user()->currentmonsterhp = 0; user()->save(); redirect('/victory'); } // Monster's turn $page['monsterturn'] = self::handleMonsterTurn($userrow, $monster); } // Spell action if (isset($_POST['spell'])) { $pickedspell = $_POST['userspell']; if ($pickedspell == 0) { return 'You must select a spell first. Please go back and try again.'; } $newspellrow = get_spell($pickedspell); $spell = in_array($pickedspell, explode(',', user()->spells)); if (! $spell) { return 'You have not yet learned this spell. Please go back and try again.'; } if (user()->currentmp < $newspellrow['mp']) { return 'You do not have enough Magic Points to cast this spell. Please go back and try again.'; } // Spell type handling (similar to original public static function) $page['yourturn'] = self::handleSpellCast($userrow, $newspellrow); $page['monsterhp'] = "Monster's HP: ".user()->currentmonsterhp.'

'; // Check for monster defeat if (user()->currentmonsterhp <= 0) { user()->currentmonsterhp = 0; user()->save(); redirect('/victory'); } // Monster's turn $page['monsterturn'] = self::handleMonsterTurn($userrow, $monster); } // Monster's turn if player lost first swing if (! isset($_POST['run']) && ! isset($_POST['fight']) && ! isset($_POST['spell']) && $chancetoswingfirst == 0) { $page['yourturn'] = 'The monster attacks before you are ready!

'; $page['monsterhp'] = "Monster's HP: ".user()->currentmonsterhp.'

'; $page['monsterturn'] = self::handleMonsterTurn($userrow, $monster); } // Prepare command or death message if ($playerisdead != 1) { $page['command'] = <<


{$page['magiclist']}

HTML; user()->currentfight += 1; } else { $page['command'] = <<You have died.

As a consequence, you've lost half of your gold. However, you have been given back a portion of your hit points to continue your journey.

You may now continue back to town, and we hope you fair better next time. HTML; } user()->save(); // Finalize page and display it $page = render('fight', ['page' => $page]); return $page; } public static function victory() { if (user()->currentmonsterhp != 0) { redirect('/fight'); } if (user()->currentfight == 0) { redirect('/'); } $monsterrow = get_monster(user()->currentmonster); $min = (int) (($monsterrow['maxexp'] / 6) * 5); $max = (int) $monsterrow['maxexp']; $exp = mt_rand(min($min, $max), max($min, $max)); if ($exp < 1) { $exp = 1; } if (user()->expbonus != 0) { $exp += ceil((user()->expbonus / 100) * $exp); } $min = (int) (($monsterrow['maxgold'] / 6) * 5); $max = (int) $monsterrow['maxgold']; $gold = mt_rand(min($min, $max), max($min, $max)); if ($gold < 1) { $gold = 1; } if (user()->goldbonus != 0) { $gold += ceil((user()->goldbonus / 100) * $exp); } if (user()->experience + $exp < 16777215) { $newexp = user()->experience += $exp; $warnexp = ''; } else { $newexp = user()->experience; $exp = 0; $warnexp = 'You have maxed out your experience points.'; } if (user()->gold + $gold < 16777215) { $newgold = user()->gold += $gold; $warngold = ''; } else { $newgold = user()->gold; $gold = 0; $warngold = 'You have maxed out your gold.'; } $levelrow = db()->query('SELECT * FROM levels WHERE id=? LIMIT 1;', [user()->level + 1])->fetchArray(SQLITE3_ASSOC); if (user()->level < 100) { if ($newexp >= $levelrow[user()->charclass.'_exp']) { user()->maxhp += $levelrow[user()->charclass.'_hp']; user()->maxmp += $levelrow[user()->charclass.'_mp']; user()->maxtp += $levelrow[user()->charclass.'_tp']; user()->strength += $levelrow[user()->charclass.'_strength']; user()->dexterity += $levelrow[user()->charclass.'_dexterity']; user()->attackpower += $levelrow[user()->charclass.'_strength']; user()->defensepower += $levelrow[user()->charclass.'_dexterity']; user()->level += 1; $newlevel = $levelrow['id']; if ($levelrow[user()->charclass.'_spells'] != 0) { user()->spells .= ','.$levelrow[user()->charclass.'_spells']; $spelltext = 'You have learned a new spell.
'; } else { $spelltext = ''; $newspell = ''; } $page = 'Congratulations. You have defeated the '.$monsterrow['name'].".
You gain $exp experience. $warnexp
You gain $gold gold. $warngold

You have gained a level!

You gain ".$levelrow[user()->charclass.'_hp'].' hit points.
You gain '.$levelrow[user()->charclass.'_mp'].' magic points.
You gain '.$levelrow[user()->charclass.'_tp'].' travel points.
You gain '.$levelrow[user()->charclass.'_strength'].' strength.
You gain '.$levelrow[user()->charclass.'_dexterity']." dexterity.
$spelltext
You can now continue exploring."; $title = 'Courage and Wit have served thee well!'; $dropcode = ''; } else { $page = 'Congratulations. You have defeated the '.$monsterrow['name'].".
You gain $exp experience. $warnexp
You gain $gold gold. $warngold

"; if (rand(1, 30) === 1) { $droprow = db()->query('SELECT * FROM drops WHERE mlevel <= ? ORDER BY RANDOM() LIMIT 1;', [$monsterrow['level']])->fetchArray(SQLITE3_ASSOC); $dropcode = "dropcode='".$droprow['id']."',"; $page .= 'This monster has dropped an item. Click here to reveal and equip the item, or you may also move on and continue exploring.'; } else { $dropcode = ''; $page .= 'You can now continue exploring.'; } $title = 'Victory!'; } } user()->currentaction = 'Exploring'; user()->currentfight = 0; user()->currentuberdamage = 0; user()->currentuberdefense = 0; user()->currentmonstersleep = 0; user()->currentmonsterimmune = 0; user()->save(); page_title($title); return $page; } public static function drop() { if (user()->dropcode == 0) { redirect('/'); } $droprow = get_drop(user()->dropcode); if (isset($_POST['submit'])) { $slot = $_POST['slot']; if ($slot === 0) { return 'Please go back and select an inventory slot to continue.'; } $slotstr = 'slot'.$slot.'id'; if (user()->$slotstr != 0) { $slotrow = get_drop(user()->$slotstr); $old1 = explode(',', $slotrow['attribute1']); if ($slotrow['attribute2'] != 'X') { $old2 = explode(',', $slotrow['attribute2']); } else { $old2 = [0 => 'maxhp',1 => 0]; } $new1 = explode(',', $droprow['attribute1']); if ($droprow['attribute2'] != 'X') { $new2 = explode(',', $droprow['attribute2']); } else { $new2 = [0 => 'maxhp',1 => 0]; } user()->$old1[0] -= $old1[1]; user()->$old2[0] -= $old2[1]; if ($old1[0] == 'strength') { user()->attackpower -= $old1[1]; } if ($old1[0] == 'dexterity') { user()->defensepower -= $old1[1]; } if ($old2[0] == 'strength') { user()->attackpower -= $old2[1]; } if ($old2[0] == 'dexterity') { user()->defensepower -= $old2[1]; } user()->$new1[0] += $new1[1]; user()->$new2[0] += $new2[1]; if ($new1[0] == 'strength') { user()->attackpower += $new1[1]; } if ($new1[0] == 'dexterity') { user()->defensepower += $new1[1]; } if ($new2[0] == 'strength') { user()->attackpower += $new2[1]; } if ($new2[0] == 'dexterity') { user()->defensepower += $new2[1]; } if (user()->currenthp > user()->maxhp) { user()->currenthp = user()->maxhp; } if (user()->currentmp > user()->maxmp) { user()->currentmp = user()->maxmp; } if (user()->currenttp > user()->maxtp) { user()->currenttp = user()->maxtp; } $slot_s = 'slot'.$_POST['slot']; $slot_name = "{$slot_s}name"; $slot_id = "{$slot_s}id"; user()->$slot_name = $droprow['name']; user()->$slot_id = $droprow['id']; } else { $new1 = explode(',', $droprow['attribute1']); if ($droprow['attribute2'] != 'X') { $new2 = explode(',', $droprow['attribute2']); } else { $new2 = [0 => 'maxhp',1 => 0]; } user()->$new1[0] += $new1[1]; user()->$new2[0] += $new2[1]; if ($new1[0] == 'strength') { user()->attackpower += $new1[1]; } if ($new1[0] == 'dexterity') { user()->defensepower += $new1[1]; } if ($new2[0] == 'strength') { user()->attackpower += $new2[1]; } if ($new2[0] == 'dexterity') { user()->defensepower += $new2[1]; } $slot_s = 'slot'.$_POST['slot']; $slot_name = "{$slot_s}name"; $slot_id = "{$slot_s}id"; user()->$slot_name = $droprow['name']; user()->$slot_id = $droprow['id']; } user()->save(); return 'The item has been equipped. You can now continue exploring.'; } $attributearray = ['maxhp' => 'Max HP', 'maxmp' => 'Max MP', 'maxtp' => 'Max TP', 'defensepower' => 'Defense Power', 'attackpower' => 'Attack Power', 'strength' => 'Strength', 'dexterity' => 'Dexterity', 'expbonus' => 'Experience Bonus', 'goldbonus' => 'Gold Bonus']; $page = 'The monster dropped the following item: '.$droprow['name'].'

'; $page .= 'This item has the following attribute(s):
'; $attribute1 = explode(',', $droprow['attribute1']); $page .= $attributearray[$attribute1[0]]; if ($attribute1[1] > 0) { $page .= ' +'.$attribute1[1].'
'; } else { $page .= $attribute1[1].'
'; } if ($droprow['attribute2'] != 'X') { $attribute2 = explode(',', $droprow['attribute2']); $page .= $attributearray[$attribute2[0]]; if ($attribute2[1] > 0) { $page .= ' +'.$attribute2[1].'
'; } else { $page .= $attribute2[1].'
'; } } $page .= '
Select an inventory slot from the list below to equip this item. If the inventory slot is already full, the old item will be discarded.'; $page .= '
'; $page .= 'You may also choose to just continue exploring and give up this item.'; return $page; } public static function dead() { return <<You have died.

As a consequence, you've lost half of your gold. However, you have been given back a portion of your hit points to continue your journey.

You may now continue back to town, and we hope you fair better next time. HTML; } public static function handleMonsterTurn(&$userrow, $monsterrow) { $pagearray = ''; if (user()->currentmonstersleep != 0) { $chancetowake = rand(1, 15); if ($chancetowake > user()->currentmonstersleep) { user()->currentmonstersleep = 0; $pagearray .= 'The monster has woken up.
'; } else { $pagearray .= 'The monster is still asleep.
'; } } if (user()->currentmonstersleep == 0) { $tohit = (int) ceil(mt_rand((int) ($monsterrow['maxdam'] * 0.5), (int) $monsterrow['maxdam'])); $toblock = (int) ceil(mt_rand((int) (user()->defensepower * 0.75), (int) user()->defensepower) / 4); $tododge = rand(1, 150); if ($tododge <= sqrt(user()->dexterity)) { $tohit = 0; $pagearray .= "You dodge the monster's attack. No damage has been scored.
"; $persondamage = 0; } else { $persondamage = max(1, $tohit - $toblock); if (user()->currentuberdefense != 0) { $persondamage -= (int) ceil($persondamage * (user()->currentuberdefense / 100)); } $persondamage = max(1, $persondamage); } $pagearray .= "The monster attacks you for $persondamage damage.

"; user()->currenthp -= $persondamage; if (user()->currenthp <= 0) { $newgold = (int) ceil(user()->gold / 2); $newhp = (int) ceil(user()->maxhp / 4); db()->query("UPDATE users SET currenthp=?, currentaction='In Town', currentmonster=0, currentmonsterhp=0, currentmonstersleep=0, currentmonsterimmune=0, currentfight=0, latitude=0, longitude=0, gold=? WHERE id=?;", [ $newhp, $newgold, $userrow['id'], ]); self::dead(); } } return $pagearray; } public static function handleSpellCast(&$userrow, $newspellrow) { $pagearray = ''; switch ($newspellrow['type']) { case 1: // Heal spell $newhp = min(user()->currenthp + $newspellrow['attribute'], user()->maxhp); user()->currenthp = $newhp; user()->currentmp -= $newspellrow['mp']; $pagearray = "You have cast the {$newspellrow['name']} spell, and gained {$newspellrow['attribute']} Hit Points.

"; break; case 2: // Hurt spell if (user()->currentmonsterimmune == 0) { $monsterdamage = mt_rand((int) (($newspellrow['attribute'] / 6) * 5), $newspellrow['attribute']); user()->currentmonsterhp -= $monsterdamage; $pagearray = "You have cast the {$newspellrow['name']} spell for $monsterdamage damage.

"; } else { $pagearray = "You have cast the {$newspellrow['name']} spell, but the monster is immune to it.

"; } user()->currentmp -= $newspellrow['mp']; break; case 3: // Sleep spell if (user()->currentmonsterimmune != 2) { user()->currentmonstersleep = $newspellrow['attribute']; $pagearray = "You have cast the {$newspellrow['name']} spell. The monster is asleep.

"; } else { $pagearray = "You have cast the {$newspellrow['name']} spell, but the monster is immune to it.

"; } user()->currentmp -= $newspellrow['mp']; break; case 4: // +Damage spell user()->currentuberdamage = $newspellrow['attribute']; user()->currentmp -= $newspellrow['mp']; $pagearray = "You have cast the {$newspellrow['name']} spell, and will gain {$newspellrow['attribute']}% damage until the end of this fight.

"; break; case 5: // +Defense spell user()->currentuberdefense = $newspellrow['attribute']; user()->currentmp -= $newspellrow['mp']; $pagearray = "You have cast the {$newspellrow['name']} spell, and will gain {$newspellrow['attribute']}% defense until the end of this fight.

"; break; } return $pagearray; } }