Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Issue #82 - Pushed boulder can collide with pusher #159

Open
wants to merge 7 commits into
base: barony-next
Choose a base branch
from
Open
188 changes: 125 additions & 63 deletions src/actboulder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,33 +28,60 @@
#define BOULDER_DESTX my->skill[6]
#define BOULDER_DESTY my->skill[7]

/*-------------------------------------------------------------------------------

boulderCheckAgainstEntity

causes the boulder given in my to crush the object given in entity
or vice versa

-------------------------------------------------------------------------------*/

int boulderCheckAgainstEntity(Entity* my, Entity* entity)
/* actboulder.cpp
* @param my - A pointer to the Boulder which is checking for collisions
* @param entity - A pointer to the current Entity being checked against @my
* @param bWasBoulderPushed - True if the Boulder was pushed before calling this function
* @returns true - If the Boulder was destroyed as a result of a collision
* @returns false - Default case
* Checks for collisions against every Entity on the map
* Damages Players or Monsters. Can be destroyed if the Entity survives
* Destroys Doors and stops movement in every other case
*/
bool BoulderCheckAgainstEntity(Entity* const my, Entity* const entity, const bool bWasBoulderPushed)
{
if (!my || !entity)
if ( my == nullptr || entity == nullptr )
{
return 0;
printlog("ERROR: BoulderCheckAgainstEntity() - A parameter is null. my = %d, entity = %d.", (my == nullptr), (entity == nullptr));
return false;
}

// Boulders crush or hurt Players and Monsters
if ( entity->behavior == &actPlayer || entity->behavior == &actMonster )
{
if ( entityInsideEntity( my, entity ) )
bool bWasEntityHit = false;

// Calculate collision differently if the Boulder was pushed
if ( bWasBoulderPushed )
{
Stat* stats = entity->getStats();
if ( stats )
// If the Boulder was pushed, check to see if the Entity is in front of the Boulder
if ( entityInFrontOfEntity(my, entity, BOULDER_ROLLDIR) )
{
bWasEntityHit = true;
}
}
else
{
// Check if the Entity is inside of the Boulder
if ( entityInsideEntity(my, entity) )
{
bWasEntityHit = true;
}
}

// If the Entity was hit, damage them TODOR: (also handles killing them)
if ( bWasEntityHit )
{
Stat* entityStats = entity->getStats();
if ( entityStats != nullptr )
{
// If a Player was hit, message them to let them know, and shake the screen
if ( entity->behavior == &actPlayer )
{
Uint32 color = SDL_MapRGB(mainsurface->format, 255, 0, 0);
messagePlayerColor(entity->skill[2], color, language[455]);
messagePlayerColor(entity->skill[2], color, language[455]); // "You are struck by a boulder!"

// Shake the screen
if ( entity->skill[2] == clientnum )
{
camera_shakex += .1;
Expand All @@ -63,31 +90,37 @@ int boulderCheckAgainstEntity(Entity* my, Entity* entity)
else
{
strcpy((char*)net_packet->data, "SHAK");
net_packet->data[4] = 10; // turns into .1
net_packet->data[4] = 10; // Turns into .1
net_packet->data[5] = 10;
net_packet->address.host = net_clients[entity->skill[2] - 1].host;
net_packet->address.port = net_clients[entity->skill[2] - 1].port;
net_packet->len = 6;
sendPacketSafe(net_sock, -1, net_packet, entity->skill[2] - 1);
}
}
playSoundEntity(my, 181, 128);
playSoundEntity(entity, 28, 64);

playSoundEntity(my, 181, 128); // "BoulderCrunch.ogg"
playSoundEntity(entity, 28, 64); // "Damage.ogg"

spawnGib(entity);
entity->modHP(-80);
entity->setObituary(language[1505]);
entity->setObituary(language[1505]); // "fails to dodge the incoming boulder."

// If a Player was hit, and killed, attempt to unlock the Steam Achievement "Throw Me The Whip!"
if ( entity->behavior == &actPlayer )
if ( stats->HP <= 0 )
{
if ( entityStats->HP <= 0 )
{
steamAchievementClient(entity->skill[2], "BARONY_ACH_THROW_ME_THE_WHIP");
}
if ( stats->HP > 0 )
}

// If the Entity survived being hit by the Boulder, destroy the Boulder
if ( entityStats->HP > 0 )
{
// spawn several rock items
int i = 8 + rand() % 4;

int c;
for ( c = 0; c < i; c++ )
// Spawn several Rock Items
Uint8 numberOfRocks = 8 + rand() % 4;
for ( Uint8 iRockIndex = 0; iRockIndex < numberOfRocks; iRockIndex++ )
{
Entity* entity = newEntity(-1, 1, map.entities);
entity->flags[INVISIBLE] = true;
Expand All @@ -103,52 +136,67 @@ int boulderCheckAgainstEntity(Entity* my, Entity* entity)
entity->vel_z = -.25 - (rand() % 5) / 10.0;
entity->flags[PASSABLE] = true;
entity->behavior = &actItem;
entity->flags[USERFLAG1] = true; // no collision: helps performance
entity->skill[10] = GEM_ROCK; // type
entity->skill[11] = WORN; // status
entity->skill[12] = 0; // beatitude
entity->skill[13] = 1; // count
entity->skill[14] = 0; // appearance
entity->skill[15] = false; // identified
entity->flags[USERFLAG1] = true; // No collision, helps performance
entity->skill[10] = GEM_ROCK; // Type
entity->skill[11] = WORN; // Status
entity->skill[12] = 0; // Beatitude
entity->skill[13] = 1; // Count
entity->skill[14] = 0; // Appearance
entity->skill[15] = false; // Identified
}

double ox = my->x;
double oy = my->y;

// destroy the boulder
playSoundEntity(my, 67, 128);
list_RemoveNode(my->mynode);

// on sokoban, destroying boulders spawns scorpions
// On the Sokoban map, destroying Boulders spawns Scorpions
if ( !strcmp(map.name, "Sokoban") )
{
Entity* monster = summonMonster(SCORPION, ox, oy);
if ( monster )
Entity* sokobanScorpion = summonMonster(SCORPION, static_cast<long>(my->x), static_cast<long>(my->y));
if ( sokobanScorpion != nullptr )
{
int c;
for ( c = 0; c < MAXPLAYERS; c++ )
// Message all Players that a Scorpion was summoned
for ( Uint8 iPlayerIndex = 0; iPlayerIndex < MAXPLAYERS; iPlayerIndex++ )
{
// Don't message Players that are not connected
if ( client_disconnected[iPlayerIndex] )
{
continue;
}

Uint32 color = SDL_MapRGB(mainsurface->format, 255, 128, 0);
messagePlayerColor(c, color, language[406]);
messagePlayerColor(iPlayerIndex, color, language[406]); // "You have angered the gods of Sokoban!"
}
}
}

return 1;
// Destroy the Boulder
playSoundEntity(my, 67, 128); // "BustWall.ogg"
list_RemoveNode(my->mynode);

return true;
}
}
else
{
printlog("ERROR: BoulderCheckAgainstEntity() - Entity Stats are null.");
return false;
}
}

return false;
}

// Boulders stop moving when hitting anything but Players, Monsters, and Doors
else if ( entity->behavior == &actGate || entity->behavior == &actBoulder || entity->behavior == &actChest || entity->behavior == &actHeadstone || entity->behavior == &actFountain || entity->behavior == &actSink )
{
// Passable Entities like open Gates wont block a Boulder
if ( !entity->flags[PASSABLE] )
{
if ( entityInsideEntity( my, entity ) )
if ( entityInsideEntity(my, entity) )
{
// stop the boulder
// Stop the Boulder
BOULDER_STOPPED = 1;
BOULDER_ROLLING = 0;
playSoundEntity(my, 181, 128);
playSoundEntity(my, 181, 128); // "BoulderCrunch.ogg"

// Make the Boulder impassable
if ( my->flags[PASSABLE] )
{
my->flags[PASSABLE] = false;
Expand All @@ -159,26 +207,38 @@ int boulderCheckAgainstEntity(Entity* my, Entity* entity)
}
}
}

return false;
}

// Boulders destroy Doors
else if ( entity->behavior == &actDoor )
{
if ( entityInsideEntity( my, entity ) )
if ( entityInsideEntity(my, entity) )
{
playSoundEntity(entity, 28, 64);
entity->skill[4] = 0;
if ( !entity->skill[0] )
playSoundEntity(entity, 28, 64); // "Damage.ogg"

entity->skill[4] = 0; // DOOR_HEALTH

// TODOR: What does this do?
if ( !entity->skill[0] ) // DOOR_DIR
{
entity->skill[6] = (my->x > entity->x);
entity->skill[6] = (my->x > entity->x); // DOOR_SMACKED
}
else
{
entity->skill[6] = (my->y < entity->y);
entity->skill[6] = (my->y < entity->y); // DOOR_SMACKED
}
playSoundEntity(my, 181, 128);

playSoundEntity(my, 181, 128); // "BoulderCrunch.ogg"
}

return false;
}
return 0;
}

return false;
} // BoulderCheckAgainstEntity()


/*-------------------------------------------------------------------------------

Expand Down Expand Up @@ -208,10 +268,12 @@ void actBoulder(Entity* my)
// gravity
bool nobounce = true;
if ( !BOULDER_NOGROUND )
{
if ( noground )
{
BOULDER_NOGROUND = true;
}
}
if ( my->z < 0 || BOULDER_NOGROUND )
{
my->vel_z = std::min<real_t>(my->vel_z + .1, 3.0);
Expand All @@ -235,7 +297,7 @@ void actBoulder(Entity* my)
{
continue;
}
if ( boulderCheckAgainstEntity(my, entity) )
if ( BoulderCheckAgainstEntity(my, entity, false) )
{
return;
}
Expand Down Expand Up @@ -338,7 +400,7 @@ void actBoulder(Entity* my)
{
continue;
}
if ( boulderCheckAgainstEntity(my, entity) )
if ( BoulderCheckAgainstEntity(my, entity, false) )
{
return;
}
Expand Down Expand Up @@ -507,7 +569,7 @@ void actBoulder(Entity* my)
{
continue;
}
if ( boulderCheckAgainstEntity(my, entity) )
if ( BoulderCheckAgainstEntity(my, entity, true) )
{
return;
}
Expand Down
81 changes: 81 additions & 0 deletions src/collision.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,87 @@ bool entityInsideEntity(Entity* entity1, Entity* entity2)
return false;
}

/*-------------------------------------------------------------------------------

entityInFrontOfEntity

Checks whether an entity is intersecting another entity from the front
Used for boulders to prevent harming the Player pushing the boulder

-------------------------------------------------------------------------------*/

bool entityInFrontOfEntity(Entity* entity1, Entity* entity2, Sint32 direction)
{
switch ( direction )
{
case 0: // East
if ( (entity1->x + entity1->sizex) > (entity2->x - entity2->sizex) ) // Check everything East (+X) Is the Entity in front of the boulder?
{
if ( (entity1->x + entity1->sizex) < (entity2->x + entity2->sizex) ) // Check everything West (-X) Is the Entity intersecting the boulder?
{
if ( (entity1->y - entity1->sizey) < (entity2->y + entity2->sizey) ) // Check everything North (-Y) Is the Entity not too far to the left of the boulder?
{
if ( (entity1->y + entity1->sizey) > (entity2->y - entity2->sizey) ) // Check everything South (+Y) Is the Entity not too far to the right of the boulder?
{
return true;
}
}
}
}
return false;
break;
case 1: // South
if ( (entity1->y + entity1->sizey) > (entity2->y - entity2->sizey) ) // Check everything South (+Y) Is the Entity in front of the boulder?
{
if ( (entity1->y + entity1->sizey) < (entity2->y + entity2->sizey) ) // Check everything North (-Y) Is the Entity intersecting the boulder?
{
if ( (entity1->x + entity1->sizex) > (entity2->x - entity2->sizex) ) // Check everything East (+X) Is the Entity not too far to the left of the boulder?
{
if ( (entity1->x - entity1->sizex) < (entity2->x + entity2->sizex) ) // Check everything West (-X) Is the Entity not too far to the right of the boulder?
{
return true;
}
}
}
}
return false;
break;
case 2: // West
if ( (entity1->x - entity1->sizex) < (entity2->x + entity2->sizex) ) // Check everything West (-X) Is the Entity in front of the boulder?
{
if ( (entity1->x - entity1->sizex) > (entity2->x - entity2->sizex) ) // Check everything East (+X) Is the Entity intersecting the boulder?
{
if ( (entity1->y + entity1->sizey) > (entity2->y - entity2->sizey) ) // Check everything South (+Y) Is the Entity too far to the left of the boulder?
{
if ( (entity1->y - entity1->sizey) < (entity2->y + entity2->sizey) ) // Check everything North (-Y) Is the Entity too far to the right of the boulder?
{
return true;
}
}
}
}
return false;
break;
case 3: // North
if ( (entity1->y - entity1->sizey) < (entity2->y + entity2->sizey) ) // Check everything North (-Y) Is the Entity in front of the boulder?
{
if ( (entity1->y - entity1->sizey) > (entity2->y - entity2->sizey) ) // Check everything South (+Y) Is the Entity intersecting the boulder?
{
if ( (entity1->x - entity1->sizex) < (entity2->x + entity2->sizex) ) // Check everything West (-X) Is the Entity not too far to the left of the boulder?
{
if ( (entity1->x + entity1->sizex) > (entity2->x - entity2->sizex) ) // Check everything East (+X) Is the Entity not too far to the right of the boulder?
{
return true;
}
}
}
}
return false;
break;
default: return false; // Should never happen
}
}

/*-------------------------------------------------------------------------------

entityInsideSomething
Expand Down
Loading