diff --git a/TowerForge/Assets.xcassets/Sprites.spriteatlas/damage.imageset/Contents.json b/TowerForge/Assets.xcassets/Sprites.spriteatlas/damage.imageset/Contents.json new file mode 100644 index 00000000..75949a8e --- /dev/null +++ b/TowerForge/Assets.xcassets/Sprites.spriteatlas/damage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "damage.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "damage 1.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "damage 2.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TowerForge/Assets.xcassets/Sprites.spriteatlas/damage.imageset/damage 1.png b/TowerForge/Assets.xcassets/Sprites.spriteatlas/damage.imageset/damage 1.png new file mode 100644 index 00000000..6936f6a4 Binary files /dev/null and b/TowerForge/Assets.xcassets/Sprites.spriteatlas/damage.imageset/damage 1.png differ diff --git a/TowerForge/Assets.xcassets/Sprites.spriteatlas/damage.imageset/damage 2.png b/TowerForge/Assets.xcassets/Sprites.spriteatlas/damage.imageset/damage 2.png new file mode 100644 index 00000000..6936f6a4 Binary files /dev/null and b/TowerForge/Assets.xcassets/Sprites.spriteatlas/damage.imageset/damage 2.png differ diff --git a/TowerForge/Assets.xcassets/Sprites.spriteatlas/damage.imageset/damage.png b/TowerForge/Assets.xcassets/Sprites.spriteatlas/damage.imageset/damage.png new file mode 100644 index 00000000..6936f6a4 Binary files /dev/null and b/TowerForge/Assets.xcassets/Sprites.spriteatlas/damage.imageset/damage.png differ diff --git a/TowerForge/Assets.xcassets/Sprites.spriteatlas/nocost.imageset/Contents.json b/TowerForge/Assets.xcassets/Sprites.spriteatlas/nocost.imageset/Contents.json new file mode 100644 index 00000000..a21d33e8 --- /dev/null +++ b/TowerForge/Assets.xcassets/Sprites.spriteatlas/nocost.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "nocost.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "nocost 1.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "nocost 2.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TowerForge/Assets.xcassets/Sprites.spriteatlas/nocost.imageset/nocost 1.png b/TowerForge/Assets.xcassets/Sprites.spriteatlas/nocost.imageset/nocost 1.png new file mode 100644 index 00000000..618ef801 Binary files /dev/null and b/TowerForge/Assets.xcassets/Sprites.spriteatlas/nocost.imageset/nocost 1.png differ diff --git a/TowerForge/Assets.xcassets/Sprites.spriteatlas/nocost.imageset/nocost 2.png b/TowerForge/Assets.xcassets/Sprites.spriteatlas/nocost.imageset/nocost 2.png new file mode 100644 index 00000000..618ef801 Binary files /dev/null and b/TowerForge/Assets.xcassets/Sprites.spriteatlas/nocost.imageset/nocost 2.png differ diff --git a/TowerForge/Assets.xcassets/Sprites.spriteatlas/nocost.imageset/nocost.png b/TowerForge/Assets.xcassets/Sprites.spriteatlas/nocost.imageset/nocost.png new file mode 100644 index 00000000..618ef801 Binary files /dev/null and b/TowerForge/Assets.xcassets/Sprites.spriteatlas/nocost.imageset/nocost.png differ diff --git a/TowerForge/TowerForge.xcodeproj/project.pbxproj b/TowerForge/TowerForge.xcodeproj/project.pbxproj index 25494225..ad542a65 100644 --- a/TowerForge/TowerForge.xcodeproj/project.pbxproj +++ b/TowerForge/TowerForge.xcodeproj/project.pbxproj @@ -181,6 +181,10 @@ 9B0406142BB89BE00026E903 /* PowerUpSelectionNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B0406132BB89BE00026E903 /* PowerUpSelectionNode.swift */; }; 9B0406162BB89E140026E903 /* InvulnerabilityPowerUpDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B0406152BB89E140026E903 /* InvulnerabilityPowerUpDelegate.swift */; }; 9B0406182BB8A1E10026E903 /* PowerUpDelegateFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B0406172BB8A1E10026E903 /* PowerUpDelegateFactory.swift */; }; + 9B274DC42BD24B210062715C /* DamagePowerUp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B274DC32BD24B210062715C /* DamagePowerUp.swift */; }; + 9B274DC62BD24C4F0062715C /* DamagePowerUpDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B274DC52BD24C4F0062715C /* DamagePowerUpDelegate.swift */; }; + 9B274DC82BD250420062715C /* NoCostPowerUp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B274DC72BD250420062715C /* NoCostPowerUp.swift */; }; + 9B274DCA2BD252330062715C /* NoCostPowerUpDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B274DC92BD252320062715C /* NoCostPowerUpDelegate.swift */; }; 9B8696552BAD759F0002377C /* Grid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B8696542BAD759F0002377C /* Grid.swift */; }; 9BC60BC82BB9BE6D001A6737 /* DisabledEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BC60BC72BB9BE6D001A6737 /* DisabledEvent.swift */; }; 9BD669682BAFDE5E00DC8C4C /* GridDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD669672BAFDE5E00DC8C4C /* GridDelegate.swift */; }; @@ -444,6 +448,10 @@ 9B0406132BB89BE00026E903 /* PowerUpSelectionNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PowerUpSelectionNode.swift; sourceTree = ""; }; 9B0406152BB89E140026E903 /* InvulnerabilityPowerUpDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvulnerabilityPowerUpDelegate.swift; sourceTree = ""; }; 9B0406172BB8A1E10026E903 /* PowerUpDelegateFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PowerUpDelegateFactory.swift; sourceTree = ""; }; + 9B274DC32BD24B210062715C /* DamagePowerUp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamagePowerUp.swift; sourceTree = ""; }; + 9B274DC52BD24C4F0062715C /* DamagePowerUpDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamagePowerUpDelegate.swift; sourceTree = ""; }; + 9B274DC72BD250420062715C /* NoCostPowerUp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoCostPowerUp.swift; sourceTree = ""; }; + 9B274DC92BD252320062715C /* NoCostPowerUpDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoCostPowerUpDelegate.swift; sourceTree = ""; }; 9B8696542BAD759F0002377C /* Grid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Grid.swift; sourceTree = ""; }; 9BC60BC72BB9BE6D001A6737 /* DisabledEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisabledEvent.swift; sourceTree = ""; }; 9BD669672BAFDE5E00DC8C4C /* GridDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GridDelegate.swift; sourceTree = ""; }; @@ -957,6 +965,10 @@ 9B0406172BB8A1E10026E903 /* PowerUpDelegateFactory.swift */, 9B04060F2BB879990026E903 /* InvulnerabilityPowerUp.swift */, 9B0406152BB89E140026E903 /* InvulnerabilityPowerUpDelegate.swift */, + 9B274DC32BD24B210062715C /* DamagePowerUp.swift */, + 9B274DC52BD24C4F0062715C /* DamagePowerUpDelegate.swift */, + 9B274DC72BD250420062715C /* NoCostPowerUp.swift */, + 9B274DC92BD252320062715C /* NoCostPowerUpDelegate.swift */, ); path = PowerUps; sourceTree = ""; @@ -1602,6 +1614,7 @@ BA82C7672BCBCB00000515A0 /* StatisticsDatabase+Codable.swift in Sources */, 3CD37AA52BBEC10700222D8A /* FirebaseRemoteEventSubscriber.swift in Sources */, BA82C7792BCC6943000515A0 /* CenturionAchievement.swift in Sources */, + 9B274DC82BD250420062715C /* NoCostPowerUp.swift in Sources */, 52A794172BBC4F690083C976 /* GamePlayer.swift in Sources */, 3CBE72FD2BC8D64F00CC446A /* RemoteMoveEvent.swift in Sources */, 3CE951632BAE037C008B2785 /* AiSystem.swift in Sources */, @@ -1668,6 +1681,7 @@ 527A07842BB3FD9A00CD9D08 /* TimerSystem.swift in Sources */, BA82C7462BC8797F000515A0 /* StatisticsDatabase.swift in Sources */, 3C3CBDF72BB81D970001B8A9 /* TFCameraNode.swift in Sources */, + 9B274DCA2BD252330062715C /* NoCostPowerUpDelegate.swift in Sources */, BA82C76D2BCBD8F7000515A0 /* StatisticsDatabase+Merge.swift in Sources */, 3CE951562BACA0CF008B2785 /* Collidable.swift in Sources */, BA82C7422BC86FE1000515A0 /* TotalGamesStatistic.swift in Sources */, @@ -1685,6 +1699,7 @@ 3C9955AF2BA48FD200D33FA5 /* MeleeUnit.swift in Sources */, 5240D0AD2BB33D4C004F1486 /* PositionSystem.swift in Sources */, 5295A2022BA9FBD9005018A8 /* SceneManagerDelegate.swift in Sources */, + 9B274DC42BD24B210062715C /* DamagePowerUp.swift in Sources */, 52DF5FE12BA3349600135367 /* TFTextures.swift in Sources */, 520062582BA8ED73000DBA30 /* HomeComponent.swift in Sources */, 52DF5FA82BA32B2300135367 /* AppDelegate.swift in Sources */, @@ -1751,6 +1766,7 @@ 3CE951672BAEAB0E008B2785 /* ContactSystem.swift in Sources */, 529190E32BBFB59B001D8821 /* StatePopupNode.swift in Sources */, 3CE951692BAEB719008B2785 /* RequestSpawnEvent.swift in Sources */, + 9B274DC62BD24C4F0062715C /* DamagePowerUpDelegate.swift in Sources */, BA82C7832BCD2B30000515A0 /* Mission.swift in Sources */, 3CFA72E72BC0398E0081337F /* RemoteEventManager.swift in Sources */, ); diff --git a/TowerForge/TowerForge/GameModule/PowerUps/DamagePowerUp.swift b/TowerForge/TowerForge/GameModule/PowerUps/DamagePowerUp.swift new file mode 100644 index 00000000..f3438629 --- /dev/null +++ b/TowerForge/TowerForge/GameModule/PowerUps/DamagePowerUp.swift @@ -0,0 +1,29 @@ +// +// DamagePowerUp.swift +// TowerForge +// +// Created by Keith Gan on 19/4/24. +// + +import Foundation + +class DamagePowerUp: EventTransformation { + let DURATION = CGFloat(5) + let DAMAGE_SCALE = CGFloat(2) + let id: UUID + let player: Player + + required init(player: Player = .ownPlayer) { + self.id = UUID() + self.player = player + } + + func transformEvent(event: TFEvent) -> TFEvent { + guard let damageEvent = event as? DamageEvent, damageEvent.player == player else { + return event + } + + return DamageEvent(on: damageEvent.entityId, at: damageEvent.timestamp, with: damageEvent.damage * DAMAGE_SCALE, + player: damageEvent.player) + } +} diff --git a/TowerForge/TowerForge/GameModule/PowerUps/DamagePowerUpDelegate.swift b/TowerForge/TowerForge/GameModule/PowerUps/DamagePowerUpDelegate.swift new file mode 100644 index 00000000..d3b13cf7 --- /dev/null +++ b/TowerForge/TowerForge/GameModule/PowerUps/DamagePowerUpDelegate.swift @@ -0,0 +1,25 @@ +// +// DamagePowerUpDelegate.swift +// TowerForge +// +// Created by Keith Gan on 19/4/24. +// + +import Foundation + +class DamagePowerUpDelegate: PowerUpNodeDelegate { + let eventManager: EventManager + + init(eventManager: EventManager) { + self.eventManager = eventManager + } + + func powerUpNodeDidSelect() { + let damagePowerUp = DamagePowerUp() + eventManager.addTransformation(eventTransformation: damagePowerUp) + + DispatchQueue.main.asyncAfter(deadline: .now() + damagePowerUp.DURATION) { + self.eventManager.removeTransformation(eventTransformation: damagePowerUp) + } + } +} diff --git a/TowerForge/TowerForge/GameModule/PowerUps/NoCostPowerUp.swift b/TowerForge/TowerForge/GameModule/PowerUps/NoCostPowerUp.swift new file mode 100644 index 00000000..69cbc23b --- /dev/null +++ b/TowerForge/TowerForge/GameModule/PowerUps/NoCostPowerUp.swift @@ -0,0 +1,28 @@ +// +// NoCostPowerUp.swift +// TowerForge +// +// Created by Keith Gan on 19/4/24. +// + +import Foundation + +class NoCostPowerUp: EventTransformation { + let DURATION = CGFloat(3) + let id: UUID + let player: Player + + required init(player: Player = .ownPlayer) { + self.id = UUID() + self.player = player + } + + func transformEvent(event: TFEvent) -> TFEvent { + guard let requestSpawnEvent = event as? RequestSpawnEvent, requestSpawnEvent.player == player else { + return event + } + + return WaveSpawnEvent(ofType: requestSpawnEvent.entityType, timestamp: requestSpawnEvent.timestamp, position: + requestSpawnEvent.position, player: requestSpawnEvent.player) + } +} diff --git a/TowerForge/TowerForge/GameModule/PowerUps/NoCostPowerUpDelegate.swift b/TowerForge/TowerForge/GameModule/PowerUps/NoCostPowerUpDelegate.swift new file mode 100644 index 00000000..0dcdd8b8 --- /dev/null +++ b/TowerForge/TowerForge/GameModule/PowerUps/NoCostPowerUpDelegate.swift @@ -0,0 +1,25 @@ +// +// NoCostPowerUpDelegate.swift +// TowerForge +// +// Created by Keith Gan on 19/4/24. +// + +import Foundation + +class NoCostPowerUpDelegate: PowerUpNodeDelegate { + let eventManager: EventManager + + init(eventManager: EventManager) { + self.eventManager = eventManager + } + + func powerUpNodeDidSelect() { + let noCostPowerUp = NoCostPowerUp() + eventManager.addTransformation(eventTransformation: noCostPowerUp) + + DispatchQueue.main.asyncAfter(deadline: .now() + noCostPowerUp.DURATION) { + self.eventManager.removeTransformation(eventTransformation: noCostPowerUp) + } + } +} diff --git a/TowerForge/TowerForge/GameModule/PowerUps/PowerUpDelegateFactory.swift b/TowerForge/TowerForge/GameModule/PowerUps/PowerUpDelegateFactory.swift index 3365a9bc..84d8889c 100644 --- a/TowerForge/TowerForge/GameModule/PowerUps/PowerUpDelegateFactory.swift +++ b/TowerForge/TowerForge/GameModule/PowerUps/PowerUpDelegateFactory.swift @@ -13,6 +13,10 @@ class PowerUpDelegateFactory { switch type { case .invulnerability: return InvulnerabilityPowerUpDelegate(eventManager: eventManager) + case .damage: + return DamagePowerUpDelegate(eventManager: eventManager) + case .nocost: + return NoCostPowerUpDelegate(eventManager: eventManager) } } } diff --git a/TowerForge/TowerForge/Metrics/Inference/InferenceEngineFactory.swift b/TowerForge/TowerForge/Metrics/Inference/InferenceEngineFactory.swift index 09f8d16f..d82e6c1d 100644 --- a/TowerForge/TowerForge/Metrics/Inference/InferenceEngineFactory.swift +++ b/TowerForge/TowerForge/Metrics/Inference/InferenceEngineFactory.swift @@ -10,7 +10,5 @@ import Foundation class InferenceEngineFactory { static var availableInferenceEngines: [(StatisticsEngine) -> any InferenceEngine] = - [ { stats in AchievementsEngine(stats) }, - { stats in MissionsEngine(stats) }, - { stats in RankingEngine(stats) } ] + [ { stats in AchievementsEngine(stats) }, { stats in MissionsEngine(stats) }, { stats in RankingEngine(stats) } ] } diff --git a/TowerForge/TowerForge/Nodes/PowerUpNode.swift b/TowerForge/TowerForge/Nodes/PowerUpNode.swift index 6c195592..092352d7 100644 --- a/TowerForge/TowerForge/Nodes/PowerUpNode.swift +++ b/TowerForge/TowerForge/Nodes/PowerUpNode.swift @@ -9,16 +9,33 @@ import SpriteKit enum PowerUp: String { case invulnerability + case damage + case nocost var imageName: String { switch self { case .invulnerability: return "invulnerability" + case .damage: + return "damage" + case .nocost: + return "nocost" + } + } + + var cooldown: CGFloat { + switch self { + case .invulnerability: + return CGFloat(10) + case .damage: + return CGFloat(10) + case .nocost: + return CGFloat(30) } } static var allPowerUps: [PowerUp] { - [.invulnerability] + [.invulnerability, .damage, .nocost] } } @@ -30,6 +47,7 @@ class PowerUpNode: TFEntity { static let size = UnitNode.size let type: PowerUp var delegate: PowerUpNodeDelegate + var enabled = true init(type: PowerUp, delegate: PowerUpNodeDelegate, at position: CGPoint) { self.type = type @@ -45,7 +63,27 @@ class PowerUpNode: TFEntity { } private func setUpButtonComponent(size: CGSize) { - let buttonDelegate = TFButtonDelegate(onTouchBegan: { self.delegate.powerUpNodeDidSelect() }, onTouchEnded: {}) + let buttonDelegate = TFButtonDelegate(onTouchBegan: onTouchBegan, onTouchEnded: {}) addComponent(ButtonComponent(size: size, buttonDelegate: buttonDelegate)) } + + private func onTouchBegan() { + if !self.enabled { + return + } + self.enabled = false + update(alpha: 0.5) + self.delegate.powerUpNodeDidSelect() + Foundation.Timer.scheduledTimer(withTimeInterval: self.type.cooldown, repeats: false) { _ in + self.enabled = true + self.update(alpha: 1.0) + } + } + + private func update(alpha: CGFloat) { + guard let spriteComponent = component(ofType: SpriteComponent.self) else { + return + } + spriteComponent.alpha = alpha + } }