CSpriteObject.h 14.1 KB
Newer Older
Gerhard Stein's avatar
Gerhard Stein committed
1 2 3 4 5 6 7 8 9 10 11
/*
 * CSpriteObject.h
 *
 *  Created on: 17.05.2009
 *      Author: gerstrong
 *
 *  This class handles the objects like sprites that are draw on the screen
 *  It also handles the AI if any.
 */


12 13
#ifndef CSpriteObject_H
#define CSpriteObject_H
Gerhard Stein's avatar
Gerhard Stein committed
14

15
#include <base/GsEvent.h>
16

Gerhard Stein's avatar
Gerhard Stein committed
17 18 19 20 21 22
#include "ActionFormat.h"
#include "direction.h"
#include "CBehaviorEngine.h"

// structures for each AI module's data
#include "CMap.h"
23
#include "graphics/GsGraphics.h"
Gerhard Stein's avatar
Gerhard Stein committed
24
#include "options.h"
Gerhard Stein's avatar
Gerhard Stein committed
25
#include "sdl/audio/Audio.h"
Gerhard Stein's avatar
Gerhard Stein committed
26 27 28 29

// Enumerations are here
#include "objenums.h"

30 31 32 33
#include <base/utils/FindFile.h>

#include "fileio/KeenFiles.h"

Gerhard Stein's avatar
Gerhard Stein committed
34
#include <base/GsPython.h>
35

36

37 38
const int COLISION_RES = (1<<STC);

Gerhard Stein's avatar
Gerhard Stein committed
39
// The bouncing box used by the object which is used to determine the collisions
Gerhard Stein's avatar
Gerhard Stein committed
40 41
struct BoundingBox
{
Gerhard Stein's avatar
Gerhard Stein committed
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
    int x1, x2, y1, y2;
    BoundingBox(int l_x1 = 0, int l_x2 = 0,
		int l_y1 = 0, int l_y2 = 0 ) :
      x1(l_x1), x2(l_x2),
      y1(l_y1), y2(l_y2) {}
    
    void operator()(const int l_x1,
		    const int l_y1,
		    const int l_x2,
		    const int l_y2 )
    {
      x1 = l_x1; x2 = l_x2;
      y1 = l_y1; y2 = l_y2;
    }
    
    
    unsigned int Width()
    {	return (x2-x1);		}
    
    unsigned int Height()
    {	return (y2-y1);		}
Gerhard Stein's avatar
Gerhard Stein committed
63 64 65
};


Gerhard Stein's avatar
Gerhard Stein committed
66 67
class CSpriteObject;

Gerhard Stein's avatar
Gerhard Stein committed
68
// Event that will be used to move the objects in the game
69
struct ObjMove
Gerhard Stein's avatar
Gerhard Stein committed
70
{
Gerhard Stein's avatar
Gerhard Stein committed
71
    Vector2D<int> m_Vec;
Gerhard Stein's avatar
Gerhard Stein committed
72
    
Gerhard Stein's avatar
Gerhard Stein committed
73
    ObjMove(const Vector2D<int>& Vector) : m_Vec(Vector) {}
74
    ObjMove(const int offx, const int offy) : m_Vec(offx, offy) {}
Gerhard Stein's avatar
Gerhard Stein committed
75
    
76
    virtual ~ObjMove() {}
Gerhard Stein's avatar
Gerhard Stein committed
77 78
};

Gerhard Stein's avatar
Gerhard Stein committed
79 80
// Event that will be used to move the objects in the game together with another object.
// This is applied for example whenever keen is being moved on the platform
81
struct ObjMoveCouple : ObjMove
Gerhard Stein's avatar
Gerhard Stein committed
82
{
83
    CSpriteObject &mSecond;
Gerhard Stein's avatar
Gerhard Stein committed
84
    ObjMoveCouple(const Vector2D<int>& vec,
Gerhard Stein's avatar
Gerhard Stein committed
85 86 87
		  CSpriteObject &second) :
      ObjMove(vec), mSecond(second)  {}
    
88
    ObjMoveCouple(const int offx, const int offy,
Gerhard Stein's avatar
Gerhard Stein committed
89 90
		  CSpriteObject &second) :
      ObjMove(offx, offy), mSecond(second) {}
91 92 93 94
};

// Same as above but for multiple couples

95
struct ObjMoveCouples : ObjMove
96 97
{
    std::vector<CSpriteObject*> mCarriedObjVec;
Gerhard Stein's avatar
Gerhard Stein committed
98
    
Gerhard Stein's avatar
Gerhard Stein committed
99
    ObjMoveCouples(const Vector2D<int>& Vector,
Gerhard Stein's avatar
Gerhard Stein committed
100 101 102
		   std::vector<CSpriteObject*> &carriedObjVec) :
      ObjMove(Vector), mCarriedObjVec(carriedObjVec)  {}
    
103
    ObjMoveCouples(const int offx, const int offy,
Gerhard Stein's avatar
Gerhard Stein committed
104 105
		   std::vector<CSpriteObject*> &carriedObjVec) :
      ObjMove(offx, offy), mCarriedObjVec(carriedObjVec) {}
Gerhard Stein's avatar
Gerhard Stein committed
106 107
};

Gerhard Stein's avatar
Gerhard Stein committed
108

109 110 111
// Small special routine for spawning objects. Might be called by other objects and the level manager
void spawnObj(const CSpriteObject *obj);

Gerhard Stein's avatar
Gerhard Stein committed
112 113
class CSpriteObject
{
Gerhard Stein's avatar
Gerhard Stein committed
114
  public:
115
    CSpriteObject(CMap *pmap, Uint32 x, Uint32 y, const int spriteVar);
Gerhard Stein's avatar
Gerhard Stein committed
116
    
Gerhard Stein's avatar
Gerhard Stein committed
117
    unsigned int m_index;        	// Like an ID for some objects that need this implementation
Gerhard Stein's avatar
Gerhard Stein committed
118 119 120
    
    
    
121
    unsigned int mHealthPoints;              // episode 1 style four-shots-to-kill
122
    bool mTurnAroundOnCliff = false;    // Can enemy turn around if there is a cliff
123
    bool mEndGameOnDefeat = false;    // End game if enemy is defeated. Useful for the last boss in some mods
Gerhard Stein's avatar
Gerhard Stein committed
124 125 126
    bool exists;
    bool onscreen;    				// true=(scrx,scry) position is visible onscreen
    bool hasbeenonscreen;
127
    int mSpriteIdx;      		// which sprite should this object be drawn with
Gerhard Stein's avatar
Gerhard Stein committed
128 129 130 131 132
    int xDirection;					// the direction to where the object is looking/heading to
    int yDirection;					// same for vertical
    
    int scrx, scry;           		// x,y pixel position on screen
    
Gerhard Stein's avatar
Gerhard Stein committed
133
    virtual void pumpEvent(const CEvent *evPtr);
Gerhard Stein's avatar
Gerhard Stein committed
134
    
Gerhard Stein's avatar
Gerhard Stein committed
135
    virtual void processEvents();
Gerhard Stein's avatar
Gerhard Stein committed
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
    
    // Bounding Boxes
    BoundingBox m_BBox;
    
    // if zero, priority tiles will not be honored and object will always
    // appear in front of the background
    bool honorPriority;
    bool dontdraw;	// tells the object whether to get drawn or not. The object is still existent in this while
    bool solid;
    
    bool canbezapped;         // if 0 ray will not stop on hitdetect
    
    bool inhibitfall;         // if true common_enemy_ai will not do falling
    
    bool cansupportplayer;
    
Gerhard Stein's avatar
Gerhard Stein committed
152
    unsigned char blockedl, blockedr, blockedu, blockedd;
Gerhard Stein's avatar
Gerhard Stein committed
153 154
    bool onslope;
    signed int xinertia, yinertia;
155
    CSpriteObject *pSupportedbyobject;
Gerhard Stein's avatar
Gerhard Stein committed
156
    
157
    bool mIsDead, dying;
Gerhard Stein's avatar
Gerhard Stein committed
158 159
    
    
160
    bool m_jumpdownfromobject;
Gerhard Stein's avatar
Gerhard Stein committed
161 162 163
    
    
    
164 165 166
    /*
     * \brief Calculate Bounding Boxes fro collision
     */
Gerhard Stein's avatar
Gerhard Stein committed
167 168
    void calcBoundingBoxes();
    
169 170 171 172
    /**
     * @brief setupCollisionModel Should be called when an object is created. It will setup the collision model for ingame as required.
     */
    void setupCollisionModel();
Gerhard Stein's avatar
Gerhard Stein committed
173 174 175 176 177 178 179 180 181
    
    void performCollisionsSameBox();
    void performCollisions();
    void alignToTile();
    void setScrPos( int px, int py );
    bool PoleCollision();
    virtual bool calcVisibility();
    
    /**
182
     * @brief This will verify whether object has to fall or not.
Gerhard Stein's avatar
Gerhard Stein committed
183 184 185
	 * 				This function must be called when it might be moving
	 * 				because it also checks the lower sloped tiles cases
	 *
186
     * @todo		This function should also be called by foes in some cases
Gerhard Stein's avatar
Gerhard Stein committed
187
	 */
Gerhard Stein's avatar
Gerhard Stein committed
188 189 190
    bool verifyForFalling();
    
    /**
Gerhard Stein's avatar
Gerhard Stein committed
191 192 193 194 195
	 * \description	This function will change the direction of an object when
	 * 				it detects a coming gap while moving
	 * \param		speed Amount of CSFed coordinates to move the object back
	 * 				when it over that gap
	 */
Gerhard Stein's avatar
Gerhard Stein committed
196 197 198 199 200
    void performCliffStop(const int &speed);
    
    
    
    // Moving parts
Gerhard Stein's avatar
Gerhard Stein committed
201
    void moveToForce(const Vector2D<int> &dir);
Gerhard Stein's avatar
Gerhard Stein committed
202
    void moveToForce(const int new_x, const int new_y);
Gerhard Stein's avatar
Gerhard Stein committed
203
    void moveDir(const Vector2D<int> &dir);
Gerhard Stein's avatar
Gerhard Stein committed
204 205
    void moveToHorizontal(const int& new_x);
    void moveToVertical(const int& new_y);
Gerhard Stein's avatar
Gerhard Stein committed
206
    void moveTo(const Vector2D<Uint32> &new_loc);
Gerhard Stein's avatar
Gerhard Stein committed
207 208 209
    void moveTo(const int new_x, const int new_y);
    void moveXDir(const int amount, const bool force = false);
    void moveYDir(const int amount);
210 211
    virtual void moveLeft(const int amnt, const bool = false);
    virtual void moveRight(const int amnt, const bool = false);
Gerhard Stein's avatar
Gerhard Stein committed
212 213 214 215 216
    virtual void moveUp(const int amnt);
    virtual void moveDown(const int amnt);
    
    // new moving parts
    /**
Gerhard Stein's avatar
Gerhard Stein committed
217 218 219
	 * \brief	This function checks if there is any collision and moves the object safely
	 * \param	dir	The direction where the object has to go to...
	 */
Gerhard Stein's avatar
Gerhard Stein committed
220
    void processMove(const Vector2D<int>& dir);
Gerhard Stein's avatar
Gerhard Stein committed
221 222
    void processMoveBitLeft();
    void processMoveBitRight();
Gerhard Stein's avatar
Gerhard Stein committed
223
    virtual void processMoveBitDown();
Gerhard Stein's avatar
Gerhard Stein committed
224
    void processMoveBitUp();
Gerhard Stein's avatar
Gerhard Stein committed
225 226 227
    void processMove(const int move_x, const int move_y);
    
    /*
Gerhard Stein's avatar
Gerhard Stein committed
228 229 230 231
	 * \brief As especially in Galaxy some tiles still can get into blocks where they shouldn't
	 *  	  So this function will pull them out. Same method is used in the original games
	 *  	  and will give a more Commander Keen like feeling
	 */
Gerhard Stein's avatar
Gerhard Stein committed
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
    void processPushOutCollision();
    
    void decreaseXInertia(const int value);
    void InertiaAndFriction_X(const int friction_rate = 10);
    
    virtual void process() { }
    
    /**
	 * @brief turnAroundOnCliff Turn around when there is a cliff where the foe
	 *                          must not fall.
	 * @param x1 most left point of the Sprite Box
	 * @param x2 most right point of the Sprite Box
	 * @param y2 lowest point of the Sprite Box
	 * @return true if the foe will blocked so he can turn around, otherwise false.
	 * @note slopes do not count as cliffs.
	 */
    bool turnAroundOnCliff( int x1, int x2, int y2 );
    
    /**
	 * @brief turnAroundOnSlope make the foe turn around, whenever a slope is detected
	 * @param x1 most left point of the Sprite Box
	 * @param x2 most right point of the Sprite Box
	 * @param y2 lowest point of the Sprite Box
	 * @return true if the foe will blocked so he can turn around, otherwise false.
	 * @note slopes do not count as cliffs.
	 */
    bool turnAroundOnSlope( int x1, int x2, int y2 );
    
    
261
    bool hitdetect(CSpriteObject &hitobject);
Gerhard Stein's avatar
Gerhard Stein committed
262
    bool hitdetectWithTile(const int num, const int lx, const int ly, const int lw, const int lh, const int res);
Gerhard Stein's avatar
Gerhard Stein committed
263 264 265 266 267
    bool hitdetectWithTilePropertyRect(const Uint16 Property, int &lx, int &ly, const int lw, const int lh, const int res);
    bool hitdetectWithTilePropertyRectRO(const Uint16 Property, const int lx, const int ly, const int lw, const int lh, const int res);
    bool hitdetectWithTilePropertyHor(const Uint16 Property, const int lxl, const int lxr, const int ly, const int res);
    bool hitdetectWithTilePropertyVert(const Uint16 Property, const int lx, const int lyu, const int lyd, const int res);
    bool hitdetectWithTileProperty(const int Property, const int x, const int y);
gerstrong@gmail.com's avatar
gerstrong@gmail.com committed
268 269 270 271

    virtual void kill(const bool force = false,
                      const bool noDieProcess = false);

Gerhard Stein's avatar
Gerhard Stein committed
272 273 274 275
    void blink(Uint16 frametime);
    
    // Collision parts
    /**
Gerhard Stein's avatar
Gerhard Stein committed
276 277 278 279 280 281
	 * \brief 	Those functions check the the collision states and return also a number of what type of block
	 * 			the collision is happening.
	 * \return	returns the number of the block property. 0 means no collision. Any other number depends.
	 * 			1 is blocked, the other depends on the engine. In Keen Galaxy they mostly represent sloped tiles
	 * 			In vorticons the up part have other numbers which represent ice and slippery.
	 */
Gerhard Stein's avatar
Gerhard Stein committed
282 283
    int checkSolidR(int x1, int x2, int y1, int y2);
    int checkSolidL(int x1, int x2, int y1, int y2);
Gerhard Stein's avatar
Gerhard Stein committed
284 285 286 287 288 289
    virtual int checkSolidU( int x1, int x2, int y1, const bool push_mode=false );
    virtual int checkSolidD( int x1, int x2, int y2, const bool push_mode=false );
    
    virtual bool checkMapBoundaryL(const int x1);
    virtual bool checkMapBoundaryR(const int x2);
    virtual bool checkMapBoundaryU(const int y1);
290
    virtual bool checkMapBoundaryD(const int y2);
Gerhard Stein's avatar
Gerhard Stein committed
291 292 293 294 295 296 297 298 299 300
    
    
    // special functions for sloped tiles
    bool checkslopedU( int c, int y1, Sint8 blocked);
    bool checkslopedD( int c, int y2, Sint8 blocked);
    void adjustSlopedTiles( int x, int y1, int y2, const int xspeed );
    bool moveSlopedTileDown( int x, int y, const int xspeed );
    void moveSlopedTileUp( int x, int y, const int xspeed );
    
    // getters for positions
Gerhard Stein's avatar
Gerhard Stein committed
301
    Vector2D<int> &getPosition()
302
    { return m_Pos; }
Gerhard Stein's avatar
Gerhard Stein committed
303
    
304 305
    auto getXPosition() const -> int
    { return int(m_Pos.x); }
Gerhard Stein's avatar
Gerhard Stein committed
306
    
307 308
    auto getYPosition() const -> int
    { return int(m_Pos.y); }
Gerhard Stein's avatar
Gerhard Stein committed
309
    
310 311
    auto getXLeftPos() const -> int
    { return int(m_Pos.x)+m_BBox.x1; }
Gerhard Stein's avatar
Gerhard Stein committed
312
    
313 314
    auto getXRightPos()  const -> int
    { return int(m_Pos.x)+m_BBox.x2; }
Gerhard Stein's avatar
Gerhard Stein committed
315
    
316 317
    auto getXMidPos()  const -> int
    { return int(m_Pos.x)+(m_BBox.x2-m_BBox.x1)/2; }
Gerhard Stein's avatar
Gerhard Stein committed
318
    
319 320
    auto getYUpPos() const -> int
    { return int(m_Pos.y)+m_BBox.y1; }
Gerhard Stein's avatar
Gerhard Stein committed
321
    
322 323
    auto getYDownPos() const -> int
    { return int(m_Pos.y)+m_BBox.y2; }
Gerhard Stein's avatar
Gerhard Stein committed
324
    
325 326
    auto getYMidPos() const -> int
    { return int(m_Pos.y)+(m_BBox.y2-m_BBox.y1)/2; }
Gerhard Stein's avatar
Gerhard Stein committed
327
    
328 329
    auto getMidPos() const -> Vector2D<int>
    { return Vector2D<int>(getXMidPos(), getYMidPos()); }
Gerhard Stein's avatar
Gerhard Stein committed
330 331 332 333
    
    void processFallPhysics(const int boost);
    void processFallPhysics();
    virtual void processFalling();
334 335
    virtual void getTouchedBy(CSpriteObject&) {}
    virtual bool isNearby(CSpriteObject&) { return true; }
gerstrong@gmail.com's avatar
gerstrong@gmail.com committed
336
    virtual void getShotByRay(object_t &);
337
    void kill_intersecting_tile(int mpx, int mpy, CSpriteObject &theObject);
338
    CMap *getMapPtr() { return mpMap; }
Gerhard Stein's avatar
Gerhard Stein committed
339 340
    
    /**
Gerhard Stein's avatar
Gerhard Stein committed
341 342
	 *  \description plays certain sound of an object. Stereo will automatically applied when used
	 */
Gerhard Stein's avatar
Gerhard Stein committed
343 344 345 346 347
    void playSound( const GameSound snd,
		    const SoundPlayMode mode=SoundPlayMode::PLAY_NOW );
    
    virtual void draw();
    
348
    virtual ~CSpriteObject();
Gerhard Stein's avatar
Gerhard Stein committed
349
    
350
    int getSpecialIdx() const
351
    {   return mPlayerIdx;    }
352

353
    int getSpriteVariantIdx() const
354
    {   return mSprVar;    }
355 356

    void setSpecialIdx(const int i)
357
    {   mPlayerIdx = i;    }
358

359 360
    void setSpriteVariantId(const int i)
    {   mSprVar = i;    }
Gerhard Stein's avatar
Gerhard Stein committed
361 362
  protected:
    
363 364 365 366
    /**
     * @brief cancelAllMoveTasks cancels out all the already created move tasks
     */
    void cancelAllMoveTasks();
Gerhard Stein's avatar
Gerhard Stein committed
367
    
368 369 370
    // This container will held the triggered events of the object
    // TODO: This create too much fragmentation. Find a way to make this better
    std::vector< ObjMove* > mMoveTasks;
Gerhard Stein's avatar
Gerhard Stein committed
371 372 373
    
    
    
374
#if USE_PYTHON3
375 376 377 378 379 380 381 382
    /**
     * @brief loadAiGetterInteger
     * @param pModule
     * @param pyMethodStr
     * @param value
     * @return
     */
    bool loadAiGetterInteger(PyObject * pModule, const std::string &pyMethodStr, int &value);
Gerhard Stein's avatar
Gerhard Stein committed
383 384
    
    
385 386 387 388 389 390 391 392
    /**
     * @brief loadAiGetterBool
     * @param pModule
     * @param pyMethodStr
     * @param value
     * @return
     */
    bool loadAiGetterBool(PyObject * pModule, const std::string &pyMethodStr, bool &value);
Gerhard Stein's avatar
Gerhard Stein committed
393 394 395
    
    
    
396 397 398 399 400
    /**
     * @brief loadPythonScripts     Load an external script file which might modify the behaviour of the sprite object
     * @param scriptBaseName        Basename is the filename with any extension or path. Recommendation: Use the name of the foe
     * @return if load was successful true, otherwise false.
     */
401
    virtual bool loadPythonScripts(const std::string &scriptBaseName);
402
#endif
Gerhard Stein's avatar
Gerhard Stein committed
403
    
404
    CMap *mpMap;
Gerhard Stein's avatar
Gerhard Stein committed
405 406
    
    Uint16 m_blinktime;
407 408 409
    bool mInvincible = false;   /** Shot might hit the object but it has no effect at all */
    bool mRecoverFromStun = false; /** If foe get shot they might be able to recover at later time */
    bool mNeverStop = false;        /** This will make foe continue walking and never change actions (Keen 9 - Cybloog) */
410
    bool mPogoStunnable = false;        /** This will make foe continue walking and never change actions (Keen 9 - Cybloog) */
411
    bool mMayShoot = false;         /** If enemy if allowed to shoot. Not all of them are able to do that.*/
Gerhard Stein's avatar
Gerhard Stein committed
412
    
413
    GameSound mWalkSound;
Gerhard Stein's avatar
Gerhard Stein committed
414
    
Gerhard Stein's avatar
Gerhard Stein committed
415
    Vector2D<int> m_Pos; 	// x,y location in map coords, CSFed, represent as 2D Vector
Gerhard Stein's avatar
Gerhard Stein committed
416 417 418 419 420 421 422 423
    
    static int m_number_of_objects;
    
    // Action Format related stuff
    ActionFormatType m_Action;
    
    Uint8 transluceny;
    
424 425 426 427
protected:

    int mSprVar = 0; // Sprite variant, which is used by the Spritemap

428
    int mPlayerIdx = 0; // Special index for different usages. In case of players, that is its index
429

Gerhard Stein's avatar
Gerhard Stein committed
430 431
};

432 433 434 435 436 437
/**
 *	\description This event will spawn a new object
 *
 *	\param		pObject Pointer to the allocated memory of the Object. Caution: This allocation
 */
struct EventSpawnObject : CEvent {
Gerhard Stein's avatar
Gerhard Stein committed
438
    
439
    const CSpriteObject *pObject;
Gerhard Stein's avatar
Gerhard Stein committed
440
    
441
    EventSpawnObject( const CSpriteObject* pObject ) :
Gerhard Stein's avatar
Gerhard Stein committed
442
      pObject( pObject ) {}
443 444
};

445
#endif // CSpriteObject_H_