Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 141 additions & 24 deletions engine/openbor.c
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,7 @@ Script updated_script; //execute when ingame update finished
Script loading_script; // in loading screen
Script input_script_all; //keyscript for all players
Script key_script_all; //keyscript for all players
Script score_script_all; //score listener for all players
Script timetick_script; //time tick script.

//player script
Expand Down Expand Up @@ -1182,6 +1183,7 @@ void init_scripts()
Script_Init(&endlevel_script, "endlevel", NULL, 1);
Script_Init(&input_script_all, "inputall", NULL, 1);
Script_Init(&key_script_all, "keyall", NULL, 1);
Script_Init(&score_script_all, "scoreall", NULL, 1);
Script_Init(&timetick_script, "timetick", NULL, 1);
Script_Init(&loading_script, "loading", NULL, 1);
for(i = 0; i < MAX_PLAYERS; i++)
Expand Down Expand Up @@ -1238,6 +1240,10 @@ void load_scripts()
{
Script_Clear(&key_script_all, 2);
}
if(!load_script(&score_script_all, "data/scripts/scoreall.c"))
{
Script_Clear(&score_script_all, 2);
}
if(!load_script(&timetick_script, "data/scripts/timetick.c"))
{
Script_Clear(&timetick_script, 2);
Expand Down Expand Up @@ -1332,6 +1338,7 @@ void load_scripts()
Script_Compile(&endlevel_script);
Script_Compile(&input_script_all);
Script_Compile(&key_script_all);
Script_Compile(&score_script_all);
Script_Compile(&timetick_script);
Script_Compile(&loading_script);
for(i = 0; i < MAX_PLAYERS; i++)
Expand Down Expand Up @@ -1381,6 +1388,7 @@ void clear_scripts()
Script_Clear(&endlevel_script, 2);
Script_Clear(&input_script_all, 2);
Script_Clear(&key_script_all, 2);
Script_Clear(&score_script_all, 2);
Script_Clear(&timetick_script, 2);
Script_Clear(&loading_script, 2);
for(i = 0; i < MAX_PLAYERS; i++)
Expand Down Expand Up @@ -2422,7 +2430,8 @@ void execute_spawn_script(s_spawn_entry *p, entity *e)
tempvar.dblVal = (DOUBLE)p->position.z;
Script_Set_Local_Variant(cs, "spawnz", &tempvar);
tempvar.dblVal = (DOUBLE)p->position.y;
Script_Set_Local_Variant(cs, "spawna", &tempvar);
Script_Set_Local_Variant(cs, "spawna", &tempvar); // Legacy alias for spawny.
Script_Set_Local_Variant(cs, "spawny", &tempvar);
ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
tempvar.lVal = (LONG)p->at;
Script_Set_Local_Variant(cs, "spawnat", &tempvar);
Expand All @@ -2435,6 +2444,7 @@ void execute_spawn_script(s_spawn_entry *p, entity *e)
Script_Set_Local_Variant(cs, "spawnx", &tempvar);
Script_Set_Local_Variant(cs, "spawnz", &tempvar);
Script_Set_Local_Variant(cs, "spawna", &tempvar);
Script_Set_Local_Variant(cs, "spawny", &tempvar);
Script_Set_Local_Variant(cs, "spawnat", &tempvar);
}
}
Expand Down Expand Up @@ -2502,6 +2512,37 @@ void execute_key_script_all(int player)
}
}

/*
* Caskey, Damon V.
* 2026-08-20
*
* Execute the shared score listener with the zero-based
* player index and signed 64-bit score adjustment.
*/
void execute_score_script_all(int playerindex, int64_t score)
{
ScriptVariant tempvar;
Script *cs = &score_script_all;

if(Script_IsInitialized(cs))
{
ScriptVariant_Init(&tempvar);
ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
tempvar.lVal = (LONG)playerindex;
Script_Set_Local_Variant(cs, "player", &tempvar);

ScriptVariant_ChangeType(&tempvar, VT_INTEGER64);
tempvar.llVal = score;
Script_Set_Local_Variant(cs, "score", &tempvar);

Script_Execute(cs);

ScriptVariant_Clear(&tempvar);
Script_Set_Local_Variant(cs, "player", &tempvar);
Script_Set_Local_Variant(cs, "score", &tempvar);
}
}

void execute_timetick_script(int time, int gotime)
{
ScriptVariant tempvar;
Expand Down Expand Up @@ -4084,6 +4125,25 @@ static bool command_token_get_uint64(const s_command_token* token, uint64_t* res
return true;
}

/*
* Caskey, Damon V.
* 2026-08-20
*
* Convert a null-terminated command argument to a
* signed 64-bit integer using the bounded token parser.
*/
static bool command_argument_get_int64(const char* argument, int64_t* result) {
s_command_token token;

assert(argument);
assert(result);

token.text = argument;
token.length = strlen(argument);

return command_token_get_int64(&token, result);
}

/*
* Caskey, Damon V.
* 2026-08-06
Expand Down Expand Up @@ -15743,7 +15803,16 @@ s_model *load_cached_model(char *name, char *owner, char unload)
}
break;
case CMD_MODEL_SCORE:
newchar->score = GET_INT_ARG(1);
if(!command_argument_get_int64(GET_ARG(1), &newchar->score))
{
borShutdown(
1,
"Invalid signed 64-bit score '%s' in %s, line %zu.\n",
GET_ARG(1),
filename,
line
);
}
newchar->multiple = GET_INT_ARG(2); // New var multiple for force/scoring
break;
case CMD_MODEL_SMARTBOMB:
Expand Down Expand Up @@ -24582,10 +24651,15 @@ void load_level(char *filename)
break;
case CMD_LEVEL_SCORE:
// So score can be overriden in the levels .txt file
next.score = GET_INT_ARG(1);
if(next.score == -1)
if(!command_argument_get_int64(GET_ARG(1), &next.score))
{
next.score = 0; // So negative values cannot be added
borShutdown(
1,
"Invalid signed 64-bit score '%s' in %s, line %d.\n",
GET_ARG(1),
filename,
line
);
}
next.multiple = GET_INT_ARG(2);
if(next.multiple == -1)
Expand Down Expand Up @@ -25387,7 +25461,9 @@ void updatestatus() {
}

if(set->continuescore == 2) {
player[i].score = player[i].score + 1;
if(player[i].score < UINT64_MAX) {
player[i].score++;
}
}
}
}
Expand Down Expand Up @@ -26212,13 +26288,13 @@ void predrawstatus()
tmp = player[i].score; //work around issue on 64bit where sizeof(long) != sizeof(int)
if(!pscore[i][2] && !pscore[i][3] && !pscore[i][4] && !pscore[i][5])
{
font_printf(videomodes.shiftpos[i] + pscore[i][0], savedata.windowpos + pscore[i][1], pscore[i][6], 0, (scoreformat ? "%s - %09lu" : "%s - %lu"), (char *)(player[i].ent->name), tmp);
font_printf(videomodes.shiftpos[i] + pscore[i][0], savedata.windowpos + pscore[i][1], pscore[i][6], 0, (scoreformat ? "%s - %09" PRIu64 : "%s - %" PRIu64), (char *)(player[i].ent->name), tmp);
}
else
{
font_printf(videomodes.shiftpos[i] + pscore[i][0], savedata.windowpos + pscore[i][1], pscore[i][6], 0, "%s", player[i].ent->name);
font_printf(videomodes.shiftpos[i] + pscore[i][2], savedata.windowpos + pscore[i][3], pscore[i][6], 0, "-");
font_printf(videomodes.shiftpos[i] + pscore[i][4], savedata.windowpos + pscore[i][5], pscore[i][6], 0, (scoreformat ? "%09lu" : "%lu"), tmp);
font_printf(videomodes.shiftpos[i] + pscore[i][4], savedata.windowpos + pscore[i][5], pscore[i][6], 0, (scoreformat ? "%09" PRIu64 : "%" PRIu64), tmp);
}

if(player[i].ent->energy_state.health_current <= 0)
Expand Down Expand Up @@ -26617,10 +26693,21 @@ void update_loading(s_loadingbar *s, int value, int max)
}
}

void addscore(int playerindex, int add)
/*
* Caskey, Damon V.
* 2026-08-20
*
* Apply a signed 64-bit score adjustment to an unsigned
* player score. Saturate at zero or UINT64_MAX, award
* crossed life thresholds without an unbounded loop, and
* execute the player's score script.
*/
void addscore(int playerindex, int64_t add)
{
uint64_t add_magnitude = 0;
uint64_t life_awards = 0;
uint64_t old_score = 0;
uint64_t s = 0;
uint64_t next1up = 0;
ScriptVariant var; // used for execute script
Script *cs;

Expand All @@ -26631,28 +26718,56 @@ void addscore(int playerindex, int add)

playerindex &= 3;

s = player[playerindex].score;
old_score = player[playerindex].score;
s = old_score;
cs = score_script + playerindex;

if (lifescore > 0) next1up = ((s / lifescore) + 1) * lifescore;
else lifescore = 0;
if(add >= 0)
{
add_magnitude = (uint64_t)add;

s += add;
if(s > 999999999)
if(add_magnitude > UINT64_MAX - s)
{
s = UINT64_MAX;
}
else
{
s += add_magnitude;
}
}
else
{
s = 999999999;
add_magnitude = add == INT64_MIN
? (uint64_t)INT64_MAX + UINT64_C(1)
: (uint64_t)-add;

s = add_magnitude > s ? 0 : s - add_magnitude;
}

while(s > next1up)
/*
* Preserve the legacy strict threshold comparison: a
* life is awarded only after score exceeds the boundary.
*/
if(lifescore > 0 && s > old_score)
{
life_awards = ((s - 1) / lifescore) - (old_score / lifescore);
}

if(life_awards > 0)
{
if(global_sample_list.one_up >= 0)
{
sound_play_sample(global_sample_list.one_up, 0, savedata.effectvol, savedata.effectvol, 100);
}

player[playerindex].lives++;
next1up += lifescore;
if(life_awards > UINT64_MAX - player[playerindex].lives)
{
player[playerindex].lives = UINT64_MAX;
}
else
{
player[playerindex].lives += life_awards;
}
}

player[playerindex].score = s;
Expand All @@ -26661,13 +26776,15 @@ void addscore(int playerindex, int add)
if(Script_IsInitialized(cs))
{
ScriptVariant_Init(&var);
ScriptVariant_ChangeType(&var, VT_INTEGER);
var.lVal = (LONG)add;
ScriptVariant_ChangeType(&var, VT_INTEGER64);
var.llVal = add;
Script_Set_Local_Variant(cs, "score", &var);
Script_Execute(cs);
ScriptVariant_Clear(&var);
Script_Set_Local_Variant(cs, "score", &var);
}

execute_score_script_all(playerindex, add);
}


Expand Down Expand Up @@ -52118,7 +52235,7 @@ void hallfame(int addtoscore)
{
int done = 0;
int topten[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
u32 score;
uint64_t score;
char name[MAX_NAME_LEN + 1];
int i, p, y;
char tmpBuff[MAX_BUFFER_LEN] = {""};
Expand Down Expand Up @@ -52181,7 +52298,7 @@ void hallfame(int addtoscore)
for(i = 0; i < 10; i++)
{
font_printf(_colx(topten[i], col1), y + videomodes.vShift, topten[i], 0, "%2i. %s", i + 1, savescore.hscoren[i]);
font_printf(_colx(topten[i], col2), y + videomodes.vShift, topten[i], 0, (scoreformat ? "%09lu" : "%u"), savescore.highsc[i]);
font_printf(_colx(topten[i], col2), y + videomodes.vShift, topten[i], 0, (scoreformat ? "%09" PRIu64 : "%" PRIu64), savescore.highsc[i]);
y += (videomodes.vRes - videomodes.vShift - 56 - 32) / 10; //font_heights[topten[i]] + 6;
}

Expand Down Expand Up @@ -52283,7 +52400,7 @@ void showcomplete(int num)
font_printf(videomodes.hShift + tscore[0], videomodes.vShift + tscore[1], 0, 0, Tr("Total Score"));
for(i = 0, j = 2, k = 3; i < levelsets[current_set].maxplayers; i++, j = j + 2, k = k + 2) if(player[i].lives > 0)
{
font_printf(videomodes.hShift + tscore[j], videomodes.vShift + tscore[k], 0, 0, (scoreformat ? "%09lu" : "%lu"), player[i].score);
font_printf(videomodes.hShift + tscore[j], videomodes.vShift + tscore[k], 0, 0, (scoreformat ? "%09" PRIu64 : "%" PRIu64), player[i].score);
}

while(_time > nexttime)
Expand Down
15 changes: 8 additions & 7 deletions engine/openbor.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ typedef uint64_t key_mask_t;
"Special thanks to SEGA and SNK.\n\n"

#define COMPATIBLEVERSION 0x00033749
#define CV_SAVED_GAME 0x00033748
#define CV_HIGH_SCORE 0x00033747
#define CV_SAVED_GAME 0x00033750
#define CV_HIGH_SCORE 0x00033751
#define GAME_SPEED_DEFAULT 200
#define THINK_SPEED 2
#define COUNTER_SPEED_DEFAULT (GAME_SPEED_DEFAULT*2)
Expand Down Expand Up @@ -3605,7 +3605,7 @@ typedef struct
int index; // Assign on model read. ~~
char *name; // Model name and default entity name. ~~
char *path; // Path, so scripts can dynamically get files, sprites, sounds, etc. ~~
unsigned score; // Points given to player when defeated or collected as item. ~~
int64_t score; // Points added to or deducted from the player when defeated or collected as item. ~~
int health; // Starting and maximum hit points. ~~ hp
float scroll; // Autoscroll like panel entity. ~~
unsigned offscreenkill; // Distance allowed out of screen until killed. ~~
Expand Down Expand Up @@ -4104,7 +4104,7 @@ typedef struct
char alias[MAX_NAME_LEN];
int health[MAX_PLAYERS];
int mp; // mp's variable for mpbar by tails
unsigned score; // So score can be overridden for enemies/obstacles
int64_t score; // So score can be overridden for enemies/obstacles
int multiple; // So score can be overridden for enemies/obstacles
s_axis_principal_float position; //x, y, z location.
unsigned credit;
Expand Down Expand Up @@ -4748,7 +4748,8 @@ unsigned char *model_get_colourmap(s_model *model, unsigned which);
void ent_set_colourmap(entity *ent, uint64_t which);
void predrawstatus();
void drawstatus();
void addscore(int playerindex, int add);
void addscore(int playerindex, int64_t add);
void execute_score_script_all(int playerindex, int64_t score);
void free_ent(entity *e);
void free_ents();
int alloc_ents();
Expand Down Expand Up @@ -5048,7 +5049,7 @@ typedef struct
unsigned stage; // Stage
unsigned pLives[MAX_PLAYERS]; // Player Lives Left
unsigned pCredits[MAX_PLAYERS]; // Player Credits Left
unsigned pScores[MAX_PLAYERS]; // Player Scores
uint64_t pScores[MAX_PLAYERS]; // Player Scores
unsigned credits; // Number Of Credits
unsigned times_completed;
unsigned which_set;
Expand All @@ -5071,7 +5072,7 @@ typedef struct
typedef struct
{
unsigned compatibleversion;
unsigned highsc[10];
uint64_t highsc[10];
char hscoren[10][MAX_NAME_LEN];
} s_savescore;

Expand Down
4 changes: 1 addition & 3 deletions engine/source/openborscript/model.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ static const model_property_info model_properties[] = {
.id_string = "MODEL_PROPERTY_SCORE",
.config_flags = PROPERTY_ACCESS_CONFIG_MACRO_DEFAULT,
.offset = PROPERTY_MEMBER_OFFSET(s_model, score),
.type = VT_INTEGER },
.type = VT_INTEGER64 },

{.property = MODEL_PROPERTY_SCROLL,
.id_string = "MODEL_PROPERTY_SCROLL",
Expand Down Expand Up @@ -555,5 +555,3 @@ HRESULT openbor_set_model_property(ScriptVariant** varlist, ScriptVariant** cons
}




Loading