From 953bdfdc72cc42e359dcca08fd5f64272eff40e2 Mon Sep 17 00:00:00 2001 From: Anton Tarasenko Date: Sun, 17 Jul 2022 04:13:01 +0700 Subject: [PATCH] Add new functionality to `EPawn`/`EPlaceable` --- .../Gameplay/BaseClasses/Frontend/EPawn.uc | 3 +- .../BaseClasses/Frontend/EPlaceable.uc | 57 ++++- .../KF1Frontend/BaseImplementation/EKFPawn.uc | 74 ++++++- .../BaseImplementation/EKFPlaceable.uc | 202 ++++++++++++++++++ 4 files changed, 329 insertions(+), 7 deletions(-) create mode 100644 sources/Gameplay/KF1Frontend/BaseImplementation/EKFPlaceable.uc diff --git a/sources/Gameplay/BaseClasses/Frontend/EPawn.uc b/sources/Gameplay/BaseClasses/Frontend/EPawn.uc index f38030f..aa01130 100644 --- a/sources/Gameplay/BaseClasses/Frontend/EPawn.uc +++ b/sources/Gameplay/BaseClasses/Frontend/EPawn.uc @@ -1,8 +1,7 @@ /** * Interface for a *Pawn* - base class for any entity that can be * controlled by player or AI. To avoid purity for the sake of itself, in - * Acedia it will also be bundled with such typical components as health, - * collision, etc. + * Acedia it will also be bundled with typical components like health. * Copyright 2022 Anton Tarasenko *------------------------------------------------------------------------------ * This file is part of Acedia. diff --git a/sources/Gameplay/BaseClasses/Frontend/EPlaceable.uc b/sources/Gameplay/BaseClasses/Frontend/EPlaceable.uc index 7402552..790c9d1 100644 --- a/sources/Gameplay/BaseClasses/Frontend/EPlaceable.uc +++ b/sources/Gameplay/BaseClasses/Frontend/EPlaceable.uc @@ -1,5 +1,7 @@ /** - * Interface for any entity that can be placed into the game world. + * Interface for any entity that can be placed into the game world. To + * avoid purity for the sake of itself, in Acedia it will also be bundled with + * typical components such as collision and visibility. * Copyright 2022 Anton Tarasenko *------------------------------------------------------------------------------ * This file is part of Acedia. @@ -23,10 +25,61 @@ class EPlaceable extends EInterface /** * Returns position of the caller `EPlaceable` * - * @return Vector that describes position of the caller `EPlaceable`. + * @return `Vector` that describes position of the caller `EPlaceable`. */ public function Vector GetLocation(); +/** + * Returns rotation of the caller `EPlaceable` + * + * @return `Rotator` that describes rotation of the caller `EPlaceable`. + */ +public function Rotator GetRotation(); + +/** + * Is caller `EPlaceable` considered static (i.e. does not move or change over + * time)? + * + * @return `true` for static `EPlaceable`s and `false` for all others. + */ +public function bool IsStatic(); + +/** + * Is caller `EPlaceable` capable of colliding other `EPlaceable`s? + * + * @return `true` for `EPlaceable`s that are capable of collision and `false` + * for any others. + */ +public function bool IsColliding(); + +/** + * Is caller `EPlaceable` blocking colliding `EPlaceable`s? + * + * Blocking `EPlaceable`s cannot occupy the same space on the map. + * + * @return `true` for `EPlaceable`s that are currently blocking and `false` + * for any others. + */ +public function bool IsBlocking(); + +/** + * Changes whether caller `EPlaceable` is blocking other `EPlaceable`s. + * + * @param newBlocking `true` to make caller `EPlaceable` start blocking others + * and `false` to prevent it from blocking. + * @return `true` for static `EPlaceable`s and `false` for all others. + */ +public function SetBlocking(bool newBlocking); + +/** + * Checks if given placeable can be seen by players on the map. It is not + * required that it is actually seen by someone at the moment of call, but that + * it could be visible in principle. + * + * @return `true` if caller `EPlaceable` is visible and `false` otherwise. + */ +public function bool IsVisible(); + defaultproperties { } \ No newline at end of file diff --git a/sources/Gameplay/KF1Frontend/BaseImplementation/EKFPawn.uc b/sources/Gameplay/KF1Frontend/BaseImplementation/EKFPawn.uc index 884513d..2f96c57 100644 --- a/sources/Gameplay/KF1Frontend/BaseImplementation/EKFPawn.uc +++ b/sources/Gameplay/KF1Frontend/BaseImplementation/EKFPawn.uc @@ -57,9 +57,10 @@ public function EInterface Copy() public function bool Supports(class newInterfaceClass) { - if (newInterfaceClass == none) return false; - if (newInterfaceClass == class'EPlaceable') return true; - if (newInterfaceClass == class'EKFPawn') return true; + if (newInterfaceClass == none) return false; + if (newInterfaceClass == class'EPlaceable') return true; + if (newInterfaceClass == class'EKFPlaceable') return true; + if (newInterfaceClass == class'EKFPawn') return true; return false; } @@ -70,6 +71,7 @@ public function EInterface As(class newInterfaceClass) return none; } if ( newInterfaceClass == class'EPlaceable' + || newInterfaceClass == class'EKFPlaceable' || newInterfaceClass == class'EKFPawn') { return Copy(); @@ -117,6 +119,72 @@ public function Vector GetLocation() return Vect(0.0, 0.0, 0.0); } + +public function Rotator GetRotation() +{ + local Pawn pawnInstance; + + pawnInstance = GetNativeInstance(); + if (pawnInstance != none) { + return pawnInstance.rotation; + } + return Rot(0.0, 0.0, 0.0); +} + +public function bool IsStatic() +{ + local Pawn pawnInstance; + + pawnInstance = GetNativeInstance(); + if (pawnInstance != none) { + return pawnInstance.bStatic; + } + return false; +} + +public function bool IsColliding() +{ + local Pawn pawnInstance; + + pawnInstance = GetNativeInstance(); + if (pawnInstance != none) { + return pawnInstance.bCollideActors; + } + return false; +} + +public function bool IsBlocking() +{ + local Pawn pawnInstance; + + pawnInstance = GetNativeInstance(); + if (pawnInstance != none) { + return pawnInstance.bBlockActors; + } + return false; +} + +public function SetBlocking(bool newBlocking) +{ + local Pawn pawnInstance; + + pawnInstance = GetNativeInstance(); + if (pawnInstance != none) { + pawnInstance.bBlockActors = newBlocking; + } +} + +public function bool IsVisible() +{ + local Pawn pawnInstance; + + pawnInstance = GetNativeInstance(); + if (pawnInstance != none) { + return (!pawnInstance.bHidden && pawnInstance.drawType != DT_None); + } + return false; +} + public function EPlayer GetPlayer() { local Pawn pawnInstance; diff --git a/sources/Gameplay/KF1Frontend/BaseImplementation/EKFPlaceable.uc b/sources/Gameplay/KF1Frontend/BaseImplementation/EKFPlaceable.uc new file mode 100644 index 0000000..19dd984 --- /dev/null +++ b/sources/Gameplay/KF1Frontend/BaseImplementation/EKFPlaceable.uc @@ -0,0 +1,202 @@ +/** + * Implementation of `EPlaceable` for classic Killing Floor weapons that + * changes as little as possible and only on request from another mod, + * otherwise not altering gameplay at all. + * Copyright 2022 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 . + */ +class EKFPlaceable extends EPlaceable + abstract; + +var private NativeActorRef actorReference; + +protected function Finalizer() +{ + _.memory.Free(actorReference); + actorReference = none; +} + +/** + * Creates new `EKFPlaceable` that refers to the `actorInstance` pawn. + * + * @param actorInstance Native actor class that new `EKFPlaceable` will + * represent. + * @return New `EKFPlaceable` that represents given `actorInstance`. + */ +public final static /*unreal*/ function EKFPlaceable Wrap(Actor actorInstance) +{ + local EKFPlaceable newReference; + + if (actorInstance == none) { + return none; + } + newReference = EKFPlaceable(__().memory.Allocate(class'EKFPlaceable')); + newReference.actorReference = __server().unreal.ActorRef(actorInstance); + return newReference; +} + +public function EInterface Copy() +{ + local Actor actorInstance; + + actorInstance = GetNativeInstance(); + return Wrap(actorInstance); +} + +public function bool Supports(class newInterfaceClass) +{ + if (newInterfaceClass == none) return false; + if (newInterfaceClass == class'EPlaceable') return true; + if (newInterfaceClass == class'EKFPlaceable') return true; + + if (newInterfaceClass == class'EKFPawn') { + return (Pawn(GetNativeInstance()) != none); + } + return false; +} + +public function EInterface As(class newInterfaceClass) +{ + local Pawn pawnInstance; + + if (!IsExistent()) { + return none; + } + if ( newInterfaceClass == class'EPlaceable' + || newInterfaceClass == class'EKFPlaceable') + { + return Copy(); + } + if ( newInterfaceClass == class'EPawn' + || newInterfaceClass == class'EKFPawn') + { + pawnInstance = Pawn(GetNativeInstance()); + if (pawnInstance != none) { + return class'EKFPawn'.static.Wrap(pawnInstance); + } + } + return none; +} + +public function bool IsExistent() +{ + return (GetNativeInstance() != none); +} + +public function bool SameAs(EInterface other) +{ + local EKFPlaceable otherPlaceable; + + otherPlaceable = EKFPlaceable(other); + if (otherPlaceable == none) { + return false; + } + return (GetNativeInstance() == otherPlaceable.GetNativeInstance()); +} + +/** + * Returns `Pawn` instance represented by the caller `EKFPlaceable`. + * + * @return `Pawn` instance represented by the caller `EKFPlaceable`. + */ +public final /*unreal*/ function Actor GetNativeInstance() +{ + if (actorReference != none) { + return actorReference.Get(); + } + return none; +} + +public function Vector GetLocation() +{ + local Actor actorInstance; + + actorInstance = GetNativeInstance(); + if (actorInstance != none) { + return actorInstance.location; + } + return Vect(0.0, 0.0, 0.0); +} + +public function Rotator GetRotation() +{ + local Actor actorInstance; + + actorInstance = GetNativeInstance(); + if (actorInstance != none) { + return actorInstance.rotation; + } + return Rot(0.0, 0.0, 0.0); +} + +public function bool IsStatic() +{ + local Actor actorInstance; + + actorInstance = GetNativeInstance(); + if (actorInstance != none) { + return actorInstance.bStatic; + } + return false; +} + +public function bool IsColliding() +{ + local Actor actorInstance; + + actorInstance = GetNativeInstance(); + if (actorInstance != none) { + return actorInstance.bCollideActors; + } + return false; +} + +public function bool IsBlocking() +{ + local Actor actorInstance; + + actorInstance = GetNativeInstance(); + if (actorInstance != none) { + return actorInstance.bBlockActors; + } + return false; +} + +public function SetBlocking(bool newBlocking) +{ + local Actor actorInstance; + + actorInstance = GetNativeInstance(); + if (actorInstance != none) { + actorInstance.bBlockActors = newBlocking; + } +} + +public function bool IsVisible() +{ + local Actor actorInstance; + + actorInstance = GetNativeInstance(); + if (actorInstance != none) { + return (!actorInstance.bHidden && actorInstance.drawType != DT_None); + } + return false; +} + +defaultproperties +{ +} \ No newline at end of file