Merge branch 'unstable' of github.com:sm64ex-coop-dev/sm64ex-coop into unstable

This commit is contained in:
MysterD 2022-04-29 21:32:18 -07:00
commit 2d85ba5a35
21 changed files with 821 additions and 150 deletions

View file

@ -3198,6 +3198,9 @@ GEO_CONTEXT_RENDER = 1
--- @type integer
GFX_NUM_MASTER_LISTS = 8
--- @type integer
GRAPH_EXTRA_FORCE_3D = (1 << 0)
--- @type integer
GRAPH_NODE_TYPE_400 = 0x400

View file

@ -3860,6 +3860,47 @@ function get_level_name(courseNum, levelNum, areaIndex)
-- ...
end
--- @param courseNum integer
--- @param levelNum integer
--- @param areaIndex integer
--- @param charCase integer
--- @return string
function get_level_name_ascii(courseNum, levelNum, areaIndex, charCase)
-- ...
end
--- @param courseNum integer
--- @param levelNum integer
--- @param areaIndex integer
--- @param charCase integer
--- @return Pointer_integer
function get_level_name_sm64(courseNum, levelNum, areaIndex, charCase)
-- ...
end
--- @param courseNum integer
--- @param starNum integer
--- @return string
function get_star_name(courseNum, starNum)
-- ...
end
--- @param courseNum integer
--- @param starNum integer
--- @param charCase integer
--- @return string
function get_star_name_ascii(courseNum, starNum, charCase)
-- ...
end
--- @param courseNum integer
--- @param starNum integer
--- @param charCase integer
--- @return Pointer_integer
function get_star_name_sm64(courseNum, starNum, charCase)
-- ...
end
--- @param m MarioState
--- @return nil
function adjust_sound_for_speed(m)
@ -7149,6 +7190,16 @@ function movtexqc_register(name, level, area, type)
-- ...
end
--- @param transType integer
--- @param time integer
--- @param red integer
--- @param green integer
--- @param blue integer
--- @return nil
function play_transition(transType, time, red, green, blue)
-- ...
end
--- @param usingBackupSlot boolean
--- @return nil
function save_file_set_using_backup_slot(usingBackupSlot)
@ -7211,6 +7262,12 @@ function obj_check_hitbox_overlap(o1, o2)
-- ...
end
--- @param behaviorId BehaviorId
--- @return integer
function obj_count_objects_with_behavior_id(behaviorId)
-- ...
end
--- @param objList ObjectList
--- @return Object
function obj_get_first(objList)
@ -7239,6 +7296,13 @@ function obj_get_first_with_behavior_id_and_field_s32(behaviorId, fieldIndex, va
-- ...
end
--- @param o Object
--- @param behaviorId BehaviorId
--- @return Object
function obj_get_nearest_object_with_behavior_id(o, behaviorId)
-- ...
end
--- @param o Object
--- @return Object
function obj_get_next(o)

View file

@ -488,6 +488,7 @@
--- @class GraphNode
--- @field public children GraphNode
--- @field public extraFlags integer
--- @field public flags integer
--- @field public next GraphNode
--- @field public parent GraphNode

View file

@ -1058,6 +1058,7 @@
- GEO_CONTEXT_HELD_OBJ
- GEO_CONTEXT_RENDER
- GFX_NUM_MASTER_LISTS
- GRAPH_EXTRA_FORCE_3D
- GRAPH_NODE_TYPE_400
- GRAPH_NODE_TYPE_ANIMATED_PART
- GRAPH_NODE_TYPE_BACKGROUND

View file

@ -2924,6 +2924,117 @@
<br />
## [get_level_name_ascii](#get_level_name_ascii)
### Lua Example
`local stringValue = get_level_name_ascii(courseNum, levelNum, areaIndex, charCase)`
### Parameters
| Field | Type |
| ----- | ---- |
| courseNum | `integer` |
| levelNum | `integer` |
| areaIndex | `integer` |
| charCase | `integer` |
### Returns
- `string`
### C Prototype
`const char *get_level_name_ascii(s16 courseNum, s16 levelNum, s16 areaIndex, s16 charCase);`
[:arrow_up_small:](#)
<br />
## [get_level_name_sm64](#get_level_name_sm64)
### Lua Example
`local PointerValue = get_level_name_sm64(courseNum, levelNum, areaIndex, charCase)`
### Parameters
| Field | Type |
| ----- | ---- |
| courseNum | `integer` |
| levelNum | `integer` |
| areaIndex | `integer` |
| charCase | `integer` |
### Returns
- `Pointer` <`integer`>
### C Prototype
`const u8 *get_level_name_sm64(s16 courseNum, s16 levelNum, s16 areaIndex, s16 charCase);`
[:arrow_up_small:](#)
<br />
## [get_star_name](#get_star_name)
### Lua Example
`local stringValue = get_star_name(courseNum, starNum)`
### Parameters
| Field | Type |
| ----- | ---- |
| courseNum | `integer` |
| starNum | `integer` |
### Returns
- `string`
### C Prototype
`const char *get_star_name(s16 courseNum, s16 starNum);`
[:arrow_up_small:](#)
<br />
## [get_star_name_ascii](#get_star_name_ascii)
### Lua Example
`local stringValue = get_star_name_ascii(courseNum, starNum, charCase)`
### Parameters
| Field | Type |
| ----- | ---- |
| courseNum | `integer` |
| starNum | `integer` |
| charCase | `integer` |
### Returns
- `string`
### C Prototype
`const char *get_star_name_ascii(s16 courseNum, s16 starNum, s16 charCase);`
[:arrow_up_small:](#)
<br />
## [get_star_name_sm64](#get_star_name_sm64)
### Lua Example
`local PointerValue = get_star_name_sm64(courseNum, starNum, charCase)`
### Parameters
| Field | Type |
| ----- | ---- |
| courseNum | `integer` |
| starNum | `integer` |
| charCase | `integer` |
### Returns
- `Pointer` <`integer`>
### C Prototype
`const u8 *get_star_name_sm64(s16 courseNum, s16 starNum, s16 charCase);`
[:arrow_up_small:](#)
<br />
---
# functions from mario.h

View file

@ -4919,6 +4919,30 @@
<br />
## [play_transition](#play_transition)
### Lua Example
`play_transition(transType, time, red, green, blue)`
### Parameters
| Field | Type |
| ----- | ---- |
| transType | `integer` |
| time | `integer` |
| red | `integer` |
| green | `integer` |
| blue | `integer` |
### Returns
- None
### C Prototype
`void play_transition(s16 transType, s16 time, u8 red, u8 green, u8 blue);`
[:arrow_up_small:](#)
<br />
## [save_file_set_using_backup_slot](#save_file_set_using_backup_slot)
### Lua Example
@ -5131,6 +5155,26 @@
<br />
## [obj_count_objects_with_behavior_id](#obj_count_objects_with_behavior_id)
### Lua Example
`local integerValue = obj_count_objects_with_behavior_id(behaviorId)`
### Parameters
| Field | Type |
| ----- | ---- |
| behaviorId | [enum BehaviorId](constants.md#enum-BehaviorId) |
### Returns
- `integer`
### C Prototype
`s32 obj_count_objects_with_behavior_id(enum BehaviorId behaviorId);`
[:arrow_up_small:](#)
<br />
## [obj_get_first](#obj_get_first)
### Lua Example
@ -5215,6 +5259,27 @@
<br />
## [obj_get_nearest_object_with_behavior_id](#obj_get_nearest_object_with_behavior_id)
### Lua Example
`local ObjectValue = obj_get_nearest_object_with_behavior_id(o, behaviorId)`
### Parameters
| Field | Type |
| ----- | ---- |
| o | [Object](structs.md#Object) |
| behaviorId | [enum BehaviorId](constants.md#enum-BehaviorId) |
### Returns
[Object](structs.md#Object)
### C Prototype
`struct Object *obj_get_nearest_object_with_behavior_id(struct Object *o, enum BehaviorId behaviorId);`
[:arrow_up_small:](#)
<br />
## [obj_get_next](#obj_get_next)
### Lua Example

View file

@ -759,6 +759,11 @@
- level_info.h
- [get_level_name](functions-3.md#get_level_name)
- [get_level_name_ascii](functions-3.md#get_level_name_ascii)
- [get_level_name_sm64](functions-3.md#get_level_name_sm64)
- [get_star_name](functions-3.md#get_star_name)
- [get_star_name_ascii](functions-3.md#get_star_name_ascii)
- [get_star_name_sm64](functions-3.md#get_star_name_sm64)
<br />
@ -1339,6 +1344,7 @@
- [hud_hide](functions-4.md#hud_hide)
- [hud_show](functions-4.md#hud_show)
- [movtexqc_register](functions-4.md#movtexqc_register)
- [play_transition](functions-4.md#play_transition)
- [save_file_set_using_backup_slot](functions-4.md#save_file_set_using_backup_slot)
- [set_environment_region](functions-4.md#set_environment_region)
- [warp_exit_level](functions-4.md#warp_exit_level)
@ -1357,10 +1363,12 @@
- [get_temp_object_hitbox](functions-4.md#get_temp_object_hitbox)
- [get_trajectory](functions-4.md#get_trajectory)
- [obj_check_hitbox_overlap](functions-4.md#obj_check_hitbox_overlap)
- [obj_count_objects_with_behavior_id](functions-4.md#obj_count_objects_with_behavior_id)
- [obj_get_first](functions-4.md#obj_get_first)
- [obj_get_first_with_behavior_id](functions-4.md#obj_get_first_with_behavior_id)
- [obj_get_first_with_behavior_id_and_field_f32](functions-4.md#obj_get_first_with_behavior_id_and_field_f32)
- [obj_get_first_with_behavior_id_and_field_s32](functions-4.md#obj_get_first_with_behavior_id_and_field_s32)
- [obj_get_nearest_object_with_behavior_id](functions-4.md#obj_get_nearest_object_with_behavior_id)
- [obj_get_next](functions-4.md#obj_get_next)
- [obj_get_next_with_same_behavior_id](functions-4.md#obj_get_next_with_same_behavior_id)
- [obj_get_next_with_same_behavior_id_and_field_f32](functions-4.md#obj_get_next_with_same_behavior_id_and_field_f32)

View file

@ -709,6 +709,7 @@
| Field | Type | Access |
| ----- | ---- | ------ |
| children | [GraphNode](structs.md#GraphNode) | |
| extraFlags | `integer` | |
| flags | `integer` | |
| next | [GraphNode](structs.md#GraphNode) | |
| parent | [GraphNode](structs.md#GraphNode) | |

View file

@ -803,7 +803,10 @@ void create_next_audio_buffer(s16 *samples, u32 num_samples) {
/**
* Called from threads: thread5_game_loop
*/
extern f32 *smlua_get_vec3f_for_play_sound(f32 *pos);
void play_sound(s32 soundBits, f32 *pos) {
pos = smlua_get_vec3f_for_play_sound(pos);
sSoundRequests[sSoundRequestCount].soundBits = soundBits;
sSoundRequests[sSoundRequestCount].position = pos;
sSoundRequests[sSoundRequestCount].customFreqScale = 0;
@ -811,6 +814,7 @@ void play_sound(s32 soundBits, f32 *pos) {
}
void play_sound_with_freq_scale(s32 soundBits, f32* pos, f32 freqScale) {
pos = smlua_get_vec3f_for_play_sound(pos);
sSoundRequests[sSoundRequestCount].soundBits = soundBits;
sSoundRequests[sSoundRequestCount].position = pos;
sSoundRequests[sSoundRequestCount].customFreqScale = freqScale;

View file

@ -7,150 +7,283 @@
#include "level_table.h"
#include "types.h"
extern u8* seg2_course_name_table[];
#ifdef VERSION_EU
extern u8 *course_name_table_eu_en[];
extern u8 *course_name_table_eu_fr[];
extern u8 *course_name_table_eu_de[];
extern u8 *act_name_table_eu_en[];
extern u8 *act_name_table_eu_fr[];
extern u8 *act_name_table_eu_de[];
#else
extern u8 *seg2_course_name_table[];
extern u8 *seg2_act_name_table[];
#endif
static const char charset[0xFF + 1] = {
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 7
' ', ' ', 'a', 'b', 'c', 'd', 'e', 'f', // 15
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 23
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 31
'w', 'x', 'y', 'z', ' ', ' ', ' ', ' ', // 39
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 49
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 55
' ', ' ', ' ', ' ', ' ', ' ', '\'', ' ', // 63
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 71
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 79
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 87
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 95
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 103
' ', ' ', ' ', ' ', ' ', ' ', ' ', ',', // 111
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 119
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 127
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 135
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 143
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 151
' ', ' ', ' ', ' ', ' ', ' ', ' ', '-', // 159
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 167
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 175
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 183
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 192
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 199
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 207
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 215
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 223
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 231
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 239
' ', ' ', '!', ' ', ' ', ' ', ' ', ' ', // 247
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' // 255
static const struct { const char *str; u8 c; } sSm64CharMap[] = {
// Digits
{ "0", 0x00 }, { "1", 0x01 }, { "2", 0x02 }, { "3", 0x03 }, { "4", 0x04 },
{ "5", 0x05 }, { "6", 0x06 }, { "7", 0x07 }, { "8", 0x08 }, { "9", 0x09 },
// Capital letters
{ "A", 0x0A }, { "B", 0x0B }, { "C", 0x0C }, { "D", 0x0D }, { "E", 0x0E },
{ "F", 0x0F }, { "G", 0x10 }, { "H", 0x11 }, { "I", 0x12 }, { "J", 0x13 },
{ "K", 0x14 }, { "L", 0x15 }, { "M", 0x16 }, { "N", 0x17 }, { "O", 0x18 },
{ "P", 0x19 }, { "Q", 0x1A }, { "R", 0x1B }, { "S", 0x1C }, { "T", 0x1D },
{ "U", 0x1E }, { "V", 0x1F }, { "W", 0x20 }, { "X", 0x21 }, { "Y", 0x22 },
{ "Z", 0x23 },
// Letters
{ "a", 0x24 }, { "b", 0x25 }, { "c", 0x26 }, { "d", 0x27 }, { "e", 0x28 },
{ "f", 0x29 }, { "g", 0x2A }, { "h", 0x2B }, { "i", 0x2C }, { "j", 0x2D },
{ "k", 0x2E }, { "l", 0x2F }, { "m", 0x30 }, { "n", 0x31 }, { "o", 0x32 },
{ "p", 0x33 }, { "q", 0x34 }, { "r", 0x35 }, { "s", 0x36 }, { "t", 0x37 },
{ "u", 0x38 }, { "v", 0x39 }, { "w", 0x3A }, { "x", 0x3B }, { "y", 0x3C },
{ "z", 0x3D },
// Punctuation
{ "...", 0xE6 }, // ellipsis
{ ")(", 0xE2 }, // close-open parentheses
{ "<<", 0xF5 }, // double quote open
{ ">>", 0xF6 }, // double quote close
{ "\'", 0x3E }, // apostrophe
{ ".", 0x3F }, // period
{ ",", 0x6F }, // comma
{ " ", 0x9E }, // space
{ "-", 0x9F }, // dash
{ "(", 0xE1 }, // open parentheses
{ ")", 0xE3 }, // close parentheses
{ "&", 0xE5 }, // ampersand
{ "!", 0xF2 }, // exclamation mark
{ "%", 0xF3 }, // percent
{ "?", 0xF4 }, // question mark
{ "~", 0xF7 }, // tilde
// Symbols
{ "[A]", 0x54 }, // bold A
{ "[B]", 0x55 }, // bold B
{ "[C]", 0x56 }, // bold C
{ "[Z]", 0x57 }, // bold Z
{ "[R]", 0x58 }, // bold R
{ "<->", 0xE4 }, // left-right arrow
{ "^", 0x50 }, // up arrow
{ "|", 0x51 }, // down arrow
{ "<", 0x52 }, // left arrow
{ ">", 0x53 }, // right arrow
{ "+", 0xF9 }, // coin
{ "@", 0xFA }, // star filled
{ "*", 0xFB }, // multiply
{ "$", 0xFD }, // star empty
{ "\n", 0xFE }, // New line
{ NULL, 0xFF }, // Null terminator
};
static void convert_string(const u8* str, char* output) {
s32 strPos = 0;
bool capitalizeChar = true;
static const char *ascii_to_sm64_char(u8 *str64, const char *strAscii) {
for (s32 i = 0; sSm64CharMap[i].str != NULL; ++i) {
if (strstr(strAscii, sSm64CharMap[i].str) == strAscii) {
*str64 = sSm64CharMap[i].c;
return strAscii + strlen(sSm64CharMap[i].str);
}
}
*str64 = 0x9E;
return strAscii + 1;
}
while (str[strPos] != 0xFF) {
if (str[strPos] < 0xFF) {
output[strPos] = charset[str[strPos]];
static char *sm64_to_ascii_char(char *strAscii, const u8 *str64) {
for (s32 i = 0; sSm64CharMap[i].str != NULL; ++i) {
if (sSm64CharMap[i].c == *str64) {
s32 l = strlen(sSm64CharMap[i].str);
memcpy(strAscii, sSm64CharMap[i].str, l);
return strAscii + l;
}
}
*strAscii = ' ';
return strAscii + 1;
}
// if the char is a letter we can capatalize it
if (capitalizeChar && 0x0A <= str[strPos] && str[strPos] <= 0x23) {
output[strPos] -= ('a' - 'A');
capitalizeChar = false;
static void convert_string_ascii_to_sm64(u8 *str64, const char *strAscii) {
for (; *strAscii != 0; str64++) {
strAscii = ascii_to_sm64_char(str64, strAscii);
}
*str64 = 0xFF;
}
static void convert_string_sm64_to_ascii(char *strAscii, const u8 *str64) {
for (; *str64 != 0xFF; str64++) {
strAscii = sm64_to_ascii_char(strAscii, str64);
}
*strAscii = 0;
}
static void capitalize_string_ascii(char *strAscii) {
for (; *strAscii != 0; strAscii++) {
if (*strAscii >= 'a' && *strAscii <= 'z') {
*strAscii += ('A' - 'a');
}
}
}
static void capitalize_string_sm64(u8 *str64) {
for (; *str64 != 0xFF; str64++) {
if (*str64 >= 0x24 && *str64 <= 0x3D) {
*str64 -= 26;
}
}
}
static void decapitalize_string_ascii(char *strAscii) {
for (bool decap = false; *strAscii != 0; strAscii++) {
if (*strAscii >= 'A' && *strAscii <= 'Z') {
if (decap) {
*strAscii += ('a' - 'A');
} else {
decap = true;
}
}
else {
output[strPos] = ' ';
} else if (*strAscii < '0' && *strAscii != '\'') {
decap = false;
}
}
}
// decide if the next character should be capitalized
switch (output[strPos]) {
case ' ':
//if (str[strPos] != 158)
//fprintf(stdout, "Unknown Character (%i)\n", str[strPos]); // inform that an unknown char was found
case '-':
capitalizeChar = true;
break;
default:
capitalizeChar = false;
break;
static void decapitalize_string_sm64(u8 *str64) {
for (bool decap = false; *str64 != 0xFF; str64++) {
if (*str64 >= 0x0A && *str64 <= 0x23) {
if (decap) {
*str64 += 26;
} else {
decap = true;
}
} else if (*str64 >= 0x3F) {
decap = false;
}
}
}
strPos++;
const char *get_level_name_ascii(s16 courseNum, s16 levelNum, s16 areaIndex, s16 charCase) {
static char output[256];
// Valid course: BOB to RR, Bowser stages and Secret courses
// There is no course name for Cake Ending, make it defaults to "Peach's Castle"
if (courseNum >= COURSE_MIN && courseNum < COURSE_MAX) {
void **courseNameTbl = NULL;
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH: courseNameTbl = segmented_to_virtual(course_name_table_eu_en); break;
case LANGUAGE_FRENCH: courseNameTbl = segmented_to_virtual(course_name_table_eu_fr); break;
case LANGUAGE_GERMAN: courseNameTbl = segmented_to_virtual(course_name_table_eu_de); break;
}
#else
courseNameTbl = segmented_to_virtual(seg2_course_name_table);
#endif
const u8 *courseName = segmented_to_virtual(courseNameTbl[courseNum - COURSE_BOB]);
convert_string_sm64_to_ascii(output, courseName + 3);
}
// Castle level
else if (courseNum == COURSE_NONE) {
switch (levelNum) {
case LEVEL_CASTLE: {
switch (areaIndex) {
case 1: snprintf(output, 256, "Castle Main Floor"); break;
case 2: snprintf(output, 256, "Castle Upper Floor"); break;
case 3: snprintf(output, 256, "Castle Basement"); break;
default: snprintf(output, 256, "Castle Purgatory"); break;
}
} break;
case LEVEL_CASTLE_GROUNDS: snprintf(output, 256, "Castle Grounds"); break;
case LEVEL_CASTLE_COURTYARD: snprintf(output, 256, "Castle Courtyard"); break;
default: snprintf(output, 256, "Peach's Castle");
}
}
// Default
else {
snprintf(output, 256, "Peach's Castle");
}
output[strPos] = '\0';
// Capitalize or decapitalize text
if (charCase == -1) {
decapitalize_string_ascii(output);
} else if (charCase == +1) {
capitalize_string_ascii(output);
}
return output;
}
const u8 *get_level_name_sm64(s16 courseNum, s16 levelNum, s16 areaIndex, s16 charCase) {
static u8 output[256];
const char *levelName = get_level_name_ascii(courseNum, levelNum, areaIndex, charCase);
convert_string_ascii_to_sm64(output, levelName);
return output;
}
const char *get_level_name(s16 courseNum, s16 levelNum, s16 areaIndex) {
static char stage[188] = { 0 };
//printf("get_level_name: %i %i %i, COURSE_MAX: %u COURSE_MIN: %u.\n", courseNum, levelNum, areaIndex, COURSE_MAX, COURSE_MIN);
// Overrides for non-course based locations.
if (courseNum == COURSE_NONE) {
// A switch case is much more effective here
// then a if statement, It allows for the
// same results for a different level much easier.
// It also auto-covers if none of the cases match
// with a default.
switch (levelNum) {
case LEVEL_CASTLE_GROUNDS:
strcpy(stage, "Castle Grounds");
break;
case LEVEL_CASTLE:
// Switch case inside a switch case,
// I think it looks ugly but it works.
switch (areaIndex) {
case 1:
strcpy(stage, "Castle Main Floor");
break;
case 2:
strcpy(stage, "Castle Upper Floor");
break;
case 3:
strcpy(stage, "Castle Basement");
break;
default: // If we don't have a proper corresponding area, We return the default.
strcpy(stage, "Castle Purgatory");
break;
}
break;
case LEVEL_CASTLE_COURTYARD:
strcpy(stage, "Castle Courtyard");
break;
default: // If we don't have a proper corresponding level, We return the default.
strcpy(stage, "Peach's Castle");
break;
}
return stage;
}
// If we are in in Course 0 we are in the castle which doesn't have a string.
if (COURSE_IS_VALID_COURSE(courseNum)) {
void **courseNameTbl = NULL;
#ifndef VERSION_EU
courseNameTbl = segmented_to_virtual(seg2_course_name_table);
#else
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
courseNameTbl = segmented_to_virtual(course_name_table_eu_en);
break;
case LANGUAGE_FRENCH:
courseNameTbl = segmented_to_virtual(course_name_table_eu_fr);
break;
case LANGUAGE_GERMAN:
courseNameTbl = segmented_to_virtual(course_name_table_eu_de);
break;
}
#endif
u8 *courseName = segmented_to_virtual(courseNameTbl[courseNum - 1]);
convert_string(&courseName[3], stage);
} else {
strcpy(stage, "Peach's Castle");
}
return stage;
return get_level_name_ascii(courseNum, levelNum, areaIndex, -1);
}
const char *get_star_name_ascii(s16 courseNum, s16 starNum, s16 charCase) {
static char output[256];
// Main courses: BOB to RR
if (COURSE_IS_MAIN_COURSE(courseNum)) {
if (starNum >= 1 && starNum <= 6) {
void **actNameTable = NULL;
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH: actNameTable = segmented_to_virtual(act_name_table_eu_en); break;
case LANGUAGE_FRENCH: actNameTable = segmented_to_virtual(act_name_table_eu_fr); break;
case LANGUAGE_GERMAN: actNameTable = segmented_to_virtual(act_name_table_eu_de); break;
}
#else
actNameTable = segmented_to_virtual(seg2_act_name_table);
#endif
const u8 *starName = segmented_to_virtual(actNameTable[(courseNum - COURSE_BOB) * 6 + (starNum - 1)]);
convert_string_sm64_to_ascii(output, starName);
} else if (starNum == 7) {
snprintf(output, 256, "100 Coins Star");
} else {
snprintf(output, 256, "A Secret Star!");
}
}
// Castle stars: Toads' and Mips'
else if (courseNum == COURSE_NONE) {
switch (starNum) {
case 1: snprintf(output, 256, "Toad Star 1"); break;
case 2: snprintf(output, 256, "Toad Star 2"); break;
case 3: snprintf(output, 256, "Toad Star 3"); break;
case 4: snprintf(output, 256, "Mips Star 1"); break;
case 5: snprintf(output, 256, "Mips Star 2"); break;
default: snprintf(output, 256, "A Secret Star!");
}
}
// Bonus courses: Bowser stages and Secret courses
else if (courseNum <= COURSE_MAX) {
snprintf(output, 256, "Star %d", starNum);
}
// Default
else {
snprintf(output, 256, "A Secret Star!");
}
// Capitalize or decapitalize text
if (charCase == -1) {
decapitalize_string_ascii(output);
} else if (charCase == +1) {
capitalize_string_ascii(output);
}
return output;
}
const u8 *get_star_name_sm64(s16 courseNum, s16 starNum, s16 charCase) {
static u8 output[256];
const char *starName = get_star_name_ascii(courseNum, starNum, charCase);
convert_string_ascii_to_sm64(output, starName);
return output;
}
const char *get_star_name(s16 courseNum, s16 starNum) {
return get_star_name_ascii(courseNum, starNum, -1);
}

View file

@ -3,6 +3,11 @@
#include <PR/ultratypes.h>
const char *get_level_name_ascii(s16 courseNum, s16 levelNum, s16 areaIndex, s16 charCase);
const u8 *get_level_name_sm64(s16 courseNum, s16 levelNum, s16 areaIndex, s16 charCase);
const char *get_level_name(s16 courseNum, s16 levelNum, s16 areaIndex);
const char *get_star_name_ascii(s16 courseNum, s16 starNum, s16 charCase);
const u8 *get_star_name_sm64(s16 courseNum, s16 starNum, s16 charCase);
const char *get_star_name(s16 courseNum, s16 starNum);
#endif // LEVEL_INFO_H

View file

@ -929,7 +929,7 @@ static void bubbled_offset_visual(struct MarioState* m) {
}
s32 act_bubbled(struct MarioState* m) {
if (m->playerIndex == 0) {
if (m->playerIndex == 0 && m->area->camera->mode == CAMERA_MODE_WATER_SURFACE) {
set_camera_mode(m->area->camera, CAMERA_MODE_FREE_ROAM, 1);
}
struct MarioState* targetMarioState = nearest_mario_state_to_object(m->marioObj);

View file

@ -13,6 +13,7 @@
#include "game/level_update.h"
#include "pc/lua/smlua_hooks.h"
#include "pc/utils/misc.h"
#include "pc/debuglog.h"
/**
* This file contains the code that processes the scene graph for rendering.
@ -264,7 +265,7 @@ void patch_mtx_interpolated(f32 delta) {
static u8 increment_mat_stack() {
Mtx *mtx = alloc_display_list(sizeof(*mtx));
Mtx *mtxPrev = alloc_display_list(sizeof(*mtxPrev));
if (mtx == NULL || mtxPrev == NULL) { return FALSE; }
if (mtx == NULL || mtxPrev == NULL) { LOG_ERROR("Failed to allocate our matrices for the matrix stack."); return FALSE; }
gMatStackIndex++;
mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]);
@ -460,7 +461,7 @@ static void geo_process_camera(struct GraphNodeCamera *node) {
Mat4 cameraTransform;
// Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB.
if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; }
if (gMatStackIndex >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
Mtx *rollMtx = alloc_display_list(sizeof(*rollMtx));
if (rollMtx == NULL) { return; }
@ -511,7 +512,7 @@ static void geo_process_translation_rotation(struct GraphNodeTranslationRotation
Vec3f translation;
// Sanity check our stack index, If we above or equal to our stack size. Return top prevent OOB.
if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; }
if (gMatStackIndex >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
vec3s_to_vec3f(translation, node->translation);
mtxf_rotate_zxy_and_translate(mtxf, translation, node->rotation);
@ -540,7 +541,7 @@ static void geo_process_translation(struct GraphNodeTranslation *node) {
Vec3f translation;
// Sanity check our stack index, If we above or equal to our stack size. Return top prevent OOB.
if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; }
if (gMatStackIndex >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
vec3s_to_vec3f(translation, node->translation);
mtxf_rotate_zxy_and_translate(mtxf, translation, gVec3sZero);
@ -568,7 +569,7 @@ static void geo_process_rotation(struct GraphNodeRotation *node) {
Mat4 mtxf;
// Sanity check our stack index, If we above or equal to our stack size. Return top prevent OOB.
if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; }
if (gMatStackIndex >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
mtxf_rotate_zxy_and_translate(mtxf, gVec3fZero, node->rotation);
mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]);
@ -604,7 +605,7 @@ static void geo_process_scale(struct GraphNodeScale *node) {
Vec3f prevScaleVec;
// Sanity check our stack index, If we above or equal to our stack size. Return top prevent OOB.
if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; }
if (gMatStackIndex >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
vec3f_set(scaleVec, node->scale, node->scale, node->scale);
mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex], scaleVec);
@ -635,7 +636,7 @@ static void geo_process_billboard(struct GraphNodeBillboard *node) {
Vec3f translation;
// Sanity check our stack index, If we above or equal to our stack size. Return top prevent OOB.
if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; }
if (gMatStackIndex >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
s16 nextMatStackIndex = gMatStackIndex + 1;
@ -654,6 +655,8 @@ static void geo_process_billboard(struct GraphNodeBillboard *node) {
gCurGraphNodeObject->scale);
mtxf_scale_vec3f(gMatStackPrev[nextMatStackIndex], gMatStackPrev[nextMatStackIndex],
gCurGraphNodeObject->scale);
} else {
//LOG_ERROR("gCurGraphNodeObject and gCurGraphNodeHeldObject are both NULL!");
}
// Increment the matrix stack, If we fail to do so. Just return.
@ -805,7 +808,7 @@ static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) {
Vec3f translationPrev;
// Sanity check our stack index, If we above or equal to our stack size. Return top prevent OOB.
if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; }
if (gMatStackIndex >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
u16 *animAttribute = gCurrAnimAttribute;
u8 animType = gCurAnimType;
@ -899,7 +902,7 @@ static void geo_process_shadow(struct GraphNodeShadow *node) {
f32 shadowScale;
// Sanity check our stack index, If we above or equal to our stack size. Return top prevent OOB.
if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; }
if (gMatStackIndex >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
if (gCurGraphNodeCamera != NULL && gCurGraphNodeObject != NULL) {
if (gCurGraphNodeHeldObject != NULL) {
@ -1284,7 +1287,7 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) {
Vec3f scalePrev;
// Sanity check our stack index, If we above or equal to our stack size. Return top prevent OOB.
if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; }
if (gMatStackIndex >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; }
#ifdef F3DEX_GBI_2
gSPLookAt(gDisplayListHead++, &lookAt);

View file

@ -5,6 +5,7 @@
#include "chat_commands.h"
#include "pc/network/ban_list.h"
#include "pc/debuglog.h"
#include "level_table.h"
enum ChatConfirmCommand {
CCC_NONE,
@ -181,6 +182,88 @@ bool exec_chat_command(char* command) {
return true;
}
#if defined(DEBUG) && defined(DEVELOPMENT)
if (gNetworkSystem == &gNetworkSystemSocket && str_starts_with("/warp ", command)) {
static const struct { const char *name; s32 num; } sLevelNumByName[] = {
#undef STUB_LEVEL
#undef DEFINE_LEVEL
#define STUB_LEVEL(...)
#define DEFINE_LEVEL(_0, levelnum, _2, levelname, ...) { #levelname, levelnum },
#include "levels/level_defines.h"
#undef STUB_LEVEL
#undef DEFINE_LEVEL
};
// Params
char *paramLevel = command + 6;
if (*paramLevel == 0 || *paramLevel == ' ') {
djui_chat_message_create("Missing parameters: [LEVEL] [AREA] [ACT]");
return true;
}
char *paramArea = strchr(paramLevel, ' ');
if (paramArea++ == NULL || *paramArea == 0 || *paramArea == ' ') {
djui_chat_message_create("Missing parameters: [AREA] [ACT]");
return true;
}
char *paramAct = strchr(paramArea, ' ');
if (paramAct++ == NULL || *paramAct == 0 || *paramAct == ' ') {
djui_chat_message_create("Missing parameters: [ACT]");
return true;
}
*(paramArea - 1) = 0;
*(paramAct - 1) = 0;
// Level
s32 level = -1;
if (sscanf(paramLevel, "%d", &level) <= 0) {
for (s32 i = 0; i != (s32) (sizeof(sLevelNumByName) / sizeof(sLevelNumByName[0])); ++i) {
if (strstr(paramLevel, sLevelNumByName[i].name) == paramLevel) {
level = sLevelNumByName[i].num;
break;
}
}
if (level == -1) {
char message[256];
snprintf(message, 256, "Invalid [LEVEL] parameter: %s", paramLevel);
djui_chat_message_create(message);
return true;
}
}
// Area
s32 area = -1;
if (sscanf(paramArea, "%d", &area) <= 0) {
char message[256];
snprintf(message, 256, "Invalid [AREA] parameter: %s", paramArea);
djui_chat_message_create(message);
return true;
}
// Act
s32 act = -1;
if (sscanf(paramAct, "%d", &act) <= 0) {
char message[256];
snprintf(message, 256, "Invalid [ACT] parameter: %s", paramAct);
djui_chat_message_create(message);
return true;
}
// Warp
if (!dynos_warp_to_level(level, area, act)) {
char message[256];
snprintf(message, 256, "Unable to warp to: %s %s %s", paramLevel, paramArea, paramAct);
djui_chat_message_create(message);
return true;
}
// OK
char message[256];
snprintf(message, 256, "Warping to: %s %s %s...", paramLevel, paramArea, paramAct);
djui_chat_message_create(message);
return true;
}
#endif
return smlua_call_chat_command_hook(command);
}
@ -191,6 +274,9 @@ void display_chat_commands(void) {
djui_chat_message_create("/ban [NAME|ID] - Ban this player from the current game");
djui_chat_message_create("/permban [NAME|ID] - Ban this player from any game you host");
}
#if defined(DEBUG) && defined(DEVELOPMENT)
djui_chat_message_create("/warp [LEVEL] [AREA] [ACT] - Level can be either a numeric value or a shorthand name");
#endif
if (sConfirming != CCC_NONE) { djui_chat_message_create("/confirm"); }
smlua_display_chat_commands();
}

View file

@ -563,15 +563,16 @@ static struct LuaObjectField sGlobalTexturesFields[LUA_GLOBAL_TEXTURES_FIELD_COU
{ "star", LVT_COBJECT, offsetof(struct GlobalTextures, star), true, LOT_TEXTUREINFO },
};
#define LUA_GRAPH_NODE_FIELD_COUNT 6
#define LUA_GRAPH_NODE_FIELD_COUNT 7
static struct LuaObjectField sGraphNodeFields[LUA_GRAPH_NODE_FIELD_COUNT] = {
{ "children", LVT_COBJECT_P, offsetof(struct GraphNode, children), false, LOT_GRAPHNODE },
{ "flags", LVT_S16, offsetof(struct GraphNode, flags), false, LOT_NONE },
// { "georef", LVT_???, offsetof(struct GraphNode, georef), true, LOT_??? }, <--- UNIMPLEMENTED
{ "next", LVT_COBJECT_P, offsetof(struct GraphNode, next), false, LOT_GRAPHNODE },
{ "parent", LVT_COBJECT_P, offsetof(struct GraphNode, parent), false, LOT_GRAPHNODE },
{ "prev", LVT_COBJECT_P, offsetof(struct GraphNode, prev), false, LOT_GRAPHNODE },
{ "type", LVT_S16, offsetof(struct GraphNode, type), false, LOT_NONE },
{ "children", LVT_COBJECT_P, offsetof(struct GraphNode, children), false, LOT_GRAPHNODE },
{ "extraFlags", LVT_U8, offsetof(struct GraphNode, extraFlags), false, LOT_NONE },
{ "flags", LVT_S16, offsetof(struct GraphNode, flags), false, LOT_NONE },
// { "georef", LVT_???, offsetof(struct GraphNode, georef), true, LOT_??? }, <--- UNIMPLEMENTED
{ "next", LVT_COBJECT_P, offsetof(struct GraphNode, next), false, LOT_GRAPHNODE },
{ "parent", LVT_COBJECT_P, offsetof(struct GraphNode, parent), false, LOT_GRAPHNODE },
{ "prev", LVT_COBJECT_P, offsetof(struct GraphNode, prev), false, LOT_GRAPHNODE },
{ "type", LVT_S16, offsetof(struct GraphNode, type), false, LOT_NONE },
};
#define LUA_GRAPH_NODE_OBJECT_FIELD_COUNT 19

View file

@ -1258,6 +1258,7 @@ char gSmluaConstants[] = ""
"GRAPH_RENDER_HAS_ANIMATION = (1 << 5)\n"
"GRAPH_RENDER_CYLBOARD = (1 << 6)\n"
"GRAPH_RENDER_PLAYER = (1 << 7)\n"
"GRAPH_EXTRA_FORCE_3D = (1 << 0)\n"
"GRAPH_NODE_TYPE_FUNCTIONAL = 0x100\n"
"GRAPH_NODE_TYPE_400 = 0x400\n"
"GRAPH_NODE_TYPE_ROOT = 0x001\n"

View file

@ -7764,6 +7764,83 @@ int smlua_func_get_level_name(lua_State* L) {
return 1;
}
int smlua_func_get_level_name_ascii(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 4)) { return 0; }
s16 courseNum = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
s16 levelNum = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 2"); return 0; }
s16 areaIndex = smlua_to_integer(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 3"); return 0; }
s16 charCase = smlua_to_integer(L, 4);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 4"); return 0; }
lua_pushstring(L, get_level_name_ascii(courseNum, levelNum, areaIndex, charCase));
return 1;
}
int smlua_func_get_level_name_sm64(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 4)) { return 0; }
s16 courseNum = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
s16 levelNum = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 2"); return 0; }
s16 areaIndex = smlua_to_integer(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 3"); return 0; }
s16 charCase = smlua_to_integer(L, 4);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 4"); return 0; }
smlua_push_pointer(L, LVT_U8_P, (void*)get_level_name_sm64(courseNum, levelNum, areaIndex, charCase));
return 1;
}
int smlua_func_get_star_name(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 2)) { return 0; }
s16 courseNum = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
s16 starNum = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 2"); return 0; }
lua_pushstring(L, get_star_name(courseNum, starNum));
return 1;
}
int smlua_func_get_star_name_ascii(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 3)) { return 0; }
s16 courseNum = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
s16 starNum = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 2"); return 0; }
s16 charCase = smlua_to_integer(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 3"); return 0; }
lua_pushstring(L, get_star_name_ascii(courseNum, starNum, charCase));
return 1;
}
int smlua_func_get_star_name_sm64(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 3)) { return 0; }
s16 courseNum = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
s16 starNum = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 2"); return 0; }
s16 charCase = smlua_to_integer(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 3"); return 0; }
smlua_push_pointer(L, LVT_U8_P, (void*)get_star_name_sm64(courseNum, starNum, charCase));
return 1;
}
/////////////
// mario.h //
/////////////
@ -14727,6 +14804,25 @@ int smlua_func_movtexqc_register(lua_State* L) {
return 1;
}
int smlua_func_play_transition(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 5)) { return 0; }
s16 transType = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
s16 time = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 2"); return 0; }
u8 red = smlua_to_integer(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 3"); return 0; }
u8 green = smlua_to_integer(L, 4);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 4"); return 0; }
u8 blue = smlua_to_integer(L, 5);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 5"); return 0; }
play_transition(transType, time, red, green, blue);
return 1;
}
int smlua_func_save_file_set_using_backup_slot(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 1)) { return 0; }
@ -14849,6 +14945,17 @@ int smlua_func_obj_check_hitbox_overlap(lua_State* L) {
return 1;
}
int smlua_func_obj_count_objects_with_behavior_id(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 1)) { return 0; }
int behaviorId = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
lua_pushinteger(L, obj_count_objects_with_behavior_id(behaviorId));
return 1;
}
int smlua_func_obj_get_first(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 1)) { return 0; }
@ -14901,6 +15008,19 @@ int smlua_func_obj_get_first_with_behavior_id_and_field_s32(lua_State* L) {
return 1;
}
int smlua_func_obj_get_nearest_object_with_behavior_id(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 2)) { return 0; }
struct Object* o = (struct Object*)smlua_to_cobject(L, 1, LOT_OBJECT);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
int behaviorId = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 2"); return 0; }
smlua_push_object(L, LOT_OBJECT, obj_get_nearest_object_with_behavior_id(o, behaviorId));
return 1;
}
int smlua_func_obj_get_next(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 1)) { return 0; }
@ -16398,6 +16518,11 @@ void smlua_bind_functions_autogen(void) {
// level_info.h
smlua_bind_function(L, "get_level_name", smlua_func_get_level_name);
smlua_bind_function(L, "get_level_name_ascii", smlua_func_get_level_name_ascii);
smlua_bind_function(L, "get_level_name_sm64", smlua_func_get_level_name_sm64);
smlua_bind_function(L, "get_star_name", smlua_func_get_star_name);
smlua_bind_function(L, "get_star_name_ascii", smlua_func_get_star_name_ascii);
smlua_bind_function(L, "get_star_name_sm64", smlua_func_get_star_name_sm64);
// mario.h
smlua_bind_function(L, "adjust_sound_for_speed", smlua_func_adjust_sound_for_speed);
@ -16953,6 +17078,7 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "hud_hide", smlua_func_hud_hide);
smlua_bind_function(L, "hud_show", smlua_func_hud_show);
smlua_bind_function(L, "movtexqc_register", smlua_func_movtexqc_register);
smlua_bind_function(L, "play_transition", smlua_func_play_transition);
smlua_bind_function(L, "save_file_set_using_backup_slot", smlua_func_save_file_set_using_backup_slot);
smlua_bind_function(L, "set_environment_region", smlua_func_set_environment_region);
smlua_bind_function(L, "warp_exit_level", smlua_func_warp_exit_level);
@ -16967,10 +17093,12 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "get_temp_object_hitbox", smlua_func_get_temp_object_hitbox);
smlua_bind_function(L, "get_trajectory", smlua_func_get_trajectory);
smlua_bind_function(L, "obj_check_hitbox_overlap", smlua_func_obj_check_hitbox_overlap);
smlua_bind_function(L, "obj_count_objects_with_behavior_id", smlua_func_obj_count_objects_with_behavior_id);
smlua_bind_function(L, "obj_get_first", smlua_func_obj_get_first);
smlua_bind_function(L, "obj_get_first_with_behavior_id", smlua_func_obj_get_first_with_behavior_id);
smlua_bind_function(L, "obj_get_first_with_behavior_id_and_field_f32", smlua_func_obj_get_first_with_behavior_id_and_field_f32);
smlua_bind_function(L, "obj_get_first_with_behavior_id_and_field_s32", smlua_func_obj_get_first_with_behavior_id_and_field_s32);
smlua_bind_function(L, "obj_get_nearest_object_with_behavior_id", smlua_func_obj_get_nearest_object_with_behavior_id);
smlua_bind_function(L, "obj_get_next", smlua_func_obj_get_next);
smlua_bind_function(L, "obj_get_next_with_same_behavior_id", smlua_func_obj_get_next_with_same_behavior_id);
smlua_bind_function(L, "obj_get_next_with_same_behavior_id_and_field_f32", smlua_func_obj_get_next_with_same_behavior_id_and_field_f32);

View file

@ -1,5 +1,6 @@
#include "smlua.h"
#include "src/pc/mods/mods.h"
#include "audio/external.h"
u8 gSmLuaConvertSuccess = false;
@ -21,6 +22,21 @@ s16* smlua_get_vec3s_from_buffer(void) {
return sVec3sBuffer[sVec3sBufferIndex++];
}
f32 *smlua_get_vec3f_for_play_sound(f32 *pos) {
if (pos < (f32 *) sVec3fBuffer || pos >= (f32 *) (sVec3fBuffer + VEC3F_BUFFER_COUNT)) {
return pos;
}
if (memcmp(pos, gGlobalSoundSource, sizeof(Vec3f)) == 0) {
return gGlobalSoundSource;
}
for (s32 i = 0; i != MAX_PLAYERS; ++i) {
if (gMarioStates[i].marioObj && memcmp(pos, gMarioStates[i].marioObj->header.gfx.cameraToObject, sizeof(Vec3f)) == 0) {
return gMarioStates[i].marioObj->header.gfx.cameraToObject;
}
}
return pos;
}
///////////////////////////////////////////////////////////////////////////////////////////
void smlua_bind_function(lua_State* L, const char* name, void* func) {

View file

@ -29,4 +29,6 @@ void movtexqc_register(const char* name, s16 level, s16 area, s16 type);
f32 get_environment_region(u8 index);
void set_environment_region(u8 index, s32 value);
void play_transition(s16 transType, s16 time, u8 red, u8 green, u8 blue);
#endif

View file

@ -156,6 +156,40 @@ struct Object *obj_get_first_with_behavior_id_and_field_f32(enum BehaviorId beha
return NULL;
}
struct Object *obj_get_nearest_object_with_behavior_id(struct Object *o, enum BehaviorId behaviorId) {
f32 minDist = 0x20000;
const BehaviorScript *behavior = get_behavior_from_id(behaviorId);
struct Object *closestObj = NULL;
if (behavior) {
enum ObjectList objList = get_object_list_from_behavior(behavior);
for (struct Object *obj = obj_get_first(objList); obj != NULL; obj = obj_get_next(obj)) {
if (obj->behavior == behavior && obj->activeFlags != ACTIVE_FLAG_DEACTIVATED) {
f32 objDist = dist_between_objects(o, obj);
if (objDist < minDist) {
closestObj = obj;
minDist = objDist;
}
}
}
}
return closestObj;
}
s32 obj_count_objects_with_behavior_id(enum BehaviorId behaviorId) {
const BehaviorScript *behavior = get_behavior_from_id(behaviorId);
s32 count = 0;
if (behavior) {
enum ObjectList objList = get_object_list_from_behavior(behavior);
for (struct Object *obj = obj_get_first(objList); obj != NULL; obj = obj_get_next(obj)) {
if (obj->behavior == behavior) { count++; }
}
}
return count;
}
struct Object *obj_get_next(struct Object *o) {
if (gObjectLists && o) {
enum ObjectList objList = get_object_list_from_behavior(o->behavior);

View file

@ -28,6 +28,10 @@ struct Object *obj_get_next_with_same_behavior_id(struct Object *o);
struct Object *obj_get_next_with_same_behavior_id_and_field_s32(struct Object *o, s32 fieldIndex, s32 value);
struct Object *obj_get_next_with_same_behavior_id_and_field_f32(struct Object *o, s32 fieldIndex, f32 value);
struct Object *obj_get_nearest_object_with_behavior_id(struct Object *o, enum BehaviorId behaviorId);
s32 obj_count_objects_with_behavior_id(enum BehaviorId behaviorId);
// misc obj helpers
struct SpawnParticlesInfo* obj_get_temp_spawn_particles_info(enum ModelExtendedId modelId);