mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
2
Commits
heap-fixes
...
hook-steal
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b649c416c | ||
|
|
1a50bebff1 |
@@ -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` | âś… | - |
|
||||
|
||||
@@ -98,6 +98,8 @@ auto_quick_save=3
|
||||
display_bonus_damage=1
|
||||
;Set to 1 to get notification of karma changes in the notification window
|
||||
display_karma_changes=0
|
||||
;Set to 1 to use the hi-res dialog border/background at resolutions above 640x480. Requires art\intrface\HR_ALLTLK.FRM (for example from f2_res.dat)
|
||||
enable_dialog_border=1
|
||||
;Set to one to hide areas outside map bounds when using higher than 640x480 resolution, and to zero to disable
|
||||
enable_high_resolution_stencil=1
|
||||
;Set to 1 to extend the action points bar to show up to 16 AP instead of 10 (requires iface_apbar_e.frm)
|
||||
|
||||
@@ -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
|
||||
+85
-29
@@ -279,6 +279,8 @@ static int gGameDialogBackgroundWindow = -1;
|
||||
// 0x518744
|
||||
static int gGameDialogWindow = -1;
|
||||
|
||||
static bool gameDialogUseHrArt = false;
|
||||
|
||||
// 0x518748
|
||||
static Rect _backgrndRects[8] = {
|
||||
{ 126, 14, 152, 40 },
|
||||
@@ -291,6 +293,37 @@ static Rect _backgrndRects[8] = {
|
||||
{ 504, 40, 514, 188 },
|
||||
};
|
||||
|
||||
static bool gameDialogShouldUseHrArt()
|
||||
{
|
||||
return settings.ui.enable_dialog_border
|
||||
&& (screenGetWidth() > GAME_DIALOG_WINDOW_WIDTH || screenGetHeight() > GAME_DIALOG_WINDOW_HEIGHT);
|
||||
}
|
||||
|
||||
static int gameDialogHrArtYOffset()
|
||||
{
|
||||
return gameDialogUseHrArt ? 5 : 0;
|
||||
}
|
||||
|
||||
static Rect gameDialogGetBackgroundRect(int index)
|
||||
{
|
||||
Rect rect = _backgrndRects[index];
|
||||
int yOffset = gameDialogHrArtYOffset();
|
||||
rect.top += yOffset;
|
||||
rect.bottom += yOffset;
|
||||
return rect;
|
||||
}
|
||||
|
||||
static int gameDialogGetBackgroundWindowY()
|
||||
{
|
||||
// center onplay area if large enough, else center on screen
|
||||
int visibleHeight = screenGetVisibleHeight();
|
||||
if (visibleHeight >= GAME_DIALOG_WINDOW_HEIGHT) {
|
||||
return (visibleHeight - GAME_DIALOG_WINDOW_HEIGHT) / 2;
|
||||
}
|
||||
|
||||
return (screenGetHeight() - GAME_DIALOG_WINDOW_HEIGHT) / 2;
|
||||
}
|
||||
|
||||
// 0x5187C8
|
||||
static bool _talk_need_to_center = true;
|
||||
|
||||
@@ -2494,31 +2527,35 @@ int _gdCreateHeadWindow()
|
||||
int windowWidth = GAME_DIALOG_WINDOW_WIDTH;
|
||||
|
||||
// NOTE: Uninline.
|
||||
talk_to_create_background_window();
|
||||
gameDialogWindowRenderBackground();
|
||||
if (talk_to_create_background_window() == -1 || gameDialogWindowRenderBackground() == -1) {
|
||||
_gdDestroyHeadWindow();
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char* buf = windowGetBuffer(gGameDialogBackgroundWindow);
|
||||
ConstBuffer2D backgroundBuf = windowGetBuffer2D(gGameDialogBackgroundWindow);
|
||||
|
||||
for (int index = 0; index < 8; index++) {
|
||||
soundContinueAll();
|
||||
|
||||
Rect* rect = &(_backgrndRects[index]);
|
||||
int width = rect->right - rect->left;
|
||||
int height = rect->bottom - rect->top;
|
||||
Rect rect = gameDialogGetBackgroundRect(index);
|
||||
int width = rect.right - rect.left;
|
||||
int height = rect.bottom - rect.top;
|
||||
_backgrndBufs[index] = (unsigned char*)internal_malloc(width * height);
|
||||
if (_backgrndBufs[index] == nullptr) {
|
||||
_gdDestroyHeadWindow();
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char* src = buf;
|
||||
src += windowWidth * rect->top + rect->left;
|
||||
|
||||
blitBufferToBuffer(src, width, height, windowWidth, _backgrndBufs[index], width);
|
||||
Buffer2D savedBackgroundBuf { _backgrndBufs[index], width, height };
|
||||
blitBuffer2D(backgroundBuf, rect.left, rect.top, width, height, savedBackgroundBuf);
|
||||
}
|
||||
|
||||
_gdialog_window_create();
|
||||
if (_gdialog_window_create() == -1) {
|
||||
_gdDestroyHeadWindow();
|
||||
return -1;
|
||||
}
|
||||
|
||||
gGameDialogDisplayBuffer = windowGetBuffer(gGameDialogBackgroundWindow) + windowWidth * 14 + 126;
|
||||
gGameDialogDisplayBuffer = windowGetBuffer(gGameDialogBackgroundWindow) + windowWidth * (14 + gameDialogHrArtYOffset()) + 126;
|
||||
|
||||
// TODO: jnz at 0x447275 without cmp or test, not sure what that means.
|
||||
if (false) {
|
||||
@@ -2547,10 +2584,12 @@ void _gdDestroyHeadWindow()
|
||||
gGameDialogBackgroundWindow = -1;
|
||||
}
|
||||
|
||||
gameDialogUseHrArt = false;
|
||||
gExpandedBarterEnabled = false;
|
||||
|
||||
for (int index = 0; index < 8; index++) {
|
||||
internal_free(_backgrndBufs[index]);
|
||||
_backgrndBufs[index] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4551,13 +4590,14 @@ static const char* expandedBarterFrmName()
|
||||
// 0x44AAD8
|
||||
static int talk_to_create_background_window()
|
||||
{
|
||||
gameDialogUseHrArt = false;
|
||||
|
||||
gExpandedBarterEnabled = settings.ui.expand_barter_window
|
||||
&& screenGetHeight() >= GAME_DIALOG_WINDOW_HEIGHT + kExpandedBarterExtraHeight
|
||||
&& FrmImage().lock(OBJ_TYPE_INTERFACE, expandedBarterFrmName());
|
||||
|
||||
int backgroundWindowX = (screenGetWidth() - GAME_DIALOG_WINDOW_WIDTH) / 2;
|
||||
int effectiveBgHeight = GAME_DIALOG_WINDOW_HEIGHT + (gExpandedBarterEnabled ? kExpandedBarterExtraHeight : 0);
|
||||
int backgroundWindowY = (screenGetHeight() - effectiveBgHeight) / 2;
|
||||
int backgroundWindowY = gameDialogGetBackgroundWindowY();
|
||||
|
||||
gGameDialogBackgroundWindow = windowCreate(backgroundWindowX,
|
||||
backgroundWindowY,
|
||||
@@ -4577,15 +4617,29 @@ static int talk_to_create_background_window()
|
||||
int gameDialogWindowRenderBackground()
|
||||
{
|
||||
FrmImage backgroundFrmImage;
|
||||
// alltlk.frm - dialog screen background
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 103, 0, 0, 0);
|
||||
if (!backgroundFrmImage.lock(backgroundFid)) {
|
||||
return -1;
|
||||
|
||||
if (gameDialogShouldUseHrArt()) {
|
||||
if (backgroundFrmImage.lock(OBJ_TYPE_INTERFACE, "HR_ALLTLK.frm")
|
||||
&& backgroundFrmImage.getWidth() >= GAME_DIALOG_WINDOW_WIDTH
|
||||
&& backgroundFrmImage.getHeight() >= GAME_DIALOG_WINDOW_HEIGHT) {
|
||||
gameDialogUseHrArt = true;
|
||||
} else {
|
||||
backgroundFrmImage.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
int windowWidth = GAME_DIALOG_WINDOW_WIDTH;
|
||||
unsigned char* windowBuffer = windowGetBuffer(gGameDialogBackgroundWindow);
|
||||
blitBufferToBuffer(backgroundFrmImage.getData(), windowWidth, 480, windowWidth, windowBuffer, windowWidth);
|
||||
if (!backgroundFrmImage.isLocked()) {
|
||||
// alltlk.frm - dialog screen background
|
||||
FrmId backgroundFid(OBJ_TYPE_INTERFACE, 103);
|
||||
if (!backgroundFrmImage.lock(backgroundFid)) {
|
||||
return -1;
|
||||
}
|
||||
gameDialogUseHrArt = false;
|
||||
}
|
||||
|
||||
ConstBuffer2D backgroundFrmBuf = backgroundFrmImage.getBuffer();
|
||||
Buffer2D windowBuf = windowGetBuffer2D(gGameDialogBackgroundWindow);
|
||||
blitBuffer2D(backgroundFrmBuf, 0, 0, GAME_DIALOG_WINDOW_WIDTH, GAME_DIALOG_WINDOW_HEIGHT, windowBuf);
|
||||
|
||||
if (!_dialogue_just_started) {
|
||||
windowRefresh(gGameDialogBackgroundWindow);
|
||||
@@ -4734,11 +4788,13 @@ void gameDialogRenderTalkingHead(Art* headFrm, int frame)
|
||||
GAME_DIALOG_WINDOW_WIDTH);
|
||||
}
|
||||
|
||||
int yOffset = gameDialogHrArtYOffset();
|
||||
|
||||
Rect headRect;
|
||||
headRect.left = 126;
|
||||
headRect.top = 14;
|
||||
headRect.top = 14 + yOffset;
|
||||
headRect.right = 514;
|
||||
headRect.bottom = 214;
|
||||
headRect.bottom = 214 + yOffset;
|
||||
|
||||
unsigned char* dest = windowGetBuffer(gGameDialogBackgroundWindow);
|
||||
|
||||
@@ -4748,7 +4804,7 @@ void gameDialogRenderTalkingHead(Art* headFrm, int frame)
|
||||
_upperHighlightFrmImage.getWidth(),
|
||||
dest,
|
||||
426,
|
||||
15,
|
||||
15 + yOffset,
|
||||
GAME_DIALOG_WINDOW_WIDTH,
|
||||
_light_BlendTable,
|
||||
_light_GrayTable);
|
||||
@@ -4759,20 +4815,20 @@ void gameDialogRenderTalkingHead(Art* headFrm, int frame)
|
||||
_lowerHighlightFrmImage.getWidth(),
|
||||
dest,
|
||||
129,
|
||||
214 - _lowerHighlightFrmImage.getHeight() - 2,
|
||||
214 + yOffset - _lowerHighlightFrmImage.getHeight() - 2,
|
||||
GAME_DIALOG_WINDOW_WIDTH,
|
||||
_dark_BlendTable,
|
||||
_dark_GrayTable);
|
||||
|
||||
for (int index = 0; index < 8; ++index) {
|
||||
Rect* rect = &(_backgrndRects[index]);
|
||||
int width = rect->right - rect->left;
|
||||
Rect rect = gameDialogGetBackgroundRect(index);
|
||||
int width = rect.right - rect.left;
|
||||
|
||||
blitBufferToBufferTrans(_backgrndBufs[index],
|
||||
width,
|
||||
rect->bottom - rect->top,
|
||||
rect.bottom - rect.top,
|
||||
width,
|
||||
dest + GAME_DIALOG_WINDOW_WIDTH * rect->top + rect->left,
|
||||
dest + GAME_DIALOG_WINDOW_WIDTH * rect.top + rect.left,
|
||||
GAME_DIALOG_WINDOW_WIDTH);
|
||||
}
|
||||
|
||||
|
||||
+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);
|
||||
|
||||
@@ -160,6 +160,7 @@ void initSettingsRegistry(bool isMapper)
|
||||
SETTING(display_karma_changes);
|
||||
SETTING(display_bonus_damage);
|
||||
SETTING(numbers_in_dialogue);
|
||||
SETTING(enable_dialog_border);
|
||||
SETTING_P(auto_quick_save, clamp(0, 10));
|
||||
SETTING(enable_high_resolution_stencil);
|
||||
SETTING(extend_ap_bar);
|
||||
|
||||
@@ -69,6 +69,7 @@ struct UISettings {
|
||||
bool display_karma_changes = false;
|
||||
bool display_bonus_damage = false;
|
||||
bool numbers_in_dialogue = false;
|
||||
bool enable_dialog_border = true;
|
||||
int auto_quick_save = 0;
|
||||
bool enable_high_resolution_stencil = true;
|
||||
int inventory_columns = 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();
|
||||
|
||||
+30
-5
@@ -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;
|
||||
@@ -1087,25 +1112,25 @@ int skillsPerformStealing(Object* thief, Object* target, Object* item, bool isPl
|
||||
// 573: You plant the %s.
|
||||
messageListItem.num = isPlanting ? 573 : 571;
|
||||
if (!messageListGetItem(&gSkillsMessageList, &messageListItem)) {
|
||||
return -1;
|
||||
return SkillStealResult::fail;
|
||||
}
|
||||
|
||||
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;
|
||||
return SkillStealResult::fail;
|
||||
}
|
||||
|
||||
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