Anton Tarasenko
4 years ago
2 changed files with 152 additions and 2 deletions
@ -0,0 +1,141 @@
|
||||
/** |
||||
* Helper object for `FixLogSpam` fix, responsible for fixing log spam |
||||
* due to missing `ShopVolume`s missing `WeaponLocker` in the `myTrader` |
||||
* variable. |
||||
* Copyright 2021 Anton Tarasenko |
||||
*------------------------------------------------------------------------------ |
||||
* This file is part of Acedia. |
||||
* |
||||
* Acedia 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, version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* Acedia 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 Acedia. If not, see <https://www.gnu.org/licenses/>. |
||||
*/ |
||||
class HelperTrader extends AcediaObject |
||||
config(AcediaFixes); |
||||
|
||||
/** |
||||
* `WeaponLocker` seems be an actor that was supposed to play a certain |
||||
* animation whenever players enter a shop. Each `WeaponLocker` is also |
||||
* supposed to find the shop (`ShopVolume`) it's linked to during |
||||
* `PreBeginPlay()` event and record itself inside `ShopVolume`'s `myTrader` |
||||
* variable. However this sometimes does not happen: either due to locker's |
||||
* placement or due to map maker forgetting to put one in at all. |
||||
* Since `ShoVolume`s do not attempt to check whether their `myTrader` has |
||||
* a valid reference, they generate log spam when it does not. |
||||
* Note that while `WeaponLocker` was supposed to do some action when |
||||
* players enter the shop, it does not actually do anything, so we do not need |
||||
* to care about linking lost lockers to their intended shops, we just need to |
||||
* link some locker to shops with empty `myTrader` references. Maps with |
||||
* custom animated (or otherwise somehow active) lockers should be themselves |
||||
* responsible that their animations are being played correctly. |
||||
* This fix deals with issue by either: |
||||
* 1. Spawning our own `WeaponLocker` and assigning it to the shops |
||||
* with empty `myTrader`; |
||||
* 2. Finding any already existing locker on the map and linking that |
||||
* to the shops with empty `myTrader`. |
||||
* First way is prefereable, since we prefer not to touch placed |
||||
* `WeaponLocker`s in case someone decides to use them correctly and makes |
||||
* a custom class that plays welcome animation in some shop, but forgets about |
||||
* `WeaponLocker`s for other regular shops. |
||||
*/ |
||||
|
||||
// Remember instance of `WeaponLocker` that we spawned, so we can clean |
||||
// it up later. |
||||
var private WeaponLocker dummyLocker; |
||||
// Remember fixed shops, so we can unfix them later. |
||||
var private array<ShopVolume> fixedShops; |
||||
|
||||
var LoggerAPI.Definition errNoReplacementLocker; |
||||
|
||||
protected function Constructor() |
||||
{ |
||||
local LevelInfo level; |
||||
local ShopVolume nextShop; |
||||
local WeaponLocker replacementLocker; |
||||
level = _.unreal.GetLevel(); |
||||
// Get locker |
||||
replacementLocker = SpawnDummyWeaponLocker(); |
||||
if (replacementLocker == none) { |
||||
replacementLocker = FindExistingWeaponLocker(); |
||||
} |
||||
if (replacementLocker == none) |
||||
{ |
||||
_.logger.Auto(errNoReplacementLocker); |
||||
return; |
||||
} |
||||
// Setup locker |
||||
foreach level.DynamicActors(class'KFMod.ShopVolume', nextShop) |
||||
{ |
||||
if (nextShop == none) continue; |
||||
if (nextShop.myTrader != none) continue; |
||||
nextShop.myTrader = replacementLocker; |
||||
fixedShops[fixedShops.length] = nextShop; |
||||
} |
||||
} |
||||
|
||||
protected function Finalizer() |
||||
{ |
||||
local int i; |
||||
for (i = 0; i < fixedShops.length; i += 1) |
||||
{ |
||||
if (fixedShops[i] != none) { |
||||
fixedShops[i].myTrader = none; |
||||
} |
||||
} |
||||
if (dummyLocker != none && !dummyLocker.bPendingDelete) { |
||||
dummyLocker.Destroy(); |
||||
} |
||||
} |
||||
|
||||
private final function WeaponLocker SpawnDummyWeaponLocker() |
||||
{ |
||||
local bool savedCollideWorld, savedCollideActors; |
||||
if (dummyLocker != none && !dummyLocker.bPendingDelete) { |
||||
return dummyLocker; |
||||
} |
||||
// Disable collision so that dummy `WeaponLocker` would both not affect |
||||
// gameplay and would not fail spawning due to being inside terrain or |
||||
// another actor. |
||||
savedCollideWorld = class'WeaponLocker'.default.bCollideWorld; |
||||
savedCollideActors = class'WeaponLocker'.default.bBlockActors; |
||||
class'WeaponLocker'.default.bCollideWorld = false; |
||||
class'WeaponLocker'.default.bBlockActors = false; |
||||
dummyLocker = WeaponLocker(_.memory.Allocate(class'WeaponLocker')); |
||||
class'WeaponLocker'.default.bCollideWorld = savedCollideWorld; |
||||
class'WeaponLocker'.default.bBlockActors = savedCollideActors; |
||||
if (dummyLocker != none) |
||||
{ |
||||
dummyLocker.bHidden = true; |
||||
dummyLocker.SetDrawType(DT_None); |
||||
dummyLocker.SetCollision(false); |
||||
} |
||||
return dummyLocker; |
||||
} |
||||
|
||||
private final function WeaponLocker FindExistingWeaponLocker() |
||||
{ |
||||
local LevelInfo level; |
||||
local WeaponLocker nextLocker; |
||||
level = _.unreal.GetLevel(); |
||||
foreach level.DynamicActors(class'KFMod.WeaponLocker', nextLocker) |
||||
{ |
||||
if (nextLocker != none) { |
||||
return nextLocker; |
||||
} |
||||
} |
||||
return none; |
||||
} |
||||
|
||||
defaultproperties |
||||
{ |
||||
errNoReplacementLocker = (l=LOG_Error,m="`FixLogSpam` cannot find or spawn `WeaponLocker` actor. Shop log spam will not be disabled.") |
||||
} |
Loading…
Reference in new issue