Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
292 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/media/items_equip.png b/media/items_equip.png
index cb2217e..09faf29 100644
Binary files a/media/items_equip.png and b/media/items_equip.png differ
diff --git a/media/slime.png b/media/slime.png
index 6d6114b..6ffb2e3 100644
Binary files a/media/slime.png and b/media/slime.png differ
diff --git a/src/Constants.h b/src/Constants.h
index 9fedb12..a6c9f07 100644
--- a/src/Constants.h
+++ b/src/Constants.h
@@ -1,654 +1,655 @@
/** 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/>.
*/
#ifndef CONSTANTS_H_INCLUDED
#define CONSTANTS_H_INCLUDED
#include <string>
const std::string APP_NAME = "Witch Blast";
const std::string APP_VERSION = "0.4.6b";
const std::string CONFIG_FILE = "config.dat";
const std::string SAVE_FILE = "game.sav";
const std::string SAVE_DATA_FILE = "data/data.sav";
const std::string HISCORES_FILE = "data/scores.dat";
const std::string SAVE_VERSION = "SAVE_0.4.1";
const int NB_LANGUAGES = 5;
const std::string languageString[NB_LANGUAGES] = { "english", "french", "german", "spanish", "russian" };
const unsigned int SCORES_MAX = 10;
// Client size
const int SCREEN_WIDTH = 970;
const int SCREEN_HEIGHT = 720;
// Tile set
const int TILE_WIDTH = 64;
const int TILE_HEIGHT = 64;
// Tile map offset
const int OFFSET_X = 5;
const int OFFSET_Y = 5;
const int MAP_WIDTH = 15;
const int MAP_HEIGHT = 9;
const int MENU_MAP_WIDTH = 16;
const int MENU_MAP_HEIGHT = 13;
const int GAME_WIDTH = MAP_WIDTH * TILE_WIDTH;
const int GAME_HEIGHT = MAP_HEIGHT * TILE_HEIGHT;
const int FLOOR_WIDTH = 13;
const int FLOOR_HEIGHT = 7;
const int ITEM_WIDTH = 32;
const int ITEM_HEIGHT = 32;
const int BOLT_WIDTH = 24;
const int BOLT_HEIGHT = 24;
const int BOLT_PRO_LINE = 10;
const int BB_LEFT = 22;
const int BB_RIGHT = 22;
const int BB_TOP = 4;
const int BB_BOTTOM = 31;
const float FADE_IN_DELAY = 1.0f;
const float FADE_OUT_DELAY = 1.0f;
const float EXPLOSION_DELAY = 2.0f;
const float DEATH_CERTIFICATE_DELAY = 3.5f;
const float ACHIEVEMENT_DELAY_MAX = 7.0f;
const float KeyRoomFXDelay = 2.0f;
enum enum_images {
IMAGE_PLAYER_0,
IMAGE_PLAYER_1,
IMAGE_BOLT,
IMAGE_TILES,
IMAGE_RAT,
IMAGE_MINIMAP,
IMAGE_MAP_BACKGROUND,
IMAGE_ITEMS,
IMAGE_ITEMS_EQUIP,
IMAGE_ITEMS_PRES,
IMAGE_ITEMS_EQUIP_PRES,
IMAGE_CHEST,
IMAGE_BAT,
IMAGE_FLOWER,
IMAGE_SLIME,
IMAGE_IMP,
IMAGE_SPIDER_EGG,
IMAGE_SPIDER_WEB,
IMAGE_LITTLE_SPIDER,
IMAGE_BUBBLE,
IMAGE_WITCH,
IMAGE_CAULDRON,
IMAGE_SNAKE,
IMAGE_PUMPKIN,
IMAGE_GHOST,
IMAGE_ZOMBIE,
IMAGE_BUTCHER,
IMAGE_GIANT_SLIME,
IMAGE_KING_RAT,
IMAGE_CYCLOP,
IMAGE_GIANT_SPIDER,
IMAGE_FRANCKY,
IMAGE_BLOOD,
IMAGE_CORPSES,
IMAGE_CORPSES_BIG,
IMAGE_STAR,
IMAGE_STAR_2,
IMAGE_HURT_IMPACT,
IMAGE_INTERFACE,
IMAGE_HUD_SHOTS,
IMAGE_EXPLOSION,
IMAGE_KEYS_QWER,
IMAGE_KEYS_AZER,
IMAGE_MESSAGE_ICONS,
IMAGE_INTRO,
IMAGE_TITLE,
IMAGE_OVERLAY,
IMAGE_LIGHT_CONE,
IMAGE_DIVINITY,
IMAGE_PNJ,
IMAGE_FAIRY,
IMAGE_KEY_AREA,
IMAGE_UI_LIFE,
IMAGE_UI_MANA,
IMAGE_UI_SPELLS,
IMAGE_UI_MESSAGE,
IMAGE_UI_TOP_LAYER,
IMAGE_FOG,
IMAGE_TITLE_ANIM,
IMAGE_SPLATTER,
IMAGE_WITCH_INTRO,
IMAGE_ITEM_DESCRIPTION,
IMAGE_DEATH_CERTIFICATE,
NB_IMAGES
};
enum sound_resources {
SOUND_NONE = -1,
SOUND_BLAST_STANDARD,
SOUND_BLAST_FLOWER,
SOUND_BLAST_LIGHTNING,
SOUND_BLAST_FIRE,
SOUND_BLAST_ICE,
SOUND_BLAST_ILLUSION,
SOUND_BLAST_POISON,
SOUND_BLAST_STONE,
SOUND_DOOR_CLOSING,
SOUND_DOOR_OPENING,
SOUND_CHEST_OPENING,
SOUND_IMPACT,
SOUND_BONUS,
SOUND_DRINK,
SOUND_EAT,
SOUND_PLAYER_HIT,
SOUND_PLAYER_DIE,
SOUND_ENNEMY_DYING,
SOUND_COIN_PICK_UP,
SOUND_PAY,
SOUND_WALL_IMPACT,
SOUND_BIG_WALL_IMPACT,
SOUND_KING_RAT_1,
SOUND_KING_RAT_2,
SOUND_KING_RAT_DIE,
SOUND_SLIME_JUMP,
SOUND_SLIME_IMAPCT,
SOUND_SLIME_IMAPCT_WEAK,
SOUND_SLIME_SMASH,
SOUND_ICE_CHARGE,
SOUND_ELECTRIC_CHARGE,
SOUND_SHOT_SELECT,
SOUND_HEART,
SOUND_RAT_DYING,
SOUND_BAT_DYING,
SOUND_IMP_HURT,
SOUND_IMP_DYING,
SOUND_ROCK_IMPACT_LIGHT,
SOUND_ROCK_IMPACT_MEDIUM,
SOUND_ROCK_IMPACT_HEAVY,
SOUND_THROW,
SOUND_CYCLOP_00,
SOUND_CYCLOP_DIE,
SOUND_CYCLOPS_IMPACT,
SOUND_BUTCHER_00,
SOUND_BUTCHER_01,
SOUND_BUTCHER_HURT,
SOUND_BUTCHER_DIE,
SOUND_VIB,
SOUND_BOOM_00,
SOUND_CLANG_00,
SOUND_BUBBLE_00,
SOUND_BUBBLE_01,
SOUND_TRAP,
SOUND_EGG_SMASH_00,
SOUND_EGG_SMASH_01,
SOUND_SPIDER_WALKING,
SOUND_SPIDER_WEB,
SOUND_SPIDER_HURT,
SOUND_SPIDER_DIE,
SOUND_SPIDER_LITTLE_DIE,
SOUND_WITCH_00,
SOUND_WITCH_01,
SOUND_WITCH_02,
SOUND_WITCH_DIE_00,
SOUND_WITCH_DIE_01,
SOUND_INVOKE,
SOUND_CAULDRON,
SOUND_CAULDRON_DIE,
SOUND_SNAKE_DIE,
SOUND_PUMPKIN_00,
SOUND_PUMPKIN_01,
SOUND_PUMPKIN_DIE,
SOUND_CRITICAL,
SOUND_GONG,
SOUND_TELEPORT,
SOUND_SPELL_CHARGE,
SOUND_FIREBALL,
SOUND_MESSAGE,
SOUND_EARTHQUAKE,
SOUND_SPELL_FREEZE,
SOUND_SPELL_SHIELD,
SOUND_HEAVY_STEP_00,
SOUND_HEAVY_STEP_01,
SOUND_NIGHT,
SOUND_GRUMBLE,
SOUND_ZOMBIE_00,
SOUND_ZOMBIE_01,
SOUND_ZOMBIE_ATTACKING,
SOUND_ZOMBIE_DYING,
SOUND_GHOST,
SOUND_GHOST_DYING,
SOUND_ELECTRICITY,
SOUND_ELECTRIC_BLAST,
SOUND_FRANCKY_00,
SOUND_FRANCKY_01,
SOUND_FRANCKY_02,
SOUND_FRANCKY_DYING,
SOUND_OM,
SOUND_GLASS,
SOUND_HICCUP,
SOUND_SPLATCH,
SOUND_INTRO_WITCH,
SOUND_FORCE_FIELD,
SOUND_DOOR_OPENING_BOSS,
SOUND_ACHIEVEMENT,
};
enum corpses_ressources{
FRAME_CORPSE_RAT,
FRAME_CORPSE_BAT,
FRAME_CORPSE_FLOWER,
FRAME_CORPSE_GREEN_RAT,
FRAME_CORPSE_SLIME,
FRAME_CORPSE_BLACK_RAT,
FRAME_CORPSE_IMP_RED,
FRAME_CORPSE_IMP_BLUE,
FRAME_CORPSE_SLIME_RED,
FRAME_CORPSE_SLIME_BLUE,
FRAME_CORPSE_SPIDER_EGG,
FRAME_CORPSE_LITTLE_SPIDER,
FRAME_CORPSE_SPIDER_WEB,
FRAME_CORPSE_RAT_HELMET,
FRAME_CORPSE_BLACK_RAT_HELMET,
FRAME_CORPSE_SLIME_VIOLET,
FRAME_CORPSE_WITCH,
FRAME_CORPSE_WITCH_RED,
FRAME_CORPSE_CAULDRON,
FRAME_CORPSE_SNAKE,
FRAME_CORPSE_SNAKE_BLOOD,
FRAME_CORPSE_PUMPKIN,
FRAME_CORPSE_FLOWER_ICE,
FRAME_CORPSE_GHOST,
FRAME_CORPSE_ZOMBIE,
FRAME_CORPSE_ZOMBIE_DARK,
FRAME_CORPSE_FRANCKY_TORSO,
FRAME_CORPSE_FRANCKY_HEAD,
FRAME_CORPSE_FRANCKY_HAND,
FRAME_CORPSE_FRANCKY_FOOT,
FRAME_CORPSE_FLOWER_FIRE,
FRAME_CORPSE_KING_RAT,
FRAME_CORPSE_GIANT_SLIME,
FRAME_CORPSE_CYCLOP,
FRAME_CORPSE_BUTCHER,
FRAME_CORPSE_GIANT_SPIDER
};
// chests
enum chest_type_enum {
ChestBasic,
ChestExit,
ChestChallenge,
ChestFairy,
};
const float CHEST_APPEAR_DELAY = 1.5f;
// Artefact Info
const float ARTEFACT_RECT_WIDTH = 650.0f;
const float ARTEFACT_RECT_HEIGHT = 100.0f;
const float ARTEFACT_POS_Y = 450.0f;
const float ARTEFACT_BORDER = 3.0f;
const float ARTEFACT_ZOOM_TIME = 0.5f;
// shot types
enum enumShotType {
ShotTypeStandard,
ShotTypeIce,
ShotTypeIllusion,
ShotTypeStone,
ShotTypeLightning,
ShotTypeFire,
ShotTypePoison,
ShotTypeBomb,
ShotTypeCold,
ShotTypeDeterministic
};
// special shots effects
const int MAX_SHOT_LEVEL = 3;
const float STATUS_FROZEN_DELAY[MAX_SHOT_LEVEL] // how long the freeze occurs
= { 4.0f, 5.0f, 6.0f };
const float STATUS_FROZEN_BOLT_DELAY[MAX_SHOT_LEVEL] // reload time
= { 3.0f, 2.6f, 2.0f };
const float STATUS_FROZEN_MULT[MAX_SHOT_LEVEL] // speed multiplier (= 3 times slower)
= { 0.38f, 0.33f, 0.28f };
const float STONE_DECOIL_DELAY[MAX_SHOT_LEVEL] // how long the stun occurs
= { 0.18f, 0.3f, 0.5f };
const float STONE_DECOIL_VELOCITY[MAX_SHOT_LEVEL] // Decoil velocity
= { 125.0f, 160.0f, 220.0f };
const float ILLUSION_DAMAGE_DECREASE[MAX_SHOT_LEVEL] // Illusion damage malus
= { 0.8f, 0.9f, 1.0f };
const float LIGHTNING_VISCOSITY_INCREASE[MAX_SHOT_LEVEL] // Air resistance
= { 0.01, 0.015f, 0.02f };
const float FIRE_DAMAGE_INCREASE[MAX_SHOT_LEVEL] // Fire damage's bonus
= { 1.15f, 1.3f, 1.45f };
const float POISON_TIMER[MAX_SHOT_LEVEL]
= { 10.5f, 12.5f, 12.5f };
const float POISON_DAMAGE[MAX_SHOT_LEVEL]
= { 1, 1, 1 };
const float POISON_DELAY[MAX_SHOT_LEVEL]
= { 2.0f, 1.5f, 1.0f };
// divinity
enum enumDivinityType {
DivinityHealer,
DivinityFighter,
DivinityIce,
DivinityStone,
NB_DIVINITY
};
const std::string divinityLabel[NB_DIVINITY]
{
"divinity_healer",
"divinity_fighter",
"divinity_ice",
"divinity_stone",
};
const int MAX_DIVINITY_LEVEL = 5;
const int DIVINITY_LEVEL_TRESHOLD[MAX_DIVINITY_LEVEL] =
{ 100, 300, 500, 900, 1400};
// entity type
const int ENTITY_PLAYER = 1;
const int ENTITY_FAMILIAR = 2;
const int ENTITY_DOOR = 3;
const int ENTITY_ARTIFACT_DESCRIPTION = 9;
const int ENTITY_BLOOD = 11;
const int ENTITY_CORPSE = 12;
const int ENTITY_EFFECT = 13;
const int ENTITY_FLYING_TEXT = 14;
const int ENTITY_BOLT = 15;
const int ENTITY_ENEMY_BOLT = 16;
const int ENTITY_PNJ = 17;
const int ENTITY_CHEST = 18;
const int ENTITY_ITEM = 19;
const int ENTITY_EXPLOSION = 20;
+const int ENTITY_FAMILIAR_LOCAL = 21;
const int ENTITY_ENEMY = 31;
const int ENTITY_ENEMY_INVOCATED = 32;
const int ENTITY_ENEMY_BOSS = 33;
const int ENTITY_ENEMY_NC = 34;
const int ENTITY_ENEMY_MAX = ENTITY_ENEMY_NC;
const int ENTITY_ENEMY_MAX_COUNT = ENTITY_ENEMY_BOSS;
const float DOOR_OPEN_TIME = 1.0f;
const float DOOR_CLOSE_TIME = 1.0f;
// Player game play
const float INITIAL_PLAYER_SPEED = 220.0f;
const int INITIAL_PLAYER_HP = 20;
const float INITIAL_PLAYER_FIRE_DELAY = 0.7f;
const float ACQUIRE_DELAY = 2.3f;
const float UNLOCK_DELAY = 1.2f;
const float WORSHIP_DELAY = 2.0f;
const float INVINCIBLE_DELAY = 1.5f;
const float HICCUP_DELAY = 5.0f;
const float INITIAL_BOLT_LIFE = 0.45f;
const int INITIAL_BOLT_DAMAGES = 8;
const float INITIAL_BOLT_VELOCITY = 700.0f;
const float INITIAL_BOLT_VISCOSITY = 0.98f;
const float FAIRY_SPEED = 220.0f;
const float FAIRY_FIRE_DELAY = 0.8f;
const float ICE_FAIRY_FIRE_DELAY = 1.3f;
const float TARGET_FAIRY_FIRE_DELAY = 1.0f;
const float FAIRY_BOLT_LIFE = 0.4f;
const int FAIRY_BOLT_DAMAGES = 8;
const int FAIRY_FIRE_DAMAGES = 12;
const float FAIRY_BOLT_VELOCITY = 700.0f;
// Rat
const float RAT_SPEED = 195.0f;
const float RAT_SPEED_HELMET = 140.0f;
const int RAT_HP = 16;
const int RAT_HP_HELMET = 24;
const int RAT_DAMAGES = 5;
const int RAT_BB_LEFT = 14;
const int RAT_BB_WIDTH_DIFF = 28;
const int RAT_BB_TOP = 22;
const int RAT_BB_HEIGHT_DIFF = 22;
// Green Rat
const float GREEN_RAT_SPEED = 180.0f;
const int GREEN_RAT_HP = 16;
const int GREEN_RAT_DAMAGES = 5;
const float GREEN_RAT_FADE = 1.0f;
// Black Rat
const float BLACK_RAT_SPEED = 195.0f;
const float BLACK_RAT_SPEED_HELMET = 125.0f;
const int BLACK_RAT_HP = 16;
const int BLACK_RAT_HP_HELMET = 24;
const int BLACK_RAT_DAMAGES = 5;
// Bat
const float BAT_SPEED = 270.0f;
const int BAT_HP = 5;
const int BAT_DAMAGES = 5;
// Zombie
const float ZOMBIE_SPEED = 80.0f;
const int ZOMBIE_HP = 80;
const int ZOMBIE_DAMAGE = 10;
// Evl Flower
const int EVIL_FLOWER_HP = 16;
const int EVIL_FLOWER_MELEE_DAMAGES = 6;
const int EVIL_FLOWER_MISSILE_DAMAGES = 5;
const int EVIL_FLOWER_FIRE_MISSILE_DAMAGES = 8;
const int EVIL_FLOWER_BB_LEFT = 14;
const int EVIL_FLOWER_BB_WIDTH_DIFF = 28;
const int EVIL_FLOWER_BB_TOP = 22;
const int EVIL_FLOWER_BB_HEIGHT_DIFF = 22;
const float EVIL_FLOWER_FIRE_DELAY = 2.2f;
const float EVIL_FLOWER_FIRE_VELOCITY = 230.0f;
// Snake
const float SNAKE_SPEED = 150.0f;
const int SNAKE_HP = 16;
const int SNAKE_DAMAGE = 5;
const float SNAKE_BLOOD_SPEED = 170.0f;
const int SNAKE_BLOOD_HP = 32;
const int SNAKE_BLOOD_DAMAGE = 8;
// Slime
const int SLIME_HP = 16;
const int SLIME_DAMAGES = 5;
const int SLIME_BB_LEFT = 13;
const int SLIME_BB_WIDTH_DIFF = 26;
const int SLIME_BB_TOP = 38;
const int SLIME_BB_HEIGHT_DIFF = 40;
const float SLIME_FIRE_VELOCITY = 240.0f;
// Imp
const float IMP_SPEED = 190.0f;
const int IMP_HP = 20;
const int IMP_MELEE_DAMAGES = 5;
const int IMP_MISSILE_DAMAGES = 8;
const float IMP_FIRE_VELOCITY = 260.0f;
// Witch
const int WITCH_HP = 80;
const int WITCH_DAMAGE = 5;
const int WITCH_VELOCITY = 140.0f;
// Cauldron
const int CAULDRON_HP = 150;
// Ghost
const float GHOST_SPEED = 140.0f;
const int GHOST_HP = 40;
const int GHOST_DAMAGE = 8;
// Butcher
const int BUTCHER_HP = 120;
const int BUTCHER_DAMAGES = 8;
const int BUTCHER_VELOCITY = 100;
// Giant Slime
const int GIANT_SLIME_HP = 250;
const int GIANT_SLIME_DAMAGES = 8;
const int GIANT_SLIME_MISSILE_DAMAGES = 6;
const float GIANT_SLIME_MISSILE_DELAY = 0.33f;
const float GIANT_SLIME_FIRE_VELOCITY = 200.0f;
const int GIANT_SLIME_BB_LEFT = 26;
const int GIANT_SLIME_BB_WIDTH_DIFF = 52;
const int GIANT_SLIME_BB_TOP = 64;
const int GIANT_SLIME_BB_HEIGHT_DIFF = 12;
const int GIANT_SLIME_SPEED = 80.0f;
const float GIANT_SLIME_ULTRA_JUMP_VELOCITY = 1700.0f;
const float GIANT_SLIME_ULTRA_FALL_VELOCITY = -2000.0f;
const float GIANT_SLIME_ULTRA_JUMP_TIMER = 2.3f;
// KingRat
const float KING_RAT_SPEED = 210.0f;
const float KING_RAT_RUNNING_SPEED = 750.0f;
const float KING_RAT_BERSERK_SPEED = 300.0f;
const float KING_RAT_RUNNING_RECOIL = 750.0f;
const int KING_RAT_HP = 700;
const int KING_RAT_DAMAGES = 8;
// Cyclops
const float CYCLOP_SPEED[4] = { 140, 150, 160, 170};
const int CYCLOP_NUMBER_ROCKS[4] = { 5, 7, 9, 12};
const float CYCLOP_FIRE_DELAY[4] = { 0.3f, 0.26f, 0.23f, 0.2f};
const int CYCLOP_HP = 880;
const int CYCLOP_DAMAGES = 8;
// Giant Spider
const float GIANT_SPIDER_SPEED[4] = { 240, 245, 250, 255 };
const int GIANT_SPIDER_NUMBER_EGGS[4] = { 12, 14, 16, 19};
const float GIANT_SPIDER_FIRE_DELAY[4] = { 0.8f, 0.7f, 0.6f, 0.5f};
const int GIANT_SPIDER_HP = 800;
const int GIANT_SPIDER_DAMAGE = 8;
// EFFECTS
const float HURTING_DELAY = 0.4f;
const float HEART_BEAT_DELAY = 1.2f;
// messages
const int NB_MSG_LINES = 3;
enum EnumMessages
{
MsgInfoLevel1,
MsgInfoLevel2,
MsgInfoLevel3,
MsgInfoLevel4,
MsgInfoLevel5,
MsgInfoLevel6,
MsgInfoRatsBats,
MsgInfoSnakes,
MsgInfoWitches,
MsgInfoGold,
MsgInfoFamiliar,
MsgInfoButcher,
MsgInfoGiantSlime,
MsgInfoCyclops,
MsgInfoWererat,
MsgInfoGiantSpiderBefore,
MsgInfoGiantSpiderAfter,
MsgInfoFranky,
MsgInfoDivHealer,
MsgInfoDivFighter,
MsgInfoDivIce,
MsgInfoDivStone,
MsgInfoDivIntervention,
MsgInfoDivGift,
MsgTutoBasics,
MsgTutoTips,
MsgTutoItems,
MsgTutoShops,
MsgTutoBossDoor,
MsgTutoChallengeDoor,
MsgTutoTemple,
MsgTutoHeal,
MsgTutoShots,
MsgTutoSpell,
NB_MESSAGES
};
enum EnumMessagesType
{
MessageTypeInfo,
MessageTypeTutorial,
};
struct messageStruct
{
int icon;
EnumMessagesType messageType;
EnumMessages type;
std::string message[NB_MSG_LINES];
float timer;
float timerMax;
};
enum EnumWorldEvents
{
// info
EventMeetRatsOrBats,
EventMeetSnakes,
EventMeetWitches,
EventGetCoin,
EventPietyMax,
EventTripleHit,
EventCompleteSet,
// tuto
EventBeingHurted,
EventFindShop,
EventFindBossDoor,
EventFindChallengeDoor,
EventFindTemple,
EventGetItem,
EventGetSpecialShot,
EventGetFamiliar,
EventGetSpell,
NB_EVENTS
};
enum EnumInteractionType
{
InteractionTypeTemple,
InteractionTypeMerchandise,
};
#endif // CONSTANTS_H_INCLUDED
diff --git a/src/Items.h b/src/Items.h
index c8bccd2..d691b8f 100644
--- a/src/Items.h
+++ b/src/Items.h
@@ -1,548 +1,555 @@
#ifndef ITEMS_H
#define ITEMS_H
#include "Constants.h"
const int SPECIAL_SHOT_SLOTS_STANDARD = 2;
const int SPECIAL_SHOT_SLOTS_ADVANCED = 2;
const int SPECIAL_SHOT_SLOTS = 1 + SPECIAL_SHOT_SLOTS_STANDARD + SPECIAL_SHOT_SLOTS_ADVANCED;
/** Rarity enum
* Rarity of the equipment.
*/
enum enumRarity
{
RarityCommon, /**< Common */
RarityUncommon, /**< Uncommon */
RarityRare /**< Rare */
};
/** Familiar enum
* Familiars.
*/
enum enumFamiliar
{
FamiliarNone = -1, /**< No familiar */
FamiliarFairy, /**< Standard Fairy */
FamiliarFairyTarget, /**< Target Fairy */
FamiliarFairyFire, /**< Fire Fairy */
FamiliarFairyIce, /**< Ice Fairy */
FamiliarFairyPoison, /**< Poison Fairy */
};
// spells
enum enumCastSpell
{
SpellTeleport,
SpellSlimeExplode,
SpellFireball,
SpellFreeze,
SpellEarthquake,
SpellProtection,
SpellWeb,
SpellFlower,
SpellNone
};
const int SPELL_MAX = SpellNone;
const std::string spellLabel[SpellNone] =
{
"spell_teleport",
"spell_slime_explode",
"spell_fireball",
"spell_freeze",
"spell_earthquake",
"spell_protection",
"spell_web",
};
/** Item type enum
* All the items and equipments.
*/
enum enumItemType
{
ItemCopperCoin,
ItemSilverCoin,
ItemGoldCoin,
ItemBossHeart,
ItemBonusHealth,
ItemHealthVerySmall,
ItemHealthSmall,
ItemHealth,
ItemHealthVerySmallPoison,
ItemMagicianHat, // first equip item
ItemLeatherBoots,
ItemBookDualShots,
ItemRageAmulet,
ItemBossKey,
ItemDisplacementGloves,
ItemMahoganyStaff,
ItemFairy,
ItemLeatherBelt,
ItemBloodSnake,
ItemGemIce,
ItemGemIllusion,
ItemGemStone,
ItemGemLightning,
ItemFairyTarget,
ItemRingIce,
ItemRingStone,
ItemRingLightning,
ItemRingIllusion,
ItemBookTripleShots,
ItemBroochFinesse,
ItemFairyFire,
ItemFairyIce,
ItemMagicianRobe,
ItemGemFire,
ItemRingFire,
ItemManualStaff,
ItemSpellTeleport,
ItemSpellSlimeExplode,
ItemSpellFireball,
ItemSpellFreeze,
ItemSpellEarthquake,
ItemSpellProtection,
ItemManualSlime,
ItemBookDualShotsQuick,
ItemBookTripleShotsQuick,
ItemManualHealth,
ItemRearShot,
ItemBookRandomShot,
ItemSpellWeb,
ItemBookMagicI,
ItemBookMagicII,
ItemSulfur,
ItemFloorMap,
ItemAlcohol,
ItemLuck,
ItemFairyPowder,
ItemBookRapidShots,
ItemGemPoison,
ItemSpellFlower,
ItemFairyPoison,
ItemRingPoison,
ItemBookPrayerI,
ItemBookPrayerII,
+ ItemPetSlime,
NUMBER_ITEMS
};
const int FirstEquipItem = (int) ItemMagicianHat; /*!< Used as an offset when creating items */
/*!
* \brief Item structure
*
* Contains all the data for an item.
*/
struct itemStuct
{
enumItemType type; /**< The item ID */
std::string name; /**< The item name */
std::string description; /**< The item description */
int price; /**< The item price (for shops) */
bool equip; /**< True if the item is an equipment */
enumFamiliar familiar; /**< True if the "item" is a familiar */
bool canBeSold; /**< True if the item is can be sold */
bool canBeFound; /**< True if the item is can be found */
bool generatesStance; /**< True if picking the item generates an acquiring stance*/
int level; /**< Minimal level where the item can be found */
enumRarity rarity; /**< Item rarity */
bool isFloorItem; /**< Floor item */
int requirement; /**< Pre-requisite item */
enumShotType specialShot; /**< Special shot */
enumCastSpell spell; /**< Spell */
};
/** Array with all the items and data */
const itemStuct items[NUMBER_ITEMS] =
{
{
ItemCopperCoin, "item_copper", "item_copper_desc",
1, false, FamiliarNone, false, false, false, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemSilverCoin, "item_silver", "item_silver_desc",
5, false, FamiliarNone, false, false, false, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemGoldCoin, "item_gold", "item_gold_desc",
20, false, FamiliarNone, false, false, false, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemBossHeart, "item_titan_heart", "item_titan_heart_desc",
250, false, FamiliarNone, false, false, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemBonusHealth, "item_elven_cookie", "item_elven_cookie_desc",
250, false, FamiliarNone, false, false, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemHealthVerySmall, "item_apple", "item_apple_desc",
2, false, FamiliarNone, true, false, false, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemHealthSmall, "item_bread", "item_bread_desc",
4, false, FamiliarNone, true, false, false, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemHealthSmall, "item_cheese", "item_cheese_desc",
8, false, FamiliarNone, true, false, false, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemHealthVerySmallPoison, "item_apple_green", "item_apple_green_desc",
2, false, FamiliarNone, true, false, false, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemMagicianHat, "item_sorcerer_hat", "item_sorcerer_hat_desc",
20, true, FamiliarNone, true, true, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemLeatherBoots, "item_velvet_boots", "item_velvet_boots_desc",
20, true, FamiliarNone, true, true, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemBookDualShots, "item_spell_dual", "item_spell_dual_desc",
20, true, FamiliarNone, true, true, true, 1, RarityRare, false, -1, ShotTypeStandard, SpellNone
},
{
ItemRageAmulet, "item_rage_amulet", "item_rage_amulet_desc",
20, true, FamiliarNone, true, true, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemBossKey, "item_boss_key", "item_boss_key_desc",
10, true, FamiliarNone, false, false, true, 1, RarityCommon, true, -1, ShotTypeStandard, SpellNone
},
{
ItemDisplacementGloves, "item_displacement_gloves", "item_displacement_gloves_desc",
20, true, FamiliarNone, true, true, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemMahoganyStaff, "item_staff", "item_staff_desc",
25, true, FamiliarNone, true, true, true, 2, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemFairy, "item_fairy", "item_fairy_desc",
20, true, FamiliarFairy, false, true, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemLeatherBelt, "item_leather_belt", "item_leather_belt_desc",
20, true, FamiliarNone, true, true, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemBloodSnake, "item_blood_snake", "item_blood_snake_desc",
20, true, FamiliarNone, true, true, true, 1, RarityUncommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemGemIce, "item_gem_ice", "item_gem_ice_desc",
25, true, FamiliarNone, true, true, true, 2, RarityCommon, false, -1, ShotTypeIce, SpellNone
},
{
ItemGemIllusion, "item_gem_illusion", "item_gem_illusion_desc",
30, true, FamiliarNone, true, true, true, 4, RarityUncommon, false, -1, ShotTypeIllusion, SpellNone
},
{
ItemGemStone, "item_gem_stone", "item_gem_stone_desc",
25, true, FamiliarNone, true, true, true, 2, RarityCommon, false, -1, ShotTypeStone, SpellNone
},
{
ItemGemLightning, "item_gem_lightning", "item_gem_lightning_desc",
25, true, FamiliarNone, true, true, true, 2, RarityCommon, false, -1, ShotTypeLightning, SpellNone
},
{
ItemFairyTarget, "item_fairy_target", "item_fairy_target_desc",
40, true, FamiliarFairyTarget, false, true, true, 2, RarityUncommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemRingIce, "item_ring_ice", "item_ring_ice_desc",
45, true, FamiliarNone, true, true, true, 3, RarityUncommon, false, ItemGemIce, ShotTypeStandard, SpellNone
},
{
ItemRingStone, "item_ring_stone", "item_ring_stone_desc",
45, true, FamiliarNone, true, true, true, 3, RarityUncommon, false, ItemGemStone, ShotTypeStandard, SpellNone
},
{
ItemRingLightning, "item_ring_lightning", "item_ring_lightning_desc",
45, true, FamiliarNone, true, true, true, 3, RarityUncommon, false, ItemGemLightning, ShotTypeStandard, SpellNone
},
{
ItemRingIllusion, "item_ring_illusion", "item_ring_illusion_desc",
50, true, FamiliarNone, true, true, true, 4, RarityUncommon, false, ItemGemIllusion, ShotTypeStandard, SpellNone
},
{
ItemBookTripleShots, "item_spell_triple", "item_spell_triple_desc",
50, true, FamiliarNone, true, true, true, 4, RarityCommon, false, ItemBookDualShots, ShotTypeStandard, SpellNone
},
{
ItemBroochFinesse, "item_brooch_finesse", "item_brooch_finesse_desc",
20, true, FamiliarNone, true, true, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemFairyFire, "item_fairy_fire", "item_fairy_fire_desc",
30, true, FamiliarFairyFire, false, true, true, 2, RarityUncommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemFairyIce, "item_fairy_ice", "item_fairy_ice_desc",
30, true, FamiliarFairyIce, false, true, true, 2, RarityUncommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemMagicianRobe, "item_robe_magician", "item_robe_magician_desc",
25, true, FamiliarNone, true, true, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemGemFire, "item_gem_fire", "item_gem_fire_desc",
30, true, FamiliarNone, true, true, true, 4, RarityUncommon, false, -1, ShotTypeFire, SpellNone
},
{
ItemRingFire, "item_ring_fire", "item_ring_fire_desc",
50, true, FamiliarNone, true, true, true, 4, RarityUncommon, false, ItemGemFire, ShotTypeStandard, SpellNone
},
{
ItemManualStaff, "item_manual_staff", "item_manual_staff_desc",
20, true, FamiliarNone, true, true, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemSpellTeleport, "item_spell_teleport", "item_spell_teleport_desc",
60, true, FamiliarNone, false, false, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellTeleport
},
{
ItemSpellSlimeExplode, "item_spell_slime_explode", "item_spell_slime_explode_desc",
60, true, FamiliarNone, false, false, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellSlimeExplode
},
{
ItemSpellFireball, "item_spell_fireball", "item_spell_fireball_desc",
60, true, FamiliarNone, false, false, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellFireball
},
{
ItemSpellFreeze, "item_spell_freeze", "item_spell_freeze_desc",
60, true, FamiliarNone, false, false, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellFreeze
},
{
ItemSpellEarthquake, "item_spell_earthquake", "item_spell_earthquake_desc",
60, true, FamiliarNone, false, false, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellEarthquake
},
{
ItemSpellProtection, "item_spell_protection", "item_spell_protection_desc",
60, true, FamiliarNone, false, false, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellProtection
},
{
ItemManualSlime, "item_manual_slime", "item_manual_slime_desc",
30, true, FamiliarNone, true, true, true, 3, RarityUncommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemBookDualShotsQuick, "item_spell_dual_quick", "item_spell_dual_quick_desc",
20, true, FamiliarNone, true, true, true, 1, RarityRare, false, -1, ShotTypeStandard, SpellNone
},
{
ItemBookTripleShotsQuick, "item_spell_triple_quick", "item_spell_triple_quick_desc",
50, true, FamiliarNone, true, true, true, 4, RarityCommon, false, ItemBookDualShotsQuick, ShotTypeStandard, SpellNone
},
{
ItemManualHealth, "item_manual_health", "item_manual_health_desc",
20, true, FamiliarNone, true, true, true, 2, RarityCommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemRearShot, "item_rear_shot", "item_rear_shot_desc",
20, true, FamiliarNone, true, true, true, 1, RarityUncommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemBookRandomShot, "item_book_random_shot", "item_book_random_shot_desc",
20, true, FamiliarNone, true, true, true, 1, RarityUncommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemSpellWeb, "item_spell_web", "item_spell_web_desc",
60, true, FamiliarNone, false, false, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellWeb
},
{
ItemBookMagicI, "item_book_magic_i", "item_book_magic_i_desc",
35, true, FamiliarNone, true, true, true, 4, RarityRare, false, -1, ShotTypeStandard, SpellNone
},
{
ItemBookMagicII, "item_book_magic_ii", "item_book_magic_ii_desc",
35, true, FamiliarNone, true, true, true, 4, RarityRare, false, -1, ShotTypeStandard, SpellNone
},
{
ItemSulfur, "item_sulfur", "item_sulfur_desc",
35, true, FamiliarNone, true, true, true, 2, RarityRare, false, -1, ShotTypeStandard, SpellNone
},
{
ItemFloorMap, "item_floor_map", "item_floor_map_desc",
10, true, FamiliarNone, false, false, true, 1, RarityCommon, true, -1, ShotTypeStandard, SpellNone
},
{
ItemAlcohol, "item_alcohol", "item_alcohol_desc",
10, true, FamiliarNone, false, false, true, 1, RarityCommon, true, -1, ShotTypeStandard, SpellNone
},
{
ItemLuck, "item_luck", "item_luck_desc",
10, true, FamiliarNone, false, false, true, 1, RarityCommon, true, -1, ShotTypeStandard, SpellNone
},
{
ItemFairyPowder, "item_fairy_powder", "item_fairy_powder_desc",
10, true, FamiliarNone, false, false, true, 1, RarityCommon, true, -1, ShotTypeStandard, SpellNone
},
{
ItemBookRapidShots, "item_rapid_shots", "item_rapid_shots_desc",
20, true, FamiliarNone, true, true, true, 1, RarityRare, false, -1, ShotTypeStandard, SpellNone
},
{
ItemGemPoison, "item_gem_poison", "item_gem_poison_desc",
30, true, FamiliarNone, true, true, true, 4, RarityUncommon, false, -1, ShotTypePoison, SpellNone
},
{
ItemSpellFlower, "item_spell_flower", "item_spell_flower_desc",
60, true, FamiliarNone, false, false, true, 1, RarityCommon, false, -1, ShotTypeStandard, SpellFlower
},
{
ItemFairyPoison, "item_fairy_poison", "item_fairy_poison_desc",
30, true, FamiliarFairyPoison, false, true, true, 2, RarityUncommon, false, -1, ShotTypeStandard, SpellNone
},
{
ItemRingPoison, "item_ring_poison", "item_ring_poison_desc",
50, true, FamiliarNone, true, true, true, 4, RarityUncommon, false, ItemGemPoison, ShotTypeStandard, SpellNone
},
{
ItemBookPrayerI, "item_book_prayer_i", "item_book_prayer_i_desc",
35, true, FamiliarNone, true, true, true, 3, RarityRare, false, -1, ShotTypeStandard, SpellNone
},
{
ItemBookPrayerII, "item_book_prayer_ii", "item_book_prayer_ii_desc",
35, true, FamiliarNone, true, true, true, 3, RarityRare, false, -1, ShotTypeStandard, SpellNone
},
+ {
+ ItemSulfur, "item_pet_slime", "item_pet_slime_desc",
+ 50, true, FamiliarNone, true, true, true, 1, RarityRare, false, -1, ShotTypeStandard, SpellNone
+ },
};
/** Item equipment type enum
* All the equipments.
*/
enum item_equip_enum {
EQUIP_MAGICIAN_HAT,
EQUIP_LEATHER_BOOTS,
EQUIP_BOOK_DUAL,
EQUIP_RAGE_AMULET,
EQUIP_BOSS_KEY,
EQUIP_DISPLACEMENT_GLOVES,
EQUIP_MAHOGANY_STAFF,
EQUIP_FAIRY,
EQUIP_LEATHER_BELT,
EQUIP_BLOOD_SNAKE,
EQUIP_GEM_ICE,
EQUIP_GEM_ILLUSION,
EQUIP_GEM_STONE,
EQUIP_GEM_LIGHTNING,
EQUIP_FAIRY_ICE,
EQUIP_RING_ICE,
EQUIP_RING_STONE,
EQUIP_RING_LIGHTNING,
EQUIP_RING_ILLUSION,
EQUIP_BOOK_TRIPLE,
EQUIP_BROOCH_FINESSE,
EQUIP_FAIRY_FIRE,
EQUIP_FAIRY_TARGET,
EQUIP_MAGICIAN_ROBE,
EQUIP_GEM_FIRE,
EQUIP_RING_FIRE,
EQUIP_MANUAL_STAFF,
EQUIP_SPELL_TELEPORT,
EQUIP_SPELL_SLIME_EXPLODE,
EQUIP_SPELL_FIREBALL,
EQUIP_SPELL_FREEZE,
EQUIP_SPELL_EARTHQUAKE,
EQUIP_SPELL_PROTECTION,
EQUIP_MANUAL_SLIMES,
EQUIP_BOOK_DUAL_QUICK,
EQUIP_BOOK_TRIPLE_QUICK,
EQUIP_MANUAL_HEALTH,
EQUIP_REAR_SHOT,
EQUIP_BOOK_RANDOM,
EQUIP_SPELL_WEB,
EQUIP_BOOK_MAGIC_I,
EQUIP_BOOK_MAGIC_II,
EQUIP_SULFUR,
EQUIP_FLOOR_MAP,
EQUIP_ALCOHOL,
EQUIP_LUCK,
EQUIP_FAIRY_POWDER,
EQUIP_RAPID_SHOT,
EQUIP_GEM_POISON,
EQUIP_SPELL_FLOWER,
EQUIP_FAIRY_POISON,
EQUIP_RING_POISON,
EQUIP_BOOK_PRAYER_I,
EQUIP_BOOK_PRAYER_II,
+ EQUIP_PET_SLIME,
NUMBER_EQUIP_ITEMS
};
const std::vector<item_equip_enum> sortedEquipement =
{
// clothes
EQUIP_MAGICIAN_ROBE,
EQUIP_MAGICIAN_HAT,
EQUIP_LEATHER_BOOTS,
EQUIP_DISPLACEMENT_GLOVES,
EQUIP_LEATHER_BELT,
EQUIP_RAGE_AMULET,
EQUIP_BROOCH_FINESSE,
EQUIP_RING_ICE,
EQUIP_RING_STONE,
EQUIP_RING_LIGHTNING,
EQUIP_RING_FIRE,
EQUIP_RING_ILLUSION,
EQUIP_RING_POISON,
// weapons
EQUIP_MAHOGANY_STAFF,
EQUIP_BLOOD_SNAKE,
EQUIP_REAR_SHOT,
EQUIP_SULFUR,
EQUIP_GEM_ICE,
EQUIP_GEM_STONE,
EQUIP_GEM_LIGHTNING,
EQUIP_GEM_FIRE,
EQUIP_GEM_ILLUSION,
EQUIP_GEM_POISON,
// books
EQUIP_MANUAL_STAFF,
EQUIP_MANUAL_SLIMES,
EQUIP_MANUAL_HEALTH,
EQUIP_BOOK_RANDOM,
EQUIP_BOOK_MAGIC_I,
EQUIP_BOOK_MAGIC_II,
EQUIP_BOOK_PRAYER_I,
EQUIP_BOOK_PRAYER_II,
EQUIP_BOOK_DUAL,
EQUIP_BOOK_TRIPLE,
EQUIP_BOOK_DUAL_QUICK,
EQUIP_BOOK_TRIPLE_QUICK,
EQUIP_RAPID_SHOT,
// familiars
EQUIP_FAIRY,
EQUIP_FAIRY_ICE,
EQUIP_FAIRY_FIRE,
EQUIP_FAIRY_POISON,
EQUIP_FAIRY_TARGET,
+ EQUIP_PET_SLIME,
// spells
EQUIP_SPELL_TELEPORT,
EQUIP_SPELL_SLIME_EXPLODE,
EQUIP_SPELL_FIREBALL,
EQUIP_SPELL_FREEZE,
EQUIP_SPELL_EARTHQUAKE,
EQUIP_SPELL_PROTECTION,
EQUIP_SPELL_WEB,
EQUIP_SPELL_FLOWER,
// others
EQUIP_BOSS_KEY,
EQUIP_FLOOR_MAP,
EQUIP_ALCOHOL,
EQUIP_LUCK,
EQUIP_FAIRY_POWDER
};
#endif
diff --git a/src/PlayerEntity.cpp b/src/PlayerEntity.cpp
index 7af5cd0..0846bfe 100644
--- a/src/PlayerEntity.cpp
+++ b/src/PlayerEntity.cpp
@@ -1,2626 +1,2646 @@
#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}
};
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;
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 = 0;
// init the shots (to none)
for (int i = 0; i < SPECIAL_SHOT_SLOTS; i++)
{
specialShots[i] = ShotTypeStandard;
specialShotLevel[i] = 0;
}
specialShotIndex = 0;
needInitShotType = false;
computePlayer();
firingDirection = 5;
facingDirection = 2;
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;
isRegeneration = 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)
{
if (isRegeneration) return -1.0f;
float result = 1.0f;
if (divineInterventionDelay < 0.25f)
result = 4 * divineInterventionDelay;
else if (divineInterventionDelay > WORSHIP_DELAY - 0.25f)
result = (WORSHIP_DELAY - divineInterventionDelay) * 4;
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;
}
divinityStruct PlayerEntity::getDivinity()
{
return divinity;
}
int PlayerEntity::getPiety()
{
return divinity.piety;
}
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);
}
+ // spells
+ else if (items[acquiredItem].spell != SpellNone)
+ {
+ setActiveSpell(items[acquiredItem].spell, false);
+ game().proceedEvent(EventGetSpell);
+ }
+
+ // pet slime
+ else if (acquiredItem == ItemPetSlime)
+ {
+ new SlimePetEntity();
+ }
+
// 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_HAT])
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;
BoltEntity* bolt = new BoltEntity(x, y - 10, boltLifeTime, ShotTypeStandard, 0);
bolt->setDamages(fireDamages);
bolt->setVelocity(recoil.velocity.vectorTo(Vector2D(0, 0), 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* doorEntity = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_TILES),
(MAP_WIDTH / 2) * TILE_WIDTH - TILE_WIDTH / 2,
TILE_HEIGHT / 2, 64, 64, 1);
doorEntity->setZ(TILE_HEIGHT);
doorEntity->setImagesProLine(10);
doorEntity->setFrame(189);
doorEntity->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();
}
}
if (playerStatus != playerStatusDead)
{
if (invincibleDelay >= 0.0f) invincibleDelay -= delay;
}
z = y + 4;
}
bool PlayerEntity::canCollide()
{
return invincibleDelay <= 0.0f;
}
void PlayerEntity::setSpecialState(enumSpecialState state, bool active, float timer, float param1, float param2)
{
BaseCreatureEntity::setSpecialState(state, active, timer, param1, param2);
computePlayer();
}
void PlayerEntity::renderPlayer(sf::RenderTarget* app)
{
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_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_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_BROOCH_FINESSE])
{
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);
}
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);
}
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);
}
// 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_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) && 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() == 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));
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
{
// shadow
//sprite.setTextureRect(sf::IntRect( 2 * width, 11 * height, width, height));
//app->draw(sprite);
renderHalo(app);
renderPlayer(app);
// shield
if (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;
}
}
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);
}
}
}
}
if (game().getShowLogical() && playerStatus != playerStatusDead)
{
displayBoundingBox(app);
displayCenterAndZ(app);
}
}
void PlayerEntity::calculateBB()
{
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);
}
}
}
void PlayerEntity::move(int direction)
{
if (playerStatus == playerStatusAcquire && statusTimer < ACQUIRE_DELAY / 2)
{
acquireItemAfterStance();
}
if (playerStatus == playerStatusPlaying)
{
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));
{
switch (direction)
{
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);
}
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, y - 20, boltLifeTime, boltType, shotLevel);
int boltDamage = fireDamages;
if (criticalChance > 0)
if (rand()% 100 < criticalChance)
{
boltDamage += boltDamage;
bolt->setCritical(true);
}
bolt->setDamages(boltDamage);
if (equip[EQUIP_DISPLACEMENT_GLOVES])
{
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()
{
for (int i = -1; i <= 1; i += 2)
for (int j = -1; j <= 1; j += 2)
{
BoltEntity* bolt = new BoltEntity(x, y - 10, boltLifeTime, ShotTypeFire, 0);
bolt->setDamages(10);
float velx = fireVelocity * i * 0.42f;
float vely = fireVelocity * j * 0.42f;
bolt->setVelocity(Vector2D(velx, vely));
if (hp <= hpMax / 5)
{
BoltEntity* bolt = new BoltEntity(x, y - 10, boltLifeTime, ShotTypeFire, 0);
bolt->setDamages(10);
float velx = 0.0f;
float vely = 0.0f;
if (i == -1 && j == -1) velx = -fireVelocity * i * 0.6f;
else if (i == -1 && j == 1) velx = fireVelocity * i * 0.6f;
else if (i == 1 && j == -1) vely= -fireVelocity * i * 0.6f;
else if (i == 1 && j == 1) vely = fireVelocity * 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)
{
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, y - 10, boltLifeTime, ShotTypeStandard, 0);
bolt->setDamages(fireDamages / 2);
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, y - 10, boltLifeTime, ShotTypeStandard, 0);
bolt->setDamages(fireDamages);
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;
bool divinityInvoked = false;
if (hp - hurtParam.damage <= hpMax / 4 && divinity.divinity >= 0)
{
divinityInvoked = triggerDivinityBefore();
if (divinityInvoked)
game().testAndAddMessageToQueue((EnumMessages)(MsgInfoDivIntervention));
}
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();
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 (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
&& i + FirstEquipItem != ItemMagicianRobe)
loseItem(enumItemType(i), true);
}
}
remove(SAVE_FILE.c_str());
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 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);
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;
}
}
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_DISPLACEMENT_GLOVES]) fireDelayBonus -= 0.10f;
if (equip[EQUIP_MAGICIAN_HAT]) fireDelayBonus -= 0.2f;
if (equip[EQUIP_LEATHER_BELT]) fireDelayBonus -= 0.15f;
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_BROOCH_FINESSE]) 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_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] = ResistanceHigh;
break;
}
case (DivinityStone):
{
if (divinity.level >= 5) resistance[ResistanceRecoil] = ResistanceVeryHigh;
if (divinity.level >= 3) resistance[ResistanceStone] = ResistanceHigh;
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]++;
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;
}
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();
}
}
}
// DIVINITY
void PlayerEntity::donate(int n)
{
if (gold >= n)
{
gold -= n;
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;
}
}
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)
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;
int multBonus = 6;
if (divinity.divinity == DivinityFighter) multBonus = 8;
for (float i = 0.0f; i < 2 * PI; i += PI / 16)
{
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));
bolt->setFlying(true);
bolt->setViscosity(1.0f);
bolt->setLifetime(-1.0f);
bolt->setGoThrough(true);
bolt->setFromPlayer(false);
}
}
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->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:
{
break;
}
case DivinityFighter:
{
int r = rand() % 3;
if (r == 0) return false;
SoundManager::getInstance().playSound(SOUND_OM);
divinity.interventions ++;
divineHeal(hpMax / 3);
if (r == 1) divineProtection(5.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);
divinity.interventions ++;
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() % 3;
r = 1;
divineProtection(10.0f, 0.5f);
if (r == 0) return false;
SoundManager::getInstance().playSound(SOUND_OM);
divinity.interventions ++;
divineHeal(hpMax / 3);
if (r == 1)
{
divineRepulse();
game().makeColorEffect(X_GAME_COLOR_BROWN, 3.0f);
}
else
{
divineFury();
game().makeColorEffect(X_GAME_COLOR_BROWN, 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);
divinity.interventions ++;
divineHeal(hpMax);
break;
}
case DivinityFighter:
{
SoundManager::getInstance().playSound(SOUND_OM);
divinity.interventions ++;
divineHeal(hpMax / 2);
break;
}
}
game().testAndAddMessageToQueue((EnumMessages)(MsgInfoDivIntervention));
}
}
void PlayerEntity::addPiety(int n)
{
if (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;
computePlayer();
}
}
void PlayerEntity::worship(enumDivinityType id)
{
int oldPiety = divinity.piety;
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)
{
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 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 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, y - 10, boltLifeTime + 0.5f, boltType, shotLevel);
int boltDamage = fireDamages * (equip[EQUIP_BOOK_MAGIC_II] ? 4 : 3);
if (equip[EQUIP_BOOK_MAGIC_II] && boltDamage < 16) boltDamage = 16;
else if (!equip[EQUIP_BOOK_MAGIC_II] && boltDamage < 12) boltDamage = 12;
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, y - 10, 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);
}
diff --git a/src/PlayerEntity.h b/src/PlayerEntity.h
index be87ef5..39bbe0f 100644
--- a/src/PlayerEntity.h
+++ b/src/PlayerEntity.h
@@ -1,593 +1,595 @@
#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;
};
/*! \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();
/*!
* \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 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 loadDivinity(int id, int piety, int level, int interventions);
bool triggerDivinityBefore();
void triggerDivinityAfter();
void divineFury();
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) override;
void setItemToBuy(ItemEntity* item);
ItemEntity* getItemToBuy();
void castTeleport();
protected:
virtual void readCollidingEntity(CollidingSpriteEntity* entity);
void generateBolt(float velx, float vely);
void rageFire();
virtual void collideMapRight();
virtual void collideMapLeft();
virtual void collideMapTop();
virtual void collideMapBottom();
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 criticalChance;
float invincibleDelay;
float divineInterventionDelay;
bool isRegeneration;
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;
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;
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();
ItemEntity* itemToBuy;
};
#endif // PLAYERSPRITE_H
diff --git a/src/SlimePetEntity.cpp b/src/SlimePetEntity.cpp
new file mode 100644
index 0000000..cb42dcc
--- /dev/null
+++ b/src/SlimePetEntity.cpp
@@ -0,0 +1,253 @@
+#include "SlimePetEntity.h"
+#include "PlayerEntity.h"
+#include "EnemyBoltEntity.h"
+#include "ExplosionEntity.h"
+#include "sfml_game/SpriteEntity.h"
+#include "sfml_game/ImageManager.h"
+#include "sfml_game/SoundManager.h"
+#include "Constants.h"
+#include "WitchBlastGame.h"
+
+SlimePetEntity::SlimePetEntity()
+ : BaseCreatureEntity (ImageManager::getInstance().getImage(IMAGE_SLIME), 200, 200, 64, 64)
+{
+ creatureSpeed = 0.0f;
+ velocity = Vector2D(0.0f, 0.0f);
+ hp = SLIME_HP;
+
+ jumpingDelay = 0.6f + 0.1f * (rand() % 20);
+
+ type = ENTITY_FAMILIAR_LOCAL;
+
+ frame = 0;
+ shadowFrame = 3;
+ imagesProLine = 4;
+
+ isJumping = false;
+ h = 0.0f;
+ attackDelay = -1.0f;
+
+ viscosity = 0.98f;
+ sprite.setOrigin(32, 44);
+
+ h = 1500;
+ hVelocity = 0.0f;
+ isJumping = true;
+ isFirstJumping = true;
+
+ x = GAME_WIDTH * 0.5f;
+ y = GAME_HEIGHT * 0.5f;
+
+ if (game().getPlayer()->getX() < 2 * TILE_WIDTH) x = 2.5f * TILE_WIDTH;
+ else if (game().getPlayer()->getX() > GAME_WIDTH - 2 * TILE_WIDTH) x = GAME_WIDTH - 2.5f * TILE_WIDTH;
+ else if (game().getPlayer()->getY() < 2 * TILE_HEIGHT) y = 2.5f * TILE_HEIGHT;
+ else if (game().getPlayer()->getY() > GAME_HEIGHT - 2 * TILE_HEIGHT) y = GAME_HEIGHT - 2.5f * TILE_HEIGHT;
+}
+
+void SlimePetEntity::animate(float delay)
+{
+ float slimeDelay = delay;
+ if (specialState[SpecialStateIce].active) slimeDelay = delay * specialState[SpecialStateIce].param1;
+
+ attackDelay -= delay;
+
+ if (isJumping)
+ {
+ hVelocity -= 700.0f * slimeDelay;
+
+ h += hVelocity * slimeDelay;
+
+ bool firstTimeGround = false;
+
+ if (h <= 0.0f)
+ {
+ if (hp <= 0)
+ dying();
+ else
+ {
+ h = 0.0f;
+ if (isFirstJumping)
+ {
+ isFirstJumping = false;
+ firstTimeGround = true;
+ hVelocity = 160.0f;
+ SoundManager::getInstance().playSound(SOUND_SLIME_IMAPCT);
+ }
+ else
+ {
+ jumpingDelay = 0.3f + 0.1f * (rand() % 15);
+ isJumping = false;
+ SoundManager::getInstance().playSound(SOUND_SLIME_IMAPCT_WEAK);
+ }
+ }
+ }
+ if (firstTimeGround) frame = 0;
+ else if (hVelocity > -190.0f) frame = 2;
+ else frame = 1;
+ }
+ else
+ {
+ jumpingDelay -= slimeDelay;
+ if (jumpingDelay < 0.0f)
+ {
+ SoundManager::getInstance().playSound(SOUND_SLIME_JUMP);
+ hVelocity = 350.0f + rand() % 300;
+ isJumping = true;
+ isFirstJumping = true;
+
+ float randVel = 250.0f + rand() % 250;
+
+ setVelocity(Vector2D(x, y).vectorTo(game().getPlayerPosition(), randVel ));
+ }
+ else if (jumpingDelay < 0.1f)
+ frame = 1;
+ else frame = 0;
+ }
+
+ BaseCreatureEntity::animate(delay);
+ if (canCollide()) testSpriteCollisions();
+ z = y + 14;
+}
+
+void SlimePetEntity::readCollidingEntity(CollidingSpriteEntity* entity)
+{
+ if (canCollide() && collideWithEntity(entity))
+ {
+ if (entity->getType() >= ENTITY_ENEMY && entity->getType() <= ENTITY_ENEMY_MAX_COUNT)
+ {
+ EnemyEntity* enemyEntity = static_cast<EnemyEntity*>(entity);
+ if (enemyEntity->canCollide())
+ {
+ if (attackDelay <= 0.0f)
+ {
+ enemyEntity->hurt(getHurtParams(8, ShotTypeStandard,0, false, SourceTypeMelee, EnemyTypeNone,false));
+ attackDelay = 0.65f;
+ }
+
+ if (enemyEntity->getMovingStyle() == movWalking)
+ {
+ Vector2D vel = Vector2D(enemyEntity->getX(), enemyEntity->getY()).vectorTo(Vector2D(x, y), 100.0f );
+ giveRecoil(false, vel, 0.3f);
+ }
+ }
+ }
+ }
+}
+
+void SlimePetEntity::render(sf::RenderTarget* app)
+{
+ // shadow
+ if (h < 1055)
+ {
+ int fade = 255;
+ if (h > 800)
+ fade = - (h - 1055);
+ sprite.setColor(sf::Color(255, 255, 255, fade));
+ sprite.setPosition(x, y);
+ sprite.setTextureRect(sf::IntRect(shadowFrame * width, 0, width, height));
+ app->draw(sprite);
+ sprite.setColor(sf::Color(255, 255, 255, 255));
+ }
+
+ // sprite
+ sprite.setPosition(x, y - h);
+ sprite.setTextureRect(sf::IntRect(frame * width, 4 * height, width, height));
+ app->draw(sprite);
+
+ if (game().getShowLogical())
+ {
+ displayBoundingBox(app);
+ displayCenterAndZ(app);
+ }
+}
+
+void SlimePetEntity::calculateBB()
+{
+ boundingBox.left = (int)x - width / 2 + SLIME_BB_LEFT;
+ boundingBox.width = width - SLIME_BB_WIDTH_DIFF;
+ boundingBox.top = (int)y - height / 2 + SLIME_BB_TOP - 15;
+ boundingBox.height = height - SLIME_BB_HEIGHT_DIFF;
+}
+
+void SlimePetEntity::collideMapRight()
+{
+ velocity.x = -velocity.x * 0.8f;
+}
+
+void SlimePetEntity::collideMapLeft()
+{
+ velocity.x = -velocity.x * 0.8f;
+}
+
+void SlimePetEntity::collideMapTop()
+{
+ velocity.y = -velocity.y * 0.8f;
+}
+
+void SlimePetEntity::collideMapBottom()
+{
+ velocity.y = -velocity.y * 0.8f;
+}
+
+void SlimePetEntity::changeRoom()
+{
+ h = 1500;
+ hVelocity = 0.0f;
+ isJumping = true;
+ isFirstJumping = true;
+ x = 300;
+ y = 250;
+}
+
+bool SlimePetEntity::collideWithMap(int direction)
+{
+ calculateBB();
+
+ int xTile0 = (boundingBox.left - offsetX) / tileWidth;
+ int xTilef = (boundingBox.left + boundingBox.width - offsetX) / tileWidth;
+ int yTile0 = (boundingBox.top - offsetY) / tileHeight;
+ int yTilef = (boundingBox.top + boundingBox.height - offsetY) / tileHeight;
+
+ if (boundingBox.top < 0) yTile0 = -1;
+
+ for (int xTile = xTile0; xTile <= xTilef; xTile++)
+ for (int yTile = yTile0; yTile <= yTilef; yTile++)
+ {
+ if (!game().getCurrentMap()->isFlyable(xTile, yTile))
+ {
+ switch (direction)
+ {
+ case DIRECTION_LEFT:
+ if (map->isLeftBlocking(xTile, yTile)) return true;
+ break;
+
+ case DIRECTION_RIGHT:
+ if (map->isRightBlocking(xTile, yTile)) return true;
+ break;
+
+ case DIRECTION_TOP:
+ if (map->isUpBlocking(xTile, yTile)) return true;
+ break;
+
+ case DIRECTION_BOTTOM:
+ if (map->isDownBlocking(xTile, yTile)) return true;
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool SlimePetEntity::canCollide()
+{
+ return h <= 70.0f;
+}
+
+BaseCreatureEntity::enumMovingStyle SlimePetEntity::getMovingStyle()
+{
+ if (h <= 70.0f)
+ return movWalking;
+ else
+ return movFlying;
+}
diff --git a/src/SlimePetEntity.h b/src/SlimePetEntity.h
new file mode 100644
index 0000000..76d1094
--- /dev/null
+++ b/src/SlimePetEntity.h
@@ -0,0 +1,39 @@
+#ifndef SLIMEPETSPRITE_H
+#define SLIMEPETSPRITE_H
+
+#include "EnemyEntity.h"
+
+
+class SlimePetEntity : public BaseCreatureEntity
+{
+ public:
+ SlimePetEntity();
+ virtual void animate(float delay);
+ virtual void render(sf::RenderTarget* app);
+ virtual void calculateBB();
+ virtual bool canCollide();
+
+ void changeRoom();
+
+ protected:
+ virtual bool collideWithMap(int direction);
+ virtual void collideMapRight();
+ virtual void collideMapLeft();
+ virtual void collideMapTop();
+ virtual void collideMapBottom();
+
+ virtual void readCollidingEntity(CollidingSpriteEntity* entity);
+
+ virtual enumMovingStyle getMovingStyle();
+
+ private:
+ float jumpingDelay;
+ float h, hVelocity;
+ float attackDelay;
+
+ bool isJumping;
+ bool isFirstJumping;
+ bool invocated;
+};
+
+#endif // SLIMESPRITE_H
diff --git a/src/WitchBlastGame.cpp b/src/WitchBlastGame.cpp
index 2da1272..7be3e4a 100644
--- a/src/WitchBlastGame.cpp
+++ b/src/WitchBlastGame.cpp
@@ -1,5301 +1,5305 @@
/** 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 "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 "LittleSpiderEntity.h"
#include "SpiderEggEntity.h"
#include "FranckyEntity.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 <iostream>
#include <sstream>
#include <fstream>
#include <ctime>
#include <algorithm>
//#define START_LEVEL 5
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 },
};
// 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;
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);
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);
}
// loading resources
const char *const images[] =
{
"media/player_0.png", "media/player_1.png",
"media/bolt.png", "media/tiles01.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/witch.png",
"media/cauldron.png", "media/snake.png",
"media/pumpkin.png", "media/ghost.png",
"media/zombie.png",
"media/butcher.png", "media/giant_slime.png",
"media/king_rat.png", "media/cyclops.png",
"media/giant_spider.png", "media/francky.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/fog.png", "media/title_animation.png",
"media/splatter.png", "media/witch_intro.png",
"media/item_description.png", "media/death_certificate.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_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",
};
// 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;
saveInFight.monsters.clear();
isPausing = false;
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);
loadGameData();
loadHiScores();
srand(time(NULL));
}
void WitchBlastGame::enableAA(bool enable)
{
for (int i = 0; i < NB_IMAGES; i++)
{
if (i != IMAGE_TILES && i != IMAGE_MINIMAP && 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);
}
DungeonMap* WitchBlastGame::getCurrentMap()
{
return currentMap;
}
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;
}
void WitchBlastGame::onUpdate()
{
if (!isPausing) // && (achievementsQueue.empty() || !currentMap->isCleared()) )
{
if (isPlayerAlive) player->setItemToBuy(NULL);
EntityManager::getInstance().animate(deltaTime);
if (sf::Keyboard::isKeyPressed(input[KeyTimeControl]))
{
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);
}
}
}
}
if (isPlayerAlive)
{
if (player->getHp() <= 0)
{
isPlayerAlive = false;
playMusic(MusicEnding);
}
}
}
}
void WitchBlastGame::startNewGame(bool fromSaveFile)
{
gameState = gameStateInit;
isPausing = false;
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
playLevel(saveInFight.isFight);
}
if (!fromSaveFile)
{
// the player
player = new PlayerEntity((TILE_WIDTH * MAP_WIDTH * 0.5f),
(TILE_HEIGHT * MAP_HEIGHT * 0.5f));
resetKilledEnemies();
#ifdef START_LEVEL
for (int i = 1; i < START_LEVEL; 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);
#endif // START_LEVEL
startNewLevel();
}
}
void WitchBlastGame::startNewLevel()
{
// reset floor items
player->resetFloorItem();
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 <= 6) testAndAddMessageToQueue((EnumMessages)(MsgInfoLevel1 + level - 1));
if (level == 1)
{
testAndAddMessageToQueue(MsgTutoBasics);
testAndAddMessageToQueue(MsgTutoTips);
}
playLevel(false);
}
void WitchBlastGame::playLevel(bool isFight)
{
if (level == 1)
ImageManager::getInstance().getImage(IMAGE_TILES)->loadFromFile("media/tiles01.png");
else if (level == 2)
ImageManager::getInstance().getImage(IMAGE_TILES)->loadFromFile("media/tiles02.png");
else if (level == 3)
ImageManager::getInstance().getImage(IMAGE_TILES)->loadFromFile("media/tiles03.png");
else if (level == 4)
ImageManager::getInstance().getImage(IMAGE_TILES)->loadFromFile("media/tiles04.png");
else if (level == 5)
ImageManager::getInstance().getImage(IMAGE_TILES)->loadFromFile("media/tiles05.png");
else
ImageManager::getInstance().getImage(IMAGE_TILES)->loadFromFile("media/tiles06.png");
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);
}
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;
while (app->pollEvent(event))
{
// Close window : exit
if (event.type == sf::Event::Closed) 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::Return
|| event.key.code == sf::Keyboard::Space
|| event.key.code == sf::Keyboard::Escape)
{
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;
// Process events
sf::Event event;
while (app->pollEvent(event))
{
// Close window : exit
if (event.type == sf::Event::Closed)
{
if (gameState == gameStatePlaying && !player->isDead()) saveGame();
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 && !isPausing) player->selectNextShotType();
}
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::Escape)
{
if (player->isDead()) backToMenu = true;
else if (gameState == gameStatePlaying && !isPausing) isPausing = true;
else if (gameState == gameStatePlaying && isPausing) isPausing = false;
}
if (event.key.code == input[KeyFireSelect])
{
if (gameState == gameStatePlaying && !isPausing) player->selectNextShotType();
}
if (event.key.code == input[KeySpell])
{
if (gameState == gameStatePlaying && !isPausing) player->castSpell();
}
if (event.key.code == input[KeyDown] || event.key.code == sf::Keyboard::Down)
{
// in game menu ?
if (gameState == gameStatePlaying && isPausing)
{
menuInGame.index++;
if (menuInGame.index == menuInGame.items.size()) menuInGame.index = 0;
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
}
else if (event.key.code == input[KeyUp] || event.key.code == sf::Keyboard::Up)
{
// in game menu ?
if (gameState == gameStatePlaying && isPausing)
{
if (menuInGame.index == 0) menuInGame.index = menuInGame.items.size() - 1;
else menuInGame.index--;
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
}
else if (event.key.code == sf::Keyboard::Return)
{
switch (menuInGame.items[menuInGame.index].id)
{
case MenuStartNew:
case MenuStartOld:
case MenuKeys:
case MenuConfig:
case MenuTutoReset:
case MenuConfigBack:
case MenuLanguage:
case MenuCredits:
case MenuHiScores:
case MenuPlayerName:
case MenuVolumeMusic:
case MenuVolumeSound:
std::cout << "[ERROR] Bad Menu ID\n";
break;
case MenuExit:
backToMenu = true;
remove(SAVE_FILE.c_str());
break;
case MenuContinue:
isPausing = false;
break;
case MenuSaveAndQuit:
saveGame();
backToMenu = true;
break;
}
}
if (event.key.code == input[KeyFire])
{
if (gameState == gameStatePlaying && !isPausing) firingDirection = player->getFacingDirection();
}
if (event.key.code == sf::Keyboard::Return)
{
if (player->isDead() && !xGame[xGameTypeFade].active && sf::Keyboard::isKeyPressed(sf::Keyboard::Return))
{
if (player->getDeathAge() < DEATH_CERTIFICATE_DELAY)
player->setDeathAge(DEATH_CERTIFICATE_DELAY);
else
backToMenu = true;
}
else if (!messagesQueue.empty())
{
if (messagesQueue.front().timer > 0.5f)
messagesQueue.front().timer = 0.5f;
}
else if (!achievementsQueue.empty())
{
if (achievementsQueue.front().timer > 0.5f)
achievementsQueue.front().timer = 0.5f;
}
}
if (event.key.code == input[KeyInteract])
{
if (!player->isDead() && interaction.active)
player->interact(interaction.type, interaction.id);
}
if (event.key.code == sf::Keyboard::X)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LShift)) startNewGame(false);
}
if (event.key.code == sf::Keyboard::F1)
{
if (!isPlayerAlive && player->getDeathAge() > 3.5f)
{
if (scoreSaveFile.compare("") == 0) saveDeathScreen();
}
}
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, 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);
}
}
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_invocated, 2);
}
}
if (event.key.code == sf::Keyboard::F12)
{
initMonsterArray();
findPlaceMonsters(EnemyTypeZombie, 2);
findPlaceMonsters(EnemyTypeZombieDark, 2);
findPlaceMonsters(EnemyTypeGhost, 2);
}
if (event.key.code == sf::Keyboard::F4)
{
for (int i = 0; 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())
isPausing = true;
}
if (gameState == gameStatePlaying && !isPausing)
{
if (player->canMove()) player->setVelocity(Vector2D(0.0f, 0.0f));
if (sf::Keyboard::isKeyPressed(input[KeyLeft]))
{
if (sf::Keyboard::isKeyPressed(input[KeyUp]))
player->move(7);
else if (sf::Keyboard::isKeyPressed(input[KeyDown]))
player->move(1);
else
player->move(4);
}
else if (sf::Keyboard::isKeyPressed(input[KeyRight]))
{
if (sf::Keyboard::isKeyPressed(input[KeyUp]))
player->move(9);
else if (sf::Keyboard::isKeyPressed(input[KeyDown]))
player->move(3);
else
player->move(6);
}
else if (sf::Keyboard::isKeyPressed(input[KeyUp]))
{
player->move(8);
}
else if (sf::Keyboard::isKeyPressed(input[KeyDown]))
{
player->move(2);
}
player->resestFireDirection();
if (sf::Keyboard::isKeyPressed(input[KeyFireLeft]))
player->fire(4);
else if (sf::Keyboard::isKeyPressed(input[KeyFireRight]))
player->fire(6);
else if (sf::Keyboard::isKeyPressed(input[KeyFireUp]))
player->fire(8);
else if (sf::Keyboard::isKeyPressed(input[KeyFireDown]))
player->fire(2);
// alternative "one button" gameplay
else if (sf::Keyboard::isKeyPressed(input[KeyFire]))
{
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 && !isPausing))
{
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();
if (achievementsQueue.empty()) music.play();
}
}
}
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++;
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;
}
else
{
prepareIntro();
}
}
}
void WitchBlastGame::addLifeBarToDisplay(std::string label, int hp, int hpMax)
{
lifeBar.toDisplay = true;
lifeBar.label = label;
lifeBar.hp = hp;
lifeBar.hpMax = hpMax;
}
void WitchBlastGame::renderGame()
{
lifeBar.toDisplay = false;
EntityManager::getInstance().renderUnder(app, 5000);
}
void WitchBlastGame::renderHud()
{
// boss life bar ?
if (lifeBar.toDisplay) renderLifeBar();
// 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);
}
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 (sf::Keyboard::isKeyPressed(input[KeyTimeControl]))
{
// 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 (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);
}
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);
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 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 (isPausing)
{
// 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();
}
else if (!achievementsQueue.empty() && (currentMap->isCleared() || achievementsQueue.front().hasStarted) )
{
int fade = 200;
if (achievementsQueue.front().timer < 0.5f) fade = achievementsQueue.front().timer * 400;
if (achievementsQueue.front().timer > ACHIEVEMENT_DELAY_MAX - 0.5f) fade = (ACHIEVEMENT_DELAY_MAX - achievementsQueue.front().timer) * 400;
if (!achievementsQueue.front().hasStarted)
{
music.pause();
SoundManager::getInstance().playSound(SOUND_ACHIEVEMENT);
achievementsQueue.front().hasStarted = true;
achievementState[achievementsQueue.front().type] = AchievementDone;
}
sf::Sprite bg;
bg.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEM_DESCRIPTION));
bg.setPosition(800 - 4 * fade + 20 + MAP_WIDTH * TILE_WIDTH * 0.5f - bg.getTextureRect().width * 0.5, 80);
app->draw(bg);
game().write("ACHIEVEMENT UNLOCKED", 19, 800 - 4 * fade + 470.0f, 92.0f, ALIGN_CENTER, sf::Color::White, app, 0, 0);
game().write(achievementsQueue.front().message, 18, 800 - 4 * fade + 470.0f, 120.0f, ALIGN_CENTER, sf::Color::White, app, 0, 0);
game().write("Press [enter] to close", 12, 800 - 4 * fade + 675.0f, 152.0f, ALIGN_RIGHT, sf::Color::White, app, 0, 0);
}
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 >= 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);
}
}
// 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);
}
}
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";
scoreSaveFile = ss.str();
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(scoreSaveFile);
}
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();
scores.push_back(lastScore);
std::sort (scores.begin(), scores.end(), compareScores);
saveHiScores();
}
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;
if (menuState == MenuStateMain)
menu = &menuMain;
else if (menuState == MenuStateConfig)
menu = &menuConfig;
else if (menuState == MenuStateFirst)
menu = &menuFirst;
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)
{
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 (event.type == sf::Event::KeyPressed)
{
if (menuState == MenuStateCredits)
{
if (event.key.code == sf::Keyboard::Escape || event.key.code == sf::Keyboard::Return)
menuState = MenuStateMain;
}
else if (menuState == MenuStateHiScores)
{
if (parameters.playerName.size() > 0
&& (event.key.code == sf::Keyboard::Escape || event.key.code == sf::Keyboard::Return))
{
menuState = MenuStateMain;
if (lastScore.level > 0)
{
lastScore.level = 0;
lastScore.score = 0;
playMusic(MusicIntro);
}
}
}
else 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)
{
if (menuState == MenuStateConfig) menuState = MenuStateMain;
else app->close();
}
else if (event.key.code == input[KeyDown] || event.key.code == sf::Keyboard::Down)
{
menu->index++;
if (menu->index == menu->items.size()) menu->index = 0;
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
else if (event.key.code == input[KeyUp] || event.key.code == sf::Keyboard::Up)
{
if (menu->index == 0) menu->index = menu->items.size() - 1;
else menu->index--;
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
else if (event.key.code == input[KeyRight] || event.key.code == sf::Keyboard::Right)
{
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 (event.key.code == input[KeyLeft] || event.key.code == sf::Keyboard::Left)
{
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 (event.key.code == sf::Keyboard::Return)
{
switch (menu->items[menu->index].id)
{
case MenuStartNew:
startNewGame(false);
remove(SAVE_FILE.c_str());
break;
case MenuStartOld:
startNewGame(true);
break;
case MenuKeys:
menuState = MenuStateKeys;
menuKeyIndex = 0;
break;
case MenuCredits:
menuState = MenuStateCredits;
break;
case MenuHiScores:
menuState = MenuStateHiScores;
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:
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();
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
{
// 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), 0, 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 - " << " 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::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, 230, ALIGN_CENTER, sf::Color(255, 255, 255, 255), app, 1, 1);
int yCursorInit = 340;
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::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), 0, 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;
lastTime = getAbsolutTime();
if (deltaTime > 0.05f) deltaTime = 0.05f;
switch (gameState)
{
case gameStateInit:
case gameStateKeyConfig:
case gameStateMenu:
updateMenu();
break;
case gameStateIntro:
updateIntro();
break;
case gameStatePlaying:
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->getTile(i, 0) < 4) currentMap->setTile(i, 0, MAP_DOOR);
if (currentMap->getTile(i, MAP_HEIGHT - 1) < 4) currentMap->setTile(i, MAP_HEIGHT - 1, MAP_DOOR);
}
for(i = 0; i < MAP_HEIGHT; i++)
{
if (currentMap->getTile(0, i) < 4) currentMap->setTile(0, i, MAP_DOOR);
if (currentMap->getTile(MAP_WIDTH - 1, i) < 4) currentMap->setTile(MAP_WIDTH - 1, i, MAP_DOOR);
}
roomClosed = true;
}
}
void WitchBlastGame::openDoors()
{
int i, j;
for(i = 0; i < MAP_WIDTH; i++)
for(j = 0; j < MAP_WIDTH; j++)
if (currentMap->getTile(i, j) == MAP_DOOR) currentMap->setTile(i, j, MAP_DOOR_OPEN);
roomClosed = false;
SoundManager::getInstance().playSound(SOUND_DOOR_OPENING);
if (currentMap->hasNeighbourUp() == 2 && !bossRoomOpened)
currentMap->setTile(MAP_WIDTH/2, 0, MAP_DOOR);
else
doorEntity[0]->openDoor();
if (currentMap->hasNeighbourLeft() == 2 && !bossRoomOpened)
currentMap->setTile(0, MAP_HEIGHT / 2, MAP_DOOR);
else
doorEntity[1]->openDoor();
if (currentMap->hasNeighbourDown() == 2 && !bossRoomOpened)
currentMap->setTile(MAP_WIDTH / 2, MAP_HEIGHT - 1, MAP_DOOR);
else
doorEntity[2]->openDoor();
if (currentMap->hasNeighbourRight() == 2 && !bossRoomOpened)
currentMap->setTile(MAP_WIDTH - 1, MAP_HEIGHT / 2, MAP_DOOR);
else
doorEntity[3]->openDoor();
}
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::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::checkDoor(int doorId, roomTypeEnum roomCurrent, roomTypeEnum roomNeighbour)
{
if (roomNeighbour == roomTypeNULL)
{
doorEntity[doorId]->setVisible(false);
return;
}
doorEntity[doorId]->setVisible(true);
doorEntity[doorId]->setDoorType(DoorStandard);
if (roomNeighbour == roomTypeBoss || roomCurrent == roomTypeBoss)
doorEntity[doorId]->setDoorType(DoorBoss);
if (roomNeighbour == roomTypeChallenge || roomCurrent == roomTypeChallenge)
doorEntity[doorId]->setDoorType(DoorChallenge);
if (roomNeighbour == roomTypeBoss && !bossRoomOpened)
{
doorEntity[doorId]->setOpen(false);
switch (doorId)
{
case 0:
currentMap->setTile(MAP_WIDTH/2, 0, MAP_DOOR);
break;
case 1:
currentMap->setTile(0, MAP_HEIGHT / 2, MAP_DOOR);
break;
case 2:
currentMap->setTile(MAP_WIDTH/2, MAP_HEIGHT - 1, MAP_DOOR);
break;
case 3:
currentMap->setTile(MAP_WIDTH - 1, MAP_HEIGHT / 2, MAP_DOOR);
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());
checkDoor(1, currentMap->getRoomType(), currentMap->getNeighbourLeft());
checkDoor(2, currentMap->getRoomType(), currentMap->getNeighbourDown());
checkDoor(3, currentMap->getRoomType(), currentMap->getNeighbourRight());
// keystones
if (currentMap->getNeighbourUp() || currentMap->getRoomType() == roomTypeExit)
{
SpriteEntity* keystoneEntity = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_TILES),
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
TILE_HEIGHT / 2, 192, 64, 1);
keystoneEntity->setZ(1000);
keystoneEntity->setFrame(24);
keystoneEntity->setType(ENTITY_EFFECT);
}
if (currentMap->getNeighbourDown())
{
SpriteEntity* keystoneEntity = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_TILES),
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
MAP_HEIGHT * TILE_WIDTH - TILE_HEIGHT / 2, 192, 64, 1);
keystoneEntity->setZ(1000);
keystoneEntity->setAngle(180);
keystoneEntity->setFrame(24);
keystoneEntity->setType(ENTITY_EFFECT);
}
if (currentMap->getNeighbourLeft())
{
SpriteEntity* keystoneEntity = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_TILES),
TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2, 192, 64, 1);
keystoneEntity->setZ(1000);
keystoneEntity->setAngle(270);
keystoneEntity->setFrame(24);
keystoneEntity->setType(ENTITY_EFFECT);
}
if (currentMap->getNeighbourRight())
{
SpriteEntity* keystoneEntity = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_TILES),
MAP_WIDTH * TILE_WIDTH - TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2, 192, 64, 1);
keystoneEntity->setZ(1000);
keystoneEntity->setAngle(90);
keystoneEntity->setFrame(24);
keystoneEntity->setType(ENTITY_EFFECT);
}
+
+ // pet slime
+ if (player->isEquiped(EQUIP_PET_SLIME)) new SlimePetEntity();
}
void WitchBlastGame::refreshMinimap()
{
for (int j=0; j < FLOOR_HEIGHT; j++)
for (int i=0; i < FLOOR_WIDTH; i++)
{
int n = currentFloor->getRoom(i, j);
if (n > 0 && currentFloor->getMap(i, j)->isVisited())
{
if (currentFloor->getRoom(i, j) == roomTypeStarting
|| currentFloor->getRoom(i, j) == roomTypeChallenge
|| currentFloor->getRoom(i, j) == roomTypeBonus
|| currentFloor->getRoom(i, j) == roomTypeKey
|| currentFloor->getRoom(i, j) == roomTypeBoss
|| currentFloor->getRoom(i, j) == roomTypeStandard)
{
if ( currentFloor->getMap(i, j)->containsHealth())
miniMap->setTile(i, j, 5);
else
miniMap->setTile(i, j, roomTypeStandard);
}
else
{
if (currentFloor->getRoom(i, j) == roomTypeMerchant)
miniMap->setTile(i, j, 3);
else if (currentFloor->getRoom(i, j) == roomTypeTemple)
miniMap->setTile(i, j, 7);
else
miniMap->setTile(i, j, currentFloor->getRoom(i, j));
}
}
else if (n > 0 && currentFloor->getMap(i, j)->isKnown())
{
switch (currentFloor->getRoom(i, j))
{
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 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 gameStateMenu:
renderMenu();
break;
case gameStatePlaying:
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)
{
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);
}
}
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)
{
// 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);
}
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);
}
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 // "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, false);
proceedEvent(EventMeetRatsOrBats);
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);
break;
case EnemyTypeSpiderEgg:
new SpiderEggEntity(xm, ym, false);
break;
case EnemyTypeSpiderLittle:
new LittleSpiderEntity(xm, ym, 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 EnemyTypeSpiderEgg_invocated:
new SpiderEggEntity(xm, ym, true);
break;
case EnemyTypeSpiderLittle_invocated:
new LittleSpiderEntity(xm, ym, 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 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;
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 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--;
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;
}
}
}
}
}
void WitchBlastGame::generateStandardMap()
{
initMonsterArray();
saveInFight.monsters.clear();
generateStandardRoom(level);
}
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;
// 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 && items[eq].requirement >= FirstEquipItem
&& !player->isEquiped(items[eq].requirement - FirstEquipItem)) 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 = 4;
break;
case RarityUncommon:
n = 2;
break;
case RarityRare:
n = 1;
break;
}
for (int j = 0; j < n; j++)
{
bonusSet.push_back(i);
setSize++;
}
}
}
int bonusType = 0;
if (setSize > 0) bonusType = bonusSet[rand() % setSize];
return (item_equip_enum) bonusType;
}
enumItemType WitchBlastGame::getItemSpell()
{
enumCastSpell n = (enumCastSpell)(rand() % SPELL_MAX);
while (player->getActiveSpell().spell == n) n = (enumCastSpell)(rand() % SPELL_MAX);
enumItemType item = ItemMagicianHat;
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;
}
return item;
}
void WitchBlastGame::generateChallengeBonus(float x, float y)
{
// loot
if (player->getActiveSpell().spell == SpellNone || rand() % 2 == 0)
{
ItemEntity* newItem = new ItemEntity(getItemSpell(), x, y);
newItem->setVelocity(Vector2D(100.0f + rand()% 250));
if (newItem->getVelocity().y < 0.0f) newItem->setVelocity(Vector2D(newItem->getVelocity().x, -newItem->getVelocity().y));
newItem->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 = new ItemEntity(ItemBonusHealth, 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() % 9;
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 > 0 && 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->setTile(MAP_WIDTH / 2, 0, 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->setTile(MAP_WIDTH / 2, MAP_HEIGHT - 1, 0);
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->setTile(0, MAP_HEIGHT / 2, 0);
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->setTile(MAP_WIDTH - 1, MAP_HEIGHT / 2, 0);
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);
bool ok = false;
switch (musicChoice)
{
case MusicDungeon:
if (rand() % 2 == 0)
{
ok = music.openFromFile("media/sound/game_Fantasy_Theme_Of_Elvarim.ogg");
}
else
{
ok = music.openFromFile("media/sound/game_Marching_United.ogg");
}
break;
case MusicEnding:
ok = music.openFromFile("media/sound/ending_Music_Is_His_Only_Friend.ogg");
music.setVolume(parameters.musicVolume * 50 / 100);
break;
case MusicBoss:
if (rand() % 2 == 0)
{
ok = music.openFromFile("media/sound/boss_The_Spider_Machine.ogg");
}
else
{
ok = music.openFromFile("media/sound/boss_Pub_Stomp_Deluxe.ogg");
}
break;
case MusicChallenge:
ok = music.openFromFile("media/sound/challenge_Under_Siege.ogg");
break;
case MusicIntro:
ok = music.openFromFile("media/sound/menu_Our_Ship_To_Candletown.ogg");
music.setVolume(parameters.musicVolume * 60 / 100);
break;
}
if (ok)
music.play();
}
void WitchBlastGame::updateMusicVolume()
{
if (music.getStatus() == sf::Music::Playing)
{
if (parameters.musicVolume == 0)
music.stop();
else
music.setVolume(parameters.musicVolume * 60 / 100);
}
else
{
if (parameters.musicVolume > 0)
{
bool ok = music.openFromFile("media/sound/menu_Our_Ship_To_Candletown.ogg");
music.setVolume(parameters.musicVolume * 60 / 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;
// 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)->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);
if (tile == MAP_DOOR && !(k > 0 && k < MAP_WIDTH - 1 && l > 0 && l < MAP_HEIGHT - 1)) tile = 0;
file << tile << " ";
}
file << 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;
}
}
}
}
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;
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;
// 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()
{
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];
// 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;
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);
}
}
// 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);
}
}
}
// 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;
player = new PlayerEntity((TILE_WIDTH * MAP_WIDTH * 0.5f),
(TILE_HEIGHT * MAP_HEIGHT * 0.5f));
player->setHp(hp);
player->setHpMax(hpMax);
player->setGold(gold);
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);
// 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;
// tuto
for (int i = 0; i < NB_MESSAGES; i++)
{
messageStruct msg = getMessage((EnumMessages)i);
if (msg.messageType == MessageTypeTutorial)
{
file << gameMessagesToSkip[i] << " ";
}
else file << "0 ";
}
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);
if (file)
{
// version
std::string v;
file >> v;
if (v != SAVE_VERSION)
{
file.close();
remove(SAVE_DATA_FILE.c_str());
return;
}
// tuto
for (int i = 0; i < NB_MESSAGES; i++)
{
file >> gameMessagesToSkip[i];
}
}
// Achievements
// TODO load and save
for (int i = 0; i < NB_ACHIEVEMENTS; i++)
{
achievementState[i] = AchievementUndone;
}
}
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";
// 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]);
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 = 60;
parameters.soundVolume = 100;
parameters.playerName = "";
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;
// 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(KeyTimeControl, "keyboard_time_control");
addKey(KeyFireSelect, "keyboard_fire_select");
int i = config.findInt("language");
if (i >= 0) 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;
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 (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 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]++;
player->offerMonster(enemyType, hurtingType);
// achievements
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 == EnemyTypeRat || enemyType == EnemyTypeRatHelmet
|| enemyType == EnemyTypeRatBlack || enemyType == EnemyTypeRatBlackHelmet))
if (killedEnemies[EnemyTypeRat] + killedEnemies[EnemyTypeRatHelmet]
+ killedEnemies[EnemyTypeRatBlack] + killedEnemies[EnemyTypeRatBlackHelmet] >= 1)
registerAchievement(AchievementRats);
}
}
}
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();
}
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::initEvents()
{
for (int i = 0; i < NB_EVENTS; i++)
worldEvent[i] = false;
}
void WitchBlastGame::proceedEvent(EnumWorldEvents event)
{
// achievements
if (event == EventGetCoin)
{
if (!achievementState[Achievement100] && player->getGold() > 100)
registerAchievement(Achievement100);
}
else if (event == EventPietyMax)
{
if (!achievementState[AchievementPietyMax]) registerAchievement(AchievementPietyMax);
}
else if (event == EventTripleHit)
{
if (!achievementState[Achievement3Hits]) registerAchievement(Achievement3Hits);
}
else if (event == EventCompleteSet)
{
if (!achievementState[AchievementCompleteSet]) registerAchievement(AchievementCompleteSet);
}
// 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);
}
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);
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_BROOCH_FINESSE])
{
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);
}
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);
}
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);
}
// hat
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));
}
// boots
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);
}
// 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 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 EnemyTypeGhost:
value = "enemy_type_ghost";
break;
case EnemyTypeZombie_invocated:
case EnemyTypeZombie:
value = "enemy_type_zombie";
break;
case EnemyTypeZombieDark:
value = "enemy_type_zombie_dark";
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;
// 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;
// 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 EnemyTypeSpiderWeb:
value = "enemy_type_spider_web";
break;
case EnemyTypeNone:
value = "enemy_type_himself";
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;
}
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 << " ";
// 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;
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.hasStarted = false;
achievementsQueue.push(ach);
}
}
WitchBlastGame &game()
{
return *gameptr;
}
diff --git a/src/sfml_game/CollidingSpriteEntity.h b/src/sfml_game/CollidingSpriteEntity.h
index 98384fd..24d193d 100644
--- a/src/sfml_game/CollidingSpriteEntity.h
+++ b/src/sfml_game/CollidingSpriteEntity.h
@@ -1,81 +1,81 @@
/** 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/>.
*/
#ifndef COLLIDINGSPRITEENTITY_H_INCLUDED
#define COLLIDINGSPRITEENTITY_H_INCLUDED
#include "SpriteEntity.h"
#include "GameMap.h"
// Basis class for Jouster
class CollidingSpriteEntity : public SpriteEntity
{
public:
CollidingSpriteEntity(sf::Texture* image, float x = 0.0f, float y = 0.0f, int width = -1, int height = -1);
~CollidingSpriteEntity();
GameMap* getMap();
- void setMap(GameMap* map, int tileWidth, int tileHeight, int offsetX, int offsetY);
+ virtual void setMap(GameMap* map, int tileWidth, int tileHeight, int offsetX, int offsetY);
void setTileDimensions(int width, int height);
virtual void render(sf::RenderTarget* app);
virtual void animate(float delay);
virtual void calculateBB();
virtual void makeFall();
virtual bool collideWithMap(int direction);
virtual bool isCollidingWithMap();
virtual void stuck();
virtual bool collideWithEntity(CollidingSpriteEntity* entity);
void displayBoundingBox(sf::RenderTarget* app);
sf::IntRect getBoundingBox();
enum directionEnum
{
DIRECTION_RIGHT,
DIRECTION_LEFT,
DIRECTION_TOP,
DIRECTION_BOTTOM
};
bool isOnGround();
protected:
GameMap* map; // map to test collisions with
sf::IntRect boundingBox; // BoundingBox
int tileWidth;
int tileHeight;
int offsetX;
int offsetY;
float normalWeight;
float maxY;
virtual void exitMap(int direction);
virtual void collideMapRight();
virtual void collideMapLeft();
virtual void collideMapTop();
virtual void collideMapBottom();
virtual void collideEntity(CollidingSpriteEntity* entity);
virtual void testSpriteCollisions();
virtual void readCollidingEntity(CollidingSpriteEntity* entity);
};
#endif // COLLIDINGSPRITEENTITY_H_INCLUDED

File Metadata

Mime Type
text/x-diff
Expires
Fri, Jun 19, 7:55 PM (1 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
73025
Default Alt Text
(292 KB)

Event Timeline