Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F134874
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
39 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/BaseCreatureEntity.cpp b/src/BaseCreatureEntity.cpp
index 3e32ecd..41499d4 100644
--- a/src/BaseCreatureEntity.cpp
+++ b/src/BaseCreatureEntity.cpp
@@ -1,783 +1,785 @@
#include "BaseCreatureEntity.h"
#include "sfml_game/ImageManager.h"
#include "sfml_game/SoundManager.h"
#include "Constants.h"
#include "WitchBlastGame.h"
#include "ExplosionEntity.h"
#include "TextMapper.h"
#include <iostream>
#include <sstream>
BaseCreatureEntity::BaseCreatureEntity(sf::Texture* image, float x = 0.0f, float y = 0.0f, int spriteWidth = -1, int spriteHeight = -1)
: CollidingSpriteEntity (image, x, y, spriteWidth, spriteHeight )
{
hurting = false;
hurtingType = ShotTypeStandard;
shadowFrame = -1;
setMap(game().getCurrentMap(), TILE_WIDTH, TILE_HEIGHT, 0, 0);
hpDisplay = 0;
armor = 0.0f;
movingStyle = movWalking;
for (int i = 0; i < NB_SPECIAL_STATES; i++)
{
specialState[i].type = (enumSpecialState)i;
specialState[i].active = false;
specialState[i].timer = 0.0f;
specialState[i].param1 = 0.0f;
specialState[i].param2 = 0.0f;
}
for (int i = 0; i < NB_RESISTANCES; i++)
{
resistance[i] = ResistanceStandard;
}
recoil.active = false;
facingDirection = 2;
}
int BaseCreatureEntity::getHp()
{
return hp;
}
int BaseCreatureEntity::getHpMax()
{
return hpMax;
}
void BaseCreatureEntity::setHp(int hp)
{
this->hp = hp;
}
void BaseCreatureEntity::setHpMax(int hpMax)
{
this->hpMax = hpMax;
}
int BaseCreatureEntity::getHpDisplay()
{
return hpDisplay;
}
float BaseCreatureEntity::getCreatureSpeed()
{
return creatureSpeed;
}
IntCoord BaseCreatureEntity::getCurrentTile()
{
int xMap = (x) / TILE_WIDTH;
int yMap = (y) / TILE_HEIGHT;
return (IntCoord(xMap, yMap));
}
BaseCreatureEntity::enumMovingStyle BaseCreatureEntity::getMovingStyle()
{
return movingStyle;
}
bool BaseCreatureEntity::isSpecialStateActive(enumSpecialState state)
{
return specialState[state].active;
}
void BaseCreatureEntity::setSpecialState(enumSpecialState state, bool active, float timer, float param1, float param2)
{
specialState[state].active = active;
specialState[state].timer = timer;
specialState[state].param1 = param1;
specialState[state].param2 = param2;
}
float BaseCreatureEntity::animateStates(float delay)
{
for (int i = 0; i < NB_SPECIAL_STATES; i++)
{
if (specialState[i].active)
{
specialState[i].timer -= delay;
if (specialState[i].timer <= 0.0f) setSpecialState((enumSpecialState)i, false, 0.0f, 0.0f, 0.0f);
}
}
// ice
if (specialState[SpecialStateIce].active) delay *= specialState[SpecialStateIce].param1;
// poison
if (specialState[SpecialStatePoison].active)
{
specialState[SpecialStatePoison].param3 -= delay;
if (specialState[SpecialStatePoison].param3 <= 0.0f)
{
specialState[SpecialStatePoison].param3 += specialState[SpecialStatePoison].param2;
// TODO
hurt(getHurtParams(specialState[SpecialStatePoison].param1, ShotTypeDeterministic, 0, false, SourceTypePoison, NB_ENEMY, false));
}
}
return delay;
}
void BaseCreatureEntity::animateColors(float delay)
{
// no color
sprite.setColor(sf::Color(255, 255, 255, 255 ));
if (hurting && hp > 0)
{
hurtingDelay -= delay;
if (hurtingDelay > 0.0f)
{
int fadeColor = (sf::Uint8)((HURTING_DELAY - hurtingDelay) * 255);
if (hurtingDelay > HURTING_DELAY) fadeColor = 0;
if (hurtingType == ShotTypeIce || hurtingType == ShotTypeCold)
sprite.setColor(sf::Color(fadeColor, fadeColor, 255, 255 )); // blue
else if (hurtingType == ShotTypePoison)
sprite.setColor(sf::Color(fadeColor, 255, fadeColor, 255 )); // green
else
sprite.setColor(sf::Color(255, fadeColor, fadeColor, 255 )); // red
}
else
{
hurting = false;
sprite.setColor(sf::Color(255, 255, 255, 255 ));
}
}
if (specialState[SpecialStateIce].active) sprite.setColor(sf::Color(100, 100, 255, 255 ));
else if (specialState[SpecialStatePoison].active) sprite.setColor(sf::Color(100, 255, 100, 255 ));
}
void BaseCreatureEntity::animateRecoil(float delay)
{
// recoil
if (recoil.active)
{
recoil.velocity.x *= 0.97f;
recoil.velocity.y *= 0.97f;
recoil.timer -= delay;
if (recoil.timer <= 0.0f)
{
recoil.active = false;
computeFacingDirection();
// TODO ?
}
}
}
void BaseCreatureEntity::animatePhysics(float delay)
{
velocity.x *= viscosity;
velocity.y *= viscosity;
float velx = velocity.x;
float vely = velocity.y;
if (specialState[SpecialStateSlow].active)
{
velx *= specialState[SpecialStateSlow].param1;
vely *= specialState[SpecialStateSlow].param1;
}
if (recoil.active)
{
if (recoil.stun)
{
velx = 0.0f;
vely = 0.0f;
}
velx += recoil.velocity.x;
vely += recoil.velocity.y;
}
spin *= viscosity;
angle += spin * delay;
if (isCollidingWithMap())
{
stuck();
}
else
{
if ((int)velx > 0)
{
x += velx * delay;
if (collideWithMap(DIRECTION_LEFT))
{
x = (float)((int)x);
while (collideWithMap(DIRECTION_LEFT))
x--;
collideMapRight();
}
else if (x > map->getWidth() * tileWidth + offsetX)
{
exitMap(DIRECTION_RIGHT);
}
}
else if ((int)velx < 0)
{
x += velx * delay;
if (collideWithMap(DIRECTION_RIGHT))
{
x = (float)((int)x);
while (collideWithMap(DIRECTION_RIGHT))
x++;
collideMapLeft();
}
else if (x < offsetX)
{
exitMap(DIRECTION_LEFT);
}
}
}
vely += weight * delay;
if ( vely > maxY) vely = maxY;
if ((int)vely > 0)
{
y += vely * delay;
if (collideWithMap(DIRECTION_BOTTOM))
{
y = (float)((int)y);
while (collideWithMap(DIRECTION_BOTTOM))
y--;
collideMapBottom();
}
}
else if ((int)vely < 0)
{
y += vely * delay;
if (collideWithMap(DIRECTION_TOP))
{
y = (float)((int)y);
while (collideWithMap(DIRECTION_TOP))
y++;
collideMapTop();
}
}
if (lifetime > 0)
{
if (age >= lifetime) dyingFromAge();
}
age += delay;
}
void BaseCreatureEntity::dyingFromAge()
{
dying();
}
void BaseCreatureEntity::animate(float delay)
{
if (hpDisplay > hp) hpDisplay--;
else if (hpDisplay < hp) hpDisplay++;
delay = animateStates(delay);
animateColors(delay);
animateRecoil(delay);
animatePhysics(delay);
z = y + height/2;
}
void BaseCreatureEntity::render(sf::RenderTarget* app)
{
if (!isDying && shadowFrame > -1)
{
// shadow
int nx = shadowFrame;
int ny = 0;
if (imagesProLine > 0 && shadowFrame >= imagesProLine)
{
nx = shadowFrame % imagesProLine;
ny = shadowFrame / imagesProLine;
}
sprite.setTextureRect(sf::IntRect(nx * width, ny * height, width, height));
app->draw(sprite);
}
CollidingSpriteEntity::render(app);
if (game().getShowLogical())
{
displayBoundingBox(app);
displayCenterAndZ(app);
}
}
void BaseCreatureEntity::calculateBB()
{
}
bool BaseCreatureEntity::collideWithMap(int direction)
{
calculateBB();
int xTile0 = (boundingBox.left - offsetX) / tileWidth;
int xTilef = (boundingBox.left + boundingBox.width - offsetX) / tileWidth;
int yTile0 = (boundingBox.top - offsetY) / tileHeight;
int yTilef = (boundingBox.top + boundingBox.height - offsetY) / tileHeight;
if (boundingBox.top < 0) yTile0 = -1;
switch (direction)
{
case DIRECTION_RIGHT:
if (xTilef > xTile0) xTilef = xTile0;
break;
case DIRECTION_LEFT:
if (xTilef > xTile0) xTile0 = xTilef;
break;
case DIRECTION_TOP:
if (yTilef > yTile0) yTilef = yTile0;
break;
case DIRECTION_BOTTOM:
if (yTilef > yTile0) yTile0 = yTilef;
break;
}
for (int xTile = xTile0; xTile <= xTilef; xTile++)
for (int yTile = yTile0; yTile <= yTilef; yTile++)
{
if (movingStyle == movWalking)
{
if ( dynamic_cast<DungeonMap*>(map)->isWalkable(xTile, yTile) == false ) return true;
}
else if (movingStyle == movFlying)
{
if ( dynamic_cast<DungeonMap*>(map)->isFlyable(xTile, yTile) == false ) return true;
}
}
return false;
}
bool BaseCreatureEntity::determineSatusChance(enumStateResistance resistance, int level)
{
bool hit = true;
switch (resistance)
{
case ResistanceVeryLow:
case ResistanceLow:
case ResistanceStandard: hit = true; break;
case ResistanceHigh: hit = rand() % 8 <= level * 2; break;
case ResistanceVeryHigh: hit = rand() % 10 <= level * 2; break;
case ResistanceImmune: hit = false; break;
}
return hit;
}
int BaseCreatureEntity::determineDamageBonus(enumStateResistance resistance, int level)
{
int bonus = 0;
switch (resistance)
{
case ResistanceVeryLow: bonus = 40 + 10 * level; break;
case ResistanceLow: bonus = 20 + 5 * level; break;
case ResistanceStandard: bonus = 0; break;
case ResistanceHigh: bonus = -25 + 5 * level; break;
case ResistanceVeryHigh: bonus = -50 + 5 * level; break;
case ResistanceImmune: bonus = -100 + 5 * level; break;
}
return bonus;
}
bool BaseCreatureEntity::textTooClose(TextEntity* textEntity, float xDistMin, float yDistMin)
{
EntityManager::EntityList* entityList =EntityManager::getInstance().getList();
EntityManager::EntityList::iterator it;
for (it = entityList->begin (); it != entityList->end ();)
{
GameEntity *e = *it;
it++;
if (e->getType() == ENTITY_FLYING_TEXT)
{
if (e != textEntity)
{
if (textEntity->getX() - e->getX() < xDistMin && textEntity->getX() - e->getX() > - xDistMin
&& textEntity->getY() - e->getY() < yDistMin && textEntity->getY() - e->getY() > - yDistMin)
return true;
}
}
}
return false;
}
+void BaseCreatureEntity::makeExplode()
+{
+ ExplosionEntity* expl = new ExplosionEntity(x, y, ExplosionTypeStandard, 16, EnemyTypeNone);
+ expl->setCanHurtPlayer(false);
+ game().addCorpse(x, y, FRAME_CORPSE_SLIME_VIOLET);
+ SoundManager::getInstance().playSound(SOUND_BOOM_00);
+}
+
int BaseCreatureEntity::hurt(StructHurt hurtParam)
{
int oldHp = hp;
int absorbedHp = 0;
bool poisoned = false;
hurtingType = hurtParam.hurtingType;
if (armor > 0.01f && hurtingType != ShotTypeDeterministic)
{
absorbedHp = hurtParam.damage * armor;
if (absorbedHp == 0) absorbedHp = 1;
hurtParam.damage -= absorbedHp;
}
if (hurtingType == ShotTypeIce
&& determineSatusChance(resistance[ResistanceFrozen], hurtParam.level))
{
// frozen ?
specialState[SpecialStateIce].active = true;
float frozenDelayMult = 1.0f;
float frozenMultAdd = 0.0f;
if (resistance[ResistanceFrozen] == ResistanceHigh)
{
if (hurtParam.level == 0)
{
frozenDelayMult = 0.8f;
frozenMultAdd = 0.2f;
}
else
{
frozenDelayMult = 0.85f;
frozenMultAdd = 0.15f;
}
}
else if (resistance[ResistanceFrozen] == ResistanceVeryHigh)
{
if (hurtParam.level < 2)
{
frozenDelayMult = 0.7f;
frozenMultAdd = 0.25f;
}
else
{
frozenDelayMult = 0.8f;
frozenMultAdd = 0.2f;
}
}
specialState[SpecialStateIce].timer = STATUS_FROZEN_DELAY[hurtParam.level] * frozenDelayMult;
specialState[SpecialStateIce].param1 = STATUS_FROZEN_MULT[hurtParam.level] + frozenMultAdd;
}
else if (hurtingType == ShotTypePoison && determineSatusChance(resistance[ResistancePoison], hurtParam.level))
{
specialState[SpecialStatePoison].active = true;
specialState[SpecialStatePoison].timer = POISON_TIMER[hurtParam.level];
specialState[SpecialStatePoison].param1 = POISON_DAMAGE[hurtParam.level];
specialState[SpecialStatePoison].param2 = POISON_DELAY[hurtParam.level];
specialState[SpecialStatePoison].param3 = POISON_DELAY[hurtParam.level];
poisoned = true;
}
// damage bonus
if (hurtingType == ShotTypeIce || hurtingType == ShotTypeCold)
hurtParam.damage += (hurtParam.damage * determineDamageBonus(resistance[ResistanceIce], hurtParam.level)) / 100;
else if (hurtingType == ShotTypeFire)
hurtParam.damage += (hurtParam.damage * determineDamageBonus(resistance[ResistanceFire], hurtParam.level)) / 100;
else if (hurtingType == ShotTypeLightning)
hurtParam.damage += (hurtParam.damage * determineDamageBonus(resistance[ResistanceLightning], hurtParam.level)) / 100;
else if (hurtingType == ShotTypeStone)
hurtParam.damage += (hurtParam.damage * determineDamageBonus(resistance[ResistanceStone], hurtParam.level)) / 100;
else if (hurtingType == ShotTypeIllusion)
hurtParam.damage += (hurtParam.damage * determineDamageBonus(resistance[ResistanceIllusion], hurtParam.level)) / 100;
//else if (hurtingType == ShotTypePoison)
// hurtParam.damage += (hurtParam.damage * determineDamageBonus(resistance[ResistancePoison], hurtParam.level)) / 100;
if (hurtParam.damage > 0)
{
hurting = true;
hurtingDelay = HURTING_DELAY;
this->hurtingType = hurtingType;
hp -= hurtParam.damage;
if (hp <= 0)
{
hp = 0;
prepareDying();
// exploding ?
if (game().getPlayer()->isEquiped(EQUIP_SULFUR) && canExplode)
{
int luck = hurtingType == ShotTypeFire ? 33 : 25;
- if (rand() % 100 < luck)
- {
- ExplosionEntity* expl = new ExplosionEntity(x, y, ExplosionTypeStandard, 16, EnemyTypeNone);
- expl->setCanHurtPlayer(false);
- game().addCorpse(x, y, FRAME_CORPSE_SLIME_VIOLET);
- SoundManager::getInstance().playSound(SOUND_BOOM_00);
- }
+ if (rand() % 100 < luck) makeExplode();
}
}
if (oldHp > 0)
{
int displayedDamage = hurtParam.damage;
if (hurtParam.goThrough && hp == 0)
{
hurtParam.damage = oldHp + absorbedHp;
displayedDamage = oldHp;
}
std::ostringstream oss;
oss << "-" << displayedDamage;
int textSize;
if (displayedDamage < 8) textSize = 17;
else textSize = 17 + (displayedDamage - 3) / 5;
TextEntity* text = new TextEntity(oss.str(), textSize, x, y - 20.0f);
text->setColor(TextEntity::COLOR_FADING_RED);
text->setAge(-0.6f);
text->setLifetime(0.3f);
text->setWeight(-60.0f);
text->setZ(2000);
text->setAlignment(ALIGN_CENTER);
text->setType(ENTITY_FLYING_TEXT);
while (textTooClose(text, 15, 15)) text->setY(text->getY() - 5);
if (hurtParam.critical)
{
TextEntity* textCrit = new TextEntity(tools::getLabel("critical"), 16, x, text->getY() - 16.0f);
textCrit->setColor(TextEntity::COLOR_FADING_RED);
textCrit->setAge(-0.6f);
textCrit->setLifetime(0.3f);
textCrit->setWeight(-60.0f);
textCrit->setZ(2000);
textCrit->setAlignment(ALIGN_CENTER);
textCrit->setType(ENTITY_FLYING_TEXT);
}
if (poisoned)
{
TextEntity* textCrit = new TextEntity(tools::getLabel("poison"), 16, x, text->getY() - 16.0f);
textCrit->setColor(TextEntity::COLOR_FADING_RED);
textCrit->setAge(-0.6f);
textCrit->setLifetime(0.3f);
textCrit->setWeight(-60.0f);
textCrit->setZ(2000);
textCrit->setAlignment(ALIGN_CENTER);
textCrit->setType(ENTITY_FLYING_TEXT);
}
if (hurtParam.critical) SoundManager::getInstance().playSound(SOUND_CRITICAL);
}
}
return hurtParam.damage;
}
void BaseCreatureEntity::prepareDying()
{
dying();
}
void BaseCreatureEntity::dying()
{
isDying = true;
}
void BaseCreatureEntity::computeFacingDirection()
{
if (abs((int)velocity.x) > 0 || abs((int)velocity.y) > 0)
{
if (abs((int)velocity.x) > abs((int)velocity.y))
{
if (velocity.x > 0.0f) facingDirection = 6;
else facingDirection = 4;
}
else
{
if (velocity.y > 0.0f) facingDirection = 2;
else facingDirection = 8;
}
}
}
void BaseCreatureEntity::giveRecoil(bool stun, Vector2D velocity, float timer)
{
if (resistance[ResistanceRecoil] == ResistanceHigh)
{
velocity.x *= 0.75f;
velocity.y *= 0.75f;
timer *= 0.75f;
}
else if (resistance[ResistanceRecoil] == ResistanceVeryHigh)
{
velocity.x *= 0.5f;
velocity.y *= 0.5f;
timer *= 0.5f;
}
if (!(recoil.active && recoil.stun))
{
recoil.active = true;
recoil.stun = stun;
if (this->velocity.x > 1.0f && velocity.x > 1.0f) recoil.velocity.x = velocity.x + this->velocity.x;
else if (this->velocity.x < -1.0f && velocity.x < -1.0f) recoil.velocity.x = velocity.x + this->velocity.x;
else recoil.velocity.x = velocity.x;
if (this->velocity.y > 1.0f && velocity.y > 1.0f) recoil.velocity.y = velocity.y + this->velocity.y;
else if (this->velocity.y < -1.0f && velocity.y < -1.0f) recoil.velocity.y = velocity.y + this->velocity.y;
else recoil.velocity.y = velocity.y;
recoil.timer = timer;
}
}
void BaseCreatureEntity::inflictsRecoilTo(BaseCreatureEntity* targetEntity)
{
}
bool BaseCreatureEntity::canCollide()
{
return true;
}
void BaseCreatureEntity::generateStar(sf::Color starColor)
{
game().generateStar(starColor, x, y);
}
static bool intersectsSegments(Vector2D a1, Vector2D a2, Vector2D b1, Vector2D b2)
{
Vector2D b(a2.x - a1.x, a2.y - a1.y);
Vector2D d(b2.x - b1.x, b2.y - b1.y);
float bDotDPerp = b.x * d.y - b.y * d.x;
// if b dot d == 0, it means the lines are parallel so have infinite intersection points
if (bDotDPerp == 0) return false;
Vector2D c(b1.x - a1.x, b1.y - a1.y);
float t = (c.x * d.y - c.y * d.x) / bDotDPerp;
if (t < 0 || t > 1) return false;
float u = (c.x * b.y - c.y * b.x) / bDotDPerp;
if (u < 0 || u > 1) return false;
return true;
}
static bool intersectsTile(Vector2D a1, Vector2D a2, int xTile, int yTile)
{
int posX = xTile * TILE_WIDTH;
int posY = yTile * TILE_HEIGHT;
if (intersectsSegments(a1, a2, Vector2D(posX, posY), Vector2D(posX + TILE_WIDTH, posY))) return true;
else if (intersectsSegments(a1, a2, Vector2D(posX, posY + TILE_HEIGHT), Vector2D(posX + TILE_WIDTH, posY + TILE_HEIGHT))) return true;
else if (intersectsSegments(a1, a2, Vector2D(posX + TILE_WIDTH, posY), Vector2D(posX + TILE_WIDTH, posY + TILE_HEIGHT))) return true;
else if (intersectsSegments(a1, a2, Vector2D(posX, posY), Vector2D(posX, posY + TILE_HEIGHT))) return true;
else
return false;
}
bool BaseCreatureEntity::canSee(float xf, float yf)
{
int tileX0 = x / TILE_WIDTH;
int tileXf = xf / TILE_WIDTH;
int tileY0 = y / TILE_HEIGHT;
int tileYf = yf / TILE_HEIGHT;
int xBegin, xEnd, yBegin, yEnd;
if (tileXf < tileX0)
{
xBegin = tileXf;
xEnd = tileX0;
}
else
{
xBegin = tileX0;
xEnd = tileXf;
}
if (tileYf < tileY0)
{
yBegin = tileYf;
yEnd = tileY0;
}
else
{
yBegin = tileY0;
yEnd = tileYf;
}
for (int i = xBegin; i <= xEnd; i++ )
for (int j = yBegin; j <= yEnd; j++ )
{
if (!game().getCurrentMap()->isShootable(i, j))
if (intersectsTile(Vector2D(x, y), game().getPlayerPosition(), i , j))
return false;
}
return true;
}
bool BaseCreatureEntity::canWalkTo(float xf, float yf)
{
int tileX0 = x / TILE_WIDTH;
int tileXf = xf / TILE_WIDTH;
int tileY0 = y / TILE_HEIGHT;
int tileYf = yf / TILE_HEIGHT;
int xBegin, xEnd, yBegin, yEnd;
if (tileXf < tileX0)
{
xBegin = tileXf;
xEnd = tileX0;
}
else
{
xBegin = tileX0;
xEnd = tileXf;
}
if (tileYf < tileY0)
{
yBegin = tileYf;
yEnd = tileY0;
}
else
{
yBegin = tileY0;
yEnd = tileYf;
}
for (int i = xBegin; i <= xEnd; i++ )
for (int j = yBegin; j <= yEnd; j++ )
{
if (!game().getCurrentMap()->isWalkable(i, j))
if (intersectsTile(Vector2D(x, y), game().getPlayerPosition(), i , j))
return false;
}
return true;
}
void BaseCreatureEntity::heal(int healPoints)
{
int savedHp = hp;
hp += healPoints;
if (hp > hpMax) hp = hpMax;
int healedHp = hp - savedHp;
if (savedHp > 0)
{
std::ostringstream oss;
oss << "+" << healedHp;
int textSize;
if (healedHp < 8) textSize = 17;
else textSize = 17 + (healedHp - 3) / 5;
TextEntity* text = new TextEntity(oss.str(), textSize, x, y - 20.0f);
text->setColor(TextEntity::COLOR_FADING_GREEN);
text->setAge(-0.6f);
text->setLifetime(0.3f);
text->setWeight(-60.0f);
text->setZ(2000);
text->setAlignment(ALIGN_CENTER);
text->setType(ENTITY_FLYING_TEXT);
while (textTooClose(text, 15, 15)) text->setY(text->getY() - 5);
}
}
diff --git a/src/BaseCreatureEntity.h b/src/BaseCreatureEntity.h
index bcda3e0..3d3ab11 100644
--- a/src/BaseCreatureEntity.h
+++ b/src/BaseCreatureEntity.h
@@ -1,232 +1,233 @@
#ifndef BASECREATUREENTITY_H
#define BASECREATUREENTITY_H
#include "sfml_game/CollidingSpriteEntity.h"
#include "TextEntity.h"
#include "Constants.h"
enum enemyTypeEnum
{
// normal
EnemyTypeBat,
EnemyTypeRat,
EnemyTypeRatBlack,
EnemyTypeRatHelmet,
EnemyTypeRatBlackHelmet,
EnemyTypeEvilFlower,
EnemyTypeEvilFlowerIce,
EnemyTypeEvilFlowerFire,
EnemyTypeSnake,
EnemyTypeSnakeBlood,
EnemyTypeSlime,
EnemyTypeSlimeRed,
EnemyTypeSlimeBlue,
EnemyTypeSlimeViolet,
EnemyTypeImpBlue,
EnemyTypeImpRed,
EnemyTypePumpkin,
EnemyTypeWitch,
EnemyTypeWitchRed,
EnemyTypeCauldron,
EnemyTypeSpiderEgg,
EnemyTypeSpiderLittle,
EnemyTypeGhost,
EnemyTypeZombie,
EnemyTypeZombieDark,
// mini boss
EnemyTypeBubble,
EnemyTypeBubbleIce,
EnemyTypeBubbleGreater,
// boss
EnemyTypeButcher,
EnemyTypeSlimeBoss,
EnemyTypeCyclops,
EnemyTypeRatKing,
EnemyTypeSpiderGiant,
EnemyTypeFrancky,
// invocated
EnemyTypeBat_invocated,
EnemyTypeRat_invocated,
EnemyTypeRatGreen,
EnemyTypeRatHelmet_invocated,
EnemyTypeSnake_invocated,
EnemyTypeSnakeBlood_invocated,
EnemyTypeSlime_invocated,
EnemyTypeSlimeRed_invocated,
EnemyTypeSlimeBlue_invocated,
EnemyTypeSlimeViolet_invocated,
EnemyTypePumpkin_invocated,
EnemyTypeSpiderEgg_invocated,
EnemyTypeSpiderLittle_invocated,
EnemyTypeZombie_invocated,
EnemyTypeRockFalling,
EnemyTypeRockMissile,
EnemyTypeSpiderWeb,
EnemyTypeFranckyHead,
EnemyTypeFranckyHand,
EnemyTypeFranckyFoot,
EnemyTypeNone, // player of fairy
NB_ENEMY // = no enemy
};
enum sourceTypeEnum
{
SourceTypeMelee,
SourceTypeBolt,
SourceTypeExplosion,
SourceTypePoison
};
struct StructHurt
{
int damage;
enumShotType hurtingType;
int level;
bool critical;
sourceTypeEnum sourceType;
enemyTypeEnum enemyType;
bool goThrough;
};
class BaseCreatureEntity : public CollidingSpriteEntity
{
public:
BaseCreatureEntity(sf::Texture* image, float x, float y, int spriteWidth, int spriteHeight);
int getHp();
int getHpMax();
void setHp(int hp);
void setHpMax(int hpMax);
int getHpDisplay();
float getCreatureSpeed();
IntCoord getCurrentTile();
virtual void animate(float delay);
virtual float animateStates(float delay);
virtual void animateColors(float delay);
virtual void animateRecoil(float delay);
virtual void animatePhysics(float delay);
virtual void render(sf::RenderTarget* app);
virtual void calculateBB();
virtual bool collideWithMap(int direction);
virtual int hurt(StructHurt hurtParam);
virtual void prepareDying();
virtual void dying();
enum enumMovingStyle { movWalking, movFlying};
virtual enumMovingStyle getMovingStyle();
enum enumBloodColor { BloodNone = -1, BloodRed, BloodGreen, BloodRock, BloodEgg, BloodBubble, BloodBubbleIce};
enum enumSpecialState
{
SpecialStateIce, // = 0
SpecialStateSlow,
SpecialStatePoison,
DivineStateProtection,
DivineStateSpeed,
DivineStateFireRate,
DivineStateFireDamage,
NB_SPECIAL_STATES
};
enum enumStateResistance { ResistanceImmune, ResistanceVeryHigh, ResistanceHigh, ResistanceStandard, ResistanceLow, ResistanceVeryLow};
struct specialStateStuct
{
enumSpecialState type;
bool active;
float timer;
float param1;
float param2;
float param3;
};
specialStateStuct specialState[NB_SPECIAL_STATES];
virtual void setSpecialState(enumSpecialState state, bool active, float timer, float param1, float param2);
enum enumResistances
{
ResistanceIce, // = 0
ResistanceFire,
ResistanceStone,
ResistanceLightning,
ResistanceIllusion,
ResistancePoison,
ResistanceRecoil,
ResistanceFrozen,
NB_RESISTANCES
};
enumStateResistance resistance[NB_RESISTANCES];
bool isSpecialStateActive(enumSpecialState state);
virtual void giveRecoil(bool stun, Vector2D velocity, float timer);
virtual void inflictsRecoilTo(BaseCreatureEntity* targetEntity);
virtual void computeFacingDirection();
virtual void dyingFromAge();
virtual bool canCollide();
bool canSee(float xf, float yf);
bool canWalkTo(float xf, float yf);
void heal(int healPoints);
static StructHurt getHurtParams(int damage,
enumShotType hurtingType,
int level,
bool critical,
sourceTypeEnum sourceType,
enemyTypeEnum enemyType,
bool goThrough)
{
StructHurt hurtParams;
hurtParams.damage = damage;
hurtParams.hurtingType = hurtingType;
hurtParams.level = level;
hurtParams.critical = critical;
hurtParams.sourceType = sourceType;
hurtParams.enemyType = enemyType;
hurtParams.goThrough = goThrough;
return hurtParams;
}
protected:
int hp;
int hpMax;
int hpDisplay;
float creatureSpeed;
int shadowFrame;
int facingDirection;
float armor;
bool canExplode; // true if the monster can explode with a fire attack
bool hurting;
float hurtingDelay;
enumShotType hurtingType;
enumBloodColor bloodColor;
enumMovingStyle movingStyle;
struct recoilStruct
{
bool active;
Vector2D velocity;
bool stun;
float timer;
} recoil;
void generateStar(sf::Color starColor);
+ virtual void makeExplode();
private:
bool determineSatusChance(enumStateResistance resistance, int level);
int determineDamageBonus(enumStateResistance resistance, int level);
bool textTooClose(TextEntity* textEntity, float xDistMin, float yDistMin);
};
#endif // BASECREATUREENTITY_H
diff --git a/src/SlimeEntity.cpp b/src/SlimeEntity.cpp
index 4486a10..44c5e42 100644
--- a/src/SlimeEntity.cpp
+++ b/src/SlimeEntity.cpp
@@ -1,383 +1,393 @@
#include "SlimeEntity.h"
#include "PlayerEntity.h"
#include "EnemyBoltEntity.h"
#include "ExplosionEntity.h"
#include "sfml_game/SpriteEntity.h"
#include "sfml_game/ImageManager.h"
#include "sfml_game/SoundManager.h"
#include "Constants.h"
#include "WitchBlastGame.h"
SlimeEntity::SlimeEntity(float x, float y, slimeTypeEnum slimeType, bool invocated)
: EnemyEntity (ImageManager::getInstance().getImage(IMAGE_SLIME), x, y)
{
creatureSpeed = 0.0f;
velocity = Vector2D(0.0f, 0.0f);
hp = SLIME_HP;
meleeDamages = SLIME_DAMAGES;
this->slimeType = slimeType;
this->invocated = invocated;
if (invocated)
{
type = ENTITY_ENEMY_INVOCATED;
jumpingDelay = 0.1f;
age = 0.0f;
}
else
{
jumpingDelay = 0.6f + 0.1f * (rand() % 20);
}
if (slimeType == SlimeTypeBlue)
{
resistance[ResistanceFrozen] = ResistanceImmune;
resistance[ResistanceIce] = ResistanceVeryHigh;
resistance[ResistanceFire] = ResistanceVeryLow;
enemyType = invocated ? EnemyTypeSlimeBlue_invocated : EnemyTypeSlimeBlue;
deathFrame = FRAME_CORPSE_SLIME_BLUE;
}
else if (slimeType == SlimeTypeRed)
{
resistance[ResistanceIce] = ResistanceVeryLow;
resistance[ResistanceFire] = ResistanceVeryHigh;
enemyType = invocated ? EnemyTypeSlimeRed_invocated : EnemyTypeSlimeRed;
deathFrame = FRAME_CORPSE_SLIME_RED;
}
else if (slimeType == SlimeTypeViolet)
{
enemyType = invocated ? EnemyTypeSlimeViolet_invocated : EnemyTypeSlimeViolet;
canExplode = false;
deathFrame = FRAME_CORPSE_SLIME_VIOLET;
}
else
{
enemyType = invocated ? EnemyTypeSlime_invocated : EnemyTypeSlime;
deathFrame = FRAME_CORPSE_SLIME;
}
bloodColor = BloodGreen;
frame = 0;
shadowFrame = 3;
imagesProLine = 4;
isJumping = false;
h = 0.0f;
viscosity = 0.98f;
sprite.setOrigin(32, 44);
isPet = false;
+ willExplode = false;
}
void SlimeEntity::animate(float delay)
{
float slimeDelay = delay;
if (specialState[SpecialStateIce].active) slimeDelay = delay * specialState[SpecialStateIce].param1;
if (isJumping)
{
hVelocity -= 700.0f * slimeDelay;
h += hVelocity * slimeDelay;
bool firstTimeGround = false;
if (h <= 0.0f)
{
if (hp <= 0)
dying();
else
{
h = 0.0f;
if (isFirstJumping)
{
isFirstJumping = false;
firstTimeGround = true;
hVelocity = 160.0f;
SoundManager::getInstance().playSound(SOUND_SLIME_IMAPCT);
if (slimeType == SlimeTypeBlue || slimeType == SlimeTypeRed)
fire();
else if (slimeType == SlimeTypeViolet)
{
hp = 0;
dying();
}
}
else
{
jumpingDelay = 0.4f + 0.1f * (rand() % 20);
isJumping = false;
SoundManager::getInstance().playSound(SOUND_SLIME_IMAPCT_WEAK);
}
}
}
if (firstTimeGround) frame = 0;
else if (hVelocity > -190.0f) frame = 2;
else frame = 1;
}
else
{
jumpingDelay -= slimeDelay;
if (jumpingDelay < 0.0f)
{
SoundManager::getInstance().playSound(SOUND_SLIME_JUMP);
hVelocity = 350.0f + rand() % 300;
isJumping = true;
isFirstJumping = true;
float randVel = 250.0f + rand() % 250;
if (!game().getPlayer()->isEquiped(EQUIP_MANUAL_SLIMES) && rand() % 2 == 0)
{
setVelocity(Vector2D(x, y).vectorTo(game().getPlayerPosition(), randVel ));
}
else
velocity = Vector2D(randVel);
}
else if (jumpingDelay < 0.1f)
frame = 1;
else frame = 0;
}
EnemyEntity::animate(delay);
z = y + 14;
}
+void SlimeEntity::makeExplode()
+{
+ if (isJumping)
+ willExplode = true;
+ else
+ BaseCreatureEntity::makeExplode();
+}
+
void SlimeEntity::readCollidingEntity(CollidingSpriteEntity* entity)
{
if (!isDying && !isAgonising && collideWithEntity(entity))
{
if (!isPet && (entity->getType() == ENTITY_PLAYER || entity->getType() == ENTITY_BOLT ) )
{
PlayerEntity* playerEntity = dynamic_cast<PlayerEntity*>(entity);
BoltEntity* boltEntity = dynamic_cast<BoltEntity*>(entity);
if (playerEntity != NULL && !playerEntity->isDead())
{
if (playerEntity->hurt(getHurtParams(meleeDamages, meleeType, meleeDamages, false, SourceTypeMelee, enemyType, false)))
{
float xs = (x + playerEntity->getX()) / 2;
float ys = (y + playerEntity->getY()) / 2;
SpriteEntity* star = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_HURT_IMPACT), xs, ys);
star->setFading(true);
star->setZ(y+ 100);
star->setLifetime(0.7f);
star->setType(ENTITY_EFFECT);
star->setSpin(400.0f);
}
inflictsRecoilTo(playerEntity);
}
else if (boltEntity != NULL && !boltEntity->getDying() && boltEntity->getAge() > 0.05f)
{
collideWithBolt(boltEntity);
}
}
else // collision with other enemy ?
{
if (entity->getType() >= ENTITY_ENEMY && entity->getType() <= ENTITY_ENEMY_MAX_COUNT)
{
if (this != entity)
{
EnemyEntity* enemyEntity = static_cast<EnemyEntity*>(entity);
if (enemyEntity->canCollide()) collideWithEnemy(enemyEntity);
}
}
}
}
}
void SlimeEntity::render(sf::RenderTarget* app)
{
if (!isDying && shadowFrame > -1)
{
// shadow
sprite.setPosition(x, y);
sprite.setTextureRect(sf::IntRect(shadowFrame * width, 0, width, height));
app->draw(sprite);
}
sprite.setPosition(x, y - h);
sprite.setTextureRect(sf::IntRect(frame * width, slimeType * height, width, height));
app->draw(sprite);
if (game().getShowLogical())
{
displayBoundingBox(app);
displayCenterAndZ(app);
}
}
void SlimeEntity::calculateBB()
{
boundingBox.left = (int)x - width / 2 + SLIME_BB_LEFT;
boundingBox.width = width - SLIME_BB_WIDTH_DIFF;
boundingBox.top = (int)y - height / 2 + SLIME_BB_TOP - 15;
boundingBox.height = height - SLIME_BB_HEIGHT_DIFF;
}
void SlimeEntity::collideMapRight()
{
// if (x > OFFSET_X + MAP_WIDTH * TILE_WIDTH)
velocity.x = -velocity.x * 0.8f;
}
void SlimeEntity::collideMapLeft()
{
// if (x < OFFSET_X + MAP_WIDTH )
velocity.x = -velocity.x * 0.8f;
}
void SlimeEntity::collideMapTop()
{
// if (y > OFFSET_Y + MAP_HEIGHT * TILE_HEIGHT)
velocity.y = -velocity.y * 0.8f;
}
void SlimeEntity::collideMapBottom()
{
// if (y < OFFSET_Y + MAP_HEIGHT )
velocity.y = -velocity.y * 0.8f;
}
void SlimeEntity::collideWithEnemy(EnemyEntity* entity)
{
if (recoil.active && recoil.stun) return;
if (entity->getMovingStyle() == movWalking)
{
Vector2D vel = Vector2D(entity->getX(), entity->getY()).vectorTo(Vector2D(x, y), 100.0f );
giveRecoil(false, vel, 0.3f);
computeFacingDirection();
}
}
bool SlimeEntity::collideWithMap(int direction)
{
calculateBB();
int xTile0 = (boundingBox.left - offsetX) / tileWidth;
int xTilef = (boundingBox.left + boundingBox.width - offsetX) / tileWidth;
int yTile0 = (boundingBox.top - offsetY) / tileHeight;
int yTilef = (boundingBox.top + boundingBox.height - offsetY) / tileHeight;
if (boundingBox.top < 0) yTile0 = -1;
for (int xTile = xTile0; xTile <= xTilef; xTile++)
for (int yTile = yTile0; yTile <= yTilef; yTile++)
{
if (!game().getCurrentMap()->isFlyable(xTile, yTile))
{
switch (direction)
{
case DIRECTION_LEFT:
if (map->isLeftBlocking(xTile, yTile)) return true;
break;
case DIRECTION_RIGHT:
if (map->isRightBlocking(xTile, yTile)) return true;
break;
case DIRECTION_TOP:
if (map->isUpBlocking(xTile, yTile)) return true;
break;
case DIRECTION_BOTTOM:
if (map->isDownBlocking(xTile, yTile)) return true;
break;
}
}
}
return false;
}
void SlimeEntity::dying()
{
if (slimeType == SlimeTypeViolet) explode();
+ else if (willExplode) BaseCreatureEntity::makeExplode();
EnemyEntity::dying();
}
void SlimeEntity::prepareDying()
{
if (!isJumping)
dying();
}
bool SlimeEntity::canCollide()
{
- return h <= 70.0f;
+ return h <= 70.0f && hp > 0;
}
BaseCreatureEntity::enumMovingStyle SlimeEntity::getMovingStyle()
{
if (h <= 70.0f)
return movWalking;
else
return movFlying;
}
void SlimeEntity::fire()
{
for (int i = 0; i < 4; i++)
{
EnemyBoltEntity* bolt;
if (slimeType == SlimeTypeBlue)
{
bolt = new EnemyBoltEntity(x, y, ShotTypeIce, 0, enemyType);
bolt->setDamages(5);
}
else if (slimeType == SlimeTypeRed)
{
bolt = new EnemyBoltEntity(x, y, ShotTypeFire, 0, enemyType);
bolt->setDamages(8);
}
else
return;
switch (i)
{
case 0: bolt->setVelocity(Vector2D(SLIME_FIRE_VELOCITY, 0)); break;
case 1: bolt->setVelocity(Vector2D(-SLIME_FIRE_VELOCITY, 0)); break;
case 2: bolt->setVelocity(Vector2D(0, SLIME_FIRE_VELOCITY)); break;
case 3: bolt->setVelocity(Vector2D(0, -SLIME_FIRE_VELOCITY)); break;
}
}
if (slimeType == SlimeTypeBlue) SoundManager::getInstance().playSound(SOUND_BLAST_ICE);
else if (slimeType == SlimeTypeRed) SoundManager::getInstance().playSound(SOUND_BLAST_FIRE);
else SoundManager::getInstance().playSound(SOUND_BLAST_FLOWER);
}
void SlimeEntity::explode()
{
int damage = 12;
if (isPet) damage = game().getPlayer()->isEquiped(EQUIP_BOOK_MAGIC_II) ? 24 : 18;
new ExplosionEntity(x, y, ExplosionTypeStandard, damage, enemyType);
game().makeShake(1.0f);
SoundManager::getInstance().playSound(SOUND_BOOM_00);
}
void SlimeEntity::makePet(int direction)
{
isPet = true;
hVelocity = 450.0f;
SoundManager::getInstance().playSound(SOUND_SLIME_JUMP);
isJumping = true;
isFirstJumping = true;
switch (direction)
{
case 4: velocity.x = -350.0f; velocity.y = -0; break;
case 6: velocity.x = 350.0f; velocity.y = -0; break;
case 2: velocity.y = 350.0f; velocity.x = -0; break;
default: velocity.y = -350.0f; velocity.x = -0; break;
}
}
void SlimeEntity::drop()
{
if (!invocated) EnemyEntity::drop();
}
diff --git a/src/SlimeEntity.h b/src/SlimeEntity.h
index 4963215..70d8782 100644
--- a/src/SlimeEntity.h
+++ b/src/SlimeEntity.h
@@ -1,47 +1,49 @@
#ifndef SLIMESPRITE_H
#define SLIMESPRITE_H
#include "EnemyEntity.h"
#include "PlayerEntity.h"
enum slimeTypeEnum { SlimeTypeStandard, SlimeTypeRed, SlimeTypeBlue, SlimeTypeViolet };
class SlimeEntity : public EnemyEntity
{
public:
SlimeEntity(float x, float y, slimeTypeEnum slimeType, bool invocated);
virtual void animate(float delay);
virtual void render(sf::RenderTarget* app);
virtual void calculateBB();
virtual bool canCollide();
void makePet(int direction);
protected:
virtual bool collideWithMap(int direction);
virtual void collideMapRight();
virtual void collideMapLeft();
virtual void collideMapTop();
virtual void collideMapBottom();
virtual void readCollidingEntity(CollidingSpriteEntity* entity);
virtual void collideWithEnemy(EnemyEntity* entity) override;
virtual void dying();
virtual void prepareDying();
virtual void drop();
virtual enumMovingStyle getMovingStyle();
+ virtual void makeExplode();
private:
float jumpingDelay;
bool isJumping;
bool isPet;
bool isFirstJumping;
bool invocated;
slimeTypeEnum slimeType;
void fire();
void explode();
+ bool willExplode;
};
#endif // SLIMESPRITE_H
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Jun 19, 4:36 PM (1 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
73022
Default Alt Text
(39 KB)
Attached To
Mode
R78 witchblast
Attached
Detach File
Event Timeline