1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #ifndef TWINE_SCENE_ACTOR_H
24 #define TWINE_SCENE_ACTOR_H
25 
26 #include "common/scummsys.h"
27 #include "twine/parser/anim.h"
28 #include "twine/parser/entity.h"
29 #include "twine/shared.h"
30 
31 namespace TwinE {
32 
33 /** Total number of sprites allowed in the game */
34 #define NUM_SPRITES 425 // 200 for lba1
35 
36 /** Total number of bodies allowed in the game */
37 #define NUM_BODIES 469 // 131 for lba1
38 
39 /** Actors move structure */
40 struct ActorMoveStruct {
41 	int16 from = 0;
42 	int16 to = 0;
43 	int16 numOfStep = 0;
44 	int32 timeOfChange = 0;
45 
46 	/**
47 	 * Get actor real angle
48 	 * @param time engine time used for interpolation
49 	 */
50 	int32 getRealAngle(int32 time);
51 
52 	/**
53 	 * Get actor step
54 	 * @param time engine time used for interpolation
55 	 */
56 	int32 getRealValue(int32 time);
57 };
58 
59 /** Actors animation timer structure */
60 struct AnimTimerDataStruct {
61 	const KeyFrame *ptr = nullptr;
62 	int32 time = 0;
63 };
64 
65 /** Actors static flags structure */
66 struct StaticFlagsStruct {
67 	uint32 bComputeCollisionWithObj : 1;    // 0x000001
68 	uint32 bComputeCollisionWithBricks : 1; // 0x000002
69 	uint32 bIsZonable : 1;                  // 0x000004
70 	uint32 bUsesClipping : 1;               // 0x000008
71 	uint32 bCanBePushed : 1;                // 0x000010
72 	uint32 bComputeLowCollision : 1;        // 0x000020
73 	uint32 bCanDrown : 1;                   // 0x000040
74 	uint32 bComputeCollisionWithFloor : 1;  // 0x000080
75 	uint32 bUnk0100 : 1;                    // 0x000100
76 	uint32 bIsHidden : 1;                   // 0x000200
77 	uint32 bIsSpriteActor : 1;              // 0x000400
78 	uint32 bCanFall : 1;                    // 0x000800
79 	uint32 bDoesntCastShadow : 1;           // 0x001000
80 	uint32 bIsBackgrounded : 1;             // 0x002000
81 	uint32 bIsCarrierActor : 1;             // 0x004000
82 	// take smaller value for bound, or if not set take average for bound
83 	uint32 bUseMiniZv : 1;                  // 0x008000
84 	uint32 bHasInvalidPosition : 1;         // 0x010000
85 	uint32 bNoElectricShock : 1;            // 0x020000
86 	uint32 bHasSpriteAnim3D : 1;            // 0x040000
87 	uint32 bNoPreClipping : 1;              // 0x080000
88 	uint32 bHasZBuffer : 1;                 // 0x100000
89 	uint32 bHasZBufferInWater : 1;          // 0x200000
90 };
91 
92 /** Actors dynamic flags structure */
93 struct DynamicFlagsStruct {
94 	uint16 bWaitHitFrame : 1;     // 0x0001 wait for hit frame
95 	uint16 bIsHitting : 1;        // 0x0002 hit frame anim
96 	uint16 bAnimEnded : 1;        // 0x0004 anim ended in the current loop (will be looped in the next engine loop)
97 	uint16 bAnimFrameReached : 1; // 0x0008 new frame anim reached
98 	uint16 bIsVisible : 1;        // 0x0010 actor has been drawn in this loop
99 	uint16 bIsDead : 1;           // 0x0020 is dead
100 	uint16 bIsSpriteMoving : 1;   // 0x0040 door is opening or closing (wait to reach the destination position)
101 	uint16 bIsRotationByAnim : 1; // 0x0080 actor rotation is managed by its animaation not by the engine
102 	uint16 bIsFalling : 1;        // 0x0100 is falling on scene
103 	uint16 bUnk0200 : 1;          // 0x0200 unused
104 	uint16 bUnk0400 : 1;          // 0x0400 unused
105 	uint16 bUnk0800 : 1;          // 0x0800 unused
106 	uint16 bUnk1000 : 1;          // 0x1000 unused
107 	uint16 bUnk2000 : 1;          // 0x2000 unused
108 	uint16 bUnk4000 : 1;          // 0x4000 unused
109 	uint16 bUnk8000 : 1;          // 0x8000 unused
110 };
111 
112 /**
113  * Bonus type flags - a bitfield value, of which the bits mean:
114  * bit 8: clover leaf,
115  * bit 7: small key,
116  * bit 6: magic,
117  * bit 5: life,
118  * bit 4: money,
119  * If more than one type of bonus is selected, the actual type of bonus
120  * will be chosen randomly each time player uses Action.
121  */
122 struct BonusParameter {
123 	uint16 unk1 : 1;
124 	uint16 unk2 : 1;
125 	uint16 unk3 : 1;
126 	uint16 unk4 : 1;
127 	uint16 kashes : 1;
128 	uint16 lifepoints : 1;
129 	uint16 magicpoints : 1;
130 	uint16 key : 1;
131 	uint16 cloverleaf : 1;
132 	uint16 unused : 7;
133 };
134 
135 #define kActorMaxLife 50
136 
137 /**
138  * Actors structure
139  *
140  * Such as characters, doors, moving plataforms, invisible actors, ...
141  */
142 class ActorStruct {
143 private:
144 	ShapeType _brickShape = ShapeType::kNone; // field_3
145 	bool _brickCausesDamage = false;
146 
147 	EntityData _entityData;
148 public:
149 	StaticFlagsStruct _staticFlags;
150 	DynamicFlagsStruct _dynamicFlags;
151 
brickShape()152 	inline ShapeType brickShape() const { return _brickShape; }
setBrickShape(ShapeType shapeType)153 	inline void setBrickShape(ShapeType shapeType) {
154 		_brickShape = shapeType;
155 		_brickCausesDamage = false;
156 	}
setBrickCausesDamage()157 	inline void setBrickCausesDamage() { _brickCausesDamage = true; }
brickCausesDamage()158 	inline bool brickCausesDamage() { return _brickCausesDamage; }
159 	void loadModel(int32 modelIndex, bool lba1);
160 
161 	void addLife(int32 val);
162 
163 	void setLife(int32 val);
164 
165 	bool isAttackWeaponAnimationActive() const;
166 	bool isAttackAnimationActive() const;
167 	bool isJumpAnimationActive() const;
168 
169 	const IVec3 &pos() const;
170 
171 	int32 _entity = 0; // costumeIndex - index into bodyTable
172 	BodyType _body = BodyType::btNormal;
173 	AnimationTypes _anim = AnimationTypes::kAnimNone;
174 	AnimationTypes _animExtra = AnimationTypes::kStanding;
175 	AnimationTypes _animExtraPtr = AnimationTypes::kAnimNone;
176 	int32 _sprite = 0;
177 	EntityData *_entityDataPtr = nullptr;
178 
179 	int16 _actorIdx = 0; // own actor index
180 	IVec3 _pos;
181 	int32 _strengthOfHit = 0;
182 	int32 _hitBy = 0;
183 	BonusParameter _bonusParameter;
184 	int32 _angle = 0; // facing angle of actor. Minumum is 0 (SW). Going counter clock wise
185 	int32 _speed = 0;
186 	ControlMode _controlMode = ControlMode::kNoMove;
187 	int32 _delayInMillis = 0;
188 	int32 _cropLeft = 0;
189 	int32 _cropTop = 0;
190 	int32 _cropRight = 0;
191 	int32 _cropBottom = 0;
192 	int32 _followedActor = 0; // same as info3
193 	int32 _bonusAmount = 0;
194 	int32 _talkColor = COLOR_BLACK;
195 	int32 _armor = 0;
196 	int32 _life = 0;
197 
198 	IVec3 _collisionPos;
199 
200 	int32 _positionInMoveScript = 0;
201 	uint8 *_moveScript = nullptr;
202 	int32 _moveScriptSize = 0;
203 
204 	int32 _positionInLifeScript = 0;
205 	uint8 *_lifeScript = nullptr;
206 	int32 _lifeScriptSize = 0;
207 
208 	int32 _labelIdx = 0;        // script label index
209 	int32 _currentLabelPtr = 0; // pointer to LABEL offset
210 	int32 _pausedTrackPtr = 0;
211 
212 	/**
213 	 * colliding actor id
214 	 */
215 	int32 _collision = 0;
216 	/**
217 	 * actor id we are standing on
218 	 */
219 	int32 _standOn = 0;
220 	int32 _zone = 0;
221 
222 	int32 _lastRotationAngle = ANGLE_0;
223 	IVec3 _lastPos;
224 	int32 _previousAnimIdx = 0;
225 	int32 _doorStatus = 0;
226 	int32 _animPosition = 0;
227 	AnimType _animType = AnimType::kAnimationTypeLoop;
228 	int32 _spriteActorRotation = 0;
229 	uint8 _brickSound = 0U;
230 
231 	BoundingBox _boudingBox;
232 	ActorMoveStruct _move;
233 	AnimTimerDataStruct _animTimerData;
234 };
235 
pos()236 inline const IVec3 &ActorStruct::pos() const {
237 	return _pos;
238 }
239 
addLife(int32 val)240 inline void ActorStruct::addLife(int32 val) {
241 	setLife(_life + val);
242 }
243 
setLife(int32 val)244 inline void ActorStruct::setLife(int32 val) {
245 	_life = val;
246 	if (_life > kActorMaxLife) {
247 		_life = kActorMaxLife;
248 	}
249 }
250 
251 class TwinEEngine;
252 
253 class Actor {
254 private:
255 	TwinEEngine *_engine;
256 
257 	/** Hero 3D entity for normal behaviour */
258 	EntityData _heroEntityNORMAL;
259 	/** Hero 3D entity for athletic behaviour */
260 	EntityData _heroEntityATHLETIC;
261 	/** Hero 3D entity for aggressive behaviour */
262 	EntityData _heroEntityAGGRESSIVE;
263 	/** Hero 3D entity for discrete behaviour */
264 	EntityData _heroEntityDISCRETE;
265 	/** Hero 3D entity for protopack behaviour */
266 	EntityData _heroEntityPROTOPACK;
267 
268 	void initSpriteActor(int32 actorIdx);
269 
270 	/**
271 	 * Initialize 3D actor body
272 	 * @param bodyIdx 3D actor body index
273 	 * @param actorIdx 3D actor index
274 	 */
275 	int32 initBody(BodyType bodyIdx, int32 actorIdx, ActorBoundingBox &actorBoundingBox);
276 
277 	void loadBehaviourEntity(ActorStruct *actor, EntityData &entityData, int16 &bodyAnimIndex, int32 index);
278 
279 public:
280 	Actor(TwinEEngine *engine);
281 
282 	ActorStruct *_processActorPtr = nullptr;
283 
284 	/** Actor shadow coordinate */
285 	IVec3 _shadowCoord;
286 
287 	HeroBehaviourType _heroBehaviour = HeroBehaviourType::kNormal;
288 	/** Hero auto aggressive mode */
289 	bool _autoAggressive = true;
290 	/** Previous Hero behaviour */
291 	HeroBehaviourType _previousHeroBehaviour = HeroBehaviourType::kNormal;
292 	/** Previous Hero angle */
293 	int16 _previousHeroAngle = 0;
294 
295 	int16 _cropBottomScreen = 0;
296 
297 	/** Hero current anim for normal behaviour */
298 	int16 _heroAnimIdxNORMAL = 0;
299 	/** Hero current anim for athletic behaviour */
300 	int16 _heroAnimIdxATHLETIC = 0;
301 	/** Hero current anim for aggressive behaviour */
302 	int16 _heroAnimIdxAGGRESSIVE = 0;
303 	/** Hero current anim for discrete behaviour */
304 	int16 _heroAnimIdxDISCRETE = 0;
305 	/** Hero current anim for protopack behaviour */
306 	int16 _heroAnimIdxPROTOPACK = 0;
307 
308 	/** Hero anim for behaviour menu */
309 	int16 _heroAnimIdx[4];
310 
311 	/** Restart hero variables while opening new scenes */
312 	void restartHeroScene();
313 
314 	/** Load hero 3D body and animations */
315 	void loadHeroEntities();
316 
317 	TextId getTextIdForBehaviour() const;
318 
319 	/**
320 	 * Set hero behaviour
321 	 * @param behaviour behaviour value to set
322 	 */
323 	void setBehaviour(HeroBehaviourType behaviour);
324 
325 	/**
326 	 * Initialize 3D actor
327 	 * @param bodyIdx 3D actor body index
328 	 * @param actorIdx 3D actor index
329 	 */
330 	void initModelActor(BodyType bodyIdx, int16 actorIdx);
331 
332 	/**
333 	 * Initialize actors
334 	 * @param actorIdx actor index to init
335 	 */
336 	void initActor(int16 actorIdx);
337 
338 	/**
339 	 * Reset actor
340 	 * @param actorIdx actor index to init
341 	 */
342 	void resetActor(int16 actorIdx);
343 
344 	/**
345 	 * Process hit actor
346 	 * @param actorIdx actor hitting index
347 	 * @param actorIdxAttacked actor attacked index
348 	 * @param strengthOfHit actor hitting strength of hit
349 	 * @param angle angle of actor hitting
350 	 */
351 	void hitActor(int32 actorIdx, int32 actorIdxAttacked, int32 strengthOfHit, int32 angle);
352 
353 	/** Process actor carrier */
354 	void processActorCarrier(int32 actorIdx);
355 
356 	/** Process actor extra bonus */
357 	void processActorExtraBonus(int32 actorIdx);
358 };
359 
360 } // namespace TwinE
361 
362 #endif
363