diff --git a/config.php b/config.php deleted file mode 100644 index b1d2606..0000000 --- a/config.php +++ /dev/null @@ -1,11 +0,0 @@ - "localhost", // MySQL server name. (Default: localhost) - "user" => "", // MySQL username. - "pass" => "", // MySQL password. - "name" => "", // MySQL database name. - "prefix" => "dk", // Prefix for table names. (Default: dk) - "secretword" => ""); // Secret word used when hashing information for cookies. - -?> \ No newline at end of file diff --git a/public/css/dragon.css b/public/css/dragon.css new file mode 100644 index 0000000..d8a36e8 --- /dev/null +++ b/public/css/dragon.css @@ -0,0 +1,21 @@ +* { + box-sizing: border-box; +} + +body { + background-image: url(/img/bg/bg.webp); + background-repeat: repeat; +} + +#container { + max-width: 996px; + margin: 0 auto; +} + +.mb-1 { + margin-bottom: 1rem; +} + +.mb-2 { + margin-bottom: 2rem; +} \ No newline at end of file diff --git a/images/background.gif b/public/img/background.gif similarity index 100% rename from images/background.gif rename to public/img/background.gif diff --git a/images/background.jpg b/public/img/background.jpg similarity index 100% rename from images/background.jpg rename to public/img/background.jpg diff --git a/images/bars_green.gif b/public/img/bars_green.gif similarity index 100% rename from images/bars_green.gif rename to public/img/bars_green.gif diff --git a/images/bars_red.gif b/public/img/bars_red.gif similarity index 100% rename from images/bars_red.gif rename to public/img/bars_red.gif diff --git a/images/bars_yellow.gif b/public/img/bars_yellow.gif similarity index 100% rename from images/bars_yellow.gif rename to public/img/bars_yellow.gif diff --git a/public/img/bg/bg.webp b/public/img/bg/bg.webp new file mode 100644 index 0000000..bdc5375 Binary files /dev/null and b/public/img/bg/bg.webp differ diff --git a/images/button_character.gif b/public/img/button_character.gif similarity index 100% rename from images/button_character.gif rename to public/img/button_character.gif diff --git a/images/button_fastspells.gif b/public/img/button_fastspells.gif similarity index 100% rename from images/button_fastspells.gif rename to public/img/button_fastspells.gif diff --git a/images/button_functions.gif b/public/img/button_functions.gif similarity index 100% rename from images/button_functions.gif rename to public/img/button_functions.gif diff --git a/images/button_help.gif b/public/img/button_help.gif similarity index 100% rename from images/button_help.gif rename to public/img/button_help.gif diff --git a/images/button_inventory.gif b/public/img/button_inventory.gif similarity index 100% rename from images/button_inventory.gif rename to public/img/button_inventory.gif diff --git a/images/button_location.gif b/public/img/button_location.gif similarity index 100% rename from images/button_location.gif rename to public/img/button_location.gif diff --git a/images/button_login.gif b/public/img/button_login.gif similarity index 100% rename from images/button_login.gif rename to public/img/button_login.gif diff --git a/images/button_logout.gif b/public/img/button_logout.gif similarity index 100% rename from images/button_logout.gif rename to public/img/button_logout.gif diff --git a/images/button_register.gif b/public/img/button_register.gif similarity index 100% rename from images/button_register.gif rename to public/img/button_register.gif diff --git a/images/button_shoutbox.gif b/public/img/button_shoutbox.gif similarity index 100% rename from images/button_shoutbox.gif rename to public/img/button_shoutbox.gif diff --git a/images/button_spells.gif b/public/img/button_spells.gif similarity index 100% rename from images/button_spells.gif rename to public/img/button_spells.gif diff --git a/images/button_status.gif b/public/img/button_status.gif similarity index 100% rename from images/button_status.gif rename to public/img/button_status.gif diff --git a/images/button_towns.gif b/public/img/button_towns.gif similarity index 100% rename from images/button_towns.gif rename to public/img/button_towns.gif diff --git a/images/compass_01.gif b/public/img/compass_01.gif similarity index 100% rename from images/compass_01.gif rename to public/img/compass_01.gif diff --git a/images/compass_02.gif b/public/img/compass_02.gif similarity index 100% rename from images/compass_02.gif rename to public/img/compass_02.gif diff --git a/images/compass_03.gif b/public/img/compass_03.gif similarity index 100% rename from images/compass_03.gif rename to public/img/compass_03.gif diff --git a/images/compass_04.gif b/public/img/compass_04.gif similarity index 100% rename from images/compass_04.gif rename to public/img/compass_04.gif diff --git a/images/dkforumsbutton.gif b/public/img/dkforumsbutton.gif similarity index 100% rename from images/dkforumsbutton.gif rename to public/img/dkforumsbutton.gif diff --git a/images/help_exploring.jpg b/public/img/help_exploring.jpg similarity index 100% rename from images/help_exploring.jpg rename to public/img/help_exploring.jpg diff --git a/images/help_fighting.jpg b/public/img/help_fighting.jpg similarity index 100% rename from images/help_fighting.jpg rename to public/img/help_fighting.jpg diff --git a/images/icon_armor.gif b/public/img/icon_armor.gif similarity index 100% rename from images/icon_armor.gif rename to public/img/icon_armor.gif diff --git a/images/icon_shield.gif b/public/img/icon_shield.gif similarity index 100% rename from images/icon_shield.gif rename to public/img/icon_shield.gif diff --git a/images/icon_weapon.gif b/public/img/icon_weapon.gif similarity index 100% rename from images/icon_weapon.gif rename to public/img/icon_weapon.gif diff --git a/images/logo.gif b/public/img/logo.gif similarity index 100% rename from images/logo.gif rename to public/img/logo.gif diff --git a/images/map.gif b/public/img/map.gif similarity index 100% rename from images/map.gif rename to public/img/map.gif diff --git a/images/title_exploring.gif b/public/img/title_exploring.gif similarity index 100% rename from images/title_exploring.gif rename to public/img/title_exploring.gif diff --git a/images/title_fighting.gif b/public/img/title_fighting.gif similarity index 100% rename from images/title_fighting.gif rename to public/img/title_fighting.gif diff --git a/images/town_1.gif b/public/img/town_1.gif similarity index 100% rename from images/town_1.gif rename to public/img/town_1.gif diff --git a/images/town_2.gif b/public/img/town_2.gif similarity index 100% rename from images/town_2.gif rename to public/img/town_2.gif diff --git a/images/town_3.gif b/public/img/town_3.gif similarity index 100% rename from images/town_3.gif rename to public/img/town_3.gif diff --git a/images/town_4.gif b/public/img/town_4.gif similarity index 100% rename from images/town_4.gif rename to public/img/town_4.gif diff --git a/images/town_5.gif b/public/img/town_5.gif similarity index 100% rename from images/town_5.gif rename to public/img/town_5.gif diff --git a/images/town_6.gif b/public/img/town_6.gif similarity index 100% rename from images/town_6.gif rename to public/img/town_6.gif diff --git a/images/town_7.gif b/public/img/town_7.gif similarity index 100% rename from images/town_7.gif rename to public/img/town_7.gif diff --git a/images/town_8.gif b/public/img/town_8.gif similarity index 100% rename from images/town_8.gif rename to public/img/town_8.gif diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..86ce24b --- /dev/null +++ b/public/index.php @@ -0,0 +1,5 @@ + 'Intro', 'step' => 'first']); + exit; +} + +// Database setup; create tables and default data (if requested) +if ($step == 'second') { + $istart = microtime(true); // time the database setup + if (!isset($_POST['mode'])) redirect('/install/'); // dont run install if a button wasnt clicked + $complete = $_POST['mode'] == 'complete'; // complete or partial setup + + // Create Control table + $db->table('control')->create([ + 'id INTEGER PRIMARY KEY', + "game_name TEXT DEFAULT 'Dragon Knight'", + 'game_size INTEGER DEFAULT 250', + 'game_open INTEGER DEFAULT 1', + "admin_email TEXT DEFAULT ''", + 'forum_type INTEGER DEFAULT 1', + "forum_addr TEXT DEFAULT ''", + "class_1_name TEXT DEFAULT 'Mage'", + "class_2_name TEXT DEFAULT 'Warrior'", + "class_3_name TEXT DEFAULT 'Paladin'", + 'verify_email INTEGER DEFAULT 1', + 'show_news INTEGER DEFAULT 1', + 'show_online INTEGER DEFAULT 1', + 'show_babble INTEGER DEFAULT 1' + ]); + + // Insert default control row + $db->insertDefaultValues(); + + // Create Babble table + $db->table('babble')->create([ + 'id INTEGER PRIMARY KEY', + 'posted DATETIME DEFAULT CURRENT_TIMESTAMP', + 'author INTEGER DEFAULT 1', + 'babble TEXT NOT NULL' + ]); + + // Create Drops table + $db->table('drops')->create([ + 'id INTEGER PRIMARY KEY', + 'name TEXT NOT NULL', + 'level INTEGER DEFAULT 1', + 'type INTEGER DEFAULT 1', + "attr1 TEXT DEFAULT ''", + "attr2 TEXT DEFAULT ''" + ]); + + // Add default drops if complete install + if ($complete) { + $db->insert([ + ['name' => 'Life Pebble', 'level' => 1, 'type' => 1, 'attr1' => 'hp,10', 'attr2' => '' ], + ['name' => 'Life Stone', 'level' => 10, 'type' => 1, 'attr1' => 'hp,25', 'attr2' => '' ], + ['name' => 'Life Rock', 'level' => 25, 'type' => 1, 'attr1' => 'hp,50', 'attr2' => '' ], + ['name' => 'Life Ore', 'level' => 50, 'type' => 1, 'attr1' => 'hp,100', 'attr2' => '' ], + ['name' => 'Life Gem', 'level' => 75, 'type' => 1, 'attr1' => 'hp,150', 'attr2' => '' ], + ['name' => 'Magic Pebble', 'level' => 1, 'type' => 1, 'attr1' => 'mp,10', 'attr2' => '' ], + ['name' => 'Magic Stone', 'level' => 10, 'type' => 1, 'attr1' => 'mp,25', 'attr2' => '' ], + ['name' => 'Magic Rock', 'level' => 25, 'type' => 1, 'attr1' => 'mp,50', 'attr2' => '' ], + ['name' => 'Magic Ore', 'level' => 50, 'type' => 1, 'attr1' => 'mp,100', 'attr2' => '' ], + ['name' => 'Magic Gem', 'level' => 75, 'type' => 1, 'attr1' => 'mp,150', 'attr2' => '' ], + ['name' => "Dragon's Scale", 'level' => 10, 'type' => 1, 'attr1' => 'def,25', 'attr2' => '' ], + ['name' => "Dragon's Plate", 'level' => 30, 'type' => 1, 'attr1' => 'def,50', 'attr2' => '' ], + ['name' => "Dragon's Claw", 'level' => 10, 'type' => 1, 'attr1' => 'atk,25', 'attr2' => '' ], + ['name' => "Dragon's Fang", 'level' => 30, 'type' => 1, 'attr1' => 'atk,50', 'attr2' => '' ], + ['name' => "Dragon's Tear", 'level' => 35, 'type' => 1, 'attr1' => 'str,75', 'attr2' => '' ], + ['name' => "Dragon's Wing", 'level' => 35, 'type' => 1, 'attr1' => 'dex,75', 'attr2' => '' ], + ['name' => "Demon's Sin", 'level' => 35, 'type' => 1, 'attr1' => 'hp,-50', 'attr2' => 'str,50' ], + ['name' => "Demon's Fall", 'level' => 35, 'type' => 1, 'attr1' => 'mp,-50', 'attr2' => 'str,50' ], + ['name' => "Demon's Lie", 'level' => 45, 'type' => 1, 'attr1' => 'hp,-100', 'attr2' => 'str,100' ], + ['name' => "Demon's Hate", 'level' => 45, 'type' => 1, 'attr1' => 'mp,-100', 'attr2' => 'str,100' ], + ['name' => "Angel's Joy", 'level' => 25, 'type' => 1, 'attr1' => 'hp,25', 'attr2' => 'str,25' ], + ['name' => "Angel's Rise", 'level' => 30, 'type' => 1, 'attr1' => 'hp,50', 'attr2' => 'str,50' ], + ['name' => "Angel's Truth", 'level' => 35, 'type' => 1, 'attr1' => 'hp,75', 'attr2' => 'str,75' ], + ['name' => "Angel's Grace", 'level' => 40, 'type' => 1, 'attr1' => 'hp,100', 'attr2' => 'str,100' ], + ['name' => "Seraph's Strength", 'level' => 25, 'type' => 1, 'attr1' => 'mp,25', 'attr2' => 'dex,25' ], + ['name' => "Seraph's Power", 'level' => 30, 'type' => 1, 'attr1' => 'mp,50', 'attr2' => 'dex,50' ], + ['name' => "Seraph's Justice", 'level' => 35, 'type' => 1, 'attr1' => 'mp,75', 'attr2' => 'dex,75' ], + ['name' => "Seraph's Judgement", 'level' => 40, 'type' => 1, 'attr1' => 'mp,100', 'attr2' => 'dex,100' ], + ['name' => 'Ruby', 'level' => 50, 'type' => 1, 'attr1' => 'hp,150', 'attr2' => '' ], + ['name' => 'Sapphire', 'level' => 50, 'type' => 1, 'attr1' => 'mp,150', 'attr2' => '' ], + ['name' => 'Emerald', 'level' => 50, 'type' => 1, 'attr1' => 'str,150', 'attr2' => '' ], + ['name' => 'Amethyst', 'level' => 50, 'type' => 1, 'attr1' => 'dex,150', 'attr2' => '' ], + ['name' => 'Topaz', 'level' => 50, 'type' => 1, 'attr1' => 'atk,150', 'attr2' => '' ], + ['name' => 'Diamond', 'level' => 50, 'type' => 1, 'attr1' => 'def,150', 'attr2' => '' ], + ['name' => "Ocean Blessing", 'level' => 77, 'type' => 1, 'attr1' => 'str,7007', 'attr2' => 'dex,7007'], + ['name' => 'Memory Tonic', 'level' => 5, 'type' => 1, 'attr1' => 'exp,10', 'attr2' => '' ], + ['name' => 'Memory Potion', 'level' => 30, 'type' => 1, 'attr1' => 'exp,20', 'attr2' => '' ], + ['name' => 'Memory Elixir', 'level' => 50, 'type' => 1, 'attr1' => 'exp,30', 'attr2' => '' ], + ['name' => 'Gold Tonic', 'level' => 5, 'type' => 1, 'attr1' => 'gold,10', 'attr2' => '' ], + ['name' => 'Gold Potion', 'level' => 30, 'type' => 1, 'attr1' => 'gold,20', 'attr2' => '' ], + ['name' => 'Gold Elixir', 'level' => 50, 'type' => 1, 'attr1' => 'gold,30', 'attr2' => '' ], + ]); + } + + // Create Forum table + $db->table('forum')->create([ + 'id INTEGER PRIMARY KEY', + 'posted DATETIME DEFAULT CURRENT_TIMESTAMP', + 'new_post DATETIME DEFAULT CURRENT_TIMESTAMP', + 'author INTEGER DEFAULT 1', + "subject TEXT DEFAULT ''", + "message TEXT DEFAULT ''", + 'locked INTEGER DEFAULT 0', + 'sticky INTEGER DEFAULT 0', + 'parent INTEGER DEFAULT 0' + ]); + + // Create Items table + $db->table('items')->create([ + 'id INTEGER PRIMARY KEY', + 'type INTEGER DEFAULT 1', + 'name TEXT NOT NULL', + 'cost INTEGER DEFAULT 0', + "attr1 TEXT DEFAULT ''", + "attr2 TEXT DEFAULT ''", + "icon TEXT DEFAULT ''" + ]); + + // Create default items, if complete install + if ($complete) { + $db->insert([ + // Type 1 - weapons + ['type' => 1, 'name' => 'Stick', 'cost' => 10, 'attr1' => 'atk,2', 'attr2' => '', 'icon' => 'stick.png' ], + ['type' => 1, 'name' => 'Branch', 'cost' => 30, 'attr1' => 'atk,4', 'attr2' => '', 'icon' => 'branch.png' ], + ['type' => 1, 'name' => 'Club', 'cost' => 40, 'attr1' => 'atk,6', 'attr2' => '', 'icon' => 'club.png' ], + ['type' => 1, 'name' => 'Dagger', 'cost' => 80, 'attr1' => 'atk,8', 'attr2' => '', 'icon' => 'dagger.png' ], + ['type' => 1, 'name' => 'Hatchet', 'cost' => 120, 'attr1' => 'atk,12', 'attr2' => '', 'icon' => 'hatchet.png' ], + ['type' => 1, 'name' => 'Axe', 'cost' => 200, 'attr1' => 'atk,18', 'attr2' => '', 'icon' => 'axe.png' ], + ['type' => 1, 'name' => 'Spear', 'cost' => 300, 'attr1' => 'atk,25', 'attr2' => '', 'icon' => 'spear.png' ], + ['type' => 1, 'name' => 'Poleaxe', 'cost' => 500, 'attr1' => 'atk,35', 'attr2' => '', 'icon' => 'poleaxe.png' ], + ['type' => 1, 'name' => 'Warhammer', 'cost' => 800, 'attr1' => 'atk,50', 'attr2' => '', 'icon' => 'warhammer.png' ], + ['type' => 1, 'name' => 'Longsword', 'cost' => 1200, 'attr1' => 'atk,65', 'attr2' => '', 'icon' => 'longsword.png' ], + ['type' => 1, 'name' => 'Claymore', 'cost' => 1800, 'attr1' => 'atk,85', 'attr2' => '', 'icon' => 'claymore.png' ], + ['type' => 1, 'name' => 'Demon Axe', 'cost' => 2800, 'attr1' => 'atk,125', 'attr2' => 'exp,-5', 'icon' => 'demonaxe.png' ], + ['type' => 1, 'name' => 'Dark Sword', 'cost' => 4500, 'attr1' => 'atk,225', 'attr2' => 'exp,-10', 'icon' => 'darksword.png' ], + ['type' => 1, 'name' => 'Magic Axe', 'cost' => 2800, 'attr1' => 'atk,95', 'attr2' => 'exp,5', 'icon' => 'magicaxe.png' ], + ['type' => 1, 'name' => 'Bright Sword', 'cost' => 4500, 'attr1' => 'atk,185', 'attr2' => 'exp,10', 'icon' => 'brightsword.png'], + ['type' => 1, 'name' => 'Dragonbane', 'cost' => 10000, 'attr1' => 'atk,300', 'attr2' => 'str,50', 'icon' => 'dragonbane.png' ], + + // Type 2 - armors + ['type' => 2, 'name' => 'Underwear', 'cost' => 25, 'attr1' => 'def,2', 'attr2' => 'gold,10', 'icon' => 'underwear.png' ], + ['type' => 2, 'name' => 'Clothes', 'cost' => 50, 'attr1' => 'def,5', 'attr2' => '', 'icon' => 'clothes.png' ], + ['type' => 2, 'name' => 'Leather', 'cost' => 75, 'attr1' => 'def,10', 'attr2' => '', 'icon' => 'leather.png' ], + ['type' => 2, 'name' => 'Hard Leather', 'cost' => 150, 'attr1' => 'def,25', 'attr2' => '', 'icon' => 'hardleather.png' ], + ['type' => 2, 'name' => 'Chainmail', 'cost' => 300, 'attr1' => 'def,35', 'attr2' => '', 'icon' => 'chainmail.png' ], + ['type' => 2, 'name' => 'Scale Armor', 'cost' => 900, 'attr1' => 'def,50', 'attr2' => '', 'icon' => 'scalearmor.png' ], + ['type' => 2, 'name' => 'Platemail', 'cost' => 1800, 'attr1' => 'def,100', 'attr2' => '', 'icon' => 'platemail.png' ], + ['type' => 2, 'name' => 'Magic Plate', 'cost' => 3000, 'attr1' => 'def,125', 'attr2' => 'mp,50', 'icon' => 'magicplate.png' ], + ['type' => 2, 'name' => 'Darkmail', 'cost' => 5000, 'attr1' => 'def,200', 'attr2' => 'exp,-10', 'icon' => 'darkmail.png' ], + ['type' => 2, 'name' => 'Dragon Plate', 'cost' => 10000, 'attr1' => 'def,165', 'attr2' => 'exp,10', 'icon' => 'dragonplate.png' ], + ['type' => 2, 'name' => 'Destiny Raiment', 'cost' => 50000, 'attr1' => 'def,200', 'attr2' => 'dex,50', 'icon' => 'destinyraiment.png'], + + // Type 3 - shields + ['type' => 3, 'name' => 'Reed Shield', 'cost' => 50, 'attr1' => 'def,5', 'attr2' => '', 'icon' => 'reedshield.png' ], + ['type' => 3, 'name' => 'Buckler', 'cost' => 100, 'attr1' => 'def,10', 'attr2' => '', 'icon' => 'nuckler.png' ], + ['type' => 3, 'name' => 'Round Shield', 'cost' => 500, 'attr1' => 'def,25', 'attr2' => '', 'icon' => 'roundshield.png' ], + ['type' => 3, 'name' => 'Tower Shield', 'cost' => 2500, 'attr1' => 'def,50', 'attr2' => '', 'icon' => 'towershield.png' ], + ['type' => 3, 'name' => 'Silver Shield', 'cost' => 10000, 'attr1' => 'def,100', 'attr2' => '', 'icon' => 'silvershield.png'], + ['type' => 3, 'name' => 'Dragon Shield', 'cost' => 25000, 'attr1' => 'def,125', 'attr2' => 'mp,100', 'icon' => 'dragonshield.png'], + ['type' => 3, 'name' => 'Aegis', 'cost' => 50000, 'attr1' => 'def,225', 'attr2' => 'exp,10', 'icon' => 'aegis.png' ] + ]); + } + + // Create Monsters table + $db->table('monsters')->create([ + 'id INTEGER PRIMARY KEY', + 'name TEXT NOT NULL', + 'level INTEGER DEFAULT 1', + 'hp INTEGER DEFAULT 1', + 'atk INTEGER DEFAULT 1', + 'def INTEGER DEFAULT 1', + 'exp INTEGER DEFAULT 1', + 'gold INTEGER DEFAULT 1', + 'immune INTEGER DEFAULT 0', + "image TEXT DEFAULT ''" + ]); + + // Fill monsters table if complete install + if ($complete) { + $db->insert([ + ['name' => 'Blue Slime', 'level' => 1, 'hp' => 4, 'atk' => 3, 'def' => 1, 'exp' => 1, 'gold' => 1, 'immune' => 0], + ['name' => 'Red Slime', 'level' => 1, 'hp' => 6, 'atk' => 5, 'def' => 1, 'exp' => 2, 'gold' => 1, 'immune' => 0], + ['name' => 'Critter', 'level' => 1, 'hp' => 6, 'atk' => 5, 'def' => 2, 'exp' => 4, 'gold' => 2, 'immune' => 0], + ['name' => 'Creature', 'level' => 2, 'hp' => 10, 'atk' => 8, 'def' => 2, 'exp' => 4, 'gold' => 2, 'immune' => 0], + ['name' => 'Shadow', 'level' => 2, 'hp' => 10, 'atk' => 9, 'def' => 3, 'exp' => 6, 'gold' => 2, 'immune' => 1], + ['name' => 'Drake', 'level' => 2, 'hp' => 11, 'atk' => 10, 'def' => 3, 'exp' => 8, 'gold' => 3, 'immune' => 0], + ['name' => 'Shade', 'level' => 3, 'hp' => 12, 'atk' => 10, 'def' => 3, 'exp' => 10, 'gold' => 3, 'immune' => 1], + ['name' => 'Drakelor', 'level' => 3, 'hp' => 14, 'atk' => 12, 'def' => 4, 'exp' => 10, 'gold' => 3, 'immune' => 0], + ['name' => 'Silver Slime', 'level' => 30, 'hp' => 15, 'atk' => 100, 'def' => 200, 'exp' => 15, 'gold' => 1000, 'immune' => 2], + ['name' => 'Scamp', 'level' => 4, 'hp' => 16, 'atk' => 13, 'def' => 5, 'exp' => 15, 'gold' => 5, 'immune' => 0], + ['name' => 'Raven', 'level' => 4, 'hp' => 16, 'atk' => 13, 'def' => 5, 'exp' => 18, 'gold' => 6, 'immune' => 0], + ['name' => 'Scorpion', 'level' => 5, 'hp' => 18, 'atk' => 14, 'def' => 6, 'exp' => 20, 'gold' => 7, 'immune' => 0], + ['name' => 'Illusion', 'level' => 5, 'hp' => 20, 'atk' => 15, 'def' => 6, 'exp' => 20, 'gold' => 7, 'immune' => 1], + ['name' => 'Nightshade', 'level' => 6, 'hp' => 22, 'atk' => 16, 'def' => 6, 'exp' => 24, 'gold' => 8, 'immune' => 0], + ['name' => 'Drakemal', 'level' => 6, 'hp' => 22, 'atk' => 18, 'def' => 7, 'exp' => 24, 'gold' => 8, 'immune' => 0], + ['name' => 'Shadow Raven', 'level' => 6, 'hp' => 24, 'atk' => 18, 'def' => 7, 'exp' => 26, 'gold' => 9, 'immune' => 1], + ['name' => 'Ghost', 'level' => 6, 'hp' => 24, 'atk' => 20, 'def' => 8, 'exp' => 28, 'gold' => 9, 'immune' => 0], + ['name' => 'Frost Raven', 'level' => 7, 'hp' => 26, 'atk' => 20, 'def' => 8, 'exp' => 30, 'gold' => 10, 'immune' => 0], + ['name' => 'Rogue Scorpion', 'level' => 7, 'hp' => 28, 'atk' => 22, 'def' => 9, 'exp' => 32, 'gold' => 11, 'immune' => 0], + ['name' => 'Ghoul', 'level' => 7, 'hp' => 29, 'atk' => 24, 'def' => 9, 'exp' => 34, 'gold' => 11, 'immune' => 0], + ['name' => 'Magician', 'level' => 8, 'hp' => 30, 'atk' => 24, 'def' => 10, 'exp' => 36, 'gold' => 12, 'immune' => 0], + ['name' => 'Rogue', 'level' => 8, 'hp' => 30, 'atk' => 25, 'def' => 12, 'exp' => 40, 'gold' => 13, 'immune' => 0], + ['name' => 'Drakefin', 'level' => 8, 'hp' => 32, 'atk' => 26, 'def' => 12, 'exp' => 40, 'gold' => 13, 'immune' => 0], + ['name' => 'Shimmer', 'level' => 8, 'hp' => 32, 'atk' => 26, 'def' => 14, 'exp' => 45, 'gold' => 15, 'immune' => 1], + ['name' => 'Fire Raven', 'level' => 9, 'hp' => 34, 'atk' => 28, 'def' => 14, 'exp' => 45, 'gold' => 15, 'immune' => 0], + ['name' => 'Dybbuk', 'level' => 9, 'hp' => 34, 'atk' => 28, 'def' => 14, 'exp' => 50, 'gold' => 17, 'immune' => 0], + ['name' => 'Knave', 'level' => 9, 'hp' => 36, 'atk' => 30, 'def' => 15, 'exp' => 52, 'gold' => 17, 'immune' => 0], + ['name' => 'Goblin', 'level' => 10, 'hp' => 36, 'atk' => 30, 'def' => 15, 'exp' => 54, 'gold' => 18, 'immune' => 0], + ['name' => 'Skeleton', 'level' => 10, 'hp' => 38, 'atk' => 30, 'def' => 18, 'exp' => 58, 'gold' => 19, 'immune' => 0], + ['name' => 'Dark Slime', 'level' => 10, 'hp' => 38, 'atk' => 32, 'def' => 18, 'exp' => 62, 'gold' => 21, 'immune' => 0], + ['name' => 'Silver Scorpion', 'level' => 40, 'hp' => 30, 'atk' => 160, 'def' => 350, 'exp' => 63, 'gold' => 2000, 'immune' => 2], + ['name' => 'Mirage', 'level' => 11, 'hp' => 40, 'atk' => 32, 'def' => 20, 'exp' => 64, 'gold' => 21, 'immune' => 1], + ['name' => 'Sorceror', 'level' => 11, 'hp' => 41, 'atk' => 33, 'def' => 22, 'exp' => 68, 'gold' => 23, 'immune' => 0], + ['name' => 'Imp', 'level' => 12, 'hp' => 42, 'atk' => 34, 'def' => 22, 'exp' => 70, 'gold' => 23, 'immune' => 0], + ['name' => 'Nymph', 'level' => 12, 'hp' => 43, 'atk' => 35, 'def' => 22, 'exp' => 70, 'gold' => 23, 'immune' => 0], + ['name' => 'Scoundrel', 'level' => 12, 'hp' => 43, 'atk' => 35, 'def' => 22, 'exp' => 75, 'gold' => 25, 'immune' => 0], + ['name' => 'Megaskeleton', 'level' => 13, 'hp' => 44, 'atk' => 36, 'def' => 24, 'exp' => 78, 'gold' => 26, 'immune' => 0], + ['name' => 'Grey Wolf', 'level' => 13, 'hp' => 44, 'atk' => 36, 'def' => 24, 'exp' => 82, 'gold' => 27, 'immune' => 0], + ['name' => 'Phantom', 'level' => 14, 'hp' => 46, 'atk' => 38, 'def' => 24, 'exp' => 85, 'gold' => 28, 'immune' => 1], + ['name' => 'Specter', 'level' => 14, 'hp' => 46, 'atk' => 38, 'def' => 24, 'exp' => 90, 'gold' => 30, 'immune' => 0], + ['name' => 'Dark Scorpion', 'level' => 15, 'hp' => 48, 'atk' => 40, 'def' => 26, 'exp' => 95, 'gold' => 32, 'immune' => 1], + ['name' => 'Warlock', 'level' => 15, 'hp' => 48, 'atk' => 40, 'def' => 26, 'exp' => 100, 'gold' => 33, 'immune' => 1], + ['name' => 'Orc', 'level' => 15, 'hp' => 49, 'atk' => 42, 'def' => 28, 'exp' => 104, 'gold' => 35, 'immune' => 0], + ['name' => 'Sylph', 'level' => 15, 'hp' => 49, 'atk' => 42, 'def' => 28, 'exp' => 106, 'gold' => 35, 'immune' => 0], + ['name' => 'Wraith', 'level' => 16, 'hp' => 50, 'atk' => 45, 'def' => 30, 'exp' => 108, 'gold' => 36, 'immune' => 0], + ['name' => 'Hellion', 'level' => 16, 'hp' => 50, 'atk' => 45, 'def' => 30, 'exp' => 110, 'gold' => 37, 'immune' => 0], + ['name' => 'Bandit', 'level' => 16, 'hp' => 52, 'atk' => 45, 'def' => 30, 'exp' => 114, 'gold' => 38, 'immune' => 0], + ['name' => 'Ultraskeleton', 'level' => 16, 'hp' => 52, 'atk' => 46, 'def' => 32, 'exp' => 116, 'gold' => 39, 'immune' => 0], + ['name' => 'Dark Wolf', 'level' => 17, 'hp' => 54, 'atk' => 47, 'def' => 36, 'exp' => 120, 'gold' => 40, 'immune' => 1], + ['name' => 'Troll', 'level' => 17, 'hp' => 56, 'atk' => 48, 'def' => 36, 'exp' => 120, 'gold' => 40, 'immune' => 0], + ['name' => 'Werewolf', 'level' => 17, 'hp' => 56, 'atk' => 48, 'def' => 38, 'exp' => 124, 'gold' => 41, 'immune' => 0], + ['name' => 'Hellcat', 'level' => 18, 'hp' => 58, 'atk' => 50, 'def' => 38, 'exp' => 128, 'gold' => 43, 'immune' => 0], + ['name' => 'Spirit', 'level' => 18, 'hp' => 58, 'atk' => 50, 'def' => 38, 'exp' => 132, 'gold' => 44, 'immune' => 0], + ['name' => 'Nisse', 'level' => 19, 'hp' => 60, 'atk' => 52, 'def' => 40, 'exp' => 132, 'gold' => 44, 'immune' => 0], + ['name' => 'Dawk', 'level' => 19, 'hp' => 60, 'atk' => 54, 'def' => 40, 'exp' => 136, 'gold' => 45, 'immune' => 0], + ['name' => 'Figment', 'level' => 19, 'hp' => 64, 'atk' => 55, 'def' => 42, 'exp' => 140, 'gold' => 47, 'immune' => 1], + ['name' => 'Hellhound', 'level' => 20, 'hp' => 66, 'atk' => 56, 'def' => 44, 'exp' => 140, 'gold' => 47, 'immune' => 0], + ['name' => 'Wizard', 'level' => 20, 'hp' => 66, 'atk' => 56, 'def' => 44, 'exp' => 144, 'gold' => 48, 'immune' => 0], + ['name' => 'Uruk', 'level' => 20, 'hp' => 68, 'atk' => 58, 'def' => 44, 'exp' => 146, 'gold' => 49, 'immune' => 0], + ['name' => 'Siren', 'level' => 50, 'hp' => 68, 'atk' => 400, 'def' => 800, 'exp' => 10000, 'gold' => 50, 'immune' => 2], + ['name' => 'Megawraith', 'level' => 21, 'hp' => 70, 'atk' => 60, 'def' => 46, 'exp' => 155, 'gold' => 52, 'immune' => 0], + ['name' => 'Dawkin', 'level' => 21, 'hp' => 70, 'atk' => 60, 'def' => 46, 'exp' => 155, 'gold' => 52, 'immune' => 0], + ['name' => 'Grey Bear', 'level' => 21, 'hp' => 70, 'atk' => 62, 'def' => 48, 'exp' => 160, 'gold' => 53, 'immune' => 0], + ['name' => 'Haunt', 'level' => 22, 'hp' => 72, 'atk' => 62, 'def' => 48, 'exp' => 160, 'gold' => 53, 'immune' => 0], + ['name' => 'Hellbeast', 'level' => 22, 'hp' => 74, 'atk' => 64, 'def' => 50, 'exp' => 165, 'gold' => 55, 'immune' => 0], + ['name' => 'Fear', 'level' => 23, 'hp' => 76, 'atk' => 66, 'def' => 52, 'exp' => 165, 'gold' => 55, 'immune' => 0], + ['name' => 'Beast', 'level' => 23, 'hp' => 76, 'atk' => 66, 'def' => 52, 'exp' => 170, 'gold' => 57, 'immune' => 0], + ['name' => 'Ogre', 'level' => 23, 'hp' => 78, 'atk' => 68, 'def' => 54, 'exp' => 170, 'gold' => 57, 'immune' => 0], + ['name' => 'Dark Bear', 'level' => 24, 'hp' => 80, 'atk' => 70, 'def' => 56, 'exp' => 175, 'gold' => 58, 'immune' => 1], + ['name' => 'Fire', 'level' => 24, 'hp' => 80, 'atk' => 72, 'def' => 56, 'exp' => 175, 'gold' => 58, 'immune' => 0], + ['name' => 'Polgergeist', 'level' => 25, 'hp' => 84, 'atk' => 74, 'def' => 58, 'exp' => 180, 'gold' => 60, 'immune' => 0], + ['name' => 'Fright', 'level' => 25, 'hp' => 86, 'atk' => 76, 'def' => 58, 'exp' => 180, 'gold' => 60, 'immune' => 0], + ['name' => 'Lycan', 'level' => 25, 'hp' => 88, 'atk' => 78, 'def' => 60, 'exp' => 185, 'gold' => 62, 'immune' => 0], + ['name' => 'Terra Elemental', 'level' => 25, 'hp' => 88, 'atk' => 80, 'def' => 62, 'exp' => 185, 'gold' => 62, 'immune' => 1], + ['name' => 'Necromancer', 'level' => 26, 'hp' => 90, 'atk' => 80, 'def' => 62, 'exp' => 190, 'gold' => 63, 'immune' => 0], + ['name' => 'Ultrawraith', 'level' => 26, 'hp' => 90, 'atk' => 82, 'def' => 64, 'exp' => 190, 'gold' => 63, 'immune' => 0], + ['name' => 'Dawkor', 'level' => 26, 'hp' => 92, 'atk' => 82, 'def' => 64, 'exp' => 195, 'gold' => 65, 'immune' => 0], + ['name' => 'Werebear', 'level' => 26, 'hp' => 92, 'atk' => 84, 'def' => 65, 'exp' => 195, 'gold' => 65, 'immune' => 0], + ['name' => 'Brute', 'level' => 27, 'hp' => 94, 'atk' => 84, 'def' => 65, 'exp' => 200, 'gold' => 67, 'immune' => 0], + ['name' => 'Large Beast', 'level' => 27, 'hp' => 96, 'atk' => 88, 'def' => 66, 'exp' => 200, 'gold' => 67, 'immune' => 0], + ['name' => 'Horror', 'level' => 27, 'hp' => 96, 'atk' => 88, 'def' => 68, 'exp' => 210, 'gold' => 70, 'immune' => 0], + ['name' => 'Flame', 'level' => 28, 'hp' => 100, 'atk' => 90, 'def' => 70, 'exp' => 210, 'gold' => 70, 'immune' => 0], + ['name' => 'Lycanthor', 'level' => 28, 'hp' => 100, 'atk' => 90, 'def' => 70, 'exp' => 210, 'gold' => 70, 'immune' => 0], + ['name' => 'Wyrm', 'level' => 28, 'hp' => 100, 'atk' => 92, 'def' => 72, 'exp' => 220, 'gold' => 73, 'immune' => 0], + ['name' => 'Aero Elemental', 'level' => 29, 'hp' => 104, 'atk' => 94, 'def' => 74, 'exp' => 220, 'gold' => 73, 'immune' => 1], + ['name' => 'Dawkare', 'level' => 29, 'hp' => 106, 'atk' => 96, 'def' => 76, 'exp' => 220, 'gold' => 73, 'immune' => 0], + ['name' => 'Large Brute', 'level' => 29, 'hp' => 108, 'atk' => 98, 'def' => 78, 'exp' => 230, 'gold' => 77, 'immune' => 0], + ['name' => 'Frost Wyrm', 'level' => 30, 'hp' => 110, 'atk' => 100, 'def' => 80, 'exp' => 230, 'gold' => 77, 'immune' => 0], + ['name' => 'Knight', 'level' => 30, 'hp' => 110, 'atk' => 102, 'def' => 80, 'exp' => 240, 'gold' => 80, 'immune' => 0], + ['name' => 'Lycanthra', 'level' => 30, 'hp' => 112, 'atk' => 104, 'def' => 82, 'exp' => 240, 'gold' => 80, 'immune' => 0], + ['name' => 'Terror', 'level' => 31, 'hp' => 115, 'atk' => 108, 'def' => 84, 'exp' => 250, 'gold' => 83, 'immune' => 0], + ['name' => 'Blaze', 'level' => 31, 'hp' => 118, 'atk' => 108, 'def' => 84, 'exp' => 250, 'gold' => 83, 'immune' => 0], + ['name' => 'Aqua Elemental', 'level' => 31, 'hp' => 120, 'atk' => 110, 'def' => 90, 'exp' => 260, 'gold' => 87, 'immune' => 1], + ['name' => 'Fire Wyrm', 'level' => 32, 'hp' => 120, 'atk' => 110, 'def' => 90, 'exp' => 260, 'gold' => 87, 'immune' => 0], + ['name' => 'Lesser Wyvern', 'level' => 32, 'hp' => 122, 'atk' => 110, 'def' => 92, 'exp' => 270, 'gold' => 90, 'immune' => 0], + ['name' => 'Doomer', 'level' => 32, 'hp' => 124, 'atk' => 112, 'def' => 92, 'exp' => 270, 'gold' => 90, 'immune' => 0], + ['name' => 'Armor Knight', 'level' => 33, 'hp' => 130, 'atk' => 115, 'def' => 95, 'exp' => 280, 'gold' => 93, 'immune' => 0], + ['name' => 'Wyvern', 'level' => 33, 'hp' => 134, 'atk' => 120, 'def' => 95, 'exp' => 290, 'gold' => 97, 'immune' => 0], + ['name' => 'Nightmare', 'level' => 33, 'hp' => 138, 'atk' => 125, 'def' => 100, 'exp' => 300, 'gold' => 100, 'immune' => 0], + ['name' => 'Fira Elemental', 'level' => 34, 'hp' => 140, 'atk' => 125, 'def' => 100, 'exp' => 310, 'gold' => 103, 'immune' => 1], + ['name' => 'Megadoomer', 'level' => 34, 'hp' => 140, 'atk' => 128, 'def' => 105, 'exp' => 320, 'gold' => 107, 'immune' => 0], + ['name' => 'Greater Wyvern', 'level' => 34, 'hp' => 145, 'atk' => 130, 'def' => 105, 'exp' => 335, 'gold' => 112, 'immune' => 0], + ['name' => 'Advocate', 'level' => 35, 'hp' => 148, 'atk' => 132, 'def' => 108, 'exp' => 350, 'gold' => 117, 'immune' => 0], + ['name' => 'Strong Knight', 'level' => 35, 'hp' => 150, 'atk' => 135, 'def' => 110, 'exp' => 365, 'gold' => 122, 'immune' => 0], + ['name' => 'Liche', 'level' => 35, 'hp' => 150, 'atk' => 135, 'def' => 110, 'exp' => 380, 'gold' => 127, 'immune' => 0], + ['name' => 'Ultradoomer', 'level' => 36, 'hp' => 155, 'atk' => 140, 'def' => 115, 'exp' => 395, 'gold' => 132, 'immune' => 0], + ['name' => 'Fanatic', 'level' => 36, 'hp' => 160, 'atk' => 140, 'def' => 115, 'exp' => 410, 'gold' => 137, 'immune' => 0], + ['name' => 'Green Dragon', 'level' => 36, 'hp' => 160, 'atk' => 140, 'def' => 115, 'exp' => 425, 'gold' => 142, 'immune' => 0], + ['name' => 'Fiend', 'level' => 37, 'hp' => 160, 'atk' => 145, 'def' => 120, 'exp' => 445, 'gold' => 148, 'immune' => 0], + ['name' => 'Greatest Wyvern', 'level' => 37, 'hp' => 162, 'atk' => 150, 'def' => 120, 'exp' => 465, 'gold' => 155, 'immune' => 0], + ['name' => 'Lesser Devil', 'level' => 37, 'hp' => 164, 'atk' => 150, 'def' => 120, 'exp' => 485, 'gold' => 162, 'immune' => 0], + ['name' => 'Liche Master', 'level' => 38, 'hp' => 168, 'atk' => 155, 'def' => 125, 'exp' => 505, 'gold' => 168, 'immune' => 0], + ['name' => 'Zealot', 'level' => 38, 'hp' => 168, 'atk' => 155, 'def' => 125, 'exp' => 530, 'gold' => 177, 'immune' => 0], + ['name' => 'Serafiend', 'level' => 38, 'hp' => 170, 'atk' => 155, 'def' => 125, 'exp' => 555, 'gold' => 185, 'immune' => 0], + ['name' => 'Pale Knight', 'level' => 39, 'hp' => 175, 'atk' => 160, 'def' => 130, 'exp' => 580, 'gold' => 193, 'immune' => 0], + ['name' => 'Blue Dragon', 'level' => 39, 'hp' => 180, 'atk' => 160, 'def' => 130, 'exp' => 605, 'gold' => 202, 'immune' => 0], + ['name' => 'Obsessive', 'level' => 40, 'hp' => 180, 'atk' => 160, 'def' => 135, 'exp' => 630, 'gold' => 210, 'immune' => 0], + ['name' => 'Devil', 'level' => 40, 'hp' => 184, 'atk' => 164, 'def' => 135, 'exp' => 666, 'gold' => 222, 'immune' => 0], + ['name' => 'Liche Prince', 'level' => 40, 'hp' => 190, 'atk' => 168, 'def' => 138, 'exp' => 660, 'gold' => 220, 'immune' => 0], + ['name' => 'Cherufiend', 'level' => 41, 'hp' => 195, 'atk' => 170, 'def' => 140, 'exp' => 690, 'gold' => 230, 'immune' => 0], + ['name' => 'Red Dragon', 'level' => 41, 'hp' => 200, 'atk' => 180, 'def' => 145, 'exp' => 720, 'gold' => 240, 'immune' => 0], + ['name' => 'Greater Devil', 'level' => 41, 'hp' => 200, 'atk' => 180, 'def' => 145, 'exp' => 750, 'gold' => 250, 'immune' => 0], + ['name' => 'Renegade', 'level' => 42, 'hp' => 205, 'atk' => 185, 'def' => 150, 'exp' => 780, 'gold' => 260, 'immune' => 0], + ['name' => 'Archfiend', 'level' => 42, 'hp' => 210, 'atk' => 190, 'def' => 150, 'exp' => 810, 'gold' => 270, 'immune' => 0], + ['name' => 'Liche Lord', 'level' => 42, 'hp' => 210, 'atk' => 190, 'def' => 155, 'exp' => 850, 'gold' => 283, 'immune' => 0], + ['name' => 'Greatest Devil', 'level' => 43, 'hp' => 215, 'atk' => 195, 'def' => 160, 'exp' => 890, 'gold' => 297, 'immune' => 0], + ['name' => 'Dark Knight', 'level' => 43, 'hp' => 220, 'atk' => 200, 'def' => 160, 'exp' => 930, 'gold' => 310, 'immune' => 0], + ['name' => 'Giant', 'level' => 43, 'hp' => 220, 'atk' => 200, 'def' => 165, 'exp' => 970, 'gold' => 323, 'immune' => 0], + ['name' => 'Shadow Dragon', 'level' => 44, 'hp' => 225, 'atk' => 200, 'def' => 170, 'exp' => 1010, 'gold' => 337, 'immune' => 0], + ['name' => 'Liche King', 'level' => 44, 'hp' => 225, 'atk' => 205, 'def' => 170, 'exp' => 1050, 'gold' => 350, 'immune' => 0], + ['name' => 'Incubus', 'level' => 44, 'hp' => 230, 'atk' => 205, 'def' => 175, 'exp' => 1100, 'gold' => 367, 'immune' => 1], + ['name' => 'Traitor', 'level' => 45, 'hp' => 230, 'atk' => 205, 'def' => 175, 'exp' => 1150, 'gold' => 383, 'immune' => 0], + ['name' => 'Demon', 'level' => 45, 'hp' => 240, 'atk' => 210, 'def' => 180, 'exp' => 1200, 'gold' => 400, 'immune' => 0], + ['name' => 'Dark Dragon', 'level' => 45, 'hp' => 245, 'atk' => 215, 'def' => 180, 'exp' => 1250, 'gold' => 417, 'immune' => 1], + ['name' => 'Insurgent', 'level' => 46, 'hp' => 250, 'atk' => 220, 'def' => 190, 'exp' => 1300, 'gold' => 433, 'immune' => 0], + ['name' => 'Leviathan', 'level' => 46, 'hp' => 255, 'atk' => 225, 'def' => 190, 'exp' => 1350, 'gold' => 450, 'immune' => 0], + ['name' => 'Grey Daemon', 'level' => 46, 'hp' => 260, 'atk' => 230, 'def' => 190, 'exp' => 1400, 'gold' => 467, 'immune' => 0], + ['name' => 'Succubus', 'level' => 47, 'hp' => 265, 'atk' => 240, 'def' => 200, 'exp' => 1460, 'gold' => 487, 'immune' => 1], + ['name' => 'Demon Prince', 'level' => 47, 'hp' => 270, 'atk' => 240, 'def' => 200, 'exp' => 1520, 'gold' => 507, 'immune' => 0], + ['name' => 'Black Dragon', 'level' => 47, 'hp' => 275, 'atk' => 250, 'def' => 205, 'exp' => 1580, 'gold' => 527, 'immune' => 1], + ['name' => 'Nihilist', 'level' => 47, 'hp' => 280, 'atk' => 250, 'def' => 205, 'exp' => 1640, 'gold' => 547, 'immune' => 0], + ['name' => 'Behemoth', 'level' => 48, 'hp' => 285, 'atk' => 260, 'def' => 210, 'exp' => 1700, 'gold' => 567, 'immune' => 0], + ['name' => 'Demagogue', 'level' => 48, 'hp' => 290, 'atk' => 260, 'def' => 210, 'exp' => 1760, 'gold' => 587, 'immune' => 0], + ['name' => 'Demon Lord', 'level' => 48, 'hp' => 300, 'atk' => 270, 'def' => 220, 'exp' => 1820, 'gold' => 607, 'immune' => 0], + ['name' => 'Red Daemon', 'level' => 48, 'hp' => 310, 'atk' => 280, 'def' => 230, 'exp' => 1880, 'gold' => 627, 'immune' => 0], + ['name' => 'Colossus', 'level' => 49, 'hp' => 320, 'atk' => 300, 'def' => 240, 'exp' => 1940, 'gold' => 647, 'immune' => 0], + ['name' => 'Demon King', 'level' => 49, 'hp' => 330, 'atk' => 300, 'def' => 250, 'exp' => 2000, 'gold' => 667, 'immune' => 0], + ['name' => 'Dark Daemon', 'level' => 49, 'hp' => 340, 'atk' => 320, 'def' => 260, 'exp' => 2200, 'gold' => 733, 'immune' => 1], + ['name' => 'Titan', 'level' => 50, 'hp' => 360, 'atk' => 340, 'def' => 270, 'exp' => 2400, 'gold' => 800, 'immune' => 0], + ['name' => 'Black Daemon', 'level' => 50, 'hp' => 400, 'atk' => 400, 'def' => 280, 'exp' => 3000, 'gold' => 1000, 'immune' => 1], + ['name' => 'Lucifuge', 'level' => 50, 'hp' => 600, 'atk' => 600, 'def' => 400, 'exp' => 10000, 'gold' => 10000, 'immune' => 2], + ]); + } + + // Create News table + $db->table('news')->create([ + 'id INTEGER PRIMARY KEY', + 'posted DATETIME DEFAULT CURRENT_TIMESTAMP', + 'author INTEGER DEFAULT 1', + "title TEXT DEFAULT ''", + "content TEXT DEFAULT ''" + ]); + + // Create Spells table + $db->table('spells')->create([ + 'id INTEGER PRIMARY KEY', + 'name TEXT NOT NULL', + 'type INTEGER DEFAULT 1', + 'mp INTEGER DEFAULT 0', + "effect TEXT DEFAULT ''", + "icon TEXT DEFAULT ''" + ]); + + // Fill spells if complete install + if ($complete) { + $db->table('spells')->insert([ + // Type 1 = healing + ['name' => 'Heal', 'type' => 1, 'mp' => 5, 'effect' => 'heal:self,10', 'icon' => 'heal.png' ], + ['name' => 'Cure', 'type' => 1, 'mp' => 10, 'effect' => 'heal:self,25', 'icon' => 'cure.png' ], + ['name' => 'Breath', 'type' => 1, 'mp' => 25, 'effect' => 'heal:self,50', 'icon' => 'breath.png'], + ['name' => 'Revive', 'type' => 1, 'mp' => 50, 'effect' => 'heal:self,100', 'icon' => 'revive.png'], + ['name' => 'Gaia', 'type' => 1, 'mp' => 75, 'effect' => 'heal:self,150', 'icon' => 'gaia.png' ], + + // Type 2 = damage + ['name' => 'Slash', 'type' => 2, 'mp' => 5, 'effect' => 'damage:opp,10', 'icon' => 'slash.png' ], + ['name' => 'Magic Missile', 'type' => 2, 'mp' => 12, 'effect' => 'damage:opp,35', 'icon' => 'missile.png' ], + ['name' => 'Fireball', 'type' => 2, 'mp' => 25, 'effect' => 'damage:opp,70', 'icon' => 'fireball.png' ], + ['name' => 'Pain', 'type' => 2, 'mp' => 40, 'effect' => 'damage:opp,100', 'icon' => 'pain.png' ], + ['name' => 'Lightning', 'type' => 2, 'mp' => 50, 'effect' => 'damage:opp,130', 'icon' => 'lightning.png'], + ['name' => 'Chaos', 'type' => 2, 'mp' => 75, 'effect' => 'damage:opp,200', 'icon' => 'chaos.png' ], + + // Type 3 = sleep + ['name' => 'Sleep', 'type' => 3, 'mp' => 10, 'effect' => 'sleep:opp,3', 'icon' => 'sleep.png' ], + ['name' => 'Dream', 'type' => 3, 'mp' => 30, 'effect' => 'sleep:opp,6', 'icon' => 'dream.png' ], + ['name' => 'Nightmare', 'type' => 3, 'mp' => 60, 'effect' => 'sleep:opp,13', 'icon' => 'nightmare.png'], + + // Type 4 = rage + ['name' => 'Craze', 'type' => 4, 'mp' => 10, 'effect' => 'rage:self,3', 'icon' => 'craze.png'], + ['name' => 'Rage', 'type' => 4, 'mp' => 30, 'effect' => 'rage:self,6', 'icon' => 'rage.png' ], + ['name' => 'Fury', 'type' => 4, 'mp' => 60, 'effect' => 'rage:self,13', 'icon' => 'fury.png' ], + + // Type 5 = protect + ['name' => 'Ward', 'type' => 5, 'mp' => 10, 'effect' => 'protect:self,3', 'icon' => 'ward.png' ], + ['name' => 'Guard', 'type' => 5, 'mp' => 30, 'effect' => 'protect:self,6', 'icon' => 'guard.png' ], + ['name' => 'Barrier', 'type' => 5, 'mp' => 60, 'effect' => 'protect:self,13', 'icon' => 'barrier.png'], + ]); + } + + // Create Towns table + $db->table('towns')->create([ + 'id INTEGER PRIMARY KEY', + 'name TEXT NOT NULL', + 'x INTEGER DEFAULT 0', + 'y INTEGER DEFAULT 0', + 'inn_cost INTEGER DEFAULT 0', + 'map_cost INTEGER DEFAULT 5', + 'tp_cost INTEGER DEFAULT 0', + "shop_list TEXT DEFAULT ''", + "image TEXT DEFAULT ''", + ]); + + // Fill towns table if complete install + if ($complete) { + $db->insert([ + ['name' => 'Midworld', 'x' => 0, 'y' => 0, 'inn_cost' => 5, 'map_cost' => 5, 'tp_cost' => 0, 'shop_list' => '1,2,3,17,18,19,28,29', 'image' => 'midworld.png'], + ['name' => 'Roma', 'x' => 30, 'y' => 30, 'inn_cost' => 10, 'map_cost' => 25, 'tp_cost' => 5, 'shop_list' => '2,3,4,18,19,29', 'image' => 'roma.png' ], + ['name' => 'Bris', 'x' => 70, 'y' => -70, 'inn_cost' => 25, 'map_cost' => 50, 'tp_cost' => 15, 'shop_list' => '2,3,4,5,18,19,20,29,30', 'image' => 'bris.png' ], + ['name' => 'Kalle', 'x' => -100, 'y' => 100, 'inn_cost' => 40, 'map_cost' => 100, 'tp_cost' => 30, 'shop_list' => '5,6,8,10,12,21,22,23,29,30', 'image' => 'kalle.png' ], + ['name' => 'Narcissa', 'x' => -130, 'y' => -130, 'inn_cost' => 60, 'map_cost' => 500, 'tp_cost' => 50, 'shop_list' => '4,7,9,11,13,21,22,23,29,30,31', 'image' => 'narcissa.png'], + ['name' => 'Hambry', 'x' => 170, 'y' => 170, 'inn_cost' => 90, 'map_cost' => 1000, 'tp_cost' => 80, 'shop_list' => '10,11,12,13,14,23,24,30,31', 'image' => 'hambry.png' ], + ['name' => 'Gilead', 'x' => 200, 'y' => -200, 'inn_cost' => 100, 'map_cost' => 3000, 'tp_cost' => 110,'shop_list' => '12,13,14,15,24,25,26,32', 'image' => 'gilead.png' ], + ['name' => 'Endworld', 'x' => -250, 'y' => -250, 'inn_cost' => 150, 'map_cost' => 9000, 'tp_cost' => 160,'shop_list' => '16,27,33', 'image' => 'endworld.png'], + ]); + } + + // Create Users table + $db->table('users')->create([ + 'id INTEGER PRIMARY KEY', + 'username TEXT NOT NULL', + 'password TEXT NOT NULL', + "email TEXT DEFAULT ''", + 'verified INTEGER DEFAULT 1', + 'registered DATETIME DEFAULT CURRENT_TIMESTAMP', + 'last_online DATETIME DEFAULT CURRENT_TIMESTAMP', + 'currently INTEGER DEFAULT 0', + 'role INTEGER DEFAULT 1', + 'class INTEGER DEFAULT 1', + 'level INTEGER DEFAULT 1', + 'exp INTEGER DEFAULT 0', + 'gold INTEGER DEFAULT 0', + 'hp INTEGER DEFAULT 0', + 'max_hp INTEGER DEFAULT 0', + 'mp INTEGER DEFAULT 0', + 'max_mp INTEGER DEFAULT 0', + 'tp INTEGER DEFAULT 0', + 'max_tp INTEGER DEFAULT 0', + 'str INTEGER DEFAULT 0', + 'atk INTEGER DEFAULT 0', + 'dex INTEGER DEFAULT 0', + 'def INTEGER DEFAULT 0', + 'weapon_id INTEGER DEFAULT 0', + 'armor_id INTEGER DEFAULT 0', + 'shield_id INTEGER DEFAULT 0', + 'slot_1_id INTEGER DEFAULT 0', + 'slot_2_id INTEGER DEFAULT 0', + 'slot_3_id INTEGER DEFAULT 0', + "spells TEXT DEFAULT ''", + "maps TEXT DEFAULT ''", + ]); + + // Create Fights table + $db->table('fights')->create([ + 'id INTEGER PRIMARY KEY', + 'user_id INTEGER DEFAULT 1', + 'monster_id INTEGER DEFAULT 1', + 'turn INTEGER DEFAULT 1', + 'user_hp INTEGER DEFAULT 0', + 'user_mp INTEGER DEFAULT 0', + 'monster_hp INTEGER DEFAULT 0', + 'monster_mp INTEGER DEFAULT 0', + 'user_uber_dmg INTEGER DEFAULT 0', + 'monster_uber_dmg INTEGER DEFAULT 0', + 'user_uber_def INTEGER DEFAULT 0', + 'monster_uber_def INTEGER DEFAULT 0', + 'monster_immune INTEGER DEFAULT 0', + 'monster_sleep INTEGER DEFAULT 0', + ]); + + echo render('install/layout', ['title' => 'Database', 'step' => 'second', 'complete' => $complete]); + exit; +} diff --git a/server/bootstrap.php b/server/bootstrap.php new file mode 100644 index 0000000..8b54b52 --- /dev/null +++ b/server/bootstrap.php @@ -0,0 +1,15 @@ + [], + 'order' => [], + 'limit' => 0, + 'values' => [], + ]; + + /** + * Open a connection to the database. + */ + public function __construct(string $path, array $opts = []) + { + $opts = !empty($opts) ? $opts : [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + ]; + + try { + $this->c = new PDO("sqlite:$path", null, null, $opts); + $this->c->exec('PRAGMA foreign_keys = ON;'); // Enable foreign keys + $this->c->exec('PRAGMA journal_mode = WAL;'); // Enable WAL + } catch (PDOException $e) { + $this->error = "Failed to open database: " . $e->getMessage(); + throw $e; + } + } + + /** + * Change the current working table. + */ + public function table(string $name): Database + { + $this->table = $name; + return $this; + } + + /** + * Create a table with the name of the current working table. Will drop + * the table if it already exists. + */ + public function create(array $columns): PDOStatement|false + { + $query = "CREATE TABLE IF NOT EXISTS $this->table (" . implode(', ', $columns) . ');'; + $this->addToLog($query); + return $this->c->query($query); + } + + /** + * Drop the current working table if it exists. + */ + public function drop(): PDOStatement|false + { + $query = "DROP TABLE IF EXISTS $this->table;"; + $this->addToLog($query); + return $this->c->query($query); + } + + /** + * Return the current working table's schema. + */ + public function schema(): array + { + $query = "PRAGMA table_info($this->table);"; + $this->addToLog($query); + return $this->c->query($query)->fetchAll(PDO::FETCH_ASSOC); + } + + /** + * Insert data into the current working table. Pass an array of key/value + * pairs to insert one record, or an array of arrays to insert multiple. Returns + * the number of rows inserted, or false on failure. + */ + public function insert(array $data): int|false + { + // If the first element is not an array we can assume we're doing a single insert. + if (!isset($data[0])) { + $query = "INSERT INTO $this->table (" . implode(', ', array_keys($data)) . ')' + . ' VALUES (' . implode(', ', array_fill(0, count($data), '?')) . ');'; + $this->addToLog($query); + return $this->c->prepare($query)->execute(array_values($data)); + } + + // Otherwise we will build a multi-insert query. + $query = "INSERT INTO $this->table (" . implode(', ', array_keys($data[0])) . ') VALUES '; + $placeholders = []; + $values = []; + + foreach ($data as $row) { + $placeholders[] = '(' . implode(', ', array_fill(0, count($row), '?')) . ')'; + foreach ($row as $value) $values[] = $value; + } + + $query .= implode(', ', $placeholders) . ';'; + + $this->addToLog($query); + return $this->c->prepare($query)->execute($values); + } + + /** + * Insert a default record into the current working table. + */ + public function insertDefaultValues(): int|false + { + $query = "INSERT INTO $this->table DEFAULT VALUES;"; + $this->addToLog($query); + return $this->c->prepare($query)->execute(); + } + + /** + * Add a where clause to the builder. All values are paramaterized. + */ + public function where(string $column, string $operator, mixed $value): Database + { + $this->builder['where'][] = "$column $operator ?"; + $this->builder['values'][] = $value; + return $this; + } + + /** + * Add an order clause to the builder. + */ + public function order(string $column, string $direction = 'ASC'): Database + { + $this->builder['order'] = "$column $direction"; + return $this; + } + + /** + * Set a limit in the builder. + */ + public function limit(int $limit): Database + { + $this->builder['limit'] = $limit; + return $this; + } + + /** + * Build a select query and return the result. By default selects the entire + * row. Optionally use fetchAll, but there is also the selectAll() alias method + * for this. + */ + public function select(string $what = '*', bool $fetchAll = false): array|false + { + $query = "SELECT $what FROM $this->table"; + if (!empty($this->builder['where'])) $query .= " WHERE " . implode(' AND ', $this->builder['where']); + if (!empty($this->builder['order'])) $query .= " ORDER BY " . $this->builder['order']; + if (!empty($this->builder['limit'])) $query .= " LIMIT " . $this->builder['limit']; + + $this->addToLog($query); + + try { + $stmt = $this->c->prepare($query); + $stmt->execute($this->builder['values']); + } catch (PDOException $e) { + $this->error = "Failed to execute query: " . $e->getMessage(); + return false; + } + + $this->resetBuilder(); + return $fetchAll ? $stmt->fetchAll() : $stmt->fetch(); + } + + /** + * Delete records from the current working table. Returns the number of rows + * deleted, or false on failure. Uses where clauses if set. + */ + public function delete(): int|false + { + $query = "DELETE FROM $this->table"; + if (!empty($this->builder['where'])) $query .= " WHERE " . implode(' AND ', $this->builder['where']); + $this->addToLog($query); + + $this->resetBuilder(); + return $this->c->exec($query); + } + + /** + * Update records in the current working table. Returns the number of rows + * updated, or false on failure. Uses where clauses if set. + */ + public function update(array $data): int|false + { + $query = "UPDATE $this->table SET " . implode(', ', array_keys($data)) . ' = ?'; + if (!empty($this->builder['where'])) $query .= " WHERE " . implode(' AND ', $this->builder['where']); + $this->addToLog($query); + + $values = array_merge(array_values($data), $this->builder['values']); + + $this->resetBuilder(); + return $this->c->prepare($query)->execute($values); + } + + /** + * Get the number of rows in the current working table. Can use where clauses. + */ + public function count(): int|false + { + return $this->select('COUNT(*)', true)[0]['COUNT(*)']; + } + + /** + * Alias for $db->select(true) + */ + public function selectAll(string $what = '*'): array|false + { + return $this->select($what, true); + } + + /** + * Return whether the given table exists. + */ + public function tableExists(string $name): bool + { + $query = "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='$name';"; + $this->addToLog($query); + return $this->c->query($query)->fetchColumn() > 0; + } + + /** + * Return the PDO instance; for when more complex operations are needed. + */ + public function c(): PDO + { + return $this->c; + } + + /** + * Alias for PDO::prepare + */ + public function prepare(string $query): PDOStatement + { + return $this->c->prepare($query); + } + + /** + * Alias for PDO::lastInsertId + */ + public function lastInsertId(): int + { + return $this->c->lastInsertId(); + } + + /** + * Alias for PDO::exec + */ + public function exec(string $query): int + { + $this->addToLog($query); + return $this->c->exec($query); + } + + /** + * Alias for PDO::beginTransaction + */ + public function begin(): bool + { + return $this->c->beginTransaction(); + } + + /** + * Alias for PDO::commit + */ + public function commit(): bool + { + return $this->c->commit(); + } + + /** + * Alias for PDO::rollBack + */ + public function rollBack(): bool + { + return $this->c->rollBack(); + } + + /** + * Alias for PDO::query + */ + public function query(string $query): PDOStatement|false + { + $this->addToLog($query); + return $this->c->query($query); + } + + /** + * Add the query to the log and increment the number of queries executed. + */ + private function addToLog(string $query): void + { + $this->log[] = $query; + $this->queries++; + } + + /** + * Reset the builder to it's default structure. + */ + public function resetBuilder(): void + { + $this->builder = [ + 'where' => [], + 'order' => [], + 'limit' => 0, + 'values' => [], + ]; + } + + /** + * Return the log of executed queries. + */ + public function log(): array + { + return $this->log; + } + + /** + * Return the number of queries executed. + */ + public function queries(): int + { + return $this->queries; + } + + /** + * Return the last error message. + */ + public function error(): string + { + return $this->error; + } +} \ No newline at end of file diff --git a/server/database/README.md b/server/database/README.md new file mode 100644 index 0000000..62eb5f8 --- /dev/null +++ b/server/database/README.md @@ -0,0 +1,4 @@ +## /server/database +This README is here to allow git to keep this folder present in the repo. +The SQLite database for the game is generated into this folder, and PDO +will not create the path TO the SQLite database. \ No newline at end of file diff --git a/server/database/dragon.db b/server/database/dragon.db new file mode 100644 index 0000000..68ac8c5 Binary files /dev/null and b/server/database/dragon.db differ diff --git a/lib.php b/server/lib.php similarity index 87% rename from lib.php rename to server/lib.php index 32af9f5..e223f25 100644 --- a/lib.php +++ b/server/lib.php @@ -1,72 +1,35 @@ + Installation for Dragon Knight is a simple two-step process: + set up the database tables, then create the admin user. After + that, you're done. +

+ +

+ You have two options for database setup: complete or partial. + +

+

+ +

+ Click the appropriate button below for your preferred installation method. +

+ + - OR -
+ +
+

diff --git a/server/templates/install/layout.php b/server/templates/install/layout.php new file mode 100644 index 0000000..075c3be --- /dev/null +++ b/server/templates/install/layout.php @@ -0,0 +1,16 @@ + + + + + + <?= $title ?> | Installer + + + +
+

Dragon Knight Installation

+

+ +
+ + \ No newline at end of file diff --git a/server/templates/install/second.php b/server/templates/install/second.php new file mode 100644 index 0000000..c48eaa9 --- /dev/null +++ b/server/templates/install/second.php @@ -0,0 +1,52 @@ +

+ If you're seeing this page with no errors, then database setup is complete! +

+ + +

+ You chose a complete install, so the database has been filled with all sorts of + cool starting data! Items, drops, monsters, towns, weapons, armor, et cetera. +

+ +

+ You chose a partial install, so the database has been left empty. The onus is now + on you to fill it up with all your awesome ideas! +

+ + +

+ The next step is to create the admin account you'll run the game from. Do so + below. Since your install was partial, you can't choose + a class here. Once you make some classes, you can assign yourself one in the admin + panel. +

+ +
+
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+ + +
+ + + +
diff --git a/templates/leftnav.php b/server/templates/leftnav.php similarity index 100% rename from templates/leftnav.php rename to server/templates/leftnav.php diff --git a/templates/login.php b/server/templates/login.php similarity index 100% rename from templates/login.php rename to server/templates/login.php diff --git a/templates/lostpassword.php b/server/templates/lostpassword.php similarity index 100% rename from templates/lostpassword.php rename to server/templates/lostpassword.php diff --git a/templates/minimal.php b/server/templates/minimal.php similarity index 100% rename from templates/minimal.php rename to server/templates/minimal.php diff --git a/templates/onlinechar.php b/server/templates/onlinechar.php similarity index 100% rename from templates/onlinechar.php rename to server/templates/onlinechar.php diff --git a/templates/primary.php b/server/templates/primary.php similarity index 100% rename from templates/primary.php rename to server/templates/primary.php diff --git a/templates/register.php b/server/templates/register.php similarity index 100% rename from templates/register.php rename to server/templates/register.php diff --git a/templates/rightnav.php b/server/templates/rightnav.php similarity index 100% rename from templates/rightnav.php rename to server/templates/rightnav.php diff --git a/templates/showchar.php b/server/templates/showchar.php similarity index 100% rename from templates/showchar.php rename to server/templates/showchar.php diff --git a/templates/towns.php b/server/templates/towns.php similarity index 100% rename from templates/towns.php rename to server/templates/towns.php diff --git a/templates/verify.php b/server/templates/verify.php similarity index 100% rename from templates/verify.php rename to server/templates/verify.php