name: hgame-gms2-safe-edit description: Safe editing guidance for the hgame GameMaker Studio 2 JRPG project. Use when Codex or an agent needs to inspect, modify, refactor narrowly, debug, or extend this repository's GML code, GMS2 objects, rooms, scripts, save data, inventory, equipment, character, skill, menu, NPC, movement, audio, or room-state systems.
HGame GMS2 Safe Edit
First Steps
Use this skill before changing this repository. Treat the project as a GMS2 2024.13.1+ project with hand-maintained GML conventions and fragile serialized data.
- Inspect the local files before editing. Start with
rg --files, then use targetedrgsearches for function names, enum names,global.variables, andds_grid_*access. - Prefer editing
.gmlscript/event files. Avoid.yyedits unless resource metadata truly must change, such as adding/removing an event ineventList, changing an object parent/child relationship, or adding/removing a GMS2 resource. - Before using any GML API, verify that it already appears in the project or is a current built-in GameMaker function. Do not invent helper names or use plugin-only/deprecated APIs.
- Keep changes narrow. Do not reorganize the project, rename resources, or redesign the save/inventory/equipment/character data model unless the user explicitly asks for that refactor.
- Preserve existing
ds_grid, struct, enum, sentinel, and save-file contracts. These are part of runtime behavior, not incidental implementation details. - When editing GML, prefer APIs already present in this repository. If a new GameMaker API is needed, verify it against current official GameMaker documentation before using it.
Project Map
hgame.yypandhgame.resource_order: GMS2 project metadata. Avoid manual edits unless a resource change requires it.scripts/: reusable GML functions and data catalogs. This is the safest place for most logic changes.objects/: object event code. Event files are named by GMS2 event type, such asCreate_0.gml,Step_0.gml,Draw_64.gml, andDestroy_0.gml.rooms/: room metadata and instance creation code. Instance creation files often setglobal.bgm,global.roomid, item/NPC state, or room transitions.sprites/,sounds/,fonts/,tilesets/,options/: resource metadata and assets. Treat.yyfiles here as generated/editor-owned unless a resource task requires touching them.notes/: developer notes, not runtime code.
Core Systems
Boot, Globals, Time, Debug
objects/obj_title_menu/*initializes title-menu state, audio volume globals, settings,global.savef,global.sub_menu,global.talking, andglobal.noresting.objects/obj_gamestart/Create_0.gmlinitializes a new or loaded run: debug flag, message speed, total/game time,global.talking,global.overweight,global.noresting,global.bgm,global.battle,global.gameover, room status, andglobal.saveDATA.objects/obj_gamestart/Step_0.gmlcreates or re-creates persistent runtime managers and player/partner instances.objects/obj_control/*defines global input aliases viaglobalvar:lkey,rkey,ukey,dkey,akey,bkey,xkey,ykey, pressed/released variants, function keys, andkey_cooldown.objects/obj_allways/*manages debug hotkeys, quick save/load, total/game time, in-game time,mp_gridpathfinding grids, battle BGM gain, and game-over transitions.objects/obj_bgm/*manages BGM start/loop tracks and fades byglobal.bgm;global.battlecontrols the second BGM group inobj_allways.
Save And Load
scripts/scr_saving_system/scr_saving_system.gmlis the central save/load script. Be very conservative here.scr_saving(_datanum)writessavedataN.savas JSON throughbuffer_create,buffer_write, andbuffer_save.- Inventory and equipment are serialized with
ds_grid_write; their heights are stored separately. - Room status is stored as a versioned struct returned by
room_status_save_data(). The active room-state format starts atversion = 2; legacy grid migration code was intentionally removed because the project had no meaningful old room-state saves yet. Future migrations should be added throughroom_status_load_data()version dispatch. - Character data is not saved as raw nested grids. It clones each character struct with
variable_clone, convertsskill_listandspellbook_listgrids into arrays of structs, and writesglobal.saveDATA.Schara_status. scr_loading(_datanum)only parses JSON intoglobal.saveDATA. Rehydration happens later in object code:obj_gamestart/Create_0.gmlrestores global time and merges saved room state over freshreroomsatus()defaults.obj_item_manager/Step_0.gmlrebuildsinventoryandequipmentfromds_grid_read.obj_charsatus/Step_0.gmlrebuilds character structs,skill_list, andspellbook_listgrids.
- Do not change save field names, grid widths, enum columns, or character struct fields without a migration plan and backwards compatibility.
Character Data
scripts/scr_character/scr_character.gmlreplaces the older deprecateddis_scr_gamerulecharacter implementation.chara_id(_id)returns a character struct. Important fields include identity, stats, modifiers, HP/MP, class/race strings, equipment slots,skill_list,spellbook, andspellbook_list.obj_charsatus/Create_0.gmlcreates globalchara_statuswith widthchara_status_w = 2; column0is character id, column1is the character struct.load_chara(_id)searcheschara_status, returns the stored struct, applies old-save compatibility for spellbooks, clamps HP/MP, and refreshes modifiers.- Character equipment slots store full equipment structs or
0:main_h,sec_h,armor,accessoryA,accessoryB,accessoryC.
Inventory And Equipment
scripts/scr_item/scr_item.gmldefinesenum DS_INVENTORY:NAME = 0,AMOUNT = 1,I_ID = 2.obj_item_manager/Create_0.gmlcreates globalinventorywithinventory_w = 3and globalequipmentwithequipment_w = 4.item_id(_id)is the item catalog and returns a struct. Some item ids are decimals, such as0.1,1.1, and2.8; preserve that convention.add_item_id()merges stacks by item id and caps inventory amounts at999; empty first cell value0means an empty grid row.scripts/scr_equipment/scr_equipment.gmldefinesenum DS_EQUIPMENT:NAME = 0,AMOUNT = 1,E_ID = 2,CUR_DURABILITY = 3.equipment_id(_id)is the equipment catalog.equip_partsvalues are meaningful:0two-handed main-hand only,1main hand only,2main or off hand,3armor,4accessory slots.apply_equipment()removes old attr mods/effects, sets a slot, applies new attr mods/effects, then callsrecalc_AC().- Equipment/item effect lists use arrays of structs like
{type: APP_EFFECT.ITEM_POTION, t_id:[2,4,2]}. Route new effects through the existingAPP_EFFECTenum andapply_effect()pattern.
Skill And Spell Data
scripts/scr_skill/scr_skill.gmldefinesDS_SKILLandDS_SPELL.DS_SKILLcolumns areNAME,S_ID, andSOURCE_COUNT.SOURCE_COUNTallows multiple sources for the same skill;remove_skill_id()decrements before removing rows.DS_SPELLcolumns areNAME,S_ID, andISENALBE = 2;ISENABLE = 2is an alias. Preserve the existing misspelledISENALBEuses for compatibility.add_spell_id()may also add a skill when a spell is enabled.set_spell_enable_by_row()enforcesget_spell_enable_limit().
Room State And Instance Data
scripts/scr_roomsatus/scr_roomsatus.gmlcreates globalroom_statusas a versioned struct:{ version, rooms }.- Each room entry stores
room_id,room_name,room_data, and aninstancesarray. Room-level state should useroom_status_current_set_room_custom()/room_status_current_get_room_custom(). - Each tracked instance uses a stable
rs_idstring rather than a grid column. Current tracked types are"item","equipment","npc", and"hostile_npc". - Room instance Creation Code should set
rs_id = "<stable instance id>"for tracked placed instances. Item and equipment instances can also setrs_restorable. obj_item_p,obj_equip_p,obj_npc, andobj_hostile_npcinitializers_id,rs_restorable, andrs_state_ready, then apply/capture room state through theroom_status_*helpers during Step/interaction.obj_hostile_npcinstances without Creation Code can be auto-bound by type and default position when they have a matching registry entry.restor_roomsatus()remains as a compatibility wrapper for rest/refresh flows, but it now restores entries from the struct registry instead of the old grid.- NPC positions are captured continuously, but default room entry behavior does not restore saved positions unless
restore_positionis set, for example viaroom_status_current_set_restore_position(). - For complex NPC or room-specific flags, prefer the generic
customhelpers over adding one-off grid columns or hard-coded save fields.
Menus, Messages, And Interaction
- Menu objects use
global.pauseandglobal.sub_menuas state-machine controls. Destroy events usually resetglobal.sub_menu = 0. - Menu navigation uses input aliases from
obj_controland helperscr_menu_movement_jump(). scripts/scr_msg/scr_msg.gmlcreates pages/options andobj_msgbox;scripts/scr_msg_game/scr_msg_game.gmlcontains message ids and branching text.- Item use creates
obj_menu_useitemand stores a closure inu_scr, then applies the underlying effect after a target character is chosen.
Movement And NPCs
scripts/scr_movement/scr_movement.gmlapplies velocity, facing, vector path movement, and solid collision nudging. It expects instance fields likevx,vy,vs,acc,sprinting,face, andblock_solid.scripts/scr_player_movement/scr_player_movement.gmltranslates global input aliases into player velocity and sprint state.scripts/scr_npc_behavior/scr_npc_behavior.gmldispatches numeric NPC behaviors: idle/default, random move, talking, follow, close follow, and away.- NPC objects initialize movement fields and
block_solidin theirCreateevents. Hostile NPCs also maintain path state withfollow_path,follow_target, andfollow_timer.
GML Style
- Use GMS2.3+ script functions:
function name(_arg) { ... }. - Prefix function parameters and temporary locals with
_where the surrounding code does so, such as_id,_chara,_equipment,_row. - Keep catalog functions as
switch(_id)blocks returning structs. Add new item/equipment/skill cases near similar ids and keep#regioncomments when helpful. - Use
argument_countandargument[]for optional arguments when matching existing scripts. - Use existing input aliases (
akey,bkey,dpkey, etc.) instead of calling raw keyboard/gamepad checks from unrelated code. - Use
global.for project-level state where the project already does; useglobalvaronly for the established shared grids/input variables. - Use
0as the existing empty sentinel inds_gridrows and equipment slots; useundefinedornooneonly where existing code expects them. - Keep Chinese in-game text and comments consistent with nearby files. Do not rewrite wording unless the task is text/content work.
- Preserve existing formatting in touched files. This codebase uses mixed semicolon style and GML brace conventions; do not run broad formatters.
Reserved Instance Variables
GameMaker Studio 2 uses many built-in instance variables that must NOT be used as local or temporary variable names.
Examples include but are not limited to:
- x, y
- hspeed, vspeed, speed, direction
- image_index, image_speed
- visible, solid
- id, object_index
Rules:
- NEVER use built-in instance variable names as local variables.
- ALWAYS use
_prefix for parameters and temporary variables (e.g._x,_y,_speed). - If a variable name conflicts with a built-in variable, rename it safely.
- Treat
xandyas position properties only, never as generic variables.
If a variable name could potentially conflict with a built-in variable, prefer:
_namefor parameters and localstmp_namefor temporary values
Forbidden Changes
- Do not manually churn
.yyfiles,hgame.yyp, orhgame.resource_orderfor normal logic edits. - Do not invent GML functions, resource names, audio groups, sprites, object names, or scripts. Verify first with
rgor official GameMaker docs. - Do not use plugin-only APIs or deprecated APIs. Deprecated files here, such as
dis_scr_gameruleanddis_scr_item_script_execute, are reference/legacy material, not patterns to revive. - Do not broadly refactor the save system, inventory/equipment grids, character structs,
room_status, or menu state machines without explicit user approval. - Do not break these enum/grid contracts:
DS_INVENTORY:NAME,AMOUNT,I_IDDS_EQUIPMENT:NAME,AMOUNT,E_ID,CUR_DURABILITYDS_SKILL:NAME,S_ID,SOURCE_COUNTDS_SPELL:NAME,S_ID,ISENALBE/ISENABLE
- Do not remove old-save compatibility checks from
load_chara()orobj_charsatus/Step_0.gml. - Do not change save JSON field names or grid widths unless also handling migration.
Staged Resource Creation
When a new GMS2 script/object/resource is needed, do not directly register it as a real project resource unless explicitly approved.
Preferred workflow:
-
Create staged files using the prefix
NEW_.- Example:
NEW_scr_potion_system.gml - Example:
NEW_obj_potion_menu_Create_0.gml - Example:
NEW_obj_potion_menu_Step_0.gml
- Example:
-
Do not modify:
hgame.yyphgame.resource_order- resource tree metadata
-
Tell the user what to create manually in GameMaker IDE.
- Example: create a script named
scr_potion_system - Example: create an object named
obj_potion_menu - Example: add Create / Step / Draw GUI events as needed
- Example: create a script named
-
After the user creates the resource in GameMaker IDE, move/copy the staged
NEW_code into the corresponding.gmlevent/script file, or let the user do it own. -
Remove the
NEW_prefix only after the IDE-created resource exists. -
Never treat
NEW_files as runtime code. They are drafts/templates only.
Encoding
All project text files are UTF-8 encoded.
Rules:
- Always read and write text files as UTF-8.
- Preserve Chinese comments, strings, dialogue, and UI text.
- If Chinese text appears garbled, assume the file was read with the wrong encoding and re-read it as UTF-8.
- Do not rewrite, normalize, or “repair” garbled text unless the user explicitly asks.
- Do not change line endings or file encoding during unrelated edits.
Safe Edit Checklist
Before editing:
- Identify the owning system and read its script plus the relevant object events.
- Search every function/enum/global/grid column you plan to touch.
- Check whether the target file participates in save/load or room instance creation.
- If a
.yyedit seems necessary, explain why and limit the diff to the exact metadata field.
While editing:
- Prefer adding a small function, enum case, catalog case, or localized branch over changing shared flow.
- Keep data shape stable. Extend structs additively and add fallback checks for old saves.
- Use existing helpers:
load_chara,load_inventory,load_equipment,add_item_id,add_equipment_id,apply_effect_list,create_msg_box,scr_menu_movement_jump. - Keep room state ids, item/equipment ids, and skill ids deterministic and documented near their cases.
After editing:
- Run
rg -nchecks for typos in changed function, enum, and field names. - Review
git diffand confirm no unintended.yy, asset, or generated metadata churn. - For save-related changes, reason through new game, old save load, save, reload, and empty-grid cases.
- If GameMaker is not available for a full compile, state that limitation clearly in the final response.
Skill Maintenance
This skill may be updated when the project architecture changes.
Rules:
- Do not weaken or remove safety rules without explicit user approval.
- Prefer appending new project facts over rewriting old sections.
- When code and this skill disagree, inspect the current code and report the mismatch before editing the skill.
- Mark uncertain observations as unconfirmed.
- Keep this skill focused on durable project conventions, not one-off task notes.