MCCodes - Chapter 6: Gang System

MCCodes Walkthrough Tutorial

Welcome to Chapter 6! In Chapter 5: Attacking System, we saw how you can use your stats and items to fight other players. But sometimes, strength comes in numbers! What if you want to team up with other players, work together, share resources, and maybe even fight other teams? That's where the Gang System comes in.

The Problem: Teaming Up for Fun and Profit

Playing solo is fine, but many games are more fun with friends or teammates. How can players form persistent groups, manage their membership, share resources like money, communicate privately, participate in group activities, and even engage in conflicts with other groups?

The Solution: MCCodes provides a robust Gang System. Think of it like a virtual clubhouse or team management system. It allows players to create or join groups called "gangs". Once inside, members can:

It adds a whole layer of social interaction and cooperative gameplay to the game.

How Gangs Work: A Clubhouse Tour

Let's explore the different parts of the Gang System from a player's perspective.

1. Finding a Clubhouse (gangcentral.php)

Just like looking for clubs in a town, you need a place to see which gangs exist. This is handled by gangcentral.php.

When you visit this page, you'll typically see a list of all the gangs in the game:

Gang Central

> Create A Gang Here

Gang Listings
--------------------------------------------------
Gang        | Members | President   | Respect
--------------------------------------------------
The Sharks  | 15      | Big Tuna    | 1500
The Jets    | 12      | Riff        | 1200
... more gangs ...
--------------------------------------------------

This page shows you the basic info and provides links to view each gang in more detail or to start your own gang (if you meet the requirements, like having enough money - see creategang.php).

2. Looking Inside a Clubhouse (gangs.php)

Clicking on a gang's name (like "The Sharks") in the Gang Central list takes you to gangs.php?action=view&ID=GangID. This page shows you the public profile of that specific gang.

Here you might see:

3. Joining the Club (Applying via gangs.php)

If you're not already in a gang and you like what you see, you can click the "Apply" link on the gang's profile page (gangs.php?action=apply&ID=GangID).

This usually presents a form where you can write a short message explaining why you want to join. Clicking "Submit" sends your application to the gang's leaders.

4. Inside the Clubhouse (yourgang.php) - The Member Hub

Once your application is accepted (or if you created the gang), you gain access to the members-only area: yourgang.php. This is the main hub for everything related to your gang.

yourgang.php typically has several sections or links:

5. Clubhouse Management (Staff Roles)

Gangs have a hierarchy:

These roles allow for organized management of the gang's affairs.

How It Works Under the Hood

Let's trace the flow of viewing gangs and applying to join.

Step-by-Step Walkthrough:

  1. Visit Central: You click the "Gang Central" link, requesting gangcentral.php.
  2. Setup: gangcentral.php includes globals.php (Chapter 2: Global Setup & Session Management) to set up your session, connect to the DB ($db), load your info ($ir), etc.
  3. Fetch Gangs: It queries the gangs table, possibly joining with users to get the President's name.
  4. Display List: It loops through the results and displays the HTML table of gangs, including links to gangs.php?action=view&ID=... for each.
  5. View Specific Gang: You click a link, requesting gangs.php?action=view&ID=GangID.
  6. Setup: gangs.php includes globals.php.
  7. Fetch Details: It uses the GangID from the URL ($_GET['ID']) to query the gangs table for that specific gang's details (name, desc, president ID, VP ID, respect). It also queries users to get the President/VP names and counts members.
  8. Display Profile: It shows the gang's profile information and provides links like "Apply" (gangs.php?action=apply&ID=...).
  9. Click Apply: You click the apply link, requesting gangs.php?action=apply&ID=GangID.
  10. Show Form: If you're not already in a gang ($ir['gang'] == 0), it displays the application text area and a submit button (pointing to gangs.php?action=applys&ID=...). It includes a CSRF token for security (Chapter 9: Security Functions (CSRF/Password/Validation)).
  11. Submit Application: You fill out the form and submit it. The request goes to gangs.php?action=applys&ID=GangID with your text ($_POST['application']) and the CSRF token.
  12. Process Application:
    • gangs.php includes globals.php.
    • It verifies the CSRF token.
    • It checks again if you're already in a gang.
    • If all checks pass, it inserts a new row into the applications table containing your User ID, the Gang ID, and your application text.
    • It also inserts a record into the gangevents table to notify the gang leaders that a new application arrived.
    • It displays a success message "Application Sent".
  13. Approval (Later): A gang leader (President/VP) logs in, goes to yourgang.php, navigates to the Staff > Applications section. They see your application, read your text, and click "Accept" or "Decline". Accepting adds your $userid to the gang (UPDATE users SET gang = GangID WHERE userid = $userid) and deletes the application record. Declining just deletes the application record. You get an event notification either way.

Sequence Diagram (Viewing & Applying):

sequenceDiagram
    participant B as Browser
    participant GC as gangcentral.php
    participant GP as gangs.php
    participant DB as Database
    participant YG as yourgang.php (Staff)

    B->>GC: Request gangcentral.php
    GC->>DB: Fetch list of gangs
    DB-->>GC: Gang data
    GC-->>B: Display gang list (links to gangs.php)

    B->>GP: Request gangs.php?action=view&ID=X
    GP->>DB: Fetch details for Gang X
    DB-->>GP: Gang profile data
    GP-->>B: Display Gang X profile (with Apply link)

    B->>GP: Click Apply link (gangs.php?action=apply&ID=X)
    GP-->>B: Display application form (if not in gang)

    B->>GP: Submit Application (gangs.php?action=applys&ID=X + text)
    GP->>GP: Verify CSRF, check if already in gang
    GP->>DB: INSERT into `applications` table (userID, gangID, text)
    GP->>DB: INSERT into `gangevents` table (notify leaders)
    DB-->>GP: Inserts successful
    GP-->>B: Display "Application Sent"

    Note over B, YG: Later... Gang Leader logs in
    B->>YG: Request yourgang.php?action=staff&act2=apps
    YG->>DB: Fetch applications for Gang X
    DB-->>YG: List of applications (including yours)
    YG-->>B: Display application list with Accept/Decline buttons

    B->>YG: Leader clicks Accept (POST to yourgang.php)
    YG->>YG: Verify CSRF
    YG->>DB: UPDATE users SET gang = X WHERE userid = YourID
    YG->>DB: DELETE from `applications` table
    YG->>DB: INSERT into `gangevents` (notify members)
    YG->>DB: INSERT into `events` (notify applicant)
    DB-->>YG: Updates successful
    YG-->>B: Display "Application Accepted"

This shows the journey from discovering a gang to submitting an application and how it gets processed by the gang's staff later via yourgang.php.

Diving into the Code

Let's look at simplified code snippets.

(Note:* MCCodes often uses global $db, $ir, $userid, $h; at the start of functions to access variables defined in globals.php. While functional, modern PHP often encourages passing these as arguments or using object properties instead.)*

1. gangcentral.php (Listing Gangs)

<?php
// File: gangcentral.php (Simplified)
require_once('globals.php'); // Setup $ir, $db, $h

echo "<h3>Gang Central</h3>";
// Link to create a gang (checks money/gang status inside creategang.php)
echo "<a href='creategang.php'>&gt; Create A Gang Here</a><br />";
echo "<hr /><u>Gang Listings</u><br />";
echo "<table cellspacing=1 class='table'>
        <tr><th>Gang</th><th>Members</th><th>President</th><th>Respect</th></tr>";

// Query to get all gangs and their presidents' names
$gq = $db->query(
    "SELECT g.gangID, g.gangNAME, g.gangRESPECT, u.userid, u.username
     FROM gangs AS g
     LEFT JOIN users AS u ON g.gangPRESIDENT = u.userid
     ORDER BY g.gangID ASC"
);

while ($gangdata = $db->fetch_row($gq)) {
    // Count members for this gang
    $count_query = $db->query(
        "SELECT COUNT(userid) FROM users WHERE gang = {$gangdata['gangID']}"
    );
    $member_count = $db->fetch_single($count_query);
    $db->free_result($count_query);

    // Display row
    echo "<tr>
            <td><a href='gangs.php?action=view&ID={$gangdata['gangID']}'>{$gangdata['gangNAME']}</a></td>
            <td>{$member_count}</td>
            <td><a href='viewuser.php?u={$gangdata['userid']}'>{$gangdata['username']}</a></td>
            <td>{$gangdata['gangRESPECT']}</td>
          </tr>";
}
$db->free_result($gq); // Free the main query result
echo '</table>';
$h->endpage();
?>

2. gangs.php (Viewing a Gang Profile & Applying)

<?php
// File: gangs.php (Simplified)
require_once('globals.php'); // Setup $ir, $db, $h

// Get Gang ID from URL, ensure it's a positive number
$_GET['ID'] = isset($_GET['ID']) ? abs((int)$_GET['ID']) : 0;
if (!$_GET['ID']) { die("Invalid Gang ID."); }
$gang_id = $_GET['ID'];

// Fetch this specific gang's data
$gq = $db->query(
    "SELECT gangPRESIDENT, gangVICEPRES, gangNAME, gangID, gangRESPECT, gangDESC
     FROM gangs
     WHERE gangID = {$gang_id}"
);
if ($db->num_rows($gq) == 0) { die("Gang not found."); }
$gangdata = $db->fetch_row($gq);
$db->free_result($gq);

// Default action is 'view'
$action = $_GET['action'] ?? 'view';

// --- VIEW ACTION ---
if ($action == 'view') {
    echo "<h3><u>{$gangdata['gangNAME']} Gang</u></h3><hr />";

    // Fetch President Name
    $pres_q = $db->query("SELECT username FROM users WHERE userid = {$gangdata['gangPRESIDENT']}");
    $pres_name = ($db->num_rows($pres_q) > 0) ? $db->fetch_single($pres_q) : 'N/A';
    $db->free_result($pres_q);
    echo "President: {$pres_name}<br />";

    // Fetch Vice-President Name (similar query)
    // ... code to get VP name ...
    echo "Vice-President: {$vp_name}<hr />";

    // Count Members
    $count_q = $db->query("SELECT COUNT(userid) FROM users WHERE gang = {$gang_id}");
    $member_count = $db->fetch_single($count_q);
    $db->free_result($count_q);
    echo "Members: {$member_count}<br />";
    echo "Description: {$gangdata['gangDESC']}<br />";
    echo "Respect Level: {$gangdata['gangRESPECT']}<br />";

    // Links
    echo "&gt; <a href='gangs.php?action=userlist&ID={$gang_id}'>User List</a><br />";
    if ($ir['gang'] == 0) { // Only show Apply link if user is not in a gang
        echo "&gt; <a href='gangs.php?action=apply&ID={$gang_id}'>Apply</a>";
    }
}
// --- APPLY FORM ACTION ---
elseif ($action == 'apply') {
    if ($ir['gang'] == 0) {
        $apply_csrf = request_csrf_code('gang_apply'); // Generate CSRF token
        echo "<h3>Apply to {$gangdata['gangNAME']}</h3>";
        echo "<form action='gangs.php?action=applys&ID={$gang_id}' method='post'>
                Why should you be accepted?<br />
                <textarea name='application' rows='7' cols='40'></textarea><br />
                <input type='hidden' name='verf' value='{$apply_csrf}' />
                <input type='submit' value='Send Application' />
              </form>";
    } else {
        echo 'You are already in a gang.';
    }
}
// --- SUBMIT APPLICATION ACTION ---
elseif ($action == 'applys') {
    if (!$ir['gang']) {
        // Verify CSRF token
        if (!isset($_POST['verf']) || !verify_csrf_code('gang_apply', stripslashes($_POST['verf']))) {
            die("CSRF validation failed. Please try applying again.");
        }

        $application_text = $db->escape(htmlentities(stripslashes($_POST['application'] ?? ''), ENT_QUOTES, 'ISO-8859-1'));

        // Insert into applications table
        $db->query(
            "INSERT INTO applications (appUSER, appGANG, appTEXT)
             VALUES($userid, {$gang_id}, '{$application_text}')"
        );

        // Add gang event
        $gang_event_text = $db->escape("<a href='viewuser.php?u={$userid}'>{$ir['username']}</a> applied.");
        $db->query(
            "INSERT INTO gangevents (gevGANG, gevTIME, gevTEXT)
             VALUES({$gang_id}, " . time() . ", '{$gang_event_text}')"
        );

        echo "Application sent to {$gangdata['gangNAME']}!";
    } else {
        echo 'You are already in a gang.';
    }
}
// ... other actions like userlist ...

$h->endpage();
?>

3. yourgang.php (The Member Hub - Simplified Index & Donate)

<?php
// File: yourgang.php (Simplified Index/Donate)
require_once('globals.php'); // Setup $ir, $db, $h

// Check if user is actually in a gang
if (!$ir['gang']) {
    die("You're not in a gang.");
}

// Fetch data for the user's gang
$gq = $db->query("SELECT * FROM gangs WHERE gangID = {$ir['gang']}");
if ($db->num_rows($gq) == 0) { die("Your gang seems to have been deleted."); }
$gangdata = $db->fetch_row($gq);
$db->free_result($gq);

echo "<h3><u>Your Gang - {$gangdata['gangNAME']}</u></h3>";

// --- Determine Action ---
$action = $_GET['action'] ?? 'index'; // Default to index view

// --- INDEX ACTION ---
if ($action == 'index') {
    echo "<table cellspacing=1 class='table'>
            <tr><td><a href='yourgang.php?action=summary'>Summary</a></td>
                <td><a href='yourgang.php?action=donate'>Donate</a></td></tr>
            <tr><td><a href='yourgang.php?action=members'>Members</a></td>
                <td><a href='yourgang.php?action=crimes'>Crimes</a></td></tr>
            <tr><td><a href='yourgang.php?action=forums'>Forums</a></td>
                <td><a href='yourgang.php?action=leave'>Leave</a></td></tr>";
    // Show Staff link only if President or VP
    if ($gangdata['gangPRESIDENT'] == $userid || $gangdata['gangVICEPRES'] == $userid) {
        echo "<tr><td colspan='2'><a href='yourgang.php?action=staff&act2=idx'>Staff Room</a></td></tr>";
    }
    echo "</table><br />";

    echo "<b>Gang Announcement:</b><br /><div>{$gangdata['gangAMENT']}</div><br />";

    // Show last 10 events (query gangevents table, loop and display)
    // ... code to fetch and display last 10 events ...
}
// --- DONATE FORM ACTION ---
elseif ($action == 'donate') {
    $donate_csrf = request_csrf_code('yourgang_donate');
    echo "<b>Donate to the Vault</b><br />";
    echo "Vault has: " . money_formatter($gangdata['gangMONEY']) . " and {$gangdata['gangCRYSTALS']} crystals.<br />";
    echo "You have: " . money_formatter($ir['money']) . " and {$ir['crystals']} crystals.<br />";
    echo "<form action='yourgang.php?action=donate2' method='post'>
            Money: <input type='text' name='money' value='0' /><br />
            Crystals: <input type='text' name='crystals' value='0' /><br />
            <input type='hidden' name='verf' value='{$donate_csrf}' />
            <input type='submit' value='Donate' />
          </form>";
}
// --- DONATE SUBMIT ACTION ---
elseif ($action == 'donate2') {
    // Verify CSRF
    if (!isset($_POST['verf']) || !verify_csrf_code('yourgang_donate', stripslashes($_POST['verf']))) {
        die("CSRF validation failed. Please try donating again.");
    }

    $money_to_donate = isset($_POST['money']) ? abs((int)$_POST['money']) : 0;
    $crystals_to_donate = isset($_POST['crystals']) ? abs((int)$_POST['crystals']) : 0;

    // Check if player has enough
    if ($money_to_donate > $ir['money'] || $crystals_to_donate > $ir['crystals']) {
        die("You don't have enough to donate that amount.");
    }
    if ($money_to_donate == 0 && $crystals_to_donate == 0) {
        die("You didn't specify an amount to donate.");
    }

    // Update player's balance
    $db->query("UPDATE users SET money = money - {$money_to_donate}, crystals = crystals - {$crystals_to_donate} WHERE userid = $userid");
    // Update gang vault
    $db->query("UPDATE gangs SET gangMONEY = gangMONEY + {$money_to_donate}, gangCRYSTALS = gangCRYSTALS + {$crystals_to_donate} WHERE gangID = {$ir['gang']}");

    // Log gang event
    $donate_event_text = $db->escape("<a href='viewuser.php?u={$userid}'>{$ir['username']}</a> donated.");
    $db->query("INSERT INTO gangevents (gevGANG, gevTIME, gevTEXT) VALUES({$ir['gang']}, " . time() . ", '{$donate_event_text}')");

    echo "Donation successful!";
}
// --- STAFF ACTIONS (Example: Apps) ---
elseif ($action == 'staff' && ($gangdata['gangPRESIDENT'] == $userid || $gangdata['gangVICEPRES'] == $userid)) {
    $staff_action = $_GET['act2'] ?? 'idx';
    if ($staff_action == 'apps') {
        // Check if accepting/declining
        $app_id = isset($_POST['app']) ? abs((int)$_POST['app']) : 0;
        $app_what = isset($_POST['what']) ? $_POST['what'] : ''; // 'accept' or 'decline'

        if ($app_id > 0 && ($app_what == 'accept' || $app_what == 'decline')) {
             // Verify CSRF for the specific app action form
             // ... CSRF check ...

             // Fetch application details (appUSER, username)
             // ... DB query for application ...

             if ($app_what == 'accept') {
                 // Check gang capacity
                 // ... DB query to count members ...
                 // if (member_count >= gangdata['gangCAPACITY']) { die("Gang is full."); }

                 // Add user to gang
                 // ... UPDATE users SET gang = gangID WHERE userid = appUSER ...
                 // ... DELETE from applications ...
                 // ... Add events (user event, gang event) ...
                 echo "Application accepted.";

             } else { // Decline
                 // ... DELETE from applications ...
                 // ... Add events (user event, gang event) ...
                 echo "Application declined.";
             }

        } else {
            // Display list of applications
            echo "<b>Applications</b><br />";
            // ... Query applications table ...
            // ... Loop and display each application with Accept/Decline forms (including CSRF tokens per form) ...
        }
    }
    // ... other staff actions (vault, upgrades, wars etc.) ...
}

$h->endpage();
?>

Key Files and Tables

Conclusion

You've now learned about the Gang System in MCCodes! It's like a comprehensive clubhouse management system built into the game.

This system adds a significant social and cooperative dimension, allowing players to form alliances, share resources, and achieve goals together.

Many game systems need things to happen automatically on a schedule -- like refilling energy, ending jail sentences, or processing gang crime results. How does MCCodes handle these timed events?


Next Up: Chapter 7: Cron Job System

Previously: Chapter 5: Attacking System


First published April 21, 2025

Tags: MCCodes Walkthrough Tutorial