Updated: Difference between revisions
Created page with "<code>updated.c</code> is OpenBOR's project-wide post-update hook. The engine loads it from a fixed path and executes it near the end of eligible refresh passes, after logical gameplay processing and screen preparation but before the queued screen content is rendered. This placement makes <code>updated.c</code> a powerful finalization point for systems that need the completed state of the pass. Typical uses include aggregate event resolution, encounter summaries, target..." |
No edit summary |
||
| (One intermediate revision by the same user not shown) | |||
| Line 15: | Line 15: | ||
No model, level, or configuration command attaches the file. Projects that do not need the hook may omit it. | No model, level, or configuration command attaches the file. Projects that do not need the hook may omit it. | ||
The file is loaded and compiled during engine startup, then cleared when the engine shuts down. Source uses a normal <code>main()</code> entry point: | The file is loaded and compiled during engine startup, then cleared when the engine shuts down. Source uses a normal <code>[[main()]]</code> entry point: | ||
<syntaxhighlight lang="c" line> | <syntaxhighlight lang="c" line> | ||
| Line 24: | Line 24: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<code>global_system_finish()</code> represents a project-defined helper in this compact example. Logic may instead be written directly inside <code>main()</code>. | <code>global_system_finish()</code> represents a project-defined helper in this compact example. Logic may instead be written directly inside <code>[[main()]]</code>. | ||
The return value of <code>main()</code> is ignored. Changes made through script functions, variables, entities, or engine properties provide the hook's effects. | The return value of <code>[[main()]]</code> is ignored. Changes made through script functions, variables, entities, or engine properties provide the hook's effects. | ||
== Execution Timing == | == Execution Timing == | ||
| Line 33: | Line 33: | ||
# OpenBOR refreshes player input. | # OpenBOR refreshes player input. | ||
# Global [[Update.c]] executes, followed by the current level's pre-update script. | # Global [[Update|Update.c]] executes, followed by the current level's pre-update script. | ||
# Key scripts process applicable input. | # Key scripts process applicable input. | ||
# OpenBOR performs every logical time step due for the pass. | # OpenBOR performs every logical time step due for the pass. | ||
| Line 55: | Line 55: | ||
* Changes to entity position, sprite state, remap, draw method, or other display properties generally appear on a later display pass because the entity's native sprite was already prepared. | * Changes to entity position, sprite state, remap, draw method, or other display properties generally appear on a later display pass because the entity's native sprite was already prepared. | ||
Use [[Update.c]], a level pre-update script, a model update script, or an earlier event when native entity presentation must reflect a change immediately during the same preparation pass. Use <code>updated.c</code> for global overlays and additions that intentionally enter the queue after native entities. | Use [[Update|Update.c]], a level pre-update script, a model update script, or an earlier event when native entity presentation must reflect a change immediately during the same preparation pass. Use <code>updated.c</code> for global overlays and additions that intentionally enter the queue after native entities. | ||
== Refresh Passes and Logical Time == | == Refresh Passes and Logical Time == | ||
| Line 66: | Line 66: | ||
* Delayed refreshes may update every eligible entity several times, then run <code>updated.c</code> once. | * Delayed refreshes may update every eligible entity several times, then run <code>updated.c</code> once. | ||
* Model update scripts and combat events may execute many times before one call to <code>updated.c</code>. | * Model update scripts and combat events may execute many times before one call to <code>updated.c</code>. | ||
* <code>openborvariant("elapsed_time")</code> may remain unchanged between consecutive calls or may have advanced several counts. | * <code>[[openborvariant("elapsed_time")]]</code> may remain unchanged between consecutive calls or may have advanced several counts. | ||
This frequency is ideal for aggregation, publication, orchestration, and display preparation. Exact logical-tick simulation should compare elapsed time deliberately or use a hook inside logical entity processing. | This frequency is ideal for aggregation, publication, orchestration, and display preparation. Exact logical-tick simulation should compare elapsed time deliberately or use a hook inside logical entity processing. | ||
| Line 100: | Line 100: | ||
=== Completing a Shared Collection Phase === | === Completing a Shared Collection Phase === | ||
Managers started in [[Update.c]] can resolve their complete data after model and event scripts have contributed: | Managers started in [[Update|Update.c]] can resolve their complete data after model and event scripts have contributed: | ||
<syntaxhighlight lang="c" line> | <syntaxhighlight lang="c" line> | ||
| Line 152: | Line 152: | ||
OpenBOR supplies no event-specific local variables to <code>updated.c</code>. The script receives no automatic <code>self</code>, player index, entity handle, attacker, or level handle. | OpenBOR supplies no event-specific local variables to <code>updated.c</code>. The script receives no automatic <code>self</code>, player index, entity handle, attacker, or level handle. | ||
Context may be obtained through system and property functions such as <code>openborvariant()</code>, player accessors, entity enumeration, global variables, indexed variables, and project-maintained handles. Useful system values include <code>elapsed_time</code>, <code>game_paused</code>, <code>in_level</code>, <code>current_set</code>, and <code>current_stage</code>. | Context may be obtained through system and property functions such as <code>[[openborvariant()]]</code>, player accessors, entity enumeration, global variables, indexed variables, and project-maintained handles. Useful system values include <code>[[Openborvariant("elapsed time")|elapsed_time]]</code>, <code>game_paused</code>, <code>in_level</code>, <code>current_set</code>, and <code>current_stage</code>. | ||
Variables declared inside <code>main()</code> follow normal function scope. Values intentionally stored with <code>setlocalvar()</code> belong to the <code>updated.c</code> script object and persist for later executions of this same script. | Variables declared inside <code>[[main()]]</code> follow normal function scope. Values intentionally stored with <code>[[setlocalvar()]]</code> belong to the <code>updated.c</code> script object and persist for later executions of this same script. | ||
Local storage is not shared with <code>update.c</code>. Use global variables, indexed variables, entity variables, or another shared engine object when both hooks need the same data. | Local storage is not shared with <code>[[Update|update.c]]</code>. Use global variables, indexed variables, entity variables, or another shared engine object when both hooks need the same data. | ||
=== Shared State from Update.c === | === Shared State from Update.c === | ||
| Line 213: | Line 213: | ||
|} | |} | ||
This behavior means the global pre-update and post-update hooks are not guaranteed to form a one-to-one pair. During a default in-game pause, <code>update.c</code> stops while <code>updated.c</code> continues. | This behavior means the global pre-update and post-update hooks are not guaranteed to form a one-to-one pair. During a default in-game pause, <code>[[Update|update.c]]</code> stops while <code>updated.c</code> continues. | ||
Pause-sensitive managers should test <code>openborvariant("game_paused")</code>. Idempotent finalization is also valuable when a manager may receive repeated post-update calls without new logical work. | Pause-sensitive managers should test <code>[[openborvariant("game_paused")]]</code>. Idempotent finalization is also valuable when a manager may receive repeated post-update calls without new logical work. | ||
== Alwaysupdate == | == Alwaysupdate == | ||
| Line 228: | Line 228: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Enabling <code>alwaysupdate</code> makes <code>updated.c</code> execute whenever OpenBOR calls its central update routine, including pauses and non-game screens. This setting also expands [[Update.c]] execution. | Enabling <code>alwaysupdate</code> makes <code>updated.c</code> execute whenever OpenBOR calls its central update routine, including pauses and non-game screens. This setting also expands [[Update|Update.c]] execution. | ||
Level-only properties and entity assumptions need guards under <code>alwaysupdate 1</code>. Test <code>openborvariant("in_level")</code> and relevant screen-status variants before accessing context that may not exist. | Level-only properties and entity assumptions need guards under <code>alwaysupdate 1</code>. Test <code>[[openborvariant("in_level")]]</code> and relevant screen-status variants before accessing context that may not exist. | ||
Level post-update scripts still require a loaded level because their script objects belong to that level. Global <code>updated.c</code> can run alone on screens where no level is active. | Level post-update scripts still require a loaded level because their script objects belong to that level. Global <code>updated.c</code> can run alone on screens where no level is active. | ||
| Line 306: | Line 306: | ||
== See Also == | == See Also == | ||
* [[Update.c]] | * [[Update|Update.c]] | ||
* [[OpenBOR Script]] | * [[Script Overview|OpenBOR Script]] | ||
* [[Openborvariant]] | * [[Openborvariant]] | ||
* [[Global variables]] | * [[Global variables]] | ||
| Line 313: | Line 313: | ||
* Model update script | * Model update script | ||
* Level updated script | * Level updated script | ||
[[Category:OpenBOR Index]] | |||
[[Category: | [[Category:Script]] | ||
[[Category: | [[Category:Script Events]] | ||
Latest revision as of 19:23, 17 August 2026
updated.c is OpenBOR's project-wide post-update hook. The engine loads it from a fixed path and executes it near the end of eligible refresh passes, after logical gameplay processing and screen preparation but before the queued screen content is rendered.
This placement makes updated.c a powerful finalization point for systems that need the completed state of the pass. Typical uses include aggregate event resolution, encounter summaries, target-registry commits, global interface elements, diagnostic overlays, post-update bookkeeping, controller arbitration, cached result publication, and other project managers.
updated.c has distinctive pause behavior. During in-game pauses it continues to execute by default even though logical time, entity updates, and update.c have stopped. This difference is central to choosing and guarding the hook correctly.
File and Syntax
OpenBOR looks for the following file automatically:
data/scripts/updated.c
No model, level, or configuration command attaches the file. Projects that do not need the hook may omit it.
The file is loaded and compiled during engine startup, then cleared when the engine shuts down. Source uses a normal main() entry point:
void main()
{
global_system_finish();
}
global_system_finish() represents a project-defined helper in this compact example. Logic may instead be written directly inside main().
The return value of main() is ignored. Changes made through script functions, variables, entities, or engine properties provide the hook's effects.
Execution Timing
The relevant order for an ordinary unpaused gameplay refresh is:
- OpenBOR refreshes player input.
- Global Update.c executes, followed by the current level's pre-update script.
- Key scripts process applicable input.
- OpenBOR performs every logical time step due for the pass.
- Scroller, timer, status, and entity processing run during each logical step.
- Model update scripts run from inside eligible entity updates.
- OpenBOR clears the screen buffer and prepares background, status, text-object, and entity-sprite content.
- Global
updated.cexecutes. - Current level
updatedscriptexecutes, when one exists. - Pause or main-menu requests are handled.
- The complete sprite queue is drawn and copied to the display.
Entity state is therefore available after all logical steps completed. Script drawing functions can still add content before the queue is consumed.
The global hook executes before its level counterpart. Projects may publish common post-update results in updated.c, then let the active level extend them or add stage-specific presentation in its own post-update script.
State Finalization and Screen Preparation
updated.c begins after OpenBOR has prepared native display content for the pass. This timing creates two different kinds of effect:
- New script drawings queued by
updated.ccan appear during the current screen render because the sprite queue has not yet been drawn. - Changes to entity position, sprite state, remap, draw method, or other display properties generally appear on a later display pass because the entity's native sprite was already prepared.
Use Update.c, a level pre-update script, a model update script, or an earlier event when native entity presentation must reflect a change immediately during the same preparation pass. Use updated.c for global overlays and additions that intentionally enter the queue after native entities.
Refresh Passes and Logical Time
OpenBOR's refresh layer and logical time-step layer are distinct. One call to the central update routine may process zero, one, or several logical steps depending on accumulated real time and catch-up requirements.
updated.c executes once after that time-step loop and screen preparation. Consequently:
- Some refresh passes may run
updated.ceven though no entity update was due. - Delayed refreshes may update every eligible entity several times, then run
updated.conce. - Model update scripts and combat events may execute many times before one call to
updated.c. openborvariant("elapsed_time")may remain unchanged between consecutive calls or may have advanced several counts.
This frequency is ideal for aggregation, publication, orchestration, and display preparation. Exact logical-tick simulation should compare elapsed time deliberately or use a hook inside logical entity processing.
Practical Uses
| Pattern | Use of updated.c
|
|---|---|
| Two-phase manager completion | Resolve event collections, commit registries, publish aggregate results, or close transactions opened by update.c.
|
| Encounter summary | Count or classify surviving entities, objective state, targets, resources, or threats after all due entity updates finished. |
| Global interface | Queue objective markers, cooperative meters, controller prompts, accessibility feedback, debug panels, or other project-wide overlays before rendering. |
| Deferred arbitration | Resolve requests collected from several entities without letting entity-list order decide the outcome. |
| Shared cache publication | Finalize target lists, spatial summaries, combat statistics, or other information that later passes can consume efficiently. |
| Pause-aware presentation | Maintain script-side pause menus, indicators, prompts, or diagnostics while ordinary gameplay logic is stopped. |
| Diagnostics | Finish pass measurements, compare pre-update and post-update state, emit traces, or display final counters. |
Completing a Shared Collection Phase
Managers started in Update.c can resolve their complete data after model and event scripts have contributed:
void main()
{
combat_events_resolve();
target_registry_commit();
threat_map_publish();
}
This pattern avoids depending on whichever entity happened to update first. Requests can be collected throughout the pass and resolved from the finished set.
Global Overlay
Post-update summaries and development information may be queued before the current screen render:
void main()
{
update_encounter_summary();
draw_global_debug_overlay();
}
Useful summaries include active enemy groups, objective progress, target priority, combo state, cooperative resources, encounter phases, and script performance counters.
Pause-Aware Logic
Default execution continues during an in-game pause. Systems that should stop can return early, while pause-specific systems can take the opposite branch:
void main()
{
int paused = openborvariant("game_paused");
if(paused)
{
update_pause_overlay();
return;
}
finish_gameplay_managers();
}
Logical time does not advance during the paused branch. Pause animation that requires real-time movement needs a real-time source rather than elapsed_time.
Local Variables and Context
OpenBOR supplies no event-specific local variables to updated.c. The script receives no automatic self, player index, entity handle, attacker, or level handle.
Context may be obtained through system and property functions such as openborvariant(), player accessors, entity enumeration, global variables, indexed variables, and project-maintained handles. Useful system values include elapsed_time, game_paused, in_level, current_set, and current_stage.
Variables declared inside main() follow normal function scope. Values intentionally stored with setlocalvar() belong to the updated.c script object and persist for later executions of this same script.
Local storage is not shared with update.c. Use global variables, indexed variables, entity variables, or another shared engine object when both hooks need the same data.
Shared State from Update.c
data/scripts/update.c may publish a pass identifier:
void main()
{
void pass = getglobalvar("global_update_pass");
if(pass == NULL())
{
pass = 0;
}
setglobalvar("global_update_pass", pass + 1);
}
data/scripts/updated.c can read the shared global value:
void main()
{
void pass = getglobalvar("global_update_pass");
if(pass != NULL())
{
setglobalvar("global_update_complete", pass);
}
}
This compact example records completion of paired unpaused passes. Paused gameplay can execute updated.c without a matching update.c, so real systems should not assume that a fresh pre-update phase always occurred.
Pause Behavior
Default updated.c execution requires gameplay context but does not require gameplay to be unpaused.
| Situation | updated.c
|
|---|---|
| Unpaused gameplay | Executes once near the end of the refresh pass. |
| Paused gameplay | Executes by default while the engine continues refreshing the pause display. |
| Non-game screen | Does not execute by default. |
Any central update call with alwaysupdate 1
|
Executes. |
This behavior means the global pre-update and post-update hooks are not guaranteed to form a one-to-one pair. During a default in-game pause, update.c stops while updated.c continues.
Pause-sensitive managers should test openborvariant("game_paused"). Idempotent finalization is also valuable when a manager may receive repeated post-update calls without new logical work.
Alwaysupdate
The alwaysupdate setting belongs in data/script.txt:
alwaysupdate 1
# Default
alwaysupdate 0
Enabling alwaysupdate makes updated.c execute whenever OpenBOR calls its central update routine, including pauses and non-game screens. This setting also expands Update.c execution.
Level-only properties and entity assumptions need guards under alwaysupdate 1. Test openborvariant("in_level") and relevant screen-status variants before accessing context that may not exist.
Level post-update scripts still require a loaded level because their script objects belong to that level. Global updated.c can run alone on screens where no level is active.
Relationship to Other Update Hooks
| Hook | Scope | Placement |
|---|---|---|
data/scripts/update.c
|
Complete project | Once before key scripts and all due logical entity updates in an eligible refresh pass. |
Level updatescript
|
Current level | Immediately after global update.c while that level exists.
|
| Model update script | Eligible entity using that model | Inside each native entity update during every due logical step. |
data/scripts/updated.c
|
Complete project | Once after logical processing and native screen preparation in an eligible refresh pass. |
Level updatedscript
|
Current level | Immediately after global updated.c while that level exists.
|
Choose updated.c for project-wide work that needs the completed pass or must add global content just before rendering. Stage-specific finalization belongs to the level post-update script; per-entity behavior belongs to the model update script.
Common Mistakes
| Mistake | Result | Better approach |
|---|---|---|
| Assuming one call per logical tick | Timers or simulations drift when a refresh contains zero or several time steps. | Track elapsed_time or use logical entity processing.
|
Assuming every call follows update.c
|
Paused gameplay runs updated.c without running the default pre-update hook.
|
Check pause and pass state, then make finalization idempotent where needed. |
Expecting self
|
No entity is supplied to the global script. | Obtain explicit handles through player, entity, global, or system interfaces. |
Sharing state with setlocalvar() across both global files
|
Each file reads a separate local-variable table. | Use global, indexed, or entity variables for shared state. |
| Changing entity visuals and expecting the queued sprite to change immediately | Native entity display data was already prepared. | Change entity visual state earlier or accept a later-pass result. |
Accessing level data under alwaysupdate 1 without a guard
|
The hook can execute when no level exists. | Test in_level first.
|
| Repeating expensive full-entity scans during a pause | No logical entity work changed, yet the post-update hook keeps running. | Cache results or skip gameplay aggregation while paused. |
| Placing stage-only rules in the global file | Logic remains active across the whole project and requires repeated stage checks. | Use the level's post-update script. |
See Also
- Update.c
- OpenBOR Script
- Openborvariant
- Global variables
- Drawmethod
- Model update script
- Level updated script