Commit 74fc8870 authored by Gerhard Stein's avatar Gerhard Stein

Platform fixes which allow multiple players to interact

parent 24043ee5
......@@ -818,18 +818,18 @@ void CSpriteObject::processEvents()
{
while(!m_EventCont.empty())
{
if( ObjMoveCouple* pObjMove = m_EventCont.occurredEvent<ObjMoveCouple>())
{
auto move = pObjMove->m_Vec;
processMove(move);
pObjMove->mSecond.processMove(move);
m_EventCont.pop_Event();
}
if( ObjMoveCouple* pObjMove = m_EventCont.occurredEvent<ObjMoveCouple>())
{
auto move = pObjMove->m_Vec;
processMove(move);
pObjMove->mSecond.processMove(move);
m_EventCont.pop_Event();
}
if( ObjMove* pObjMove = m_EventCont.occurredEvent<ObjMove>())
{
processMove(pObjMove->m_Vec);
m_EventCont.pop_Event();
processMove(pObjMove->m_Vec);
m_EventCont.pop_Event();
}
}
}
......@@ -20,12 +20,14 @@ CSpriteObject::CSpriteObject(CMap *pmap,
const int spriteVar) :
mHealthPoints(1),
sprite(BLANKSPRITE),
m_jumpdownfromobject(false),
mp_Map(pmap),
m_blinktime(0),
m_invincible(false),
m_Pos(x,y),
transluceny(0),
mSprVar(spriteVar)
{
m_number_of_objects++;
exists = true;
......
......@@ -71,15 +71,30 @@ struct ObjMove : public CEvent
// This is applied for example whenever keen is being moved on the platform
struct ObjMoveCouple : public CEvent
{
VectorD2<int> m_Vec;
CSpriteObject &mSecond;
ObjMoveCouple(const VectorD2<int>& Vector,
CSpriteObject &second) :
m_Vec(Vector), mSecond(second) {}
ObjMoveCouple(const int offx, const int offy,
CSpriteObject &second) :
m_Vec(offx, offy), mSecond(second) {}
VectorD2<int> m_Vec;
CSpriteObject &mSecond;
ObjMoveCouple(const VectorD2<int>& Vector,
CSpriteObject &second) :
m_Vec(Vector), mSecond(second) {}
ObjMoveCouple(const int offx, const int offy,
CSpriteObject &second) :
m_Vec(offx, offy), mSecond(second) {}
};
// Same as above but for multiple couples
struct ObjMoveCouples : public CEvent
{
VectorD2<int> m_Vec;
std::vector<CSpriteObject*> mCarriedObjVec;
ObjMoveCouples(const VectorD2<int>& Vector,
std::vector<CSpriteObject*> &carriedObjVec) :
m_Vec(Vector), mCarriedObjVec(carriedObjVec) {}
ObjMoveCouples(const int offx, const int offy,
std::vector<CSpriteObject*> &carriedObjVec) :
m_Vec(offx, offy), mCarriedObjVec(carriedObjVec) {}
};
......@@ -123,6 +138,9 @@ public:
// This container will held the triggered events of the object
CEventContainer m_EventCont;
bool m_jumpdownfromobject;
void calcBoundingBoxes();
void performCollisionsSameBox();
void performCollisions();
......@@ -190,7 +208,7 @@ public:
virtual void process() { }
// The object can hold events process them here!
void processEvents();
virtual void processEvents();
bool turnAroundOnCliff( int x1, int x2, int y2 );
......
......@@ -15,6 +15,9 @@
#include "sdl/input/CInput.h"
#include "engine/spritedefines.h"
int CCamera::mCamlead = 0;
bool CCamera::mCamLeadChange = false;
CCamera::CCamera(CMap *pmap, Uint32 x, Uint32 y, CSpriteObject *p_attacher) :
CSpriteObject(pmap, x, y, 0),
mp_AttachedObject(p_attacher)
......@@ -28,6 +31,21 @@ mp_AttachedObject(p_attacher)
m_moving = true;
}
void CCamera::cycleCamlead()
{
const int numPlayers = g_pBehaviorEngine->mPlayers;
if( numPlayers == 1 ) // For one player this doesn't make sense
return;
if( mCamlead<(numPlayers-1) )
mCamlead++;
else
mCamlead = 0;
mCamLeadChange = true;
}
void CCamera::attachObject(CSpriteObject *p_attacher)
{
mp_AttachedObject = p_attacher;
......@@ -35,6 +53,7 @@ void CCamera::attachObject(CSpriteObject *p_attacher)
void CCamera::setPosition(const VectorD2<int>& newpos)
{
int cam_x = newpos.x-((g_pVideoDriver->getGameResolution().w/2)<<STC);
int cam_y = newpos.y-((g_pVideoDriver->getGameResolution().h/2)<<STC);
......@@ -45,6 +64,11 @@ void CCamera::setPosition(const VectorD2<int>& newpos)
cam_y = 0;
moveToForce(newpos);
// Only the lead camera may change the scroll position
if(mCamlead != mp_AttachedObject->getSpriteVariantId())
return;
mp_Map->gotoPos(cam_x>>STC, cam_y>>STC);
reAdjust();
......@@ -52,7 +76,25 @@ void CCamera::setPosition(const VectorD2<int>& newpos)
void CCamera::process(const bool force)
{
if(m_freeze)
// Cycle Cam Code
if( g_pInput->getPressedCommand(mCamlead, IC_CAMLEAD) )
{
cycleCamlead();
}
const int camId = mp_AttachedObject->getSpriteVariantId();
if(camId != mCamlead)
return;
if(mCamLeadChange)
{
mCamLeadChange = false;
setPosition(m_Pos);
}
if(m_freeze)
return;
SDL_Rect gamerect = g_pVideoDriver->getGameResolution().SDLRect();
......
......@@ -22,6 +22,11 @@ class CCamera : public CSpriteObject
public:
CCamera(CMap *pmap, Uint32 x, Uint32 y, CSpriteObject *p_attacher=NULL);
/**
* @brief cycleCamlead passes the camera lead only enables the cam which has the lead
*/
void cycleCamlead();
/**
* \brief Whenever the object where the camera has to follow up is created it needs to be attached
* in order to follow it.
......@@ -63,6 +68,9 @@ public:
void reAdjust();
bool outOfSight();
bool CamLead() const
{ return mCamlead; }
bool m_attached;
bool m_freeze;
......@@ -78,6 +86,8 @@ public:
private:
CSpriteObject *mp_AttachedObject;
static int mCamlead;
static bool mCamLeadChange;
};
#endif /* CCAMERA_H_ */
......@@ -49,13 +49,15 @@ struct EventExitLevel : CEvent {
const uint16_t levelObject;
const bool sucess;
const bool teleport;
EventExitLevel(const uint16_t l, const bool s, const bool t=false) :
levelObject(l), sucess(s), teleport(t){}
const int who;
EventExitLevel(const uint16_t l, const bool s, const bool t, const bool lWho) :
levelObject(l), sucess(s), teleport(t), who(lWho) {}
};
struct EventExitLevelWithFoot : CEvent {
const uint16_t levelObject;
EventExitLevelWithFoot(const uint16_t l) : levelObject(l) {}
const int who;
EventExitLevelWithFoot(const uint16_t l, const int lWho) : levelObject(l), who(lWho) {}
};
......@@ -65,8 +67,10 @@ struct EventRestartLevel : CEvent {};
struct EventPlayerEndLevel : CEvent {
const uint16_t levelObject;
const bool sucess;
const int who;
EventPlayerEndLevel(const EventExitLevel &ev) :
levelObject(ev.levelObject), sucess(ev.sucess) {}
levelObject(ev.levelObject), sucess(ev.sucess),
who(ev.who) {}
};
struct EventPlayerRideFoot : CEvent {
......
......@@ -91,29 +91,29 @@ void CMapPlayGalaxy::ponder()
if( visibility )
{
// Process the AI of the object as it's given
objRef.process();
// Process the AI of the object as it's given
objRef.process();
// process all the objects' events
objRef.processEvents();
// process all the objects' events
objRef.processEvents();
// Check collision between objects using NlogN order
auto theOther = obj; theOther++;
for( ; theOther != mObjectPtr.end() ; theOther++)
{
auto &theOtherRef = *(theOther->get());
if( !theOtherRef.exists )
continue;
// Check collision between objects using NlogN order
auto theOther = obj; theOther++;
for( ; theOther != mObjectPtr.end() ; theOther++)
{
auto &theOtherRef = *(theOther->get());
if( !theOtherRef.exists )
continue;
objRef.isNearby(theOtherRef);
theOtherRef.isNearby(objRef);
objRef.isNearby(theOtherRef);
theOtherRef.isNearby(objRef);
if( objRef.hitdetect(theOtherRef) )
{
objRef.getTouchedBy(theOtherRef);
theOtherRef.getTouchedBy(objRef);
}
}
if( objRef.hitdetect(theOtherRef) )
{
objRef.getTouchedBy(theOtherRef);
theOtherRef.getTouchedBy(objRef);
}
}
}
}
......
......@@ -296,7 +296,7 @@ void CPlayGameGalaxy::ponder()
{
m_LevelPlay.setMsgBoxOpen(msgboxactive);
m_LevelPlay.ponder();
}
}
// Draw some Textboxes with Messages only if one of those is open and needs to be drawn
if(msgboxactive)
......
......@@ -25,7 +25,7 @@ namespace galaxy {
CFlag(CMap *pmap, const VectorD2<Uint32> &Location,
const VectorD2<Uint32> &Destination, const int sprVar,
const bool newAction = true);
const bool newAction);
void deserialize(CSaveGameController &savedGame)
......
......@@ -190,8 +190,16 @@ void CPlayerBase::getAnotherLife(const int lc_x, const int lc_y, const bool disp
void CPlayerBase::processCamera()
{
m_camera.process();
m_camera.processEvents();
}
bool CPlayerBase::calcVisibility()
{
return true;
}
void CPlayerBase::processInput()
......@@ -266,6 +274,43 @@ void CPlayerBase::processInput()
void CPlayerBase::processEvents()
{
while(!m_EventCont.empty())
{
if( ObjMoveCouple* pObjMove = m_EventCont.occurredEvent<ObjMoveCouple>())
{
auto move = pObjMove->m_Vec;
processMove(move);
pObjMove->mSecond.processMove(move);
m_EventCont.pop_Event();
}
if( ObjMoveCouples* pObjMove = m_EventCont.occurredEvent<ObjMoveCouples>())
{
auto move = pObjMove->m_Vec;
auto playerVec = pObjMove->mCarriedObjVec;
processMove(move);
for(auto &player : playerVec)
{
if(!player->m_jumpdownfromobject)
player->processMove(move);
}
m_EventCont.pop_Event();
}
if( ObjMove* pObjMove = m_EventCont.occurredEvent<ObjMove>())
{
processMove(pObjMove->m_Vec);
m_EventCont.pop_Event();
}
}
}
// Process the touching of certain tile, like items and hazards...
......@@ -475,7 +520,7 @@ void CPlayerBase::processDead()
pdialogevent->addOption("Try Again", new EventRestartLevel() );
std::string exitMsg = "Exit to " + g_pBehaviorEngine->mapLevelName;
pdialogevent->addOption(exitMsg, new EventExitLevel(mp_Map->getLevel(), false) );
pdialogevent->addOption(exitMsg, new EventExitLevel(mp_Map->getLevel(), false, false, mSprVar) );
EventContainer.add( pdialogevent );
}
......
......@@ -113,11 +113,25 @@ public:
*/
void getAnotherLife(const int lc_x, const int lc_y, const bool display, const bool alt);
/**
* \description Camera of the player gets performed here...
*/
void processCamera();
/**
* @brief Player can always be visible and active, even if he is not seen.
* @return
*/
bool calcVisibility();
/**
* \description Read the Input of the Player and sets the variables accordingly
*/
virtual void processInput();
// The object can hold events process them here!
void processEvents();
void processLevelMiscFlagsCheck();
/**
......
......@@ -52,7 +52,6 @@ CPlayerLevel::CPlayerLevel(CMap *pmap, const Uint16 foeID, Uint32 x, Uint32 y,
CInventory &l_Inventory, stCheat &Cheatmode,
const size_t offset, const int playerID) :
CPlayerBase(pmap, foeID, x, y, facedir, l_Inventory, Cheatmode, playerID),
m_jumpdownfromobject(false),
mPlacingGem(false),
mPoleGrabTime(0),
mExitDoorTimer(0),
......@@ -1414,7 +1413,7 @@ void CPlayerLevel::processExiting()
g_pMusicPlayer->stop();
CEventContainer& EventContainer = g_pBehaviorEngine->m_EventList;
const std::string loading_text = g_pBehaviorEngine->getString("WORLDMAP_LOAD_TEXT");
EventContainer.add( new EventExitLevel(mp_Map->getLevel(), true) );
EventContainer.add( new EventExitLevel(mp_Map->getLevel(), true, false, mSprVar) );
g_pGfxEngine->setupEffect(new CDimDark(8));
EventContainer.add( new EventSendBitmapDialogMsg(*g_pGfxEngine->getBitmap("KEENTHUMBSUP"), loading_text, LEFT) );
m_Inventory.Item.m_gem.empty();
......@@ -1725,7 +1724,7 @@ void CPlayerLevel::processEnterDoor()
const std::string loading_text = g_pBehaviorEngine->getString("WORLDMAP_LOAD_TEXT");
EventContainer.add( new EventSendBitmapDialogMsg(*g_pGfxEngine->getBitmap("KEENTHUMBSUP"), loading_text, LEFT) );
g_pBehaviorEngine->m_EventList.add( new EventExitLevel(mp_Map->getLevel(), true, mustTeleportOnMap) );
g_pBehaviorEngine->m_EventList.add( new EventExitLevel(mp_Map->getLevel(), true, mustTeleportOnMap, mSprVar) );
dontdraw = true;
m_Inventory.Item.m_gem.empty();
......@@ -1741,7 +1740,7 @@ void CPlayerLevel::processEnterDoor()
CEventContainer& EventContainer = g_pBehaviorEngine->m_EventList;
const std::string loading_text = g_pBehaviorEngine->getString("WORLDMAP_LOAD_TEXT");
EventContainer.add( new EventSendBitmapDialogMsg(*g_pGfxEngine->getBitmap("KEENTHUMBSUP"), loading_text, LEFT) );
g_pBehaviorEngine->m_EventList.add( new EventExitLevel(mp_Map->getLevel(), true) );
g_pBehaviorEngine->m_EventList.add( new EventExitLevel(mp_Map->getLevel(), true, false, mSprVar) );
dontdraw = true;
m_Inventory.Item.m_gem.empty();
return;
......@@ -1754,6 +1753,7 @@ void CPlayerLevel::processEnterDoor()
moveToForce(new_pos);
new_pos.x += ((m_BBox.x2-m_BBox.x1)/2);
new_pos.y += ((m_BBox.y2-m_BBox.y1)/2);
m_camera.setPosition(new_pos);
//o->ypos = TILE2MU(*t%256 - 1) + 15;
......@@ -2556,7 +2556,7 @@ void CPlayerLevel::process()
const std::string loading_text = g_pBehaviorEngine->getString("WORLDMAP_LOAD_TEXT");
EventContainer.wait(1.0f);
EventContainer.add( new EventSendBitmapDialogMsg(*g_pGfxEngine->getBitmap("KEENTHUMBSUP"), loading_text, LEFT) );
g_pBehaviorEngine->m_EventList.add( new EventExitLevel(mp_Map->getLevel(), true) );
g_pBehaviorEngine->m_EventList.add( new EventExitLevel(mp_Map->getLevel(), true, false, mSprVar) );
m_Inventory.Item.m_gem.empty();
m_Inventory.Item.fuse_levels_completed++;
mp_Map->mFuseInLevel = false;
......@@ -2583,8 +2583,7 @@ void CPlayerLevel::process()
{
processExiting();
m_camera.process();
m_camera.processEvents();
processCamera();
performCollisions();
......
......@@ -298,7 +298,6 @@ public:
int checkSolidD( int x1, int x2, int y2, const bool push_mode=false );
bool m_jumpdownfromobject;
bool mPlacingGem;
bool mExitTouched;
......
......@@ -117,6 +117,10 @@ VectorD2<int> CPlayerWM::fetchFootDestCoord()
return newCoord;
}
/**
* The main process cycle for the player itself only on the map
*/
......@@ -134,49 +138,52 @@ void CPlayerWM::process()
(this->*mProcessPtr)();
// Events for the Player are processed here.
CEventContainer& EventContainer = g_pBehaviorEngine->m_EventList;
if( EventPlayerEndLevel* ev = EventContainer.occurredEvent<EventPlayerEndLevel>() )
{
if(ev->sucess)
{
finishLevel(ev->levelObject);
if(g_pBehaviorEngine->getEpisode() == 5)
{
// enough fuses broken, in fact of all the fuses levels, except the secret one.
// then open the elevator door for the last level!
// NOTE: I'm not sure, if there is a better way to do it. if you know one, go ahead and improve this!
if(m_Inventory.Item.fuse_levels_completed >= 4)
{
// Must happen only once!
m_Inventory.Item.fuse_levels_completed = 0;
int x = (0x1A)<<CSF; // upper left corner of that elevator
int y = (0x37)<<CSF; // on the map
// I only will change the closed elevator tiles!
const int tileID = mp_Map->getPlaneDataAt(1, x, y);
// I only will change the closed elevator tiles!
if(tileID == 0x072C)
{
const int t_ul = tileID+10;
const int t_ur = mp_Map->getPlaneDataAt(1, x+(1<<CSF), y) + 10;
const int t_ll = mp_Map->getPlaneDataAt(1, x, y+(1<<CSF)) + 10;
const int t_lr = mp_Map->getPlaneDataAt(1, x+(1<<CSF), y+(1<<CSF)) + 10;
x >>= CSF; y >>= CSF;
mp_Map->setTile(x, y, t_ul, true);
mp_Map->setTile(x+1, y, t_ur, true);
mp_Map->setTile(x, y+1, t_ll, true);
mp_Map->setTile(x+1, y+1, t_lr, true);
}
}
}
}
EventContainer.pop_Event();
// Events for the Player are processed here.
CEventContainer& EventContainer = g_pBehaviorEngine->m_EventList;
if( EventPlayerEndLevel* ev = EventContainer.occurredEvent<EventPlayerEndLevel>() )
{
if(ev->who == mSprVar)
{
if(ev->sucess)
{
finishLevel(ev->levelObject);
if(g_pBehaviorEngine->getEpisode() == 5)
{
// enough fuses broken, in fact of all the fuses levels, except the secret one.
// then open the elevator door for the last level!
// NOTE: I'm not sure, if there is a better way to do it. if you know one, go ahead and improve this!
if(m_Inventory.Item.fuse_levels_completed >= 4)
{
// Must happen only once!
m_Inventory.Item.fuse_levels_completed = 0;
int x = (0x1A)<<CSF; // upper left corner of that elevator
int y = (0x37)<<CSF; // on the map
// I only will change the closed elevator tiles!
const int tileID = mp_Map->getPlaneDataAt(1, x, y);
// I only will change the closed elevator tiles!
if(tileID == 0x072C)
{
const int t_ul = tileID+10;
const int t_ur = mp_Map->getPlaneDataAt(1, x+(1<<CSF), y) + 10;
const int t_ll = mp_Map->getPlaneDataAt(1, x, y+(1<<CSF)) + 10;
const int t_lr = mp_Map->getPlaneDataAt(1, x+(1<<CSF), y+(1<<CSF)) + 10;
x >>= CSF; y >>= CSF;
mp_Map->setTile(x, y, t_ul, true);
mp_Map->setTile(x+1, y, t_ur, true);
mp_Map->setTile(x, y+1, t_ll, true);
mp_Map->setTile(x+1, y+1, t_lr, true);
}
}
}
}
EventContainer.pop_Event();
}
}
if( EventPlayerRideFoot* ev = EventContainer.occurredEvent<EventPlayerRideFoot>() )
......@@ -213,8 +220,7 @@ void CPlayerWM::process()
EventContainer.pop_Event();
}
m_camera.process();
m_camera.processEvents();
processCamera();
}
......@@ -941,7 +947,7 @@ void CPlayerWM::startLevel(Uint16 object)
if(mp_Map->findTile(flag_dest, &x, &y, 2) || g_pBehaviorEngine->m_option[OPT_LVLREPLAYABILITY].value || level >= shipLevel)
{
g_pBehaviorEngine->m_EventList.add(new EventEnterLevel(object));
g_pBehaviorEngine->m_EventList.add(new EventEnterLevel(object));
}
}
......@@ -1000,7 +1006,7 @@ void CPlayerWM::finishLevel(const int object)
VectorD2<Uint32> dst(csfX, csfY);
CFlag *pFlag = new CFlag(mp_Map, src, dst, mSprVar);
CFlag *pFlag = new CFlag(mp_Map, src, dst, mSprVar, true);
g_pBehaviorEngine->m_EventList.spawnObj(pFlag);
......
......@@ -12,8 +12,7 @@
namespace galaxy {
CPlatform::CPlatform(CMap *pmap, const Uint16 foeID, Uint32 x, Uint32 y) :
CGalaxySpriteObject(pmap, foeID, x, y, 0),
mp_CarriedPlayer(NULL)
CGalaxySpriteObject(pmap, foeID, x, y, 0)
{
m_ActionBaseOffset = 0x316A;
}
......@@ -40,13 +39,15 @@ void CPlatform::movePlatLeft(const int amnt)
if(amnt <= 0)
return;
if(mp_CarriedPlayer)
if(!mCarriedPlayerVec.empty())
{
if(!mp_CarriedPlayer->m_jumpdownfromobject)
{
m_EventCont.add(new ObjMoveCouple(-amnt,0, *mp_CarriedPlayer));
return;
}
std::vector<CSpriteObject*> carriedObjVec;
for(auto &player : mCarriedPlayerVec)
carriedObjVec.push_back(player);
m_EventCont.add(new ObjMoveCouples(-amnt, 0, carriedObjVec));
return;
}
moveLeft(amnt);
}
......@@ -57,14 +58,17 @@ void CPlatform::movePlatRight(const int amnt)
if(amnt <= 0)
return;
if(mp_CarriedPlayer)
{
if(!mp_CarriedPlayer->m_jumpdownfromobject)
{
m_EventCont.add(new ObjMoveCouple(amnt,0,*mp_CarriedPlayer));
return;
}
}
if(!mCarriedPlayerVec.empty())
{
std::vector<CSpriteObject*> carriedObjVec;
for(auto &player : mCarriedPlayerVec)
carriedObjVec.push_back(player);
m_EventCont.add(new ObjMoveCouples(amnt,0, carriedObjVec));
return;
}
// Now move the platform itself.
moveRight(amnt);
......@@ -73,14 +77,16 @@ void CPlatform::movePlatRight(const int amnt)
void CPlatform::movePlatUp(const int amnt)
{
// First move the object on platform if any
if(mp_CarriedPlayer)
{
if(!mp_CarriedPlayer->m_jumpdownfromobject)
{
m_EventCont.add(new ObjMoveCouple(0,-amnt,*mp_CarriedPlayer));
return;
}
}
if(!mCarriedPlayerVec.empty())
{
std::vector<CSpriteObject*> carriedObjVec;
for(auto &player : mCarriedPlayerVec)
carriedObjVec.push_back(player);
m_EventCont.add(new ObjMoveCouples(0,-amnt, carriedObjVec));
return;
}
// Now move the platform itself.
moveUp(amnt);
......@@ -89,14 +95,16 @@ void CPlatform::movePlatUp(const int amnt)
void CPlatform::movePlatDown(const int amnt)
{
// First move the object on platform if any
if(mp_CarriedPlayer)
{
if(!mp_CarriedPlayer->m_jumpdownfromobject)
{
m_EventCont.add(new ObjMoveCouple(0,amnt,*mp_CarriedPlayer));
return;
}
}