mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-28 12:47:58 +03:00
parent
1e1ff3092b
commit
309efee3c6
11 changed files with 65 additions and 21 deletions
|
@ -284,10 +284,10 @@
|
|||
"O_KEY_OPTION_2": "Key Option 2",
|
||||
"O_KEY_OPTION_3": "Key Option 3",
|
||||
"O_KEY_OPTION_4": "Key Option 4",
|
||||
"O_KEY_HOLE_1": "Key Hole 1",
|
||||
"O_KEY_HOLE_2": "Key Hole 2",
|
||||
"O_KEY_HOLE_3": "Key Hole 3",
|
||||
"O_KEY_HOLE_4": "Key Hole 4",
|
||||
"O_KEY_HOLE_1": "Keyhole 1",
|
||||
"O_KEY_HOLE_2": "Keyhole 2",
|
||||
"O_KEY_HOLE_3": "Keyhole 3",
|
||||
"O_KEY_HOLE_4": "Keyhole 4",
|
||||
"O_PICKUP_ITEM_1": "Pickup Item 1",
|
||||
"O_PICKUP_ITEM_2": "Pickup Item 2",
|
||||
"O_PICKUP_OPTION_1": "Pickup Option 1",
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
- fixed Story So Far feature looping cutscenes forever (#1551, regression from 4.4)
|
||||
- improved object name matching in console commands to work like TR2X
|
||||
- improved vertex movement when looking through water portals even more (#1493)
|
||||
- improved console commands targeting creatures and pickups (#1667)
|
||||
|
||||
## [4.4](https://github.com/LostArtefacts/TRX/compare/tr1-4.3...tr1-4.4) - 2024-09-20
|
||||
- added `/exit` command (#1462)
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
- fixed `/endlevel` displaying a success message in the title screen
|
||||
- fixed very loud music volume set by default (#1614)
|
||||
- improved vertex movement when looking through water portals (#1493)
|
||||
- improved console commands targeting creatures and pickups (#1667)
|
||||
|
||||
## [0.3](https://github.com/LostArtefacts/TR2X/compare/0.2...0.3) - 2024-09-20
|
||||
- added new console commands:
|
||||
|
|
|
@ -110,10 +110,10 @@ static bool M_SetCurrentValue(
|
|||
assert(option->target != NULL);
|
||||
switch (option->type) {
|
||||
case COT_BOOL:
|
||||
if (String_Match(new_value, "on|true|1")) {
|
||||
if (String_Match(new_value, "^(on|true|1)$")) {
|
||||
*(bool *)option->target = true;
|
||||
return true;
|
||||
} else if (String_Match(new_value, "off|false|0")) {
|
||||
} else if (String_Match(new_value, "^(off|false|0)$")) {
|
||||
*(bool *)option->target = false;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -22,8 +22,9 @@ static COMMAND_RESULT M_Entrypoint(const COMMAND_CONTEXT *ctx);
|
|||
|
||||
static bool M_CanTargetObjectCreature(const GAME_OBJECT_ID object_id)
|
||||
{
|
||||
return Object_IsObjectType(object_id, g_EnemyObjects)
|
||||
|| Object_IsObjectType(object_id, g_AllyObjects);
|
||||
return (Object_IsObjectType(object_id, g_EnemyObjects)
|
||||
|| Object_IsObjectType(object_id, g_AllyObjects))
|
||||
&& Object_GetObject(object_id)->loaded;
|
||||
}
|
||||
|
||||
static COMMAND_RESULT M_KillAllEnemies(void)
|
||||
|
|
|
@ -25,11 +25,27 @@ static COMMAND_RESULT M_TeleportToObject(const char *user_input);
|
|||
|
||||
static COMMAND_RESULT M_Entrypoint(const COMMAND_CONTEXT *ctx);
|
||||
|
||||
static bool M_ObjectCanBePickedUp(const GAME_OBJECT_ID object_id)
|
||||
{
|
||||
if (!Object_IsObjectType(object_id, g_PickupObjects)) {
|
||||
return true;
|
||||
}
|
||||
for (int32_t item_num = 0; item_num < Item_GetTotalCount(); item_num++) {
|
||||
const ITEM *const item = Item_Get(item_num);
|
||||
if (item->object_id == object_id && item->status != IS_INVISIBLE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool M_CanTargetObject(const GAME_OBJECT_ID object_id)
|
||||
{
|
||||
return !Object_IsObjectType(object_id, g_NullObjects)
|
||||
&& !Object_IsObjectType(object_id, g_AnimObjects)
|
||||
&& !Object_IsObjectType(object_id, g_InvObjects);
|
||||
&& !Object_IsObjectType(object_id, g_InvObjects)
|
||||
&& Object_GetObject(object_id)->loaded
|
||||
&& M_ObjectCanBePickedUp(object_id);
|
||||
}
|
||||
|
||||
static inline bool M_IsFloatRound(const float num)
|
||||
|
|
|
@ -135,10 +135,10 @@ OBJ_NAME_DEFINE(O_KEY_OPTION_1, "Key Option 1")
|
|||
OBJ_NAME_DEFINE(O_KEY_OPTION_2, "Key Option 2")
|
||||
OBJ_NAME_DEFINE(O_KEY_OPTION_3, "Key Option 3")
|
||||
OBJ_NAME_DEFINE(O_KEY_OPTION_4, "Key Option 4")
|
||||
OBJ_NAME_DEFINE(O_KEY_HOLE_1, "Key Hole 1")
|
||||
OBJ_NAME_DEFINE(O_KEY_HOLE_2, "Key Hole 1")
|
||||
OBJ_NAME_DEFINE(O_KEY_HOLE_3, "Key Hole 1")
|
||||
OBJ_NAME_DEFINE(O_KEY_HOLE_4, "Key Hole 1")
|
||||
OBJ_NAME_DEFINE(O_KEY_HOLE_1, "Keyhole 1")
|
||||
OBJ_NAME_DEFINE(O_KEY_HOLE_2, "Keyhole 1")
|
||||
OBJ_NAME_DEFINE(O_KEY_HOLE_3, "Keyhole 1")
|
||||
OBJ_NAME_DEFINE(O_KEY_HOLE_4, "Keyhole 1")
|
||||
OBJ_NAME_DEFINE(O_PICKUP_ITEM_1, "Pickup Item 1")
|
||||
OBJ_NAME_DEFINE(O_PICKUP_ITEM_2, "Pickup Item 2")
|
||||
OBJ_NAME_DEFINE(O_SCION_ITEM_1, "Scion 1")
|
||||
|
|
|
@ -199,10 +199,10 @@ OBJ_NAME_DEFINE(O_KEY_OPTION_1, "Key Option 1")
|
|||
OBJ_NAME_DEFINE(O_KEY_OPTION_2, "Key Option 2")
|
||||
OBJ_NAME_DEFINE(O_KEY_OPTION_3, "Key Option 3")
|
||||
OBJ_NAME_DEFINE(O_KEY_OPTION_4, "Key Option 4")
|
||||
OBJ_NAME_DEFINE(O_KEY_HOLE_1, "Key Hole 1")
|
||||
OBJ_NAME_DEFINE(O_KEY_HOLE_2, "Key Hole 2")
|
||||
OBJ_NAME_DEFINE(O_KEY_HOLE_3, "Key Hole 3")
|
||||
OBJ_NAME_DEFINE(O_KEY_HOLE_4, "Key Hole 4")
|
||||
OBJ_NAME_DEFINE(O_KEY_HOLE_1, "Keyhole 1")
|
||||
OBJ_NAME_DEFINE(O_KEY_HOLE_2, "Keyhole 2")
|
||||
OBJ_NAME_DEFINE(O_KEY_HOLE_3, "Keyhole 3")
|
||||
OBJ_NAME_DEFINE(O_KEY_HOLE_4, "Keyhole 4")
|
||||
OBJ_NAME_DEFINE(O_PICKUP_ITEM_1, "Pickup Item 1")
|
||||
OBJ_NAME_DEFINE(O_PICKUP_ITEM_2, "Pickup Item 2")
|
||||
OBJ_NAME_DEFINE(O_PICKUP_OPTION_1, "Pickup Option 1")
|
||||
|
|
|
@ -13,6 +13,7 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
bool is_full;
|
||||
bool is_word;
|
||||
int32_t score;
|
||||
} STRING_FUZZY_SCORE;
|
||||
|
||||
|
|
|
@ -95,9 +95,9 @@ bool String_Match(const char *const subject, const char *const pattern)
|
|||
|
||||
pcre2_match_data *const match_data =
|
||||
pcre2_match_data_create(ovec_size, NULL);
|
||||
const int flags = 0;
|
||||
const int rc = pcre2_match(
|
||||
re, usubject, PCRE2_ZERO_TERMINATED, 0,
|
||||
PCRE2_ANCHORED | PCRE2_ENDANCHORED, match_data, NULL);
|
||||
re, usubject, PCRE2_ZERO_TERMINATED, 0, flags, match_data, NULL);
|
||||
pcre2_match_data_free(match_data);
|
||||
pcre2_code_free(re);
|
||||
|
||||
|
@ -111,14 +111,14 @@ bool String_IsEmpty(const char *const value)
|
|||
|
||||
bool String_ParseBool(const char *const value, bool *const target)
|
||||
{
|
||||
if (String_Match(value, "0|false|off")) {
|
||||
if (String_Match(value, "^(0|false|off)$")) {
|
||||
if (target != NULL) {
|
||||
*target = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (String_Match(value, "1|true|on")) {
|
||||
if (String_Match(value, "^(1|true|on)$")) {
|
||||
if (target != NULL) {
|
||||
*target = true;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
static STRING_FUZZY_SCORE M_GetScore(
|
||||
const char *user_input, const char *reference, int32_t weight);
|
||||
static void M_DiscardNonFullMatches(VECTOR *matches);
|
||||
static void M_DiscardNonWordMatches(VECTOR *matches);
|
||||
static void M_SortMatches(VECTOR *matches);
|
||||
static void M_DiscardDuplicateMatches(VECTOR *matches);
|
||||
|
||||
|
@ -32,6 +33,7 @@ static STRING_FUZZY_SCORE M_GetScore(
|
|||
|
||||
// Assume a partial match
|
||||
bool is_full = false;
|
||||
bool is_word = false;
|
||||
int32_t score = letter_score + percent_score;
|
||||
if (String_Match(reference, full_regex)) {
|
||||
// Got a full match
|
||||
|
@ -39,6 +41,7 @@ static STRING_FUZZY_SCORE M_GetScore(
|
|||
score += FULL_MATCH_SCORE_BONUS;
|
||||
} else if (String_Match(reference, word_regex)) {
|
||||
// Got a word match
|
||||
is_word = true;
|
||||
score += WORD_MATCH_SCORE_BONUS;
|
||||
} else if (String_CaseSubstring(reference, user_input) == NULL) {
|
||||
// No match.
|
||||
|
@ -50,6 +53,7 @@ static STRING_FUZZY_SCORE M_GetScore(
|
|||
|
||||
return (STRING_FUZZY_SCORE) {
|
||||
.is_full = is_full,
|
||||
.is_word = is_word,
|
||||
.score = score * weight,
|
||||
};
|
||||
}
|
||||
|
@ -73,6 +77,25 @@ static void M_DiscardNonFullMatches(VECTOR *const matches)
|
|||
}
|
||||
}
|
||||
|
||||
static void M_DiscardNonWordMatches(VECTOR *const matches)
|
||||
{
|
||||
bool has_word_match = false;
|
||||
for (int32_t i = 0; i < matches->count; i++) {
|
||||
const STRING_FUZZY_MATCH *const match = Vector_Get(matches, i);
|
||||
if (match->score.is_word) {
|
||||
has_word_match = true;
|
||||
}
|
||||
}
|
||||
if (has_word_match) {
|
||||
for (int32_t i = matches->count - 1; i >= 0; i--) {
|
||||
const STRING_FUZZY_MATCH *const match = Vector_Get(matches, i);
|
||||
if (!match->score.is_word) {
|
||||
Vector_RemoveAt(matches, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void M_SortMatches(VECTOR *const matches)
|
||||
{
|
||||
// sort by match length so that best-matching results appear first
|
||||
|
@ -129,6 +152,7 @@ VECTOR *String_FuzzyMatch(const char *user_input, const VECTOR *const source)
|
|||
}
|
||||
|
||||
M_DiscardNonFullMatches(matches);
|
||||
M_DiscardNonWordMatches(matches);
|
||||
M_DiscardDuplicateMatches(matches);
|
||||
M_SortMatches(matches);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue