diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..27ed978 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tools"] + path = tools + url = https://github.com/GenZmeY/KF2-BuildTools diff --git a/CTI/Classes/AddItems.uc b/CTI/Classes/AddItems.uc new file mode 100644 index 0000000..f2a8fe4 --- /dev/null +++ b/CTI/Classes/AddItems.uc @@ -0,0 +1,66 @@ +class AddItems extends Object + dependson(CTI) + config(CTI); + +var private config Array Item; + +public static function InitConfig(int Version, int LatestVersion) +{ + switch (Version) + { + case `NO_CONFIG: + ApplyDefault(); + + default: break; + } + + if (LatestVersion != Version) + { + StaticSaveConfig(); + } +} + +private static function ApplyDefault() +{ + default.Item.Length = 0; + default.Item.AddItem("SomePackage.SomeWeapon"); +} + +public static function Array > Load(E_LogLevel LogLevel) +{ + local Array > ItemList; + local class ItemClass; + local String ItemRaw; + local int Line; + + `Log_Info("Load Items to add:"); + foreach default.Item(ItemRaw, Line) + { + ItemClass = class(DynamicLoadObject(ItemRaw, class'Class')); + if (ItemClass == None) + { + `Log_Warn("[" $ Line + 1 $ "]" @ "Can't load Item class:" @ ItemRaw); + } + else + { + ItemList.AddItem(ItemClass); + `Log_Debug("[" $ Line + 1 $ "]" @ "Loaded successfully:" @ ItemRaw); + } + } + + if (ItemList.Length == default.Item.Length) + { + `Log_Info("Items to add list loaded successfully (" $ default.Item.Length @ "entries)"); + } + else + { + `Log_Info("Items to add list: loaded" @ ItemList.Length @ "of" @ default.Item.Length @ "entries"); + } + + return ItemList; +} + +defaultproperties +{ + +} diff --git a/CTI/Classes/CTI.uc b/CTI/Classes/CTI.uc new file mode 100644 index 0000000..c2d2c64 --- /dev/null +++ b/CTI/Classes/CTI.uc @@ -0,0 +1,247 @@ +class CTI extends Info + config(CTI); + +const LatestVersion = 1; + +const CfgRemoveItems = class'RemoveItems'; +const CfgAddItems = class'AddItems'; +const Helper = class'Helper'; + +var private config int Version; +var private config E_LogLevel LogLevel; +var private config bool bPreloadContent; +var private config bool bForcePreloadContent; +var private config bool UnlockDLC; + +var private KFGameInfo KFGI; +var private KFGameReplicationInfo KFGRI; + +var private Array > RemoveItems; +var private Array > AddItems; + +var private Array RepInfos; + +var private bool ReadyToSync; + +public simulated function bool SafeDestroy() +{ + `Log_Trace(`Location); + + return (bPendingDelete || bDeleteMe || Destroy()); +} + +public event PreBeginPlay() +{ + `Log_Trace(`Location); + + `Log_Debug("PreBeginPlay readyToSync" @ ReadyToSync); + + if (WorldInfo.NetMode == NM_Client) + { + `Log_Fatal("NetMode == NM_Client, Destroy..."); + SafeDestroy(); + return; + } + + Super.PreBeginPlay(); + + PreInit(); +} + +public event PostBeginPlay() +{ + `Log_Trace(`Location); + + if (bPendingDelete || bDeleteMe) return; + + Super.PostBeginPlay(); + + PostInit(); +} + +private function PreInit() +{ + `Log_Trace(`Location); + + if (Version == `NO_CONFIG) + { + LogLevel = LL_Info; + bPreloadContent = true; + bForcePreloadContent = true; + UnlockDLC = false; + SaveConfig(); + } + + CfgRemoveItems.static.InitConfig(Version, LatestVersion); + CfgAddItems.static.InitConfig(Version, LatestVersion); + + switch (Version) + { + case `NO_CONFIG: + `Log_Info("Config created"); + + case MaxInt: + `Log_Info("Config updated to version"@LatestVersion); + break; + + case LatestVersion: + `Log_Info("Config is up-to-date"); + break; + + default: + `Log_Warn("The config version is higher than the current version (are you using an old mutator?)"); + `Log_Warn("Config version is" @ Version @ "but current version is" @ LatestVersion); + `Log_Warn("The config version will be changed to" @ LatestVersion); + break; + } + + if (LatestVersion != Version) + { + Version = LatestVersion; + SaveConfig(); + } + + if (LogLevel == LL_WrongLevel) + { + LogLevel = LL_Info; + `Log_Warn("Wrong 'LogLevel', return to default value"); + SaveConfig(); + } + `Log_Base("LogLevel:" @ LogLevel); + + RemoveItems = CfgRemoveItems.static.Load(LogLevel); + AddItems = CfgAddItems.static.Load(LogLevel); +} + +private function PostInit() +{ + local CTI_RepInfo RepLink; + + `Log_Trace(`Location); + + if (WorldInfo == None || WorldInfo.Game == None) + { + SetTimer(1.0f, false, nameof(PostInit)); + return; + } + + KFGI = KFGameInfo(WorldInfo.Game); + if (KFGI == None) + { + `Log_Fatal("Incompatible gamemode:" @ WorldInfo.Game); + SafeDestroy(); + return; + } + + if (UnlockDLC && KFGI.KFGFxManagerClass != class'CTI_GFxMoviePlayer_Manager') + { + KFGI.KFGFxManagerClass = class'CTI_GFxMoviePlayer_Manager'; + `Log_Info("DLC unlocked"); + } + + if (KFGI.GameReplicationInfo == None) + { + SetTimer(1.0f, false, nameof(PostInit)); + return; + } + + KFGRI = KFGameReplicationInfo(KFGI.GameReplicationInfo); + if (KFGRI == None) + { + `Log_Fatal("Incompatible Replication info:" @ KFGI.GameReplicationInfo); + SafeDestroy(); + return; + } + + Helper.static.ModifyTrader(KFGRI, RemoveItems, AddItems, CfgRemoveItems.default.bAll); + + if (bPreloadContent) + { + Helper.static.PreloadContent(AddItems); + } + + ReadyToSync = true; + + foreach RepInfos(RepLink) + { + if (RepLink.PendingSync) + { + RepLink.ServerSync(); + } + } +} + +public function NotifyLogin(Controller C) +{ + `Log_Trace(`Location); + + CreateRepLink(C); +} + +public function NotifyLogout(Controller C) +{ + `Log_Trace(`Location); + + DestroyRepLink(C); +} + +public function bool CreateRepLink(Controller C) +{ + local CTI_RepInfo RepLink; + + `Log_Trace(`Location); + + if (C == None) return false; + + RepLink = Spawn(class'CTI_RepInfo', C); + + if (RepLink == None) return false; + + RepLink.PrepareSync( + Self, + LogLevel, + RemoveItems, + AddItems, + CfgRemoveItems.default.bAll, + bPreloadContent, + bForcePreloadContent); + + RepInfos.AddItem(RepLink); + + if (ReadyToSync) + { + RepLink.ServerSync(); + } + else + { + RepLink.PendingSync = true; + } + + return true; +} + +public function bool DestroyRepLink(Controller C) +{ + local CTI_RepInfo RepLink; + + `Log_Trace(`Location); + + if (C == None) return false; + + foreach RepInfos(RepLink) + { + if (RepLink.Owner == C) + { + RepLink.SafeDestroy(); + RepInfos.RemoveItem(RepLink); + return true; + } + } + + return false; +} + +DefaultProperties +{ + ReadyToSync = false +} \ No newline at end of file diff --git a/CTI/Classes/CTI.upkg b/CTI/Classes/CTI.upkg new file mode 100644 index 0000000..29cb156 --- /dev/null +++ b/CTI/Classes/CTI.upkg @@ -0,0 +1,4 @@ +[Flags] +AllowDownload=True +ClientOptional=False +ServerSideOnly=False diff --git a/CTI/Classes/CTIMut.uc b/CTI/Classes/CTIMut.uc new file mode 100644 index 0000000..b4da5ee --- /dev/null +++ b/CTI/Classes/CTIMut.uc @@ -0,0 +1,62 @@ +class CTIMut extends KFMutator; + +var private CTI CTI; + +public simulated function bool SafeDestroy() +{ + return (bPendingDelete || bDeleteMe || Destroy()); +} + +public event PreBeginPlay() +{ + Super.PreBeginPlay(); + + if (WorldInfo.NetMode == NM_Client) return; + + foreach WorldInfo.DynamicActors(class'CTI', CTI) + { + `Log_Base("Found 'CTI'"); + break; + } + + if (CTI == None) + { + `Log_Base("Spawn 'CTI'"); + CTI = WorldInfo.Spawn(class'CTI'); + } + + if (CTI == None) + { + `Log_Base("Can't Spawn 'CTI', Destroy..."); + SafeDestroy(); + } +} + +public function AddMutator(Mutator Mut) +{ + if (Mut == Self) return; + + if (Mut.Class == Class) + Mut.Destroy(); + else + Super.AddMutator(Mut); +} + +public function NotifyLogin(Controller C) +{ + Super.NotifyLogin(C); + + CTI.NotifyLogin(C); +} + +public function NotifyLogout(Controller C) +{ + Super.NotifyLogout(C); + + CTI.NotifyLogout(C); +} + +DefaultProperties +{ + +} \ No newline at end of file diff --git a/CTI/Classes/CTI_GFxMenu_Trader.uc b/CTI/Classes/CTI_GFxMenu_Trader.uc new file mode 100644 index 0000000..09faf43 --- /dev/null +++ b/CTI/Classes/CTI_GFxMenu_Trader.uc @@ -0,0 +1,8 @@ +class CTI_GFxMenu_Trader extends KFGFxMenu_Trader + dependsOn(CTI_GFxTraderContainer_Store); + +defaultproperties +{ + SubWidgetBindings.Remove((WidgetName="shopContainer",WidgetClass=class'KFGFxTraderContainer_Store')) + SubWidgetBindings.Add((WidgetName="shopContainer",WidgetClass=class'CTI_GFxTraderContainer_Store')) +} diff --git a/CTI/Classes/CTI_GFxMoviePlayer_Manager.uc b/CTI/Classes/CTI_GFxMoviePlayer_Manager.uc new file mode 100644 index 0000000..78604f3 --- /dev/null +++ b/CTI/Classes/CTI_GFxMoviePlayer_Manager.uc @@ -0,0 +1,8 @@ +class CTI_GFxMoviePlayer_Manager extends KFGFxMoviePlayer_Manager + dependsOn(CTI_GFxMenu_Trader); + +defaultproperties +{ + WidgetBindings.Remove((WidgetName="traderMenu",WidgetClass=class'KFGFxMenu_Trader')) + WidgetBindings.Add((WidgetName="traderMenu",WidgetClass=class'CTI_GFxMenu_Trader')) +} diff --git a/CTI/Classes/CTI_GFxTraderContainer_Store.uc b/CTI/Classes/CTI_GFxTraderContainer_Store.uc new file mode 100644 index 0000000..37ce4be --- /dev/null +++ b/CTI/Classes/CTI_GFxTraderContainer_Store.uc @@ -0,0 +1,20 @@ +class CTI_GFxTraderContainer_Store extends KFGFxTraderContainer_Store; + +function bool IsItemFiltered(STraderItem Item, optional bool bDebug) +{ + if (KFPC.GetPurchaseHelper().IsInOwnedItemList(Item.ClassName)) + return true; + if (KFPC.GetPurchaseHelper().IsInOwnedItemList(Item.DualClassName)) + return true; + if (!KFPC.GetPurchaseHelper().IsSellable(Item)) + return true; + if (Item.WeaponDef.default.PlatformRestriction != PR_All && class'KFUnlockManager'.static.IsPlatformRestricted(Item.WeaponDef.default.PlatformRestriction)) + return true; + + return false; +} + +defaultproperties +{ + +} diff --git a/CTI/Classes/CTI_RepInfo.uc b/CTI/Classes/CTI_RepInfo.uc new file mode 100644 index 0000000..a2bda06 --- /dev/null +++ b/CTI/Classes/CTI_RepInfo.uc @@ -0,0 +1,309 @@ +class CTI_RepInfo extends ReplicationInfo; + +const Helper = class'Helper'; + +var public bool PendingSync; + +var private CTI CTI; +var private E_LogLevel LogLevel; +var private Array > RemoveItems; +var private Array > AddItems; +var private bool ReplaceMode; +var private bool PreloadContent; +var private bool ForcePreloadContent; + +var private int Recieved; +var private int SyncSize; + +var private KFGFxWidget_PartyInGame PartyInGameWidget; +var private GFxObject Notification; + +replication +{ + if (bNetInitial && Role == ROLE_Authority) + LogLevel, ReplaceMode, PreloadContent, ForcePreloadContent, SyncSize; +} + +public simulated function bool SafeDestroy() +{ + `Log_Trace(`Location); + + return (bPendingDelete || bDeleteMe || Destroy()); +} + +public function PrepareSync( + CTI _CTI, + E_LogLevel _LogLevel, + Array > _RemoveItems, + Array > _AddItems, + bool _ReplaceMode, + bool _PreloadContent, + bool _ForcePreloadContent) +{ + CTI = _CTI; + LogLevel = _LogLevel; + RemoveItems = _RemoveItems; + AddItems = _AddItems; + ReplaceMode = _ReplaceMode; + PreloadContent = _PreloadContent; + ForcePreloadContent = _ForcePreloadContent; + SyncSize = RemoveItems.Length + AddItems.Length; +} + +private simulated function PlayerController GetPlayerController() +{ + local PlayerController PC; + + PC = PlayerController(Owner); + + if (PC == None && ROLE < ROLE_Authority) + { + PC = GetALocalPlayerController(); + } + + return PC; +} + +private simulated function SetPartyInGameWidget() +{ + local KFPlayerController KFPC; + + `Log_Trace(`Location); + + KFPC = KFPlayerController(GetPlayerController()); + if (KFPC == None) return; + if (KFPC.MyGFxManager == None) return; + if (KFPC.MyGFxManager.PartyWidget == None) return; + + PartyInGameWidget = KFGFxWidget_PartyInGame(KFPC.MyGFxManager.PartyWidget); + Notification = PartyInGameWidget.Notification; +} + +private simulated function bool CheckPartyInGameWidget() +{ + if (PartyInGameWidget == None) + { + SetPartyInGameWidget(); + } + + return (PartyInGameWidget != None); +} + +private simulated function UpdateNotification(String Title, String Downloading, String Remainig, int Percent) +{ + if (Notification != None) + { + Notification.SetString("itemName", Title); + Notification.SetFloat("percent", Percent); + Notification.SetInt("queue", 0); + Notification.SetString("downLoading", Downloading); + Notification.SetString("remaining", Remainig); + Notification.SetObject("notificationInfo", Notification); + Notification.SetVisible(true); + } +} + +private reliable client function ClientSync(class WeapDef, optional bool Remove = false) +{ + `Log_Trace(`Location); + + if (WeapDef == None) + { + `Log_Fatal("WeapDef is:" @ WeapDef); + SafeDestroy(); + return; + } + + if (CheckPartyInGameWidget()) + { + PartyInGameWidget.SetReadyButtonVisibility(false); + } + + if (Remove) + { + RemoveItems.AddItem(WeapDef); + } + else + { + AddItems.AddItem(WeapDef); + } + + Recieved = RemoveItems.Length + AddItems.Length; + if (CheckPartyInGameWidget()) + { + UpdateNotification( + "Sync items, please wait...", + Remove ? "-" : "+" @ Repl(String(WeapDef), "KFWeapDef_", ""), + Recieved @ "/" @ SyncSize, + (float(Recieved) / float(SyncSize)) * 100); + } + + if (Recieved == SyncSize && (PreloadContent || ForcePreloadContent)) + { + if (CheckPartyInGameWidget()) + { + UpdateNotification( + "Preload Content, please wait...", + "Game isn't frozen", + "Don't panic", + 0); + } + } + + ServerSync(); +} + +private simulated reliable client function SyncFinished() +{ + local KFGameReplicationInfo KFGRI; + + `Log_Trace(`Location); + + if (WorldInfo == None || WorldInfo.GRI == None) + { + SetTimer(1.0f, false, nameof(SyncFinished)); + return; + } + + KFGRI = KFGameReplicationInfo(WorldInfo.GRI); + if (KFGRI == None) + { + `Log_Fatal("Incompatible Replication info:" @ WorldInfo.GRI); + SafeDestroy(); + return; + } + + Helper.static.ModifyTrader(KFGRI, RemoveItems, AddItems, ReplaceMode); + + if (PreloadContent) + { + Helper.static.PreloadContent(AddItems); + } + if (ForcePreloadContent) + { + PreloadContentWorkaround(); + } + + if (CheckPartyInGameWidget()) + { + Notification.SetVisible(false); + PartyInGameWidget.SetReadyButtonVisibility(true); + PartyInGameWidget.UpdateReadyButtonText(); + PartyInGameWidget.UpdateReadyButtonVisibility(); + } + + SafeDestroy(); +} + +public reliable server function ServerSync() +{ + `Log_Trace(`Location); + + PendingSync = false; + + if (bPendingDelete || bDeleteMe) return; + + if (SyncSize <= Recieved || WorldInfo.NetMode == NM_StandAlone) + { + SyncFinished(); + if (!CTI.DestroyRepLink(Controller(Owner))) + { + SafeDestroy(); + } + } + else + { + if (Recieved < RemoveItems.Length) + { + ClientSync(RemoveItems[Recieved++], true); + } + else + { + ClientSync(AddItems[Recieved++ - RemoveItems.Length], false); + } + } +} + +private simulated function PreloadContentWorkaround() +{ + local PlayerController PC; + local Pawn P; + local KFInventoryManager KFIM; + local class CW; + local Weapon W; + local int Index; + local DroppedPickup DP; + local float Time; + + `Log_Trace(`Location); + + PC = GetPlayerController(); + + if (PC == None) + { + SetTimer(0.1f, false, nameof(PreloadContentWorkaround)); + return; + } + + P = PC.Pawn; + if (P == None) + { + SetTimer(0.1f, false, nameof(PreloadContentWorkaround)); + return; + } + + KFIM = KFInventoryManager(P.InvManager); + if (KFIM == None) + { + SetTimer(0.1f, false, nameof(PreloadContentWorkaround)); + return; + } + + KFIM.bInfiniteWeight = true; + Time = WorldInfo.TimeSeconds - 1.0f; + + for (Index = 0; Index < AddItems.Length; Index++) + { + CW = class (DynamicLoadObject(AddItems[Index].default.WeaponClassPath, class'Class')); + if (CW != None && Weapon(P.FindInventoryType(CW)) == None) + { + P.CreateInventory(CW); + } + } + + foreach KFIM.InventoryActors(class'Weapon', W) + { + if (W != None) + { + KFIM.PendingWeapon = W; + KFIM.ChangedWeapon(); + if (W.CanThrow()) + { + P.TossInventory(W); + W.Destroy(); + } + } + } + + foreach WorldInfo.DynamicActors(class'DroppedPickup', DP) + { + if (DP.Instigator == P && DP.CreationTime > Time) + { + DP.Destroy(); + } + } + + KFIM.bInfiniteWeight = false; + + `Log_Info("Force Preload Finished"); +} + +defaultproperties +{ + bAlwaysRelevant = false + bOnlyRelevantToOwner = true + bSkipActorPropertyReplication = false + + PendingSync = false + Recieved = 0 +} diff --git a/CTI/Classes/Helper.uc b/CTI/Classes/Helper.uc new file mode 100644 index 0000000..83a2a36 --- /dev/null +++ b/CTI/Classes/Helper.uc @@ -0,0 +1,73 @@ +class Helper extends Object; + +private delegate int ByPrice(class A, class B) +{ + return A.default.BuyPrice > B.default.BuyPrice ? -1 : 0; +} + +public static simulated function ModifyTrader( + KFGameReplicationInfo KFGRI, + Array > RemoveItems, + Array > AddItems, + bool ReplaceMode) +{ + local KFGFxObject_TraderItems TraderItems; + local STraderItem Item; + local class WeapDef; + local Array > WeapDefs; + local int Index; + local int MaxItemID; + + if (KFGRI == None) return; + + TraderItems = KFGFxObject_TraderItems(DynamicLoadObject(KFGRI.TraderItemsPath, class'KFGFxObject_TraderItems')); + + if (!ReplaceMode) + { + foreach TraderItems.SaleItems(Item) + { + if (Item.WeaponDef != None && RemoveItems.Find(Item.WeaponDef) == INDEX_NONE) + { + WeapDefs.AddItem(Item.WeaponDef); + } + } + } + + for (Index = 0; Index < AddItems.Length; Index++) + WeapDefs.AddItem(AddItems[Index]); + + WeapDefs.Sort(ByPrice); + + TraderItems.SaleItems.Length = 0; + MaxItemID = 0; + foreach WeapDefs(WeapDef) + { + Item.WeaponDef = WeapDef; + Item.ItemID = ++MaxItemID; + TraderItems.SaleItems.AddItem(Item); + } + + TraderItems.SetItemsInfo(TraderItems.SaleItems); + + KFGRI.TraderItems = TraderItems; +} + +public static function PreloadContent(Array > WeapDefs) +{ + local class KFW; + local int Index; + + for (Index = 0; Index < WeapDefs.Length; Index++) + { + KFW = class (DynamicLoadObject(WeapDefs[Index].default.WeaponClassPath, class'Class')); + if (KFW != None) + { + class'KFWeapon'.static.TriggerAsyncContentLoad(KFW); + } + } +} + +defaultproperties +{ + +} \ No newline at end of file diff --git a/CTI/Classes/RemoveItems.uc b/CTI/Classes/RemoveItems.uc new file mode 100644 index 0000000..46fdb50 --- /dev/null +++ b/CTI/Classes/RemoveItems.uc @@ -0,0 +1,75 @@ +class RemoveItems extends Object + dependson(CTI) + config(CTI); + +var public config bool bAll; +var private config Array Item; + +public static function InitConfig(int Version, int LatestVersion) +{ + switch (Version) + { + case `NO_CONFIG: + ApplyDefault(); + + default: break; + } + + if (LatestVersion != Version) + { + StaticSaveConfig(); + } +} + +private static function ApplyDefault() +{ + default.bAll = false; + default.Item.Length = 0; + default.Item.AddItem("KFGame.KFWeapDef_9mmDual"); +} + +public static function Array > Load(E_LogLevel LogLevel) +{ + local Array > ItemList; + local class ItemClass; + local String ItemRaw; + local int Line; + + `Log_Info("Load items to remove:"); + if (default.bAll) + { + `Log_Info("Remove all default items"); + } + else + { + foreach default.Item(ItemRaw, Line) + { + ItemClass = class(DynamicLoadObject(ItemRaw, class'Class')); + if (ItemClass == None) + { + `Log_Warn("[" $ Line + 1 $ "]" @ "Can't load item class:" @ ItemRaw); + } + else + { + ItemList.AddItem(ItemClass); + `Log_Debug("[" $ Line + 1 $ "]" @ "Loaded successfully:" @ ItemRaw); + } + } + + if (ItemList.Length == default.Item.Length) + { + `Log_Info("Items to remove list loaded successfully (" $ default.Item.Length @ "entries)"); + } + else + { + `Log_Info("Items to remove list: loaded" @ ItemList.Length @ "of" @ default.Item.Length @ "entries"); + } + } + + return ItemList; +} + +defaultproperties +{ + +} diff --git a/CTI/Classes/_Logger.uc b/CTI/Classes/_Logger.uc new file mode 100644 index 0000000..69fb0e7 --- /dev/null +++ b/CTI/Classes/_Logger.uc @@ -0,0 +1,19 @@ +class _Logger extends Object + abstract; + +enum E_LogLevel +{ + LL_WrongLevel, + LL_Fatal, + LL_Error, + LL_Warning, + LL_Info, + LL_Debug, + LL_Trace, + LL_All +}; + +defaultproperties +{ + +} diff --git a/CTI/Constants.uci b/CTI/Constants.uci new file mode 100644 index 0000000..1003f19 --- /dev/null +++ b/CTI/Constants.uci @@ -0,0 +1,2 @@ +// Constants +`define NO_CONFIG 0 diff --git a/CTI/Globals.uci b/CTI/Globals.uci new file mode 100644 index 0000000..a48ac52 --- /dev/null +++ b/CTI/Globals.uci @@ -0,0 +1,3 @@ +// Imports +`include(Logger.uci) +`include(Constants.uci) diff --git a/CTI/Logger.uci b/CTI/Logger.uci new file mode 100644 index 0000000..cb2e407 --- /dev/null +++ b/CTI/Logger.uci @@ -0,0 +1,11 @@ +// Logger +`define Log_Tag 'CTI' + +`define Log_Base(msg, cond) `log(`msg `if(`cond), `cond`{endif}, `Log_Tag) + +`define Log_Fatal(msg) `log("FATAL:" @ `msg, (LogLevel >= LL_Fatal), `Log_Tag) +`define Log_Error(msg) `log("ERROR:" @ `msg, (LogLevel >= LL_Error), `Log_Tag) +`define Log_Warn(msg) `log("WARN:" @ `msg, (LogLevel >= LL_Warning), `Log_Tag) +`define Log_Info(msg) `log("INFO:" @ `msg, (LogLevel >= LL_Info), `Log_Tag) +`define Log_Debug(msg) `log("DEBUG:" @ `msg, (LogLevel >= LL_Debug), `Log_Tag) +`define Log_Trace(msg) `log("TRACE:" @ `msg, (LogLevel >= LL_Trace), `Log_Tag) diff --git a/PublicationContent/description.txt b/PublicationContent/description.txt new file mode 100644 index 0000000..3139b14 --- /dev/null +++ b/PublicationContent/description.txt @@ -0,0 +1,9 @@ +[h1]Custom Trader Inventory[/h1] + +[h1]Description[/h1] +description will come later... + +[b]Mutator:[/b] CTI.CTIMut + +[h1]Sources[/h1] +[url=https://github.com/GenZmeY/KF2-CustomTraderInventory]https://github.com/GenZmeY/KF2-CustomTraderInventory[/url] diff --git a/PublicationContent/preview.png b/PublicationContent/preview.png new file mode 100644 index 0000000..c1fc1c3 Binary files /dev/null and b/PublicationContent/preview.png differ diff --git a/PublicationContent/tags.txt b/PublicationContent/tags.txt new file mode 100644 index 0000000..bcf8fe8 --- /dev/null +++ b/PublicationContent/tags.txt @@ -0,0 +1 @@ +Mutators diff --git a/PublicationContent/title.txt b/PublicationContent/title.txt new file mode 100644 index 0000000..f0e8a1f --- /dev/null +++ b/PublicationContent/title.txt @@ -0,0 +1 @@ +Custom Trader Inventory \ No newline at end of file diff --git a/builder.cfg b/builder.cfg new file mode 100644 index 0000000..132aeaa --- /dev/null +++ b/builder.cfg @@ -0,0 +1,52 @@ +### Build parameters ### + +# If True - compresses the mutator when compiling +# Scripts will be stored in binary form +# (reduces the size of the output file) +StripSource="True" + +# Mutators to be compiled +# Specify them with a space as a separator, +# Mutators will be compiled in the specified order +PackageBuildOrder="CTI" + + +### Steam Workshop upload parameters ### + +# Mutators that will be uploaded to the workshop +# Specify them with a space as a separator, +# The order doesn't matter +PackageUpload="CTI" + + +### Test parameters ### + +# Map: +Map="KF-Nuked" + +# Game: +# Survival: KFGameContent.KFGameInfo_Survival +# WeeklyOutbreak: KFGameContent.KFGameInfo_WeeklySurvival +# Endless: KFGameContent.KFGameInfo_Endless +# Objective: KFGameContent.KFGameInfo_Objective +# Versus: KFGameContent.KFGameInfo_VersusSurvival +Game="KFGameContent.KFGameInfo_Endless" + +# Difficulty: +# Normal: 0 +# Hard: 1 +# Suicide: 2 +# Hell: 3 +Difficulty="0" + +# GameLength: +# 4 waves: 0 +# 7 waves: 1 +# 10 waves: 2 +GameLength="0" + +# Mutators +Mutators="CTI.CTIMut" + +# Additional parameters +Args="" diff --git a/tools b/tools new file mode 160000 index 0000000..2f173aa --- /dev/null +++ b/tools @@ -0,0 +1 @@ +Subproject commit 2f173aad7a6f4578574764801136a0d86e830653