Added DivisionOperatorFix option for signed integer division (#278)

* it changes the behavior of vanilla division operator to use signed
integer division. Before it used signed division for floats but
unsigned for integers.

Added a new "div" operator for unsigned integer division.
Moved mathematical script functions from Utils.cpp to new Math.cpp.
Added include guard to sfall.h and main.h in modders pack.
This commit is contained in:
NovaRain
2020-02-02 21:02:06 +08:00
parent eb204f0a04
commit 53b407b8a5
18 changed files with 214 additions and 117 deletions
+3
View File
@@ -584,6 +584,9 @@ StartGDialogFix=0
;attacker_results - unused, must be 0 or not equal to the target_results argument when specifying result flags for the target
AttackComplexFix=0
;Set to 1 to fix the issue with the division operator treating negative integers as unsigned
DivisionOperatorFix=1
;Set to 1 to enable the balanced bullet distribution formula for burst attacks
ComputeSprayMod=0
+4
View File
@@ -1,3 +1,5 @@
#ifndef MAIN_H
#define MAIN_H
#include "..\scripting\headers\sfall.h"
#include "..\scripting\headers\define_lite.h"
@@ -71,3 +73,5 @@ end
procedure InitConfigs begin
translationIni := GetIniConfigStr("Main", "TranslationsINI", "Translations.ini", "ddraw.ini");
end
#endif
@@ -344,6 +344,7 @@ There are several changes in this version of sslc which may result in problems f
- fixed compiler giving "assignment operator expected" error when a variable-like macro is not being defined properly
- added new logical operators "AndAlso", "OrElse" for short-circuit evaluation of logical expressions
- added an alternative (C/Java-style) assignment operator "="
- added support for new "div" operator (unsigned integer division)
> sfall 4.2.2
- added support for new opcode "reg_anim_callback"
+1 -1
View File
@@ -112,7 +112,7 @@
#define MSGBOX_SMALL (0x2)
#define MSGBOX_ALIGN_LEFT (0x4) // text aligned to left
#define MSGBOX_ALIGN_TOP (0x8) // text aligned to top
#define MSGBOX_YESNO (0x10) // uses YES/NO buttons instead of DONE
#define MSGBOX_YESNO (0x10) // use YES/NO buttons instead of DONE
#define MSGBOX_CLEAN (0x20) // no buttons
//remove inven obj defines
+3 -3
View File
@@ -10,10 +10,10 @@
#define below(a, b) (unsigned_comp(a, b) < 0)
#define below_equal(a, b) (unsigned_comp(a, b) <= 0)
procedure unsigned_comp(variable a, variable b) begin
// for sfall 4.2.3/3.8.23
pure procedure unsigned_comp(variable a, variable b) begin
if ((a bwxor b) == 0) then return 0; // a == b
if (b == 0) then return 1;
return 1 if (a / b) else -1;
return 1 if ((b == 0) orElse a div b) else -1;
end
#define MAX(x, y) ((x > y) * x + (x <= y) * y)
+5
View File
@@ -1,3 +1,6 @@
#ifndef SFALL_H
#define SFALL_H
//Recognised modes for set_shader_mode and get_game_mode
#define WORLDMAP (0x1)
#define DIALOG (0x4)
@@ -354,3 +357,5 @@
#define set_fake_perk_npc(npc, perk, level, image, desc) sfall_func5("set_fake_perk_npc", npc, perk, level, image, desc)
#define set_fake_trait_npc(npc, trait, active, image, desc) sfall_func5("set_fake_trait_npc", npc, trait, active, image, desc)
#define set_selectable_perk_npc(npc, perk, active, image, desc) sfall_func5("set_selectable_perk_npc", npc, perk, active, image, desc)
#endif
@@ -360,6 +360,8 @@
0x827d - void register_hook_proc_spec(int hook, procedure proc)
0x827e - void reg_anim_callback(procedure proc)
0x827f - div operator (unsigned integer division)
* These functions require AllowUnsafeScripting to be enabled in ddraw.ini
+7 -1
View File
@@ -2505,7 +2505,7 @@ void BugFixes::init()
// Missing game initialization
LoadGameHook::OnBeforeGameInit() += Initialization;
// Fix vanilla negate operator on float values
// Fix vanilla negate operator for float values
MakeCall(0x46AB68, NegateFixHack);
// Fix incorrect int-to-float conversion
// op_mult:
@@ -2514,6 +2514,12 @@ void BugFixes::init()
// op_div:
SafeWrite16(0x46A566, 0x04DB);
SafeWrite16(0x46A4E7, 0x04DB);
// Fix for vanilla division operator treating negative integers as unsigned
if (GetConfigInt("Misc", "DivisionOperatorFix", 1)) {
dlog("Applying division operator fix.", DL_INIT);
SafeWrite32(0x46A51D, 0xFBF79990); // xor edx, edx; div ebx > cdq; idiv ebx
dlogr(" Done", DL_INIT);
}
//if (GetConfigInt("Misc", "SpecialUnarmedAttacksFix", 1)) {
dlog("Applying Special Unarmed Attacks fix.", DL_INIT);
+4 -2
View File
@@ -17,9 +17,7 @@
*/
#include "..\..\..\FalloutEngine\Fallout2.h"
#include "..\..\..\SafeWrite.h"
#include "..\..\..\Version.h"
#include "..\..\KillCounter.h"
#include "..\..\HookScripts.h"
#include "..\..\ScriptExtender.h"
#include "..\Arrays.h"
@@ -32,6 +30,10 @@ namespace sfall
namespace script
{
void sf_typeof(OpcodeContext& ctx) {
ctx.setReturn(static_cast<int>(ctx.arg(0).type()));
}
void __declspec(naked) op_set_global_script_repeat() {
__asm {
mov esi, ecx;
+3 -3
View File
@@ -18,15 +18,15 @@
#pragma once
/*
Opcodes for core sfall features.
*/
/* Opcodes for core sfall features. */
namespace sfall
{
namespace script
{
void sf_typeof(OpcodeContext&);
void __declspec() op_set_global_script_repeat();
void __declspec() op_set_global_script_type();
+112
View File
@@ -0,0 +1,112 @@
/*
* sfall
* Copyright (C) 2008-2020 The sfall team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cmath>
#include "..\OpcodeContext.h"
#include "Math.h"
namespace sfall
{
namespace script
{
void sf_div(OpcodeContext& ctx) {
if (ctx.arg(1).rawValue() == 0) {
ctx.printOpcodeError("%s - division by zero.", ctx.getOpcodeName());
return;
}
if (ctx.arg(0).isFloat() || ctx.arg(1).isFloat()) {
ctx.setReturn(ctx.arg(0).asFloat() / ctx.arg(1).asFloat());
} else {
ctx.setReturn(ctx.arg(0).rawValue() / ctx.arg(1).rawValue()); // unsigned division
}
}
void sf_sqrt(OpcodeContext& ctx) {
ctx.setReturn(sqrt(ctx.arg(0).asFloat()));
}
void sf_abs(OpcodeContext& ctx) {
if (ctx.arg(0).isInt()) {
ctx.setReturn(abs((int)ctx.arg(0).rawValue()));
} else {
ctx.setReturn(abs(ctx.arg(0).asFloat()));
}
}
void sf_sin(OpcodeContext& ctx) {
ctx.setReturn(sin(ctx.arg(0).asFloat()));
}
void sf_cos(OpcodeContext& ctx) {
ctx.setReturn(cos(ctx.arg(0).asFloat()));
}
void sf_tan(OpcodeContext& ctx) {
ctx.setReturn(tan(ctx.arg(0).asFloat()));
}
void sf_arctan(OpcodeContext& ctx) {
ctx.setReturn(atan2(ctx.arg(0).asFloat(), ctx.arg(1).asFloat()));
}
void sf_power(OpcodeContext& ctx) {
const ScriptValue &base = ctx.arg(0),
&power = ctx.arg(1);
float result = 0.0;
if (power.isFloat())
result = pow(base.asFloat(), power.floatValue());
else
result = pow(base.asFloat(), (int)power.rawValue());
if (base.isInt() && power.isInt()) {
ctx.setReturn(static_cast<int>(result));
} else {
ctx.setReturn(result);
}
}
void sf_log(OpcodeContext& ctx) {
ctx.setReturn(log(ctx.arg(0).asFloat()));
}
void sf_exponent(OpcodeContext& ctx) {
ctx.setReturn(exp(ctx.arg(0).asFloat()));
}
void sf_ceil(OpcodeContext& ctx) {
ctx.setReturn(static_cast<int>(ceil(ctx.arg(0).asFloat())));
}
void sf_round(OpcodeContext& ctx) {
float arg = ctx.arg(0).asFloat();
int argI = static_cast<int>(arg);
float mod = arg - static_cast<float>(argI);
if (abs(mod) >= 0.5) argI += (mod > 0 ? 1 : -1);
ctx.setReturn(argI);
}
void sf_floor2(OpcodeContext& ctx) {
ctx.setReturn(static_cast<int>(floor(ctx.arg(0).asFloat())));
}
}
}
+55
View File
@@ -0,0 +1,55 @@
/*
* sfall
* Copyright (C) 2008-2020 The sfall team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
namespace sfall
{
namespace script
{
class OpcodeContext;
void sf_div(OpcodeContext&);
void sf_sqrt(OpcodeContext&);
void sf_abs(OpcodeContext&);
void sf_sin(OpcodeContext&);
void sf_cos(OpcodeContext&);
void sf_tan(OpcodeContext&);
void sf_arctan(OpcodeContext&);
void sf_power(OpcodeContext&);
void sf_log(OpcodeContext&);
void sf_exponent(OpcodeContext&);
void sf_ceil(OpcodeContext&);
void sf_round(OpcodeContext&);
void sf_floor2(OpcodeContext&);
}
}
@@ -23,6 +23,7 @@
#include "Anims.h"
#include "Core.h"
#include "Interface.h"
#include "Math.h"
#include "Misc.h"
#include "Objects.h"
#include "Perks.h"
@@ -16,16 +16,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cmath>
#include "..\..\..\FalloutEngine\Fallout2.h"
#include "..\..\..\FalloutEngine\EngineUtils.h"
#include "..\..\ScriptExtender.h"
#include "..\..\FileSystem.h"
#include "..\..\Message.h"
#include "..\Arrays.h"
#include "..\OpcodeContext.h"
#include "..\ScriptValue.h"
#include "Utils.h"
@@ -99,34 +95,6 @@ static bool FalloutStringCompare(const char* str1, const char* str2, long codePa
}
}
void sf_sqrt(OpcodeContext& ctx) {
ctx.setReturn(sqrt(ctx.arg(0).asFloat()));
}
void sf_abs(OpcodeContext& ctx) {
if (ctx.arg(0).isInt()) {
ctx.setReturn(abs((int)ctx.arg(0).rawValue()));
} else {
ctx.setReturn(abs(ctx.arg(0).asFloat()));
}
}
void sf_sin(OpcodeContext& ctx) {
ctx.setReturn(sin(ctx.arg(0).asFloat()));
}
void sf_cos(OpcodeContext& ctx) {
ctx.setReturn(cos(ctx.arg(0).asFloat()));
}
void sf_tan(OpcodeContext& ctx) {
ctx.setReturn(tan(ctx.arg(0).asFloat()));
}
void sf_arctan(OpcodeContext& ctx) {
ctx.setReturn(atan2(ctx.arg(0).asFloat(), ctx.arg(1).asFloat()));
}
void sf_strlen(OpcodeContext& ctx) {
ctx.setReturn(
static_cast<int>(strlen(ctx.arg(0).strValue()))
@@ -152,10 +120,6 @@ void sf_ord(OpcodeContext& ctx) {
ctx.setReturn(static_cast<unsigned long>(firstChar));
}
void sf_typeof(OpcodeContext& ctx) {
ctx.setReturn(static_cast<int>(ctx.arg(0).type()));
}
static int _stdcall StringSplit(const char* str, const char* split) {
int id;
size_t count, splitLen = strlen(split);
@@ -380,44 +344,6 @@ void sf_string_format(OpcodeContext& ctx) {
}
}
void sf_power(OpcodeContext& ctx) {
const ScriptValue &base = ctx.arg(0),
&power = ctx.arg(1);
float result = 0.0;
if (power.isFloat())
result = pow(base.asFloat(), power.floatValue());
else
result = pow(base.asFloat(), (int)power.rawValue());
if (base.isInt() && power.isInt()) {
ctx.setReturn(static_cast<int>(result));
} else {
ctx.setReturn(result);
}
}
void sf_log(OpcodeContext& ctx) {
ctx.setReturn(log(ctx.arg(0).asFloat()));
}
void sf_exponent(OpcodeContext& ctx) {
ctx.setReturn(exp(ctx.arg(0).asFloat()));
}
void sf_ceil(OpcodeContext& ctx) {
ctx.setReturn(static_cast<int>(ceil(ctx.arg(0).asFloat())));
}
void sf_round(OpcodeContext& ctx) {
float arg = ctx.arg(0).asFloat();
int argI = static_cast<int>(arg);
float mod = arg - static_cast<float>(argI);
if (abs(mod) >= 0.5) {
argI += (mod > 0 ? 1 : -1);
}
ctx.setReturn(argI);
}
void sf_message_str_game(OpcodeContext& ctx) {
const char* msg = nullptr;
@@ -454,10 +380,6 @@ void sf_add_extra_msg_file(OpcodeContext& ctx) {
ctx.setReturn(result);
}
void sf_floor2(OpcodeContext& ctx) {
ctx.setReturn(static_cast<int>(floor(ctx.arg(0).asFloat())));
}
void sf_get_string_pointer(OpcodeContext& ctx) {
ctx.setReturn(reinterpret_cast<long>(ctx.arg(0).strValue()), DataType::INT);
}
-26
View File
@@ -25,18 +25,6 @@ namespace script
class OpcodeContext;
void sf_sqrt(OpcodeContext&);
void sf_abs(OpcodeContext&);
void sf_sin(OpcodeContext&);
void sf_cos(OpcodeContext&);
void sf_tan(OpcodeContext&);
void sf_arctan(OpcodeContext&);
void sf_string_split(OpcodeContext&);
void sf_atoi(OpcodeContext&);
@@ -55,24 +43,10 @@ void sf_string_format(OpcodeContext&);
void sf_ord(OpcodeContext&);
void sf_typeof(OpcodeContext&);
void sf_power(OpcodeContext&);
void sf_log(OpcodeContext&);
void sf_exponent(OpcodeContext&);
void sf_ceil(OpcodeContext&);
void sf_round(OpcodeContext&);
void sf_message_str_game(OpcodeContext&);
void sf_add_extra_msg_file(OpcodeContext&);
void sf_floor2(OpcodeContext&);
void sf_get_string_pointer(OpcodeContext&);
void sf_get_text_width(OpcodeContext&);
+3 -1
View File
@@ -26,6 +26,7 @@
#include "Handlers\FileSystem.h"
#include "Handlers\Graphics.h"
#include "Handlers\Interface.h"
#include "Handlers\Math.h"
#include "Handlers\Memory.h"
#include "Handlers\Misc.h"
#include "Handlers\Objects.h"
@@ -189,7 +190,7 @@ static SfallOpcodeInfo opcodeInfoArray[] = {
{0x260, "reg_anim_turn_towards", sf_reg_anim_turn_towards, 3, false, 0, {ARG_OBJECT, ARG_INT, ARG_INT}},
{0x261, "metarule2_explosions", sf_explosions_metarule, 3, true, -1, {ARG_INT, ARG_INT, ARG_INT}},
{0x262, "register_hook_proc", sf_register_hook, 2, false, 0, {ARG_INT, ARG_INT}},
{0x263, "power", sf_power, 2, true, 0, {ARG_NUMBER, ARG_NUMBER}},
{0x263, "power", sf_power, 2, true, 0, {ARG_NUMBER, ARG_NUMBER}}, // '^' operator
{0x264, "log", sf_log, 1, true, 0, {ARG_NUMBER}},
{0x265, "exponent", sf_exponent, 1, true, 0, {ARG_NUMBER}},
{0x266, "ceil", sf_ceil, 1, true, 0, {ARG_NUMBER}},
@@ -219,6 +220,7 @@ static SfallOpcodeInfo opcodeInfoArray[] = {
{0x27d, "register_hook_proc_spec", sf_register_hook, 2, false, 0, {ARG_INT, ARG_INT}},
{0x27e, "reg_anim_callback", sf_reg_anim_callback, 1, false, 0, {ARG_INT}},
{0x27f, "div", sf_div, 2, true, 0, {ARG_NUMBER, ARG_NUMBER}}, // div operator
};
// An array for opcode info, indexed by opcode.
+2
View File
@@ -312,6 +312,7 @@
<ClInclude Include="Modules\LoadOrder.h" />
<ClInclude Include="Modules\Objects.h" />
<ClInclude Include="Modules\PlayerModel.h" />
<ClInclude Include="Modules\Scripting\Handlers\Math.h" />
<ClInclude Include="Modules\SpeedPatch.h" />
<ClInclude Include="Modules\SubModules\CombatBlock.h" />
<ClInclude Include="Modules\Worldmap.h" />
@@ -405,6 +406,7 @@
<ClCompile Include="Modules\LoadOrder.cpp" />
<ClCompile Include="Modules\Objects.cpp" />
<ClCompile Include="Modules\PlayerModel.cpp" />
<ClCompile Include="Modules\Scripting\Handlers\Math.cpp" />
<ClCompile Include="Modules\SpeedPatch.cpp" />
<ClCompile Include="Modules\SubModules\CombatBlock.cpp" />
<ClCompile Include="Modules\Worldmap.cpp" />
+8 -2
View File
@@ -298,6 +298,9 @@
<ClInclude Include="Modules\TalkingHeads.h">
<Filter>Modules\Features</Filter>
</ClInclude>
<ClInclude Include="Modules\Scripting\Handlers\Math.h">
<Filter>Modules\Scripting\Handlers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
@@ -496,6 +499,9 @@
</ClCompile>
<ClCompile Include="CRC.cpp" />
<ClCompile Include="CheckAddress.cpp" />
<ClCompile Include="Modules\SubModules\CombatBlock.cpp">
<Filter>Modules\SubModules</Filter>
</ClCompile>
<ClCompile Include="Modules\PlayerModel.cpp">
<Filter>Modules\SimplePatches</Filter>
</ClCompile>
@@ -544,8 +550,8 @@
<ClCompile Include="Modules\TalkingHeads.cpp">
<Filter>Modules\Features</Filter>
</ClCompile>
<ClCompile Include="Modules\SubModules\CombatBlock.cpp">
<Filter>Modules\SubModules</Filter>
<ClCompile Include="Modules\Scripting\Handlers\Math.cpp">
<Filter>Modules\Scripting\Handlers</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>