Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mirrored SCM Function opcodes fixes from CLEO5. #30

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
## 2.1.0

- Added opcode 0DD5 (get_platform).
- Added opcode **0DD5 ([get_platform](https://library.sannybuilder.com/#/gta3/CLEO/0DD5))**
- Added opcode **2002 ([cleo_return_with](https://library.sannybuilder.com/#/gta3/CLEO/2002))**
- Added opcode **2003 ([cleo_return_fail](https://library.sannybuilder.com/#/gta3/CLEO/2003))**
- 'argument count' parameter of **0AB1 (cleo_call)** is now optional. `cleo_call @LABEL args 0` can be written as `cleo_call @LABEL`
- 'argument count' parameter of **0AB2 (cleo_return)** is now optional. `cleo_return 0` can be written as `cleo_return`
- SCM functions **(0AB1)** now keep their own GOSUB's call stack
- correct support of condition result of opcode **0AB1 (cleo_call)** used in multi conditional 'if' statements.
- Partially fixed 0ADD (spawn car like a cheat) for GTA3. Now opcode can spawn not only the tank. Still no support for models with id greater than 127.
- Fixed 0ADB to return GXT label instead of car name (same as in Cleo SA).
- Crash fix in 0AF4 read_string_from_ini_file. Fixed some internal data-type sizes.
Expand Down
143 changes: 143 additions & 0 deletions source/CLEO_SDK/test_scripts/TestScmFunctions.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
{$CLEO .cs}
nop

while true
1@ = 0
cleo_call @SUM {numArgs} 2 {args} 2 3 {result} 1@
if
1@ == 5
then
print_formatted_now "~g~2 + 3 = %d" {time} 1000 {arg} 1@
else
print_formatted_now "~r~2 + 3 = %d" {time} 5000 {arg} 1@
wait 5000
end
wait 1000

if
cleo_call @PASS_TRUE
then
print_formatted_now "~g~PASS TRUE ok" {time} 1000
else
print_formatted_now "~r~PASS TRUE failed" {time} 5000
wait 5000
end
wait 1000

if
cleo_call @PASS_FALSE
then
print_formatted_now "~r~PASS FALSE failed" {time} 5000
wait 5000
else
print_formatted_now "~g~PASS FALSE ok" {time} 1000
end
wait 1000

if
not cleo_call @PASS_TRUE
then
print_formatted_now "~r~negation failed" {time} 5000
wait 5000
else
print_formatted_now "~g~negation ok" {time} 1000
end
wait 1000

cleo_call @COMBINE {numArgs} 0 {result} 1@
if
1@ == 1
then
print_formatted_now "~g~COMBINE ok" {time} 1000
else
print_formatted_now "~r~COMBINE failed" {time} 5000
wait 5000
end
wait 1000

if and
cleo_call @RET_WITH_TRUE {numArgs} 0 {result} 1@ 2@
1@ == 5
2@ == 6
then
print_formatted_now "~g~RET WITH TRUE ok" {time} 1000
else
print_formatted_now "~r~RET WITH TRUE failed %d %d" {time} 5000 {args} 1@ 2@
wait 5000
end
wait 1000

if and
not cleo_call @RET_WITH_FALSE {numArgs} 0 {result} 1@ 2@
1@ == 5
2@ == 6
then
print_formatted_now "~g~RET WITH FALSE ok" {time} 1000
else
print_formatted_now "~r~RET WITH FALSE failed %d %d" {time} 5000 {args} 1@ 2@
wait 5000
end
wait 1000

1@ = 7
2@ = 8
if and
not cleo_call @RET_FAIL {numArgs} 0 {result} 1@ 2@
1@ == 7
2@ == 8
then
print_formatted_now "~g~RET FAIL ok" {time} 1000
else
print_formatted_now "~r~RET FAIL failed %d %d" {time} 5000 {args} 1@ 2@
wait 5000
end
wait 1000
end

terminate_this_custom_script


:FUNC
cleo_return {numArgs} 4 {args} TIMERA 444 23 TIMERB


:SUM
005A: 0@ += 1@
cleo_return {numArgs} 1 {args} 0@


:PASS_TRUE
return_true
cleo_return


:PASS_FALSE
return_false
cleo_return


:COMBINE
if and
cleo_call @PASS_TRUE
not cleo_call @PASS_FALSE
then
0@ = 1
else
0@ = 2
end
cleo_return 1 0@


:RET_WITH_TRUE
cleo_return_with true {args} 5 6


:RET_WITH_FALSE
cleo_return_with false {args} 5 6


:RET_FAIL
1@ = 2
2@ = 3
cleo_return_fail

107 changes: 85 additions & 22 deletions source/III.VC.CLEO/CustomOpcodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ void CustomOpcodes::Register()
#endif

Opcodes::RegisterOpcode(0x0DD5, GET_PLATFORM);

// CLEO 5
Opcodes::RegisterOpcode(0x2002, SCM_FUNCTION_RET_WITH);
Opcodes::RegisterOpcode(0x2003, SCM_FUNCTION_RET_FAIL);
}

eOpcodeResult CustomOpcodes::DUMMY(CScript *script)
Expand Down Expand Up @@ -985,34 +989,93 @@ eOpcodeResult CustomOpcodes::MATH_LOG(CScript *script)

eOpcodeResult CustomOpcodes::CALL_SCM_FUNCTION(CScript *script)
{
script->m_pScmFunction = new ScmFunction(script);
script->Collect(2);
int addr = game.Scripts.Params[0].nVar;
unsigned int paramCount = game.Scripts.Params[1].nVar;
if(paramCount > 0)
script->Collect(paramCount);
memset(script->m_aLVars, 0, 64);
if(paramCount > 0)
memcpy(script->m_aLVars, game.Scripts.Params, paramCount * 4);
script->m_pScmFunction->retAddr = script->m_dwIp;
script->JumpTo(addr);
int label;
script->Collect(1);
label = game.Scripts.Params[0].nVar;

DWORD paramCount = 0;
if(script->GetNextParamType() != PARAM_TYPE_END_OF_PARAMS)
{
script->Collect(1);
paramCount = game.Scripts.Params[0].nVar;

if (paramCount > 0)
script->Collect(paramCount);
}

new ScmFunction(script);

// transfer params as local variables
if (paramCount > 0)
memcpy(script->m_aLVars, game.Scripts.Params, paramCount * sizeof(tScriptVar));

script->JumpTo(label);

return OR_CONTINUE;
}

eOpcodeResult CustomOpcodes::SCM_FUNCTION_RET(CScript *script)
{
DWORD retArgCount = 0;
if (script->GetNextParamType() != PARAM_TYPE_END_OF_PARAMS)
{
script->Collect(1);
retArgCount = game.Scripts.Params[0].nVar;

if (retArgCount > 0)
{
script->Collect(retArgCount);
}
}

ScmFunction::Return(script);

if(retArgCount > 0)
script->Store(retArgCount);
script->m_dwIp++; // 0AB1 var arg terminator

return OR_CONTINUE;
}

eOpcodeResult CustomOpcodes::SCM_FUNCTION_RET_WITH(CScript* script)
{
script->Collect(1);
unsigned int paramCount = game.Scripts.Params[0].nVar;
if(paramCount > 0)
script->Collect(paramCount);
memcpy(script->m_aLVars, script->m_pScmFunction->vars, 64);
script->m_dwIp = script->m_pScmFunction->retAddr;
if(paramCount > 0)
script->Store(paramCount);
script->m_dwIp++;
ScmFunction *prev = script->m_pScmFunction->prev;
delete script->m_pScmFunction;
script->m_pScmFunction = prev;
bool result = game.Scripts.Params[0].nVar != 0;

static tScriptVar retArgs[16];
DWORD retArgCount = 0;
while (script->GetNextParamType() != PARAM_TYPE_END_OF_PARAMS)
{
script->Collect(1);
retArgs[retArgCount] = game.Scripts.Params[0];
retArgCount++;
}

script->m_bCondResult = result;
ScmFunction::Return(script);

if (retArgCount > 0)
{
memcpy(game.Scripts.Params, retArgs, retArgCount * sizeof(tScriptVar));
script->Store(retArgCount);
}
script->m_dwIp++; // 0AB1 var arg terminator

return OR_CONTINUE;
}

eOpcodeResult CustomOpcodes::SCM_FUNCTION_RET_FAIL(CScript* script)
{
script->m_bCondResult = false;
ScmFunction::Return(script);

// skip unused target return params
while (script->GetNextParamType() != PARAM_TYPE_END_OF_PARAMS)
{
script->Collect(1);
}
script->m_dwIp++; // and terminator itself

return OR_CONTINUE;
}

Expand Down
2 changes: 2 additions & 0 deletions source/III.VC.CLEO/CustomOpcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class CustomOpcodes
static eOpcodeResult WINAPI MATH_LOG(CScript *script);
static eOpcodeResult WINAPI CALL_SCM_FUNCTION(CScript *script);
static eOpcodeResult WINAPI SCM_FUNCTION_RET(CScript *script);
static eOpcodeResult WINAPI SCM_FUNCTION_RET_WITH(CScript* script);
static eOpcodeResult WINAPI SCM_FUNCTION_RET_FAIL(CScript* script);
static eOpcodeResult WINAPI GET_LABEL_OFFSET(CScript *script);
static eOpcodeResult WINAPI GET_VAR_OFFSET(CScript *script);
static eOpcodeResult WINAPI BIT_AND(CScript *script);
Expand Down
34 changes: 33 additions & 1 deletion source/III.VC.CLEO/CustomScript.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#endif

#include "ScmFunction.h"
#include <wtypes.h>


enum eScriptType :unsigned short
{
Expand Down Expand Up @@ -48,6 +50,36 @@ struct tParamType
bool processed : 1; // did we process long string already
};

enum eLogicalOperation : WORD
{
NONE = 0, // just replace

AND_2 = 1, // AND operation on results of next two conditional opcodes
AND_3,
AND_4,
AND_5,
AND_6,
AND_7,
AND_END,

OR_2 = 21, // OR operation on results of next two conditional opcodes
OR_3,
OR_4,
OR_5,
OR_6,
OR_7,
OR_END,
};
static eLogicalOperation& operator--(eLogicalOperation& o)
{
if (o == eLogicalOperation::NONE) return o; // can not be decremented anymore
if (o == eLogicalOperation::OR_2) return o = eLogicalOperation::NONE;

auto val = static_cast<WORD>(o); // to number
val--;
return o = static_cast<eLogicalOperation>(val);
}

class CScript
{
public:
Expand All @@ -70,7 +102,7 @@ class CScript
#endif
/* 0x7B */ bool m_bAwake;
/* 0x7C */ unsigned int m_dwWakeTime;
/* 0x80 */ unsigned short m_wIfOp;
/* 0x80 */ eLogicalOperation m_wIfOp;
/* 0x82 */ bool m_bNotFlag;
/* 0x83 */ bool m_bDeathArrestCheckEnabled;
/* 0x84 */ bool m_bWastedOrBusted;
Expand Down
Loading