Jump to content
MakeWebGames

Magictallguy

Administrators
  • Posts

    2,130
  • Joined

  • Last visited

  • Days Won

    145

Everything posted by Magictallguy

  1. Merry Calendar Change Day!
  2. begins chanting Bring back the Marketplace! Bring back the Marketplace! Bring back the Marketplace!
  3. Still around!
  4. You mentioned using phone data while connected to WiFi, so I'm unclear on whether your phone (on just WiFi) has the same result. As soon as you clarify that, we can start throwing (maybe educated?) guesses at the cause
  5. The installer has an extra comma in the query's column definitions Find: INSERT INTO `users` (`username`, `login_name`, `userpass`, `level`, `money`, `crystals`, `donatordays`, `user_level`, `energy`, `maxenergy`, `will`, `maxwill`, `brave`, `maxbrave`, `hp`, `maxhp`, `location`, `gender`, `signedup`, `email`, `bankmoney`, `lastip`, `lastip_signup`, `pass_salt`, , `display_pic`, `staffnotes`, `voted`, `user_notepad`) See that random blank column between `pass_salt` and `display_pic`? Remove it INSERT INTO `users` (`username`, `login_name`, `userpass`, `level`, `money`, `crystals`, `donatordays`, `user_level`, `energy`, `maxenergy`, `will`, `maxwill`, `brave`, `maxbrave`, `hp`, `maxhp`, `location`, `gender`, `signedup`, `email`, `bankmoney`, `lastip`, `lastip_signup`, `pass_salt`, `display_pic`, `staffnotes`, `voted`, `user_notepad`) Note: `lib/basic_error_handler.php` has a DEBUG constant. Set it to `true` and you'll see error messages This only applies if the project's directory is not the webroot (you have localhost/upload/{game-files}). The installer "expects" things to be at webroot
  6. I didn't add any >100 formatting, but that'd be easy enough. Hell, I might even update to use a checkbox for it so users can see the direct value if they need to, or just a "yup, this is guaranteed" output. Go sick 😄
  7. I really like the ability to visualise how the crime formulae may result; so I took your idea and added the ability to select from an existing crime, or assume the default formula ((WILL*0.8)/2.5)+(LEVEL/4) and calculate as desired. I also stripped the jQuery dependence; pure vanilla JS, woo! Fair note to our more sensitive-eyed programmers; there's no dark mode by default. Note: Written in a PHP8.4 environment. Older versions may need to change the match() call to a switch() equivalent crime-formula.php <?php declare(strict_types=1); $_GET['action'] ??= null; $_GET['id'] = array_key_exists('id', $_GET) && is_numeric($_GET['id']) && (int)$_GET['id'] > 0 ? (int)$_GET['id'] : null; class CrimeFormula { private static ?self $inst = null; private ?database $db; private ?array $settings; /** * @param database $db * @param array $settings */ public function __construct(database $db, array $settings) { $this->db = $db; $this->settings = $settings; $this->run(); } /** * @return void */ private function run(): void { $response = match ($_GET['action']) { 'get-crime-by-id' => $this->getCrimeById($_GET['id']), default => [ 'type' => 'error', 'message' => 'No action given', ], }; if ($this->isAjax()) { header('Content-type: application/json'); echo json_encode($response); exit; } if (array_key_exists('location', $response)) { header('Location: ' . $response['location']); exit; } echo $this->template('crime-select', [ '%id%' => $_GET['id'], '%menu.opts:crimes%' => $this->renderMenuOptsCrimes($_GET['id']), ]); } /** * @param int|null $id * * @return array|null */ private function getCrimeById(?int $id): ?array { if (empty($id)) { return null; } $get_crime = $this->db->query( 'SELECT * FROM crimes WHERE crimeID = ' . $id . ' LIMIT 1', ); $row = $this->db->fetch_row($get_crime); $this->db->free_result($get_crime); return $row ?? null; } /** * @return bool */ private function isAjax(): bool { return array_key_exists('HTTP_X_REQUESTED_WITH', $_SERVER) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest'; } /** * @param string $fileName * @param array $replacements * * @return string|null */ private function template(string $fileName, array $replacements = []): ?string { $path = str_replace('/', DIRECTORY_SEPARATOR, __DIR__ . '/' . $fileName . '.html'); if (!file_exists($path)) { return null; } $content = file_get_contents($path); return strtr($content, $replacements); } /** * @param int|null $selected * * @return string */ private function renderMenuOptsCrimes(?int $selected = null): string { $ret = ''; $rows = $this->db->query( 'SELECT crimeID, crimeNAME, crimeBRAVE FROM crimes ORDER BY crimeBRAVE', ); while ($row = $this->db->fetch_row($rows)) { $ret .= sprintf( '<option value="%u" %s>%s [%s brave]</option>%s', $row['crimeID'], (int)$row['crimeID'] === $selected ? 'selected' : '', stripslashes(htmlspecialchars($row['crimeNAME'])), number_format((int)$row['crimeBRAVE']), PHP_EOL, ); } $this->db->free_result($rows); return $ret; } /** * @param database $db * @param array $settings * * @return self|null */ public static function getInstance(database $db, array $settings): ?self { if (self::$inst === null) { self::$inst = new self($db, $settings); } return self::$inst; } } global $db, $set; require_once __DIR__ . '/globals_nonauth.php'; $module = CrimeFormula::getInstance($db, $set); crime-select.html <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Crime Formula Tests</title> </head> <body> <div class="container" style="margin: 0 auto;"> <form id="crime-selection-form" method="get"> <div class="row py-2"> <div class="col"> <div class="form-group"> <label for="crime">Select Crime</label> <select name="crime" id="crime" class="form-control"> <option value="0" selected>--- None ---</option> %menu.opts:crimes% </select> </div> </div> </div> <div class="row py-2"> <div class="col-lg-6 col-md"> <div class="form-group"> <label for="level">Level</label> <input type="number" name="level" id="level" class="form-control" value="1" step="1"> </div> </div> <div class="col-lg-6 col-md"> <div class="form-group"> <label for="will">Will</label> <input type="number" name="will" id="will" class="form-control" value="100" step="1"> </div> </div> </div> </form> </div> <div class="container"> <span class="d-block m-1" id="crime-formula-raw"></span> <span class="d-block m-1" id="crime-formula-formatted"></span> <span class="d-block m-1" id="crime-response"></span> </div> <script> const apiCall = (path) => { return fetch(path, { headers: { 'credentials': 'same-origin', 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/json' }, signal: AbortSignal.timeout(5000) }); }; const getCrime = (id, callback) => { apiCall(`crime-formula.php?action=get-crime-by-id&id=${id}`) .then(response => response.json()) .then(data => callback(data)); }; const responseElem = document.getElementById("crime-response"); const formulaRawElem = document.getElementById("crime-formula-raw"); const formulaFormattedElem = document.getElementById("crime-formula-formatted"); const updateCrimeInfo = (formula, will, level) => { let formulaFormatted = formula.replace('WILL', will).replace('LEVEL', level); formulaRawElem.innerText = formula; formulaFormattedElem.innerText = formulaFormatted; /* Dirty. Don't do this if you can avoid it. And certainly *never* trust user input with it. */ let amnt = eval(formulaFormatted); responseElem.innerText = amnt.toLocaleString(undefined, {maximumFractionDigits: 3}) + "%"; }; const getCrimeFullEvent = (e) => { e.stopPropagation(); e.preventDefault(); if ([undefined, null].includes(responseElem) || [undefined, null].includes(formulaRawElem) || [undefined, null].includes(formulaFormattedElem)) { console.error("Form element missing: crime-response/crime-formula-raw/crime-formula-formatted"); return; } let will = document.getElementById("will").value; let level = document.getElementById("level").value; let id = document.getElementById("crime").value; if ([undefined, null].includes(will)) { will = 100; } if ([undefined, null].includes(level)) { level = 1; } if ([undefined, null].includes(id)) { id = 0; } let formula = '((WILL*0.8)/2.5)+(LEVEL/4)'; if (id > 0) { getCrime(id, (data) => { if ([undefined, null].includes(data)) { console.error("Blank crime data response"); return false; } if (data.hasOwnProperty("type") && data.type !== "success") { console.error(data); return false; } updateCrimeInfo(data.crimePERCFORM, will, level); return true; }); } else { updateCrimeInfo(formula, will, level); } }; window.addEventListener("DOMContentLoaded", () => { const formElem = document.getElementById("crime-selection-form"); if ([undefined, null].includes(formElem)) { console.error("Form element missing: crime-selection-form"); return; } formElem.addEventListener("keyup", (e) => getCrimeFullEvent(e)); formElem.addEventListener("mouseup", (e) => getCrimeFullEvent(e)); }); </script> </body> </html> 2025-09-22 18-58-18.mp4
  8. For anyone wanting to take this on, you're lookin' at CrateJS to re-wrap
  9. Note: In higher-traffic areas, this may introduce race conditions. In that scenario, I'd recommend using the database (the one your project is already using) to track this information; amongst other things, most RDBMS support query queuing as default. For low-traffic areas and areas where you don't foresee an upsurge in activity (refer to your metrics), then this file-based approach may be perfectly sufficient for your needs
  10. Technically, yes! It is certainly possible to run multiple sites that reference a single database. More often than not, though, the question is "why"? If, for example, I was to start a mafia-style game with MCC then I decided I wanted a sci-fi style game with gRPG; I could do the leg-work and make them compatible. That being said, what of the players? Someone playing a mafia-style game with [x] currency will likely be confused by having [y] currency in the sci-fi game. I'm a firm believer of "fit for purpose"; each project gets their own database(s) as necessary. If you want to make a merge of the open-source engines, you go right ahead 😄
  11. These can be added into the Dockerfile as RUN directives
  12. Summer! Life generally tends to get louder in the summer. People are out (and away from their keyboards) more often. We're still just a message away though. As for gRPG, I've already framed a structure for the multi-PHP-version supports and have begun tweaking the various branches
  13. Minor control issue; W responds (piece rotation), but ASD do not. All arrow keys work.
  14. Hmm, could Cloudflare be doing the derp on an old resource? @Dayo
  15. Adding a mobile screeny for the light theme to confirm This is very likely a caching issue - we're on CSS build 8 now
  16. Looks like your browser simply failed to grab the site's CSS properly. Clear the cache and try again 🙂 Chiming in with mobile screenshot too! Samsung Galaxy S23
  17. I have not as I wasn't thinking of backwards compatibility. This change is part of a rolling set of changes I intend to make to suit more recent technologies. As for the claim that "nobody" has PHP 8.4 yet; SiteEU, WebWiz, HawkHost, Kinsta, SwitchWeb, NameCheap, GoDaddy, Google Cloud Hosting and AWS absolutely do support it. Honourable mention to cPanel's EasyApache which added PHP 8.4 support in December just gone. Again, I will add backward compatibility for PHP 8.0. Might send up a couple of branched releases so people can select their desired version.
  18. You changed setenv to getenv? Of course that wouldn't work
  19. Back when I was on Windows, I loved mLocati's PowerShell PHP Manager - you may wish to consider looking into it. Its primary purpose is to provide an easy way to install multiple PHP versions and choose whichever one the system considers active. As for your host, perhaps a request to their support might be fruitful.
  20. PHP 8.4 required. I'll push an 8.0-friendly version shortly
  21. I decided it's time to blow off the dust and give this project some TLC. So, a small update list! now comes with a Docker configuration no longer relies on Composer There will be more updates to come as the longer I look, the more I kick my younger self 😄
  22. Head up to the object/property declarations and initialise the $querystring property Find: protected string $querystring; Replace with: protected string $querystring = '';
  23. That's the installation of Composer itself. You now need to run `composer install` on the command line in the project's root to grab the 3rd-party dependencies. A future release will factor out the Composer reliance. But for now, that's the way
  24. The autoload file is generated after running `composer install` in the project's root directory.
×
×
  • Create New...