/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation This program 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ 609 %{ #include "StdH.h" #include "Models/CutSequences/SpaceShip/SpaceShip.h" #include "Models/CutSequences/SpaceShip/Door.h" #include "Models/CutSequences/SpaceShip/LightBeam.h" #include "EntitiesMP/Effector.h" #include "EntitiesMP/Light.h" %} uses "EntitiesMP/PyramidSpaceShipMarker"; enum PSSState { 0 PSSS_IDLE "Idle", // idle 1 PSSS_MOVING "Moving", // process of moving trough markers 2 PSSS_REACHED_DESTINATION "Reached destination", // process of turning on 3 PSSS_KILLING_BEAM_FIREING "Killing beam fireing", // killing beam fireing 4 PSSS_BEAM_DEACTIVATED "Killing beam deactivated", // killing beam gas been deactivated, wait to pick up Sam 5 PSSS_DOORS_CLOSED "Doors closed", // doors closed }; event EForcePathMarker { CEntityPointer penForcedPathMarker, }; %{ #define STRETCH_X (200.0f*m_fStretch) #define STRETCH_Y (100.0f*m_fStretch) #define STRETCH_Z (200.0f*m_fStretch) #define PSS_STRETCH (FLOAT3D(STRETCH_X, STRETCH_Y, STRETCH_Z)*m_fStretch) #define SND_FALLOFF 1000.0f #define SND_HOTSPOT 250.0f #define SND_VOLUME 2.0f #define BIG_LIGHT_BEAM_LIFE_TIME (8.0f) #define SMALL_FLARE_WAIT 2.0f #define SMALL_FLARES_LIFE_TIME (BIG_LIGHT_BEAM_LIFE_TIME+SMALL_FLARE_WAIT) #define SMALL_LIGHTNING_WAIT 1.5f #define SMALL_LIGHTININGS_LIFE_TIME (SMALL_FLARES_LIFE_TIME+SMALL_LIGHTNING_WAIT) #define BIG_FLARE_WAIT 1.0f #define BIG_FLARE_LIFE_TIME (SMALL_LIGHTININGS_LIFE_TIME+BIG_FLARE_WAIT) #define BM_DX (0.414657f*STRETCH_X) #define BM_DY (-1.72731f*STRETCH_Y) #define BM_DZ (0.414657f*STRETCH_Z) #define BM_FLARE_DY (-0.25f*STRETCH_Y) #define BM_MASTER_Y (-1.76648f*STRETCH_Y) %} class CPyramidSpaceShip: CMovableModelEntity { name "PyramidSpaceShip"; thumbnail "Thumbnails\\PyramidSpaceShip.tbn"; features "HasName", "IsTargetable"; properties: 1 CTString m_strName "Name" 'N' = "Pyramid Space Ship", // name 3 FLOAT m_fMovingSpeed = 0.0f, // current speed 5 CEntityPointer m_penBeamHit "Beam hit target marker" 'T', // target point for light beam 6 CEntityPointer m_penLightBeam "Beam model holder" 'B', // light beam model holder 7 FLOAT m_tmBeamTime =-1.0f, // light beam time var 8 CEntityPointer m_penHitPlaceFlare "Hit place flare" 'H', // hit place model holder 9 FLOAT m_tmHitFlareTime =-1.0f, // light beam hit flare time var 10 FLOAT m_iRingCounter = 0, // ring counter 11 FLOAT m_fRatio =0.0f, // misc ratio 12 CTString m_strDescription = "", // description 13 enum PSSState m_epssState = PSSS_IDLE, // current state 14 FLOAT m_fStretch "Stretch" 'S' = 1.0f, // stretch factor // path properties 20 BOOL m_bStopMoving = FALSE, // stop moving on next marker 21 CEntityPointer m_penTarget "Target" 'T' COLOR(C_lBLUE|0xFF), // next path target 29 CEntityPointer m_penFlyAwayTarget "Fly away path marker" COLOR(C_lBLUE|0xFF), // fly away path marker 22 CEntityPointer m_penLast, // previous marker 23 BOOL m_bMoving = FALSE, // set while moving 24 FLOAT m_fRot = 0.0f, // current rotation 25 FLOAT m_fLastRotSpeed = 0.0f, // last speed rotation 26 FLOAT m_fRotSpeed = 0.0f, // current speed rotation 27 BOOL m_bApplyDamageToHitted = TRUE, // if damage should be applied 28 FLOAT m_tmTemp = 0.0f, // temporary time var 30 FLOAT m_tmAtMarker = 0.0f, // time when current marker was reached 31 FLOAT m_tmDelta = 0.0f, // time to reach next marker 32 FLOAT3D m_vPNp0 = FLOAT3D(0,0,0), 33 FLOAT3D m_vPNp1 = FLOAT3D(0,0,0), 34 FLOAT3D m_vTNp0 = FLOAT3D(0,0,0), 35 FLOAT3D m_vTNp1 = FLOAT3D(0,0,0), 36 FLOATquat3D m_qPNp0 = FLOATquat3D(0,0,0,0), 37 FLOATquat3D m_qPNp1 = FLOATquat3D(0,0,0,0), 38 FLOATquat3D m_qANp0 = FLOATquat3D(0,0,0,0), 39 FLOATquat3D m_qANp1 = FLOATquat3D(0,0,0,0), 40 FLOAT m_fRotSpeedp0 = 0.0f, 41 FLOAT m_fRotSpeedp1 = 0.0f, 42 FLOAT m_fTRotSpeedp0 = 0.0f, 43 FLOAT m_fTRotSpeedp1 = 0.0f, 50 CSoundObject m_soPlates, 51 CSoundObject m_soBeamMachine, 52 CSoundObject m_soBeam, 53 CSoundObject m_soFlaresFX, 54 BOOL m_bFireingDeactivatedBeam=FALSE, 55 BOOL m_bImmediateAnimations=FALSE, 56 FLOAT m_fWaitAfterKillingBeam "Wait after auto killing beam" 'W' = 1.0f, 60 BOOL m_bInvisible "Invisible" 'I' = FALSE, components: 1 model MODEL_SPACESHIP "Models\\CutSequences\\SpaceShip\\SpaceShip.mdl", 2 model MODEL_BODY "Models\\CutSequences\\SpaceShip\\Body.mdl", 3 texture TEXTURE_BODY "Models\\CutSequences\\SpaceShip\\Body.tex", 4 model MODEL_DOOR "Models\\CutSequences\\SpaceShip\\Door.mdl", 5 texture TEXTURE_DOOR "Models\\CutSequences\\SpaceShip\\Door.tex", 6 model MODEL_BEAMMACHINE "Models\\CutSequences\\SpaceShip\\BeamMachine.mdl", 7 texture TEXTURE_BEAMMACHINE "Models\\CutSequences\\SpaceShip\\BeamMachine.tex", 8 model MODEL_BEAMRIM "Models\\CutSequences\\SpaceShip\\BeamMachineRim.mdl", 9 texture TEXTURE_BEAMRIM "Models\\CutSequences\\SpaceShip\\BeamMachineRim.tex", 10 class CLASS_EFFECTOR "Classes\\Effector.ecl", 11 model MODEL_SHIP_INSIDE "Models\\CutSequences\\SpaceShip\\Fillin.mdl", 20 sound SOUND_PLATES "Sounds\\CutSequences\\SpaceShip\\SSPlates.wav", 21 sound SOUND_BEAMMACHINE "Sounds\\CutSequences\\SpaceShip\\SSProbe.wav", 22 sound SOUND_BEAM "Sounds\\CutSequences\\SpaceShip\\LaserBeam.wav", 23 sound SOUND_WARMUP "Sounds\\CutSequences\\SpaceShip\\Warmup.wav", functions: void Precache(void) { PrecacheModel (MODEL_SPACESHIP ); PrecacheModel (MODEL_BODY ); PrecacheTexture (TEXTURE_BODY ); PrecacheModel (MODEL_DOOR ); PrecacheTexture (TEXTURE_DOOR ); PrecacheModel (MODEL_BEAMMACHINE ); PrecacheTexture (TEXTURE_BEAMMACHINE ); PrecacheModel (MODEL_BEAMRIM ); PrecacheModel (MODEL_SHIP_INSIDE ); PrecacheTexture (TEXTURE_BEAMRIM ); PrecacheClass (CLASS_EFFECTOR, ET_SIZING_RING_FLARE); PrecacheClass (CLASS_EFFECTOR, ET_SIZING_BIG_BLUE_FLARE); PrecacheClass (CLASS_EFFECTOR, ET_LIGHTNING); PrecacheClass (CLASS_EFFECTOR, ET_MOVING_RING); PrecacheSound (SOUND_PLATES ); PrecacheSound (SOUND_BEAMMACHINE ); PrecacheSound (SOUND_BEAM ); PrecacheSound (SOUND_WARMUP ); } BOOL IsTargetValid(SLONG slPropertyOffset, CEntity *penTarget) { if(penTarget==NULL) { return FALSE; } if( slPropertyOffset==offsetof(CPyramidSpaceShip, m_penTarget) || slPropertyOffset==offsetof(CPyramidSpaceShip, m_penFlyAwayTarget)) { return( IsDerivedFromClass(penTarget, "Pyramid Space Ship Marker")); } return TRUE; } // Check if entity is moved on a route set up by its targets BOOL MovesByTargetedRoute( CTString &strTargetProperty) const { strTargetProperty = "Target"; return TRUE; } /* Check if entity can drop marker for making linked route. */ BOOL DropsMarker( CTFileName &fnmMarkerClass, CTString &strTargetProperty) const { fnmMarkerClass = CTFILENAME("Classes\\PyramidSpaceShipMarker.ecl"); strTargetProperty = "Target"; return TRUE; } // returns description const CTString &GetDescription(void) const { if (m_penTarget!=NULL) { ((CTString&)m_strDescription).PrintF("->%s", m_penTarget->GetName()); } else { ((CTString&)m_strDescription).PrintF("->"); } return m_strDescription; } CPlacement3D GetLerpedPlacement(void) const { return CMovableEntity::GetLerpedPlacement(); } void PreMoving() { // remember old placement for lerping en_plLastPlacement = en_plPlacement; } void HideBeamMachine(void) { if(GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_BEAM_RIM) != NULL) { RemoveAttachment(SPACESHIP_ATTACHMENT_BEAM_RIM); } if(GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_BEAM) != NULL) { RemoveAttachment(SPACESHIP_ATTACHMENT_BEAM); } } void ShowBeamMachine(void) { AddAttachment(SPACESHIP_ATTACHMENT_BEAM_RIM, MODEL_BEAMRIM, TEXTURE_BEAMRIM); AddAttachment(SPACESHIP_ATTACHMENT_BEAM, MODEL_BEAMMACHINE, TEXTURE_BEAMMACHINE); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_BEAM_RIM)->amo_moModelObject.StretchModel(PSS_STRETCH); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_BEAM)->amo_moModelObject.StretchModel(PSS_STRETCH); } void InitializePathMoving( CPyramidSpaceShipMarker *penStartMarker) { // set as current m_penTarget = penStartMarker; m_epssState = PSSS_MOVING; // check all markers for correct type and numbers INDEX ctMarkers=1; CPyramidSpaceShipMarker *pcm0 = (CPyramidSpaceShipMarker*)&*m_penTarget; if( pcm0 == NULL) { return; } CPyramidSpaceShipMarker *pcm = (CPyramidSpaceShipMarker*)&*pcm0->m_penTarget; // loop thru markers while( pcm!=NULL && pcm->m_penTarget!=pcm0) { pcm = (CPyramidSpaceShipMarker*)&*pcm->m_penTarget; if (pcm==NULL) { WarningMessage( "Space ship path - broken link!"); return; } ctMarkers++; if (ctMarkers>500) { WarningMessage( "Space ship path - invalid marker loop!"); return; } } // check if we have enough markers to do smooth interpolation if( ctMarkers<2) { WarningMessage( "Space ship path requires at least 2 markers in order to work!"); return; } // prepare internal variables FLOAT tmCurrent = _pTimer->CurrentTick(); m_tmAtMarker = tmCurrent; m_tmDelta = 0.0f; m_bStopMoving = FALSE; m_penLast = pcm; // keep last marker ASSERT( pcm->m_penTarget == m_penTarget); m_bMoving = TRUE; AddToMovers(); } void DoMoving() { if (!m_bMoving) { return; } // read current tick FLOAT tmCurrent = _pTimer->CurrentTick(); // lerping is initially enabled BOOL bLerping = TRUE; // if we hit a marker if( tmCurrent > (m_tmAtMarker+m_tmDelta - _pTimer->TickQuantum*3/2)) { // get markers CPyramidSpaceShipMarker *pcmNm1 = &(CPyramidSpaceShipMarker&)*m_penLast; CPyramidSpaceShipMarker *pcmNp0 = &(CPyramidSpaceShipMarker&)*m_penTarget; CPyramidSpaceShipMarker *pcmNp1 = &(CPyramidSpaceShipMarker&)*pcmNp0->m_penTarget; CPyramidSpaceShipMarker *pcmNp2 = &(CPyramidSpaceShipMarker&)*pcmNp1->m_penTarget; // if there is a trigger at the hit marker if (pcmNp0->m_penTrigger!=NULL) { // trigger it SendToTarget(pcmNp0->m_penTrigger, EET_TRIGGER, NULL); } // update markers for next interval m_penTarget = pcmNp1; m_penLast = pcmNp0; // get markers CPyramidSpaceShipMarker &cmNm1 = *pcmNm1; CPyramidSpaceShipMarker &cmNp0 = *pcmNp0; CPyramidSpaceShipMarker &cmNp1 = *pcmNp1; CPyramidSpaceShipMarker &cmNp2 = *pcmNp2; // get positions from four markers const FLOAT3D &vPNm1 = cmNm1.GetPlacement().pl_PositionVector; const FLOAT3D &vPNp0 = cmNp0.GetPlacement().pl_PositionVector; const FLOAT3D &vPNp1 = cmNp1.GetPlacement().pl_PositionVector; const FLOAT3D &vPNp2 = cmNp2.GetPlacement().pl_PositionVector; ANGLE3D aPNm1 = cmNm1.GetPlacement().pl_OrientationAngle; ANGLE3D aPNp0 = cmNp0.GetPlacement().pl_OrientationAngle; ANGLE3D aPNp1 = cmNp1.GetPlacement().pl_OrientationAngle; ANGLE3D aPNp2 = cmNp2.GetPlacement().pl_OrientationAngle; FLOAT fRotSpeedm1 = cmNm1.m_fRotSpeed; FLOAT fRotSpeedp0 = cmNp0.m_fRotSpeed; FLOAT fRotSpeedp1 = cmNp1.m_fRotSpeed; FLOAT fRotSpeedp2 = cmNp2.m_fRotSpeed; // find quaternions for rotations FLOATquat3D qPNm1; qPNm1.FromEuler(aPNm1); FLOATquat3D qPNp0; qPNp0.FromEuler(aPNp0); FLOATquat3D qPNp1; qPNp1.FromEuler(aPNp1); FLOATquat3D qPNp2; qPNp2.FromEuler(aPNp2); // make all angles between quaternion pairs acute if( qPNm1%qPNp0<0 ) { qPNp0 = -qPNp0; } if( qPNp0%qPNp1<0 ) { qPNp1 = -qPNp1; } if( qPNp1%qPNp2<0 ) { qPNp2 = -qPNp2; } // update time and position m_tmAtMarker = m_tmAtMarker+m_tmDelta; m_tmDelta = cmNp0.m_fDeltaTime; m_vPNp0 = vPNp0; m_vPNp1 = vPNp1; m_fRotSpeedp0 = fRotSpeedp0; m_fRotSpeedp1 = fRotSpeedp1; m_qPNp0 = qPNp0; m_qPNp1 = qPNp1; // determine delta time multipliers FLOAT tmDNm1 = cmNm1.m_fDeltaTime; FLOAT tmDNp0 = cmNp0.m_fDeltaTime; FLOAT tmDNp1 = cmNp1.m_fDeltaTime; FLOAT fD0 = 2*tmDNp0 / (tmDNm1+tmDNp0); FLOAT fD1 = 2*tmDNp0 / (tmDNp0+tmDNp1); // determine biases, tensions and continuities FLOAT fBNp0 = cmNp0.m_fBias; FLOAT fTNp0 = cmNp0.m_fTension; FLOAT fCNp0 = cmNp0.m_fContinuity; FLOAT fBNp1 = cmNp1.m_fBias; FLOAT fTNp1 = cmNp1.m_fTension; FLOAT fCNp1 = cmNp1.m_fContinuity; FLOAT fF00 = (1-fTNp0)*(1-fCNp0)*(1-fBNp0) / 2; FLOAT fF01 = (1-fTNp0)*(1+fCNp0)*(1+fBNp0) / 2; FLOAT fF10 = (1-fTNp1)*(1+fCNp1)*(1-fBNp1) / 2; FLOAT fF11 = (1-fTNp1)*(1-fCNp1)*(1+fBNp1) / 2; // find tangents for translation m_vTNp0 = ( (vPNp1-vPNp0) * fF00 + (vPNp0-vPNm1) * fF01) * fD0; m_vTNp1 = ( (vPNp2-vPNp1) * fF10 + (vPNp1-vPNp0) * fF11) * fD1; // find tangents for moving speed m_fTRotSpeedp0 = ( (fRotSpeedp1-fRotSpeedp0) * fF00 + (fRotSpeedp0-fRotSpeedm1) * fF01) * fD0; m_fTRotSpeedp1 = ( (fRotSpeedp2-fRotSpeedp1) * fF10 + (fRotSpeedp1-fRotSpeedp0) * fF11) * fD1; // find tangents for rotation FLOATquat3D qTNp0, qTNp1; qTNp0 = ( Log(qPNp0.Inv()*qPNp1) * fF00 + Log(qPNm1.Inv()*qPNp0) * fF01) * fD0; qTNp1 = ( Log(qPNp1.Inv()*qPNp2) * fF10 + Log(qPNp0.Inv()*qPNp1) * fF11) * fD1; // find squad parameters m_qANp0 = qPNp0*Exp( (qTNp0 - Log(qPNp0.Inv()*qPNp1))/2 ); m_qANp1 = qPNp1*Exp( (Log(qPNp0.Inv()*qPNp1) - qTNp1)/2 ); // check for stop moving if( cmNp0.m_bStopMoving && m_fRotSpeed==0.0f) { m_bStopMoving = TRUE; } } // calculate the parameter value and hermit basis FLOAT fT = (tmCurrent - m_tmAtMarker) / m_tmDelta; FLOAT fH0 = 2*fT*fT*fT - 3*fT*fT + 1; FLOAT fH1 = -2*fT*fT*fT + 3*fT*fT; FLOAT fH2 = fT*fT*fT - 2*fT*fT + fT; FLOAT fH3 = fT*fT*fT - fT*fT; // interpolate position, rotation and fov FLOAT3D vPos = m_vPNp0*fH0 + m_vPNp1*fH1 + m_vTNp0*fH2 + m_vTNp1*fH3; FLOAT fRotSpeed = m_fRotSpeedp0*fH0 + m_fRotSpeedp1*fH1 + m_fTRotSpeedp0*fH2 + m_fTRotSpeedp1*fH3; FLOATquat3D qRot = Squad(fT, m_qPNp0, m_qPNp1, m_qANp0, m_qANp1); FLOATmatrix3D mRotLocal; MakeRotationMatrixFast(mRotLocal, ANGLE3D(m_fRot,0,0)); FLOATmatrix3D mRot; qRot.ToMatrix(mRot); mRot = mRotLocal*mRot; // just cache near polygons for various engine needs en_vNextPosition = vPos; en_mNextRotation = mRot; CacheNearPolygons(); // set new placement CPlacement3D plNew; plNew.pl_PositionVector = vPos; DecomposeRotationMatrixNoSnap(plNew.pl_OrientationAngle, mRot); SetPlacement_internal(plNew, mRot, TRUE); // if lerping is disabled if (!bLerping) { // make last placement same as this one en_plLastPlacement = en_plPlacement; } // set new speed m_fLastRotSpeed = m_fRotSpeed; m_fRotSpeed = fRotSpeed; m_fRot += m_fRotSpeed; } void PostMoving() { if (!m_bMoving) { return; } // remember new position for particles if (en_plpLastPositions!=NULL) { en_plpLastPositions->AddPosition(en_vNextPosition); } // if( m_bStopMoving) { m_bMoving = FALSE; // mark for removing from list of movers en_ulFlags |= ENF_INRENDERING; m_epssState = PSSS_REACHED_DESTINATION; // remember old placement for lerping en_plLastPlacement = en_plPlacement; } } void SpawnBeamMachineFlares(void) { // spawn small beam machine flares CPlacement3D plSpaceShip = GetPlacement(); CPlacement3D plFlare1 = CPlacement3D( FLOAT3D( BM_DX, BM_DY+BM_FLARE_DY, 0), ANGLE3D(0,0,0)); CPlacement3D plFlare2 = CPlacement3D( FLOAT3D( 0, BM_DY+BM_FLARE_DY, -BM_DZ), ANGLE3D(0,0,0)); CPlacement3D plFlare3 = CPlacement3D( FLOAT3D( -BM_DX, BM_DY+BM_FLARE_DY, 0), ANGLE3D(0,0,0)); CPlacement3D plFlare4 = CPlacement3D( FLOAT3D( 0, BM_DY+BM_FLARE_DY, BM_DZ), ANGLE3D(0,0,0)); plFlare1.RelativeToAbsolute(plSpaceShip); plFlare2.RelativeToAbsolute(plSpaceShip); plFlare3.RelativeToAbsolute(plSpaceShip); plFlare4.RelativeToAbsolute(plSpaceShip); CEntity *penFlare1 = CreateEntity( plFlare1, CLASS_EFFECTOR); CEntity *penFlare2 = CreateEntity( plFlare2, CLASS_EFFECTOR); CEntity *penFlare3 = CreateEntity( plFlare3, CLASS_EFFECTOR); CEntity *penFlare4 = CreateEntity( plFlare4, CLASS_EFFECTOR); ESpawnEffector eSpawnFlare; eSpawnFlare.tmLifeTime = SMALL_FLARES_LIFE_TIME; eSpawnFlare.tmLifeTime = 10.5f; eSpawnFlare.eetType = ET_SIZING_RING_FLARE; penFlare1->Initialize( eSpawnFlare); penFlare2->Initialize( eSpawnFlare); penFlare3->Initialize( eSpawnFlare); penFlare4->Initialize( eSpawnFlare); } void SpawnBeamMachineMainFlare(void) { // spawn main flare CPlacement3D plSpaceShip = GetPlacement(); CPlacement3D plFlare = CPlacement3D( FLOAT3D(0, BM_MASTER_Y+BM_FLARE_DY, 0), ANGLE3D(0,0,0)); plFlare.RelativeToAbsolute(GetPlacement()); CEntity *penFlare = CreateEntity( plFlare, CLASS_EFFECTOR); ESpawnEffector eSpawnFlare; eSpawnFlare.tmLifeTime = 20.0f; eSpawnFlare.fSize = 1.0f; eSpawnFlare.eetType = ET_SIZING_BIG_BLUE_FLARE; penFlare->Initialize( eSpawnFlare); } void ShowBeamMachineHitFlare(void) { if( m_penHitPlaceFlare!=NULL && IsOfClass(m_penHitPlaceFlare, "ModelHolder2") ) { CModelObject *pmo = m_penHitPlaceFlare->GetModelObject(); if( pmo != NULL) { m_penHitPlaceFlare->SwitchToModel(); } } } void HideBeamMachineHitFlare(void) { m_tmHitFlareTime = -1; if( m_penHitPlaceFlare!=NULL && IsOfClass(m_penHitPlaceFlare, "ModelHolder2") ) { CModelObject *pmo = m_penHitPlaceFlare->GetModelObject(); if( pmo != NULL) { m_penHitPlaceFlare->SwitchToEditorModel(); pmo->mo_colBlendColor = C_WHITE|CT_OPAQUE; } } } void SpawnBeamMachineLightnings(void) { // spawn beam lightnings CPlacement3D plLightning1 = CPlacement3D( FLOAT3D(BM_DX, BM_DY, 0), ANGLE3D(0,0,0)); CPlacement3D plLightning2 = CPlacement3D( FLOAT3D(0, BM_DY, -BM_DZ), ANGLE3D(0,0,0)); CPlacement3D plLightning3 = CPlacement3D( FLOAT3D(-BM_DX, BM_DY, 0), ANGLE3D(0,0,0)); CPlacement3D plLightning4 = CPlacement3D( FLOAT3D(0, BM_DY, BM_DZ), ANGLE3D(0,0,0)); CPlacement3D plLightningDest = CPlacement3D( FLOAT3D(0, BM_MASTER_Y, 0), ANGLE3D(0,0,0)); CPlacement3D plSpaceShip = GetPlacement(); plLightningDest.RelativeToAbsolute(plSpaceShip); plLightning1.RelativeToAbsolute(plSpaceShip); plLightning2.RelativeToAbsolute(plSpaceShip); plLightning3.RelativeToAbsolute(plSpaceShip); plLightning4.RelativeToAbsolute(plSpaceShip); CEntity *penLightning1 = CreateEntity( plLightning1, CLASS_EFFECTOR); CEntity *penLightning2 = CreateEntity( plLightning2, CLASS_EFFECTOR); CEntity *penLightning3 = CreateEntity( plLightning3, CLASS_EFFECTOR); CEntity *penLightning4 = CreateEntity( plLightning4, CLASS_EFFECTOR); ESpawnEffector eSpawnLightning; eSpawnLightning.eetType = ET_LIGHTNING; eSpawnLightning.tmLifeTime = SMALL_LIGHTININGS_LIFE_TIME; eSpawnLightning.vDestination = plLightningDest.pl_PositionVector; eSpawnLightning.fSize = 16.0f; eSpawnLightning.ctCount = 16; penLightning1->Initialize( eSpawnLightning); penLightning2->Initialize( eSpawnLightning); penLightning3->Initialize( eSpawnLightning); penLightning4->Initialize( eSpawnLightning); } void SpawnBeamMachineMainLightning(void) { // spawn main lightning FLOAT3D vDestination = GetPlacement().pl_PositionVector + FLOAT3D( 0, BM_MASTER_Y, 0); CPlacement3D plSource = CPlacement3D( vDestination, ANGLE3D(0,0,0)); if( m_penBeamHit != NULL) { plSource.pl_PositionVector = m_penBeamHit->GetPlacement().pl_PositionVector; CEntity *penEffector = CreateEntity( plSource, CLASS_EFFECTOR); ESpawnEffector eSpawnEffector; eSpawnEffector.eetType = ET_LIGHTNING; eSpawnEffector.tmLifeTime = BIG_LIGHT_BEAM_LIFE_TIME; eSpawnEffector.vDestination = vDestination; eSpawnEffector.fSize = 32.0f; eSpawnEffector.ctCount = 32; penEffector->Initialize( eSpawnEffector); } } void SpawnMovingRing(void) { if( m_penBeamHit != NULL) { FLOAT3D vStart = GetPlacement().pl_PositionVector + FLOAT3D( 0, BM_MASTER_Y, 0); CPlacement3D plSource = CPlacement3D( vStart, ANGLE3D(0,0,0)); FLOAT3D vHitPlace = m_penBeamHit->GetPlacement().pl_PositionVector; CEntity *penEffector = CreateEntity( plSource, CLASS_EFFECTOR); ESpawnEffector eSpawnEffector; eSpawnEffector.eetType = ET_MOVING_RING; eSpawnEffector.tmLifeTime = BIG_LIGHT_BEAM_LIFE_TIME; eSpawnEffector.vDestination = vHitPlace+FLOAT3D(0.0f, 0.0f, 0.0f); eSpawnEffector.fSize = 16.0f; eSpawnEffector.ctCount = 2; penEffector->Initialize( eSpawnEffector); } } void TurnOnLightBeam(void) { if( m_penLightBeam!=NULL && IsOfClass(m_penLightBeam, "ModelHolder2") ) { CModelObject *pmo = m_penLightBeam->GetModelObject(); m_penLightBeam->SwitchToModel(); pmo->mo_colBlendColor = C_WHITE|CT_OPAQUE; } } void TurnOffLightBeam(void) { m_tmBeamTime=-1.0f; if( m_penLightBeam!=NULL && IsOfClass(m_penLightBeam, "ModelHolder2") ) { m_penLightBeam->SwitchToEditorModel(); CModelObject *pmo = m_penLightBeam->GetModelObject(); } } BOOL AdjustShadingParameters(FLOAT3D &vLightDirection, COLOR &colLight, COLOR &colAmbient) { FLOAT fBeamRatio = 1.0f; // light beam if( m_penLightBeam!=NULL && IsOfClass(m_penLightBeam, "ModelHolder2") ) { CModelObject *pmo = m_penLightBeam->GetModelObject(); if( pmo != NULL) { if( m_tmBeamTime>-1.0f) { FLOAT fT = _pTimer->CurrentTick()-m_tmBeamTime; fBeamRatio = 1.0f-ClampUp(fT/2.0f, 1.0f); UBYTE ub = UBYTE (255.0f*fBeamRatio); COLOR col = RGBAToColor(ub,ub,ub,ub); pmo->mo_colBlendColor = col; } } } // hit flare if( m_penHitPlaceFlare!=NULL && IsOfClass(m_penHitPlaceFlare, "ModelHolder2") ) { CModelObject *pmo = m_penHitPlaceFlare->GetModelObject(); if( pmo != NULL) { if( m_tmHitFlareTime>-1.0f) { FLOAT fT = _pTimer->CurrentTick()-m_tmHitFlareTime; FLOAT fRatio = (Sin(fT*2000)*0.5f+0.5f)*(Sin(fT*1333)*0.5f+0.5f); /*if(fRatio>0.5f) { fRatio=0.0f; } else { fRatio=1.0f; }*/ UBYTE ub = UBYTE((200+55*fRatio)*fBeamRatio); //ub = 255; COLOR col = RGBAToColor(ub,ub,ub,ub); pmo->mo_colBlendColor = col; } } } return FALSE; }; procedures: MPIntro() { SwitchToModel(); m_bImmediateAnimations=TRUE; autocall OpenDoors() EReturn; autocall FireLightBeam() EReturn; m_epssState = PSSS_BEAM_DEACTIVATED; autowait(m_fWaitAfterKillingBeam); autocall FireLightBeam() EReturn; m_bImmediateAnimations=FALSE; autocall CloseDoors() EReturn; return EReturn(); } OpenDoors() { // if ship inside not yet added if( GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_SHIPINSIDE) == NULL) { // add it AddAttachment( SPACESHIP_ATTACHMENT_SHIPINSIDE, MODEL_SHIP_INSIDE, TEXTURE_BODY); GetModelObject()->StretchModel(PSS_STRETCH); } ShowBeamMachine(); if( !m_bImmediateAnimations) { PlaySound( m_soPlates, SOUND_PLATES, SOF_3D); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR1)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPENING, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR2)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPENING, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR3)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPENING, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR4)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPENING, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR5)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPENING, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR6)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPENING, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR7)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPENING, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR8)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPENING, 0); } else { GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR1)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPEN, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR2)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPEN, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR3)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPEN, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR4)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPEN, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR5)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPEN, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR6)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPEN, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR7)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPEN, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR8)->amo_moModelObject.PlayAnim(DOOR_ANIM_OPEN, 0); } // all children lights named pulsating should pulsate FOREACHINLIST( CEntity, en_lnInParent, en_lhChildren, iten) { if( IsOfClass(iten, "Light")) { if( iten->GetName() == "Pulsating") { CLight *penLight = (CLight *) &*iten; EChangeAnim eChange; eChange.iLightAnim=3; eChange.bLightLoop=TRUE; penLight->SendEvent(eChange); } else if( iten->GetName() == "Motors") { CLight *penLight = (CLight *) &*iten; EChangeAnim eChange; eChange.iLightAnim=4; eChange.bLightLoop=TRUE; penLight->SendEvent(eChange); } } } m_epssState = PSSS_KILLING_BEAM_FIREING; return EReturn(); } CloseDoors() { m_epssState=PSSS_DOORS_CLOSED; // if ship inside attachment added if( GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_SHIPINSIDE) != NULL) { PlaySound( m_soPlates, SOUND_PLATES, SOF_3D); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR1)->amo_moModelObject.PlayAnim(DOOR_ANIM_CLOSING, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR2)->amo_moModelObject.PlayAnim(DOOR_ANIM_CLOSING, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR3)->amo_moModelObject.PlayAnim(DOOR_ANIM_CLOSING, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR4)->amo_moModelObject.PlayAnim(DOOR_ANIM_CLOSING, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR5)->amo_moModelObject.PlayAnim(DOOR_ANIM_CLOSING, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR6)->amo_moModelObject.PlayAnim(DOOR_ANIM_CLOSING, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR7)->amo_moModelObject.PlayAnim(DOOR_ANIM_CLOSING, 0); GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR8)->amo_moModelObject.PlayAnim(DOOR_ANIM_CLOSING, 0); autowait( GetModelObject()->GetAttachmentModel( SPACESHIP_ATTACHMENT_DOOR1)->amo_moModelObject.GetAnimLength(DOOR_ANIM_CLOSING)); // remove ship inside attachment RemoveAttachment( SPACESHIP_ATTACHMENT_SHIPINSIDE); } HideBeamMachine(); InitializePathMoving( (CPyramidSpaceShipMarker*)&*m_penFlyAwayTarget); return EReturn(); } FireLightBeam() { if(m_epssState==PSSS_DOORS_CLOSED) { return; } if(m_epssState==PSSS_BEAM_DEACTIVATED) { m_bFireingDeactivatedBeam=TRUE; } if( !m_bImmediateAnimations) { PlaySound( m_soBeamMachine, SOUND_BEAMMACHINE, SOF_3D); GetModelObject()->PlayAnim(SPACESHIP_ANIM_OPENING, 0); autowait( GetModelObject()->GetAnimLength(SPACESHIP_ANIM_OPENING)); } else { GetModelObject()->PlayAnim(SPACESHIP_ANIM_OPEN, 0); } if( !m_bImmediateAnimations) { PlaySound( m_soBeamMachine, SOUND_WARMUP, SOF_3D); SpawnBeamMachineFlares(); autowait( SMALL_FLARE_WAIT); } else { SpawnBeamMachineFlares(); } SpawnBeamMachineLightnings(); if( !m_bImmediateAnimations) { autowait( SMALL_LIGHTNING_WAIT); } SpawnBeamMachineMainFlare(); if( !m_bImmediateAnimations) { autowait( BIG_FLARE_WAIT); } // turn on light beam TurnOnLightBeam(); if(!m_bFireingDeactivatedBeam) { SpawnBeamMachineMainLightning(); } m_soBeam.Set3DParameters(SND_FALLOFF, SND_HOTSPOT, SND_VOLUME, 1.0f); PlaySound( m_soBeam, SOUND_BEAM, SOF_3D|SOF_LOOP); ShowBeamMachineHitFlare(); m_tmHitFlareTime = _pTimer->CurrentTick(); m_iRingCounter = 0; while(_pTimer->CurrentTick()CurrentTick(); while( _pTimer->CurrentTick() < m_tmTemp+0.49f) { autowait(_pTimer->TickQuantum); // cast ray for possible damage if( m_penBeamHit != NULL && !m_bFireingDeactivatedBeam) { // cast ray FLOAT3D vSource = GetPlacement().pl_PositionVector + FLOAT3D( 0, BM_MASTER_Y, 0); FLOAT3D vDestination = m_penBeamHit->GetPlacement().pl_PositionVector; CCastRay crRay( this, vSource, vDestination); crRay.cr_bHitTranslucentPortals = FALSE; crRay.cr_bPhysical = FALSE; crRay.cr_ttHitModels = CCastRay::TT_COLLISIONBOX; crRay.cr_fTestR = 16.0f; GetWorld()->CastRay(crRay); // if entity is hit if( crRay.cr_penHit != NULL) { InflictDirectDamage( crRay.cr_penHit, this, DMT_BULLET, 10000.0f/GetGameDamageMultiplier()*_pTimer->TickQuantum/0.5f/16.0f, FLOAT3D(0, 0, 0), (vSource-vDestination).Normalize()); crRay.cr_penHit->SendEvent( EHitBySpaceShipBeam()); } } } } m_tmBeamTime = _pTimer->CurrentTick(); while(_pTimer->CurrentTick()TickQuantum); FLOAT tmNow = _pTimer->CurrentTick(); FLOAT fRatio = CalculateRatio(tmNow, m_tmBeamTime, m_tmBeamTime+2.0f, 0, 1.0f); m_soBeam.Set3DParameters(SND_FALLOFF, SND_HOTSPOT, fRatio*SND_VOLUME, 1.0f); } // turn off light beam TurnOffLightBeam(); HideBeamMachineHitFlare(); // little pause autowait( 2.0f); GetModelObject()->PlayAnim(SPACESHIP_ANIM_CLOSING, 0); PlaySound( m_soBeamMachine, SOUND_BEAMMACHINE, SOF_3D); autowait( GetModelObject()->GetAnimLength(SPACESHIP_ANIM_CLOSING)); m_tmHitFlareTime = -1.0f; m_tmBeamTime = -1.0f; if(m_bFireingDeactivatedBeam) { jump CloseDoors(); } return EReturn(); } Main() { // declare yourself as a model InitAsEditorModel(); //InitAsEditorModel(); SetPhysicsFlags(EPF_MODEL_IMMATERIAL|EPF_MOVABLE); SetCollisionFlags(ECF_MODEL_HOLDER); m_bImmediateAnimations=FALSE; en_fAcceleration = 1e6f; en_fDeceleration = 1e6f; m_soBeam.Set3DParameters(SND_FALLOFF, SND_HOTSPOT, SND_VOLUME, 1.0f); m_soBeamMachine.Set3DParameters(SND_FALLOFF, SND_HOTSPOT, SND_VOLUME/2.0f, 1.0f); m_soPlates.Set3DParameters(SND_FALLOFF, SND_HOTSPOT, SND_VOLUME/2.0f, 1.0f); m_soFlaresFX.Set3DParameters(SND_FALLOFF, SND_HOTSPOT, SND_VOLUME, 1.0f); // set appearance SetModel(MODEL_SPACESHIP); SetModelMainTexture(TEXTURE_BODY); AddAttachment(SPACESHIP_ATTACHMENT_BODY, MODEL_BODY, TEXTURE_BODY); AddAttachment(SPACESHIP_ATTACHMENT_DOOR1, MODEL_DOOR, TEXTURE_DOOR); AddAttachment(SPACESHIP_ATTACHMENT_DOOR2, MODEL_DOOR, TEXTURE_DOOR); AddAttachment(SPACESHIP_ATTACHMENT_DOOR3, MODEL_DOOR, TEXTURE_DOOR); AddAttachment(SPACESHIP_ATTACHMENT_DOOR4, MODEL_DOOR, TEXTURE_DOOR); AddAttachment(SPACESHIP_ATTACHMENT_DOOR5, MODEL_DOOR, TEXTURE_DOOR); AddAttachment(SPACESHIP_ATTACHMENT_DOOR6, MODEL_DOOR, TEXTURE_DOOR); AddAttachment(SPACESHIP_ATTACHMENT_DOOR7, MODEL_DOOR, TEXTURE_DOOR); AddAttachment(SPACESHIP_ATTACHMENT_DOOR8, MODEL_DOOR, TEXTURE_DOOR); GetModelObject()->StretchModel(PSS_STRETCH); ModelChangeNotify(); m_bMoving = FALSE; m_epssState = PSSS_IDLE; m_bFireingDeactivatedBeam=FALSE; autowait( 0.25f); // turn off light beam TurnOffLightBeam(); // turn off light beam hit flare HideBeamMachineHitFlare(); // start moving wait() { on( EActivate): { if( !m_bInvisible) { SwitchToModel(); } InitializePathMoving((CPyramidSpaceShipMarker*)&*m_penTarget); resume; } on( ETrigger): { if(m_epssState == PSSS_IDLE) { // ignore all triggs } else if( m_epssState==PSSS_KILLING_BEAM_FIREING) { call FireLightBeam(); } else if(m_epssState==PSSS_BEAM_DEACTIVATED) { call FireLightBeam(); } else if(m_epssState == PSSS_REACHED_DESTINATION) { call OpenDoors(); } resume; } on (EForcePathMarker eForcePathMarker): { if(m_epssState != PSSS_IDLE) { m_penTarget = eForcePathMarker.penForcedPathMarker; InitializePathMoving((CPyramidSpaceShipMarker*)&*m_penTarget); } resume; } on( EEnvironmentStart): { call MPIntro(); resume; } on( EEnvironmentStop): { m_bMoving = FALSE; PostMoving(); resume; } on( EDeactivate): { m_epssState = PSSS_BEAM_DEACTIVATED; resume; } on( EReturn): { resume; } } Destroy(); return; } };