From f14f37f970a8ceb686a6a5e0bd7b165b3395b717 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 14:39:31 +0300 Subject: [PATCH 01/42] Add target_override_protection --- src/mapper/mp_proto.cc | 6 ++++++ src/mapper/mp_proto.h | 1 + src/mapper/mp_targt.cc | 13 ++++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/mapper/mp_proto.cc b/src/mapper/mp_proto.cc index 513fb57..2b0ef90 100644 --- a/src/mapper/mp_proto.cc +++ b/src/mapper/mp_proto.cc @@ -29,6 +29,12 @@ static int mp_pick_kill_type(); static char kYes[] = "YES"; static char kNo[] = "NO"; +// 0x53DAFC +static char default_proto_builder_name[36] = "EVERTS SCOTTY"; + +// 0x559924 +char* proto_builder_name = default_proto_builder_name; + // 0x559B94 static const char* wall_light_strs[] = { "North/South", diff --git a/src/mapper/mp_proto.h b/src/mapper/mp_proto.h index e6a520e..e4e1443 100644 --- a/src/mapper/mp_proto.h +++ b/src/mapper/mp_proto.h @@ -3,6 +3,7 @@ namespace fallout { +extern char* proto_builder_name; extern bool can_modify_protos; void init_mapper_protos(); diff --git a/src/mapper/mp_targt.cc b/src/mapper/mp_targt.cc index b654011..1ea92df 100644 --- a/src/mapper/mp_targt.cc +++ b/src/mapper/mp_targt.cc @@ -5,6 +5,7 @@ #include "art.h" #include "game.h" #include "map.h" +#include "mapper/mp_proto.h" #include "proto.h" #include "window_manager_private.h" @@ -22,7 +23,17 @@ static bool tgt_overriden = false; // 0x49B2F0 void target_override_protection() { - // TODO: Incomplete. + char* name; + + tgt_overriden = true; + + name = getenv("MAIL_NAME"); + if (name != NULL) { + // NOTE: Unsafe, backing buffer is 32 byte max. + strcpy(proto_builder_name, strupr(name)); + } else { + strcpy(proto_builder_name, "UNKNOWN"); + } } // 0x49B2F0 From 59c43590cca46147f245265a738f1148cfe5f3f9 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 15:29:59 +0300 Subject: [PATCH 02/42] Add target_header_save --- src/mapper/mp_targt.cc | 34 ++++++++++++++++++++++++++++++++++ src/mapper/mp_targt.h | 1 + 2 files changed, 35 insertions(+) diff --git a/src/mapper/mp_targt.cc b/src/mapper/mp_targt.cc index 1ea92df..7d7799b 100644 --- a/src/mapper/mp_targt.cc +++ b/src/mapper/mp_targt.cc @@ -11,9 +11,20 @@ namespace fallout { +#define TARGET_DAT "target.dat" + +typedef struct TargetList { + int field_0; + int field_4; + int field_8; +} TargetList; + // 0x53F354 static char default_target_path_base[] = "\\fallout2\\dev\\proto\\"; +// 0x559CC4 +static TargetList targetlist = { 0 }; + // 0x559CD0 static char* target_path_base = default_target_path_base; @@ -73,6 +84,29 @@ int target_exit() return 0; } +// 0x49B454 +int target_header_save() +{ + char path[COMPAT_MAX_PATH]; + FILE* stream; + + target_make_path(path, -1); + strcat(path, TARGET_DAT); + + stream = fopen(path, "wb"); + if (stream == NULL) { + return -1; + } + + if (fwrite(&targetlist, sizeof(targetlist), 1, stream) != 1) { + // FIXME: Leaking `stream`. + return -1; + } + + fclose(stream); + return 0; +} + // 0x49BD98 int pick_rot() { diff --git a/src/mapper/mp_targt.h b/src/mapper/mp_targt.h index 2a0578d..1fd3d19 100644 --- a/src/mapper/mp_targt.h +++ b/src/mapper/mp_targt.h @@ -8,6 +8,7 @@ bool target_overriden(); void target_make_path(char* path, int pid); int target_init(); int target_exit(); +int target_header_save(); int pick_rot(); int target_pick_global_var(int* value_ptr); int target_pick_map_var(int* value_ptr); From ed7ffac816e3bab34586d2c6c00664be7f416859 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 15:31:23 +0300 Subject: [PATCH 03/42] Add target_header_load --- src/mapper/mp_targt.cc | 26 ++++++++++++++++++++++++++ src/mapper/mp_targt.h | 1 + 2 files changed, 27 insertions(+) diff --git a/src/mapper/mp_targt.cc b/src/mapper/mp_targt.cc index 7d7799b..c5f1cff 100644 --- a/src/mapper/mp_targt.cc +++ b/src/mapper/mp_targt.cc @@ -107,6 +107,32 @@ int target_header_save() return 0; } +// 0x49B4E8 +int target_header_load() +{ + char path[COMPAT_MAX_PATH]; + FILE* stream; + + target_make_path(path, -1); + strcat(path, TARGET_DAT); + + stream = fopen(path, "rb"); + if (stream == NULL) { + return -1; + } + + if (fread(&targetlist, sizeof(targetlist), 1, stream) != 1) { + // FIXME: Leaking `stream`. + return -1; + } + + targetlist.field_0 = 0; + targetlist.field_4 = 0; + + fclose(stream); + return 0; +} + // 0x49BD98 int pick_rot() { diff --git a/src/mapper/mp_targt.h b/src/mapper/mp_targt.h index 1fd3d19..af47cc9 100644 --- a/src/mapper/mp_targt.h +++ b/src/mapper/mp_targt.h @@ -9,6 +9,7 @@ void target_make_path(char* path, int pid); int target_init(); int target_exit(); int target_header_save(); +int target_header_load(); int pick_rot(); int target_pick_global_var(int* value_ptr); int target_pick_map_var(int* value_ptr); From c3a6d07dc41cb4c8fc29655579b63e0e9e97433d Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 16:24:07 +0300 Subject: [PATCH 04/42] Add target_find_free_subnode --- src/mapper/mp_targt.cc | 37 ++++++++++++++++++++++++++++++----- src/mapper/mp_targt.h | 44 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/src/mapper/mp_targt.cc b/src/mapper/mp_targt.cc index c5f1cff..6d2a75a 100644 --- a/src/mapper/mp_targt.cc +++ b/src/mapper/mp_targt.cc @@ -6,6 +6,7 @@ #include "game.h" #include "map.h" #include "mapper/mp_proto.h" +#include "memory.h" #include "proto.h" #include "window_manager_private.h" @@ -13,9 +14,14 @@ namespace fallout { #define TARGET_DAT "target.dat" +typedef struct TargetNode { + TargetSubNode subnode; + struct TargetNode* next; +} TargetNode; + typedef struct TargetList { - int field_0; - int field_4; + TargetNode* tail; + int count; int field_8; } TargetList; @@ -23,7 +29,7 @@ typedef struct TargetList { static char default_target_path_base[] = "\\fallout2\\dev\\proto\\"; // 0x559CC4 -static TargetList targetlist = { 0 }; +static TargetList targetlist = { NULL, 0, 0 }; // 0x559CD0 static char* target_path_base = default_target_path_base; @@ -126,13 +132,34 @@ int target_header_load() return -1; } - targetlist.field_0 = 0; - targetlist.field_4 = 0; + targetlist.tail = NULL; + targetlist.count = 0; fclose(stream); return 0; } +// 0x49B9C0 +int target_find_free_subnode(TargetSubNode** subnode_ptr) +{ + TargetNode* node = (TargetNode*)internal_malloc(sizeof(TargetNode)); + if (node == NULL) { + *subnode_ptr = NULL; + return -1; + } + + *subnode_ptr = &(node->subnode); + + node->subnode.field_0 = -1; + node->subnode.field_28 = 0; + node->next = targetlist.tail; + + targetlist.tail = node; + targetlist.count++; + + return 0; +} + // 0x49BD98 int pick_rot() { diff --git a/src/mapper/mp_targt.h b/src/mapper/mp_targt.h index af47cc9..2769cc4 100644 --- a/src/mapper/mp_targt.h +++ b/src/mapper/mp_targt.h @@ -3,6 +3,49 @@ namespace fallout { +typedef struct TargetSubNode { + int field_0; + int field_4; + int field_8; + int field_C; + int field_10; + int field_14; + int field_18; + int field_1C; + int field_20; + int field_24; + int field_28; + int field_2C; + int field_30; + int field_34; + int field_38; + int field_3C; + int field_40; + int field_44; + int field_48; + int field_4C; + int field_50; + int field_54; + int field_58; + int field_5C; + int field_60; + int field_64; + int field_68; + int field_6C; + int field_70; + int field_74; + int field_78; + int field_7C; + int field_80; + int field_84; + int field_88; + int field_8C; + int field_90; + int field_94; + int field_98; + int field_9C; +} TargetSubNode; + void target_override_protection(); bool target_overriden(); void target_make_path(char* path, int pid); @@ -10,6 +53,7 @@ int target_init(); int target_exit(); int target_header_save(); int target_header_load(); +int target_find_free_subnode(TargetSubNode** subnode_ptr); int pick_rot(); int target_pick_global_var(int* value_ptr); int target_pick_map_var(int* value_ptr); From fd3cd887b6d76b542773f9eeee161a0ff169f114 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 16:40:18 +0300 Subject: [PATCH 05/42] Add target_load --- src/mapper/mp_targt.cc | 56 +++++++++++++++++++++++++++++++++++++++++- src/mapper/mp_targt.h | 3 ++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/mapper/mp_targt.cc b/src/mapper/mp_targt.cc index 6d2a75a..6d4ba60 100644 --- a/src/mapper/mp_targt.cc +++ b/src/mapper/mp_targt.cc @@ -139,6 +139,60 @@ int target_header_load() return 0; } +// 0x49B6BC +int target_load(int pid, TargetSubNode** subnode_ptr) +{ + char path[COMPAT_MAX_PATH]; + size_t len; + char* extension; + FILE* stream; + TargetSubNode* subnode; + + target_make_path(path, pid); + + len = strlen(path); + path[len] = '\\'; + _proto_list_str(pid, path + len + 1); + + extension = strchr(path + len + 1, '.'); + if (extension != NULL) { + strcpy(extension + 1, "tgt"); + } else { + strcat(path, ".tgt"); + } + + stream = fopen(path, "rb"); + if (stream == NULL) { + *subnode_ptr = NULL; + return -1; + } + + if (target_find_free_subnode(&subnode) == -1) { + *subnode_ptr = NULL; + // FIXME: Leaks `stream`. + return -1; + } + + fread(subnode, sizeof(TargetSubNode), 1, stream); + + *subnode_ptr = subnode; + + while (subnode->next != NULL) { + subnode->next = (TargetSubNode*)internal_malloc(sizeof(TargetSubNode)); + if (subnode->next == NULL) { + // FIXME: Leaks `stream`. + return -1; + } + + subnode = subnode->next; + fread(subnode, sizeof(TargetSubNode), 1, stream); + } + + fclose(stream); + + return 0; +} + // 0x49B9C0 int target_find_free_subnode(TargetSubNode** subnode_ptr) { @@ -151,7 +205,7 @@ int target_find_free_subnode(TargetSubNode** subnode_ptr) *subnode_ptr = &(node->subnode); node->subnode.field_0 = -1; - node->subnode.field_28 = 0; + node->subnode.next = NULL; node->next = targetlist.tail; targetlist.tail = node; diff --git a/src/mapper/mp_targt.h b/src/mapper/mp_targt.h index 2769cc4..d85b20f 100644 --- a/src/mapper/mp_targt.h +++ b/src/mapper/mp_targt.h @@ -14,7 +14,7 @@ typedef struct TargetSubNode { int field_1C; int field_20; int field_24; - int field_28; + struct TargetSubNode* next; int field_2C; int field_30; int field_34; @@ -53,6 +53,7 @@ int target_init(); int target_exit(); int target_header_save(); int target_header_load(); +int target_load(int pid, TargetSubNode** subnode_ptr); int target_find_free_subnode(TargetSubNode** subnode_ptr); int pick_rot(); int target_pick_global_var(int* value_ptr); From 25a3de62e7b67227727c8f347b8cbd9aebb7131a Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 17:05:26 +0300 Subject: [PATCH 06/42] Add target_ptr --- src/mapper/mp_targt.cc | 14 ++++++++++++++ src/mapper/mp_targt.h | 1 + 2 files changed, 15 insertions(+) diff --git a/src/mapper/mp_targt.cc b/src/mapper/mp_targt.cc index 6d4ba60..d920c71 100644 --- a/src/mapper/mp_targt.cc +++ b/src/mapper/mp_targt.cc @@ -214,6 +214,20 @@ int target_find_free_subnode(TargetSubNode** subnode_ptr) return 0; } +// 0x49BD00 +int target_ptr(int pid, TargetSubNode** subnode_ptr) +{ + TargetNode* node = targetlist.tail; + while (node != NULL) { + if (node->subnode.field_0 == pid) { + *subnode_ptr = &(node->subnode); + return 0; + } + } + + return target_load(pid, subnode_ptr); +} + // 0x49BD98 int pick_rot() { diff --git a/src/mapper/mp_targt.h b/src/mapper/mp_targt.h index d85b20f..e169605 100644 --- a/src/mapper/mp_targt.h +++ b/src/mapper/mp_targt.h @@ -55,6 +55,7 @@ int target_header_save(); int target_header_load(); int target_load(int pid, TargetSubNode** subnode_ptr); int target_find_free_subnode(TargetSubNode** subnode_ptr); +int target_ptr(int pid, TargetSubNode** subnode_ptr); int pick_rot(); int target_pick_global_var(int* value_ptr); int target_pick_map_var(int* value_ptr); From caf28a728609c6d37ae5f1e56491b36ec8ae794e Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 17:07:43 +0300 Subject: [PATCH 07/42] Add target_tid_ptr --- src/mapper/mp_targt.cc | 18 ++++++++++++++++++ src/mapper/mp_targt.h | 1 + 2 files changed, 19 insertions(+) diff --git a/src/mapper/mp_targt.cc b/src/mapper/mp_targt.cc index d920c71..c9da5ff 100644 --- a/src/mapper/mp_targt.cc +++ b/src/mapper/mp_targt.cc @@ -228,6 +228,24 @@ int target_ptr(int pid, TargetSubNode** subnode_ptr) return target_load(pid, subnode_ptr); } +// 0x49BD38 +int target_tid_ptr(int pid, int tid, TargetSubNode** subnode_ptr) +{ + TargetSubNode* subnode; + if (target_ptr(pid, &subnode) == -1) { + return -1; + } + + while (subnode != NULL) { + if (subnode->field_4 == tid) { + *subnode_ptr = subnode; + return 0; + } + } + + return -1; +} + // 0x49BD98 int pick_rot() { diff --git a/src/mapper/mp_targt.h b/src/mapper/mp_targt.h index e169605..1c830c8 100644 --- a/src/mapper/mp_targt.h +++ b/src/mapper/mp_targt.h @@ -56,6 +56,7 @@ int target_header_load(); int target_load(int pid, TargetSubNode** subnode_ptr); int target_find_free_subnode(TargetSubNode** subnode_ptr); int target_ptr(int pid, TargetSubNode** subnode_ptr); +int target_tid_ptr(int pid, int tid, TargetSubNode** subnode_ptr); int pick_rot(); int target_pick_global_var(int* value_ptr); int target_pick_map_var(int* value_ptr); From 96573a7209a9c138ada8084fe1ac654a3e005fdf Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 17:14:49 +0300 Subject: [PATCH 08/42] Add target_remove_all --- src/mapper/mp_targt.cc | 28 ++++++++++++++++++++++++++++ src/mapper/mp_targt.h | 1 + 2 files changed, 29 insertions(+) diff --git a/src/mapper/mp_targt.cc b/src/mapper/mp_targt.cc index c9da5ff..c72ca2a 100644 --- a/src/mapper/mp_targt.cc +++ b/src/mapper/mp_targt.cc @@ -214,6 +214,34 @@ int target_find_free_subnode(TargetSubNode** subnode_ptr) return 0; } +// 0x49BCBC +int target_remove_all() +{ + TargetNode* node; + TargetNode* node_next; + TargetSubNode* subnode; + TargetSubNode* subnode_next; + + node = targetlist.tail; + targetlist.tail = NULL; + + while (node != NULL) { + node_next = node->next; + + subnode = node->subnode.next; + while (subnode != NULL) { + subnode_next = subnode->next; + internal_free(subnode); + subnode = subnode_next; + } + + internal_free(node); + node = node_next; + } + + return 0; +} + // 0x49BD00 int target_ptr(int pid, TargetSubNode** subnode_ptr) { diff --git a/src/mapper/mp_targt.h b/src/mapper/mp_targt.h index 1c830c8..9c65ed5 100644 --- a/src/mapper/mp_targt.h +++ b/src/mapper/mp_targt.h @@ -55,6 +55,7 @@ int target_header_save(); int target_header_load(); int target_load(int pid, TargetSubNode** subnode_ptr); int target_find_free_subnode(TargetSubNode** subnode_ptr); +int target_remove_all(); int target_ptr(int pid, TargetSubNode** subnode_ptr); int target_tid_ptr(int pid, int tid, TargetSubNode** subnode_ptr); int pick_rot(); From 05b4c125e6420932109435d83781a574b38a9b47 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 17:19:51 +0300 Subject: [PATCH 09/42] Add target_save --- src/mapper/mp_targt.cc | 41 +++++++++++++++++++++++++++++++++++++++++ src/mapper/mp_targt.h | 1 + 2 files changed, 42 insertions(+) diff --git a/src/mapper/mp_targt.cc b/src/mapper/mp_targt.cc index c72ca2a..12b9cc9 100644 --- a/src/mapper/mp_targt.cc +++ b/src/mapper/mp_targt.cc @@ -139,6 +139,47 @@ int target_header_load() return 0; } +// 0x49B58C +int target_save(int pid) +{ + char path[COMPAT_MAX_PATH]; + size_t len; + char* extension; + FILE* stream; + TargetSubNode* subnode; + + if (target_ptr(pid, &subnode) == -1) { + return -1; + } + + target_make_path(path, pid); + + len = strlen(path); + path[len] = '\\'; + _proto_list_str(pid, path + len + 1); + + extension = strchr(path + len + 1, '.'); + if (extension != NULL) { + strcpy(extension + 1, "tgt"); + } else { + strcat(path, ".tgt"); + } + + stream = fopen(path, "wb"); + if (stream == NULL) { + return -1; + } + + while (subnode != NULL) { + fwrite(subnode, sizeof(TargetSubNode), 1, stream); + subnode = subnode->next; + } + + fclose(stream); + + return 0; +} + // 0x49B6BC int target_load(int pid, TargetSubNode** subnode_ptr) { diff --git a/src/mapper/mp_targt.h b/src/mapper/mp_targt.h index 9c65ed5..db84194 100644 --- a/src/mapper/mp_targt.h +++ b/src/mapper/mp_targt.h @@ -53,6 +53,7 @@ int target_init(); int target_exit(); int target_header_save(); int target_header_load(); +int target_save(int pid); int target_load(int pid, TargetSubNode** subnode_ptr); int target_find_free_subnode(TargetSubNode** subnode_ptr); int target_remove_all(); From 29e81f3bf46283783c43680c38a7acacff57f455 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 17:37:21 +0300 Subject: [PATCH 10/42] Add target_remove --- src/mapper/mp_targt.cc | 36 ++++++++++++++++++++++++++++++++++++ src/mapper/mp_targt.h | 1 + 2 files changed, 37 insertions(+) diff --git a/src/mapper/mp_targt.cc b/src/mapper/mp_targt.cc index 12b9cc9..b0c4595 100644 --- a/src/mapper/mp_targt.cc +++ b/src/mapper/mp_targt.cc @@ -255,6 +255,42 @@ int target_find_free_subnode(TargetSubNode** subnode_ptr) return 0; } +// 0x49BBD4 +int target_remove(int pid) +{ + TargetNode* node; + TargetSubNode* subnode; + TargetSubNode* subnode_next; + + node = targetlist.tail; + while (node != NULL) { + if (node->subnode.field_0 == pid) { + break; + } + node = node->next; + } + + if (node == NULL) { + return -1; + } + + subnode = node->subnode.next; + + if (node == targetlist.tail) { + targetlist.tail = targetlist.tail->next; + } + + internal_free(node); + + while (subnode != NULL) { + subnode_next = subnode->next; + internal_free(subnode); + subnode = subnode_next; + } + + return 0; +} + // 0x49BCBC int target_remove_all() { diff --git a/src/mapper/mp_targt.h b/src/mapper/mp_targt.h index db84194..3c23959 100644 --- a/src/mapper/mp_targt.h +++ b/src/mapper/mp_targt.h @@ -56,6 +56,7 @@ int target_header_load(); int target_save(int pid); int target_load(int pid, TargetSubNode** subnode_ptr); int target_find_free_subnode(TargetSubNode** subnode_ptr); +int target_remove(int pid); int target_remove_all(); int target_ptr(int pid, TargetSubNode** subnode_ptr); int target_tid_ptr(int pid, int tid, TargetSubNode** subnode_ptr); From fe47d88035d385c39f633b2c1db0d4070ff7f02c Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 17:47:43 +0300 Subject: [PATCH 11/42] Add target_remove_tid --- src/mapper/mp_targt.cc | 46 ++++++++++++++++++++++++++++++++++++++++++ src/mapper/mp_targt.h | 1 + 2 files changed, 47 insertions(+) diff --git a/src/mapper/mp_targt.cc b/src/mapper/mp_targt.cc index b0c4595..5d41fbc 100644 --- a/src/mapper/mp_targt.cc +++ b/src/mapper/mp_targt.cc @@ -291,6 +291,52 @@ int target_remove(int pid) return 0; } +// 0x49BC3C +int target_remove_tid(int pid, int tid) +{ + TargetNode* node; + TargetSubNode* subnode; + TargetSubNode* subnode_next; + + node = targetlist.tail; + while (node != NULL) { + if (node->subnode.field_0 == pid) { + break; + } + node = node->next; + } + + if (node == NULL) { + return -1; + } + + if (node->subnode.field_4 == tid) { + subnode_next = node->subnode.next; + if (subnode_next != NULL) { + memcpy(&(node->subnode), subnode_next, sizeof(TargetSubNode)); + internal_free(subnode_next); + } else { + target_remove(pid); + } + + // FIXME: Should probably return 0 here. + } else { + subnode = &(node->subnode); + while (subnode != NULL) { + subnode_next = subnode->next; + if (subnode_next->field_4 == tid) { + subnode->next = subnode_next->next; + internal_free(subnode_next); + return 0; + } + + subnode = subnode_next; + } + } + + return -1; +} + // 0x49BCBC int target_remove_all() { diff --git a/src/mapper/mp_targt.h b/src/mapper/mp_targt.h index 3c23959..0d88665 100644 --- a/src/mapper/mp_targt.h +++ b/src/mapper/mp_targt.h @@ -57,6 +57,7 @@ int target_save(int pid); int target_load(int pid, TargetSubNode** subnode_ptr); int target_find_free_subnode(TargetSubNode** subnode_ptr); int target_remove(int pid); +int target_remove_tid(int pid, int tid); int target_remove_all(); int target_ptr(int pid, TargetSubNode** subnode_ptr); int target_tid_ptr(int pid, int tid, TargetSubNode** subnode_ptr); From 8d2d5df65f49cac845f4d89dc7b26b3159f9abab Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 17:54:17 +0300 Subject: [PATCH 12/42] Add target_new --- src/mapper/mp_targt.cc | 52 +++++++++++++++++++++++++++++++++++------- src/mapper/mp_targt.h | 5 ++-- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/src/mapper/mp_targt.cc b/src/mapper/mp_targt.cc index 5d41fbc..994e62b 100644 --- a/src/mapper/mp_targt.cc +++ b/src/mapper/mp_targt.cc @@ -22,7 +22,7 @@ typedef struct TargetNode { typedef struct TargetList { TargetNode* tail; int count; - int field_8; + int next_tid; } TargetList; // 0x53F354 @@ -245,7 +245,7 @@ int target_find_free_subnode(TargetSubNode** subnode_ptr) *subnode_ptr = &(node->subnode); - node->subnode.field_0 = -1; + node->subnode.pid = -1; node->subnode.next = NULL; node->next = targetlist.tail; @@ -255,6 +255,42 @@ int target_find_free_subnode(TargetSubNode** subnode_ptr) return 0; } +// 0x49BA10 +int target_new(int pid, int* tid_ptr) +{ + TargetSubNode* subnode; + TargetSubNode* new_subnode; + + if (target_ptr(pid, &subnode) == -1) { + if (target_find_free_subnode(&subnode) == -1) { + return -1; + } + } + + new_subnode = (TargetSubNode*)internal_malloc(sizeof(TargetSubNode)); + if (new_subnode == NULL) { + return -1; + } + + new_subnode->next = NULL; + + while (subnode->next != NULL) { + subnode = subnode->next; + } + + subnode->next = new_subnode; + + new_subnode->pid = pid; + new_subnode->tid = targetlist.next_tid; + + *tid_ptr = targetlist.next_tid; + + targetlist.count++; + targetlist.next_tid++; + + return 0; +} + // 0x49BBD4 int target_remove(int pid) { @@ -264,7 +300,7 @@ int target_remove(int pid) node = targetlist.tail; while (node != NULL) { - if (node->subnode.field_0 == pid) { + if (node->subnode.pid == pid) { break; } node = node->next; @@ -300,7 +336,7 @@ int target_remove_tid(int pid, int tid) node = targetlist.tail; while (node != NULL) { - if (node->subnode.field_0 == pid) { + if (node->subnode.pid == pid) { break; } node = node->next; @@ -310,7 +346,7 @@ int target_remove_tid(int pid, int tid) return -1; } - if (node->subnode.field_4 == tid) { + if (node->subnode.tid == tid) { subnode_next = node->subnode.next; if (subnode_next != NULL) { memcpy(&(node->subnode), subnode_next, sizeof(TargetSubNode)); @@ -324,7 +360,7 @@ int target_remove_tid(int pid, int tid) subnode = &(node->subnode); while (subnode != NULL) { subnode_next = subnode->next; - if (subnode_next->field_4 == tid) { + if (subnode_next->tid == tid) { subnode->next = subnode_next->next; internal_free(subnode_next); return 0; @@ -370,7 +406,7 @@ int target_ptr(int pid, TargetSubNode** subnode_ptr) { TargetNode* node = targetlist.tail; while (node != NULL) { - if (node->subnode.field_0 == pid) { + if (node->subnode.pid == pid) { *subnode_ptr = &(node->subnode); return 0; } @@ -388,7 +424,7 @@ int target_tid_ptr(int pid, int tid, TargetSubNode** subnode_ptr) } while (subnode != NULL) { - if (subnode->field_4 == tid) { + if (subnode->tid == tid) { *subnode_ptr = subnode; return 0; } diff --git a/src/mapper/mp_targt.h b/src/mapper/mp_targt.h index 0d88665..eb70695 100644 --- a/src/mapper/mp_targt.h +++ b/src/mapper/mp_targt.h @@ -4,8 +4,8 @@ namespace fallout { typedef struct TargetSubNode { - int field_0; - int field_4; + int pid; + int tid; int field_8; int field_C; int field_10; @@ -56,6 +56,7 @@ int target_header_load(); int target_save(int pid); int target_load(int pid, TargetSubNode** subnode_ptr); int target_find_free_subnode(TargetSubNode** subnode_ptr); +int target_new(int pid, int* tid_ptr); int target_remove(int pid); int target_remove_tid(int pid, int tid); int target_remove_all(); From 8929941d138e194e04bfac1b5d2bfd8731a3a3b1 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 18:07:37 +0300 Subject: [PATCH 13/42] Add target_init --- src/mapper/mp_targt.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mapper/mp_targt.cc b/src/mapper/mp_targt.cc index 994e62b..c85ba6f 100644 --- a/src/mapper/mp_targt.cc +++ b/src/mapper/mp_targt.cc @@ -77,7 +77,8 @@ void target_make_path(char* path, int pid) // 0x49B424 int target_init() { - // TODO: Incomplete. + target_remove_all(); + target_header_load(); return 0; } From e0b18a878513261106117580a8d9519fe38e7cf8 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 18:08:21 +0300 Subject: [PATCH 14/42] Add target_exit --- src/mapper/mp_targt.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/mapper/mp_targt.cc b/src/mapper/mp_targt.cc index c85ba6f..ab61837 100644 --- a/src/mapper/mp_targt.cc +++ b/src/mapper/mp_targt.cc @@ -86,7 +86,12 @@ int target_init() // 0x49B434 int target_exit() { - // TODO: Incomplete. + if (can_modify_protos) { + target_header_save(); + target_remove_all(); + } else { + target_remove_all(); + } return 0; } From 1c2fd05bcdaa36f027d1fae89300130ef5f2afff Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 18:33:32 +0300 Subject: [PATCH 15/42] Add proto_subdata_setup_int_button --- src/mapper/mp_proto.cc | 55 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/mapper/mp_proto.cc b/src/mapper/mp_proto.cc index 2b0ef90..7e787fd 100644 --- a/src/mapper/mp_proto.cc +++ b/src/mapper/mp_proto.cc @@ -22,6 +22,7 @@ namespace fallout { #define NO 1 static int proto_choose_container_flags(Proto* proto); +static int proto_subdata_setup_int_button(const char* title, int key, int value, int min_value, int max_value, int* y, int a7); static void proto_critter_flags_redraw(int win, int pid); static int proto_critter_flags_modify(int pid); static int mp_pick_kill_type(); @@ -57,6 +58,9 @@ int edit_window_color = 1; // 0x559C60 bool can_modify_protos = false; +// 0x559C68 +static int subwin = -1; + // 0x559C6C static int critFlagList[CRITTER_FLAG_COUNT] = { CRITTER_NO_STEAL, @@ -221,6 +225,57 @@ int proto_choose_container_flags(Proto* proto) return 0; } +// 0x492A3C +int proto_subdata_setup_int_button(const char* title, int key, int value, int min_value, int max_value, int* y, int a7) +{ + char text[36]; + int button_x; + int value_offset_x; + + button_x = 10; + value_offset_x = 90; + + if (a7 == 9) { + *y -= 189; + } + + if (a7 > 8) { + button_x = 165; + value_offset_x -= 16; + } + + _win_register_text_button(subwin, + button_x, + *y, + -1, + -1, + -1, + key, + title, + 0); + + if (value >= min_value && value < max_value) { + sprintf(text, "%d", value); + windowDrawText(subwin, + text, + 38, + button_x + value_offset_x, + *y + 4, + _colorTable[32747] | 0x10000); + } else { + windowDrawText(subwin, + "", + 38, + button_x + value_offset_x, + *y + 4, + _colorTable[31744] | 0x10000); + } + + *y += 21; + + return 0; +} + // 0x495438 const char* proto_wall_light_str(int flags) { From b0b161ceb5b1ab5da62f782085941a1517ffe01a Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 19:31:16 +0300 Subject: [PATCH 16/42] Add proto_subdata_setup_fid_button --- src/art.cc | 8 ++++++ src/art.h | 1 + src/mapper/mp_proto.cc | 58 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/src/art.cc b/src/art.cc index bb1a0f3..1e92439 100644 --- a/src/art.cc +++ b/src/art.cc @@ -438,6 +438,14 @@ void artRender(int fid, unsigned char* dest, int width, int height, int pitch) artUnlock(handle); } +// mapper2.exe: 0x40A03C +int art_list_str(int fid, char* name) +{ + // TODO: Incomplete. + + return -1; +} + // 0x419160 Art* artLock(int fid, CacheEntry** handlePtr) { diff --git a/src/art.h b/src/art.h index f7c31b4..650b241 100644 --- a/src/art.h +++ b/src/art.h @@ -123,6 +123,7 @@ char* artGetObjectTypeName(int objectType); int artIsObjectTypeHidden(int objectType); int artGetFidgetCount(int headFid); void artRender(int fid, unsigned char* dest, int width, int height, int pitch); +int art_list_str(int fid, char* name); Art* artLock(int fid, CacheEntry** cache_entry); unsigned char* artLockFrameData(int fid, int frame, int direction, CacheEntry** out_cache_entry); unsigned char* artLockFrameDataReturningSize(int fid, CacheEntry** out_cache_entry, int* widthPtr, int* heightPtr); diff --git a/src/mapper/mp_proto.cc b/src/mapper/mp_proto.cc index 7e787fd..8de5c5d 100644 --- a/src/mapper/mp_proto.cc +++ b/src/mapper/mp_proto.cc @@ -2,6 +2,7 @@ #include +#include "art.h" #include "color.h" #include "combat_ai.h" #include "critter.h" @@ -23,6 +24,7 @@ namespace fallout { static int proto_choose_container_flags(Proto* proto); static int proto_subdata_setup_int_button(const char* title, int key, int value, int min_value, int max_value, int* y, int a7); +static int proto_subdata_setup_fid_button(const char* title, int key, int fid, int* y, int a5); static void proto_critter_flags_redraw(int win, int pid); static int proto_critter_flags_modify(int pid); static int mp_pick_kill_type(); @@ -276,6 +278,62 @@ int proto_subdata_setup_int_button(const char* title, int key, int value, int mi return 0; } +// 0x492B28 +int proto_subdata_setup_fid_button(const char* title, int key, int fid, int* y, int a5) +{ + char text[36]; + char* pch; + int button_x; + int value_offset_x; + + button_x = 10; + value_offset_x = 90; + + if (a5 == 9) { + *y -= 189; + } + + if (a5 > 8) { + button_x = 165; + value_offset_x -= 16; + } + + _win_register_text_button(subwin, + button_x, + *y, + -1, + -1, + -1, + key, + title, + 0); + + if (art_list_str(fid, text) != -1) { + pch = strchr(text, '.'); + if (pch != NULL) { + *pch = '\0'; + } + + windowDrawText(subwin, + text, + 80, + button_x + value_offset_x, + *y + 4, + _colorTable[32747] | 0x10000); + } else { + windowDrawText(subwin, + "None", + 80, + button_x + value_offset_x, + *y + 4, + _colorTable[992] | 0x10000); + } + + *y += 21; + + return 0; +} + // 0x495438 const char* proto_wall_light_str(int flags) { From 4a94b19f604403b16c4568c2684cab6059951783 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 19:36:17 +0300 Subject: [PATCH 17/42] Add proto_subdata_setup_pid_button --- src/mapper/mp_proto.cc | 50 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/mapper/mp_proto.cc b/src/mapper/mp_proto.cc index 8de5c5d..6e1b1be 100644 --- a/src/mapper/mp_proto.cc +++ b/src/mapper/mp_proto.cc @@ -25,6 +25,7 @@ namespace fallout { static int proto_choose_container_flags(Proto* proto); static int proto_subdata_setup_int_button(const char* title, int key, int value, int min_value, int max_value, int* y, int a7); static int proto_subdata_setup_fid_button(const char* title, int key, int fid, int* y, int a5); +static int proto_subdata_setup_pid_button(const char* title, int key, int pid, int* y, int a5); static void proto_critter_flags_redraw(int win, int pid); static int proto_critter_flags_modify(int pid); static int mp_pick_kill_type(); @@ -334,6 +335,55 @@ int proto_subdata_setup_fid_button(const char* title, int key, int fid, int* y, return 0; } +// 0x492C20 +int proto_subdata_setup_pid_button(const char* title, int key, int pid, int* y, int a5) +{ + int button_x; + int value_offset_x; + + button_x = 10; + value_offset_x = 90; + + if (a5 == 9) { + *y -= 189; + } + + if (a5 > 8) { + button_x = 165; + value_offset_x = 74; + } + + _win_register_text_button(subwin, + button_x, + *y, + -1, + -1, + -1, + key, + title, + 0); + + if (pid != -1) { + windowDrawText(subwin, + protoGetName(pid), + 49, + button_x + value_offset_x, + *y + 4, + _colorTable[32747] | 0x10000); + } else { + windowDrawText(subwin, + "None", + 49, + button_x + value_offset_x, + *y + 4, + _colorTable[992] | 0x10000); + } + + *y += 21; + + return 0; +} + // 0x495438 const char* proto_wall_light_str(int flags) { From 84288612ef147fc89abbea2eac1771bdcaf9a1af Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 19:43:56 +0300 Subject: [PATCH 18/42] Add map_toggle_block_obj_viewing_on --- src/mapper/map_func.cc | 9 +++++++++ src/mapper/map_func.h | 1 + 2 files changed, 10 insertions(+) diff --git a/src/mapper/map_func.cc b/src/mapper/map_func.cc index b9f297d..def62b9 100644 --- a/src/mapper/map_func.cc +++ b/src/mapper/map_func.cc @@ -2,6 +2,9 @@ namespace fallout { +// 0x5595CC +static bool block_obj_view_on = false; + // 0x4825B0 void setup_map_dirs() { @@ -14,4 +17,10 @@ void copy_proto_lists() // TODO: Incomplete. } +// 0x485D44 +bool map_toggle_block_obj_viewing_on() +{ + return block_obj_view_on; +} + } // namespace fallout diff --git a/src/mapper/map_func.h b/src/mapper/map_func.h index 1292604..44d3166 100644 --- a/src/mapper/map_func.h +++ b/src/mapper/map_func.h @@ -5,6 +5,7 @@ namespace fallout { void setup_map_dirs(); void copy_proto_lists(); +bool map_toggle_block_obj_viewing_on(); } // namespace fallout From 9178abc53db553736283ded9c72146d5f3b13e7e Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 19:47:15 +0300 Subject: [PATCH 19/42] Add toolbar_proto --- src/mapper/map_func.cc | 12 ++++++++++++ src/mapper/map_func.h | 1 + src/proto.cc | 3 +-- src/proto.h | 1 + 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/mapper/map_func.cc b/src/mapper/map_func.cc index def62b9..b9f853b 100644 --- a/src/mapper/map_func.cc +++ b/src/mapper/map_func.cc @@ -1,5 +1,7 @@ #include "mapper/map_func.h" +#include "proto.h" + namespace fallout { // 0x5595CC @@ -17,6 +19,16 @@ void copy_proto_lists() // TODO: Incomplete. } +// 0x484400 +int toolbar_proto(int type, int id) +{ + if (id < proto_max_id(type)) { + return (type << 24) | id; + } else { + return -1; + } +} + // 0x485D44 bool map_toggle_block_obj_viewing_on() { diff --git a/src/mapper/map_func.h b/src/mapper/map_func.h index 44d3166..e779f28 100644 --- a/src/mapper/map_func.h +++ b/src/mapper/map_func.h @@ -5,6 +5,7 @@ namespace fallout { void setup_map_dirs(); void copy_proto_lists(); +int toolbar_proto(int type, int id); bool map_toggle_block_obj_viewing_on(); } // namespace fallout diff --git a/src/proto.cc b/src/proto.cc index 001217f..f266498 100644 --- a/src/proto.cc +++ b/src/proto.cc @@ -39,7 +39,6 @@ static int _proto_find_free_subnode(int type, Proto** out_ptr); static void _proto_remove_some_list(int type); static void _proto_remove_list(int type); static int _proto_new_id(int type); -static int _proto_max_id(int type); // 0x50CF3C static char _aProto_0[] = "proto\\"; @@ -2170,7 +2169,7 @@ static int _proto_new_id(int type) } // 0x4A2214 -static int _proto_max_id(int type) +int proto_max_id(int type) { return _protoLists[type].max_entries_num; } diff --git a/src/proto.h b/src/proto.h index f00eef9..f49d1a6 100644 --- a/src/proto.h +++ b/src/proto.h @@ -137,6 +137,7 @@ int proto_new(int* pid, int type); void _proto_remove_all(); int protoGetProto(int pid, Proto** protoPtr); int _ResetPlayer(); +int proto_max_id(int type); static bool isExitGridPid(int pid) { From 7f920fe13b623f229c0cfca14ced7f0f994e3bac Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 19:57:14 +0300 Subject: [PATCH 20/42] Add erase_rect --- src/mapper/map_func.cc | 22 ++++++++++++++++++++++ src/mapper/map_func.h | 3 +++ 2 files changed, 25 insertions(+) diff --git a/src/mapper/map_func.cc b/src/mapper/map_func.cc index b9f853b..f328b0a 100644 --- a/src/mapper/map_func.cc +++ b/src/mapper/map_func.cc @@ -1,6 +1,7 @@ #include "mapper/map_func.h" #include "proto.h" +#include "window_manager.h" namespace fallout { @@ -19,6 +20,27 @@ void copy_proto_lists() // TODO: Incomplete. } +// 0x4843A0 +void erase_rect(Rect* rect) +{ + Rect r = *rect; + + r.bottom = rect->top; + windowRefreshAll(&r); + + r.bottom = rect->bottom; + r.left = rect->right; + windowRefreshAll(&r); + + r.left = rect->left; + r.top = rect->bottom; + windowRefreshAll(&r); + + r.top = rect->top; + r.right = rect->left; + windowRefreshAll(&r); +} + // 0x484400 int toolbar_proto(int type, int id) { diff --git a/src/mapper/map_func.h b/src/mapper/map_func.h index e779f28..0961c90 100644 --- a/src/mapper/map_func.h +++ b/src/mapper/map_func.h @@ -1,10 +1,13 @@ #ifndef FALLOUT_MAPPER_MAP_FUNC_H_ #define FALLOUT_MAPPER_MAP_FUNC_H_ +#include "geometry.h" + namespace fallout { void setup_map_dirs(); void copy_proto_lists(); +void erase_rect(Rect* rect); int toolbar_proto(int type, int id); bool map_toggle_block_obj_viewing_on(); From 84aecfa823c5808e5946dbfd58be6e85414aca59 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 20:07:02 +0300 Subject: [PATCH 21/42] Add draw_rect --- src/mapper/map_func.cc | 26 ++++++++++++++++++++++++++ src/mapper/map_func.h | 1 + 2 files changed, 27 insertions(+) diff --git a/src/mapper/map_func.cc b/src/mapper/map_func.cc index f328b0a..8b032f2 100644 --- a/src/mapper/map_func.cc +++ b/src/mapper/map_func.cc @@ -1,6 +1,8 @@ #include "mapper/map_func.h" +#include "memory.h" #include "proto.h" +#include "svga.h" #include "window_manager.h" namespace fallout { @@ -20,6 +22,30 @@ void copy_proto_lists() // TODO: Incomplete. } +// 0x4842D4 +void draw_rect(Rect* rect, unsigned char color) +{ + int width = rect->right - rect->left; + int height = rect->bottom - rect->top; + int max_dimension; + + if (height < width) { + max_dimension = width; + } else { + max_dimension = height; + } + + unsigned char* buffer = (unsigned char*)internal_malloc(max_dimension); + if (buffer != NULL) { + memset(buffer, color, max_dimension); + _scr_blit(buffer, width, 1, 0, 0, width, 1, rect->left, rect->top); + _scr_blit(buffer, 1, height, 0, 0, 1, height, rect->left, rect->top); + _scr_blit(buffer, width, 1, 0, 0, width, 1, rect->left, rect->bottom); + _scr_blit(buffer, 1, height, 0, 0, 1, height, rect->right, rect->top); + internal_free(buffer); + } +} + // 0x4843A0 void erase_rect(Rect* rect) { diff --git a/src/mapper/map_func.h b/src/mapper/map_func.h index 0961c90..3d03b42 100644 --- a/src/mapper/map_func.h +++ b/src/mapper/map_func.h @@ -7,6 +7,7 @@ namespace fallout { void setup_map_dirs(); void copy_proto_lists(); +void draw_rect(Rect* rect); void erase_rect(Rect* rect); int toolbar_proto(int type, int id); bool map_toggle_block_obj_viewing_on(); From bb3513956c010803bbbd46c7d354f4b85c957e34 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 21:34:41 +0300 Subject: [PATCH 22/42] Add op_force_encounter --- src/sfall_opcodes.cc | 17 +++++++++++++++ src/worldmap.cc | 52 ++++++++++++++++++++++++++++++++++++++++++++ src/worldmap.h | 7 ++++++ 3 files changed, 76 insertions(+) diff --git a/src/sfall_opcodes.cc b/src/sfall_opcodes.cc index ea45d4e..8d8cd57 100644 --- a/src/sfall_opcodes.cc +++ b/src/sfall_opcodes.cc @@ -138,6 +138,13 @@ static void op_in_world_map(Program* program) programStackPushInteger(program, GameMode::isInGameMode(GameMode::kWorldmap) ? 1 : 0); } +// force_encounter +static void op_force_encounter(Program* program) +{ + int map = programStackPopInteger(program); + wmForceEncounter(map, 0); +} + // set_world_map_pos static void op_set_world_map_pos(Program* program) { @@ -541,6 +548,14 @@ static void op_get_attack_type(Program* program) } } +// force_encounter_with_flags +static void op_force_encounter_with_flags(Program* program) +{ + unsigned int flags = programStackPopInteger(program); + int map = programStackPopInteger(program); + wmForceEncounter(map, flags); +} + // atoi static void opParseInt(Program* program) { @@ -894,6 +909,7 @@ void sfallOpcodesInit() interpreterRegisterOpcode(0x816A, op_set_global_script_repeat); interpreterRegisterOpcode(0x816C, op_key_pressed); interpreterRegisterOpcode(0x8170, op_in_world_map); + interpreterRegisterOpcode(0x8171, op_force_encounter); interpreterRegisterOpcode(0x8172, op_set_world_map_pos); interpreterRegisterOpcode(0x8193, opGetCurrentHand); interpreterRegisterOpcode(0x819B, op_set_global_script_type); @@ -927,6 +943,7 @@ void sfallOpcodesInit() interpreterRegisterOpcode(0x8221, opGetScreenHeight); interpreterRegisterOpcode(0x8224, op_create_message_window); interpreterRegisterOpcode(0x8228, op_get_attack_type); + interpreterRegisterOpcode(0x8229, op_force_encounter_with_flags); interpreterRegisterOpcode(0x822D, opCreateArray); interpreterRegisterOpcode(0x822E, opSetArray); interpreterRegisterOpcode(0x822F, opGetArray); diff --git a/src/worldmap.cc b/src/worldmap.cc index 3243d8d..8b30255 100644 --- a/src/worldmap.cc +++ b/src/worldmap.cc @@ -817,6 +817,8 @@ static double gGameTimeIncRemainder = 0.0; static FrmImage _backgroundFrmImage; static FrmImage _townFrmImage; static bool wmFaded = false; +static int wmForceEncounterMapId = -1; +static unsigned int wmForceEncounterFlags = 0; static inline bool cityIsValid(int city) { @@ -929,6 +931,9 @@ static int wmGenDataInit() wmGenData.tabsScrollingDelta = 0; wmGenData.viewportMaxX = 0; + wmForceEncounterMapId = -1; + wmForceEncounterFlags = 0; + return 0; } @@ -979,6 +984,9 @@ static int wmGenDataReset() wmMarkSubTileRadiusVisited(wmGenData.worldPosX, wmGenData.worldPosY); + wmForceEncounterMapId = -1; + wmForceEncounterFlags = 0; + return 0; } @@ -3347,6 +3355,33 @@ static int wmRndEncounterOccurred() } } + // SFALL: Handle forced encounter. + // CE: In Sfall a check for forced encounter is inserted instead of check + // for Horrigan encounter (above). This implemenation gives Horrigan + // encounter a priority. + if (wmForceEncounterMapId != -1) { + if ((wmForceEncounterFlags & ENCOUNTER_FLAG_NO_CAR) != 0) { + if (wmGenData.isInCar) { + wmMatchAreaContainingMapIdx(wmForceEncounterMapId, &(wmGenData.currentCarAreaId)); + } + } + + // For unknown reason fadeout and blinking icon are mutually exclusive. + if ((wmForceEncounterFlags & ENCOUNTER_FLAG_FADEOUT) != 0) { + wmFadeOut(); + } else if ((wmForceEncounterFlags & ENCOUNTER_FLAG_NO_ICON) == 0) { + bool special = (wmForceEncounterFlags & ENCOUNTER_FLAG_ICON_SP) != 0; + wmBlinkRndEncounterIcon(special); + } + + mapLoadById(wmForceEncounterMapId); + + wmForceEncounterMapId = -1; + wmForceEncounterFlags = 0; + + return 1; + } + // NOTE: Uninline. wmPartyFindCurSubTile(); @@ -6608,4 +6643,21 @@ void wmCarSetCurrentArea(int area) wmGenData.currentCarAreaId = area; } +void wmForceEncounter(int map, unsigned int flags) +{ + if ((wmForceEncounterFlags & (1 << 31)) != 0) { + return; + } + + wmForceEncounterMapId = map; + wmForceEncounterFlags = flags; + + // I don't quite understand the reason why locking needs one more flag. + if ((wmForceEncounterFlags & ENCOUNTER_FLAG_LOCK) != 0) { + wmForceEncounterFlags |= (1 << 31); + } else { + wmForceEncounterFlags &= ~(1 << 31); + } +} + } // namespace fallout diff --git a/src/worldmap.h b/src/worldmap.h index 901b0a6..20ea1c2 100644 --- a/src/worldmap.h +++ b/src/worldmap.h @@ -229,6 +229,12 @@ typedef enum Map { MAP_IN_GAME_MOVIE1 = 149, } Map; +#define ENCOUNTER_FLAG_NO_CAR 0x1 +#define ENCOUNTER_FLAG_LOCK 0x2 +#define ENCOUNTER_FLAG_NO_ICON 0x4 +#define ENCOUNTER_FLAG_ICON_SP 0x8 +#define ENCOUNTER_FLAG_FADEOUT 0x10 + extern unsigned char* circleBlendTable; int wmWorldMap_init(); @@ -279,6 +285,7 @@ int wmTeleportToArea(int areaIdx); void wmSetPartyWorldPos(int x, int y); void wmCarSetCurrentArea(int area); +void wmForceEncounter(int map, unsigned int flags); } // namespace fallout From 427672741a58e87196511371e17411f1324d7f21 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 2 Sep 2023 22:06:37 +0300 Subject: [PATCH 23/42] Add op_list_as_array --- src/sfall_arrays.cc | 20 ++++++++++ src/sfall_arrays.h | 1 + src/sfall_lists.cc | 92 ++++++++++++++++++++++++-------------------- src/sfall_lists.h | 3 ++ src/sfall_opcodes.cc | 9 +++++ 5 files changed, 84 insertions(+), 41 deletions(-) diff --git a/src/sfall_arrays.cc b/src/sfall_arrays.cc index e074b4c..c0d064b 100644 --- a/src/sfall_arrays.cc +++ b/src/sfall_arrays.cc @@ -11,6 +11,7 @@ #include #include "interpreter.h" +#include "sfall_lists.h" namespace fallout { @@ -647,6 +648,25 @@ ProgramValue ScanArray(ArrayId arrayId, const ProgramValue& val, Program* progra return arr->ScanArray(val, program); } +ArrayId ListAsArray(int type) +{ + std::vector objects; + sfall_lists_fill(type, objects); + + int count = static_cast(objects.size()); + ArrayId arrayId = CreateTempArray(count, 0); + auto arr = get_array_by_id(arrayId); + + // A little bit ugly and likely inefficient. + for (int index = 0; index < count; index++) { + arr->SetArray(ProgramValue { index }, + ArrayElement { ProgramValue { objects[index] }, nullptr }, + false); + } + + return arrayId; +} + ArrayId StringSplit(const char* str, const char* split) { size_t splitLen = strlen(split); diff --git a/src/sfall_arrays.h b/src/sfall_arrays.h index bd96ad5..d976afb 100644 --- a/src/sfall_arrays.h +++ b/src/sfall_arrays.h @@ -26,6 +26,7 @@ void ResizeArray(ArrayId arrayId, int newLen); void DeleteAllTempArrays(); int StackArray(const ProgramValue& key, const ProgramValue& val, Program* program); ProgramValue ScanArray(ArrayId arrayId, const ProgramValue& val, Program* program); +ArrayId ListAsArray(int type); ArrayId StringSplit(const char* str, const char* split); diff --git a/src/sfall_lists.cc b/src/sfall_lists.cc index a582ae2..55150b1 100644 --- a/src/sfall_lists.cc +++ b/src/sfall_lists.cc @@ -1,7 +1,6 @@ #include "sfall_lists.h" #include -#include #include "object.h" #include "scripts.h" @@ -66,46 +65,7 @@ int sfallListsCreate(int listType) int listId = _state->nextListId++; List& list = _state->lists[listId]; - if (listType == LIST_TILES) { - // For unknown reason this list type is not implemented in Sfall. - } else if (listType == LIST_SPATIAL) { - for (int elevation = 0; elevation < ELEVATION_COUNT; elevation++) { - Script* script = scriptGetFirstSpatialScript(elevation); - while (script != nullptr) { - Object* obj = script->owner; - if (obj == nullptr) { - obj = scriptGetSelf(script->program); - } - list.objects.push_back(obj); - script = scriptGetNextSpatialScript(); - } - } - } else { - // CE: Implementation is slightly different. Sfall manually loops thru - // elevations (3) and hexes (40000) and use |objectFindFirstAtLocation| - // (originally |obj_find_first_at_tile|) to obtain next object. This - // functionality is already implemented in |objectFindFirst| and - // |objectFindNext|. - // - // As a small optimization |LIST_ALL| is handled separately since there - // is no need to check object type. - if (listType == LIST_ALL) { - Object* obj = objectFindFirst(); - while (obj != nullptr) { - list.objects.push_back(obj); - obj = objectFindNext(); - } - } else { - Object* obj = objectFindFirst(); - while (obj != nullptr) { - int objectType = PID_TYPE(obj->pid); - if (objectType < kObjectTypeToListTypeSize && kObjectTypeToListType[objectType] == listType) { - list.objects.push_back(obj); - } - obj = objectFindNext(); - } - } - } + sfall_lists_fill(listType, list.objects); return listId; } @@ -131,4 +91,54 @@ void sfallListsDestroy(int listId) } } +void sfall_lists_fill(int type, std::vector& objects) +{ + if (type == LIST_TILES) { + // For unknown reason this list type is not implemented in Sfall. + return; + } + + objects.reserve(100); + + if (type == LIST_SPATIAL) { + for (int elevation = 0; elevation < ELEVATION_COUNT; elevation++) { + Script* script = scriptGetFirstSpatialScript(elevation); + while (script != nullptr) { + Object* obj = script->owner; + if (obj == nullptr) { + obj = scriptGetSelf(script->program); + } + objects.push_back(obj); + script = scriptGetNextSpatialScript(); + } + } + } else { + // CE: Implementation is slightly different. Sfall manually loops thru + // elevations (3) and hexes (40000) and use |objectFindFirstAtLocation| + // (originally |obj_find_first_at_tile|) to obtain next object. This + // functionality is already implemented in |objectFindFirst| and + // |objectFindNext|. + // + // As a small optimization |LIST_ALL| is handled separately since there + // is no need to check object type. + if (type == LIST_ALL) { + Object* obj = objectFindFirst(); + while (obj != nullptr) { + objects.push_back(obj); + obj = objectFindNext(); + } + } else { + Object* obj = objectFindFirst(); + while (obj != nullptr) { + int objectType = PID_TYPE(obj->pid); + if (objectType < kObjectTypeToListTypeSize + && kObjectTypeToListType[objectType] == type) { + objects.push_back(obj); + } + obj = objectFindNext(); + } + } + } +} + } // namespace fallout diff --git a/src/sfall_lists.h b/src/sfall_lists.h index cbcd239..67f3455 100644 --- a/src/sfall_lists.h +++ b/src/sfall_lists.h @@ -1,6 +1,8 @@ #ifndef FALLOUT_SFALL_LISTS_H_ #define FALLOUT_SFALL_LISTS_H_ +#include + #include "obj_types.h" namespace fallout { @@ -22,6 +24,7 @@ void sfallListsExit(); int sfallListsCreate(int listType); Object* sfallListsGetNext(int listId); void sfallListsDestroy(int listId); +void sfall_lists_fill(int type, std::vector& objects); } // namespace fallout diff --git a/src/sfall_opcodes.cc b/src/sfall_opcodes.cc index 8d8cd57..032e1db 100644 --- a/src/sfall_opcodes.cc +++ b/src/sfall_opcodes.cc @@ -556,6 +556,14 @@ static void op_force_encounter_with_flags(Program* program) wmForceEncounter(map, flags); } +// list_as_array +static void op_list_as_array(Program* program) +{ + int type = programStackPopInteger(program); + int arrayId = ListAsArray(type); + programStackPushInteger(program, arrayId); +} + // atoi static void opParseInt(Program* program) { @@ -953,6 +961,7 @@ void sfallOpcodesInit() interpreterRegisterOpcode(0x8233, opTempArray); interpreterRegisterOpcode(0x8234, opFixArray); interpreterRegisterOpcode(0x8235, opStringSplit); + interpreterRegisterOpcode(0x8236, op_list_as_array); interpreterRegisterOpcode(0x8237, opParseInt); interpreterRegisterOpcode(0x8238, op_atof); interpreterRegisterOpcode(0x8239, opScanArray); From b706756ec960599f02ab6007e7e0516925edd53e Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 3 Sep 2023 13:34:16 +0300 Subject: [PATCH 24/42] Add op_get_script --- src/sfall_opcodes.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sfall_opcodes.cc b/src/sfall_opcodes.cc index 032e1db..a07f21d 100644 --- a/src/sfall_opcodes.cc +++ b/src/sfall_opcodes.cc @@ -275,6 +275,13 @@ static void op_abs(Program* program) } } +// get_script +static void op_get_script(Program* program) +{ + Object* obj = static_cast(programStackPopPointer(program)); + programStackPushInteger(program, obj->field_80 + 1); +} + // get_proto_data static void op_get_proto_data(Program* program) { @@ -932,6 +939,7 @@ void sfallOpcodesInit() interpreterRegisterOpcode(0x81EB, op_get_ini_string); interpreterRegisterOpcode(0x81EC, op_sqrt); interpreterRegisterOpcode(0x81ED, op_abs); + interpreterRegisterOpcode(0x81F5, op_get_script); interpreterRegisterOpcode(0x8204, op_get_proto_data); interpreterRegisterOpcode(0x8205, op_set_proto_data); interpreterRegisterOpcode(0x820D, opListBegin); From b40bfcc64a820ea3f50b4268d539fdb3566fb99a Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 3 Sep 2023 16:26:52 +0300 Subject: [PATCH 25/42] Add some metarules --- CMakeLists.txt | 2 + src/combat.cc | 5 + src/combat.h | 1 + src/game_mouse.cc | 5 + src/game_mouse.h | 1 + src/inventory.cc | 5 + src/inventory.h | 1 + src/sfall_ini.cc | 49 +++++++ src/sfall_ini.h | 6 + src/sfall_metarules.cc | 289 +++++++++++++++++++++++++++++++++++++++++ src/sfall_metarules.h | 12 ++ src/sfall_opcodes.cc | 50 +++++++ src/window.cc | 55 +++++++- src/window.h | 4 + 14 files changed, 483 insertions(+), 2 deletions(-) create mode 100644 src/sfall_metarules.cc create mode 100644 src/sfall_metarules.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c6c918..ae87c6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -275,6 +275,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC "src/sfall_kb_helpers.h" "src/sfall_lists.cc" "src/sfall_lists.h" + "src/sfall_metarules.cc" + "src/sfall_metarules.h" "src/sfall_opcodes.cc" "src/sfall_opcodes.h" "src/sfall_arrays.cc" diff --git a/src/combat.cc b/src/combat.cc index 70098c0..6d28fe0 100644 --- a/src/combat.cc +++ b/src/combat.cc @@ -6825,4 +6825,9 @@ void combat_reset_hit_location_penalty() } } +Attack* combat_get_data() +{ + return &_main_ctd; +} + } // namespace fallout diff --git a/src/combat.h b/src/combat.h index 2438b37..6a1667c 100644 --- a/src/combat.h +++ b/src/combat.h @@ -74,6 +74,7 @@ bool damageModGetDisplayBonusDamage(); int combat_get_hit_location_penalty(int hit_location); void combat_set_hit_location_penalty(int hit_location, int penalty); void combat_reset_hit_location_penalty(); +Attack* combat_get_data(); static inline bool isInCombat() { diff --git a/src/game_mouse.cc b/src/game_mouse.cc index fca7c79..193ee4f 100644 --- a/src/game_mouse.cc +++ b/src/game_mouse.cc @@ -2464,4 +2464,9 @@ void gameMouseRefreshImmediately() renderPresent(); } +Object* gmouse_get_outlined_object() +{ + return gGameMouseHighlightedItem; +} + } // namespace fallout diff --git a/src/game_mouse.h b/src/game_mouse.h index 2b99efe..73544b2 100644 --- a/src/game_mouse.h +++ b/src/game_mouse.h @@ -103,6 +103,7 @@ void gameMouseLoadItemHighlight(); void _gmouse_remove_item_outline(Object* object); void gameMouseRefreshImmediately(); +Object* gmouse_get_outlined_object(); } // namespace fallout diff --git a/src/inventory.cc b/src/inventory.cc index 351584c..4b53126 100644 --- a/src/inventory.cc +++ b/src/inventory.cc @@ -5981,4 +5981,9 @@ int _inven_set_timer(Object* a1) return seconds; } +Object* inven_get_current_target_obj() +{ + return _target_stack[_target_curr_stack]; +} + } // namespace fallout diff --git a/src/inventory.h b/src/inventory.h index 58dcf31..7f4aa00 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -27,6 +27,7 @@ int inventoryOpenLooting(Object* a1, Object* a2); int inventoryOpenStealing(Object* a1, Object* a2); void inventoryOpenTrade(int win, Object* a2, Object* a3, Object* a4, int a5); int _inven_set_timer(Object* a1); +Object* inven_get_current_target_obj(); } // namespace fallout diff --git a/src/sfall_ini.cc b/src/sfall_ini.cc index 91af85c..f4a2c91 100644 --- a/src/sfall_ini.cc +++ b/src/sfall_ini.cc @@ -145,4 +145,53 @@ bool sfall_ini_get_string(const char* triplet, char* value, size_t size) return true; } +bool sfall_ini_set_int(const char* triplet, int value) +{ + char stringValue[20]; + compat_itoa(value, stringValue, 10); + + return sfall_ini_set_string(triplet, stringValue); +} + +bool sfall_ini_set_string(const char* triplet, const char* value) +{ + char fileName[kFileNameMaxSize]; + char section[kSectionMaxSize]; + + const char* key = parse_ini_triplet(triplet, fileName, section); + if (key == nullptr) { + return false; + } + + Config config; + if (!configInit(&config)) { + return false; + } + + char path[COMPAT_MAX_PATH]; + bool loaded = false; + + if (basePath[0] != '\0' && !is_system_file_name(fileName)) { + // Attempt to load requested file in base directory. + snprintf(path, sizeof(path), "%s\\%s", basePath, fileName); + loaded = configRead(&config, path, false); + } + + if (!loaded) { + // There was no base path set, requested file is a system config, or + // non-system config file was not found the base path - attempt to load + // from current working directory. + strcpy(path, fileName); + loaded = configRead(&config, path, false); + } + + configSetString(&config, section, key, value); + + bool saved = configWrite(&config, path, false); + + configFree(&config); + + return saved; +} + } // namespace fallout diff --git a/src/sfall_ini.h b/src/sfall_ini.h index ac4cdd8..092b40c 100644 --- a/src/sfall_ini.h +++ b/src/sfall_ini.h @@ -14,6 +14,12 @@ bool sfall_ini_get_int(const char* triplet, int* value); /// Reads string key identified by "fileName|section|key" triplet into `value`. bool sfall_ini_get_string(const char* triplet, char* value, size_t size); +/// Writes integer key identified by "fileName|section|key" triplet. +bool sfall_ini_set_int(const char* triplet, int value); + +/// Writes string key identified by "fileName|section|key" triplet. +bool sfall_ini_set_string(const char* triplet, const char* value); + } // namespace fallout #endif /* FALLOUT_SFALL_INI_H_ */ diff --git a/src/sfall_metarules.cc b/src/sfall_metarules.cc new file mode 100644 index 0000000..558645b --- /dev/null +++ b/src/sfall_metarules.cc @@ -0,0 +1,289 @@ +#include "sfall_metarules.h" + +#include "combat.h" +#include "debug.h" +#include "game.h" +#include "game_dialog.h" +#include "game_mouse.h" +#include "interface.h" +#include "inventory.h" +#include "object.h" +#include "sfall_ini.h" +#include "text_font.h" +#include "tile.h" +#include "window.h" +#include "worldmap.h" + +namespace fallout { + +typedef void(MetaruleHandler)(Program* program, int args); + +// Simplified cousin of `SfallMetarule` from Sfall. +typedef struct MetaruleInfo { + const char* name; + MetaruleHandler* handler; + int minArgs; + int maxArgs; +} MetaruleInfo; + +static void mf_car_gas_amount(Program* program, int args); +static void mf_combat_data(Program* program, int args); +static void mf_critter_inven_obj2(Program* program, int args); +static void mf_dialog_obj(Program* program, int args); +static void mf_get_cursor_mode(Program* program, int args); +static void mf_get_flags(Program* program, int args); +static void mf_get_object_data(Program* program, int args); +static void mf_get_text_width(Program* program, int args); +static void mf_intface_redraw(Program* program, int args); +static void mf_loot_obj(Program* program, int args); +static void mf_metarule_exist(Program* program, int args); +static void mf_outlined_object(Program* program, int args); +static void mf_set_cursor_mode(Program* program, int args); +static void mf_set_flags(Program* program, int args); +static void mf_set_ini_setting(Program* program, int args); +static void mf_set_outline(Program* program, int args); +static void mf_show_window(Program* program, int args); +static void mf_tile_refresh_display(Program* program, int args); + +constexpr MetaruleInfo kMetarules[] = { + { "car_gas_amount", mf_car_gas_amount, 0, 0 }, + { "combat_data", mf_combat_data, 0, 0 }, + { "critter_inven_obj2", mf_critter_inven_obj2, 2, 2 }, + { "dialog_obj", mf_dialog_obj, 0, 0 }, + { "get_cursor_mode", mf_get_cursor_mode, 0, 0 }, + { "get_flags", mf_get_flags, 1, 1 }, + { "get_object_data", mf_get_object_data, 2, 2 }, + { "get_text_width", mf_get_text_width, 1, 1 }, + { "intface_redraw", mf_intface_redraw, 0, 1 }, + { "loot_obj", mf_loot_obj, 0, 0 }, + { "metarule_exist", mf_metarule_exist, 1, 1 }, + { "outlined_object", mf_outlined_object, 0, 0 }, + { "set_cursor_mode", mf_set_cursor_mode, 1, 1 }, + { "set_flags", mf_set_flags, 2, 2 }, + { "set_ini_setting", mf_set_ini_setting, 2, 2 }, + { "set_outline", mf_set_outline, 2, 2 }, + { "show_window", mf_show_window, 0, 1 }, + { "tile_refresh_display", mf_tile_refresh_display, 0, 0 }, +}; + +constexpr int kMetarulesMax = sizeof(kMetarules) / sizeof(kMetarules[0]); + +void mf_car_gas_amount(Program* program, int args) +{ + programStackPushInteger(program, wmCarGasAmount()); +} + +void mf_combat_data(Program* program, int args) +{ + if (isInCombat()) { + programStackPushPointer(program, combat_get_data()); + } else { + programStackPushPointer(program, nullptr); + } +} + +void mf_critter_inven_obj2(Program* program, int args) +{ + int slot = programStackPopInteger(program); + Object* obj = static_cast(programStackPopPointer(program)); + + switch (slot) { + case 0: + programStackPushPointer(program, critterGetArmor(obj)); + break; + case 1: + programStackPushPointer(program, critterGetItem2(obj)); + break; + case 2: + programStackPushPointer(program, critterGetItem1(obj)); + break; + case -2: + programStackPushInteger(program, obj->data.inventory.length); + break; + default: + programFatalError("mf_critter_inven_obj2: invalid type"); + } +} + +void mf_dialog_obj(Program* program, int args) +{ + if (GameMode::isInGameMode(GameMode::kDialog)) { + programStackPushPointer(program, gGameDialogSpeaker); + } else { + programStackPushPointer(program, nullptr); + } +} + +void mf_get_cursor_mode(Program* program, int args) +{ + programStackPushInteger(program, gameMouseGetMode()); +} + +void mf_get_flags(Program* program, int args) +{ + Object* object = static_cast(programStackPopPointer(program)); + programStackPushInteger(program, object->flags); +} + +void mf_get_object_data(Program* program, int args) +{ + size_t offset = static_cast(programStackPopInteger(program)); + void* ptr = programStackPopPointer(program); + + if (offset % 4 != 0) { + programFatalError("mf_get_object_data: bad offset %d", offset); + } + + int value = *reinterpret_cast(reinterpret_cast(ptr) + offset); + programStackPushInteger(program, value); +} + +void mf_get_text_width(Program* program, int args) +{ + const char* string = programStackPopString(program); + programStackPushInteger(program, fontGetStringWidth(string)); +} + +void mf_intface_redraw(Program* program, int args) +{ + if (args == 0) { + interfaceBarRefresh(); + } else { + // TODO: Incomplete. + programFatalError("mf_intface_redraw: not implemented"); + } + + programStackPushInteger(program, -1); +} + +void mf_loot_obj(Program* program, int args) +{ + if (GameMode::isInGameMode(GameMode::kInventory)) { + programStackPushPointer(program, inven_get_current_target_obj()); + } else { + programStackPushPointer(program, nullptr); + } +} + +void mf_metarule_exist(Program* program, int args) +{ + const char* metarule = programStackPopString(program); + + for (int index = 0; index < kMetarulesMax; index++) { + if (strcmp(kMetarules[index].name, metarule) == 0) { + programStackPushInteger(program, 1); + return; + } + } + + programStackPushInteger(program, 0); +} + +void mf_outlined_object(Program* program, int args) +{ + programStackPushPointer(program, gmouse_get_outlined_object()); +} + +void mf_set_cursor_mode(Program* program, int args) +{ + int mode = programStackPopInteger(program); + gameMouseSetMode(mode); + programStackPushInteger(program, -1); +} + +void mf_set_flags(Program* program, int args) +{ + int flags = programStackPopInteger(program); + Object* object = static_cast(programStackPopPointer(program)); + + object->flags = flags; + + programStackPushInteger(program, -1); +} + +void mf_set_ini_setting(Program* program, int args) +{ + ProgramValue value = programStackPopValue(program); + const char* triplet = programStackPopString(program); + + if (value.isString()) { + const char* stringValue = programGetString(program, value.opcode, value.integerValue); + if (!sfall_ini_set_string(triplet, stringValue)) { + debugPrint("set_ini_setting: unable to write '%s' to '%s'", + stringValue, + triplet); + } + } else { + int integerValue = value.asInt(); + if (!sfall_ini_set_int(triplet, integerValue)) { + debugPrint("set_ini_setting: unable to write '%d' to '%s'", + integerValue, + triplet); + } + } + + programStackPushInteger(program, -1); +} + +void mf_set_outline(Program* program, int args) +{ + int outline = programStackPopInteger(program); + Object* object = static_cast(programStackPopPointer(program)); + object->outline = outline; + programStackPushInteger(program, -1); +} + +void mf_show_window(Program* program, int args) +{ + if (args == 0) { + _windowShow(); + } else if (args == 1) { + const char* windowName = programStackPopString(program); + if (!_windowShowNamed(windowName)) { + debugPrint("show_window: window '%s' is not found", windowName); + } + } + + programStackPushInteger(program, -1); +} + +void mf_tile_refresh_display(Program* program, int args) +{ + tileWindowRefresh(); + programStackPushInteger(program, -1); +} + +void sfall_metarule(Program* program, int args) +{ + static ProgramValue values[6]; + + for (int index = 0; index < args; index++) { + values[index] = programStackPopValue(program); + } + + const char* metarule = programStackPopString(program); + + for (int index = 0; index < args; index++) { + programStackPushValue(program, values[index]); + } + + int metaruleIndex = -1; + for (int index = 0; index < kMetarulesMax; index++) { + if (strcmp(kMetarules[index].name, metarule) == 0) { + metaruleIndex = index; + break; + } + } + + if (metaruleIndex == -1) { + programFatalError("op_sfall_func: '%s' is not implemented", metarule); + } + + if (args < kMetarules[metaruleIndex].minArgs || args > kMetarules[metaruleIndex].maxArgs) { + programFatalError("op_sfall_func: '%s': invalid number of args", metarule); + } + + kMetarules[metaruleIndex].handler(program, args); +} + +} // namespace fallout diff --git a/src/sfall_metarules.h b/src/sfall_metarules.h new file mode 100644 index 0000000..360fc0c --- /dev/null +++ b/src/sfall_metarules.h @@ -0,0 +1,12 @@ +#ifndef FALLOUT_SFALL_METARULES_H_ +#define FALLOUT_SFALL_METARULES_H_ + +#include "interpreter.h" + +namespace fallout { + +void sfall_metarule(Program* program, int args); + +} // namespace fallout + +#endif /* FALLOUT_SFALL_METARULES_H_ */ diff --git a/src/sfall_opcodes.cc b/src/sfall_opcodes.cc index a07f21d..2534e4b 100644 --- a/src/sfall_opcodes.cc +++ b/src/sfall_opcodes.cc @@ -26,6 +26,7 @@ #include "sfall_ini.h" #include "sfall_kb_helpers.h" #include "sfall_lists.h" +#include "sfall_metarules.h" #include "stat.h" #include "svga.h" #include "tile.h" @@ -889,6 +890,48 @@ static void opArtExists(Program* program) programStackPushInteger(program, artExists(fid)); } +// sfall_func0 +static void op_sfall_func0(Program* program) +{ + sfall_metarule(program, 0); +} + +// sfall_func1 +static void op_sfall_func1(Program* program) +{ + sfall_metarule(program, 1); +} + +// sfall_func2 +static void op_sfall_func2(Program* program) +{ + sfall_metarule(program, 2); +} + +// sfall_func3 +static void op_sfall_func3(Program* program) +{ + sfall_metarule(program, 3); +} + +// sfall_func4 +static void op_sfall_func4(Program* program) +{ + sfall_metarule(program, 4); +} + +// sfall_func5 +static void op_sfall_func5(Program* program) +{ + sfall_metarule(program, 5); +} + +// sfall_func6 +static void op_sfall_func6(Program* program) +{ + sfall_metarule(program, 6); +} + // div (/) static void op_div(Program* program) { @@ -986,6 +1029,13 @@ void sfallOpcodesInit() interpreterRegisterOpcode(0x826F, op_obj_blocking_at); interpreterRegisterOpcode(0x8271, opPartyMemberList); interpreterRegisterOpcode(0x8274, opArtExists); + interpreterRegisterOpcode(0x8276, op_sfall_func0); + interpreterRegisterOpcode(0x8277, op_sfall_func1); + interpreterRegisterOpcode(0x8278, op_sfall_func2); + interpreterRegisterOpcode(0x8279, op_sfall_func3); + interpreterRegisterOpcode(0x827A, op_sfall_func4); + interpreterRegisterOpcode(0x827B, op_sfall_func5); + interpreterRegisterOpcode(0x827C, op_sfall_func6); interpreterRegisterOpcode(0x827F, op_div); } diff --git a/src/window.cc b/src/window.cc index fd9e9d8..8d496dd 100644 --- a/src/window.cc +++ b/src/window.cc @@ -70,6 +70,8 @@ typedef struct ManagedWindow { typedef int (*INITVIDEOFN)(); +static void redrawButton(ManagedButton* managedButton); + // 0x51DCAC static int _holdTime = 250; @@ -663,6 +665,38 @@ void _setButtonGFX(int width, int height, unsigned char* normal, unsigned char* } } +// 0x4B75F4 +static void redrawButton(ManagedButton* managedButton) +{ + _win_register_button_image(managedButton->btn, managedButton->normal, managedButton->pressed, managedButton->hover, false); +} + +// 0x4B7610 +bool _windowHide() +{ + ManagedWindow* managedWindow = &(gManagedWindows[gCurrentManagedWindowIndex]); + if (managedWindow->window == -1) { + return false; + } + + windowHide(managedWindow->window); + + return true; +} + +// 0x4B7648 +bool _windowShow() +{ + ManagedWindow* managedWindow = &(gManagedWindows[gCurrentManagedWindowIndex]); + if (managedWindow->window == -1) { + return false; + } + + windowShow(managedWindow->window); + + return true; +} + // 0x4B7734 int _windowWidth() { @@ -1714,7 +1748,8 @@ bool _windowAddButtonGfx(const char* buttonName, char* pressedFileName, char* no buttonSetMask(managedButton->btn, managedButton->normal); } - _win_register_button_image(managedButton->btn, managedButton->normal, managedButton->pressed, managedButton->hover, 0); + // NOTE: Uninline. + redrawButton(managedButton); return true; } @@ -1952,7 +1987,8 @@ bool _windowAddButtonTextWithOffsets(const char* buttonName, const char* text, i buttonSetMask(managedButton->btn, managedButton->normal); } - _win_register_button_image(managedButton->btn, managedButton->normal, managedButton->pressed, managedButton->hover, 0); + // NOTE: Uninline. + redrawButton(managedButton); return true; } @@ -2646,4 +2682,19 @@ void _fillBuf3x3(unsigned char* src, int srcWidth, int srcHeight, unsigned char* destWidth); } +bool _windowShowNamed(const char* windowName) +{ + for (int index = 0; index < MANAGED_WINDOW_COUNT; index++) { + ManagedWindow* managedWindow = &(gManagedWindows[index]); + if (managedWindow->window != -1) { + if (compat_stricmp(managedWindow->name, windowName) == 0) { + windowShow(managedWindow->window); + return true; + } + } + } + + return false; +} + } // namespace fallout diff --git a/src/window.h b/src/window.h index 2ae415c..dde6b19 100644 --- a/src/window.h +++ b/src/window.h @@ -63,6 +63,8 @@ void _doRightButtonPress(int btn, int keyCode); void sub_4B704C(int btn, int mouseEvent); void _doRightButtonRelease(int btn, int keyCode); void _setButtonGFX(int width, int height, unsigned char* normal, unsigned char* pressed, unsigned char* a5); +bool _windowHide(); +bool _windowShow(); int _windowWidth(); int _windowHeight(); bool _windowDraw(); @@ -127,6 +129,8 @@ void _drawScaledBuf(unsigned char* dest, int destWidth, int destHeight, unsigned void _alphaBltBuf(unsigned char* src, int srcWidth, int srcHeight, int srcPitch, unsigned char* alphaWindowBuffer, unsigned char* alphaBuffer, unsigned char* dest, int destPitch); void _fillBuf3x3(unsigned char* src, int srcWidth, int srcHeight, unsigned char* dest, int destWidth, int destHeight); +bool _windowShowNamed(const char* name); + } // namespace fallout #endif /* WINDOW_H */ From ad3e0eb752150c78cb5fbe48dd0dfc44c033d4f0 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 3 Sep 2023 16:51:29 +0300 Subject: [PATCH 26/42] Add op_explosions_metarule --- src/sfall_opcodes.cc | 71 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/sfall_opcodes.cc b/src/sfall_opcodes.cc index 2534e4b..d070539 100644 --- a/src/sfall_opcodes.cc +++ b/src/sfall_opcodes.cc @@ -34,6 +34,18 @@ namespace fallout { +typedef enum ExplosionMetarule { + EXPL_FORCE_EXPLOSION_PATTERN = 1, + EXPL_FORCE_EXPLOSION_ART = 2, + EXPL_FORCE_EXPLOSION_RADIUS = 3, + EXPL_FORCE_EXPLOSION_DMGTYPE = 4, + EXPL_STATIC_EXPLOSION_RADIUS = 5, + EXPL_GET_EXPLOSION_DAMAGE = 6, + EXPL_SET_DYNAMITE_EXPLOSION_DAMAGE = 7, + EXPL_SET_PLASTIC_EXPLOSION_DAMAGE = 8, + EXPL_SET_EXPLOSION_MAX_TARGET = 9, +} ExplosionMetarule; + static constexpr int kVersionMajor = 4; static constexpr int kVersionMinor = 3; static constexpr int kVersionPatch = 4; @@ -651,6 +663,64 @@ static void opGetStringLength(Program* program) programStackPushInteger(program, static_cast(strlen(string))); } +// metarule2_explosions +static void op_explosions_metarule(Program* program) +{ + int param2 = programStackPopInteger(program); + int param1 = programStackPopInteger(program); + int metarule = programStackPopInteger(program); + + switch (metarule) { + case EXPL_FORCE_EXPLOSION_PATTERN: + if (param1 != 0) { + explosionSetPattern(2, 4); + } else { + explosionSetPattern(0, 6); + } + programStackPushInteger(program, 0); + break; + case EXPL_FORCE_EXPLOSION_ART: + explosionSetFrm(param1); + programStackPushInteger(program, 0); + break; + case EXPL_FORCE_EXPLOSION_RADIUS: + explosionSetRadius(param1); + programStackPushInteger(program, 0); + break; + case EXPL_FORCE_EXPLOSION_DMGTYPE: + explosionSetDamageType(param1); + programStackPushInteger(program, 0); + break; + case EXPL_STATIC_EXPLOSION_RADIUS: + weaponSetGrenadeExplosionRadius(param1); + weaponSetRocketExplosionRadius(param2); + programStackPushInteger(program, 0); + break; + case EXPL_GET_EXPLOSION_DAMAGE: + if (1) { + int minDamage; + int maxDamage; + explosiveGetDamage(param1, &minDamage, &maxDamage); + + ArrayId arrayId = CreateTempArray(2, 0); + SetArray(arrayId, ProgramValue { 0 }, ProgramValue { minDamage }, false, program); + SetArray(arrayId, ProgramValue { 1 }, ProgramValue { maxDamage }, false, program); + + programStackPushInteger(program, arrayId); + } + break; + case EXPL_SET_DYNAMITE_EXPLOSION_DAMAGE: + explosiveSetDamage(PROTO_ID_DYNAMITE_I, param1, param2); + break; + case EXPL_SET_PLASTIC_EXPLOSION_DAMAGE: + explosiveSetDamage(PROTO_ID_PLASTIC_EXPLOSIVES_I, param1, param2); + break; + case EXPL_SET_EXPLOSION_MAX_TARGET: + explosionSetMaxTargets(param1); + break; + } +} + // pow (^) static void op_power(Program* program) { @@ -1022,6 +1092,7 @@ void sfallOpcodesInit() interpreterRegisterOpcode(0x8253, opTypeOf); interpreterRegisterOpcode(0x8256, opGetArrayKey); interpreterRegisterOpcode(0x8257, opStackArray); + interpreterRegisterOpcode(0x8261, op_explosions_metarule); interpreterRegisterOpcode(0x8263, op_power); interpreterRegisterOpcode(0x8267, opRound); interpreterRegisterOpcode(0x826B, opGetMessage); From 6e9f1ae51734d583d949375a7c0fefd291b3c456 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 3 Sep 2023 18:23:19 +0300 Subject: [PATCH 27/42] Add op_set_self --- src/interpreter_extra.cc | 23 +++++++++++++++++++++-- src/scripts.cc | 2 ++ src/scripts.h | 2 ++ src/sfall_opcodes.cc | 14 ++++++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/interpreter_extra.cc b/src/interpreter_extra.cc index b2d3295..ca3e5e0 100644 --- a/src/interpreter_extra.cc +++ b/src/interpreter_extra.cc @@ -1580,12 +1580,22 @@ static void opPickup(Program* program) return; } - if (script->target == NULL) { + Object* self = script->target; + + // SFALL: Override `self` via `op_set_self`. + // CE: Implementation is different. Sfall integrates via `scriptGetSid` by + // returning fake script with overridden `self` (and `target` in this case). + if (script->overriddenSelf != nullptr) { + self = script->overriddenSelf; + script->overriddenSelf = nullptr; + } + + if (self == NULL) { scriptPredefinedError(program, "pickup_obj", SCRIPT_ERROR_OBJECT_IS_NULL); return; } - actionPickUp(script->target, object); + actionPickUp(self, object); } // drop_obj @@ -4548,6 +4558,15 @@ static void opUseObjectOnObject(Program* program) } Object* self = scriptGetSelf(program); + + // SFALL: Override `self` via `op_set_self`. + // CE: Implementation is different. Sfall integrates via `scriptGetSid` by + // returning fake script with overridden `self`. + if (script->overriddenSelf != nullptr) { + self = script->overriddenSelf; + script->overriddenSelf = nullptr; + } + if (PID_TYPE(self->pid) == OBJ_TYPE_CRITTER) { _action_use_an_item_on_object(self, target, item); } else { diff --git a/src/scripts.cc b/src/scripts.cc index 58dab5d..1485fff 100644 --- a/src/scripts.cc +++ b/src/scripts.cc @@ -2214,6 +2214,8 @@ int scriptAdd(int* sidPtr, int scriptType) scr->procs[index] = SCRIPT_PROC_NO_PROC; } + scr->overriddenSelf = nullptr; + scriptListExtent->length++; return 0; diff --git a/src/scripts.h b/src/scripts.h index 5cc3220..782591c 100644 --- a/src/scripts.h +++ b/src/scripts.h @@ -143,6 +143,8 @@ typedef struct Script { int field_D4; int field_D8; int field_DC; + + Object* overriddenSelf; } Script; extern const char* gScriptProcNames[SCRIPT_PROC_COUNT]; diff --git a/src/sfall_opcodes.cc b/src/sfall_opcodes.cc index d070539..d202c1b 100644 --- a/src/sfall_opcodes.cc +++ b/src/sfall_opcodes.cc @@ -345,6 +345,19 @@ static void op_set_proto_data(Program* program) *reinterpret_cast(reinterpret_cast(proto) + offset) = value; } +// set_self +static void op_set_self(Program* program) +{ + Object* obj = static_cast(programStackPopPointer(program)); + + int sid = scriptGetSid(program); + + Script* scr; + if (scriptGetScript(sid, &scr) == 0) { + scr->overriddenSelf = obj; + } +} + // list_begin static void opListBegin(Program* program) { @@ -1055,6 +1068,7 @@ void sfallOpcodesInit() interpreterRegisterOpcode(0x81F5, op_get_script); interpreterRegisterOpcode(0x8204, op_get_proto_data); interpreterRegisterOpcode(0x8205, op_set_proto_data); + interpreterRegisterOpcode(0x8206, op_set_self); interpreterRegisterOpcode(0x820D, opListBegin); interpreterRegisterOpcode(0x820E, opListNext); interpreterRegisterOpcode(0x820F, opListEnd); From 8c61b0bd8c9818506340562c21960356c951abe0 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 3 Sep 2023 19:15:50 +0300 Subject: [PATCH 28/42] Add sort_rect --- src/mapper/map_func.cc | 20 ++++++++++++++++++++ src/mapper/map_func.h | 1 + 2 files changed, 21 insertions(+) diff --git a/src/mapper/map_func.cc b/src/mapper/map_func.cc index 8b032f2..0ba769c 100644 --- a/src/mapper/map_func.cc +++ b/src/mapper/map_func.cc @@ -22,6 +22,26 @@ void copy_proto_lists() // TODO: Incomplete. } +// 0x484294 +void sort_rect(Rect* a, Rect* b) +{ + if (b->right > b->left) { + a->left = b->left; + a->right = b->right; + } else { + a->left = b->right; + a->right = b->left; + } + + if (b->bottom > b->top) { + a->top = b->top; + a->bottom = b->bottom; + } else { + a->top = b->bottom; + a->bottom = b->top; + } +} + // 0x4842D4 void draw_rect(Rect* rect, unsigned char color) { diff --git a/src/mapper/map_func.h b/src/mapper/map_func.h index 3d03b42..843f72a 100644 --- a/src/mapper/map_func.h +++ b/src/mapper/map_func.h @@ -7,6 +7,7 @@ namespace fallout { void setup_map_dirs(); void copy_proto_lists(); +void sort_rect(Rect* a, Rect* b); void draw_rect(Rect* rect); void erase_rect(Rect* rect); int toolbar_proto(int type, int id); From 30a3bf9b7127874ce3aae21834abc72af1d00b7e Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 3 Sep 2023 20:12:20 +0300 Subject: [PATCH 29/42] Add pick_region --- src/input.cc | 7 +++++++ src/input.h | 1 + src/mapper/map_func.cc | 44 ++++++++++++++++++++++++++++++++++++++++++ src/mapper/map_func.h | 3 ++- 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/input.cc b/src/input.cc index ccfa5a6..1bf56ac 100644 --- a/src/input.cc +++ b/src/input.cc @@ -199,6 +199,13 @@ int inputGetInput() return -1; } +// 0x4C8BC8 +void get_input_position(int* x, int* y) +{ + *x = _input_mx; + *y = _input_my; +} + // 0x4C8BDC void _process_bk() { diff --git a/src/input.h b/src/input.h index 93a0c93..5539af1 100644 --- a/src/input.h +++ b/src/input.h @@ -13,6 +13,7 @@ typedef int(ScreenshotHandler)(int width, int height, unsigned char* buffer, uns int inputInit(int a1); void inputExit(); int inputGetInput(); +void get_input_position(int* x, int* y); void _process_bk(); void enqueueInputEvent(int a1); void inputEventQueueReset(); diff --git a/src/mapper/map_func.cc b/src/mapper/map_func.cc index 0ba769c..92a96fa 100644 --- a/src/mapper/map_func.cc +++ b/src/mapper/map_func.cc @@ -1,6 +1,10 @@ #include "mapper/map_func.h" +#include "color.h" +#include "game_mouse.h" +#include "input.h" #include "memory.h" +#include "mouse.h" #include "proto.h" #include "svga.h" #include "window_manager.h" @@ -22,6 +26,46 @@ void copy_proto_lists() // TODO: Incomplete. } +// 0x4841C4 +void pick_region(Rect* rect) +{ + Rect temp; + int x; + int y; + + gameMouseSetCursor(MOUSE_CURSOR_PLUS); + gameMouseObjectsHide(); + + while (1) { + if (inputGetInput() == -2 + && (mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_DOWN) != 0) { + break; + } + } + + get_input_position(&x, &y); + temp.left = x; + temp.top = y; + temp.right = x; + temp.bottom = y; + + while ((mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_UP) == 0) { + inputGetInput(); + + get_input_position(&x, &y); + + if (x != temp.right || y != temp.bottom) { + erase_rect(rect); + sort_rect(rect, &temp); + draw_rect(rect, _colorTable[32747]); + } + } + + erase_rect(rect); + gameMouseSetCursor(MOUSE_CURSOR_ARROW); + gameMouseObjectsShow(); +} + // 0x484294 void sort_rect(Rect* a, Rect* b) { diff --git a/src/mapper/map_func.h b/src/mapper/map_func.h index 843f72a..71517e9 100644 --- a/src/mapper/map_func.h +++ b/src/mapper/map_func.h @@ -7,8 +7,9 @@ namespace fallout { void setup_map_dirs(); void copy_proto_lists(); +void pick_region(Rect* rect); void sort_rect(Rect* a, Rect* b); -void draw_rect(Rect* rect); +void draw_rect(Rect* rect, unsigned char color); void erase_rect(Rect* rect); int toolbar_proto(int type, int id); bool map_toggle_block_obj_viewing_on(); From 0d83cff24ec98ebacc0962cbe5f39a6fd02eaa1c Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 3 Sep 2023 20:24:36 +0300 Subject: [PATCH 30/42] Add place_entrance_hex --- src/actions.cc | 3 +++ src/actions.h | 2 ++ src/mapper/map_func.cc | 30 ++++++++++++++++++++++++++++++ src/mapper/map_func.h | 1 + 4 files changed, 36 insertions(+) diff --git a/src/actions.cc b/src/actions.cc index 292e5ce..8368546 100644 --- a/src/actions.cc +++ b/src/actions.cc @@ -48,6 +48,9 @@ typedef enum ScienceRepairTargetType { // 0x5106D0 static bool _action_in_explode = false; +// 0x5106D4 +int rotation; + // 0x5106E0 static const int gNormalDeathAnimations[DAMAGE_TYPE_COUNT] = { ANIM_DANCING_AUTOFIRE, diff --git a/src/actions.h b/src/actions.h index 67d425f..86c0f31 100644 --- a/src/actions.h +++ b/src/actions.h @@ -6,6 +6,8 @@ namespace fallout { +extern int rotation; + int _action_attack(Attack* attack); int _action_use_an_item_on_object(Object* a1, Object* a2, Object* a3); int _action_use_an_object(Object* a1, Object* a2); diff --git a/src/mapper/map_func.cc b/src/mapper/map_func.cc index 92a96fa..1fcd136 100644 --- a/src/mapper/map_func.cc +++ b/src/mapper/map_func.cc @@ -1,13 +1,17 @@ #include "mapper/map_func.h" +#include "actions.h" #include "color.h" #include "game_mouse.h" #include "input.h" +#include "map.h" #include "memory.h" #include "mouse.h" #include "proto.h" #include "svga.h" +#include "tile.h" #include "window_manager.h" +#include "window_manager_private.h" namespace fallout { @@ -26,6 +30,32 @@ void copy_proto_lists() // TODO: Incomplete. } +// 0x482708 +void place_entrance_hex() +{ + int x; + int y; + int tile; + + while (inputGetInput() != -2) { + } + + if ((mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_DOWN) != 0) { + if (_mouse_click_in(0, 0, _scr_size.right - _scr_size.left, _scr_size.bottom - _scr_size.top - 100)) { + mouseGetPosition(&x, &y); + + tile = tileFromScreenXY(x, y, gElevation); + if (tile != -1) { + if (tileSetCenter(tile, TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS) == 0) { + mapSetEnteringLocation(tile, gElevation, rotation); + } else { + win_timed_msg("ERROR: Entrance out of range!", _colorTable[31744]); + } + } + } + } +} + // 0x4841C4 void pick_region(Rect* rect) { diff --git a/src/mapper/map_func.h b/src/mapper/map_func.h index 71517e9..ff06627 100644 --- a/src/mapper/map_func.h +++ b/src/mapper/map_func.h @@ -7,6 +7,7 @@ namespace fallout { void setup_map_dirs(); void copy_proto_lists(); +void place_entrance_hex(); void pick_region(Rect* rect); void sort_rect(Rect* a, Rect* b); void draw_rect(Rect* rect, unsigned char color); From ee1923866729e13f25aaa695edfb6a88b9e4a9e9 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 3 Sep 2023 20:48:23 +0300 Subject: [PATCH 31/42] Add update_toolname --- src/mapper/mapper.cc | 80 ++++++++++++++++++++++++++++++++++++++++++++ src/proto.cc | 2 +- src/proto.h | 1 + 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/mapper/mapper.cc b/src/mapper/mapper.cc index 8afe3eb..ff3d184 100644 --- a/src/mapper/mapper.cc +++ b/src/mapper/mapper.cc @@ -46,6 +46,7 @@ static void edit_mapper(); static void mapper_load_toolbar(int a1, int a2); static void redraw_toolname(); static void clear_toolname(); +static void update_toolname(int* pid, int type, int id); static void update_high_obj_name(Object* obj); static int mapper_mark_exit_grid(); static void mapper_mark_all_exit_grids(); @@ -1408,6 +1409,85 @@ void clear_toolname() redraw_toolname(); } +// 0x48B328 +void update_toolname(int* pid, int type, int id) +{ + Proto* proto; + + *pid = toolbar_proto(type, id); + + if (protoGetProto(*pid, &proto) == -1) { + return; + } + + windowDrawText(tool_win, + protoGetName(proto->pid), + 120, + _scr_size.right - _scr_size.left - 149, + 60, + 260); + + switch (PID_TYPE(proto->pid)) { + case OBJ_TYPE_ITEM: + windowDrawText(tool_win, + gItemTypeNames[proto->item.type], + 120, + _scr_size.right - _scr_size.left - 149, + 70, + 260); + break; + case OBJ_TYPE_CRITTER: + windowDrawText(tool_win, + "", + 120, + _scr_size.right - _scr_size.left - 149, + 70, + 260); + break; + case OBJ_TYPE_WALL: + windowDrawText(tool_win, + proto_wall_light_str(proto->wall.flags), + 120, + _scr_size.right - _scr_size.left - 149, + 70, + 260); + break; + case OBJ_TYPE_TILE: + windowDrawText(tool_win, + "", + 120, + _scr_size.right - _scr_size.left - 149, + 70, + 260); + break; + case OBJ_TYPE_MISC: + windowDrawText(tool_win, + "", + 120, + _scr_size.right - _scr_size.left - 149, + 70, + 260); + break; + default: + windowDrawText(tool_win, + "", + 120, + _scr_size.right - _scr_size.left - 149, + 70, + 260); + break; + } + + windowDrawText(tool_win, + "", + 120, + _scr_size.right - _scr_size.left - 149, + 80, + 260); + + redraw_toolname(); +} + // 0x48B5BC void update_high_obj_name(Object* obj) { diff --git a/src/proto.cc b/src/proto.cc index f266498..0920054 100644 --- a/src/proto.cc +++ b/src/proto.cc @@ -167,7 +167,7 @@ char* _proto_none_str; static char* gBodyTypeNames[BODY_TYPE_COUNT]; // 0x664834 -static char* gItemTypeNames[ITEM_TYPE_COUNT]; +char* gItemTypeNames[ITEM_TYPE_COUNT]; // 0x66484C static char* gDamageTypeNames[DAMAGE_TYPE_COUNT]; diff --git a/src/proto.h b/src/proto.h index f49d1a6..40cded9 100644 --- a/src/proto.h +++ b/src/proto.h @@ -101,6 +101,7 @@ extern char _cd_path_base[COMPAT_MAX_PATH]; extern MessageList gProtoMessageList; extern char* _proto_none_str; +extern char* gItemTypeNames[ITEM_TYPE_COUNT]; void proto_make_path(char* path, int pid); int _proto_list_str(int pid, char* proto_path); From d46ee075838c5f853c2d2c4c12f6e69a77eb9099 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 3 Sep 2023 21:30:59 +0300 Subject: [PATCH 32/42] Add mapper_destroy_highlight_obj --- src/mapper/mapper.cc | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/mapper/mapper.cc b/src/mapper/mapper.cc index ff3d184..2902444 100644 --- a/src/mapper/mapper.cc +++ b/src/mapper/mapper.cc @@ -48,6 +48,7 @@ static void redraw_toolname(); static void clear_toolname(); static void update_toolname(int* pid, int type, int id); static void update_high_obj_name(Object* obj); +static void mapper_destroy_highlight_obj(Object** a1, Object** a2); static int mapper_mark_exit_grid(); static void mapper_mark_all_exit_grids(); @@ -1501,6 +1502,28 @@ void update_high_obj_name(Object* obj) } } +// 0x48B680 +void mapper_destroy_highlight_obj(Object** a1, Object** a2) +{ + Rect rect; + int elevation; + + if (a2 != NULL && *a2 != NULL) { + elevation = (*a2)->elevation; + reg_anim_clear(*a2); + objectDestroy(*a2, &rect); + tileWindowRefreshRect(&rect, elevation); + *a2 = NULL; + } + + if (a1 != NULL && *a1 != NULL) { + elevation = (*a1)->elevation; + objectDestroy(*a1, &rect); + tileWindowRefreshRect(&rect, elevation); + *a1 = NULL; + } +} + // 0x48C604 int mapper_inven_unwield(Object* obj, int right_hand) { From def8effa9f1026441119de40046e6c83094f7370 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 3 Sep 2023 21:42:17 +0300 Subject: [PATCH 33/42] Add handle_new_map --- src/mapper/mapper.cc | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/mapper/mapper.cc b/src/mapper/mapper.cc index 2902444..de0d778 100644 --- a/src/mapper/mapper.cc +++ b/src/mapper/mapper.cc @@ -49,6 +49,8 @@ static void clear_toolname(); static void update_toolname(int* pid, int type, int id); static void update_high_obj_name(Object* obj); static void mapper_destroy_highlight_obj(Object** a1, Object** a2); +static void update_art(int a1, int a2); +static void handle_new_map(int* a1, int* a2); static int mapper_mark_exit_grid(); static void mapper_mark_all_exit_grids(); @@ -182,6 +184,9 @@ int art_scale_width = 49; // 0x559888 int art_scale_height = 48; +// 0x5598A0 +static bool map_entered = false; + // 0x5598A4 static char* tmp_map_name = kTmpMapName; @@ -1524,6 +1529,45 @@ void mapper_destroy_highlight_obj(Object** a1, Object** a2) } } +// 0x48B850 +void update_art(int a1, int a2) +{ + // TODO: Incomplete. +} + +// 0x48C524 +void handle_new_map(int* a1, int* a2) +{ + Rect rect; + + rect.left = 30; + rect.top = 62; + rect.right = 50; + rect.bottom = 88; + blitBufferToBuffer(e_num[gElevation], + 19, + 26, + 19, + tool + rect.top * rectGetWidth(&_scr_size) + rect.left, + rectGetWidth(&_scr_size)); + windowRefreshRect(tool_win, &rect); + + if (*a1 < 0 || *a1 > 6) { + *a1 = 4; + } + + *a2 = 0; + update_art(*a1, *a2); + + print_toolbar_name(OBJ_TYPE_TILE); + + map_entered = false; + + if (tileRoofIsVisible()) { + tile_toggle_roof(true); + } +} + // 0x48C604 int mapper_inven_unwield(Object* obj, int right_hand) { From a30fb4cfdd179a66074ea9d5ac2e2e7220a43bd4 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 3 Sep 2023 22:21:14 +0300 Subject: [PATCH 34/42] Add mapper_refresh_rotation --- src/mapper/mapper.cc | 101 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/src/mapper/mapper.cc b/src/mapper/mapper.cc index de0d778..f69d23f 100644 --- a/src/mapper/mapper.cc +++ b/src/mapper/mapper.cc @@ -2,6 +2,7 @@ #include +#include "actions.h" #include "animation.h" #include "art.h" #include "color.h" @@ -49,6 +50,7 @@ static void clear_toolname(); static void update_toolname(int* pid, int type, int id); static void update_high_obj_name(Object* obj); static void mapper_destroy_highlight_obj(Object** a1, Object** a2); +static void mapper_refresh_rotation(); static void update_art(int a1, int a2); static void handle_new_map(int* a1, int* a2); static int mapper_mark_exit_grid(); @@ -104,6 +106,26 @@ static char kSwapPrototypse[] = " Swap Prototypes "; static char kTmpMapName[] = "TMP$MAP#.MAP"; +// 0x559618 +int rotate_arrows_x_offs[] = { + 31, + 38, + 31, + 11, + 3, + 11, +}; + +// 0x559630 +int rotate_arrows_y_offs[] = { + 7, + 23, + 37, + 37, + 23, + 7, +}; + // 0x559648 char* menu_0[] = { kNew, @@ -208,6 +230,9 @@ int menu_val_2[8]; // 0x6EAA80 unsigned char e_num[4][19 * 26]; +// 0x6EBD28 +unsigned char rotate_arrows[2][6][10 * 10]; + // 0x6EC408 int menu_val_1[21]; @@ -1052,6 +1077,36 @@ int mapper_edit_init(int argc, char** argv) // ARROWS for (index = 0; index < ROTATION_COUNT; index++) { + int x = rotate_arrows_x_offs[index] + 285; + int y = rotate_arrows_y_offs[index] + 25; + unsigned char v1 = lbm_buf[27 * (_scr_size.right + 1) + 287]; + int k; + + blitBufferToBuffer(lbm_buf + y * rectGetWidth(&_scr_size) + x, + 10, + 10, + rectGetWidth(&_scr_size), + rotate_arrows[1][index], + 10); + + for (k = 0; k < 100; k++) { + if (rotate_arrows[1][index][k] == v1) { + rotate_arrows[1][index][k] = 0; + } + } + + blitBufferToBuffer(lbm_buf + y * rectGetWidth(&_scr_size) + x - 52, + 10, + 10, + rectGetWidth(&_scr_size), + rotate_arrows[0][index], + 10); + + for (k = 0; k < 100; k++) { + if (rotate_arrows[1][index][k] == v1) { + rotate_arrows[1][index][k] = 0; + } + } } // COPY @@ -1529,6 +1584,52 @@ void mapper_destroy_highlight_obj(Object** a1, Object** a2) } } +// 0x48B6EC +void mapper_refresh_rotation() +{ + Rect rect; + char string[2]; + int index; + + rect.left = 270; + rect.top = 431 - (_scr_size.bottom - 99); + rect.right = 317; + rect.bottom = rect.top + 47; + + sprintf(string, "%d", rotation); + + if (tool != NULL) { + windowFill(tool_win, + 290, + 452 - (_scr_size.bottom - 99), + 10, + 12, + tool[(452 - (_scr_size.bottom - 99)) * (_scr_size.right + 1) + 289]); + windowDrawText(tool_win, + string, + 10, + 292, + 452 - (_scr_size.bottom - 99), + 0x2010104); + + for (index = 0; index < 6; index++) { + int x = rotate_arrows_x_offs[index] + 269; + int y = rotate_arrows_y_offs[index] + (430 - (_scr_size.bottom - 99)); + + blitBufferToBufferTrans(rotate_arrows[index == rotation][index], + 10, + 10, + 10, + tool + y * (_scr_size.right + 1) + x, + _scr_size.right + 1); + } + + windowRefreshRect(tool_win, &rect); + } else { + debugPrint("Error: mapper_refresh_rotation: tool buffer invalid!"); + } +} + // 0x48B850 void update_art(int a1, int a2) { From 91806d8ccb4215c9df3bf626112d4f101fba6e6b Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 3 Sep 2023 22:31:52 +0300 Subject: [PATCH 35/42] Fix missing include --- src/sfall_metarules.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sfall_metarules.cc b/src/sfall_metarules.cc index 558645b..8c3e110 100644 --- a/src/sfall_metarules.cc +++ b/src/sfall_metarules.cc @@ -1,5 +1,7 @@ #include "sfall_metarules.h" +#include + #include "combat.h" #include "debug.h" #include "game.h" From 0e447c55a814cbc5472ca8359ecfdc9f24235c0b Mon Sep 17 00:00:00 2001 From: Eir Nym <485399+eirnym@users.noreply.github.com> Date: Thu, 28 Sep 2023 16:26:52 +0200 Subject: [PATCH 36/42] Upgrade zlib to 1.3 (#323) --- third_party/zlib/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/zlib/CMakeLists.txt b/third_party/zlib/CMakeLists.txt index 7a89186..7cca827 100644 --- a/third_party/zlib/CMakeLists.txt +++ b/third_party/zlib/CMakeLists.txt @@ -2,7 +2,7 @@ include(FetchContent) FetchContent_Declare(zlib GIT_REPOSITORY "https://github.com/madler/zlib" - GIT_TAG "v1.2.11" + GIT_TAG "v1.3" ) FetchContent_GetProperties(zlib) From 81fce5f4a29a51c983780225b9f0538573bea727 Mon Sep 17 00:00:00 2001 From: Vasilii Rogin Date: Mon, 9 Oct 2023 20:50:59 +0300 Subject: [PATCH 37/42] Fix wrong pointer dereferecing in aiFindAttackers (#324) --- src/combat_ai.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/combat_ai.cc b/src/combat_ai.cc index 2110b9d..315f574 100644 --- a/src/combat_ai.cc +++ b/src/combat_ai.cc @@ -1464,7 +1464,7 @@ static int aiFindAttackers(Object* critter, Object** whoHitMePtr, Object** whoHi *whoHitFriendPtr = NULL; } - if (*whoHitByFriendPtr != NULL) { + if (whoHitByFriendPtr != NULL) { *whoHitByFriendPtr = NULL; } From f411d75643211dce56772ff54c7a21494b6a1d9f Mon Sep 17 00:00:00 2001 From: sonilyan <286258386@qq.com> Date: Tue, 31 Oct 2023 18:46:25 +0800 Subject: [PATCH 38/42] Add overriddenSelf initialization for scriptRead (#329) --- src/scripts.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/scripts.cc b/src/scripts.cc index 1485fff..7c8755c 100644 --- a/src/scripts.cc +++ b/src/scripts.cc @@ -1998,6 +1998,8 @@ static int scriptRead(Script* scr, File* stream) scr->localVarsCount = 0; } + scr->overriddenSelf = nullptr; + return 0; } From 601f0c7b44a4bab719bed92d6196e25c1a1ea8ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=BBP=2E=28P=20izzy=29?= Date: Tue, 16 Jan 2024 06:06:47 -0600 Subject: [PATCH 39/42] fix CMake condition to allow build on OpenBSD & FreeBSD (#341) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae87c6e..d7f8f39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -362,7 +362,7 @@ add_subdirectory("third_party/fpattern") target_link_libraries(${EXECUTABLE_NAME} ${FPATTERN_LIBRARY}) target_include_directories(${EXECUTABLE_NAME} PRIVATE ${FPATTERN_INCLUDE_DIR}) -if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux") +if((NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux") AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")) add_subdirectory("third_party/zlib") add_subdirectory("third_party/sdl2") else() From e23c4eddda7b6a1f28644e2cdcd3d2527f3b10fd Mon Sep 17 00:00:00 2001 From: Vasilii Rogin Date: Tue, 16 Jan 2024 14:24:49 +0200 Subject: [PATCH 40/42] Use delay_ms instead of spinwait (#262) --- CMakeLists.txt | 2 ++ src/character_editor.cc | 52 ++++++++++++++--------------------------- src/credits.cc | 7 +++--- src/dbox.cc | 14 +++++------ src/delay.cc | 11 +++++++++ src/delay.h | 6 +++++ src/elevator.cc | 4 ++-- src/game_dialog.cc | 10 +++----- src/input.cc | 8 ++----- src/loadsave.cc | 17 +++++++------- src/movie_lib.cc | 12 ++++++++++ src/pipboy.cc | 10 ++++---- src/preferences.cc | 4 ++-- src/vcr.cc | 4 ++-- 14 files changed, 81 insertions(+), 80 deletions(-) create mode 100644 src/delay.cc create mode 100644 src/delay.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d7f8f39..d2b19cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -253,6 +253,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC target_sources(${EXECUTABLE_NAME} PUBLIC "src/audio_engine.cc" "src/audio_engine.h" + "src/delay.cc" + "src/delay.h" "src/fps_limiter.cc" "src/fps_limiter.h" "src/platform_compat.cc" diff --git a/src/character_editor.cc b/src/character_editor.cc index 70563ec..ab4a3e4 100644 --- a/src/character_editor.cc +++ b/src/character_editor.cc @@ -16,6 +16,7 @@ #include "db.h" #include "dbox.h" #include "debug.h" +#include "delay.h" #include "draw.h" #include "game.h" #include "game_mouse.h" @@ -1991,7 +1992,7 @@ static int _get_input_str(int win, int cancelKeyCode, char* text, int maxLength, windowRefresh(win); - while (getTicksSince(_frame_time) < 1000 / 24) { } + delay_ms(1000 / 24 - (getTicks() - _frame_time)); renderPresent(); sharedFpsLimiter.throttle(); @@ -2281,8 +2282,7 @@ static void characterEditorDrawBigNumber(int x, int y, int flags, int value, int windowWidth); windowRefreshRect(windowHandle, &rect); renderPresent(); - while (getTicksSince(_frame_time) < BIG_NUM_ANIMATION_DELAY) - ; + delay_ms(BIG_NUM_ANIMATION_DELAY - (getTicks() - _frame_time)); } blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * ones, @@ -2304,8 +2304,7 @@ static void characterEditorDrawBigNumber(int x, int y, int flags, int value, int windowWidth); windowRefreshRect(windowHandle, &rect); renderPresent(); - while (getTicksSince(_frame_time) < BIG_NUM_ANIMATION_DELAY) - ; + delay_ms(BIG_NUM_ANIMATION_DELAY - (getTicks() - _frame_time)); } blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * tens, @@ -3530,11 +3529,9 @@ static int characterEditorEditAge() } if (v33 > dbl_50170B) { - while (getTicksSince(_frame_time) < 1000 / _repFtime) - ; + delay_ms(1000 / _repFtime - (getTicks() - _frame_time)); } else { - while (getTicksSince(_frame_time) < 1000 / 24) - ; + delay_ms(1000 / 24 - (getTicks() - _frame_time)); } keyCode = inputGetInput(); @@ -3548,8 +3545,7 @@ static int characterEditorEditAge() } else { windowRefresh(win); - while (getTicksSince(_frame_time) < 1000 / 24) - ; + delay_ms(1000 / 24 - (getTicks() - _frame_time)); } renderPresent(); @@ -3699,8 +3695,7 @@ static void characterEditorEditGender() windowRefresh(win); - while (getTicksSince(_frame_time) < 41) - ; + delay_ms(41 - (getTicks() - _frame_time)); renderPresent(); sharedFpsLimiter.throttle(); @@ -3778,12 +3773,9 @@ static void characterEditorAdjustPrimaryStat(int eventCode) } if (v11 >= 19.2) { - unsigned int delay = 1000 / _repFtime; - while (getTicksSince(_frame_time) < delay) { - } + delay_ms(1000 / _repFtime - (getTicks() - _frame_time)); } else { - while (getTicksSince(_frame_time) < 1000 / 24) { - } + delay_ms(1000 / 24 - (getTicks() - _frame_time)); } renderPresent(); @@ -5279,11 +5271,9 @@ static void characterEditorHandleAdjustSkillButtonPressed(int keyCode) if (!isUsingKeyboard) { unspentSp = pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS); if (repeatDelay >= dbl_5018F0) { - while (getTicksSince(_frame_time) < 1000 / _repFtime) { - } + delay_ms(1000 / _repFtime - (getTicks() - _frame_time)); } else { - while (getTicksSince(_frame_time) < 1000 / 24) { - } + delay_ms(1000 / 24 - (getTicks() - _frame_time)); } int keyCode = inputGetInput(); @@ -6141,11 +6131,9 @@ static int perkDialogHandleInput(int count, void (*refreshProc)()) } if (v19 < dbl_5019BE) { - while (getTicksSince(_frame_time) < 1000 / 24) { - } + delay_ms(1000 / 24 - (getTicks() - _frame_time)); } else { - while (getTicksSince(_frame_time) < 1000 / _repFtime) { - } + delay_ms(1000 / _repFtime - (getTicks() - _frame_time)); } renderPresent(); @@ -6188,11 +6176,9 @@ static int perkDialogHandleInput(int count, void (*refreshProc)()) } if (v19 < dbl_5019BE) { - while (getTicksSince(_frame_time) < 1000 / 24) { - } + delay_ms(1000 / 24 - (getTicks() - _frame_time)); } else { - while (getTicksSince(_frame_time) < 1000 / _repFtime) { - } + delay_ms(1000 / _repFtime - (getTicks() - _frame_time)); } renderPresent(); @@ -6224,11 +6210,9 @@ static int perkDialogHandleInput(int count, void (*refreshProc)()) } if (v19 < dbl_5019BE) { - while (getTicksSince(_frame_time) < 1000 / 24) { - } + delay_ms(1000 / 24 - (getTicks() - _frame_time)); } else { - while (getTicksSince(_frame_time) < 1000 / _repFtime) { - } + delay_ms(1000 / _repFtime - (getTicks() - _frame_time)); } renderPresent(); diff --git a/src/credits.cc b/src/credits.cc index c380bbf..be17580 100644 --- a/src/credits.cc +++ b/src/credits.cc @@ -9,6 +9,7 @@ #include "cycle.h" #include "db.h" #include "debug.h" +#include "delay.h" #include "draw.h" #include "game_mouse.h" #include "input.h" @@ -172,8 +173,7 @@ void creditsOpen(const char* filePath, int backgroundFid, bool useReversedStyle) windowBuffer, windowWidth); - while (getTicksSince(tick) < CREDITS_WINDOW_SCROLLING_DELAY) { - } + delay_ms(CREDITS_WINDOW_SCROLLING_DELAY - (getTicks() - tick)); tick = getTicks(); @@ -215,8 +215,7 @@ void creditsOpen(const char* filePath, int backgroundFid, bool useReversedStyle) windowBuffer, windowWidth); - while (getTicksSince(tick) < CREDITS_WINDOW_SCROLLING_DELAY) { - } + delay_ms(CREDITS_WINDOW_SCROLLING_DELAY - (getTicks() - tick)); tick = getTicks(); diff --git a/src/dbox.cc b/src/dbox.cc index eee9345..b0caacf 100644 --- a/src/dbox.cc +++ b/src/dbox.cc @@ -9,6 +9,7 @@ #include "character_editor.h" #include "color.h" #include "debug.h" +#include "delay.h" #include "draw.h" #include "game.h" #include "game_sound.h" @@ -885,8 +886,8 @@ int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLen } unsigned int delay = (scrollCounter > 14.4) ? 1000 / scrollDelay : 1000 / 24; - while (getTicksSince(scrollTick) < delay) { - } + + delay_ms(delay - (getTicks() - scrollTick)); if (_game_user_wants_to_quit != 0) { rc = 1; @@ -909,8 +910,7 @@ int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLen doubleClickSelectedFileIndex = -2; } - while (getTicksSince(tick) < (1000 / 24)) { - } + delay_ms(1000 / 24 - (getTicks() - tick)); } if (_game_user_wants_to_quit) { @@ -1335,8 +1335,7 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen // FIXME: Missing windowRefresh makes blinking useless. unsigned int delay = (scrollCounter > 14.4) ? 1000 / scrollDelay : 1000 / 24; - while (getTicksSince(scrollTick) < delay) { - } + delay_ms(delay - (getTicks() - scrollTick)); if (_game_user_wants_to_quit != 0) { rc = 1; @@ -1369,8 +1368,7 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen doubleClickSelectedFileIndex = -2; } - while (getTicksSince(tick) < (1000 / 24)) { - } + delay_ms(1000 / 24 - (getTicks() - tick)); } if (_game_user_wants_to_quit != 0) { diff --git a/src/delay.cc b/src/delay.cc new file mode 100644 index 0000000..dd9fa68 --- /dev/null +++ b/src/delay.cc @@ -0,0 +1,11 @@ +#include "delay.h" + +#include + +void delay_ms(int ms) +{ + if (ms <= 0) { + return; + } + SDL_Delay(ms); +} diff --git a/src/delay.h b/src/delay.h new file mode 100644 index 0000000..32b6f01 --- /dev/null +++ b/src/delay.h @@ -0,0 +1,6 @@ +#ifndef DELAY_H +#define DELAY_H + +void delay_ms(int ms); + +#endif diff --git a/src/elevator.cc b/src/elevator.cc index adbbb1e..e343417 100644 --- a/src/elevator.cc +++ b/src/elevator.cc @@ -8,6 +8,7 @@ #include "art.h" #include "cycle.h" #include "debug.h" +#include "delay.h" #include "draw.h" #include "game_mouse.h" #include "game_sound.h" @@ -453,8 +454,7 @@ int elevatorSelectLevel(int elevator, int* mapPtr, int* elevationPtr, int* tileP windowRefresh(gElevatorWindow); - while (getTicksSince(tick) < delay) { - } + delay_ms(delay - (getTicks() - tick)); renderPresent(); sharedFpsLimiter.throttle(); diff --git a/src/game_dialog.cc b/src/game_dialog.cc index 48a6518..017c1ce 100644 --- a/src/game_dialog.cc +++ b/src/game_dialog.cc @@ -13,6 +13,7 @@ #include "critter.h" #include "cycle.h" #include "debug.h" +#include "delay.h" #include "dialog.h" #include "display_monitor.h" #include "draw.h" @@ -2936,7 +2937,6 @@ void _gdialog_scroll_subwin(int win, int a2, unsigned char* a3, unsigned char* a int v7; unsigned char* v9; Rect rect; - unsigned int tick; v7 = a6; v9 = a4; @@ -2971,9 +2971,7 @@ void _gdialog_scroll_subwin(int win, int a2, unsigned char* a3, unsigned char* a v7 += 10; v9 -= 10 * (GAME_DIALOG_WINDOW_WIDTH); - tick = getTicks(); - while (getTicksSince(tick) < 33) { - } + delay_ms(33); renderPresent(); sharedFpsLimiter.throttle(); @@ -3011,9 +3009,7 @@ void _gdialog_scroll_subwin(int win, int a2, unsigned char* a3, unsigned char* a rect.top += 10; - tick = getTicks(); - while (getTicksSince(tick) < 33) { - } + delay_ms(33); renderPresent(); sharedFpsLimiter.throttle(); diff --git a/src/input.cc b/src/input.cc index 1bf56ac..14c5463 100644 --- a/src/input.cc +++ b/src/input.cc @@ -4,6 +4,7 @@ #include "audio_engine.h" #include "color.h" +#include "delay.h" #include "dinput.h" #include "draw.h" #include "kb.h" @@ -641,12 +642,7 @@ void inputPauseForTocks(unsigned int delay) // 0x4C93B8 void inputBlockForTocks(unsigned int ms) { - unsigned int start = SDL_GetTicks(); - unsigned int diff; - do { - // NOTE: Uninline - diff = getTicksSince(start); - } while (diff < ms); + delay_ms(ms); } // 0x4C93E0 diff --git a/src/loadsave.cc b/src/loadsave.cc index a0fa76b..7091e90 100644 --- a/src/loadsave.cc +++ b/src/loadsave.cc @@ -18,6 +18,7 @@ #include "db.h" #include "dbox.h" #include "debug.h" +#include "delay.h" #include "display_monitor.h" #include "draw.h" #include "file_utils.h" @@ -672,9 +673,9 @@ int lsgSaveGame(int mode) } if (scrollCounter > 14.4) { - while (getTicksSince(start) < 1000 / scrollVelocity) { } + delay_ms(1000 / scrollVelocity - (getTicks() - start)); } else { - while (getTicksSince(start) < 1000 / 24) { } + delay_ms(1000 / 24 - (getTicks() - start)); } keyCode = inputGetInput(); @@ -718,8 +719,7 @@ int lsgSaveGame(int mode) doubleClickSlot = -1; } - while (getTicksSince(tick) < 1000 / 24) { - } + delay_ms(1000 / 24 - (getTicks() - tick)); } if (rc == 1) { @@ -1175,9 +1175,9 @@ int lsgLoadGame(int mode) } if (scrollCounter > 14.4) { - while (getTicksSince(start) < 1000 / scrollVelocity) { } + delay_ms(1000 / scrollVelocity - (getTicks() - start)); } else { - while (getTicksSince(start) < 1000 / 24) { } + delay_ms(1000 / 24 - (getTicks() - start)); } keyCode = inputGetInput(); @@ -1227,7 +1227,7 @@ int lsgLoadGame(int mode) doubleClickSlot = -1; } - while (getTicksSince(time) < 1000 / 24) { } + delay_ms(1000 / 24 - (getTicks() - time)); } if (rc == 1) { @@ -2387,8 +2387,7 @@ static int _get_input_str2(int win, int doneKeyCode, int cancelKeyCode, char* de windowRefresh(win); } - while (getTicksSince(tick) < 1000 / 24) { - } + delay_ms(1000 / 24 - (getTicks() - tick)); renderPresent(); sharedFpsLimiter.throttle(); diff --git a/src/movie_lib.cc b/src/movie_lib.cc index e407ce1..5db883b 100644 --- a/src/movie_lib.cc +++ b/src/movie_lib.cc @@ -9,6 +9,7 @@ #include #include "audio_engine.h" +#include "delay.h" #include "platform_compat.h" namespace fallout { @@ -794,6 +795,8 @@ static int _syncWait() if (_sync_active) { if (((_sync_time + 1000 * compat_timeGetTime()) & 0x80000000) != 0) { result = 1; + + delay_ms(-(_sync_time + 1000 * compat_timeGetTime()) / 1000 - 3); while (((_sync_time + 1000 * compat_timeGetTime()) & 0x80000000) != 0) ; } @@ -1148,6 +1151,7 @@ static int _MVE_sndConfigure(int a1, int a2, int a3, int a4, int a5, int a6) } // 0x4F56C0 +// Looks like this function is not used static void _MVE_syncSync() { if (_sync_active) { @@ -1294,6 +1298,10 @@ static void _MVE_sndSync() break; } v0 = true; + +#ifdef EMSCRIPTEN + delay_ms(1); +#endif } if (dword_6B3660 != dword_6B3AE4) { @@ -1318,6 +1326,10 @@ static int _syncWaitLevel(int a1) v2 = _sync_time + a1; do { result = v2 + 1000 * compat_timeGetTime(); + if (result < 0) { + delay_ms(-result / 1000 - 3); + } + result = v2 + 1000 * compat_timeGetTime(); } while (result < 0); _sync_time += _sync_wait_quanta; diff --git a/src/pipboy.cc b/src/pipboy.cc index 45f79db..9a47261 100644 --- a/src/pipboy.cc +++ b/src/pipboy.cc @@ -13,6 +13,7 @@ #include "cycle.h" #include "dbox.h" #include "debug.h" +#include "delay.h" #include "draw.h" #include "game.h" #include "game_mouse.h" @@ -2001,8 +2002,7 @@ static bool pipboyRest(int hours, int minutes, int duration) pipboyDrawDate(); windowRefresh(gPipboyWindow); - while (getTicksSince(start) < 50) { - } + delay_ms(50 - (getTicks() - start)); } renderPresent(); @@ -2072,8 +2072,7 @@ static bool pipboyRest(int hours, int minutes, int duration) pipboyDrawHitPoints(); windowRefresh(gPipboyWindow); - while (getTicksSince(start) < 50) { - } + delay_ms(50 - (getTicks() - start)); } renderPresent(); @@ -2366,8 +2365,7 @@ static int pipboyRenderScreensaver() v31 -= 1; } else { windowRefreshRect(gPipboyWindow, &gPipboyWindowContentRect); - while (getTicksSince(time) < 50) { - } + delay_ms(50 - (getTicks() - time)); } renderPresent(); diff --git a/src/preferences.cc b/src/preferences.cc index 4cbd94b..9e93307 100644 --- a/src/preferences.cc +++ b/src/preferences.cc @@ -7,6 +7,7 @@ #include "combat.h" #include "combat_ai.h" #include "debug.h" +#include "delay.h" #include "draw.h" #include "game.h" #include "game_mouse.h" @@ -1570,8 +1571,7 @@ static void _DoThing(int eventCode) blitBufferToBufferTrans(_preferencesFrmImages[PREFERENCES_WINDOW_FRM_KNOB_ON].getData(), 21, 12, 21, gPreferencesWindowBuffer + PREFERENCES_WINDOW_WIDTH * meta->knobY + v31, PREFERENCES_WINDOW_WIDTH); windowRefresh(gPreferencesWindow); - while (getTicksSince(tick) < 35) - ; + delay_ms(35 - (getTicks() - tick)); renderPresent(); sharedFpsLimiter.throttle(); diff --git a/src/vcr.cc b/src/vcr.cc index 54791f2..a4faf12 100644 --- a/src/vcr.cc +++ b/src/vcr.cc @@ -2,6 +2,7 @@ #include +#include "delay.h" #include "input.h" #include "kb.h" #include "memory.h" @@ -228,8 +229,7 @@ int vcrUpdate() * (vcrEntry->time - stru_6AD940.time) / (vcrEntry->counter - stru_6AD940.counter); - while (getTicksSince(_vcr_start_time) < delay) { - } + delay_ms(delay - (getTicks() - _vcr_start_time)); } } From 16f4ab7787ae4bf8f61cc7cbeb73251f46709a55 Mon Sep 17 00:00:00 2001 From: Jo Date: Tue, 16 Jan 2024 20:42:32 +0800 Subject: [PATCH 41/42] Improve pointer comparsion for Nevada and Sonora mods (#291) --- src/interpreter.cc | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/interpreter.cc b/src/interpreter.cc index a147ce8..3e3cc4e 100644 --- a/src/interpreter.cc +++ b/src/interpreter.cc @@ -1131,7 +1131,12 @@ static void opConditionalOperatorLessThanEquals(Program* program) case VALUE_TYPE_PTR: switch (value[0].opcode) { case VALUE_TYPE_INT: - result = (uintptr_t)value[1].pointerValue <= (uintptr_t)value[0].integerValue; + if (value[0].integerValue > 0) { + result = (uintptr_t)value[1].pointerValue <= (uintptr_t)value[0].integerValue; + } else { + // (ptr <= int{0 or negative}) means (ptr == nullptr) + result = nullptr == value[1].pointerValue; + } break; default: assert(false && "Should be unreachable"); @@ -1385,7 +1390,12 @@ static void opConditionalOperatorGreaterThan(Program* program) case VALUE_TYPE_PTR: switch (value[0].opcode) { case VALUE_TYPE_INT: - result = (uintptr_t)value[1].pointerValue > (uintptr_t)value[0].integerValue; + if (value[0].integerValue > 0) { + result = (uintptr_t)value[1].pointerValue > (uintptr_t)value[0].integerValue; + } else { + // (ptr > int{0 or negative}) means (ptr != nullptr) + result = nullptr != value[1].pointerValue; + } break; default: assert(false && "Should be unreachable"); From c6565ac96aef5c92f1baadad8e31b1dee338bc9e Mon Sep 17 00:00:00 2001 From: c6 <31777460+c6-dev@users.noreply.github.com> Date: Tue, 16 Jan 2024 16:56:21 +0400 Subject: [PATCH 42/42] Sfall: add VersionString, ConfigFile, PatchFile (#309) --- src/game.cc | 10 +++++++++- src/game_config.cc | 13 +++++++++++-- src/game_config.h | 2 +- src/sfall_config.cc | 3 +++ src/sfall_config.h | 3 +++ src/version.cc | 10 +++++++++- 6 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/game.cc b/src/game.cc index 648e501..47fadb1 100644 --- a/src/game.cc +++ b/src/game.cc @@ -1363,8 +1363,16 @@ static int gameDbInit() return -1; } + // SFALL: custom patch file name. + char* patch_filename = nullptr; + if (configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PATCH_FILE, &patch_filename)) { + if (patch_filename == nullptr || *patch_file_name == '\0') { + patch_filename = "patch%03d.dat"; + } + } + for (patch_index = 0; patch_index < 1000; patch_index++) { - snprintf(filename, sizeof(filename), "patch%03d.dat", patch_index); + snprintf(filename, sizeof(filename), patch_filename, patch_index); if (compat_access(filename, 0) == 0) { dbOpen(filename, 0, NULL, 1); diff --git a/src/game_config.cc b/src/game_config.cc index 7063ec7..b3c0a1f 100644 --- a/src/game_config.cc +++ b/src/game_config.cc @@ -1,4 +1,5 @@ #include "game_config.h" +#include "sfall_config.h" #include #include @@ -120,6 +121,14 @@ bool gameConfigInit(bool isMapper, int argc, char** argv) configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_SORT_SCRIPT_LIST_KEY, 0); } + // SFALL: custom config file name. + char* configFileName = nullptr; + if (configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_CONFIG_FILE, &configFileName)) { + if (configFileName == nullptr || *configFileName == '\0') { + configFileName = DEFAULT_GAME_CONFIG_FILE_NAME; + } + } + // Make `fallout2.cfg` file path. char* executable = argv[0]; char* ch = strrchr(executable, '\\'); @@ -136,14 +145,14 @@ bool gameConfigInit(bool isMapper, int argc, char** argv) sizeof(gGameConfigFilePath), "%s\\%s", executable, - GAME_CONFIG_FILE_NAME); + configFileName); } *ch = '\\'; } else { if (isMapper) { strcpy(gGameConfigFilePath, MAPPER_CONFIG_FILE_NAME); } else { - strcpy(gGameConfigFilePath, GAME_CONFIG_FILE_NAME); + strcpy(gGameConfigFilePath, configFileName); } } diff --git a/src/game_config.h b/src/game_config.h index 78a1299..0c76377 100644 --- a/src/game_config.h +++ b/src/game_config.h @@ -5,7 +5,7 @@ namespace fallout { -#define GAME_CONFIG_FILE_NAME "fallout2.cfg" +#define DEFAULT_GAME_CONFIG_FILE_NAME "fallout2.cfg" #define MAPPER_CONFIG_FILE_NAME "mapper2.cfg" #define GAME_CONFIG_SYSTEM_KEY "system" diff --git a/src/sfall_config.cc b/src/sfall_config.cc index 353bb37..85c2ce7 100644 --- a/src/sfall_config.cc +++ b/src/sfall_config.cc @@ -58,6 +58,9 @@ bool sfallConfigInit(int argc, char** argv) configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER3, 270); configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER4, 360); configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_AUTO_QUICK_SAVE, 0); + configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_VERSION_STRING, ""); + configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_CONFIG_FILE, ""); + configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PATCH_FILE, ""); configSetString(&gSfallConfig, SFALL_CONFIG_SCRIPTS_KEY, SFALL_CONFIG_INI_CONFIG_FOLDER, ""); configSetString(&gSfallConfig, SFALL_CONFIG_SCRIPTS_KEY, SFALL_CONFIG_GLOBAL_SCRIPT_PATHS, ""); diff --git a/src/sfall_config.h b/src/sfall_config.h index da2c298..7d4b2fb 100644 --- a/src/sfall_config.h +++ b/src/sfall_config.h @@ -72,6 +72,9 @@ namespace fallout { #define SFALL_CONFIG_INI_CONFIG_FOLDER "IniConfigFolder" #define SFALL_CONFIG_GLOBAL_SCRIPT_PATHS "GlobalScriptPaths" #define SFALL_CONFIG_AUTO_QUICK_SAVE "AutoQuickSave" +#define SFALL_CONFIG_VERSION_STRING "VersionString" +#define SFALL_CONFIG_CONFIG_FILE "ConfigFile" +#define SFALL_CONFIG_PATCH_FILE "PatchFile" #define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_MULTIPLIER 1 #define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_DIVISOR 3 diff --git a/src/version.cc b/src/version.cc index 4422bd3..ca4f7ad 100644 --- a/src/version.cc +++ b/src/version.cc @@ -1,4 +1,5 @@ #include "version.h" +#include "sfall_config.h" #include @@ -7,7 +8,14 @@ namespace fallout { // 0x4B4580 void versionGetVersion(char* dest, size_t size) { - snprintf(dest, size, "FALLOUT II %d.%02d", VERSION_MAJOR, VERSION_MINOR); + // SFALL: custom version string. + char* versionString = nullptr; + if (configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_VERSION_STRING, &versionString)) { + if (*versionString == '\0') { + versionString = nullptr; + } + } + snprintf(dest, size, (versionString != nullptr ? versionString : "FALLOUT II %d.%02d"), VERSION_MAJOR, VERSION_MINOR); } } // namespace fallout