MCCodes - Chapter 5: Attacking System
Welcome to Chapter 5! In Chapter 4: Item Management, we saw how you can get items like weapons and armor. Now, it's time to learn how you can put that gear to use against other players in the game's Attacking System.
The Problem: Proving Your Strength
So far, we've seen how to interact with the game world (Crimes) and manage your character's belongings (Items). But what about interacting directly with other players? How can you test your character's strength against theirs? How does the game handle fights, determine who wins, and what happens afterward?
The Solution: MCCodes has a built-in Attacking System that handles Player-vs-Player (PvP) combat. Think of it like the referee and rulebook for a duel or a street fight. When you decide to attack another player, a specific set of files manages the entire process:
- Initiating the Fight: Starting the attack and checking if it's allowed.
- Calculating Blows: Figuring out if attacks hit or miss, and how much damage they do based on stats and equipment.
- Tracking Health: Reducing players' health points (HP) as they take damage.
- Determining the Winner: Deciding who wins when one player's HP drops to zero (or near zero).
- Handling the Aftermath: Giving rewards (like money or experience) to the winner, potentially penalizing the loser, and maybe sending the loser to the hospital.
This system makes sure fights follow consistent rules and have clear outcomes.
How to Use the Attacking System (As a Player)
Imagine you want to pick a fight with another player named "BadGuyBob". Here's how it typically unfolds:
- Find Your Target: You might find BadGuyBob's profile page by clicking their name somewhere in the game (like a user list or forum post).
- Click "Attack": On their profile, you'll likely see an "[Attack]" link. Clicking this link usually takes you to
attack.php
, telling it who you want to fight (e.g.,attack.php?ID=BobUserID
). - Prepare for Battle: The
attack.php
page loads. It first checks if you can attack Bob (Are you both in the same location? Are you healthy enough? Do you have enough energy?). If everything is okay, it will show you:- Your health vs. Bob's health.
- A list of weapons you have equipped (like "Fists", "Knife", "Pistol").
- Choose Your Weapon: You click on the weapon you want to use for your first attack. This tells
attack.php
which weapon's stats to use. - Exchange Blows: The page refreshes, showing the result of your attack:
- "You hit BadGuyBob with your Knife for 10 damage!" (Bob's HP goes down).
- "You tried to hit BadGuyBob but missed!" (Bob's HP stays the same). Then, the page also shows Bob's counter-attack:
- "BadGuyBob hit you with his Fists for 5 damage!" (Your HP goes down).
- "BadGuyBob tried to hit you but missed!" (Your HP stays the same).
- Continue the Fight: If neither player is defeated, the page shows the updated health bars and asks you to choose a weapon again for the next round. This continues back and forth.
- The Outcome: Eventually, someone's HP will drop to 0 or 1.
- You Win: If you defeat Bob, the page might change to show options like "Mug Them" (steal money), "Hospitalize Them" (send them to the hospital for a long time), or "Leave Them" (just walk away, maybe gain some XP). Clicking one of these options takes you to a different page (like
attackwon.php
orattackbeat.php
) to process the final result. - You Lose: If Bob defeats you, the page might automatically redirect you to
attacklost.php
, telling you that you lost and potentially penalizing you (like losing some experience points).
- You Win: If you defeat Bob, the page might change to show options like "Mug Them" (steal money), "Hospitalize Them" (send them to the hospital for a long time), or "Leave Them" (just walk away, maybe gain some XP). Clicking one of these options takes you to a different page (like
How it Works Under the Hood: attack.php
- The Referee
The main file controlling the fight is attack.php
. Let's walk through what happens step-by-step when you initiate and fight one round.
Step-by-Step Walkthrough (One Round):
- Request: You click "[Attack]" on Bob's profile, sending a request like
attack.php?ID=BobUserID
. - Setup & Checks:
-
attack.php
includesglobals.php
. This gets your info ($ir
) and connects to the database ($db
), as explained in Chapter 2: Global Setup & Session Management. - It fetches Bob's user data from the database (
$odata
). - It runs many checks: Are you attacking yourself? Are you or Bob in jail/hospital? Are you both in the same location? Do you have enough energy (usually 50% required to start)? If any check fails, it stops with an error message.
-
- Energy Cost: If this is the very first time you're initiating the attack sequence against Bob (checked using a special PHP variable called
$_SESSION['attacking']
), it deducts the energy cost from your account ($ir['energy']
) and updates the database. It also resets any log of previous damage from this fight. - Display Interface: If no weapon was chosen yet (
$_GET['wepid']
is not set), it displays the health bars for you and Bob, and shows links for each of your equipped weapons. Each link points back toattack.php
but includes the weapon ID (wepid
) and the next step number (nextstep=1
). - Attacker's Turn (Weapon Chosen): You click the link for your "Knife". The request is now something like
attack.php?ID=BobUserID&wepid=KnifeID&nextstep=1
.-
attack.php
sees thewepid
. - It gets the Knife's stats (
weapon
power) from theitems
table. - Hit Chance: It calculates your chance to hit Bob, usually based on your Agility vs. Bob's Agility (
$hitratio = max(10, min(60 * $ir['agility'] / $odata['agility'], 95))
). This keeps the chance between 10% and 95%. - Roll for Hit: It generates a random number (
rand(1, 100)
). If the number is less than or equal to$hitratio
, it's a hit! - Calculate Damage (if Hit):
- Base damage depends on the weapon's power, your Strength, and Bob's Guard stat (
$mydamage = ($weapon_power * $ir['strength'] / ($odata['guard'] / 1.5)) * random_factor
). - It checks if Bob has armor equipped (
$odata['equip_armor']
). If yes, it gets the armor's rating from theitems
table and subtracts it from$mydamage
. - Damage cannot go below 1 (usually). Sometimes there's a small chance for critical hits (more damage) or glancing blows (less damage).
- The final damage is rounded.
- Base damage depends on the weapon's power, your Strength, and Bob's Guard stat (
- Apply Damage & Log: If it was a hit, Bob's HP is reduced (
$odata['hp'] -= $mydamage
), and theusers
table is updated in the database. A message like "You hit Bob for X damage" is shown and added to a temporary log stored in$_SESSION['attacklog']
. - If it was a miss, a "You missed" message is shown and logged.
-
- Check Defender Defeat: The script checks if Bob's HP is now less than or equal to 1 (
$odata['hp'] <= 1
). If yes, the fight is over! It displays the "You Won!" options (Mug/Hospitalize/Leave) which link toattackwon.php
,attackbeat.php
, orattacktake.php
. - Defender's Turn (If Not Defeated): If Bob is still standing:
- The script randomly chooses one of Bob's equipped weapons (or Fists if none).
- It calculates Bob's hit chance against you (Bob's Agility vs. your Agility).
- It rolls for Bob's hit.
- If Bob hits, it calculates damage (Bob's Strength, Bob's weapon, your Guard, your armor).
- It applies damage to your HP (
$youdata['hp'] -= $dam
), updates your record in theusers
table, and logs the result (e.g., "Bob hit you for Y damage"). - If Bob misses, it logs the miss.
- Check Attacker Defeat: The script checks if your HP is now less than or equal to 1 (
$youdata['hp'] <= 1
). If yes, the fight is over! It shows a "Continue" button that links toattacklost.php
. - Next Round: If neither player is defeated, the script displays the updated health bars and the weapon selection links again, but this time the links will have
nextstep=3
(since step 1 was your attack and step 2 was the counter-attack).
Sequence Diagram (Simplified Attack Round):
sequenceDiagram participant B as Browser participant AP as attack.php participant G as globals.php participant DB as Database B->>AP: Request attack.php?ID=TargetID (Initial) AP->>G: require 'globals.php' G->>DB: Fetch Attacker ($ir) & Settings ($set) G-->>AP: Setup done AP->>DB: Fetch Defender ($odata) data DB-->>AP: Defender data received AP->>AP: Perform checks (location, energy, jail, etc.) alt First step of attack AP->>DB: Deduct energy cost from attacker AP->>AP: Initialize attack log in session end AP-->>B: Display health bars & weapon choices (links with wepid & nextstep=1) B->>AP: Click weapon link (attack.php?ID=TargetID&wepid=X&nextstep=1) AP->>DB: Fetch weapon X details DB-->>AP: Weapon details received AP->>AP: Calculate Attacker hit chance & damage AP->>AP: Roll for hit alt Attacker Hits AP->>DB: Fetch Defender armor details (if any) DB-->>AP: Armor details received AP->>AP: Apply armor reduction to damage AP->>DB: Update Defender HP in users table AP->>AP: Log hit details in session else Attacker Misses AP->>AP: Log miss details in session end AP->>AP: Check if Defender defeated alt Defender NOT Defeated AP->>AP: Calculate Defender counter-attack (choose weapon, calc hit/dmg) AP->>AP: Roll for Defender hit alt Defender Hits AP->>DB: Fetch Attacker armor details (if any) DB-->>AP: Armor details received AP->>AP: Apply armor reduction to damage AP->>DB: Update Attacker HP in users table AP->>AP: Log defender hit in session else Defender Misses AP->>AP: Log defender miss in session end AP->>AP: Check if Attacker defeated alt Attacker NOT Defeated AP-->>B: Display round results & weapon choices (nextstep=3) else Attacker Defeated AP-->>B: Display results & link to attacklost.php end else Defender Defeated AP-->>B: Display results & links to attackwon/beat/take.php end
This diagram shows the back-and-forth calculation within a single request to attack.php
once a weapon is chosen.
Diving into the Code
Let's look at simplified snippets from the core files.
1. attack.php
(The Core Logic - Simplified)
<?php
// File: attack.php (Simplified Concept)
require_once('globals.php'); // Loads $ir, $db, $h, session etc.
// --- Get Target ID & Initial Checks ---
$target_id = isset($_GET['ID']) ? abs((int)$_GET['ID']) : 0;
if (!$target_id || $target_id == $userid) { die("Invalid target."); }
if ($ir['hp'] <= 1) { die("You are unconscious."); }
// ... (many other checks: jail, hospital, location, energy check for first hit) ...
// --- Fetch Target Data ---
$q = $db->query("SELECT u.*, us.* FROM users u JOIN userstats us ON u.userid=us.userid WHERE u.userid = {$target_id}");
if ($db->num_rows($q) == 0) { die("Target does not exist."); }
$odata = $db->fetch_row($q);
$db->free_result($q);
// ... (more checks using $odata: target hp, jail, hospital) ...
$youdata = $ir; // Use $youdata for attacker, $odata for defender
// --- Process Weapon Choice (if made) ---
$chosen_wepid = isset($_GET['wepid']) ? abs((int)$_GET['wepid']) : 0;
if ($chosen_wepid > 0)
{
// Check if it's the first action in this fight sequence
if (!isset($_SESSION['attacking']) || $_SESSION['attacking'] == 0) {
if ($youdata['energy'] >= $youdata['maxenergy'] / 2) {
$cost = floor($youdata['maxenergy'] / 2);
$db->query("UPDATE users SET energy = energy - {$cost} WHERE userid = $userid");
$_SESSION['attacklog'] = ''; // Reset log
$_SESSION['attackdmg'] = 0; // Reset total damage
$youdata['energy'] -= $cost;
} else { die("Not enough energy to start."); }
}
$_SESSION['attacking'] = 1; // Mark attack as in progress in session
$db->query("UPDATE users SET attacking = {$target_id} WHERE userid = $userid"); // Mark in DB too
// --- Attacker's Turn ---
$q_wep = $db->query("SELECT itmname, weapon FROM items WHERE itmid = {$chosen_wepid}");
if ($db->num_rows($q_wep) == 0) { die("Invalid weapon chosen."); }
$weapon_info = $db->fetch_row($q_wep);
$db->free_result($q_wep);
// Calculate Hit Chance (simplified)
$hitratio = max(10, min(60 * $youdata['agility'] / $odata['agility'], 95));
$did_hit = (rand(1, 100) <= $hitratio);
if ($did_hit) {
// Calculate Base Damage (simplified)
$mydamage = (int)(($weapon_info['weapon'] * $youdata['strength'] / ($odata['guard'] / 1.5)) * (rand(8000, 12000) / 10000));
// Apply Armor Reduction (simplified)
if ($odata['equip_armor'] > 0) {
$armor_rating = $db->fetch_single($db->query("SELECT armor FROM items WHERE itmid = {$odata['equip_armor']}"));
$mydamage -= $armor_rating;
}
$mydamage = max(1, $mydamage); // Ensure minimum damage
// Apply Damage & Update DB
$odata['hp'] -= $mydamage;
if ($odata['hp'] < 1) { $mydamage += abs($odata['hp']-1); $odata['hp'] = 0; } // Adjust damage if overkill
$db->query("UPDATE users SET hp = {$odata['hp']} WHERE userid = {$target_id}");
$log_msg = "{$_GET['nextstep']}. Using your {$weapon_info['itmname']} you hit {$odata['username']} doing {$mydamage} damage ({$odata['hp']})";
echo "<font color=red>{$log_msg}</font><br />\n";
$_SESSION['attacklog'] .= "<font color=red>{$log_msg}</font><br />\n";
$_SESSION['attackdmg'] += $mydamage; // Track total damage dealt
} else {
$log_msg = "{$_GET['nextstep']}. You tried to hit {$odata['username']} but missed ({$odata['hp']})";
echo "<font color=red>{$log_msg}</font><br />\n";
$_SESSION['attacklog'] .= "<font color=red>{$log_msg}</font><br />\n";
}
// --- Check if Defender is Defeated ---
if ($odata['hp'] <= 0) {
$_SESSION['attackwon'] = $target_id; // Store winner status in session
echo "<b>What do you want to do?</b><br />
<form action='attackwon.php?ID={$target_id}' method='post'><input type='submit' value='Mug Them' /></form>
<form action='attackbeat.php?ID={$target_id}' method='post'><input type='submit' value='Hospitalize Them' /></form>
<form action='attacktake.php?ID={$target_id}' method='post'><input type='submit' value='Leave Them' /></form>";
} else {
// --- Defender's Turn (Simplified - similar logic as attacker) ---
// ... Code to choose defender weapon, calculate hit, damage, apply to $youdata['hp'] ...
// ... Update $userid's HP in DB ...
// ... Log defender's action to screen and $_SESSION['attacklog'] ...
$defender_action_log = "..."; // Placeholder for defender's action message
echo $defender_action_log;
// --- Check if Attacker is Defeated ---
if ($youdata['hp'] <= 0) {
$_SESSION['attacklost'] = 1; // Store loser status in session
$db->query("UPDATE users SET hp = 0 WHERE userid = {$userid}"); // Ensure HP is 0
echo "<form action='attacklost.php?ID={$target_id}' method='post'><input type='submit' value='Continue' />";
}
// If no one is defeated, the code will fall through to show the weapon choice again
}
}
// --- Display Interface (If fight continues) ---
if ($youdata['hp'] > 0 && $odata['hp'] > 0)
{
// Display Health Bars (using simple images or text)
echo "Your Health: {$youdata['hp']}/{$youdata['maxhp']} | {$odata['username']}'s Health: {$odata['hp']}/{$odata['maxhp']}<br/>";
// Display Weapon Choices
echo "Attack with:<br />";
$next_step_num = isset($_GET['nextstep']) ? $_GET['nextstep'] + 2 : 1;
$q_myweps = $db->query("SELECT itmid, itmname FROM items WHERE itmid IN ({$ir['equip_primary']}, {$ir['equip_secondary']}) AND (weapon > 0 OR itmname = 'Fists')"); // Include Fists concept
while ($row = $db->fetch_row($q_myweps)) {
echo "<a href='attack.php?nextstep={$next_step_num}&ID={$target_id}&wepid={$row['itmid']}'>{$row['itmname']}</a><br />";
}
$db->free_result($q_myweps);
// ... (Add a link for Fists if no weapons equipped) ...
}
$h->endpage();
?>
- Includes
globals.php
: Essential for setup. - Checks: Lots of initial checks prevent invalid attacks.
- Fetches Data: Gets info for both attacker (
$youdata
, which is$ir
) and defender ($odata
). - Session Usage: Uses
$_SESSION['attacking']
,$_SESSION['attacklog']
,$_SESSION['attackdmg']
,$_SESSION['attackwon']
,$_SESSION['attacklost']
to keep track of the fight's state between page loads. This is important because each click on a weapon link is a new page request. - Weapon Choice (
$_GET['wepid']
): Triggers the core combat calculation. - Combat Logic: Calculates hit chance, damage, applies armor, updates HP in the database, and logs the results.
- Turn-Based: Attacker goes first, then defender (if still alive), then checks if attacker is alive.
- Outcome: If someone is defeated, it directs the player to the appropriate outcome page (
attackwon.php
,attacklost.php
, etc.). - Interface: If the fight continues, it shows health and weapon choices for the next round.
2. Outcome Files (attackwon.php
, attacklost.php
, etc. - Simplified Concepts)
These files handle the result after the fight in attack.php
is finished.
attackwon.php
(Mug Them):- Includes
globals.php
. - Gets target ID (
$_GET['ID']
). - Crucial Check: Verifies
$_SESSION['attackwon'] == $target_id
to prevent cheating (ensures the player actually won this fight according to the session). - Fetches target data (
$r
). - Calculates amount to steal (
$stole = round($r['money'] * percentage)
). - Updates attacker's money (
UPDATE users SET money = money + $stole WHERE userid = $userid
). - Updates defender's money and HP (
UPDATE users SET money = money - $stole, hp = 1, hospital = X, hospreason = 'Mugged by...' WHERE userid = $target_id
). - Adds an event for the defender:
event_add($target_id, "You were mugged by {$ir['username']}...")
. - Logs the full attack details:
INSERT INTO attacklogs ... VALUES (..., 'won', time(), $stole, '{$_SESSION['attacklog']}')
. - Resets session:
$_SESSION['attackwon'] = 0; $_SESSION['attacking'] = 0;
. - Displays a success message.
- Calls
$h->endpage()
.
- Includes
attacklost.php
(You Lost):- Includes
globals.php
. - Gets target ID (
$_GET['ID']
). - Fetches target data (
$r
). - Crucial Check: Verifies
$_SESSION['attacklost'] == 1
. - Calculates experience penalty (e.g., based on level difference).
- Updates attacker's XP (
UPDATE users SET exp = max(0, exp - $penalty), attacking = 0 WHERE userid = $userid
). - Adds an event for the winner:
event_add($target_id, "{$ir['username']} attacked you and lost.")
. - Logs the attack:
INSERT INTO attacklogs ... VALUES (..., 'lost', time(), 0, '{$_SESSION['attacklog']}')
. - Resets session:
$_SESSION['attacklost'] = 0; $_SESSION['attacking'] = 0;
. - Displays loss message and penalty.
- Calls
$h->endpage()
.
- Includes
attackbeat.php
(Hospitalize Them): Similar toattackwon.php
, but instead of stealing money, it sets a longer hospital time for the loser and potentially gives XP or respect (if gangs are involved) to the winner.attacktake.php
(Leave Them): Similar toattackwon.php
, but usually gives XP instead of money, and sets a shorter hospital time for the loser.
These outcome files ensure the consequences of the fight (rewards, penalties, status changes) are properly applied and logged.
Key Files and Tables
- Core Logic:
-
attack.php
: Manages the turn-based combat, calculates hits/damage, checks for win/loss conditions.
-
- Outcome Processing:
-
attackwon.php
: Handles the "Mug" outcome after winning. -
attacklost.php
: Handles the outcome after losing. -
attackbeat.php
: Handles the "Hospitalize" outcome after winning. -
attacktake.php
: Handles the "Leave Them" outcome after winning.
-
- Database Tables:
-
users
: Stores player HP, stats (Strength, Agility, Guard), equipped items (equip_primary
,equip_secondary
,equip_armor
), energy, location, jail/hospital status. -
userstats
: Stores the precise stat values. -
items
: Defines items, including weapon power (weapon
) and armor rating (armor
). Referenced via IDs in theusers
table. -
attacklogs
: Stores a record of completed attacks, including attacker, defender, result, time, amount stolen (if any), and the turn-by-turn log saved from$_SESSION['attacklog']
.
-
- PHP Sessions (
$_SESSION
): Used temporarily to store the state of an ongoing attack (like who won/lost, total damage, the fight log) across multiple page requests within the fight.
Conclusion
You've now seen how the Attacking System in MCCodes brings players into direct conflict!
- It starts with
attack.php
, which acts as the referee, checking rules and calculating hits and damage based on player stats and equipped items (Chapter 4: Item Management). - The fight progresses turn-by-turn, with HP updates stored in the database (
users
table). - PHP Sessions (
$_SESSION
) are used to remember the fight's state between turns. - Once a winner is determined, specialized files like
attackwon.php
orattacklost.php
handle the final consequences -- distributing rewards, applying penalties, and logging the encounter.
This system creates a dynamic way for players to test their strength and strategy against each other. Often, these attacks are related to another major feature: Gangs.
Next Up: Chapter 6: Gang System
Previously: Chapter 4: Item Management
First published April 21, 2025
Tags: MCCodes Walkthrough Tutorial