toontown-just-works/toontown/coghq/DistributedStomper.py
2024-07-07 18:08:39 -05:00

347 lines
14 KiB
Python

from panda3d.core import *
from direct.interval.IntervalGlobal import *
from StomperGlobals import *
from direct.distributed import ClockDelta
from direct.showbase.PythonUtil import lerp
import math
import DistributedCrusherEntity
import MovingPlatform
from direct.directnotify import DirectNotifyGlobal
from direct.task import Task
from toontown.toonbase import ToontownGlobals
class DistributedStomper(DistributedCrusherEntity.DistributedCrusherEntity):
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedStomper')
stomperSounds = ['phase_4/audio/sfx/CHQ_FACT_stomper_small.ogg', 'phase_9/audio/sfx/CHQ_FACT_stomper_med.ogg', 'phase_9/audio/sfx/CHQ_FACT_stomper_large.ogg']
stomperModels = ['phase_9/models/cogHQ/square_stomper']
def __init__(self, cr):
self.stomperModels = ['phase_9/models/cogHQ/square_stomper']
self.lastPos = Point3(0, 0, 0)
self.model = None
self.smokeTrack = None
self.ival = None
self.smoke = None
self.shadow = None
self.sound = None
self.crushSurface = None
self.cogStyle = 0
self.loaded = 0
self.crushedList = []
self.sounds = []
self.wantSmoke = 1
self.wantShadow = 1
self.animateShadow = 1
self.removeHeadFloor = 0
self.removeCamBarrierCollisions = 0
for s in self.stomperSounds:
self.sounds.append(loader.loadSfx(s))
DistributedCrusherEntity.DistributedCrusherEntity.__init__(self, cr)
return
def generateInit(self):
self.notify.debug('generateInit')
DistributedCrusherEntity.DistributedCrusherEntity.generateInit(self)
def generate(self):
self.notify.debug('generate')
DistributedCrusherEntity.DistributedCrusherEntity.generate(self)
def announceGenerate(self):
self.notify.debug('announceGenerate')
DistributedCrusherEntity.DistributedCrusherEntity.announceGenerate(self)
self.loadModel()
def disable(self):
self.notify.debug('disable')
self.ignoreAll()
if self.ival:
self.ival.pause()
del self.ival
self.ival = None
if self.smokeTrack:
self.smokeTrack.pause()
del self.smokeTrack
self.smokeTrack = None
DistributedCrusherEntity.DistributedCrusherEntity.disable(self)
return
def delete(self):
self.notify.debug('delete')
self.unloadModel()
taskMgr.remove(self.taskName('smokeTask'))
DistributedCrusherEntity.DistributedCrusherEntity.delete(self)
def loadModel(self):
self.loaded = 1
self.stomperModels = ['phase_9/models/cogHQ/square_stomper']
if self.cogStyle == 1:
self.stomperModels = ['phase_11/models/lawbotHQ/LB_square_stomper']
self.notify.debug('loadModel')
shadow = None
self.sound = self.sounds[self.soundPath]
self.rotateNode = self.attachNewNode('rotate')
stomperModel = loader.loadModel(self.stomperModels[self.modelPath])
if self.style == 'vertical':
model = stomperModel
self.rotateNode.setP(-90)
sideList = model.findAllMatches('**/collSide')
for side in sideList:
side.stash()
upList = model.findAllMatches('**/collUp')
for up in upList:
up.stash()
head = model.find('**/head')
shaft = model.find('**/shaft')
self.crushSurface = head.find('**/collDownWalls')
self.shadow = None
if self.wantShadow:
shadow = loader.loadModel('phase_3/models/props/square_drop_shadow').getChild(0)
shadow.setScale(0.3 * self.headScale[0], 0.3 * self.headScale[2], 1)
shadow.setAlphaScale(0.8)
shadow.flattenMedium()
shadow.reparentTo(self)
shadow.setPos(0, 0, 0.025)
shadow.setTransparency(1)
self.shadow = shadow
floorHeadNp = model.find('**/head_collisions/**/collDownFloor')
floorHead = floorHeadNp.node()
if self.removeHeadFloor:
floorHeadNp.stash()
else:
for i in xrange(floorHead.getNumSolids()):
floorHead.modifySolid(i).setEffectiveNormal(Vec3(0.0, -1.0, 0.0))
floorShaft = model.find('**/shaft_collisions/**/collDownFloor').node()
for i in xrange(floorShaft.getNumSolids()):
floorShaft.modifySolid(i).setEffectiveNormal(Vec3(0.0, -1.0, 0.0))
self.accept(self.crushMsg, self.checkSquashedToon)
elif self.style == 'horizontal':
model = MovingPlatform.MovingPlatform()
model.setupCopyModel(self.getParentToken(), stomperModel, 'collSideFloor')
head = model.find('**/head')
head.node().setPreserveTransform(0)
head.setZ(1.0)
for child in head.findAllMatches('+ModelNode'):
child.node().setPreserveTransform(ModelNode.PTNet)
model.flattenLight()
upList = model.findAllMatches('**/collUp')
for up in upList:
up.stash()
downList = model.findAllMatches('**/collDown')
for down in downList:
down.stash()
self.crushSurface = model.find('**/head_collisions/**/collSideWalls')
if self.removeCamBarrierCollisions:
walls = model.findAllMatches('**/collDownWalls')
for wall in walls:
node = wall.node()
bitmask = node.getIntoCollideMask()
invBitmask = BitMask32(ToontownGlobals.CameraBitmask)
invBitmask.invertInPlace()
bitmask &= invBitmask
node.setIntoCollideMask(bitmask)
shaft = model.find('**/shaft')
shaft.setScale(self.shaftScale)
head.setScale(self.headScale)
model.find('**/shaft').node().setPreserveTransform(0)
model.flattenLight()
self.model = model
if self.motion == MotionSwitched:
self.model.setPos(0, -self.range, 0)
self.model.reparentTo(self.rotateNode)
if self.wantSmoke:
self.smoke = loader.loadModel('phase_4/models/props/test_clouds')
self.smoke.setColor(0.8, 0.7, 0.5, 1)
self.smoke.setBillboardPointEye()
return
def stashCrushSurface(self, isStunned):
self.notify.debug('stashCrushSurface(%s)' % isStunned)
if self.crushSurface and not self.crushSurface.isEmpty():
if isStunned:
self.crushSurface.stash()
else:
self.crushSurface.unstash()
def unloadModel(self):
if self.ival:
self.ival.pause()
del self.ival
self.ival = None
if self.smoke:
self.smoke.removeNode()
del self.smoke
self.smoke = None
if self.shadow:
self.shadow.removeNode()
del self.shadow
self.shadow = None
if self.model:
if isinstance(self.model, MovingPlatform.MovingPlatform):
self.model.destroy()
else:
self.model.removeNode()
del self.model
self.model = None
return
def sendStompToon(self):
messenger.send(self.crushMsg)
def doCrush(self):
self.notify.debug('doCrush, crushedList = %s' % self.crushedList)
for crushableId in self.crushedList:
crushable = self.level.entities.get(crushableId)
if crushable:
if self.style == 'vertical':
axis = 2
else:
axis = 0
crushable.playCrushMovie(self.entId, axis)
self.crushedList = []
def getMotionIval(self, mode = STOMPER_START):
if self.range == 0.0:
return (None, 0)
wantSound = self.soundOn
if self.motion is MotionLinear:
motionIval = Sequence(LerpPosInterval(self.model, self.period / 2.0, Point3(0, -self.range, 0), startPos=Point3(0, 0, 0), fluid=1), WaitInterval(self.period / 4.0), LerpPosInterval(self.model, self.period / 4.0, Point3(0, 0, 0), startPos=Point3(0, -self.range, 0), fluid=1))
elif self.motion is MotionSinus:
def sinusFunc(t, self = self):
theta = math.pi + t * 2.0 * math.pi
c = math.cos(theta)
self.model.setFluidY((0.5 + c * 0.5) * -self.range)
motionIval = Sequence(LerpFunctionInterval(sinusFunc, duration=self.period))
elif self.motion is MotionSlowFast:
def motionFunc(t, self = self):
stickTime = 0.2
turnaround = 0.95
t = t % 1
if t < stickTime:
self.model.setFluidY(0)
elif t < turnaround:
self.model.setFluidY((t - stickTime) * -self.range / (turnaround - stickTime))
elif t > turnaround:
self.model.setFluidY(-self.range + (t - turnaround) * self.range / (1 - turnaround))
motionIval = Sequence(LerpFunctionInterval(motionFunc, duration=self.period))
elif self.motion is MotionCrush:
def motionFunc(t, self = self):
stickTime = 0.2
pauseAtTopTime = 0.5
turnaround = 0.85
t = t % 1
if t < stickTime:
self.model.setFluidY(0)
elif t <= turnaround - pauseAtTopTime:
self.model.setFluidY((t - stickTime) * -self.range / (turnaround - pauseAtTopTime - stickTime))
elif t > turnaround - pauseAtTopTime and t <= turnaround:
self.model.setFluidY(-self.range)
elif t > turnaround:
self.model.setFluidY(-self.range + (t - turnaround) * self.range / (1 - turnaround))
tStick = 0.2 * self.period
tUp = 0.45 * self.period
tPause = 0.2 * self.period
tDown = 0.15 * self.period
motionIval = Sequence(Wait(tStick), LerpPosInterval(self.model, tUp, Vec3(0, -self.range, 0), blendType='easeInOut', fluid=1), Wait(tPause), Func(self.doCrush), LerpPosInterval(self.model, tDown, Vec3(0, 0, 0), blendType='easeInOut', fluid=1))
elif self.motion is MotionSwitched:
if mode == STOMPER_STOMP:
motionIval = Sequence(Func(self.doCrush), LerpPosInterval(self.model, 0.35, Vec3(0, 0, 0), blendType='easeInOut', fluid=1))
elif mode == STOMPER_RISE:
motionIval = Sequence(LerpPosInterval(self.model, 0.5, Vec3(0, -self.range, 0), blendType='easeInOut', fluid=1))
wantSound = 0
else:
motionIval = None
else:
def halfSinusFunc(t, self = self):
self.model.setFluidY(math.sin(t * math.pi) * -self.range)
motionIval = Sequence(LerpFunctionInterval(halfSinusFunc, duration=self.period))
return (motionIval, wantSound)
def startStomper(self, startTime, mode = STOMPER_START):
if self.ival:
self.ival.pause()
del self.ival
self.ival = None
motionIval, wantSound = self.getMotionIval(mode)
if motionIval == None:
return
self.ival = Parallel(Sequence(motionIval, Func(self.__startSmokeTask), Func(self.sendStompToon)), name=self.uniqueName('Stomper'))
if wantSound:
sndDur = motionIval.getDuration()
self.ival.append(Sequence(Wait(sndDur), Func(base.playSfx, self.sound, node=self.model, volume=0.45)))
if self.shadow is not None and self.animateShadow:
def adjustShadowScale(t, self = self):
modelY = self.model.getY()
maxHeight = 10
a = min(-modelY / maxHeight, 1.0)
self.shadow.setScale(lerp(1, 0.2, a))
self.shadow.setAlphaScale(lerp(1, 0.2, a))
self.ival.append(LerpFunctionInterval(adjustShadowScale, duration=self.period))
if mode == STOMPER_START:
self.ival.loop()
self.ival.setT(globalClock.getFrameTime() - self.level.startTime + self.period * self.phaseShift)
else:
self.ival.start(startTime)
return
def stopStomper(self):
if self.ival:
self.ival.pause()
if self.smokeTrack:
self.smokeTrack.finish()
del self.smokeTrack
self.smokeTrack = None
return
def setMovie(self, mode, timestamp, crushedList):
self.notify.debug('setMovie %d' % mode)
timestamp = ClockDelta.globalClockDelta.networkToLocalTime(timestamp)
now = globalClock.getFrameTime()
if mode == STOMPER_START or mode == STOMPER_RISE or mode == STOMPER_STOMP:
self.crushedList = crushedList
self.startStomper(timestamp, mode)
def __startSmokeTask(self):
taskMgr.remove(self.taskName('smokeTask'))
if self.wantSmoke:
taskMgr.add(self.__smokeTask, self.taskName('smokeTask'))
def __smokeTask(self, task):
self.smoke.reparentTo(self)
self.smoke.setScale(1)
if self.smokeTrack:
self.smokeTrack.finish()
del self.smokeTrack
self.smokeTrack = Sequence(Parallel(LerpScaleInterval(self.smoke, 0.2, Point3(4, 1, 4)), LerpColorScaleInterval(self.smoke, 1, Vec4(1, 1, 1, 0))), Func(self.smoke.reparentTo, hidden), Func(self.smoke.clearColorScale))
self.smokeTrack.start()
return Task.done
def checkSquashedToon(self):
if self.style == 'vertical':
tPos = base.localAvatar.getPos(self.rotateNode)
zRange = self.headScale[2]
xRange = self.headScale[0]
yRange = 5
if tPos[2] < zRange and tPos[2] > -zRange and tPos[0] < xRange and tPos[0] > -xRange and tPos[1] < yRange / 10.0 and tPos[1] > -yRange:
self.level.b_setOuch(self.damage, 'Squish')
base.localAvatar.setZ(self.getZ(render) + 0.025)