2020-10-14 15:16:30 +02:00
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers , whose names
* are too numerous to list here . Please refer to the COPYRIGHT
* file distributed with this source distribution .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* 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 .
*
*/
2020-12-21 12:31:32 +01:00
# include "twine/script/script_life_v1.h"
2020-11-14 20:54:38 +01:00
# include "common/memstream.h"
2020-10-25 22:53:01 +01:00
# include "common/stream.h"
2020-12-21 12:31:32 +01:00
# include "twine/scene/actor.h"
# include "twine/scene/animations.h"
# include "twine/audio/music.h"
# include "twine/audio/sound.h"
# include "twine/scene/collision.h"
2020-10-14 15:16:30 +02:00
# include "twine/flamovies.h"
2020-12-21 12:31:32 +01:00
# include "twine/scene/gamestate.h"
# include "twine/scene/grid.h"
2020-10-14 15:16:30 +02:00
# include "twine/holomap.h"
2020-10-23 13:44:38 +02:00
# include "twine/input.h"
2020-12-21 12:31:32 +01:00
# include "twine/menu/interface.h"
# include "twine/menu/menu.h"
# include "twine/scene/movements.h"
# include "twine/renderer/redraw.h"
# include "twine/renderer/renderer.h"
# include "twine/renderer/screens.h"
2020-12-21 19:37:07 +01:00
# include "twine/resources/resources.h"
2020-12-21 12:31:32 +01:00
# include "twine/scene/scene.h"
2020-10-14 15:16:30 +02:00
# include "twine/text.h"
2020-10-26 01:59:37 +01:00
# include "twine/twine.h"
2020-10-14 15:16:30 +02:00
namespace TwinE {
2021-01-08 19:49:34 +01:00
// the y position for lTEXT opcode - see lCLEAR (used in credits scene)
// TODO: move into scene class?
static int32 lTextYPos ;
2020-10-14 15:16:30 +02:00
2020-11-03 22:29:51 +01:00
struct LifeScriptContext {
2020-10-27 19:02:59 +01:00
int32 actorIdx ;
ActorStruct * actor ;
2020-11-03 22:31:55 +01:00
Common : : MemorySeekableReadWriteStream stream ;
2020-11-03 20:17:03 +01:00
uint8 * opcodePtr ; // local opcode script pointer
2020-11-03 22:31:55 +01:00
LifeScriptContext ( int32 _actorIdx , ActorStruct * _actor ) : actorIdx ( _actorIdx ) , actor ( _actor ) , stream ( _actor - > lifeScript , _actor - > lifeScriptSize ) {
assert ( actor - > positionInLifeScript > = 0 ) ;
stream . skip ( _actor - > positionInLifeScript ) ;
updateOpcodePos ( ) ;
}
void setOpcode ( uint8 opcode ) {
* opcodePtr = opcode ;
}
void updateOpcodePos ( ) {
opcodePtr = actor - > lifeScript + stream . pos ( ) ;
}
2020-10-27 19:02:59 +01:00
} ;
2020-11-19 23:21:39 +01:00
/**
* Returns @ c - 1 Need implementation , @ c 0 Condition false , @ c 1 - Condition true
*/
2020-11-03 22:29:51 +01:00
typedef int32 ScriptLifeFunc ( TwinEEngine * engine , LifeScriptContext & ctx ) ;
2020-10-14 15:16:30 +02:00
2020-10-21 11:23:09 +02:00
struct ScriptLifeFunction {
2020-10-14 15:16:30 +02:00
const char * name ;
ScriptLifeFunc * function ;
2020-10-21 11:23:09 +02:00
} ;
2020-10-14 15:16:30 +02:00
# define MAPFUNC(name, func) \
{ name , func }
/** Script condition operators */
enum LifeScriptOperators {
/*==*/ kEqualTo = 0 ,
/*> */ kGreaterThan = 1 ,
/*< */ kLessThan = 2 ,
/*>=*/ kGreaterThanOrEqualTo = 3 ,
/*<=*/ kLessThanOrEqualTo = 4 ,
/*!=*/ kNotEqualTo = 5
} ;
/** Script condition command opcodes */
enum LifeScriptConditions {
2020-12-21 12:31:32 +01:00
/*0x00*/ kcCOL = 0 , /*<! Current actor collision with another actor. (Parameter = Actor Index) */
/*0x01*/ kcCOL_OBJ = 1 , /*<! Actor collision with the actor passed as parameter. (Parameter = Actor Index, Parameter = Actor Index) */
/*0x02*/ kcDISTANCE = 2 , /*<! Distance between the current actor and the actor passed as parameter. (Parameter = Actor Index, Parameter = Distance between) */
/*0x03*/ kcZONE = 3 , /*<! Current actor tread on zone passed as parameter. (Parameter = Zone Index) */
/*0x04*/ kcZONE_OBJ = 4 , /*<! The actor passed as parameter will tread on zone passed as parameter. (Parameter = Actor Index, Parameter = Zone Index) */
/*0x05*/ kcBODY = 5 , /*<! Body of the current actor. (Parameter = Body Index) */
/*0x06*/ kcBODY_OBJ = 6 , /*<! Body of the actor passed as parameter. (Parameter = Body Index) */
/*0x07*/ kcANIM = 7 , /*<! Body Animation of the current actor. (Parameter = Animation Index) */
/*0x08*/ kcANIM_OBJ = 8 , /*<! Body Animation of the actor passed as parameter. (Parameter = Animation Index) */
/*0x09*/ kcL_TRACK = 9 , /*<! Current actor track. (Parameter = Track Index) */
/*0x0A*/ kcL_TRACK_OBJ = 10 , /*<! Track of the actor passed as parameter. (Parameter = Track Index) */
/*0x0B*/ kcFLAG_CUBE = 11 , /*<! Game Cube Flags. (Parameter = Cube Flag Index, Parameter = 0 (not set), = 1 (set))k */
/*0x0C*/ kcCONE_VIEW = 12 , /*<! The actor passed as parameter have a "vision in circle". (Parameter = Actor Index, Parameter = Distance) */
/*0x0D*/ kcHIT_BY = 13 , /*<! Current actor hited by the actor passed as parameter. (Parameter = Actor Index) */
/*0x0E*/ kcACTION = 14 , /*<! Hero action behavior. (Parameter = Behaviour Index) */
/*0x0F*/ kcFLAG_GAME = 15 , /*<! Game Flags (See further list). (Parameter = Flag Index, Parameter = 0 (not set), = 1 (set)) */
/*0x10*/ kcLIFE_POINT = 16 , /*<! Current actor life points. (Parameter = Life points) */
/*0x11*/ kcLIFE_POINT_OBJ = 17 , /*<! Life points of the current actor passed as parameter. (Parameter = Life points) */
/*0x12*/ kcNUM_LITTLE_KEYS = 18 , /*<! Number of keys. (Parameter = Number of keys) */
/*0x13*/ kcNUM_GOLD_PIECES = 19 , /*<! Coins/Gold Amount. (Parameter = Coins/Gold amount) */
/*0x14*/ kcBEHAVIOUR = 20 , /*<! Hero behaviour. (Parameter = Behaviour Index) */
/*0x15*/ kcCHAPTER = 21 , /*<! Story Chapters. (Parameter = Chapter Index) */
/*0x16*/ kcDISTANCE_3D = 22 , /*<! Distance between the actor passed as parameter and the current actor. (Parameter = Actor Index, Parameter = Distance) */
/*0x17 - 23 unused */
/*0x18 - 24 unused */
/*0x19*/ kcUSE_INVENTORY = 25 , /*<! Use inventory object. (Parameter = Object Index in the inventory, Paramenter = 0 (Not in Inventory), = 1 (In the Inventory)) */
/*0x1A*/ kcCHOICE = 26 , /*<! Menu choice. (Parameter = Text Index in the current Text Bank) */
/*0x1B*/ kcFUEL = 27 , /*<! Amount of fuel gas the Hero have in his inventory. (Parameter = Gas amount) */
/*0x1C*/ kcCARRIED_BY = 28 , /*<! The current is carried by the actor passed as paramenter. (Parameter = Actor Index) */
/*0x1D*/ kcCDROM = 29 /*<! CDROM audio tracks. (Parameter = Audio Tracks Index) */
2020-10-14 15:16:30 +02:00
} ;
2020-11-19 23:21:39 +01:00
/**
* Returns @ c 1 Condition value size ( 1 byte ) , @ c 2 Condition value size ( 2 byes )
*/
2020-11-03 22:29:51 +01:00
static int32 processLifeConditions ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-26 01:59:37 +01:00
int32 conditionValueSize = 1 ;
2020-11-03 22:31:55 +01:00
int32 conditionOpcode = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
switch ( conditionOpcode ) {
case kcCOL :
2020-10-27 19:02:59 +01:00
if ( ctx . actor - > life < = 0 ) {
2020-10-14 15:16:30 +02:00
engine - > _scene - > currentScriptValue = - 1 ;
} else {
2020-10-27 19:02:59 +01:00
engine - > _scene - > currentScriptValue = ctx . actor - > collision ;
2020-10-14 15:16:30 +02:00
}
break ;
case kcCOL_OBJ : {
2020-11-03 22:31:55 +01:00
int32 actorIdx = ctx . stream . readByte ( ) ;
2020-10-25 12:39:40 +01:00
if ( engine - > _scene - > getActor ( actorIdx ) - > life < = 0 ) {
2020-10-14 15:16:30 +02:00
engine - > _scene - > currentScriptValue = - 1 ;
} else {
2020-10-25 12:39:40 +01:00
engine - > _scene - > currentScriptValue = engine - > _scene - > getActor ( actorIdx ) - > collision ;
2020-10-14 15:16:30 +02:00
}
2020-10-26 01:59:37 +01:00
break ;
}
2020-10-14 15:16:30 +02:00
case kcDISTANCE : {
2020-11-03 22:31:55 +01:00
int32 actorIdx = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
conditionValueSize = 2 ;
2020-10-25 12:39:40 +01:00
ActorStruct * otherActor = engine - > _scene - > getActor ( actorIdx ) ;
2020-10-14 15:16:30 +02:00
if ( ! otherActor - > dynamicFlags . bIsDead ) {
2020-10-27 19:02:59 +01:00
if ( ABS ( ctx . actor - > y - otherActor - > y ) > = 1500 ) {
2020-10-14 15:16:30 +02:00
engine - > _scene - > currentScriptValue = MAX_TARGET_ACTOR_DISTANCE ;
} else {
// Returns int32, so we check for integer overflow
2020-10-27 19:02:59 +01:00
int32 distance = engine - > _movements - > getDistance2D ( ctx . actor - > x , ctx . actor - > z , otherActor - > x , otherActor - > z ) ;
2020-10-14 15:16:30 +02:00
if ( ABS ( distance ) > MAX_TARGET_ACTOR_DISTANCE ) {
engine - > _scene - > currentScriptValue = MAX_TARGET_ACTOR_DISTANCE ;
} else {
engine - > _scene - > currentScriptValue = distance ;
}
}
} else {
engine - > _scene - > currentScriptValue = MAX_TARGET_ACTOR_DISTANCE ;
}
2020-10-26 01:59:37 +01:00
break ;
}
2020-10-14 15:16:30 +02:00
case kcZONE :
2020-10-27 19:02:59 +01:00
engine - > _scene - > currentScriptValue = ctx . actor - > zone ;
2020-10-14 15:16:30 +02:00
break ;
case kcZONE_OBJ : {
2020-11-03 22:31:55 +01:00
int32 actorIdx = ctx . stream . readByte ( ) ;
2020-10-25 12:39:40 +01:00
engine - > _scene - > currentScriptValue = engine - > _scene - > getActor ( actorIdx ) - > zone ;
2020-10-26 01:59:37 +01:00
break ;
}
2020-10-14 15:16:30 +02:00
case kcBODY :
2021-01-26 20:14:46 +01:00
engine - > _scene - > currentScriptValue = ( int16 ) ctx . actor - > body ;
2020-10-14 15:16:30 +02:00
break ;
case kcBODY_OBJ : {
2020-11-03 22:31:55 +01:00
int32 actorIdx = ctx . stream . readByte ( ) ;
2021-01-26 20:14:46 +01:00
engine - > _scene - > currentScriptValue = ( int16 ) engine - > _scene - > getActor ( actorIdx ) - > body ;
2020-10-26 01:59:37 +01:00
break ;
}
2020-10-14 15:16:30 +02:00
case kcANIM :
2020-11-14 12:24:16 +01:00
engine - > _scene - > currentScriptValue = ( int16 ) ctx . actor - > anim ;
2020-10-14 15:16:30 +02:00
break ;
case kcANIM_OBJ : {
2020-11-03 22:31:55 +01:00
int32 actorIdx = ctx . stream . readByte ( ) ;
2020-11-14 12:24:16 +01:00
engine - > _scene - > currentScriptValue = ( int16 ) engine - > _scene - > getActor ( actorIdx ) - > anim ;
2020-10-26 01:59:37 +01:00
break ;
}
2020-10-14 15:16:30 +02:00
case kcL_TRACK :
2020-10-27 19:02:59 +01:00
engine - > _scene - > currentScriptValue = ctx . actor - > labelIdx ;
2020-10-14 15:16:30 +02:00
break ;
case kcL_TRACK_OBJ : {
2020-11-03 22:31:55 +01:00
int32 actorIdx = ctx . stream . readByte ( ) ;
2020-10-25 12:39:40 +01:00
engine - > _scene - > currentScriptValue = engine - > _scene - > getActor ( actorIdx ) - > labelIdx ;
2020-10-26 01:59:37 +01:00
break ;
}
2020-10-14 15:16:30 +02:00
case kcFLAG_CUBE : {
2020-11-03 22:31:55 +01:00
int32 flagIdx = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
engine - > _scene - > currentScriptValue = engine - > _scene - > sceneFlags [ flagIdx ] ;
2020-10-26 01:59:37 +01:00
break ;
}
2020-10-14 15:16:30 +02:00
case kcCONE_VIEW : {
2020-10-25 12:39:40 +01:00
int32 newAngle = 0 ;
2020-11-03 22:31:55 +01:00
int32 targetActorIdx = ctx . stream . readByte ( ) ;
2020-10-25 12:39:40 +01:00
ActorStruct * targetActor = engine - > _scene - > getActor ( targetActorIdx ) ;
2020-10-14 15:16:30 +02:00
conditionValueSize = 2 ;
if ( ! targetActor - > dynamicFlags . bIsDead ) {
2020-10-27 19:02:59 +01:00
if ( ABS ( targetActor - > y - ctx . actor - > y ) < 1500 ) {
newAngle = engine - > _movements - > getAngleAndSetTargetActorDistance ( ctx . actor - > x , ctx . actor - > z , targetActor - > x , targetActor - > z ) ;
2020-10-14 15:16:30 +02:00
if ( ABS ( engine - > _movements - > targetActorDistance ) > MAX_TARGET_ACTOR_DISTANCE ) {
engine - > _movements - > targetActorDistance = MAX_TARGET_ACTOR_DISTANCE ;
}
} else {
engine - > _movements - > targetActorDistance = MAX_TARGET_ACTOR_DISTANCE ;
}
2020-11-19 23:12:06 +01:00
if ( IS_HERO ( targetActorIdx ) ) {
2020-11-19 23:41:44 +01:00
int32 heroAngle = ClampAngle ( ctx . actor - > angle + ANGLE_360 + ANGLE_45 - newAngle + ANGLE_360 ) ;
2020-10-14 15:16:30 +02:00
2020-11-19 23:41:44 +01:00
if ( ABS ( heroAngle ) > ANGLE_90 ) {
2020-10-14 15:16:30 +02:00
engine - > _scene - > currentScriptValue = MAX_TARGET_ACTOR_DISTANCE ;
} else {
engine - > _scene - > currentScriptValue = engine - > _movements - > targetActorDistance ;
}
} else {
2020-11-14 12:48:11 +01:00
if ( engine - > _actor - > heroBehaviour = = HeroBehaviourType : : kDiscrete ) {
2020-11-19 23:41:44 +01:00
int32 heroAngle = ClampAngle ( ctx . actor - > angle + ANGLE_360 + ANGLE_45 - newAngle + ANGLE_360 ) ;
2020-10-14 15:16:30 +02:00
2020-11-19 23:41:44 +01:00
if ( ABS ( heroAngle ) > ANGLE_90 ) {
2020-10-14 15:16:30 +02:00
engine - > _scene - > currentScriptValue = MAX_TARGET_ACTOR_DISTANCE ;
} else {
engine - > _scene - > currentScriptValue = engine - > _movements - > targetActorDistance ;
}
} else {
engine - > _scene - > currentScriptValue = engine - > _movements - > targetActorDistance ;
}
}
} else {
engine - > _scene - > currentScriptValue = MAX_TARGET_ACTOR_DISTANCE ;
}
2020-11-04 23:58:23 +01:00
break ;
}
2020-10-14 15:16:30 +02:00
case kcHIT_BY :
2020-10-27 19:02:59 +01:00
engine - > _scene - > currentScriptValue = ctx . actor - > hitBy ;
2020-10-14 15:16:30 +02:00
break ;
case kcACTION :
2020-11-21 14:27:49 +01:00
engine - > _scene - > currentScriptValue = engine - > _movements - > shouldTriggerZoneAction ( ) ? 1 : 0 ;
2020-10-14 15:16:30 +02:00
break ;
case kcFLAG_GAME : {
2020-11-03 22:31:55 +01:00
int32 flagIdx = ctx . stream . readByte ( ) ;
2020-11-22 12:07:28 +01:00
if ( ! engine - > _gameState - > inventoryDisabled ( ) | |
( engine - > _gameState - > inventoryDisabled ( ) & & flagIdx > = MaxInventoryItems ) ) {
2021-01-07 21:46:05 +01:00
engine - > _scene - > currentScriptValue = engine - > _gameState - > hasGameFlag ( flagIdx ) ;
2020-10-14 15:16:30 +02:00
} else {
if ( flagIdx = = GAMEFLAG_INVENTORY_DISABLED ) {
2021-01-06 08:06:06 +01:00
// TODO: this case should already get handled in the above if branch as the flagIdx is bigger than MaxInventoryItems
2020-11-22 12:07:28 +01:00
engine - > _scene - > currentScriptValue = engine - > _gameState - > inventoryDisabled ( ) ;
2020-10-14 15:16:30 +02:00
} else {
engine - > _scene - > currentScriptValue = 0 ;
}
}
2020-10-26 01:59:37 +01:00
break ;
}
2020-10-14 15:16:30 +02:00
case kcLIFE_POINT :
2020-10-27 19:02:59 +01:00
engine - > _scene - > currentScriptValue = ctx . actor - > life ;
2020-10-14 15:16:30 +02:00
break ;
case kcLIFE_POINT_OBJ : {
2020-11-03 22:31:55 +01:00
int32 actorIdx = ctx . stream . readByte ( ) ;
2020-10-25 12:39:40 +01:00
engine - > _scene - > currentScriptValue = engine - > _scene - > getActor ( actorIdx ) - > life ;
2020-10-26 01:59:37 +01:00
break ;
}
2020-10-14 15:16:30 +02:00
case kcNUM_LITTLE_KEYS :
engine - > _scene - > currentScriptValue = engine - > _gameState - > inventoryNumKeys ;
break ;
case kcNUM_GOLD_PIECES :
conditionValueSize = 2 ;
engine - > _scene - > currentScriptValue = engine - > _gameState - > inventoryNumKashes ;
break ;
case kcBEHAVIOUR :
2020-11-14 12:48:11 +01:00
engine - > _scene - > currentScriptValue = ( int16 ) engine - > _actor - > heroBehaviour ;
2020-10-14 15:16:30 +02:00
break ;
case kcCHAPTER :
engine - > _scene - > currentScriptValue = engine - > _gameState - > gameChapter ;
break ;
case kcDISTANCE_3D : {
int32 targetActorIdx ;
ActorStruct * targetActor ;
2020-11-03 22:31:55 +01:00
targetActorIdx = ctx . stream . readByte ( ) ;
2020-10-25 12:39:40 +01:00
targetActor = engine - > _scene - > getActor ( targetActorIdx ) ;
2020-10-14 15:16:30 +02:00
conditionValueSize = 2 ;
if ( ! targetActor - > dynamicFlags . bIsDead ) {
// Returns int32, so we check for integer overflow
2020-10-27 19:02:59 +01:00
int32 distance = engine - > _movements - > getDistance3D ( ctx . actor - > x , ctx . actor - > y , ctx . actor - > z , targetActor - > x , targetActor - > y , targetActor - > z ) ;
2020-10-14 15:16:30 +02:00
if ( ABS ( distance ) > MAX_TARGET_ACTOR_DISTANCE ) {
engine - > _scene - > currentScriptValue = MAX_TARGET_ACTOR_DISTANCE ;
} else {
engine - > _scene - > currentScriptValue = distance ;
}
} else {
engine - > _scene - > currentScriptValue = MAX_TARGET_ACTOR_DISTANCE ;
}
2020-10-26 01:59:37 +01:00
break ;
}
2020-10-14 15:16:30 +02:00
case 23 : // unused
case 24 :
break ;
case kcUSE_INVENTORY : {
2020-11-03 22:31:55 +01:00
int32 item = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
2020-11-22 12:07:28 +01:00
if ( ! engine - > _gameState - > inventoryDisabled ( ) ) {
2020-10-14 15:16:30 +02:00
if ( item = = engine - > loopInventoryItem ) {
engine - > _scene - > currentScriptValue = 1 ;
} else {
2020-11-22 12:07:28 +01:00
if ( engine - > _gameState - > inventoryFlags [ item ] = = 1 & & engine - > _gameState - > hasItem ( ( InventoryItems ) item ) ) {
2020-10-14 15:16:30 +02:00
engine - > _scene - > currentScriptValue = 1 ;
} else {
engine - > _scene - > currentScriptValue = 0 ;
}
}
if ( engine - > _scene - > currentScriptValue = = 1 ) {
2020-12-07 16:59:29 +01:00
engine - > _redraw - > addOverlay ( OverlayType : : koInventoryItem , item , 0 , 0 , 0 , OverlayPosType : : koNormal , 3 ) ;
2020-10-14 15:16:30 +02:00
}
} else {
engine - > _scene - > currentScriptValue = 0 ;
}
2020-10-26 01:59:37 +01:00
break ;
}
2020-10-14 15:16:30 +02:00
case kcCHOICE :
conditionValueSize = 2 ;
engine - > _scene - > currentScriptValue = engine - > _gameState - > choiceAnswer ;
break ;
case kcFUEL :
engine - > _scene - > currentScriptValue = engine - > _gameState - > inventoryNumGas ;
break ;
case kcCARRIED_BY :
2020-10-27 19:02:59 +01:00
engine - > _scene - > currentScriptValue = ctx . actor - > standOn ;
2020-10-14 15:16:30 +02:00
break ;
case kcCDROM :
engine - > _scene - > currentScriptValue = 1 ;
break ;
default :
2020-10-26 01:59:37 +01:00
error ( " Actor condition opcode %d " , conditionOpcode ) ;
2020-10-14 15:16:30 +02:00
break ;
}
return conditionValueSize ;
}
2020-11-19 23:21:39 +01:00
/**
* Returns @ c - 1 Need implementation , @ c 0 Condition false , @ c 1 Condition true
*/
2020-11-03 22:29:51 +01:00
static int32 processLifeOperators ( TwinEEngine * engine , LifeScriptContext & ctx , int32 valueSize ) {
2020-11-03 22:31:55 +01:00
const int32 operatorCode = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
2020-10-26 01:59:37 +01:00
int32 conditionValue ;
2020-10-14 15:16:30 +02:00
if ( valueSize = = 1 ) {
2020-11-03 22:31:55 +01:00
conditionValue = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
} else if ( valueSize = = 2 ) {
2020-11-03 22:31:55 +01:00
conditionValue = ctx . stream . readSint16LE ( ) ;
2020-10-14 15:16:30 +02:00
} else {
2020-11-03 22:31:55 +01:00
error ( " Unknown operator value size %d " , valueSize ) ;
2020-10-14 15:16:30 +02:00
}
switch ( operatorCode ) {
case kEqualTo :
if ( engine - > _scene - > currentScriptValue = = conditionValue ) {
return 1 ;
}
break ;
case kGreaterThan :
if ( engine - > _scene - > currentScriptValue > conditionValue ) {
return 1 ;
}
break ;
case kLessThan :
if ( engine - > _scene - > currentScriptValue < conditionValue ) {
return 1 ;
}
break ;
case kGreaterThanOrEqualTo :
if ( engine - > _scene - > currentScriptValue > = conditionValue ) {
return 1 ;
}
break ;
case kLessThanOrEqualTo :
if ( engine - > _scene - > currentScriptValue < = conditionValue ) {
return 1 ;
}
break ;
case kNotEqualTo :
if ( engine - > _scene - > currentScriptValue ! = conditionValue ) {
return 1 ;
}
break ;
default :
2020-10-26 20:07:38 +01:00
warning ( " Unknown life script operator opcode %d " , operatorCode ) ;
2020-10-14 15:16:30 +02:00
break ;
}
return 0 ;
}
/** Life script command definitions */
2020-11-19 23:21:39 +01:00
/**
* For unused opcodes
*/
2020-11-03 22:29:51 +01:00
static int32 lEMPTY ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* End of Actor Life Script
* @ note Opcode @ c 0x00
*/
2020-11-03 22:29:51 +01:00
static int32 lEND ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-27 19:02:59 +01:00
ctx . actor - > positionInLifeScript = - 1 ;
2020-10-14 15:16:30 +02:00
return 1 ; // break script
}
2020-11-19 23:21:39 +01:00
/**
* No Operation
* @ note Opcode @ c 0x01
*/
2020-11-03 22:29:51 +01:00
static int32 lNOP ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
ctx . stream . skip ( 1 ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To execute a switch no if . It ' s used to toggle the switch .
* @ note Opcode @ c 0x02
*/
2020-11-03 22:29:51 +01:00
static int32 lSNIF ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-27 19:02:59 +01:00
const int32 valueSize = processLifeConditions ( engine , ctx ) ;
2020-11-03 20:17:03 +01:00
if ( ! processLifeOperators ( engine , ctx , valueSize ) ) {
2020-11-03 22:31:55 +01:00
ctx . setOpcode ( 0x0D ) ; // SWIF
2020-10-14 15:16:30 +02:00
}
2020-11-03 22:31:55 +01:00
ctx . stream . seek ( ctx . stream . readSint16LE ( ) ) ; // condition offset
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To jump to another offset in the current script . ( Parameter = Offset )
* @ note Opcode @ c 0x03
*/
2020-11-03 22:29:51 +01:00
static int32 lOFFSET ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
ctx . stream . seek ( ctx . stream . readSint16LE ( ) ) ; // offset
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Will never execute that condition .
* @ note Opcode @ c 0x04
*/
2020-11-03 22:29:51 +01:00
static int32 lNEVERIF ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-27 19:02:59 +01:00
int32 valueSize = processLifeConditions ( engine , ctx ) ;
2020-11-03 20:17:03 +01:00
processLifeOperators ( engine , ctx , valueSize ) ;
2020-11-03 22:31:55 +01:00
ctx . stream . seek ( ctx . stream . readSint16LE ( ) ) ; // condition offset
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Will not execute the condition .
* @ note Opcode @ c 0x06
*/
2020-11-03 22:29:51 +01:00
static int32 lNO_IF ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Specify a new label
* @ note Opcode @ c 0x0A
*/
2020-11-03 22:29:51 +01:00
static int32 lLABEL ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-19 23:21:39 +01:00
ctx . stream . skip ( 1 ) ; // label id - script offset
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To stop running the current script
* @ note Opcode @ c 0x0B
*/
2020-11-03 22:29:51 +01:00
static int32 lRETURN ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-14 15:16:30 +02:00
return 1 ; // break script
}
2020-11-19 23:21:39 +01:00
/**
* Do a certain statement according the condition .
* @ note Opcode @ c 0x0C
*/
2020-11-03 22:29:51 +01:00
static int32 lIF ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-27 19:02:59 +01:00
int32 valueSize = processLifeConditions ( engine , ctx ) ;
2020-11-03 20:17:03 +01:00
if ( ! processLifeOperators ( engine , ctx , valueSize ) ) {
2020-11-03 22:31:55 +01:00
ctx . stream . seek ( ctx . stream . readSint16LE ( ) ) ; // condition offset
2020-10-14 15:16:30 +02:00
} else {
2020-11-03 22:31:55 +01:00
ctx . stream . skip ( 2 ) ;
2020-10-14 15:16:30 +02:00
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To execute a switch if .
* @ note Opcode @ c 0x0D
*/
2020-11-03 22:29:51 +01:00
static int32 lSWIF ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-27 19:02:59 +01:00
int32 valueSize = processLifeConditions ( engine , ctx ) ;
2020-11-03 20:17:03 +01:00
if ( ! processLifeOperators ( engine , ctx , valueSize ) ) {
2020-11-03 22:31:55 +01:00
ctx . stream . seek ( ctx . stream . readSint16LE ( ) ) ; // condition offset
2020-10-14 15:16:30 +02:00
} else {
2020-11-03 22:31:55 +01:00
ctx . stream . skip ( 2 ) ;
ctx . setOpcode ( 0x02 ) ; // SNIF
2020-10-14 15:16:30 +02:00
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Will only execute that condition one time .
* @ note Opcode @ c 0x0E
*/
2020-11-03 22:29:51 +01:00
static int32 lONEIF ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-27 19:02:59 +01:00
int32 valueSize = processLifeConditions ( engine , ctx ) ;
2020-11-03 20:17:03 +01:00
if ( ! processLifeOperators ( engine , ctx , valueSize ) ) {
2020-11-03 22:31:55 +01:00
ctx . stream . seek ( ctx . stream . readSint16LE ( ) ) ; // condition offset
2020-10-14 15:16:30 +02:00
} else {
2020-11-03 22:31:55 +01:00
ctx . stream . skip ( 2 ) ;
ctx . setOpcode ( 0x04 ) ; // NEVERIF
2020-10-14 15:16:30 +02:00
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Else statement for an IF condition .
* @ note Opcode @ c 0x0F
*/
2020-11-03 22:29:51 +01:00
static int32 lELSE ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
ctx . stream . seek ( ctx . stream . readSint16LE ( ) ) ; // offset
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Choose new body for the current actor ( Parameter = File3D Body Instance )
* @ note Opcode @ c 0x11
*/
2020-11-03 22:29:51 +01:00
static int32 lBODY ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2021-01-26 20:14:46 +01:00
BodyType bodyIdx = ( BodyType ) ctx . stream . readByte ( ) ;
2020-10-27 19:02:59 +01:00
engine - > _actor - > initModelActor ( bodyIdx , ctx . actorIdx ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Choose new body for the actor passed as parameter ( Parameter = Actor Index , Parameter = File3D Body Instance )
* @ note Opcode @ c 0x12
*/
2020-11-03 22:29:51 +01:00
static int32 lBODY_OBJ ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 otherActorIdx = ctx . stream . readByte ( ) ;
2021-01-26 20:14:46 +01:00
BodyType otherBodyIdx = ( BodyType ) ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
engine - > _actor - > initModelActor ( otherBodyIdx , otherActorIdx ) ;
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Choose new animation for the current actor ( Parameter = File3D Animation Instance )
* @ note Opcode @ c 0x13
*/
2020-11-03 22:29:51 +01:00
static int32 lANIM ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
AnimationTypes animIdx = ( AnimationTypes ) ctx . stream . readByte ( ) ;
2021-01-26 18:35:23 +01:00
engine - > _animations - > initAnim ( animIdx , kAnimationTypeLoop , AnimationTypes : : kStanding , ctx . actorIdx ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Choose new animation for the actor passed as parameter ( Parameter = Actor Index , Parameter = File3D Animation Instance )
* @ note Opcode @ c 0x14
*/
2020-11-03 22:29:51 +01:00
static int32 lANIM_OBJ ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 otherActorIdx = ctx . stream . readByte ( ) ;
AnimationTypes otherAnimIdx = ( AnimationTypes ) ctx . stream . readByte ( ) ;
2021-01-26 18:35:23 +01:00
engine - > _animations - > initAnim ( otherAnimIdx , kAnimationTypeLoop , AnimationTypes : : kStanding , otherActorIdx ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Same as SET_COMPORTAMENT
* @ note Opcode @ c 0x15
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_LIFE ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
ctx . actor - > positionInLifeScript = ctx . stream . readSint16LE ( ) ; // offset
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Same as SET_COMPORTAMENT_OBJ
* @ note Opcode @ c 0x16
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_LIFE_OBJ ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 otherActorIdx = ctx . stream . readByte ( ) ;
engine - > _scene - > getActor ( otherActorIdx ) - > positionInLifeScript = ctx . stream . readSint16LE ( ) ; // offset
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set a new track for the current actor . ( Parameter = Track offset )
* @ note Opcode @ c 0x17
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_TRACK ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
ctx . actor - > positionInMoveScript = ctx . stream . readSint16LE ( ) ; // offset
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set a new track for tha actor passed as parameter ( Parameter = Actor Index , Parameter = Track offset )
* @ note Opcode @ c 0x18
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_TRACK_OBJ ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 otherActorIdx = ctx . stream . readByte ( ) ;
engine - > _scene - > getActor ( otherActorIdx ) - > positionInMoveScript = ctx . stream . readSint16LE ( ) ; // offset
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Choose a message to display . ( Parameter = Text Index in the current Text Bank )
* @ note Opcode @ c 0x19
*/
2020-11-03 22:29:51 +01:00
static int32 lMESSAGE ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
const int32 textIdx = ctx . stream . readSint16LE ( ) ;
2020-10-14 15:16:30 +02:00
engine - > freezeTime ( ) ;
if ( engine - > _text - > showDialogueBubble ) {
2020-10-27 19:02:59 +01:00
engine - > _redraw - > drawBubble ( ctx . actorIdx ) ;
2020-10-14 15:16:30 +02:00
}
2020-10-27 19:02:59 +01:00
engine - > _text - > setFontCrossColor ( ctx . actor - > talkColor ) ;
engine - > _scene - > talkingActor = ctx . actorIdx ;
2021-01-30 14:16:23 +01:00
engine - > _text - > drawTextProgressive ( textIdx ) ;
2021-02-17 20:53:40 +01:00
if ( engine - > _scene - > currentSceneIdx = = LBA1SceneId : : Principal_Island_Library & & engine - > _scene - > talkingActor = = 8 ) /* && (*(short *)lifeScriptPosition == 0xe2 [226])*/ {
engine - > unlockAchievement ( " LBA_ACH_008 " ) ;
}
2020-10-14 15:16:30 +02:00
engine - > unfreezeTime ( ) ;
2020-11-26 22:23:30 +01:00
engine - > _redraw - > redrawEngineActions ( true ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To set the current actor static flag fallable . ( Parameter = value & 1 )
* @ note Opcode @ c 0x1A
*/
2020-11-03 22:29:51 +01:00
static int32 lFALLABLE ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
const int32 flag = ctx . stream . readByte ( ) ;
2020-10-27 19:02:59 +01:00
ctx . actor - > staticFlags . bCanFall = flag & 1 ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To set direction for current actor .
* @ note Opcode @ c 0x1B
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_DIRMODE ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
const int32 controlMode = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
2020-10-27 19:02:59 +01:00
ctx . actor - > controlMode = ( ControlMode ) controlMode ;
2020-11-19 18:18:04 +01:00
if ( ctx . actor - > controlMode = = ControlMode : : kFollow | | ctx . actor - > controlMode = = ControlMode : : kFollow2 ) {
2020-11-03 22:31:55 +01:00
ctx . actor - > followedActor = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To set direction
* @ note Opcode @ c 0x1C
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_DIRMODE_OBJ ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
const int32 otherActorIdx = ctx . stream . readByte ( ) ;
const int32 controlMode = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
2020-10-26 00:24:41 +01:00
ActorStruct * otherActor = engine - > _scene - > getActor ( otherActorIdx ) ;
otherActor - > controlMode = ( ControlMode ) controlMode ;
2020-11-19 18:18:04 +01:00
if ( otherActor - > controlMode = = ControlMode : : kFollow | | ctx . actor - > controlMode = = ControlMode : : kFollow2 ) {
2020-11-03 22:31:55 +01:00
otherActor - > followedActor = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Camara follow the actor ( Parameter = Actor to Follow )
* @ note Opcode @ c 0x1D
*/
2020-11-03 22:29:51 +01:00
static int32 lCAM_FOLLOW ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
const int32 followedActorIdx = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
if ( engine - > _scene - > currentlyFollowedActor ! = followedActorIdx ) {
2020-10-26 01:59:37 +01:00
const ActorStruct * followedActor = engine - > _scene - > getActor ( followedActorIdx ) ;
2020-12-25 13:08:38 +01:00
engine - > _grid - > newCameraX = followedActor - > x / BRICK_SIZE ;
engine - > _grid - > newCameraY = followedActor - > y / BRICK_HEIGHT ;
engine - > _grid - > newCameraZ = followedActor - > z / BRICK_SIZE ;
2020-10-14 15:16:30 +02:00
engine - > _scene - > currentlyFollowedActor = followedActorIdx ;
2020-10-22 12:42:57 +02:00
engine - > _redraw - > reqBgRedraw = true ;
2020-10-14 15:16:30 +02:00
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set a new behavior for Twinsen ( Paramenter = Behavior Index )
* @ note Opcode @ c 0x1E
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_BEHAVIOUR ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-14 12:48:11 +01:00
const HeroBehaviourType behavior = ( HeroBehaviourType ) ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
2021-01-26 18:35:23 +01:00
engine - > _animations - > initAnim ( AnimationTypes : : kStanding , kAnimationTypeLoop , AnimationTypes : : kAnimInvalid , 0 ) ;
2020-10-14 15:16:30 +02:00
engine - > _actor - > setBehaviour ( behavior ) ;
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set a new value for the cube flag ( Paramter = Cube Flag Index , Parameter = Value )
* @ note Opcode @ c 0x1F
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_FLAG_CUBE ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
const int32 flagIdx = ctx . stream . readByte ( ) ;
const int32 flagValue = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
engine - > _scene - > sceneFlags [ flagIdx ] = flagValue ;
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set a new behaviour for the current actor . ( Paramter = Comportament number )
* @ note Opcode @ c 0x20
*/
2020-11-03 22:29:51 +01:00
static int32 lCOMPORTEMENT ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
ctx . stream . skip ( 1 ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set a new comportament for the current actor . ( Parameter = Comportament Offset )
* @ note Opcode @ c 0x21
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_COMPORTEMENT ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
ctx . actor - > positionInLifeScript = ctx . stream . readSint16LE ( ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set a new comportament for the actor passed as parameter . ( Paramter = Actor Index , Parameter = Comportament Offset )
* @ note Opcode @ c 0x22
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_COMPORTEMENT_OBJ ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
const int32 otherActorIdx = ctx . stream . readByte ( ) ;
engine - > _scene - > getActor ( otherActorIdx ) - > positionInLifeScript = ctx . stream . readSint16LE ( ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* End of comportament .
* @ note Opcode @ c 0x23
*/
2020-11-03 22:29:51 +01:00
static int32 lEND_COMPORTEMENT ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-14 15:16:30 +02:00
return 1 ; // break
}
2020-11-19 23:21:39 +01:00
/**
* Set a new value for the game flag ( Paramter = Game Flag Index , Parameter = Value )
* @ note Opcode @ c 0x24
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_FLAG_GAME ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-22 12:07:28 +01:00
const uint8 flagIdx = ctx . stream . readByte ( ) ;
const uint8 flagValue = ctx . stream . readByte ( ) ;
2021-01-07 21:53:40 +01:00
engine - > _gameState - > setGameFlag ( flagIdx , flagValue ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Kill the actor passed as paramenter ( Parameter = Actor Index )
* @ note Opcode @ c 0x25
*/
2020-11-03 22:29:51 +01:00
static int32 lKILL_OBJ ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
const int32 otherActorIdx = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
engine - > _actor - > processActorCarrier ( otherActorIdx ) ;
2020-11-03 20:17:03 +01:00
ActorStruct * otherActor = engine - > _scene - > getActor ( otherActorIdx ) ;
2020-10-26 20:07:38 +01:00
otherActor - > dynamicFlags . bIsDead = 1 ;
otherActor - > entity = - 1 ;
otherActor - > zone = - 1 ;
otherActor - > life = 0 ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Kill the current actor
* @ note Opcode @ c 0x26
*/
2020-11-03 22:29:51 +01:00
static int32 lSUICIDE ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-27 19:02:59 +01:00
engine - > _actor - > processActorCarrier ( ctx . actorIdx ) ;
ctx . actor - > dynamicFlags . bIsDead = 1 ;
ctx . actor - > entity = - 1 ;
ctx . actor - > zone = - 1 ;
ctx . actor - > life = 0 ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Use one key collected in the behaviors menu .
* @ note Opcode @ c 0x27
*/
2020-11-03 22:29:51 +01:00
static int32 lUSE_ONE_LITTLE_KEY ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-14 15:16:30 +02:00
engine - > _gameState - > inventoryNumKeys - - ;
if ( engine - > _gameState - > inventoryNumKeys < 0 ) {
engine - > _gameState - > inventoryNumKeys = 0 ;
}
2020-12-07 16:59:29 +01:00
engine - > _redraw - > addOverlay ( OverlayType : : koSprite , SPRITEHQR_KEY , 0 , 0 , 0 , OverlayPosType : : koFollowActor , 1 ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To give money . ( Paramenter = Amount )
* @ note Opcode @ c 0x28
*/
2020-11-03 22:29:51 +01:00
static int32 lGIVE_GOLD_PIECES ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-14 15:16:30 +02:00
int16 oldNumKashes = engine - > _gameState - > inventoryNumKashes ;
2020-10-27 19:02:59 +01:00
bool hideRange = false ;
2020-11-03 22:31:55 +01:00
int16 kashes = ctx . stream . readSint16LE ( ) ;
2020-10-14 15:16:30 +02:00
engine - > _gameState - > inventoryNumKashes - = kashes ;
if ( engine - > _gameState - > inventoryNumKashes < 0 ) {
engine - > _gameState - > inventoryNumKashes = 0 ;
}
2020-12-07 16:59:29 +01:00
engine - > _redraw - > addOverlay ( OverlayType : : koSprite , SPRITEHQR_KASHES , 10 , 15 , 0 , OverlayPosType : : koNormal , 3 ) ;
2020-10-14 15:16:30 +02:00
2020-10-26 20:07:38 +01:00
for ( int16 i = 0 ; i < OVERLAY_MAX_ENTRIES ; i + + ) {
2020-10-14 15:16:30 +02:00
OverlayListStruct * overlay = & engine - > _redraw - > overlayList [ i ] ;
2020-12-07 16:59:29 +01:00
if ( overlay - > info0 ! = - 1 & & overlay - > type = = OverlayType : : koNumberRange ) {
2020-10-14 15:16:30 +02:00
overlay - > info0 = engine - > _collision - > getAverageValue ( overlay - > info1 , overlay - > info0 , 100 , overlay - > lifeTime - engine - > lbaTime - 50 ) ;
overlay - > info1 = engine - > _gameState - > inventoryNumKashes ;
overlay - > lifeTime = engine - > lbaTime + 150 ;
2020-10-27 19:02:59 +01:00
hideRange = true ;
2020-10-14 15:16:30 +02:00
break ;
}
}
if ( ! hideRange ) {
2020-12-07 16:59:29 +01:00
engine - > _redraw - > addOverlay ( OverlayType : : koNumberRange , oldNumKashes , 50 , 20 , engine - > _gameState - > inventoryNumKashes , OverlayPosType : : koNormal , 3 ) ;
2020-10-14 15:16:30 +02:00
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* The game will not play the current actor script anymore
* @ note Opcode @ c 0x29
*/
2020-11-03 22:29:51 +01:00
static int32 lEND_LIFE ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-27 19:02:59 +01:00
ctx . actor - > positionInLifeScript = - 1 ;
2020-10-14 15:16:30 +02:00
return 1 ; // break;
}
2020-11-19 23:21:39 +01:00
/**
* The current actor will stop doing the track .
* @ note Opcode @ c 0x2A
*/
2020-11-03 22:29:51 +01:00
static int32 lSTOP_L_TRACK ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-27 19:02:59 +01:00
ctx . actor - > pausedTrackPtr = ctx . actor - > currentLabelPtr ;
ctx . actor - > positionInMoveScript = - 1 ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* The current actor will resume the tracked started before .
* @ note Opcode @ c 0x2B
*/
2020-11-03 22:29:51 +01:00
static int32 lRESTORE_L_TRACK ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-27 19:02:59 +01:00
ctx . actor - > positionInMoveScript = ctx . actor - > pausedTrackPtr ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* The actor passed as parameter will say that massage ( Parameter = Actor Index , Parameter = Text Index in the current Text Bank )
* @ note Opcode @ c 0x2C
*/
2020-11-03 22:29:51 +01:00
static int32 lMESSAGE_OBJ ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
const int32 otherActorIdx = ctx . stream . readByte ( ) ;
const int32 textIdx = ctx . stream . readSint16LE ( ) ;
2020-10-14 15:16:30 +02:00
engine - > freezeTime ( ) ;
if ( engine - > _text - > showDialogueBubble ) {
engine - > _redraw - > drawBubble ( otherActorIdx ) ;
}
2020-10-25 12:39:40 +01:00
engine - > _text - > setFontCrossColor ( engine - > _scene - > getActor ( otherActorIdx ) - > talkColor ) ;
2020-10-14 15:16:30 +02:00
engine - > _scene - > talkingActor = otherActorIdx ;
2021-01-30 14:16:23 +01:00
engine - > _text - > drawTextProgressive ( textIdx ) ;
2020-10-14 15:16:30 +02:00
engine - > unfreezeTime ( ) ;
2020-11-26 22:23:30 +01:00
engine - > _redraw - > redrawEngineActions ( true ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To increment the current chapter value
* @ note Opcode @ c 0x2D
*/
2020-11-03 22:29:51 +01:00
static int32 lINC_CHAPTER ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-14 15:16:30 +02:00
engine - > _gameState - > gameChapter + + ;
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Found an object . ( Parameter = Object Index )
* @ note Opcode @ c 0x2E
*/
2020-11-03 22:29:51 +01:00
static int32 lFOUND_OBJECT ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
const int32 item = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
engine - > _gameState - > processFoundItem ( item ) ;
2020-11-26 22:23:30 +01:00
engine - > _redraw - > redrawEngineActions ( true ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set a new value to open the door ( left way ) ( Parameter = distance to open ) .
* @ note Opcode @ c 0x2F
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_DOOR_LEFT ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 distance = ctx . stream . readSint16LE ( ) ;
2020-10-14 15:16:30 +02:00
2020-11-19 23:41:44 +01:00
ctx . actor - > angle = ANGLE_270 ;
2020-10-27 19:02:59 +01:00
ctx . actor - > x = ctx . actor - > lastX - distance ;
ctx . actor - > dynamicFlags . bIsSpriteMoving = 0 ;
ctx . actor - > speed = 0 ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set a new value to open the door ( right way ) ( Parameter = distance to open ) .
* @ note Opcode @ c 0x30
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_DOOR_RIGHT ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 distance = ctx . stream . readSint16LE ( ) ;
2020-10-14 15:16:30 +02:00
2020-11-19 23:41:44 +01:00
ctx . actor - > angle = ANGLE_90 ;
2020-10-27 19:02:59 +01:00
ctx . actor - > x = ctx . actor - > lastX + distance ;
ctx . actor - > dynamicFlags . bIsSpriteMoving = 0 ;
ctx . actor - > speed = 0 ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set a new value to open the door ( up way ) ( Parameter = distance to open ) .
* @ note Opcode @ c 0x31
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_DOOR_UP ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 distance = ctx . stream . readSint16LE ( ) ;
2020-10-14 15:16:30 +02:00
2020-11-19 23:41:44 +01:00
ctx . actor - > angle = ANGLE_180 ;
2020-10-27 19:02:59 +01:00
ctx . actor - > z = ctx . actor - > lastZ - distance ;
ctx . actor - > dynamicFlags . bIsSpriteMoving = 0 ;
ctx . actor - > speed = 0 ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set a new value to open the door ( down way ) ( Parameter = distance to open ) .
* @ note Opcode @ c 0x32
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_DOOR_DOWN ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 distance = ctx . stream . readSint16LE ( ) ;
2020-10-14 15:16:30 +02:00
2020-11-19 23:41:44 +01:00
ctx . actor - > angle = ANGLE_0 ;
2020-10-27 19:02:59 +01:00
ctx . actor - > z = ctx . actor - > lastZ + distance ;
ctx . actor - > dynamicFlags . bIsSpriteMoving = 0 ;
ctx . actor - > speed = 0 ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Give actor bonus . ( Parameter = 0 ( Don ' t change the actor bonus ) , > 0 ( Change to another bonus ) )
* @ note Opcode @ c 0x33
*/
2020-11-03 22:29:51 +01:00
static int32 lGIVE_BONUS ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 flag = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
2020-11-14 20:54:38 +01:00
if ( ctx . actor - > bonusParameter . cloverleaf | | ctx . actor - > bonusParameter . kashes | | ctx . actor - > bonusParameter . key | | ctx . actor - > bonusParameter . lifepoints | | ctx . actor - > bonusParameter . magicpoints ) {
2020-10-27 19:02:59 +01:00
engine - > _actor - > processActorExtraBonus ( ctx . actorIdx ) ;
2020-10-14 15:16:30 +02:00
}
if ( flag ! = 0 ) {
2020-11-14 20:54:38 +01:00
ctx . actor - > bonusParameter . unk1 = 1 ;
2020-10-14 15:16:30 +02:00
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Change to another room . ( Parameter = Scene Index )
* @ note Opcode @ c 0x34
*/
2020-11-03 22:29:51 +01:00
static int32 lCHANGE_CUBE ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 sceneIdx = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
engine - > _scene - > needChangeScene = sceneIdx ;
2020-10-24 18:32:22 +02:00
engine - > _scene - > heroPositionType = ScenePositionType : : kScene ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To set the current actor to collid with objects . ( Parameter = 1 ( True ) = other values ( False ) )
* @ note Opcode @ c 0x35
*/
2020-11-03 22:29:51 +01:00
static int32 lOBJ_COL ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 collision = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
if ( collision ! = 0 ) {
2020-10-27 19:02:59 +01:00
ctx . actor - > staticFlags . bComputeCollisionWithObj = 1 ;
2020-10-14 15:16:30 +02:00
} else {
2020-10-27 19:02:59 +01:00
ctx . actor - > staticFlags . bComputeCollisionWithObj = 0 ;
2020-10-14 15:16:30 +02:00
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To set the current actor to collid with bricks . ( Parameter = 1 ( True ) , = 2 ( True and the actor is dead ) , = other values ( False ) )
* @ note Opcode @ c 0x36
*/
2020-11-03 22:29:51 +01:00
static int32 lBRICK_COL ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 collision = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
2020-10-27 19:02:59 +01:00
ctx . actor - > staticFlags . bComputeCollisionWithBricks = 0 ;
ctx . actor - > staticFlags . bComputeLowCollision = 0 ;
2020-10-14 15:16:30 +02:00
if ( collision = = 1 ) {
2020-10-27 19:02:59 +01:00
ctx . actor - > staticFlags . bComputeCollisionWithBricks = 1 ;
2020-10-14 15:16:30 +02:00
} else if ( collision = = 2 ) {
2020-10-27 19:02:59 +01:00
ctx . actor - > staticFlags . bComputeCollisionWithBricks = 1 ;
ctx . actor - > staticFlags . bComputeLowCollision = 1 ;
2020-10-14 15:16:30 +02:00
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To use various conditions for the same IF statement . ( Use above an IF condition )
* @ note Opcode @ c 0x37
*/
2020-11-03 22:29:51 +01:00
static int32 lOR_IF ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-27 19:02:59 +01:00
int32 valueSize = processLifeConditions ( engine , ctx ) ;
2020-11-03 20:17:03 +01:00
if ( processLifeOperators ( engine , ctx , valueSize ) ) {
2020-11-03 22:31:55 +01:00
ctx . stream . seek ( ctx . stream . readSint16LE ( ) ) ; // condition offset
2020-10-14 15:16:30 +02:00
} else {
2020-11-03 22:31:55 +01:00
ctx . stream . skip ( 2 ) ;
2020-10-14 15:16:30 +02:00
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Put an actor invisible ( Parameter = 1 ( True ) , = 0 ( False ) )
* @ note Opcode @ c 0x38
*/
2020-11-03 22:29:51 +01:00
static int32 lINVISIBLE ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
ctx . actor - > staticFlags . bIsHidden = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Camara zoom in and zoom out . ( Parameter = 1 ( in ) = 0 ( out ) )
* @ note Opcode @ c 0x39
*/
2020-11-03 22:29:51 +01:00
static int32 lZOOM ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2021-02-10 18:37:55 +01:00
int zoomScreen = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
2021-02-10 18:37:55 +01:00
if ( zoomScreen & & ! engine - > _redraw - > inSceneryView & & engine - > cfgfile . SceZoom ) {
2020-10-21 19:53:01 +02:00
engine - > _screens - > fadeToBlack ( engine - > _screens - > mainPaletteRGBA ) ;
2021-02-10 18:37:55 +01:00
engine - > initSceneryView ( ) ;
2020-10-14 15:16:30 +02:00
engine - > _screens - > setBackPal ( ) ;
2020-10-22 12:42:57 +02:00
engine - > _screens - > lockPalette = true ;
2021-02-10 18:37:55 +01:00
} else if ( ! zoomScreen & & engine - > _redraw - > inSceneryView ) {
2020-10-21 19:53:01 +02:00
engine - > _screens - > fadeToBlack ( engine - > _screens - > mainPaletteRGBA ) ;
2021-02-10 18:37:55 +01:00
engine - > exitSceneryView ( ) ;
2020-10-14 15:16:30 +02:00
engine - > _screens - > setBackPal ( ) ;
2020-10-22 12:42:57 +02:00
engine - > _screens - > lockPalette = true ;
engine - > _redraw - > reqBgRedraw = true ;
2020-10-14 15:16:30 +02:00
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set new postion for the current actor ( Parameter = Track Index )
* @ note Opcode @ c 0x3A
*/
2020-11-03 22:29:51 +01:00
static int32 lPOS_POINT ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 trackIdx = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
2020-10-26 01:59:37 +01:00
const ScenePoint & sp = engine - > _scene - > sceneTracks [ trackIdx ] ;
2020-10-25 21:12:23 +01:00
engine - > _renderer - > destX = sp . x ;
engine - > _renderer - > destY = sp . y ;
engine - > _renderer - > destZ = sp . z ;
2020-10-27 19:02:59 +01:00
ctx . actor - > x = sp . x ;
ctx . actor - > y = sp . y ;
ctx . actor - > z = sp . z ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To set the magic level . ( Paramater = Magic Level )
* @ note Opcode @ c 0x3B
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_MAGIC_LEVEL ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
engine - > _gameState - > magicLevelIdx = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
engine - > _gameState - > inventoryMagicPoints = engine - > _gameState - > magicLevelIdx * 20 ;
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Substract the magic points . ( Parameter = Points Value )
* @ note Opcode @ c 0x3C
*/
2020-11-03 22:29:51 +01:00
static int32 lSUB_MAGIC_POINT ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
engine - > _gameState - > inventoryMagicPoints = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
if ( engine - > _gameState - > inventoryMagicPoints < 0 ) {
engine - > _gameState - > inventoryMagicPoints = 0 ;
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set new a life point . ( Parameter = Actor Index , Parameter = Points Value )
* @ note Opcode @ c 0x3D
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_LIFE_POINT_OBJ ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 otherActorIdx = ctx . stream . readByte ( ) ;
static int32 lifeValue = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
2020-10-25 12:39:40 +01:00
engine - > _scene - > getActor ( otherActorIdx ) - > life = lifeValue ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Substract the life points . ( Parameter = Actor Index , Parameter = Points Value )
* @ note Opcode @ c 0x3E
*/
2020-11-03 22:29:51 +01:00
static int32 lSUB_LIFE_POINT_OBJ ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 otherActorIdx = ctx . stream . readByte ( ) ;
static int32 lifeValue = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
2020-11-19 18:23:42 +01:00
ActorStruct * otherActor = engine - > _scene - > getActor ( otherActorIdx ) ;
otherActor - > life - = lifeValue ;
2020-10-14 15:16:30 +02:00
2020-11-19 18:23:42 +01:00
if ( otherActor - > life < 0 ) {
otherActor - > life = 0 ;
2020-10-14 15:16:30 +02:00
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Hit an actor . ( Parameter = Actor Index )
* @ note Opcode @ c 0x3F
*/
2020-11-03 22:29:51 +01:00
static int32 lHIT_OBJ ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 otherActorIdx = ctx . stream . readByte ( ) ;
int32 strengthOfHit = ctx . stream . readByte ( ) ;
2020-10-27 19:02:59 +01:00
engine - > _actor - > hitActor ( ctx . actorIdx , otherActorIdx , strengthOfHit , engine - > _scene - > getActor ( otherActorIdx ) - > angle ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Play FLA cutscenes ( Parameter = Cutscene Name )
* @ note Opcode @ c 0x40
*/
2020-11-03 22:29:51 +01:00
static int32 lPLAY_FLA ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int strIdx = 0 ;
char movie [ 64 ] ;
do {
const byte c = ctx . stream . readByte ( ) ;
2020-11-04 22:44:13 +01:00
movie [ strIdx + + ] = c ;
2020-11-03 22:31:55 +01:00
if ( c = = ' \0 ' ) {
break ;
}
if ( strIdx > = ARRAYSIZE ( movie ) ) {
error ( " Max string size exceeded for fla name " ) ;
}
} while ( true ) ;
2020-10-14 15:16:30 +02:00
engine - > _flaMovies - > playFlaMovie ( movie ) ;
2020-10-21 19:53:01 +02:00
engine - > setPalette ( engine - > _screens - > paletteRGBA ) ;
2020-10-14 15:16:30 +02:00
engine - > _screens - > clearScreen ( ) ;
engine - > flip ( ) ;
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Play Midis ( Parameter = Midis Index )
* @ note Opcode @ c 0x41
*/
2020-11-03 22:29:51 +01:00
static int32 lPLAY_MIDI ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 midiIdx = ctx . stream . readByte ( ) ;
2020-10-22 12:27:06 +02:00
engine - > _music - > playMidiMusic ( midiIdx ) ; // TODO: improve this
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To increment the clover box current value .
* @ note Opcode @ c 0x42
*/
2020-11-03 22:29:51 +01:00
static int32 lINC_CLOVER_BOX ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-14 15:16:30 +02:00
if ( engine - > _gameState - > inventoryNumLeafsBox < 10 ) {
engine - > _gameState - > inventoryNumLeafsBox + + ;
2021-02-17 20:53:40 +01:00
if ( engine - > _gameState - > inventoryNumLeafsBox = = 5 ) {
engine - > unlockAchievement ( " LBA_ACH_003 " ) ;
}
2020-10-14 15:16:30 +02:00
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To set an inventory object as used ( Parameter = Object Index )
* @ note Opcode @ c 0x43
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_USED_INVENTORY ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 item = ctx . stream . readByte ( ) ;
2020-11-03 20:12:15 +01:00
if ( item < InventoryItems : : kKeypad ) { // TODO: this looks wrong - why only up to keypad?
2020-10-14 15:16:30 +02:00
engine - > _gameState - > inventoryFlags [ item ] = 1 ;
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Add an option for the asked choice . ( Parameter = Text Index in the current Text Bank )
* @ note Opcode @ c 0x44
*/
2020-11-03 22:29:51 +01:00
static int32 lADD_CHOICE ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 choiceIdx = ctx . stream . readSint16LE ( ) ;
2020-10-14 15:16:30 +02:00
engine - > _gameState - > gameChoices [ engine - > _gameState - > numChoices + + ] = choiceIdx ;
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* The current actor will ask something ( parameter ) with choices to choose . ( Parameter = Text Index in the current Text Bank )
* @ note Opcode @ c 0x45
*/
2020-11-03 22:29:51 +01:00
static int32 lASK_CHOICE ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 choiceIdx = ctx . stream . readSint16LE ( ) ;
2020-10-14 15:16:30 +02:00
engine - > freezeTime ( ) ;
if ( engine - > _text - > showDialogueBubble ) {
2020-10-27 19:02:59 +01:00
engine - > _redraw - > drawBubble ( ctx . actorIdx ) ;
2020-10-14 15:16:30 +02:00
}
2020-10-27 19:02:59 +01:00
engine - > _text - > setFontCrossColor ( ctx . actor - > talkColor ) ;
2020-10-14 15:16:30 +02:00
engine - > _gameState - > processGameChoices ( choiceIdx ) ;
engine - > _gameState - > numChoices = 0 ;
engine - > unfreezeTime ( ) ;
2020-11-26 22:23:30 +01:00
engine - > _redraw - > redrawEngineActions ( true ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Show text in full screen . ( Parameter = Text Index in the current Text Bank )
* @ note Opcode @ c 0x46
*/
2020-11-03 22:29:51 +01:00
static int32 lBIG_MESSAGE ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 textIdx = ctx . stream . readSint16LE ( ) ;
2020-10-14 15:16:30 +02:00
engine - > freezeTime ( ) ;
engine - > _text - > textClipFull ( ) ;
if ( engine - > _text - > showDialogueBubble ) {
2020-10-27 19:02:59 +01:00
engine - > _redraw - > drawBubble ( ctx . actorIdx ) ;
2020-10-14 15:16:30 +02:00
}
2020-10-27 19:02:59 +01:00
engine - > _text - > setFontCrossColor ( ctx . actor - > talkColor ) ;
engine - > _scene - > talkingActor = ctx . actorIdx ;
2021-01-30 14:16:23 +01:00
engine - > _text - > drawTextProgressive ( textIdx ) ;
2020-10-14 15:16:30 +02:00
engine - > _text - > textClipSmall ( ) ;
engine - > unfreezeTime ( ) ;
2020-11-26 22:23:30 +01:00
engine - > _redraw - > redrawEngineActions ( true ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To initiate the hidden meca - pingouin in the current scene . ( Parameter = Actor Index )
* @ note Opcode @ c 0x47
*/
2020-11-03 22:29:51 +01:00
static int32 lINIT_PINGOUIN ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 pingouinActor = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
engine - > _scene - > mecaPinguinIdx = pingouinActor ;
2020-10-26 01:59:37 +01:00
ActorStruct * mecaPinguin = engine - > _scene - > getActor ( pingouinActor ) ;
2020-10-25 12:39:40 +01:00
mecaPinguin - > dynamicFlags . bIsDead = 1 ;
mecaPinguin - > entity = - 1 ;
mecaPinguin - > zone = - 1 ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To set an holomap position . ( Parameter = Holomap / Scene Index )
* @ note Opcode @ c 0x48
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_HOLO_POS ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
static int32 location = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
engine - > _holomap - > setHolomapPosition ( location ) ;
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To clear an holomap position . ( Parameter = Holomap / Scene Index )
* @ note Opcode @ c 0x49
*/
2020-11-03 22:29:51 +01:00
static int32 lCLR_HOLO_POS ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
static int32 location = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
engine - > _holomap - > clearHolomapPosition ( location ) ;
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Add to the current fuel value the passed parameter . ( Parameter = Fuel Amount )
* @ note Opcode @ c 0x4A
*/
2020-11-03 22:29:51 +01:00
static int32 lADD_FUEL ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
engine - > _gameState - > inventoryNumGas + = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
if ( engine - > _gameState - > inventoryNumGas > 100 ) {
engine - > _gameState - > inventoryNumGas = 100 ;
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Substract the to fuel value the value passed as parameter . ( Parameter = Fuel Amount )
* @ note Opcode @ c 0x4B
*/
2020-11-03 22:29:51 +01:00
static int32 lSUB_FUEL ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
engine - > _gameState - > inventoryNumGas - = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
if ( engine - > _gameState - > inventoryNumGas < 0 ) {
engine - > _gameState - > inventoryNumGas = 0 ;
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To set a GRID disappearing ceiling piece ( Parameter = Disappearing ceiling piece Index )
* @ note Opcode @ c 0x4C
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_GRM ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
engine - > _grid - > cellingGridIdx = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
engine - > _grid - > initCellingGrid ( engine - > _grid - > cellingGridIdx ) ;
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* The current actor will say the message passed as paramenter . ( Parameter = Actor Index )
* @ note Opcode @ c 0x4D
*/
2020-11-03 22:29:51 +01:00
static int32 lSAY_MESSAGE ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int16 textEntry = ctx . stream . readSint16LE ( ) ;
2020-10-14 15:16:30 +02:00
2020-12-07 16:59:29 +01:00
engine - > _redraw - > addOverlay ( OverlayType : : koText , textEntry , 0 , 0 , ctx . actorIdx , OverlayPosType : : koFollowActor , 2 ) ;
2020-10-14 15:16:30 +02:00
2020-11-02 23:09:27 +01:00
ScopedEngineFreeze scoped ( engine ) ;
2020-10-14 15:16:30 +02:00
engine - > _text - > initVoxToPlay ( textEntry ) ;
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* The actor passed as parameter will say the message passed as paramenter . ( Parameter = Actor Index , Parameter = Text Index in the current Text Bank )
* @ note Opcode @ c 0x4E
*/
2020-11-03 22:29:51 +01:00
static int32 lSAY_MESSAGE_OBJ ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 otherActorIdx = ctx . stream . readByte ( ) ;
int16 textEntry = ctx . stream . readSint16LE ( ) ;
2020-10-14 15:16:30 +02:00
2020-12-07 16:59:29 +01:00
engine - > _redraw - > addOverlay ( OverlayType : : koText , textEntry , 0 , 0 , otherActorIdx , OverlayPosType : : koFollowActor , 2 ) ;
2020-10-14 15:16:30 +02:00
2020-11-02 23:09:27 +01:00
ScopedEngineFreeze scoped ( engine ) ;
2020-10-14 15:16:30 +02:00
engine - > _text - > initVoxToPlay ( textEntry ) ;
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set Twinsen life point as full .
* @ note Opcode @ c 0x4F
*/
2020-11-03 22:29:51 +01:00
static int32 lFULL_POINT ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-14 15:16:30 +02:00
engine - > _scene - > sceneHero - > life = 50 ;
engine - > _gameState - > inventoryMagicPoints = engine - > _gameState - > magicLevelIdx * 20 ;
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Change actor orientation . ( Parameter = New Angle )
* @ note Opcode @ c 0x50
*/
2020-11-03 22:29:51 +01:00
static int32 lBETA ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 newAngle = ctx . stream . readSint16LE ( ) ;
2020-11-19 23:41:44 +01:00
ctx . actor - > angle = ToAngle ( newAngle ) ;
2020-10-27 19:02:59 +01:00
engine - > _movements - > clearRealAngle ( ctx . actor ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* To unset the GRID disappearing ceiling piece .
* @ note Opcode @ c 0x51
*/
2020-11-03 22:29:51 +01:00
static int32 lGRM_OFF ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-14 15:16:30 +02:00
if ( engine - > _grid - > cellingGridIdx ! = - 1 ) {
engine - > _grid - > useCellingGrid = - 1 ;
engine - > _grid - > cellingGridIdx = - 1 ;
engine - > _grid - > createGridMap ( ) ;
2020-11-26 22:23:30 +01:00
engine - > _redraw - > redrawEngineActions ( true ) ;
2020-10-14 15:16:30 +02:00
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Fade palette to red
* @ note Opcode @ c 0x52
*/
2020-11-03 22:29:51 +01:00
static int32 lFADE_PAL_RED ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-02 23:09:27 +01:00
ScopedEngineFreeze scoped ( engine ) ;
2020-10-21 19:53:01 +02:00
engine - > _screens - > fadePalRed ( engine - > _screens - > mainPaletteRGBA ) ;
2020-10-22 12:42:57 +02:00
engine - > _screens - > useAlternatePalette = false ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Fade alarm to red
* @ note Opcode @ c 0x53
*/
2020-11-03 22:29:51 +01:00
static int32 lFADE_ALARM_RED ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-02 23:09:27 +01:00
ScopedEngineFreeze scoped ( engine ) ;
2020-10-30 20:09:28 +01:00
HQR : : getEntry ( engine - > _screens - > palette , Resources : : HQR_RESS_FILE , RESSHQR_ALARMREDPAL ) ;
2020-10-21 19:53:01 +02:00
engine - > _screens - > convertPalToRGBA ( engine - > _screens - > palette , engine - > _screens - > paletteRGBA ) ;
engine - > _screens - > fadePalRed ( engine - > _screens - > paletteRGBA ) ;
2020-10-22 12:42:57 +02:00
engine - > _screens - > useAlternatePalette = true ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Fade alarm to palette
* @ note Opcode @ c 0x54
*/
2020-11-03 22:29:51 +01:00
static int32 lFADE_ALARM_PAL ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-02 23:09:27 +01:00
ScopedEngineFreeze scoped ( engine ) ;
2020-10-30 20:09:28 +01:00
HQR : : getEntry ( engine - > _screens - > palette , Resources : : HQR_RESS_FILE , RESSHQR_ALARMREDPAL ) ;
2020-10-21 19:53:01 +02:00
engine - > _screens - > convertPalToRGBA ( engine - > _screens - > palette , engine - > _screens - > paletteRGBA ) ;
engine - > _screens - > adjustCrossPalette ( engine - > _screens - > paletteRGBA , engine - > _screens - > mainPaletteRGBA ) ;
2020-10-22 12:42:57 +02:00
engine - > _screens - > useAlternatePalette = false ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Fade red to palette
* @ note Opcode @ c 0x55
*/
2020-11-03 22:29:51 +01:00
static int32 lFADE_RED_PAL ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-02 23:09:27 +01:00
ScopedEngineFreeze scoped ( engine ) ;
2020-10-21 19:53:01 +02:00
engine - > _screens - > fadeRedPal ( engine - > _screens - > mainPaletteRGBA ) ;
2020-10-22 12:42:57 +02:00
engine - > _screens - > useAlternatePalette = false ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Fade red to alarm
* @ note Opcode @ c 0x56
*/
2020-11-03 22:29:51 +01:00
static int32 lFADE_RED_ALARM ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-02 23:09:27 +01:00
ScopedEngineFreeze scoped ( engine ) ;
2020-10-30 20:09:28 +01:00
HQR : : getEntry ( engine - > _screens - > palette , Resources : : HQR_RESS_FILE , RESSHQR_ALARMREDPAL ) ;
2020-10-21 19:53:01 +02:00
engine - > _screens - > convertPalToRGBA ( engine - > _screens - > palette , engine - > _screens - > paletteRGBA ) ;
engine - > _screens - > fadeRedPal ( engine - > _screens - > paletteRGBA ) ;
2020-10-22 12:42:57 +02:00
engine - > _screens - > useAlternatePalette = true ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Fade palette to alarm
* @ note Opcode @ c 0x57
*/
2020-11-03 22:29:51 +01:00
static int32 lFADE_PAL_ALARM ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-02 23:09:27 +01:00
ScopedEngineFreeze scoped ( engine ) ;
2020-10-30 20:09:28 +01:00
HQR : : getEntry ( engine - > _screens - > palette , Resources : : HQR_RESS_FILE , RESSHQR_ALARMREDPAL ) ;
2020-10-21 19:53:01 +02:00
engine - > _screens - > convertPalToRGBA ( engine - > _screens - > palette , engine - > _screens - > paletteRGBA ) ;
engine - > _screens - > adjustCrossPalette ( engine - > _screens - > mainPaletteRGBA , engine - > _screens - > paletteRGBA ) ;
2020-10-22 12:42:57 +02:00
engine - > _screens - > useAlternatePalette = true ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Explode an object . ( Parameter = Object Index )
* @ note Opcode @ c 0x58
*/
2020-11-03 22:29:51 +01:00
static int32 lEXPLODE_OBJ ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 otherActorIdx = ctx . stream . readByte ( ) ;
2020-10-25 12:39:40 +01:00
ActorStruct * otherActor = engine - > _scene - > getActor ( otherActorIdx ) ;
2020-10-14 15:16:30 +02:00
engine - > _extra - > addExtraExplode ( otherActor - > x , otherActor - > y , otherActor - > z ) ; // RECHECK this
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Turn on bubbles while actors talk .
* @ note Opcode @ c 0x59
*/
2020-11-03 22:29:51 +01:00
static int32 lBUBBLE_ON ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-06 16:44:03 +01:00
engine - > _text - > showDialogueBubble = true ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Turn off bubbles while actors talk .
* @ note Opcode @ c 0x5A
*/
2020-11-03 22:29:51 +01:00
static int32 lBUBBLE_OFF ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-06 16:44:03 +01:00
engine - > _text - > showDialogueBubble = true ; // TODO: this looks wrong - why true and not false?
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* The actor will ask something with choices to choose . ( Parameter = Actor Index , Parameter = Text Index in the current Text Bank )
* @ note Opcode @ c 0x5B
*/
2020-11-03 22:29:51 +01:00
static int32 lASK_CHOICE_OBJ ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 otherActorIdx = ctx . stream . readByte ( ) ;
int32 choiceIdx = ctx . stream . readSint16LE ( ) ;
2020-10-14 15:16:30 +02:00
engine - > freezeTime ( ) ;
if ( engine - > _text - > showDialogueBubble ) {
engine - > _redraw - > drawBubble ( otherActorIdx ) ;
}
2020-10-25 12:39:40 +01:00
engine - > _text - > setFontCrossColor ( engine - > _scene - > getActor ( otherActorIdx ) - > talkColor ) ;
2020-10-14 15:16:30 +02:00
engine - > _gameState - > processGameChoices ( choiceIdx ) ;
engine - > _gameState - > numChoices = 0 ;
engine - > unfreezeTime ( ) ;
2020-11-26 22:23:30 +01:00
engine - > _redraw - > redrawEngineActions ( true ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set a dark palette .
* @ note Opcode @ c 0x5C
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_DARK_PAL ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-02 23:09:27 +01:00
ScopedEngineFreeze scoped ( engine ) ;
2020-10-30 20:09:28 +01:00
HQR : : getEntry ( engine - > _screens - > palette , Resources : : HQR_RESS_FILE , RESSHQR_DARKPAL ) ;
2020-10-14 15:16:30 +02:00
if ( ! engine - > _screens - > lockPalette ) {
2020-10-21 19:53:01 +02:00
engine - > _screens - > convertPalToRGBA ( engine - > _screens - > palette , engine - > _screens - > paletteRGBA ) ;
engine - > setPalette ( engine - > _screens - > paletteRGBA ) ;
2020-10-14 15:16:30 +02:00
}
2020-10-22 12:42:57 +02:00
engine - > _screens - > useAlternatePalette = true ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set main palette .
* @ note Opcode @ c 0x5D
*/
2020-11-03 22:29:51 +01:00
static int32 lSET_NORMAL_PAL ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-22 12:42:57 +02:00
engine - > _screens - > useAlternatePalette = false ;
2020-10-14 15:16:30 +02:00
if ( ! engine - > _screens - > lockPalette ) {
2020-10-21 19:53:01 +02:00
engine - > setPalette ( engine - > _screens - > mainPaletteRGBA ) ;
2020-10-14 15:16:30 +02:00
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Show Sendell message .
* @ note Opcode @ c 0x5E
*/
2020-11-03 22:29:51 +01:00
static int32 lMESSAGE_SENDELL ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-02 23:09:27 +01:00
ScopedEngineFreeze scoped ( engine ) ;
2020-10-21 19:53:01 +02:00
engine - > _screens - > fadeToBlack ( engine - > _screens - > paletteRGBA ) ;
2020-12-22 14:06:06 +01:00
engine - > _screens - > loadImage ( RESSHQR_TWINSEN_ZOE_SENDELLIMG , RESSHQR_TWINSEN_ZOE_SENDELLPAL ) ;
2020-10-14 15:16:30 +02:00
engine - > _text - > textClipFull ( ) ;
2021-01-08 21:18:41 +01:00
engine - > _text - > setFontCrossColor ( COLOR_WHITE ) ;
2020-11-22 12:36:35 +01:00
engine - > _text - > drawTextBoxBackground = false ;
2020-10-24 14:26:50 +02:00
const bool tmpFlagDisplayText = engine - > cfgfile . FlagDisplayText ;
engine - > cfgfile . FlagDisplayText = true ;
2021-01-30 14:16:23 +01:00
engine - > _text - > drawTextProgressive ( TextId : : kSendell ) ;
2021-01-08 21:18:41 +01:00
engine - > cfgfile . FlagDisplayText = tmpFlagDisplayText ;
2020-11-22 12:36:35 +01:00
engine - > _text - > drawTextBoxBackground = true ;
2020-10-14 15:16:30 +02:00
engine - > _text - > textClipSmall ( ) ;
2020-10-21 19:53:01 +02:00
engine - > _screens - > fadeToBlack ( engine - > _screens - > paletteRGBACustom ) ;
2020-10-14 15:16:30 +02:00
engine - > _screens - > clearScreen ( ) ;
2020-10-21 19:53:01 +02:00
engine - > setPalette ( engine - > _screens - > paletteRGBA ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set new animation for the current actor ( Parameter = Animation Index )
* @ note Opcode @ c 0x5F
*/
2020-11-03 22:29:51 +01:00
static int32 lANIM_SET ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
AnimationTypes animIdx = ( AnimationTypes ) ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
2020-11-14 12:24:16 +01:00
ctx . actor - > anim = AnimationTypes : : kAnimNone ;
2020-10-27 19:02:59 +01:00
ctx . actor - > previousAnimIdx = - 1 ;
2021-01-26 18:35:23 +01:00
engine - > _animations - > initAnim ( animIdx , kAnimationTypeLoop , AnimationTypes : : kStanding , ctx . actorIdx ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Displays holomap travel animation . ( Parameter = Trajectory )
* @ note Opcode @ c 0x60
*/
2020-11-03 22:29:51 +01:00
static int32 lHOLOMAP_TRAJ ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2021-01-24 16:54:30 +01:00
engine - > _scene - > holomapTrajectory = ctx . stream . readByte ( ) ;
2020-11-21 19:31:22 +01:00
return 0 ;
2020-10-14 15:16:30 +02:00
}
2020-11-19 23:21:39 +01:00
/**
* Game over .
* @ note Opcode @ c 0x61
*/
2020-11-03 22:29:51 +01:00
static int32 lGAME_OVER ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-14 15:16:30 +02:00
engine - > _scene - > sceneHero - > dynamicFlags . bAnimEnded = 1 ;
engine - > _scene - > sceneHero - > life = 0 ;
engine - > _gameState - > inventoryNumLeafs = 0 ;
return 1 ; // break
}
2020-11-19 23:21:39 +01:00
/**
* End of the game .
* @ note Opcode @ c 0x62
*/
2020-11-03 22:29:51 +01:00
static int32 lTHE_END ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-14 15:16:30 +02:00
engine - > quitGame = 1 ;
engine - > _gameState - > inventoryNumLeafs = 0 ;
engine - > _scene - > sceneHero - > life = 50 ;
engine - > _gameState - > inventoryMagicPoints = 80 ;
2020-10-26 00:13:54 +01:00
engine - > _scene - > currentSceneIdx = LBA1SceneId : : Polar_Island_Final_Battle ;
2020-10-14 15:16:30 +02:00
engine - > _actor - > heroBehaviour = engine - > _actor - > previousHeroBehaviour ;
engine - > _scene - > newHeroX = - 1 ;
engine - > _scene - > sceneHero - > angle = engine - > _actor - > previousHeroAngle ;
2020-10-26 00:13:54 +01:00
engine - > autoSave ( ) ;
2020-10-14 15:16:30 +02:00
return 1 ; // break;
}
2020-11-19 23:21:39 +01:00
/**
* Stop the current played midi .
* @ note Opcode @ c 0x63
*/
2020-11-03 22:29:51 +01:00
static int32 lMIDI_OFF ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-14 15:16:30 +02:00
engine - > _music - > stopMidiMusic ( ) ;
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Play a CD Track ( Paramenter = CD Track ) .
* @ note Opcode @ c 0x64
*/
2020-11-03 22:29:51 +01:00
static int32 lPLAY_CD_TRACK ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 track = ctx . stream . readByte ( ) ;
2020-10-14 15:16:30 +02:00
engine - > _music - > playTrackMusic ( track ) ;
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set isometric projections
* @ note Opcode @ c 0x65
*/
2020-11-03 22:29:51 +01:00
static int32 lPROJ_ISO ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2021-01-08 08:14:39 +01:00
engine - > _gameState - > initEngineProjections ( ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Set 3 D projections
* @ note Opcode @ c 0x66
*/
2020-11-03 22:29:51 +01:00
static int32 lPROJ_3D ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2021-01-08 08:29:41 +01:00
// TODO: only used for credits scene? If not, then move the credits related code into the menu->showCredits method
2020-10-14 15:16:30 +02:00
engine - > _screens - > copyScreen ( engine - > frontVideoBuffer , engine - > workVideoBuffer ) ;
engine - > flip ( ) ;
2021-01-08 08:29:41 +01:00
engine - > _scene - > enableGridTileRendering = false ;
2020-10-14 15:16:30 +02:00
2021-01-07 21:17:53 +01:00
engine - > _renderer - > setCameraPosition ( engine - > width ( ) / 2 , engine - > height ( ) / 2 , 128 , 1024 , 1024 ) ;
2020-10-14 15:16:30 +02:00
engine - > _renderer - > setCameraAngle ( 0 , 1500 , 0 , 25 , - 128 , 0 , 13000 ) ;
2021-01-08 21:55:47 +01:00
engine - > _renderer - > setLightVector ( ANGLE_315 , ANGLE_334 , ANGLE_0 ) ;
2020-10-14 15:16:30 +02:00
2020-11-01 22:35:29 +01:00
engine - > _text - > initTextBank ( TextBankId : : Credits ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Only display the text . ( e . g . like in the credit list ) ( Parameter = Text Index in the current Text Bank )
* @ note Opcode @ c 0x67
*/
2020-11-03 22:29:51 +01:00
static int32 lTEXT ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-11-03 22:31:55 +01:00
int32 textIdx = ctx . stream . readSint16LE ( ) ;
2020-10-14 15:16:30 +02:00
2021-01-08 19:44:35 +01:00
const int32 textHeight = 40 ;
2021-01-08 19:49:34 +01:00
if ( lTextYPos < engine - > height ( ) - textHeight ) {
2020-10-14 15:16:30 +02:00
if ( engine - > cfgfile . Version = = USA_VERSION ) {
if ( ! textIdx ) {
2020-10-28 19:48:45 +01:00
textIdx = TextId : : kSaveSettings ;
2020-10-14 15:16:30 +02:00
}
}
2020-11-19 23:21:39 +01:00
char textStr [ 256 ] ;
2020-10-14 15:16:30 +02:00
engine - > _text - > getMenuText ( textIdx , textStr , sizeof ( textStr ) ) ;
2020-10-25 23:16:17 +01:00
int32 textSize = engine - > _text - > getTextSize ( textStr ) ;
int32 textBoxRight = textSize ;
2021-01-08 19:49:34 +01:00
int32 textBoxBottom = lTextYPos + textHeight ;
2021-01-08 19:44:19 +01:00
engine - > _text - > setFontColor ( COLOR_WHITE ) ;
2021-01-08 19:49:34 +01:00
engine - > _text - > drawText ( 0 , lTextYPos , textStr ) ;
2021-01-07 21:17:53 +01:00
if ( textSize > engine - > width ( ) - 1 ) {
textBoxRight = engine - > width ( ) - 1 ;
2020-10-14 15:16:30 +02:00
}
2021-01-08 19:49:34 +01:00
engine - > copyBlockPhys ( 0 , lTextYPos , textBoxRight , textBoxBottom ) ;
lTextYPos + = textHeight ;
2020-10-14 15:16:30 +02:00
}
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Clear displayed text in the screen .
* @ note Opcode @ c 0x68
*/
2020-11-03 22:29:51 +01:00
static int32 lCLEAR_TEXT ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2021-01-08 19:49:34 +01:00
lTextYPos = 0 ;
2021-01-07 21:17:53 +01:00
const Common : : Rect rect ( 0 , 0 , engine - > width ( ) - 1 , engine - > height ( ) / 2 ) ;
2021-01-30 14:35:12 +01:00
engine - > _interface - > drawFilledRect ( rect , COLOR_BLACK ) ;
2020-11-25 18:20:38 +01:00
engine - > copyBlockPhys ( rect ) ;
2020-10-14 15:16:30 +02:00
return 0 ;
}
2020-11-19 23:21:39 +01:00
/**
* Exit the script execution .
* @ note Opcode @ c 0x69
*/
2020-11-03 22:29:51 +01:00
static int32 lBRUTAL_EXIT ( TwinEEngine * engine , LifeScriptContext & ctx ) {
2020-10-14 15:16:30 +02:00
engine - > quitGame = 0 ;
return 1 ; // break
}
static const ScriptLifeFunction function_map [ ] = {
/*0x00*/ MAPFUNC ( " END " , lEND ) ,
/*0x01*/ MAPFUNC ( " NOP " , lNOP ) ,
/*0x02*/ MAPFUNC ( " SNIF " , lSNIF ) ,
/*0x03*/ MAPFUNC ( " OFFSET " , lOFFSET ) ,
/*0x04*/ MAPFUNC ( " NEVERIF " , lNEVERIF ) ,
/*0x05*/ MAPFUNC ( " " , lEMPTY ) , // unused
/*0x06*/ MAPFUNC ( " NO_IF " , lNO_IF ) ,
/*0x07*/ MAPFUNC ( " " , lEMPTY ) , // unused
/*0x08*/ MAPFUNC ( " " , lEMPTY ) , // unused
/*0x09*/ MAPFUNC ( " " , lEMPTY ) , // unused
/*0x0A*/ MAPFUNC ( " LABEL " , lLABEL ) ,
/*0x0B*/ MAPFUNC ( " RETURN " , lRETURN ) ,
/*0x0C*/ MAPFUNC ( " IF " , lIF ) ,
/*0x0D*/ MAPFUNC ( " SWIF " , lSWIF ) ,
/*0x0E*/ MAPFUNC ( " ONEIF " , lONEIF ) ,
/*0x0F*/ MAPFUNC ( " ELSE " , lELSE ) ,
2020-11-19 23:21:39 +01:00
/*0x10*/ MAPFUNC ( " ENDIF " , lEMPTY ) , // End of a conditional statement (e.g. IF)
2020-10-14 15:16:30 +02:00
/*0x11*/ MAPFUNC ( " BODY " , lBODY ) ,
/*0x12*/ MAPFUNC ( " BODY_OBJ " , lBODY_OBJ ) ,
/*0x13*/ MAPFUNC ( " ANIM " , lANIM ) ,
/*0x14*/ MAPFUNC ( " ANIM_OBJ " , lANIM_OBJ ) ,
/*0x15*/ MAPFUNC ( " SET_LIFE " , lSET_LIFE ) ,
/*0x16*/ MAPFUNC ( " SET_LIFE_OBJ " , lSET_LIFE_OBJ ) ,
/*0x17*/ MAPFUNC ( " SET_TRACK " , lSET_TRACK ) ,
/*0x18*/ MAPFUNC ( " SET_TRACK_OBJ " , lSET_TRACK_OBJ ) ,
/*0x19*/ MAPFUNC ( " MESSAGE " , lMESSAGE ) ,
/*0x1A*/ MAPFUNC ( " FALLABLE " , lFALLABLE ) ,
/*0x1B*/ MAPFUNC ( " SET_DIRMODE " , lSET_DIRMODE ) ,
/*0x1C*/ MAPFUNC ( " SET_DIRMODE_OBJ " , lSET_DIRMODE_OBJ ) ,
/*0x1D*/ MAPFUNC ( " CAM_FOLLOW " , lCAM_FOLLOW ) ,
/*0x1E*/ MAPFUNC ( " SET_BEHAVIOUR " , lSET_BEHAVIOUR ) ,
/*0x1F*/ MAPFUNC ( " SET_FLAG_CUBE " , lSET_FLAG_CUBE ) ,
/*0x20*/ MAPFUNC ( " COMPORTEMENT " , lCOMPORTEMENT ) ,
/*0x21*/ MAPFUNC ( " SET_COMPORTEMENT " , lSET_COMPORTEMENT ) ,
/*0x22*/ MAPFUNC ( " SET_COMPORTEMENT_OBJ " , lSET_COMPORTEMENT_OBJ ) ,
/*0x23*/ MAPFUNC ( " END_COMPORTEMENT " , lEND_COMPORTEMENT ) ,
/*0x24*/ MAPFUNC ( " SET_FLAG_GAME " , lSET_FLAG_GAME ) ,
/*0x25*/ MAPFUNC ( " KILL_OBJ " , lKILL_OBJ ) ,
/*0x26*/ MAPFUNC ( " SUICIDE " , lSUICIDE ) ,
/*0x27*/ MAPFUNC ( " USE_ONE_LITTLE_KEY " , lUSE_ONE_LITTLE_KEY ) ,
/*0x28*/ MAPFUNC ( " GIVE_GOLD_PIECES " , lGIVE_GOLD_PIECES ) ,
/*0x29*/ MAPFUNC ( " END_LIFE " , lEND_LIFE ) ,
/*0x2A*/ MAPFUNC ( " STOP_L_TRACK " , lSTOP_L_TRACK ) ,
/*0x2B*/ MAPFUNC ( " RESTORE_L_TRACK " , lRESTORE_L_TRACK ) ,
/*0x2C*/ MAPFUNC ( " MESSAGE_OBJ " , lMESSAGE_OBJ ) ,
/*0x2D*/ MAPFUNC ( " INC_CHAPTER " , lINC_CHAPTER ) ,
/*0x2E*/ MAPFUNC ( " FOUND_OBJECT " , lFOUND_OBJECT ) ,
/*0x2F*/ MAPFUNC ( " SET_DOOR_LEFT " , lSET_DOOR_LEFT ) ,
/*0x30*/ MAPFUNC ( " SET_DOOR_RIGHT " , lSET_DOOR_RIGHT ) ,
/*0x31*/ MAPFUNC ( " SET_DOOR_UP " , lSET_DOOR_UP ) ,
/*0x32*/ MAPFUNC ( " SET_DOOR_DOWN " , lSET_DOOR_DOWN ) ,
/*0x33*/ MAPFUNC ( " GIVE_BONUS " , lGIVE_BONUS ) ,
/*0x34*/ MAPFUNC ( " CHANGE_CUBE " , lCHANGE_CUBE ) ,
/*0x35*/ MAPFUNC ( " OBJ_COL " , lOBJ_COL ) ,
/*0x36*/ MAPFUNC ( " BRICK_COL " , lBRICK_COL ) ,
/*0x37*/ MAPFUNC ( " OR_IF " , lOR_IF ) ,
/*0x38*/ MAPFUNC ( " INVISIBLE " , lINVISIBLE ) ,
/*0x39*/ MAPFUNC ( " ZOOM " , lZOOM ) ,
/*0x3A*/ MAPFUNC ( " POS_POINT " , lPOS_POINT ) ,
/*0x3B*/ MAPFUNC ( " SET_MAGIC_LEVEL " , lSET_MAGIC_LEVEL ) ,
/*0x3C*/ MAPFUNC ( " SUB_MAGIC_POINT " , lSUB_MAGIC_POINT ) ,
/*0x3D*/ MAPFUNC ( " SET_LIFE_POINT_OBJ " , lSET_LIFE_POINT_OBJ ) ,
/*0x3E*/ MAPFUNC ( " SUB_LIFE_POINT_OBJ " , lSUB_LIFE_POINT_OBJ ) ,
/*0x3F*/ MAPFUNC ( " HIT_OBJ " , lHIT_OBJ ) ,
/*0x40*/ MAPFUNC ( " PLAY_FLA " , lPLAY_FLA ) ,
/*0x41*/ MAPFUNC ( " PLAY_MIDI " , lPLAY_MIDI ) ,
/*0x42*/ MAPFUNC ( " INC_CLOVER_BOX " , lINC_CLOVER_BOX ) ,
/*0x43*/ MAPFUNC ( " SET_USED_INVENTORY " , lSET_USED_INVENTORY ) ,
/*0x44*/ MAPFUNC ( " ADD_CHOICE " , lADD_CHOICE ) ,
/*0x45*/ MAPFUNC ( " ASK_CHOICE " , lASK_CHOICE ) ,
/*0x46*/ MAPFUNC ( " BIG_MESSAGE " , lBIG_MESSAGE ) ,
/*0x47*/ MAPFUNC ( " INIT_PINGOUIN " , lINIT_PINGOUIN ) ,
/*0x48*/ MAPFUNC ( " SET_HOLO_POS " , lSET_HOLO_POS ) ,
/*0x49*/ MAPFUNC ( " CLR_HOLO_POS " , lCLR_HOLO_POS ) ,
/*0x4A*/ MAPFUNC ( " ADD_FUEL " , lADD_FUEL ) ,
/*0x4B*/ MAPFUNC ( " SUB_FUEL " , lSUB_FUEL ) ,
/*0x4C*/ MAPFUNC ( " SET_GRM " , lSET_GRM ) ,
/*0x4D*/ MAPFUNC ( " SAY_MESSAGE " , lSAY_MESSAGE ) ,
/*0x4E*/ MAPFUNC ( " SAY_MESSAGE_OBJ " , lSAY_MESSAGE_OBJ ) ,
/*0x4F*/ MAPFUNC ( " FULL_POINT " , lFULL_POINT ) ,
/*0x50*/ MAPFUNC ( " BETA " , lBETA ) ,
/*0x51*/ MAPFUNC ( " GRM_OFF " , lGRM_OFF ) ,
/*0x52*/ MAPFUNC ( " FADE_PAL_RED " , lFADE_PAL_RED ) ,
/*0x53*/ MAPFUNC ( " FADE_ALARM_RED " , lFADE_ALARM_RED ) ,
/*0x54*/ MAPFUNC ( " FADE_ALARM_PAL " , lFADE_ALARM_PAL ) ,
/*0x55*/ MAPFUNC ( " FADE_RED_PAL " , lFADE_RED_PAL ) ,
/*0x56*/ MAPFUNC ( " FADE_RED_ALARM " , lFADE_RED_ALARM ) ,
/*0x57*/ MAPFUNC ( " FADE_PAL_ALARM " , lFADE_PAL_ALARM ) ,
/*0x58*/ MAPFUNC ( " EXPLODE_OBJ " , lEXPLODE_OBJ ) ,
/*0x59*/ MAPFUNC ( " BUBBLE_ON " , lBUBBLE_ON ) ,
/*0x5A*/ MAPFUNC ( " BUBBLE_OFF " , lBUBBLE_OFF ) ,
/*0x5B*/ MAPFUNC ( " ASK_CHOICE_OBJ " , lASK_CHOICE_OBJ ) ,
/*0x5C*/ MAPFUNC ( " SET_DARK_PAL " , lSET_DARK_PAL ) ,
/*0x5D*/ MAPFUNC ( " SET_NORMAL_PAL " , lSET_NORMAL_PAL ) ,
/*0x5E*/ MAPFUNC ( " MESSAGE_SENDELL " , lMESSAGE_SENDELL ) ,
/*0x5F*/ MAPFUNC ( " ANIM_SET " , lANIM_SET ) ,
/*0x60*/ MAPFUNC ( " HOLOMAP_TRAJ " , lHOLOMAP_TRAJ ) ,
/*0x61*/ MAPFUNC ( " GAME_OVER " , lGAME_OVER ) ,
/*0x62*/ MAPFUNC ( " THE_END " , lTHE_END ) ,
/*0x63*/ MAPFUNC ( " MIDI_OFF " , lMIDI_OFF ) ,
/*0x64*/ MAPFUNC ( " PLAY_CD_TRACK " , lPLAY_CD_TRACK ) ,
/*0x65*/ MAPFUNC ( " PROJ_ISO " , lPROJ_ISO ) ,
/*0x66*/ MAPFUNC ( " PROJ_3D " , lPROJ_3D ) ,
/*0x67*/ MAPFUNC ( " TEXT " , lTEXT ) ,
/*0x68*/ MAPFUNC ( " CLEAR_TEXT " , lCLEAR_TEXT ) ,
/*0x69*/ MAPFUNC ( " BRUTAL_EXIT " , lBRUTAL_EXIT ) } ;
ScriptLife : : ScriptLife ( TwinEEngine * engine ) : _engine ( engine ) {
2021-01-08 19:49:34 +01:00
lTextYPos = 0 ;
2020-10-14 15:16:30 +02:00
}
void ScriptLife : : processLifeScript ( int32 actorIdx ) {
2020-10-25 12:39:40 +01:00
ActorStruct * actor = _engine - > _scene - > getActor ( actorIdx ) ;
int32 end = - 2 ;
2020-10-14 15:16:30 +02:00
2020-11-03 22:31:55 +01:00
LifeScriptContext ctx ( actorIdx , actor ) ;
2020-10-14 15:16:30 +02:00
do {
2020-11-03 22:31:55 +01:00
const byte scriptOpcode = ctx . stream . readByte ( ) ;
if ( scriptOpcode < ARRAYSIZE ( function_map ) ) {
2020-10-27 19:02:59 +01:00
end = function_map [ scriptOpcode ] . function ( _engine , ctx ) ;
2020-10-14 15:16:30 +02:00
} else {
2020-11-03 22:31:55 +01:00
error ( " Actor %d with wrong offset/opcode - Offset: %d (opcode: %i) " , actorIdx , ctx . stream . pos ( ) - 1 , scriptOpcode ) ;
2020-10-14 15:16:30 +02:00
}
2020-11-03 22:31:55 +01:00
if ( end < 0 ) {
2020-10-25 23:16:17 +01:00
warning ( " Actor %d Life script [%s] not implemented " , actorIdx , function_map [ scriptOpcode ] . name ) ;
2020-10-14 15:16:30 +02:00
}
2020-11-03 22:31:55 +01:00
ctx . updateOpcodePos ( ) ;
2020-10-14 15:16:30 +02:00
} while ( end ! = 1 ) ;
}
} // namespace TwinE