[G2NK] Dodatkowe wolne AIVARy. 268 2

O temacie

Autor Khantor

Zaczęty 1.11.2020 roku

Wyświetleń 268

Odpowiedzi 2

Khantor

Khantor

Użytkownicy
posty45
Propsy10
Profesjabrak
  • Użytkownicy

Khantor

[G2NK] Dodatkowe wolne AIVARy.
2020-11-01, 19:31(Ostatnia zmiana: 2020-11-01, 19:40)
Witam. Często można spotkać opinię, że w Gothicu jest za mało wolnych AIVarów do wykorzystania, ale chyba nie znalazłem nigdzie sposobu, żeby te dodatkowe AIVary sobie zwolnić. Jak wiemy, w G2NK mamy do dyspozycji 11 wolnych AIVarów (89-99 gdzie 89 jest wykorzystywany przez LeGo do tworzenia nowej umiejętności), na upartego 12, bo AIVar 72 "AIV_NPCIsRanger" nie jest w ogóle wykorzystywany w skryptach. Pokażę więc dzisiaj, w jaki sposób zwolnić sobie dodatkowe 52 AIVary. Jak ktoś bardzo potrzebuje i się uprze to może sobie zwolnić ich jeszcze więcej. Z góry uprzedzam, że wymaga to dosyć sporo monotonnej roboty, ale nie ma nic za darmo. Potrzebny Ikarus i LeGo.

Jeśli przyjrzymy się AIVarom które mamy w Gothicu to możemy zauważyć, że duża ich część przyjmuje tylko wartości 0-1, a większość przyjmuje wartości nie większe niż 23. Jeśli mamy do wykorzystania ograniczoną ilość AIVarów, z czego każdy ma wielkość 32 bitów, to zużycie go na zapisanie tylko 1-5 bitów to straszne marnotractwo miejsca. Jako, że chyba żaden, poza "AIV_INVINCIBLE" nie jest w żaden sposób czytany przez silnik, to jedyne co musimy zrobić, to skompresować z góry ograniczone AIVary o długości 1-5 bitów w jeden. Poniżej wyznaczona przeze mnie lista AIVarów do kompresji.

AIVary 0-1; - 1 bit

AIV_NpcStartedTalk
AIV_TalkedToPlayer
AIV_PlayerHasPickedMyPocket
AIV_PursuitEnd
AIV_RANSACKED
AIV_DeathInvGiven
AIV_PASSGATE
AIV_PARTYMEMBER
AIV_VictoryXPGiven
AIV_Gender
AIV_SeenLeftRoom
AIV_ToughGuyNewsOverride
AIV_MM_ThreatenBeforeAttack
AIV_MM_FollowInWater
AIV_MM_PRIORITY
AIV_DuelLost
AIV_MM_Packhunter
AIV_MagicUser
AIV_DropDeadAndKill
AIV_IGNORE_Murder
AIV_IGNORE_Theft
AIV_IGNORE_Sheepkiller
AIV_ToughGuy
AIV_NewsOverride
AIV_EnemyOverride
AIV_LOADGAME
AIV_DefeatedByPlayer
AIV_KilledByPlayer
AIV_IgnoresFakeGuild
AIV_NoFightParker
AIV_NPCIsRanger
AIV_IgnoresArmor
AIV_StoryBandit
AIV_StoryBandit_Esteban


AIVary 0-2; - 2 bity

AIV_Guardpassage_Status
AIV_TAPOSITION


AIVary 0-3; - 2 bity

AIV_LastFightAgainstPlayer
AIV_Food
AIV_ArenaFight


AIVary 0-4; - 3 bity

AIV_NpcSawPlayerCommit


AIVary 0-7; - 3 bity

AIV_ChapterInv


AIVary 0-19; - 5 bitów

AIV_ATTACKREASON
AIV_LastPlayerAR


AIVary 0-23 godziny; - 5 bitów

AIV_MM_SleepStart
AIV_MM_SleepEnd
AIV_MM_RestStart
AIV_MM_RestEnd
AIV_MM_RoamStart
AIV_MM_RoamEnd
AIV_MM_EatGroundStart
AIV_MM_EatGroundEnd
AIV_MM_WuselStart
AIV_MM_WuselEnd
AIV_MM_OrcSitStart
AIV_MM_OrcSitEnd


AIVar 0-14; - 4 bity

AIV_MM_ShrinkState

56 powyższych AIVarów można skompresować do 4. Zaczynamy od napisania funkcji, która nam będzie:
a) Kompresować wiele AIVarów w jeden i w razie potrzeby zmieniać ich wartości w obrębie skompresowanego AIVaru.
b) Odczytywać ze skompresowanego AIVara wartości AIVarów składowych.

Gotowiec:

func int PowerFunction (var int Basic_of_Power, var int Power)
{
var int Powered_Number; Powered_Number = 1;
var int index; index = 0;

if (Power < 0)
{
Power = 0;
};

if (Power == 0)
{
return Powered_Number;
};

var int loopStart; loopStart = MEM_StackPos.position;
if (index < Power)
{
Powered_Number = Powered_Number * Basic_of_Power;

index += 1;
MEM_StackPos.position = loopStart;
};

return Powered_Number;
};

func int Byte_for_AIVars (var C_NPC AIVar_Taker, var int AIVar_Input, var int Value_to_AIVar, var int Write_or_Read) //var int Write_or_Read = 0 - wpisanie w skompresowany AIVar AIVaru składowego AIVar_Input którego wartość wynosi Value_to_AIVar; var int Write_or_Read = 1 - odczytanie ze skompresowanego AIVara wartości AIVara składowego AIVar_Input.
// Value_to_AIVar - AIVary 5 - bitowe określające godziny mogą przyjmować wartość "-1". U nas rolę "-1" będzie pełnić "31".
{
var int Nr_CompressedAIVar; Nr_CompressedAIVar = 0; // Na którym z 4 skompresowanych AIVarów będzie znajował się nam nasz AIVar kompresowany
var int Bit_AIVar_CompressedAIVar; Bit_AIVar_CompressedAIVar = 0; // Od którego bitu w AIVarze skompresowanym zaczyna się nasz AIVar kompresowany
var int Bit_Position_AIVar; Bit_Position_AIVar = 0; // Długość w bitach AIVaru kompresowanego

if (AIVar_Input == AIV_MM_OrcSitEnd) // 41
{
Nr_CompressedAIVar = 1;
Bit_AIVar_CompressedAIVar = 1;
Bit_Position_AIVar = 5;
}
else if (AIVar_Input == AIV_MM_SleepStart) // 30
{
Nr_CompressedAIVar = 1;
Bit_AIVar_CompressedAIVar = 6;
Bit_Position_AIVar = 5;
}
else if (AIVar_Input == AIV_MM_SleepEnd) // 31
{
Nr_CompressedAIVar = 1;
Bit_AIVar_CompressedAIVar = 11;
Bit_Position_AIVar = 5;
}
else if (AIVar_Input == AIV_MM_RestStart) // 32
{
Nr_CompressedAIVar = 1;
Bit_AIVar_CompressedAIVar = 16;
Bit_Position_AIVar = 5;
}
else if (AIVar_Input == AIV_MM_RestEnd) // 33
{
Nr_CompressedAIVar = 1;
Bit_AIVar_CompressedAIVar = 21;
Bit_Position_AIVar = 5;
}
else if (AIVar_Input == AIV_MM_RoamStart) // 34
{
Nr_CompressedAIVar = 1;
Bit_AIVar_CompressedAIVar = 26;
Bit_Position_AIVar = 5;
}
else if (AIVar_Input == AIV_IgnoresFakeGuild) // 70
{
Nr_CompressedAIVar = 1;
Bit_AIVar_CompressedAIVar = 31;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_MM_RoamEnd) // 35
{
Nr_CompressedAIVar = 2;
Bit_AIVar_CompressedAIVar = 1;
Bit_Position_AIVar = 5;
}
else if (AIVar_Input == AIV_MM_EatGroundStart) // 36
{
Nr_CompressedAIVar = 2;
Bit_AIVar_CompressedAIVar = 6;
Bit_Position_AIVar = 5;
}
else if (AIVar_Input == AIV_MM_EatGroundEnd) // 37
{
Nr_CompressedAIVar = 2;
Bit_AIVar_CompressedAIVar = 11;
Bit_Position_AIVar = 5;
}
else if (AIVar_Input == AIV_MM_WuselStart) // 38
{
Nr_CompressedAIVar = 2;
Bit_AIVar_CompressedAIVar = 16;
Bit_Position_AIVar = 5;
}
else if (AIVar_Input == AIV_MM_WuselEnd) // 39
{
Nr_CompressedAIVar = 2;
Bit_AIVar_CompressedAIVar = 21;
Bit_Position_AIVar = 5;
}
else if (AIVar_Input == AIV_MM_OrcSitStart) // 40
{
Nr_CompressedAIVar = 2;
Bit_AIVar_CompressedAIVar = 26;
Bit_Position_AIVar = 5;
}
else if (AIVar_Input == AIV_DeathInvGiven) // 11
{
Nr_CompressedAIVar = 2;
Bit_AIVar_CompressedAIVar = 31;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_NoFightParker) // 71
{
Nr_CompressedAIVar = 3;
Bit_AIVar_CompressedAIVar = 1;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_NPCIsRanger) // 72
{
Nr_CompressedAIVar = 3;
Bit_AIVar_CompressedAIVar = 2;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_IgnoresArmor) // 73
{
Nr_CompressedAIVar = 3;
Bit_AIVar_CompressedAIVar = 3;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_StoryBandit) // 74
{
Nr_CompressedAIVar = 3;
Bit_AIVar_CompressedAIVar = 4;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_StoryBandit_Esteban) // 75
{
Nr_CompressedAIVar = 3;
Bit_AIVar_CompressedAIVar = 5;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_ATTACKREASON) // 9
{
Nr_CompressedAIVar = 3;
Bit_AIVar_CompressedAIVar = 6;
Bit_Position_AIVar = 5;
}
else if (AIVar_Input == AIV_MM_ShrinkState) // 42
{
Nr_CompressedAIVar = 3;
Bit_AIVar_CompressedAIVar = 11;
Bit_Position_AIVar = 4;
}
else if (AIVar_Input == AIV_ChapterInv) // 49
{
Nr_CompressedAIVar = 3;
Bit_AIVar_CompressedAIVar = 15;
Bit_Position_AIVar = 3;
}
else if (AIVar_Input == AIV_NpcSawPlayerCommit) // 1
{
Nr_CompressedAIVar = 3;
Bit_AIVar_CompressedAIVar = 18;
Bit_Position_AIVar = 3;
}
else if (AIVar_Input == AIV_ArenaFight) // 45
{
Nr_CompressedAIVar = 3;
Bit_AIVar_CompressedAIVar = 21;
Bit_Position_AIVar = 2;
}
else if (AIVar_Input == AIV_Guardpassage_Status) // 12
{
Nr_CompressedAIVar = 3;
Bit_AIVar_CompressedAIVar = 23;
Bit_Position_AIVar = 2;
}
else if (AIVar_Input == AIV_TAPOSITION) // 19
{
Nr_CompressedAIVar = 3;
Bit_AIVar_CompressedAIVar = 25;
Bit_Position_AIVar = 2;
}
else if (AIVar_Input == AIV_NpcStartedTalk) // 3
{
Nr_CompressedAIVar = 3;
Bit_AIVar_CompressedAIVar = 27;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_TalkedToPlayer) // 5
{
Nr_CompressedAIVar = 3;
Bit_AIVar_CompressedAIVar = 28;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_PlayerHasPickedMyPocket) // 6
{
Nr_CompressedAIVar = 3;
Bit_AIVar_CompressedAIVar = 29;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_PursuitEnd) // 8
{
Nr_CompressedAIVar = 3;
Bit_AIVar_CompressedAIVar = 30;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_RANSACKED) // 10
{
Nr_CompressedAIVar = 3;
Bit_AIVar_CompressedAIVar = 31;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_PASSGATE) // 14
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 1;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_PARTYMEMBER) // 15
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 2;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_VictoryXPGiven) // 16
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 3;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_Gender) // 17
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 4;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_SeenLeftRoom) // 21
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 5;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_ToughGuyNewsOverride) // 25
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 6;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_MM_ThreatenBeforeAttack) // 26
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 7;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_MM_FollowInWater) // 28
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 8;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_MM_PRIORITY) // 29
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 9;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_DuelLost) // 48
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 10;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_MM_Packhunter) // 50
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 11;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_MagicUser) // 51
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 12;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_DropDeadAndKill) // 52
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 13;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_IGNORE_Murder) // 54
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 14;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_IGNORE_Theft) // 55
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 15;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_IGNORE_Sheepkiller) // 56
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 16;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_ToughGuy) // 57
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 17;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_NewsOverride) // 58
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 18;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_EnemyOverride) // 61
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 19;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_KilledByPlayer) // 67
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 20;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_LOADGAME) // 65
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 21;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_DefeatedByPlayer) // 66
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 22;
Bit_Position_AIVar = 1;
}
else if (AIVar_Input == AIV_Food) // 18
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 23;
Bit_Position_AIVar = 2;
}
else if (AIVar_Input == AIV_LastFightAgainstPlayer) // 0
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 25;
Bit_Position_AIVar = 2;
}
else if (AIVar_Input == AIV_LastPlayerAR) // 47
{
Nr_CompressedAIVar = 4;
Bit_AIVar_CompressedAIVar = 27;
Bit_Position_AIVar = 5;
};

if ((Value_to_AIVar < PowerFunction(2, Bit_Position_AIVar))
&& (Value_to_AIVar >= 0))
{
var int AIVar_Initial_Value; AIVar_Initial_Value = 0;
if (Nr_CompressedAIVar == 1)
{
AIVar_Initial_Value = AIVar_Taker.aivar[AIV_FirstCompressed];
}
else if (Nr_CompressedAIVar == 2)
{
AIVar_Initial_Value = AIVar_Taker.aivar[AIV_SecondCompressed];
}
else if (Nr_CompressedAIVar == 3)
{
AIVar_Initial_Value = AIVar_Taker.aivar[AIV_ThirdCompressed];
}
else if (Nr_CompressedAIVar == 4)
{
AIVar_Initial_Value = AIVar_Taker.aivar[AIV_FourthCompressed];
};

var int AIVar_Value; AIVar_Value = 0;

var int Component1; Component1 = 0;
Component1 = AIVar_Initial_Value%(PowerFunction(2, Bit_AIVar_CompressedAIVar + Bit_Position_AIVar - 1));

var int Component2; Component2 = 0;
Component2 = PowerFunction(2, Bit_AIVar_CompressedAIVar - 1);

if (Write_or_Read == 0)
{
AIVar_Value = AIVar_Initial_Value - Component1 + (Value_to_AIVar * Component2) + Component1%Component2;

if (Nr_CompressedAIVar == 1)
{
AIVar_Taker.aivar[AIV_FirstCompressed] = AIVar_Value;
}
else if (Nr_CompressedAIVar == 2)
{
AIVar_Taker.aivar[AIV_SecondCompressed] = AIVar_Value;
}
else if (Nr_CompressedAIVar == 3)
{
AIVar_Taker.aivar[AIV_ThirdCompressed] = AIVar_Value;
}
else if (Nr_CompressedAIVar == 4)
{
AIVar_Taker.aivar[AIV_FourthCompressed] = AIVar_Value;
};
}
else if (Write_or_Read == 1)
{
AIVar_Value = (Component1 - Component1%Component2) / Component2;

return AIVar_Value;
};
};
};

Teraz czeka nas najbardziej monotonna i mozolna część - zamienianie w plikach wszystkich kompresowanych AIVarów na ich skompresowaną wersję. Tutaj trzeba uważać na jedną rzecz. Część AIVarów, szczególne te 5 bitowe z 1 i 2 skompresowanego oznaczające godziny, występują w 2 miejscach jako argumenty innych funkcji. Tak się składa, że nie możemy jako argumentu funkcji wsadzić innej funkcji bo Gothic głupieje. W takiej sytuacji, musimy jako argument wsadzić wartości AIVarów wyciągnęte ze skompresowanego ręcznie. O co chodzi - przykład pliku "_Work/Data/Scripts/Content/AI/Monster/RTN_Monster/ZS_MM_AllScheduler.d". W orginale funkcja wygląda tak:

func void ZS_MM_AllScheduler()
{
self.aivar[AIV_MM_PRIORITY] = PRIO_EAT;

//ADDON>
if (self.guild == GIL_STONEGUARDIAN)
&& (RavenIsDead == TRUE)
{
B_KillNpc (self);
};
//ADDON<

if (Wld_IsTime (self.aivar[AIV_MM_SleepStart],00,self.aivar[AIV_MM_SleepEnd],00) || (self.aivar[AIV_MM_SleepStart] == OnlyRoutine))
{
AI_StartState (self, ZS_MM_Rtn_Sleep, 1, "");
}
else if (Wld_IsTime (self.aivar[AIV_MM_RestStart],00,self.aivar[AIV_MM_RestEnd],00) || (self.aivar[AIV_MM_RestStart] == OnlyRoutine))
{
AI_StartState (self, ZS_MM_Rtn_Rest, 1, "");
}
else if (Wld_IsTime (self.aivar[AIV_MM_RoamStart],00,self.aivar[AIV_MM_RoamEnd],00) || (self.aivar[AIV_MM_RoamStart] == OnlyRoutine))
{
AI_StartState (self, ZS_MM_Rtn_Roam, 1, "");
}
else if (Wld_IsTime (self.aivar[AIV_MM_EatGroundStart],00,self.aivar[AIV_MM_EatGroundEnd],00) || (self.aivar[AIV_MM_EatGroundStart] == OnlyRoutine))
{
AI_StartState (self, ZS_MM_Rtn_EatGround, 1, "");
}
else if (Wld_IsTime (self.aivar[AIV_MM_WuselStart],00,self.aivar[AIV_MM_WuselEnd],00) || (self.aivar[AIV_MM_WuselStart] == OnlyRoutine))
{
AI_StartState (self, ZS_MM_Rtn_Wusel, 1, "");
}
else if (Wld_IsTime (self.aivar[AIV_MM_OrcSitStart],00,self.aivar[AIV_MM_OrcSitEnd],00) || (self.aivar[AIV_MM_OrcSitStart] == OnlyRoutine))
{
AI_StartState (self, ZS_MM_Rtn_OrcSit, 1, "");
}
else
{
AI_StartState (self, ZS_MM_Rtn_Rest, 1, ""); //Default = Rest
};
};

Jak widać w funkcji "Wld_IsTime" jednymi z argumentów są wartości AIVarów, które po skompresowaniu będziemy wyciągać za pomocą funkcji. Mielibyśmy więc w tym przypadku funkcję "Byte_for_AIVars" jako argument funkcji "Wld_IsTime". Unikamy tego wpisując wartości AIVarów ręcznie:

func void ZS_MM_AllScheduler()
{
Byte_for_AIVars(self, AIV_MM_PRIORITY, PRIO_EAT, 0);

//ADDON>
if (self.guild == GIL_STONEGUARDIAN)
&& (RavenIsDead == TRUE)
{
B_KillNpc (self);
};
//ADDON<

if (Wld_IsTime ((self.aivar[AIV_FirstCompressed]%1024 - (self.aivar[AIV_FirstCompressed]%1024)%32) / 32,00,(self.aivar[AIV_FirstCompressed]%32768 - (self.aivar[AIV_FirstCompressed]%32768)%1024) / 1024,00) || ((self.aivar[AIV_FirstCompressed]%1024 - (self.aivar[AIV_FirstCompressed]%1024)%32) / 32 == 31))
{
AI_StartState (self, ZS_MM_Rtn_Sleep, 1, "");
}
else if (Wld_IsTime ((self.aivar[AIV_FirstCompressed]%1048576 - (self.aivar[AIV_FirstCompressed]%1048576)%32768) / 32768,00,(self.aivar[AIV_FirstCompressed]%33554432 - (self.aivar[AIV_FirstCompressed]%33554432)%1048576) / 1048576,00) || ((self.aivar[AIV_FirstCompressed]%1048576 - (self.aivar[AIV_FirstCompressed]%1048576)%32768) / 32768 == 31))
{
AI_StartState (self, ZS_MM_Rtn_Rest, 1, "");
}
else if (Wld_IsTime ((self.aivar[AIV_FirstCompressed]%1073741824 - (self.aivar[AIV_FirstCompressed]%1073741824)%33554432) / 33554432,00,(self.aivar[AIV_SecondCompressed]%32 - (self.aivar[AIV_SecondCompressed]%32)%1) / 1,00) || ((self.aivar[AIV_FirstCompressed]%1073741824 - (self.aivar[AIV_FirstCompressed]%1073741824)%33554432) / 33554432 == 31))
{
AI_StartState (self, ZS_MM_Rtn_Roam, 1, "");
}
else if (Wld_IsTime ((self.aivar[AIV_SecondCompressed]%1024 - (self.aivar[AIV_SecondCompressed]%1024)%32) / 32,00,(self.aivar[AIV_SecondCompressed]%32768 - (self.aivar[AIV_SecondCompressed]%32768)%1024) / 1024,00) || ((self.aivar[AIV_SecondCompressed]%1024 - (self.aivar[AIV_SecondCompressed]%1024)%32) / 32 == 31))
{
AI_StartState (self, ZS_MM_Rtn_EatGround, 1, "");
}
else if (Wld_IsTime ((self.aivar[AIV_SecondCompressed]%1048576 - (self.aivar[AIV_SecondCompressed]%1048576)%32768) / 32768,00,(self.aivar[AIV_SecondCompressed]%33554432 - (self.aivar[AIV_SecondCompressed]%33554432)%1048576) / 1048576,00) || ((self.aivar[AIV_SecondCompressed]%1048576 - (self.aivar[AIV_SecondCompressed]%1048576)%32768) / 32768 == 31))
{
AI_StartState (self, ZS_MM_Rtn_Wusel, 1, "");
}
else if (Wld_IsTime ((self.aivar[AIV_SecondCompressed]%1073741824 - (self.aivar[AIV_SecondCompressed]%1073741824)%33554432) / 33554432,00,(self.aivar[AIV_FirstCompressed]%32 - (self.aivar[AIV_FirstCompressed]%32)%1) / 1,00) || ((self.aivar[AIV_SecondCompressed]%1073741824 - (self.aivar[AIV_SecondCompressed]%1073741824)%33554432) / 33554432 == 31))
{
AI_StartState (self, ZS_MM_Rtn_OrcSit, 1, "");
}
else
{
AI_StartState (self, ZS_MM_Rtn_Rest, 1, ""); //Default = Rest
};
};

Podane wyżej wartości będą poprawne tylko, jeśli nie zmienicie wartości "Nr_CompressedAIVar", "Bit_AIVar_CompressedAIVar", "Bit_Position_AIVar" podanych przeze mnie. Jak zmienicie to musicie je sobie wyliczyć na nowo i wstawić. Oczywiście stałym "AIV_FirstCompressed", "AIV_SecondCompressed", "AIV_ThirdCompressed" i "AIV_FourthCompressed" nadajemy wartości jakichś wolnych AIVarów. Lista wolnych AIVarów po kompresji:

//const int AIV_TALENT_INDEX                                         = 89; - wykorzystywany przez LeGo do tworzenia nowej umiejętności, ale możemy go sobie zabrać i użyć do własnych celów.

const int AIV_90                         = 90;
const int AIV_91                         = 91;
const int AIV_92                         = 92;

const int AIV_93                 = 93;
const int AIV_94                 = 94;
const int AIV_95                         = 95;

const int AIV_96         = 96;
const int AIV_97                 = 97;
const int AIV_98                 = 98;

const int AIV_99           = 99;

const int AIV_FirstCompressed = 0;
const int AIV_SecondCompressed = 1;
const int AIV_ThirdCompressed = 3;
const int AIV_FourthCompressed = 5;

const int Free_AIVar_01 = 6;
const int Free_AIVar_02 = 8;
const int Free_AIVar_03 = 9;

const int Free_AIVar_04 = 10;
const int Free_AIVar_05 = 11;
const int Free_AIVar_06 = 12;
const int Free_AIVar_07 = 14;
const int Free_AIVar_08 = 15;
const int Free_AIVar_09 = 16;
const int Free_AIVar_10 = 17;

const int Free_AIVar_11 = 18;
const int Free_AIVar_12 = 19;
const int Free_AIVar_13 = 21;
const int Free_AIVar_14 = 25;
const int Free_AIVar_15 = 26;
const int Free_AIVar_16 = 28;
const int Free_AIVar_17 = 29;

const int Free_AIVar_18 = 30;
const int Free_AIVar_19 = 31;
const int Free_AIVar_20 = 32;
const int Free_AIVar_21 = 33;
const int Free_AIVar_22 = 34;
const int Free_AIVar_23 = 35;
const int Free_AIVar_24 = 36;

const int Free_AIVar_25 = 37;
const int Free_AIVar_26 = 38;
const int Free_AIVar_27 = 39;
const int Free_AIVar_28 = 40;
const int Free_AIVar_29 = 41;
const int Free_AIVar_30 = 42;
const int Free_AIVar_31 = 45;

const int Free_AIVar_32 = 47;
const int Free_AIVar_33 = 48;
const int Free_AIVar_34 = 49;
const int Free_AIVar_35 = 50;
const int Free_AIVar_36 = 51;
const int Free_AIVar_37 = 52;
const int Free_AIVar_38 = 54;

const int Free_AIVar_39 = 55;
const int Free_AIVar_40 = 56;
const int Free_AIVar_41 = 57;
const int Free_AIVar_42 = 58;
const int Free_AIVar_43 = 61;
const int Free_AIVar_44 = 65;
const int Free_AIVar_45 = 66;

const int Free_AIVar_46 = 67;
const int Free_AIVar_47 = 70;
const int Free_AIVar_48 = 71;
const int Free_AIVar_49 = 72;
const int Free_AIVar_50 = 73;
const int Free_AIVar_51 = 74;
const int Free_AIVar_52 = 75;

Po skończonej kompresji mamy łącznie 63 wolne AIVary, czyli więcej niż zajętych. Jak ktoś bardzo chce i potrzebuje, to może np. przyjąć, że AIVary określające poziom władania bronią nigdy nie przekroczy nam 127 ( 8 bitów) i 3 z nich skompresować w 1 zwalniając 2, itp.

Rozwiązanie to ma jedną wadę. Nie pamiętam dokładnie jak to było, ale zaraz po włączeniu Gothica, chyba LeGo i Ikarus (?) nie inicjują się do pierwszego wczytania gry. Oznacza to, że żeby wszystko działało, to po włączeniu nowej gry musimy dać nową grę jeszcze raz - odpalić nową grę z już załadowanej gry a nie z menu głównego, inaczej nie będzie działać, AIVary NPCtom się nie ustawią i będzie burdel kompletny. Wydaje mi się, że Siemekk kiedyś napisał jak sobie z tym poradzić, żeby Ikarus był zainicjowany od razu po włączeniu gry, ale nie zapisałem tego nigdzie a teraz znaleźć nie mogę. Może jak go ładnie poprosicie to to wrzuci.
 

Splash

Splash

Moderator
posty4126
Propsy3339
ProfesjaNierób
  • Moderator

Splash
Moderator

[G2NK] Dodatkowe wolne AIVARy.
#1 2020-11-01, 19:56(Ostatnia zmiana: 2020-11-03, 23:22)
Kiedyś napisałem skrypt, który nie wymaga aż tyle grzebania w skryptach. Jedyne co jest potrzebne to jeden wolny aivar w którym będziemy przechowywać handle'a do obiektu klasy AdditionalAivars.
const int AIV_MoreAivars = 99; //indeks aivara, w którym będzie przechowywany handle
const int MAX_ADDITIONAL_AIVARS = 10; //ilość dodatkowych aivarów

const int MAX_ADDITIONAL_AIVARS = 12;

class AdditionalAivars {
    var int aivar[MAX_ADDITIONAL_AIVARS];
};

instance AdditionalAivar@(AdditionalAivars);

func void SetAdditionalAivar(var c_npc slf, var int index, var int value) {
    var int hndl; hndl = MEM_ReadStatArr(slf.aivar, AIV_MoreAivars);

    if (!Hlp_IsValidHandle(hndl)) {
        slf.aivar[AIV_MoreAivars] = new(AdditionalAivar@);
    };

    MEM_WriteIntArray(getPtr(hndl), index, value);
};

func int GetAdditionalAivar(var c_npc slf, var int index) {
    var int hndl; hndl = MEM_ReadStatArr(slf.aivar, AIV_MoreAivars);

    if (Hlp_IsValidHandle(hndl)) {
        return MEM_ReadIntArray(getPtr(hndl), index);
    };
};

func void ClearAdditionalAivars(var c_npc slf) {
    var int hndl; hndl = MEM_ReadStatArr(slf.aivar, AIV_MoreAivars);

    if (Hlp_IsValidHandle(hndl)) {
        var int i;

        repeat(i, MAX_ADDITIONAL_AIVARS);
            SetAdditionalAivar(slf, i, 0);
        end;
    };
};

func void DeleteAdditionalAivars(var c_npc slf) {
    var int hndl; hndl = MEM_ReadStatArr(slf.aivar, AIV_MoreAivars);

    if (Hlp_IsValidHandle(hndl)) {
        delete(hndl);
    };
};
 
Nie zajmuję się multiplayerami do Gothica. Przestańcie zawracać mi tym głowę...

Wowoz

Wowoz

Użytkownicy
Wowoźny
posty3710
Propsy4856
NagrodyVV
Profesjabrak
  • Użytkownicy
  • Wowoźny
Ajwar jest ogólnie w pyte. Polecam do szyneczki albo dodać trochę do leczo. Palce lizać
 


0 użytkowników i 1 Gość przegląda ten wątek.
0 użytkowników
Do góry