mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
@@ -98,7 +98,7 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
|
||||
| KeyPress | `HOOK_KEYPRESS` | ✅ | Third hook arg is currently `0`; CE doesn't use VK codes. |
|
||||
| MouseClick | `HOOK_MOUSECLICK` | ✅ | - |
|
||||
| UseSkill | `HOOK_USESKILL` | 🚫 | - |
|
||||
| Steal | `HOOK_STEAL` | 🚫 | Et tu |
|
||||
| Steal | `HOOK_STEAL` | ✅ | - |
|
||||
| WithinPerception | `HOOK_WITHINPERCEPTION` | ✅ | - |
|
||||
| InventoryMove | `HOOK_INVENTORYMOVE` | ✅ | - |
|
||||
| InvenWield | `HOOK_INVENWIELD` | ✅ | - |
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
#include "sfall.h"
|
||||
#include "dik.h"
|
||||
#include "lib.arrays.h"
|
||||
|
||||
variable steal_mode := 0;
|
||||
|
||||
procedure steal_mode_name(variable mode) begin
|
||||
if (mode == 1) then return "force_success";
|
||||
if (mode == 2) then return "caught_fail";
|
||||
if (mode == 3) then return "silent_fail";
|
||||
if (mode == 4) then return "xp_override";
|
||||
return "vanilla";
|
||||
end
|
||||
|
||||
procedure steal_handler begin
|
||||
variable
|
||||
args := get_sfall_args,
|
||||
thief := args[0],
|
||||
target := args[1],
|
||||
item := args[2],
|
||||
is_planting := args[3],
|
||||
quantity := args[4],
|
||||
thief_name := "<null>",
|
||||
target_name := "<null>",
|
||||
item_name := "<null>";
|
||||
|
||||
if (thief) then thief_name := obj_name(thief);
|
||||
if (target) then target_name := obj_name(target);
|
||||
if (item) then item_name := obj_name(item);
|
||||
|
||||
display_msg(string_format6("steal mode=%s thief=%s target=%s item=%s planting=%d qty=%d",
|
||||
steal_mode_name(steal_mode),
|
||||
thief_name,
|
||||
target_name,
|
||||
item_name,
|
||||
is_planting,
|
||||
quantity));
|
||||
display_msg(string_format1("steal args=%s", debug_array_str(args)));
|
||||
|
||||
if (thief != dude_obj) then return;
|
||||
|
||||
if (steal_mode == 1) then begin
|
||||
display_msg("steal forcing success");
|
||||
display_msg(sprintf(mstr_skill(571 + is_planting * 2), item_name));
|
||||
set_sfall_return(1);
|
||||
end else if (steal_mode == 2) then begin
|
||||
display_msg("steal forcing caught failure");
|
||||
display_msg(sprintf(mstr_skill(570 + is_planting * 2), item_name));
|
||||
set_sfall_return(0);
|
||||
end else if (steal_mode == 3) then begin
|
||||
display_msg("steal forcing silent failure");
|
||||
set_sfall_return(2);
|
||||
end else if (steal_mode == 4) then begin
|
||||
display_msg("steal forcing success with xp override 77");
|
||||
display_msg(sprintf(mstr_skill(571 + is_planting * 2), item_name));
|
||||
set_sfall_return(1);
|
||||
set_sfall_return(77);
|
||||
end
|
||||
end
|
||||
|
||||
procedure keypress_handler begin
|
||||
variable
|
||||
pressed := get_sfall_arg_at(0),
|
||||
key := get_sfall_arg_at(1);
|
||||
|
||||
if (not pressed) then return;
|
||||
if (key != DIK_X) then return;
|
||||
|
||||
steal_mode += 1;
|
||||
if (steal_mode > 4) then steal_mode := 0;
|
||||
|
||||
display_msg(string_format1("steal mode -> %s", steal_mode_name(steal_mode)));
|
||||
end
|
||||
|
||||
procedure start begin
|
||||
if (not game_loaded) then return;
|
||||
|
||||
display_msg("steal manual test ready: press X to cycle vanilla / force_success / caught_fail / silent_fail / xp_override");
|
||||
display_msg("open a steal screen and move an item in either direction; mode 4 should award 77 XP for a successful action");
|
||||
|
||||
register_hook_proc(HOOK_KEYPRESS, keypress_handler);
|
||||
register_hook_proc(HOOK_STEAL, steal_handler);
|
||||
end
|
||||
+23
-10
@@ -330,7 +330,7 @@ static void inventoryDrawCenteredText(unsigned char* buffer, int pitch, int widt
|
||||
static void inventoryExamineItem(Object* critter, Object* item);
|
||||
static void inventorySetLeftPaneCritter(Object* critter, Object* target, int inventoryWindowType);
|
||||
static void inventoryWindowOpenContextMenu(int eventCode, int inventoryWindowType);
|
||||
static InventoryMoveResult _move_inventory(Object* item, int slotIndex, Object* targetObj, bool isPlanting);
|
||||
static InventoryMoveResult _move_inventory(Object* item, int slotIndex, Object* targetObj, bool isPlanting, int* stealXpOverridePtr);
|
||||
static std::pair<int, int> barterComputeTablesValue(Object* dude, Object* npc, bool offerButton = false);
|
||||
static std::pair<int, int> barterComputeTablesWeight(Object* dude, Object* npc);
|
||||
static int barterAttemptTransaction(Object* dude, Object* offerTable, Object* npc, Object* barterTable);
|
||||
@@ -4622,11 +4622,12 @@ int inventoryOpenLooting(Object* looter, Object* target)
|
||||
_gStealSize += itemGetSize(_stack[_curr_stack]);
|
||||
|
||||
InventoryItem* inventoryItem = &(_pud->items[_pud->length - (slotIndex + _stack_offset[_curr_stack] + 1)]);
|
||||
InventoryMoveResult rc = _move_inventory(inventoryItem->item, slotIndex, _target_stack[_target_curr_stack], true);
|
||||
int stealXpOverride = -1;
|
||||
InventoryMoveResult rc = _move_inventory(inventoryItem->item, slotIndex, _target_stack[_target_curr_stack], true, &stealXpOverride);
|
||||
if (rc == INVENTORY_MOVE_RESULT_CAUGHT_STEALING) {
|
||||
isCaughtStealing = true;
|
||||
} else if (rc == INVENTORY_MOVE_RESULT_SUCCESS) {
|
||||
stealingXp += stealingXpBonus;
|
||||
stealingXp += stealXpOverride >= 0 ? stealXpOverride : stealingXpBonus;
|
||||
stealingXpBonus += 10;
|
||||
}
|
||||
|
||||
@@ -4646,11 +4647,12 @@ int inventoryOpenLooting(Object* looter, Object* target)
|
||||
_gStealSize += itemGetSize(_stack[_curr_stack]);
|
||||
|
||||
InventoryItem* inventoryItem = &(_target_pud->items[_target_pud->length - (slotIndex + _target_stack_offset[_target_curr_stack] + 1)]);
|
||||
InventoryMoveResult rc = _move_inventory(inventoryItem->item, slotIndex, _target_stack[_target_curr_stack], false);
|
||||
int stealXpOverride = -1;
|
||||
InventoryMoveResult rc = _move_inventory(inventoryItem->item, slotIndex, _target_stack[_target_curr_stack], false, &stealXpOverride);
|
||||
if (rc == INVENTORY_MOVE_RESULT_CAUGHT_STEALING) {
|
||||
isCaughtStealing = true;
|
||||
} else if (rc == INVENTORY_MOVE_RESULT_SUCCESS) {
|
||||
stealingXp += stealingXpBonus;
|
||||
stealingXp += stealXpOverride >= 0 ? stealXpOverride : stealingXpBonus;
|
||||
stealingXpBonus += 10;
|
||||
}
|
||||
|
||||
@@ -4764,8 +4766,11 @@ int inventoryOpenStealing(Object* thief, Object* target)
|
||||
|
||||
// 0x474708
|
||||
// note: this is looting and stealing, not the inventory screen
|
||||
static InventoryMoveResult _move_inventory(Object* item, int slotIndex, Object* targetObj, bool isPlanting)
|
||||
static InventoryMoveResult _move_inventory(Object* item, int slotIndex, Object* targetObj, bool isPlanting, int* stealXpOverridePtr)
|
||||
{
|
||||
assert(stealXpOverridePtr != nullptr);
|
||||
*stealXpOverridePtr = -1;
|
||||
|
||||
bool needRefresh = true;
|
||||
|
||||
Rect rect;
|
||||
@@ -4827,13 +4832,17 @@ static InventoryMoveResult _move_inventory(Object* item, int slotIndex, Object*
|
||||
}
|
||||
|
||||
if (quantityToMove != -1) {
|
||||
bool skipMove = false;
|
||||
if (_gIsSteal && _inven_dude == gDude) {
|
||||
if (skillsPerformStealing(_inven_dude, targetObj, item, true) == 0) {
|
||||
SkillStealResult stealResult = skillsPerformStealing(_inven_dude, targetObj, item, quantityToMove, true, stealXpOverridePtr);
|
||||
if (stealResult == SkillStealResult::Caught) {
|
||||
result = INVENTORY_MOVE_RESULT_CAUGHT_STEALING;
|
||||
} else if (stealResult == SkillStealResult::Fail) {
|
||||
skipMove = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (result != INVENTORY_MOVE_RESULT_CAUGHT_STEALING) {
|
||||
if (!skipMove && result != INVENTORY_MOVE_RESULT_CAUGHT_STEALING) {
|
||||
if (itemMove(_inven_dude, targetObj, item, quantityToMove) != -1) {
|
||||
result = INVENTORY_MOVE_RESULT_SUCCESS;
|
||||
} else {
|
||||
@@ -4854,13 +4863,17 @@ static InventoryMoveResult _move_inventory(Object* item, int slotIndex, Object*
|
||||
}
|
||||
|
||||
if (quantityToMove != -1) {
|
||||
bool skipMove = false;
|
||||
if (_gIsSteal && _inven_dude == gDude) {
|
||||
if (skillsPerformStealing(_inven_dude, targetObj, item, false) == 0) {
|
||||
SkillStealResult stealResult = skillsPerformStealing(_inven_dude, targetObj, item, quantityToMove, false, stealXpOverridePtr);
|
||||
if (stealResult == SkillStealResult::Caught) {
|
||||
result = INVENTORY_MOVE_RESULT_CAUGHT_STEALING;
|
||||
} else if (stealResult == SkillStealResult::Fail) {
|
||||
skipMove = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (result != INVENTORY_MOVE_RESULT_CAUGHT_STEALING) {
|
||||
if (!skipMove && result != INVENTORY_MOVE_RESULT_CAUGHT_STEALING) {
|
||||
if (itemMove(targetObj, _inven_dude, item, quantityToMove) == 0) {
|
||||
if ((item->flags & OBJECT_IN_RIGHT_HAND) != 0) {
|
||||
targetObj->fid = buildFid(FID_TYPE(targetObj->fid), targetObj->fid & 0xFFF, FID_ANIM_TYPE(targetObj->fid), 0, targetObj->rotation + 1);
|
||||
|
||||
@@ -324,6 +324,54 @@ int scriptHooks_AmmoCost(Object* weapon, int rounds, int ammoCost, AmmoCostHookT
|
||||
return overrideAmmoCost >= 0 ? overrideAmmoCost : ammoCost;
|
||||
}
|
||||
|
||||
/*
|
||||
Runs when checking an attempt to steal or plant an item.
|
||||
|
||||
Critter arg0 - The thief
|
||||
Obj arg1 - The target
|
||||
Item arg2 - The item being stolen/planted
|
||||
int arg3 - 0 when stealing, 1 when planting
|
||||
int arg4 - Quantity being stolen/planted
|
||||
|
||||
int ret0 - Override the handler:
|
||||
2 - fail without being caught
|
||||
1 - success
|
||||
0 - fail and get caught
|
||||
-1 - use engine handler
|
||||
int ret1 - Override XP gained for this action. Values below 0 are ignored.
|
||||
*/
|
||||
int scriptHooks_Steal(Object* thief, Object* target, Object* item, bool isPlanting, int quantity, int* xpOverride)
|
||||
{
|
||||
assert(thief != nullptr);
|
||||
assert(target != nullptr);
|
||||
assert(item != nullptr);
|
||||
assert(quantity >= 0);
|
||||
assert(xpOverride != nullptr);
|
||||
|
||||
*xpOverride = -1;
|
||||
|
||||
ScriptHookCall hook(HOOK_STEAL, 2, { thief, target, item, isPlanting ? 1 : 0, quantity });
|
||||
hook.call();
|
||||
|
||||
if (hook.numReturnValues() <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hook.numReturnValues() > 1) {
|
||||
int overrideXp = hook.getReturnValueAt(1).asInt();
|
||||
if (overrideXp >= 0) {
|
||||
*xpOverride = overrideXp;
|
||||
}
|
||||
}
|
||||
|
||||
int overrideResult = hook.getReturnValueAt(0).asInt();
|
||||
if (overrideResult >= 0 && overrideResult <= 2) {
|
||||
return overrideResult;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
Runs immediately after a critter dies for any reason.
|
||||
|
||||
|
||||
@@ -267,6 +267,7 @@ enum AmmoCostHookType {
|
||||
bool scriptHooksRegister(Program* program, HookType hookType, int procedureIndex);
|
||||
bool scriptHooks_StdProcedure(int procedureNumber, Object* self, Object* source, Object* target, int fixedParam, bool after);
|
||||
int scriptHooks_AmmoCost(Object* weapon, int rounds, int ammoCost, AmmoCostHookType hookType);
|
||||
int scriptHooks_Steal(Object* thief, Object* target, Object* item, bool isPlanting, int quantity, int* xpOverride);
|
||||
|
||||
bool scriptHooksInit();
|
||||
void scriptHooksReset();
|
||||
|
||||
+34
-13
@@ -4,6 +4,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "actions.h"
|
||||
#include "color.h"
|
||||
#include "combat.h"
|
||||
@@ -24,6 +26,7 @@
|
||||
#include "random.h"
|
||||
#include "scripts.h"
|
||||
#include "settings.h"
|
||||
#include "sfall_script_hooks.h"
|
||||
#include "stat.h"
|
||||
#include "trait.h"
|
||||
|
||||
@@ -1028,8 +1031,30 @@ int skillUse(Object* obj, Object* target, int skill, int skillBonus)
|
||||
}
|
||||
|
||||
// 0x4ABBE4
|
||||
int skillsPerformStealing(Object* thief, Object* target, Object* item, bool isPlanting)
|
||||
SkillStealResult skillsPerformStealing(Object* thief, Object* target, Object* item, int quantity, bool isPlanting, int* xpOverride)
|
||||
{
|
||||
assert(thief != nullptr);
|
||||
assert(target != nullptr);
|
||||
assert(item != nullptr);
|
||||
assert(quantity >= 0);
|
||||
assert(xpOverride != nullptr);
|
||||
|
||||
*xpOverride = -1;
|
||||
|
||||
int hookXpOverride = -1;
|
||||
int hookResult = scriptHooks_Steal(thief, target, item, isPlanting, quantity, &hookXpOverride);
|
||||
if (hookXpOverride >= 0) {
|
||||
*xpOverride = hookXpOverride;
|
||||
}
|
||||
|
||||
if (hookResult == static_cast<int>(SkillStealResult::Fail)) {
|
||||
return SkillStealResult::Fail;
|
||||
}
|
||||
|
||||
if (hookResult == static_cast<int>(SkillStealResult::Success) || hookResult == static_cast<int>(SkillStealResult::Caught)) {
|
||||
return static_cast<SkillStealResult>(hookResult);
|
||||
}
|
||||
|
||||
int howMuch;
|
||||
|
||||
int stealModifier = -_gStealCount + 1;
|
||||
@@ -1086,26 +1111,22 @@ int skillsPerformStealing(Object* thief, Object* target, Object* item, bool isPl
|
||||
// 571: You steal the %s.
|
||||
// 573: You plant the %s.
|
||||
messageListItem.num = isPlanting ? 573 : 571;
|
||||
if (!messageListGetItem(&gSkillsMessageList, &messageListItem)) {
|
||||
return -1;
|
||||
if (messageListGetItem(&gSkillsMessageList, &messageListItem)) {
|
||||
snprintf(text, sizeof(text), messageListItem.text, objectGetName(item));
|
||||
displayMonitorAddMessage(text);
|
||||
}
|
||||
|
||||
snprintf(text, sizeof(text), messageListItem.text, objectGetName(item));
|
||||
displayMonitorAddMessage(text);
|
||||
|
||||
return 1;
|
||||
return SkillStealResult::Success;
|
||||
} else {
|
||||
// 570: You're caught stealing the %s.
|
||||
// 572: You're caught planting the %s.
|
||||
messageListItem.num = isPlanting ? 572 : 570;
|
||||
if (!messageListGetItem(&gSkillsMessageList, &messageListItem)) {
|
||||
return -1;
|
||||
if (messageListGetItem(&gSkillsMessageList, &messageListItem)) {
|
||||
snprintf(text, sizeof(text), messageListItem.text, objectGetName(item));
|
||||
displayMonitorAddMessage(text);
|
||||
}
|
||||
|
||||
snprintf(text, sizeof(text), messageListItem.text, objectGetName(item));
|
||||
displayMonitorAddMessage(text);
|
||||
|
||||
return 0;
|
||||
return SkillStealResult::Caught;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -12,6 +12,12 @@ extern int _gIsSteal;
|
||||
extern int _gStealCount;
|
||||
extern int _gStealSize;
|
||||
|
||||
enum class SkillStealResult {
|
||||
Caught = 0,
|
||||
Success = 1,
|
||||
Fail = 2,
|
||||
};
|
||||
|
||||
int skillsInit();
|
||||
void skillsReset();
|
||||
void skillsExit();
|
||||
@@ -35,7 +41,7 @@ char* skillGetDescription(int skill);
|
||||
char* skillGetAttributes(int skill);
|
||||
int skillGetFrmId(int skill);
|
||||
int skillUse(Object* obj, Object* target, int skill, int skillBonus);
|
||||
int skillsPerformStealing(Object* thief, Object* target, Object* item, bool isPlanting);
|
||||
SkillStealResult skillsPerformStealing(Object* thief, Object* target, Object* item, int quantity, bool isPlanting, int* xpOverride);
|
||||
int skillGetGameDifficultyModifier(int skill);
|
||||
int skillUpdateLastUse(int skill);
|
||||
int skillsUsageSave(File* stream);
|
||||
|
||||
Reference in New Issue
Block a user