MCCodes - Chapter 3: Crime System
Welcome to Chapter 3! In Chapter 2: Global Setup & Session Management, we learned how MCCodes sets everything up when you load a page, including figuring out who you are ($ir
) and connecting to the game's brain (the database $db
). Now that the stage is set, let's dive into one of the first things you might do in the game: committing crimes!
The Problem: Earning Your Keep (The Risky Way)
In many online text-based games, you need ways to earn money, experience points (XP), and maybe find useful items without necessarily fighting other players. How can the game provide a solo activity where players can take risks for potential rewards?
The Solution: MCCodes uses a Crime System. This system lets players attempt various criminal activities. Each crime has a cost, a chance of success based on the player's abilities, and different outcomes depending on whether they succeed or fail. It's a core Player vs. Environment (PVE) feature -- you're challenging the game's rules, not another player.
What are Crimes? The Risk vs. Reward Game
Think of crimes as mini-games of chance. You choose an action, like "Search the Streets" or "Rob a Convenience Store".
- The Risk: Each crime costs a resource called Brave. Brave is like your nerve or courage. You only have a limited amount, and it refills over time. If you fail a crime, you might just lose the Brave you spent, or worse, you could end up in Jail!
- The Reward: If you succeed, you get rewards! This could be Money, sometimes special currency like Crystals, Experience Points (XP) to level up, Crime XP (which makes you better at future crimes), and sometimes even Items.
- The Chance: Your success isn't guaranteed. It depends on:
- Your character's Stats (like Will, Level, Crime XP).
- The specific Crime's Difficulty (defined by a formula).
- A bit of Luck (a random chance element).
How to Use the Crime System (As a Player)
Let's see how you'd actually commit a crime in the game.
Navigate to the Crime Page: You'll typically find a link in the main menu (set up by
header.php
as we saw in Chapter 1: Page Rendering & Structure) that takes you tocriminal.php
.See the List: The
criminal.php
page shows you a list of available crimes. These are usually grouped by category or difficulty.Analogy: Imagine a bulletin board in a shady part of town, listing various "opportunities".
Here's a simplified example of what you might see:
Criminal Centre Petty Crimes ------------------------------------------- Crime | Cost | Do ------------------------------------------- Search the streets | 2 Brave | [Do] Pickpocket someone | 3 Brave | [Do] Minor Offenses ------------------------------------------- Crime | Cost | Do ------------------------------------------- Rob a hobo | 5 Brave | [Do] Steal hubcaps | 6 Brave | [Do]
Choose Your Crime: You look at the list, check the Brave cost, and decide which crime you want to attempt.
Click "Do": Clicking the "[Do]" link next to a crime sends your request to the server. This link actually points to another file,
docrime.php
, and tells it which crime you chose (using a number, the Crime ID, in the web address). For example, clicking "Do" for "Search the streets" might go todocrime.php?c=1
.See the Outcome: The
docrime.php
script processes your attempt. After a moment, the page will reload or update, showing you the result:- Success: "You search the streets and find $50!" (You gain money, XP, etc.)
- Failure: "You search the streets but find nothing useful." (You lose the Brave you spent).
- Jail: "A police officer spots you trying to pickpocket and arrests you! You're sent to jail for 5 minutes." (You lose Brave and are put in jail, unable to play normally for a while).
How it Works Under the Hood
Let's trace what happens when you click that "Do" link for a crime.
Step-by-Step Walkthrough:
- Request: Your browser sends a request to
docrime.php
, including the Crime ID (e.g.,?c=1
). - Setup:
docrime.php
includesglobals.php
. This sets up your session, connects to the database ($db
), loads your player data ($ir
), etc. (as seen in Chapter 2). - Checks: It checks if you're already in jail or the hospital (
$ir['jail'] > 0
). If so, it stops you. - Get Crime Details: It uses the Crime ID (
$_GET['c']
) to look up the crime's details in thecrimes
database table (cost, formula, rewards, texts, jail time). - Check Brave: It checks if you have enough Brave (
$ir['brave']
) to pay the crime's cost (crimeBRAVE
). If not, it stops you. - Deduct Brave: If you have enough, it subtracts the Brave cost from your character. This updates your
$ir['brave']
value and saves it back to theusers
table in the database. - Calculate Success: This is the tricky part! The crime has a
crimePERCFORM
(Percent Formula) stored in the database, like'((WILL*0.8)/2.5)+(LEVEL/4)'
. The script replacesWILL
andLEVEL
with your actual stats from$ir
and calculates a success percentage ($sucrate
).- (Caution:* MCCodes uses a PHP function called
eval()
here. While powerful,eval()
can be a security risk if not used very carefully, as it executes code stored as text. Modern development often avoidseval()
.)*
- (Caution:* MCCodes uses a PHP function called
- Roll the Dice: The script generates a random number (e.g., between 1 and 100).
- Determine Outcome:
- If the random number is less than or equal to your calculated
$sucrate
, you succeed! - Otherwise, you fail. The script might also have a chance to send you to jail on failure (often another random roll).
- If the random number is less than or equal to your calculated
- Apply Results:
- Success: Adds rewards (money, crystals, XP, Crime XP) to your
$ir
data and updates theusers
table. If the crime gives an item, it calls a function to add it to your inventory (we'll see this in Chapter 4: Item Management). - Failure: No rewards, just Brave lost.
- Jail: Sets your
$ir['jail']
time and$ir['jail_reason']
and updates theusers
table.
- Success: Adds rewards (money, crystals, XP, Crime XP) to your
- Show Message: Displays the appropriate text message for success, failure, or jail (stored in the
crimes
table). - Finish Page: Calls
$h->endpage()
to complete the HTML page.
Sequence Diagram:
sequenceDiagram participant B as Browser participant CP as criminal.php participant DP as docrime.php participant G as globals.php participant DB as Database B->>CP: Request criminal.php CP->>G: require 'globals.php' (loads $ir, $h, etc.) G-->>CP: Setup complete CP->>DB: Fetch crime groups & crimes DB-->>CP: Return crime list data CP-->>B: Display list of crimes with "Do" links (to docrime.php?c=ID) B->>DP: Click "Do" (Request docrime.php?c=ID) DP->>G: require 'globals.php' (loads $ir, $h, etc.) G-->>DP: Setup complete DP->>DP: Check if user jailed/hospitalized (using $ir) DP->>DB: Fetch details for crime ID from `crimes` table DB-->>DP: Return crime details (cost, formula, rewards...) DP->>DP: Check if $ir['brave'] >= crime cost DP->>DB: Update user's brave (deduct cost) DP->>DP: Calculate success rate (using formula & $ir stats) DP->>DP: Roll random number, compare to success rate alt Success DP->>DB: Update user's money, xp, crimexp, crystals opt Crime gives item DP->>DP: Call item_add() function end DP-->>B: Display success message else Failure alt Jail DP->>DB: Update user's jail time and reason DP-->>B: Display jail message else Simple Fail DP-->>B: Display failure message end end DP->>H: $h->endpage()
Diving into the Code
Let's look at simplified snippets of the key files.
1. criminal.php
(Displaying the List)
This file mainly fetches data and displays it in an HTML table.
<?php
// File: criminal.php (Simplified)
require_once('globals.php'); // Setup session, user data ($ir), etc.
// Check if player can access this page
if ($ir['jail'] || $ir['hospital']) {
die('This page cannot be accessed while in jail or hospital.');
}
echo "<h3>Criminal Centre</h3>";
echo "<table width='75%' cellspacing='1' class='table'>
<tr><th>Crime</th><th>Cost</th><th>Do</th></tr>";
// Get crime groups (e.g., "Petty Crimes", "Minor Offenses")
$q_groups = $db->query("SELECT cgID, cgNAME FROM crimegroups ORDER BY cgORDER ASC");
// Get all crimes
$crimes_data = [];
$q_crimes = $db->query("SELECT crimeGROUP, crimeNAME, crimeBRAVE, crimeID FROM crimes ORDER BY crimeBRAVE ASC");
while ($row = $db->fetch_row($q_crimes)) {
$crimes_data[] = $row;
}
$db->free_result($q_crimes);
// Loop through groups and display crimes within each group
while ($group = $db->fetch_row($q_groups)) {
echo "<tr><td colspan='3' class='h'>{$group['cgNAME']}</td></tr>"; // Group header
foreach ($crimes_data as $crime) {
if ($crime['crimeGROUP'] == $group['cgID']) {
// Display one row for each crime in this group
echo "<tr>
<td>{$crime['crimeNAME']}</td>
<td>{$crime['crimeBRAVE']} Brave</td>
<td><a href='docrime.php?c={$crime['crimeID']}'>Do</a></td>
</tr>";
}
}
}
$db->free_result($q_groups);
echo '</table>';
$h->endpage(); // Finish the HTML page structure
?>
- Includes
globals.php
: Gets everything ready. - Checks Jail/Hospital: Prevents access if needed.
- Database Queries: Gets the list of crime groups and all crimes from the database (more on this in Chapter 10: Database Interaction).
- HTML Table: Uses loops (
while
,foreach
) to build the table structure, showing the crime name, brave cost, and a link todocrime.php
with the specificcrimeID
.
2. docrime.php
(Processing the Attempt)
This is where the core logic happens.
<?php
// File: docrime.php (Simplified)
require_once('globals.php'); // Setup session, user data ($ir), etc.
// Get the chosen crime ID from the URL (?c=ID)
$crime_id = isset($_GET['c']) ? abs((int)$_GET['c']) : 0;
if ($crime_id <= 0) {
die("Invalid Crime ID.");
}
// Check if player can access
if ($ir['jail'] > 0 || $ir['hospital'] > 0) {
die('This page cannot be accessed while in jail or hospital.');
}
// Fetch crime details from the database
$q = $db->query("SELECT * FROM crimes WHERE crimeID = {$crime_id} LIMIT 1");
if ($db->num_rows($q) == 0) {
die("Invalid Crime.");
}
$crime_data = $db->fetch_row($q);
$db->free_result($q);
// Check if player has enough Brave
if ($ir['brave'] < $crime_data['crimeBRAVE']) {
die("You do not have enough Brave to perform this crime.");
}
// --- Action Starts ---
echo $crime_data['crimeITEXT']; // Display initial text ("You attempt to...")
// Deduct Brave
$ir['brave'] -= $crime_data['crimeBRAVE'];
$db->query("UPDATE users SET brave = {$ir['brave']} WHERE userid = $userid");
// Calculate Success Rate using the formula
$sucrate = 0;
$formula = str_replace(
['LEVEL', 'CRIMEXP', 'WILL', 'IQ' /* ... other stats ... */],
[$ir['level'], $ir['crimexp'], $ir['will'], $ir['IQ'] /* ... */],
$crime_data['crimePERCFORM'] // Get formula text from DB
);
// WARNING: eval() is used here. Be cautious with this function!
eval('$sucrate = ' . $formula . ';');
$sucrate = max(5, min(95, (int)$sucrate)); // Keep rate between 5% and 95%
// Roll the dice!
$roll = rand(1, 100);
if ($roll <= $sucrate) {
// --- SUCCESS ---
echo "<br />" . str_replace('{money}', $crime_data['crimeSUCCESSMUNY'], $crime_data['crimeSTEXT']);
// Calculate rewards
$gain_money = $crime_data['crimeSUCCESSMUNY'];
$gain_crys = $crime_data['crimeSUCCESSCRYS'];
$gain_xp = (int) ($gain_money / 8); // Example XP calculation
$gain_crimexp = $crime_data['crimeXP'];
// Update user in database
$db->query("UPDATE users
SET money = money + {$gain_money},
crystals = crystals + {$gain_crys},
exp = exp + {$gain_xp},
crimexp = crimexp + {$gain_crimexp}
WHERE userid = $userid");
// Give item if applicable
if ($crime_data['crimeSUCCESSITEM'] > 0) {
// item_add() will be covered in Chapter 4
item_add($userid, $crime_data['crimeSUCCESSITEM'], 1);
echo "<br />You also found an item!";
}
} elseif (rand(1, 3) == 1 && $crime_data['crimeJAILTIME'] > 0) {
// --- JAILED (Example: 1 in 3 chance on failure, if crime can jail) ---
echo "<br />" . $crime_data['crimeJTEXT'];
$db->query("UPDATE users
SET jail = {$crime_data['crimeJAILTIME']},
jail_reason = '{$db->escape($crime_data['crimeJREASON'])}'
WHERE userid = $userid");
} else {
// --- FAILURE ---
echo "<br />" . $crime_data['crimeFTEXT'];
// Only Brave was lost (already deducted)
}
echo "<br /><br /><a href='docrime.php?c={$crime_id}'>Try Again</a>";
echo "<br /><a href='criminal.php'>Back to Crimes</a>";
$h->endpage(); // Finish the page
?>
- Gets Crime ID: Reads
$_GET['c']
. - Fetches Data: Loads the specific crime's details (
$crime_data
). - Checks Brave: Compares
$ir['brave']
to$crime_data['crimeBRAVE']
. - Deducts Brave: Updates the
users
table immediately. - Calculates Success (
$sucrate
): Usesstr_replace
to put player stats into the formula string from the database, then useseval()
to run it. Limits the result to a reasonable range (5-95%). - Random Roll: Uses
rand(1, 100)
to determine the outcome. - Handles Outcomes: Uses
if/elseif/else
blocks:- Success: Prints success text, calculates gains, updates
users
table with rewards, and callsitem_add()
if needed (more in Chapter 4: Item Management). - Jail: Prints jail text, updates
users
table with jail time and reason. (Note: The chance of jail on failure might vary). - Failure: Prints failure text.
- Success: Prints success text, calculates gains, updates
- Provides Links: Lets the user try again or go back to the main crime list.
3. Database (crimes
Table)
This table, defined in dbdata.sql
, stores all the information about each crime. Key columns include:
-
crimeID
: Unique number for the crime. -
crimeNAME
: Name displayed to the player (e.g., "Search the streets"). -
crimeBRAVE
: How much Brave it costs. -
crimePERCFORM
: The formula string used to calculate success rate (e.g.,'LEVEL*2 + WILL*1'
). -
crimeSUCCESSMUNY
: Money reward on success. -
crimeSUCCESSCRYS
: Crystal reward on success. -
crimeSUCCESSITEM
: ID of the item reward on success (0 if none). We'll learn about items in Chapter 4: Item Management. -
crimeGROUP
: Which group the crime belongs to (links tocrimegroups
table). -
crimeITEXT
: Text shown when the crime is attempted. -
crimeSTEXT
: Text shown on success. -
crimeFTEXT
: Text shown on simple failure. -
crimeJTEXT
: Text shown when jailed. -
crimeJAILTIME
: How long (in minutes/seconds, depends on game setup) the player is jailed for. -
crimeJREASON
: Reason displayed when jailed. -
crimeXP
: Crime XP awarded on success.
Admins can add, edit, or delete crimes and crime groups using the Staff Panel (staff_crimes.php
), which modifies this database table.
Conclusion
You've now learned about the Crime System, a fundamental PVE (Player vs Environment) activity in MCCodes!
- Players visit
criminal.php
to see a list of crimes. - Each crime costs Brave and has a chance of Success, Failure, or Jail.
- Clicking "Do" runs
docrime.php
, which checks requirements, deducts Brave, calculates success based on player stats and the crime's formula, and determines the outcome using random chance. - Success yields rewards like money, XP, items, failure just loses Brave, and jail locks the player out temporarily.
- The
crimes
table in the database stores all the details for each crime.
This system provides a core gameplay loop where players can risk resources (Brave) to gain rewards and improve their character, driven by their stats and a little luck.
Speaking of rewards, many crimes can award items. But how are items managed, stored, and used? Let's find out!
Next Up: Chapter 4: Item Management
Previously: Chapter 2: Global Setup & Session Management
First published April 21, 2025
Tags: MCCodes Walkthrough Tutorial