mirror of
https://github.com/ptitSeb/Serious-Engine
synced 2024-12-25 07:14:50 +01:00
353 lines
9.7 KiB
C++
353 lines
9.7 KiB
C++
/* 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. */
|
|
|
|
103
|
|
%{
|
|
#include "StdH.h"
|
|
%}
|
|
|
|
uses "EntitiesMP/ShipMarker";
|
|
|
|
event EHarbor {
|
|
};
|
|
|
|
%{
|
|
|
|
// adjust angular velocity
|
|
ANGLE AdjustRotationSpeed(ANGLE aDiference, ANGLE aMaxSpeed)
|
|
{
|
|
aDiference = NormalizeAngle(aDiference);
|
|
aDiference = Clamp(aDiference, -aMaxSpeed, +aMaxSpeed);
|
|
return aDiference;
|
|
}
|
|
|
|
%}
|
|
|
|
class CShip : CMovableBrushEntity {
|
|
name "Ship";
|
|
thumbnail "Thumbnails\\Ship.tbn";
|
|
features "HasName", "IsTargetable";
|
|
|
|
properties:
|
|
1 CTString m_strName "Name" 'N' = "Ship",
|
|
2 CTString m_strDescription = "",
|
|
|
|
3 CEntityPointer m_penTarget "Target" 'T',
|
|
4 FLOAT m_fSpeed "Speed [m/s]" 'S' = 10.0f,
|
|
5 FLOAT m_fRotation "Rotation [deg/s]" 'R' = 30.0f,
|
|
6 FLOAT m_fRockingV "Rocking V" 'V' = 10.0f,
|
|
7 FLOAT m_fRockingA "Rocking A" 'A' = 10.0f,
|
|
8 FLOAT m_fAcceleration "Acceleration" 'C' = 10.0f,
|
|
|
|
10 BOOL m_bMoving = TRUE,
|
|
11 FLOAT m_fRockSign = 1.0f,
|
|
12 FLOAT m_fLastTargetDistance = UpperLimit(0.0f),
|
|
|
|
20 CEntityPointer m_penSail "Sail" 'L',
|
|
21 ANIMATION m_iSailUpAnim "Sail roll-up anim"=0,
|
|
22 ANIMATION m_iSailDownAnim "Sail roll-down anim"=0,
|
|
23 ANIMATION m_iSailSailAnim "Sail sailing anim"=0,
|
|
24 ANIMATION m_iSailWaveingAnim "Sail wawing anim"=0,
|
|
|
|
30 FLOAT m_fOriginalRockingV = 0.0f,
|
|
31 FLOAT m_fOriginalRockingA = 0.0f,
|
|
32 FLOAT m_fNextRockingV = 0.0f,
|
|
33 FLOAT m_fNextRockingA = 0.0f,
|
|
34 FLOAT m_tmRockingChange=1, // how many second to change rocking parameters
|
|
35 FLOAT m_tmRockingChangeStart=-1, // when changing of rocking parameters has started
|
|
components:
|
|
functions:
|
|
/* 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\\ShipMarker.ecl");
|
|
strTargetProperty = "Target";
|
|
return TRUE;
|
|
}
|
|
const CTString &GetDescription(void) const {
|
|
((CTString&)m_strDescription).PrintF("-><none>");
|
|
if (m_penTarget!=NULL) {
|
|
((CTString&)m_strDescription).PrintF("->%s", m_penTarget->GetName());
|
|
}
|
|
return m_strDescription;
|
|
}
|
|
/* Get anim data for given animation property - return NULL for none. */
|
|
CAnimData *GetAnimData(SLONG slPropertyOffset)
|
|
{
|
|
if((slPropertyOffset==offsetof(CShip, m_iSailUpAnim)
|
|
||slPropertyOffset==offsetof(CShip, m_iSailDownAnim)
|
|
||slPropertyOffset==offsetof(CShip, m_iSailSailAnim)
|
|
||slPropertyOffset==offsetof(CShip, m_iSailWaveingAnim))
|
|
&&m_penSail!=NULL) {
|
|
return m_penSail->GetModelObject()->GetData();
|
|
} else {
|
|
return CEntity::GetAnimData(slPropertyOffset);
|
|
}
|
|
};
|
|
|
|
// calculate velocities towards marker
|
|
void SetMovingSpeeds(void)
|
|
{
|
|
// if the brush should not be moving, or there is no target
|
|
if (!m_bMoving || m_penTarget==NULL) {
|
|
// just rock
|
|
SetDesiredRotation(ANGLE3D(0,0,GetRockingSpeed()));
|
|
return;
|
|
}
|
|
|
|
CShipMarker *penTarget = (CShipMarker *)(CEntity*)m_penTarget;
|
|
const CPlacement3D &plThis = GetPlacement();
|
|
|
|
// get direction to target
|
|
const FLOAT3D &vTarget = penTarget->GetPlacement().pl_PositionVector;
|
|
const FLOAT3D &vNow = plThis.pl_PositionVector;
|
|
FLOAT3D vDirection = vTarget-vNow;
|
|
FLOAT fTargetDistance = vDirection.Length();
|
|
// if got close enough
|
|
if (fTargetDistance<m_fSpeed*5*_pTimer->TickQuantum) {
|
|
// switch to next marker
|
|
NextMarker();
|
|
return;
|
|
}
|
|
|
|
vDirection/=fTargetDistance;
|
|
ANGLE3D aAngle;
|
|
DirectionVectorToAngles(vDirection, aAngle);
|
|
aAngle-=plThis.pl_OrientationAngle;
|
|
aAngle(1) = AdjustRotationSpeed(aAngle(1), m_fRotation);
|
|
aAngle(2) = 0;
|
|
aAngle(3) = GetRockingSpeed();
|
|
|
|
SetDesiredRotation(aAngle);
|
|
|
|
// set speed
|
|
SetDesiredTranslation(FLOAT3D(0,0,-m_fSpeed));
|
|
|
|
en_fAcceleration = m_fAcceleration;
|
|
en_fDeceleration = m_fAcceleration;
|
|
}
|
|
|
|
// calculate rocking velocity
|
|
ANGLE GetRockingSpeed(void)
|
|
{
|
|
// if rocking changing time has not passed
|
|
TIME tmSinceChangeStarted = _pTimer->CurrentTick()-m_tmRockingChangeStart;
|
|
if (tmSinceChangeStarted<m_tmRockingChange) {
|
|
// calculate current rocking parameters
|
|
FLOAT fFactor = tmSinceChangeStarted/m_tmRockingChange;
|
|
m_fRockingV = Lerp(m_fOriginalRockingV, m_fNextRockingV, fFactor);
|
|
m_fRockingA = Lerp(m_fOriginalRockingA, m_fNextRockingA, fFactor);
|
|
}
|
|
|
|
if (m_fRockingV==0) {
|
|
return 0;
|
|
}
|
|
|
|
ANGLE aAngle = GetPlacement().pl_OrientationAngle(3);
|
|
ANGLE aRotation = Sqrt(m_fRockingA*m_fRockingA-aAngle*aAngle)*m_fRockingV;
|
|
if (aRotation<2 && aAngle*m_fRockSign>0) {
|
|
m_fRockSign = -m_fRockSign;
|
|
};
|
|
|
|
if (aRotation<2) {
|
|
aRotation = 2;
|
|
}
|
|
aRotation *=m_fRockSign;
|
|
|
|
return aRotation;
|
|
}
|
|
|
|
// switch to next marker
|
|
void NextMarker(void)
|
|
{
|
|
// get next marker
|
|
CShipMarker *penTarget = (CShipMarker *)(CEntity*)m_penTarget;
|
|
CShipMarker *penNextTarget = (CShipMarker *)(CEntity*)penTarget->m_penTarget;
|
|
|
|
// if this marker is harbor
|
|
if (penTarget->m_bHarbor) {
|
|
// stop
|
|
StopSailing();
|
|
// start being in harbor
|
|
SendEvent(EHarbor());
|
|
}
|
|
|
|
// if got to end
|
|
if (penNextTarget==NULL) {
|
|
// stop
|
|
StopSailing();
|
|
return;
|
|
}
|
|
|
|
// get properties from marker
|
|
FLOAT fSpeed = penTarget->m_fSpeed;
|
|
if (fSpeed>=0) {
|
|
m_fSpeed = fSpeed;
|
|
}
|
|
FLOAT fRotation = penTarget->m_fRotation;
|
|
if (fRotation>=0) {
|
|
m_fRotation = fRotation;
|
|
}
|
|
FLOAT fAcceleration = penTarget->m_fAcceleration;
|
|
if (fAcceleration>=0) {
|
|
m_fAcceleration = fAcceleration;
|
|
}
|
|
|
|
m_fOriginalRockingV = m_fRockingV;
|
|
m_fOriginalRockingA = m_fRockingA;
|
|
|
|
FLOAT fRockingV = penTarget->m_fRockingV;
|
|
if (fRockingV>=0) {
|
|
m_fNextRockingV = fRockingV;
|
|
} else {
|
|
m_fNextRockingV = m_fRockingV;
|
|
}
|
|
FLOAT fRockingA = penTarget->m_fRockingA;
|
|
if (fRockingA>=0) {
|
|
m_fNextRockingA = fRockingA;
|
|
} else {
|
|
m_fNextRockingA = m_fRockingA;
|
|
}
|
|
m_tmRockingChange = penTarget->m_tmRockingChange;
|
|
m_tmRockingChangeStart = _pTimer->CurrentTick();
|
|
|
|
// remember next marker as current target
|
|
m_penTarget = penNextTarget;
|
|
SetMovingSpeeds();
|
|
}
|
|
|
|
void StartSailing()
|
|
{
|
|
m_bMoving = TRUE;
|
|
// calculate velocities towards marker
|
|
SetMovingSpeeds();
|
|
}
|
|
|
|
void StopSailing(void)
|
|
{
|
|
m_bMoving = FALSE;
|
|
SetDesiredRotation(ANGLE3D(0,0,GetDesiredRotation()(3)));
|
|
SetDesiredTranslation(FLOAT3D(0,0,0));
|
|
}
|
|
|
|
// do moving
|
|
void PreMoving(void) {
|
|
// calculate velocities towards marker
|
|
SetMovingSpeeds();
|
|
CMovableBrushEntity::PreMoving();
|
|
};
|
|
|
|
procedures:
|
|
Sail() {
|
|
// roll the sail down
|
|
m_penSail->GetModelObject()->PlayAnim(m_iSailDownAnim, 0);
|
|
autowait(m_penSail->GetModelObject()->GetAnimLength(m_iSailDownAnim));
|
|
// start sail waveing
|
|
m_penSail->GetModelObject()->PlayAnim(m_iSailWaveingAnim, AOF_LOOPING);
|
|
|
|
// wait until touched by a player or started
|
|
wait() {
|
|
on (EBegin) : { resume; }
|
|
on (ETouch eTouch) : {
|
|
if (IsDerivedFromClass(eTouch.penOther, "PlayerEntity")) {
|
|
stop;
|
|
}
|
|
}
|
|
on (EStart) : {
|
|
stop;
|
|
}
|
|
}
|
|
|
|
// blow the sail up
|
|
m_penSail->GetModelObject()->PlayAnim(m_iSailSailAnim, 0);
|
|
|
|
// start moving
|
|
StartSailing();
|
|
// sail until we come to harbor
|
|
wait() {
|
|
on (EBegin) : { resume; }
|
|
on (EHarbor) : { stop; }
|
|
}
|
|
|
|
// stay in harbor
|
|
jump Harbor();
|
|
}
|
|
Harbor() {
|
|
// roll the sail up
|
|
m_penSail->GetModelObject()->PlayAnim(m_iSailUpAnim, 0);
|
|
|
|
// stay in harbor until we are triggered
|
|
wait() {
|
|
on (EBegin) : { resume; }
|
|
on (ETrigger) : { stop; }
|
|
}
|
|
// start sailing
|
|
jump Sail();
|
|
}
|
|
|
|
|
|
Main() {
|
|
// declare yourself as a brush
|
|
InitAsBrush();
|
|
SetPhysicsFlags(EPF_BRUSH_MOVING&~(EPF_ABSOLUTETRANSLATE|EPF_NOACCELERATION));
|
|
SetCollisionFlags(ECF_BRUSH);
|
|
|
|
// stop moving brush
|
|
ForceFullStop();
|
|
|
|
// assure valid target
|
|
if (m_penTarget!=NULL && !IsOfClass(m_penTarget, "Ship Marker")) {
|
|
WarningMessage("Target '%s' is not of ShipMarker class!", m_penTarget->GetName());
|
|
m_penTarget = NULL;
|
|
}
|
|
// assure valid sail
|
|
if (m_penSail!=NULL && m_penSail->GetRenderType()!=RT_MODEL) {
|
|
WarningMessage("Sail '%s' is not a model!", m_penSail->GetName());
|
|
m_penSail = NULL;
|
|
}
|
|
|
|
// wait until game starts
|
|
autowait(0.1f);
|
|
|
|
// if sail is not valid
|
|
if (m_penSail==NULL) {
|
|
// don't continue
|
|
WarningMessage("Ship will not work without a valid sail!");
|
|
return;
|
|
}
|
|
|
|
// forever
|
|
wait() {
|
|
// on the beginning
|
|
on (EBegin) : {
|
|
// start sailing
|
|
call Sail();
|
|
}
|
|
|
|
// move is obstructed
|
|
on (EBlock eBlock) : {
|
|
// inflict damage to entity that block brush
|
|
InflictDirectDamage(eBlock.penOther, this, DMT_BRUSH, 10.0f,
|
|
FLOAT3D(0.0f,0.0f,0.0f), (FLOAT3D &)eBlock.plCollision);
|
|
resume;
|
|
}
|
|
}
|
|
}
|
|
};
|