How PHPDTS Manages NPCs and Instantiates Non-Player Characters: A Deep Dive into the NPC Management System
PHPDTS treats NPCs as player records stored in the same database table, instantiating them by merging template configurations with a base structure and persisting via player_format_with_db_structure() and array_insert().
The amarillonmc/phpdts project implements a unified architecture where non-player characters (NPCs) are technically indistinguishable from human players at the database level. This design allows the NPC management system to leverage the same persistence layer and attribute schema for both entity types, simplifying state management and combat resolution.
Unified Player-NPC Architecture
In PHPDTS, there is no separate npcs table. Instead, the system stores all entities—human and computer-controlled—in the players table (prefixed as {$tablepre}players). The distinction between a user and an NPC is determined by the type field and the presence of specific initialization flags. This architecture ensures that combat, movement, and status effects work identically regardless of whether the target is a human opponent or an AI-controlled character.
Bulk NPC Initialization at Game Start
When a new game instance begins, the engine populates the world with predefined NPCs through a bulk creation process defined in include/system.func.php.
Loading NPC Templates
The system first loads static NPC definitions from the game configuration cache. At line 74 of include/system.func.php, the engine executes:
include_once config('npc',$gamecfg);
This imports the $npcinfo array from gamedata/cache/npc.php, which contains associative definitions for every NPC type, including base statistics, possible sub-variants, spawn quantities, and equipment loadouts.
Merging and Instantiating
For each NPC type defined in $npcinfo, the engine loops through the required spawn count ($npcs['num']) and constructs individual records. The instantiation follows a strict merging protocol:
-
Base structure initialization – The system retrieves
$npcinit, a default player structure containing neutral values for all required database columns. -
Template merging – At line 85, the engine overlays type-specific data:
$npc = array_merge($npcinit,$npcs); -
Instance metadata assignment – Lines 87-90 assign runtime identifiers:
$npc['type'] = $i; // NPC type identifier $npc['endtime']= $now; // Creation timestamp $npc['sNo'] = $j; // Sequential spawn number
After merging, the system randomizes gender, location coordinates, club affiliation, and weapon selections based on the template’s allowed ranges.
Persistence to Database
Before insertion, the associative array must conform to the database schema. Line 155 invokes:
$npc = player_format_with_db_structure($npc);
This helper function (defined in include/global.func.php) maps the raw NPC array to the exact column structure expected by the players table. Finally, line 156 persists the record:
$db->array_insert("{$tablepre}players", $npc);
Dynamic NPC Spawning with addnpc()
For event-driven scenarios—such as summoning a boss after a player action—the system provides the addnpc() function at line 725 of include/system.func.php. This enables ad-hoc instantiation without rebooting the game instance.
Function Signature and Merging Logic
function addnpc($type,$sub,$num,$time = 0,$anpcdata = NULL) {
$npcinit = get_npcinit(); // line 735
$anpcinfo = get_addnpcinfo(); // line 736
$anpc = array_merge($npcinit,$anpcinfo[$type]); // line 738
$anpc = array_merge($anpc,$anpc['sub'][$sub]); // line 739
The function accepts five parameters:
$type: The primary NPC classification from the template system.$sub: The sub-variant index for differentiating specific instances (e.g., elite vs. standard).$num: Quantity to spawn.$time: Optional expiration timestamp (0 for permanent).$anpcdata: Optional associative array for overriding specific attributes (name, level, health).
Finalizing Dynamic Instances
Lines 746-748 finalize the NPC record:
$npc = $anpc;
$npc['type'] = $type;
$npc['endtime']= $time;
The function calculates derived statistics such as experience points based on level and global base rates, then applies the same persistence pipeline as bulk creation. Lines 824-826 format and insert the final record:
$npc = player_format_with_db_structure($npc); // line 824
$db->array_insert("{$tablepre}players", $npc); // line 826
Practical Example: Spawning a Boss
To summon a custom boss during an event, developers call:
addnpc(99, 1, 1, $now + 300, [
'name' => 'The Dark Overlord',
'club' => 'evil',
'lvl' => 99,
'mhp' => 5000,
'msp' => 2000,
'wep' => '巨剑',
'wepk' => 'w',
]);
This creates a single instance of type 99, sub-variant 1, lasting five minutes, with custom health and weapon attributes.
Key Files in the NPC Management System
The following files define the complete lifecycle of non-player characters in the codebase:
include/system.func.php– Contains the core instantiation logic, including the bulk initialization loop and theaddnpc()function for dynamic spawning.gamedata/cache/npc.php– Stores the$npcinfoarray with all NPC templates and sub-variant definitions.include/init.func.php– Invokes the bulk NPC creation routines when initializing a new game round.include/global.func.php– Providesplayer_format_with_db_structure(), which normalizes NPC arrays for database insertion.
Summary
- PHPDTS unifies entities by storing NPCs and players in the same
playerstable, distinguishing them only through thetypefield and initialization metadata. - Template-driven instantiation loads definitions from
config('npc'), merges them with$npcinit, and randomizes location, gender, and equipment before persistence. - Bulk creation occurs at game start through the initialization loop in
include/system.func.php, handling multiple instances per NPC type. - Dynamic spawning uses
addnpc()to inject NPCs mid-game, supporting custom attribute overrides via the$anpcdataparameter. - Schema normalization via
player_format_with_db_structure()ensures all NPC arrays match the database column structure before insertion.
Frequently Asked Questions
How does PHPDTS store NPC data compared to regular players?
PHPDTS stores NPCs and human players in the identical players table using the same schema. The system differentiates them through the type column and initialization flags, allowing combat and movement systems to treat both entity types uniformly without conditional logic for database access.
What is the difference between bulk NPC creation and the addnpc() function?
Bulk creation runs once during game initialization to populate the world with standard NPCs according to predefined quotas in npc.php. The addnpc() function enables runtime spawning during active gameplay, accepting parameters for custom attributes, expiration timers, and specific sub-variants—ideal for event-driven boss encounters or temporary modifiers.
Where are NPC templates defined in the codebase?
NPC templates reside in gamedata/cache/npc.php, which exports the $npcinfo array. This file is generated by the installer and defines all base statistics, possible locations, equipment sets, and sub-variant configurations for every NPC type in the game.
How are NPC attributes like location and gender randomized during instantiation?
During the merging phase in include/system.func.php, the system applies randomization functions to select values from the template’s allowed ranges. Specifically, after the array_merge($npcinit, $npcs) operation at line 85, the code shuffles sub-variants if they exceed the spawn count, then assigns random gender, club affiliation, map coordinates, and weapon selections before calculating derived stats like HP and SP.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →