doomsday: Redo the M&S stomp attack.
This commit is contained in:
parent
f9ae4556f1
commit
d7490bf7a1
3 changed files with 171 additions and 17 deletions
36
toontown/effects/ShakeCamera.py
Normal file
36
toontown/effects/ShakeCamera.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
import random
|
||||
from otp.ai.MagicWordGlobal import *
|
||||
|
||||
class ShakeCamera:
|
||||
def __init__(self, intensity, duration=0.5, rate=30.0):
|
||||
self.intensity = intensity
|
||||
self.duration = duration
|
||||
self.rate = rate
|
||||
|
||||
self.elapsed = 0.0
|
||||
|
||||
def start(self):
|
||||
taskMgr.add(self.__task, 'shakeCamera')
|
||||
|
||||
def __task(self, task):
|
||||
random_x = random.random()*2 - 1
|
||||
random_z = random.random()*2 - 1
|
||||
|
||||
lifecycle = self.elapsed / self.duration
|
||||
if lifecycle > 1.0:
|
||||
base.cam.setPos(0, 0, 0)
|
||||
return task.done
|
||||
|
||||
displacement = (1-lifecycle) * self.intensity
|
||||
|
||||
base.cam.setPos(random_x * displacement, 0, random_z * displacement)
|
||||
|
||||
task.delayTime = 1.0/self.rate
|
||||
self.elapsed += 1.0/self.rate
|
||||
return task.again
|
||||
|
||||
@magicWord(category=CATEGORY_GRAPHICAL, types=[float])
|
||||
def shakeCamera(intensity):
|
||||
"""Momentarily shake the camera, as if something heavy went bump nearby."""
|
||||
sc = ShakeCamera(intensity)
|
||||
sc.start()
|
|
@ -12,6 +12,7 @@ from InvasionSuitBase import InvasionSuitBase
|
|||
from toontown.distributed.DelayDeletable import DelayDeletable
|
||||
from toontown.distributed.DelayDelete import *
|
||||
import random
|
||||
from ThumpAttack import ThumpAttack
|
||||
|
||||
class DistributedInvasionSuit(DistributedSuitBase, InvasionSuitBase, FSM, DelayDeletable):
|
||||
def __init__(self, cr):
|
||||
|
@ -53,11 +54,8 @@ class DistributedInvasionSuit(DistributedSuitBase, InvasionSuitBase, FSM, DelayD
|
|||
# Get a few things defined for our Shakers
|
||||
self.shakerRadialAttack = None
|
||||
self.stompSfx = loader.loadSfx('phase_5/audio/sfx/SA_tremor.ogg')
|
||||
self.msStartStomp = Sequence(
|
||||
Func(self.play, 'walk', fromFrame=0, toFrame=22),
|
||||
Wait(0.9),
|
||||
Func(self.loop, 'walk', fromFrame=22, toFrame=62)
|
||||
)
|
||||
self.msStompLoop = None
|
||||
self.msStartStomp = None
|
||||
self.msSoundLoop = Sequence(SoundInterval(self.stompSfx, duration=1.6, startTime=0.3, volume=0.4, node=self))
|
||||
|
||||
def announceGenerate(self):
|
||||
|
@ -143,18 +141,20 @@ class DistributedInvasionSuit(DistributedSuitBase, InvasionSuitBase, FSM, DelayD
|
|||
|
||||
def enterMarch(self, time):
|
||||
if self.style.name == 'ms':
|
||||
self.__stompGenerate()
|
||||
self.msStartStomp.start(time)
|
||||
self.msSoundLoop.loop(time)
|
||||
self.shakerRadialAttack = taskMgr.add(self.__checkToonsInRadius, self.uniqueName('ShakerAttack'))
|
||||
else:
|
||||
self.loop('walk', 0)
|
||||
self.startMoveTask()
|
||||
|
||||
def exitMarch(self):
|
||||
if self.msStartStomp.isPlaying():
|
||||
if self.msStartStomp and self.msStartStomp.isPlaying():
|
||||
self.msStartStomp.finish()
|
||||
if self.msSoundLoop.isPlaying():
|
||||
self.msSoundLoop.finish()
|
||||
if self.msStompLoop and self.msStompLoop.isPlaying():
|
||||
self.msStompLoop.finish()
|
||||
self.loop('neutral', 0)
|
||||
self.stopMoveTask()
|
||||
self.stopShakerRadialAttack()
|
||||
|
@ -162,7 +162,7 @@ class DistributedInvasionSuit(DistributedSuitBase, InvasionSuitBase, FSM, DelayD
|
|||
|
||||
def enterAttack(self, time):
|
||||
if self.style.name == 'ms':
|
||||
self.shakerRadialAttack = taskMgr.add(self.__checkToonsInRadius, self.uniqueName('ShakerAttack'))
|
||||
self.__stompGenerate()
|
||||
self.msStartStomp.start(time)
|
||||
self.msSoundLoop.loop(time)
|
||||
return
|
||||
|
@ -174,10 +174,12 @@ class DistributedInvasionSuit(DistributedSuitBase, InvasionSuitBase, FSM, DelayD
|
|||
self._attackInterval.pause()
|
||||
self.cleanupProp(self._attackInterval.prop, self._attackInterval.propIsActor)
|
||||
#hehehe manual cleanup. so bad
|
||||
if self.msStartStomp.isPlaying():
|
||||
if self.msStartStomp and self.msStartStomp.isPlaying():
|
||||
self.msStartStomp.finish()
|
||||
if self.msSoundLoop.isPlaying():
|
||||
self.msSoundLoop.finish()
|
||||
if self.msStompLoop and self.msStompLoop.isPlaying():
|
||||
self.msStompLoop.finish()
|
||||
self.stopShakerRadialAttack()
|
||||
|
||||
def setAttackInfo(self, targetId, attackProp, attackDamage):
|
||||
|
@ -458,15 +460,35 @@ class DistributedInvasionSuit(DistributedSuitBase, InvasionSuitBase, FSM, DelayD
|
|||
if toon.hp > 0:
|
||||
base.localAvatar.enableAvatarControls()
|
||||
|
||||
def __checkToonsInRadius(self, task):
|
||||
def __stomp(self):
|
||||
if self.exploding:
|
||||
return task.done
|
||||
return
|
||||
|
||||
ta = ThumpAttack(lambda: \
|
||||
self.applyShakeAttack(base.localAvatar,
|
||||
SafezoneInvasionGlobals.MoveShakerDamageRadius)
|
||||
)
|
||||
ta.reparentTo(self.getParent())
|
||||
ta.setPos(self, 0, 0, 0)
|
||||
ta.start()
|
||||
|
||||
def __stompGenerate(self):
|
||||
if not self.msStompLoop:
|
||||
self.msStompLoop = Sequence(
|
||||
ActorInterval(self, 'walk', startFrame=22, endFrame=39),
|
||||
Func(self.__stomp),
|
||||
ActorInterval(self, 'walk', startFrame=39, endFrame=59),
|
||||
Func(self.__stomp),
|
||||
ActorInterval(self, 'walk', startFrame=59, endFrame=62)
|
||||
)
|
||||
|
||||
if not self.msStartStomp:
|
||||
self.msStartStomp = Sequence(
|
||||
Func(self.play, 'walk', fromFrame=0, toFrame=22),
|
||||
Wait(0.9),
|
||||
Func(self.msStompLoop.loop)
|
||||
)
|
||||
|
||||
toon = base.localAvatar
|
||||
if toon:
|
||||
if Vec3(toon.getPos(self)).length() <= SafezoneInvasionGlobals.MoveShakerRadius:
|
||||
self.applyShakeAttack(toon, SafezoneInvasionGlobals.MoveShakerDamageRadius)
|
||||
return task.cont
|
||||
|
||||
def applyShakeAttack(self, toon, damage):
|
||||
if not getattr(localAvatar.controlManager.currentControls, 'isAirborne', 0):
|
||||
|
@ -595,4 +617,4 @@ class DistributedInvasionSuit(DistributedSuitBase, InvasionSuitBase, FSM, DelayD
|
|||
|
||||
def exitFinaleStompAttack(self):
|
||||
self.finaleAttackJump.finish()
|
||||
self.finaleStompSequence.finish()
|
||||
self.finaleStompSequence.finish()
|
||||
|
|
96
toontown/election/ThumpAttack.py
Normal file
96
toontown/election/ThumpAttack.py
Normal file
|
@ -0,0 +1,96 @@
|
|||
from panda3d.core import *
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
from direct.interval.IntervalGlobal import *
|
||||
from otp.ai.MagicWordGlobal import *
|
||||
from toontown.toonbase import ToontownGlobals
|
||||
from toontown.effects.ShakeCamera import ShakeCamera
|
||||
import SafezoneInvasionGlobals
|
||||
|
||||
class ThumpAttack(NodePath, DirectObject):
|
||||
SPEED = 10.0
|
||||
RANGE = SafezoneInvasionGlobals.MoveShakerRadius
|
||||
|
||||
FADE_TIME = 0.2
|
||||
|
||||
INNER_RADIUS = 0.95 # Only outer 5% of the shockwave shell counts.
|
||||
|
||||
SHAKE_INTENSITY = 64.0 # How dizzy we get from this thump.
|
||||
|
||||
cm = CardMaker('thump_geom')
|
||||
cm.setFrame(-1, 1, -1, 1)
|
||||
|
||||
def __init__(self, callback):
|
||||
NodePath.__init__(self, 'thump')
|
||||
DirectObject.__init__(self)
|
||||
|
||||
self.geom = self.attachNewNode(self.cm.generate())
|
||||
self.geom.setP(-90)
|
||||
self.geom.setTransparency(1)
|
||||
self.geom.setDepthWrite(0)
|
||||
self.geom.setDepthTest(0)
|
||||
self.geom.setBin('shadow', 0)
|
||||
|
||||
self.collisionName = 'thumpCollide-%d' % id(self)
|
||||
self.collision = self.attachNewNode(CollisionNode(self.collisionName))
|
||||
csphere = CollisionSphere(0,0,0,1)
|
||||
csphere.setTangible(0)
|
||||
self.collision.node().addSolid(csphere)
|
||||
self.collision.node().setIntoCollideMask(ToontownGlobals.WallBitmask)
|
||||
|
||||
self.callback = callback
|
||||
|
||||
def start(self):
|
||||
spreadTime = self.RANGE/self.SPEED
|
||||
|
||||
interval = Sequence(
|
||||
Parallel(
|
||||
LerpScaleInterval(self, spreadTime,
|
||||
self.RANGE, startScale=0),
|
||||
|
||||
Sequence(
|
||||
Wait(spreadTime - self.FADE_TIME),
|
||||
LerpColorScaleInterval(self, self.FADE_TIME, (1,1,1,0))
|
||||
)
|
||||
),
|
||||
|
||||
Func(self.cleanup)
|
||||
)
|
||||
|
||||
offset = base.localAvatar.getPos(render) - self.getPos(render)
|
||||
intensity = self.SHAKE_INTENSITY/offset.lengthSquared()
|
||||
|
||||
shake = ShakeCamera(intensity)
|
||||
shake.start()
|
||||
|
||||
interval.start()
|
||||
|
||||
self.accept('enter' + self.collisionName, self.__handleCollide)
|
||||
self.accept('again' + self.collisionName, self.__handleCollide)
|
||||
|
||||
def __handleCollide(self, ce):
|
||||
# Find out how far base.localAvatar is within us:
|
||||
offset = base.localAvatar.getPos(self) - Point3(0, 0, 0)
|
||||
|
||||
if offset.lengthSquared() < self.INNER_RADIUS*self.INNER_RADIUS:
|
||||
return # Too far inside, not on the front of the shockwave.
|
||||
|
||||
# Are they on the ground?
|
||||
if getattr(base.localAvatar.controlManager.currentControls, 'isAirborne', 0):
|
||||
return # Yeah, we're safe.
|
||||
|
||||
self.ignoreAll() # Ignore subsequent collisions.
|
||||
|
||||
self.callback()
|
||||
|
||||
def cleanup(self):
|
||||
self.ignoreAll()
|
||||
self.removeNode()
|
||||
|
||||
@magicWord(category=CATEGORY_DEBUG)
|
||||
def doThump():
|
||||
"""Plays a 'thump attack' effect in front of your current position."""
|
||||
|
||||
thump = ThumpAttack(lambda: base.localAvatar.setSystemMessage(0, 'Gotcha!'))
|
||||
thump.setPos(spellbook.getInvoker(), 0, 5, 0)
|
||||
thump.reparentTo(render)
|
||||
thump.start()
|
Loading…
Reference in a new issue