Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F108372
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
334 KB
Referenced Files
None
Subscribers
None
View Options
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/src/PlayerEntity.cpp b/src/PlayerEntity.cpp
index 6adab94..cfa385d 100644
--- a/src/PlayerEntity.cpp
+++ b/src/PlayerEntity.cpp
@@ -1,3507 +1,3511 @@
#include "PlayerEntity.h"
#include "SlimeEntity.h"
#include "SlimePetEntity.h"
#include "FallingRockEntity.h"
#include "BoltEntity.h"
#include "SpiderWebEntity.h"
#include "EvilFlowerEntity.h"
#include "EnemyBoltEntity.h"
#include "ItemEntity.h"
#include "FairyEntity.h"
#include "sfml_game/ImageManager.h"
#include "sfml_game/SoundManager.h"
#include "Constants.h"
#include "WitchBlastGame.h"
#include "TextEntity.h"
#include "TextMapper.h"
#include <iostream>
#include <sstream>
#define SPIRAL_STAIRCASE
const int xHalo[9][3] =
{
{ 13, 13, 18},
{ 47, 45, 37},
{ 48, 47, 44},
{ 15, 15, 16},
{ 45, 45, 45},
{ 46, 44, 42},
{ 13, 13, 13},
{ 13, 24, 36},
{ 13, 17, 13}
};
const int yHalo[9][3] =
{
{ 26, 25, 25},
{ 23, 23, 23},
{ 23, 24, 25},
{ 31, 32, 34},
{ 23, 23, 23},
{ 23, 22, 21},
{ 26, 26, 26},
{ 26, 15, 6},
{ 25, 27, 25}
};
const int KEYS_MOVE_TOLERANCE = 36;
PlayerEntity::PlayerEntity(float x, float y)
: BaseCreatureEntity (ImageManager::getInstance().getImage(IMAGE_PLAYER_0), x, y, 64, 96)
{
currentFireDelay = -1.0f;
randomFireDelay = -1.0f;
invincibleDelay = -1.0f;
divineInterventionDelay = -1.0f;
fireAnimationDelay = -1.0f;
fireAnimationDelayMax = 0.4f;
spellAnimationDelay = -1.0f;
spellAnimationDelayMax = 0.7f;
canFirePlayer = true;
type = ENTITY_PLAYER;
imagesProLine = 8;
playerStatus = playerStatusPlaying;
hp = INITIAL_PLAYER_HP;
#ifdef TEST_MODE
hp = INITIAL_PLAYER_HP * 100;
#endif // TEST_MODE
hpDisplay = hp;
hpMax = hp;
gold = 0;
+ donation = 0;
deathAge = -1.0f;
hiccupDelay = HICCUP_DELAY;
idleAge = 0.0f;
boltLifeTime = INITIAL_BOLT_LIFE;
specialBoltTimer = -1.0f;
bloodColor = BloodRed;
canExplode = false;
// init the equipment (to empty)
for (int i = 0; i < NUMBER_EQUIP_ITEMS; i++) equip[i] = false;
collidingDirection = 5;
// init the shots (to none)
for (int i = 0; i < SPECIAL_SHOT_SLOTS; i++)
{
specialShots[i] = ShotTypeStandard;
specialShotLevel[i] = 0;
}
// init the consumibles
for (int i = 0; i < MAX_SLOT_CONSUMABLES; i++)
consumable[i] = -1;
specialShotIndex = 0;
needInitShotType = false;
computePlayer();
firingDirection = 5;
facingDirection = 2;
keyDirection = 5;
sprite.setOrigin(32, 80);
protection.active = false;
armor = 0.0f;
activeSpell.delay = -1.0f;
activeSpell.spell = SpellNone;
divinity.divinity = -1;
divinity.piety = 0;
divinity.level = 0;
divinity.interventions = 0;
divinity.percentsToNextLevels = 0.0f;
shouldBeSavedFromDivinity = false;
isRegeneration = false;
isFairyTransmuted = false;
itemToBuy = NULL;
}
void PlayerEntity::moveTo(float newX, float newY)
{
float dx = newX - x;
float dy = newY - y;
x = newX;
y = newY;
for(int unsigned i = 0; i < fairies.size(); i++)
{
fairies[i]->setX(fairies[i]->getX() + dx);
fairies[i]->setY(fairies[i]->getY() + dy);
}
}
int PlayerEntity::getFacingDirection()
{
return facingDirection;
}
void PlayerEntity::setFacingDirection(int facingDirection)
{
if (facingDirection == 4 || facingDirection == 6 || facingDirection == 2 || facingDirection == 8)
this->facingDirection = facingDirection;
}
float PlayerEntity::getPercentFireDelay()
{
if (canFirePlayer) return 1.0f;
else return (1.0f - currentFireDelay / fireDelay);
}
float PlayerEntity::getLightCone()
{
if (playerStatus == playerStatusPraying)
{
float result = 1.0f;
if (statusTimer < 0.25f)
result = 4 * statusTimer;
else if (statusTimer > WORSHIP_DELAY - 0.25f)
result = (WORSHIP_DELAY - statusTimer) * 4;
return result;
}
else if (divineInterventionDelay > 0.0f)
{
float result = 1.0f;
if (divineInterventionDelay < 0.25f)
result = 4 * divineInterventionDelay;
else if (divineInterventionDelay > WORSHIP_DELAY - 0.25f)
result = (WORSHIP_DELAY - divineInterventionDelay) * 4;
if (isRegeneration) result *= 0.4f;
return result;
}
else return -1.0f;
}
float PlayerEntity::getPercentSpellDelay()
{
if (activeSpell.spell == SpellNone)
return getPercentFireDelay();
else
{
if (activeSpell.delay <= 0.0f) return 1.0f;
else return (1.0f - activeSpell.delay / activeSpell.delayMax);
}
}
bool PlayerEntity::isPoisoned()
{
return (specialState[SpecialStatePoison].active);
}
int PlayerEntity::getCollidingDirection()
{
return collidingDirection;
}
PlayerEntity::playerStatusEnum PlayerEntity::getPlayerStatus()
{
return playerStatus;
}
void PlayerEntity::setPlayerStatus(PlayerEntity::playerStatusEnum playerStatus)
{
this->playerStatus = playerStatus;
}
bool PlayerEntity::isDead()
{
return playerStatus == playerStatusDead;
}
enemyTypeEnum PlayerEntity::getLastHurtingEnemy()
{
return lastHurtingEnemy;
}
sourceTypeEnum PlayerEntity::getLastHurtingSource()
{
return lastHurtingSource;
}
float PlayerEntity::getDeathAge()
{
return deathAge;
}
void PlayerEntity::setDeathAge(float deathAge)
{
this->deathAge = deathAge;
}
bool PlayerEntity::getFairyTransmuted()
{
return isFairyTransmuted;
}
divinityStruct PlayerEntity::getDivinity()
{
return divinity;
}
int PlayerEntity::getPiety()
{
return divinity.piety;
}
void PlayerEntity::stuck()
{
if (playerStatus != playerStatusEntering)
castTeleport();
}
void PlayerEntity::setEntering()
{
playerStatus = playerStatusEntering;
}
void PlayerEntity::setLeavingLevel()
{
playerStatus = playerStatusGoingNext;
}
void PlayerEntity::pay(int price)
{
gold -= price;
displayAcquiredGold(-price);
if (gold < 0) gold = 0;
SoundManager::getInstance().playSound(SOUND_PAY);
}
void PlayerEntity::acquireItemAfterStance()
{
if (acquiredItem >= FirstEquipItem)
{
equip[acquiredItem - FirstEquipItem] = true;
if (acquiredItem != ItemBossKey) game().proceedEvent(EventGetItem);
// familiar
if (items[acquiredItem].familiar != FamiliarNone)
{
setEquiped(acquiredItem - FirstEquipItem, true);
game().proceedEvent(EventGetFamiliar);
}
// shot types
else if (items[acquiredItem].specialShot != (ShotTypeStandard))
{
registerSpecialShot(acquiredItem);
game().proceedEvent(EventGetSpecialShot);
}
// spells
else if (items[acquiredItem].spell != SpellNone)
{
setActiveSpell(items[acquiredItem].spell, false);
game().proceedEvent(EventGetSpell);
}
// pet slime
else if (acquiredItem == ItemPetSlime)
{
new SlimePetEntity();
}
// alchemy book
else if (acquiredItem == ItemBookAlchemy)
{
game().acquireAlchemyBook();
}
// floor item
else if (acquiredItem == ItemFloorMap)
game().revealFloor();
else if (acquiredItem == ItemAlcohol)
hiccupDelay = HICCUP_DELAY;
// acquirement
if (equip[EQUIP_DISPLACEMENT_GLOVES] && equip[EQUIP_LEATHER_BOOTS] && equip[EQUIP_MAGICIAN_HAT] && equip[EQUIP_MAGICIAN_ROBE])
game().registerAchievement(AchievementCompleteSet);
computePlayer();
}
else
{
if (acquiredItem == ItemBossHeart)
{
int hpBonus = 2 + rand() % 4;
hpMax += hpBonus;
hp += hpBonus;
hpDisplay += hpBonus;
SoundManager::getInstance().playSound(SOUND_EAT);
std::ostringstream oss;
oss << "HP Max +" << hpBonus;
TextEntity* text = new TextEntity(oss.str(), 15, x, y - 50.0f);
text->setColor(TextEntity::COLOR_FADING_GREEN);
text->setAlignment(ALIGN_CENTER);
text->setAge(-1.0f);
text->setLifetime(1.2f);
text->setWeight(-60.0f);
text->setType(ENTITY_FLYING_TEXT);
text->setZ(2000);
}
else if (acquiredItem == ItemBonusHealth)
{
hpMax += 1;
hp = hpMax;
SoundManager::getInstance().playSound(SOUND_EAT);
TextEntity* text = new TextEntity("HP Max + 1", 15, x, y - 50.0f);
text->setColor(TextEntity::COLOR_FADING_GREEN);
text->setAlignment(ALIGN_CENTER);
text->setAge(-1.0f);
text->setLifetime(1.2f);
text->setWeight(-60.0f);
text->setType(ENTITY_FLYING_TEXT);
text->setZ(2000);
}
}
spriteItem->setDying(true);
spriteItemStar->setDying(true);
playerStatus = playerStatusPlaying;
}
void PlayerEntity::resetFloorItem()
{
equip[EQUIP_BOSS_KEY] = false;
equip[EQUIP_FLOOR_MAP] = false;
equip[EQUIP_ALCOHOL] = false;
equip[EQUIP_FAIRY_POWDER] = false;
equip[EQUIP_LUCK] = false;
computePlayer();
}
void PlayerEntity::setItemToBuy(ItemEntity* item)
{
itemToBuy = item;
}
ItemEntity* PlayerEntity::getItemToBuy()
{
return itemToBuy;
}
void PlayerEntity::animate(float delay)
{
// shot timer
if (specialBoltTimer >= 0.0f)
{
specialBoltTimer -= delay;
if (specialBoltTimer <= 0.0f)
{
if (getShotType() == ShotTypeIce) SoundManager::getInstance().playSound(SOUND_ICE_CHARGE);
}
}
if (playerStatus == playerStatusGoingNext)
{
return;
}
if (playerStatus == playerStatusStairs)
{
x += velocity.x * delay;
y += velocity.y * delay;
age += delay;
frame = ((int)(age * 7.0f)) % 4;
if (frame == 3) frame = 1;
if (x < (MAP_WIDTH / 2) * TILE_WIDTH - TILE_WIDTH / 2)
{
facingDirection = 8;
game().moveToOtherMap(8);
}
return;
}
// rate of fire
if (!canFirePlayer)
{
currentFireDelay -= delay;
canFirePlayer = (currentFireDelay <= 0.0f);
}
if (randomFireDelay >= 0.0f) randomFireDelay -= delay;
// spells
if (activeSpell.spell != SpellNone && activeSpell.delay > 0.0f)
{
if (game().getCurrentMap()->isCleared())
activeSpell.delay -= 40 * delay;
else
activeSpell.delay -= delay;
if (activeSpell.spell == SpellProtection && protection.active)
activeSpell.delay = activeSpell.delayMax;
if (activeSpell.delay <= 0.0f) SoundManager::getInstance().playSound(SOUND_SPELL_CHARGE);
}
// protection
if (protection.active)
{
protection.timer -= delay;
if (protection.timer <= 0.0f)
{
protection.active = false;
computePlayer();
}
}
// acquisition animation
if (playerStatus == playerStatusAcquire)
{
statusTimer -= delay;
if (statusTimer <= 0.0f)
{
acquireItemAfterStance();
}
}
else if (equip[EQUIP_ALCOHOL] && playerStatus == playerStatusPlaying)
{
hiccupDelay -= delay;
if (hiccupDelay <= 0.0f)
{
hiccupDelay = 4.0f;
// hiccup
recoil.active = true;
recoil.stun = true;
recoil.velocity = Vector2D(350.0f);
recoil.timer = 0.4f;
for (int i = 0; i < 4; i++)
{
BoltEntity* bolt = new BoltEntity(x, getBolPositionY(), boltLifeTime, ShotTypePoison, 0);
bolt->setDamages(4);
bolt->setFlying(isFairyTransmuted);
//bolt->setVelocity(recoil.velocity.vectorTo(Vector2D(0, 0), fireVelocity));
bolt->setVelocity(Vector2D(fireVelocity));
}
TextEntity* text = new TextEntity("*hic*", 16, x, y - 30.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);
SoundManager::getInstance().playSound(SOUND_HICCUP);
SoundManager::getInstance().playSound(SOUND_BLAST_STANDARD);
}
}
if (divineInterventionDelay > 0.0f) divineInterventionDelay -= delay;
if (fireAnimationDelay > 0.0f)
{
fireAnimationDelay -= delay;
if (fireAnimationDelay <= 0.0f) fireAnimationDelay = -1.0f;
}
if (spellAnimationDelay > 0.0f)
{
spellAnimationDelay -= delay;
if (spellAnimationDelay <= 0.0f) spellAnimationDelay = -1.0f;
}
// unlocking animation
else if (playerStatus == playerStatusUnlocking || playerStatus == playerStatusPraying)
{
statusTimer -= delay;
if (statusTimer <= 0.0f)
{
playerStatus = playerStatusPlaying;
}
}
if (playerStatus == playerStatusDead)
{
deathAge += delay;
velocity = Vector2D(0.0f, 0.0f);
}
else
testSpriteCollisions();
// key room collision
if (game().getCurrentMap()->getRoomType() == roomTypeKey && !game().getCurrentMap()->isCleared())
{
sf::IntRect col1;
col1.width = 198;
col1.height = 68;
col1.top = 254;
col1.left = 380;
sf::IntRect col2;
col2.width = 68;
col2.height = 198;
col2.top = 189;
col2.left = 445;
if (boundingBox.intersects(col1) || boundingBox.intersects(col2))
{
recoil.active = true;
recoil.stun = true;
recoil.velocity = Vector2D(GAME_WIDTH / 2, GAME_HEIGHT /2).vectorTo(Vector2D(x, y), 650.0f);
recoil.timer = 0.4f;
game().activateKeyRoomEffect(true);
}
}
//collidingDirection = 0;
BaseCreatureEntity::animate(delay);
if (firingDirection != 5)
facingDirection = firingDirection;
// find the frame
if (firingDirection != 5)
{
if (fireAnimationDelay < 0.0f)
fireAnimationDelay = fireAnimationDelayMax;
fireAnimationDirection = firingDirection;
}
else if (isMoving())
{
frame = ((int)(age * 7.0f)) % 4;
if (frame == 3) frame = 1;
}
else if (playerStatus == playerStatusAcquire || playerStatus == playerStatusUnlocking || playerStatus == playerStatusPraying)
frame = 3;
else if (playerStatus == playerStatusDead)
frame = 0;
else // standing
{
frame = 1;
}
if (playerStatus != playerStatusPlaying || isMoving() || firingDirection != 5)
idleAge = 0.0f;
else
idleAge += delay;
if (x < 0)
game().moveToOtherMap(4);
else if (x > MAP_WIDTH * TILE_WIDTH)
game().moveToOtherMap(6);
else if (y < 0)
game().moveToOtherMap(8);
else if (y > MAP_HEIGHT * TILE_HEIGHT)
game().moveToOtherMap(2);
#ifdef SPIRAL_STAIRCASE
else if (playerStatus == playerStatusPlaying
&& game().getCurrentMap()->getRoomType() == roomTypeExit && y < TILE_HEIGHT * 0.6f)
{
playerStatus = playerStatusStairs;
velocity.y = creatureSpeed / 12;
velocity.x = -creatureSpeed / 3;
facingDirection = 4;
SpriteEntity* exitDoorEntity = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_TILES),
(MAP_WIDTH / 2) * TILE_WIDTH - TILE_WIDTH / 2,
TILE_HEIGHT / 2, 64, 64, 1);
exitDoorEntity->setZ(TILE_HEIGHT);
exitDoorEntity->setImagesProLine(24);
exitDoorEntity->setFrame(MAP_WALL_BEGIN + 21 + 24 * game().getCurrentMap()->getWallType());
exitDoorEntity->setType(ENTITY_EFFECT);
SpriteEntity* exitDoorAroundEntity = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_DOORS),
(MAP_WIDTH / 2) * TILE_WIDTH - TILE_WIDTH / 2,
TILE_HEIGHT / 2, 64, 64, 1);
exitDoorAroundEntity->setZ(TILE_HEIGHT + 1);
exitDoorAroundEntity->setImagesProLine(8);
exitDoorAroundEntity->setFrame(5 + 7 * 8);
exitDoorAroundEntity->setType(ENTITY_EFFECT);
SpriteEntity* exitDoorEntityShadow = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_TILES_SHADOW),
(MAP_WIDTH / 2) * TILE_WIDTH - TILE_WIDTH / 2,
TILE_HEIGHT / 2, 64, 64, 1);
exitDoorEntityShadow->setZ(TILE_HEIGHT + 2);
exitDoorEntityShadow->setImagesProLine(10);
exitDoorEntityShadow->setFrame(4);
exitDoorEntityShadow->setType(ENTITY_EFFECT);
}
#endif
if (playerStatus == playerStatusEntering)
{
if (boundingBox.left > TILE_WIDTH
&& (boundingBox.left + boundingBox.width) < TILE_WIDTH * (MAP_WIDTH - 1)
&& boundingBox.top > TILE_HEIGHT
&& (boundingBox.top + boundingBox.height) < TILE_HEIGHT * (MAP_HEIGHT - 1))
{
playerStatus = playerStatusPlaying;
game().closeDoors();
}
else
{
if (x < 2 * TILE_WIDTH)
{
velocity.x = creatureSpeed;
velocity.y = 0.0f;
}
else if (x > (MAP_WIDTH - 3) * TILE_WIDTH)
{
velocity.x = -creatureSpeed;
velocity.y = 0.0f;
}
else if (y < 2 * TILE_HEIGHT)
{
velocity.y = creatureSpeed;
velocity.x = 0.0f;
}
else if (y > (MAP_HEIGHT - 3) * TILE_HEIGHT)
{
velocity.y = -creatureSpeed;
velocity.x = 0.0f;
}
}
}
if (playerStatus != playerStatusDead)
{
// effects
if (invincibleDelay >= 0.0f) invincibleDelay -= delay;
if (specialState[SpecialStateConfused].active)
SoundManager::getInstance().playSound(SOUND_VAMPIRE_HYPNOSIS, false);
// rage
if (specialState[SpecialStateRage].active)
{
specialState[SpecialStateRage].param3 -= delay;
if (specialState[SpecialStateRage].param3 <= 0.0f)
{
specialState[SpecialStateRage].param3 += specialState[SpecialStateRage].param2;
rageFire(specialState[SpecialStateRage].param1, true, 1.5f);
}
}
}
z = y + 4;
}
bool PlayerEntity::canCollide()
{
return invincibleDelay <= 0.0f;
}
void PlayerEntity::setSpecialState(enumSpecialState state, bool active, float timer, float param1, float param2, bool waitUnclear)
{
BaseCreatureEntity::setSpecialState(state, active, timer, param1, param2, waitUnclear);
computePlayer();
}
void PlayerEntity::renderPlayer(sf::RenderTarget* app)
{
if (invincibleDelay > 0.0f)
{
if ((int)(age * 10.0f) % 2 == 0)return;
}
sf::Color savedColor = sprite.getColor();
if (isPoisoned()) sprite.setColor(sf::Color(180, 255, 180, 255));
// body
if (isMirroring)
sprite.setTextureRect(sf::IntRect( frame * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( frame * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setColor(savedColor);
// boots
if (equip[EQUIP_BOOTS_ADVANCED] && playerStatus != playerStatusDead)
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (21 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (21 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
else if (equip[EQUIP_LEATHER_BOOTS] && playerStatus != playerStatusDead)
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (9 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (9 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_ROBE_ADVANCED] && playerStatus != playerStatusDead)
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (12 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (12 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (15 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (15 + frame) * width, spriteDy * height, width, height));
sprite.setColor(sf::Color(255, 255, 255, 100 + 100 * cosf(game().getAbsolutTime() * 3.5f)));
app->draw(sprite, sf::BlendAdd);
sprite.setColor(sf::Color(255, 255, 255, 255));
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
else if (equip[EQUIP_MAGICIAN_ROBE])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (12 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (12 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_GLOVES_ADVANCED] && playerStatus != playerStatusDead)
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (24 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (24 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
else if (equip[EQUIP_DISPLACEMENT_GLOVES])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (21 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (21 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_CRITICAL_ADVANCED])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (24 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (24 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
else if (equip[EQUIP_CRITICAL])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (18 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (18 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
if (equip[EQUIP_RAGE_AMULET])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (18 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (18 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_LEATHER_BELT])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (15 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (15 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
// staff
int frameDx = equip[EQUIP_MAHOGANY_STAFF] ? 6 : 3;
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (frameDx + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (frameDx + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
if (equip[EQUIP_BLOOD_SNAKE])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (27 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (27 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_REAR_SHOT])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
// shot type
if (getShotType() != ShotTypeStandard)
{
switch (getShotType())
{
case ShotTypeIce:
sprite.setColor(sf::Color(100, 220, 255, 255));
break;
case ShotTypeStone:
sprite.setColor(sf::Color(120, 120, 150, 255));
break;
case ShotTypeLightning:
sprite.setColor(sf::Color(255, 255, 0, 255));
break;
case ShotTypeIllusion:
sprite.setColor(sf::Color(240, 180, 250, 255));
break;
case ShotTypeStandard:
sprite.setColor(sf::Color(255, 255, 255, 0));
break;
case ShotTypeFire:
sprite.setColor(sf::Color(255, 180, 0, 255));
break;
case ShotTypePoison:
sprite.setColor(sf::Color(50, 255, 50, 255));
break;
default:
std::cout << "[WARNING] Can not render shot type: " << getShotType() << std::endl;
}
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (3 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (3 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setColor(savedColor);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
// hat
if (equip[EQUIP_HAT_ADVANCED] && playerStatus != playerStatusDead)
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (9 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (9 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
else if (equip[EQUIP_MAGICIAN_HAT] && playerStatus != playerStatusDead)
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (6 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (6 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
}
void PlayerEntity::renderHalo(sf::RenderTarget* app)
{
if (frame > 2 || spriteDy > 8) return;
// gems
if ((getShotType() == ShotTypeIce || getShotType() == ShotTypeLightning || getShotType() == ShotTypeFire || getShotType() == ShotTypePoison) && playerStatus != playerStatusDead)
{
int fade;
sf::Color savedColor = sprite.getColor();
if (getShotType() != ShotTypeIce || specialBoltTimer <= 0.0f) fade = 255;
else fade = ((STATUS_FROZEN_BOLT_DELAY[getShotLevel()] - specialBoltTimer) / STATUS_FROZEN_BOLT_DELAY[getShotLevel()]) * 128;
if (getShotType() == ShotTypeLightning)
fade = 150 + rand() % 105;
if (getShotType() == ShotTypeFire)
fade = 200 + rand() % 40;
if (getShotType() == ShotTypePoison)
fade = 150 + rand() % 40;
if (getShotType() == ShotTypeIce)
sprite.setTextureRect(sf::IntRect(448, 864, 20, 20));
else if (getShotType() == ShotTypeLightning)
sprite.setTextureRect(sf::IntRect(448 + 20, 864, 20, 20));
else if (getShotType() == ShotTypeFire)
sprite.setTextureRect(sf::IntRect(448 + 40, 864, 20, 20));
else if (getShotType() == ShotTypePoison)
sprite.setTextureRect(sf::IntRect(448, 864 + 20, 20, 20));
sprite.setColor(sf::Color(255, 255, 255, fade));
if (isMirroring)
sprite.setPosition(x - 10 + 64 - xHalo[spriteDy][frame], y - 10 + yHalo[spriteDy][frame]);
else
sprite.setPosition(x - 10 + xHalo[spriteDy][frame], y - 10 + yHalo[spriteDy][frame]);
sf::RenderStates r;
r.blendMode = sf::BlendAdd;
app->draw(sprite, r);
sprite.setPosition(x, y);
sprite.setColor(savedColor);
}
}
void PlayerEntity::render(sf::RenderTarget* app)
{
sprite.setPosition(x, y);
spriteDy = 0;
isMirroring = false;
if (idleAge > 8.5f)
{
idleAge -= 8.5f;
}
else if (idleAge >= 7.5)
{
spriteDy = 8;
frame = 2;
}
else if (idleAge >= 7.0)
{
spriteDy = 8;
frame = 1;
}
else if (idleAge >= 6.0)
{
spriteDy = 8;
frame = 0;
}
else if (idleAge >= 5.5f && facingDirection != 2)
{
facingDirection = 2;
idleAge -= 2.0f;
}
else if (fireAnimationDelay <= 0.0f && spellAnimationDelay <= 0.0f)
{
if (facingDirection == 6) spriteDy = 1;
else if (facingDirection == 8) spriteDy = 2;
else if (facingDirection == 4)
{
spriteDy = 1;
isMirroring = true;
}
}
else if (spellAnimationDelay >= 0.0f)
{
spriteDy = 7;
if (spellAnimationDelay < spellAnimationDelayMax * 0.1f) frame = 0;
else if (spellAnimationDelay < spellAnimationDelayMax * 0.2f) frame = 1;
else if (spellAnimationDelay < spellAnimationDelayMax * 0.7f) frame = 2;
else if (spellAnimationDelay < spellAnimationDelayMax * 0.85f) frame = 1;
else frame = 0;
}
else
{
if (fireAnimationDirection == 2) spriteDy = 3;
else if (fireAnimationDirection == 6) spriteDy = 4;
else if (fireAnimationDirection == 8) spriteDy = 5;
else if (fireAnimationDirection == 4)
{
spriteDy = 4;
isMirroring = true;
}
if (fireAnimationDelay < fireAnimationDelayMax * 0.2f) frame = 0;
else if (fireAnimationDelay < fireAnimationDelayMax * 0.4f) frame = 1;
else if (fireAnimationDelay < fireAnimationDelayMax * 0.6f) frame = 2;
else if (fireAnimationDelay < fireAnimationDelayMax * 0.8f) frame = 1;
else frame = 0;
}
if (playerStatus == playerStatusAcquire || playerStatus == playerStatusUnlocking)
{
spriteDy = 6;
frame = ((int)(age * 10.0f)) % 4;
if (frame == 3) frame = 1;
}
else if (playerStatus == playerStatusPraying)
{
spriteDy = 7;
frame = ((int)(age * 10.0f)) % 4;
if (frame == 3) frame = 1;
float delay = playerStatus == playerStatusPraying ? WORSHIP_DELAY : UNLOCK_DELAY;
if (statusTimer < delay * 0.1f) frame = 0;
else if (statusTimer < delay * 0.2f) frame = 1;
else if (statusTimer < delay * 0.7f) frame = 2;
else if (statusTimer < delay * 0.85f) frame = 1;
else frame = 0;
}
if (playerStatus == playerStatusDead)
{
frame = (int)(deathAge / 0.35f);
if (frame > 6) frame = 6;
spriteDy = 9;
sprite.setTextureRect(sf::IntRect( frame * width, spriteDy * height, width, height));
app->draw(sprite);
}
else
{
if (isFairyTransmuted)
{
frame = 0;
if (velocity.x * velocity.x + velocity.y * velocity.y > 400)
frame = ((int)(age * 24.0f)) % 2;
else
frame = ((int)(age * 18.0f)) % 2;
sf::Sprite fairySprite;
fairySprite.setColor(sprite.getColor());
fairySprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_FAIRY));
fairySprite.setPosition(sprite.getPosition());
fairySprite.setOrigin(26, 62);
switch (facingDirection)
{
case 8: fairySprite.setTextureRect(sf::IntRect( (2 + frame) * 48, 6 * 72, 48, 72)); break;
case 4: fairySprite.setTextureRect(sf::IntRect( (4 + frame) * 48, 6 * 72, 48, 72)); break;
case 6: fairySprite.setTextureRect(sf::IntRect( (5 + frame) * 48, 6 * 72, - 48, 72)); break;
default: fairySprite.setTextureRect(sf::IntRect( frame * 48, 6 * 72, 48, 72)); break;
}
app->draw(fairySprite);
}
else
{
renderHalo(app);
renderPlayer(app);
}
// shield
if (playerStatus != playerStatusStairs && (specialState[DivineStateProtection].active || protection.active))
{
int firstFrame = 8;
if (specialState[DivineStateProtection].active && divinity.divinity == DivinityStone) firstFrame = 16;
float timer = specialState[DivineStateProtection].active ? specialState[DivineStateProtection].timer : protection.timer;
sprite.setTextureRect(sf::IntRect( firstFrame * width, 9 * height, width, height));
app->draw(sprite);
sf::Color savedColor = sprite.getColor();
sprite.setColor(sf::Color(255, 255, 255, 100 + cos(age * (timer < 2.0f ? 25 : 10)) * 30 ));
sprite.setTextureRect(sf::IntRect( (firstFrame + 1) * width, 9 * height, width, height));
app->draw(sprite);
sprite.setColor(savedColor);
}
// divine field
if (divinity.level > 1)
{
bool displayField = false;
int fieldFrame;
int fieldFade;
switch (divinity.divinity)
{
case DivinityHealer:
{
displayField = true;
fieldFrame = 10;
fieldFade = 40 * (divinity.level - 1);
break;
}
case DivinityFighter:
{
displayField = true;
fieldFrame = 12;
fieldFade = 40 * (divinity.level - 1);
break;
}
case DivinityIce:
{
if (divinity.level > 2)
{
displayField = true;
fieldFrame = 14;
fieldFade = 80 * (divinity.level - 3);
}
break;
}
case DivinityStone:
{
if (divinity.level > 2)
{
displayField = true;
fieldFrame = 16;
fieldFade = 80 * (divinity.level - 3);
}
break;
}
case DivinityAir:
{
if (divinity.level > 1)
{
displayField = true;
fieldFrame = 18;
fieldFade = 40 * (divinity.level - 1);
}
break;
}
}
if (displayField)
{
sf::Color savedColor = sprite.getColor();
sprite.setColor(sf::Color(255, 255, 255, fieldFade ));
sprite.setTextureRect(sf::IntRect( fieldFrame * width, 9 * height, width, height));
app->draw(sprite);
if (divinity.divinity != DivinityStone && divinity.divinity != DivinityHealer)
{
sprite.setColor(sf::Color(255, 255, 255, 2 + fieldFade / 2 + cos(age * 15) * fieldFade / 2 ));
sprite.setTextureRect(sf::IntRect( (fieldFrame + 1) * width, 9 * height, width, height));
app->draw(sprite);
sprite.setColor(savedColor);
}
if (divinity.divinity == DivinityHealer && divineInterventionDelay > 0.0f && isRegeneration)
{
sprite.setTextureRect(sf::IntRect( (fieldFrame + 1) * width, 9 * height, width, height));
app->draw(sprite);
}
sprite.setColor(savedColor);
}
}
}
if (game().getShowLogical() && playerStatus != playerStatusDead)
{
displayBoundingBox(app);
displayCenterAndZ(app);
}
}
void PlayerEntity::calculateBB()
{
if (isFairyTransmuted)
{
boundingBox.left = (int)x - 10;
boundingBox.width = 20;
boundingBox.top = (int)y - 29;
boundingBox.height = 20;
}
else
{
boundingBox.left = (int)x - 10;
boundingBox.width = 20;
boundingBox.top = (int)y - 29;
boundingBox.height = 33;
}
}
void PlayerEntity::readCollidingEntity(CollidingSpriteEntity* entity)
{
if (playerStatus == playerStatusDead || !canCollide()) return;
EnemyBoltEntity* boltEntity = dynamic_cast<EnemyBoltEntity*>(entity);
if (collideWithEntity(entity))
{
if (boltEntity != NULL && !boltEntity->getDying())
{
boltEntity->collide();
// TODO bolt source
hurt(getHurtParams(boltEntity->getDamages(),
boltEntity->getBoltType(),
boltEntity->getLevel(),
boltEntity->isCritical(),
SourceTypeBolt,
boltEntity->getEnemyType(),
false));
game().generateBlood(x, y, bloodColor);
float xs = (x + boltEntity->getX()) / 2;
float ys = (y + boltEntity->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);
}
}
}
bool PlayerEntity::willCollideWithMap(int dx, int dy, bool checkMiddle)
{
float oldX = x, oldY = y;
bool collide = true;
x = oldX + dx;
y = oldY + dy;
if (!isCollidingWithMap())
collide = false;
else if (checkMiddle)
{
x = oldX + dx / 2;
y = oldY + dy / 2;
if (!isCollidingWithMap())
collide = false;
}
x = oldX;
y = oldY;
return collide;
}
void PlayerEntity::move(int direction)
{
float oldX = x, oldY = y;
bool touchUp, touchDown, touchLeft, touchRight;
x = oldX + 1;
touchRight = isCollidingWithMap();
x = oldX - 1;
touchLeft = isCollidingWithMap();
x = oldX;
y = oldY + 1;
touchDown = isCollidingWithMap();
y = oldY - 1;
touchUp = isCollidingWithMap();
y = oldY;
if (specialState[SpecialStateConfused].active)
{
switch (direction)
{
case 4: direction = 6; break;
case 6: direction = 4; break;
case 2: direction = 8; break;
case 8: direction = 2; break;
case 1: direction = 9; break;
case 9: direction = 1; break;
case 7: direction = 3; break;
case 3: direction = 7; break;
}
}
keyDirection = direction;
if (playerStatus == playerStatusAcquire && statusTimer < ACQUIRE_DELAY / 2)
{
acquireItemAfterStance();
}
if (playerStatus == playerStatusPlaying)
{
collidingDirection = 5;
switch (keyDirection)
{
case 1:
if (touchDown && touchLeft)
{
direction = 5;
collidingDirection = 1;
}
else if (touchDown)
{
direction = 4;
collidingDirection = 2;
}
else if (touchLeft)
{
direction = 2;
collidingDirection = 4;
}
break;
case 3:
if (touchDown && touchRight)
{
direction = 5;
collidingDirection = 3;
}
else if (touchDown)
{
direction = 6;
collidingDirection = 2;
}
else if (touchRight)
{
direction = 2;
collidingDirection = 6;
}
break;
case 7:
if (touchUp && touchLeft)
{
direction = 5;
collidingDirection = 7;
}
else if (touchUp)
{
direction = 4;
collidingDirection = 8;
}
else if (touchLeft)
{
direction = 8;
collidingDirection = 1;
}
break;
case 9:
if (touchUp && touchRight)
{
direction = 5;
collidingDirection = 9;
}
else if (touchUp)
{
direction = 6;
collidingDirection = 8;
}
else if (touchRight)
{
direction = 8;
collidingDirection = 6;
}
break;
case 4:
if (touchLeft)
{
x = oldX - 2;
if (!willCollideWithMap(0, KEYS_MOVE_TOLERANCE, true))
direction = 2;
else if (!willCollideWithMap(0, -KEYS_MOVE_TOLERANCE, true))
direction = 8;
else
{
direction = 5;
collidingDirection = 4;
}
x = oldX;
}
break;
case 6:
if (touchRight)
{
x = oldX + 2;
if (!willCollideWithMap(0, KEYS_MOVE_TOLERANCE, true))
direction = 2;
else if (!willCollideWithMap(0, -KEYS_MOVE_TOLERANCE, true))
direction = 8;
else
{
direction = 5;
collidingDirection = 6;
}
x = oldX;
}
break;
case 8:
if (touchUp)
{
y = oldY - 2;
if (!willCollideWithMap(KEYS_MOVE_TOLERANCE, 0, true))
direction = 6;
else if (!willCollideWithMap(-KEYS_MOVE_TOLERANCE, 0, true))
direction = 4;
else
{
direction = 5;
collidingDirection = 8;
}
y = oldY;
}
break;
case 2:
if (touchDown)
{
y = oldY + 2;
if (!willCollideWithMap(KEYS_MOVE_TOLERANCE, 0, true))
direction = 6;
else if (!willCollideWithMap(-KEYS_MOVE_TOLERANCE, 0, true))
direction = 4;
else
{
direction = 5;
collidingDirection = 2;
}
y = oldY;
}
break;
}
float speedx = 0.0f, speedy = 0.0f;
if (direction == 4)
speedx = - creatureSpeed;
else if (direction == 1 || direction == 7)
speedx = - creatureSpeed * 0.7f;
else if (direction == 6)
speedx = creatureSpeed;
else if (direction == 3 || direction == 9)
speedx = creatureSpeed * 0.7f;
if (direction == 2)
speedy = creatureSpeed;
else if (direction == 1 || direction == 3)
speedy = creatureSpeed * 0.7f;
else if (direction == 8)
speedy = - creatureSpeed;
else if (direction == 7 || direction == 9)
speedy = - creatureSpeed * 0.7f;
setVelocity(Vector2D(speedx, speedy));
if (firingDirection != 5)
facingDirection = firingDirection;
else
{
switch (keyDirection)
{
case 8:
facingDirection = 8;
break;
case 2:
facingDirection = 2;
break;
case 4:
facingDirection = 4;
break;
case 6:
facingDirection = 6;
break;
case 7:
if (facingDirection != 4 && facingDirection != 8) facingDirection = 4;
break;
case 1:
if (facingDirection != 4 && facingDirection != 2) facingDirection = 4;
break;
case 9:
if (facingDirection != 6 && facingDirection != 8) facingDirection = 6;
break;
case 3:
if (facingDirection != 6 && facingDirection != 2) facingDirection = 6;
break;
}
}
}
}
bool PlayerEntity::isMoving()
{
if (velocity.x < -1.0f || velocity.x > 1.0f) return true;
if (velocity.y < -1.0f || velocity.y > 1.0f) return true;
return false;
}
bool PlayerEntity::isEquiped(int eq)
{
return equip[eq];
}
bool* PlayerEntity::getEquipment()
{
return equip;
}
void PlayerEntity::setEquiped(int item, bool toggleEquipped)
{
equip[item] = toggleEquipped;
if (toggleEquipped && items[FirstEquipItem + item].familiar > FamiliarNone)
{
FairyEntity* fairy = new FairyEntity(x - 50.0f + rand() % 100,
y - 50.0f + rand() % 100,
items[FirstEquipItem + item].familiar);
fairies.push_back(fairy);
if (fairies.size() == 3) game().registerAchievement(AchievementFairies);
}
computePlayer();
}
void PlayerEntity::generateBolt(float velx, float vely)
{
enumShotType boltType = ShotTypeStandard;
unsigned int shotLevel = 1;
switch (getShotType())
{
case ShotTypeIce:
if (getShotType() == ShotTypeIce)
{
if (specialBoltTimer <= 0.0f)
{
boltType = ShotTypeIce;
shotLevel = getShotLevel();
needInitShotType = true;
}
else boltType = ShotTypeCold;
}
break;
case ShotTypeStandard:
case ShotTypeIllusion:
case ShotTypeStone:
case ShotTypeLightning:
case ShotTypeFire:
case ShotTypePoison:
boltType = getShotType();
shotLevel = getShotLevel();
break;
default:
std::cout << "[WARNING] Can not generate shot type: " << getShotType() << std::endl;
}
BoltEntity* bolt = new BoltEntity(x, getBolPositionY(), boltLifeTime, boltType, shotLevel);
bolt->setFlying(isFairyTransmuted);
int boltDamage = fireDamages;
if (criticalChance > 0)
if (rand()% 100 < criticalChance)
{
boltDamage *= equip[EQUIP_CRITICAL_ADVANCED] ? 3 : 2;
bolt->setCritical(true);
}
bolt->setDamages(boltDamage);
if (equip[EQUIP_GLOVES_ADVANCED])
{
if (firingDirection == 2 || firingDirection == 8)
velx += velocity.x * 0.7f;
else if (firingDirection == 4 || firingDirection == 6)
vely += velocity.y * 0.7f;
}
bolt->setVelocity(Vector2D(velx, vely));
}
void PlayerEntity::rageFire(float damage, bool full, float velMult)
{
float tempFireVelocity = fireVelocity * velMult;
for (int i = -1; i <= 1; i += 2)
for (int j = -1; j <= 1; j += 2)
{
BoltEntity* bolt = new BoltEntity(x, getBolPositionY(), boltLifeTime, ShotTypeFire, 0);
bolt->setDamages(10);
bolt->setFlying(isFairyTransmuted);
float velx = tempFireVelocity * i * 0.42f;
float vely = tempFireVelocity * j * 0.42f;
bolt->setVelocity(Vector2D(velx, vely));
if (full)
{
BoltEntity* bolt = new BoltEntity(x, getBolPositionY(), boltLifeTime, ShotTypeFire, 0);
bolt->setDamages(10);
bolt->setFlying(isFairyTransmuted);
float velx = 0.0f;
float vely = 0.0f;
if (i == -1 && j == -1) velx = -tempFireVelocity * i * 0.6f;
else if (i == -1 && j == 1) velx = tempFireVelocity * i * 0.6f;
else if (i == 1 && j == -1) vely= -tempFireVelocity * i * 0.6f;
else if (i == 1 && j == 1) vely = tempFireVelocity * i * 0.6f;
bolt->setVelocity(Vector2D(velx, vely));
}
}
SoundManager::getInstance().playSound(SOUND_BLAST_FIRE);
}
void PlayerEntity::resestFireDirection()
{
firingDirection = 5;
}
int PlayerEntity::getFireDirection()
{
return firingDirection;
}
void PlayerEntity::fire(int direction)
{
if (age < 0.7f) return;
firingDirection = direction;
if (playerStatus != playerStatusDead)
for(int unsigned i = 0; i < fairies.size(); i++)
fairies[i]->fire(direction);
if (canFirePlayer && playerStatus != playerStatusDead && playerStatus != playerStatusAcquire)
{
switch (getShotType())
{
case ShotTypeCold:
case ShotTypeIce:
SoundManager::getInstance().playPitchModSound(SOUND_BLAST_ICE);
break;
case ShotTypeFire:
SoundManager::getInstance().playPitchModSound(SOUND_BLAST_FIRE);
break;
case ShotTypeIllusion:
SoundManager::getInstance().playPitchModSound(SOUND_BLAST_ILLUSION);
break;
case ShotTypeLightning:
SoundManager::getInstance().playPitchModSound(SOUND_BLAST_LIGHTNING);
break;
case ShotTypePoison:
SoundManager::getInstance().playPitchModSound(SOUND_BLAST_POISON);
break;
case ShotTypeStone:
SoundManager::getInstance().playPitchModSound(SOUND_BLAST_STONE);
break;
default:
SoundManager::getInstance().playPitchModSound(SOUND_BLAST_STANDARD);
break;
}
if (equip[EQUIP_BOOK_DUAL] || equip[EQUIP_BOOK_TRIPLE]
|| equip[EQUIP_BOOK_DUAL_QUICK] || equip[EQUIP_BOOK_TRIPLE_QUICK])
{
float shoot_angle = 0.2f;
if ((direction == 4 && velocity.x < -1.0f) || (direction == 6 && velocity.x > 1.0f)
|| (direction == 8 && velocity.y < -1.0f) || (direction == 2 && velocity.y > 1.0f))
shoot_angle = 0.1f;
else if ((direction == 6 && velocity.x < -1.0f) || (direction == 4 && velocity.x > 1.0f)
|| (direction == 2 && velocity.y < -1.0f) || (direction == 8 && velocity.y > 1.0f))
shoot_angle = (equip[EQUIP_BOOK_TRIPLE] || equip[EQUIP_BOOK_TRIPLE_QUICK]) ? 0.35f : 0.2f;
else if (!equip[EQUIP_BOOK_TRIPLE] && !equip[EQUIP_BOOK_TRIPLE_QUICK])
shoot_angle = 0.1f;
switch(direction)
{
case 4:
generateBolt(-fireVelocity * cos(shoot_angle), fireVelocity * sin(shoot_angle));
generateBolt(-fireVelocity * cos(shoot_angle), - fireVelocity * sin(shoot_angle));
break;
case 6:
generateBolt(fireVelocity * cos(shoot_angle), fireVelocity * sin(shoot_angle));
generateBolt(fireVelocity * cos(shoot_angle), - fireVelocity * sin(shoot_angle));
break;
case 8:
generateBolt(fireVelocity * sin(shoot_angle), -fireVelocity * cos(shoot_angle));
generateBolt(-fireVelocity * sin(shoot_angle), - fireVelocity * cos(shoot_angle));
break;
case 2:
generateBolt(fireVelocity * sin(shoot_angle), fireVelocity * cos(shoot_angle));
generateBolt(-fireVelocity * sin(shoot_angle), fireVelocity * cos(shoot_angle));
break;
}
}
if (equip[EQUIP_RAPID_SHOT])
{
Vector2D boltDirection;
switch(direction)
{
case 4:
boltDirection = Vector2D(0, 0).vectorNearlyTo(Vector2D(-1, 0), fireVelocity, 0.2f);
break;
case 6:
boltDirection = Vector2D(0, 0).vectorNearlyTo(Vector2D(1, 0), fireVelocity, 0.2f);
break;
case 8:
boltDirection = Vector2D(0, 0).vectorNearlyTo(Vector2D(0, -1), fireVelocity, 0.2f);
break;
case 2:
boltDirection = Vector2D(0, 0).vectorNearlyTo(Vector2D(0, 1), fireVelocity, 0.2f);
break;
}
generateBolt(boltDirection.x, boltDirection.y);
}
else if (!(equip[EQUIP_BOOK_DUAL] || equip[EQUIP_BOOK_DUAL_QUICK]) || (equip[EQUIP_BOOK_TRIPLE] || equip[EQUIP_BOOK_TRIPLE_QUICK]))
{
switch(direction)
{
case 4:
generateBolt(-fireVelocity, 0.0f);
break;
case 6:
generateBolt(fireVelocity, 0.0f);
break;
case 8:
generateBolt(0.0f, -fireVelocity);
break;
case 2:
generateBolt(0.0f, fireVelocity);
break;
}
}
if (equip[EQUIP_REAR_SHOT])
{
BoltEntity* bolt = new BoltEntity(x, getBolPositionY(), boltLifeTime, ShotTypeStandard, 0);
bolt->setDamages(fireDamages / 2);
bolt->setFlying(isFairyTransmuted);
float velx = 0.0f;
float vely = 0.0f;
switch (direction)
{
case 4:
velx = fireVelocity * 0.75f;
break;
case 6:
velx = -fireVelocity * 0.75f;
break;
case 2:
vely = -fireVelocity * 0.75f;
break;
case 8:
vely = fireVelocity * 0.75f;
break;
}
bolt->setVelocity(Vector2D(velx, vely));
}
if (equip[EQUIP_BOOK_RANDOM] && randomFireDelay <= 0.0f)
{
BoltEntity* bolt = new BoltEntity(x, getBolPositionY(), boltLifeTime, ShotTypeStandard, 0);
bolt->setDamages(fireDamages);
bolt->setFlying(isFairyTransmuted);
float shotAngle = rand() % 360;
bolt->setVelocity(Vector2D(fireVelocity * 0.75f * cos(shotAngle), fireVelocity * 0.75f * sin(shotAngle)));
randomFireDelay = fireDelay * 1.5f;
}
canFirePlayer = false;
currentFireDelay = fireDelay;
if (needInitShotType) initShotType();
}
}
bool PlayerEntity::canMove()
{
return (playerStatus == playerStatusPlaying
|| (playerStatus == playerStatusAcquire && statusTimer < ACQUIRE_DELAY / 2));
}
int PlayerEntity::hurt(StructHurt hurtParam)
{
if (playerStatus == playerStatusDead) return false;
if (isFairyTransmuted && hurtParam.hurtingType != ShotTypeDeterministic)
{
hurtParam.damage *= 2;
}
shouldBeSavedFromDivinity = false;
bool divinityInvoked = false;
if (hp - hurtParam.damage <= hpMax / 4 && divinity.divinity >= 0)
{
divinityInvoked = triggerDivinityBefore();
if (divinityInvoked)
{
game().testAndAddMessageToQueue((EnumMessages)(MsgInfoDivIntervention));
shouldBeSavedFromDivinity = true;
}
}
if (invincibleDelay <= 0.0f || hurtParam.hurtingType == ShotTypeDeterministic)
{
SoundManager::getInstance().playSound(SOUND_PLAYER_HIT);
int oldHp = hp;
if (BaseCreatureEntity::hurt(hurtParam) > 0)
{
if (hurtParam.hurtingType != ShotTypeDeterministic)
{
invincibleDelay = INVINCIBLE_DELAY;
if (equip[EQUIP_RAGE_AMULET]) rageFire(10, hp <= hpMax / 5, 1.0f);
game().generateBlood(x, y, bloodColor);
}
hurtingDelay = HURTING_DELAY * 2.0f;
game().generateBlood(x, y, bloodColor);
game().proceedEvent(EventBeingHurted);
lastHurtingEnemy = hurtParam.enemyType;
lastHurtingSource = hurtParam.sourceType;
// divinity
offerHealth(oldHp - hp);
if (!divinityInvoked && hp <= hpMax / 4 && divinity.divinity >= 0)
{
triggerDivinityAfter();
}
return true;
}
}
return false;
}
void PlayerEntity::setMap(GameMap* map, int tileWidth, int tileHeight, int offsetX, int offsetY)
{
CollidingSpriteEntity::setMap(map, tileWidth, tileHeight, offsetX, offsetY);
//if (slimePet != NULL) slimePet->setMap(map, tileWidth, tileHeight, offsetX, offsetY);
}
void PlayerEntity::loseItem(enumItemType itemType, bool isEquip)
{
CollidingSpriteEntity* itemSprite
= new CollidingSpriteEntity(ImageManager::getInstance().getImage(isEquip ? IMAGE_ITEMS_EQUIP : IMAGE_ITEMS), x, y, 32, 32);
itemSprite->setMap(map, TILE_WIDTH, TILE_HEIGHT, 0, 0);
itemSprite->setZ(-1);
itemSprite->setFrame(itemType);
itemSprite->setImagesProLine(10);
itemSprite->setType(ENTITY_BLOOD);
itemSprite->setVelocity(Vector2D(200 + rand()%450));
itemSprite->setViscosity(0.95f);
itemSprite->setSpin( (rand() % 700) - 350.0f);
}
void PlayerEntity::dying()
{
if (shouldBeSavedFromDivinity)
{
hp = 33 * hpMax / 100;
return;
}
else if (divinity.divinity > -1 && divinity.interventions < divinity.level - 1)
{
hp = 1;
return;
}
playerStatus = playerStatusDead;
deathAge = 0.0f;
hp = 0;
SoundManager::getInstance().playSound(SOUND_PLAYER_DIE);
setVelocity(Vector2D(0.0f, 0.0f));
int i;
for (i = 0; i < gold && i < 10; i++) loseItem(ItemCopperCoin, false);
for (i = 0; i < 5; i++) game().generateBlood(x, y, BloodRed);
for (i = 0; i < NUMBER_EQUIP_ITEMS; i++)
{
if (equip[i])
{
if (items[i + FirstEquipItem].familiar == FamiliarNone)
loseItem(enumItemType(i), true);
}
}
remove(SAVE_FILE.c_str());
if (game().getLevel() == 1) game().registerAchievement(AchievementNoob);
game().calculateScore();
}
void PlayerEntity::displayAcquiredGold(int n)
{
std::ostringstream oss;
if (n > 0) oss << "+";
oss << n;
TextEntity* text = new TextEntity(oss.str(), 16, x, y - 30.0f);
text->setColor(TextEntity::COLOR_FADING_YELLOW);
text->setAge(-0.6f);
text->setLifetime(0.3f);
text->setWeight(-60.0f);
text->setZ(2000);
text->setAlignment(ALIGN_CENTER);
text->setType(ENTITY_FLYING_TEXT);
}
void PlayerEntity::acquireItem(enumItemType type)
{
if (items[type].generatesStance) acquireStance(type);
else if (items[type].consumable)
{
acquireConsumable(type);
}
else switch (type)
{
case ItemCopperCoin:
gold++;
displayAcquiredGold(1);
SoundManager::getInstance().playSound(SOUND_COIN_PICK_UP);
game().proceedEvent(EventGetCoin);
break;
case ItemSilverCoin:
gold = gold + 5;
displayAcquiredGold(5);
SoundManager::getInstance().playSound(SOUND_COIN_PICK_UP);
game().proceedEvent(EventGetCoin);
break;
case ItemGoldCoin:
gold = gold + 10;
displayAcquiredGold(10);
SoundManager::getInstance().playSound(SOUND_COIN_PICK_UP);
game().proceedEvent(EventGetCoin);
break;
case ItemHealthVerySmallPoison:
specialState[SpecialStatePoison].active = false;
case ItemHealthVerySmall:
heal(equip[EQUIP_MANUAL_HEALTH] ? 5 : 3);
SoundManager::getInstance().playSound(SOUND_EAT);
break;
case ItemHealthSmall:
heal(equip[EQUIP_MANUAL_HEALTH] ? 10 : 7);
SoundManager::getInstance().playSound(SOUND_EAT);
break;
case ItemHealth:
heal(equip[EQUIP_MANUAL_HEALTH] ? 22 : 15);
SoundManager::getInstance().playSound(SOUND_EAT);
break;
default:
break;
}
}
bool isUnidentified(enumItemType item)
{
return (item >= ItemPotion01 && item < ItemPotion01 + NUMBER_UNIDENTIFIED);
}
int PlayerEntity::getConsumable(int n)
{
if (n < 0 || n >= MAX_SLOT_CONSUMABLES) return -1;
else return consumable[n];
}
void PlayerEntity::setConsumable(int n, int type)
{
if (n < 0 || n >= MAX_SLOT_CONSUMABLES) return;
consumable[n] = type;
}
void PlayerEntity::dropConsumables(int n)
{
if (n < 0 || n >= MAX_SLOT_CONSUMABLES) return;
if (playerStatus != playerStatusPlaying) return;
ItemEntity* newItem = new ItemEntity((enumItemType)(consumable[n]), x, y);
newItem->setVelocity(Vector2D(100.0f + rand()% 250));
newItem->setViscosity(0.96f);
newItem->setAge(-10.0f);
consumable[n] = -1;
}
void PlayerEntity::tryToConsume(int n)
{
if (n < 0 || n >= MAX_SLOT_CONSUMABLES) return;
if (playerStatus != playerStatusPlaying) return;
if (consumable[n] > -1)
{
// unidentified
if (isUnidentified((enumItemType)consumable[n]))
{
game().setPotionToKnown((enumItemType)consumable[n]);
consumable[n] = game().getPotion((enumItemType)consumable[n]);
consume((enumItemType)consumable[n]);
}
else if (items[consumable[n]].consumable)
// known
{
consume((enumItemType)consumable[n]);
}
else
{
std::cout << "[ERROR] Trying to consume item: " << items[consumable[n]].name << std::endl;
}
}
consumable[n] = -1;
}
void PlayerEntity::consume(enumItemType item)
{
switch(item)
{
case ItemScrollRevelation:
reveal();
spellAnimationDelay = spellAnimationDelayMax;
SoundManager::getInstance().playSound(SOUND_SCROLL);
break;
case ItemPotionHealth:
heal(equip[EQUIP_MANUAL_HEALTH] ? 28 : 18);
SoundManager::getInstance().playSound(SOUND_DRINK);
break;
case ItemPotionPoison:
specialState[SpecialStatePoison].active = true;
specialState[SpecialStatePoison].timer = POISON_TIMER[0];
specialState[SpecialStatePoison].param1 = POISON_DAMAGE[0];
specialState[SpecialStatePoison].param2 = POISON_DELAY[0];
specialState[SpecialStatePoison].param3 = POISON_DELAY[0];
displayFlyingText( x, y - 20.0f, 16, tools::getLabel("poison"), TextEntity::COLOR_FADING_RED);
SoundManager::getInstance().playSound(SOUND_DRINK);
break;
case ItemPotionSpeed:
specialState[SpecialStateSpeed].active = false;
specialState[SpecialStateSpeed].waitUnclear = true;
specialState[SpecialStateSpeed].timer = 30;
specialState[SpecialStateSpeed].param1 = 1.5f;
displayFlyingText( x, y - 20.0f, 16, tools::getLabel("effect_speed"), TextEntity::COLOR_FADING_BLUE);
SoundManager::getInstance().playSound(SOUND_DRINK);
break;
case ItemPotionSlow:
specialState[SpecialStateSlow].active = false;
specialState[SpecialStateSlow].waitUnclear = true;
specialState[SpecialStateSlow].timer = 30;
specialState[SpecialStateSlow].param1 = 0.35f;
displayFlyingText( x, y - 20.0f, 16, tools::getLabel("effect_slow"), TextEntity::COLOR_FADING_RED);
SoundManager::getInstance().playSound(SOUND_DRINK);
break;
case ItemPotionWeakness:
specialState[SpecialStateWeakness].active = false;
specialState[SpecialStateWeakness].waitUnclear = true;
specialState[SpecialStateWeakness].timer = 30;
specialState[SpecialStateWeakness].param1 = 0.5f;
displayFlyingText( x, y - 20.0f, 16, tools::getLabel("effect_weakness"), TextEntity::COLOR_FADING_RED);
SoundManager::getInstance().playSound(SOUND_DRINK);
break;
case ItemPotionStrength:
specialState[SpecialStateStrength].active = false;
specialState[SpecialStateStrength].waitUnclear = true;
specialState[SpecialStateStrength].timer = 30;
specialState[SpecialStateStrength].param1 = 1.5f;
displayFlyingText( x, y - 20.0f, 16, tools::getLabel("effect_strength"), TextEntity::COLOR_FADING_BLUE);
SoundManager::getInstance().playSound(SOUND_DRINK);
break;
case ItemPotionOblivion:
game().forget();
for (int i = 0; i < MAX_SLOT_CONSUMABLES; i++)
{
if (consumable[i] > -1)
{
if (consumable[i] >= ItemPotion01 + NUMBER_UNIDENTIFIED && consumable[i] < FirstEquipItem )
{
consumable[i] = game().getPotion((enumItemType)consumable[i]);
}
}
}
displayFlyingText( x, y - 20.0f, 16, tools::getLabel("effect_forget"), TextEntity::COLOR_FADING_RED);
SoundManager::getInstance().playSound(SOUND_DRINK);
break;
case ItemPotionConfusion:
specialState[SpecialStateConfused].active = false;
specialState[SpecialStateConfused].waitUnclear = true;
specialState[SpecialStateConfused].timer = 10;
displayFlyingText( x, y - 20.0f, 16, tools::getLabel("effect_confusion"), TextEntity::COLOR_FADING_RED);
SoundManager::getInstance().playSound(SOUND_DRINK);
break;
case ItemPotionCure:
for (int i = 0; i < DivineStateProtection; i++)
{
specialState[i].active = false;
specialState[i].waitUnclear = false;
}
displayFlyingText( x, y - 20.0f, 16, tools::getLabel("effect_cure"), TextEntity::COLOR_FADING_BLUE);
SoundManager::getInstance().playSound(SOUND_DRINK);
break;
case ItemPotionRage:
specialState[SpecialStateRage].active = false;
specialState[SpecialStateRage].waitUnclear = true;
specialState[SpecialStateRage].timer = 20.5f;
specialState[SpecialStateRage].param1 = 12;
specialState[SpecialStateRage].param2 = 2;
specialState[SpecialStateRage].param3 = 2;
displayFlyingText( x, y - 20.0f, 16, tools::getLabel("effect_rage"), TextEntity::COLOR_FADING_RED);
SoundManager::getInstance().playSound(SOUND_DRINK);
break;
default:
std::cout << "[ERROR] Trying to consume item: " << items[item].name << std::endl;
break;
}
SpriteEntity* usedItem = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_ITEMS), x, y, 32, 32);
usedItem->setImagesProLine(10);
usedItem->setFrame((int)item);
usedItem->setFading(true);
usedItem->setZ(y - 100);
usedItem->setLifetime(0.7f);
usedItem->setAge(-0.4);
usedItem->setType(ENTITY_EFFECT);
usedItem->setSpin(150.0f);
usedItem->setVelocity(Vector2D(60));
}
void PlayerEntity::reveal()
{
for (int i = 0; i < MAX_SLOT_CONSUMABLES; i++)
{
if (consumable[i] > -1)
{
if (isUnidentified((enumItemType)consumable[i]))
{
game().setPotionToKnown((enumItemType)consumable[i]);
consumable[i] = game().getPotion((enumItemType)consumable[i]);
}
}
}
if (game().getCurrentMap()->callRevelation())
{
game().refreshMinimap();
SoundManager::getInstance().playSound(SOUND_SECRET);
}
}
bool PlayerEntity::canAquireConsumable(enumItemType type)
{
int nbConsumableSlot = equip[EQUIP_BAG] ? 4 : 2;
for (int i = 0; i < nbConsumableSlot; i++)
{
if (consumable[i] <= 0) return true;
}
return false;
}
void PlayerEntity::acquireConsumable(enumItemType type)
{
int nbConsumableSlot = equip[EQUIP_BAG] ? 4 : 2;
int emptySlot = -1;
for (int i = 0; emptySlot == -1 && i < nbConsumableSlot; i++)
{
if (consumable[i] <= 0) emptySlot = i;
}
if (emptySlot > -1)
{
consumable[emptySlot] = type;
// events
game().proceedEvent(EventConsumable);
if (isUnidentified(type)) game().proceedEvent(EventPotion);
}
}
void PlayerEntity::onClearRoom()
{
if (divinity.divinity == DivinityHealer)
{
if (divinity.level > 1 && hp < hpMax)
{
divineInterventionDelay = WORSHIP_DELAY / 2;
isRegeneration = true;
if (divinity.level >= 5) heal(4);
else if (divinity.level >= 4) heal(3);
else if (divinity.level >= 3) heal(2);
else if (divinity.level >= 2) heal(1);
}
}
}
void PlayerEntity::computePlayer()
{
float boltLifeTimeBonus = 1.0f;
float fireDelayBonus = 1.0f;
float creatureSpeedBonus = 1.0f;
float fireVelocityBonus = 1.0f;
float fireDamagesBonus = 1.0f;
armor = 0.0f;
criticalChance = 0;
for (int i = 0; i < NB_RESISTANCES; i++) resistance[i] = ResistanceStandard;
if (equip[EQUIP_GLOVES_ADVANCED]) fireDelayBonus -= 0.15f;
else if (equip[EQUIP_DISPLACEMENT_GLOVES]) fireDelayBonus -= 0.10f;
if (equip[EQUIP_HAT_ADVANCED])
{
fireDelayBonus -= 0.3f;
resistance[ResistanceIce] = (enumStateResistance)(resistance[ResistanceIce] - 1);
resistance[ResistanceStone] = (enumStateResistance)(resistance[ResistanceStone] - 1);
resistance[ResistanceLightning] = (enumStateResistance)(resistance[ResistanceLightning] - 1);
resistance[ResistanceFire] = (enumStateResistance)(resistance[ResistanceFire] - 1);
}
else if (equip[EQUIP_MAGICIAN_HAT]) fireDelayBonus -= 0.2f;
if (equip[EQUIP_LEATHER_BELT]) fireDelayBonus -= 0.15f;
if (equip[EQUIP_BOOTS_ADVANCED]) creatureSpeedBonus += 0.25f;
else if (equip[EQUIP_LEATHER_BOOTS]) creatureSpeedBonus += 0.15f;
if (equip[EQUIP_BOOK_TRIPLE]) fireDelayBonus += 0.7f;
else if (equip[EQUIP_BOOK_DUAL]) fireDelayBonus += 0.5f;
if (equip[EQUIP_CRITICAL]) criticalChance += 5;
if (equip[EQUIP_MANUAL_STAFF]) boltLifeTimeBonus += 0.4f;
if (equip[EQUIP_MAHOGANY_STAFF])
{
fireVelocityBonus += 0.15f;
fireDamagesBonus += 0.5f;
}
if (equip[EQUIP_BLOOD_SNAKE]) fireDamagesBonus += 0.5f;
if (equip[EQUIP_ROBE_ADVANCED]) armor += 0.2f;
else if (equip[EQUIP_MAGICIAN_ROBE]) armor += 0.15f;
// divinity
switch (divinity.divinity)
{
case (DivinityHealer):
{
break;
}
case (DivinityFighter):
{
if (divinity.level >= 5)
fireDamagesBonus += 0.5f;
else if (divinity.level >= 4)
fireDamagesBonus += 0.375f;
else if (divinity.level >= 3)
fireDamagesBonus += 0.25f;
else if (divinity.level >= 2)
fireDamagesBonus += 0.125f;
break;
}
case (DivinityIce):
{
if (divinity.level >= 5) resistance[ResistanceFrozen] = ResistanceVeryHigh;
if (divinity.level >= 3) resistance[ResistanceIce] = (enumStateResistance)(resistance[ResistanceIce] - 1);
break;
}
case (DivinityStone):
{
if (divinity.level >= 5) resistance[ResistanceRecoil] = ResistanceVeryHigh;
if (divinity.level >= 3) resistance[ResistanceStone] = (enumStateResistance)(resistance[ResistanceStone] - 1);
break;
}
case (DivinityAir):
{
if (divinity.level > 1) creatureSpeedBonus += (divinity.level - 1) * 0.04f;
if (divinity.level >= 3) resistance[ResistanceLightning] = (enumStateResistance)(resistance[ResistanceLightning] - 1);
break;
}
}
fireDelay = INITIAL_PLAYER_FIRE_DELAY * fireDelayBonus;
creatureSpeed = INITIAL_PLAYER_SPEED * creatureSpeedBonus;
fireVelocity = INITIAL_BOLT_VELOCITY * fireVelocityBonus;
fireDamages = INITIAL_BOLT_DAMAGES * fireDamagesBonus;
boltLifeTime = INITIAL_BOLT_LIFE * boltLifeTimeBonus;
// gems
for (int i = 1; i < SPECIAL_SHOT_SLOTS; i++)
{
specialShotLevel[i] = 0;
switch (specialShots[i])
{
case ShotTypeIce:
if (equip[EQUIP_RING_ICE]) specialShotLevel[i]++;
if (divinity.divinity == DivinityIce && divinity.level >= 4) specialShotLevel[i]++;
break;
case ShotTypeStone:
if (equip[EQUIP_RING_STONE]) specialShotLevel[i]++;
if (divinity.divinity == DivinityStone && divinity.level >= 4) specialShotLevel[i]++;
break;
case ShotTypeLightning:
if (equip[EQUIP_RING_LIGHTNING]) specialShotLevel[i]++;
if (divinity.divinity == DivinityAir && divinity.level >= 4) specialShotLevel[i]++;
break;
case ShotTypeIllusion:
if (equip[EQUIP_RING_ILLUSION]) specialShotLevel[i]++;
break;
case ShotTypeFire:
if (equip[EQUIP_RING_FIRE]) specialShotLevel[i]++;
break;
case ShotTypePoison:
if (equip[EQUIP_RING_POISON]) specialShotLevel[i]++;
break;
default:
break;
}
}
if (getShotType() == ShotTypeIllusion) fireDamages *= ILLUSION_DAMAGE_DECREASE[getShotLevel()];
else if (getShotType() == ShotTypeFire) fireDamages *= FIRE_DAMAGE_INCREASE[getShotLevel()];
// divinity
if (specialState[DivineStateProtection].active)
armor += specialState[DivineStateProtection].param1;
// post-computation
if (equip[EQUIP_BOOK_TRIPLE_QUICK]) fireDamages *= 0.65f;
else if (equip[EQUIP_BOOK_DUAL_QUICK]) fireDamages *= 0.75f;
else if (equip[EQUIP_RAPID_SHOT])
{
fireDelay *= 0.20f;
fireDamages *= 0.25f;
}
if (equip[EQUIP_ALCOHOL]) fireDamages *= 1.25f;
// spells
if (protection.active) armor += protection.value;
if (armor > 1.0f) armor = 1.0f;
// fairy ?
if (isFairyTransmuted)
{
fireDamages *= 0.5f;
creatureSpeed *= 1.5f;
movingStyle = movFlying;
}
else
{
movingStyle = movWalking;
}
// potions
if (specialState[SpecialStateWeakness].active && !specialState[SpecialStateStrength].active)
fireDamages *= specialState[SpecialStateWeakness].param1;
if (specialState[SpecialStateStrength].active && !specialState[SpecialStateWeakness].active)
fireDamages *= specialState[SpecialStateStrength].param1;
}
void PlayerEntity::acquireStance(enumItemType type)
{
velocity.x = 0.0f;
velocity.y = 0.0f;
playerStatus = playerStatusAcquire;
statusTimer = ACQUIRE_DELAY;
acquiredItem = (enumItemType)(type);
SoundManager::getInstance().playSound(SOUND_BONUS);
game().showArtefactDescription(type);
enumItemType itemFrame = type;
int itemImage = IMAGE_ITEMS;
if (itemFrame >= FirstEquipItem)
{
itemFrame = (enumItemType)(itemFrame - FirstEquipItem);
itemImage = IMAGE_ITEMS_EQUIP;
}
spriteItem = new SpriteEntity(
ImageManager::getInstance().getImage(itemImage),
x, y - 100.0f, ITEM_WIDTH, ITEM_HEIGHT);
spriteItem->setFrame((int)itemFrame);
spriteItem->setImagesProLine(10);
spriteItem->setZ(z);
spriteItem->setLifetime(ACQUIRE_DELAY);
spriteItemStar = new SpriteEntity(
ImageManager::getInstance().getImage(IMAGE_STAR),
x, y - 100.0f);
spriteItemStar->setScale(4.0f, 4.0f);
spriteItemStar->setZ(z-1.0f);
spriteItemStar->setLifetime(ACQUIRE_DELAY);
spriteItemStar->setSpin(50.0f);
}
void PlayerEntity::collideMapRight()
{
collidingDirection = 6;
if (recoil.active) recoil.velocity.x = -recoil.velocity.x * 0.7f;
}
void PlayerEntity::collideMapLeft()
{
collidingDirection = 4;
if (recoil.active) recoil.velocity.x = -recoil.velocity.x * 0.7f;
}
void PlayerEntity::collideMapTop()
{
collidingDirection = 8;
if (recoil.active) recoil.velocity.y= -recoil.velocity.y * 0.7f;
}
void PlayerEntity::collideMapBottom()
{
collidingDirection = 2;
if (recoil.active) recoil.velocity.y= -recoil.velocity.y * 0.7f;
}
void PlayerEntity::useBossKey()
{
velocity.x = 0.0f;
velocity.y = 0.0f;
playerStatus = playerStatusUnlocking;
statusTimer = UNLOCK_DELAY;
acquiredItem = (enumItemType)(type - FirstEquipItem);
SoundManager::getInstance().playSound(SOUND_DOOR_OPENING_BOSS);
equip[EQUIP_BOSS_KEY] = false;
SpriteEntity* spriteItem = new SpriteEntity(
ImageManager::getInstance().getImage(IMAGE_ITEMS_EQUIP),
x, y - 80.0f, ITEM_WIDTH, ITEM_HEIGHT);
spriteItem->setFrame(EQUIP_BOSS_KEY);
spriteItem->setZ(z);
spriteItem->setAge(-UNLOCK_DELAY * 0.5f);
spriteItem->setLifetime(UNLOCK_DELAY * 0.5f);
spriteItem->setFading(true);
spriteItem->setSpin(300);
}
enumShotType PlayerEntity::getShotType()
{
return specialShots[specialShotIndex];
}
int PlayerEntity::getShotIndex()
{
return specialShotIndex;
}
void PlayerEntity::setShotIndex(int index)
{
specialShotIndex = index;
}
enumShotType PlayerEntity::getShotType(int slot)
{
return specialShots[slot];
}
void PlayerEntity::setShotType(int slot, enumShotType shotType)
{
specialShots[slot] = shotType;
}
void PlayerEntity::registerSpecialShot(int item)
{
bool found = false;
int index = 1;
while (index < SPECIAL_SHOT_SLOTS && !found)
{
found = specialShots[index] == ShotTypeStandard;
if (!found) index++;
}
if (found)
{
this->specialShots[index] = items[item].specialShot;
specialShotIndex = index;
initShotType();
}
}
void PlayerEntity::selectNextShotType()
{
int index = specialShotIndex + 1;
bool found = false;
while (index < SPECIAL_SHOT_SLOTS && !found)
{
if (specialShots[index] == ShotTypeStandard) index++;
else found = true;
}
if (found)
{
specialShotIndex = index;
initShotType();
}
else
specialShotIndex = 0;
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
computePlayer();
}
void PlayerEntity::initShotType()
{
specialBoltTimer = STATUS_FROZEN_BOLT_DELAY[getShotLevel()];
needInitShotType = false;
if (getShotType() == ShotTypeLightning)
SoundManager::getInstance().playSound(SOUND_ELECTRIC_CHARGE);
}
unsigned int PlayerEntity::getShotLevel()
{
return specialShotLevel[specialShotIndex];
}
unsigned int PlayerEntity::getShotLevel(int index)
{
return specialShotLevel[index];
}
int PlayerEntity::getFairieNumber()
{
return fairies.size();
}
FairyEntity* PlayerEntity::getFairy(unsigned int n)
{
if (n < fairies.size())
return fairies[n];
else
return NULL;
}
bool PlayerEntity::canGetNewShot(bool advancedShot)
{
int nbSpecial =0;
int nbAdvanced =0;
for (int i = 1; i < SPECIAL_SHOT_SLOTS; i++)
{
switch (specialShots[i])
{
case ShotTypeIce:
case ShotTypeStone:
case ShotTypeLightning:
nbSpecial++;
break;
case ShotTypeFire:
case ShotTypeIllusion:
case ShotTypePoison:
nbAdvanced++;
break;
case ShotTypeStandard:
break;
default:
std::cout << "[WARNING] Can not register shot type: " << getShotType() << std::endl;
}
}
if (advancedShot)
return (nbAdvanced >= SPECIAL_SHOT_SLOTS_ADVANCED);
else
return (nbSpecial >= SPECIAL_SHOT_SLOTS_STANDARD);
}
void PlayerEntity::interact(EnumInteractionType interaction, int id)
{
if (playerStatus == playerStatusPlaying)
{
// praying at the temple
if (interaction == InteractionTypeTemple)
{
if (divinity.divinity == id)
{
// donation
if (gold >= 10)
{
donate(10);
}
}
else
{
worship((enumDivinityType)id);
}
}
else if (interaction == InteractionTypeMerchandise)
{
if (itemToBuy != NULL) itemToBuy->buy();
}
}
}
float PlayerEntity::getBolPositionY()
{
if (isFairyTransmuted)
return y - 25;
else
return y - 20;
}
bool PlayerEntity::collideWithMap(int direction)
{
if (playerStatus == playerStatusEntering)
return false;
else
return BaseCreatureEntity::collideWithMap(direction);
}
// DIVINITY
void PlayerEntity::donate(int n)
{
if (gold >= n)
{
gold -= n;
+ donation += n;
+ if (donation >= 100) game().registerAchievement(AchievementFanatic);
displayAcquiredGold(-n);
SoundManager::getInstance().playSound(SOUND_PAY);
// standard : 1 gold = 3 piety
int pietyProGold = 3;
if (divinity.divinity == DivinityHealer)
pietyProGold = 5;
addPiety(pietyProGold * n);
// check item invoke
bool divineGift = false;
enumItemType itemType = ItemCopperCoin;
if (divinity.level >= 3 && game().getItemsCount() == 0)
{
if (divinity.divinity == DivinityHealer && !equip[EQUIP_MANUAL_HEALTH])
{
// Healer + level 3 = Health manual
divineGift = true;
itemType = ItemManualHealth;
}
else if (divinity.divinity == DivinityIce && !equip[EQUIP_GEM_ICE])
{
divineGift = true;
itemType = ItemGemIce;
}
else if (divinity.divinity == DivinityStone && !equip[EQUIP_GEM_STONE])
{
divineGift = true;
itemType = ItemGemStone;
}
else if (divinity.divinity == DivinityAir && !equip[EQUIP_GEM_LIGHTNING])
{
divineGift = true;
itemType = ItemGemLightning;
}
}
if (divineGift)
{
float xItem = GAME_WIDTH / 2;
float yItem = GAME_HEIGHT * 0.8f;
new ItemEntity(itemType, xItem, yItem);
SoundManager::getInstance().playSound(SOUND_OM);
divineInterventionDelay = WORSHIP_DELAY / 2;
isRegeneration = false;
for (int i = 0; i < 8; i++)
{
game().generateStar(sf::Color::White, xItem, yItem);
game().generateStar(sf::Color(255, 255, 210), xItem, yItem);
}
game().testAndAddMessageToQueue((EnumMessages)(MsgInfoDivGift));
}
}
}
void PlayerEntity::offerMonster(enemyTypeEnum monster, enumShotType hurtingType)
{
if (divinity.divinity > -1)
{
// standard : 1 monster = 2 piety - 1 boss = 20 piety
int pietyProMonster = 2;
int pietyProBoss = 20;
switch (divinity.divinity)
{
case DivinityHealer:
if (monster == EnemyTypeGhost
|| monster == EnemyTypeZombie
|| monster == EnemyTypeZombieDark
|| monster == EnemyTypeImpBlue
|| monster == EnemyTypeImpRed
|| monster == EnemyTypeWitch
|| monster == EnemyTypeWitchRed
|| monster == EnemyTypeBogeyman)
pietyProMonster = 4;
else
pietyProMonster = 0;
break;
case DivinityFighter:
pietyProMonster = 3;
pietyProBoss = 30;
break;
case DivinityIce:
if (monster == EnemyTypeSlimeRed
|| monster == EnemyTypeImpRed
|| monster == EnemyTypeEvilFlowerFire)
pietyProMonster = 4;
if (hurtingType == ShotTypeCold || hurtingType == ShotTypeIce)
{
pietyProMonster *= 1.5f;
pietyProBoss = 25;
}
break;
case DivinityStone:
if (hurtingType == ShotTypeCold || hurtingType == ShotTypeIce)
{
pietyProMonster = 3;
pietyProBoss = 30;
}
else
{
pietyProBoss = 25;
}
break;
}
if (monster < EnemyTypeButcher) // normal or mini-boss
{
addPiety(pietyProMonster);
}
else if (monster < EnemyTypeBat_invocated) // boss
{
addPiety(pietyProBoss);
}
}
}
void PlayerEntity::offerHealth(int lostHp)
{
if (divinity.divinity == DivinityHealer)
{
addPiety(lostHp * 2.5f);
}
}
void PlayerEntity::offerChallenge()
{
if (divinity.divinity >= 0)
addPiety(30);
}
void PlayerEntity::divineFury()
{
enumShotType shotType = ShotTypeStandard;
if (divinity.divinity == DivinityIce) shotType = ShotTypeIce;
else if (divinity.divinity == DivinityStone) shotType = ShotTypeStone;
else if (divinity.divinity == DivinityAir) shotType = ShotTypeLightning;
int multBonus = 6;
if (divinity.divinity == DivinityFighter) multBonus = 8;
for (int i = 0; i < (divinity.divinity == DivinityAir ? 16 : 32); i ++)
{
BoltEntity* bolt = new BoltEntity(TILE_WIDTH * 1.5f + rand() % (MAP_WIDTH - 3) * TILE_WIDTH ,
TILE_HEIGHT * 1.5f + rand() % (MAP_HEIGHT - 3) * TILE_HEIGHT,
boltLifeTime, shotType, 0);
bolt->setDamages(8 + divinity.level * multBonus);
float velx = 400 * cos(i);
float vely = 400 * sin(i);
bolt->setVelocity(Vector2D(velx, vely));
if (divinity.divinity == DivinityAir)
{
bolt->setFlying(true);
bolt->setLifetime(-1.0f);
}
else
{
bolt->setLifetime(8.0f);
}
bolt->setViscosity(1.0f);
bolt->setGoThrough(true);
bolt->setFromPlayer(false);
}
}
void PlayerEntity::divineDestroyUndead()
{
game().destroyUndead(40);
}
void PlayerEntity::divineIce()
{
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_ENEMY && e->getType() <= ENTITY_ENEMY_MAX)
{
EnemyEntity* enemy = dynamic_cast<EnemyEntity*>(e);
enemy->setSpecialState(SpecialStateIce, true, 10.0f, 0.1f, 0.0f);
}
}
}
void PlayerEntity::divineRepulse()
{
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_ENEMY && e->getType() <= ENTITY_ENEMY_MAX)
{
EnemyEntity* enemy = dynamic_cast<EnemyEntity*>(e);
enemy->hurt(getHurtParams
(8,
ShotTypeStandard,
0,
false,
SourceTypeBolt,
EnemyTypeNone,
false));
enemy->giveRecoil(true, Vector2D(x, y).vectorTo(Vector2D(enemy->getX(), enemy->getY()), 700.0f), 2.0f);
}
}
// effect
for (int i = 0; i < 40; i++)
{
SpriteEntity* spriteRock = new SpriteEntity(
ImageManager::getInstance().getImage(IMAGE_CYCLOP),
x, y, 64, 64);
spriteRock->setZ(1000.0f);
spriteRock->setImagesProLine(20);
spriteRock->setFrame(rand() % 2 == 0 ? 38 : 58);
spriteRock->setSpin(-100 + rand()%200);
spriteRock->setVelocity(Vector2D(400 + rand()%400));
spriteRock->setFading(true);
spriteRock->setAge(-0.8f);
spriteRock->setLifetime(2.0f);
spriteRock->setType(ENTITY_EFFECT);
}
game().makeShake(1.0f);
SoundManager::getInstance().playSound(SOUND_EARTHQUAKE);
}
void PlayerEntity::divineProtection(float duration, float armorBonus)
{
setSpecialState(DivineStateProtection, true, 4.0f, 0.8f, 0.0f);
}
void PlayerEntity::divineHeal(int hpHealed)
{
hp += hpHealed;
if (hp > hpMax) hp = hpMax;
specialState[SpecialStatePoison].active = false;
divineInterventionDelay = WORSHIP_DELAY;
isRegeneration = false;
}
bool PlayerEntity::triggerDivinityBefore()
{
if (divinity.divinity > -1 && divinity.interventions < divinity.level - 1)
{
switch (divinity.divinity)
{
case DivinityHealer:
{
if (game().getUndeadCount() > 0 && rand() % 2 == 0)
{
SoundManager::getInstance().playSound(SOUND_OM);
incrementDivInterventions();
divineHeal(hpMax / 2);
divineDestroyUndead();
game().makeColorEffect(X_GAME_COLOR_WHITE, 0.45f);
return true;
}
break;
}
case DivinityFighter:
{
int r = rand() % 3;
if (r == 0) return false;
SoundManager::getInstance().playSound(SOUND_OM);
incrementDivInterventions();
divineHeal(hpMax / 3);
if (r == 1) divineProtection(10.0f, 0.8f);
else divineFury();
game().makeColorEffect(X_GAME_COLOR_RED, 0.45f);
return true;
break;
}
case DivinityIce:
{
int r = rand() % 3;
if (r == 0) return false;
SoundManager::getInstance().playSound(SOUND_OM);
incrementDivInterventions();
divineHeal(hpMax / 3);
if (r == 1)
{
divineIce();
game().makeColorEffect(X_GAME_COLOR_BLUE, 7.5f);
}
else
{
divineFury();
game().makeColorEffect(X_GAME_COLOR_BLUE, 0.5f);
}
return true;
break;
}
case DivinityStone:
{
int r = rand() % 2;
divineProtection(12.0f, 0.5f);
SoundManager::getInstance().playSound(SOUND_OM);
incrementDivInterventions();
divineHeal(hpMax / 3);
if (r == 0)
{
divineRepulse();
game().makeColorEffect(X_GAME_COLOR_BROWN, 3.0f);
}
else
{
divineFury();
game().makeColorEffect(X_GAME_COLOR_BROWN, 0.5f);
}
return true;
break;
}
case DivinityAir:
{
int r = rand() % 3;
if (r == 0) return false;
SoundManager::getInstance().playSound(SOUND_OM);
incrementDivInterventions();
divineHeal(hpMax / 3);
/*if (r == 1)
{
divineIce();
game().makeColorEffect(X_GAME_COLOR_BLUE, 7.5f);
}
else*/
{
divineFury();
game().makeColorEffect(X_GAME_COLOR_VIOLET, 0.5f);
}
return true;
break;
}
}
}
return false;
}
void PlayerEntity::triggerDivinityAfter()
{
if (divinity.divinity > -1 && divinity.interventions < divinity.level - 1)
{
switch (divinity.divinity)
{
case DivinityHealer:
{
SoundManager::getInstance().playSound(SOUND_OM);
incrementDivInterventions();
divineHeal(hpMax);
break;
}
//case DivinityFighter:
default:
{
SoundManager::getInstance().playSound(SOUND_OM);
incrementDivInterventions();
divineHeal(hpMax / 2);
break;
}
}
game().testAndAddMessageToQueue((EnumMessages)(MsgInfoDivIntervention));
}
}
void PlayerEntity::addPiety(int n)
{
if (n > 0 && equip[EQUIP_BOOK_PRAYER_I]) n *= 1.5f;
int oldLevel = divinity.level;
divinity.piety += n;
if (divinity.piety >= DIVINITY_LEVEL_TRESHOLD[MAX_DIVINITY_LEVEL - 1])
{
divinity.piety = DIVINITY_LEVEL_TRESHOLD[MAX_DIVINITY_LEVEL - 1];
divinity.percentsToNextLevels = 1.0f;
game().registerAchievement(AchievementPietyMax);
divinity.level = MAX_DIVINITY_LEVEL + 1;
}
else
{
int i = 0;
while (divinity.piety > DIVINITY_LEVEL_TRESHOLD[i] && i < (MAX_DIVINITY_LEVEL + 1)) i++;
divinity.level = i + 1;
if (divinity.level == 1)
divinity.percentsToNextLevels = (float)divinity.piety / (float)DIVINITY_LEVEL_TRESHOLD[0];
else
divinity.percentsToNextLevels
= (float)(divinity.piety - DIVINITY_LEVEL_TRESHOLD[divinity.level - 2])
/ (float)(DIVINITY_LEVEL_TRESHOLD[divinity.level - 1] - DIVINITY_LEVEL_TRESHOLD[divinity.level - 2]);
}
if (divinity.level > oldLevel)
{
SoundManager::getInstance().playSound(SOUND_OM);
divineInterventionDelay = WORSHIP_DELAY / 2;
isRegeneration = false;
pietyLevelUp();
computePlayer();
}
else if (divinity.level < oldLevel)
{
computePlayer();
}
}
void PlayerEntity::pietyLevelUp()
{
std::string label = "";
switch (divinity.divinity)
{
case DivinityFighter:
label = "div_fighter_lvl";
break;
case DivinityHealer:
if (divinity.level == 2) label = "div_healer_lvl_2";
else label = "div_healer_lvl_3";
break;
case DivinityIce:
if (divinity.level == 3) label = "div_ice_lvl_3";
else if (divinity.level == 4) label = "div_ice_lvl_4";
else if (divinity.level == 5) label = "div_ice_lvl_5";
break;
case DivinityStone:
if (divinity.level == 3) label = "div_stone_lvl_3";
else if (divinity.level == 4) label = "div_stone_lvl_4";
else if (divinity.level == 5) label = "div_stone_lvl_5";
break;
case DivinityAir:
if (divinity.level == 4) label = "div_air_lvl_4";
else label = "div_air_lvl";
break;
}
if (label.compare("") != 0) game().addDivLevelMessageToQueue(label);
}
void PlayerEntity::incrementDivInterventions()
{
divinity.interventions++;
addPiety(-divinity.piety * (equip[EQUIP_BOOK_PRAYER_II] ? 0.04f : 0.08f));
}
void PlayerEntity::worship(enumDivinityType id)
{
int oldPiety = divinity.piety;
+ int oldLevel = divinity.level;
bool isReconversion = divinity.divinity > -1;
playerStatus = playerStatusPraying;
statusTimer = WORSHIP_DELAY;
SoundManager::getInstance().playSound(SOUND_OM);
divinity.divinity = id;
divinity.piety = 0;
divinity.level = 1;
divinity.percentsToNextLevels = 0.0f;
facingDirection = 2;
// text
float x0 = MAP_WIDTH * 0.5f * TILE_WIDTH;
float y0 = MAP_HEIGHT * 0.5f * TILE_HEIGHT + 140.0f;
std::stringstream ss;
ss << tools::getLabel("worshipping") << " ";
ss << tools::getLabel(divinityLabel[divinity.divinity] + "_0");
TextEntity* text = new TextEntity(ss.str(), 24, x0, y0);
text->setAlignment(ALIGN_CENTER);
text->setLifetime(2.5f);
text->setWeight(-36.0f);
text->setZ(1200);
text->setColor(TextEntity::COLOR_FADING_WHITE);
// reconversion
if (isReconversion)
{
- if (divinity.level >= 4)
+ if (oldLevel >= 4)
game().registerAchievement(AchievementApostate);
addPiety((equip[EQUIP_BOOK_PRAYER_I]) ? 0.66 * oldPiety : 0.5 * oldPiety);
if (divinity.interventions > divinity.level - 1)
divinity.interventions = divinity.level - 1;
}
else
divinity.interventions = 0;
// message
game().testAndAddMessageToQueue((EnumMessages)(MsgInfoDivHealer + (int)id));
}
void PlayerEntity::loadDivinity(int id, int piety, int level, int interventions)
{
divinity.divinity = id;
divinity.piety = piety;
divinity.level = level;
divinity.interventions = interventions;
if (id >= 0) addPiety(0);
}
// MAGIC
castSpellStruct PlayerEntity::getActiveSpell()
{
return activeSpell;
}
void PlayerEntity::setActiveSpell(enumCastSpell spell, bool fromSaveInFight)
{
if (activeSpell.spell != SpellNone)
{
// drop the old spell
equip[activeSpell.frame] = false;
ItemEntity* newItem = new ItemEntity((enumItemType)(ItemMagicianHat + activeSpell.frame), x, y);
newItem->setVelocity(Vector2D(100.0f + rand()% 250));
newItem->setViscosity(0.96f);
}
activeSpell.spell = spell;
switch (spell)
{
case SpellTeleport:
activeSpell.delayMax = 20.0f;
activeSpell.frame = ItemSpellTeleport - FirstEquipItem;
break;
case SpellSlimeExplode:
activeSpell.delayMax = 40.0f;
activeSpell.frame = ItemSpellSlimeExplode - FirstEquipItem;
break;
case SpellFireball:
activeSpell.delayMax = 20.0f;
activeSpell.frame = ItemSpellFireball - FirstEquipItem;
break;
case SpellFreeze:
activeSpell.delayMax = 40.0f;
activeSpell.frame = ItemSpellFreeze - FirstEquipItem;
break;
case SpellEarthquake:
activeSpell.delayMax = 40.0f;
activeSpell.frame = ItemSpellEarthquake - FirstEquipItem;
break;
case SpellProtection:
activeSpell.delayMax = 40.0f;
activeSpell.frame = ItemSpellProtection - FirstEquipItem;
break;
case SpellWeb:
activeSpell.delayMax = 35.0f;
activeSpell.frame = ItemSpellWeb - FirstEquipItem;
break;
case SpellFlower:
activeSpell.delayMax = 80.0f;
activeSpell.frame = ItemSpellFlower - FirstEquipItem;
break;
case SpellFairy:
activeSpell.delayMax = 10.0f;
activeSpell.frame = ItemSpellFairy - FirstEquipItem;
break;
case SpellTime:
activeSpell.delayMax = 70.0f;
activeSpell.frame = ItemSpellTime - FirstEquipItem;
break;
case SpellNone:
break;
}
if (fromSaveInFight) activeSpell.delay = 1.0f;
else activeSpell.delay = activeSpell.delayMax;
}
void PlayerEntity::castSpell()
{
if (playerStatus != playerStatusPlaying) return;
if (canCastSpell())
{
activeSpell.delay = equip[EQUIP_BOOK_MAGIC_I] ? activeSpell.delayMax * 0.8f : activeSpell.delayMax;
switch (activeSpell.spell)
{
case SpellTeleport:
castTeleport();
break;
case SpellSlimeExplode:
castSummonsSlimeExplode();
break;
case SpellFireball:
castFireball();
break;
case SpellFreeze:
spellAnimationDelay = spellAnimationDelayMax;
castFreeze();
break;
case SpellEarthquake:
spellAnimationDelay = spellAnimationDelayMax;
castEarthquake();
break;
case SpellProtection:
spellAnimationDelay = spellAnimationDelayMax;
castProtection();
break;
case SpellWeb:
castWeb();
break;
case SpellFlower:
spellAnimationDelay = spellAnimationDelayMax;
castSummonsFlower();
break;
case SpellFairy:
castTransmuteFairy();
break;
case SpellTime:
spellAnimationDelay = spellAnimationDelayMax;
castTimeStop();
break;
case SpellNone:
break;
}
}
}
bool PlayerEntity::canCastSpell()
{
return activeSpell.spell != SpellNone && activeSpell.delay <= 0.0f;
}
void PlayerEntity::castTeleport()
{
bool ok = false;
int xm, ym;
float xNew = x, yNew = y;
invincibleDelay = equip[EQUIP_BOOK_MAGIC_II] ? 2.5f : 2.0f;
SoundManager::getInstance().playSound(SOUND_TELEPORT);
game().makeColorEffect(X_GAME_COLOR_VIOLET, 0.3f);
for(int i=0; i < 6; i++)
{
generateStar(sf::Color(50, 50, 255, 255));
generateStar(sf::Color(200, 200, 255, 255));
}
int counter = 150;
while (!ok && counter > 0)
{
counter--;
int distanceMin = 20000;
if (counter < 50) distanceMin = 30000;
else if (counter < 100) distanceMin = 25000;
xm = 1 +rand() % (MAP_WIDTH - 3);
ym = 1 +rand() % (MAP_HEIGHT - 3);
if (game().getCurrentMap()->isWalkable(xm, ym))
{
// enemy or bolt ?
EntityManager::EntityList* entityList =EntityManager::getInstance().getList();
EntityManager::EntityList::iterator it;
bool isBad = false;
xNew = xm * TILE_WIDTH + TILE_WIDTH * 0.5f;
yNew = ym * TILE_HEIGHT+ TILE_HEIGHT * 0.5f;
for (it = entityList->begin (); !isBad && it != entityList->end ();)
{
GameEntity *e = *it;
it++;
if ((e->getType() >= ENTITY_ENEMY && e->getType() <= ENTITY_ENEMY_MAX_COUNT) || e->getType() == ENTITY_ENEMY_BOLT)
isBad = Vector2D(xNew, yNew).distance2(Vector2D(e->getX(), e->getY())) < distanceMin;
}
if (!isBad)
{
x = xNew;
y = yNew;
}
}
}
for(int i=0; i < 6; i++)
{
generateStar(sf::Color(50, 50, 255, 255));
generateStar(sf::Color(200, 200, 255, 255));
}
}
void PlayerEntity::initFallingGrid()
{
for (int i = 0; i < MAP_WIDTH; i++)
for (int j = 0; j < MAP_HEIGHT; j++)
fallingGrid[i][j] = false;
}
void PlayerEntity::fallRock()
{
int rx, ry;
do
{
rx = 1 + rand() % (MAP_WIDTH - 2);
ry = 1 + rand() % (MAP_HEIGHT - 2);
}
while (fallingGrid[rx][ry]);
fallingGrid[rx][ry] = true;
new FallingRockEntity(rx * TILE_WIDTH + TILE_WIDTH / 2,
ry * TILE_HEIGHT + TILE_HEIGHT / 2,
rand() % 3,
true);
}
void PlayerEntity::castSummonsSlimeExplode()
{
SlimeEntity* slime = new SlimeEntity( ((int)(x) / TILE_WIDTH) * TILE_WIDTH + TILE_WIDTH * 0.5f,
y - 5, SlimeTypeViolet, true);
slime->makePet(facingDirection);
game().makeColorEffect(X_GAME_COLOR_VIOLET, 0.3f);
}
void PlayerEntity::castFireball()
{
SoundManager::getInstance().playSound(SOUND_FIREBALL);
game().makeColorEffect(X_GAME_COLOR_RED, 0.3f);
enumShotType boltType = ShotTypeFire;
unsigned int shotLevel = 2;
BoltEntity* bolt = new BoltEntity(x, getBolPositionY(), boltLifeTime + 0.5f, boltType, shotLevel);
int boltDamage = fireDamages * (equip[EQUIP_BOOK_MAGIC_II] ? 4 : 3);
if (equip[EQUIP_BOOK_MAGIC_II] && boltDamage < 32) boltDamage = 32;
else if (!equip[EQUIP_BOOK_MAGIC_II] && boltDamage < 24) boltDamage = 24;
bolt->setDamages(boltDamage);
bolt->setGoThrough(true);
float velx = 0.0f, vely = 0.0f;
if (facingDirection == 4) velx = -fireVelocity;
else if (facingDirection == 8) vely = -fireVelocity;
else if (facingDirection == 2) vely = fireVelocity;
else velx = fireVelocity;
bolt->setVelocity(Vector2D(velx, vely));
}
void PlayerEntity::castFreeze()
{
int iceLevel = equip[EQUIP_BOOK_MAGIC_II] ? 2 : 1;
for (float i = 0.0f; i < 2 * PI; i += PI / 8)
{
BoltEntity* bolt1 = new BoltEntity(x, getBolPositionY(), boltLifeTime, ShotTypeIce, iceLevel);
bolt1->setDamages(1);
float velx = fireVelocity * cos(i);
float vely = fireVelocity * sin(i);
bolt1->setVelocity(Vector2D(velx, vely));
}
game().makeColorEffect(X_GAME_COLOR_BLUE, 0.3f);
SoundManager::getInstance().playSound(SOUND_SPELL_FREEZE);
}
void PlayerEntity::castEarthquake()
{
initFallingGrid();
int nbIterations = equip[EQUIP_BOOK_MAGIC_II] ? 24 : 22;
for (int i = 0; i < nbIterations; i++) fallRock();
game().makeShake(0.25f);
game().makeColorEffect(X_GAME_COLOR_BROWN, 0.3f);
SoundManager::getInstance().playSound(SOUND_EARTHQUAKE);
}
void PlayerEntity::castProtection()
{
protection.active = true;
protection.value = equip[EQUIP_BOOK_MAGIC_II] ? 0.6f : 0.4f;
protection.timer = 10.0f;
computePlayer();
game().makeColorEffect(X_GAME_COLOR_BLUE, 0.3f);
SoundManager::getInstance().playSound(SOUND_SPELL_SHIELD);
}
void PlayerEntity::castWeb()
{
SoundManager::getInstance().playSound(SOUND_SPIDER_WEB);
int nbWeb = equip[EQUIP_BOOK_MAGIC_II] ? 4 : 3;
for (int i = 0; i < nbWeb; i++)
{
SpiderWebEntity* web = new SpiderWebEntity(x, y, true);
float webVel = 100 + rand()% 500;
float webAngle = -60 + rand() % 120;
webAngle = PI * webAngle / 180.0f;
if (facingDirection == 4) webAngle += PI;
else if (facingDirection == 8) webAngle -= PI * 0.5;
else if (facingDirection == 2) webAngle += PI * 0.5;
web->setVelocity(Vector2D(webVel * cos(webAngle), webVel * sin(webAngle)));
}
}
void PlayerEntity::castSummonsFlower()
{
SoundManager::getInstance().playSound(SOUND_INVOKE);
EvilFlowerEntity* flower = new EvilFlowerEntity(x, y, FlowerTypePet);
flower->setLifetime(equip[EQUIP_BOOK_MAGIC_II] ? 45 : 35);
if (equip[EQUIP_BOOK_MAGIC_II]) flower->setFireDelayMax(EVIL_FLOWER_FIRE_DELAY * 0.8f);
}
void PlayerEntity::castTransmuteFairy()
{
if (isFairyTransmuted)
{
movingStyle = movWalking;
if (isCollidingWithMap())
movingStyle = movFlying;
else
{
SoundManager::getInstance().playSound(SOUND_INVOKE);
isFairyTransmuted = false;
computePlayer();
for(int i=0; i < 6; i++)
{
generateStar(sf::Color(50, 50, 255, 255));
generateStar(sf::Color(200, 200, 255, 255));
}
}
}
else
{
SoundManager::getInstance().playSound(SOUND_INVOKE);
isFairyTransmuted = true;
computePlayer();
for(int i=0; i < 6; i++)
{
generateStar(sf::Color(50, 50, 255, 255));
generateStar(sf::Color(200, 200, 255, 255));
}
}
}
void PlayerEntity::castTimeStop()
{
specialState[SpecialStateTime].active = true;
specialState[SpecialStateTime].timer = equip[EQUIP_BOOK_MAGIC_II] ? 7 : 5;
game().pauseMusic();
}
diff --git a/src/PlayerEntity.h b/src/PlayerEntity.h
index 641867f..9c98698 100644
--- a/src/PlayerEntity.h
+++ b/src/PlayerEntity.h
@@ -1,624 +1,643 @@
#ifndef PLAYERSPRITE_H
#define PLAYERSPRITE_H
#include "BaseCreatureEntity.h"
#include "ItemEntity.h"
#include "Constants.h"
class FairyEntity;
struct castSpellStruct
{
enumCastSpell spell;
float delay;
float delayMax;
int frame;
};
struct divinityStruct
{
int divinity;
int piety;
int level;
int interventions;
float percentsToNextLevels;
};
const int MAX_SLOT_CONSUMABLES = 4;
/*! \class PlayerEntity
* \brief Class for the player
*
* It contains the game logic of the player and the rendering.
*/
class PlayerEntity : public BaseCreatureEntity
{
public:
/*!
* \brief Constructor
*
* Constructor of the PlayerEntity class.
*
* \param x : x position of the player
* \param y : y position of the player
*/
PlayerEntity(float x, float y);
/*!
* \brief updates the player
*
* Updates the player.
* Called in the game loop.
*
* \param delay : elapsed time since the last call
*/
virtual void animate(float delay);
/*!
* \brief render the player
*
* Render the player.
* Called in the game loop.
*
* \param app : Rendering target
*/
virtual void render(sf::RenderTarget* app);
/*!
* \brief Moves the player to another place
*
* Moves the player to another place.
* Called when changing room, the "familiers" will move too.
*
* \param newX : target x position of the player
* \param newY : target y position of the player
*/
void moveTo(float newX, float newY);
/*!
* \brief returns the direction the player is facing
*
* Return the direction the player is facing.
* Use to know in which direction he has to fire with the "one button" gameplay.
*
* \return : the facing direction. 4 = left, 8 = north, 6 = right, 2 = south
*/
int getFacingDirection();
void setFacingDirection(int facingDirection);
/*!
* \brief update the bounding box
*
* Update the bounding box of the player.
* Used before testing collision.
*/
virtual void calculateBB();
virtual bool canCollide();
/*!
* \brief Moves the player in the given direction
*
* Moves the player in the given direction.
*
* \param direction : direction of the new map. Numeric pad, diagonals included : 4 = left, 8 = north, 7 = north-west...
*/
void move(int direction);
/*!
* \brief Fires in the given direction
*
* Fires the player in the given direction.
*
* \param direction : direction of the new map. 4 = left, 8 = north, 6 = right, 2 = south
*/
void fire(int direction);
/*!
* \brief reset the fire direction of the player
*/
void resestFireDirection();
/*!
* \brief accessor on the fire direction of the player
*/
int getFireDirection();
/*!
* \brief returns if the player is moving or not
*
* Returns if the player is moving or not.
*
* \return : True if the player is moving
*/
bool isMoving();
/*!
* \brief returns if an item is equipped or not
*
* Returns if an item is equipped or not.
*
* \param eq : the equip item ID
* \return : True if the item is in possession of the player
*/
bool isEquiped(int eq);
bool* getEquipment();
/*!
* \brief returns if the player is poisoned or not
*
* \return : True if the player is poisoned
*/
bool isPoisoned();
/*!
* \brief updates the equipment of the player
*
* Updates the equipment of the player.
*
* \param item : the equip item ID
* \param toggleEquipped : True if the item has to be equipped
*/
void setEquiped(int item, bool toggleEquipped);
divinityStruct getDivinity();
int getPiety();
bool getFairyTransmuted();
/*!
* \brief updates the entering status of the player
*
* Updates the entering status of the player.
* Used when the player is entering in a not yet cleared room.
*/
void setEntering();
/*!
* \brief updates the status of the player to going up
*
* Updates the status of the player to going up.
* Used when the player is leaving a level.
*/
void setLeavingLevel();
/*!
* \brief returns if the player can move or not
*
* Returns if the player can move or not.
*
* \return : True if the player can move
*/
bool canMove();
/*!
* \brief called when the player is dying
*
* Called when the player is dying (HP <= 0).
*/
virtual void dying();
/*!
* \brief hurts the player
*
* Hurts the player.
* Calld when the player is hurt, usually when colliding with a monster or a missile.
*
* \param damages : the inflicted damages
* \param hurtingType : damages type
* \param level : damages level
* \return : True if the player has been hurt
*/
virtual int hurt(StructHurt hurtParam) override;
/*!
* \brief returns if the player is dead or not
*
* Returns if the player is dead or not.
*
* \return : True if the player is dead
*/
bool isDead();
/*!
* \brief returns the fire delay percentage
*
* Returns the fire delay percentage.
* Used (currently) when displaying the blue bar in the HUD.
*
* \return : the percentage (between 0.0f for empty to 1.0 for full)
*/
float getPercentFireDelay();
/*!
* \brief returns the light cone percentage
*
* \return : the percentage (between 0.0f for empty to 1.0 for full) or -1.0f if no light cone
*/
float getLightCone();
/*!
* \brief called when the player get an item
*
* Called when the player get an item.
* When the item is an equip item, he starts an "acquiring stance".
*
* \param type : item ID
*/
void acquireItem(enumItemType type);
/*!
* \brief called when the player get an item and ends the stance
*
*/
void acquireItemAfterStance();
/*!
* \brief makes the player drop an item
*
* Makes the player drop an item.
* Called when the player dies.
*
* \param itemType : item ID
* \param isEquip : True if it's an equip item (not the same texture)
*/
void loseItem(enumItemType itemType, bool isEquip);
/*!
* \brief starts the acquire stance
*
* Starts the acquire stance.
* Called when the player get an equip object. The item is "highlighted" and a description is displayed.
*
* \param type : item ID
*/
void acquireStance(enumItemType type);
/*!
* \brief starts the opening stance
*
* Starts the boss door opening animation.
* Remove the key from the inventory.
*/
void useBossKey();
/*!
* \brief accessor on the gold
*
* Accessor on the gold.
*
* \return : the gold
*/
int getGold() {return gold; }
/*!
* \brief mutator on the gold
*
* Mutator on the gold.
*
* \param gold : the new gold value
*/
void setGold(int gold) { this->gold = gold; }
+ /*!
+ * \brief accessor on the donation
+ *
+ * Accessor on the donation.
+ *
+ * \return : the donation
+ */
+ int getDonation() {return donation; }
+
+ /*!
+ * \brief mutator on the donation
+ *
+ * Mutator on the donation.
+ *
+ * \param gold : the new donation value
+ */
+ void setDonation(int gold) { this->donation = gold; }
+
/*!
* \brief pay some gold
*
* Pay some gold. Usually in shops.
*
* \param gold : the price to pay
*/
void pay(int price);
void displayAcquiredGold(int n);
/** Player status enum
* The different player states.
*/
enum playerStatusEnum
{
playerStatusPlaying, /**< Player is playing "normally" */
playerStatusEntering, /**< Player is entering a not yet cleared room (walking is forced) */
playerStatusAcquire, /**< Player is under acquiring stance */
playerStatusUnlocking, /**< Player is under unlocking stance */
playerStatusPraying, /**< Player is under unlocking stance */
playerStatusStairs, /**< Player walk the stairs */
playerStatusGoingNext, /**< Player goes to next level */
playerStatusDead /**< Player RIP */
};
/*!
* \brief accessor on the player status
*
* Accessor on the player status.
*
* \return : the player status
*/
playerStatusEnum getPlayerStatus();
/*!
* \brief mutator on the player status
*
* Mutator on the player status.
*
* \param player status : the new player status value
*/
void setPlayerStatus(playerStatusEnum playerStatus);
/*!
* \brief accessor on the colliding direction
*
* Accessor on the colliding direction.
*
* \return : the colliding direction
*/
int getCollidingDirection();
/*!
* \brief compute all the player data (stats / items)
*/
void computePlayer();
/*!
* \brief register a new special shot and select it
*
* \param item : Item which provides the shot
*/
void registerSpecialShot(int item);
/*!
* \brief accessor on current shot type
*
* \return : the current shot type
*/
enumShotType getShotType();
/*!
* \brief accessor on current shot level
*
* \return : the current shot level
*/
unsigned int getShotLevel();
/*!
* \brief accessor a shot level
* \param index : the index of the shot
* \return : the shot level
*/
unsigned int getShotLevel(int index);
/*!
* \brief accessor on current shot index
*
* Accessor on the current shot index.
*
* \return : the current shot index
*/
int getShotIndex();
/*!
* \brief mutator on the shot index
*
* Mutator on the shot index.
*
* \param index : the new shot index
*/
void setShotIndex(int index);
/*!
* \brief accessor on current shot type of a slot
*
* \param slot : The slot number
* \return : the current shot type
*/
enumShotType getShotType(int slot);
/*!
* \brief mutator on a shot slot
*
* Mutator on a shot slot.
*
* \param index : the shot index
* \param shotType : the shot type to set
*/
void setShotType(int slot, enumShotType shotType);
/*!
* \brief select the next shot type
*
* Select the next shot type.
*/
void selectNextShotType();
/*!
* \brief accessor on the fairies number
*/
int getFairieNumber();
/*!
* \brief accessor on a fairy
* \param n : index of the fairy in the vector
*/
FairyEntity* getFairy(unsigned int n);
/*!
* \brief checks if the player can get a new shot type
*
* \param advancedShot : true if the shot type is "advanced"
* \return : true if there is a free slot
*/
bool canGetNewShot(bool advancedShot);
/*!
* \brief returns time since player's death
* \return : time since player's death (in seconds)
*/
float getDeathAge();
/*!
* \brief mutator on the player's death age
* \param deathAge : the new player's death (in seconds)
*/
void setDeathAge(float deathAge);
virtual void setMap(GameMap* map, int tileWidth, int tileHeight, int offsetX, int offsetY) override;
/*!
* \brief casts a spell (if possible)
*/
void castSpell();
void onClearRoom();
void resetFloorItem();
void interact(EnumInteractionType interaction, int id);
void worship(enumDivinityType divinity);
void donate(int n);
void offerMonster(enemyTypeEnum monster, enumShotType hurtingType);
void offerHealth(int lostHp);
void offerChallenge();
void addPiety(int n);
void pietyLevelUp();
void loadDivinity(int id, int piety, int level, int interventions);
bool triggerDivinityBefore();
void triggerDivinityAfter();
void divineFury();
void divineDestroyUndead();
void divineIce();
void divineRepulse();
void divineProtection(float duration, float armorBonus);
void divineHeal(int hpHealed);
void setActiveSpell(enumCastSpell spell, bool fromSaveInFight);
castSpellStruct getActiveSpell();
float getPercentSpellDelay();
bool canCastSpell();
enemyTypeEnum getLastHurtingEnemy();
sourceTypeEnum getLastHurtingSource();
virtual void setSpecialState(enumSpecialState state, bool active, float timer, float param1, float param2, bool waitUnclear = false) override;
void setItemToBuy(ItemEntity* item);
ItemEntity* getItemToBuy();
void castTeleport();
virtual bool collideWithMap(int direction) override;
bool canAquireConsumable(enumItemType type);
int getConsumable(int n);
void setConsumable(int n, int type);
void dropConsumables(int n);
void tryToConsume(int n);
void consume(enumItemType item);
protected:
virtual void readCollidingEntity(CollidingSpriteEntity* entity);
void generateBolt(float velx, float vely);
void rageFire(float damage, bool full, float velMult);
virtual void collideMapRight();
virtual void collideMapLeft();
virtual void collideMapTop();
virtual void collideMapBottom();
virtual void stuck() override;
private:
int fireDamages;
float fireVelocity;
float fireDelay;
float fireAnimationDelay;
float fireAnimationDelayMax;
int fireAnimationDirection;
float spellAnimationDelay;
float spellAnimationDelayMax;
float currentFireDelay;
float randomFireDelay;
float hiccupDelay;
float boltLifeTime;
int gold;
+ int donation;
int criticalChance;
float invincibleDelay;
float divineInterventionDelay;
bool isRegeneration;
bool isFairyTransmuted;
bool canFirePlayer;
playerStatusEnum playerStatus;
float statusTimer;
enumItemType acquiredItem;
bool equip[NUMBER_EQUIP_ITEMS];
SpriteEntity* spriteItem;
SpriteEntity* spriteItemStar;
float specialBoltTimer;
enumShotType specialShots[SPECIAL_SHOT_SLOTS];
unsigned int specialShotLevel[SPECIAL_SHOT_SLOTS];
int specialShotIndex;
bool needInitShotType;
int collidingDirection; /*!< Colliding direction (4, 8, 6, 2) to detect collision with closed doors */
int firingDirection;
int keyDirection;
bool willCollideWithMap(int dx, int dy, bool checkMiddle);
std::vector<FairyEntity*> fairies;
float idleAge;
float deathAge;
enemyTypeEnum lastHurtingEnemy;
sourceTypeEnum lastHurtingSource;
int spriteDy;
void renderPlayer(sf::RenderTarget* app);
void renderHalo(sf::RenderTarget* app);
divinityStruct divinity;
bool shouldBeSavedFromDivinity;
void fallRock();
void initFallingGrid();
bool fallingGrid[MAP_WIDTH][MAP_HEIGHT];
/*!
* \brief init the current shot type.
*
* Init the current shot type.
* Called when the player get a new shot, or after a switch.
*/
void initShotType();
castSpellStruct activeSpell;
struct protectionStruct
{
bool active;
float value;
float timer;
} protection;
void castSummonsSlimeExplode();
void castFireball();
void castFreeze();
void castEarthquake();
void castProtection();
void castWeb();
void castSummonsFlower();
void castTransmuteFairy();
void castTimeStop();
ItemEntity* itemToBuy;
float getBolPositionY();
void incrementDivInterventions();
int consumable[MAX_SLOT_CONSUMABLES];
void acquireConsumable(enumItemType type);
void reveal();
};
#endif // PLAYERSPRITE_H
diff --git a/src/WitchBlastGame.cpp b/src/WitchBlastGame.cpp
index ef2714e..e5eed1e 100644
--- a/src/WitchBlastGame.cpp
+++ b/src/WitchBlastGame.cpp
@@ -1,7223 +1,7224 @@
/** This file is part of Witch Blast.
*
* Witch Blast is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Witch Blast is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Witch Blast. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WitchBlastGame.h"
#include "sfml_game/SpriteEntity.h"
#include "sfml_game/TileMapEntity.h"
#include "DungeonMap.h"
#include "sfml_game/ImageManager.h"
#include "sfml_game/SoundManager.h"
#include "sfml_game/EntityManager.h"
#include "Constants.h"
#include "RatEntity.h"
#include "BlackRatEntity.h"
#include "GreenRatEntity.h"
#include "KingRatEntity.h"
#include "CyclopsEntity.h"
#include "GiantSpiderEntity.h"
#include "GiantSlimeEntity.h"
#include "ButcherEntity.h"
#include "BatEntity.h"
#include "ImpEntity.h"
#include "SlimeEntity.h"
#include "LargeSlimeEntity.h"
#include "PumpkinEntity.h"
#include "ChestEntity.h"
#include "EvilFlowerEntity.h"
#include "BubbleEntity.h"
#include "ItemEntity.h"
#include "WitchEntity.h"
#include "CauldronEntity.h"
#include "SnakeEntity.h"
#include "GhostEntity.h"
#include "ZombieEntity.h"
#include "ZombieDarkEntity.h"
#include "BogeymanEntity.h"
#include "LittleSpiderEntity.h"
#include "SpiderEggEntity.h"
#include "FranckyEntity.h"
#include "VampireEntity.h"
#include "ObstacleEntity.h"
#include "ArtefactDescriptionEntity.h"
#include "PnjEntity.h"
#include "TextEntity.h"
#include "StandardRoomGenerator.h"
#include "Scoring.h"
#include "MessageGenerator.h"
#include "TextMapper.h"
#include "SlimePetEntity.h"
#include "SausageEntity.h"
#include <iostream>
#include <sstream>
#include <fstream>
#include <ctime>
#include <algorithm>
#define LEVEL_TEST_MODE
#ifdef ONLINE_MODE
#include "OnlineScoring.h"
#endif // ONLINE_MODE
const float PORTRAIT_DIAPLAY_TIME = 5.0f;
const unsigned int ACHIEV_LINES = 3;
const int VolumeModifier = 55;
static std::string intToString(int n)
{
std::ostringstream oss;
oss << n;
return oss.str();
}
static std::string keyToString(sf::Keyboard::Key key)
{
std::string s = "Unknown";
if (key >= sf::Keyboard::A && key <= sf::Keyboard::Z)
{
char c = 'A' + key - sf::Keyboard::A;
std::ostringstream oss;
oss << c;
s = oss.str();
}
else if (key >= sf::Keyboard::Num0 && key <= sf::Keyboard::Num9)
{
char c = '0' + key - sf::Keyboard::Num0;
std::ostringstream oss;
oss << c;
s = oss.str();
}
else if (key >= sf::Keyboard::Numpad0 && key <= sf::Keyboard::Numpad9)
{
char c = '0' + key - sf::Keyboard::Num0;
std::ostringstream oss;
oss << c << " (numpad)";
s = oss.str();
}
else if (key >= sf::Keyboard::F1 && key <= sf::Keyboard::F15)
{
std::ostringstream oss;
oss << "F" << (int)key - (int)sf::Keyboard::F1;
s = oss.str();
}
else if (key == sf::Keyboard::Escape) s = "Escape";
else if (key == sf::Keyboard::LControl) s = "Left Control";
else if (key == sf::Keyboard::LShift) s = "Left Shift";
else if (key == sf::Keyboard::LAlt) s = "Left Alt";
else if (key == sf::Keyboard::LSystem) s = "Left System";
else if (key == sf::Keyboard::RControl) s = "Right Control";
else if (key == sf::Keyboard::RShift) s = "Right Shift";
else if (key == sf::Keyboard::RAlt) s = "Right Alt";
else if (key == sf::Keyboard::RSystem) s = "Right System";
else if (key == sf::Keyboard::Space) s = "Space";
else if (key == sf::Keyboard::Tab) s = "Tab";
else if (key == sf::Keyboard::Left) s = "Left arrow";
else if (key == sf::Keyboard::Right) s = "Right arrow";
else if (key == sf::Keyboard::Up) s = "Up arrow";
else if (key == sf::Keyboard::Down) s = "Down arrow";
else if (key == sf::Keyboard::LBracket) s = "[";
else if (key == sf::Keyboard::RBracket) s = "]";
else if (key == sf::Keyboard::SemiColon) s = ";";
else if (key == sf::Keyboard::Comma) s = ",";
else if (key == sf::Keyboard::Period) s = ".";
else if (key == sf::Keyboard::Quote) s = "Quote";
else if (key == sf::Keyboard::Slash) s = "/";
else if (key == sf::Keyboard::BackSlash) s = "\\";
else if (key == sf::Keyboard::Tilde) s = "~";
else if (key == sf::Keyboard::Equal) s = "=";
else if (key == sf::Keyboard::Dash) s = "_";
else if (key == sf::Keyboard::Return) s = "Return";
else if (key == sf::Keyboard::BackSpace) s = "BackSpace";
else if (key == sf::Keyboard::PageUp) s = "Page Up";
else if (key == sf::Keyboard::PageDown) s = "Page Down";
else if (key == sf::Keyboard::End) s = "End";
else if (key == sf::Keyboard::Home) s = "Home";
else if (key == sf::Keyboard::Insert) s = "Insert";
else if (key == sf::Keyboard::Delete) s = "Delete";
else if (key == sf::Keyboard::Add) s = "+";
else if (key == sf::Keyboard::Subtract) s = "-";
else if (key == sf::Keyboard::Multiply) s = "*";
else if (key == sf::Keyboard::Divide) s = "/";
else if (key == sf::Keyboard::Pause) s = "Pause";
else if (key == sf::Keyboard::KeyCount) s = "Key Count";
return s;
}
std::map<EnumWorldEvents, EnumMessages> eventToMessage =
{
{ EventMeetRatsOrBats, MsgInfoRatsBats },
{ EventMeetSnakes, MsgInfoSnakes },
{ EventMeetWitches, MsgInfoWitches },
{ EventGetCoin, MsgInfoGold },
{ EventGetFamiliar, MsgInfoFamiliar },
{ EventBeingHurted, MsgTutoHeal },
{ EventFindShop, MsgTutoShops },
{ EventFindBossDoor, MsgTutoBossDoor },
{ EventFindChallengeDoor, MsgTutoChallengeDoor },
{ EventFindTemple, MsgTutoTemple },
{ EventGetItem, MsgTutoItems },
{ EventGetSpecialShot, MsgTutoShots },
{ EventGetSpell, MsgTutoSpell },
{ EventAchievement, MsgTutoAchievements },
{ EventConsumable, MsgTutoConsumables },
{ EventPotion, MsgTutoPotions },
};
// author: AFS
// source: https://github.com/LaurentGomila/SFML/wiki/Source:-Letterbox-effect-using-a-view
static sf::View getLetterboxView(sf::View view, int windowWidth, int windowHeight)
{
// Compares the aspect ratio of the window to the aspect ratio of the view,
// and sets the view's viewport accordingly in order to archieve a letterbox effect.
// A new view (with a new viewport set) is returned.
float windowRatio = windowWidth / (float) windowHeight;
float viewRatio = view.getSize().x / (float) view.getSize().y;
float sizeX = 1;
float sizeY = 1;
float posX = 0;
float posY = 0;
bool horizontalSpacing = true;
if (windowRatio < viewRatio)
horizontalSpacing = false;
// If horizontalSpacing is true, the black bars will appear on the left and right side.
// Otherwise, the black bars will appear on the top and bottom.
if (horizontalSpacing)
{
sizeX = viewRatio / windowRatio;
posX = (1 - sizeX) / 2.0;
}
else
{
sizeY = windowRatio / viewRatio;
posY = (1 - sizeY) / 2.0;
}
view.setViewport( sf::FloatRect(posX, posY, sizeX, sizeY) );
return view;
}
static sf::View getFullScreenLetterboxView(sf::View view, int clientWidth, int clientHeight)
{
sf::View returnView(sf::FloatRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
float clientRatio = clientWidth / (float) clientHeight;
float viewRatio = view.getSize().x / (float) view.getSize().y;
float sizeX = 1;
float sizeY = 1;
float posX = 0;
float posY = 0;
bool horizontalSpacing = true;
if (clientRatio > viewRatio)
horizontalSpacing = false;
// If horizontalSpacing is true, the black bars will appear on the left and right side.
// Otherwise, the black bars will appear on the top and bottom.
if (horizontalSpacing)
{
sizeX = clientRatio / viewRatio;
posX = (1 - sizeX) / 2.0;
}
else
{
sizeY = viewRatio / clientRatio;
posY = (1 - sizeY) / 2.0;
}
returnView.setViewport( sf::FloatRect(posX, posY, sizeX, sizeY) );
return returnView;
}
namespace
{
WitchBlastGame* gameptr;
}
WitchBlastGame::WitchBlastGame()
{
gameptr = this;
gameFromSaveFile = false;
configureFromFile();
if (parameters.vsync == false)
{
//app->setVerticalSyncEnabled(false);
app->setFramerateLimit(60);
}
// Fullscreen ?
if (parameters.fullscreen)
{
create(SCREEN_WIDTH, SCREEN_HEIGHT, APP_NAME + " V" + APP_VERSION, true, parameters.vsync);
sf::View view = app->getDefaultView();
view = getFullScreenLetterboxView( view, SCREEN_WIDTH, SCREEN_HEIGHT );
app->setView(view);
}
else
{
create(SCREEN_WIDTH, SCREEN_HEIGHT, APP_NAME + " V" + APP_VERSION, false, parameters.vsync);
}
// init current music
currentStandardMusic = 0;
// loading resources
const char *const images[] =
{
"media/player_0.png", "media/player_1.png",
"media/bolt.png", "media/tiles.png",
"media/rat.png", "media/minimap.png",
"media/map_background.png",
"media/items.png", "media/items_equip.png",
"media/items.png", "media/items_equip.png",
"media/chest.png", "media/bat.png",
"media/evil_flower.png", "media/slime.png",
"media/imp.png", "media/spider_egg.png",
"media/spider_web.png", "media/little_spider.png",
"media/bubble.png", "media/eyeball.png",
"media/witch.png",
"media/cauldron.png", "media/snake.png",
"media/pumpkin.png", "media/ghost.png",
"media/zombie.png", "media/bogeyman.png",
"media/sausage.png",
"media/butcher.png", "media/giant_slime.png",
"media/king_rat.png", "media/cyclops.png",
"media/giant_spider.png", "media/francky.png",
"media/vampire.png", "media/vampire_bat.png",
"media/vampire_part.png",
"media/blood.png",
"media/corpses.png", "media/corpses_big.png",
"media/star.png", "media/star2.png",
"media/hurt_impact.png",
"media/interface.png", "media/hud_shots.png",
"media/explosion.png", "media/keys_qwer.png",
"media/keys_azer.png", "media/message_icons.png",
"media/night.png", "media/title.png",
"media/overlay_00.png", "media/light_cone.png",
"media/divinity.png",
"media/pnj.png", "media/fairy.png",
"media/key_area.png",
"media/ui_life.png", "media/ui_mana.png",
"media/ui_spells.png", "media/ui_message.png",
"media/ui_top_layer.png", "media/ui_achiev.png",
"media/fog.png", "media/title_animation.png",
"media/splatter.png", "media/witch_intro.png",
"media/item_description.png", "media/death_certificate.png",
"media/achievements.png", "media/boss_pictures.png",
"media/portrait_part.png", "media/dungeon_random.png",
"media/dungeon_objects.png", "media/shadows_standard.png",
"media/shadows_corners.png", "media/shadows_medium.png",
"media/shadows_small.png", "media/doors.png",
"media/destroyable_objects.png", "media/hall_of_fame.png",
};
for (const char *const filename : images)
ImageManager::getInstance().addImage(filename);
const char *const sounds[] =
{
"media/sound/blast00.ogg", "media/sound/blast01.ogg",
"media/sound/blast_elec.ogg", "media/sound/blast_fire.ogg",
"media/sound/blast_ice.ogg", "media/sound/blast_illusion.ogg",
"media/sound/blast_poison.ogg", "media/sound/blast_stone.ogg",
"media/sound/door_closing.ogg", "media/sound/door_opening.ogg",
"media/sound/chest_opening.ogg", "media/sound/impact.ogg",
"media/sound/bonus.ogg", "media/sound/drink.ogg",
"media/sound/eat.ogg", "media/sound/player_hit.ogg",
"media/sound/player_die.ogg", "media/sound/ennemy_dying.ogg",
"media/sound/coin.ogg", "media/sound/pay.ogg",
"media/sound/wall_impact.ogg", "media/sound/big_wall_impact.ogg",
"media/sound/king_rat_cry_1.ogg", "media/sound/king_rat_cry_2.ogg",
"media/sound/king_rat_die.ogg", "media/sound/slime_jump.ogg",
"media/sound/slime_impact.ogg", "media/sound/slime_impact_weak.ogg",
"media/sound/slime_impact_boss.ogg",
"media/sound/slime_smash.ogg", "media/sound/ice_charge.ogg",
"media/sound/electric.ogg", "media/sound/select.ogg",
"media/sound/heart.ogg", "media/sound/rat_die.ogg",
"media/sound/bat_die.ogg", "media/sound/imp_hurt.ogg",
"media/sound/imp_die.ogg", "media/sound/rock_impact.ogg",
"media/sound/rock_impact_medium.ogg", "media/sound/rock_impact_heavy.ogg",
"media/sound/throw.ogg", "media/sound/cyclop00.ogg",
"media/sound/cyclop_die.ogg", "media/sound/cyclops_impact.ogg",
"media/sound/butcher_00.ogg", "media/sound/butcher_01.ogg",
"media/sound/butcher_hurt.ogg", "media/sound/butcher_die.ogg",
"media/sound/vib.ogg",
"media/sound/boom_00.ogg", "media/sound/clang_00.ogg",
"media/sound/bubble_00.ogg", "media/sound/bubble_01.ogg",
"media/sound/trap.ogg", "media/sound/egg_smash_00.ogg",
"media/sound/egg_smash_01.ogg", "media/sound/spider_walking.ogg",
"media/sound/spider_web.ogg", "media/sound/spider_hurt.ogg",
"media/sound/spider_die.ogg", "media/sound/little_spider_die.ogg",
"media/sound/witch_00.ogg", "media/sound/witch_01.ogg",
"media/sound/witch_die_00.ogg", "media/sound/witch_die_01.ogg",
"media/sound/witch_02.ogg", "media/sound/invoke.ogg",
"media/sound/cauldron.ogg", "media/sound/cauldron_die.ogg",
"media/sound/snake_die.ogg", "media/sound/pumpkin_00.ogg",
"media/sound/pumpkin_01.ogg", "media/sound/pumpkin_die.ogg",
"media/sound/critical.ogg",
"media/sound/gong.ogg", "media/sound/teleport.ogg",
"media/sound/spell_charge.ogg", "media/sound/fireball.ogg",
"media/sound/message.ogg", "media/sound/earthquake.ogg",
"media/sound/spell_freeze.ogg", "media/sound/spell_shield.ogg",
"media/sound/heavy_step_00.ogg", "media/sound/heavy_step_01.ogg",
"media/sound/night.ogg", "media/sound/grumble.ogg",
"media/sound/zombie_00.ogg", "media/sound/zombie_01.ogg",
"media/sound/zombie_attack.ogg", "media/sound/zombie_die.ogg",
"media/sound/ghost.ogg", "media/sound/ghost_die.ogg",
"media/sound/electricity.ogg",
"media/sound/electric_blast.ogg", "media/sound/francky_00.ogg",
"media/sound/francky_01.ogg", "media/sound/francky_02.ogg",
"media/sound/francky_die.ogg", "media/sound/om.ogg",
"media/sound/glass.ogg", "media/sound/hiccup.ogg",
"media/sound/splatch.ogg", "media/sound/intro_witch.ogg",
"media/sound/force_field.ogg", "media/sound/door_opening_boss.ogg",
"media/sound/achievement.ogg",
"media/sound/vampire_flying.ogg", "media/sound/vampire_flap.ogg",
"media/sound/vampire_sonic.ogg", "media/sound/vampire_laughing.ogg",
"media/sound/vampire_transform_bolt.ogg", "media/sound/vampire_transform_bat.ogg",
"media/sound/vampire_hypnosis.ogg", "media/sound/vampire_cry.ogg",
"media/sound/vampire_dying.ogg", "media/sound/ice_block.ogg",
"media/sound/bogeyman_die.ogg", "media/sound/bogeyman_attack.ogg",
"media/sound/bogeyman_vortex_00.ogg", "media/sound/bogeyman_vortex_01.ogg",
"media/sound/barrel_hit.ogg", "media/sound/barrel_smash.ogg",
"media/sound/secret.ogg", "media/sound/scroll.ogg",
"media/sound/tic_tac.ogg",
};
// AA in fullscreen
if (parameters.fullscreen) enableAA(true);
// game main client position in the UI
xOffset = OFFSET_X;
yOffset = OFFSET_Y;
SoundManager::getInstance().setVolume(parameters.soundVolume);
for (const char *const filename : sounds)
{
SoundManager::getInstance().addSound(filename);
}
if (font.loadFromFile("media/DejaVuSans-Bold.ttf"))
{
myText.setFont(font);
}
miniMap = NULL;
currentMap = NULL;
currentFloor = NULL;
lastScore.score = 0;
lastScore.name = "";
lastScore.level = 0;
int i;
for (i = 0; i < NB_X_GAME; i++) xGame[i].active = false;
for (i = 0; i < NUMBER_EQUIP_ITEMS; i++) equipNudeToDisplay[i] = false;
for (i = 0; i < NB_MESSAGES; i++) gameMessagesToSkip[i] = false;
for (i = 0; i < NB_ACHIEVEMENTS; i++) achievementState[i] = AchievementUndone;
for (i = 0; i < NB_ENEMY; i++) globalData.killedMonster[i] = 0;
saveInFight.monsters.clear();
showLogical = false;
showGameTime = false;
uiSprites.shotsSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_HUD_SHOTS));
uiSprites.topLayer.setTexture(*ImageManager::getInstance().getImage(IMAGE_UI_TOP_LAYER));
uiSprites.topLayer.setPosition(0, 602);
uiSprites.msgBoxSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_UI_MESSAGE));
uiSprites.iconSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_MESSAGE_ICONS));
uiSprites.iconSprite.setPosition(12, 614);
uiSprites.mapBgSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_MAP_BACKGROUND));
uiSprites.mapBgSprite.setPosition(342, 23);
introScreenSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_INTRO));
titleSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_TITLE));
titleSprite.setOrigin(titleSprite.getTextureRect().width / 2, titleSprite.getTextureRect().height / 2);
scoreState = ScoreOK;
loopCounter = 0;
loadGameData();
loadHiScores();
receiveScoreFromServer();
srand(time(NULL));
fairySpriteOffsetY = 0;
if (isAdvanced()) fairySpriteOffsetY = 72 + 72 * (rand() % 4);
}
void WitchBlastGame::enableAA(bool enable)
{
for (int i = 0; i < NB_IMAGES; i++)
{
if (i != IMAGE_TILES && i != IMAGE_DUNGEON_OBJECTS
&& i != IMAGE_TILES_SHADOW && i != IMAGE_TILES_SHADOW_CORNER && i != IMAGE_TILES_SHADOW_MEDIUM
&& i != IMAGE_MINIMAP
&& i != IMAGE_DOORS
&& i != IMAGE_FOG
&& i != IMAGE_ITEMS_PRES && i != IMAGE_ITEMS_EQUIP_PRES && i != IMAGE_CORPSES
&& i != IMAGE_CORPSES_BIG)
ImageManager::getInstance().getImage(i)->setSmooth(enable);
}
}
WitchBlastGame::~WitchBlastGame()
{
// cleaning all entities
EntityManager::getInstance().clean();
// cleaning data
if (miniMap != NULL) delete (miniMap);
if (currentFloor != NULL) delete (currentFloor);
if (sendScoreThread.joinable()) sendScoreThread.join();
if (receiveScoreThread.joinable()) receiveScoreThread.join();
}
DungeonMap* WitchBlastGame::getCurrentMap()
{
return currentMap;
}
GameFloor* WitchBlastGame::getCurrentFloor()
{
return currentFloor;
}
int WitchBlastGame::getFloorX()
{
return floorX;
}
int WitchBlastGame::getFloorY()
{
return floorY;
}
DungeonMapEntity* WitchBlastGame::getCurrentMapEntity()
{
return dungeonEntity;
}
PlayerEntity* WitchBlastGame::getPlayer()
{
return player;
}
Vector2D WitchBlastGame::getPlayerPosition()
{
return Vector2D(player->getX(), player->getY());
}
int WitchBlastGame::getLevel()
{
return level;
}
int WitchBlastGame::getChallengeLevel()
{
return challengeLevel;
}
bool WitchBlastGame::getShowLogical()
{
return showLogical;
}
float WitchBlastGame::getDeltaTime()
{
return deltaTime;
}
float WitchBlastGame::getGameTime()
{
return gameTime;
}
void WitchBlastGame::onUpdate()
{
if (gameState == gameStatePlaying)
{
if (isPlayerAlive) player->setItemToBuy(NULL);
// time stop
if (player->isSpecialStateActive(SpecialStateTime))
{
if (loopCounter == 0)
EntityManager::getInstance().animate(deltaTime);
else
player->animate(deltaTime);
loopCounter++;
if (loopCounter > 3) loopCounter = 0;
SoundManager::getInstance().playSound(SOUND_CLOCK, false);
}
else
{
EntityManager::getInstance().animate(deltaTime);
if (isPressing(KeyTimeControl, false))
{
EntityManager::getInstance().animate(deltaTime);
SoundManager::getInstance().playSound(SOUND_VIB, false);
}
}
if (isPlayerAlive) gameTime += deltaTime;
for (int i = 0; i < NB_X_GAME; i++)
{
if (xGame[i].active)
{
xGame[i].timer -= deltaTime;
if (xGame[i].timer <= 0.0f)
{
xGame[i].active = false;
if (i == (int)xGameTypeFade && xGame[i].param == X_GAME_FADE_OUT)
{
if (player->getPlayerStatus() == PlayerEntity::playerStatusGoingNext)
{
level++;
startNewLevel();
}
else
startNewGame(false, 1);
}
}
}
}
if (isPlayerAlive)
{
if (player->getHp() <= 0)
{
isPlayerAlive = false;
playMusic(MusicEnding);
}
}
}
else if (gameState == gameStatePlayingDisplayBoss)
{
bossDisplayTimer += deltaTime;
if (bossDisplayTimer >= PORTRAIT_DIAPLAY_TIME) gameState = gameStatePlaying;
}
}
void WitchBlastGame::startNewGame(bool fromSaveFile, int startingLevel)
{
gameState = gameStateInit;
level = 1;
challengeLevel = 1;
gameTime = 0.0f;
initEvents();
scoreSaveFile = "";
interaction.active = false;
// cleaning all entities
EntityManager::getInstance().clean();
SoundManager::getInstance().stopSound(SOUND_NIGHT);
// cleaning the message queue
std::queue<messageStruct> empty;
std::swap( messagesQueue, empty );
// cleaning the achievements queue
std::queue<achievementStruct> empty2;
std::swap( achievementsQueue, empty2 );
// cleaning data
if (miniMap != NULL) delete (miniMap);
if (currentFloor != NULL) delete (currentFloor);
miniMap = NULL;
currentFloor = NULL;
// init in game menu
buildInGameMenu();
dungeonEntity = new DungeonMapEntity();
// the interface
uiSprites.gui.setTexture(*ImageManager::getInstance().getImage(IMAGE_INTERFACE));
// key symbol on the interface
uiSprites.keySprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEMS_EQUIP));
uiSprites.keySprite.setTextureRect(sf::IntRect(ITEM_WIDTH * EQUIP_BOSS_KEY, 0, ITEM_WIDTH, ITEM_HEIGHT));
uiSprites.keySprite.setPosition(737, 612);
miniMap = new GameMap(FLOOR_WIDTH, FLOOR_HEIGHT);
// minimap on the interface
miniMapEntity = new TileMapEntity(ImageManager::getInstance().getImage(IMAGE_MINIMAP), miniMap, 19, 15, 10);
miniMapEntity->setTileBox(20, 16);
miniMapEntity->setX(800);
miniMapEntity->setY(645);
miniMapEntity->setZ(10001.0f);
// doors
doorEntity[0] = new DoorEntity(8);
doorEntity[1] = new DoorEntity(4);
doorEntity[2] = new DoorEntity(2);
doorEntity[3] = new DoorEntity(6);
saveInFight.isFight = false;
if (fromSaveFile)
{
if (!loadGame())
{
fromSaveFile = false;
}
else
{
gameFromSaveFile = true;
playLevel(saveInFight.isFight);
}
}
if (!fromSaveFile)
{
gameFromSaveFile = false;
// the player
player = new PlayerEntity((TILE_WIDTH * MAP_WIDTH * 0.5f),
(TILE_HEIGHT * MAP_HEIGHT * 0.5f));
resetKilledEnemies();
randomizePotionMap();
if (startingLevel > 1)
{
for (int i = 1; i < startingLevel; i++)
{
level = i;
if (level == 3)
{
player->acquireItem(getItemSpell());
player->acquireItemAfterStance();
}
player->setHpMax(player->getHpMax() + 2 + rand() % 4);
item_equip_enum item = getRandomEquipItem(false, false);
player->acquireItem((enumItemType)(item + FirstEquipItem));
player->acquireItemAfterStance();
item = getRandomEquipItem(true, true);
player->acquireItem((enumItemType)(item + FirstEquipItem));
player->acquireItemAfterStance();
if (i % 2 == 0)
{
item = getRandomEquipItem(false, false);
player->acquireItem((enumItemType)(item + FirstEquipItem));
player->acquireItemAfterStance();
}
}
level++;
player->setHp(player->getHpMax());
player->setGold(8 + rand() % 45);
if (startingLevel > 2)
{
player->loadDivinity(rand() % NB_DIVINITY, (startingLevel - 2) * 200, 1, 0);
}
}
startNewLevel();
}
}
void WitchBlastGame::startNewLevel()
{
// reset floor items
player->resetFloorItem();
// reset present items
resetPresentItems();
bool needShop = false;
// create the new level
if (currentFloor != NULL)
{
if (level > 1)
{
if (!currentFloor->hasRoomOfType(roomTypeMerchant)) needShop = true;
}
delete currentFloor;
}
currentFloor = new GameFloor(level);
if (needShop) currentFloor->setForceShop();
currentFloor->createFloor();
// center it
floorX = FLOOR_WIDTH / 2;
floorY = FLOOR_HEIGHT / 2;
// move the player
if (level == 1)
player->moveTo((TILE_WIDTH * MAP_WIDTH * 0.5f),
(TILE_HEIGHT * MAP_HEIGHT * 0.5f));
else
player->moveTo((TILE_WIDTH * MAP_WIDTH * 0.5f),
(TILE_HEIGHT * MAP_HEIGHT - 2 * TILE_HEIGHT));
// the boss room is closed
bossRoomOpened = false;
if (level <= 7) testAndAddMessageToQueue((EnumMessages)(MsgInfoLevel1 + level - 1));
if (level == 1)
{
testAndAddMessageToQueue(MsgTutoBasics);
testAndAddMessageToQueue(MsgTutoTips);
}
playLevel(false);
}
void WitchBlastGame::playLevel(bool isFight)
{
isPlayerAlive = true;
if (!isFight)
{
player->setVelocity(Vector2D(0.0f, 0.0f));
player->setPlayerStatus(PlayerEntity::playerStatusPlaying);
}
// first map is open
roomClosed = false;
// generate the map
refreshMap();
// items from save
currentMap->restoreMapObjects();
if (isFight)
{
checkEntering();
saveMapItems();
}
// populate with monsters
if (isFight)
{
auto monsters_save = saveInFight.monsters;
saveInFight.monsters.clear();
for (auto monster: monsters_save)
addMonster(monster.id, monster.x, monster.y);
if (currentMap->getRoomType() == roomTypeBoss) playMusic(MusicBoss);
else if (currentMap->getRoomType() == roomTypeChallenge) playMusic(MusicChallenge);
else playMusic(MusicDungeon);
}
else
playMusic(MusicDungeon);
// game time counter an state
lastTime = getAbsolutTime();
gameState = gameStatePlaying;
// fade in
xGame[xGameTypeFade].active = true;
xGame[xGameTypeFade].param = X_GAME_FADE_IN;
xGame[xGameTypeFade].timer = FADE_IN_DELAY;
float x0 = MAP_WIDTH * 0.5f * TILE_WIDTH;
float y0 = MAP_HEIGHT * 0.5f * TILE_HEIGHT + 40.0f;
std::ostringstream oss;
oss << tools::getLabel("level") << " " << level;
TextEntity* text = new TextEntity(oss.str(), 30, x0, y0);
text->setAlignment(ALIGN_CENTER);
text->setLifetime(2.5f);
text->setWeight(-36.0f);
text->setZ(1000);
text->setColor(TextEntity::COLOR_FADING_WHITE);
/*new ItemEntity(ItemScrollRevelation, 100, 100);
new ItemEntity(ItemScrollRevelation, 150, 100);
new ItemEntity(ItemPotion02, 200, 100);
new ItemEntity(ItemPotion01, 250, 100);
new ItemEntity(ItemBag, 450, 100);
new ItemEntity(ItemFloorMap, 500, 100);*/
}
void WitchBlastGame::prepareIntro()
{
EntityManager::getInstance().clean();
introSprites[0] = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_FOG));
introSprites[0]->setX(SCREEN_WIDTH / 2);
introSprites[0]->setY(SCREEN_HEIGHT - 202);
introSprites[1] = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_FOG));
introSprites[1]->setX(SCREEN_WIDTH / 2 + 970);
introSprites[1]->setY(SCREEN_HEIGHT - 202);
gameState = gameStateIntro;
gameTime = 0.0f;
introState = 0;
introSoundState = 0;
SoundManager::getInstance().playSound(SOUND_NIGHT);
}
void WitchBlastGame::updateIntro()
{
gameTime += deltaTime;
bool toMenu = false;
for (int i = 0; i < 2; i++)
{
introSprites[i]->setX(introSprites[i]->getX() - deltaTime * 35);
if (introSprites[i]->getX() < - SCREEN_WIDTH / 2) introSprites[i]->setX(introSprites[i]->getX() + 2 * SCREEN_WIDTH);
}
if (gameTime > 2.0f && introSoundState == 0)
{
SoundManager::getInstance().playSound(SOUND_INTRO_WITCH);
introSoundState++;
}
else if (gameTime > 7.0f && introSoundState == 1)
{
playMusic(MusicIntro);
introSoundState++;
}
if (introState == 0 && gameTime > 2.5f)
{
introState = 1;
introSprites[2] = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_TITLE_ANIM),
SCREEN_WIDTH / 2,
SCREEN_HEIGHT / 2,
310, 278, 3);
introSprites[2]->setZ(50);
}
else if (introState == 1)
{
int frame = (gameTime - 2.5f) * 8.0f;
if (frame > 16)
{
frame = 16;
introState = 2;
introSprites[3] = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_WITCH_INTRO));
introSprites[3]->setX(368 + 1000);
introSprites[3]->setY(424 - 480);
introSprites[3]->setZ(40);
EntityManager::getInstance().sortByZ();
}
introSprites[2]->setFrame(frame);
}
else if (introState == 2)
{
float xSprite = introSprites[3]->getX() - deltaTime * 800;
float ySprite = introSprites[3]->getY() + deltaTime * 400;
if (xSprite < 368)
{
introState = 3;
introSprites[3]->setDying(true);
EntityManager::getInstance().animate(deltaTime);
xSprite = 368;
ySprite = 424;
introSprites[4] = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_SPLATTER));
introSprites[4]->setX(368);
introSprites[4]->setY(424);
introSprites[4]->setZ(45);
introSprites[4]->setScale(0.5f, 0.5f);
EntityManager::getInstance().sortByZ();
SoundManager::getInstance().stopSound(SOUND_INTRO_WITCH);
SoundManager::getInstance().playSound(SOUND_SPLATCH);
}
else
{
introSprites[3]->setX(xSprite);
introSprites[3]->setY(ySprite);
introSprites[3]->setAngle(gameTime * 500);
}
}
else if (introState == 3)
{
float scale = introSprites[4]->getScaleX();
scale += deltaTime * 5.0f;
if (scale > 1.0f) scale = 1.0f;
introSprites[4]->setScale(scale, scale);
if (gameTime > 8.0f)
{
introState = 4;
introSprites[2]->setDying(true);
introSprites[4]->setDying(true);
EntityManager::getInstance().animate(deltaTime);
toMenu = true;
}
}
sf::Event event;
bool stopDemo = false;
while (app->pollEvent(event))
{
// Close window : exit
if (event.type == sf::Event::Closed)
{
//saveGameData();
app->close();
}
if (event.type == sf::Event::Resized)
{
enableAA(true);
sf::View view = app->getDefaultView();
view = getLetterboxView( view, event.size.width, event.size.height );
app->setView(view);
}
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::Escape) stopDemo = true;
}
}
if (isPressing(KeyFireDown, true)) stopDemo = true;
if (stopDemo)
{
if (introState < 4)
{
if (introState > 0) introSprites[2]->setDying(true);
if (introState == 2) introSprites[3]->setDying(true);
if (introState > 2) introSprites[4]->setDying(true);
EntityManager::getInstance().animate(deltaTime);
if (introState < 3)
{
SoundManager::getInstance().stopSound(SOUND_INTRO_WITCH);
SoundManager::getInstance().playSound(SOUND_SPLATCH);
}
}
toMenu = true;
}
if (toMenu)
{
if (introSoundState <= 1) playMusic(MusicIntro);
switchToMenu();
}
}
void WitchBlastGame::renderIntro()
{
app->draw(introScreenSprite);
titleSprite.setPosition(SCREEN_WIDTH / 2 - 15, 371);
if (introState == 4) app->draw(titleSprite);
EntityManager::getInstance().render(app);
}
void WitchBlastGame::updateRunningGame()
{
bool backToMenu = false;
bool escape = false;
// Process events
sf::Event event;
while (app->pollEvent(event))
{
// Close window : exit
if (event.type == sf::Event::Closed)
{
if (gameState == gameStatePlaying && !player->isDead()) saveGame();
saveGameData();
app->close();
}
if (event.type == sf::Event::Resized)
{
enableAA(true);
sf::View view = app->getDefaultView();
view = getLetterboxView( view, event.size.width, event.size.height );
app->setView(view);
}
if (event.type == sf::Event::MouseWheelMoved)
{
if (gameState == gameStatePlaying) player->selectNextShotType();
}
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::Escape)
{
escape = true;
}
if (event.key.code == sf::Keyboard::Return && gameState == gameStatePlaying)
{
if (!achievementsQueue.empty())
{
if (achievementsQueue.front().timer > 1.0f)
achievementsQueue.front().timer = 1.0f;
}
else if (!messagesQueue.empty())
{
if (messagesQueue.front().timer > 0.5f)
messagesQueue.front().timer = 0.5f;
}
}
if (event.key.code == sf::Keyboard::X)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LShift)) startNewGame(false, 1);
}
if (event.key.code >= sf::Keyboard::Num1 && event.key.code <= sf::Keyboard::Num8)
{
#ifdef LEVEL_TEST_MODE
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt) && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
{
startNewGame(false, event.key.code - sf::Keyboard::Num1 + 1);
}
else
#endif
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LShift))
{
player->dropConsumables(event.key.code - sf::Keyboard::Num1);
}
else
{
player->tryToConsume(event.key.code - sf::Keyboard::Num1);
}
}
if (event.key.code == sf::Keyboard::F1)
{
if (!isPlayerAlive && player->getDeathAge() > 3.5f)
{
if (scoreSaveFile.compare("") == 0) saveDeathScreen();
}
else
{
saveScreen();
}
}
if (event.key.code == sf::Keyboard::F2)
{
showLogical = !showLogical;
}
if (event.key.code == sf::Keyboard::F3)
{
showGameTime = !showGameTime;
}
// DEBUG
#ifdef TEST_MODE
/*if (event.key.code == sf::Keyboard::Delete)
{
StructHurt hurt;
hurt.critical = false;
hurt.damage = 1;
hurt.enemyType = EnemyTypeGhost; //EnemyTypeNone;
hurt.goThrough = false;
hurt.hurtingType = ShotTypeStandard;
hurt.level = 0;
hurt.sourceType = SourceTypeMelee;
player->hurt(hurt);
}*/
if (event.key.code == sf::Keyboard::F5)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
{
new BubbleEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 + 70,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2, BubbleTriple, 0);
new BubbleEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 - 70,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2, BubbleIce, 0);
}
else
{
initMonsterArray();
findPlaceMonsters(EnemyTypeRat, 1);
findPlaceMonsters(EnemyTypeRatBlack, 1);
findPlaceMonsters(EnemyTypeRatGreen, 1);
findPlaceMonsters(EnemyTypeRatHelmet, 1);
findPlaceMonsters(EnemyTypeRatBlackHelmet, 1);
}
}
if (event.key.code == sf::Keyboard::F6)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
{
new ButcherEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else
{
initMonsterArray();
findPlaceMonsters(EnemyTypeBat, 1);
findPlaceMonsters(EnemyTypeBatSkeleton, 2);
findPlaceMonsters(EnemyTypeImpBlue, 1);
findPlaceMonsters(EnemyTypeImpRed, 1);
}
}
if (event.key.code == sf::Keyboard::F7)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
{
new GiantSlimeEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else
{
initMonsterArray();
findPlaceMonsters(EnemyTypeEvilFlower, 1);
findPlaceMonsters(EnemyTypeEvilFlowerIce, 1);
findPlaceMonsters(EnemyTypeEvilFlowerFire, 1);
findPlaceMonsters(EnemyTypePumpkin, 1);
}
}
if (event.key.code == sf::Keyboard::F8)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
{
new CyclopsEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else
{
initMonsterArray();
findPlaceMonsters(EnemyTypeSlime, 1);
findPlaceMonsters(EnemyTypeSlimeBlue, 1);
findPlaceMonsters(EnemyTypeSlimeRed, 1);
findPlaceMonsters(EnemyTypeSlimeViolet, 1);
}
}
if (event.key.code == sf::Keyboard::F9)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
{
new KingRatEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else
{
initMonsterArray();
findPlaceMonsters(EnemyTypeSnake, 2);
findPlaceMonsters(EnemyTypeSnakeBlood, 2);
}
}
if (event.key.code == sf::Keyboard::F10)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
{
new GiantSpiderEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else
{
initMonsterArray();
findPlaceMonsters(EnemyTypeWitch, 1);
findPlaceMonsters(EnemyTypeWitchRed, 1);
findPlaceMonsters(EnemyTypeCauldron, 1);
findPlaceMonsters(EnemyTypeCauldronElemental, 1);
}
}
if (event.key.code == sf::Keyboard::F11)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
{
new FranckyEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else
{
initMonsterArray();
findPlaceMonsters(EnemyTypeSpiderEgg_invocated, 2);
findPlaceMonsters(EnemyTypeSpiderLittle, 2);
findPlaceMonsters(EnemyTypeSpiderTarantula, 2);
}
}
if (event.key.code == sf::Keyboard::F12)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
{
new VampireEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else
{
initMonsterArray();
findPlaceMonsters(EnemyTypeZombie, 2);
findPlaceMonsters(EnemyTypeZombieDark, 2);
findPlaceMonsters(EnemyTypeGhost, 2);
findPlaceMonsters(EnemyTypeBogeyman, 2);
}
}
if (event.key.code == sf::Keyboard::F4)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
for (int i = 0; i < NUMBER_ITEMS - NUMBER_EQUIP_ITEMS; i++)
new ItemEntity((enumItemType)i, 100 + (i % 14) * 58, 100 + (i / 14) * 60);
else
for (int i = NUMBER_ITEMS - NUMBER_EQUIP_ITEMS; i < NUMBER_ITEMS; i++)
new ItemEntity((enumItemType)i, 100 + (i % 14) * 58, 100 + (i / 14) * 60);
}
#endif // TEST_MODE
}
}
if (event.type == sf::Event::LostFocus && !player->isDead())
gameState = gameStatePlayingPause;
// POST EVENT
if (escape)
{
if (player->isDead()) backToMenu = true;
else if (gameState == gameStatePlaying) gameState = gameStatePlayingPause;
else if (gameState == gameStatePlayingPause) gameState = gameStatePlaying;
else if (gameState == gameStatePlayingDisplayBoss) gameState = gameStatePlaying;
}
if (player->isDead() && !xGame[xGameTypeFade].active && isPressing(KeyFireDown, true))
{
if (player->getDeathAge() < DEATH_CERTIFICATE_DELAY) player->setDeathAge(DEATH_CERTIFICATE_DELAY);
else backToMenu = true;
}
else if (gameState == gameStatePlayingPause)
{
if (isPressing(KeyDown, true))
{
menuInGame.index++;
if (menuInGame.index == menuInGame.items.size()) menuInGame.index = 0;
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
else if (isPressing(KeyUp, true))
{
if (menuInGame.index == 0) menuInGame.index = menuInGame.items.size() - 1;
else menuInGame.index--;
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
else if (isPressing(KeyFireDown, true))
{
switch (menuInGame.items[menuInGame.index].id)
{
case MenuStartNew:
case MenuStartOld:
case MenuKeys:
case MenuJoystick:
case MenuConfig:
case MenuTutoReset:
case MenuConfigBack:
case MenuLanguage:
case MenuCredits:
case MenuHiScores:
case MenuPlayerName:
case MenuVolumeMusic:
case MenuVolumeSound:
case MenuAchievements:
std::cout << "[ERROR] Bad Menu ID\n";
break;
case MenuExit:
backToMenu = true;
remove(SAVE_FILE.c_str());
break;
case MenuContinue:
gameState = gameStatePlaying;
break;
case MenuSaveAndQuit:
saveGame();
backToMenu = true;
break;
}
}
}
else if (gameState == gameStatePlaying)
{
if (player->canMove()) player->setVelocity(Vector2D(0.0f, 0.0f));
if (isPressing(KeyLeft, false))
{
if (isPressing(KeyUp, false))
player->move(7);
else if (isPressing(KeyDown, false))
player->move(1);
else
player->move(4);
}
else if (isPressing(KeyRight, false))
{
if (isPressing(KeyUp, false))
player->move(9);
else if (isPressing(KeyDown, false))
player->move(3);
else
player->move(6);
}
else if (isPressing(KeyUp, false))
{
player->move(8);
}
else if (isPressing(KeyDown, false))
{
player->move(2);
}
if (isPressing(KeyInteract, true))
{
if (!player->isDead() && interaction.active) player->interact(interaction.type, interaction.id);
}
if (isPressing(KeyFireSelect, true))
{
if (gameState == gameStatePlaying) player->selectNextShotType();
}
if (isPressing(KeySpell, true))
{
if (gameState == gameStatePlaying) player->castSpell();
}
player->resestFireDirection();
if (isPressing(KeyFireLeft, false))
player->fire(4);
else if (isPressing(KeyFireRight, false))
player->fire(6);
else if (isPressing(KeyFireUp, false))
player->fire(8);
else if (isPressing(KeyFireDown, false))
player->fire(2);
// alternative "one button" gameplay
else if (isPressing(KeyFire, false))
{
if (gameState == gameStatePlaying && isPressing(KeyFire, true))
firingDirection = player->getFacingDirection();
player->fire(firingDirection);
}
// alternative "firing with the mouse" gameplay
else if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
sf::Vector2i mousePosition = sf::Mouse::getPosition(*app);
int xm = mousePosition.x - player->getX();
int ym = mousePosition.y - player->getY();
if (abs(xm) >= abs(ym))
{
if (xm > 0) player->fire(6);
else player->fire(4);
}
else
{
if (ym > 0) player->fire(2);
else player->fire(8);
}
}
// spell (right click)
if (sf::Mouse::isButtonPressed(sf::Mouse::Right) && (gameState == gameStatePlaying))
{
sf::Vector2i mousePosition = sf::Mouse::getPosition(*app);
int xm = mousePosition.x - player->getX();
int ym = mousePosition.y - player->getY();
if (abs(xm) >= abs(ym))
{
if (xm > 0) player->setFacingDirection(6);
else player->setFacingDirection(4);
}
else
{
if (ym > 0) player->setFacingDirection(2);
else player->setFacingDirection(8);
}
player->castSpell();
}
// message queue
if (!messagesQueue.empty())
{
messagesQueue.front().timer -= deltaTime;
if (messagesQueue.front().timer < 0.0f)
{
messagesQueue.pop();
if (!messagesQueue.empty()) SoundManager::getInstance().playSound(SOUND_MESSAGE);
}
}
// achievement queue
if (!achievementsQueue.empty() && achievementsQueue.front().hasStarted)
{
achievementsQueue.front().timer -= deltaTime;
if (achievementsQueue.front().timer < 0.0f)
{
achievementsQueue.pop();
}
}
}
else if (gameState == gameStatePlayingDisplayBoss)
{
if (isPressing(KeyFireDown, true)) gameState = gameStatePlaying;
}
onUpdate();
verifyDoorUnlocking();
checkInteraction();
if (roomClosed)
{
if (getEnemyCount() == 0)
{
currentMap->setCleared(true);
if (currentMap->getRoomType() == roomTypeKey)
new ItemEntity( (enumItemType)(ItemBossKey),
MAP_WIDTH / 2 * TILE_WIDTH + TILE_WIDTH / 2,
MAP_HEIGHT / 2 * TILE_HEIGHT + TILE_HEIGHT / 2);
player->onClearRoom();
openDoors();
remove(SAVE_FILE.c_str());
if (currentMap->getRoomType() == roomTypeBoss)
{
playMusic(MusicDungeon);
}
else if (currentMap->getRoomType() == roomTypeChallenge && !player->isDead())
{
ChestEntity* chest = new ChestEntity((TILE_WIDTH * MAP_WIDTH * 0.5f),
(TILE_HEIGHT * MAP_HEIGHT * 0.5f),
ChestChallenge, false);
chest->makeAppear();
// sound
SoundManager::getInstance().playSound(SOUND_GONG);
playMusic(MusicDungeon);
// text
float x0 = MAP_WIDTH * 0.5f * TILE_WIDTH;
float y0 = MAP_HEIGHT * 0.5f * TILE_HEIGHT + 40.0f;
TextEntity* text = new TextEntity("COMPLETE !", 30, x0, y0);
text->setAlignment(ALIGN_CENTER);
text->setLifetime(2.5f);
text->setWeight(-36.0f);
text->setZ(1200);
text->setColor(TextEntity::COLOR_FADING_WHITE);
challengeLevel++;
if (challengeLevel == 5) registerAchievement(AchievementChallenges);
player->offerChallenge();
}
}
}
if (backToMenu)
{
if (player->isDead())
{
EntityManager::getInstance().clean();
introSprites[0] = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_FOG));
introSprites[0]->setX(SCREEN_WIDTH / 2);
introSprites[0]->setY(SCREEN_HEIGHT - 202);
introSprites[1] = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_FOG));
introSprites[1]->setX(SCREEN_WIDTH / 2 + 970);
introSprites[1]->setY(SCREEN_HEIGHT - 202);
switchToMenu();
menuState = MenuStateHiScores;
#ifdef ONLINE_MODE
menuScoreIndex = 0;
#else
menuScoreIndex = 2;
#endif
}
else
{
prepareIntro();
switchToMenu();
menuState = MenuStateMain;
}
}
}
void WitchBlastGame::addLifeBarToDisplay(std::string label, int hp, int hpMax)
{
lifeBar.toDisplay = true;
lifeBar.label = label;
lifeBar.hp = hp;
lifeBar.hpMax = hpMax;
}
void WitchBlastGame::renderBossPortrait()
{
if (gameState == gameStatePlayingDisplayBoss)
{
float transitionTime = 2.5f;
float endTime = PORTRAIT_DIAPLAY_TIME;
int xBoss = GAME_WIDTH / 2 - 267;
int fade = 255;
if (bossDisplayTimer < 0.25f)
{
xBoss += (0.25f - bossDisplayTimer) * 3000;
//fade = 255 - (0.25f - bossDisplayTimer) * 1000;
}
else if (bossDisplayTimer > endTime - 0.75f)
{
fade = (endTime - bossDisplayTimer) * 333;
if (fade < 0) fade = 0;
}
// background
sf::RectangleShape rectangle;
rectangle.setFillColor(sf::Color(0, 0, 0, fade));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH, MAP_HEIGHT * TILE_HEIGHT));
app->draw(rectangle);
// boss
if (bossDisplayTimer > transitionTime) // + 1.0f)
{
EnemyEntity* boss = getBoss();
if (boss)
{
sf::View view = app->getView();
view.move(-5, -5);
app->setView(view);
boss->render(app);
view.move(5, 5);
app->setView(view);
}
/*if (bossDisplayTimer < transitionTime + 1.5f)
{
rectangle.setFillColor(sf::Color(0, 0, 0, (1.5 - (bossDisplayTimer - transitionTime)) * 510));
app->draw(rectangle);
std::cout << 1.5 - (bossDisplayTimer - transitionTime) << " ";
}*/
//if (bossDisplayTimer < transitionTime + 2.0f)
{
//rectangle.setFillColor(sf::Color(0, 0, 0, (2.0 - (bossDisplayTimer - transitionTime)) * 255));
//app->draw(rectangle);
//std::cout << 1.5 - (bossDisplayTimer - transitionTime) << " ";
}
}
// boss portrait
if (bossDisplayTimer < transitionTime)
{
sf::Sprite bossSprite;
bossSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_BOSS_PICTURES));
bossSprite.setPosition(xBoss, 0);
app->draw(bossSprite);
}
else
{
if (bossDisplayState == 0)
{
SoundManager::getInstance().playSound(SOUND_BOOM_00);
for (int i = 0; i < 250; i++)
{
SpriteEntity* spriteStar = new SpriteEntity(
ImageManager::getInstance().getImage(IMAGE_PORTRAIT_PART),
GAME_WIDTH / 2 - 150 + rand() % 300, GAME_HEIGHT / 2 - 150 + rand() % 300);
spriteStar->setScale(5.0f, 5.0f);
spriteStar->setZ(7000.0f);
spriteStar->setSpin(-100 + rand()%200);
spriteStar->setVelocity(Vector2D(400 + rand()%800));
spriteStar->setFading(true);
spriteStar->setLifetime(4.1f + (rand() % 100) * 0.003f );
spriteStar->setColor(sf::Color(rand() % 255, rand() % 255, 255, 128));
spriteStar->setColor(sf::Color(40, 4, 40, 128));
spriteStar->setType(ENTITY_EFFECT);
if (rand()% 2 == 0) spriteStar->setRenderAdd();
}
bossDisplayState = 1;
}
else if (bossDisplayState == 1 && bossDisplayTimer > transitionTime + 0.2f)
{
bossDisplayState = 2;
for (int i = 0; i < 50; i++)
{
SpriteEntity* spriteStar = new SpriteEntity(
ImageManager::getInstance().getImage(IMAGE_PORTRAIT_PART),
GAME_WIDTH / 2 - 150 + rand() % 300, GAME_HEIGHT / 2 - 150 + rand() % 300);
spriteStar->setScale(4.0f, 4.0f);
spriteStar->setZ(7000.0f);
spriteStar->setSpin(-100 + rand()%200);
spriteStar->setVelocity(Vector2D(400 + rand()%800));
spriteStar->setFading(true);
spriteStar->setLifetime(4.1f + (rand() % 100) * 0.003f );
spriteStar->setColor(sf::Color(rand() % 255, rand() % 255, 255, 128));
spriteStar->setColor(sf::Color(20, 2, 20, 128));
spriteStar->setType(ENTITY_EFFECT);
spriteStar->setRenderAdd();
}
}
else if (bossDisplayState == 2 && bossDisplayTimer > transitionTime + 0.4f)
{
bossDisplayState = 3;
for (int i = 0; i < 50; i++)
{
SpriteEntity* spriteStar = new SpriteEntity(
ImageManager::getInstance().getImage(IMAGE_PORTRAIT_PART),
GAME_WIDTH / 2 - 150 + rand() % 300, GAME_HEIGHT / 2 - 150 + rand() % 300);
spriteStar->setScale(3.0f, 3.0f);
spriteStar->setZ(7000.0f);
spriteStar->setSpin(-100 + rand()%200);
spriteStar->setVelocity(Vector2D(400 + rand()%800));
spriteStar->setFading(true);
spriteStar->setLifetime(4.1f + (rand() % 100) * 0.003f );
spriteStar->setColor(sf::Color(rand() % 255, rand() % 255, 255, 128));
spriteStar->setColor(sf::Color(20, 2, 20, 128));
spriteStar->setType(ENTITY_EFFECT);
spriteStar->setRenderAdd();
}
}
animateEffects();
}
}
}
void WitchBlastGame::renderGame()
{
lifeBar.toDisplay = false;
EntityManager::getInstance().renderUnder(app, 5000);
EntityManager::getInstance().renderUnder(app, 5000);
}
void WitchBlastGame::generateUiParticle(float x, float y)
{
SpriteEntity* particle = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_BOLT),
x, y, BOLT_WIDTH, BOLT_HEIGHT);
particle->setFading(true);
particle->setImagesProLine(BOLT_PRO_LINE);
particle->setZ(10000);
particle->setLifetime(0.5f);
particle->setVelocity(Vector2D(30 + rand() % 50));
particle->setWeight(200);
particle->setType(ENTITY_EFFECT);
//particle->setFrame(BOLT_PRO_LINE + 2);
particle->setFrame(BOLT_PRO_LINE * 2 + 6);
particle->setRenderAdd();
particle->setScale(0.35f, 0.35f);
particle->setFading(true);
}
void WitchBlastGame::renderHud()
{
// boss life bar ?
if (lifeBar.toDisplay && gameState != gameStatePlayingDisplayBoss) renderLifeBar();
renderBossPortrait();
// interaction text ?
if (interaction.active)
{
if (interaction.type == InteractionTypeTemple)
write(interaction.label, 20, GAME_WIDTH / 2, 480, ALIGN_CENTER,sf::Color::White, app, 2, 2);
else if (interaction.type == InteractionTypeMerchandise)
write(interaction.label, 20, GAME_WIDTH / 2, 480, ALIGN_CENTER,sf::Color::White, app, 2, 2);
}
// light cone ?
float fade = player->getLightCone();
if (fade > 0.0f)
{
sf::Sprite cone;
cone.setTexture(*ImageManager::getInstance().getImage(IMAGE_LIGHT_CONE));
cone.setPosition(player->getX() - 64, player->getY() - 580);
cone.setColor(sf::Color(255, 255, 255, 255 * fade));
app->draw(cone, sf::BlendAdd);
}
app->draw(uiSprites.gui);
EntityManager::getInstance().renderAfter(app, 5000);
if (gameState == gameStatePlayingDisplayBoss)
{
// boss name
int fade = 255;
if (bossDisplayTimer < 0.25f)
{
fade = 255 - (0.25f - bossDisplayTimer) * 1000;
}
else if (bossDisplayTimer > PORTRAIT_DIAPLAY_TIME - 0.25f)
{
fade = (PORTRAIT_DIAPLAY_TIME - bossDisplayTimer) * 1000;
if (fade < 0) fade = 0;
}
write("THE COOK", 27, GAME_WIDTH / 2, 540, ALIGN_CENTER, sf::Color(255, 255, 255, fade), app, 0, 0);
}
}
void WitchBlastGame::renderLifeBar()
{
if (lifeBar.toDisplay)
{
float l = lifeBar.hp * ((MAP_WIDTH - 1) * TILE_WIDTH) / lifeBar.hpMax;
int label_dy = 0;
sf::RectangleShape rectangle(sf::Vector2f((MAP_WIDTH - 1) * TILE_WIDTH, 25));
rectangle.setFillColor(sf::Color(0, 0, 0,128));
rectangle.setPosition(sf::Vector2f(TILE_WIDTH / 2, label_dy + 22));
rectangle.setOutlineThickness(1);
rectangle.setOutlineColor(sf::Color(200, 200, 200, 200));
app->draw(rectangle);
rectangle.setSize(sf::Vector2f(l, 25));
rectangle.setFillColor(sf::Color(190, 20, 20));
rectangle.setOutlineThickness(0);
rectangle.setPosition(sf::Vector2f(TILE_WIDTH / 2, label_dy + 22));
app->draw(rectangle);
game().write( lifeBar.label,
18,
TILE_WIDTH / 2 + 10.0f,
label_dy + 23,
ALIGN_LEFT,
sf::Color(255, 255, 255),
app, 0 , 0);
}
}
void WitchBlastGame::renderRunningGame()
{
EntityManager::getInstance().sortByZ();
if (!isPlayerAlive)
{
sf::View view = app->getView();
sf::View viewSave = app->getView();
if (!parameters.zoom || player->getDeathAge() > 4.0f)
{
// do nothing
}
else if (player->getDeathAge() > 3.0f)
{
view.zoom(1.0f - 0.75f * (4.0f - player->getDeathAge()));
float xDiff = view.getCenter().x - player->getX();
float yDiff = view.getCenter().y - player->getY();
view.setCenter(view.getCenter().x - xDiff * (4.0f - player->getDeathAge()),
view.getCenter().y - yDiff * (4.0f - player->getDeathAge()));
}
else if (player->getDeathAge() > 1.0f)
{
view.zoom(0.25f);
view.setCenter(player->getX(), player->getY());
}
else
{
view.zoom(1.0f - 0.75f * (player->getDeathAge()));
float xDiff = view.getCenter().x - player->getX();
float yDiff = view.getCenter().y - player->getY();
view.setCenter(view.getCenter().x - xDiff * player->getDeathAge(),
view.getCenter().y - yDiff * player->getDeathAge());
}
view.move(-5, -5);
app->setView(view);
renderGame();
app->setView(viewSave);
renderHud();
}
else if (parameters.zoom && gameTime < 1.0f)
{
sf::View view = app->getView();
sf::View viewSave = app->getView();
view.zoom(0.25f + 0.75f * (gameTime));
view.move(-5, -5);
app->setView(view);
renderGame();
app->setView(viewSave);
renderHud();
}
else if (xGame[xGameTypeShake].active)
{
sf::View view = app->getView();
sf::View viewSave = app->getView();
view.move(-4 + rand() % 9, -4 + rand() % 9);
app->setView(view);
renderGame();
app->setView(viewSave);
renderHud();
}
else
{
sf::View view = app->getView();
sf::View viewSave = app->getView();
view.move(-OFFSET_X, -OFFSET_Y);
app->setView(view);
renderGame();
app->setView(viewSave);
renderHud();
}
sf::RectangleShape rectangle(sf::Vector2f(200, 25));
// effects
if (player->isSpecialStateActive(SpecialStateTime))
{
sf::RectangleShape whiteLine = sf::RectangleShape(sf::Vector2f(GAME_WIDTH, 2));
whiteLine.setFillColor(sf::Color(255, 255, 255, 32));
for (int i = 0; i < 8; i++)
{
whiteLine.setPosition(xOffset, yOffset + rand() % GAME_HEIGHT);
app->draw(whiteLine);
}
}
if (isPressing(KeyTimeControl, false) && gameState == gameStatePlaying)
{
// effect
int effectFade = 10 + 20 * (1.0f + cos(12.0f * getAbsolutTime())) * 0.5f;
rectangle.setFillColor(sf::Color(0, 255, 255, effectFade));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH , MAP_HEIGHT * TILE_HEIGHT));
sf::RenderStates r;
r.blendMode = sf::BlendAlpha ;
app->draw(rectangle, r);
}
if (xGame[xGameTypeFade].active && xGame[xGameTypeFade].param == X_GAME_FADE_IN)
{
// fade in
rectangle.setFillColor(sf::Color(0, 0, 0, 255 - ((FADE_IN_DELAY - xGame[xGameTypeFade].timer) / FADE_IN_DELAY) * 255));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH , MAP_HEIGHT * TILE_HEIGHT));
app->draw(rectangle);
}
else if (xGame[xGameTypeFade].active && xGame[xGameTypeFade].param == X_GAME_FADE_OUT)
{
// fade out
rectangle.setFillColor(sf::Color(0, 0, 0, ((FADE_IN_DELAY - xGame[xGameTypeFade].timer) / FADE_IN_DELAY) * 255));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH , MAP_HEIGHT * TILE_HEIGHT));
app->draw(rectangle);
}
if (player->isSpecialStateActive(SpecialStateConfused))
{
specialStateStuct specialState = player->getSpecialState(SpecialStateConfused);
// effect
int effectFade = 150 + cos(3.0f * getAbsolutTime()) * 100;
// fade
int fade = 55;
if (specialState.timer < 0.4f)
fade = 55 - (0.4f - specialState.timer) / 0.4f * 55;
else if (specialState.timer > specialState.param1 - 0.4f)
fade = (specialState.param1 - specialState.timer) / 0.4f * 55;
if (fade < 0) fade = 0;
else if (fade > 55) fade = 55;
fade *= 1.5f;
rectangle.setFillColor(sf::Color(255 - effectFade, 0, effectFade, fade));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH , MAP_HEIGHT * TILE_HEIGHT));
sf::RenderStates r;
r.blendMode = sf::BlendAlpha ;
app->draw(rectangle, r);
}
else if (xGame[xGameTypeFadeColor].active)
{
// color fade
unsigned int r = 0, g = 0, b = 0;
switch (xGame[xGameTypeFadeColor].param)
{
case X_GAME_COLOR_RED:
r = 255;
g = 100;
break;
case X_GAME_COLOR_GREEN:
g = 255;
break;
case X_GAME_COLOR_BLUE:
b = 255;
break;
case X_GAME_COLOR_VIOLET:
r = 255;
b = 200;
break;
case X_GAME_COLOR_BROWN:
r = 200;
b = 100;
g = 150;
break;
case X_GAME_COLOR_WHITE:
r = 255;
b = 255;
g = 255;
break;
}
int alpha = xGame[xGameTypeFadeColor].timer * 200.0f / xGame[xGameTypeFadeColor].duration;
rectangle.setFillColor(sf::Color(r, g, b, alpha));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH , MAP_HEIGHT * TILE_HEIGHT));
app->draw(rectangle, sf::BlendAdd);
}
if (gameState != gameStatePlayingDisplayBoss) renderMessages();
app->draw(uiSprites.topLayer);
std::ostringstream oss;
oss << player->getGold();
write(oss.str(), 18, 518, 619, ALIGN_CENTER, sf::Color::White, app, 0, 0);
myText.setColor(sf::Color(0, 0, 0, 255));
myText.setCharacterSize(16);
oss.str("");
oss << tools::getLabel("level") << " " << level;
write(oss.str(), 16, 880, 610, ALIGN_CENTER, sf::Color::Black, app, 0, 0);
//if (gameState == gameStatePlaying)
{
// life
// if (player->isPoisoned()) TODO
sf::Sprite hpSprite;
hpSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_UI_LIFE));
int hpFade = 88.0f * (float)player->getHpDisplay() / (float)player->getHpMax();
if (hpFade < 0) hpFade = 0;
else if (hpFade > 88) hpFade = 88;
hpSprite.setPosition(170, 619 + 88 - hpFade);
hpSprite.setTextureRect(sf::IntRect(0, 88 - hpFade, 88, hpFade));
app->draw(hpSprite);
oss.str("");
oss << player->getHp() << "/" << player->getHpMax();
write(oss.str(), 16, 210, 654, ALIGN_CENTER, sf::Color::White, app, 0, 0);
// mana
sf::Sprite manaSprite;
manaSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_UI_MANA));
int manaFade = player->getPercentFireDelay() * 98;
manaSprite.setPosition(558, 614 + 98 - manaFade);
manaSprite.setTextureRect(sf::IntRect(0, 98 - manaFade, 98, manaFade));
app->draw(manaSprite);
if (player->getActiveSpell().spell != SpellNone)
{
//oss.str("");
//oss << tools::getLabel(spellLabel[player->getActiveSpell().spell]);
//if (player->isEquiped(EQUIP_BOOK_MAGIC_II)) oss << "+";
//write(oss.str(), 14, 95, 663, ALIGN_LEFT, sf::Color::White, app, 0, 0);
// TODO
sf::Sprite spellSprite;
spellSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_UI_SPELLS));
spellSprite.setPosition(568, 624);
int frame = player->getActiveSpell().spell;
spellSprite.setTextureRect(sf::IntRect(frame * 78, 78, 78, 78));
//spellSprite.scale(2.0f, 2.0f);
app->draw(spellSprite);
int spellFade = player->getPercentSpellDelay() * 78;
spellSprite.setPosition(568, 624 + 78 - spellFade);
spellSprite.setTextureRect(sf::IntRect(frame * 78, 78 - spellFade, 78, spellFade));
app->draw(spellSprite);
if (player->canCastSpell())
{
float fade = (cos(8.0f * getAbsolutTime()) + 1.0f) * 0.5f;
spellSprite .setColor(sf::Color(255, 255, 255, 255 * fade));
app->draw(spellSprite, sf::BlendAdd);
}
}
// drawing the key on the interface
if (player->isEquiped(EQUIP_BOSS_KEY)) app->draw(uiSprites.keySprite);
// drawing the level items
if (player->isEquiped(EQUIP_FLOOR_MAP))
{
sf::Sprite mapSprite;
mapSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEMS_EQUIP));
mapSprite.setTextureRect(sf::IntRect(ITEM_WIDTH * 3, ITEM_HEIGHT * 4, ITEM_WIDTH, ITEM_HEIGHT));
mapSprite.setPosition(737, 648);
app->draw(mapSprite);
}
if (player->isEquiped(EQUIP_ALCOHOL))
{
sf::Sprite alcSprite;
alcSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEMS_EQUIP));
alcSprite.setTextureRect(sf::IntRect(ITEM_WIDTH * 4, ITEM_HEIGHT * 4, ITEM_WIDTH, ITEM_HEIGHT));
alcSprite.setPosition(737, 681);
app->draw(alcSprite);
}
if (player->isEquiped(EQUIP_LUCK))
{
sf::Sprite alcSprite;
alcSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEMS_EQUIP));
alcSprite.setTextureRect(sf::IntRect(ITEM_WIDTH * 5, ITEM_HEIGHT * 4, ITEM_WIDTH, ITEM_HEIGHT));
alcSprite.setPosition(704, 681);
app->draw(alcSprite);
}
if (player->isEquiped(EQUIP_FAIRY_POWDER))
{
sf::Sprite alcSprite;
alcSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEMS_EQUIP));
alcSprite.setTextureRect(sf::IntRect(ITEM_WIDTH * 6, ITEM_HEIGHT * 4, ITEM_WIDTH, ITEM_HEIGHT));
alcSprite.setPosition(671, 681);
app->draw(alcSprite);
}
// drawing the consumable
if (!player->isEquiped(EQUIP_BAG))
{
sf::RectangleShape shadow(sf::Vector2f(70, 33));
shadow.setFillColor(sf::Color(0, 0, 0, 128));
shadow.setPosition(sf::Vector2f(386, 614));
app->draw(shadow);
}
for (int i = 0; i < MAX_SLOT_CONSUMABLES; i++)
{
if (player->getConsumable(i) > -1)
{
int n = player->getConsumable(i);
sf::Sprite consSprite;
consSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEMS));
consSprite.setTextureRect(sf::IntRect(ITEM_WIDTH * (n % 10), ITEM_HEIGHT * (n / 10), ITEM_WIDTH, ITEM_HEIGHT));
consSprite.setPosition(315 + 37 * i, 615);
app->draw(consSprite);
}
}
// drawing message icon
if (!messagesQueue.empty())
{
int fade = 255;
if (messagesQueue.front().timer < 0.5f)
{
fade = (2 * messagesQueue.front().timer) * 255;
}
else if (messagesQueue.front().timerMax - messagesQueue.front().timer < 0.5f)
{
fade = (2 * (messagesQueue.front().timerMax - messagesQueue.front().timer)) * 255;
}
uiSprites.iconSprite.setColor(sf::Color(255, 255, 255, fade));
uiSprites.iconSprite.setTextureRect(sf::IntRect((messagesQueue.front().icon % 10) * 72, (messagesQueue.front().icon / 10) * 96, 72, 96));
app->draw(uiSprites.iconSprite);
}
// drawing the divinity
if (player->getDivinity().divinity >= 0)
{
sf::Sprite divSprite;
divSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_DIVINITY));
divSprite.setPosition(100, 614);
divSprite.setTextureRect(sf::IntRect(player->getDivinity().divinity * 48, 0, 48, 85));
app->draw(divSprite);
float fade = player->getLightCone();
if (fade > 0.0f && player->getPlayerStatus() != PlayerEntity::playerStatusPraying)
{
divSprite.setTextureRect(sf::IntRect(player->getDivinity().divinity * 48, 85, 48, 85));
divSprite.setColor(sf::Color(255, 255, 255, 255 * fade));
app->draw(divSprite);
}
rectangle.setOutlineThickness(0);
if (player->getDivinity().interventions + 1 < player->getDivinity().level)
{
int fade = 50 + 50 * cosf(game().getAbsolutTime() * 8);
rectangle.setFillColor(sf::Color(100 + fade, 100 + fade, 200 + fade / 2, 255));
}
else
rectangle.setFillColor(sf::Color(100, 100, 200, 255));
rectangle.setPosition(sf::Vector2f(101, 689));
rectangle.setSize(sf::Vector2f(46 * player->getDivinity().percentsToNextLevels, 9));
app->draw(rectangle);
std::ostringstream oss;
if (player->getDivinity().level == MAX_DIVINITY_LEVEL + 1) oss << "MAX";
else oss << "lvl " << player->getDivinity().level;
write(oss.str(), 11, 122, 702, ALIGN_CENTER, sf::Color::White, app, 0, 0);
}
// render the shots
renderHudShots(app);
if (gameState == gameStatePlayingPause)
{
// background
rectangle.setFillColor(sf::Color(0, 0, 0, 200));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH, MAP_HEIGHT * TILE_HEIGHT));
app->draw(rectangle);
// minimap
int mapx = 350;
int mapy = 30;
// background
app->draw(rectangle);
app->draw(uiSprites.mapBgSprite);
// map
float miniX = miniMapEntity->getX();
float miniY = miniMapEntity->getY();
miniMapEntity->setX(mapx);
miniMapEntity->setY(mapy);
miniMapEntity->computeVertices();
miniMapEntity->render(app);
miniMapEntity->setX(miniX);
miniMapEntity->setY(miniY);
miniMapEntity->computeVertices();
float x = 200;
float y = 480;
// items
write(tools::getLabel("inventory"), 16, x, y, ALIGN_LEFT, sf::Color::White, app, 0, 0);
int n = 0;
for (auto i: sortedEquipement)
{
if (i != EQUIP_BOSS_KEY && player->isEquiped(i))
{
sf::Sprite itemSprite;
itemSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEMS_EQUIP));
itemSprite.setPosition(x + n * 32, y + 20);
itemSprite.setTextureRect(sf::IntRect((i % 10) * 32, (i / 10) * 32, 32, 32));
app->draw(itemSprite);
n++;
}
}
renderInGameMenu();
}
if (player->isDead())
{
float deathAge = player->getDeathAge();
if (deathAge > DEATH_CERTIFICATE_DELAY)
{
rectangle.setFillColor(sf::Color(0, 0, 0, 180));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH , MAP_HEIGHT * TILE_HEIGHT));
app->draw(rectangle);
renderDeathScreen(80, 110);
if (scoreSaveFile.compare("") == 0)
{
write(tools::getLabel("certificate_capture"), 16, 80, 430, ALIGN_LEFT, sf::Color::White, app, 0, 0);
}
else
{
std::stringstream ss;
ss << tools::getLabel("certificate_saved") << " " << scoreSaveFile;
write(ss.str(), 16, 80, 430, ALIGN_LEFT, sf::Color::White, app, 0, 0);
}
}
else if (deathAge > DEATH_CERTIFICATE_DELAY - 1.0f)
{
rectangle.setFillColor(sf::Color(0, 0, 0, 180 * (deathAge - 2.5f)));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH , MAP_HEIGHT * TILE_HEIGHT));
app->draw(rectangle);
renderDeathScreen(80 + (DEATH_CERTIFICATE_DELAY - deathAge) * 1000, 110);
}
}
else if (currentMap->getRoomType() == roomTypeExit && level >= 7 /*LAST_LEVEL*/)
{
float x0 = (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2;
write(tools::getLabel("congratulations_1"), 25, x0, 220, ALIGN_CENTER, sf::Color::White, app, 2, 2);
write(tools::getLabel("congratulations_2"), 23, x0, 250, ALIGN_CENTER, sf::Color::White, app, 2, 2);
write(tools::getLabel("congratulations_3"), 23, x0, 280, ALIGN_CENTER, sf::Color::White, app, 2, 2);
registerAchievement(AchievementWin);
}
}
// show game time
if (showGameTime)
{
int minutes = (int)gameTime / 60;
int secondes = (int)gameTime % 60;
std::stringstream ss;
if (minutes < 10) ss << "0";
ss << minutes;
ss << ":";
if (secondes < 10) ss << "0";
ss << secondes;
write(ss.str(), 14, 4, 4, ALIGN_LEFT, sf::Color::Green, app, 0,0);
}
// achievements ?
if (!achievementsQueue.empty()) // && (currentMap->isCleared() || achievementsQueue.front().hasStarted) )
{
if (!achievementsQueue.front().hasStarted)
{
SoundManager::getInstance().playSound(SOUND_ACHIEVEMENT);
achievementsQueue.front().hasStarted = true;
achievementState[achievementsQueue.front().type] = AchievementDone;
saveGameData();
proceedEvent(EventAchievement);
// text
float x0 = MAP_WIDTH * 0.5f * TILE_WIDTH;
float y0 = MAP_HEIGHT * 0.5f * TILE_HEIGHT + 40.0f;
TextEntity* text = new TextEntity(tools::getLabel("achievement_complete"), 30, x0, y0);
text->setAlignment(ALIGN_CENTER);
text->setLifetime(2.5f);
text->setWeight(-36.0f);
text->setZ(1200);
text->setColor(TextEntity::COLOR_FADING_WHITE);
}
int xPos = 560;
int yPos = 4;
int opening = 384;
float achievAge = ACHIEVEMENT_DELAY_MAX - achievementsQueue.front().timer;
sf::Sprite spriteScroll;
if (achievAge < 1.0f)
opening = 32;
else if (achievAge < 2.0f)
opening = 32 + (achievAge - 1.0f) * (384 - 32);
else if (achievAge > ACHIEVEMENT_DELAY_MAX - 1.0f)
opening = 32 + (ACHIEVEMENT_DELAY_MAX - achievAge) * (384 - 32);
if (achievAge < 0.5f)
spriteScroll.setColor(sf::Color(255, 255, 255, 500 * achievAge));
else if (achievAge > ACHIEVEMENT_DELAY_MAX - 0.5f)
spriteScroll.setColor(sf::Color(255, 255, 255, 500 * (ACHIEVEMENT_DELAY_MAX - achievAge)));
spriteScroll.setTexture(*ImageManager::getInstance().getImage(IMAGE_UI_ACHIEV));
spriteScroll.setTextureRect(sf::IntRect(128 + 384 - opening, 0, opening, 64));
spriteScroll.setPosition(xPos + 384 - opening, yPos);
app->draw(spriteScroll);
if ((achievAge > 1.0f && achievAge < 2.0f) || achievAge > ACHIEVEMENT_DELAY_MAX - 1.0f)
spriteScroll.setTextureRect(sf::IntRect(32 * ((int)(achievAge * 8) % 4), 0, 32, 64));
else
spriteScroll.setTextureRect(sf::IntRect(0, 0, 32, 64));
spriteScroll.setPosition(xPos + 394 - opening - 16, yPos);
app->draw(spriteScroll);
if (achievAge > 2.0f && achievAge < ACHIEVEMENT_DELAY_MAX - 1.0f)
{
sf::Sprite icon;
icon.setTexture(*ImageManager::getInstance().getImage(IMAGE_ACHIEVEMENTS));
icon.setTextureRect(sf::IntRect( ((achievementsQueue.front().type + 1) % 10) * 64,
((achievementsQueue.front().type + 1) / 10) * 64, 64, 64));
icon.setPosition(xPos + 308, yPos + 9);
icon.setScale(0.7f, 0.7f);
app->draw(icon);
icon.setColor(sf::Color(255, 255, 255, 50 + 50 * cosf(getAbsolutTime() * 4)));
app->draw(icon, sf::BlendAdd);
game().write(achievementsQueue.front().message, 13, xPos + 34, yPos + 10, ALIGN_LEFT, sf::Color::Black, app, 0, 0);
if (achievements[achievementsQueue.front().type].unlockType == UnlockItem)
{
game().write(tools::getLabel(items[achievements[achievementsQueue.front().type].unlock].name),
13, xPos + 70, yPos + 34, ALIGN_LEFT, sf::Color::Black, app, 0, 0);
}
else if (achievements[achievementsQueue.front().type].unlockType == UnlockFunctionality)
{
game().write(tools::getLabel(functionalityLabel[achievements[achievementsQueue.front().type].unlock]),
13, xPos + 70, yPos + 34, ALIGN_LEFT, sf::Color::Black, app, 0, 0);
}
}
//if (achievAge < 1.0f)
{
int i = achievementsQueue.front().counter;
if (i < 64)
{
for (int j = 0; j < 2; j++)
{
generateUiParticle(xPos + 394 + 16 + 4 - 32 - 40, yPos - i + 64);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - 40, yPos - i + 64 + 1);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - 40, yPos - i + 64 + 2);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - 40, yPos - i + 64 + 3);
}
}
else if (i < 40 + 64)
{
for (int j = 0; j < 2; j++)
{
generateUiParticle(xPos + 394 + 16 + 4 - 32 - 40 + i - 64, yPos);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - 40 + i - 63, yPos);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - 40 + i - 62, yPos);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - 40 + i - 61, yPos);
}
}
else if (i < 40 + 64 + 64)
{
for (int j = 0; j < 2; j++)
{
generateUiParticle(xPos + 394 + 16 + 4 - opening, yPos + i - 40 - 64);
generateUiParticle(xPos + 394 + 16 + 4 - opening, yPos + i - 40 - 64 + 1);
generateUiParticle(xPos + 394 + 16 + 4 - opening, yPos + i - 40 - 64 + 2);
generateUiParticle(xPos + 394 + 16 + 4 - opening, yPos + i - 40 - 64 + 3);
}
}
else if (i < 40 + 64 + 40 + 64)
{
for (int j = 0; j < 2; j++)
{
generateUiParticle(xPos + 394 + 16 + 4 - 32 - i + 144, yPos + 64);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - i + 144 + 1, yPos + 64);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - i + 144 + 2, yPos + 64);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - i + 144 + 3, yPos + 64);
}
}
achievementsQueue.front().counter += 4;
}
}
// show player effects
if (isPlayerAlive)
{
float x0 = 20, y0 = 540, yStep = -20;
for (int i = 0; i < NB_SPECIAL_STATES; i++)
{
if ( (player->isSpecialStateActive((enumSpecialState)i) && player->getSpecialState((enumSpecialState)i).timer > 0.35f)
|| player->getSpecialState((enumSpecialState)i).waitUnclear)
{
std::stringstream oss;
oss << tools::getLabel(specialStateToLabel[i]) << " : ";
if (player->getSpecialState((enumSpecialState)i).waitUnclear)
{
oss << "waiting";
int n = (int)(getAbsolutTime() * 3) % 3;
if (n == 0) oss << ".";
else if (n == 1) oss << "..";
else oss << "...";
}
else
oss << (int)(player->getSpecialState((enumSpecialState)i).timer);
write(oss.str(), 12, x0, y0, ALIGN_LEFT, specialStateToColor[i], app, 0, 0);
y0 += yStep;
}
}
}
}
void WitchBlastGame::renderMessages()
{
// message queue
if (!messagesQueue.empty())
{
int dy = 30;
if (messagesQueue.front().timer < 0.5f)
{
dy *= (2 * messagesQueue.front().timer);
}
else if (messagesQueue.front().timerMax - messagesQueue.front().timer < 0.5f)
{
dy *= (2 * (messagesQueue.front().timerMax - messagesQueue.front().timer));
}
uiSprites.msgBoxSprite.setPosition(0, 590 - dy);
app->draw(uiSprites.msgBoxSprite);
std::stringstream ss;
ss << messagesQueue.front().message[0];
ss << ": ";
ss << messagesQueue.front().message[1];
ss << std::endl;
ss << messagesQueue.front().message[2];
write(ss.str(), 16, 10, 592 - dy, ALIGN_LEFT, sf::Color::White, app, 0,0);
}
}
void WitchBlastGame::saveDeathScreen()
{
std::stringstream ss;
ss << "rip_";
time_t t = time(0); // get time now
struct tm * now = localtime( & t );
ss << (now->tm_year + 1900);
if (now->tm_mon < 9) ss << "0";
ss << (now->tm_mon + 1);
if (now->tm_mday < 9) ss << "0";
ss << now->tm_mday;
if (now->tm_hour <= 9) ss << "0";
ss << (now->tm_hour);
if (now->tm_min <= 9) ss << "0";
ss << (now->tm_min);
if (now->tm_sec <= 9) ss << "0";
ss << (now->tm_sec);
ss << ".png";
int width = 810, height = 300, border = 4;
int x = 80, y = 110;
sf::Image screenShot(app->capture());
sf::Image savedImage;
savedImage.create(width + border * 2, height + border * 2);
savedImage.copy(screenShot,0 , 0, sf::IntRect( x - border, y - border, width + border * 2, height + border * 2));
savedImage.saveToFile(ss.str());
}
void WitchBlastGame::saveScreen()
{
std::stringstream ss;
ss << "screenshot_";
time_t t = time(0); // get time now
struct tm * now = localtime( & t );
ss << (now->tm_year + 1900);
if (now->tm_mon < 9) ss << "0";
ss << (now->tm_mon + 1);
if (now->tm_mday < 9) ss << "0";
ss << now->tm_mday;
if (now->tm_hour <= 9) ss << "0";
ss << (now->tm_hour);
if (now->tm_min <= 9) ss << "0";
ss << (now->tm_min);
if (now->tm_sec <= 9) ss << "0";
ss << (now->tm_sec);
ss << ".png";
sf::Image screenShot(app->capture());
screenShot.saveToFile(ss.str());
}
void WitchBlastGame::renderDeathScreen(float x, float y)
{
int xRect = 810;
sf::Sprite rectangle;
rectangle.setTexture(*ImageManager::getInstance().getImage(IMAGE_DEATH_CERTIFICATE));
rectangle.setPosition(x - 4, y - 4);
app->draw(rectangle);
std::stringstream ss;
ss << parameters.playerName << " - " << tools::getLabel("dc_certificate");
write(ss.str(), 18, x + xRect / 2, y + 5, ALIGN_CENTER, sf::Color::Black, app, 0, 0);
ss.str(std::string());
ss.clear();
ss << tools::getLabel("dc_killed_by") << " " << sourceToString(player->getLastHurtingSource(), player->getLastHurtingEnemy()) << "." << std::endl;
int minutes = (int)gameTime / 60;
if (minutes < 1) minutes = 1;
ss << tools::getLabel("dc_died_level") << " " << level << " " << tools::getLabel("dc_after") << " " << minutes << " " << tools::getLabel("dc_minutes") << "." << std::endl;
ss << tools::getLabel("dc_killed_monsters") << ": " << bodyCount << std::endl;
ss << tools::getLabel("dc_gold") << ": " << player->getGold() << std::endl;
ss << tools::getLabel("dc_challenges") << ": " << challengeLevel - 1 << std::endl;
write(ss.str(), 16, x + 112, y + 50, ALIGN_LEFT, sf::Color::Black, app, 0, 0);
// player
renderPlayer(x + 40, y + 48, player->getEquipment(), player->getShotType(), 1, 0);
// items
write(tools::getLabel("inventory"), 16, x + 14, y + 165, ALIGN_LEFT, sf::Color::Black, app, 0, 0);
int n = 0;
for (auto i: sortedEquipement)
{
if (i != EQUIP_BOSS_KEY && player->isEquiped(i))
{
sf::Sprite itemSprite;
itemSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEMS_EQUIP));
itemSprite.setPosition(x + 14 + n * 32, y + 183);
itemSprite.setTextureRect(sf::IntRect((i % 10) * 32, (i / 10) * 32, 32, 32));
app->draw(itemSprite);
n++;
}
}
ss.str("");
ss.clear();
ss << "Score: " << score;
write(ss.str(), 24, x + xRect / 2, y + 240, ALIGN_CENTER, sf::Color::Black, app, 0, 0);
}
bool compareScores(WitchBlastGame::StructScore s1, WitchBlastGame::StructScore s2)
{
return s1.score > s2.score;
}
void WitchBlastGame::calculateScore()
{
score = 0;
bodyCount = 0;
for (int enemyType = EnemyTypeBat; enemyType < EnemyTypeRockFalling; enemyType++)
{
bodyCount += killedEnemies[enemyType];
score += killedEnemies[enemyType] * getMonsterScore((enemyTypeEnum)enemyType);
}
score += getChallengeScore(challengeLevel);
score += getGoldScore(player->getGold());
for (int i = 0; i < NUMBER_EQUIP_ITEMS; i++)
{
if (player->isEquiped(i)) score += getItemScore((item_equip_enum)i);
lastScore.equip[i] = player->isEquiped(i);
}
// to save
lastScore.name = parameters.playerName;
lastScore.score = score;
lastScore.level = level;
lastScore.shotType = player->getShotType();
lastScore.divinity = player->getDivinity().divinity;
lastScore.killedBy = player->getLastHurtingEnemy();
lastScore.time = (int)gameTime;
scores.push_back(lastScore);
std::sort (scores.begin(), scores.end(), compareScores);
saveHiScores();
// Online
#ifdef ONLINE_MODE
if (!gameFromSaveFile)
{
sendScoreToServer();
}
else
{
receiveScoreFromServer();
}
#endif // ONLINE_MODE
}
void WitchBlastGame::switchToMenu()
{
gameState = gameStateMenu;
buildMenu(false);
if (!config.configFileExists())
{
menuState = MenuStateFirst;
menuFirst.index = 0;
menuKeyIndex = 0;
}
}
void WitchBlastGame::updateMenu()
{
SoundManager::getInstance().playSound(SOUND_NIGHT, false);
menuStuct* menu = NULL;
bool noMenu = false;
if (menuState == MenuStateMain)
menu = &menuMain;
else if (menuState == MenuStateConfig)
menu = &menuConfig;
else if (menuState == MenuStateFirst)
menu = &menuFirst;
else
noMenu = true;
bool escape = false;
EntityManager::getInstance().animate(deltaTime);
for (int i = 0; i < 2; i++)
{
introSprites[i]->setX(introSprites[i]->getX() - deltaTime * 35);
if (introSprites[i]->getX() < - SCREEN_WIDTH / 2) introSprites[i]->setX(introSprites[i]->getX() + 2 * SCREEN_WIDTH);
}
// Process events
sf::Event event;
while (app->pollEvent(event))
{
// Close window : exit
if (event.type == sf::Event::Closed)
{
saveGameData();
app->close();
}
if (event.type == sf::Event::Resized)
{
enableAA(true);
sf::View view = app->getDefaultView();
view = getLetterboxView( view, event.size.width, event.size.height );
app->setView(view);
}
if (event.type == sf::Event::TextEntered)
{
if (menuState == MenuStateChangeName)
{
if (event.text.unicode < 128)
{
char c = static_cast<char>(event.text.unicode);
if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')
parameters.playerName += static_cast<char>(event.text.unicode);
}
}
}
if (event.type == sf::Event::KeyPressed && menuState == MenuStateKeys)
{
bool alreadyUsed = false;
if (event.key.code == sf::Keyboard::Escape) alreadyUsed = true;
for (unsigned int i = 0; i < menuKeyIndex; i++)
if (input[i] == event.key.code) alreadyUsed = true;
// TODO more tests
if (!alreadyUsed)
{
input[menuKeyIndex] = event.key.code;
menuKeyIndex++;
if (menuKeyIndex == NumberKeys)
{
menuState = MenuStateConfig;
saveConfigurationToFile();
}
}
}
else if (menuState == MenuStateJoystick)
{
bool alreadyUsed = false;
int nbButtons = sf::Joystick::getButtonCount(0);
bool found = false;
JoystickInputStruct jInput;
// Escape = out
if (event.key.code == sf::Keyboard::Escape)
{
menuState = MenuStateConfig;
saveConfigurationToFile();
return;
}
// button pressed ?
for (int i = 0; !found && i < nbButtons; i++)
{
if (sf::Joystick::isButtonPressed(0, i))
{
jInput.isButton = true;
jInput.value = i;
jInput.axis = sf::Joystick::X;
found = true;
}
}
if (!found)
{
// axis ?
for (int i = sf::Joystick::X; i <= sf::Joystick::PovY; i++)
{
if (sf::Joystick::hasAxis(0, (sf::Joystick::Axis)i))
{
if (sf::Joystick::getAxisPosition(0, (sf::Joystick::Axis)i) < -50)
{
jInput.isButton = false;
jInput.value = -1;
jInput.axis = (sf::Joystick::Axis)i;
found = true;
}
else if (sf::Joystick::getAxisPosition(0, (sf::Joystick::Axis)i) > 50)
{
jInput.isButton = false;
jInput.value = 1;
jInput.axis = (sf::Joystick::Axis)i;
found = true;
}
}
}
}
if (found)
{
// already exist ?
for (unsigned int i = 0; i < menuKeyIndex; i++)
{
if (jInput.isButton && joystickInput[i].isButton
&& joystickInput[i].value == jInput.value)
alreadyUsed = true;
if (!jInput.isButton && !joystickInput[i].isButton
&& joystickInput[i].axis == jInput.axis
&& joystickInput[i].value == jInput.value)
alreadyUsed = true;
}
if (!alreadyUsed)
{
joystickInput[menuKeyIndex] = jInput;
menuKeyIndex++;
if (menuKeyIndex == NumberKeys)
{
menuState = MenuStateConfig;
saveConfigurationToFile();
}
}
}
}
else
{
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::F1)
{
saveScreen();
}
if (menuState == MenuStateChangeName)
{
if (event.key.code == sf::Keyboard::Escape || event.key.code == sf::Keyboard::Return)
{
saveConfigurationToFile();
menuState = MenuStateMain;
}
else if (event.key.code == sf::Keyboard::BackSpace)
{
if (parameters.playerName.size() > 0)
parameters.playerName.erase(parameters.playerName.size() - 1);
}
}
else if (event.key.code == sf::Keyboard::Escape)
{
escape = true;
}
}
}
}
// END EVENT PROCESSING
if (menuState == MenuStateAchievements)
{
if (isPressing(KeyRight, true))
{
if (menuAchIndex % 8 < 7) menuAchIndex++;
}
else if (isPressing(KeyLeft, true))
{
if (menuAchIndex % 8 > 0) menuAchIndex--;
}
else if (isPressing(KeyDown, true))
{
if (menuAchIndex / 8 < ACHIEV_LINES) menuAchIndex += 8;
}
else if (isPressing(KeyUp, true))
{
if (menuAchIndex / 8 > 0) menuAchIndex -= 8;
}
else if (isPressing(KeyFireDown, true))
{
if (menuAchIndex / 8 >= ACHIEV_LINES) menuState = MenuStateMain;
}
if (escape) menuState = MenuStateMain;
}
else if (menuState == MenuStateCredits)
{
if (escape || isPressing(KeyFireDown, true)) menuState = MenuStateMain;
}
else if (menuState == MenuStateHiScores)
{
if (escape || isPressing(KeyFireDown, true))
{
menuScoreIndex++;
if (menuScoreIndex > 2)
{
menuState = MenuStateMain;
if (lastScore.level > 0)
{
lastScore.level = 0;
lastScore.score = 0;
playMusic(MusicIntro);
}
}
}
}
if (!noMenu)
{
if (escape)
{
saveGameData();
app->close();
}
else if (isPressing(KeyDown, true))
{
menu->index++;
if (menu->index == menu->items.size()) menu->index = 0;
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
else if (isPressing(KeyUp, true))
{
if (menu->index == 0) menu->index = menu->items.size() - 1;
else menu->index--;
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
else if (isPressing(KeyRight, true))
{
if (menu->items[menu->index].id == MenuLanguage)
{
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
parameters.language++;
if (parameters.language >= NB_LANGUAGES) parameters.language = 0;
if (menuState == MenuStateConfig) saveConfigurationToFile();
tools::setLanguage(languageString[parameters.language]);
buildMenu(true);
}
else if (menu->items[menu->index].id == MenuVolumeSound)
{
parameters.soundVolume = (parameters.soundVolume / 10) * 10 + 10;
if (parameters.soundVolume > 100) parameters.soundVolume = 100;
saveConfigurationToFile();
SoundManager::getInstance().setVolume(parameters.soundVolume);
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
else if (menu->items[menu->index].id == MenuVolumeMusic)
{
parameters.musicVolume = (parameters.musicVolume / 10) * 10 + 10;
if (parameters.musicVolume > 100) parameters.musicVolume = 100;
saveConfigurationToFile();
updateMusicVolume();
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
}
else if (isPressing(KeyLeft, true))
{
if (menu->items[menu->index].id == MenuLanguage)
{
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
parameters.language--;
if (parameters.language < 0) parameters.language = NB_LANGUAGES - 1;
if (menuState == MenuStateConfig) saveConfigurationToFile();
tools::setLanguage(languageString[parameters.language]);
buildMenu(true);
}
else if (menu->items[menu->index].id == MenuVolumeSound)
{
parameters.soundVolume = (parameters.soundVolume / 10) * 10 - 10;
if (parameters.soundVolume < 0) parameters.soundVolume = 0;
saveConfigurationToFile();
SoundManager::getInstance().setVolume(parameters.soundVolume);
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
else if (menu->items[menu->index].id == MenuVolumeMusic)
{
parameters.musicVolume = (parameters.musicVolume / 10) * 10 - 10;
if (parameters.musicVolume < 0) parameters.musicVolume = 0;
saveConfigurationToFile();
updateMusicVolume();
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
}
else if (isPressing(KeyFireDown, true))
{
switch (menu->items[menu->index].id)
{
case MenuStartNew:
startNewGame(false, 1);
remove(SAVE_FILE.c_str());
break;
case MenuStartOld:
startNewGame(true, 1);
break;
case MenuKeys:
menuState = MenuStateKeys;
menuKeyIndex = 0;
break;
case MenuJoystick:
if (sf::Joystick::isConnected(0))
{
buildMenu(true);
menuState = MenuStateJoystick;
menuKeyIndex = 0;
}
else
buildMenu(true);
break;
case MenuCredits:
menuState = MenuStateCredits;
break;
case MenuHiScores:
menuState = MenuStateHiScores;
#ifdef ONLINE_MODE
menuScoreIndex = 0;
#else
menuScoreIndex = 2;
#endif
receiveScoreFromServer();
//loadHiScoresOnline(false);
//loadHiScoresOnline(true);
break;
case MenuAchievements:
menuState = MenuStateAchievements;
menuAchIndex = 0;
break;
case MenuPlayerName:
menuState = MenuStateChangeName;
break;
case MenuConfig:
menuState = MenuStateConfig;
break;
case MenuTutoReset:
for (int i = 0; i < NB_MESSAGES; i++) gameMessagesToSkip[i] = false;
SoundManager::getInstance().playSound(SOUND_SPELL_FREEZE);
saveGameData();
break;
case MenuConfigBack:
menuState = MenuStateMain;
break;
case MenuLanguage:
if (menuState == MenuStateFirst)
{
registerLanguage();
if (parameters.playerName.compare("") == 0 )
{
menuMain.index = 0;
menuState = MenuStateChangeName;
}
else
menuState = MenuStateMain;
}
break;
case MenuExit:
saveGameData();
app->close();
break;
case MenuVolumeSound:
case MenuVolumeMusic:
break;
case MenuContinue:
case MenuSaveAndQuit:
std::cout << "[ERROR] Bad Menu ID\n";
break;
}
}
}
}
void WitchBlastGame::renderMenu()
{
if (menuState == MenuStateCredits)
{
renderCredits();
return;
}
else if (menuState == MenuStateHiScores)
{
//renderHiScores();
if (menuScoreIndex == 0)
renderScores(scoresOnline, "Best Players (ON-LINE)");
else if (menuScoreIndex == 1)
renderScores(scoresOnlineDay, "Best TODAY Scores (ON-LINE)");
else
renderScores(scores, "Best Scores (local)");
return;
}
else if (menuState == MenuStateAchievements)
{
renderAchievements();
return;
}
app->draw(introScreenSprite);
if (titleSprite.getPosition().y > 160) titleSprite.move(0, -8);
else if (titleSprite.getPosition().y < 160) titleSprite.setPosition(SCREEN_WIDTH / 2 - 15, 160);
app->draw(titleSprite);
EntityManager::getInstance().render(app);
menuStuct* menu = nullptr;
if (menuState == MenuStateMain || menuState == MenuStateChangeName)
menu = &menuMain;
else if (menuState == MenuStateConfig)
menu = &menuConfig;
else if (menuState == MenuStateFirst)
menu = &menuFirst;
int xAlign = 290;
int yTop = 320;
int yStep = 40;
if (menuState == MenuStateKeys)
{
// menu keys
if (config.configFileExists())
write(tools::getLabel("key_configuration"), 18, xAlign, 295, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 1, 1);
else
write(tools::getLabel("key_configuration_desc"), 18, xAlign, 295, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 1, 1);
for (unsigned int i = 0; i < NumberKeys; i++)
{
sf::Color itemColor;
if (menuKeyIndex == i) itemColor = sf::Color(255, 255, 255, 255);
else itemColor = sf::Color(180, 180, 180, 255);
std::ostringstream oss;
oss << tools::getLabel(inputKeyString[i]) << ": ";
if (menuKeyIndex == i) oss << tools::getLabel("key_configuration_insert");
else if (menuKeyIndex > i) oss << keyToString(input[i]);
write(oss.str(), 16, xAlign, 330 + i * 25, ALIGN_LEFT, itemColor, app, 1, 1);
}
}
else if (menuState == MenuStateJoystick)
{
// menu keys
if (config.configFileExists())
write(tools::getLabel("joystick_configuration"), 18, xAlign, 295, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 1, 1);
else
write(tools::getLabel("joystick_configuration_desc"), 18, xAlign, 295, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 1, 1);
for (unsigned int i = 0; i < NumberKeys; i++)
{
sf::Color itemColor;
if (menuKeyIndex == i) itemColor = sf::Color(255, 255, 255, 255);
else itemColor = sf::Color(180, 180, 180, 255);
std::ostringstream oss;
oss << tools::getLabel(inputKeyString[i]) << ": ";
if (menuKeyIndex == i) oss << tools::getLabel("joystick_configuration_insert");
else if (menuKeyIndex > i) oss << "OK";
write(oss.str(), 16, xAlign, 330 + i * 25, ALIGN_LEFT, itemColor, app, 1, 1);
}
}
else
{
// menu
for (unsigned int i = 0; i < menu->items.size(); i++)
{
sf::Color itemColor;
if (menu->index == i)
{
itemColor = sf::Color(255, 255, 255, 255);
sf::Sprite fairySprite;
fairySprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_FAIRY));
fairySprite.setTextureRect(sf::IntRect( 48 * ((int)(20 *getAbsolutTime()) % 2), fairySpriteOffsetY, 48, 48));
fairySprite.setPosition(xAlign - 60, yTop - 10 + i * yStep + 5 * cos( 6 * getAbsolutTime()));
app->draw(fairySprite);
}
else itemColor = sf::Color(120, 120, 120, 255);
std::string label = menu->items[i].label;
if (menu->items[i].id == MenuLanguage)
{
std::ostringstream oss;
oss << label << " : " << tools::getLabel(languageString[parameters.language]);
label = oss.str();
}
else if (menu->items[i].id == MenuPlayerName)
{
std::ostringstream oss;
oss << label << " : " << parameters.playerName;
if (menuState == MenuStateChangeName && (int)(getAbsolutTime() * 3) % 2 == 0) oss << "_";
label = oss.str();
}
else if (menu->items[i].id == MenuVolumeSound)
{
std::ostringstream oss;
oss << label << " : ";
if (parameters.soundVolume == 0) oss << "OFF";
else oss << parameters.soundVolume;
label = oss.str();
}
else if (menu->items[i].id == MenuVolumeMusic)
{
std::ostringstream oss;
oss << label << " : ";
if (parameters.musicVolume == 0) oss << "OFF";
else oss << parameters.musicVolume;
label = oss.str();
}
write(label, 21, xAlign, yTop + i * yStep, ALIGN_LEFT, itemColor, app, 1, 1);
}
write(menu->items[menu->index].description, 18, xAlign,
yTop + menu->items.size() * yStep + 8, ALIGN_LEFT, sf::Color(60, 80, 220), app, 0, 0);
// Keys
if (menuState == MenuStateFirst)
{
// displaying the standard key configuration
int xKeys = 270;
int yKeys = 380;
sf::Sprite keysSprite;
if (parameters.language == 1) // french
keysSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_KEYS_AZER));
else
keysSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_KEYS_QWER));
keysSprite.setPosition(xKeys, yKeys);
app->draw(keysSprite);
// legend
write(tools::getLabel("keys_move"), 16, xKeys + 190, yKeys + 10, ALIGN_LEFT, sf::Color::White, app, 1, 1);
write(tools::getLabel("keys_time"), 16, xKeys + 295, yKeys + 14, ALIGN_LEFT, sf::Color::White, app, 1, 1);
write(tools::getLabel("keys_fire"), 16, xKeys + 360, yKeys + 54, ALIGN_LEFT, sf::Color::White, app, 1, 1);
write(tools::getLabel("key_spell"), 16, xKeys + 148, yKeys + 184, ALIGN_CENTER, sf::Color::White, app, 1, 1);
// TODO key interact
std::ostringstream oss;
oss << tools::getLabel("keys_select_1") << std::endl << tools::getLabel("keys_select_2");
write(oss.str(), 16, xKeys + 4, yKeys + 100, ALIGN_LEFT, sf::Color::White, app, 1, 1);
}
}
std::ostringstream oss;
oss << APP_NAME << " v" << APP_VERSION << " - 2014-2015 - " << " Seby (code), Pierre \"dejam0rt\" Baron (2D art)";
write(oss.str(), 17, 5, 680, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 1, 1);
}
void WitchBlastGame::renderAchievements()
{
app->draw(introScreenSprite);
if (titleSprite.getPosition().y > 160) titleSprite.move(0, -8);
else if (titleSprite.getPosition().y < 160) titleSprite.setPosition(SCREEN_WIDTH / 2 - 15, 180);
app->draw(titleSprite);
// achievements
write(tools::getLabel("menu_achievements"), 30, 485, 280, ALIGN_CENTER, sf::Color(255, 255, 255, 255), app, 1, 1);
int achWidth = 64, achHeight = 64, x0 = 180, y0 = 380, xStep = 16, yStep = 16, nbProLine = 8;
if (menuAchIndex / 8 < ACHIEV_LINES)
{
sf::RectangleShape rectangle(sf::Vector2f(achWidth, achHeight));
rectangle.setPosition(x0 + (menuAchIndex % nbProLine) * (achWidth + xStep), y0 + (menuAchIndex / nbProLine) * (achHeight + yStep));
rectangle.setOutlineThickness(3);
rectangle.setOutlineColor(sf::Color(50, 255, 50));
app->draw(rectangle);
}
sf::Sprite sprite;
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ACHIEVEMENTS));
for (int k : sortedAchievements)
{
int i = sortedAchievements[k];
sprite.setPosition(x0 + (k % nbProLine) * (achWidth + xStep), y0 + (k / nbProLine) * (achHeight + yStep));
if (achievementState[i] == AchievementDone)
{
sprite.setTextureRect(sf::IntRect( ((i + 1) % 10) * achWidth, ((i + 1) / 10) * achHeight, achWidth, achHeight));
}
else
{
sprite.setTextureRect(sf::IntRect(0, 0, achWidth, achHeight));
}
app->draw(sprite);
}
if (menuAchIndex / 8 >= ACHIEV_LINES)
{
write(tools::getLabel("config_back"), 17, 485, 620, ALIGN_CENTER, sf::Color(255, 255, 255, 255), app, 1, 1);
}
else
{
write(tools::getLabel("config_back"), 17, 485, 620, ALIGN_CENTER, sf::Color(180, 180, 180, 255), app, 1, 1);
sf::Color fontColor = sf::Color::White;
std::stringstream oss;
int achIndex = sortedAchievements[menuAchIndex];
if (!achievementState[achIndex] == AchievementDone && (
achIndex == AchievementGiantSlime
|| achIndex == AchievementCyclops
|| achIndex == AchievementRatKing
|| achIndex == AchievementGiantSpider
|| achIndex == AchievementFrancky
|| achIndex == AchievementVampire)
)
oss << "???";
else
oss << tools::getLabel(achievements[achIndex].label);
oss << ": ";
if (achievementState[achIndex] == AchievementDone)
{
oss << tools::getLabel(achievements[achIndex].label + "_desc");
if (achievements[achIndex].unlockType == UnlockItem && achievements[achIndex].unlock > -1)
oss << "\nUNLOCK: " << tools::getLabel(items[achievements[achIndex].unlock].name);
else if (achievements[achIndex].unlockType == UnlockFunctionality && achievements[achIndex].unlock > -1)
oss << "\nUNLOCK: " << tools::getLabel(functionalityLabel[achievements[achIndex].unlock]);
}
else
{
if (isFunctionalityLocked(FunctionalityAllAchievements))
oss << "???";
else
oss << tools::getLabel(achievements[achIndex].label + "_desc");
fontColor = sf::Color(150, 150, 150);
}
write(oss.str(), 19, 100, 650, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 1, 1);
}
}
void WitchBlastGame::renderCredits()
{
app->draw(introScreenSprite);
if (titleSprite.getPosition().y > 160) titleSprite.move(0, -8);
else if (titleSprite.getPosition().y < 160) titleSprite.setPosition(SCREEN_WIDTH / 2 - 15, 180);
app->draw(titleSprite);
// credits
write(tools::getLabel("credits"), 30, 485, 275, ALIGN_CENTER, sf::Color(255, 255, 255, 255), app, 1, 1);
int yCursorInit = 365;
int yStep = 30;
int xLeft = 30;
int xRight = 470;
int xMarging = 20;
int yCursor = yCursorInit;
write("Code", 22, xLeft, yCursor, ALIGN_LEFT, sf::Color(210, 210, 255, 255), app, 0,0);
yCursor += yStep;
int i = 0;
while (creditsCode[i] != "END")
{
write(creditsCode[i], 19, xLeft + xMarging, yCursor, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 0,0);
yCursor += yStep;
i++;
}
yCursor += yStep;
write("2D Art", 22, xLeft, yCursor, ALIGN_LEFT, sf::Color(210, 210, 255, 255), app, 0,0);
yCursor += yStep;
i = 0;
while (credits2D[i] != "END")
{
write(credits2D[i], 19, xLeft + xMarging, yCursor, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 0,0);
yCursor += yStep;
i++;
}
yCursor += yStep;
write("Sound", 22, xLeft, yCursor, ALIGN_LEFT, sf::Color(210, 210, 255, 255), app, 0,0);
yCursor += yStep;
i = 0;
while (creditsSound[i] != "END")
{
write(creditsSound[i], 19, xLeft + xMarging, yCursor, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 0,0);
yCursor += yStep;
i++;
}
yCursor += yStep;
////// RIGHT
yCursor = yCursorInit + yStep;
write("Music", 22, xRight, yCursor, ALIGN_LEFT, sf::Color(210, 210, 255, 255), app, 0,0);
yCursor += yStep;
i = 0;
while (creditsMusic[i] != "END")
{
write(creditsMusic[i], 19, xRight + xMarging, yCursor, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 0,0);
yCursor += yStep;
i++;
}
yCursor += yStep;
write("Translation", 22, xRight, yCursor, ALIGN_LEFT, sf::Color(210, 210, 255, 255), app, 0,0);
yCursor += yStep;
i = 0;
while (creditsTranslate[i] != "END")
{
write(creditsTranslate[i], 19, xRight + xMarging, yCursor, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 0,0);
yCursor += yStep;
i++;
}
yCursor += yStep;
}
void WitchBlastGame::renderScores(std::vector <StructScore> scoresToRender, std::string title)
{
sf::Sprite bgSprite;
bgSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_HALL_OF_FAME));
app->draw(bgSprite);
// hi-scores-title
write(title, 30, 485, 60, ALIGN_CENTER, sf::Color(0, 0, 0, 255), app, 0, 0);
int xEquip = 540;
//int yEquip = 360;
int xPlayerLeft = 60;
int xPlayerRight = 850;
int xName = 260;
int xTime = 420;
int xLevel = 480;
int xScore = 180;
int y0 = 130;
int yStep = 50;
for (unsigned int i = 0; i < scoresToRender.size() && i < SCORES_MAX; i++)
{
sf::Color color = sf::Color( 15, 15, 15);
if (scoresToRender[i].score == lastScore.score && scoresToRender[i].level == lastScore.level && scoresToRender[i].name == lastScore.name)
{
int fade = 1 + cosf(getAbsolutTime() * 8) * 63;
color = sf::Color(255 - fade, 128, 255 - fade);
}
// equipment
int n = 0;
for (auto ii: scoreEquipement)
if (ii != EQUIP_BOSS_KEY && scoresToRender[i].equip[ii]) n++;
int dx = 30;
if (n > 14) dx = 16;
else if (n > 8) dx = 20;
n = 0;
for (auto ii: scoreEquipement)
{
if (ii != EQUIP_BOSS_KEY && scoresToRender[i].equip[ii])
{
sf::Sprite itemSprite;
itemSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEMS_EQUIP));
itemSprite.setPosition(xEquip + n * dx, y0 + 22 + yStep * i);
itemSprite.setTextureRect(sf::IntRect((ii % 10) * 32, (ii / 10) * 32, 32, 32));
app->draw(itemSprite);
n++;
}
}
if (i < 2)
renderPlayer((i % 2 == 0) ? xPlayerLeft : xPlayerRight, y0 - 14 + yStep * i, scoresToRender[i].equip, scoresToRender[i].shotType, 2, 7);
else if (i >= 8)
renderPlayer((i % 2 == 0) ? xPlayerLeft : xPlayerRight, y0 - 14 + yStep * i, scoresToRender[i].equip, scoresToRender[i].shotType, 0, 8);
else
renderPlayer((i % 2 == 0) ? xPlayerLeft : xPlayerRight, y0 - 14 + yStep * i, scoresToRender[i].equip, scoresToRender[i].shotType, 1, 0);
write(scoresToRender[i].name, 16, xName, y0 + 28 + yStep * i, ALIGN_LEFT, color, app, 0, 0);
std::stringstream levelSS;
levelSS << "lvl " << scoresToRender[i].level;
write(levelSS.str(), 16, xLevel, y0 + 28 + yStep * i, ALIGN_LEFT, color, app, 0, 0);
write(intToString(scoresToRender[i].score), 17, xScore, y0 + 28 + yStep * i, ALIGN_LEFT, color, app, 0, 0);
std::stringstream timeSS;
if (scoresToRender[i].time < 100)
{
timeSS << scoresToRender[i].time << " s";
}
else
{
int minutes = scoresToRender[i].time / 60;
if (minutes < 1) minutes = 1;
timeSS << minutes << " m";
}
write(timeSS.str(), 16, xTime, y0 + 28 + yStep * i, ALIGN_LEFT, color, app, 0, 0);
write(intToString(scoresToRender[i].score), 17, xScore, y0 + 28 + yStep * i, ALIGN_LEFT, color, app, 0, 0);
}
// retrieving from DB ?
if ( (menuScoreIndex == 0 && scoreState == ScoreLoading)
|| (menuScoreIndex == 1 && ((scoreState == ScoreLoading) || (scoreState == ScoreLoadingDay))))
{
std::stringstream oss;
oss << "Loading";
int n = (int)(getAbsolutTime() * 3) % 3;
if (n == 0) oss << ".";
else if (n == 1) oss << "..";
else oss << "...";
write(oss.str(), 15, 20, 20, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 1, 1);
}
}
void WitchBlastGame::renderHiScores()
{
sf::Sprite bgSprite;
bgSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_INTRO));
app->draw(bgSprite);
// hi-scores-title
write(tools::getLabel("hi_scores"), 30, 485, 20, ALIGN_CENTER, sf::Color(255, 255, 255, 255), app, 1, 1);
int x0 = 25;
int x1 = 70;
int x2 = 125;
int x3 = 430;
int y0 = 130;
int yStep = 100;
int xRight = SCREEN_WIDTH / 2;
sf::RectangleShape line(sf::Vector2f(2, 600));
line.setPosition(SCREEN_WIDTH / 2, 80);
app->draw(line);
for (unsigned int i = 0; i < scores.size() && i < SCORES_MAX; i++)
{
int index = i < SCORES_MAX / 2 ? i : i - SCORES_MAX / 2;
sf::Color color = sf::Color( 220, 220, 220);
if (scores[i].score == lastScore.score && scores[i].level == lastScore.level && scores[i].name == lastScore.name)
{
int fade = 1 + cosf(getAbsolutTime() * 8) * 63;
color = sf::Color(255, 128 + fade, 255);
}
renderPlayer(x1 + (i / 5) * xRight, y0 + yStep * index, scores[i].equip, scores[i].shotType, 1, 0);
write(intToString(i + 1), 24, x0 + (i / 5) * xRight, y0 + 30 + yStep * index, ALIGN_CENTER, color, app, 1, 1);
std::stringstream ss;
ss << scores[i].name << " (" << scores[i].level << ")";
write(ss.str(), 17, x2 + (i / 5) * xRight, y0 + 30 + yStep * index, ALIGN_LEFT, color, app, 1, 1);
write(intToString(scores[i].score), 17, x3 + (i / 5) * xRight, y0 + 30 + yStep * index, ALIGN_RIGHT, color, app, 1, 1);
}
}
void WitchBlastGame::renderInGameMenu()
{
menuStuct* menu = &menuInGame;
int xAlign = 290;
int yAlign = 200;
{
// menu
for (unsigned int i = 0; i < menu->items.size(); i++)
{
sf::Color itemColor;
if (menu->index == i)
{
itemColor = sf::Color(255, 255, 255, 255);
sf::Sprite fairySprite;
fairySprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_FAIRY));
fairySprite.setTextureRect(sf::IntRect( 48 * ((int)(8 *getAbsolutTime()) % 2), fairySpriteOffsetY, 48, 48));
fairySprite.setPosition(xAlign - 60, yAlign + i * 90 + 5 * cos( 6 * getAbsolutTime()));
app->draw(fairySprite);
}
else itemColor = sf::Color(120, 120, 120, 255);
std::string label = menu->items[i].label;
write(label, 23, xAlign, yAlign + 10 + i * 90, ALIGN_LEFT, itemColor, app, 1, 1);
write(menu->items[i].description, 15, xAlign, yAlign + i * 90 + 50, ALIGN_LEFT, itemColor, app, 0, 0);
}
}
}
void WitchBlastGame::startGame()
{
lastTime = getAbsolutTime();
prepareIntro();
// Start game loop
while (app->isOpen())
{
deltaTime = getAbsolutTime() - lastTime;
if (deltaTime < 0.008f)
{
float sleepTime = 1.0f / 60.0f - deltaTime;
sf::sleep(sf::seconds(sleepTime));
deltaTime = getAbsolutTime() - lastTime;
}
lastTime = getAbsolutTime();
if (deltaTime > 0.05f) deltaTime = 0.05f;
updateActionKeys();
switch (gameState)
{
case gameStateInit:
case gameStateKeyConfig:
case gameStateJoystickConfig:
case gameStateMenu:
updateMenu();
break;
case gameStateIntro:
updateIntro();
break;
case gameStatePlaying:
case gameStatePlayingPause:
case gameStatePlayingDisplayBoss:
updateRunningGame();
break;
}
onRender();
}
quitGame();
}
void WitchBlastGame::createFloor()
{
// TODO : extracts from createNewGame
}
void WitchBlastGame::closeDoors()
{
if (!currentMap->isCleared())
{
int i;
for(i = 0; i < MAP_WIDTH; i++)
{
if (currentMap->isDoor(i, 0)) currentMap->closeDoor(i, 0);
if (currentMap->isDoor(i, MAP_HEIGHT - 1)) currentMap->closeDoor(i, MAP_HEIGHT - 1);
}
for(i = 0; i < MAP_HEIGHT; i++)
{
if (currentMap->isDoor(0, i)) currentMap->closeDoor(0, i);
if (currentMap->isDoor(MAP_WIDTH - 1, i)) currentMap->closeDoor(MAP_WIDTH - 1, i);
}
roomClosed = true;
}
}
void WitchBlastGame::openDoors()
{
int i;
for(i = 0; i < MAP_WIDTH; i++)
{
if (currentMap->isDoor(i, 0)) currentMap->openDoor(i, 0);
if (currentMap->isDoor(i, MAP_HEIGHT - 1)) currentMap->openDoor(i, MAP_HEIGHT - 1);
}
for(i = 0; i < MAP_HEIGHT; i++)
{
if (currentMap->isDoor(0, i)) currentMap->openDoor(0, i);
if (currentMap->isDoor(MAP_WIDTH - 1, i)) currentMap->openDoor(MAP_WIDTH - 1, i);
}
roomClosed = false;
SoundManager::getInstance().playSound(SOUND_DOOR_OPENING);
if (currentMap->hasNeighbourUp() == 2 && !bossRoomOpened)
currentMap->closeDoor(MAP_WIDTH/2, 0);
else if (currentMap->hasNeighbourUp() == 1)
doorEntity[0]->openDoor();
if (currentMap->hasNeighbourLeft() == 2 && !bossRoomOpened)
currentMap->closeDoor(0, MAP_HEIGHT / 2);
else if (currentMap->hasNeighbourLeft() == 1)
doorEntity[1]->openDoor();
if (currentMap->hasNeighbourDown() == 2 && !bossRoomOpened)
currentMap->closeDoor(MAP_WIDTH / 2, MAP_HEIGHT - 1);
else if (currentMap->hasNeighbourDown() == 1)
doorEntity[2]->openDoor();
if (currentMap->hasNeighbourRight() == 2 && !bossRoomOpened)
currentMap->closeDoor(MAP_WIDTH - 1, MAP_HEIGHT / 2);
else if (currentMap->hasNeighbourRight() == 1)
doorEntity[3]->openDoor();
}
EnemyEntity* WitchBlastGame::getBoss()
{
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_ENEMY_BOSS) return static_cast<EnemyEntity*> (e);
}
return NULL;
}
int WitchBlastGame::getEnemyCount()
{
int n=0;
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_ENEMY && e->getType() <= ENTITY_ENEMY_MAX_COUNT) n++;
}
return n;
}
int WitchBlastGame::getUndeadCount()
{
int n=0;
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_ENEMY && e->getType() <= ENTITY_ENEMY_MAX_COUNT)
{
EnemyEntity* enemy = dynamic_cast<EnemyEntity*>(e);
if (enemy->canCollide() && (enemy->getEnemyType() == EnemyTypeZombie || enemy->getEnemyType() == EnemyTypeZombieDark
|| enemy->getEnemyType() == EnemyTypeGhost || enemy->getEnemyType() == EnemyTypeVampire || enemy->getEnemyType() == EnemyTypeBat_invocated) )
n++;
}
}
return n;
}
void WitchBlastGame::killArtefactDescription()
{
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_ARTIFACT_DESCRIPTION)
{
e->setDying(true);
}
}
}
void WitchBlastGame::animateEffects()
{
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_EFFECT)
e->animate(deltaTime);
}
}
void WitchBlastGame::destroyUndead(int damage)
{
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_ENEMY && e->getType() <= ENTITY_ENEMY_MAX_COUNT)
{
EnemyEntity* enemy = dynamic_cast<EnemyEntity*>(e);
if (enemy->canCollide() && (enemy->getEnemyType() == EnemyTypeZombie || enemy->getEnemyType() == EnemyTypeZombieDark
|| enemy->getEnemyType() == EnemyTypeGhost || enemy->getEnemyType() == EnemyTypeVampire || enemy->getEnemyType() == EnemyTypeBat_invocated) )
{
enemy->hurt(BaseCreatureEntity::getHurtParams(damage, ShotTypeStandard, 0, false, SourceTypeMelee, EnemyTypeNone, false));
SpriteEntity* spriteCone = new SpriteEntity(
ImageManager::getInstance().getImage(IMAGE_LIGHT_CONE),
enemy->getX(), enemy->getZ() - 290);
spriteCone->setZ(1000.0f);
spriteCone->setFading(true);
spriteCone->setAge(-1.2f);
spriteCone->setLifetime(2.4f);
spriteCone->setRenderAdd();
}
}
}
}
int WitchBlastGame::getItemsCount()
{
int n=0;
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_ITEM) n++;
}
return n;
}
Vector2D WitchBlastGame::getNearestEnemy(float x, float y)
{
Vector2D target(-100.0f, -100.0f);
float distanceMin = -1.0f;
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_ENEMY && e->getType() <= ENTITY_ENEMY_MAX_COUNT)
{
// enemy
EnemyEntity* enemy = dynamic_cast<EnemyEntity*>(e);
if (enemy->canCollide())
{
float d2 = (x - enemy->getX()) * (x - enemy->getX()) + (y - enemy->getY()) * (y - enemy->getY());
if (target.x < -1.0f || d2 < distanceMin)
{
distanceMin = d2;
target.x = enemy->getX();
target.y = enemy->getY();
}
}
}
}
return target;
}
void WitchBlastGame::setDoorVisible(int n)
{
if (n >= 0 && n < 4)
doorEntity[n]->setVisible(true);
}
void WitchBlastGame::checkDoor(int doorId, roomTypeEnum roomCurrent, roomTypeEnum roomNeighbour, bool isNeighbourKnown)
{
if (roomNeighbour == roomTypeNULL)
{
doorEntity[doorId]->setVisible(false);
return;
}
doorEntity[doorId]->setVisible(isNeighbourKnown);
doorEntity[doorId]->setDoorType(currentMap->getDoorType(doorId));
if (roomNeighbour == roomTypeBoss && !bossRoomOpened)
{
doorEntity[doorId]->setOpen(false);
switch (doorId)
{
case 0:
currentMap->closeDoor(MAP_WIDTH/2, 0);
break;
case 1:
currentMap->closeDoor(0, MAP_HEIGHT / 2);
break;
case 2:
currentMap->closeDoor(MAP_WIDTH/2, MAP_HEIGHT - 1);
break;
case 3:
currentMap->closeDoor(MAP_WIDTH - 1, MAP_HEIGHT / 2);
break;
}
}
else
doorEntity[doorId]->setOpen(true);
}
void WitchBlastGame::refreshMap()
{
// clean the sprites from old map
EntityManager::getInstance().partialClean(10);
// if new map, it has to be randomized
bool generateMap = !(currentFloor->getMap(floorX, floorY)->isVisited());
currentMap = currentFloor->getAndVisitMap(floorX, floorY);
// load the map
dungeonEntity->refreshMap();
player->setMap(currentMap, TILE_WIDTH, TILE_HEIGHT, 0, 0);
refreshMinimap();
if(generateMap)
this->generateMap();
else
{
if (currentMap->getRoomType() == roomTypeMerchant)
{
new PnjEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2 - 1) * TILE_HEIGHT,
0);
}
}
// check doors
checkDoor(0, currentMap->getRoomType(), currentMap->getNeighbourUp(), currentMap->hasKnownNeighbour(North, true));
checkDoor(1, currentMap->getRoomType(), currentMap->getNeighbourLeft(), currentMap->hasKnownNeighbour(West, true));
checkDoor(2, currentMap->getRoomType(), currentMap->getNeighbourDown(), currentMap->hasKnownNeighbour(South, true));
checkDoor(3, currentMap->getRoomType(), currentMap->getNeighbourRight(), currentMap->hasKnownNeighbour(East, true));
// pet slime
if (player->isEquiped(EQUIP_PET_SLIME) && currentMap->getRoomType() != roomTypeTemple) new SlimePetEntity();
// barrels
checkDestroyableObjects();
}
void WitchBlastGame::refreshMinimap()
{
for (int j=0; j < FLOOR_HEIGHT; j++)
for (int i=0; i < FLOOR_WIDTH; i++)
{
int roomType = currentFloor->getRoom(i, j);
if (roomType > roomTypeNULL && currentFloor->getMap(i, j)->isVisited()&& currentFloor->getMap(i, j)->isKnown())
{
if (roomType == roomTypeStarting
|| roomType == roomTypeChallenge
|| roomType == roomTypeBonus
|| roomType == roomTypeKey
|| roomType == roomTypeBoss
|| roomType == roomTypeStandard
|| roomType == roomTypeSecret)
{
if ( currentFloor->getMap(i, j)->containsHealth())
miniMap->setTile(i, j, 5);
else
miniMap->setTile(i, j, roomTypeStandard);
}
else
{
if (roomType == roomTypeMerchant)
miniMap->setTile(i, j, 3);
else if (roomType == roomTypeTemple)
miniMap->setTile(i, j, 7);
else if (roomType == roomTypeSecret)
miniMap->setTile(i, j, 8);
else
miniMap->setTile(i, j, currentFloor->getRoom(i, j));
}
}
else if (roomType > roomTypeNULL && currentFloor->getMap(i, j)->isKnown())
{
switch (roomType)
{
case roomTypeBoss:
miniMap->setTile(i, j, 12);
proceedEvent(EventFindBossDoor);
break;
case roomTypeChallenge:
miniMap->setTile(i, j, 15);
proceedEvent(EventFindBossDoor);
break;
case roomTypeMerchant:
miniMap->setTile(i, j,
game().getPlayer()->isEquiped(EQUIP_FLOOR_MAP) ? 13 : 11 );
break;
case roomTypeKey:
miniMap->setTile(i, j,
game().getPlayer()->isEquiped(EQUIP_FLOOR_MAP) ? 14 : 11 );
break;
case roomTypeExit:
miniMap->setTile(i, j,
game().getPlayer()->isEquiped(EQUIP_FLOOR_MAP) ? 16 : 11 );
break;
case roomTypeTemple:
miniMap->setTile(i, j,
game().getPlayer()->isEquiped(EQUIP_FLOOR_MAP) ? 17 : 11 );
break;
case roomTypeBonus:
miniMap->setTile(i, j,
game().getPlayer()->isEquiped(EQUIP_FLOOR_MAP) ? 2 : 11 );
break;
case roomTypeSecret:
miniMap->setTile(i, j, 18 );
break;
case roomTypeStandard:
case roomTypeStarting:
miniMap->setTile(i, j, 11);
break;
case roomTypeNULL:
miniMap->setTile(i, j, 0);
break;
}
}
else
miniMap->setTile(i, j, 0);
}
miniMap->setTile(floorX, floorY, 10);
int xMap = 760 + (6 - floorX) * 19;
if (xMap < 710) xMap = 710;
else if (xMap > 795) xMap = 795;
int yMap = 620 + (3 - floorY) * 15;
if (yMap < 596) yMap = 596;
else if (yMap > 640) yMap = 640;
miniMapEntity->setX(xMap);
miniMapEntity->setY(yMap);
}
void WitchBlastGame::checkEntering()
{
if (!currentMap->isCleared())
{
player->setEntering();
SoundManager::getInstance().playSound(SOUND_DOOR_CLOSING);
for (int i=0; i<4; i++)
doorEntity[i]->closeDoor();
}
}
void WitchBlastGame::saveMapItems()
{
currentMap->cleanMapObjects();
// blood
std::vector <displayEntityStruct> blood = dungeonEntity->getBlood();
for (auto particle: blood)
currentMap->addSprite(ENTITY_BLOOD, particle.frame, particle.x, particle.y, particle.scale);
// corpses
std::vector <displayEntityStruct> corpses = dungeonEntity->getCorpses();
for (auto particle: corpses)
currentMap->addSprite(ENTITY_CORPSE, particle.frame, particle.x, particle.y, particle.scale);
EntityManager::EntityList* entityList = EntityManager::getInstance().getList();
EntityManager::EntityList::iterator it;
for (it = entityList->begin (); it != entityList->end ();)
{
GameEntity* e = *it;
it++;
ItemEntity* itemEntity = dynamic_cast<ItemEntity*>(e);
ChestEntity* chestEntity = dynamic_cast<ChestEntity*>(e);
if (itemEntity != NULL && !itemEntity->getDying())
{
currentMap->addItem(itemEntity->getItemType(), itemEntity->getX(), itemEntity->getY(), itemEntity->getMerchandise());
} // endif
else if (chestEntity != NULL && !chestEntity->getDying())
{
currentMap->addChest(chestEntity->getChestType(), chestEntity->getOpened(), chestEntity->getX(), chestEntity->getY());
} // endif
} // end for
}
void WitchBlastGame::moveToOtherMap(int direction)
{
// stairs to next level
if (direction == 8 && currentMap->getRoomType() == roomTypeExit)
{
if (player->getPlayerStatus() != PlayerEntity::playerStatusGoingNext)
{
player->setLeavingLevel();
xGame[xGameTypeFade].active = true;
xGame[xGameTypeFade].param = X_GAME_FADE_OUT;
xGame[xGameTypeFade].timer = FADE_OUT_DELAY;
player->setVelocity(Vector2D(0.0f, - INITIAL_PLAYER_SPEED / 2));
}
}
// go to another room
else
{
saveMapItems();
switch (direction)
{
case (4):
floorX--;
player->moveTo((MAP_WIDTH * TILE_WIDTH), player->getY());
player->move(4);
break;
case (6):
floorX++;
player->moveTo(0, player->getY());
player->move(6);
break;
case (8):
floorY--;
player->moveTo(player->getX(), MAP_HEIGHT * TILE_HEIGHT);
player->move(8);
break;
case (2):
floorY++;
player->moveTo(player->getX(), 0);
break;
}
refreshMap();
checkEntering();
currentMap->restoreMapObjects();
saveInFight.x = player->getX();
saveInFight.y = player->getY();
saveInFight.direction = direction;
saveMapItems();
if (!currentMap->isCleared())
{
saveGame();
}
}
}
void WitchBlastGame::onRender()
{
// clear the view
app->clear(sf::Color::Black);
switch (gameState)
{
case gameStateInit:
case gameStateKeyConfig:
case gameStateJoystickConfig:
case gameStateMenu:
renderMenu();
break;
case gameStatePlaying:
case gameStatePlayingPause:
case gameStatePlayingDisplayBoss:
renderRunningGame();
break;
case gameStateIntro:
renderIntro();
break;
}
app->display();
}
void WitchBlastGame::renderHudShots(sf::RenderTarget* app)
{
int xHud = 277;
int yHud = 655;
int index = 0;
for (int i = 0; i < SPECIAL_SHOT_SLOTS; i++)
{
if (i == 0 || player->getShotType(i) != ShotTypeStandard)
{
int type_shot = player->getShotType(i);
uiSprites.shotsSprite.setPosition(xHud + 55 * index, yHud);
if (index == player->getShotIndex())
{
uiSprites.shotsSprite.setTextureRect(sf::IntRect(0, 0, 48, 48));
app->draw(uiSprites.shotsSprite);
}
uiSprites.shotsSprite.setTextureRect(sf::IntRect(48 * ( 1 + type_shot), 0, 48, 48));
app->draw(uiSprites.shotsSprite);
// level
if (i > 0)
{
std::ostringstream oss;
oss << "lvl " << player->getShotLevel(i) + 1;
write(oss.str(), 10, xHud + 55 * index + 10, yHud + 48, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 0, 0);
}
index++;
}
}
}
void WitchBlastGame::generateBlood(float x, float y, BaseCreatureEntity::enumBloodColor bloodColor)
{
dungeonEntity->generateBlood(x, y, bloodColor);
// double blood if the "Blood Snake" object is equipped
if (player->isEquiped(EQUIP_BLOOD_SNAKE)) dungeonEntity->generateBlood(x, y, bloodColor);
}
void WitchBlastGame::addCorpse(float x, float y, int frame)
{
dungeonEntity->addCorpse(x, y, frame);
}
void WitchBlastGame::showArtefactDescription(enumItemType itemType)
{
killArtefactDescription();
new ArtefactDescriptionEntity(itemType);
}
void WitchBlastGame::generateMap()
{
saveInFight.monsters.clear();
if (currentMap->getRoomType() == roomTypeStandard)
generateStandardMap();
else if (currentMap->getRoomType() == roomTypeBonus)
{
currentMap->setCleared(true);
Vector2D v = currentMap->generateBonusRoom();
int bonusType = getRandomEquipItem(false, false);
if (items[FirstEquipItem + bonusType].familiar > FamiliarNone)
{
new ChestEntity(v.x, v.y, ChestFairy + items[FirstEquipItem + bonusType].familiar, false);
}
else
{
new ItemEntity( (enumItemType)(FirstEquipItem + bonusType), v.x ,v.y);
}
}
else if (currentMap->getRoomType() == roomTypeKey)
{
currentMap->generateKeyRoom();
initMonsterArray();
int x0 = MAP_WIDTH / 2;
int y0 = MAP_HEIGHT / 2;
monsterArray[x0][y0] = true;
if (level == 1)
{
findPlaceMonsters(EnemyTypeRat, 2);
findPlaceMonsters(EnemyTypeBat, 2);
}
else if (level < 6)
{
findPlaceMonsters(EnemyTypeRat, 5);
findPlaceMonsters(EnemyTypeBat, 5);
for (int i = 2; i < level; i++)
{
if (rand()%2 == 0)findPlaceMonsters(EnemyTypeImpBlue, 1);
else findPlaceMonsters(EnemyTypeImpRed, 1);
}
}
else
{
findPlaceMonsters(EnemyTypeZombie, 5);
findPlaceMonsters(EnemyTypeBat, 5);
for (int i = 5; i < level; i++)
{
if (rand()%2 == 0)findPlaceMonsters(EnemyTypeImpBlue, 1);
else findPlaceMonsters(EnemyTypeImpRed, 1);
}
}
}
else if (currentMap->getRoomType() == roomTypeMerchant)
{
currentMap->generateMerchantRoom();
ItemEntity* item1 = new ItemEntity(
ItemHealth,
(MAP_WIDTH / 2 - 1) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + 5);
item1->setMerchandise(true);
ItemEntity* item3 = new ItemEntity(
ItemHealthSmall,
(MAP_WIDTH / 2 + 1) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + 5);
item3->setMerchandise(true);
int bonusType = getRandomEquipItem(true, true);
ItemEntity* item2 = new ItemEntity(
(enumItemType)(FirstEquipItem + bonusType),
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + 5);
item2->setMerchandise(true);
// level item ?
if (rand() % 3 == 0)
{
int r = rand() % 4;
int item4Type = -1;
switch (r)
{
case 0:
if (!game().getPlayer()->isEquiped(EQUIP_FLOOR_MAP)) item4Type = ItemFloorMap;
break;
case 1:
if (!game().getPlayer()->isEquiped(EQUIP_ALCOHOL)) item4Type = ItemAlcohol;
break;
case 2:
if (!game().getPlayer()->isEquiped(EQUIP_LUCK)) item4Type = ItemLuck;
break;
default:
if (!game().getPlayer()->isEquiped(EQUIP_FAIRY_POWDER) && player->getFairieNumber() > 0) item4Type = ItemFairyPowder;
break;
}
if (item4Type > -1)
{
ItemEntity* item4 = new ItemEntity(
(enumItemType)(item4Type),
(MAP_WIDTH / 2 + 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + 5);
item4->setMerchandise(true);
}
}
// consumable item
if (rand() % 3 == 0) // potion
{
ItemEntity* item5 = new ItemEntity(
(enumItemType)(ItemPotion01 + rand() % NUMBER_UNIDENTIFIED),
(MAP_WIDTH / 2 - 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + 5);
item5->setMerchandise(true);
}
else // scroll
{
ItemEntity* item5 = new ItemEntity(
(enumItemType)ItemScrollRevelation,
(MAP_WIDTH / 2 - 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + 5);
item5->setMerchandise(true);
}
new PnjEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2 - 1) * TILE_HEIGHT,
0);
currentMap->setCleared(true);
proceedEvent(EventFindShop);
}
else if (currentMap->getRoomType() == roomTypeChallenge)
{
currentMap->generateRoomWithoutHoles(0);
if (challengeLevel == 1)
{
addMonster(EnemyTypeBubble,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else
{
addMonster(challengeLevel >= 3 ? EnemyTypeBubbleIce : EnemyTypeBubble,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 - 80,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
addMonster(challengeLevel >= 4 ? EnemyTypeBubbleGreater : EnemyTypeBubble,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 + 80,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
playMusic(MusicChallenge);
}
else if (currentMap->getRoomType() == roomTypeBoss)
{
currentMap->generateRoomWithoutHoles(0);
if (level == 1)
{
findPlaceMonsters(EnemyTypeRat, 2);
addMonster(EnemyTypeButcher,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
testAndAddMessageToQueue(MsgInfoButcher);
}
else if (level == 2)
{
addMonster(EnemyTypeSlimeBoss,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
testAndAddMessageToQueue(MsgInfoGiantSlime);
}
else if (level == 3)
{
addMonster(EnemyTypeCyclops,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
testAndAddMessageToQueue(MsgInfoCyclops);
}
else if (level == 4)
{
addMonster(EnemyTypeRatKing,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
testAndAddMessageToQueue(MsgInfoWererat);
}
else if (level == 5)
{
addMonster(EnemyTypeSpiderGiant,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
testAndAddMessageToQueue(MsgInfoGiantSpiderBefore);
}
else if (level == 6)
{
addMonster(EnemyTypeFrancky,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
testAndAddMessageToQueue(MsgInfoFranky);
}
else if (level == 7)
{
addMonster(EnemyTypeVampire,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
testAndAddMessageToQueue(MsgInfoVampire);
}
else if (level == 8)
{
// TODO
GiantSpiderEntity* b1 = new GiantSpiderEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 - 100,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
b1->setLabelDy(10);
FranckyEntity* b2 = new FranckyEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
b2->setLabelDy(-530);
KingRatEntity* b3 = new KingRatEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 + 100,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
b3->setLabelDy(-20);
new CyclopsEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 + 120,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
new CyclopsEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 - 120,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else // level > 6
{
GiantSpiderEntity* b1 = new GiantSpiderEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 - 100,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
b1->setLabelDy(10);
GiantSlimeEntity* b2 = new GiantSlimeEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
b2->setLabelDy(-510);
KingRatEntity* b3 = new KingRatEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 + 100,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
b3->setLabelDy(-20);
CyclopsEntity* b4 = new CyclopsEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
b4->setLabelDy(-540);
findPlaceMonsters(EnemyTypeCauldron, 2);
findPlaceMonsters(EnemyTypeImpBlue, 4);
}
playMusic(MusicBoss);
// boss screen
if (parameters.displayBossPortrait)
{
gameState = gameStatePlayingDisplayBoss;
bossDisplayTimer = 0.0f;
bossDisplayState = 0;
dungeonEntity->animate(0.0f);
}
}
else if (currentMap->getRoomType() == roomTypeStarting)
{
currentMap->generateRoomWithoutHoles(0);
currentMap->setCleared(true);
}
else if (currentMap->getRoomType() == roomTypeExit)
{
currentMap->generateExitRoom();
currentMap->setCleared(true);
new ChestEntity((TILE_WIDTH * MAP_WIDTH * 0.5f),
(TILE_HEIGHT * MAP_HEIGHT * 0.5f),
ChestExit, false);
}
else if (currentMap->getRoomType() == roomTypeTemple)
{
currentMap->generateTempleRoom();
currentMap->setCleared(true);
proceedEvent(EventFindTemple);
}
else if (currentMap->getRoomType() == roomTypeSecret)
{
currentMap->generateSecretRoom();
if (rand() % 7 > 0)
{
new ChestEntity((TILE_WIDTH * MAP_WIDTH * 0.5f + TILE_WIDTH),
(TILE_HEIGHT * MAP_HEIGHT * 0.5f),
ChestBasic, false);
new ChestEntity((TILE_WIDTH * MAP_WIDTH * 0.5f - TILE_WIDTH),
(TILE_HEIGHT * MAP_HEIGHT * 0.5f),
ChestBasic, false);
}
else
{
int bonusType = getRandomEquipItem(false, false);
if (items[FirstEquipItem + bonusType].familiar > FamiliarNone)
{
new ChestEntity(TILE_WIDTH * MAP_WIDTH * 0.5f,
TILE_HEIGHT * MAP_HEIGHT * 0.5f,
ChestFairy + items[FirstEquipItem + bonusType].familiar, false);
}
else
{
new ItemEntity( (enumItemType)(FirstEquipItem + bonusType),
TILE_WIDTH * MAP_WIDTH * 0.5f,
TILE_HEIGHT * MAP_HEIGHT * 0.5f);
}
}
currentMap->setCleared(true);
// secret found text
TextEntity* text = new TextEntity(tools::getLabel("secret_found"),
25,
MAP_WIDTH * 0.5f * TILE_WIDTH,
MAP_HEIGHT * 0.5f * TILE_HEIGHT + 10.0f);
text->setAlignment(ALIGN_CENTER);
text->setLifetime(2.5f);
text->setWeight(-36.0f);
text->setZ(1200);
text->setColor(TextEntity::COLOR_FADING_WHITE);
SoundManager::getInstance().playSound(SOUND_SECRET);
}
else // "normal" room
currentMap->randomize(currentMap->getRoomType());
}
void WitchBlastGame::write(std::string str, int size, float x, float y, int align, sf::Color color, sf::RenderTarget* app, int xShadow = 0, int yShadow = 0)
{
myText.setString(str);
myText.setString(sf::String::fromUtf8(str.begin(), str.end()));
myText.setCharacterSize(size);
float xFont = x;
if (align == ALIGN_CENTER)
xFont = x - myText.getLocalBounds().width / 2;
else if (align == ALIGN_RIGHT)
xFont = x - myText.getLocalBounds().width;
if (xShadow != 0 && yShadow != 0)
{
myText.setPosition(xFont + xShadow, y + yShadow);
myText.setColor(sf::Color(0, 0, 0, 255));
app->draw(myText);
}
myText.setPosition(xFont, y);
myText.setColor(color);
app->draw(myText);
}
void WitchBlastGame::initMonsterArray()
{
for (int i = 0; i < MAP_WIDTH; i++)
for (int j = 0; j < MAP_HEIGHT; j++)
monsterArray[i][j] = false;
}
void WitchBlastGame::addMonster(enemyTypeEnum monsterType, float xm, float ym)
{
StructMonster monster;
monster.id = monsterType;
monster.x = xm;
monster.y = ym;
saveInFight.monsters.push_back(monster);
switch (monsterType)
{
case EnemyTypeRat:
new RatEntity(xm, ym - 2, RatEntity::RatTypeNormal, false);
proceedEvent(EventMeetRatsOrBats);
break;
case EnemyTypeRatGreen:
new GreenRatEntity(xm, ym - 2);
proceedEvent(EventMeetRatsOrBats);
break;
case EnemyTypeRatBlack:
new BlackRatEntity(xm, ym - 5, BlackRatEntity::RatBlackTypeNormal);
break;
case EnemyTypeRatHelmet:
new RatEntity(xm, ym - 2, RatEntity::RatTypeHelmet, false);
break;
case EnemyTypeRatBlackHelmet:
new BlackRatEntity(xm, ym - 5, BlackRatEntity::RatBlackTypeHelmet);
break;
case EnemyTypeBat:
new BatEntity(xm, ym, BatStandard, false);
proceedEvent(EventMeetRatsOrBats);
break;
case EnemyTypeBatSkeleton:
new BatEntity(xm, ym, BatSkeleton, false);
break;
case EnemyTypeSnake:
new SnakeEntity(xm, ym, SnakeEntity::SnakeTypeNormal, false);
proceedEvent(EventMeetSnakes);
break;
case EnemyTypeSnakeBlood:
new SnakeEntity(xm, ym, SnakeEntity::SnakeTypeBlood, false);
proceedEvent(EventMeetSnakes);
break;
case EnemyTypeEvilFlower:
new EvilFlowerEntity(xm, ym - 2, FlowerTypeStandard);
break;
case EnemyTypeEvilFlowerIce:
new EvilFlowerEntity(xm, ym - 2, FlowerTypeIce);
break;
case EnemyTypeEvilFlowerFire:
new EvilFlowerEntity(xm, ym - 2, FlowerTypeFire);
break;
case EnemyTypeSlime:
new SlimeEntity(xm, ym, SlimeTypeStandard, false);
break;
case EnemyTypeImpRed:
new ImpEntity(xm, ym, ImpEntity::ImpTypeRed);
break;
case EnemyTypeImpBlue:
new ImpEntity(xm, ym, ImpEntity::ImpTypeBlue);
break;
case EnemyTypeSlimeRed:
new SlimeEntity(xm, ym, SlimeTypeRed, false);
break;
case EnemyTypeSlimeBlue:
new SlimeEntity(xm, ym, SlimeTypeBlue, false);
break;
case EnemyTypeSlimeViolet:
new SlimeEntity(xm, ym, SlimeTypeViolet, false);
break;
case EnemyTypePumpkin:
new PumpkinEntity(xm, ym, false);
break;
case EnemyTypeWitch:
new WitchEntity(xm, ym, WitchEntity::WitchTypeNormal);
proceedEvent(EventMeetWitches);
break;
case EnemyTypeWitchRed:
new WitchEntity(xm, ym, WitchEntity::WitchTypeRed);
proceedEvent(EventMeetWitches);
break;
case EnemyTypeCauldron:
new CauldronEntity(xm, ym, CauldronTypeStandard);
break;
case EnemyTypeCauldronElemental:
new CauldronEntity(xm, ym, CauldronTypeElemental);
break;
case EnemyTypeSpiderEgg:
new SpiderEggEntity(xm, ym, false);
break;
case EnemyTypeSpiderEgg_invocated:
new SpiderEggEntity(xm, ym, true);
break;
case EnemyTypeSpiderLittle:
new LittleSpiderEntity(xm, ym, SpiderTypeStandard, false);
break;
case EnemyTypeSpiderTarantula:
new LittleSpiderEntity(xm, ym, SpiderTypeTarantula, false);
break;
case EnemyTypeGhost:
new GhostEntity(xm, ym);
break;
case EnemyTypeZombie:
new ZombieEntity(xm, ym, false);
break;
case EnemyTypeZombieDark:
new ZombieDarkEntity(xm, ym);
break;
case EnemyTypeBogeyman:
new BogeymanEntity(xm, ym);
break;
case EnemyTypeSausage:
new SausageEntity(xm, ym, false);
break;
case EnemyTypeSpiderLittle_invocated:
new LittleSpiderEntity(xm, ym, SpiderTypeStandard, true);
break;
case EnemyTypeSpiderTarantula_invocated:
new LittleSpiderEntity(xm, ym, SpiderTypeTarantula, true);
break;
case EnemyTypeBubble:
new BubbleEntity(xm, ym, BubbleStandard, 0);
break;
case EnemyTypeBubbleIce:
new BubbleEntity(xm, ym, BubbleIce, 0);
break;
case EnemyTypeBubbleGreater:
new BubbleEntity(xm, ym, BubbleTriple, 0);
break;
case EnemyTypeSlimeLarge:
new LargeSlimeEntity(xm, ym, SlimeTypeStandard);
break;
case EnemyTypeSlimeBlueLarge:
new LargeSlimeEntity(xm, ym, SlimeTypeBlue);
break;
case EnemyTypeSlimeRedLarge:
new LargeSlimeEntity(xm, ym, SlimeTypeRed);
break;
case EnemyTypeSlimeVioletLarge:
new LargeSlimeEntity(xm, ym, SlimeTypeViolet);
break;
case EnemyTypeButcher:
new ButcherEntity(xm, ym);
break;
case EnemyTypeSlimeBoss:
new GiantSlimeEntity(xm, ym);
break;
case EnemyTypeCyclops:
new CyclopsEntity(xm, ym);
break;
case EnemyTypeRatKing:
new KingRatEntity(xm, ym);
break;
case EnemyTypeSpiderGiant:
new GiantSpiderEntity(xm, ym);
break;
case EnemyTypeFrancky:
new FranckyEntity(xm, ym);
break;
case EnemyTypeVampire:
new VampireEntity(xm, ym);
break;
default:
std::cout << "[WARNING] Enemy (" << monsterType << ") not handled in switch.\n";
}
}
void WitchBlastGame::findPlaceMonsters(enemyTypeEnum monsterType, int amount)
{
// find a suitable place
bool isMonsterFlying = monsterType == EnemyTypeBat
|| monsterType == EnemyTypeImpBlue
|| monsterType == EnemyTypeImpRed;
bool isMonsterLarge = monsterType == EnemyTypeSlimeLarge
|| monsterType == EnemyTypeSlimeBlueLarge
|| monsterType == EnemyTypeSlimeRedLarge
|| monsterType == EnemyTypeSlimeVioletLarge;
bool bOk;
int xm, ym;
float xMonster, yMonster;
for (int index = 0; index < amount; index++)
{
bOk = false;
int watchdog = 200;
while (!bOk && watchdog > 0)
{
bOk = true;
watchdog--;
if (isMonsterLarge)
{
xm = 2 +rand() % (MAP_WIDTH - 5);
ym = 2 +rand() % (MAP_HEIGHT - 5);
}
else
{
xm = 1 +rand() % (MAP_WIDTH - 3);
ym = 1 +rand() % (MAP_HEIGHT - 3);
}
if (monsterArray[xm][ym])
{
bOk = false;
}
if (bOk && !isMonsterFlying && !currentMap->isWalkable(xm, ym))
{
bOk = false;
}
if (bOk && isMonsterFlying && !currentMap->isFlyable(xm, ym))
{
bOk = false;
}
if (bOk)
{
xMonster = xm * TILE_WIDTH + TILE_WIDTH * 0.5f;
yMonster = ym * TILE_HEIGHT+ TILE_HEIGHT * 0.5f;
float dist2 = (xMonster - player->getX())*(xMonster - player->getX()) + (yMonster - player->getY())*(yMonster - player->getY());
if ( dist2 < 75000.0f)
{
bOk = false;
}
else
{
addMonster(monsterType, xMonster, yMonster);
monsterArray[xm][ym] = true;
}
}
}
}
}
bool WitchBlastGame::isAdvanced()
{
return (achievementState[AchievementVampire] == AchievementDone);
}
bool WitchBlastGame::isAdvancedLevel()
{
if (isAdvanced())
{
return (rand() % 150 < getAchievementsPercents());
}
else
return false;
}
void WitchBlastGame::generateStandardMap()
{
initMonsterArray();
saveInFight.monsters.clear();
generateStandardRoom(level, isAdvancedLevel());
}
item_equip_enum WitchBlastGame::getRandomEquipItem(bool toSale = false, bool noFairy = false)
{
std::vector<int> bonusSet;
int setSize = 0;
for (int i = 0; i < NUMBER_EQUIP_ITEMS; i++)
{
bool itemOk = true;
int eq = i + FirstEquipItem;
if (player->isEquiped(i)) itemOk = false;
if (itemOk && presentItems[i]) itemOk = false;
// TODO item already in floor
if (itemOk && toSale && !items[eq].canBeSold) itemOk = false;
if (itemOk && !toSale && !items[eq].canBeFound) itemOk = false;
if (itemOk && items[eq].level > level) itemOk = false;
if (itemOk && isItemLocked((enumItemType)eq)) itemOk = false;
if (itemOk && items[eq].requirement >= FirstEquipItem
&& !player->isEquiped(items[eq].requirement - FirstEquipItem)) itemOk = false;
if (itemOk && toSale && level == 1 && items[eq].price > 25) itemOk = false;
if (itemOk && toSale && level == 2 && items[eq].price > 35) itemOk = false;
if (itemOk && (items[eq].specialShot != ShotTypeStandard && items[eq].level < 3) && player->canGetNewShot(false))
itemOk = false;
if (itemOk && (items[eq].specialShot != ShotTypeStandard && items[eq].level >= 3) && player->canGetNewShot(true))
itemOk = false;
if (itemOk && i == EQUIP_BOOK_DUAL && (player->isEquiped(EQUIP_BOOK_DUAL_QUICK) || player->isEquiped(EQUIP_RAPID_SHOT)))
itemOk = false;
if (itemOk && i == EQUIP_BOOK_DUAL_QUICK && (player->isEquiped(EQUIP_BOOK_DUAL) || player->isEquiped(EQUIP_RAPID_SHOT)))
itemOk = false;
if (itemOk && i == EQUIP_RAPID_SHOT && (player->isEquiped(EQUIP_BOOK_DUAL_QUICK) || player->isEquiped(EQUIP_BOOK_DUAL)))
itemOk = false;
if (itemOk && noFairy && items[eq].familiar != FamiliarNone) itemOk = false;
if (itemOk)
{
int n = 0;
switch (items[eq].rarity)
{
case RarityCommon:
n = 8;
break;
case RarityUncommon:
n = 4;
break;
case RarityRare:
n = 2;
break;
case RarityVeryRare:
n = 1;
break;
}
//if (itemOk && eq == ItemPetSlime) n = 15000;
for (int j = 0; j < n; j++)
{
bonusSet.push_back(i);
setSize++;
}
}
}
int bonusType = 0;
if (setSize > 0) bonusType = bonusSet[rand() % setSize];
//addPresentItem(bonusType);
return (item_equip_enum) bonusType;
}
enumItemType WitchBlastGame::getItemSpell()
{
bool ok = false;
enumItemType item = ItemMagicianHat;
while (!ok)
{
enumCastSpell n = (enumCastSpell)(rand() % SPELL_MAX);
if (player->getActiveSpell().spell != n) ok = true;
if (ok)
{
switch (n)
{
case SpellNone:
case SpellTeleport:
item = ItemSpellTeleport;
break;
case SpellSlimeExplode:
item = ItemSpellSlimeExplode;
break;
case SpellFireball:
item = ItemSpellFireball;
break;
case SpellFreeze:
item = ItemSpellFreeze;
break;
case SpellEarthquake:
item = ItemSpellEarthquake;
break;
case SpellProtection:
item = ItemSpellProtection;
break;
case SpellWeb:
item = ItemSpellWeb;
break;
case SpellFlower:
item = ItemSpellFlower;
break;
case SpellFairy:
item = ItemSpellFairy;
break;
case SpellTime:
item = ItemSpellTime;
break;
}
ok = !isItemLocked(item);
}
}
return item;
}
void WitchBlastGame::generateChallengeBonus(float x, float y)
{
// loot
if (player->getActiveSpell().spell == SpellNone || rand() % 2 == 0)
{
enumItemType spell1 = getItemSpell();
ItemEntity* spellItem = new ItemEntity(spell1, x, y);
spellItem->setVelocity(Vector2D(100.0f + rand()% 250));
if (spellItem->getVelocity().y < 0.0f) spellItem->setVelocity(Vector2D(spellItem->getVelocity().x, -spellItem->getVelocity().y));
spellItem->setViscosity(0.96f);
if (!isFunctionalityLocked(FunctionalityDoubleSpellDrop))
{
enumItemType spell2 = spell1;
while (spell2 == spell1) spell2 = getItemSpell();
ItemEntity* spellItem2 = new ItemEntity(spell2, x, y);
spellItem2->setVelocity(Vector2D(100.0f + rand()% 250));
if (spellItem2->getVelocity().y < 0.0f) spellItem2->setVelocity(Vector2D(spellItem2->getVelocity().x, -spellItem2->getVelocity().y));
spellItem2->setViscosity(0.96f);
}
ItemEntity* healthItem1 = new ItemEntity(ItemHealthVerySmall, x, y);
healthItem1->setVelocity(Vector2D(100.0f + rand()% 250));
healthItem1->setViscosity(0.96f);
ItemEntity* healthItem2 = new ItemEntity(ItemHealthVerySmallPoison, x, y);
healthItem2->setVelocity(Vector2D(100.0f + rand()% 250));
healthItem2->setViscosity(0.96f);
}
else
{
ItemEntity* newItem;
if (challengeLevel < 4 || rand() % (player->isEquiped(EQUIP_LUCK) ? 5 : 8) > 0)
newItem = new ItemEntity(ItemBonusHealth, x, y);
else
newItem = new ItemEntity((enumItemType)(FirstEquipItem + getRandomEquipItem()), x, y);
if (newItem->getVelocity().y < 0.0f) newItem->setVelocity(Vector2D(newItem->getVelocity().x, -newItem->getVelocity().y));
newItem->setVelocity(Vector2D(100.0f + rand()% 250));
newItem->setViscosity(0.96f);
int gold = 2 + rand() % (player->isEquiped(EQUIP_LUCK) ? 9 : 14);
for (int i = 0; i < gold; i++)
{
ItemEntity* newItem = new ItemEntity(ItemCopperCoin, x, y);
newItem->setVelocity(Vector2D(90.0f + rand()% 150));
newItem->setViscosity(0.96f);
}
}
}
void WitchBlastGame::checkInteraction()
{
interaction.active = false;
if (player->getPlayerStatus() != PlayerEntity::playerStatusPlaying) return;
if (currentMap->getRoomType() == roomTypeTemple)
{
int divinity = currentMap->getDivinity(player->getX() / TILE_WIDTH, player->getZ() / TILE_HEIGHT);
if (divinity > -1)
{
interaction.active = true;
interaction.type = InteractionTypeTemple;
interaction.id = divinity;
std::stringstream ss;
ss << "[" << keyToString(input[KeyInteract]) << "] - ";
if (player->getDivinity().divinity == divinity)
{
ss << tools::getLabel("interact_donate");
if (player->getGold() < 10)
{
ss << " ";
ss << tools::getLabel("interact_donate_fail");
}
}
else
{
ss << tools::getLabel("interact_worship");
ss << " ";
ss << tools::getLabel(divinityLabel[divinity] + "_0");
}
interaction.label = ss.str();
}
}
else if (player->getItemToBuy() != NULL)
{
interaction.active = true;
interaction.type = InteractionTypeMerchandise;
interaction.id = player->getItemToBuy()->getItemType();
std::stringstream ss;
ss << tools::getLabel(items[interaction.id].name);
ss << ": ";
ss << tools::getLabel(items[interaction.id].description);
if (player->getItemToBuy()->canBePickedUp())
{
ss << std::endl;
ss << "[" << keyToString(input[KeyInteract]) << "] - ";
ss << tools::getLabel("interact_shop");
}
interaction.label = ss.str();
}
}
void WitchBlastGame::verifyDoorUnlocking()
{
int collidingDirection = (player->getCollidingDirection());
if (collidingDirection != 5 && currentMap->isCleared() && !bossRoomOpened && player->isEquiped(EQUIP_BOSS_KEY))
{
int xt = (player->getX()) / TILE_WIDTH;
int yt = (player->getY()) / TILE_HEIGHT;
if (yt <= 1 && xt >= MAP_WIDTH / 2 - 1 && xt <= MAP_WIDTH / 2 + 1 && currentMap->hasNeighbourUp() == 2)
{
doorEntity[0]->openDoor();
currentMap->openDoor(MAP_WIDTH / 2, 0);
SoundManager::getInstance().playSound(SOUND_DOOR_OPENING);
player->useBossKey();
bossRoomOpened = true;
}
if (yt >= MAP_HEIGHT - 2 && xt >= MAP_WIDTH / 2 - 1 &&xt <= MAP_WIDTH / 2 + 1 && currentMap->hasNeighbourDown() == 2)
{
doorEntity[2]->openDoor();
currentMap->openDoor(MAP_WIDTH / 2, MAP_HEIGHT - 1);
SoundManager::getInstance().playSound(SOUND_DOOR_OPENING);
player->useBossKey();
bossRoomOpened = true;
}
if (xt <= 1 && yt >= MAP_HEIGHT / 2 - 1 && yt <= MAP_HEIGHT / 2 + 1 && currentMap->hasNeighbourLeft() == 2)
{
doorEntity[1]->openDoor();
currentMap->openDoor(0, MAP_HEIGHT / 2);
SoundManager::getInstance().playSound(SOUND_DOOR_OPENING);
player->useBossKey();
bossRoomOpened = true;
}
if (xt >= MAP_WIDTH - 2 && yt >= MAP_HEIGHT / 2 - 1 && yt <= MAP_HEIGHT / 2 + 1 && currentMap->hasNeighbourRight() == 2)
{
doorEntity[3]->openDoor();
currentMap->openDoor(MAP_WIDTH - 1, MAP_HEIGHT / 2);
SoundManager::getInstance().playSound(SOUND_DOOR_OPENING);
player->useBossKey();
bossRoomOpened = true;
}
}
}
void WitchBlastGame::playMusic(musicEnum musicChoice)
{
music.stop();
if (parameters.musicVolume <= 0) return;
music.setLoop(true);
music.setVolume(parameters.musicVolume * VolumeModifier / 100);
bool ok = false;
switch (musicChoice)
{
case MusicDungeon:
{
int r = currentStandardMusic;
while (r == currentStandardMusic) r = rand() % 3;
switch (r)
{
case 0: ok = music.openFromFile("media/sound/WitchBlastTheme.ogg"); break;
case 1: ok = music.openFromFile("media/sound/SavageLife.ogg"); break;
case 2: ok = music.openFromFile("media/sound/HauntedLighthouse.ogg"); break;
}
currentStandardMusic = r;
}
break;
case MusicEnding:
ok = music.openFromFile("media/sound/AmbiantMedieval.ogg");
break;
case MusicBoss:
ok = music.openFromFile("media/sound/ShowMeThePower.ogg");
break;
case MusicChallenge:
ok = music.openFromFile("media/sound/HellsFire.ogg");
break;
case MusicIntro:
ok = music.openFromFile("media/sound/WitchBlastTheme.ogg");
break;
}
if (ok)
music.play();
}
void WitchBlastGame::pauseMusic()
{
music.pause();
}
void WitchBlastGame::resumeMusic()
{
music.play();
}
void WitchBlastGame::updateMusicVolume()
{
if (music.getStatus() == sf::Music::Playing)
{
if (parameters.musicVolume == 0)
music.stop();
else
music.setVolume(parameters.musicVolume * VolumeModifier / 100);
}
else
{
if (parameters.musicVolume > 0)
{
bool ok = music.openFromFile("media/sound/wb.ogg");
music.setVolume(parameters.musicVolume * VolumeModifier / 100);
if (ok) music.play();
}
}
}
void WitchBlastGame::makeShake(float duration)
{
xGame[xGameTypeShake].active = true;
xGame[xGameTypeShake].timer = duration;
}
void WitchBlastGame::makeColorEffect(int color, float duration)
{
xGame[xGameTypeFadeColor].active = true;
xGame[xGameTypeFadeColor].param = color;
xGame[xGameTypeFadeColor].timer = duration;
xGame[xGameTypeFadeColor].duration = duration;
}
void WitchBlastGame::saveGame()
{
if (player->getPlayerStatus() == PlayerEntity::playerStatusAcquire)
player->acquireItemAfterStance();
std::ofstream file(SAVE_FILE.c_str(), std::ios::out | std::ios::trunc);
int i, j, k, l;
if (file)
{
// version (for compatibility check)
file << SAVE_VERSION << std::endl;
time_t t = time(0); // get time now
struct tm * now = localtime( & t );
file << (now->tm_year + 1900) << '-';
if (now->tm_mon < 9) file << "0";
file << (now->tm_mon + 1) << '-';
if (now->tm_mday < 9) file << "0";
file << now->tm_mday
<< std::endl;
if (now->tm_hour <= 9) file << "0";
file << (now->tm_hour) << ':';
if (now->tm_min <= 9) file << "0";
file << (now->tm_min) << std::endl;
// floor
file << level << " " << challengeLevel << std::endl;
// game age
file << (int)gameTime << std::endl;
// player equip
for (i = 0; i < NUMBER_EQUIP_ITEMS; i++) file << player->isEquiped(i) << " ";
file << std::endl;
file << player->getShotType() << std::endl;
int nbRooms = 0;
for (j = 0; j < FLOOR_HEIGHT; j++)
{
for (i = 0; i < FLOOR_WIDTH; i++)
{
file << currentFloor->getRoom(i,j) << " ";
if (currentFloor->getRoom(i,j) > 0) nbRooms++;
}
file << std::endl;
}
// kill stats
for (i = 0; i < NB_ENEMY; i++) file << killedEnemies[i] << " ";
file << std::endl;
// potions
for(auto it = potionMap.begin(); it != potionMap.end(); ++it)
{
file << it->first << " " << it->second.effect << " " << it->second.known << std::endl;
}
// maps
if (currentMap->isCleared())
saveMapItems();
file << nbRooms << std::endl;
for (j = 0; j < FLOOR_HEIGHT; j++)
{
for (i = 0; i < FLOOR_WIDTH; i++)
{
if (currentFloor->getRoom(i,j) > 0)
{
file << i << " " << j << " "
<< currentFloor->getMap(i, j)->getRoomType() << " "
<< currentFloor->getMap(i, j)->isKnown() << " "
<< currentFloor->getMap(i, j)->isVisited() << " "
<< currentFloor->getMap(i, j)->isRevealed() << " "
<< currentFloor->getMap(i, j)->isCleared() << std::endl;
if (currentFloor->getMap(i, j)->isVisited())
{
for (l = 0; l < MAP_HEIGHT; l++)
{
for (k = 0; k < MAP_WIDTH; k++)
{
int tile = currentFloor->getMap(i, j)->getTile(k, l);
file << tile << " ";
tile = currentFloor->getMap(i, j)->getObjectTile(k, l);
if (tile == MAPOBJ_DOOR_CLOSED) tile = MAPOBJ_DOOR_OPEN;
file << tile << " ";
file << currentFloor->getMap(i, j)->getLogicalTile(k, l) << " ";
}
file << std::endl;
}
// style
file << currentFloor->getMap(i, j)->getFloorOffset() << " "
<< currentFloor->getMap(i, j)->getWallType() << std::endl;
// items, etc...
std::list<DungeonMap::itemListElement> itemList = currentFloor->getMap(i, j)->getItemList();
file << itemList.size() << std::endl;
std::list<DungeonMap::itemListElement>::iterator it;
for (it = itemList.begin (); it != itemList.end ();)
{
DungeonMap::itemListElement ilm = *it;
it++;
file << ilm.type << " " << ilm.x << " " << ilm.y << " " << ilm.merch << std::endl;
}
// chests
std::list<DungeonMap::chestListElement> chestList = currentFloor->getMap(i, j)->getChestList();
file << chestList.size() << std::endl;
std::list<DungeonMap::chestListElement>::iterator itc;
for (itc = chestList.begin (); itc != chestList.end ();)
{
DungeonMap::chestListElement ilm = *itc;
itc++;
file << ilm.type << " " << ilm.x << " " << ilm.y << " " << ilm.state << std::endl;
}
// sprites
std::list<DungeonMap::spriteListElement> spriteList = currentFloor->getMap(i, j)->getSpriteList();
file << spriteList.size() << std::endl;
std::list<DungeonMap::spriteListElement>::iterator its;
for (its = spriteList.begin (); its != spriteList.end ();)
{
DungeonMap::spriteListElement ilm = *its;
its++;
file << ilm.type << " " << ilm.frame << " " << ilm.x << " " << ilm.y << " " << ilm.scale << std::endl;
}
// doors
for (int k = 0; k < 4; k++)
file << currentFloor->getMap(i, j)->getDoorType(k) << " ";
file << std::endl;
// random sprite
for (int k = 0; k < NB_RANDOM_TILES_IN_ROOM; k++)
{
file << currentFloor->getMap(i, j)->getRandomTileElement(k).type
<< " " <<currentFloor->getMap(i, j)->getRandomTileElement(k).x
<< " " << currentFloor->getMap(i, j)->getRandomTileElement(k).y
<< " " << currentFloor->getMap(i, j)->getRandomTileElement(k).rotation << std::endl;
}
}
}
}
file << std::endl;
}
// game
file << floorX << " " << floorY << std::endl;
file << bossRoomOpened << std::endl;
// boss door !
// fight ?
if (currentMap->isCleared())
{
file << false << std::endl;
}
else
{
file << true << std::endl;
file << saveInFight.x << " " << saveInFight.y << " " << saveInFight.direction << std::endl;
file << saveInFight.monsters.size();
for (auto monster : saveInFight.monsters)
file << " " << monster.id << " " << monster.x << " " << monster.y;
file << std::endl;
}
// player
- file << player->getHp() << " " << player->getHpMax() << " " << player->getGold() << std::endl;
+ file << player->getHp() << " " << player->getHpMax() << " " << player->getGold() << " " << player->getDonation() << std::endl;
for (i = 0; i < NUMBER_EQUIP_ITEMS; i++) file << player->isEquiped(i) << " ";
file << std::endl;
file << player->getX() << " " << player->getY() << std::endl;
file << player->getShotIndex();
for (i = 0; i < SPECIAL_SHOT_SLOTS; i++) file << " " << player->getShotType(i) << std::endl;
file << player->getActiveSpell().spell << std::endl;
for (i = 0; i < MAX_SLOT_CONSUMABLES; i++)
{
file << player->getConsumable(i) << " ";
}
file << std::endl;
// divinity
file << player->getDivinity().divinity << " " << player->getDivinity().piety << " "
<< player->getDivinity().level << " " << player->getDivinity().interventions << std::endl;
// events
for (i = 0; i < NB_EVENTS; i++) file << worldEvent[i] << " ";
file.close();
}
else
{
std::cerr << "[ERROR] Saving the game..." << std::endl;
}
}
bool WitchBlastGame::loadGame()
{
resetPresentItems();
saveInFight.monsters.clear();
std::ifstream file(SAVE_FILE.c_str(), std::ios::in);
if (file)
{
int i, j, k, n;
// version
std::string v;
file >> v;
if (v != SAVE_VERSION)
{
file.close();
remove(SAVE_FILE.c_str());
return false;
}
// date an time
file >> v;
file >> v;
// floor
file >> level;
file >> challengeLevel;
file >> gameTime;
for (i = 0; i < NUMBER_EQUIP_ITEMS; i++)
{
bool eq;
file >> eq;
}
file >> n;
currentFloor = new GameFloor(level);
for (j = 0; j < FLOOR_HEIGHT; j++)
{
for (i = 0; i < FLOOR_WIDTH; i++)
{
int n;
file >> n;
currentFloor->setRoom(i, j, (roomTypeEnum)n);
}
}
// kill stats
for (int i = 0; i < NB_ENEMY; i++) file >> killedEnemies[i];
// potions
for (i = 0; i < NUMBER_UNIDENTIFIED * 2; i++)
{
int source, effect;
bool known;
file >> source >> effect >> known;
addPotionToMap((enumItemType)source, (enumItemType)effect, known);
}
// maps
int nbRooms;
file >> nbRooms;
for (k = 0; k < nbRooms; k++)
{
file >> i;
file >> j;
file >> n;
DungeonMap* iMap = new DungeonMap(currentFloor, i, j);
currentFloor->setMap(i, j, iMap);
iMap->setRoomType((roomTypeEnum)n);
bool flag;
file >> flag;
iMap->setKnown(flag);
file >> flag;
iMap->setVisited(flag);
file >> flag;
if (!flag) iMap->setRevealed(flag);
file >> flag;
iMap->setCleared(flag);
if (iMap->isVisited())
{
for (j = 0; j < MAP_HEIGHT; j++)
{
for (i = 0; i < MAP_WIDTH; i++)
{
file >> n;
iMap->setTile(i, j, n);
file >> n;
iMap->setObjectTile(i, j, n);
file >> n;
iMap->setLogicalTile(i, j, (logicalMapStateEnum)n);
}
}
// style
file >> n;
iMap->setFloorOffset(n);
file >> n;
iMap->setWallType(n);
// items int the map
file >> n;
for (i = 0; i < n; i++)
{
int t;
float x, y;
bool merc;
file >> t >> x >> y >> merc;
iMap->addItem(t, x, y, merc);
}
// chests in the map
file >> n;
for (i = 0; i < n; i++)
{
int t;
float x, y;
bool state;
file >> t >> x >> y >> state;
iMap->addChest(t, state, x, y);
}
// sprites in the map
file >> n;
for (i = 0; i < n; i++)
{
int t, f;
float x, y, scale;
file >> t >> f >> x >> y >> scale;
iMap->addSprite(t, f, x, y, scale);
}
// doors
for (int index = 0; index < 4; index++)
{
file >> n;
iMap->setDoorType(index, (doorEnum)n);
}
// random sprite
for (int index = 0; index < NB_RANDOM_TILES_IN_ROOM; index++)
{
DungeonMap::RandomTileElement rd;
file >> rd.type;
file >> rd.x;
file >> rd.y;
file >> rd.rotation;
iMap->setRandomTileElement(index, rd);
}
// random sprite
}
}
// game
file >> floorX >> floorY;
currentMap = currentFloor->getMap(floorX, floorY);
file >> bossRoomOpened;
// fight ?
file >> saveInFight.isFight;
if (saveInFight.isFight)
{
currentMap->setCleared(false);
file >> saveInFight.x;
file >> saveInFight.y;
file >> saveInFight.direction;
file >> n;
for (i = 0; i < n; i++)
{
StructMonster monster;
file >> j;
monster.id = (enemyTypeEnum)j;
file >> monster.x;
file >> monster.y;
saveInFight.monsters.push_back(monster);
}
}
// player
- int hp, hpMax, gold;
- file >> hp >> hpMax >> gold;
+ int hp, hpMax, gold, donation;
+ file >> hp >> hpMax >> gold >> donation;
player = new PlayerEntity((TILE_WIDTH * MAP_WIDTH * 0.5f),
(TILE_HEIGHT * MAP_HEIGHT * 0.5f));
player->setHp(hp);
player->setHpMax(hpMax);
player->setGold(gold);
+ player->setDonation(donation);
for (i = 0; i < NUMBER_EQUIP_ITEMS; i++)
{
bool eq;
file >> eq;
player->setEquiped(i, eq);
}
float x, y;
file >> x >> y;
if (saveInFight.isFight)
{
x = saveInFight.x;
y = saveInFight.y;
player->move(saveInFight.direction);
player->setEntering();
}
player->moveTo(x, y);
file >> n;
player->setShotIndex(n);
for (i = 0; i < SPECIAL_SHOT_SLOTS; i++)
{
file >> n;
player->setShotType(i, (enumShotType)n);
}
file >> n;
player->setActiveSpell((enumCastSpell)n, saveInFight.isFight);
for (i = 0; i < MAX_SLOT_CONSUMABLES; i++)
{
file >> n;
player->setConsumable(i, n);
}
// divinity
{
int divinityId, piety, divLevel, interventions;
file >> divinityId;
file >> piety;
file >> divLevel;
file >> interventions;
player->loadDivinity(divinityId, piety, divLevel, interventions);
}
// events
for (i = 0; i < NB_EVENTS; i++)
{
bool event;
file >> event;
worldEvent[i] = event;
}
player->computePlayer();
file.close();
remove(SAVE_FILE.c_str());
}
else
{
return false;
}
return true;
}
WitchBlastGame::saveHeaderStruct WitchBlastGame::loadGameHeader()
{
saveHeaderStruct saveHeader;
saveHeader.ok = true;
std::ifstream file(SAVE_FILE.c_str(), std::ios::in);
if (file)
{
// version
std::string v;
file >> v;
if (v != SAVE_VERSION)
{
file.close();
remove(SAVE_FILE.c_str());
saveHeader.ok = false;
}
else
{
// date an time
file >> saveHeader.date;
file >> saveHeader.time;
// floor
file >> saveHeader.level;
int challengeLevel;
file >> challengeLevel;
file >> saveHeader.gameTime;
for (int i = 0; i < NUMBER_EQUIP_ITEMS; i++)
file >> equipToDisplay[i];
file >> saveHeader.shotType;
}
}
else
{
saveHeader.ok = false;
}
return saveHeader;
}
void WitchBlastGame::saveGameData()
{
// TODO
std::ofstream file(SAVE_DATA_FILE.c_str(), std::ios::out | std::ios::trunc);
if (file)
{
// version (for compatibility check)
file << SAVE_VERSION << std::endl;
int i;
// tuto
for (i = 0; i < NB_MESSAGES; i++)
{
messageStruct msg = getMessage((EnumMessages)i);
if (msg.messageType == MessageTypeTutorial)
{
file << gameMessagesToSkip[i] << " ";
}
else file << "0 ";
}
file << std::endl;
// achievements
for (i = 0; i < NB_ACHIEVEMENTS; i++)
{
if (achievementState[i] == AchievementDone) file << "1 ";
else file << "0 ";
}
file << std::endl;
// monsters
for (i = 0; i < NB_ENEMY; i++)
{
file << globalData.killedMonster[i] << " ";
}
file << std::endl;
file.close();
}
else
{
std::cout << "[ERROR] Impossible to open save data file.\n";
}
}
void WitchBlastGame::loadGameData()
{
std::ifstream file(SAVE_DATA_FILE.c_str(), std::ios::in);
int i;
if (file)
{
// version
std::string v;
file >> v;
if (v != SAVE_VERSION)
{
file.close();
remove(SAVE_DATA_FILE.c_str());
return;
}
// tuto
for (i = 0; i < NB_MESSAGES; i++)
{
file >> gameMessagesToSkip[i];
}
}
// Achievements
for (i = 0; i < NB_ACHIEVEMENTS; i++)
{
int n;
file >> n;
if (n == 1) achievementState[i] = AchievementDone;
else achievementState[i] = AchievementUndone;
}
// Monsters
for (i = 0; i < NB_ENEMY; i++)
file >> globalData.killedMonster[i];
}
void WitchBlastGame::addKey(int logicInput, std::string key)
{
int iKey = config.findInt(key);
if (iKey >= 0)
{
sf::Keyboard::Key k = (sf::Keyboard::Key)iKey;
input[logicInput] = k;
}
}
void WitchBlastGame::saveConfigurationToFile()
{
std::map<std::string, std::string> newMap;
// parameters
newMap["language"] = intToString(parameters.language);
newMap["player_name"] = parameters.playerName;
// audio volume
newMap["volume_sound"] = intToString(parameters.soundVolume);
newMap["volume_music"] = intToString(parameters.musicVolume);
newMap["zoom_enabled"] = parameters.zoom ? "1" : "0";
newMap["vsync_enabled"] = parameters.vsync ? "1" : "0";
newMap["blood_spreading"] = parameters.bloodSpread ? "1" : "0";
newMap["fullscreen"] = parameters.fullscreen ? "1" : "0";
newMap["display_boss_portrait"] = parameters.displayBossPortrait ? "1" : "0";
// Keys
newMap["keyboard_move_up"] = intToString(input[KeyUp]);
newMap["keyboard_move_down"] = intToString(input[KeyDown]);
newMap["keyboard_move_left"] = intToString(input[KeyLeft]);
newMap["keyboard_move_right"] = intToString(input[KeyRight]);
newMap["keyboard_fire_up"] = intToString(input[KeyFireUp]);
newMap["keyboard_fire_down"] = intToString(input[KeyFireDown]);
newMap["keyboard_fire_left"] = intToString(input[KeyFireLeft]);
newMap["keyboard_fire_right"] = intToString(input[KeyFireRight]);
newMap["keyboard_spell"] = intToString(input[KeySpell]);
newMap["keyboard_interact"] = intToString(input[KeyInteract]);
newMap["keyboard_fire"] = intToString(input[KeyFire]);
newMap["keyboard_time_control"] = intToString(input[KeyTimeControl]);
newMap["keyboard_fire_select"] = intToString(input[KeyFireSelect]);
// Joystick
for (unsigned int i = 0; i < NumberKeys; i++)
{
std::stringstream oss_button;
oss_button << "joy_" << inputKeyStr[i] << "_button";
std::stringstream oss_value;
oss_value << "joy_" << inputKeyStr[i] << "_value";
std::stringstream oss_axis;
oss_axis << "joy_" << inputKeyStr[i] << "_axis";
newMap[oss_button.str()] = joystickInput[i].isButton ? "1" : "0";
newMap[oss_value.str()] = intToString(joystickInput[i].value);
newMap[oss_axis.str()] = intToString(joystickInput[i].axis);
}
config.saveToFile(CONFIG_FILE, newMap);
}
void WitchBlastGame::configureFromFile()
{
// default
parameters.language = 0; // english
parameters.zoom = true;
parameters.vsync = true;
parameters.bloodSpread = true;
parameters.fullscreen = false;
parameters.musicVolume = 80;
parameters.soundVolume = 80;
parameters.playerName = "";
parameters.displayBossPortrait = false;
input[KeyUp] = sf::Keyboard::W;
input[KeyDown] = sf::Keyboard::S;
input[KeyLeft] = sf::Keyboard::A;
input[KeyRight] = sf::Keyboard::D;
input[KeyFireUp] = sf::Keyboard::Up;
input[KeyFireDown] = sf::Keyboard::Down;
input[KeyFireLeft] = sf::Keyboard::Left;
input[KeyFireRight] = sf::Keyboard::Right;
input[KeyFire] = sf::Keyboard::RControl;
input[KeySpell] = sf::Keyboard::Space;
input[KeyInteract] = sf::Keyboard::E;
input[KeyFireSelect] = sf::Keyboard::Tab;
input[KeyTimeControl] = sf::Keyboard::RShift;
// Joystick
joystickInput[KeyUp].isButton = false;
joystickInput[KeyUp].axis = sf::Joystick::Y;
joystickInput[KeyUp].value = -1;
joystickInput[KeyDown].isButton = false;
joystickInput[KeyDown].axis = sf::Joystick::Y;
joystickInput[KeyDown].value = 1;
joystickInput[KeyLeft].isButton = false;
joystickInput[KeyLeft].axis = sf::Joystick::X;
joystickInput[KeyLeft].value = -1;
joystickInput[KeyRight].isButton = false;
joystickInput[KeyRight].axis = sf::Joystick::X;
joystickInput[KeyRight].value = 1;
for (unsigned int i = KeyFireUp; i < NumberKeys; i++)
{
joystickInput[i].isButton = true;
joystickInput[i].axis = sf::Joystick::X;
joystickInput[i].value = i - 4;
}
// from file
addKey(KeyUp, "keyboard_move_up");
addKey(KeyDown, "keyboard_move_down");
addKey(KeyLeft, "keyboard_move_left");
addKey(KeyRight, "keyboard_move_right");
addKey(KeyFireUp, "keyboard_fire_up");
addKey(KeyFireDown, "keyboard_fire_down");
addKey(KeyFireLeft, "keyboard_fire_left");
addKey(KeyFireRight, "keyboard_fire_right");
addKey(KeyFire, "keyboard_fire");
addKey(KeySpell, "keyboard_spell");
addKey(KeyInteract, "keyboard_interact");
addKey(KeyTimeControl, "keyboard_time_control");
addKey(KeyFireSelect, "keyboard_fire_select");
// Joystick
for (unsigned int i = 0; i < NumberKeys; i++)
{
std::stringstream oss_button;
oss_button << "joy_" << inputKeyStr[i] << "_button";
std::stringstream oss_value;
oss_value << "joy_" << inputKeyStr[i] << "_value";
std::stringstream oss_axis;
oss_axis << "joy_" << inputKeyStr[i] << "_axis";
int isButton = config.findInt(oss_button.str());
if (isButton > -1000)
joystickInput[i].isButton = isButton;
int n = config.findInt(oss_value.str());
if (n > -1000)
joystickInput[i].value = n;
n = config.findInt(oss_axis.str());
if (n >= sf::Joystick::Axis::X && n <= sf::Joystick::Axis::PovY)
joystickInput[i].axis = (sf::Joystick::Axis)n;
}
int i = config.findInt("language");
if (i >= 0 && i < NB_LANGUAGES) parameters.language = i;
i = config.findInt("volume_sound");
if (i >= 0) parameters.soundVolume = i;
i = config.findInt("volume_music");
if (i >= 0) parameters.musicVolume = i;
i = config.findInt("vsync_enabled");
if (i >= 0) parameters.vsync = i;
i = config.findInt("zoom_enabled");
if (i >= 0) parameters.zoom = i;
i = config.findInt("blood_spreading");
if (i >= 0) parameters.bloodSpread = i;
i = config.findInt("fullscreen");
if (i >= 0) parameters.fullscreen = i;
i = config.findInt("display_boss_portrait");
if (i >= 0) parameters.displayBossPortrait = i;
std::string playerName = config.findString("player_name");
if (playerName.size() > 0) parameters.playerName = playerName;
tools::setLanguage(languageString[parameters.language]);
}
parameterStruct WitchBlastGame::getParameters()
{
return parameters;
}
void WitchBlastGame::buildMenu(bool rebuild)
{
menuMain.items.clear();
menuConfig.items.clear();
menuFirst.items.clear();
if (!rebuild)
{
menuState = MenuStateMain;
menuMain.age = 0.0f;
menuConfig.age = 0.0f;
menuConfig.index = 0;
}
saveHeader = loadGameHeader();
menuItemStuct itemName;
itemName.label = tools::getLabel("player_name");
itemName.description = tools::getLabel("player_name_desc");
itemName.id = MenuPlayerName;
menuMain.items.push_back(itemName);
if (saveHeader.ok)
{
menuItemStuct itemStart;
itemStart.label = tools::getLabel("start_new_game");
itemStart.description = tools::getLabel("start_desc");
itemStart.id = MenuStartNew;
menuMain.items.push_back(itemStart);
menuItemStuct itemLoad;
itemStart.label = tools::getLabel("restore");
std::ostringstream oss;
oss << saveHeader.date << " " << tools::getLabel("at") << " " << saveHeader.time << " - " << tools::getLabel("level") << " " << saveHeader.level;
itemStart.description = oss.str();
itemStart.id = MenuStartOld;
menuMain.items.push_back(itemStart);
if (!rebuild) menuMain.index = 2;
}
else
{
menuItemStuct itemStart;
itemStart.label = tools::getLabel("start_new_game");
itemStart.description = tools::getLabel("begin_journey");
itemStart.id = MenuStartNew;
menuMain.items.push_back(itemStart);
if (!rebuild) menuMain.index = 1;
}
if (parameters.playerName.compare("") == 0 && menuState == MenuStateMain)
{
menuMain.index = 0;
menuState = MenuStateChangeName;
}
menuItemStuct itemConfig;
itemConfig.label = tools::getLabel("configure_game");
itemConfig.description = tools::getLabel("configure_game_desc");
itemConfig.id = MenuConfig;
menuMain.items.push_back(itemConfig);
if (!isFunctionalityLocked(FunctionalityAchievementsScreen))
{
menuItemStuct itemAchiev;
std::ostringstream oss;
oss << tools::getLabel("menu_achievements");
oss << " (" << getAchievementsPercents() << "%)";
itemAchiev.label = oss.str();
itemAchiev.description = tools::getLabel("menu_achievements_desc");
itemAchiev.id = MenuAchievements;
menuMain.items.push_back(itemAchiev);
}
//if (scores.size() > 0)
{
menuItemStuct itemHiScores;
itemHiScores.label = tools::getLabel("hi_scores");
itemHiScores.description = tools::getLabel("hi_scores_desc");
itemHiScores.id = MenuHiScores;
menuMain.items.push_back(itemHiScores);
}
menuItemStuct itemCredits;
itemCredits.label = tools::getLabel("credits");
itemCredits.description = tools::getLabel("credits_desc");
itemCredits.id = MenuCredits;
menuMain.items.push_back(itemCredits);
menuItemStuct itemExit;
itemExit.label = tools::getLabel("exit_game");
itemExit.description = tools::getLabel("return_to_desktop");
itemExit.id = MenuExit;
menuMain.items.push_back(itemExit);
// configuration
menuItemStuct itemKeys;
itemKeys.label = tools::getLabel("config_keys");
itemKeys.description = tools::getLabel("redef_input");
itemKeys.id = MenuKeys;
menuConfig.items.push_back(itemKeys);
menuItemStuct itemJoystick;
itemJoystick.label = tools::getLabel("config_joystick");
if (sf::Joystick::isConnected(0))
itemJoystick.description = tools::getLabel("redef_joystick");
else
itemJoystick.description = tools::getLabel("joystick_not_found");
itemJoystick.id = MenuJoystick;
menuConfig.items.push_back(itemJoystick);
menuItemStuct itemLanguage;
itemLanguage.label = tools::getLabel("config_lang");
itemLanguage.description = tools::getLabel("config_lang_desc");
itemLanguage.id = MenuLanguage;
menuConfig.items.push_back(itemLanguage);
menuItemStuct itemVolumeSound;
itemVolumeSound.label = tools::getLabel("volume_sound");
itemVolumeSound.description = tools::getLabel("volume_sound_desc");
itemVolumeSound.id = MenuVolumeSound;
menuConfig.items.push_back(itemVolumeSound);
menuItemStuct itemVolumeMusic;
itemVolumeMusic.label = tools::getLabel("volume_music");
itemVolumeMusic.description = tools::getLabel("volume_sound_desc");
itemVolumeMusic.id = MenuVolumeMusic;
menuConfig.items.push_back(itemVolumeMusic);
menuItemStuct itemTutoReset;
itemTutoReset.label = tools::getLabel("tuto_reset");
itemTutoReset.description = tools::getLabel("tuto_reset_desc");
itemTutoReset.id = MenuTutoReset;
menuConfig.items.push_back(itemTutoReset);
menuItemStuct itemConfigBack;
itemConfigBack.label = tools::getLabel("config_back");
itemConfigBack.description = tools::getLabel("config_back_desc");
itemConfigBack.id = MenuConfigBack;
menuConfig.items.push_back(itemConfigBack);
//first time screen
menuFirst.items.push_back(itemLanguage);
}
void WitchBlastGame::buildInGameMenu()
{
menuInGame.items.clear();
menuItemStuct itemContinue;
itemContinue.label = tools::getLabel("menu_continue");
itemContinue.description = tools::getLabel("menu_continue_desc");
itemContinue.id = MenuContinue;
menuInGame.items.push_back(itemContinue);
menuItemStuct itemSaveQuit;
itemSaveQuit.label = tools::getLabel("menu_save_quit");
itemSaveQuit.description = tools::getLabel("menu_save_quit_desc");
itemSaveQuit.id = MenuSaveAndQuit;
menuInGame.items.push_back(itemSaveQuit);
menuItemStuct itemQuit;
itemQuit.label = tools::getLabel("menu_quit");
itemQuit.description = tools::getLabel("menu_quit_desc");
itemQuit.id = MenuExit;
menuInGame.items.push_back(itemQuit);
menuInGame.index = 0;
}
void WitchBlastGame::resetKilledEnemies()
{
for (int i = 0; i < NB_ENEMY; i++) killedEnemies[i] = 0;
}
void WitchBlastGame::addKilledEnemy(enemyTypeEnum enemyType, enumShotType hurtingType)
{
if(!player->isDead())
{
if (enemyType == NB_ENEMY)
std::cout << "[ERROR] No enemy type";
else
{
killedEnemies[enemyType]++;
globalData.killedMonster[enemyType]++;
player->offerMonster(enemyType, hurtingType);
// achievements
if (enemyType == EnemyTypeButcher) registerAchievement(AchievementButcher);
else if (enemyType == EnemyTypeSlimeBoss) registerAchievement(AchievementGiantSlime);
else if (enemyType == EnemyTypeCyclops) registerAchievement(AchievementCyclops);
else if (enemyType == EnemyTypeRatKing) registerAchievement(AchievementRatKing);
else if (enemyType == EnemyTypeSpiderGiant) registerAchievement(AchievementGiantSpider);
else if (enemyType == EnemyTypeFranckyHead) registerAchievement(AchievementFrancky);
else if (enemyType == EnemyTypeVampire) registerAchievement(AchievementVampire);
else if ((enemyType == EnemyTypeRat || enemyType == EnemyTypeRatHelmet || enemyType == EnemyTypeRat_invocated
|| enemyType == EnemyTypeRatBlack || enemyType == EnemyTypeRatBlackHelmet))
{
if (globalData.killedMonster[EnemyTypeRat] + globalData.killedMonster[EnemyTypeRatHelmet] + globalData.killedMonster[EnemyTypeRat_invocated]
+ globalData.killedMonster[EnemyTypeRatBlack] + globalData.killedMonster[EnemyTypeRatBlackHelmet] >= 250)
registerAchievement(AchievementRats);
}
else if (enemyType == EnemyTypeWitch || enemyType == EnemyTypeWitchRed)
{
if (globalData.killedMonster[EnemyTypeWitch] + globalData.killedMonster[EnemyTypeWitchRed] >= 50)
registerAchievement(AchievementWitches);
}
else if (enemyType == EnemyTypeGhost)
{
if (globalData.killedMonster[EnemyTypeGhost] >= 75)
registerAchievement(AchievementGhostbuster);
}
else if (enemyType == EnemyTypeSpiderEgg || enemyType == EnemyTypeSpiderEgg_invocated)
{
if (globalData.killedMonster[EnemyTypeSpiderEgg] + globalData.killedMonster[EnemyTypeSpiderEgg_invocated] >= 100)
registerAchievement(AchievementEggs);
}
}
}
}
void WitchBlastGame::registerLanguage()
{
// default keys
if (parameters.language == 1)
{
// french keyboard
input[KeyUp] = sf::Keyboard::Z;
input[KeyLeft] = sf::Keyboard::Q;
}
else
{
// QWERT / QWERTZ keyboard
input[KeyUp] = sf::Keyboard::W;
input[KeyLeft] = sf::Keyboard::A;
}
input[KeyDown] = sf::Keyboard::S;
input[KeyRight] = sf::Keyboard::D;
input[KeyFireUp] = sf::Keyboard::Up;
input[KeyFireDown] = sf::Keyboard::Down;
input[KeyFireLeft] = sf::Keyboard::Left;
input[KeyFireRight] = sf::Keyboard::Right;
input[KeyFire] = sf::Keyboard::RControl;
input[KeyFireSelect] = sf::Keyboard::Tab;
input[KeyTimeControl] = sf::Keyboard::RShift;
input[KeySpell] = sf::Keyboard::Space;
saveConfigurationToFile();
}
int WitchBlastGame::getAchievementsPercents()
{
int n = 0;
for (int i = 0; i < NB_ACHIEVEMENTS; i++)
if (achievementState[i] == AchievementDone) n++;
return (n * 100) / NB_ACHIEVEMENTS;
}
void WitchBlastGame::testAndAddMessageToQueue(EnumMessages type)
{
if (gameMessagesToSkip[type] == false)
{
if (messagesQueue.empty()) SoundManager::getInstance().playSound(SOUND_MESSAGE);
messageStruct msg = getMessage(type);
if (type == MsgInfoDivGift || type == MsgInfoDivIntervention)
{
std::stringstream ss;
ss << tools::getLabel(divinityLabel[player->getDivinity().divinity] + "_0");
ss << " ";
if (type == MsgInfoDivGift)
ss << tools::getLabel("divinity_gift_1");
else // (type == MsgInfoDivIntervention)
ss << tools::getLabel("divinity_intervention_1");
msg.message[1] = ss.str();
msg.icon = 2 + player->getDivinity().divinity;
}
messagesQueue.push(msg);
if (msg.messageType == MessageTypeTutorial)
{
gameMessagesToSkip[type] = true;
saveGameData();
}
}
}
void WitchBlastGame::addDivLevelMessageToQueue(std::string label)
{
if (label.compare("") == 0) return;
if (messagesQueue.empty()) SoundManager::getInstance().playSound(SOUND_MESSAGE);
messageStruct msg = getMessage(MsgInfoDivLevel);
std::stringstream ss;
ss << tools::getLabel(divinityLabel[player->getDivinity().divinity] + "_0");
ss << " ";
ss << tools::getLabel(label);
msg.message[1] = ss.str();
msg.icon = 2 + player->getDivinity().divinity;
messagesQueue.push(msg);
}
void WitchBlastGame::initEvents()
{
for (int i = 0; i < NB_EVENTS; i++)
worldEvent[i] = false;
}
void WitchBlastGame::proceedEvent(EnumWorldEvents event)
{
// achievements
if (event == EventGetCoin)
{
if (achievementState[Achievement100] == AchievementUndone && player->getGold() > 100)
registerAchievement(Achievement100);
}
else if (event == EventPietyMax)
{
if (achievementState[AchievementPietyMax] == AchievementUndone) registerAchievement(AchievementPietyMax);
}
else if (event == Event4Hits)
{
if (achievementState[Achievement4Hits] == AchievementUndone) registerAchievement(Achievement4Hits);
}
// message ?
if (worldEvent[event]) return;
worldEvent[event] = true;
testAndAddMessageToQueue(eventToMessage[event]);
}
void WitchBlastGame::renderPlayer(float x, float y,
bool equip[NUMBER_EQUIP_ITEMS], int shotType,
int frame, int spriteDy)
{
bool isMirroring = false;
sf::Sprite sprite;
if (equip[EQUIP_FAIRY_FIRE])
{
sprite.setPosition(x - 35, y - 25);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_FAIRY));
sprite.setTextureRect(sf::IntRect( 0, 144, 48, 60));
app->draw(sprite);
}
if (equip[EQUIP_FAIRY_ICE])
{
sprite.setPosition(x - 5, y - 25);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_FAIRY));
sprite.setTextureRect(sf::IntRect( 0, 216, 48, 60));
app->draw(sprite);
}
if (equip[EQUIP_FAIRY])
{
sprite.setPosition(x - 40, y);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_FAIRY));
sprite.setTextureRect(sf::IntRect( 0, 0, 48, 60));
app->draw(sprite);
}
if (equip[EQUIP_FAIRY_TARGET])
{
sprite.setPosition(x - 10, y);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_FAIRY));
sprite.setTextureRect(sf::IntRect( 0, 72, 48, 60));
app->draw(sprite);
}
if (equip[EQUIP_FAIRY_POISON])
{
sprite.setPosition(x + 20, y);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_FAIRY));
sprite.setTextureRect(sf::IntRect( 0, 288, 48, 60));
app->draw(sprite);
}
if (equip[EQUIP_FAIRY_STONE])
{
sprite.setPosition(x - 5, y + 15);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_FAIRY));
sprite.setTextureRect(sf::IntRect( 0, 360, 48, 60));
app->draw(sprite);
}
// slime
if (equip[EQUIP_PET_SLIME])
{
sprite.setPosition(x - 20, y + 24);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_SLIME));
sprite.setTextureRect(sf::IntRect( 64, 256, 64, 64));
app->draw(sprite);
}
sprite.setPosition(x, y);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
int width = 64;
int height = 96;
// body
if (isMirroring)
sprite.setTextureRect(sf::IntRect( frame * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( frame * width, spriteDy * height, width, height));
app->draw(sprite);
// boots
if (equip[EQUIP_BOOTS_ADVANCED])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (21 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (21 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
else if (equip[EQUIP_LEATHER_BOOTS])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (9 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (9 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_ROBE_ADVANCED])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (12 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (12 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
else if (equip[EQUIP_MAGICIAN_ROBE])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (12 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (12 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_GLOVES_ADVANCED])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (24 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (24 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
else if (equip[EQUIP_DISPLACEMENT_GLOVES])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (21 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (21 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_CRITICAL_ADVANCED])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (24 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (24 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
else if (equip[EQUIP_CRITICAL])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (18 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (18 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
if (equip[EQUIP_RAGE_AMULET])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (18 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (18 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_LEATHER_BELT])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (15 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (15 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
// hat
if (equip[EQUIP_HAT_ADVANCED])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (9 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (9 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
else if (equip[EQUIP_MAGICIAN_HAT])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (6 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (6 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
// staff
int frameDx = equip[EQUIP_MAHOGANY_STAFF] ? 6 : 3;
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (frameDx + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (frameDx + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
if (equip[EQUIP_BLOOD_SNAKE])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (27 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (27 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_REAR_SHOT])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
// shot type
if (shotType != ShotTypeStandard)
{
switch (shotType)
{
case ShotTypeIce:
sprite.setColor(sf::Color(100, 220, 255, 255));
break;
case ShotTypeStone:
sprite.setColor(sf::Color(120, 120, 150, 255));
break;
case ShotTypeLightning:
sprite.setColor(sf::Color(255, 255, 0, 255));
break;
case ShotTypeIllusion:
sprite.setColor(sf::Color(240, 180, 250, 255));
break;
case ShotTypeStandard:
sprite.setColor(sf::Color(255, 255, 255, 0));
break;
case ShotTypeFire:
sprite.setColor(sf::Color(255, 180, 0, 255));
break;
default:
break;
}
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (3 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (3 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
}
std::string WitchBlastGame::enemyToString(enemyTypeEnum enemyType)
{
std::string value = "unknown";
switch (enemyType)
{
case EnemyTypeBat_invocated:
case EnemyTypeBat:
value = "enemy_type_bat";
break;
case EnemyTypeBatSkeleton_invocated:
case EnemyTypeBatSkeleton:
value = "enemy_type_bat_skeleton";
break;
case EnemyTypeRat_invocated:
case EnemyTypeRat:
value = "enemy_type_rat";
break;
case EnemyTypeRatBlack:
value = "enemy_type_rat_black";
break;
case EnemyTypeRatHelmet_invocated:
case EnemyTypeRatHelmet:
value = "enemy_type_rat_helmet";
break;
case EnemyTypeRatBlackHelmet:
value = "enemy_type_rat_black_helmet";
break;
case EnemyTypeEvilFlower:
value = "enemy_type_evil_flower";
break;
case EnemyTypeEvilFlowerIce:
value = "enemy_type_evil_flower_ice";
break;
case EnemyTypeEvilFlowerFire:
value = "enemy_type_evil_flower_fire";
break;
case EnemyTypeSnake_invocated:
case EnemyTypeSnake:
value = "enemy_type_snake";
break;
case EnemyTypeSnakeBlood_invocated:
case EnemyTypeSnakeBlood:
value = "enemy_type_snake_blood";
break;
case EnemyTypeSlime_invocated:
case EnemyTypeSlime:
value = "enemy_type_slime";
break;
case EnemyTypeSlimeRed_invocated:
case EnemyTypeSlimeRed:
value = "enemy_type_slime_red";
break;
case EnemyTypeSlimeBlue_invocated:
case EnemyTypeSlimeBlue:
value = "enemy_type_slime_blue";
break;
case EnemyTypeSlimeViolet_invocated:
case EnemyTypeSlimeViolet:
value = "enemy_type_slime_violet";
break;
case EnemyTypeImpBlue:
value = "enemy_type_imp_blue";
break;
case EnemyTypeImpRed:
value = "enemy_type_imp_red";
break;
case EnemyTypePumpkin_invocated:
case EnemyTypePumpkin:
value = "enemy_type_pumpkin";
break;
case EnemyTypeWitch:
value = "enemy_type_witch";
break;
case EnemyTypeWitchRed:
value = "enemy_type_witch_red";
break;
case EnemyTypeCauldron:
value = "enemy_type_cauldron";
break;
case EnemyTypeCauldronElemental:
value = "enemy_type_cauldron_elemental";
break;
case EnemyTypeGhost:
value = "enemy_type_ghost";
break;
case EnemyTypeZombie_invocated:
case EnemyTypeZombie:
value = "enemy_type_zombie";
break;
case EnemyTypeZombieDark:
value = "enemy_type_zombie_dark";
break;
case EnemyTypeBogeyman:
value = "enemy_type_bogeyman";
break;
case EnemyTypeSausage_invocated:
case EnemyTypeSausage:
value = "enemy_type_sausage";
break;
// mini boss
case EnemyTypeBubble:
value = "enemy_type_bubble";
break;
case EnemyTypeBubbleIce:
value = "enemy_type_bubble_ice";
break;
case EnemyTypeBubbleGreater:
value = "enemy_type_bubble_greater";
break;
case EnemyTypeSlimeLarge:
value = "enemy_type_slime_large";
break;
case EnemyTypeSlimeBlueLarge:
value = "enemy_type_slime_blue_large";
break;
case EnemyTypeSlimeRedLarge:
value = "enemy_type_slime_red_large";
break;
case EnemyTypeSlimeVioletLarge:
value = "enemy_type_slime_violet_large";
break;
// boss
case EnemyTypeButcher:
value = "enemy_type_boss_butcher";
break;
case EnemyTypeSlimeBoss:
value = "enemy_type_boss_slime_giant";
break;
case EnemyTypeCyclops:
value = "enemy_type_boss_cyclops";
break;
case EnemyTypeRatKing:
value = "enemy_type_boss_rat_king";
break;
case EnemyTypeSpiderGiant:
value = "enemy_type_boss_spider_giant";
break;
case EnemyTypeFranckyHand:
case EnemyTypeFranckyHead:
case EnemyTypeFranckyFoot:
case EnemyTypeFrancky:
value = "enemy_type_francky";
break;
case EnemyTypeVampire:
case EnemyTypeVampireDead:
value = "enemy_type_vampire";
break;
// invocated
case EnemyTypeRatGreen:
value = "enemy_type_green_rat";
break;
case EnemyTypeRockFalling:
value = "enemy_type_rock_falling";
break;
case EnemyTypeRockMissile:
value = "enemy_type_rock_missile";
break;
case EnemyTypeSpiderEgg:
case EnemyTypeSpiderEgg_invocated:
value = "enemy_type_spider_egg";
break;
case EnemyTypeSpiderLittle:
case EnemyTypeSpiderLittle_invocated:
value = "enemy_type_spider_little";
break;
case EnemyTypeSpiderTarantula:
case EnemyTypeSpiderTarantula_invocated:
value = "enemy_type_spider_tarantula";
break;
case EnemyTypeSpiderWeb:
value = "enemy_type_spider_web";
break;
case EnemyTypeNone:
value = "enemy_type_himself";
break;
case EnemyTypeDestroyable:
value = "";
break;
case NB_ENEMY:
break;
}
return value;
}
std::string WitchBlastGame::sourceToString(sourceTypeEnum sourceType, enemyTypeEnum enemyType)
{
std::string value = "unknown";
switch (sourceType)
{
case SourceTypeBolt:
case SourceTypeMelee:
value = tools::getLabel(enemyToString(enemyType));
break;
case SourceTypeExplosion:
value = tools::getLabel("source_explosion");
break;
case SourceTypePoison:
value = tools::getLabel("source_poison");
}
return value;
}
std::string WitchBlastGame::equipToString(bool equip[NUMBER_EQUIP_ITEMS])
{
std::stringstream oss;
for (int i = 0; i < NUMBER_EQUIP_ITEMS; i++)
oss << (equip[i] ? 1 : 0);
return oss.str();
}
void WitchBlastGame::saveHiScores()
{
std::ofstream file(HISCORES_FILE.c_str(), std::ios::out | std::ios::trunc);
if (file)
{
// version (for compatibility check)
file << SAVE_VERSION << std::endl;
file << scores.size() << std::endl;
// tuto
for (unsigned int i = 0; i < scores.size() && i < SCORES_MAX; i++)
{
file << scores[i].name << " ";
file << scores[i].level << " ";
file << scores[i].score << " ";
file << scores[i].shotType << " ";
file << scores[i].divinity << " ";
file << scores[i].killedBy << " ";
file << scores[i].time << " ";
// player equip
for (int j = 0; j < NUMBER_EQUIP_ITEMS; j++)
file << scores[i].equip[j] << " ";
file << std::endl;
}
file << std::endl;
file.close();
}
else
{
std::cout << "[ERROR] Impossible to open hi-scores file.\n";
}
}
void WitchBlastGame::loadHiScores()
{
scores.clear();
std::ifstream file(HISCORES_FILE.c_str(), std::ios::in);
if (file)
{
// version
std::string v;
file >> v;
if (v != SAVE_VERSION)
{
file.close();
remove(SAVE_DATA_FILE.c_str());
return;
}
int nbScores;
file >> nbScores;
for (int i = 0; i < nbScores; i++)
{
StructScore score;
file >> score.name;
file >> score.level;
file >> score.score;
file >> score.shotType;
file >> score.divinity;
file >> score.killedBy;
file >> score.time;
for (int j = 0; j < NUMBER_EQUIP_ITEMS; j++)
file >> score.equip[j];
scores.push_back(score);
}
}
}
void WitchBlastGame::revealFloor()
{
currentFloor->reveal();
refreshMinimap();
}
void WitchBlastGame::activateKeyRoomEffect(bool withColorEffect)
{
dungeonEntity->activateKeyRoomEffect();
if (withColorEffect) makeColorEffect(X_GAME_COLOR_VIOLET, 0.35f);
SoundManager::getInstance().playSound(SOUND_FORCE_FIELD);
}
void WitchBlastGame::generateStar(sf::Color starColor, float xStar, float yStar)
{
SpriteEntity* spriteStar = new SpriteEntity(
ImageManager::getInstance().getImage(IMAGE_STAR_2),
xStar, yStar);
spriteStar->setScale(0.8f, 0.8f);
spriteStar->setZ(1000.0f);
spriteStar->setSpin(-100 + rand()%200);
spriteStar->setVelocity(Vector2D(10 + rand()%40));
spriteStar->setWeight(-150);
spriteStar->setFading(true);
spriteStar->setAge(-0.8f);
spriteStar->setLifetime(0.1f + (rand() % 100) * 0.003f );
spriteStar->setColor(starColor);
spriteStar->setType(ENTITY_EFFECT);
}
void WitchBlastGame::registerAchievement(enumAchievementType achievement)
{
if (achievementState[achievement] == AchievementUndone)
{
achievementState[achievement] = AchievementPending;
achievementStruct ach;
ach.type = achievement;
ach.message = tools::getLabel(achievements[achievement].label);
ach.timer = ACHIEVEMENT_DELAY_MAX;
ach.counter = 0;
ach.hasStarted = false;
achievementsQueue.push(ach);
}
}
bool WitchBlastGame::isItemLocked(enumItemType item)
{
for (int i = 0; i < NB_ACHIEVEMENTS; i++)
{
if (achievementState[i] == AchievementUndone)
{
if (achievements[i].unlockType == UnlockItem)
if (achievements[i].unlock == (int)item) return true;
}
}
return false;
}
bool WitchBlastGame::isFunctionalityLocked(enumFunctionalityType func)
{
for (int i = 0; i < NB_ACHIEVEMENTS; i++)
{
if (achievementState[i] == AchievementUndone)
{
if (achievements[i].unlockType == UnlockFunctionality)
if (achievements[i].unlock == (int)func) return true;
}
}
return false;
}
void WitchBlastGame::renderDoors()
{
for (int i = 0; i < 4; i++) doorEntity[i]->renderDoors(app);
}
void WitchBlastGame::resetPresentItems()
{
for (int i = 0; i < NUMBER_EQUIP_ITEMS; i++) presentItems[i] = false;
}
bool WitchBlastGame::isPresentItem(int n)
{
if (n >= 0 && n < NUMBER_EQUIP_ITEMS) return presentItems[n];
else return false;
}
void WitchBlastGame::addPresentItem(int n)
{
if (n >= 0 && n < NUMBER_EQUIP_ITEMS) presentItems[n] = true;
}
bool WitchBlastGame::isPressing(inputKeyEnum k, bool oneShot)
{
return (actionKey[k].isPressed && (!oneShot || actionKey[k].isTriggered));
}
bool WitchBlastGame::getPressingState(inputKeyEnum k)
{
// arrows in menu
if (gameState != gameStatePlaying || player->isDead())
{
if (k == KeyLeft && sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) return true;
if (k == KeyRight && sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) return true;
if (k == KeyUp && sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) return true;
if (k == KeyDown && sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) return true;
if (k == KeyFireDown && sf::Keyboard::isKeyPressed(sf::Keyboard::Return)) return true;
}
// keyboard
if (sf::Keyboard::isKeyPressed(input[k])) return true;
if (!sf::Joystick::isConnected(0)) return false;
// joystick
if (joystickInput[k].isButton)
{
// button
if (joystickInput[k].value >= 0)
if (sf::Joystick::isButtonPressed(0, joystickInput[k].value)) return true;
}
else
{
// axis
if (joystickInput[k].value < 0 && sf::Joystick::getAxisPosition(0, joystickInput[k].axis) < -40) return true;
else if (joystickInput[k].value > 0 && sf::Joystick::getAxisPosition(0, joystickInput[k].axis) > 40) return true;
}
return false;
}
void WitchBlastGame::updateActionKeys()
{
for (unsigned int i = 0; i < NumberKeys; i++)
{
bool oldState = actionKey[i].isPressed;
actionKey[i].isPressed = getPressingState((inputKeyEnum)i);
actionKey[i].isTriggered = actionKey[i].isPressed && !oldState;
}
}
void WitchBlastGame::sendScoreToServer()
{
if (sendScoreThread.joinable()) sendScoreThread.join();
sendScoreThread = std::thread(&WitchBlastGame::sendScoreToServerThread, this);
receiveScoreFromServer();
}
void WitchBlastGame::sendScoreToServerThread()
{
#ifdef ONLINE_MODE
sendScore(lastScore.score,
lastScore.level,
lastScore.name,
equipToString(lastScore.equip),
lastScore.shotType,
lastScore.divinity,
lastScore.killedBy,
lastScore.time,
SCORE_VERSION);
#endif
}
void WitchBlastGame::receiveScoreFromServer()
{
#ifdef ONLINE_MODE
scoreState = ScoreLoading;
if (receiveScoreThread.joinable()) receiveScoreThread.join();
receiveScoreThread = std::thread(&WitchBlastGame::receiveScoreFromServerThread, this);
#endif
}
void WitchBlastGame::receiveScoreFromServerThread()
{
if (sendScoreThread.joinable()) sendScoreThread.join();
loadHiScoresOnline(false);
scoreState = ScoreLoadingDay;
loadHiScoresOnline(true);
scoreState = ScoreOK;
}
void WitchBlastGame::loadHiScoresOnline(bool fromDayOnly)
{
#ifdef ONLINE_MODE
std::vector <StructScore> scoresTemp;
std::vector<std::string> receivedScores = receiveScores(fromDayOnly);
int nbParameters = 8;
if (receivedScores.size() > 0
&& receivedScores.size() % nbParameters == 0
&& receivedScores.size() / nbParameters <= 10)
{
int nbScores = receivedScores.size() / nbParameters;
for (int i = 0; i < nbScores; i++)
{
StructScore score;
std::istringstream scoreStr(receivedScores[i * nbParameters]);
scoreStr >> score.score;
score.name = receivedScores[i * nbParameters + 1];
std::istringstream levelStr(receivedScores[i * nbParameters + 2]);
levelStr >> score.level;
for (int j = 0; j < NUMBER_EQUIP_ITEMS; j++)
{
score.equip[j] = (receivedScores[i * nbParameters + 3])[j] == '1';
}
std::istringstream shotStr(receivedScores[i * nbParameters + 4]);
shotStr >> score.shotType;
std::istringstream divStr(receivedScores[i * nbParameters + 5]);
divStr >> score.divinity;
std::istringstream killStr(receivedScores[i * nbParameters + 6]);
killStr >> score.killedBy;
std::istringstream timeStr(receivedScores[i * nbParameters + 7]);
timeStr >> score.time;
scoresTemp.push_back(score);
}
if (fromDayOnly)
{
scoresOnlineDay.clear();
scoresOnlineDay = scoresTemp;
}
else
{
scoresOnline.clear();
scoresOnline = scoresTemp;
}
}
#endif
}
void WitchBlastGame::checkDestroyableObjects()
{
for (int i = 0; i < MAP_WIDTH; i++)
for (int j = 0; j < MAP_HEIGHT; j++)
{
if (currentMap->getObjectTile(i, j) >= MAPOBJ_BARREL/* && currentMap->getObjectTile(i, j) < MAPOBJ_BARREL_EXPL + 3*/)
{
new ObstacleEntity(i * TILE_WIDTH + TILE_WIDTH / 2, j * TILE_HEIGHT + TILE_HEIGHT / 2, currentMap->getObjectTile(i, j));
}
}
}
void WitchBlastGame::randomizePotionMap()
{
potionMap.clear();
std::vector<int> potionEffect;
for (int i = 0; i < NUMBER_UNIDENTIFIED; i++) potionEffect.push_back(i);
for (int i = 0; i < NUMBER_UNIDENTIFIED; i++)
{
int r = rand() % potionEffect.size();
addPotionToMap((enumItemType)(ItemPotion01 + i), (enumItemType)(ItemPotionHealth + potionEffect[r]), false);
potionEffect.erase(potionEffect.begin() + r);
}
}
void WitchBlastGame::acquireAlchemyBook()
{
for (int i = 0; i < NUMBER_UNIDENTIFIED; i++)
{
if (rand() % 3 > 0)
{
enumItemType potion = (enumItemType)(ItemPotion01 + i);
if (!potionEffectKnown(potion)) setPotionToKnown(potion);
}
}
// drop potion
ItemEntity* potionItem = new ItemEntity( (enumItemType)(ItemPotion01 + rand() % NUMBER_UNIDENTIFIED), player->getX(), player->getY());
potionItem->setVelocity(Vector2D(100.0f + rand()% 250));
potionItem->setViscosity(0.96f);
}
void WitchBlastGame::addPotionToMap(enumItemType source, enumItemType effect, bool known)
{
potionMap[source] = structPotionMap { effect, known};
potionMap[effect] = structPotionMap { source, known};
}
enumItemType WitchBlastGame::getPotion(enumItemType source)
{
return potionMap[source].effect;
}
bool WitchBlastGame::potionEffectKnown(enumItemType source)
{
return potionMap[source].known;
}
void WitchBlastGame::setPotionToKnown(enumItemType source)
{
potionMap[source].known = true;
potionMap[potionMap[source].effect].known = true;
// message
if (messagesQueue.empty()) SoundManager::getInstance().playSound(SOUND_MESSAGE);
messageStruct msg = getMessage(MsgInfoPotionId);
std::stringstream ss;
ss << msg.message[1];
ss << " ";
ss << tools::getLabel(items[getPotion(source)].name);
msg.message[1] = ss.str();
messagesQueue.push(msg);
}
void WitchBlastGame::forgetPotions()
{
for (int i = ItemPotion01; i < FirstEquipItem; i++)
{
potionMap[(enumItemType)i].known = false;
potionMap[potionMap[(enumItemType)i].effect].known = false;
}
}
void WitchBlastGame::forget()
{
// forget map
if (!player->isEquiped(EQUIP_FLOOR_MAP))
{
currentFloor->forget(floorX, floorY);
refreshMinimap();
}
// forget potions
if (!player->isEquiped(EQUIP_BOOK_ALCHEMY))
{
forgetPotions();
}
}
WitchBlastGame &game()
{
return *gameptr;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, Apr 1, 4:34 AM (1 d, 14 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
57293
Default Alt Text
(334 KB)
Attached To
Mode
R78 witchblast
Attached
Detach File
Event Timeline