mirror of
https://github.com/open-goal/jak-project.git
synced 2024-11-23 06:09:57 +00:00
jak3: speedrunner mode (#3761)
Some checks are pending
Build / 🖥️ Windows (push) Waiting to run
Build / 🐧 Linux (push) Waiting to run
Build / 🍎 MacOS (push) Waiting to run
Inform Pages Repo / Generate Documentation (push) Waiting to run
Lint / 📝 Formatting (push) Waiting to run
Lint / 📝 Required Checks (push) Waiting to run
Lint / 📝 Optional Checks (push) Waiting to run
Some checks are pending
Build / 🖥️ Windows (push) Waiting to run
Build / 🐧 Linux (push) Waiting to run
Build / 🍎 MacOS (push) Waiting to run
Inform Pages Repo / Generate Documentation (push) Waiting to run
Lint / 📝 Formatting (push) Waiting to run
Lint / 📝 Required Checks (push) Waiting to run
Lint / 📝 Optional Checks (push) Waiting to run
Base implementation of the popup menu and speedrunner mode in Jak 3. Autosplitter is untested because I'm on Linux. Also a couple of other misc changes: - Model replacements can now have custom bone weights. Needs the "Use Custom Bone Weights" property (provided by the OpenGOAL Blender plugin) enabled in Blender. - Better error message for lump syntax errors in custom level JSON files.
This commit is contained in:
parent
5e3cb8faa6
commit
7543acfb8a
@ -90,6 +90,7 @@ def draw_func_ob(self, context):
|
||||
layout = self.layout
|
||||
ob = context.object
|
||||
layout.prop(ob, "set_invisible")
|
||||
layout.prop(ob, "enable_custom_weights")
|
||||
layout.prop(ob, "set_collision")
|
||||
if (ob.set_collision):
|
||||
layout.prop(ob, "ignore")
|
||||
@ -116,6 +117,7 @@ def register():
|
||||
|
||||
bpy.types.Object.set_invisible = bpy.props.BoolProperty(name="Invisible")
|
||||
bpy.types.Object.set_collision = bpy.props.BoolProperty(name="Apply Collision Properties")
|
||||
bpy.types.Object.enable_custom_weights = bpy.props.BoolProperty(name="Use Custom Bone Weights")
|
||||
bpy.types.Object.ignore = bpy.props.BoolProperty(name="ignore")
|
||||
bpy.types.Object.noedge = bpy.props.BoolProperty(name="No-Edge")
|
||||
bpy.types.Object.noentity = bpy.props.BoolProperty(name="No-Entity")
|
||||
|
@ -9,7 +9,8 @@ void extract(const std::string& name,
|
||||
const std::vector<NodeWithTransform>& all_nodes,
|
||||
u32 index_offset,
|
||||
u32 vertex_offset,
|
||||
u32 tex_offset) {
|
||||
u32 tex_offset,
|
||||
bool& has_custom_weights) {
|
||||
ASSERT(out.new_vertices.empty());
|
||||
|
||||
std::map<int, tfrag3::MercDraw> draw_by_material;
|
||||
@ -24,6 +25,8 @@ void extract(const std::string& name,
|
||||
if (node.mesh >= 0) {
|
||||
const auto& mesh = model.meshes[node.mesh];
|
||||
mesh_count++;
|
||||
has_custom_weights = node.extras.Has("enable_custom_weights") &&
|
||||
node.extras.Get("enable_custom_weights").Get<int>();
|
||||
for (const auto& prim : mesh.primitives) {
|
||||
prim_count++;
|
||||
// extract index buffer
|
||||
@ -39,6 +42,21 @@ void extract(const std::string& name,
|
||||
out.normals.insert(out.normals.end(), verts.normals.begin(), verts.normals.end());
|
||||
ASSERT(out.new_colors.size() == out.new_vertices.size());
|
||||
|
||||
if (prim.attributes.count("JOINTS_0") && prim.attributes.count("WEIGHTS_0")) {
|
||||
auto joints_and_weights = gltf_util::extract_and_flatten_joints_and_weights(model, prim);
|
||||
ASSERT(joints_and_weights.size() == verts.vtx.size());
|
||||
out.joints_and_weights.insert(out.joints_and_weights.end(), joints_and_weights.begin(),
|
||||
joints_and_weights.end());
|
||||
} else {
|
||||
// add fake data for vertices without this data
|
||||
gltf_util::JointsAndWeights dummy;
|
||||
dummy.joints[0] = 3;
|
||||
dummy.weights[0] = 1.f;
|
||||
for (size_t i = 0; i < out.new_vertices.size(); i++) {
|
||||
out.joints_and_weights.push_back(dummy);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: just putting it all in one material
|
||||
auto& draw = draw_by_material[prim.material];
|
||||
draw.mode = gltf_util::make_default_draw_mode(); // todo rm
|
||||
@ -119,7 +137,8 @@ const tfrag3::MercVertex& find_closest(const std::vector<tfrag3::MercVertex>& ol
|
||||
|
||||
void merc_convert_replacement(MercSwapData& out,
|
||||
const MercExtractData& in,
|
||||
const std::vector<tfrag3::MercVertex>& old_verts) {
|
||||
const std::vector<tfrag3::MercVertex>& old_verts,
|
||||
bool use_custom_weights) {
|
||||
out.new_model = in.new_model;
|
||||
out.new_indices = in.new_indices;
|
||||
out.new_textures = in.tex_pool.textures_by_idx;
|
||||
@ -127,6 +146,7 @@ void merc_convert_replacement(MercSwapData& out,
|
||||
// convert vertices
|
||||
for (size_t i = 0; i < in.new_vertices.size(); i++) {
|
||||
const auto& y = in.new_vertices[i];
|
||||
|
||||
const auto& copy_from = find_closest(old_verts, y.x, y.y, y.z);
|
||||
auto& x = out.new_vertices.emplace_back();
|
||||
x.pos[0] = y.x;
|
||||
@ -135,18 +155,27 @@ void merc_convert_replacement(MercSwapData& out,
|
||||
x.normal[0] = in.normals.at(i).x();
|
||||
x.normal[1] = in.normals.at(i).y();
|
||||
x.normal[2] = in.normals.at(i).z();
|
||||
x.weights[0] = copy_from.weights[0];
|
||||
x.weights[1] = copy_from.weights[1];
|
||||
x.weights[2] = copy_from.weights[2];
|
||||
if (use_custom_weights) {
|
||||
x.weights[0] = in.joints_and_weights.at(i).weights[0];
|
||||
x.weights[1] = in.joints_and_weights.at(i).weights[1];
|
||||
x.weights[2] = in.joints_and_weights.at(i).weights[2];
|
||||
x.mats[0] = in.joints_and_weights.at(i).joints[0];
|
||||
x.mats[1] = in.joints_and_weights.at(i).joints[1];
|
||||
x.mats[2] = in.joints_and_weights.at(i).joints[2];
|
||||
} else {
|
||||
x.weights[0] = copy_from.weights[0];
|
||||
x.weights[1] = copy_from.weights[1];
|
||||
x.weights[2] = copy_from.weights[2];
|
||||
x.mats[0] = copy_from.mats[0];
|
||||
x.mats[1] = copy_from.mats[1];
|
||||
x.mats[2] = copy_from.mats[2];
|
||||
}
|
||||
x.st[0] = y.s;
|
||||
x.st[1] = y.t;
|
||||
x.rgba[0] = in.new_colors[i][0];
|
||||
x.rgba[1] = in.new_colors[i][1];
|
||||
x.rgba[2] = in.new_colors[i][2];
|
||||
x.rgba[3] = in.new_colors[i][3];
|
||||
x.mats[0] = copy_from.mats[0];
|
||||
x.mats[1] = copy_from.mats[1];
|
||||
x.mats[2] = copy_from.mats[2];
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,18 +194,18 @@ void merc_convert_custom(MercSwapData& out, const MercExtractData& in) {
|
||||
x.normal[0] = in.normals.at(i).x();
|
||||
x.normal[1] = in.normals.at(i).y();
|
||||
x.normal[2] = in.normals.at(i).z();
|
||||
x.weights[0] = 1.0f;
|
||||
x.weights[1] = 0.0f;
|
||||
x.weights[2] = 0.0f;
|
||||
x.weights[0] = in.joints_and_weights.at(i).weights[0];
|
||||
x.weights[1] = in.joints_and_weights.at(i).weights[1];
|
||||
x.weights[2] = in.joints_and_weights.at(i).weights[2];
|
||||
x.st[0] = y.s;
|
||||
x.st[1] = y.t;
|
||||
x.rgba[0] = in.new_colors[i][0];
|
||||
x.rgba[1] = in.new_colors[i][1];
|
||||
x.rgba[2] = in.new_colors[i][2];
|
||||
x.rgba[3] = in.new_colors[i][3];
|
||||
x.mats[0] = 3;
|
||||
x.mats[1] = 0;
|
||||
x.mats[2] = 0;
|
||||
x.mats[0] = in.joints_and_weights.at(i).joints[0];
|
||||
x.mats[1] = in.joints_and_weights.at(i).joints[1];
|
||||
x.mats[2] = in.joints_and_weights.at(i).joints[2];
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,12 +228,13 @@ MercSwapData load_replacement_merc_model(const std::string& name,
|
||||
auto all_nodes = flatten_nodes_from_all_scenes(model);
|
||||
|
||||
MercExtractData extract_data;
|
||||
auto has_custom_weights = false;
|
||||
extract(name, extract_data, model, all_nodes, current_idx_count, current_vtx_count,
|
||||
current_tex_count);
|
||||
current_tex_count, has_custom_weights);
|
||||
if (custom_mdl) {
|
||||
merc_convert_custom(result, extract_data);
|
||||
} else {
|
||||
merc_convert_replacement(result, extract_data, old_verts);
|
||||
merc_convert_replacement(result, extract_data, old_verts, has_custom_weights);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -10,7 +10,7 @@ struct MercExtractData {
|
||||
std::vector<tfrag3::PreloadedVertex> new_vertices;
|
||||
std::vector<math::Vector<u8, 4>> new_colors;
|
||||
std::vector<math::Vector3f> normals;
|
||||
|
||||
std::vector<gltf_util::JointsAndWeights> joints_and_weights;
|
||||
tfrag3::MercModel new_model;
|
||||
};
|
||||
|
||||
|
@ -11,8 +11,6 @@ void pc_set_levels(u32 lev_list);
|
||||
void pc_set_active_levels(u32 lev_list);
|
||||
u32 alloc_vagdir_names(u32 heap_sym);
|
||||
inline u64 bool_to_symbol(const bool val);
|
||||
// TODO - move to common
|
||||
void encode_utf8_string(u32 src_str_ptr, u32 str_dest_ptr);
|
||||
void init_autosplit_struct();
|
||||
void callback_fetch_external_speedrun_times(bool success,
|
||||
const std::string& cache_id,
|
||||
|
@ -369,7 +369,8 @@ void InitMachine_PCPort() {
|
||||
make_function_symbol_from_c("__pc-set-active-levels",
|
||||
(void*)kmachine_extras::pc_set_active_levels);
|
||||
make_function_symbol_from_c("__pc-get-tex-remap", (void*)lookup_jak3_texture_dest_offset);
|
||||
// make_function_symbol_from_c("pc-init-autosplitter-struct", (void*)init_autosplit_struct);
|
||||
make_function_symbol_from_c("pc-init-autosplitter-struct",
|
||||
(void*)kmachine_extras::init_autosplit_struct);
|
||||
|
||||
// discord rich presence
|
||||
make_function_symbol_from_c("pc-discord-rpc-update", (void*)kmachine_extras::update_discord_rpc);
|
||||
@ -395,6 +396,45 @@ void InitMachine_PCPort() {
|
||||
(void*)pc_get_num_external_highscores);
|
||||
*/
|
||||
|
||||
// speedrunning stuff
|
||||
make_function_symbol_from_c("pc-sr-mode-get-practice-entries-amount",
|
||||
(void*)kmachine_extras::pc_sr_mode_get_practice_entries_amount);
|
||||
make_function_symbol_from_c("pc-sr-mode-get-practice-entry-name",
|
||||
(void*)kmachine_extras::pc_sr_mode_get_practice_entry_name);
|
||||
make_function_symbol_from_c("pc-sr-mode-get-practice-entry-continue-point",
|
||||
(void*)kmachine_extras::pc_sr_mode_get_practice_entry_continue_point);
|
||||
make_function_symbol_from_c(
|
||||
"pc-sr-mode-get-practice-entry-history-success",
|
||||
(void*)kmachine_extras::pc_sr_mode_get_practice_entry_history_success);
|
||||
make_function_symbol_from_c(
|
||||
"pc-sr-mode-get-practice-entry-history-attempts",
|
||||
(void*)kmachine_extras::pc_sr_mode_get_practice_entry_history_attempts);
|
||||
make_function_symbol_from_c(
|
||||
"pc-sr-mode-get-practice-entry-session-success",
|
||||
(void*)kmachine_extras::pc_sr_mode_get_practice_entry_session_success);
|
||||
make_function_symbol_from_c(
|
||||
"pc-sr-mode-get-practice-entry-session-attempts",
|
||||
(void*)kmachine_extras::pc_sr_mode_get_practice_entry_session_attempts);
|
||||
make_function_symbol_from_c("pc-sr-mode-get-practice-entry-avg-time",
|
||||
(void*)kmachine_extras::pc_sr_mode_get_practice_entry_avg_time);
|
||||
make_function_symbol_from_c("pc-sr-mode-get-practice-entry-fastest-time",
|
||||
(void*)kmachine_extras::pc_sr_mode_get_practice_entry_fastest_time);
|
||||
make_function_symbol_from_c("pc-sr-mode-record-practice-entry-attempt!",
|
||||
(void*)kmachine_extras::pc_sr_mode_record_practice_entry_attempt);
|
||||
make_function_symbol_from_c("pc-sr-mode-init-practice-info!",
|
||||
(void*)kmachine_extras::pc_sr_mode_init_practice_info);
|
||||
make_function_symbol_from_c("pc-sr-mode-get-custom-category-amount",
|
||||
(void*)kmachine_extras::pc_sr_mode_get_custom_category_amount);
|
||||
make_function_symbol_from_c("pc-sr-mode-get-custom-category-name",
|
||||
(void*)kmachine_extras::pc_sr_mode_get_custom_category_name);
|
||||
make_function_symbol_from_c(
|
||||
"pc-sr-mode-get-custom-category-continue-point",
|
||||
(void*)kmachine_extras::pc_sr_mode_get_custom_category_continue_point);
|
||||
make_function_symbol_from_c("pc-sr-mode-init-custom-category-info!",
|
||||
(void*)kmachine_extras::pc_sr_mode_init_custom_category_info);
|
||||
make_function_symbol_from_c("pc-sr-mode-dump-new-custom-category",
|
||||
(void*)kmachine_extras::pc_sr_mode_dump_new_custom_category);
|
||||
|
||||
// setup string constants
|
||||
auto user_dir_path = file_util::get_user_config_dir();
|
||||
intern_from_c(-1, 0, "*pc-user-dir-base-path*")->value() =
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
namespace jak3 {
|
||||
namespace kmachine_extras {
|
||||
using namespace jak3;
|
||||
AutoSplitterBlock g_auto_splitter_block_jak3;
|
||||
|
||||
void update_discord_rpc(u32 discord_info) {
|
||||
if (gDiscordRpcEnabled) {
|
||||
@ -225,5 +225,737 @@ inline bool symbol_to_bool(const u32 symptr) {
|
||||
return symptr != s7.offset;
|
||||
}
|
||||
|
||||
void init_autosplit_struct() {
|
||||
g_auto_splitter_block_jak3.pointer_to_symbol =
|
||||
(u64)g_ee_main_mem + (u64)intern_from_c(-1, 0, "*autosplit-info-jak3*")->value();
|
||||
}
|
||||
|
||||
// TODO - currently using a single mutex for all background task synchronization
|
||||
std::mutex background_task_lock;
|
||||
|
||||
std::string last_rpc_error;
|
||||
|
||||
// TODO - add a TTL to this
|
||||
std::unordered_map<std::string, std::vector<std::pair<std::string, float>>>
|
||||
external_speedrun_time_cache = {};
|
||||
std::unordered_map<std::string, std::vector<std::pair<std::string, float>>>
|
||||
external_race_time_cache = {};
|
||||
std::unordered_map<std::string, std::vector<std::pair<std::string, float>>>
|
||||
external_highscores_cache = {};
|
||||
|
||||
// clang-format off
|
||||
// TODO - eventually don't depend on SRC
|
||||
const std::unordered_map<std::string, std::string> external_speedrun_lookup_urls = {
|
||||
{"any", "https://www.speedrun.com/api/v1/leaderboards/nj1nww1p/category/9d8p1qkn?embed=players&max=200"},
|
||||
{"nooob", "https://www.speedrun.com/api/v1/leaderboards/nj1nww1p/category/5dwj0n0k?embed=players&max=200"},
|
||||
{"allmissions", "https://www.speedrun.com/api/v1/leaderboards/nj1nww1p/category/xd1r98k8?embed=players&max=200"},
|
||||
{"100", "https://www.speedrun.com/api/v1/leaderboards/nj1nww1p/category/zd30nndn?embed=players&max=200"},
|
||||
{"anyorbs", "https://www.speedrun.com/api/v1/leaderboards/nj1nww1p/category/jdzw79vd?embed=players&max=200"},
|
||||
{"anyhero", "https://www.speedrun.com/api/v1/leaderboards/nj1nww1p/category/9kvp50kg?embed=players&max=200"}};
|
||||
const std::unordered_map<std::string, std::string> external_race_lookup_urls = {
|
||||
{"time-trial", "https://www.speedrun.com/api/v1/leaderboards/nj1nww1p/level/kwjvyzwg/jdr8onk6?embed=players&max=200"},
|
||||
{"rally", "https://www.speedrun.com/api/v1/leaderboards/nj1nww1p/level/owo3kyw6/jdr8onk6?embed=players&max=200"}};
|
||||
const std::unordered_map<std::string, std::string> external_highscores_lookup_urls = {
|
||||
{"was-pre-game", "https://api.jakspeedruns.workers.dev/v1/highscores/9"},
|
||||
{"air-time", "https://api.jakspeedruns.workers.dev/v1/highscores/10"},
|
||||
{"total-air-time", "https://api.jakspeedruns.workers.dev/v1/highscores/11"},
|
||||
{"jump-distance", "https://api.jakspeedruns.workers.dev/v1/highscores/12"},
|
||||
{"total-jump-distance", "https://api.jakspeedruns.workers.dev/v1/highscores/13"},
|
||||
{"roll-count", "https://api.jakspeedruns.workers.dev/v1/highscores/14"},
|
||||
{"wascity-gungame", "https://api.jakspeedruns.workers.dev/v1/highscores/15"},
|
||||
{"jetboard", "https://api.jakspeedruns.workers.dev/v1/highscores/16"},
|
||||
{"gungame-yellow-2", "https://api.jakspeedruns.workers.dev/v1/highscores/17"},
|
||||
{"gungame-red-2", "https://api.jakspeedruns.workers.dev/v1/highscores/18"},
|
||||
{"gungame-ratchet", "https://api.jakspeedruns.workers.dev/v1/highscores/19"},
|
||||
{"gungame-clank", "https://api.jakspeedruns.workers.dev/v1/highscores/20"},
|
||||
{"power-game", "https://api.jakspeedruns.workers.dev/v1/highscores/21"},
|
||||
{"destroy-interceptors", "https://api.jakspeedruns.workers.dev/v1/highscores/22"}};
|
||||
// clang-format on
|
||||
|
||||
void callback_fetch_external_speedrun_times(bool success,
|
||||
const std::string& cache_id,
|
||||
std::optional<std::string> result) {
|
||||
std::scoped_lock lock{background_task_lock};
|
||||
|
||||
if (!success) {
|
||||
intern_from_c(-1, 0, "*pc-rpc-error?*")->value() = bool_to_symbol(true);
|
||||
if (result) {
|
||||
last_rpc_error = result.value();
|
||||
} else {
|
||||
last_rpc_error = "Unexpected Error Occurred";
|
||||
}
|
||||
intern_from_c(-1, 0, "*pc-waiting-on-rpc?*")->value() = bool_to_symbol(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO - might be nice to have an error if we get an unexpected payload
|
||||
if (!result) {
|
||||
intern_from_c(-1, 0, "*pc-waiting-on-rpc?*")->value() = bool_to_symbol(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the response
|
||||
const auto data = safe_parse_json(result.value());
|
||||
if (!data || !data->contains("data") || !data->at("data").contains("players") ||
|
||||
!data->at("data").at("players").contains("data") || !data->at("data").contains("runs")) {
|
||||
intern_from_c(-1, 0, "*pc-waiting-on-rpc?*")->value() = bool_to_symbol(false);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& players = data->at("data").at("players").at("data");
|
||||
auto& runs = data->at("data").at("runs");
|
||||
std::vector<std::pair<std::string, float>> times = {};
|
||||
for (const auto& run_info : runs) {
|
||||
std::pair<std::string, float> time_info;
|
||||
if (players.size() > times.size() && players.at(times.size()).contains("names") &&
|
||||
players.at(times.size()).at("names").contains("international")) {
|
||||
time_info.first = players.at(times.size()).at("names").at("international");
|
||||
} else if (players.size() > times.size() && players.at(times.size()).contains("name")) {
|
||||
time_info.first = players.at(times.size()).at("name");
|
||||
} else {
|
||||
time_info.first = "Unknown";
|
||||
}
|
||||
if (run_info.contains("run") && run_info.at("run").contains("times") &&
|
||||
run_info.at("run").at("times").contains("primary_t")) {
|
||||
time_info.second = run_info.at("run").at("times").at("primary_t");
|
||||
times.push_back(time_info);
|
||||
}
|
||||
}
|
||||
external_speedrun_time_cache[cache_id] = times;
|
||||
intern_from_c(-1, 0, "*pc-waiting-on-rpc?*")->value() = bool_to_symbol(false);
|
||||
}
|
||||
|
||||
// TODO - duplicate code, put it in a function
|
||||
void callback_fetch_external_race_times(bool success,
|
||||
const std::string& cache_id,
|
||||
std::optional<std::string> result) {
|
||||
std::scoped_lock lock{background_task_lock};
|
||||
|
||||
if (!success) {
|
||||
intern_from_c(-1, 0, "*pc-rpc-error?*")->value() = bool_to_symbol(true);
|
||||
if (result) {
|
||||
last_rpc_error = result.value();
|
||||
} else {
|
||||
last_rpc_error = "Unexpected Error Occurred";
|
||||
}
|
||||
intern_from_c(-1, 0, "*pc-waiting-on-rpc?*")->value() = bool_to_symbol(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO - might be nice to have an error if we get an unexpected payload
|
||||
if (!result) {
|
||||
intern_from_c(-1, 0, "*pc-waiting-on-rpc?*")->value() = bool_to_symbol(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the response
|
||||
const auto data = safe_parse_json(result.value());
|
||||
if (!data || !data->contains("data") || !data->at("data").contains("players") ||
|
||||
!data->at("data").at("players").contains("data") || !data->at("data").contains("runs")) {
|
||||
intern_from_c(-1, 0, "*pc-waiting-on-rpc?*")->value() = bool_to_symbol(false);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& players = data->at("data").at("players").at("data");
|
||||
auto& runs = data->at("data").at("runs");
|
||||
std::vector<std::pair<std::string, float>> times = {};
|
||||
for (const auto& run_info : runs) {
|
||||
std::pair<std::string, float> time_info;
|
||||
if (players.size() > times.size() && players.at(times.size()).contains("names") &&
|
||||
players.at(times.size()).at("names").contains("international")) {
|
||||
time_info.first = players.at(times.size()).at("names").at("international");
|
||||
} else if (players.size() > times.size() && players.at(times.size()).contains("name")) {
|
||||
time_info.first = players.at(times.size()).at("name");
|
||||
} else {
|
||||
time_info.first = "Unknown";
|
||||
}
|
||||
if (run_info.contains("run") && run_info.at("run").contains("times") &&
|
||||
run_info.at("run").at("times").contains("primary_t")) {
|
||||
time_info.second = run_info.at("run").at("times").at("primary_t");
|
||||
times.push_back(time_info);
|
||||
}
|
||||
}
|
||||
external_race_time_cache[cache_id] = times;
|
||||
intern_from_c(-1, 0, "*pc-waiting-on-rpc?*")->value() = bool_to_symbol(false);
|
||||
}
|
||||
|
||||
// TODO - duplicate code, put it in a function
|
||||
void callback_fetch_external_highscores(bool success,
|
||||
const std::string& cache_id,
|
||||
std::optional<std::string> result) {
|
||||
std::scoped_lock lock{background_task_lock};
|
||||
|
||||
if (!success) {
|
||||
intern_from_c(-1, 0, "*pc-rpc-error?*")->value() = bool_to_symbol(true);
|
||||
if (result) {
|
||||
last_rpc_error = result.value();
|
||||
} else {
|
||||
last_rpc_error = "Unexpected Error Occurred";
|
||||
}
|
||||
intern_from_c(-1, 0, "*pc-waiting-on-rpc?*")->value() = bool_to_symbol(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO - might be nice to have an error if we get an unexpected payload
|
||||
if (!result) {
|
||||
intern_from_c(-1, 0, "*pc-waiting-on-rpc?*")->value() = bool_to_symbol(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the response
|
||||
const auto data = safe_parse_json(result.value());
|
||||
std::vector<std::pair<std::string, float>> times = {};
|
||||
for (const auto& highscore_info : data.value()) {
|
||||
if (highscore_info.contains("playerName") && highscore_info.contains("score")) {
|
||||
std::pair<std::string, float> time_info;
|
||||
time_info.first = highscore_info.at("playerName");
|
||||
time_info.second = highscore_info.at("score");
|
||||
times.push_back(time_info);
|
||||
}
|
||||
}
|
||||
external_highscores_cache[cache_id] = times;
|
||||
intern_from_c(-1, 0, "*pc-waiting-on-rpc?*")->value() = bool_to_symbol(false);
|
||||
}
|
||||
|
||||
void pc_fetch_external_speedrun_times(u32 speedrun_id_ptr) {
|
||||
std::scoped_lock lock{background_task_lock};
|
||||
auto speedrun_id = std::string(Ptr<String>(speedrun_id_ptr).c()->data());
|
||||
if (external_speedrun_lookup_urls.find(speedrun_id) == external_speedrun_lookup_urls.end()) {
|
||||
lg::error("No URL for speedrun_id: '{}'", speedrun_id);
|
||||
return;
|
||||
}
|
||||
|
||||
// First check to see if we've already retrieved this info
|
||||
if (external_speedrun_time_cache.find(speedrun_id) == external_speedrun_time_cache.end()) {
|
||||
intern_from_c(-1, 0, "*pc-waiting-on-rpc?*")->value() = bool_to_symbol(true);
|
||||
intern_from_c(-1, 0, "*pc-rpc-error?*")->value() = bool_to_symbol(false);
|
||||
// otherwise, hit the URL
|
||||
WebRequestJobPayload req;
|
||||
req.callback = callback_fetch_external_speedrun_times;
|
||||
req.url = external_speedrun_lookup_urls.at(speedrun_id);
|
||||
req.cache_id = speedrun_id;
|
||||
g_background_worker.enqueue_webrequest(req);
|
||||
}
|
||||
}
|
||||
|
||||
void pc_fetch_external_race_times(u32 race_id_ptr) {
|
||||
std::scoped_lock lock{background_task_lock};
|
||||
auto race_id = std::string(Ptr<String>(race_id_ptr).c()->data());
|
||||
if (external_race_lookup_urls.find(race_id) == external_race_lookup_urls.end()) {
|
||||
lg::error("No URL for race_id: '{}'", race_id);
|
||||
return;
|
||||
}
|
||||
|
||||
// First check to see if we've already retrieved this info
|
||||
if (external_race_time_cache.find(race_id) == external_race_time_cache.end()) {
|
||||
intern_from_c(-1, 0, "*pc-waiting-on-rpc?*")->value() = bool_to_symbol(true);
|
||||
intern_from_c(-1, 0, "*pc-rpc-error?*")->value() = bool_to_symbol(false);
|
||||
// otherwise, hit the URL
|
||||
WebRequestJobPayload req;
|
||||
req.callback = callback_fetch_external_race_times;
|
||||
req.url = external_race_lookup_urls.at(race_id);
|
||||
req.cache_id = race_id;
|
||||
g_background_worker.enqueue_webrequest(req);
|
||||
}
|
||||
}
|
||||
|
||||
void pc_fetch_external_highscores(u32 highscore_id_ptr) {
|
||||
std::scoped_lock lock{background_task_lock};
|
||||
auto highscore_id = std::string(Ptr<String>(highscore_id_ptr).c()->data());
|
||||
if (external_highscores_lookup_urls.find(highscore_id) == external_highscores_lookup_urls.end()) {
|
||||
lg::error("No URL for highscore_id: '{}'", highscore_id);
|
||||
return;
|
||||
}
|
||||
|
||||
// First check to see if we've already retrieved this info
|
||||
if (external_highscores_cache.find(highscore_id) == external_highscores_cache.end()) {
|
||||
intern_from_c(-1, 0, "*pc-waiting-on-rpc?*")->value() = bool_to_symbol(true);
|
||||
intern_from_c(-1, 0, "*pc-rpc-error?*")->value() = bool_to_symbol(false);
|
||||
// otherwise, hit the URL
|
||||
WebRequestJobPayload req;
|
||||
req.callback = callback_fetch_external_highscores;
|
||||
req.url = external_highscores_lookup_urls.at(highscore_id);
|
||||
req.cache_id = highscore_id;
|
||||
g_background_worker.enqueue_webrequest(req);
|
||||
}
|
||||
}
|
||||
|
||||
void pc_get_external_speedrun_time(u32 speedrun_id_ptr,
|
||||
s32 index,
|
||||
u32 name_dest_ptr,
|
||||
u32 time_dest_ptr) {
|
||||
std::scoped_lock lock{background_task_lock};
|
||||
auto speedrun_id = std::string(Ptr<String>(speedrun_id_ptr).c()->data());
|
||||
if (external_speedrun_time_cache.find(speedrun_id) != external_speedrun_time_cache.end()) {
|
||||
const auto& runs = external_speedrun_time_cache.at(speedrun_id);
|
||||
if (index < (int)runs.size()) {
|
||||
const auto& run_info = external_speedrun_time_cache.at(speedrun_id).at(index);
|
||||
std::string converted =
|
||||
get_font_bank(GameTextVersion::JAK3)->convert_utf8_to_game(run_info.first);
|
||||
strcpy(Ptr<String>(name_dest_ptr).c()->data(), converted.c_str());
|
||||
*(Ptr<float>(time_dest_ptr).c()) = run_info.second;
|
||||
} else {
|
||||
std::string converted = get_font_bank(GameTextVersion::JAK3)->convert_utf8_to_game("");
|
||||
strcpy(Ptr<String>(name_dest_ptr).c()->data(), converted.c_str());
|
||||
*(Ptr<float>(time_dest_ptr).c()) = -1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pc_get_external_race_time(u32 race_id_ptr, s32 index, u32 name_dest_ptr, u32 time_dest_ptr) {
|
||||
std::scoped_lock lock{background_task_lock};
|
||||
auto race_id = std::string(Ptr<String>(race_id_ptr).c()->data());
|
||||
if (external_race_time_cache.find(race_id) != external_race_time_cache.end()) {
|
||||
const auto& runs = external_race_time_cache.at(race_id);
|
||||
if (index < (int)runs.size()) {
|
||||
const auto& run_info = external_race_time_cache.at(race_id).at(index);
|
||||
std::string converted =
|
||||
get_font_bank(GameTextVersion::JAK3)->convert_utf8_to_game(run_info.first);
|
||||
strcpy(Ptr<String>(name_dest_ptr).c()->data(), converted.c_str());
|
||||
*(Ptr<float>(time_dest_ptr).c()) = run_info.second;
|
||||
} else {
|
||||
std::string converted = get_font_bank(GameTextVersion::JAK3)->convert_utf8_to_game("");
|
||||
strcpy(Ptr<String>(name_dest_ptr).c()->data(), converted.c_str());
|
||||
*(Ptr<float>(time_dest_ptr).c()) = -1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pc_get_external_highscore(u32 highscore_id_ptr,
|
||||
s32 index,
|
||||
u32 name_dest_ptr,
|
||||
u32 time_dest_ptr) {
|
||||
std::scoped_lock lock{background_task_lock};
|
||||
auto highscore_id = std::string(Ptr<String>(highscore_id_ptr).c()->data());
|
||||
if (external_highscores_cache.find(highscore_id) != external_highscores_cache.end()) {
|
||||
const auto& runs = external_highscores_cache.at(highscore_id);
|
||||
if (index < (int)runs.size()) {
|
||||
const auto& run_info = external_highscores_cache.at(highscore_id).at(index);
|
||||
std::string converted =
|
||||
get_font_bank(GameTextVersion::JAK3)->convert_utf8_to_game(run_info.first);
|
||||
strcpy(Ptr<String>(name_dest_ptr).c()->data(), converted.c_str());
|
||||
*(Ptr<float>(time_dest_ptr).c()) = run_info.second;
|
||||
} else {
|
||||
std::string converted = get_font_bank(GameTextVersion::JAK3)->convert_utf8_to_game("");
|
||||
strcpy(Ptr<String>(name_dest_ptr).c()->data(), converted.c_str());
|
||||
*(Ptr<float>(time_dest_ptr).c()) = -1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s32 pc_get_num_external_speedrun_times(u32 speedrun_id_ptr) {
|
||||
std::scoped_lock lock{background_task_lock};
|
||||
auto speedrun_id = std::string(Ptr<String>(speedrun_id_ptr).c()->data());
|
||||
if (external_speedrun_time_cache.find(speedrun_id) != external_speedrun_time_cache.end()) {
|
||||
return external_speedrun_time_cache.at(speedrun_id).size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 pc_get_num_external_race_times(u32 race_id_ptr) {
|
||||
std::scoped_lock lock{background_task_lock};
|
||||
auto race_id = std::string(Ptr<String>(race_id_ptr).c()->data());
|
||||
if (external_race_time_cache.find(race_id) != external_race_time_cache.end()) {
|
||||
return external_race_time_cache.at(race_id).size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 pc_get_num_external_highscores(u32 highscore_id_ptr) {
|
||||
std::scoped_lock lock{background_task_lock};
|
||||
auto highscore_id = std::string(Ptr<String>(highscore_id_ptr).c()->data());
|
||||
if (external_highscores_cache.find(highscore_id) != external_highscores_cache.end()) {
|
||||
return external_highscores_cache.at(highscore_id).size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void to_json(json& j, const SpeedrunPracticeEntryHistoryAttempt& obj) {
|
||||
if (obj.time) {
|
||||
j["time"] = obj.time.value();
|
||||
} else {
|
||||
j["time"] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void from_json(const json& j, SpeedrunPracticeEntryHistoryAttempt& obj) {
|
||||
if (j["time"].is_null()) {
|
||||
obj.time = {};
|
||||
} else {
|
||||
obj.time = j["time"];
|
||||
}
|
||||
}
|
||||
|
||||
void to_json(json& j, const SpeedrunPracticeEntry& obj) {
|
||||
json_serialize(name);
|
||||
json_serialize(continue_point_name);
|
||||
json_serialize(flags);
|
||||
json_serialize(completed_task);
|
||||
json_serialize(features);
|
||||
json_serialize(secrets);
|
||||
json_serialize(vehicles);
|
||||
json_serialize(starting_position);
|
||||
json_serialize(starting_rotation);
|
||||
json_serialize(starting_camera_position);
|
||||
json_serialize(starting_camera_rotation);
|
||||
json_serialize(start_zone_v1);
|
||||
json_serialize(start_zone_v2);
|
||||
json_serialize_optional(end_zone_v1);
|
||||
json_serialize_optional(end_zone_v2);
|
||||
json_serialize_optional(end_task);
|
||||
json_serialize(history);
|
||||
}
|
||||
|
||||
void from_json(const json& j, SpeedrunPracticeEntry& obj) {
|
||||
json_deserialize_if_exists(name);
|
||||
json_deserialize_if_exists(continue_point_name);
|
||||
json_deserialize_if_exists(flags);
|
||||
json_deserialize_if_exists(completed_task);
|
||||
json_deserialize_if_exists(features);
|
||||
json_deserialize_if_exists(secrets);
|
||||
json_deserialize_if_exists(vehicles);
|
||||
json_deserialize_if_exists(starting_position);
|
||||
json_deserialize_if_exists(starting_rotation);
|
||||
json_deserialize_if_exists(starting_camera_position);
|
||||
json_deserialize_if_exists(starting_camera_rotation);
|
||||
json_deserialize_if_exists(start_zone_v1);
|
||||
json_deserialize_if_exists(start_zone_v2);
|
||||
json_deserialize_optional_if_exists(end_zone_v1);
|
||||
json_deserialize_optional_if_exists(end_zone_v2);
|
||||
json_deserialize_optional_if_exists(end_task);
|
||||
json_deserialize_if_exists(history);
|
||||
}
|
||||
|
||||
void to_json(json& j, const SpeedrunCustomCategoryEntry& obj) {
|
||||
json_serialize(name);
|
||||
json_serialize(secrets);
|
||||
json_serialize(features);
|
||||
json_serialize(vehicles);
|
||||
json_serialize(forbidden_features);
|
||||
json_serialize(cheats);
|
||||
json_serialize(continue_point_name);
|
||||
json_serialize(completed_task);
|
||||
}
|
||||
|
||||
void from_json(const json& j, SpeedrunCustomCategoryEntry& obj) {
|
||||
json_deserialize_if_exists(name);
|
||||
json_deserialize_if_exists(secrets);
|
||||
json_deserialize_if_exists(features);
|
||||
json_deserialize_if_exists(vehicles);
|
||||
json_deserialize_if_exists(forbidden_features);
|
||||
json_deserialize_if_exists(cheats);
|
||||
json_deserialize_if_exists(continue_point_name);
|
||||
json_deserialize_if_exists(completed_task);
|
||||
}
|
||||
|
||||
std::vector<SpeedrunPracticeEntry> g_speedrun_practice_entries;
|
||||
std::unordered_map<int, SpeedrunPracticeState> g_speedrun_practice_state;
|
||||
|
||||
s32 pc_sr_mode_get_practice_entries_amount() {
|
||||
// load practice entries from the file
|
||||
const auto file_path =
|
||||
file_util::get_user_features_dir(g_game_version) / "speedrun-practice.json";
|
||||
if (!file_util::file_exists(file_path.string())) {
|
||||
lg::info("speedrun-practice.json not found, no entries to return!");
|
||||
return 0;
|
||||
}
|
||||
const auto file_contents = safe_parse_json(file_util::read_text_file(file_path));
|
||||
if (!file_contents) {
|
||||
lg::error("speedrun-practice.json could not be parsed!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_speedrun_practice_entries = *file_contents;
|
||||
|
||||
for (size_t i = 0; i < g_speedrun_practice_entries.size(); i++) {
|
||||
const auto& entry = g_speedrun_practice_entries.at(i);
|
||||
s32 last_session_id = -1;
|
||||
s32 total_attempts = 0;
|
||||
s32 total_successes = 0;
|
||||
s32 session_attempts = 0;
|
||||
s32 session_successes = 0;
|
||||
double total_time = 0;
|
||||
float average_time = 0;
|
||||
float fastest_time = 0;
|
||||
for (const auto& [history_session, times] : entry.history) {
|
||||
s32 session_id = stoi(history_session);
|
||||
if (session_id > last_session_id) {
|
||||
last_session_id = session_id;
|
||||
}
|
||||
for (const auto& time : times) {
|
||||
total_attempts++;
|
||||
if (time.time) {
|
||||
total_successes++;
|
||||
total_time += *time.time;
|
||||
if (fastest_time == 0 || *time.time < fastest_time) {
|
||||
fastest_time = *time.time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (total_successes != 0) {
|
||||
average_time = total_time / total_successes;
|
||||
}
|
||||
g_speedrun_practice_state[i] = {last_session_id + 1, total_attempts, total_successes,
|
||||
session_attempts, session_successes, total_time,
|
||||
average_time, fastest_time};
|
||||
}
|
||||
|
||||
return g_speedrun_practice_entries.size();
|
||||
}
|
||||
|
||||
void pc_sr_mode_get_practice_entry_name(s32 entry_index, u32 name_str_ptr) {
|
||||
std::string name;
|
||||
if (entry_index < (int)g_speedrun_practice_entries.size()) {
|
||||
name = g_speedrun_practice_entries.at(entry_index).name;
|
||||
}
|
||||
strcpy(Ptr<String>(name_str_ptr).c()->data(), name.c_str());
|
||||
}
|
||||
|
||||
void pc_sr_mode_get_practice_entry_continue_point(s32 entry_index, u32 name_str_ptr) {
|
||||
std::string name;
|
||||
if (entry_index < (int)g_speedrun_practice_entries.size()) {
|
||||
name = g_speedrun_practice_entries.at(entry_index).continue_point_name;
|
||||
}
|
||||
strcpy(Ptr<String>(name_str_ptr).c()->data(), name.c_str());
|
||||
}
|
||||
|
||||
s32 pc_sr_mode_get_practice_entry_history_success(s32 entry_index) {
|
||||
return g_speedrun_practice_state.at(entry_index).total_successes;
|
||||
}
|
||||
|
||||
s32 pc_sr_mode_get_practice_entry_history_attempts(s32 entry_index) {
|
||||
return g_speedrun_practice_state.at(entry_index).total_attempts;
|
||||
}
|
||||
|
||||
s32 pc_sr_mode_get_practice_entry_session_success(s32 entry_index) {
|
||||
return g_speedrun_practice_state.at(entry_index).session_successes;
|
||||
}
|
||||
|
||||
s32 pc_sr_mode_get_practice_entry_session_attempts(s32 entry_index) {
|
||||
return g_speedrun_practice_state.at(entry_index).session_attempts;
|
||||
}
|
||||
|
||||
void pc_sr_mode_get_practice_entry_avg_time(s32 entry_index, u32 time_str_ptr) {
|
||||
const auto time = fmt::format("{:.2f}", g_speedrun_practice_state.at(entry_index).average_time);
|
||||
strcpy(Ptr<String>(time_str_ptr).c()->data(), time.c_str());
|
||||
}
|
||||
|
||||
void pc_sr_mode_get_practice_entry_fastest_time(s32 entry_index, u32 time_str_ptr) {
|
||||
const auto time = fmt::format("{:.2f}", g_speedrun_practice_state.at(entry_index).fastest_time);
|
||||
strcpy(Ptr<String>(time_str_ptr).c()->data(), time.c_str());
|
||||
}
|
||||
|
||||
u64 pc_sr_mode_record_practice_entry_attempt(s32 entry_index, u32 success_bool, u32 time_ptr) {
|
||||
auto& state = g_speedrun_practice_state.at(entry_index);
|
||||
const auto was_successful = symbol_to_bool(success_bool);
|
||||
state.total_attempts++;
|
||||
state.session_attempts++;
|
||||
bool ret = false;
|
||||
SpeedrunPracticeEntryHistoryAttempt new_history_entry;
|
||||
if (was_successful) {
|
||||
auto time = Ptr<float>(time_ptr).c();
|
||||
new_history_entry.time = *time;
|
||||
state.total_successes++;
|
||||
state.session_successes++;
|
||||
state.total_time += *time;
|
||||
state.average_time = state.total_time / state.total_successes;
|
||||
if (*time < state.fastest_time) {
|
||||
state.fastest_time = *time;
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
// persist to file
|
||||
const auto file_path =
|
||||
file_util::get_user_features_dir(g_game_version) / "speedrun-practice.json";
|
||||
if (!file_util::file_exists(file_path.string())) {
|
||||
lg::info("speedrun-practice.json not found, not persisting!");
|
||||
} else {
|
||||
auto& history = g_speedrun_practice_entries.at(entry_index).history;
|
||||
if (history.find(fmt::format("{}", state.current_session_id)) == history.end()) {
|
||||
history[fmt::format("{}", state.current_session_id)] = {};
|
||||
}
|
||||
history[fmt::format("{}", state.current_session_id)].push_back(new_history_entry);
|
||||
json data = g_speedrun_practice_entries;
|
||||
file_util::write_text_file(file_path, data.dump(2));
|
||||
}
|
||||
// return
|
||||
return bool_to_symbol(ret);
|
||||
}
|
||||
|
||||
void pc_sr_mode_init_practice_info(s32 entry_index, u32 speedrun_practice_obj_ptr) {
|
||||
if (entry_index >= (int)g_speedrun_practice_entries.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto objective = speedrun_practice_obj_ptr
|
||||
? Ptr<SpeedrunPracticeObjective>(speedrun_practice_obj_ptr).c()
|
||||
: NULL;
|
||||
if (objective) {
|
||||
const auto& json_info = g_speedrun_practice_entries.at(entry_index);
|
||||
|
||||
objective->index = entry_index;
|
||||
objective->flags = json_info.flags;
|
||||
objective->completed_task = json_info.completed_task;
|
||||
objective->features = json_info.features;
|
||||
objective->vehicles = json_info.vehicles;
|
||||
objective->secrets = json_info.secrets;
|
||||
auto starting_position =
|
||||
objective->starting_position ? Ptr<Vector>(objective->starting_position).c() : NULL;
|
||||
if (starting_position) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
starting_position->data[i] = json_info.starting_position.at(i) * METER_LENGTH;
|
||||
}
|
||||
}
|
||||
auto starting_rotation =
|
||||
objective->starting_rotation ? Ptr<Vector>(objective->starting_rotation).c() : NULL;
|
||||
if (starting_rotation) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
starting_rotation->data[i] = json_info.starting_rotation.at(i);
|
||||
}
|
||||
}
|
||||
auto starting_camera_position = objective->starting_camera_position
|
||||
? Ptr<Vector>(objective->starting_camera_position).c()
|
||||
: NULL;
|
||||
if (starting_camera_position) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
starting_camera_position->data[i] = json_info.starting_camera_position.at(i) * 4096.0;
|
||||
}
|
||||
}
|
||||
auto starting_camera_rotation = objective->starting_camera_rotation
|
||||
? Ptr<Vector>(objective->starting_camera_rotation).c()
|
||||
: NULL;
|
||||
if (starting_camera_rotation) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
starting_camera_rotation->data[i] = json_info.starting_camera_rotation.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (json_info.end_task) {
|
||||
objective->end_task = *json_info.end_task;
|
||||
} else {
|
||||
objective->end_task = 0;
|
||||
}
|
||||
|
||||
auto starting_zone = objective->start_zone_init_params
|
||||
? Ptr<ObjectiveZoneInitParams>(objective->start_zone_init_params).c()
|
||||
: NULL;
|
||||
if (starting_zone) {
|
||||
starting_zone->v1[0] = json_info.start_zone_v1.at(0) * METER_LENGTH;
|
||||
starting_zone->v1[1] = json_info.start_zone_v1.at(1) * METER_LENGTH;
|
||||
starting_zone->v1[2] = json_info.start_zone_v1.at(2) * METER_LENGTH;
|
||||
starting_zone->v1[3] = json_info.start_zone_v1.at(3) * METER_LENGTH;
|
||||
starting_zone->v2[0] = json_info.start_zone_v2.at(0) * METER_LENGTH;
|
||||
starting_zone->v2[1] = json_info.start_zone_v2.at(1) * METER_LENGTH;
|
||||
starting_zone->v2[2] = json_info.start_zone_v2.at(2) * METER_LENGTH;
|
||||
starting_zone->v2[3] = json_info.start_zone_v2.at(3) * METER_LENGTH;
|
||||
}
|
||||
|
||||
if (json_info.end_zone_v1 && json_info.end_zone_v2) {
|
||||
auto ending_zone = objective->end_zone_init_params
|
||||
? Ptr<ObjectiveZoneInitParams>(objective->end_zone_init_params).c()
|
||||
: NULL;
|
||||
if (ending_zone) {
|
||||
ending_zone->v1[0] = json_info.end_zone_v1->at(0) * METER_LENGTH;
|
||||
ending_zone->v1[1] = json_info.end_zone_v1->at(1) * METER_LENGTH;
|
||||
ending_zone->v1[2] = json_info.end_zone_v1->at(2) * METER_LENGTH;
|
||||
ending_zone->v1[3] = json_info.end_zone_v1->at(3) * METER_LENGTH;
|
||||
ending_zone->v2[0] = json_info.end_zone_v2->at(0) * METER_LENGTH;
|
||||
ending_zone->v2[1] = json_info.end_zone_v2->at(1) * METER_LENGTH;
|
||||
ending_zone->v2[2] = json_info.end_zone_v2->at(2) * METER_LENGTH;
|
||||
ending_zone->v2[3] = json_info.end_zone_v2->at(3) * METER_LENGTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<SpeedrunCustomCategoryEntry> g_speedrun_custom_categories;
|
||||
|
||||
s32 pc_sr_mode_get_custom_category_amount() {
|
||||
// load practice entries from the file
|
||||
const auto file_path =
|
||||
file_util::get_user_features_dir(g_game_version) / "speedrun-categories.json";
|
||||
if (!file_util::file_exists(file_path.string())) {
|
||||
lg::info("speedrun-categories.json not found, no entries to return!");
|
||||
return 0;
|
||||
}
|
||||
const auto file_contents = safe_parse_json(file_util::read_text_file(file_path));
|
||||
if (!file_contents) {
|
||||
lg::error("speedrun-categories.json could not be parsed!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_speedrun_custom_categories = *file_contents;
|
||||
|
||||
return g_speedrun_custom_categories.size();
|
||||
}
|
||||
|
||||
void pc_sr_mode_get_custom_category_name(s32 entry_index, u32 name_str_ptr) {
|
||||
std::string name;
|
||||
if (entry_index < (int)g_speedrun_custom_categories.size()) {
|
||||
name = g_speedrun_custom_categories.at(entry_index).name;
|
||||
}
|
||||
strcpy(Ptr<String>(name_str_ptr).c()->data(), name.c_str());
|
||||
}
|
||||
|
||||
void pc_sr_mode_get_custom_category_continue_point(s32 entry_index, u32 name_str_ptr) {
|
||||
std::string name;
|
||||
if (entry_index < (int)g_speedrun_custom_categories.size()) {
|
||||
name = g_speedrun_custom_categories.at(entry_index).continue_point_name;
|
||||
}
|
||||
strcpy(Ptr<String>(name_str_ptr).c()->data(), name.c_str());
|
||||
}
|
||||
|
||||
void pc_sr_mode_init_custom_category_info(s32 entry_index, u32 speedrun_custom_category_ptr) {
|
||||
if (entry_index >= (int)g_speedrun_custom_categories.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto category = speedrun_custom_category_ptr
|
||||
? Ptr<SpeedrunCustomCategory>(speedrun_custom_category_ptr).c()
|
||||
: NULL;
|
||||
if (category) {
|
||||
const auto& json_info = g_speedrun_custom_categories.at(entry_index);
|
||||
category->index = entry_index;
|
||||
category->secrets = json_info.secrets;
|
||||
category->features = json_info.features;
|
||||
category->vehicles = json_info.vehicles;
|
||||
category->forbidden_features = json_info.forbidden_features;
|
||||
category->cheats = json_info.cheats;
|
||||
category->completed_task = json_info.completed_task;
|
||||
}
|
||||
}
|
||||
|
||||
void pc_sr_mode_dump_new_custom_category(u32 speedrun_custom_category_ptr) {
|
||||
const auto file_path =
|
||||
file_util::get_user_features_dir(g_game_version) / "speedrun-categories.json";
|
||||
if (file_util::file_exists(file_path.string())) {
|
||||
// read current categories from file
|
||||
const auto file_contents = safe_parse_json(file_util::read_text_file(file_path));
|
||||
if (file_contents) {
|
||||
g_speedrun_custom_categories = *file_contents;
|
||||
}
|
||||
}
|
||||
|
||||
auto category = speedrun_custom_category_ptr
|
||||
? Ptr<SpeedrunCustomCategory>(speedrun_custom_category_ptr).c()
|
||||
: NULL;
|
||||
if (category) {
|
||||
SpeedrunCustomCategoryEntry new_category;
|
||||
new_category.name = fmt::format("custom-category-{}", g_speedrun_custom_categories.size());
|
||||
new_category.secrets = category->secrets;
|
||||
new_category.features = category->features;
|
||||
new_category.vehicles = category->vehicles;
|
||||
new_category.forbidden_features = category->forbidden_features;
|
||||
new_category.cheats = category->cheats;
|
||||
new_category.completed_task = category->completed_task;
|
||||
new_category.continue_point_name = "";
|
||||
g_speedrun_custom_categories.push_back(new_category);
|
||||
// convert to json and write file
|
||||
json data = g_speedrun_custom_categories;
|
||||
file_util::write_text_file(file_path, data.dump(2));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace kmachine_extras
|
||||
} // namespace jak3
|
||||
|
@ -12,8 +12,47 @@ void pc_set_levels(u32 lev_list);
|
||||
void pc_set_active_levels(u32 lev_list);
|
||||
u32 alloc_vagdir_names(u32 heap_sym);
|
||||
inline u64 bool_to_symbol(const bool val);
|
||||
// TODO - move to common
|
||||
void encode_utf8_string(u32 src_str_ptr, u32 str_dest_ptr);
|
||||
void init_autosplit_struct();
|
||||
void callback_fetch_external_speedrun_times(bool success,
|
||||
const std::string& cache_id,
|
||||
std::optional<std::string> result);
|
||||
void callback_fetch_external_race_times(bool success,
|
||||
const std::string& cache_id,
|
||||
std::optional<std::string> result);
|
||||
void callback_fetch_external_highscores(bool success,
|
||||
const std::string& cache_id,
|
||||
std::optional<std::string> result);
|
||||
void pc_fetch_external_speedrun_times(u32 speedrun_id_ptr);
|
||||
void pc_fetch_external_race_times(u32 race_id_ptr);
|
||||
void pc_fetch_external_highscores(u32 highscore_id_ptr);
|
||||
void pc_get_external_speedrun_time(u32 speedrun_id_ptr,
|
||||
s32 index,
|
||||
u32 name_dest_ptr,
|
||||
u32 time_dest_ptr);
|
||||
void pc_get_external_race_time(u32 race_id_ptr, s32 index, u32 name_dest_ptr, u32 time_dest_ptr);
|
||||
void pc_get_external_highscore(u32 highscore_id_ptr,
|
||||
s32 index,
|
||||
u32 name_dest_ptr,
|
||||
u32 time_dest_ptr);
|
||||
s32 pc_get_num_external_speedrun_times(u32 speedrun_id_ptr);
|
||||
s32 pc_get_num_external_race_times(u32 race_id_ptr);
|
||||
s32 pc_get_num_external_highscores(u32 highscore_id_ptr);
|
||||
s32 pc_sr_mode_get_practice_entries_amount();
|
||||
void pc_sr_mode_get_practice_entry_name(s32 entry_index, u32 name_str_ptr);
|
||||
void pc_sr_mode_get_practice_entry_continue_point(s32 entry_index, u32 name_str_ptr);
|
||||
s32 pc_sr_mode_get_practice_entry_history_success(s32 entry_index);
|
||||
s32 pc_sr_mode_get_practice_entry_history_attempts(s32 entry_index);
|
||||
s32 pc_sr_mode_get_practice_entry_session_success(s32 entry_index);
|
||||
s32 pc_sr_mode_get_practice_entry_session_attempts(s32 entry_index);
|
||||
void pc_sr_mode_get_practice_entry_avg_time(s32 entry_index, u32 time_str_ptr);
|
||||
void pc_sr_mode_get_practice_entry_fastest_time(s32 entry_index, u32 time_str_ptr);
|
||||
u64 pc_sr_mode_record_practice_entry_attempt(s32 entry_index, u32 success_bool, u32 time);
|
||||
void pc_sr_mode_init_practice_info(s32 entry_index, u32 speedrun_practice_obj_ptr);
|
||||
s32 pc_sr_mode_get_custom_category_amount();
|
||||
void pc_sr_mode_get_custom_category_name(s32 entry_index, u32 name_str_ptr);
|
||||
void pc_sr_mode_get_custom_category_continue_point(s32 entry_index, u32 name_str_ptr);
|
||||
void pc_sr_mode_init_custom_category_info(s32 entry_index, u32 speedrun_custom_category_ptr);
|
||||
void pc_sr_mode_dump_new_custom_category(u32 speedrun_custom_category_ptr);
|
||||
|
||||
struct DiscordInfo {
|
||||
float orb_count; // float
|
||||
@ -113,5 +152,110 @@ enum class FocusStatus : u64 {
|
||||
|
||||
#define FOCUS_TEST(status, foc) (status.test(static_cast<size_t>(foc)))
|
||||
|
||||
// To speed up finding the auto-splitter block in GOAL memory
|
||||
// all this has is a marker for LiveSplit to find, and then the pointer
|
||||
// to the symbol
|
||||
struct AutoSplitterBlock {
|
||||
const char marker[20] = "UnLiStEdStRaTs_JaK3";
|
||||
u64 pointer_to_symbol = 0;
|
||||
};
|
||||
|
||||
extern AutoSplitterBlock g_auto_splitter_block_jak3;
|
||||
|
||||
struct SpeedrunPracticeEntryHistoryAttempt {
|
||||
std::optional<float> time;
|
||||
};
|
||||
void to_json(json& j, const SpeedrunPracticeEntryHistoryAttempt& obj);
|
||||
void from_json(const json& j, SpeedrunPracticeEntryHistoryAttempt& obj);
|
||||
|
||||
struct SpeedrunPracticeEntry {
|
||||
std::string name;
|
||||
std::string continue_point_name;
|
||||
u64 flags;
|
||||
u64 completed_task;
|
||||
u64 features;
|
||||
u64 secrets;
|
||||
u64 vehicles;
|
||||
std::vector<float> starting_position;
|
||||
std::vector<float> starting_rotation;
|
||||
std::vector<float> starting_camera_position;
|
||||
std::vector<float> starting_camera_rotation;
|
||||
std::vector<float> start_zone_v1;
|
||||
std::vector<float> start_zone_v2;
|
||||
std::optional<std::vector<float>> end_zone_v1;
|
||||
std::optional<std::vector<float>> end_zone_v2;
|
||||
std::optional<u64> end_task;
|
||||
std::map<std::string, std::vector<SpeedrunPracticeEntryHistoryAttempt>> history;
|
||||
};
|
||||
void to_json(json& j, const SpeedrunPracticeEntry& obj);
|
||||
void from_json(const json& j, SpeedrunPracticeEntry& obj);
|
||||
|
||||
struct SpeedrunPracticeState {
|
||||
s32 current_session_id;
|
||||
s32 total_attempts;
|
||||
s32 total_successes;
|
||||
s32 session_attempts;
|
||||
s32 session_successes;
|
||||
double total_time;
|
||||
float average_time;
|
||||
float fastest_time;
|
||||
};
|
||||
|
||||
struct ObjectiveZoneInitParams {
|
||||
float v1[4];
|
||||
float v2[4];
|
||||
};
|
||||
|
||||
struct Vector {
|
||||
float data[4];
|
||||
};
|
||||
|
||||
struct Matrix {
|
||||
float data[16];
|
||||
};
|
||||
|
||||
struct SpeedrunPracticeObjective {
|
||||
s32 index;
|
||||
u8 pad1[4];
|
||||
u64 flags;
|
||||
u8 completed_task;
|
||||
u8 pad2[7];
|
||||
u64 features;
|
||||
u64 secrets;
|
||||
u64 vehicles;
|
||||
u32 starting_position; // Vector
|
||||
u32 starting_rotation; // Vector
|
||||
u32 starting_camera_position; // Vector
|
||||
u32 starting_camera_rotation; // Matrix
|
||||
u8 end_task;
|
||||
u32 start_zone_init_params; // ObjectiveZoneInitParams
|
||||
u32 start_zone; // irrelevant for cpp
|
||||
u32 end_zone_init_params; // ObjectiveZoneInitParams
|
||||
u32 end_zone; // irrelevant for cpp
|
||||
};
|
||||
|
||||
struct SpeedrunCustomCategoryEntry {
|
||||
std::string name;
|
||||
u64 secrets;
|
||||
u64 features;
|
||||
u64 vehicles;
|
||||
u64 forbidden_features;
|
||||
u64 cheats;
|
||||
std::string continue_point_name;
|
||||
u64 completed_task;
|
||||
};
|
||||
void to_json(json& j, const SpeedrunCustomCategoryEntry& obj);
|
||||
void from_json(const json& j, SpeedrunCustomCategoryEntry& obj);
|
||||
|
||||
struct SpeedrunCustomCategory {
|
||||
s32 index;
|
||||
u64 secrets;
|
||||
u64 features;
|
||||
u64 vehicles;
|
||||
u64 forbidden_features;
|
||||
u64 cheats;
|
||||
u8 completed_task;
|
||||
};
|
||||
|
||||
} // namespace kmachine_extras
|
||||
} // namespace jak3
|
||||
|
@ -414,11 +414,11 @@ void SubtitleEditor::draw_subtitle_options(GameSubtitleSceneInfo& scene, bool cu
|
||||
play = true;
|
||||
save_and_reload_text = true;
|
||||
}
|
||||
if (save_and_reload_text) {
|
||||
m_subtitle_db.write_subtitle_db_to_files(g_game_version);
|
||||
m_repl.rebuild_text();
|
||||
}
|
||||
if (play) {
|
||||
if (save_and_reload_text) {
|
||||
m_subtitle_db.write_subtitle_db_to_files(g_game_version);
|
||||
m_repl.rebuild_text();
|
||||
}
|
||||
if (g_game_version == GameVersion::Jak1) {
|
||||
m_jak1_editor_db.update();
|
||||
if (scene.is_cutscene) {
|
||||
|
@ -240,6 +240,10 @@
|
||||
"game-task.o"
|
||||
"game-save.o"
|
||||
"settings.o"
|
||||
"autosplit-h.o" ;; added
|
||||
"autosplit.o" ;; added
|
||||
"popup-menu-h.o" ;; added
|
||||
"speedruns-h.o" ;; added
|
||||
"mood-tables.o"
|
||||
"mood-tables2.o"
|
||||
"mood.o"
|
||||
@ -342,6 +346,8 @@
|
||||
"board-states.o"
|
||||
"mech-h.o"
|
||||
"menu.o"
|
||||
"popup-menu.o" ;; added
|
||||
"speedruns.o" ;; added
|
||||
"drawable.o"
|
||||
"drawable-group.o"
|
||||
"drawable-inline-array.o"
|
||||
|
@ -260,7 +260,9 @@
|
||||
)
|
||||
)
|
||||
(('menu)
|
||||
(set-master-mode (cond
|
||||
;; og:preserve-this Let the popup menu code handle inputs instead of the code written for the original debug menu
|
||||
(when (not *popup-menu-open*)
|
||||
(set-master-mode (cond
|
||||
((and *debug-segment* (cpad-hold? 0 l3) (cpad-pressed? 0 select start))
|
||||
'menu
|
||||
)
|
||||
@ -280,7 +282,7 @@
|
||||
*master-mode*
|
||||
)
|
||||
)
|
||||
)
|
||||
))
|
||||
(set! *pause-lock* #f)
|
||||
)
|
||||
(('pause)
|
||||
@ -1508,10 +1510,12 @@
|
||||
; (draw-color-bars *blit-displays-work*)
|
||||
; )
|
||||
|
||||
;; run debug menu
|
||||
(*menu-hook*)
|
||||
;; draw and update menus
|
||||
;; og:preserve-this Let the popup menu code handle inputs instead of the code written for the original debug menu
|
||||
(when (not *popup-menu-open*)
|
||||
(*menu-hook*))
|
||||
|
||||
; load the right language file.
|
||||
;; disabled for now: seems to load 255COMMON.TXT.
|
||||
(load-level-text-files -1)
|
||||
|
||||
;; draw screen filter
|
||||
|
@ -549,7 +549,9 @@
|
||||
)
|
||||
)
|
||||
(if (-> arg0 sky)
|
||||
(set! (-> (&-> *level* level-default texture-anim-array 9) 0) *sky-texture-anim-array*)
|
||||
;; og:preserve-this
|
||||
(set! (-> (&-> *level* level-default texture-anim-array 9) 0) (#if PC_PORT (if *hires-sky* *sky-hires-texture-anim-array* *sky-texture-anim-array*)
|
||||
*sky-texture-anim-array*))
|
||||
(set! (-> (&-> *level* level-default texture-anim-array 9) 0) #f)
|
||||
)
|
||||
(let ((s5-2 (level-get-target-inside *level*)))
|
||||
|
@ -419,9 +419,614 @@
|
||||
)
|
||||
)
|
||||
|
||||
;; og:preserve-this
|
||||
(#when PC_PORT
|
||||
(define *sky-hires-texture-anim-array*
|
||||
(the (texture-anim-array texture-anim)
|
||||
(new 'static 'texture-anim-array :type texture-anim
|
||||
(new 'static 'texture-anim
|
||||
:func-id 'texture-anim-alpha-ramp-clut-upload
|
||||
:init-func-id 'texture-anim-alpha-ramp-clut-init
|
||||
:tex #f
|
||||
:tex-name #f
|
||||
:extra (new 'static 'vector :x 24.0)
|
||||
:color (new 'static 'rgba :a #x80)
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x1 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x1 :d #x1)
|
||||
:data (new 'static 'array texture-anim-layer 0)
|
||||
)
|
||||
(new 'static 'texture-anim
|
||||
:num-layers #x2
|
||||
:func-id 'cloud-texture-anim-func
|
||||
:init-func-id 'dest-texture-init
|
||||
:tex #f
|
||||
:tex-name #f
|
||||
:extra (new 'static 'vector :x 16.0 :y 4.0)
|
||||
:color (new 'static 'rgba :a #x80)
|
||||
:frame-delta 300.0
|
||||
:frame-mod 9600.0
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x1 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x1 :d #x1)
|
||||
:data (new 'static 'array texture-anim-layer 2
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 16.0 :y 16.0 :z 24.0)
|
||||
:func-id 'cloud-texture-anim-layer-func
|
||||
:init-func-id 'noise-texture-init
|
||||
:tex #f
|
||||
:end-time 9600.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 16.0 :y 16.0 :z 24.0)
|
||||
:func-id 'cloud-texture-anim-layer-func
|
||||
:init-func-id 'noise-texture-init
|
||||
:tex #f
|
||||
:end-time 9600.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
)
|
||||
)
|
||||
(new 'static 'texture-anim
|
||||
:num-layers #x2
|
||||
:func-id 'cloud-texture-anim-func
|
||||
:init-func-id 'dest-texture-init
|
||||
:tex #f
|
||||
:tex-name #f
|
||||
:extra (new 'static 'vector :x 32.0 :y 5.0)
|
||||
:color (new 'static 'rgba :a #x80)
|
||||
:frame-delta 300.0
|
||||
:frame-mod 4800.0
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x1 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x1 :d #x1)
|
||||
:data (new 'static 'array texture-anim-layer 2
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 32.0 :y 16.0 :z 24.0)
|
||||
:func-id 'cloud-texture-anim-layer-func
|
||||
:init-func-id 'noise-texture-init
|
||||
:tex #f
|
||||
:end-time 4800.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 32.0 :y 16.0 :z 24.0)
|
||||
:func-id 'cloud-texture-anim-layer-func
|
||||
:init-func-id 'noise-texture-init
|
||||
:tex #f
|
||||
:end-time 4800.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
)
|
||||
)
|
||||
(new 'static 'texture-anim
|
||||
:num-layers #x2
|
||||
:func-id 'cloud-texture-anim-func
|
||||
:init-func-id 'dest-texture-init
|
||||
:tex #f
|
||||
:tex-name #f
|
||||
:extra (new 'static 'vector :x 64.0 :y 6.0)
|
||||
:color (new 'static 'rgba :a #x80)
|
||||
:frame-delta 300.0
|
||||
:frame-mod 2400.0
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x1 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x1 :d #x1)
|
||||
:data (new 'static 'array texture-anim-layer 2
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 64.0 :y 16.0 :z 24.0)
|
||||
:func-id 'cloud-texture-anim-layer-func
|
||||
:init-func-id 'noise-texture-init
|
||||
:tex #f
|
||||
:end-time 2400.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 64.0 :y 16.0 :z 24.0)
|
||||
:func-id 'cloud-texture-anim-layer-func
|
||||
:init-func-id 'noise-texture-init
|
||||
:tex #f
|
||||
:end-time 2400.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
)
|
||||
)
|
||||
(new 'static 'texture-anim
|
||||
:num-layers #x2
|
||||
:func-id 'cloud-texture-anim-func
|
||||
:init-func-id 'dest-texture-init
|
||||
:tex #f
|
||||
:tex-name #f
|
||||
:extra (new 'static 'vector :x 128.0 :y 8.0)
|
||||
:color (new 'static 'rgba :a #x80)
|
||||
:frame-delta 300.0
|
||||
:frame-mod 1200.0
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x1 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x1 :d #x1)
|
||||
:data (new 'static 'array texture-anim-layer 2
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 128.0 :y 16.0 :z 24.0)
|
||||
:func-id 'cloud-texture-anim-layer-func
|
||||
:init-func-id 'noise-texture-init
|
||||
:tex #f
|
||||
:end-time 1200.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 128.0 :y 16.0 :z 24.0)
|
||||
:func-id 'cloud-texture-anim-layer-func
|
||||
:init-func-id 'noise-texture-init
|
||||
:tex #f
|
||||
:end-time 1200.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
)
|
||||
)
|
||||
(new 'static 'texture-anim
|
||||
:num-layers #x2
|
||||
:func-id 'cloud-texture-anim-func
|
||||
:init-func-id 'dest-texture-init
|
||||
:tex #f
|
||||
:tex-name #f
|
||||
:extra (new 'static 'vector :x 256.0 :y 8.0)
|
||||
:color (new 'static 'rgba :a #x80)
|
||||
:frame-delta 300.0
|
||||
:frame-mod 600.0
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x1 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x1 :d #x1)
|
||||
:data (new 'static 'array texture-anim-layer 2
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 256.0 :y 16.0 :z 24.0)
|
||||
:func-id 'cloud-texture-anim-layer-func
|
||||
:init-func-id 'noise-texture-init
|
||||
:tex #f
|
||||
:end-time 600.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 256.0 :y 16.0 :z 24.0)
|
||||
:func-id 'cloud-texture-anim-layer-func
|
||||
:init-func-id 'noise-texture-init
|
||||
:tex #f
|
||||
:end-time 600.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
)
|
||||
)
|
||||
(new 'static 'texture-anim
|
||||
:num-layers #x2
|
||||
:func-id 'cloud-texture-anim-func
|
||||
:init-func-id 'dest-texture-init
|
||||
:tex #f
|
||||
:tex-name #f
|
||||
:extra (new 'static 'vector :x 512.0 :y 8.0)
|
||||
:color (new 'static 'rgba :a #x80)
|
||||
:frame-delta 300.0
|
||||
:frame-mod 450.0
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x1 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x1 :d #x1)
|
||||
:data (new 'static 'array texture-anim-layer 2
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 512.0 :y 16.0 :z 24.0)
|
||||
:func-id 'cloud-texture-anim-layer-func
|
||||
:init-func-id 'noise-texture-init
|
||||
:tex #f
|
||||
:end-time 450.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 512.0 :y 16.0 :z 24.0)
|
||||
:func-id 'cloud-texture-anim-layer-func
|
||||
:init-func-id 'noise-texture-init
|
||||
:tex #f
|
||||
:end-time 450.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
)
|
||||
)
|
||||
(new 'static 'texture-anim
|
||||
:num-layers 6
|
||||
:func #f
|
||||
:init-func-id 'dest-texture-init
|
||||
:tex #f
|
||||
:tex-name #f
|
||||
:extra (new 'static 'vector :x 512.0 :y 16.0)
|
||||
:color (new 'static 'rgba :a #x80)
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x1 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x1 :d #x1)
|
||||
:data (new 'static 'array texture-anim-layer 6
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 16.0 :y 4.0)
|
||||
:func-id 'default-texture-anim-layer-func
|
||||
:init-func-id 'src-texture-init
|
||||
:tex #f
|
||||
:end-time 300.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 0.49)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 32.0 :y 5.0)
|
||||
:func-id 'default-texture-anim-layer-func
|
||||
:init-func-id 'src-texture-init
|
||||
:tex #f
|
||||
:end-time 300.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 0.19)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 64.0 :y 6.0)
|
||||
:func-id 'default-texture-anim-layer-func
|
||||
:init-func-id 'src-texture-init
|
||||
:tex #f
|
||||
:end-time 300.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 0.145)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 128.0 :y 8.0)
|
||||
:func-id 'default-texture-anim-layer-func
|
||||
:init-func-id 'src-texture-init
|
||||
:tex #f
|
||||
:end-time 300.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 0.015)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 256.0 :y 8.0)
|
||||
:func-id 'default-texture-anim-layer-func
|
||||
:init-func-id 'src-texture-init
|
||||
:tex #f
|
||||
:end-time 300.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 0.01)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 512.0 :y 8.0)
|
||||
:func-id 'default-texture-anim-layer-func
|
||||
:init-func-id 'src-texture-init
|
||||
:tex #f
|
||||
:end-time 300.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x2 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 0.0075)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
)
|
||||
)
|
||||
(new 'static 'texture-anim
|
||||
:num-layers #x1
|
||||
:func #f
|
||||
:init-func-id 'dest-texture-init
|
||||
:tex #f
|
||||
:tex-name #f
|
||||
:extra (new 'static 'vector :x 512.0 :y 8.0)
|
||||
:color (new 'static 'rgba :a #x80)
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x1 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x1 :d #x1)
|
||||
:data (new 'static 'array texture-anim-layer 2
|
||||
(new 'static 'texture-anim-layer
|
||||
:extra (new 'static 'vector :x 512.0 :y 16.0)
|
||||
:func-id 'move-rg-to-ba-texture-anim-layer-func
|
||||
:init-func-id 'src-texture-init
|
||||
:tex #f
|
||||
:end-time 300.0
|
||||
:tex-name #f
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x1 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x1 :d #x1)
|
||||
:start-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:start-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:start-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:start-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-color (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
:end-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-st-scale (new 'static 'vector2 :data (new 'static 'array float 2 1.0 1.0))
|
||||
:end-st-offset (new 'static 'vector2 :data (new 'static 'array float 2 0.5 0.5))
|
||||
:end-qs (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0)
|
||||
)
|
||||
)
|
||||
)
|
||||
(new 'static 'texture-anim
|
||||
:func-id 'texture-anim-cloud-clut-upload
|
||||
:init-func-id 'texture-anim-cloud-clut-init
|
||||
:tex #f
|
||||
:tex-name #f
|
||||
:extra (new 'static 'vector :x 24.0 :y 0.5 :z 1.0)
|
||||
:color (new 'static 'rgba :a #x80)
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x1 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x1 :d #x1)
|
||||
:data (new 'static 'array texture-anim-layer 2)
|
||||
)
|
||||
(new 'static 'texture-anim
|
||||
:func-id 'fog-texture-anim-func
|
||||
:init-func-id 'fog-texture-anim-init
|
||||
:tex #f
|
||||
:tex-name #f
|
||||
:extra (new 'static 'vector :x 4.0 :y 6.0 :z 122880.0)
|
||||
:color (new 'static 'rgba :a #x80)
|
||||
:test (new 'static 'gs-test :ate #x1 :afail #x1 :zte #x1 :ztst (gs-ztest always))
|
||||
:alpha (new 'static 'gs-alpha :b #x1 :d #x1)
|
||||
:data (new 'static 'array texture-anim-layer 2)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defun set-layer-scale! ((n int) (val float))
|
||||
"set the scale of noise layer `n` in the hires sky anim"
|
||||
(set! (-> *sky-hires-texture-anim-array* array-data 7 data n start-color w) val)
|
||||
)
|
||||
(defun set-layer-update-time! ((n int) (val float))
|
||||
"set the update time of noise layer `n` in the hires sky anim"
|
||||
(set! (-> *sky-hires-texture-anim-array* array-data (1+ n) frame-mod) val)
|
||||
(set! (-> *sky-hires-texture-anim-array* array-data (1+ n) data 0 end-time) val)
|
||||
(set! (-> *sky-hires-texture-anim-array* array-data (1+ n) data 1 end-time) val)
|
||||
)
|
||||
|
||||
(set-layer-scale! 0 0.49)
|
||||
(set-layer-scale! 1 0.19)
|
||||
(set-layer-scale! 2 0.145)
|
||||
(set-layer-scale! 3 0.015)
|
||||
(set-layer-scale! 4 0.01)
|
||||
(set-layer-scale! 5 0.0075)
|
||||
(set-layer-update-time! 0 (fsec 16))
|
||||
(set-layer-update-time! 1 (fsec 8))
|
||||
(set-layer-update-time! 2 (fsec 6))
|
||||
(set-layer-update-time! 3 (fsec 4))
|
||||
(set-layer-update-time! 4 (fsec 3))
|
||||
(set-layer-update-time! 5 (fsec 2))
|
||||
|
||||
)
|
||||
|
||||
;; WARN: Return type mismatch float vs none.
|
||||
(defun set-fog-height! ((arg0 float))
|
||||
(set! (-> *sky-texture-anim-array* array-data 8 extra z) arg0)
|
||||
;; og:preserve-this
|
||||
(#when PC_PORT
|
||||
(set! (-> (the (array texture-anim) *sky-hires-texture-anim-array*) 10 extra z) arg0))
|
||||
(none)
|
||||
)
|
||||
|
||||
@ -429,6 +1034,10 @@
|
||||
(defun set-cloud-minmax! ((arg0 float) (arg1 float))
|
||||
(set! (-> *sky-texture-anim-array* array-data 7 extra y) arg0)
|
||||
(set! (-> *sky-texture-anim-array* array-data 7 extra z) arg1)
|
||||
;; og:preserve-this
|
||||
(#when PC_PORT
|
||||
(set! (-> *sky-hires-texture-anim-array* array-data 9 extra y) arg0)
|
||||
(set! (-> *sky-hires-texture-anim-array* array-data 9 extra z) arg1))
|
||||
(none)
|
||||
)
|
||||
|
||||
|
@ -361,6 +361,9 @@
|
||||
)
|
||||
|
||||
(define-extern *sky-texture-anim-array* (texture-anim-array texture-anim))
|
||||
;; og:preserve-this
|
||||
(#when PC_PORT
|
||||
(define-extern *sky-hires-texture-anim-array* (texture-anim-array texture-anim)))
|
||||
(define-extern *darkjak-texture-anim-array* (texture-anim-array texture-anim))
|
||||
(define-extern *darkjak-highres-texture-anim-array* (texture-anim-array texture-anim))
|
||||
(define-extern *skull-gem-texture-anim-array* (texture-anim-array texture-anim))
|
||||
@ -430,6 +433,22 @@
|
||||
)
|
||||
)
|
||||
|
||||
(defun make-sky-hires-input ((si sky-input))
|
||||
(set! (-> si fog-height) (-> (the (array texture-anim) *sky-hires-texture-anim-array*) 10 extra z))
|
||||
(set! (-> si cloud-min) (-> *sky-hires-texture-anim-array* array-data 9 extra y))
|
||||
(set! (-> si cloud-max) (-> *sky-hires-texture-anim-array* array-data 9 extra z))
|
||||
(set! (-> si cloud-dest) (the int (-> *sky-hires-texture-anim-array* array-data 8 tex dest 0)))
|
||||
(dotimes (i (-> *sky-hires-texture-anim-array* array-data 7 num-layers))
|
||||
(set! (-> si scales i) (-> *sky-hires-texture-anim-array* array-data 7 data i start-color w))
|
||||
(set! (-> si max-times i) (-> *sky-hires-texture-anim-array* array-data (1+ i) frame-mod))
|
||||
)
|
||||
(dotimes (i 11)
|
||||
(set! (-> si times i)
|
||||
(-> *sky-hires-texture-anim-array* array-data i frame-time)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro print-anim (&rest args)
|
||||
;`(format 0 ,@args)
|
||||
0
|
||||
@ -499,6 +518,29 @@
|
||||
(set! anim-idx 8) ;; fog
|
||||
;; (return #f)
|
||||
)
|
||||
((*sky-hires-texture-anim-array*)
|
||||
(when (= bucket (bucket-id tex-lcom-sky-post))
|
||||
;; skip. I believe this is only used to generate the envmap texture for the ocean.
|
||||
;; it generates the exact same thing, so if we want this on PC one day, we can just
|
||||
;; steal if from the beginning of the frame.
|
||||
(return #f)
|
||||
)
|
||||
(with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf))
|
||||
bucket
|
||||
)
|
||||
(pc-texture-anim-flag start-anim-array dma-buf)
|
||||
(pc-texture-anim-flag clouds-hires dma-buf :qwc (/ (psize-of sky-input) 16))
|
||||
(make-sky-hires-input (the sky-input (-> dma-buf base)))
|
||||
(&+! (-> dma-buf base) (psize-of sky-input))
|
||||
(pc-texture-anim-flag finish-anim-array dma-buf)
|
||||
(dotimes (i 10) ;; intentially skipping fog here!!
|
||||
(pc-update-anim-frame-time (-> *sky-hires-texture-anim-array* array-data i))
|
||||
)
|
||||
)
|
||||
;; falling through on purpose
|
||||
(set! anim-idx 10) ;; fog
|
||||
; (return #f)
|
||||
)
|
||||
((*darkjak-texture-anim-array*)
|
||||
(pc-clut-blender bucket (texture-anim-pc darkjak) anim-array)
|
||||
(return #f)
|
||||
|
@ -18,6 +18,8 @@
|
||||
)
|
||||
|
||||
(init! *sky-texture-anim-array*)
|
||||
;; og:preserve-this
|
||||
(init! *sky-hires-texture-anim-array*)
|
||||
(init! *darkjak-texture-anim-array*)
|
||||
(init! *skull-gem-texture-anim-array*)
|
||||
(init! *default-water-texture-anim-array*)
|
||||
|
@ -1383,3 +1383,18 @@
|
||||
(define *common-text-heap* (new 'global 'kheap))
|
||||
|
||||
(define *common-text* (the-as game-text-info #f))
|
||||
|
||||
;; og:preserve-this
|
||||
;; NOTE - PC PORT difference
|
||||
;; Partial translations are a thing that we should support. Parts of translating the game are intentionally made
|
||||
;; difficult for normal translators due to not wanting to make all the strings public (or in the case of subtitles,
|
||||
;; we straight up didn't have them yet)
|
||||
;;
|
||||
;; So to remedy this, we always load the english text as a fallback so that if there is only a partial translation
|
||||
;; the UX won't be horrible with everything displaying as UNKNOWN.
|
||||
;;
|
||||
;; One of the reasons we didn't do this is because it makes it obvious which strings are remaining,
|
||||
;; but there are better ways to keep track or check if strings are missing.
|
||||
(#when PC_PORT
|
||||
(kheap-alloc (define *fallback-text-heap* (new 'global 'kheap)) (* 80 1024))
|
||||
(define *fallback-text* (the game-text-info #f)))
|
@ -194,8 +194,13 @@
|
||||
(the-as string #f)
|
||||
)
|
||||
(else
|
||||
(format (clear *temp-string*) "UNKNOWN ID ~X" arg0)
|
||||
*temp-string*
|
||||
;; og:preserve-this Added fallback to English if string is not found.
|
||||
(#if PC_PORT
|
||||
(if *fallback-text-lookup?*
|
||||
(aif (lookup-text! *fallback-text* arg0 #t)
|
||||
it
|
||||
(string-format "UNKNOWN ID ~D" arg0)))
|
||||
(string-format "UNKNOWN ID ~D" arg0))
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -301,12 +306,14 @@
|
||||
)
|
||||
|
||||
(defun load-level-text-files ((arg0 int))
|
||||
(if (or *level-text-file-load-flag* (>= arg0 0))
|
||||
(load-game-text-info "common" (&-> '*common-text* value) *common-text-heap*)
|
||||
)
|
||||
0
|
||||
(none)
|
||||
)
|
||||
;; og:preserve-this Load in English file to use as a fallback
|
||||
(when (or *level-text-file-load-flag* (>= arg0 0))
|
||||
(load-game-text-info "common" (&-> '*common-text* value) *common-text-heap*)
|
||||
(#when PC_PORT
|
||||
(protect ((-> *setting-control* user-current language))
|
||||
(set! (-> *setting-control* user-current language) (language-enum english))
|
||||
(load-game-text-info "common" (&-> '*fallback-text* value) *fallback-text-heap*))))
|
||||
(none))
|
||||
|
||||
(defun draw-debug-text-box ((arg0 font-context))
|
||||
(when *cheat-mode*
|
||||
|
@ -249,6 +249,7 @@
|
||||
;; Jak 3 Specific Kernel Definitions
|
||||
(define *pc-waiting-on-rpc?* symbol)
|
||||
(define *pc-rpc-error?* symbol)
|
||||
|
||||
(define-extern pc-get-last-rpc-error (function string none))
|
||||
(define-extern pc-fetch-external-race-times (function string none))
|
||||
(define-extern pc-fetch-external-speedrun-times (function string none))
|
||||
@ -260,6 +261,27 @@
|
||||
(define-extern pc-get-num-external-speedrun-times (function string int))
|
||||
(define-extern pc-get-num-external-highscores (function string int))
|
||||
|
||||
;; Speedrunner Mode Stuff
|
||||
(define-extern pc-sr-mode-get-practice-entries-amount (function int))
|
||||
(define-extern pc-sr-mode-get-practice-entry-name (function int string none))
|
||||
(define-extern pc-sr-mode-get-practice-entry-continue-point (function int string none))
|
||||
(define-extern pc-sr-mode-get-practice-entry-history-success (function int int))
|
||||
(define-extern pc-sr-mode-get-practice-entry-history-attempts (function int int))
|
||||
(define-extern pc-sr-mode-get-practice-entry-session-success (function int int))
|
||||
(define-extern pc-sr-mode-get-practice-entry-session-attempts (function int int))
|
||||
(define-extern pc-sr-mode-get-practice-entry-avg-time (function int string none))
|
||||
(define-extern pc-sr-mode-get-practice-entry-fastest-time (function int string none))
|
||||
(define-extern pc-sr-mode-record-practice-entry-attempt! (function int symbol (pointer float) symbol))
|
||||
(declare-type speedrun-practice-objective structure)
|
||||
(define-extern pc-sr-mode-init-practice-info! (function int speedrun-practice-objective none))
|
||||
;; TODO - a menu to dump out the 3 numbers with a pre-generated name to the file
|
||||
(define-extern pc-sr-mode-get-custom-category-amount (function int))
|
||||
(define-extern pc-sr-mode-get-custom-category-name (function int string none))
|
||||
(define-extern pc-sr-mode-get-custom-category-continue-point (function int string none))
|
||||
(declare-type speedrun-custom-category structure)
|
||||
(define-extern pc-sr-mode-init-custom-category-info! (function int speedrun-custom-category none))
|
||||
(define-extern pc-sr-mode-dump-new-custom-category (function speedrun-custom-category none))
|
||||
|
||||
(define-extern file-stream-open (function file-stream string symbol file-stream))
|
||||
(define-extern file-stream-close (function file-stream file-stream))
|
||||
(define-extern file-stream-length (function file-stream int))
|
||||
|
@ -815,8 +815,18 @@
|
||||
|
||||
(define *temp-string* (new 'global 'string 2048 (the-as string #f)))
|
||||
|
||||
;; og:preserve-this
|
||||
(define *temp-string2* (new 'global 'string 2048 (the string #f)))
|
||||
|
||||
(defconstant EMPTY_STRING "")
|
||||
|
||||
(#when PC_PORT (define *pc-encoded-temp-string* (new 'global 'string 2048 (the-as string #f))))
|
||||
|
||||
(#when PC_PORT
|
||||
(define *pc-cpp-temp-string*
|
||||
"A convenient place to retrieve a string from C++"
|
||||
(new 'global 'string 2048 (the string #f))))
|
||||
|
||||
(kmemclose)
|
||||
|
||||
(defmacro string-format (&rest args)
|
||||
|
@ -2603,6 +2603,9 @@
|
||||
:trans (behavior ()
|
||||
(cond
|
||||
((= (-> self hit-points) 0.0)
|
||||
;; og:preserve-this
|
||||
(#when PC_PORT
|
||||
(set! (-> *autosplit-info-jak3* errol-dead?) 1))
|
||||
(let ((a1-0 (new 'stack-no-clear 'event-message-block)))
|
||||
(set! (-> a1-0 from) (process->ppointer self))
|
||||
(set! (-> a1-0 num-params) 0)
|
||||
|
164
goal_src/jak3/pc/features/autosplit-h.gc
Normal file
164
goal_src/jak3/pc/features/autosplit-h.gc
Normal file
@ -0,0 +1,164 @@
|
||||
;;-*-Lisp-*-
|
||||
(in-package goal)
|
||||
|
||||
;; LiveSplit ASL requires all settings to initalized _before_ you connect the process
|
||||
;; Therefore everything has to be laid out in a predictable fashion before hand
|
||||
;; So this is a lot of hard-coding, but not too bad when just copied from the debug menu code
|
||||
;;
|
||||
;; DO NOT change the order, appending to the end is safe!
|
||||
|
||||
(deftype autosplit-info (structure)
|
||||
(;; Version Info
|
||||
(version-major uint16)
|
||||
(version-minor uint16)
|
||||
;; General stats
|
||||
(num-orbs uint32)
|
||||
(num-skullgems uint32)
|
||||
(errol-dead? uint8)
|
||||
(all-collectables-acquired? uint8)
|
||||
(padding-stats uint8 198) ;; padding for future growth
|
||||
;; loading/cutscene/control related info
|
||||
(game-hash uint32)
|
||||
(in-cutscene? uint8)
|
||||
(is-loading? uint8)
|
||||
(padding-controls uint8 200) ;; padding for future growth
|
||||
;; need-resolution tasks
|
||||
(res-arena-training-1 uint8)
|
||||
(res-arena-fight-1 uint8)
|
||||
(res-wascity-chase uint8)
|
||||
(res-wascity-pre-game uint8)
|
||||
(res-desert-turtle-training uint8)
|
||||
(res-desert-course-race uint8)
|
||||
(res-desert-artifact-race-1 uint8)
|
||||
(res-wascity-leaper-race uint8)
|
||||
(res-desert-hover uint8)
|
||||
(res-arena-fight-2 uint8)
|
||||
(res-desert-catch-lizards uint8)
|
||||
(res-desert-rescue uint8)
|
||||
(res-wascity-gungame uint8)
|
||||
(res-arena-fight-3 uint8)
|
||||
(res-nest-eggs uint8)
|
||||
(res-temple-climb uint8)
|
||||
(res-desert-glide uint8)
|
||||
(res-volcano-darkeco uint8)
|
||||
(res-temple-oracle uint8)
|
||||
(res-desert-oasis-defense uint8)
|
||||
(res-temple-tests uint8)
|
||||
(res-comb-travel uint8)
|
||||
(res-mine-explore uint8)
|
||||
(res-mine-blow uint8)
|
||||
(res-mine-boss uint8)
|
||||
(res-sewer-met-hum uint8)
|
||||
(res-city-vehicle-training uint8)
|
||||
(res-city-port-fight uint8)
|
||||
(res-city-port-attack uint8)
|
||||
(res-city-gun-course-1 uint8)
|
||||
(res-city-sniper-fight uint8)
|
||||
(res-sewer-kg-met uint8)
|
||||
(res-city-destroy-darkeco uint8)
|
||||
(res-forest-kill-plants uint8)
|
||||
(res-city-destroy-grid uint8)
|
||||
(res-city-hijack-vehicle uint8)
|
||||
(res-city-port-assault uint8)
|
||||
(res-city-gun-course-2 uint8)
|
||||
(res-city-blow-barricade uint8)
|
||||
(res-city-protect-hq uint8)
|
||||
(res-sewer-hum-kg uint8)
|
||||
(res-city-power-game uint8)
|
||||
(res-desert-artifact-race-2 uint8)
|
||||
(res-nest-hunt uint8)
|
||||
(res-desert-beast-battle uint8)
|
||||
(res-desert-jump-mission uint8)
|
||||
(res-desert-chase-marauders uint8)
|
||||
(res-forest-ring-chase uint8)
|
||||
(res-factory-sky-battle uint8)
|
||||
(res-factory-assault uint8)
|
||||
(res-factory-boss uint8)
|
||||
(res-temple-defend uint8)
|
||||
(res-wascity-defend uint8)
|
||||
(res-forest-turn-on-machine uint8)
|
||||
(res-precursor-tour uint8)
|
||||
(res-city-blow-tower uint8)
|
||||
(res-tower-destroy uint8)
|
||||
(res-palace-ruins-patrol uint8)
|
||||
(res-palace-ruins-attack uint8)
|
||||
(res-comb-wild-ride uint8)
|
||||
(res-precursor-destroy-ship uint8)
|
||||
(res-desert-final-boss uint8)
|
||||
(res-city-win uint8)
|
||||
(res-desert-bbush-get-to-1 uint8)
|
||||
(res-desert-bbush-get-to-2 uint8)
|
||||
(res-desert-bbush-get-to-3 uint8)
|
||||
(res-desert-bbush-get-to-4 uint8)
|
||||
(res-desert-bbush-get-to-5 uint8)
|
||||
(res-desert-bbush-get-to-6 uint8)
|
||||
(res-desert-bbush-get-to-7 uint8)
|
||||
(res-desert-bbush-get-to-8 uint8)
|
||||
(res-desert-bbush-get-to-9 uint8)
|
||||
(res-desert-bbush-get-to-11 uint8)
|
||||
(res-desert-bbush-get-to-12 uint8)
|
||||
(res-desert-bbush-get-to-14 uint8)
|
||||
(res-desert-bbush-get-to-16 uint8)
|
||||
(res-desert-bbush-get-to-17 uint8)
|
||||
(res-wascity-bbush-get-to-18 uint8)
|
||||
(res-desert-bbush-get-to-19 uint8)
|
||||
(res-wascity-bbush-get-to-20 uint8)
|
||||
(res-wascity-bbush-get-to-21 uint8)
|
||||
(res-wascity-bbush-get-to-22 uint8)
|
||||
(res-wascity-bbush-get-to-23 uint8)
|
||||
(res-wascity-bbush-get-to-24 uint8)
|
||||
(res-wascity-bbush-get-to-25 uint8)
|
||||
(res-city-bbush-get-to-26 uint8)
|
||||
(res-city-bbush-get-to-27 uint8)
|
||||
(res-city-bbush-get-to-28 uint8)
|
||||
(res-city-bbush-get-to-29 uint8)
|
||||
(res-city-bbush-get-to-30 uint8)
|
||||
(res-city-bbush-get-to-31 uint8)
|
||||
(res-city-bbush-get-to-32 uint8)
|
||||
(res-city-bbush-get-to-33 uint8)
|
||||
(res-city-bbush-get-to-34 uint8)
|
||||
(res-city-bbush-get-to-35 uint8)
|
||||
(res-city-bbush-get-to-36 uint8)
|
||||
(res-city-bbush-get-to-37 uint8)
|
||||
(res-city-bbush-get-to-38 uint8)
|
||||
(res-city-bbush-get-to-39 uint8)
|
||||
(res-city-bbush-get-to-40 uint8)
|
||||
(res-city-bbush-get-to-41 uint8)
|
||||
(res-city-bbush-get-to-42 uint8)
|
||||
(res-city-bbush-get-to-43 uint8)
|
||||
(res-city-bbush-get-to-44 uint8)
|
||||
(res-desert-bbush-ring-1 uint8)
|
||||
(res-desert-bbush-ring-2 uint8)
|
||||
(res-wascity-bbush-ring-3 uint8)
|
||||
(res-wascity-bbush-ring-4 uint8)
|
||||
(res-city-bbush-ring-5 uint8)
|
||||
(res-city-bbush-ring-6 uint8)
|
||||
(res-desert-bbush-egg-spider-1 uint8)
|
||||
(res-desert-bbush-spirit-chase-1 uint8)
|
||||
(res-wascity-bbush-spirit-chase-2 uint8)
|
||||
(res-city-bbush-spirit-chase-3 uint8)
|
||||
(res-desert-bbush-timer-chase-1 uint8)
|
||||
(res-wascity-bbush-timer-chase-2 uint8)
|
||||
(res-desert-bbush-air-time uint8)
|
||||
(res-desert-bbush-total-air-time uint8)
|
||||
(res-desert-bbush-jump-distance uint8)
|
||||
(res-desert-bbush-total-jump-distance uint8)
|
||||
(res-desert-bbush-roll-count uint8)
|
||||
(res-desert-bbush-time-trial-1 uint8)
|
||||
(res-desert-bbush-rally uint8)
|
||||
(res-city-bbush-port-attack uint8)
|
||||
(res-desert-rescue-bbush uint8)
|
||||
(res-city-gun-course-play-for-fun uint8)
|
||||
(res-city-jetboard-bbush uint8)
|
||||
(res-desert-bbush-destroy-interceptors uint8)
|
||||
;; TODO misc other task-nodes
|
||||
(arena-fight-1-throne uint8) ;; after arena 1 cutscene
|
||||
;; TODO - orbs in level X
|
||||
;; end marker just to make things look nice in a memory view
|
||||
(end-marker uint8 4))
|
||||
(:methods
|
||||
(reset! (_type_) object)
|
||||
(update! (_type_) object)
|
||||
(debug-draw (_type_) object)))
|
||||
|
||||
(define-extern *autosplit-info-jak3* autosplit-info)
|
257
goal_src/jak3/pc/features/autosplit.gc
Normal file
257
goal_src/jak3/pc/features/autosplit.gc
Normal file
@ -0,0 +1,257 @@
|
||||
;;-*-Lisp-*-
|
||||
(in-package goal)
|
||||
(define *autosplit-info-jak3* (new 'static 'autosplit-info))
|
||||
|
||||
(pc-init-autosplitter-struct)
|
||||
|
||||
;; Setup Version
|
||||
(set! (-> *autosplit-info-jak3* version-major) 0)
|
||||
|
||||
(set! (-> *autosplit-info-jak3* version-minor) 1)
|
||||
|
||||
;; Setup markers
|
||||
(charp<-string (-> *autosplit-info-jak3* end-marker) "end")
|
||||
|
||||
;; Setup Padding
|
||||
(charp<-string (-> *autosplit-info-jak3* padding-stats) "padding-stats!")
|
||||
|
||||
(charp<-string (-> *autosplit-info-jak3* padding-controls) "padding-controls!")
|
||||
|
||||
(defconstant MAX_ORBS 600)
|
||||
|
||||
(defconstant AUTOSPLITTER_DEBUG #f)
|
||||
|
||||
(defmacro autosplit-flag-task-complete! (field-name task-name)
|
||||
"Given a field name in the autosplitter struct, and a [[game-task]] name to check, sets either a 0 or a 1"
|
||||
`(begin
|
||||
(if (!= (-> this ,field-name) (if (task-complete? *game-info* (game-task ,task-name)) 1 0))
|
||||
(format 0 "AUTOSPLIT for ~A~%" (quote ,task-name)))
|
||||
(set! (-> this ,field-name) (if (task-complete? *game-info* (game-task ,task-name)) 1 0))))
|
||||
|
||||
(defmacro autosplit-flag-task-node-closed! (field-name task-node-name)
|
||||
"Given a field name in the autosplitter struct, and a [[game-task-node]] name to check, sets either a 0 or a 1"
|
||||
`(begin
|
||||
(if (!= (-> this ,field-name) (if (task-node-closed? (game-task-node ,task-node-name)) 1 0))
|
||||
(format 0 "AUTOSPLIT for ~A~%" (quote ,task-node-name)))
|
||||
(set! (-> this ,field-name) (if (task-node-closed? (game-task-node ,task-node-name)) 1 0))))
|
||||
|
||||
(defmethod update! ((this autosplit-info))
|
||||
;; general statistics
|
||||
;; when we are blacked out in loads the value of these are temporarily 0, and that messes with the auto splitter.
|
||||
(let ((in-blackout? (>= (-> *game-info* blackout-time) (current-time))))
|
||||
(when (not in-blackout?)
|
||||
(set! (-> this num-orbs) (the int (-> *game-info* skill-total)))
|
||||
(set! (-> this num-skullgems) (the int (-> *game-info* gem-total)))
|
||||
;; ending conditions
|
||||
;; all collectables
|
||||
;; - check for all features
|
||||
;; - check for all vehicles
|
||||
;; - check for all inventory items
|
||||
;; - check for all orbs
|
||||
(set! (-> this all-collectables-acquired?)
|
||||
(if (and (logtesta? (-> *game-info* features)
|
||||
(game-feature jakc
|
||||
board
|
||||
board-launch
|
||||
board-zap
|
||||
darkeco
|
||||
darkjak
|
||||
darkjak
|
||||
darkjak-smack
|
||||
darkjak-bomb0
|
||||
darkjak-bomb1
|
||||
lighteco
|
||||
lightjak
|
||||
lightjak-regen
|
||||
lightjak-swoop
|
||||
lightjak-freeze
|
||||
lightjak-shield
|
||||
gun
|
||||
gun-red-1
|
||||
gun-yellow-1
|
||||
gun-blue-1
|
||||
gun-dark-1
|
||||
gun-red-2
|
||||
gun-yellow-2
|
||||
gun-blue-2
|
||||
gun-dark-2
|
||||
gun-red-3
|
||||
gun-yellow-3
|
||||
gun-blue-3
|
||||
gun-dark-3))
|
||||
(logtesta? (-> *game-info* vehicles) (game-vehicles v-turtle v-snake v-scorpion v-toad v-fox v-rhino v-mirage v-x-ride))
|
||||
(logtesta? (-> *game-info* items)
|
||||
(game-items amulet0
|
||||
amulet1
|
||||
amulet2
|
||||
pass-front-gate
|
||||
seal-of-mar
|
||||
cypher-gliph
|
||||
artifact-holocube
|
||||
artifact-av-reflector
|
||||
artifact-av-prism
|
||||
artifact-av-generator
|
||||
artifact-av-map
|
||||
light-eco-crystal0
|
||||
light-eco-crystal1
|
||||
light-eco-crystal2
|
||||
light-eco-crystal3
|
||||
dark-eco-crystal0
|
||||
dark-eco-crystal1
|
||||
dark-eco-crystal2
|
||||
dark-eco-crystal3))
|
||||
(>= (-> this num-orbs) MAX_ORBS))
|
||||
1
|
||||
0))))
|
||||
;; loading/cutscene related flags
|
||||
(set! (-> this in-cutscene?) (if (movie?) 1 0))
|
||||
;; need resolution flags
|
||||
(autosplit-flag-task-complete! res-arena-training-1 arena-training-1)
|
||||
(autosplit-flag-task-complete! res-arena-fight-1 arena-fight-1)
|
||||
(autosplit-flag-task-complete! res-wascity-chase wascity-chase)
|
||||
(autosplit-flag-task-complete! res-wascity-pre-game wascity-pre-game)
|
||||
(autosplit-flag-task-complete! res-desert-turtle-training desert-turtle-training)
|
||||
(autosplit-flag-task-complete! res-desert-course-race desert-course-race)
|
||||
(autosplit-flag-task-complete! res-desert-artifact-race-1 desert-artifact-race-1)
|
||||
(autosplit-flag-task-complete! res-wascity-leaper-race wascity-leaper-race)
|
||||
(autosplit-flag-task-complete! res-desert-hover desert-hover)
|
||||
(autosplit-flag-task-complete! res-arena-fight-2 arena-fight-2)
|
||||
(autosplit-flag-task-complete! res-desert-catch-lizards desert-catch-lizards)
|
||||
(autosplit-flag-task-complete! res-desert-rescue desert-rescue)
|
||||
(autosplit-flag-task-complete! res-wascity-gungame wascity-gungame)
|
||||
(autosplit-flag-task-complete! res-arena-fight-3 arena-fight-3)
|
||||
(autosplit-flag-task-complete! res-nest-eggs nest-eggs)
|
||||
(autosplit-flag-task-complete! res-temple-climb temple-climb)
|
||||
(autosplit-flag-task-complete! res-desert-glide desert-glide)
|
||||
(autosplit-flag-task-complete! res-volcano-darkeco volcano-darkeco)
|
||||
(autosplit-flag-task-complete! res-temple-oracle temple-oracle)
|
||||
(autosplit-flag-task-complete! res-desert-oasis-defense desert-oasis-defense)
|
||||
(autosplit-flag-task-complete! res-temple-tests temple-tests)
|
||||
(autosplit-flag-task-complete! res-comb-travel comb-travel)
|
||||
(autosplit-flag-task-complete! res-mine-explore mine-explore)
|
||||
(autosplit-flag-task-complete! res-mine-blow mine-blow)
|
||||
(autosplit-flag-task-complete! res-mine-boss mine-boss)
|
||||
(autosplit-flag-task-complete! res-sewer-met-hum sewer-met-hum)
|
||||
(autosplit-flag-task-complete! res-city-vehicle-training city-vehicle-training)
|
||||
(autosplit-flag-task-complete! res-city-port-fight city-port-fight)
|
||||
(autosplit-flag-task-complete! res-city-port-attack city-port-attack)
|
||||
(autosplit-flag-task-complete! res-city-gun-course-1 city-gun-course-1)
|
||||
(autosplit-flag-task-complete! res-city-sniper-fight city-sniper-fight)
|
||||
(autosplit-flag-task-complete! res-sewer-kg-met sewer-kg-met)
|
||||
(autosplit-flag-task-complete! res-city-destroy-darkeco city-destroy-darkeco)
|
||||
(autosplit-flag-task-complete! res-forest-kill-plants forest-kill-plants)
|
||||
(autosplit-flag-task-complete! res-city-destroy-grid city-destroy-grid)
|
||||
(autosplit-flag-task-complete! res-city-hijack-vehicle city-hijack-vehicle)
|
||||
(autosplit-flag-task-complete! res-city-port-assault city-port-assault)
|
||||
(autosplit-flag-task-complete! res-city-gun-course-2 city-gun-course-2)
|
||||
(autosplit-flag-task-complete! res-city-blow-barricade city-blow-barricade)
|
||||
(autosplit-flag-task-complete! res-city-protect-hq city-protect-hq)
|
||||
(autosplit-flag-task-complete! res-sewer-hum-kg sewer-hum-kg)
|
||||
(autosplit-flag-task-complete! res-city-power-game city-power-game)
|
||||
(autosplit-flag-task-complete! res-desert-artifact-race-2 desert-artifact-race-2)
|
||||
(autosplit-flag-task-complete! res-nest-hunt nest-hunt)
|
||||
(autosplit-flag-task-complete! res-desert-beast-battle desert-beast-battle)
|
||||
(autosplit-flag-task-complete! res-desert-jump-mission desert-jump-mission)
|
||||
(autosplit-flag-task-complete! res-desert-chase-marauders desert-chase-marauders)
|
||||
(autosplit-flag-task-complete! res-forest-ring-chase forest-ring-chase)
|
||||
(autosplit-flag-task-complete! res-factory-sky-battle factory-sky-battle)
|
||||
(autosplit-flag-task-complete! res-factory-assault factory-assault)
|
||||
(autosplit-flag-task-complete! res-factory-boss factory-boss)
|
||||
(autosplit-flag-task-complete! res-temple-defend temple-defend)
|
||||
(autosplit-flag-task-complete! res-wascity-defend wascity-defend)
|
||||
(autosplit-flag-task-complete! res-forest-turn-on-machine forest-turn-on-machine)
|
||||
(autosplit-flag-task-complete! res-precursor-tour precursor-tour)
|
||||
(autosplit-flag-task-complete! res-city-blow-tower city-blow-tower)
|
||||
(autosplit-flag-task-complete! res-tower-destroy tower-destroy)
|
||||
(autosplit-flag-task-complete! res-palace-ruins-patrol palace-ruins-patrol)
|
||||
(autosplit-flag-task-complete! res-palace-ruins-attack palace-ruins-attack)
|
||||
(autosplit-flag-task-complete! res-comb-wild-ride comb-wild-ride)
|
||||
(autosplit-flag-task-complete! res-precursor-destroy-ship precursor-destroy-ship)
|
||||
(autosplit-flag-task-complete! res-desert-final-boss desert-final-boss)
|
||||
(autosplit-flag-task-complete! res-city-win city-win)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-get-to-1 desert-bbush-get-to-1)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-get-to-2 desert-bbush-get-to-2)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-get-to-3 desert-bbush-get-to-3)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-get-to-4 desert-bbush-get-to-4)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-get-to-5 desert-bbush-get-to-5)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-get-to-6 desert-bbush-get-to-6)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-get-to-7 desert-bbush-get-to-7)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-get-to-8 desert-bbush-get-to-8)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-get-to-9 desert-bbush-get-to-9)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-get-to-11 desert-bbush-get-to-11)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-get-to-12 desert-bbush-get-to-12)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-get-to-14 desert-bbush-get-to-14)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-get-to-16 desert-bbush-get-to-16)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-get-to-17 desert-bbush-get-to-17)
|
||||
(autosplit-flag-task-complete! res-wascity-bbush-get-to-18 wascity-bbush-get-to-18)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-get-to-19 desert-bbush-get-to-19)
|
||||
(autosplit-flag-task-complete! res-wascity-bbush-get-to-20 wascity-bbush-get-to-20)
|
||||
(autosplit-flag-task-complete! res-wascity-bbush-get-to-21 wascity-bbush-get-to-21)
|
||||
(autosplit-flag-task-complete! res-wascity-bbush-get-to-22 wascity-bbush-get-to-22)
|
||||
(autosplit-flag-task-complete! res-wascity-bbush-get-to-23 wascity-bbush-get-to-23)
|
||||
(autosplit-flag-task-complete! res-wascity-bbush-get-to-24 wascity-bbush-get-to-24)
|
||||
(autosplit-flag-task-complete! res-wascity-bbush-get-to-25 wascity-bbush-get-to-25)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-26 city-bbush-get-to-26)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-27 city-bbush-get-to-27)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-28 city-bbush-get-to-28)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-29 city-bbush-get-to-29)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-30 city-bbush-get-to-30)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-31 city-bbush-get-to-31)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-32 city-bbush-get-to-32)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-33 city-bbush-get-to-33)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-34 city-bbush-get-to-34)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-35 city-bbush-get-to-35)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-36 city-bbush-get-to-36)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-37 city-bbush-get-to-37)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-38 city-bbush-get-to-38)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-39 city-bbush-get-to-39)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-40 city-bbush-get-to-40)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-41 city-bbush-get-to-41)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-42 city-bbush-get-to-42)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-43 city-bbush-get-to-43)
|
||||
(autosplit-flag-task-complete! res-city-bbush-get-to-44 city-bbush-get-to-44)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-ring-1 desert-bbush-ring-1)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-ring-2 desert-bbush-ring-2)
|
||||
(autosplit-flag-task-complete! res-wascity-bbush-ring-3 wascity-bbush-ring-3)
|
||||
(autosplit-flag-task-complete! res-wascity-bbush-ring-4 wascity-bbush-ring-4)
|
||||
(autosplit-flag-task-complete! res-city-bbush-ring-5 city-bbush-ring-5)
|
||||
(autosplit-flag-task-complete! res-city-bbush-ring-6 city-bbush-ring-6)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-egg-spider-1 desert-bbush-egg-spider-1)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-spirit-chase-1 desert-bbush-spirit-chase-1)
|
||||
(autosplit-flag-task-complete! res-wascity-bbush-spirit-chase-2 wascity-bbush-spirit-chase-2)
|
||||
(autosplit-flag-task-complete! res-city-bbush-spirit-chase-3 city-bbush-spirit-chase-3)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-timer-chase-1 desert-bbush-timer-chase-1)
|
||||
(autosplit-flag-task-complete! res-wascity-bbush-timer-chase-2 wascity-bbush-timer-chase-2)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-air-time desert-bbush-air-time)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-total-air-time desert-bbush-total-air-time)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-jump-distance desert-bbush-jump-distance)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-total-jump-distance desert-bbush-total-jump-distance)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-roll-count desert-bbush-roll-count)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-time-trial-1 desert-bbush-time-trial-1)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-rally desert-bbush-rally)
|
||||
(autosplit-flag-task-complete! res-city-bbush-port-attack city-bbush-port-attack)
|
||||
(autosplit-flag-task-complete! res-desert-rescue-bbush desert-rescue-bbush)
|
||||
(autosplit-flag-task-complete! res-city-gun-course-play-for-fun city-gun-course-play-for-fun)
|
||||
(autosplit-flag-task-complete! res-city-jetboard-bbush city-jetboard-bbush)
|
||||
(autosplit-flag-task-complete! res-desert-bbush-destroy-interceptors desert-bbush-destroy-interceptors)
|
||||
;; misc other tasks
|
||||
(autosplit-flag-task-node-closed! arena-fight-1-throne arena-fight-1-throne) ;; after arena 1 cutscene
|
||||
;; debug only, draw stuff to the screen so i don't have to stare at a memory editor
|
||||
(if AUTOSPLITTER_DEBUG (debug-draw this)))
|
||||
|
||||
(defmethod reset! ((this autosplit-info))
|
||||
(set! (-> this game-hash) (pc-get-unix-timestamp))
|
||||
(set! (-> this errol-dead?) 0))
|
||||
|
||||
(defmethod debug-draw ((this autosplit-info))
|
||||
(format (clear *temp-string*) "errol-dead?: ~D~%" (-> this errol-dead?))
|
||||
(format *temp-string* "all-collectables-acquired?: ~D~%" (-> this all-collectables-acquired?))
|
||||
(with-dma-buffer-add-bucket ((buf (-> (current-frame) global-buf)) (bucket-id debug-no-zbuf1))
|
||||
;; reset bucket settings prior to drawing - font won't do this for us, and
|
||||
;; draw-raw-image can sometimes mess them up. (intro sequence)
|
||||
(dma-buffer-add-gs-set-flusha buf
|
||||
(alpha-1 (new 'static 'gs-alpha :b #x1 :d #x1))
|
||||
(tex1-1 (new 'static 'gs-tex1 :mmag #x1 :mmin #x1)))
|
||||
(let ((font-ctx (new 'stack 'font-context *font-default-matrix* 10 50 0.0 (font-color default) (font-flags shadow kerning large))))
|
||||
(set! (-> font-ctx scale) 0.325)
|
||||
(draw-string-adv *temp-string* buf font-ctx))))
|
134
goal_src/jak3/pc/features/speedruns-h.gc
Normal file
134
goal_src/jak3/pc/features/speedruns-h.gc
Normal file
@ -0,0 +1,134 @@
|
||||
;;-*-Lisp-*-
|
||||
(in-package goal)
|
||||
|
||||
;; TEST - safe with malformed entries
|
||||
|
||||
(deftype speedrun-timer (process)
|
||||
((draw? symbol)
|
||||
(started? symbol)
|
||||
(stopped? symbol)
|
||||
(start-time time-frame)
|
||||
(end-time time-frame)
|
||||
(recorded-time float))
|
||||
(:methods
|
||||
(draw-timer (_type_) object)
|
||||
(start! (_type_) object)
|
||||
(reset! (_type_) object)
|
||||
(stop! (_type_) float))
|
||||
(:state-methods
|
||||
idle))
|
||||
|
||||
(defbehavior speedrun-timer-init-by-other speedrun-timer ()
|
||||
(false! (-> self draw?))
|
||||
(false! (-> self started?))
|
||||
(set! (-> self start-time) 0)
|
||||
(set! (-> self end-time) 0)
|
||||
(set! (-> self recorded-time) 0.0)
|
||||
(go-virtual idle))
|
||||
|
||||
(defstate idle (speedrun-timer)
|
||||
:virtual #t
|
||||
:code
|
||||
(behavior ()
|
||||
(loop
|
||||
(when (-> self draw?)
|
||||
(draw-timer self))
|
||||
(suspend))))
|
||||
|
||||
;; TODO - put in util
|
||||
(deftype objective-zone (process)
|
||||
((start? symbol)
|
||||
(v1 vector :inline)
|
||||
(v2 vector :inline)
|
||||
(on-enter (function none))
|
||||
(on-exit (function none)))
|
||||
(:methods
|
||||
(draw-zone (_type_) object))
|
||||
(:state-methods
|
||||
waiting-for-player
|
||||
player-inside))
|
||||
|
||||
(deftype objective-zone-init-params (structure)
|
||||
((v1 vector :inline)
|
||||
(v2 vector :inline)))
|
||||
|
||||
(defenum speedrun-practice-flags
|
||||
(none))
|
||||
|
||||
;; reset method
|
||||
(deftype speedrun-practice-objective (structure)
|
||||
((index int32)
|
||||
(flags speedrun-practice-flags)
|
||||
(completed-task game-task)
|
||||
(features game-feature)
|
||||
(secrets game-secrets)
|
||||
(vehicles game-vehicles)
|
||||
(starting-position vector)
|
||||
(starting-rotation vector)
|
||||
(starting-camera-position vector)
|
||||
(starting-camera-rotation matrix)
|
||||
(end-task game-task)
|
||||
(start-zone-init-params objective-zone-init-params)
|
||||
(start-zone (pointer objective-zone))
|
||||
(end-zone-init-params objective-zone-init-params)
|
||||
(end-zone (pointer objective-zone)))
|
||||
(:methods
|
||||
(draw-info (_type_) object)
|
||||
(reset! (_type_) object)))
|
||||
|
||||
(defenum speedrun-category
|
||||
:type uint32
|
||||
;; Main Categories
|
||||
(newgame-normal 0)
|
||||
(newgame-heromode 1)
|
||||
;; TODO - add ILs and such later
|
||||
;; there's no point in adding categories that just start from a new-game and have later restrictions
|
||||
;; because we aren't going to modify the code to make that possible
|
||||
;; ie. removing mars tomb skip if you pick "all missions"
|
||||
;; Random one for experimentation
|
||||
(all-cheats-allowed 999)
|
||||
(custom 9999))
|
||||
|
||||
(deftype speedrun-custom-category (structure)
|
||||
((index int32)
|
||||
(secrets game-secrets)
|
||||
(features game-feature)
|
||||
(vehicles game-vehicles)
|
||||
(forbidden-features game-feature)
|
||||
(pc-cheats pc-cheats)
|
||||
(completed-task game-task)))
|
||||
|
||||
(deftype speedrun-info (structure)
|
||||
((category speedrun-category)
|
||||
(active-custom-category speedrun-custom-category)
|
||||
(dump-custom-category speedrun-custom-category)
|
||||
(display-run-info? symbol)
|
||||
(practicing? symbol)
|
||||
(active-practice-objective speedrun-practice-objective)
|
||||
(waiting-to-record-practice-attempt? symbol)
|
||||
(run-started-at time-frame))
|
||||
(:methods
|
||||
(set-category! (_type_ speedrun-category) object)
|
||||
(start-run! (_type_) object)
|
||||
(enforce-settings! (_type_) object)
|
||||
(update! (_type_) object)
|
||||
(draw-run-info (_type_) object)))
|
||||
|
||||
(define-extern *speedrun-info* speedrun-info)
|
||||
|
||||
(defenum speedrun-menu-command
|
||||
:type uint32
|
||||
(reset 0)
|
||||
(exit 1))
|
||||
|
||||
(deftype speedrun-manager (process)
|
||||
((popup-menu (pointer popup-menu))
|
||||
(ignore-menu-toggle? symbol)
|
||||
(opened-with-start? symbol)
|
||||
(timer (pointer speedrun-timer)))
|
||||
(:methods
|
||||
(draw-menu (_type_) object))
|
||||
(:state-methods
|
||||
idle))
|
||||
|
||||
(define-extern *speedrun-manager* (pointer speedrun-manager))
|
766
goal_src/jak3/pc/features/speedruns.gc
Normal file
766
goal_src/jak3/pc/features/speedruns.gc
Normal file
@ -0,0 +1,766 @@
|
||||
;;-*-Lisp-*-
|
||||
(in-package goal)
|
||||
|
||||
;; TODO later - customize menu open keybind
|
||||
|
||||
(define-extern task-close! (function string symbol))
|
||||
|
||||
(define-extern *pc-dead-pool* dead-pool)
|
||||
|
||||
(define *speedrun-info* (new 'static 'speedrun-info))
|
||||
|
||||
(set! (-> *speedrun-info* active-custom-category) (new 'static 'speedrun-custom-category))
|
||||
|
||||
(set! (-> *speedrun-info* dump-custom-category) (new 'static 'speedrun-custom-category))
|
||||
|
||||
(set! (-> *speedrun-info* active-practice-objective) (new 'static 'speedrun-practice-objective))
|
||||
|
||||
(set! (-> *speedrun-info* active-practice-objective starting-position) (new 'static 'vector))
|
||||
|
||||
(set! (-> *speedrun-info* active-practice-objective starting-rotation) (new 'static 'vector))
|
||||
|
||||
(set! (-> *speedrun-info* active-practice-objective starting-camera-position) (new 'static 'vector))
|
||||
|
||||
(set! (-> *speedrun-info* active-practice-objective starting-camera-rotation) (new 'static 'matrix))
|
||||
|
||||
(set! (-> *speedrun-info* active-practice-objective start-zone-init-params) (new 'static 'objective-zone-init-params))
|
||||
|
||||
(set! (-> *speedrun-info* active-practice-objective end-zone-init-params) (new 'static 'objective-zone-init-params))
|
||||
|
||||
(defmethod draw-timer ((this speedrun-timer))
|
||||
(clear *temp-string*)
|
||||
(clear *pc-encoded-temp-string*)
|
||||
(cond
|
||||
((-> this started?)
|
||||
(format *temp-string* "~,,2fs~%" (* (the float (- (current-time) (-> this start-time))) 0.0033333334)))
|
||||
((and (!= 0 (-> this end-time)))
|
||||
(format *temp-string* "~,,2fs~%" (* (the float (- (-> this end-time) (-> this start-time))) 0.0033333334)))
|
||||
(else (format *temp-string* "0.0s~%")))
|
||||
(when *target*
|
||||
(format *temp-string* "~,,2M~%" (-> *target* control ctrl-xz-vel)))
|
||||
(pc-encode-utf8-string *temp-string* *pc-encoded-temp-string*)
|
||||
(with-dma-buffer-add-bucket ((buf (-> (current-frame) global-buf)) (bucket-id debug-no-zbuf1))
|
||||
;; reset bucket settings prior to drawing - font won't do this for us, and
|
||||
;; draw-raw-image can sometimes mess them up. (intro sequence)
|
||||
(dma-buffer-add-gs-set-flusha buf
|
||||
(alpha-1 (new 'static 'gs-alpha :b #x1 :d #x1))
|
||||
(tex1-1 (new 'static 'gs-tex1 :mmag #x1 :mmin #x1)))
|
||||
(let ((font-ctx (new 'stack 'font-context *font-default-matrix* 256 350 0.0 (font-color default) (font-flags middle shadow kerning large))))
|
||||
(set! (-> font-ctx scale) 0.325)
|
||||
(draw-string-adv *pc-encoded-temp-string* buf font-ctx))))
|
||||
|
||||
(defmethod start! ((this speedrun-timer))
|
||||
(true! (-> this started?))
|
||||
(false! (-> this stopped?))
|
||||
(set-time! (-> this start-time))
|
||||
(set! (-> this end-time) 0))
|
||||
|
||||
(defmethod reset! ((this speedrun-timer))
|
||||
(false! (-> this started?))
|
||||
(false! (-> this stopped?))
|
||||
(set! (-> this start-time) 0)
|
||||
(set! (-> this end-time) 0))
|
||||
|
||||
(defmethod stop! ((this speedrun-timer))
|
||||
(when (not (-> this stopped?))
|
||||
(false! (-> this started?))
|
||||
(true! (-> this stopped?))
|
||||
(set-time! (-> this end-time))
|
||||
(set! (-> this recorded-time) (* (the float (- (-> this end-time) (-> this start-time))) 0.0033333334)))
|
||||
(-> this recorded-time))
|
||||
|
||||
(defmethod set-category! ((this speedrun-info) (category speedrun-category))
|
||||
(set! (-> this category) category))
|
||||
|
||||
(defconstant HERO_MODE_SECRETS
|
||||
(game-secrets hero-mode
|
||||
endless-ammo
|
||||
invulnerable
|
||||
endless-dark
|
||||
endless-light
|
||||
unlimited-turbos
|
||||
vehicle-hit-points
|
||||
board-fast
|
||||
vehicle-fox
|
||||
vehicle-mirage
|
||||
vehicle-x-ride
|
||||
darkjak-tracking
|
||||
button-invis
|
||||
gun-upgrade-red-1
|
||||
gun-upgrade-red-2
|
||||
gun-upgrade-red-3
|
||||
gun-upgrade-yellow-1
|
||||
gun-upgrade-yellow-2
|
||||
gun-upgrade-yellow-3
|
||||
gun-upgrade-blue-1
|
||||
gun-upgrade-blue-2
|
||||
gun-upgrade-blue-3
|
||||
gun-upgrade-dark-1
|
||||
gun-upgrade-dark-2
|
||||
gun-upgrade-dark-3
|
||||
gun-upgrade-ammo-red
|
||||
gun-upgrade-ammo-yellow
|
||||
gun-upgrade-ammo-blue
|
||||
gun-upgrade-ammo-dark))
|
||||
|
||||
(defconstant HERO_MODE_FEATURES
|
||||
(game-feature gun
|
||||
gun-red-1
|
||||
gun-red-2
|
||||
gun-red-3
|
||||
gun-yellow-1
|
||||
gun-yellow-2
|
||||
gun-yellow-3
|
||||
gun-blue-1
|
||||
gun-blue-2
|
||||
gun-blue-3
|
||||
gun-dark-1
|
||||
gun-dark-2
|
||||
gun-dark-3
|
||||
board
|
||||
gun-upgrade-yellow-ammo-1
|
||||
gun-upgrade-yellow-ammo-2
|
||||
gun-upgrade-red-ammo-1
|
||||
gun-upgrade-red-ammo-2
|
||||
gun-upgrade-blue-ammo-1
|
||||
gun-upgrade-blue-ammo-2
|
||||
gun-upgrade-dark-ammo-1
|
||||
gun-upgrade-dark-ammo-2
|
||||
board-launch
|
||||
board-zap
|
||||
darkjak
|
||||
darkjak-bomb0
|
||||
darkjak-bomb1
|
||||
lightjak
|
||||
lightjak-regen
|
||||
lightjak-freeze
|
||||
lightjak-shield
|
||||
armor0
|
||||
armor1
|
||||
armor2
|
||||
armor3
|
||||
lighteco
|
||||
darkeco))
|
||||
|
||||
(defmethod start-run! ((this speedrun-info))
|
||||
;; randomize game id so the autosplitter knows to restart
|
||||
(reset! *autosplit-info-jak3*)
|
||||
;; turn on speedrun verification display
|
||||
(true! (-> this display-run-info?))
|
||||
(send-event (ppointer->process *speedrun-manager*) 'start-run)
|
||||
;; ensure any required settings are enabled
|
||||
(enforce-settings! this)
|
||||
;; finalize any category specific setup code
|
||||
(case (-> this category)
|
||||
(((speedrun-category newgame-normal))
|
||||
(set! (-> *game-info* mode) 'debug)
|
||||
(initialize! *game-info* 'game (the game-save #f) (the string #f) (the resetter-spec #f))
|
||||
(set! (-> *game-info* mode) 'play)
|
||||
(start 'play (get-continue-by-name *game-info* "wasstada-jump-training"))
|
||||
(play-task (game-task arena-training-1) 'debug #f))
|
||||
(((speedrun-category newgame-heromode))
|
||||
(process-spawn-function process
|
||||
(lambda :behavior process ()
|
||||
(set! (-> *game-info* mode) 'debug)
|
||||
(initialize! *game-info* 'game (the game-save #f) (the string #f) (the resetter-spec #f))
|
||||
(set! (-> *game-info* mode) 'play)
|
||||
(logior! (-> *game-info* secrets) (game-secrets hero-mode))
|
||||
(logior! (-> *game-info* purchase-secrets) (game-secrets hero-mode))
|
||||
(start 'play (get-continue-by-name *game-info* "wasstada-jump-training"))
|
||||
(play-task (game-task arena-training-1) 'debug #f)
|
||||
(until (and *target* (= (-> *target* next-state name) 'target-stance))
|
||||
(suspend))
|
||||
(set! (-> *game-info* secrets) HERO_MODE_SECRETS)
|
||||
(set! (-> *game-info* purchase-secrets) HERO_MODE_SECRETS)
|
||||
(set! (-> *game-info* features) HERO_MODE_FEATURES))))
|
||||
(((speedrun-category all-cheats-allowed))
|
||||
(process-spawn-function process
|
||||
(lambda :behavior process ()
|
||||
(set! (-> *game-info* mode) 'debug)
|
||||
(initialize! *game-info* 'game (the game-save #f) (the string #f) (the resetter-spec #f))
|
||||
(set! (-> *game-info* mode) 'play)
|
||||
(start 'play (get-continue-by-name *game-info* "wasstada-jump-training"))
|
||||
(play-task (game-task arena-training-1) 'debug #f))))
|
||||
(((speedrun-category custom))
|
||||
(process-spawn-function process
|
||||
(lambda :behavior process ()
|
||||
(clear *temp-string*)
|
||||
(pc-sr-mode-get-custom-category-continue-point (-> *speedrun-info* active-custom-category index) *temp-string*)
|
||||
(if (string= *temp-string* EMPTY_STRING)
|
||||
(initialize! *game-info* 'game (the game-save #f) "intro-start" (the resetter-spec #f))
|
||||
(initialize! *game-info* 'game (the game-save #f) *temp-string* (the resetter-spec #f)))
|
||||
(until (and *target* (= (-> *target* next-state name) 'target-stance))
|
||||
(suspend))
|
||||
(when (nonzero? (-> *speedrun-info* active-custom-category completed-task))
|
||||
(task-resolution-close! (-> *speedrun-info* active-custom-category completed-task)))))))
|
||||
(if (!= -1 (-> *game-info* auto-save-which)) (set! (-> *setting-control* user-default auto-save) #t)))
|
||||
|
||||
(defmethod enforce-settings! ((this speedrun-info))
|
||||
(true! (-> *pc-settings* ps2-actor-vis?)) ;; force PS2 actor visibility
|
||||
(set-frame-rate! *pc-settings* 60 #t) ;; force FPS to `60`
|
||||
;; For posterity, the main reason why changing the cheats is useful is for two main reasons:
|
||||
;; - If you are playing a category that requires cheats (ie. a turbo jetboard one) you'd
|
||||
;; probably like the game to automatically set the appropriate ones for you
|
||||
;; - If you are playing a category that forbids cheats, you wouldn't want your run invalidated because you forgot
|
||||
(case (-> this category)
|
||||
(((speedrun-category newgame-normal) (speedrun-category newgame-heromode))
|
||||
;; disable any active cheats
|
||||
(set! (-> *pc-settings* cheats) (pc-cheats)))
|
||||
(((speedrun-category custom))
|
||||
(set! (-> *game-info* purchase-secrets) (-> *speedrun-info* active-custom-category secrets))
|
||||
(set! (-> *game-info* secrets) (-> *speedrun-info* active-custom-category secrets))
|
||||
(logior! (-> *game-info* features) (-> *speedrun-info* active-custom-category features))
|
||||
(logclear! (-> *game-info* features) (-> *speedrun-info* active-custom-category forbidden-features))
|
||||
(logior! (-> *game-info* vehicles) (-> *speedrun-info* active-custom-category vehicles))
|
||||
(set! (-> *pc-settings* cheats) (-> *speedrun-info* active-custom-category pc-cheats)))))
|
||||
|
||||
(defmethod draw-zone ((this objective-zone))
|
||||
(add-debug-box #t
|
||||
(bucket-id debug)
|
||||
(-> this v1)
|
||||
(-> this v2)
|
||||
(if (-> this start?) (static-rgba #xff #xff #x00 #x80) (static-rgba #xff #x00 #xff #x80))))
|
||||
|
||||
(defstate waiting-for-player (objective-zone)
|
||||
:virtual #t
|
||||
:event
|
||||
(behavior ((proc process) (argc int) (message symbol) (block event-message-block))
|
||||
#t)
|
||||
:trans
|
||||
(behavior ()
|
||||
;; Check to see if we have entered the zone
|
||||
(let ((min-point-x (fmin (-> self v1 x) (-> self v2 x)))
|
||||
(min-point-y (fmin (-> self v1 y) (-> self v2 y)))
|
||||
(min-point-z (fmin (-> self v1 z) (-> self v2 z)))
|
||||
(max-point-x (fmax (-> self v1 x) (-> self v2 x)))
|
||||
(max-point-y (fmax (-> self v1 y) (-> self v2 y)))
|
||||
(max-point-z (fmax (-> self v1 z) (-> self v2 z)))
|
||||
(pos (target-pos 0)))
|
||||
(when (and (and (<= min-point-x (-> pos x)) (<= (-> pos x) max-point-x))
|
||||
(and (<= min-point-y (-> pos y)) (<= (-> pos y) max-point-y))
|
||||
(and (<= min-point-z (-> pos z)) (<= (-> pos z) max-point-z)))
|
||||
(when (nonzero? (-> self on-enter))
|
||||
((-> self on-enter)))
|
||||
(go-virtual player-inside))))
|
||||
:code
|
||||
(behavior ()
|
||||
(loop
|
||||
(draw-zone self)
|
||||
(suspend))))
|
||||
|
||||
(defstate player-inside (objective-zone)
|
||||
:virtual #t
|
||||
:trans
|
||||
(behavior ()
|
||||
;; Check to see if we have entered the zone
|
||||
(let ((min-point-x (fmin (-> self v1 x) (-> self v2 x)))
|
||||
(min-point-y (fmin (-> self v1 y) (-> self v2 y)))
|
||||
(min-point-z (fmin (-> self v1 z) (-> self v2 z)))
|
||||
(max-point-x (fmax (-> self v1 x) (-> self v2 x)))
|
||||
(max-point-y (fmax (-> self v1 y) (-> self v2 y)))
|
||||
(max-point-z (fmax (-> self v1 z) (-> self v2 z)))
|
||||
(pos (target-pos 0)))
|
||||
(when (not (and (and (<= min-point-x (-> pos x)) (<= (-> pos x) max-point-x))
|
||||
(and (<= min-point-y (-> pos y)) (<= (-> pos y) max-point-y))
|
||||
(and (<= min-point-z (-> pos z)) (<= (-> pos z) max-point-z))))
|
||||
(when (nonzero? (-> self on-exit))
|
||||
((-> self on-exit)))
|
||||
(go-virtual waiting-for-player))))
|
||||
:code
|
||||
(behavior ()
|
||||
(loop
|
||||
(draw-zone self)
|
||||
(suspend))))
|
||||
|
||||
(defbehavior objective-zone-init-by-other objective-zone ((start? symbol) (params objective-zone-init-params))
|
||||
(set! (-> self start?) start?)
|
||||
(vector-copy! (-> self v1) (-> params v1))
|
||||
(vector-copy! (-> self v2) (-> params v2))
|
||||
(go-virtual waiting-for-player))
|
||||
|
||||
(defmethod draw-info ((this speedrun-practice-objective))
|
||||
(clear *temp-string*)
|
||||
(clear *pc-encoded-temp-string*)
|
||||
(pc-sr-mode-get-practice-entry-name (-> this index) *pc-encoded-temp-string*)
|
||||
(format *temp-string* "<COLOR_WHITE>Practicing: <COLOR_GREEN>~S~%" *pc-encoded-temp-string*)
|
||||
(if (> (pc-sr-mode-get-practice-entry-history-attempts (-> this index)) 0)
|
||||
(format *temp-string*
|
||||
"<COLOR_WHITE>History: <COLOR_GREEN>~D<COLOR_WHITE>/~D (~,,2f%)~%"
|
||||
(pc-sr-mode-get-practice-entry-history-success (-> this index))
|
||||
(pc-sr-mode-get-practice-entry-history-attempts (-> this index))
|
||||
(* 100.0
|
||||
(/ (the float (pc-sr-mode-get-practice-entry-history-success (-> this index)))
|
||||
(the float (pc-sr-mode-get-practice-entry-history-attempts (-> this index))))))
|
||||
(format *temp-string* "<COLOR_WHITE>History: --~%"))
|
||||
(if (> (pc-sr-mode-get-practice-entry-session-attempts (-> this index)) 0)
|
||||
(format *temp-string*
|
||||
"<COLOR_WHITE>Session: <COLOR_GREEN>~D<COLOR_WHITE>/~D (~,,2f%)~%"
|
||||
(pc-sr-mode-get-practice-entry-session-success (-> this index))
|
||||
(pc-sr-mode-get-practice-entry-session-attempts (-> this index))
|
||||
(* 100.0
|
||||
(/ (the float (pc-sr-mode-get-practice-entry-session-success (-> this index)))
|
||||
(the float (pc-sr-mode-get-practice-entry-session-attempts (-> this index))))))
|
||||
(format *temp-string* "<COLOR_WHITE>Session: --~%"))
|
||||
(pc-sr-mode-get-practice-entry-avg-time (-> this index) *pc-encoded-temp-string*)
|
||||
(format *temp-string* "<COLOR_WHITE>Average Time: <COLOR_GREEN>~Ss~%" *pc-encoded-temp-string*)
|
||||
(pc-sr-mode-get-practice-entry-fastest-time (-> this index) *pc-encoded-temp-string*)
|
||||
(format *temp-string* "<COLOR_WHITE>Fastest Time: <COLOR_GREEN>~Ss~%" *pc-encoded-temp-string*)
|
||||
(format *temp-string* "<COLOR_WHITE>\c91 L3: Reset~%")
|
||||
(pc-encode-utf8-string *temp-string* *pc-encoded-temp-string*)
|
||||
(with-dma-buffer-add-bucket ((buf (-> (current-frame) global-buf)) (bucket-id debug-no-zbuf2))
|
||||
;; reset bucket settings prior to drawing - font won't do this for us, and
|
||||
;; draw-raw-image can sometimes mess them up. (intro sequence)
|
||||
(dma-buffer-add-gs-set-flusha buf
|
||||
(alpha-1 (new 'static 'gs-alpha :b #x1 :d #x1))
|
||||
(tex1-1 (new 'static 'gs-tex1 :mmag #x1 :mmin #x1)))
|
||||
(let ((font-ctx (new 'stack 'font-context *font-default-matrix* 510 20 0.0 (font-color default) (font-flags right shadow kerning large))))
|
||||
(set! (-> font-ctx scale) 0.325)
|
||||
(draw-string-adv *pc-encoded-temp-string* buf font-ctx))))
|
||||
|
||||
(defmethod reset! ((this speedrun-practice-objective))
|
||||
;; record attempt if attempt was started
|
||||
(when (-> *speedrun-info* waiting-to-record-practice-attempt?)
|
||||
(pc-sr-mode-record-practice-entry-attempt! (-> this index)
|
||||
#f
|
||||
(&-> (the speedrun-timer (ppointer->process (-> *speedrun-manager* 0 timer))) recorded-time)))
|
||||
;; TODO - load checkpoint if not already in that checkpoint
|
||||
;; TODO - set features / cheats / completed-task / etc
|
||||
;; Update player position
|
||||
(vector-copy! (-> *target* root trans) (-> this starting-position))
|
||||
(vector-copy! (-> *target* root quat) (-> this starting-rotation))
|
||||
;; - get off jetboard and reset speed
|
||||
(vector-copy! (-> *target* control transv) *zero-vector*)
|
||||
(send-event *target* 'change-mode 'normal)
|
||||
;; Update camera position and rotation
|
||||
(vector-copy! (-> *camera-combiner* trans) (-> this starting-camera-position))
|
||||
(matrix-identity! (-> *camera-combiner* inv-camera-rot))
|
||||
(matrix-copy! (-> *camera-combiner* inv-camera-rot) (-> this starting-camera-rotation))
|
||||
(process-spawn-function process
|
||||
(lambda :behavior process ()
|
||||
(suspend)
|
||||
(send-event *camera* 'teleport)
|
||||
(deactivate self)))
|
||||
(cam-master-activate-slave #f))
|
||||
|
||||
(define *speedrun-popup-menu-entries*
|
||||
(new 'static
|
||||
'boxed-array
|
||||
:type
|
||||
popup-menu-entry
|
||||
(new 'static
|
||||
'popup-menu-button
|
||||
:label "Reset"
|
||||
:on-confirm
|
||||
(lambda ()
|
||||
(send-event (ppointer->process *speedrun-manager*) 'invoke (speedrun-menu-command reset))
|
||||
(send-event (-> *speedrun-manager* 0 popup-menu 0) 'close-menu)))
|
||||
(new 'static
|
||||
'popup-menu-submenu
|
||||
:label "Built-in Category Select"
|
||||
:entries
|
||||
(new 'static
|
||||
'boxed-array
|
||||
:type
|
||||
popup-menu-entry
|
||||
(new 'static
|
||||
'popup-menu-flag
|
||||
:label "Normal"
|
||||
:on-confirm
|
||||
(lambda ()
|
||||
(set-category! *speedrun-info* (speedrun-category newgame-normal)))
|
||||
:is-toggled?
|
||||
(lambda ()
|
||||
(= (-> *speedrun-info* category) (speedrun-category newgame-normal))))
|
||||
(new 'static
|
||||
'popup-menu-flag
|
||||
:label "Hero Mode"
|
||||
:on-confirm
|
||||
(lambda ()
|
||||
(set-category! *speedrun-info* (speedrun-category newgame-heromode)))
|
||||
:is-toggled?
|
||||
(lambda ()
|
||||
(= (-> *speedrun-info* category) (speedrun-category newgame-heromode))))
|
||||
(new 'static
|
||||
'popup-menu-flag
|
||||
:label "All Cheats Allowed"
|
||||
:on-confirm
|
||||
(lambda ()
|
||||
(set-category! *speedrun-info* (speedrun-category all-cheats-allowed)))
|
||||
:is-toggled?
|
||||
(lambda ()
|
||||
(= (-> *speedrun-info* category) (speedrun-category all-cheats-allowed))))))
|
||||
(new 'static
|
||||
'popup-menu-dynamic-submenu
|
||||
:label "Custom Category Select"
|
||||
:get-length
|
||||
(lambda ()
|
||||
(pc-sr-mode-get-custom-category-amount))
|
||||
:get-entry-label
|
||||
(lambda ((index int) (str-dest string))
|
||||
(pc-sr-mode-get-custom-category-name index str-dest))
|
||||
:on-entry-confirm
|
||||
(lambda ((index int))
|
||||
;; hydrate from cpp
|
||||
(pc-sr-mode-init-custom-category-info! index (-> *speedrun-info* active-custom-category))
|
||||
(set-category! *speedrun-info* (speedrun-category custom)))
|
||||
:entry-selected?
|
||||
(lambda ((index int))
|
||||
(and (= (-> *speedrun-info* category) (speedrun-category custom))
|
||||
(= index (-> *speedrun-info* active-custom-category index)))))
|
||||
;; TODO - disabled until finalized
|
||||
; (new 'static
|
||||
; 'popup-menu-dynamic-submenu
|
||||
; :label "Practice select"
|
||||
; :entry-disabled?
|
||||
; (lambda ()
|
||||
; (not (-> *speedrun-info* practicing?)))
|
||||
; :get-length
|
||||
; (lambda ()
|
||||
; (pc-sr-mode-get-practice-entries-amount))
|
||||
; :get-entry-label
|
||||
; (lambda ((index int) (str-dest string))
|
||||
; (pc-sr-mode-get-practice-entry-name index str-dest))
|
||||
; :on-entry-confirm
|
||||
; (lambda ((index int))
|
||||
; ;; turn on timer
|
||||
; (set! (-> (the speedrun-timer (ppointer->process (-> *speedrun-manager* 0 timer))) draw?) #t)
|
||||
; ;; tear down old processes
|
||||
; (when (nonzero? (-> *speedrun-info* active-practice-objective start-zone))
|
||||
; (deactivate (-> *speedrun-info* active-practice-objective start-zone 0)))
|
||||
; (when (nonzero? (-> *speedrun-info* active-practice-objective end-zone))
|
||||
; (deactivate (-> *speedrun-info* active-practice-objective end-zone 0)))
|
||||
; ;; init from cpp
|
||||
; (pc-sr-mode-init-practice-info! index (-> *speedrun-info* active-practice-objective))
|
||||
; ;; startup new processes
|
||||
; (set! (-> *speedrun-info* active-practice-objective start-zone)
|
||||
; (the (pointer objective-zone)
|
||||
; (process-spawn objective-zone #t (-> *speedrun-info* active-practice-objective start-zone-init-params))))
|
||||
; (set! (-> *speedrun-info* active-practice-objective start-zone 0 on-exit)
|
||||
; (lambda ()
|
||||
; (start! (the speedrun-timer (ppointer->process (-> *speedrun-manager* 0 timer))))
|
||||
; (set! (-> *speedrun-info* waiting-to-record-practice-attempt?) #t)
|
||||
; (none)))
|
||||
; (set! (-> *speedrun-info* active-practice-objective start-zone 0 on-enter)
|
||||
; (lambda ()
|
||||
; (when (and *target* (>= (-> *target* control ctrl-xz-vel) (meters 30.0)))
|
||||
; (vector-copy! (-> *target* control transv) *zero-vector*))
|
||||
; (set! (-> *speedrun-info* waiting-to-record-practice-attempt?) #f)
|
||||
; (reset! (the speedrun-timer (ppointer->process (-> *speedrun-manager* 0 timer))))
|
||||
; (none)))
|
||||
; (when (= 0 (-> *speedrun-info* active-practice-objective end-task))
|
||||
; (set! (-> *speedrun-info* active-practice-objective end-zone)
|
||||
; (the (pointer objective-zone)
|
||||
; (process-spawn objective-zone #f (-> *speedrun-info* active-practice-objective end-zone-init-params))))
|
||||
; (set! (-> *speedrun-info* active-practice-objective end-zone 0 on-enter)
|
||||
; (lambda ()
|
||||
; (when (-> *speedrun-info* waiting-to-record-practice-attempt?)
|
||||
; (stop! (the speedrun-timer (ppointer->process (-> *speedrun-manager* 0 timer))))
|
||||
; (if (pc-sr-mode-record-practice-entry-attempt! (-> *speedrun-info* active-practice-objective index)
|
||||
; #t
|
||||
; (&-> (the speedrun-timer (ppointer->process (-> *speedrun-manager* 0 timer))) recorded-time))
|
||||
; (sound-play "skill-pickup")
|
||||
; (sound-play "menu-pick"))
|
||||
; (set! (-> *speedrun-info* waiting-to-record-practice-attempt?) #f))
|
||||
; (none))))
|
||||
; (set! (-> *speedrun-info* practicing?) #t)
|
||||
; (reset! (-> *speedrun-info* active-practice-objective))
|
||||
; (set-master-mode 'game)
|
||||
; (send-event (ppointer->process (-> *speedrun-manager* 0 popup-menu)) 'close-menu))
|
||||
; :entry-selected?
|
||||
; (lambda ((index int))
|
||||
; (and (-> *speedrun-info* practicing?) (= index (-> *speedrun-info* active-practice-objective index)))))
|
||||
; (new 'static
|
||||
; 'popup-menu-button
|
||||
; :label "Stop practicing"
|
||||
; :entry-disabled?
|
||||
; (lambda ()
|
||||
; (not (-> *speedrun-info* practicing?)))
|
||||
; :on-confirm
|
||||
; (lambda ()
|
||||
; (when (-> *speedrun-info* practicing?)
|
||||
; (when (nonzero? (-> *speedrun-info* active-practice-objective start-zone))
|
||||
; (deactivate (-> *speedrun-info* active-practice-objective start-zone 0)))
|
||||
; (when (nonzero? (-> *speedrun-info* active-practice-objective end-zone))
|
||||
; (deactivate (-> *speedrun-info* active-practice-objective end-zone 0))))
|
||||
; (set! (-> *speedrun-info* practicing?) #f)
|
||||
; (set! (-> (the speedrun-timer (ppointer->process (-> *speedrun-manager* 0 timer))) draw?) #f)))
|
||||
(new 'static
|
||||
'popup-menu-submenu
|
||||
:label "Tools"
|
||||
:entries
|
||||
(new 'static
|
||||
'boxed-array
|
||||
:type
|
||||
popup-menu-entry
|
||||
(new 'static
|
||||
'popup-menu-submenu
|
||||
:label "Create custom category"
|
||||
:entries
|
||||
(new 'static
|
||||
'boxed-array
|
||||
:type
|
||||
popup-menu-entry
|
||||
(new 'static
|
||||
'popup-menu-dynamic-submenu
|
||||
:label "Select secrets"
|
||||
:get-length
|
||||
(lambda ()
|
||||
58)
|
||||
:get-entry-label
|
||||
(lambda ((index int) (str-dest string))
|
||||
(copy-string<-string str-dest (bitfield->string game-secrets index)))
|
||||
:on-entry-confirm
|
||||
(lambda ((index int))
|
||||
(logxor! (-> *speedrun-info* dump-custom-category secrets) (shl 1 index)))
|
||||
:entry-selected?
|
||||
(lambda ((index int))
|
||||
(logtest? (-> *speedrun-info* dump-custom-category secrets) (shl 1 index)))
|
||||
:on-reset
|
||||
(lambda ()
|
||||
(set! (-> *speedrun-info* dump-custom-category secrets) (game-secrets))))
|
||||
(new 'static
|
||||
'popup-menu-dynamic-submenu
|
||||
:label "Select features"
|
||||
:get-length
|
||||
(lambda ()
|
||||
58)
|
||||
:get-entry-label
|
||||
(lambda ((index int) (str-dest string))
|
||||
(copy-string<-string str-dest (bitfield->string game-feature index)))
|
||||
:on-entry-confirm
|
||||
(lambda ((index int))
|
||||
(logxor! (-> *speedrun-info* dump-custom-category features) (shl 1 index)))
|
||||
:entry-selected?
|
||||
(lambda ((index int))
|
||||
(logtest? (-> *speedrun-info* dump-custom-category features) (shl 1 index)))
|
||||
:on-reset
|
||||
(lambda ()
|
||||
(set! (-> *speedrun-info* dump-custom-category features) (game-feature))))
|
||||
(new 'static
|
||||
'popup-menu-dynamic-submenu
|
||||
:label "Select vehicles"
|
||||
:get-length
|
||||
(lambda ()
|
||||
8)
|
||||
:get-entry-label
|
||||
(lambda ((index int) (str-dest string))
|
||||
(copy-string<-string str-dest (bitfield->string game-vehicles index)))
|
||||
:on-entry-confirm
|
||||
(lambda ((index int))
|
||||
(logxor! (-> *speedrun-info* dump-custom-category vehicles) (shl 1 index)))
|
||||
:entry-selected?
|
||||
(lambda ((index int))
|
||||
(logtest? (-> *speedrun-info* dump-custom-category vehicles) (shl 1 index)))
|
||||
:on-reset
|
||||
(lambda ()
|
||||
(set! (-> *speedrun-info* dump-custom-category vehicles) (game-vehicles))))
|
||||
(new 'static
|
||||
'popup-menu-dynamic-submenu
|
||||
:label "Forbid features"
|
||||
:get-length
|
||||
(lambda ()
|
||||
58)
|
||||
:get-entry-label
|
||||
(lambda ((index int) (str-dest string))
|
||||
(copy-string<-string str-dest (bitfield->string game-feature index)))
|
||||
:on-entry-confirm
|
||||
(lambda ((index int))
|
||||
(logxor! (-> *speedrun-info* dump-custom-category forbidden-features) (shl 1 index)))
|
||||
:entry-selected?
|
||||
(lambda ((index int))
|
||||
(logtest? (-> *speedrun-info* dump-custom-category forbidden-features) (shl 1 index)))
|
||||
:on-reset
|
||||
(lambda ()
|
||||
(set! (-> *speedrun-info* dump-custom-category forbidden-features) (game-feature))))
|
||||
(new 'static
|
||||
'popup-menu-dynamic-submenu
|
||||
:label "Select cheats"
|
||||
:get-length
|
||||
(lambda ()
|
||||
17)
|
||||
:get-entry-label
|
||||
(lambda ((index int) (str-dest string))
|
||||
(copy-string<-string str-dest (bitfield->string pc-cheats index)))
|
||||
:on-entry-confirm
|
||||
(lambda ((index int))
|
||||
(logxor! (-> *speedrun-info* dump-custom-category pc-cheats) (shl 1 index)))
|
||||
:entry-selected?
|
||||
(lambda ((index int))
|
||||
(logtest? (-> *speedrun-info* dump-custom-category pc-cheats) (shl 1 index)))
|
||||
:on-reset
|
||||
(lambda ()
|
||||
(set! (-> *speedrun-info* dump-custom-category pc-cheats) (pc-cheats))))
|
||||
(new 'static
|
||||
'popup-menu-dynamic-submenu
|
||||
:label "Select completed task"
|
||||
:get-length
|
||||
(lambda ()
|
||||
(dec (the int (game-task max))))
|
||||
:get-entry-label
|
||||
(lambda ((index int) (str-dest string))
|
||||
(copy-string<-string str-dest (enum->string game-task index)))
|
||||
:on-entry-confirm
|
||||
(lambda ((index int))
|
||||
(set! (-> *speedrun-info* dump-custom-category completed-task) (the game-task index)))
|
||||
:entry-selected?
|
||||
(lambda ((index int))
|
||||
(= (-> *speedrun-info* dump-custom-category completed-task) (the game-task index)))
|
||||
:on-reset
|
||||
(lambda ()
|
||||
(set! (-> *speedrun-info* dump-custom-category completed-task) (game-task none))))
|
||||
(new 'static
|
||||
'popup-menu-button
|
||||
:label "Save new category to file"
|
||||
:on-confirm
|
||||
(lambda ()
|
||||
(pc-sr-mode-dump-new-custom-category (-> *speedrun-info* dump-custom-category))))))))
|
||||
(new 'static
|
||||
'popup-menu-button
|
||||
:label "Exit"
|
||||
:on-confirm
|
||||
(lambda ()
|
||||
(send-event (ppointer->process *speedrun-manager*) 'invoke (speedrun-menu-command exit))))))
|
||||
|
||||
(define *speedrun-manager* (the (pointer speedrun-manager) #f))
|
||||
|
||||
(defbehavior speedrun-manager-init-by-other speedrun-manager ()
|
||||
(process-mask-clear! (-> self mask) menu pause)
|
||||
(set! *speedrun-manager* (the (pointer speedrun-manager) (process->ppointer self)))
|
||||
(set! (-> self popup-menu) (process-spawn popup-menu "Speedrun Menu" *speedrun-popup-menu-entries* :to self))
|
||||
(set! (-> self timer) (process-spawn speedrun-timer :to self))
|
||||
(set! (-> self ignore-menu-toggle?) #f)
|
||||
(set! (-> self opened-with-start?) #f)
|
||||
(set! (-> *speedrun-info* practicing?) #f)
|
||||
(set! (-> *speedrun-info* waiting-to-record-practice-attempt?) #f)
|
||||
(go-virtual idle))
|
||||
|
||||
(defmethod update! ((this speedrun-info))
|
||||
"A per frame update for speedrunning related stuff"
|
||||
;; Ensure the speedrunner menu process is enabled or destroyed
|
||||
(when (and (-> *pc-settings* speedrunner-mode?) (not *speedrun-manager*))
|
||||
(process-spawn speedrun-manager :from *pc-dead-pool* :to *pc-pool*))
|
||||
(when (and (not (-> *pc-settings* speedrunner-mode?)) *speedrun-manager*)
|
||||
(deactivate (-> *speedrun-manager* 0)))
|
||||
;; do speedrunner mode things
|
||||
(when (-> *pc-settings* speedrunner-mode?)
|
||||
;; Update auto-splitter struct
|
||||
(update! *autosplit-info-jak3*)
|
||||
;; see if we should stop drawing the run info (when you finish arena training)
|
||||
(when (and (!= (-> this category) (speedrun-category custom)) (task-complete? *game-info* (game-task arena-training-1)))
|
||||
(false! (-> this display-run-info?)))
|
||||
;; Draw info to the screen
|
||||
(when (and (not (-> *speedrun-info* practicing?)) (-> this display-run-info?))
|
||||
(draw-run-info this))
|
||||
;; enforce settings even if they've changed them
|
||||
(enforce-settings! this)
|
||||
;; draw objective info if practicing
|
||||
(when (-> *speedrun-info* practicing?)
|
||||
(draw-info (-> this active-practice-objective)))))
|
||||
|
||||
(defmethod draw-run-info ((this speedrun-info))
|
||||
"Draw speedrun related settings in the bottom left corner"
|
||||
(when (and (-> *pc-settings* speedrunner-mode?) (-> this display-run-info?))
|
||||
(clear *temp-string*)
|
||||
(clear *pc-encoded-temp-string*)
|
||||
(clear *pc-cpp-temp-string*)
|
||||
(cond
|
||||
((= (-> this category) (speedrun-category custom))
|
||||
(pc-sr-mode-get-custom-category-name (-> this active-custom-category index) *pc-cpp-temp-string*)
|
||||
(format *temp-string*
|
||||
"<COLOR_WHITE>Category: <COLOR_GREEN>~S~%<COLOR_WHITE>Secrets: <COLOR_GREEN>~D~%<COLOR_WHITE>Features: <COLOR_GREEN>~D~%<COLOR_WHITE>Forbidden Features: <COLOR_GREEN>~D~%<COLOR_WHITE>Cheats: <COLOR_GREEN>~D~%<COLOR_WHITE>Version: <COLOR_GREEN>~S~%"
|
||||
*pc-cpp-temp-string*
|
||||
(-> this active-custom-category secrets)
|
||||
(-> this active-custom-category features)
|
||||
(-> this active-custom-category forbidden-features)
|
||||
(-> this active-custom-category pc-cheats)
|
||||
*pc-settings-built-sha*))
|
||||
(else
|
||||
(format *temp-string*
|
||||
"<COLOR_WHITE>Category: <COLOR_GREEN>~S~%<COLOR_WHITE>PC Cheats: <COLOR_GREEN>~S~%<COLOR_WHITE>Frame Rate: <COLOR_GREEN>~D~%<COLOR_WHITE>PS2 Actor Vis?: <COLOR_GREEN>~S~%<COLOR_WHITE>Version: <COLOR_GREEN>~S~%"
|
||||
(enum->string speedrun-category (-> this category))
|
||||
(if (= (-> *pc-settings* cheats) (pc-cheats)) "None" (pc-cheats->string (-> *pc-settings* cheats) *temp-string2*))
|
||||
(-> *pc-settings* target-fps)
|
||||
(if (-> *pc-settings* ps2-actor-vis?) "true" "false")
|
||||
*pc-settings-built-sha*)))
|
||||
(pc-encode-utf8-string *temp-string* *pc-encoded-temp-string*)
|
||||
(with-dma-buffer-add-bucket ((buf (-> (current-frame) global-buf)) (bucket-id debug-no-zbuf2))
|
||||
;; reset bucket settings prior to drawing - font won't do this for us, and
|
||||
;; draw-raw-image can sometimes mess them up. (intro sequence)
|
||||
(dma-buffer-add-gs-set-flusha buf
|
||||
(alpha-1 (new 'static 'gs-alpha :b #x1 :d #x1))
|
||||
(tex1-1 (new 'static 'gs-tex1 :mmag #x1 :mmin #x1)))
|
||||
(let ((font-ctx (new 'stack
|
||||
'font-context
|
||||
*font-default-matrix*
|
||||
510
|
||||
(if (= (-> this category) (speedrun-category custom)) 355 365)
|
||||
0.0
|
||||
(font-color default)
|
||||
(font-flags right shadow kerning large))))
|
||||
(set! (-> font-ctx scale) 0.325)
|
||||
(draw-string-adv *pc-encoded-temp-string* buf font-ctx)))))
|
||||
|
||||
;; Speedrun Menu
|
||||
|
||||
(defmethod deactivate ((this speedrun-manager))
|
||||
(set! *speedrun-manager* (the (pointer speedrun-manager) #f))
|
||||
(call-parent-method this))
|
||||
|
||||
(defmethod draw-menu ((this speedrun-manager))
|
||||
;; don't allow the menu to open during blackouts, apparently causes bugs
|
||||
(if (< (-> *game-info* blackout-time) (current-time))
|
||||
;; handle opening and closing the menu
|
||||
(cond
|
||||
((!= (-> *pc-settings* speedrunner-mode-custom-bind) 0)
|
||||
;; the user has let go of the keybind completely or partially, allow the bind to trigger again
|
||||
(when (and (-> this ignore-menu-toggle?)
|
||||
(!= (cpad-hold 0) (logior (cpad-hold 0) (-> *pc-settings* speedrunner-mode-custom-bind))))
|
||||
(false! (-> this ignore-menu-toggle?)))
|
||||
;; bind handler
|
||||
(when (and (not (-> this ignore-menu-toggle?))
|
||||
(= (cpad-hold 0) (logior (cpad-hold 0) (-> *pc-settings* speedrunner-mode-custom-bind))))
|
||||
(send-event (ppointer->process (-> this popup-menu)) 'open-menu)
|
||||
(logclear! (cpad-hold 0) (-> *pc-settings* speedrunner-mode-custom-bind))
|
||||
(logclear! (cpad-pressed 0) (-> *pc-settings* speedrunner-mode-custom-bind))
|
||||
(true! (-> this ignore-menu-toggle?))))
|
||||
(else
|
||||
(when (and (-> this ignore-menu-toggle?)
|
||||
(or (not (cpad-hold? 0 l1)) (not (cpad-hold? 0 r1)))
|
||||
(or (and (-> this opened-with-start?) (not (cpad-hold? 0 start)))
|
||||
(and (not (-> this opened-with-start?)) (not (cpad-hold? 0 select)))))
|
||||
(set! (-> this ignore-menu-toggle?) #f))
|
||||
(when (and (cpad-hold? 0 l1)
|
||||
(cpad-hold? 0 r1)
|
||||
(or (cpad-hold? 0 select) (cpad-hold? 0 start))
|
||||
(not (-> this ignore-menu-toggle?)))
|
||||
(send-event (ppointer->process (-> this popup-menu)) 'open-menu)
|
||||
(cpad-clear! 0 l1 r1)
|
||||
(cond
|
||||
((cpad-hold? 0 select) (cpad-clear! 0 select) (false! (-> this opened-with-start?)))
|
||||
((cpad-hold? 0 start) (cpad-clear! 0 start) (true! (-> this opened-with-start?))))
|
||||
(true! (-> this ignore-menu-toggle?)))))))
|
||||
|
||||
(defstate idle (speedrun-manager)
|
||||
:virtual #t
|
||||
:event
|
||||
(behavior ((proc process) (argc int) (message symbol) (block event-message-block))
|
||||
(case message
|
||||
(('start-run) (set-time! (-> *speedrun-info* run-started-at)))
|
||||
(('invoke)
|
||||
(case (-> block param 0)
|
||||
(((speedrun-menu-command reset)) (start-run! *speedrun-info*))
|
||||
(((speedrun-menu-command exit)) (set-master-mode 'game) (send-event (ppointer->process (-> self popup-menu)) 'close-menu))
|
||||
(else (format 0 "nyi: invoke ~D~%" (-> block param 0)))))))
|
||||
:trans
|
||||
(behavior ()
|
||||
(draw-menu self))
|
||||
:code
|
||||
(behavior ()
|
||||
(until #f
|
||||
(when (and (-> *speedrun-info* practicing?) (cpad-pressed? 0 l3))
|
||||
(reset! (-> *speedrun-info* active-practice-objective)))
|
||||
(when (and (-> *speedrun-info* display-run-info?)
|
||||
(= (-> *speedrun-info* category) (speedrun-category custom))
|
||||
(time-elapsed? (-> *speedrun-info* run-started-at) (seconds 15)))
|
||||
(false! (-> *speedrun-info* display-run-info?)))
|
||||
(suspend))))
|
@ -42,6 +42,10 @@
|
||||
(weather-good)
|
||||
)
|
||||
|
||||
(defun pc-cheats->string ((cheats pc-cheats) (buf object))
|
||||
(bit-enum->string pc-cheats cheats buf)
|
||||
buf)
|
||||
|
||||
;; pc enum for languages. this is the game's languages + custom ones.
|
||||
(defenum pc-language
|
||||
:type uint16
|
||||
@ -72,7 +76,7 @@
|
||||
(custom 999) ;; temp
|
||||
)
|
||||
|
||||
;; The Jak 2 version of the pc-settings object.
|
||||
;; The Jak 3 version of the pc-settings object.
|
||||
(deftype pc-settings-jak3 (pc-settings)
|
||||
(;; cheats
|
||||
(cheats pc-cheats)
|
||||
|
@ -303,9 +303,9 @@
|
||||
(defmethod update-speedrun ((obj pc-settings-jak3))
|
||||
"update speedrun module"
|
||||
;; TODO - update to new with-profiler syntax
|
||||
;; (with-profiler "speedrun-update"
|
||||
;(update! *speedrun-info*)
|
||||
;;)
|
||||
; (with-profiler "speedrun-update"
|
||||
(update! *speedrun-info*)
|
||||
; )
|
||||
(none))
|
||||
|
||||
(defmethod update-video-hacks ((obj pc-settings-jak3))
|
||||
@ -751,7 +751,8 @@
|
||||
|
||||
;; the actor pool for PC processes! it has space for 4 processes, with 16K of space.
|
||||
(define *pc-dead-pool* (new 'global 'dead-pool 4 (* 16 1024) "*pc-dead-pool*"))
|
||||
|
||||
(set! (-> *pc-pool* clock) (-> *display* base-clock))
|
||||
(+! (-> *display* base-clock ref-count) 1)
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
59
goal_src/jak3/pc/util/popup-menu-h.gc
Normal file
59
goal_src/jak3/pc/util/popup-menu-h.gc
Normal file
@ -0,0 +1,59 @@
|
||||
;;-*-Lisp-*-
|
||||
(in-package goal)
|
||||
|
||||
;; A debug-menu style popup menu, a lightweight way to make a context menu that doesn't involve the progress code
|
||||
;; and isn't debug-only
|
||||
|
||||
(define *popup-menu-open* #f)
|
||||
|
||||
(deftype popup-menu-entry (basic)
|
||||
((label string)
|
||||
(entry-disabled? (function symbol))
|
||||
(on-confirm (function none)))
|
||||
(:methods
|
||||
(draw-entry (_type_ font-context dma-buffer symbol) object)))
|
||||
|
||||
;; (deftype popup-menu-label (popup-menu-entry) ())
|
||||
|
||||
(deftype popup-menu-button (popup-menu-entry) ())
|
||||
|
||||
(deftype popup-menu-flag (popup-menu-entry)
|
||||
((is-toggled? (function symbol))))
|
||||
|
||||
(deftype popup-menu-submenu (popup-menu-entry)
|
||||
((entries (array popup-menu-entry))))
|
||||
|
||||
(deftype popup-menu-dynamic-submenu (popup-menu-entry)
|
||||
((get-length (function int))
|
||||
(get-entry-label (function int string none))
|
||||
(on-entry-confirm (function int none))
|
||||
(entry-selected? (function int symbol))
|
||||
(on-reset (function none))))
|
||||
|
||||
(deftype popup-menu-state (structure)
|
||||
((title string)
|
||||
(entries (array popup-menu-entry))
|
||||
(entry-index int32)
|
||||
(dynamic-menu? symbol)
|
||||
(get-dynamic-menu-length (function int))
|
||||
(get-dynamic-menu-entry-label (function int string none))
|
||||
(on-dynamic-menu-entry-confirm (function int none))
|
||||
(dynamic-menu-entry-selected? (function int symbol))
|
||||
(on-dynamic-menu-reset (function none))))
|
||||
|
||||
(deftype popup-menu (process)
|
||||
((title string)
|
||||
(entries (array popup-menu-entry))
|
||||
(menu-states popup-menu-state 10 :inline)
|
||||
(curr-state-index int32)
|
||||
(draw? symbol))
|
||||
(:methods
|
||||
(update-menu! (_type_) object)
|
||||
(draw-menu (_type_) object)
|
||||
(move-up! (_type_ int) object)
|
||||
(move-down! (_type_ int) object)
|
||||
(confirm! (_type_) object)
|
||||
(reset! (_type_) object)
|
||||
(back! (_type_) symbol))
|
||||
(:state-methods
|
||||
idle))
|
289
goal_src/jak3/pc/util/popup-menu.gc
Normal file
289
goal_src/jak3/pc/util/popup-menu.gc
Normal file
@ -0,0 +1,289 @@
|
||||
;;-*-Lisp-*-
|
||||
(in-package goal)
|
||||
|
||||
(defun get-widest-entry ((entries (array popup-menu-entry)) (title string) (font-ctx font-context) (start-index int) (end-index int))
|
||||
(let ((max-len 0.0))
|
||||
(dotimes (i (- end-index start-index))
|
||||
(let ((label-len (-> (get-string-length (-> entries (+ start-index i) label) font-ctx) length)))
|
||||
(when (> label-len max-len)
|
||||
(set! max-len label-len))))
|
||||
(let ((title-len (-> (get-string-length title font-ctx) length)))
|
||||
(when (> title-len max-len)
|
||||
(set! max-len title-len)))
|
||||
(the int max-len)))
|
||||
|
||||
(defun get-widest-dynamic-entry ((get-entry-label (function int string none)) (title string) (font-ctx font-context) (start-index int) (end-index int))
|
||||
(let ((max-len 0.0))
|
||||
(dotimes (i (- end-index start-index))
|
||||
(get-entry-label (+ start-index i) *pc-encoded-temp-string*)
|
||||
(let ((label-len (-> (get-string-length *pc-encoded-temp-string* font-ctx) length)))
|
||||
(when (> label-len max-len)
|
||||
(set! max-len label-len))))
|
||||
(let ((title-len (-> (get-string-length title font-ctx) length)))
|
||||
(when (> title-len max-len)
|
||||
(set! max-len title-len)))
|
||||
(the int max-len)))
|
||||
|
||||
(defmethod draw-entry ((this popup-menu-entry) (font-ctx font-context) (dma-buf dma-buffer) (hovering? symbol))
|
||||
(let ((old-x (-> font-ctx origin x))
|
||||
(old-y (-> font-ctx origin y))
|
||||
(old-color (-> font-ctx color)))
|
||||
(pc-encode-utf8-string (-> this label) *pc-encoded-temp-string*)
|
||||
(when hovering?
|
||||
(set! (-> font-ctx color) (font-color cyan)))
|
||||
(when (and (nonzero? (-> this entry-disabled?)) ((-> this entry-disabled?)))
|
||||
(set! (-> font-ctx color) (font-color menu-parent)))
|
||||
(draw-string-adv *pc-encoded-temp-string* dma-buf font-ctx)
|
||||
(set! (-> font-ctx origin x) old-x)
|
||||
(set! (-> font-ctx origin y) old-y)
|
||||
(set! (-> font-ctx color) old-color)))
|
||||
|
||||
(defmethod draw-entry ((this popup-menu-flag) (font-ctx font-context) (dma-buf dma-buffer) (hovering? symbol))
|
||||
(let ((old-x (-> font-ctx origin x))
|
||||
(old-y (-> font-ctx origin y))
|
||||
(old-color (-> font-ctx color)))
|
||||
(when ((-> this is-toggled?))
|
||||
(set! (-> font-ctx color) (font-color green))
|
||||
(set! (-> font-ctx origin x) (- old-x 6.0))
|
||||
(draw-string-adv "\c86" dma-buf font-ctx)
|
||||
(set! (-> font-ctx origin x) old-x)
|
||||
(set! (-> font-ctx origin y) old-y)
|
||||
(set! (-> font-ctx color) old-color))
|
||||
(pc-encode-utf8-string (-> this label) *pc-encoded-temp-string*)
|
||||
(when hovering?
|
||||
(set! (-> font-ctx color) (font-color cyan)))
|
||||
(draw-string-adv *pc-encoded-temp-string* dma-buf font-ctx)
|
||||
(set! (-> font-ctx origin x) old-x)
|
||||
(set! (-> font-ctx origin y) old-y)
|
||||
(set! (-> font-ctx color) old-color)))
|
||||
|
||||
(defun draw-dynamic-entry ((entry-id int) (get-label (function int string none)) (entry-selected? (function int symbol)) (font-ctx font-context) (dma-buf dma-buffer) (hovering? symbol))
|
||||
(let ((old-x (-> font-ctx origin x))
|
||||
(old-y (-> font-ctx origin y))
|
||||
(old-color (-> font-ctx color)))
|
||||
(when (entry-selected? entry-id)
|
||||
(set! (-> font-ctx color) (font-color green))
|
||||
(set! (-> font-ctx origin x) (- old-x 6.0))
|
||||
(draw-string-adv "\c86" dma-buf font-ctx)
|
||||
(set! (-> font-ctx origin x) old-x)
|
||||
(set! (-> font-ctx origin y) old-y)
|
||||
(set! (-> font-ctx color) old-color))
|
||||
(clear *pc-encoded-temp-string*)
|
||||
(get-label entry-id *pc-encoded-temp-string*)
|
||||
(pc-encode-utf8-string *pc-encoded-temp-string* *pc-encoded-temp-string*)
|
||||
(when hovering?
|
||||
(set! (-> font-ctx color) (font-color cyan)))
|
||||
(draw-string-adv *pc-encoded-temp-string* dma-buf font-ctx)
|
||||
(set! (-> font-ctx origin x) old-x)
|
||||
(set! (-> font-ctx origin y) old-y)
|
||||
(set! (-> font-ctx color) old-color)))
|
||||
|
||||
(defmethod draw-menu ((this popup-menu))
|
||||
(let ((font-ctx (new 'debug 'font-context *font-default-matrix* 0 0 0.0 (font-color default) (font-flags shadow kerning large)))
|
||||
(page-title (-> this menu-states (-> this curr-state-index) title))
|
||||
(dynamic-menu? (-> this menu-states (-> this curr-state-index) dynamic-menu?))
|
||||
(can-reset? (and (nonzero? (-> this menu-states (-> this curr-state-index) on-dynamic-menu-reset))
|
||||
(-> this menu-states (-> this curr-state-index) on-dynamic-menu-reset))))
|
||||
(set! (-> font-ctx scale) 0.25)
|
||||
(set! (-> font-ctx origin x) 15.0)
|
||||
(set! (-> font-ctx origin y) 75.0)
|
||||
(let* ((entry-count (if dynamic-menu?
|
||||
((-> this menu-states (-> this curr-state-index) get-dynamic-menu-length))
|
||||
(-> this menu-states (-> this curr-state-index) entries length)))
|
||||
(current-index (-> this menu-states (-> this curr-state-index) entry-index))
|
||||
(start-index (* (/ current-index 15) 15))
|
||||
(end-index (min (+ start-index 15) entry-count))
|
||||
(entry-count-to-render (- end-index start-index))
|
||||
(menu-rows (if (< end-index entry-count) (inc entry-count-to-render) entry-count-to-render))
|
||||
(widest-entry (if dynamic-menu?
|
||||
(get-widest-dynamic-entry (-> this menu-states (-> this curr-state-index) get-dynamic-menu-entry-label) page-title font-ctx start-index end-index)
|
||||
(get-widest-entry (-> this menu-states (-> this curr-state-index) entries) page-title font-ctx start-index end-index))))
|
||||
(with-dma-buffer-add-bucket ((buf (-> (current-frame) global-buf)) (bucket-id debug-no-zbuf2))
|
||||
;; background border
|
||||
(draw-sprite2d-xy buf
|
||||
6
|
||||
64
|
||||
(+ 17 widest-entry) ;; width
|
||||
(+ 17 (* 15 (inc menu-rows))) ;; height
|
||||
(static-rgba 255 255 255 75)
|
||||
#x3fffff)
|
||||
;; background
|
||||
(draw-sprite2d-xy buf
|
||||
7
|
||||
65
|
||||
(+ 15 widest-entry) ;; width
|
||||
(+ 15 (* 15 (inc menu-rows))) ;; height
|
||||
(static-rgba 0 0 0 255)
|
||||
#x3fffff)
|
||||
;; title
|
||||
;; TODO - function
|
||||
(pc-encode-utf8-string page-title *pc-encoded-temp-string*)
|
||||
(set! (-> font-ctx color) (font-color menu-parent))
|
||||
(let ((old-x (-> font-ctx origin x))
|
||||
(old-y (-> font-ctx origin y)))
|
||||
(draw-string-adv *pc-encoded-temp-string* buf font-ctx)
|
||||
(set! (-> font-ctx origin x) old-x)
|
||||
(set! (-> font-ctx origin y) old-y))
|
||||
(set! (-> font-ctx color) (font-color default))
|
||||
(set! (-> font-ctx origin y) (+ 15.0 (-> font-ctx origin y)))
|
||||
;; menu contents
|
||||
(dotimes (i entry-count-to-render)
|
||||
(if dynamic-menu?
|
||||
(draw-dynamic-entry (+ i start-index)
|
||||
(-> this menu-states (-> this curr-state-index) get-dynamic-menu-entry-label)
|
||||
(-> this menu-states (-> this curr-state-index) dynamic-menu-entry-selected?)
|
||||
font-ctx
|
||||
buf
|
||||
(= (+ i start-index) current-index))
|
||||
(draw-entry (-> (-> this menu-states (-> this curr-state-index) entries) i) font-ctx buf (= (+ i start-index) current-index)))
|
||||
(set! (-> font-ctx origin y) (+ 15.0 (-> font-ctx origin y))))
|
||||
(when (< end-index entry-count)
|
||||
(clear *pc-encoded-temp-string*)
|
||||
(format *pc-encoded-temp-string* "~D more..." (- entry-count end-index))
|
||||
(pc-encode-utf8-string *pc-encoded-temp-string* *pc-encoded-temp-string*)
|
||||
(set! (-> font-ctx color) (font-color menu-parent))
|
||||
(let ((old-x (-> font-ctx origin x))
|
||||
(old-y (-> font-ctx origin y)))
|
||||
(draw-string-adv *pc-encoded-temp-string* buf font-ctx)
|
||||
(set! (-> font-ctx origin x) old-x)
|
||||
(set! (-> font-ctx origin y) old-y))
|
||||
(set! (-> font-ctx color) (font-color default))
|
||||
(set! (-> font-ctx origin y) (+ 15.0 (-> font-ctx origin y))))
|
||||
;; button prompts
|
||||
(cond
|
||||
((= (-> this curr-state-index) 0)
|
||||
(pc-encode-utf8-string "<PAD_CIRCLE> Exit" *pc-encoded-temp-string*)
|
||||
)
|
||||
((and dynamic-menu? can-reset?)
|
||||
(pc-encode-utf8-string "<PAD_SQUARE> Reset / <PAD_CIRCLE> Back" *pc-encoded-temp-string*))
|
||||
(else
|
||||
(pc-encode-utf8-string "<PAD_CIRCLE> Back" *pc-encoded-temp-string*))
|
||||
)
|
||||
(set! (-> font-ctx origin x) (- 25.0 (-> font-ctx origin x)))
|
||||
(set! (-> font-ctx origin y) (+ 10.0 (-> font-ctx origin y)))
|
||||
(let ((old-x (-> font-ctx origin x))
|
||||
(old-y (-> font-ctx origin y)))
|
||||
(draw-string-adv *pc-encoded-temp-string* buf font-ctx)
|
||||
(set! (-> font-ctx origin x) old-x)
|
||||
(set! (-> font-ctx origin y) old-y))))))
|
||||
|
||||
(defmethod move-up! ((this popup-menu) (amount int))
|
||||
(let* ((curr-state (-> this menu-states (-> this curr-state-index)))
|
||||
(new-index (max 0 (-! (-> curr-state entry-index) amount))))
|
||||
;; dynamic menus don't have options that are disabled (just dont include them)
|
||||
(when (not (-> curr-state dynamic-menu?))
|
||||
(let ((entry (-> curr-state entries new-index)))
|
||||
(when (and (nonzero? (-> entry entry-disabled?)) ((-> entry entry-disabled?)))
|
||||
(set! new-index (max 0 (dec new-index))))))
|
||||
(set! (-> curr-state entry-index) new-index)))
|
||||
|
||||
(defmethod move-down! ((this popup-menu) (amount int))
|
||||
(let* ((curr-state (-> this menu-states (-> this curr-state-index)))
|
||||
(max-entries (if (-> curr-state dynamic-menu?)
|
||||
((-> curr-state get-dynamic-menu-length))
|
||||
(-> curr-state entries length)))
|
||||
(new-index (min (dec max-entries) (+! (-> curr-state entry-index) amount))))
|
||||
;; dynamic menus don't have options that are disabled (just dont include them)
|
||||
(when (not (-> curr-state dynamic-menu?))
|
||||
(let ((entry (-> curr-state entries new-index)))
|
||||
(when (and (nonzero? (-> entry entry-disabled?)) ((-> entry entry-disabled?)))
|
||||
(set! new-index (min (dec max-entries) (inc new-index))))))
|
||||
(set! (-> curr-state entry-index) new-index)))
|
||||
|
||||
(defmethod confirm! ((this popup-menu))
|
||||
(let* ((menu-state (-> this menu-states (-> this curr-state-index)))
|
||||
(dynamic-menu? (-> menu-state dynamic-menu?)))
|
||||
(if dynamic-menu?
|
||||
((-> menu-state on-dynamic-menu-entry-confirm) (-> menu-state entry-index))
|
||||
(let ((entry (-> menu-state entries (-> menu-state entry-index))))
|
||||
(cond
|
||||
((type? entry popup-menu-dynamic-submenu)
|
||||
;; TODO - dont allow more than 10 nested menus
|
||||
(inc! (-> this curr-state-index))
|
||||
(set! (-> this menu-states (-> this curr-state-index) entry-index) 0)
|
||||
(set! (-> this menu-states (-> this curr-state-index) title) (-> entry label))
|
||||
(true! (-> this menu-states (-> this curr-state-index) dynamic-menu?))
|
||||
(set! (-> this menu-states (-> this curr-state-index) get-dynamic-menu-length) (-> (the-as popup-menu-dynamic-submenu entry) get-length))
|
||||
(set! (-> this menu-states (-> this curr-state-index) get-dynamic-menu-entry-label) (-> (the-as popup-menu-dynamic-submenu entry) get-entry-label))
|
||||
(set! (-> this menu-states (-> this curr-state-index) on-dynamic-menu-entry-confirm) (-> (the-as popup-menu-dynamic-submenu entry) on-entry-confirm))
|
||||
(set! (-> this menu-states (-> this curr-state-index) dynamic-menu-entry-selected?) (-> (the-as popup-menu-dynamic-submenu entry) entry-selected?))
|
||||
(set! (-> this menu-states (-> this curr-state-index) on-dynamic-menu-reset) (-> (the-as popup-menu-dynamic-submenu entry) on-reset)))
|
||||
((type? entry popup-menu-submenu)
|
||||
;; TODO - dont allow more than 10 nested menus
|
||||
(inc! (-> this curr-state-index))
|
||||
(set! (-> this menu-states (-> this curr-state-index) entry-index) 0)
|
||||
(false! (-> this menu-states (-> this curr-state-index) dynamic-menu?))
|
||||
(set! (-> this menu-states (-> this curr-state-index) title) (-> entry label))
|
||||
(set! (-> this menu-states (-> this curr-state-index) entries) (-> (the-as popup-menu-submenu entry) entries)))
|
||||
(else
|
||||
((-> entry on-confirm)))))))
|
||||
(sound-play "menu-pick"))
|
||||
|
||||
(defmethod reset! ((this popup-menu))
|
||||
(let* ((menu-state (-> this menu-states (-> this curr-state-index))))
|
||||
(when (and (-> menu-state dynamic-menu?)
|
||||
(nonzero? (-> menu-state on-dynamic-menu-reset))
|
||||
(-> menu-state on-dynamic-menu-reset)) ;; dont call if theres no function defined
|
||||
((-> menu-state on-dynamic-menu-reset))
|
||||
(sound-play "menu-pick"))))
|
||||
|
||||
(defmethod back! ((this popup-menu))
|
||||
(sound-play "menu-pick")
|
||||
(cond
|
||||
((<= (-> this curr-state-index) 0)
|
||||
#t)
|
||||
(else
|
||||
(dec! (-> this curr-state-index))
|
||||
#f)))
|
||||
|
||||
(defbehavior popup-menu-init-by-other popup-menu ((title string) (entries (array popup-menu-entry)))
|
||||
(process-mask-clear! (-> self mask) menu pause)
|
||||
(set! (-> self curr-state-index) 0)
|
||||
(set! (-> self menu-states 0 title) title)
|
||||
(set! (-> self menu-states 0 entries) entries)
|
||||
(set! (-> self menu-states 0 entry-index) 0)
|
||||
(false! (-> self menu-states 0 dynamic-menu?))
|
||||
(false! (-> self draw?))
|
||||
(go-virtual idle))
|
||||
|
||||
(defbehavior popup-menu-event-handler popup-menu ((proc process) (argc int) (message symbol) (block event-message-block))
|
||||
(case message
|
||||
(('open-menu)
|
||||
(set-master-mode 'menu)
|
||||
(true! (-> self draw?))
|
||||
(true! *popup-menu-open*)
|
||||
(sound-play "menu-pick"))
|
||||
(('close-menu)
|
||||
(set-master-mode 'game)
|
||||
(false! (-> self draw?))
|
||||
(false! *popup-menu-open*))))
|
||||
|
||||
(defmethod update-menu! ((this popup-menu))
|
||||
(when (-> this draw?)
|
||||
;; handle input
|
||||
(cond
|
||||
((cpad-pressed? 0 select)
|
||||
(send-event this 'close-menu))
|
||||
((cpad-pressed? 0 up)
|
||||
(move-up! this 1))
|
||||
((cpad-pressed? 0 down)
|
||||
(move-down! this 1))
|
||||
((cpad-pressed? 0 left)
|
||||
(move-up! this 5))
|
||||
((cpad-pressed? 0 right)
|
||||
(move-down! this 5))
|
||||
((cpad-pressed? 0 x)
|
||||
(confirm! this))
|
||||
((cpad-pressed? 0 square)
|
||||
(reset! this))
|
||||
((cpad-pressed? 0 triangle circle)
|
||||
(when (back! this)
|
||||
(send-event this 'close-menu))))
|
||||
(draw-menu this)))
|
||||
|
||||
(defstatehandler popup-menu :event popup-menu-event-handler)
|
||||
|
||||
(defstate idle (popup-menu)
|
||||
:virtual #t
|
||||
:trans (behavior () (update-menu! self))
|
||||
:code sleep-code)
|
@ -328,11 +328,20 @@ static std::unordered_map<std::string,
|
||||
std::unique_ptr<Res> res_from_json_array(const std::string& name,
|
||||
const nlohmann::json& json_array,
|
||||
decompiler::DecompilerTypeSystem& dts) {
|
||||
ASSERT(!json_array.empty());
|
||||
std::string array_type = json_array[0].get<std::string>();
|
||||
if (json_array.empty()) {
|
||||
throw std::runtime_error(fmt::format("json for {} lump was empty", name));
|
||||
}
|
||||
auto& lump = json_array[0];
|
||||
if (lump.type() != nlohmann::detail::value_t::string) {
|
||||
throw std::runtime_error(
|
||||
fmt::format("first entry of lump \"{}\" has json type {}, but should be string", name,
|
||||
lump.type_name()));
|
||||
}
|
||||
auto array_type = lump.get<std::string>();
|
||||
if (lump_map.find(array_type) != lump_map.end()) {
|
||||
return lump_map[array_type](name, json_array, dts);
|
||||
} else {
|
||||
ASSERT_MSG(false, fmt::format("unsupported array type: {}\n", array_type));
|
||||
throw std::runtime_error(
|
||||
fmt::format("unsupported array type for lump {}: {}\n", name, array_type));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user