MCCodes - Chapter 5: Attacking System

MCCodes Walkthrough Tutorial

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:

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:

  1. 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).
  2. 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).
  3. 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").
  4. 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.
  5. 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).
  6. 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.
  7. 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 or attackbeat.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).

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):

  1. Request: You click "[Attack]" on Bob's profile, sending a request like attack.php?ID=BobUserID.
  2. Setup & Checks:
    • attack.php includes globals.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.
  3. 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.
  4. 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 to attack.php but includes the weapon ID (wepid) and the next step number (nextstep=1).
  5. 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 the wepid.
    • It gets the Knife's stats (weapon power) from the items 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 the items 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.
    • Apply Damage & Log: If it was a hit, Bob's HP is reduced ($odata['hp'] -= $mydamage), and the users 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.
  6. 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 to attackwon.php, attackbeat.php, or attacktake.php.
  7. 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 the users table, and logs the result (e.g., "Bob hit you for Y damage").
    • If Bob misses, it logs the miss.
  8. 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 to attacklost.php.
  9. 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();
?>

2. Outcome Files (attackwon.php, attacklost.php, etc. - Simplified Concepts)

These files handle the result after the fight in attack.php is finished.

These outcome files ensure the consequences of the fight (rewards, penalties, status changes) are properly applied and logged.

Key Files and Tables

Conclusion

You've now seen how the Attacking System in MCCodes brings players into direct conflict!

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