A charming, early-2000s JRPG prototype that captures the spirit of classic adventures. Assemble a party, explore handcrafted maps, and battle using an active time system where initiative, spells, items, and equipment all matter. Its script-driven events and dialogue give creators a playful toolkit to shape quests and moments.
Though modest and unfinished, Spirit of Gaia evokes retro warmth—perfect for fans of classic fantasy and developers who appreciate fast iteration and imaginative systems. It’s an inspiring foundation for hobby projects and nostalgic worlds.
Game Name: Spirit of Gaia (SoG)
Version: 0.0.3 (Alpha/Prototype)
Genre: Browser-based fantasy RPG
Developer: jezze (
License: GNU GPL (Open Source)
Project URL: http://phpfantasyrpg.sourceforge.net/
Release Era: ~2003
Inspiration: Secret of Mana, Final Fantasy (Square Soft classics)
Status: UNFINISHED PROTOTYPE - Developer admits "full of bugs and missing features"
---
Total Files: 64
File Breakdown:
Total Size: ~425 KB
Key Directories:
/ - 6 main PHP files (index, login, game, engine, admin)/includes/ - 15 include files (library, data, load, save, use, page templates)/gfx/ - 40 PNG graphics (classes/, enemies/ subdirectories)/data/ - 1 SQL file (data.sql - 12 KB)/docs/ - 2 TXT files (readme.txt, scriptsystem.txt)Lines of Code: 1,672 PHP lines (smallest game analyzed!)
---
PHP Architecture:
register_globals = Off (security-conscious!)Database Configuration (includes/data.inc.php):
`php
$db_hostname = "localhost";
$db_username = "root";
$db_password = "";
$db_name = "phpfantasyrpg";
mysql_connect($db_hostname, $db_username, $db_password);
mysql_select_db($db_name);
`
Clean Configuration: No hardcoded production credentials (unlike Robot Warz!)
Session Storage (login.php):
`php
$_SESSION["User"] = array(); // User account data
$_SESSION["Players"] = array(); // Party members
$_SESSION["Enemies"] = array(); // Battle enemies
$_SESSION["Map"] = array(); // Current map
$_SESSION["Messages"] = array(); // Game messages (rolling 5)
$_SESSION["Script"] = array(); // Script engine state
$_SESSION["Triggers"] = array(); // Quest triggers
$_SESSION["Head"] = array(); // Text header
$_SESSION["Text"] = array(); // Text content
$_SESSION["Module"] = "Explore"; // Current game mode
`
Everything in Memory: All game state stored in PHP sessions (no persistent save!)
Game Modules ($_SESSION["Module"]):
Module Switching:
`php
function module_select($module)
{
$_SESSION["Module"] = $module;
}
`
12 Tables (data/data.sql):
Core Tables:
users - User accounts (Name, Password, Email, PosX, PosY, Gold, MapID, GameID, QuestID)players - Party members (Name, Experience, CurrentLife, CurrentMana, Weapon, Armor, Shield, UserID, ClassID)players_classes - Character classes (Fighter, Magician)players_spells - Spell list (Cure, Stone Crush)players_stash - Inventory (PlayerID, ObjectID, ObjectTable)Map Tables:
maps - Map definitions (Name, MeleeClass, MeleeMin, MeleeMax)maps_coords - Walkable coordinates (MapID, PosX, PosY)maps_events - Script triggers (Event, MapID, MapPosX, MapPosY)Object Tables:
objects_equipment - Equipment (Weapons, Armor, Shields with stats)objects_items - Consumables (Candy, Medical Herb, Chocolate, Royal Jam, Tent)Social Tables:
users_messages - Message logusers_triggers - Quest completion trackingnpcs - Non-player characters (Lucca)Script Language (docs/scriptsystem.txt):
Commands Available:
`plaintext
`
Script Execution (includes/library.inc.php):
`php
function script_load($script)
{
$_SESSION["Script"] = array();
$_SESSION["Script"] = script_make($script); // Parse script
$_SESSION["ScriptStart"] = 0;
$_SESSION["ScriptPosition"] = 0;
script_start(); // Execute
}
function script_start()
{
for ($i = $_SESSION["ScriptStart"]; $i < count($_SESSION["Script"]); $i++)
{
$_SESSION["ScriptPosition"] = $i;
$value = script_vars($_SESSION["Script"][$i]);
if ($value[0] == "PAUS") { break; }
if ($value[0] == "END") { $_SESSION["Script"] = array(); }
if ($value[0] == "NEXT") { $_SESSION["ScriptStart"] = $_SESSION["ScriptPosition"] + 1; }
if ($value[0] == "MODULE") { $_SESSION["Module"] = $value[1]; }
if ($value[0] == "TEXT") { text_set($value[1], $value[2]); }
// ... etc
}
}
`
Example Script (maps_events table):
`sql
INSERT INTO maps_events VALUES (
1,
'#MODULE# #Text#\r\n#TEXT# #Introduction# #It all began a long time ago#\r\n#PAUS#\r\n#MODULE# #Explore#\r\n#END#',
1, 50, 50
);
`
Custom Event System: Like a text adventure engine for RPG events!
---
Login (login.php):
`php
function load_ok($name, $password)
{
$sql_query = "SELECT * FROM users WHERE Name = '$name' AND Password = '$password'";
$sql = mysql_query($sql_query);
if (mysql_num_rows($sql)) { return(true); }
return(false);
}
`
PLAINTEXT PASSWORDS: Passwords stored unencrypted!
Demo Account: username=demo, password=demo (mentioned in readme)
Multi-Character Party:
`php
$_SESSION["Players"] = load_players($_SESSION["User"]["ID"]);
`
Character Stats:
Derived Stats:
`php
$sn["Life"] = $sn["Vitality"] + $sn["Level"] * 10 + 50;
$sn["Mana"] = $sn["Wisdom"] + $sn["Level"] * 2 + 10;
$sn["Damage"] = $sn["Strength"] + $sn["Level"];
$sn["Defence"] = $sn["Agility"] + $sn["Level"];
`
Character Classes (2):
Turn-Based Initiative:
`php
// Initiative Gauge (0-100)
$_SESSION["Players"][$i]["Initiative"] =
$_SESSION["Players"][$i]["Initiative"] +
$_SESSION["Players"][$i]["Endurance"] +
mt_rand(0, 1);
if ($_SESSION["Players"][$i]["Initiative"] >= 100)
{
$_SESSION["Players"][$i]["Initiative"] = 100;
// Player can act
}
`
Active Time Battle (ATB) Style: Like Final Fantasy!
Combat Actions:
Damage Calculation:
`php
function use_weapon($id, $ag, $an, $tg, $tn)
{
$damage = $_SESSION[$ag][$an]["Damage"] - $_SESSION[$tg][$tn]["Defence"];
if ($damage > 0)
{
$_SESSION[$tg][$tn]["CurrentLife"] =
$_SESSION[$tg][$tn]["CurrentLife"] - $damage;
}
$_SESSION[$ag][$an]["Gauge"] = 1;
messages_add("" . $_SESSION[$ag][$an]["Name"] . " attacked " . $_SESSION[$tg][$tn]["Name"] . "");
}
`
Simple Formula: Damage = Attacker Damage - Defender Defense
Enemy AI (battle_enemy):
`php
function battle_enemy($an)
{
// Pick random living target
for ($i = 0; $i < count($_SESSION["Players"]); $i++)
{
if ($_SESSION["Players"][$i]["CurrentLife"] > 0)
{
$target[count($target)] = $i;
}
}
$tn = $target[mt_rand(0, count($target) - 1)];
// Attack
$damage = $_SESSION["Enemies"][$an]["Damage"] + mt_rand(0, 2);
$_SESSION["Players"][$tn]["CurrentLife"] -= $damage;
messages_add("" . $_SESSION["Enemies"][$an]["Name"]." attacked ".$_SESSION["Players"][$tn]["Name"]."");
}
`
Basic AI: Random target selection, random damage variance
Equipment Types:
Equipment Stats (objects_equipment):
`sql
INSERT INTO objects_equipment VALUES
(1,'Spike Club','Weapon',5,1,0,0,1,0,0,0,0);
-- Damage=5, Defence=1, Strength+1
INSERT INTO objects_equipment VALUES
(2,'Leather Vest','Armor',0,8,0,0,0,0,0,0,0);
-- Defence=8
INSERT INTO objects_equipment VALUES
(8,'Cold Sword','Weapon',10,0,2,0,0,0,0,2,0);
-- Damage=10, Life+2, Vitality+2
`
Equipment Properties:
6 Items Defined:
Item Events (PHP code in database!):
`sql
INSERT INTO objects_items VALUES
(1,'Candy',10,'status_alter($tg, $tn, \"CurrentLife\", 100);');
`
Dynamic PHP Execution: Items execute PHP scripts!
2 Spells Defined:
`php
'status_alter($tg, $tn, \"CurrentLife\", 250);'
`
`php
'status_alter($tg, $tn, \"CurrentLife\", -50);'
`
Spell Casting:
`php
function use_spell($id, $ag, $an, $tg, $tn)
{
if ($_SESSION[$ag][$an]["CurrentMana"] >= $result["Mana"])
{
script_load($_SESSION[$ag][$an]["Spells"][$id]["Event"]);
$_SESSION[$ag][$an]["CurrentMana"] -= $result["Mana"];
messages_add("" . $_SESSION[$ag][$an]["Name"] . " threw a spell on " . $_SESSION[$tg][$tn]["Name"] . "");
}
else
{
messages_add("" . $_SESSION[$ag][$an]["Name"] . " does not have enough mana");
}
}
`
4 Maps Defined:
Coordinate-Based Maps:
`sql
INSERT INTO maps_coords VALUES (1,53,52);
INSERT INTO maps_coords VALUES (1,53,51);
-- Each coordinate is a walkable tile
`
Movement System:
`php
function user_travel($posx, $posy)
{
// Move one tile toward target
if ($posx > $_SESSION["User"]["PosX"]) { $x = $_SESSION["User"]["PosX"] + 1; }
else if ($posx < $_SESSION["User"]["PosX"]) { $x = $_SESSION["User"]["PosX"] - 1; }
else { $x = $_SESSION["User"]["PosX"]; }
// ... same for Y
// Check if coordinate exists
if (isset($_SESSION["Map"]["Coords"][$x][$y]))
{
$_SESSION["User"]["PosX"] = $x;
$_SESSION["User"]["PosY"] = $y;
}
}
`
Grid-Based Movement: Click-to-move on coordinate grid
Melee Encounter System:
`php
// MeleeClass = encounter rate (128 = 1/128 chance per move)
// MeleeMin/Max = enemy level range
`
3 Enemies Defined:
Enemy Types:
admin.php - Visual map editor:
`php
// Click tiles to enable/disable
if ($_REQUEST["action"] == "map_on")
{
$_SESSION["map"]["Coords"][$_REQUEST["x"]][$_REQUEST["y"]]["Visible"] = true;
}
// Save to database
if ($_REQUEST["action"] == "save")
{
$sql_query = "DELETE FROM maps_coords WHERE MapID = '$id'";
// Re-insert all visible coordinates
for ($y = ($_SESSION["mapy"] - $ysize); $y <= ($_SESSION["mapy"] + $ysize); $y++)
{
for ($x = ($_SESSION["mapx"] - $xsize); $x <= ($_SESSION["mapx"] + $xsize); $x++)
{
if ($_SESSION["map"]["Coords"][$x][$y]["Visible"] == true)
{
$sql_query = "INSERT INTO maps_coords (MapID, PosX, PosY) VALUES ('$id', '$x', '$y')";
mysql_query($sql_query);
}
}
}
}
`
Visual Tile Editor: Click-based map painting tool
Rolling Message Log:
`php
function messages_add($text)
{
// Shift messages down
for ($i = 4; $i > 0; $i--)
{
if (isset($_SESSION["Messages"][$i - 1]))
{
$_SESSION["Messages"][$i] = $_SESSION["Messages"][$i - 1];
}
}
$_SESSION["Messages"][0] = $text;
}
`
5-Message Display: Shows last 5 game events
---
1. PLAINTEXT PASSWORDS:
`php
// load.inc.php
$sql_query = "SELECT * FROM users WHERE Name = '$name' AND Password = '$password'";
`
2. SQL INJECTION (Authentication Bypass):
`php
function load_ok($name, $password)
{
$sql_query = "SELECT * FROM users WHERE Name = '$name' AND Password = '$password'";
$sql = mysql_query($sql_query);
return(mysql_num_rows($sql));
}
`
Attack Vector:
`
username: admin' OR '1'='1
password: anything
Result: Bypasses authentication!
`
3. SQL INJECTION (All Queries):
`php
// admin.php
$sql_query = "DELETE FROM maps_coords WHERE MapID = '$id'";
$sql_query = "INSERT INTO maps_coords (MapID, PosX, PosY) VALUES ('$id', '$x', '$y')";
// load.inc.php
$sql_query = "SELECT * FROM players WHERE ID = '$id'";
$sql_query = "SELECT * FROM maps WHERE ID = '$id'";
// etc. (14+ vulnerable queries)
`
4. EVAL-LIKE BEHAVIOR (Items/Spells):
`sql
INSERT INTO objects_items VALUES
(1,'Candy',10,'status_alter($tg, $tn, \"CurrentLife\", 100);');
`
`php
script_load($_SESSION[$ag][$an]["Items"][$id]["Event"]);
`
While not direct eval(), the script_load() function executes database-stored code. If an attacker can insert into objects_items, they control code execution.
Severity: 8/10 - Database compromise → code execution
5. SESSION HIJACKING:
`php
// login.php
$_SESSION["User"]["ID"]
// No session regeneration, no HTTPS enforcement
`
6. CSRF VULNERABLE:
`php
// engine.php
if ($_REQUEST["action"] == "travel")
if ($_REQUEST["action"] == "attack")
if ($_REQUEST["action"] == "reset")
`
7. NO INPUT VALIDATION:
`php
// engine.php
use_weapon(0, "Players", 0, $_REQUEST["sg"], $_REQUEST["sn"]);
user_travel($_REQUEST["travelx"], $_REQUEST["travely"]);
`
1. register_globals = Off Required:
`plaintext
// docs/readme.txt
PHP 4.3.*:
register_globals = Off
`
Good Practice: Recognizes register_globals danger
2. No $_GET/$_POST (Uses $_REQUEST):
3. Session-Based Architecture:
4. Clean Configuration:
Rationale:
---
Positive Aspects:
Negative Aspects:
1. Script Engine:
`php
// Custom domain-specific language for events
`
Like: A text adventure language embedded in RPG
2. Database-Driven Everything:
Like: ContentManagementSystem approach to RPG
3. Session-Based Game State:
Like: Modern single-page applications
4. Gauge System:
`php
$_SESSION["Players"][$i]["Gauge"] = 1; // 1-5 gauge levels
`
Like: Secret of Mana's charge attack system
5. Initiative-Based Combat:
`php
$_SESSION["Players"][$i]["Initiative"] += $endurance + mt_rand(0,1);
if ($initiative >= 100) { / can act / }
`
Like: Final Fantasy's Active Time Battle (ATB)
1. Custom Script Language:
2. Visual Map Editor:
3. Database-Driven Content:
4. Multi-Group Battle System:
---
Year: ~2003
Evidence:
PHP Context: PHP 4.x era
Web Gaming Context:
Developers:
International Collaboration: Sweden + Netherlands
Project Philosophy:
Influenced By:
Unique Position:
Similar Games in Collection:
---
Fully Implemented ( ):
Partially Implemented (⚠️):
Missing/Broken ( ):
Playable: BARELY
Developer's Warning:
`plaintext
Notice
======
This game is yet full of bugs and missing features!
`
Installation:
Can You Play?: Technically yes, but...
Production Readiness: 0/10
From docs/readme.txt:
Priority 1 (Critical):
Priority 2 (Important):
Priority 3 (Nice-to-have):
Reality: Project appears abandoned at v0.0.3
---
Size: Smallest
Security: Very Poor
Features: Limited (Unfinished)
Graphics: Minimal
Code Quality: Amateur (But Clean)
Completeness: Prototype
vs Robot Warz (Game 57 - 6/10):
vs Solar Empire (Game 62 - 1/10):
vs OpenRPG (theoretical comparison):
Strengths:
Weaknesses:
Overall Collection: 65-70th/79
---
| Aspect | Score | Notes |
|---|---|---|
| Security | 2/10 | Plaintext passwords, SQL injection everywhere |
| Code Quality | 6/10 | Clean structure, but severe security flaws |
| Features | 4/10 | Innovative script engine, but 60% missing |
| Completeness | 4/10 | 40% complete, no save system |
| Graphics | 3/10 | Minimal PNG graphics (40 files) |
| Innovation | 8/10 | Custom script engine, ATB combat, map editor |
| Balance | N/A | Too incomplete to evaluate |
| Playability | 2/10 | Demo works, but no save/progression |
| Maintainability | 7/10 | Small, readable, well-structured |
"Ambitious Open-Source Prototype with Brilliant Ideas but Fatal Security Flaws"
Smallest Codebase - 1,672 lines (most concise game!)
Custom Script Engine - Innovative domain-specific language
Open Source - GNU GPL (only open-source game so far!)
Clean Architecture - Well-organized includes
Best Documentation - Comprehensive readme + script docs
Visual Map Editor - Unique admin tool
ATB Combat - Final Fantasy-inspired initiative system
Multi-Character Party - Full party mechanics
Database-Driven Content - Items/spells/events in DB
Gauge System - Secret of Mana-style charging
International Collaboration - Sweden + Netherlands
PLAINTEXT PASSWORDS - Stored unencrypted (worst practice!)
SQL INJECTION EVERYWHERE - All 14 queries vulnerable
AUTHENTICATION BYPASS - admin' OR '1'='1 trivial
NO SAVE SYSTEM - save.inc.php is EMPTY!
UNFINISHED - Developers admit "full of bugs and missing features"
40% COMPLETE - Missing registration, quests, shops, death, leveling
NO PROGRESSION - XP tracked but no level-up mechanics
PROJECT ABANDONED - Stuck at v0.0.3
NO INPUT VALIDATION - Direct $_REQUEST usage
SESSION HIJACKING - No session_regenerate_id()
Spirit of Gaia is an ambitious open-source RPG prototype that showcases brilliant design ideas—a custom script engine, ATB combat, visual map editor, and database-driven content—but was abandoned at 40% completion with catastrophic security flaws. It's the smallest game analyzed (1,672 lines) and the most well-documented, with comprehensive readme files explaining its inspiration from Secret of Mana and Final Fantasy. The custom script language (#MODULE# #TEXT# #PAUS#) is the most innovative approach seen in the collection.
However, it contains the WORST authentication security: plaintext passwords stored directly in the database with no hashing whatsoever. Combined with SQL injection in every single query (including authentication), anyone can bypass login with admin' OR '1'='1. The developers explicitly warn it's "full of bugs and missing features," and critically, the save.inc.php file is completely empty—there's no way to save progress!
As an educational project, Spirit of Gaia demonstrates excellent software engineering principles: clean separation of concerns, modular architecture, comprehensive documentation, and innovative design patterns. The script engine alone is worth studying. But as a deployable game, it's a non-starter: no save system, no security, and missing 60% of planned features.
The TODO list from 2003 remains unfinished: "Fix security problems" is listed as Priority 1, followed by "Finish the engine file" and "Solve battle-system." The project appears abandoned mid-development, leaving behind an intriguing proof-of-concept that demonstrates what could have been a unique open-source RPG.
If the security flaws were fixed (bcrypt passwords, prepared statements), the save system completed, and the missing features implemented, this could be a solid 7/10 game. The foundation is excellent. But as-is, it's an unfinished prototype that serves better as a learning resource than a playable game.
Medium - Represents early 2000s open-source browser RPG experimentation, demonstrates custom script engine innovation rarely seen in collection, showcases international collaboration (Sweden + Netherlands), provides best-documented codebase with comprehensive developer notes, preserves JRPG influence (Secret of Mana, Final Fantasy) in browser gaming, serves as cautionary tale about abandoned projects, documents PHP 4.x era development practices, and offers unique database-driven content approach that influenced modern game engines. Most importantly: it's the ONLY open-source game in the collection, making it valuable for educational purposes despite fatal security flaws.
Revival Potential: High - With 100-150 hours of work:
The foundation is excellent. Someone should fork this on GitHub and finish it!
---
Analysis Complete: Game 64/79 (81.0%)
Next: Time 4 Crime (Game 65) when you say "65 go!"
Running many of the scripts in this archive on a live server presents a serious security risk. These projects were created before modern hardening practices and may contain vulnerabilities that can compromise your system.
We strongly recommend using this code for reference and analysis only, or in isolated local environments. By downloading these files, you accept full responsibility for their use.