#pragma once #include "Patching.hpp" #include "Accessors.hpp" #include "Structures.hpp" #include "Defines.hpp" extern "C" { #include #include #include } #include #include #pragma warning(disable : 4996) namespace PatchFix { namespace Scripting { namespace Lua { lua_State* L[10]; std::string ScriptFileNames[10]; std::string ScriptFileData[10]; bool ScriptLoadedAndRunEnabled[10]; Dword CurrentScriptExecutionPlayerIndex; } namespace TA_API { enum DataType { DATATYPE_INTEGER, DATATYPE_FLOAT, DATATYPE_STRING }; enum UnitOrder { UNITORDER_DGUN = 9, UNITORDER_BUILD = 25, UNITORDER_MOVE = 26, UNITORDER_RECLAIM = 33, UNITORDER_REPAIR = 36, UNITORDER_SELFDESTRUCT = 38, UNITORDER_ATTACK = 46 }; const Dword MaxValuesForEachType = 0x20000; //const Dword MaxUnitInfoIDTypes = 512; DwordPtr PlayerValueInt[10]; FloatPtr PlayerValueFloat[10]; //BytePtr PlayerValueChars[10]; //UnitNameToUnitInfoID UnitNameInfoList[MaxUnitInfoIDTypes]; int GetTotalPlayers(lua_State* L); int GetPlayerActive(lua_State* L); int SendChatTextToAll(lua_State* L); int SendChatTextDataToAll(lua_State* L); int NewUnitOrder_DEBUG(lua_State* L); int GetMyMetalAmount(lua_State* L); int GetMyEnergyAmount(lua_State* L); int GetMyMetalStorageAmount(lua_State* L); int GetMyEnergyStorageAmount(lua_State* L); int GetMyMetalIncome(lua_State* L); int GetMyMetalDrain(lua_State* L); int GetMyEnergyIncome(lua_State* L); int GetMyEnergyDrain(lua_State* L); int SearchMyUnitByType(lua_State* L); //int SearchMyUnitsByType(lua_State* L); //int SearchMyUnits(lua_State* L); //int SearchPlayerUnit(lua_State* L); //int SearchPlayerUnits(lua_State* L); //int SearchAllUnit(lua_State* L); //int SearchAllUnits(lua_State* L); //int SearchMetalSpot(lua_State* L); //int SearchMetalSpots(lua_State* L); //int SearchFeature(lua_State* L); //int SearchFeatures(lua_State* L); int GetStoredIntValue(lua_State* L); int GetStoredFloatValue(lua_State* L); int SetStoredIntValue(lua_State* L); int SetStoredFloatValue(lua_State* L); int GetGameTime(lua_State* L); } bool NewFirstRun = true; Patching::Patch Scripting1; Patching::Patch Scripting2; void Scripting1Func(); void Scripting2Func(); void ScriptingInit(); void ScriptingLoop(); void ScriptingDeInit(); void InitLuaEngine(); void DeInitLuaEngine(); void LoadScripts(); //void RegisterLuaToTAFunctions(); void AllocateStoredMemoryForPlayerScripts(); void FreeStoredMemoryForPlayerScripts(); void ApplyPatches(); } } __declspec(naked) void PatchFix::Scripting::Scripting1Func() { __asm { pushad pushfd call ScriptingInit popfd popad mov eax, dword ptr ds:[0x511DE8] jmp [Scripting1.ReturnAddr] } } __declspec(naked) void PatchFix::Scripting::Scripting2Func() { __asm { pushad pushfd call ScriptingLoop popfd popad mov ecx, [eax + 0x38A47] jmp [Scripting2.ReturnAddr] } } void PatchFix::Scripting::ScriptingInit() { if (NewFirstRun) { DeInitLuaEngine(); InitLuaEngine(); LoadScripts(); NewFirstRun = false; } } void PatchFix::Scripting::ScriptingLoop() { if (Accessors::GetGameState() == Accessors::GAMESTATE_IN_GAME) { NewFirstRun = true; for (int I = 0; I < 10; I++) { if (Lua::ScriptLoadedAndRunEnabled[I] == true) { Lua::CurrentScriptExecutionPlayerIndex = I; luaL_loadstring(Lua::L[I], Lua::ScriptFileData[I].c_str()); lua_pcall(Lua::L[I], 0, LUA_MULTRET, 0); } } } } void PatchFix::Scripting::ScriptingDeInit() { DeInitLuaEngine(); } void PatchFix::Scripting::InitLuaEngine() { for (int I = 0; I < 10; I++) { AllocateStoredMemoryForPlayerScripts(); Lua::L[I] = luaL_newstate(); luaL_openlibs(Lua::L[I]); lua_register(Lua::L[I], "TA_GetTotalPlayers", TA_API::GetTotalPlayers); lua_register(Lua::L[I], "TA_GetPlayerActive", TA_API::GetPlayerActive); lua_register(Lua::L[I], "TA_SendChatTextToAll", TA_API::SendChatTextToAll); lua_register(Lua::L[I], "TA_SendChatTextDataToAll", TA_API::SendChatTextDataToAll); lua_register(Lua::L[I], "TA_NewUnitOrder_DEBUG", TA_API::NewUnitOrder_DEBUG); lua_register(Lua::L[I], "TA_GetMyMetalAmount", TA_API::GetMyMetalAmount); lua_register(Lua::L[I], "TA_GetMyEnergyAmount", TA_API::GetMyEnergyAmount); lua_register(Lua::L[I], "TA_GetMyMetalStorageTotal", TA_API::GetMyMetalStorageAmount); lua_register(Lua::L[I], "TA_GetMyEnergyStorageTotal", TA_API::GetMyEnergyStorageAmount); lua_register(Lua::L[I], "TA_GetMyMetalIncome", TA_API::GetMyMetalIncome); lua_register(Lua::L[I], "TA_GetMyMetalDrain", TA_API::GetMyMetalDrain); lua_register(Lua::L[I], "TA_GetMyEnergyIncome", TA_API::GetMyEnergyIncome); lua_register(Lua::L[I], "TA_GetMyEnergyDrain", TA_API::GetMyEnergyDrain); lua_register(Lua::L[I], "TA_SearchMyUnitByType", TA_API::SearchMyUnitByType); //lua_register(Lua::L[I], "TA_SearchMyUnitsByType", TA_API::SearchMyUnitsByType); //lua_register(Lua::L[I], "TA_SearchMyUnit", TA_API::SearchMyUnit); //lua_register(Lua::L[I], "TA_SearchMyUnits", TA_API::SearchMyUnits); //lua_register(Lua::L[I], "TA_SearchPlayerUnit", TA_API::SearchPlayerUnit); //lua_register(Lua::L[I], "TA_SearchPlayerUnits", TA_API::SearchPlayerUnits); //lua_register(Lua::L[I], "TA_SearchAllUnit", TA_API::SearchAllUnit); //lua_register(Lua::L[I], "TA_SearchAllUnits", TA_API::SearchAllUnits); //lua_register(Lua::L[I], "TA_SearchMetalSpot", TA_API::SearchMetalSpot); //lua_register(Lua::L[I], "TA_SearchMetalSpots", TA_API::SearchMetalSpots); //lua_register(Lua::L[I], "TA_SearchFeature", TA_API::SearchFeature); //lua_register(Lua::L[I], "TA_SearchFeatures", TA_API::SearchFeatures); lua_register(Lua::L[I], "TA_GetStoredIntValue", TA_API::GetStoredIntValue); lua_register(Lua::L[I], "TA_GetStoredFloatValue", TA_API::GetStoredFloatValue); lua_register(Lua::L[I], "TA_SetStoredIntValue", TA_API::SetStoredIntValue); lua_register(Lua::L[I], "TA_SetStoredFloatValue", TA_API::SetStoredFloatValue); lua_register(Lua::L[I], "TA_GetGameTime", TA_API::GetGameTime); // lua_register(Lua::L[I], "", TA_API::); } } void PatchFix::Scripting::DeInitLuaEngine() { FreeStoredMemoryForPlayerScripts(); for (int I = 0; I < 10; I++) { if (Lua::L[I]) { lua_close(Lua::L[I]); } Lua::L[I] = null; } } void PatchFix::Scripting::LoadScripts() { std::ifstream ifile; ifile.open("ScriptSlots.txt"); for (Dword L = 0; L < 10 && !ifile.eof(); L++) { ifile >> Lua::ScriptFileNames[L]; } ifile.close(); for (int I = 0; I < 10; I++) { ifile.open(Lua::ScriptFileNames[I]); Lua::ScriptFileData[I] = std::string((std::istreambuf_iterator(ifile)), std::istreambuf_iterator()); if (Lua::ScriptFileNames[I].length() > 0) { Lua::ScriptLoadedAndRunEnabled[I] = true; } else { Lua::ScriptLoadedAndRunEnabled[I] = false; } ifile.close(); } } //void PatchFix::Scripting::RegisterLuaToTAFunctions() //{ // //} void PatchFix::Scripting::AllocateStoredMemoryForPlayerScripts() { for (Dword I = 0; I < 10; I++) { TA_API::PlayerValueInt[I] = (DwordPtr)malloc(TA_API::MaxValuesForEachType * sizeof(int)); TA_API::PlayerValueFloat[I] = (FloatPtr)malloc(TA_API::MaxValuesForEachType * sizeof(float)); //TA_API::PlayerValueChars[I] = (BytePtr)malloc(TA_API::MaxValuesForEachType * sizeof(BytePtr)); if (TA_API::PlayerValueInt[I] != null && TA_API::PlayerValueFloat[I] != null) { for (Dword J = 0; J < TA_API::MaxValuesForEachType; J++) { TA_API::PlayerValueInt[I][J] = 0; TA_API::PlayerValueFloat[I][J] = 0.0f; } } } } void PatchFix::Scripting::FreeStoredMemoryForPlayerScripts() { for (Dword I = 0; I < 10; I++) { free(TA_API::PlayerValueInt[I]); free(TA_API::PlayerValueFloat[I]); } } void PatchFix::Scripting::ApplyPatches() { Scripting1.Setup(PATCHTYPE_INTERCEPT, null, null, JUMPTYPE_JMP, (VoidPtr)0x00497F40, Scripting1Func, (VoidPtr)0x00497F45); // Callback_LoadGame Scripting2.Setup(PATCHTYPE_INTERCEPT, null, null, JUMPTYPE_JMP, (VoidPtr)0x004954B7, Scripting2Func, (VoidPtr)0x004954BD); // GameLoop Scripting1.Apply(); Scripting2.Apply(); } int PatchFix::Scripting::TA_API::GetTotalPlayers(lua_State* L) { Dword TotalPlayers = Accessors::GetTotalPlayersCount(); lua_pushinteger(L, TotalPlayers); return 1; } int PatchFix::Scripting::TA_API::GetPlayerActive(lua_State* L) { Dword Arguments = lua_gettop(L); Dword IsActive; if (Arguments > 0) { Dword PlayerIndex = lua_tointeger(L, 1); IsActive = Accessors::GetPlayerActiveByIndex(PlayerIndex); lua_pushinteger(L, IsActive); return 1; } IsActive = 0; lua_pushinteger(L, IsActive); return 1; } int PatchFix::Scripting::TA_API::SendChatTextToAll(lua_State* L) { int Arguments = lua_gettop(L); if (Arguments > 0) { const char* ChatString = lua_tostring(L, 1); BuiltIn::TA_ShowChatText(Accessors::GetPlayerPtrByIndex(Lua::CurrentScriptExecutionPlayerIndex), ChatString, 4, 0); } return 0; } int PatchFix::Scripting::TA_API::SendChatTextDataToAll(lua_State* L) { int Arguments = lua_gettop(L); if (Arguments > 0) { const char* ChatString = lua_tostring(L, 1); char NewChatString[256]; Dword DataType = lua_tointeger(L, 3); if (DataType == DATATYPE_INTEGER) { Dword IntegerData = lua_tointeger(L, 2); sprintf(NewChatString, ChatString, IntegerData); } else if (DataType == DATATYPE_FLOAT) { float FloatData = lua_tonumber(L, 2); sprintf(NewChatString, ChatString, FloatData); } else if (DataType == DATATYPE_STRING) { const char* CharData = lua_tostring(L, 2); sprintf(NewChatString, ChatString, CharData); } BuiltIn::TA_ShowChatText(Accessors::GetPlayerPtrByIndex(Lua::CurrentScriptExecutionPlayerIndex), NewChatString, 4, 0); } return 0; } int PatchFix::Scripting::TA_API::NewUnitOrder_DEBUG(lua_State* L) { // only allow unit indexes within the player's allocated range // this will prevent cheating with a script touching other players via control int Arguments = lua_gettop(L); if (Arguments == 8) { Dword UnitOrderPtr = lua_tointeger(L, 8); // change to unit index //VoidPtr UnitOrderPtr = (VoidPtr)lua_topointer(L, 8); // change to unit index Dword UnitIDToBuild = lua_tointeger(L, 7); Dword PositionZ = lua_tointeger(L, 6); Dword PositionX = lua_tointeger(L, 5); Dword TargetUnit = lua_tointeger(L, 4); //VoidPtr TargetUnit = (VoidPtr)lua_topointer(L, 4); // change to unit index Dword UnitToSendOrder = lua_tointeger(L, 3); //VoidPtr UnitToOrderPtr = (VoidPtr)lua_topointer(L, 3); // change to unit index Dword AppendOrder_Bit = lua_tointeger(L, 2); Dword OrderID_Byte = lua_tointeger(L, 1); DwordPtr UnitToOrderPtr; DwordPtr UnitToSendOrderPtr; if (TargetUnit != 0) { UnitToSendOrderPtr = Accessors::GetUnitPtrByUnitIndex(TargetUnit); } else { UnitToSendOrderPtr = 0; } if (UnitToSendOrder != 0) { UnitToOrderPtr = Accessors::GetUnitPtrByUnitIndex(UnitToSendOrder); } else { UnitToOrderPtr = 0; } PositionXYZ* MapPosition = new PositionXYZ; MapPosition->X_ = PositionX; MapPosition->Z_ = PositionZ; Dword PositionY = BuiltIn::TA_GetHeightAtMapPosition(MapPosition); MapPosition->Y_ = PositionY; BuiltIn::TA_NewUnitOrder_DEBUG(OrderID_Byte, AppendOrder_Bit, UnitToOrderPtr, UnitToSendOrderPtr, MapPosition, UnitIDToBuild, UnitOrderPtr); } return 0; } int PatchFix::Scripting::TA_API::GetMyMetalAmount(lua_State* L) { float MetalAmount = Accessors::GetPlayerMetalAmount(Scripting::Lua::CurrentScriptExecutionPlayerIndex); lua_pushnumber(L, MetalAmount); return 1; } int PatchFix::Scripting::TA_API::GetMyEnergyAmount(lua_State* L) { float EnergyAmount = Accessors::GetPlayerEnergyAmount(Scripting::Lua::CurrentScriptExecutionPlayerIndex); lua_pushnumber(L, EnergyAmount); return 1; } int PatchFix::Scripting::TA_API::GetMyMetalStorageAmount(lua_State* L) { float MetalStorageAmount = Accessors::GetPlayerMetalStorageTotal(Scripting::Lua::CurrentScriptExecutionPlayerIndex); lua_pushnumber(L, MetalStorageAmount); return 1; } int PatchFix::Scripting::TA_API::GetMyEnergyStorageAmount(lua_State* L) { float EnergyStorageAmount = Accessors::GetPlayerEnergyStorageTotal(Scripting::Lua::CurrentScriptExecutionPlayerIndex); lua_pushnumber(L, EnergyStorageAmount); return 1; } int PatchFix::Scripting::TA_API::GetMyMetalIncome(lua_State* L) { float MetalIncome = Accessors::GetPlayerMetalIncome(Scripting::Lua::CurrentScriptExecutionPlayerIndex); lua_pushnumber(L, MetalIncome); return 1; } int PatchFix::Scripting::TA_API::GetMyMetalDrain(lua_State* L) { float MetalDrain = Accessors::GetPlayerMetalDrain(Scripting::Lua::CurrentScriptExecutionPlayerIndex); lua_pushnumber(L, MetalDrain); return 1; } int PatchFix::Scripting::TA_API::GetMyEnergyIncome(lua_State* L) { float EnergyIncome = Accessors::GetPlayerEnergyIncome(Scripting::Lua::CurrentScriptExecutionPlayerIndex); lua_pushnumber(L, EnergyIncome); return 1; } int PatchFix::Scripting::TA_API::GetMyEnergyDrain(lua_State* L) { float EnergyDrain = Accessors::GetPlayerEnergyDrain(Scripting::Lua::CurrentScriptExecutionPlayerIndex); lua_pushnumber(L, EnergyDrain); return 1; } int PatchFix::Scripting::TA_API::SearchMyUnitByType(lua_State* L) { /* Accepts UnitType (Dword) Returns Index of First Found Unit */ int Arguments = lua_gettop(L); short UnitIndex; if (Arguments == 1) { Dword UnitType = lua_tointeger(L, 1); UnitIndex = Accessors::GetUnitIndexByUnitType(Scripting::Lua::CurrentScriptExecutionPlayerIndex, UnitType); lua_pushinteger(L, UnitIndex); return 1; } UnitIndex = 0; lua_pushinteger(L, UnitIndex); return 1; } //int PatchFix::Scripting::TA_API::SearchMyUnitsByType(lua_State* L) //{ // //} //int PatchFix::Scripting::TA_API::SearchMyUnits(lua_State* L) //{ // //} // //int PatchFix::Scripting::TA_API::SearchPlayerUnit(lua_State* L) //{ // //} // //int PatchFix::Scripting::TA_API::SearchPlayerUnits(lua_State* L) //{ // //} // //int PatchFix::Scripting::TA_API::SearchAllUnit(lua_State* L) //{ // //} // //int PatchFix::Scripting::TA_API::SearchAllUnits(lua_State* L) //{ // //} // //int PatchFix::Scripting::TA_API::SearchMetalSpot(lua_State* L) //{ // //} // //int PatchFix::Scripting::TA_API::SearchMetalSpots(lua_State* L) //{ // //} // //int PatchFix::Scripting::TA_API::SearchFeature(lua_State* L) //{ // //} // //int PatchFix::Scripting::TA_API::SearchFeatures(lua_State* L) //{ // //} int PatchFix::Scripting::TA_API::GetStoredIntValue(lua_State* L) { int Arguments = lua_gettop(L); int RetrievedStoredIntValue = 0; if (Arguments == 1) { Dword IndexToRetrieve = lua_tointeger(L, 1); if (IndexToRetrieve < MaxValuesForEachType) { RetrievedStoredIntValue = PlayerValueInt[Lua::CurrentScriptExecutionPlayerIndex][IndexToRetrieve]; lua_pushinteger(L, RetrievedStoredIntValue); return 1; } RetrievedStoredIntValue = 0; lua_pushinteger(L, RetrievedStoredIntValue); return 1; } RetrievedStoredIntValue = 0; lua_pushinteger(L, RetrievedStoredIntValue); return 1; } int PatchFix::Scripting::TA_API::GetStoredFloatValue(lua_State* L) { int Arguments = lua_gettop(L); float RetrievedStoredFloatValue = 0; if (Arguments == 1) { Dword IndexToRetrieve = lua_tointeger(L, 1); if (IndexToRetrieve < MaxValuesForEachType) { RetrievedStoredFloatValue = PlayerValueFloat[Lua::CurrentScriptExecutionPlayerIndex][IndexToRetrieve]; lua_pushnumber(L, RetrievedStoredFloatValue); return 1; } RetrievedStoredFloatValue = 0; lua_pushnumber(L, RetrievedStoredFloatValue); return 1; } RetrievedStoredFloatValue = 0; lua_pushnumber(L, RetrievedStoredFloatValue); return 1; } int PatchFix::Scripting::TA_API::SetStoredIntValue(lua_State* L) { int Arguments = lua_gettop(L); int RetrievedIndex = 0; int RetrievedIntToStore = 0; if (Arguments == 2) { RetrievedIndex = lua_tointeger(L, 1); RetrievedIntToStore = lua_tointeger(L, 2); if (RetrievedIndex < MaxValuesForEachType) { PlayerValueInt[Lua::CurrentScriptExecutionPlayerIndex][RetrievedIndex] = RetrievedIntToStore; return 0; } return 0; } return 0; } int PatchFix::Scripting::TA_API::SetStoredFloatValue(lua_State* L) { int Arguments = lua_gettop(L); int RetrievedIndex = 0; float RetrievedFloatToStore = 0; if (Arguments == 2) { RetrievedIndex = lua_tointeger(L, 1); RetrievedFloatToStore = lua_tonumber(L, 2); if (RetrievedIndex < MaxValuesForEachType) { PlayerValueFloat[Lua::CurrentScriptExecutionPlayerIndex][RetrievedIndex] = RetrievedFloatToStore; return 0; } return 0; } return 0; } int PatchFix::Scripting::TA_API::GetGameTime(lua_State* L) { Dword GameTime = Accessors::GetGameTime(); lua_pushinteger(L, GameTime); return 1; }