Jump to content
MakeWebGames

Magictallguy

Administrators
  • Posts

    2,130
  • Joined

  • Last visited

  • Days Won

    145

Everything posted by Magictallguy

  1. As much as I would like to, I wasn't sure on just how far away from MCCv2's "origins" we wanted to pull it. So this PR is primarily PHP8-compliance (and a minor optimisation to the viewuser->staff->gethostbyaddr calls) Huh, second time I've heard that project today - and nope, but I'm curious to see what that would chuck back. Little bits, here and there. There's much more I'd like to do, but again, I don't want to pull it too far away from what it was (without community approval, at least) -- Edit: On a related note, I did write up a docker-compose.yml - runs OOTB with `docker compose up` (with optional -d flag to detach) - if we want to be able to dockerize it (great for dev *cough cough*)
  2. Done. PR sent. PR set as draft while I run tests. PR re-sent!
  3. I sure do - Orsokuma
  4. Without wanting to seem like I'm fanning the flames here; Ali, you've been posting in this topic with updates to the engine as you've gone along and responded to people posting here too. Does that not imply you've been checking as you go along? I can certainly understand the convenience of instant messaging platforms as I much prefer them myself. That being said, I've found public transparency to be useful. Not only does it allow people to read the answers to questions already asked (which might include their own), it also shows you're actively engaging the people using your stuff. Uridium raises a valid point. This is your own project-based thread in a programming-oriented forum, it makes perfect sense to talk about your project here
  5. This implies you've entered the wrong connection details. Hi, I'm one of the guys who wrote it πŸ™‚
  6. Det hΓΈres ut som et "du"-problem kekekek
  7. You previously have successfully installed this mod. The error message you're getting, in this context, means that there isn't a match in your switch() statement You've probably seen something like this.. switch ($_GET['action']) { case 'something': doSomething(); break; case 'else': doSomethingElse(); break; default: echo 'Error, this script requires an action.'; break; } ..and in your URL, you've probably seen something like: yoursite.com/staff_users.php?action=example If you're trying to give an "action" that doesn't exist (i.e., isn't in your switch() statement), then you're gonna see that "Error, action required" message. In a nutshell, make sure that whatever you're clicking on your site is going to the right place. Note: GETDATA (in this case, the $_GET['action'] bit) is case-sensitive. I.e., "example" is not a match to "Example".
  8. Based almost entirely on this query INSERT INTO `loan_shark` (ls_id, `ls_userid`, `ls_amount`, `ls_interest`, ls_daily, `ls_remaining`, `ls_time`) VALUES ('', {$ir['userid']}, {$amount}, {$interest}, {$dailyPayment}, {$remaining}, {$time}) and a cursory glance at the rest of the code, I'm throwing a guess at this: CREATE TABLE loan_shark ( ls_id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, ls_userid INT NOT NULL, ls_amount INT NOT NULL DEFAULT 0, ls_daily INT NOT NULL DEFAULT 0, ls_remaining INT NOT NULL DEFAULT 0, ls_time INT NOT NULL DEFAULT 0, FOREIGN KEY (ls_userid) REFERENCES users(userid) );
  9. I'm certainly curious - please feel free to share your experiences. I'd like to learn ^.^
  10. If running on PHP 8.2 and above, you can use null coalescence $userid = $_SESSION['switch_to'] ?? $_SESSION['userid'];
  11. Welcome (back) to MWG! There's definitely still a love for the various styles of games found here on this site, along with programmers of varying degrees itching to get into projects. We will never die! πŸ˜„
  12. Quick tip for ya; if you need to dynamically resize an image on output, but want to keep its aspect ratio, avoid using the deprecated height and width attributes. Instead, a little CSS goes a long way. .panel-image { max-width: 150px; max-height: 100px; } <img src="{pic}" alt="A basic image title" class="panel-image"> Alternatively, you can inline the styling <img src="{pic}" alt="A basic title" style="max-width: 150px; max-height: 100px;">
  13. Ooh, I'm in!
  14. Soooo, I had some free time and wrote this. It clocks in at 1,149 lines, and combines 9 files (imadd, inventory, itembuy, iteminfo, itemsell, itemsend, itemuse, equip, unequip) into 1. It's PHP 7.4-compatible. <?php declare(strict_types=1); /** * For use on MCCodes Version 2.0.5b * We shouldn't just redistribute licensed software, so here's a rewrite ;) * I do *not* claim this to be efficient or better than the original, it's just a different take on things * The length and calculable complexity of this class is ugly. I would recommend splitting this into extendable classes and consider autoloading * * See the ItemHandler constants for configurable text outputs */ global $db, $ir, $h; require_once __DIR__ . '/globals.php'; ?> <!-- Remove this if you're using Bootstrap. I just like the naming scheme --> <!--suppress CssUnusedSymbol --> <style> .text-end { text-align: end; } .form-group { display: block; padding: 5px 0; } .text-danger { color: #f00; } .text-success { color: #050; } .table-responsive { min-height: 20vh; max-height: 99.9vh; min-width: 20vh; max-width: 99.9vh; overflow: auto; } .btn { margin: 0.75vh 1vw; padding: 0.5vh 1vw; } .btn-primary { color: #fff; background-color: #337ab7; border-color: #2e6da4; border-radius: 5%; } .alert { display: block; height: auto; line-height: 1em; max-width: 50%; padding: 0.6vh 3vw; margin: 0.5vh 1vw; border-radius: 5%; } .alert-danger { color: #a94442; background-color: #f2dede; border-color: #ebccd1; } .alert-success { color: #3c763d; background-color: #dff0d8; border-color: #d6e9c6; } .alert-info { color: #31708f; background-color: #d9edf7; border-color: #bce8f1; } .alert .alert-links { margin-top: 1.1em; } .alert .alert-title { display: block; font-weight: 700; font-size: 1.125em; line-height: 1em; margin-bottom: 0.2vh; } </style> <?php /** * ItemHandler * all-in-one class for imadd, inventory, itembuy, iteminfo, itemsell, itemsend, itemuse, equip, unequip */ class ItemHandler { // Don't touch these private database $db; private array $ir; private headers $headers; private ?string $action; private ?int $id; // Do touch these! private const SECURITY_TIMEOUT = 'Your request has timed out for security reasons'; private const NO_INVENTORY = 'You don\'t have any items in your inventory'; private const INVALID_ITEM = 'You didn\'t select a valid item'; private const INVALID_QUANTITY = 'You didn\'t enter a valid quantity'; private const INVALID_EQUIP_SLOT = 'You didn\'t provide a valid equipment slot'; private const INVALID_PRICE = 'You didn\'t enter a valid price'; private const INVALID_CURRENCY = 'You didn\'t selected a valid currency'; private const INVALID_USER = 'You didn\'t select a valid user'; private const USER_NOT_EXISTS = 'Your intended recipient doesn\'t exist'; private const ITEM_NOT_EXISTS = 'The item you selected doesn\'t exist'; private const EQUIP_NOT_EXISTS = 'You don\'t have that item equipped'; private const ITEM_NOT_BUYABLE = 'You can\'t buy that item'; private const ITEM_NOT_EQUIPPABLE = 'You can\'t equip that item'; private const ITEM_NOT_USABLE = 'You can\'t use that item'; private const INSUFFICIENT_FUNDS = 'You don\'t have enough money'; private const NOT_ENOUGH_ITEMS = 'You don\'t have enough of those'; private const WORTHLESS_ITEMS = 'You can\'t sell worthless items'; private const TRANSFER_NOT_PERMITTED = 'You can\'t transfer items to that player'; private const SELF_TRANSFER_NOT_PERMITTED = 'You can\'t transfer items to yourself'; private const ITEM_PLAYER_LOCATION_MISMATCH = 'You can\'t buy items from other locations'; private const ITEM_ADDED_TO_MARKET = 'You\'ve added %sx %s to the item market for %s'; private const ITEM_PURCHASED = 'You bought %sx %s for %s'; private const ITEM_SOLD = 'You sold %sx %s for %s'; private const ITEM_TRANSFERRED = 'You sent %sx %s to %s'; private const ITEM_USED = 'You used %s'; /** * true: prevents the player from selling items if the sell value is 0 * false: allows the player to use the sell items as a trashing function; permitting sales of items regardless of sell value * @var bool preventWorthlessSales */ private bool $preventWorthlessSales = false; private string $table_users_stats = 'userstats'; private string $table_users = 'users'; private array $bar_cols = ['energy', 'will', 'brave', 'hp']; private array $stat_cols = ['strength', 'agility', 'guard', 'labour', 'IQ']; private array $currencies = ['money', 'crystals']; private array $equipSlots = ['equip_primary', 'equip_secondary', 'equip_armor']; /** * @param database $db * @param array $ir * @param headers $h * @param string|null $action * @param int|null $id */ public function __construct(database $db, array $ir, headers $h, ?string $action = null, ?int $id = null) { $this->db = $db; $this->ir = $ir; $this->headers = $h; $this->action = $action; $this->id = $id; } /** * @return void */ public function run() { switch ($this->action) { case 'buy': $this->itemPurchase(); break; case 'info': $this->itemInfo(); break; case 'sell': $this->itemSell(); break; case 'send': $this->itemSend(); break; case 'use': $this->itemUse(); break; case 'market-add': $this->itemMarketAdd(); break; case 'unequip': $this->doItemUnequip(); break; case 'equip': $this->itemEquip(); break; default: $this->inventory(); break; } } /** * @return array */ private function getEquippedItems(): array { $items = []; // Maps the equipSlots to the user's equipped items, removes 0 values and duplicates $equipped_ids = array_unique(array_filter(array_map(function ($slot) { return $this->ir[$slot]; }, $this->equipSlots))); if (!empty($equipped_ids)) { $get_items = $this->db->query( 'SELECT itmid, itmname FROM items WHERE itmid IN (' . implode(', ', $equipped_ids) . ')', ); while ($row = $this->db->fetch_row($get_items)) { $items[$row['itmid']] = $row['itmname']; } $this->db->free_result($get_items); } return $items; } /** * @param array $row * @return bool */ private function hasEffect(array $row): bool { return $row['effect1_on'] || $row['effect2_on'] || $row['effect3_on']; } // ----------------------------------------- /** * @param array $equip * @return void */ private function renderEquips(array $equip): void { $slots = [ 'primary' => $equip[$this->ir['equip_primary']] ?? '', 'secondary' => $equip[$this->ir['equip_secondary']] ?? '', 'armor' => $equip[$this->ir['equip_armor']] ?? '', ]; $code = request_csrf_code('verf'); ?> <div class="table-responsive"> <table class="table"> <?php foreach ($slots as $slot => $item) { ?> <tr> <th scope="row"><?php echo $slot === 'armor' ? 'Armor' : ucfirst($slot) . ' Weapon'; ?></th> <?php if (!empty($item)) { $slot_col = 'equip_' . $slot; ?> <td><?php echo $item; ?></td> <td><a href="/inventory.php?action=unequip&type=<?php echo $slot_col; ?>&id=<?php echo $this->ir[$slot_col]; ?>&verf=<?php echo $code; ?>">Unequip Item</a></td> <?php } else { ?> <td>None equipped.</td> <td>&nbsp;</td> <?php } ?> </tr> <?php } ?> </table> </div> <hr> <?php } /** * @return void */ private function renderInventory(): void { $get_inventory = $this->db->query( 'SELECT inv.inv_id, inv.inv_qty, i.itmid, i.itmname, i.itmsellprice, i.effect1_on, i.effect2_on, i.effect3_on, i.weapon, i.armor, it.itmtypename FROM inventory AS inv INNER JOIN items AS i ON inv.inv_itemid = i.itmid INNER JOIN itemtypes AS it ON it.itmtypeid = i.itmtype WHERE inv.inv_userid = ' . $this->ir['userid'] . ' ORDER BY i.itmtype, i.itmname' ); if (!$this->db->num_rows($get_inventory)) { $this->alert('info', self::NO_INVENTORY); } $code = request_csrf_code('verf'); ?> <h3>Inventory</h3> <div class="table-responsive"> <table class="table"> <thead> <tr> <th scope="col">Item</th> <th scope="col">Sell Value</th> <th scope="col">Total Sell Value</th> <th scope="col">Links</th> </tr> </thead> <tbody> <?php $last_type = ''; $total_inventory_value = 0; while ($row = $this->db->fetch_row($get_inventory)) { $total_inventory_value += $row['itmsellprice'] * $row['inv_qty']; if ($last_type !== $row['itmtypename']) { $last_type = $row['itmtypename']; ?> <tr> <td colspan="4"> <strong><?php echo $last_type; ?></strong> </td> </tr> <?php } $prefix = ''; if ($row['weapon'] > 0) { $prefix .= '<span class="text-danger">*</span>'; } if ($row['armor'] > 0) { $prefix .= '<span class="text-success">*</span>'; } ?> <tr> <td><?php echo $prefix . $row['itmname'] . ($row['inv_qty'] > 1 ? ' x' . number_format((int)$row['inv_qty']) : ''); ?></td> <td><?php echo money_formatter($row['itmsellprice']); ?></td> <td><?php echo money_formatter($row['itmsellprice'] * $row['inv_qty']); ?></td> <td> [<a href="inventory.php?action=info&id=<?php echo $row['itmid']; ?>">Info</a>] [<a href="inventory.php?action=send&id=<?php echo $row['inv_id']; ?>">Send</a>] [<a href="inventory.php?action=sell&id=<?php echo $row['inv_id']; ?>">Sell</a>] [<a href="inventory.php?action=market-add&id=<?php echo $row['inv_id']; ?>">Add To Market</a>] <?php if ($this->hasEffect($row)) { ?> [<a href="inventory.php?action=use&id=<?php echo $row['inv_id']; ?>">Use</a>] <?php } if ($row['weapon'] > 0) { ?> [<a href="inventory.php?action=equip&id=<?php echo $row['inv_id']; ?>&verf=<?php echo $code; ?>&type=weapon">Equip as Weapon</a>] <?php } if ($row['armor'] > 0) { ?> [<a href="inventory.php?action=equip&id=<?php echo $row['inv_id']; ?>&verf=<?php echo $code; ?>&type=armor">Equip as Armor</a>] <?php } ?> </td> </tr> <?php } ?> <tr> <td colspan="4">&nbsp;</td> </tr> <tr> <td colspan="4" class="text-end"> <strong>Total Inventory Value:</strong> <?php echo money_formatter($total_inventory_value); ?> </td> </tr> </tbody> </table> </div> <p> <small><strong>NB:</strong> Items with a small red </small><span class="text-danger">*</span><small> next to their name can be used as weapons in combat.</small><br> <small>Items with a small green </small><span class="text-success">*</span><small> next to their name can be used as armor in combat.</small> </p> <?php $this->db->free_result($get_inventory); } /** * @return void */ private function inventory() { $this->renderEquips($this->getEquippedItems()); $this->renderInventory(); } // ----------------------------------------- /** * @param array $row * @return void */ private function renderItemInfo(array $row): void { ?> <h3>Item Information</h3> <table class="table" style="width: 75%;"> <thead> <tr> <th colspan="2" style="font-weight: 700;"> Looking up info on <?php echo $row['itmname']; ?> </th> </tr> </thead> <tbody> <tr> <td colspan="2"> The <?php echo $row['itmname']; ?> is <?php echo $this->aAn($row['itmtypename']); ?> Item<br> <p> <?php echo $row['itmdesc']; ?> </p> </td> </tr> </tbody> <thead> <tr> <th colspan="2">Item Info</th> </tr> <tr> <th scope="col">Item Buy Price</th> <th scope="col">Item Sell Price</th> </tr> </thead> <tbody> <tr> <td><?php echo $row['itmbuyprice'] > 0 ? money_formatter($row['itmbuyprice']) : 'N/A'; ?></td> <td><?php echo $row['itmsellprice'] > 0 ? money_formatter($row['itmsellprice']) : 'N/A'; ?></td> </tr> </tbody> </table> <p> <a href="inventory.php">Back to Inventory</a> </p> <?php } /** * @return void */ private function itemInfo(): void { if (!$this->id) { $this->alert('error', self::INVALID_ITEM); } $get_item = $this->db->query( 'SELECT i.itmid, i.itmname, i.itmdesc, i.itmbuyprice, i.itmsellprice, it.itmtypename FROM items AS i INNER JOIN itemtypes AS it ON it.itmtypeid = i.itmtype WHERE i.itmid = ' . $this->id . ' LIMIT 1' ); if (!$this->db->num_rows($get_item)) { $this->alert('error', self::ITEM_NOT_EXISTS); } $row = $this->db->fetch_row($get_item); $this->db->free_result($get_item); $this->renderItemInfo($row); } // ----------------------------------------- /** * @param array $row * @return void */ private function renderItemSell(array $row): void { $code = request_csrf_code('sell_item_' . $row['inv_id']); ?> <h3>Sell Item</h3> <p> Enter the amount of <?php echo $this->pluralize($row['itmname'], 0); ?> you want to sell. You have <strong><?php echo $row['inv_qty']; ?></strong>.<br> <?php if ($row['inv_qty'] > 1) { ?> Altogether, they are worth <?php echo money_formatter($row['inv_qty'] * $row['itmsellprice']); ?>.<br> <?php } ?> <span class="text-italic">Note: There is no confirmation. Be sure you've entered the amount you want to sell.</span> </p> <form action="inventory.php?action=sell&id=<?php echo $row['inv_id']; ?>" method="post"> <input type="hidden" name="verf" value="<?php echo $code; ?>" /> <div class="form-group"> <label for="qty">Quantity</label> <input type="number" name="qty" id="qty" class="form-control" placeholder="0" required> </div> <button type="submit" class="btn btn-primary"> Sell Items </button> </form> <?php } /** * @param array $row * @return array */ private function doItemSell(array $row): array { $qty = array_key_exists('qty', $_POST) && is_numeric($_POST['qty']) && (int)$_POST['qty'] > 0 ? (int)$_POST['qty'] : null; if (empty($_POST['qty'])) { return [ 'type' => 'error', 'content' => self::INVALID_QUANTITY, ]; } if ($qty > $row['inv_qty']) { return [ 'type' => 'error', 'content' => self::NOT_ENOUGH_ITEMS, ]; } $value = $qty * $row['itmsellprice']; if ($this->preventWorthlessSales && !$value) { return [ 'type' => 'error', 'content' => self::WORTHLESS_ITEMS, ]; } $formatted_value = money_formatter($value); item_remove($this->ir['userid'], $row['itmid'], $qty); $this->db->query( 'UPDATE users SET money = money + ' . $value . ' WHERE userid = ' . $this->ir['userid'] ); // At this point, consider parameterised queries. $this->db->query( sprintf( 'INSERT INTO itemselllogs (isUSER, isITEM, isTOTALPRICE, isQTY, isTIME, isCONTENT) VALUES (%u, %u, %u, %u, %u, \'%s\')', $this->ir['userid'], $row['itmid'], $value, $qty, time(), $this->db->escape($this->ir['username'] . ' sold ' . $qty . ' ' . $this->pluralize($row['itmname'], $qty) . ' for ' . $formatted_value) ) ); return [ 'type' => 'success', 'content' => sprintf(self::ITEM_SOLD, number_format($qty), $this->pluralize($row['itmname'], $qty), $formatted_value), ]; } /** * @return void */ private function itemSell(): void { if (!$this->id) { $this->alert('error', self::INVALID_ITEM); } $get_item = $this->db->query( 'SELECT inv.inv_id, inv.inv_qty, i.itmid, i.itmname, i.itmsellprice FROM inventory AS inv INNER JOIN items AS i ON i.itmid = inv.inv_itemid WHERE inv.inv_id = ' . $this->id . ' AND inv.inv_userid = ' . $this->ir['userid'] . ' LIMIT 1' ); if (!$this->db->num_rows($get_item)) { $this->alert('error', self::ITEM_NOT_EXISTS); } $row = $this->db->fetch_row($get_item); $this->db->free_result($get_item); $response = array_key_exists('verf', $_POST) && verify_csrf_code('sell_item_' . $row['inv_id'], stripslashes($_POST['verf'])) ? $this->doItemSell($row) : null; if (!empty($response)) { $this->alert($response['type'], $response['content']); } $this->renderItemSell($row); } // ----------------------------------------- /** * @return void */ private function itemPurchase(): void { $qty = array_key_exists('qty', $_POST) && is_numeric($_POST['qty']) && (int)$_POST['qty'] > 0 ? (int)$_POST['qty'] : null; if (empty($qty)) { $this->alert('error', self::INVALID_QUANTITY); } if (!$this->id) { $this->alert('error', self::INVALID_ITEM); } $get_item = $this->db->query( 'SELECT s.shopLOCATION, i.itmid, i.itmname, i.itmbuyable, i.itmbuyprice FROM shopitems AS si INNER JOIN shops AS s ON s.shopID = si.sitemSHOP INNER JOIN items AS i ON i.itmid = si.sitemITEMID WHERE si.sitemITEMID = ' . $this->id ); if (!$this->db->num_rows($get_item)) { $this->alert('error', self::ITEM_NOT_EXISTS); } $row = $this->db->fetch_row($get_item); $this->db->free_result($get_item); if (!$row['itmbuyable']) { $this->alert('error', self::ITEM_NOT_BUYABLE); } if ($row['shopLOCATION'] !== $this->ir['location']) { $this->alert('error', self::ITEM_PLAYER_LOCATION_MISMATCH); } $total_value = $qty * (int)$row['itmbuyprice']; if ($total_value > $this->ir['money']) { $this->alert('error', self::INSUFFICIENT_FUNDS); } item_add($this->ir['userid'], $row['itmid'], $qty); $this->db->query( 'UPDATE users SET money = money - ' . $total_value . ' WHERE userid = ' . $this->ir['userid'] ); $this->db->query( sprintf( 'INSERT INTO itembuylogs (ibUSER, ibITEM, ibTOTALPRICE, ibQTY, ibTIME, ibCONTENT) VALUES (%u, %u, %u, %u, %u, \'%s\')', $this->ir['userid'], $row['itmid'], $total_value, $qty, time(), $this->db->escape($this->ir['username'] . ' purchased ' . $qty . ' ' . $this->pluralize($row['itmname'], $qty) . ' for ' . money_formatter($total_value)) ) ); $this->alert('success', sprintf(self::ITEM_PURCHASED, number_format($qty), $this->pluralize($row['itmname'], $qty), money_formatter($total_value))); } // ----------------------------------------- /** * @param array $row * @return string[] */ private function doItemSend(array $row): array { $target_id = array_key_exists('user', $_POST) && is_numeric($_POST['user']) && (int)$_POST['user'] > 0 ? (int)$_POST['user'] : null; $qty = array_key_exists('qty', $_POST) && is_numeric($_POST['qty']) && (int)$_POST['qty'] > 0 ? (int)$_POST['qty'] : null; if ($qty > $row['inv_qty']) { return [ 'type' => 'error', 'content' => self::NOT_ENOUGH_ITEMS ]; } if (empty($target_id)) { return [ 'type' => 'error', 'content' => self::INVALID_USER ]; } if ($target_id === $this->ir['userid']) { return [ 'type' => 'error', 'content' => self::SELF_TRANSFER_NOT_PERMITTED ]; } $get_target = $this->db->query( 'SELECT userid, username, lastip FROM users WHERE userid = ' . $target_id ); if (!$this->db->num_rows($get_target)) { return [ 'type' => 'error', 'content' => self::USER_NOT_EXISTS ]; } $target = $this->db->fetch_row($get_target); $this->db->free_result($get_target); if ($target['lastip'] === $this->ir['lastip']) { return [ 'type' => 'error', 'content' => self::TRANSFER_NOT_PERMITTED ]; } item_remove($this->ir['userid'], $row['itmid'], $qty); item_add($target['userid'], $row['itmid'], $qty); event_add($target['userid'], 'You received ' . number_format($qty) . ' ' . $this->pluralize($row['itmname'], $qty) . ' from ' . $this->ir['username']); $this->db->query( sprintf( 'INSERT INTO itemxferlogs (ixFROM, ixTO, ixITEM, ixQTY, ixTIME, ixFROMIP, ixTOIP) VALUES (%u, %u, %u, %u, %u, \'%s\', \'%s\')', $this->ir['userid'], $target['userid'], $row['itmid'], $qty, time(), $this->ir['lastip'], $target['lastip'] ) ); return [ 'type' => 'success', 'content' => sprintf(self::ITEM_TRANSFERRED, number_format($qty), $this->pluralize($row['itmname'], $qty), $target['username']) ]; } /** * @param array $row * @param int|null $get_target_id * @return void */ private function renderItemSend(array $row, ?int $get_target_id = null): void { $code = request_csrf_code('send_item_' . $row['inv_id']); ?> <h3>Send Item</h3> <p> Enter the amount of <?php echo $this->pluralize($row['itmname'], 0); ?> you want to send. You have <strong><?php echo $row['inv_qty']; ?></strong>.<br> <span class="text-italic">Note: There is no confirmation. Be sure you've entered the amount you want to send.</span> </p> <form action="inventory.php?action=send&id=<?php echo $row['inv_id']; ?>" method="post"> <input type="hidden" name="verf" value="<?php echo $code; ?>" /> <div class="form-group"> <label for="user">User ID:</label> <input type="number" name="user" id="user" class="form-control" placeholder="0" value="<?php echo $get_target_id; ?>" required> </div> <div class="form-group"> <label for="qty">Quantity</label> <input type="number" name="qty" id="qty" class="form-control" placeholder="0" required> </div> <button type="submit" class="btn btn-primary"> Send Items </button> </form> <?php } /** * @return void */ private function itemSend(): void { if (!$this->id) { $this->alert('error', self::INVALID_ITEM); } $get_item = $this->db->query( 'SELECT inv.inv_id, inv.inv_qty, inv.inv_itemid, i.itmid, i.itmname FROM inventory AS inv INNER JOIN items AS i ON inv.inv_itemid = i.itmid WHERE inv.inv_id = ' . $this->id . ' AND inv.inv_userid = ' . $this->ir['userid'] . ' LIMIT 1' ); if (!$this->db->num_rows($get_item)) { $this->alert('error', self::ITEM_NOT_EXISTS); } $row = $this->db->fetch_row($get_item); $this->db->free_result($get_item); $response = array_key_exists('verf', $_POST) && verify_csrf_code('send_item_' . $this->id, stripslashes($_POST['verf'])) ? $this->doItemSend($row) : null; if (!empty($response)) { $this->alert($response['type'], $response['content']); } $get_target_id = array_key_exists('user', $_GET) && is_numeric($_GET['user']) && (int)$_GET['user'] > 0 ? (int)$_GET['user'] : null; $this->renderItemSend($row, $get_target_id); } // ----------------------------------------- /** * @return void */ private function itemUse(): void { if (!$this->id) { $this->alert('error', self::INVALID_ITEM); } $get_item = $this->db->query( 'SELECT inv.inv_id, inv.inv_qty, i.itmid, i.itmname, i.effect1_on, i.effect2_on, i.effect3_on, i.effect1, i.effect2, i.effect3 FROM inventory AS inv INNER JOIN items AS i ON i.itmid = inv.inv_itemid WHERE inv.inv_id = ' . $this->id . ' AND inv.inv_userid = ' . $this->ir['userid'] . ' LIMIT 1' ); if (!$this->db->num_rows($get_item)) { $this->alert('error', self::ITEM_NOT_EXISTS); } $row = $this->db->fetch_row($get_item); $this->db->free_result($get_item); if (!$this->hasEffect($row)) { $this->alert('error', self::ITEM_NOT_USABLE); } for ($i = 1; $i <= 3; ++$i) { if (!$row['effect' . $i . '_on']) { continue; } $effect = unserialize($row['effect' . $i]); $max_stat = 'max' . $effect['stat']; $inc_amount = $effect['inc_type'] === 'percent' ? (in_array($effect['stat'], $this->bar_cols) ? round($this->ir[$max_stat] / 100 * $effect['inc_amount']) : round($this->ir[$effect['stat']] / 100 * $effect['inc_amount'])) : $effect['inc_amount']; if ($effect['dir'] === 'pos') { if (in_array($effect['stat'], $this->bar_cols)) { $this->ir[$effect['stat']] = min($this->ir[$effect['stat']] + $inc_amount, $this->ir[$max_stat]); } else { $this->ir[$effect['stat']] += $inc_amount; } } else { $this->ir[$effect['stat']] = max($this->ir[$effect['stat']] - $inc_amount, 0); } $table = in_array($effect['stat'], $this->stat_cols) ? $this->table_users_stats : $this->table_users; $this->db->query( 'UPDATE ' . $table . ' SET ' . $effect['stat'] . ' = ' . $this->ir[$effect['stat']] . ' WHERE userid = ' . $this->ir['userid'] ); } item_remove($this->ir['userid'], $row['itmid'], 1); $this->alert('success', sprintf(self::ITEM_USED, $this->aAn($row['itmname']))); } // ----------------------------------------- /** * @param array $row * @return array */ private function doItemMarketAdd(array $row): array { $price = array_key_exists('price', $_POST) && is_numeric($_POST['price']) && (int)$_POST['price'] > 0 ? (int)$_POST['price'] : null; $qty = array_key_exists('qty', $_POST) && is_numeric($_POST['qty']) && (int)$_POST['qty'] > 0 ? (int)$_POST['qty'] : null; $currency = array_key_exists('currency', $_POST) && in_array($_POST['currency'], $this->currencies) ? $_POST['currency'] : null; if (empty($qty)) { return [ 'type' => 'error', 'content' => self::INVALID_QUANTITY ]; } if (empty($price)) { return [ 'type' => 'error', 'content' => self::INVALID_PRICE ]; } if (empty($currency)) { return [ 'type' => 'error', 'content' => self::INVALID_CURRENCY ]; } if ($qty > $row['inv_qty']) { return [ 'type' => 'error', 'content' => self::NOT_ENOUGH_ITEMS ]; } $get_dupe = $this->db->query( sprintf( 'SELECT imID FROM itemmarket WHERE imITEM = %u AND imPRICE = %u AND imADDER = %u AND imCURRENCY = \'%s\'', $row['itmid'], $price, $this->ir['userid'], $currency ) ); $dupe = $this->db->num_rows($get_dupe) ? $this->db->fetch_single($get_dupe) : null; $this->db->free_result($get_dupe); if ($dupe) { $this->db->query( 'UPDATE itemmarket SET imQTY = imQTY + ' . $qty . ' WHERE imID = ' . $dupe ); } else { $this->db->query( sprintf( 'INSERT INTO itemmarket (imITEM, imADDER, imPRICE, imCURRENCY, imQTY) VALUES (%u, %u, %u, \'%s\', %u)', $row['itmid'], $this->ir['userid'], $price, $currency, $qty ) ); } item_remove($this->ir['userid'], $row['itmid'], $qty); $this->db->query( sprintf( 'INSERT INTO imarketaddlogs (imaITEM, imaPRICE, imaINVID, imaADDER, imaTIME, imaCONTENT) VALUES (%u, %u, %u, %u, %u, \'%s\')', $row['itmid'], $price, $row['inv_id'], $this->ir['userid'], time(), $this->db->escape($this->ir['username'] . ' added ' . $qty . ' ' . $this->pluralize($row['itmname'], $qty) . ' to the item market for ' . money_formatter($price)) ) ); return [ 'type' => 'success', 'content' => sprintf(self::ITEM_ADDED_TO_MARKET, $qty, $this->pluralize($row['itmname'], $qty), money_formatter($price)) ]; } /** * @param array $row * @return void */ private function renderItemMarketAdd(array $row): void { $code = request_csrf_code('market_item_' . $this->id); ?> <h3>Add Item to Market</h3> <p> Enter the amount of <?php echo $this->pluralize($row['itmname'], 0); ?> you want to list on the item market. You have <strong><?php echo $row['inv_qty']; ?></strong>.<br> Set the currency you want to receive and the price for <em>each</em> item. </p> <form action="inventory.php?action=market-add&id=<?php echo $this->id; ?>" method="post"> <input type="hidden" name="verf" value="<?php echo $code; ?>" /> <div class="form-group"> <label for="qty">Quantity</label> <input type="number" name="qty" id="qty" class="form-control" placeholder="0" required> </div> <div class="form-group"> <label for="price">Price</label> <input type="number" name="price" id="price" class="form-control" placeholder="0" required> </div> <div class="form-group"> <label for="currency">Currency</label> <select name="currency" id="currency" class="form-control"> <?php foreach ($this->currencies as $currency) { printf('<option value="%s">%s</option>', $currency, ucfirst($currency)); } ?> </select> </div> <button type="submit" class="btn btn-primary"> Add Item To Market </button> </form> <?php } /** * @return void */ private function itemMarketAdd(): void { if (!$this->id) { $this->alert('error', self::INVALID_ITEM); } $get_item = $this->db->query( 'SELECT inv.inv_id, inv.inv_qty, i.itmid, i.itmname FROM inventory AS inv INNER JOIN items AS i ON inv.inv_itemid = i.itmid WHERE inv.inv_id = ' . $this->id . ' AND inv.inv_userid = ' . $this->ir['userid'] . ' LIMIT 1' ); if (!$this->db->num_rows($get_item)) { $this->alert('error', self::ITEM_NOT_EXISTS); } $row = $this->db->fetch_row($get_item); $this->db->free_result($get_item); $response = array_key_exists('verf', $_POST) && verify_csrf_code('market_item_' . $this->id, stripslashes($_POST['verf'])) ? $this->doItemMarketAdd($row) : null; if (!empty($response)) { $this->alert($response['type'], $response['content']); } $this->renderItemMarketAdd($row); } // ----------------------------------------- /** * @return void */ private function doItemUnequip(): void { $type = array_key_exists('type', $_GET) && in_array($_GET['type'], $this->equipSlots) ? $_GET['type'] : null; if (empty($type)) { $this->alert('error', self::INVALID_EQUIP_SLOT); } if (empty($this->ir[$type])) { $this->alert('error', self::EQUIP_NOT_EXISTS); } item_add($this->ir['userid'], $this->ir[$type], 1); $this->db->query( 'UPDATE users SET ' . $type . ' = 0 WHERE userid = ' . $this->ir['userid'] ); $names = array_map(function ($slot) { $slot = str_replace('equip_', '', $slot); return ucfirst($slot) . ($slot !== 'armor' ? ' Weapon' : ''); }, $this->equipSlots); $this->alert('success', 'The item in your ' . $names[$type] . ' slot has been unequipped.'); } // ----------------------------------------- /** * @param array $row * @return array */ private function doEquipArmor(array $row): array { if (!array_key_exists('verf', $_GET) || !verify_csrf_code('verf', $_GET['verf'])) { return [ 'type' => 'error', 'content' => self::SECURITY_TIMEOUT, ]; } if ($this->ir['equip_armor'] > 0) { item_add($this->ir['userid'], $this->ir['equip_armor'], 1); } item_remove($this->ir['userid'], $row['itmid'], 1); $this->db->query( 'UPDATE users SET equip_armor = ' . $row['itmid'] . ' WHERE userid = ' . $this->ir['userid'] ); return [ 'type' => 'success', 'content' => 'Your armor has been equipped.' ]; } /** * @param array $row * @return string[] */ private function doEquipWeapon(array $row): array { $slots = [...array_slice($this->equipSlots, 0, 2)]; $type = array_key_exists('type', $_POST) && in_array($_POST['type'], $slots) ? $_POST['type'] : null; if (empty($type)) { return [ 'type' => 'error', 'content' => self::INVALID_EQUIP_SLOT ]; } if ($this->ir[$type] > 0) { item_add($this->ir['userid'], $this->ir[$type], 1); } item_remove($this->ir['userid'], $row['itmid'], 1); $this->db->query( 'UPDATE users SET ' . $type . ' = ' . $row['itmid'] . ' WHERE userid = ' . $this->ir['userid'] ); return [ 'type' => 'success', 'content' => 'Your weapon has been equipped.' ]; } /** * @param array $row * @param bool $multi * @return void */ private function renderEquipSelect(array $row, bool $multi = false): void { $response = array_key_exists('equip_' . $row['inv_id'], $_POST) && verify_csrf_code('equip_' . $row['inv_id'], $_POST['equip_' . $row['inv_id']]) ? (array_key_exists('type', $_POST) && $_POST['type'] === 'equip_armor' ? $this->doEquipArmor($row) : $this->doEquipWeapon($row) ) : null; if (!empty($response)) { $this->alert($response['type'], $response['content']); } $code = request_csrf_code('equip_' . $row['inv_id']); ?> <h3>Equip Item</h3> <p> Please choose the slot to equip your <?php echo $row['itmname']; ?>. If you already have an item equipped in that slot, it will be unequipped and returned to your inventory. </p> <form action="inventory.php?action=equip&id=<?php echo $this->id; ?>" method="post"> <input type="hidden" name="equip_<?php echo $row['inv_id']; ?>" value="<?php echo $code; ?>" /> <?php $cnt = 0; foreach ($this->equipSlots as $slot) { if ($slot === 'equip_armor' && !$multi) { continue; } ?> <div class="form-group"> <label for="<?php echo $slot; ?>"> <input type="radio" name="type" id="<?php echo $slot; ?>" value="<?php echo $slot; ?>" <?php echo !$cnt ? 'checked' : ''; ?> /> <?php echo ucfirst(str_replace('equip_', '', $slot)) . ($slot !== 'equip_armor' ? ' Weapon' : ''); ?> </label> </div> <?php ++$cnt; } ?> <button type="submit" class="btn btn-primary"> Equip Item </button> </form> <?php } /** * @return void */ private function itemEquip(): void { if (!$this->id) { $this->alert('error', self::INVALID_ITEM); } $get_item = $this->db->query( 'SELECT inv.inv_id, inv.inv_qty, i.itmid, i.itmname, i.weapon, i.armor FROM inventory AS inv INNER JOIN items AS i ON inv.inv_itemid = i.itmid WHERE inv.inv_id = ' . $this->id . ' AND inv.inv_userid = ' . $this->ir['userid'] . ' LIMIT 1' ); if (!$this->db->num_rows($get_item)) { $this->alert('error', self::ITEM_NOT_EXISTS); } $row = $this->db->fetch_row($get_item); $this->db->free_result($get_item); if (!$row['weapon'] && !$row['armor']) { $this->alert('error', self::ITEM_NOT_EQUIPPABLE); } if ($row['armor'] && !$row['weapon']) { $response = $this->doEquipArmor($row); $this->alert($response['type'], $response['content']); } elseif ($row['weapon'] && !$row['armor']) { $this->renderEquipSelect($row); } else { $type = array_key_exists('type', $_GET) && in_array($_GET['type'], ['weapon', 'armor']) ? $_GET['type'] : null; if ($type === 'armor') { $response = $this->doEquipArmor($row); $this->alert($response['type'], $response['content']); } $this->renderEquipSelect($row, true); } } // ----------------------------------------- /** * @param string $type * @param string $content * @return void */ private function alert(string $type, string $content): void { $alert = $type === 'error' ? 'danger' : $type; ?> <div class="alert alert-<?php echo $alert; ?>" role="alert"> <span class="alert-title"><?php echo ucfirst($type); ?></span> <?php echo $content; ?> <div class="alert-links"> <a href="inventory.php">Back to Inventory</a> </div> </div> <?php $this->headers->endpage(); exit; } /** * @param string $word * @return string */ private function aAn(string $word): string { $first_letter = substr($word, 0, 1); return in_array($first_letter, ['a', 'e', 'i', 'o', 'u']) ? 'an ' . $word : 'a ' . $word; } /** * Note: This does not respect irregular plurals in the slightest. It's just a quick and dirty way to whack an s on the end if $amount <> 1 and the word doesn't already end in s. * @param string $word * @param int $amount * @return string */ private function pluralize(string $word, int $amount = 1): string { $last_letter = substr($word, -1); return strtolower($last_letter) === 's' || $amount === 1 ? $word : $word . 's'; } } // basic int validation $_GET['id'] = array_key_exists('id', $_GET) && is_numeric($_GET['id']) && (int)$_GET['id'] > 0 ? (int)$_GET['id'] : null; $_GET['action'] ??= null; (new ItemHandler($db, $ir, $h, $_GET['action'], $_GET['id']))->run();
  15. You're too kind πŸ™‚ So, to get us back on topic, here's an update to MCCv2. I turned the rewards into a config array at the top of the file. Be sure to update the bonus_items to the id=>quantity you want to give! You're no longer limited to 2 items either. Set as many or as few as you wish - at least 1 required. PHP 7.4-friendly <?php declare(strict_types=1); global $db, $ir, $h, $set; include __DIR__ . '/globals.php'; // bonus_items = [item id => quantity, ...] $rewards = [ 'money' => 500, 'crystals' => 500, 'donatordays' => 10, 'bonus_items' => [ 2 => 100, 4 => 100, ] ]; // If the bonus item id is not set if (empty($rewards['bonus_items'])) { basic_error('The welcome pack hasn\'t been set up. Please notify an administrator.'); } // If the bonus item is set, but doesn't exist $getItems = $db->query( 'SELECT itmid, itmname FROM items WHERE itmid IN (' . implode(', ', array_keys($rewards['bonus_items'])) . ')' ); // If there's no result at all if (!$db->num_rows($getItems)) { basic_error('The items set in the Bonus Pack don\'t exist. Please notify an administrator'); } // Get the items into an array. [item id => name, ...] $items = []; while ($row = $db->fetch_row($getItems)) { $items[$row['itmid']] = $row['itmname']; } // If the amount of items in our array doesn't match the number of items set in the Bonus Pack if (count($items) !== count($rewards['bonus_items'])) { basic_error('Some of the items set in the Bonus Pack don\'t exist. Please notify an administrator'); } // If the user has already claimed their Bonus Pack if ($ir['bonus'] > 1) { basic_error('You\'ve already claimed your Bonus Pack.'); } // Ok! Looks like we're clear. Grant the Bonus Pack! // Update the user $db->query( 'UPDATE users SET money = money + ' . $rewards['money'] . ', crystals = crystals + ' . $rewards['crystals'] . ', donatordays = donatordays + ' . $rewards['donatordays'] . ', bonus = 2 WHERE userid = ' . $ir['userid'] ); // Give 'em the items foreach ($rewards['bonus_items'] as $id => $quantity) { item_add($ir['userid'], $id, $quantity); } ?> Your welcome pack has been credited successfully.<br><br> You have gained 500 game money.<br> You have gained 500 crystals.<br> You have gained 10 days donators status.<br> <?php // Dynamically output the items, meaning we can change them at any time without having to update this foreach ($items as $id => $name) { echo 'x' . $rewards['bonus_items'][$id] . ' <a href="iteminfo.php?ID=' . $id . '">' . $name . '</a><br>'; } ?> The donator status given here will give you the following benefits:<br><br> <ul> <li> Red name + cross next to your name.</li> <li> Friends and Enemies List.</li> <li> 17% Energy every 5 minutes instead of 8%.</li> <li> 25% Stats gain in the donator gym.</li> <li> Unlocking of enhanced features.</li> <li> 25 street steps instead of 10 per day.</li> </ul> This is a complementary welcome pack.<br> Just a way to say thank you for joining <?php echo $set['game_name']; ?>. <?php // End $h->endpage(); /** * A simple "error and exit" function, which keeps the output styling Dragon Blade originally wrote for this script. * @param string $msg * @return void */ function basic_error(string $msg) { global $h; ?> <hr style="width: 50%;"> <h3>ERROR</h3> <?php echo $msg; ?><br><br> <hr style="width: 50%;"> <a href="index.php">&gt; Go Back</a> <hr style="width: 50%;"> <?php $h->endpage(); exit; } And here's the same script, updated to PHP 8.2 - which, in all honesty, merely adds the return typehinting for the basic_error() function. <?php declare(strict_types=1); global $db, $ir, $h, $set; include __DIR__ . '/globals.php'; // bonus_items = [item id => quantity, ...] $rewards = [ 'money' => 500, 'crystals' => 500, 'donatordays' => 10, 'bonus_items' => [ 2 => 100, 4 => 100, ] ]; // If the bonus item id is not set if (empty($rewards['bonus_items'])) { basic_error('The welcome pack hasn\'t been set up. Please notify an administrator.'); } // If the bonus item is set, but doesn't exist $getItems = $db->query( 'SELECT itmid, itmname FROM items WHERE itmid IN (' . implode(', ', array_keys($rewards['bonus_items'])) . ')' ); // If there's no result at all if (!$db->num_rows($getItems)) { basic_error('The items set in the Bonus Pack don\'t exist. Please notify an administrator'); } // Get the items into an array. [item id => name, ...] $items = []; while ($row = $db->fetch_row($getItems)) { $items[$row['itmid']] = $row['itmname']; } // If the amount of items in our array doesn't match the number of items set in the Bonus Pack if (count($items) !== count($rewards['bonus_items'])) { basic_error('Some of the items set in the Bonus Pack don\'t exist. Please notify an administrator'); } // If the user has already claimed their Bonus Pack if ($ir['bonus'] > 1) { basic_error('You\'ve already claimed your Bonus Pack.'); } // Ok! Looks like we're clear. Grant the Bonus Pack! // Update the user $db->query( 'UPDATE users SET money = money + ' . $rewards['money'] . ', crystals = crystals + ' . $rewards['crystals'] . ', donatordays = donatordays + ' . $rewards['donatordays'] . ', bonus = 2 WHERE userid = ' . $ir['userid'] ); // Give 'em the items foreach ($rewards['bonus_items'] as $id => $quantity) { item_add($ir['userid'], $id, $quantity); } ?> Your welcome pack has been credited successfully.<br><br> You have gained 500 game money.<br> You have gained 500 crystals.<br> You have gained 10 days donators status.<br> <?php // Dynamically output the items, meaning we can change them at any time without having to update this foreach ($items as $id => $name) { echo 'x' . $rewards['bonus_items'][$id] . ' <a href="iteminfo.php?ID=' . $id . '">' . $name . '</a><br>'; } ?> The donator status given here will give you the following benefits:<br><br> <ul> <li> Red name + cross next to your name.</li> <li> Friends and Enemies List.</li> <li> 17% Energy every 5 minutes instead of 8%.</li> <li> 25% Stats gain in the donator gym.</li> <li> Unlocking of enhanced features.</li> <li> 25 street steps instead of 10 per day.</li> </ul> This is a complementary welcome pack.<br> Just a way to say thank you for joining <?php echo $set['game_name']; ?>. <?php // End $h->endpage(); /** * A simple "error and exit" function, which keeps the output styling Dragon Blade originally wrote for this script. * @param string $msg * @return void */ function basic_error(string $msg): void { global $h; ?> <hr style="width: 50%;"> <h3>ERROR</h3> <?php echo $msg; ?><br><br> <hr style="width: 50%;"> <a href="index.php">&gt; Go Back</a> <hr style="width: 50%;"> <?php $h->endpage(); exit; }
  16. Keep the flaming out of this topic please. A blow-up over genuine support is not how we do things here.
  17. Here's SRB's PHP-flavoured generator as pure HTML/CSS/JS. <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Kitten Generator</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/1.1.4/tailwind.min.css"> </head> <body> <div class="antialiased w-screen min-h-screen bg-gray-900 pb-12"> <form action="" method="post" id="kitten-form"> <div> <div class="max-w-6xl mx-auto flex pt-12"> <div class="w-1/2 p-4"> <h1 class="text-white text-3xl">Mother</h1> </div> <div class="w-1/2 p-4"> <h1 class="text-white text-3xl">Father</h1> </div> </div> <div class="max-w-6xl mx-auto flex"> <div class="w-1/2 p-4 border-r border-gray-500"> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Body Size</span> <input type="text" name="mother-body-size" id="mother-body-size" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded px-2" tabindex="1" /> </label> </div> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Build</span> <input type="text" name="mother-build" id="mother-build" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md px-2" tabindex="3" /> </label> </div> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Ears</span> <input type="text" name="mother-ears" id="mother-ears" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md px-2" tabindex="5" /> </label> </div> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Eye Color</span> <input type="text" name="mother-eye-color" id="mother-eye-color" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md px-2" tabindex="7" /> </label> </div> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Nose / Paw Pads</span> <input type="text" name="mother-nose-paw-pads" id="mother-nose-paw-pads" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md px-2" tabindex="9" /> </label> </div> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Pelt Length</span> <input type="text" name="mother-pelt-length" id="mother-pelt-length" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md px-2" tabindex="11" /> </label> </div> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Pelt Color</span> <input type="text" name="mother-pelt-color" id="mother-pelt-color" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md px-2" tabindex="13" /> </label> </div> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Pelt Markings</span> <input type="text" name="mother-pelt-markings" id="mother-pelt-markings" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md px-2" tabindex="15" /> </label> </div> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Mutation</span> <input type="text" name="mother-mutation" id="mother-mutation" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md px-2" tabindex="17" /> </label> </div> </div> <div class="w-1/2 p-4"> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Body Size</span> <input type="text" name="father-body-size" id="father-body-size" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md px-2" tabindex="2" /> </label> </div> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Build</span> <input type="text" name="father-build" id="father-build" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md px-2" tabindex="4" /> </label> </div> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Ears</span> <input type="text" name="father-ears" id="father-ears" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md px-2" tabindex="6" /> </label> </div> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Eye Color</span> <input type="text" name="father-eye-color" id="father-eye-color" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md px-2" tabindex="8" /> </label> </div> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Nose / Paw Pads</span> <input type="text" name="father-nose-paw-pads" id="father-nose-paw-pads" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md px-2" tabindex="10" /> </label> </div> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Pelt Length</span> <input type="text" name="father-pelt-length" id="father-pelt-length" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md px-2" tabindex="12" /> </label> </div> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Pelt Color</span> <input type="text" name="father-pelt-color" id="father-pelt-color" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md px-2" tabindex="14" /> </label> </div> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Pelt Markings</span> <input type="text" name="father-pelt-markings" id="father-pelt-markings" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md px-2" tabindex="16" /> </label> </div> <div class="block mb-4"> <label> <span class="block text-gray-300 text-sm">Mutation</span> <input type="text" name="father-mutation" id="father-mutation" value="" class="mt-1 block w-full shadow-sm sm:text-lg border-gray-300 rounded-md px-2" tabindex="18" /> </label> </div> </div> </div> <div class="max-w-4xl mx-auto flex justify-center mt-8"> <button type="submit" class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-gray-600 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500">Randomize</button> </div> </div> </form> <div class="max-w-6xl mx-auto flex justify-center flex-wrap mt-6 border-t pt-6" id="kitten-result"></div> </div> <script> let kittenCount = 0; const getOpts = () => { return ['body-size', 'build', 'ears', 'eye-color', 'nose-paw-pads', 'pelt-length', 'pelt-color', 'pelt-markings', 'mutation']; }; const generateKittens = () => { const opts = getOpts(); let output = []; for (let opt of opts) { const fatherOpt = `father-${opt}`; const motherOpt = `mother-${opt}`; let motherInput = document.getElementById(motherOpt).value ?? ''; let fatherInput = document.getElementById(fatherOpt).value ?? ''; console.log(`${opt}: ${motherInput} :: ${fatherInput}`); const items = [motherInput, fatherInput]; let selectedOpt = items[Math.floor(Math.random() * 2)]; let color = "#838383"; if (selectedOpt === '') { selectedOpt = (motherInput ?? fatherInput) ?? 'none'; } if (motherInput === fatherInput) { color = "#5bf132"; } else if (selectedOpt === motherInput) { color = "#ee6acb"; } else if (selectedOpt === fatherInput) { color = "#32aef1"; } output[opt] = `<span style="color: ${color};">${selectedOpt}</span>`; } const kittenCard = ` <div class="inline text-left box-border p-3 w-1/4"> <div class="border box-border p-2"> <h3 class="text-gray-300 font-bold border-b pb-1 mb-1"> Random Kitten #${++kittenCount} </h3> <div class="text-gray-300 body-size"> <span class="font-semibold">Body Size : </span> <span class="float-right">${output['body-size']}</span> </div> <div class="text-gray-300 build"> <span class="font-semibold">Build : </span> <span class="float-right">${output['build']}</span> </div> <div class="text-gray-300 ears"> <span class="font-semibold">Ears : </span> <span class="float-right">${output['ears']}</span> </div> <div class="text-gray-300 eye-color"> <span class="font-semibold">Eye Color : </span> <span class="float-right">${output['eye-color']}</span> </div> <div class="text-gray-300 nose-paw-color"> <span class="font-semibold">Nose / Paw Color : </span> <span class="float-right">${output['nose-paw-pads']}</span> </div> <div class="text-gray-300 pelt-length"> <span class="font-semibold">Pelt Length : </span> <span class="float-right">${output['pelt-length']}</span> </div> <div class="text-gray-300 pelt-color"> <span class="font-semibold">Pelt Color : </span> <span class="float-right">${output['pelt-color']}</span> </div> <div class="text-gray-300 pelt-markings"> <span class="font-semibold">Pelt Markings : </span> <span class="float-right">${output['pelt-markings']}</span> </div> <div class="text-gray-300 mutation"> <span class="font-semibold">Mutation : </span> <span class="float-right">${output['mutation']}</span> </div> </div> </div>`; document.getElementById('kitten-result').innerHTML += kittenCard; }; let formElem = document.getElementById('kitten-form'); formElem.addEventListener("submit", (e) => { e.preventDefault(); e.stopPropagation(); generateKittens(); }); </script> </body> </html> Fair note that this has never heard of "security". Blue: trait from father Pink: trait from mother Green: trait from both (matching trait) Grey: no trait 2023-08-23 15-44-43.mp4
  18. Here's a PHP 8 version, because why not? <?php declare(strict_types=1); global $db, $h, $set, $userid; include 'globals.php'; $question = strtolower($_POST['question']); ?> <h2 class="fontface"><span class="green">T</span>utorial</h2> <hr /><br /><br /> <table style="border:none;width:650px;"> <tr> <td> <p>Welcome to the Tutorial, we hope that this guide will help you to better understand the game. <p><br /> <p> You are free to choose your own path. You can protect the weak, or exploit their weakness. Spend your money to help your friends, or horde it, they can take care of themselves. Buy a gang and become the most respected group of players in the land. Declare war on an enemy, or an innocent bystander, the choice is yours. </p><br /> <h3 class="fontface"> <?php echo $set['game_name']; ?> Help Bot </h3> <small>(Ask the Bot a question below and let's see if we can get you going.)</small><br /><br /> <form action="help.php" method="POST"> Question: <input type="text" name="question" size="70" placeholder="What would you like to know? why not try typing in training, gangs or rules"> <input type="submit" value="Ask"> </form> <?php if (empty($question)) { $h->endpage(); exit; } $answer = match ($question) { 'x' => 'x', 'help' => 'What do you need help with?', 'hello', 'helo', 'hi', 'hey' => 'Hello how are you?', 'gym', 'the gym' => 'The gym is where you use energy,gold and some will potions to train your stats up.<Br />Stats help you beat up players and protect yourself as well from attacks.', 'good' => 'Im glad to hear your good.', 'strength' => 'This stat is used to calculate how much damage a weapon does.', 'agility' => 'This stat is used for dodging attacks.', 'labour' => 'This stat is used for getting promoted in jobs.', 'IQ' => 'This stat is stat is gained from courses and used for promotions.', 'crystal', 'crystals' => 'Crystals are used for various things under <a href="crystaltemple.php">Crystal Temple</a>', 'cash' => 'Cash is used to buy stuff all over the game', 'energy' => 'This is used mainly for training and attacking', 'brave' => 'This is used for doing crimes', 'health' => 'How much health you have in a fight', 'mine', 'mines' => 'Mining a great way to earn gold', 'job' => 'Nice way to earn cash and stats', 'education' => 'Used for gaining IQ', 'mail' => 'Your own personal mail system', 'events' => 'What happens to you is recorded here', 'logout' => 'Used to logout of the game, duh.', 'explore' => 'Where the main links are listed', 'search' => 'Search for other players!', 'friend list' => 'Record your friends', 'black list' => 'Record your enemies', 'missions' => 'This is where you can use some of your brave to earn some cash.', 'preferences' => 'Used to change your account around', 'donate' => 'Donate to the game and be awarded donator features', 'vote' => 'Voting earns you rewards and it helps the game grow', 'item', 'items' => 'Items are a main part of the game and used for doing lots of things', 'church' => 'Used for getting married', 'stats' => 'Stats are what determines your account and how good you are', 'travel' => 'Travel around the game', 'casino' => 'Casino, play various games earning you some cash', 'quests' => 'Quests do various tasks to earn rewards', 'banned' => 'Users banned are listed in dungeon', 'war' => 'War is when 2 gangs fight each other', 'staff' => 'Main staff can be listed under Staff, ID 1 is the overall owner', 'prison' => 'Sent here when failing crimes', 'hospital', 'hosp' => 'Sent here when attacked', 'noob', 'n00b' => 'Who you calling a noob?', 'fuck', 'shit', 'prick', 'cunt', 'bitch' => 'Please do not swear', 'robot', 'bot' => 'Who you calling a bot!', 'who are you' => 'I am the ' . $set['game_name'] . ' Bot', 'weather' => 'The weather effects your training at the gym and your mining rates when at the mines.<br />You can also visit the weather page and ask the gods for better weather.', 'money' => 'Please Explain? e.g: how to get money or what should i save for', 'how to get money' => 'The best way to get money is by going into the mines and mine for gold and sell it. You could also take a risk and put it into the stock exchange.', 'what should i save for' => 'Well that\'s upto you but personally I would save up for a better house as that will help improve your stats and player.', 'users online' => 'This is where you see who is online', 'attacking' => 'Attacking is a good way to get experience, and exert your superiority over those weaker than you. In order to attack you need 1 energy, and should have a weapon. When you win a fight you will get a percentage of experience depending on how much stronger you are compared to the person you are attacking. Make sure that you really want to fight the person, because once you start you can\'t stop until one of you loses. When you start a fight, you will have the option of using any weapon that you currently have in your items page.', 'gang', 'gangs' => 'Gangs are a group of players that band together to work for a common purpose, granted this may be robbing a bank, or taking down the losers in a rival gang.<br /> Gangs cost $500K to create, and once you buy it, you are the president of your gang.<br /> Your gang will initially be able to hold 5 members, but will be able to upgrade to more as time goes on.<br /> The President will be able to assign a Vice-President to the gang. Gangs are able to do Organised Crimes for money and respect.<br /> The president can also select to go to war with another gang. One should be careful about doing this though, as it may come back to haunt you.', 'training' => '<b>Gym: </b>To use the gym, type in the number of times you want to train, select the stat to train and click ok.<br /> The next screen will tell you how much of that stat you gained, and what your total in that stat is.<br /><br /> <b>Missions: </b>Go to the mission screen and select the mission you want to do. <br />Remember that trying a mission that is to hard may land you in jail, and lose the experience you\'ve worked so hard to get.<br /><br /> <b>School: </b>School offers courses that will raise your stats over a certain period of time<br /><br /> <b>Your Job: </b>A job will provide you with money at 5:00PM every day, as well as raising your job stats every day. <br />Some jobs have requirements before you can do them, so make sure to keep an eye out for that.<br /><br /> <b>Attacking: </b>Attacking will gain you experience when you win, but you lose experience if you lose.<br /> The amount of experience depends on the comparative strength of your enemy, if they are much weaker, you won\'t get much experience.', 'rules' => 'Rules are important, They make sure that everyone gets a chance and the games is fair and fun for all. For all the rules please check out the game rules section.', 'profile', 'profiles' => 'This is where you can look at yours and other players profiles. Very informative ', 'rucksack' => 'this is where you find your items to use within the game, you also find your weapons and armour here.<br />', 'referrals', 'referral' => 'This is where you give friends a link to the game to earn rewards.', 'lucky', 'box', 'lucky box' => 'This is your reward for logging in every hour.', default => 'Sorry, I don\'t know the answer. <br />I\'ve logged it and should have an answer for you soon.', }; ?> <br /> <span class="blue"><b>You asked the Bot:</b></span> <?php echo $question; ?><br /> <span class="gold"><b>The Bot replied:</b></span> <?php echo $answer; if (empty($answer)) { $db->query('INSERT INTO `bot` (`submitted` ,`question` )VALUES (' . $userid . ', \'' . $db->escape($question) . '\')'); ?> Sorry, I don't know the answer. <br />It has been submitted to the database. <?php $h->endpage(); exit; } ?> </td> </tr> </table> <?php $h->endpage();
  19. No worries! And no, I don't believe so. Updating it, I imagine, wouldn't be such a massive undertaking - it's a pretty small engine, and good practice! πŸ˜„
  20. It will not run on PHP 8 without minor edits (primarily removals of magic_quotes calls in a couple of core files and a removal/tweak of the gethostbyaddr() calls in viewuser.php). After those minor fixes, it seems to run ok on my localhost and a public-facing webserver, though it will fill up the error log depending on your error reporting setting. PHP 7 seems to be a little more forgiving, it's less-restrictive rulesets allow MCCv2.0.5b to run. Again, however, it will generate a few notices/warnings for the error log. PHP 5.6 doesn't seems to give a rats butt - it runs fine. MySQL, all major versions since (and including) version 5 seem to take it fine. I'd advise a number of optimisations - both to the code and the database - but that'd be another topic for another time.
  21. I'm autistic. You'll find your method πŸ˜‰
  22. About that.. It's an interesting choice to throw your toys out of the pram about asking questions while on a forum absolutely full of them. Advise re-reading this topic. The answers are here πŸ˜‰
  23. I bloody love this plugin for PhpStorm ❀️
  24. Aye, they're not bad at all. Well reputed, long-standing, experienced. Do you already have a domain? (example.com, example.net, example.tld) If so, contact wherever you bought it for that code. If not, consider creating a new one for your project. Edit; responded to DM. This isn't the correct context for the desire
×
×
  • Create New...