Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
455 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/media/minimap.png b/media/minimap.png
index 5367ae4..9d609fe 100644
Binary files a/media/minimap.png and b/media/minimap.png differ
diff --git a/src/DungeonMap.cpp b/src/DungeonMap.cpp
index 822cd5b..0827370 100644
--- a/src/DungeonMap.cpp
+++ b/src/DungeonMap.cpp
@@ -1,1734 +1,1893 @@
#include "DungeonMap.h"
#include "GameFloor.h"
#include "ItemEntity.h"
#include "ChestEntity.h"
#include "sfml_game/ImageManager.h"
#include <cstdlib>
#include <stdio.h>
#include <iostream>
#include "WitchBlastGame.h"
DungeonMap::DungeonMap(int width, int height) : GameMap(width, height)
{
}
DungeonMap::DungeonMap(GameFloor* gameFloor, int x, int y) : GameMap(MAP_WIDTH, MAP_HEIGHT)
{
this->gameFloor = gameFloor;
this->x = x;
this->y = y;
cleared = false;
+ revealed = true;
visited = false;
known = false;
for (int i = 0; i < NB_RANDOM_TILES_IN_ROOM; i++)
{
randomTileElements[i].type = -1;
randomTileElements[i].x = 0;
randomTileElements[i].y = 0;
randomTileElements[i].rotation = 0;
}
}
DungeonMap::~DungeonMap()
{
}
bool DungeonMap::isVisited()
{
return visited;
}
void DungeonMap::setVisited(bool b)
{
visited = b;
}
bool DungeonMap::isKnown()
{
return known;
}
void DungeonMap::setKnown(bool b)
{
known = b;
}
+bool DungeonMap::isRevealed()
+{
+ return revealed;
+}
+
+void DungeonMap::setRevealed(bool b)
+{
+ revealed = b;
+}
+
bool DungeonMap::isCleared()
{
return cleared;
}
void DungeonMap::setCleared(bool b)
{
cleared = b;
}
roomTypeEnum DungeonMap::getRoomType()
{
return roomType;
}
void DungeonMap::setRoomType(roomTypeEnum roomType)
{
this->roomType = roomType;
+ if (roomType == roomTypeSecret)
+ revealed = false;
}
int DungeonMap::getObjectTile(int x, int y)
{
return objectsMap[x][y];
}
logicalMapStateEnum DungeonMap::getLogicalTile(int x, int y)
{
return logicalMap[x][y];
}
void DungeonMap::setObjectTile(int x, int y, int n)
{
objectsMap[x][y] = n;
hasChanged = true;
}
void DungeonMap::setLogicalTile(int x, int y, logicalMapStateEnum state)
{
logicalMap[x][y] = state;
hasChanged = true;
}
int DungeonMap::getFloorOffset()
{
return floorOffset;
}
int DungeonMap::getWallType()
{
return wallType;
}
void DungeonMap::setFloorOffset(int n)
{
floorOffset = n;
}
void DungeonMap::setWallType(int n)
{
wallType = n;
}
doorEnum DungeonMap::getDoorType(int direction)
{
return doorType[direction];
}
void DungeonMap::setDoorType(int direction, doorEnum type)
{
doorType[direction] = type;
}
std::list<DungeonMap::itemListElement> DungeonMap::getItemList()
{
return (itemList);
}
std::list<DungeonMap::chestListElement> DungeonMap::getChestList()
{
return (chestList);
}
std::list<DungeonMap::spriteListElement> DungeonMap::getSpriteList()
{
return (spriteList);
}
DungeonMap::RandomTileElement DungeonMap::getRandomTileElement(int n)
{
if (n < 0 || n >= NB_RANDOM_TILES_IN_ROOM) return RandomTileElement { -1, 0, 0, 0};
return randomTileElements[n];
}
void DungeonMap::setRandomTileElement (int n, RandomTileElement rt)
{
if (n < 0 || n >= NB_RANDOM_TILES_IN_ROOM) return;
randomTileElements[n] = rt;
hasChanged = true;
}
void DungeonMap::displayToConsole()
{
for (int j=0; j < MAP_HEIGHT; j++)
{
for (int i=0; i < MAP_WIDTH; i++)
{
printf("%d", map[i][j]);
}
printf("\n");
}
printf("\n");
}
bool DungeonMap::isDownBlocking(int x, int y)
{
if (!inMap(x, y)) return false;
return (logicalMap[x][y] != LogicalFloor);
}
bool DungeonMap::isUpBlocking(int x, int y)
{
if (!inMap(x, y)) return false;
return (logicalMap[x][y] != LogicalFloor);
}
bool DungeonMap::isLeftBlocking(int x, int y)
{
if (!inMap(x, y)) return false;
return (logicalMap[x][y] != LogicalFloor);
}
bool DungeonMap::isRightBlocking(int x, int y)
{
if (!inMap(x, y)) return false;
return (logicalMap[x][y] != LogicalFloor);
}
bool DungeonMap::isWalkable(int x, int y)
{
if (!inMap(x, y)) return true;
if (roomType == roomTypeKey && !cleared)
{
int x0 = MAP_WIDTH / 2;
int y0 = MAP_HEIGHT / 2;
if (x >= x0 - 1 && x <= x0 +1 && y >= y0 - 1 && y <= y0 + 1)
return false;
}
return (logicalMap[x][y] == LogicalFloor);
}
bool DungeonMap::isFlyable(int x, int y)
{
if (x < 0) return true;
if (x > MAP_WIDTH - 1) return true;
if (y < 0) return true;
if (y > MAP_HEIGHT - 1) return true;
return (logicalMap[x][y] != LogicalWall);
}
bool DungeonMap::isShootable(int x, int y)
{
if (!inMap(x, y)) return true;
return (logicalMap[x][y] != LogicalWall && logicalMap[x][y] != LogicalObstacle);
}
bool DungeonMap::containsHealth()
{
ItemList::iterator it;
for (it = itemList.begin (); it != itemList.end ();)
{
itemListElement ilm = *it;
it++;
if (ilm.type >= ItemHealthVerySmall && ilm.type <= ItemHealthVerySmallPoison)
return true;
}
return false;
}
void DungeonMap::randomize(int n)
{
int i, j;
int x0 = MAP_WIDTH / 2;
int y0 = MAP_HEIGHT / 2;
initRoom();
// bonus
if (n == 5)
{
roomType = roomTypeBonus;
}
// others
else if (n > 0)
{
int r = rand() % 4;
if (r == 0) // corner blocks
{
map[1][1] = 4;
map[1][MAP_HEIGHT -2] = 4;
map[MAP_WIDTH - 2][1] = 4;
map[MAP_WIDTH - 2][MAP_HEIGHT -2] = 4;
}
else if (r == 1) // bloc in the middle
{
for (i = x0-1; i <= x0+1; i++)
for (j = y0-1; j <= y0+1; j++)
map[i][j] = 4;
}
else if (r == 2) // checker
{
for (i = 2; i < MAP_WIDTH - 2; i = i + 2)
for (j = 2; j < MAP_HEIGHT - 2; j = j + 2)
map[i][j] = 4;
}
cleared = false;
roomType = (roomTypeEnum)(rand() % 3);
}
else
{
cleared = true;
}
}
int DungeonMap::hasNeighbourLeft()
{
if (x > 0 && gameFloor->getRoom(x-1, y) > 0)
{
if (gameFloor->getRoom(x-1, y) == roomTypeBoss) return 2;
else return 1;
}
return 0;
}
int DungeonMap::hasNeighbourRight()
{
if (x < MAP_WIDTH -1 && gameFloor->getRoom(x+1, y) > 0)
{
if (gameFloor->getRoom(x+1, y) == roomTypeBoss) return 2;
else return 1;
}
return 0;
}
int DungeonMap::hasNeighbourUp()
{
if (y > 0 && gameFloor->getRoom(x, y-1) > 0)
{
if (gameFloor->getRoom(x, y-1) == roomTypeBoss) return 2;
else return 1;
}
return 0;
}
int DungeonMap::hasNeighbourDown()
{
if (y < MAP_HEIGHT -1 && gameFloor->getRoom(x, y+1) > 0)
{
if (gameFloor->getRoom(x, y+1) == roomTypeBoss) return 2;
else return 1;
}
return 0;
}
roomTypeEnum DungeonMap::getNeighbourLeft()
{
if (x > 0) return gameFloor->getRoom(x - 1, y);
else return roomTypeNULL;
}
+
+bool DungeonMap::hasKnownNeighbour(int direction, bool mustBeRevealed)
+{
+ switch (direction)
+ {
+ case North:
+ if (y > 0 && gameFloor->getRoom(x, y - 1) > 0)
+ {
+ if (mustBeRevealed)
+ return (gameFloor->getRoom(x, y - 1) != roomTypeSecret || gameFloor->getMap(x, y - 1)->isRevealed());
+ else
+ return (gameFloor->getRoom(x, y - 1) != roomTypeSecret || gameFloor->getMap(x, y - 1)->isKnown());
+ }
+ break;
+
+ case South:
+ if (y < MAP_HEIGHT -1 && gameFloor->getRoom(x, y + 1) > 0)
+ {
+ if (mustBeRevealed)
+ return (gameFloor->getRoom(x, y + 1) != roomTypeSecret || gameFloor->getMap(x, y + 1)->isRevealed());
+ else
+ return (gameFloor->getRoom(x, y + 1) != roomTypeSecret || gameFloor->getMap(x, y + 1)->isKnown());
+ }
+ break;
+
+ case West:
+ if (x > 0 && gameFloor->getRoom(x - 1, y) > 0)
+ {
+ if (mustBeRevealed)
+ return (gameFloor->getRoom(x - 1, y) != roomTypeSecret || gameFloor->getMap(x - 1, y)->isRevealed());
+ else
+ return (gameFloor->getRoom(x - 1, y) != roomTypeSecret || gameFloor->getMap(x - 1, y)->isKnown());
+ }
+ break;
+
+ case East:
+ if (x < MAP_WIDTH -1 && gameFloor->getRoom(x+1, y) > 0)
+ {
+ if (mustBeRevealed)
+ return (gameFloor->getRoom(x + 1, y) != roomTypeSecret || gameFloor->getMap(x + 1, y)->isRevealed());
+ else
+ return (gameFloor->getRoom(x + 1, y) != roomTypeSecret || gameFloor->getMap(x + 1, y)->isKnown());
+ }
+ break;
+ }
+ return false;
+}
+
roomTypeEnum DungeonMap::getNeighbourRight()
{
if (x < MAP_WIDTH - 1) return gameFloor->getRoom(x + 1, y);
else return roomTypeNULL;
}
roomTypeEnum DungeonMap::getNeighbourUp()
{
if (y > 0) return gameFloor->getRoom(x, y - 1);
else return roomTypeNULL;
}
roomTypeEnum DungeonMap::getNeighbourDown()
{
if (y < MAP_HEIGHT - 1) return gameFloor->getRoom(x, y + 1);
else return roomTypeNULL;
}
int DungeonMap::getDivinity(int x, int y)
{
if (x <= 0 || (x >= MAP_WIDTH - 1) || y <= 0 || (y >= MAP_HEIGHT - 1)) return -1;
if (map[x][y] >= MAP_TEMPLE && map[x][y] < MAP_TEMPLE + NB_DIVINITY)
return (map[x][y] - MAP_TEMPLE);
else
return -1;
}
doorEnum getRandomDoor()
{
return (doorEnum)(DoorStandard_0 + ((game().getLevel() - 1) % 8));
/////
int n = rand() % 12;
switch (game().getLevel())
{
case 1:
if (n < 6) return DoorStandard_0;
else return DoorStandard_1;
case 2:
if (n < 5) return DoorStandard_0;
else if (n < 10) return DoorStandard_1;
else return DoorStandard_2;
case 3:
if (n < 6) return DoorStandard_1;
else return DoorStandard_2;
case 4:
if (n < 5) return DoorStandard_1;
else if (n < 10) return DoorStandard_2;
else return DoorStandard_3;
case 5:
if (n < 6) return DoorStandard_2;
else return DoorStandard_3;
case 6:
if (n < 5) return DoorStandard_2;
else if (n < 10) return DoorStandard_3;
else return DoorStandard_4;
default:
if (n < 6) return DoorStandard_3;
else return DoorStandard_4;
}
return (doorEnum)(rand() % 5);
}
void DungeonMap::initRoom(int floorN, int wallN)
{
int x0 = MAP_WIDTH / 2;
int y0 = MAP_HEIGHT / 2;
int i, j;
// style
if (floorN < 0) floorOffset = ((game().getLevel() - 1) % 8) * 24 ;
else floorOffset = floorN;
if (wallN < 0) wallType = ((game().getLevel() - 1) % 8) ;
else wallType = wallN;
int wallOffset = wallType * 24;
// doors
for (i = 0; i < 4; i++) doorType[i] = DoorNone;
// outer walls
map[0][0] = wallOffset + MAP_WALL_7 + rand() % 2;
for ( i = 1 ; i < width -1 ; i++)
{
if (i == width / 2)
{
map[i][0] = wallOffset + MAP_WALL_8 + rand() % 2;
map[i][height - 1] = wallOffset + MAP_WALL_8 + rand() % 2;
}
else if (i < width / 2)
{
map[i][0] = wallOffset + MAP_WALL_87 + rand() % 8;
map[i][height - 1] = wallOffset + MAP_WALL_87 + rand() % 8;
}
else
{
map[i][0] = wallOffset + MAP_WALL_87 + rand() % 8;
map[i][height - 1] = wallOffset + MAP_WALL_87 + rand() % 8;
}
}
map[width - 1][0] = wallOffset + MAP_WALL_7 + rand() % 2;
for ( int i = 1 ; i < height -1 ; i++)
{
if (i == height / 2)
{
map[0][i] = wallOffset + MAP_WALL_8 + rand() % 2;
map[width - 1][i] = wallOffset + MAP_WALL_8 + rand() % 2;
}
else if (i < height / 2)
{
map[0][i] = wallOffset + MAP_WALL_87 + rand() % 8;
map[width - 1][i] = wallOffset + MAP_WALL_87 + rand() % 8;
}
else
{
map[0][i] = wallOffset + MAP_WALL_87 + rand() % 8;
map[width - 1][i] = wallOffset + MAP_WALL_87 + rand() % 8;
}
}
map[0][height - 1] = wallOffset + MAP_WALL_7 + rand() % 2;
map[width - 1][height - 1] = wallOffset + MAP_WALL_7 + rand() % 2;
// floor
for ( j = 1 ; j < height - 1 ; j++)
{
for ( i = 1 ; i < width - 1 ; i++)
{
map[i][j] = floorOffset + rand()%(MAP_NORMAL_FLOOR);
while (map[i][j] == map[i - 1][j] || map[i][j] == map[i][j - 1] || map[i][j] == map[i - 1][j - 1] || map[i][j] == map[i + 1][j - 1])
map[i][j] = floorOffset + rand()%(MAP_NORMAL_FLOOR);
}
}
// objects
for ( j = 0 ; j < height; j++)
{
for ( i = 0 ; i < width; i++)
{
objectsMap[i][j] = 0;
if (i == 0 || j == 0 || i == width - 1 || j == height - 1)
logicalMap[i][j] = LogicalWall;
else
logicalMap[i][j] = LogicalFloor;
}
}
// alternative floor
for (i = 0; i < 8; i++)
{
if (rand() % 2 > 0)
{
map[1 + rand() % (MAP_WIDTH - 2)][1 + rand() % (MAP_HEIGHT - 2)] = floorOffset + 16 + i;
}
}
// alternative walls
for (i = 0; i < 8; i++)
{
if (rand() % 2 > 0)
{
int xTile = 0;
int yTile = 0;
int horizontal = rand() % 2;
if (horizontal == 0)
{
yTile = rand() % 2 == 0 ? 0 : MAP_HEIGHT - 1;
xTile = 1 + rand() % 12;
if (xTile > 6) xTile++;
}
else
{
xTile = rand() % 2 == 0 ? 0 : MAP_WIDTH - 1;
yTile = 1 + rand() % 6;
if (yTile > 3) yTile++;
}
map[xTile][yTile] = i + wallOffset + MAP_WALL_87 + 8;
}
}
// doors ?
if (gameFloor != NULL)
{
if (x > 0 && gameFloor->getRoom(x - 1, y) > 0)
{
- map[0][MAP_HEIGHT / 2] = floorOffset;
- map[0][MAP_HEIGHT / 2 - 1] = floorOffset;
- map[0][MAP_HEIGHT / 2 + 1] = floorOffset;
- openDoor(0, y0);
-
- if (roomType == roomTypeBoss || gameFloor->getRoom(x - 1, y) == roomTypeBoss)
- {
- doorType[West] = DoorBoss;
- }
- else if (roomType == roomTypeChallenge || gameFloor->getRoom(x - 1, y) == roomTypeChallenge)
- {
- doorType[West] = DoorChallenge;
- }
- else if (gameFloor->getMap(x - 1, y)->isVisited())
+ if (gameFloor->getRoom(x - 1, y) != roomTypeSecret)
{
- doorType[West] = gameFloor->getMap(x - 1, y)->getDoorType(East);
+ map[0][MAP_HEIGHT / 2] = floorOffset;
+ map[0][MAP_HEIGHT / 2 - 1] = floorOffset;
+ map[0][MAP_HEIGHT / 2 + 1] = floorOffset;
+ openDoor(0, y0);
+
+ if (roomType == roomTypeBoss || gameFloor->getRoom(x - 1, y) == roomTypeBoss)
+ {
+ doorType[West] = DoorBoss;
+ }
+ else if (roomType == roomTypeChallenge || gameFloor->getRoom(x - 1, y) == roomTypeChallenge)
+ {
+ doorType[West] = DoorChallenge;
+ }
+ else if (gameFloor->getMap(x - 1, y)->isVisited())
+ {
+ doorType[West] = gameFloor->getMap(x - 1, y)->getDoorType(East);
+ }
+ else
+ {
+ // secret door
+ doorType[West] = getRandomDoor();
+ }
}
else
{
doorType[West] = getRandomDoor();
}
}
if (x < MAP_WIDTH - 1 && gameFloor->getRoom(x + 1, y) > 0)
{
- map[MAP_WIDTH - 1][MAP_HEIGHT / 2] = floorOffset;
- map[MAP_WIDTH - 1][MAP_HEIGHT / 2 - 1] = floorOffset;
- map[MAP_WIDTH - 1][MAP_HEIGHT / 2 + 1] = floorOffset;
- openDoor(MAP_WIDTH - 1, y0);
-
- if (roomType == roomTypeBoss || gameFloor->getRoom(x + 1, y) == roomTypeBoss)
- {
- doorType[East] = DoorBoss;
- }
- else if (roomType == roomTypeChallenge || gameFloor->getRoom(x + 1, y) == roomTypeChallenge)
- {
- doorType[East] = DoorChallenge;
- }
- else if (gameFloor->getMap(x + 1, y)->isVisited())
+ if (gameFloor->getRoom(x + 1, y) != roomTypeSecret)
{
- doorType[East] = gameFloor->getMap(x + 1, y)->getDoorType(West);
+ map[MAP_WIDTH - 1][MAP_HEIGHT / 2] = floorOffset;
+ map[MAP_WIDTH - 1][MAP_HEIGHT / 2 - 1] = floorOffset;
+ map[MAP_WIDTH - 1][MAP_HEIGHT / 2 + 1] = floorOffset;
+ openDoor(MAP_WIDTH - 1, y0);
+
+ if (roomType == roomTypeBoss || gameFloor->getRoom(x + 1, y) == roomTypeBoss)
+ {
+ doorType[East] = DoorBoss;
+ }
+ else if (roomType == roomTypeChallenge || gameFloor->getRoom(x + 1, y) == roomTypeChallenge)
+ {
+ doorType[East] = DoorChallenge;
+ }
+ else if (gameFloor->getMap(x + 1, y)->isVisited())
+ {
+ doorType[East] = gameFloor->getMap(x + 1, y)->getDoorType(West);
+ }
+ else
+ {
+ doorType[East] = getRandomDoor();
+ }
}
else
{
+ // secret door
doorType[East] = getRandomDoor();
}
}
if (y > 0 && gameFloor->getRoom(x, y - 1) > 0)
{
- map[MAP_WIDTH / 2][0] = floorOffset;
- map[MAP_WIDTH / 2 - 1][0] = floorOffset;
- map[MAP_WIDTH / 2 + 1][0] = floorOffset;
- openDoor(x0, 0);
-
- if (roomType == roomTypeBoss || gameFloor->getRoom(x, y - 1) == roomTypeBoss)
- {
- doorType[North] = DoorBoss;
- }
- else if (roomType == roomTypeChallenge || gameFloor->getRoom(x, y - 1) == roomTypeChallenge)
- {
- doorType[North] = DoorChallenge;
- }
- else if (gameFloor->getMap(x, y - 1)->isVisited())
+ if (gameFloor->getRoom(x, y - 1) != roomTypeSecret)
{
- doorType[North] = gameFloor->getMap(x, y - 1)->getDoorType(South);
+ map[MAP_WIDTH / 2][0] = floorOffset;
+ map[MAP_WIDTH / 2 - 1][0] = floorOffset;
+ map[MAP_WIDTH / 2 + 1][0] = floorOffset;
+ openDoor(x0, 0);
+
+ if (roomType == roomTypeBoss || gameFloor->getRoom(x, y - 1) == roomTypeBoss)
+ {
+ doorType[North] = DoorBoss;
+ }
+ else if (roomType == roomTypeChallenge || gameFloor->getRoom(x, y - 1) == roomTypeChallenge)
+ {
+ doorType[North] = DoorChallenge;
+ }
+ else if (gameFloor->getMap(x, y - 1)->isVisited())
+ {
+ doorType[North] = gameFloor->getMap(x, y - 1)->getDoorType(South);
+ }
+ else
+ {
+ doorType[North] = getRandomDoor();
+ }
}
else
{
+ // secret door
doorType[North] = getRandomDoor();
}
}
if (y < MAP_HEIGHT -1 && gameFloor->getRoom(x, y + 1) > 0)
{
- map[MAP_WIDTH / 2][MAP_HEIGHT - 1] = floorOffset;
- map[MAP_WIDTH / 2 - 1][MAP_HEIGHT - 1] = floorOffset;
- map[MAP_WIDTH / 2 + 1][MAP_HEIGHT - 1] = floorOffset;
- openDoor(x0, MAP_HEIGHT -1);
-
- if (roomType == roomTypeBoss || gameFloor->getRoom(x, y + 1) == roomTypeBoss)
- {
- doorType[South] = DoorBoss;
- }
- else if (roomType == roomTypeChallenge || gameFloor->getRoom(x, y + 1) == roomTypeChallenge)
- {
- doorType[South] = DoorChallenge;
- }
- else if (gameFloor->getMap(x, y + 1)->isVisited())
+ if (gameFloor->getRoom(x, y + 1) != roomTypeSecret)
{
- doorType[South] = gameFloor->getMap(x, y + 1)->getDoorType(North);
+ map[MAP_WIDTH / 2][MAP_HEIGHT - 1] = floorOffset;
+ map[MAP_WIDTH / 2 - 1][MAP_HEIGHT - 1] = floorOffset;
+ map[MAP_WIDTH / 2 + 1][MAP_HEIGHT - 1] = floorOffset;
+ openDoor(x0, MAP_HEIGHT -1);
+
+ if (roomType == roomTypeBoss || gameFloor->getRoom(x, y + 1) == roomTypeBoss)
+ {
+ doorType[South] = DoorBoss;
+ }
+ else if (roomType == roomTypeChallenge || gameFloor->getRoom(x, y + 1) == roomTypeChallenge)
+ {
+ doorType[South] = DoorChallenge;
+ }
+ else if (gameFloor->getMap(x, y + 1)->isVisited())
+ {
+ doorType[South] = gameFloor->getMap(x, y + 1)->getDoorType(North);
+ }
+ else
+ {
+ doorType[South] = getRandomDoor();
+ }
}
else
{
+ // secret door
doorType[South] = getRandomDoor();
}
}
if (game().getLevel() > 1 && roomType == roomTypeStarting)
{
doorType[South] = getRandomDoor();
}
else if (roomType == roomTypeExit)
{
doorType[North] = DoorExit;
}
}
// test
for (int i = 0; i < 8; i++)
{
int objX = 1 + rand() % (MAP_WIDTH - 2);
int objY = 1 + rand() % (MAP_HEIGHT - 2);
if (i == 7) objectsMap[objX][objY] = MAPOBJ_BARREL_EXPL;
else objectsMap[objX][objY] = MAPOBJ_BARREL;
}
}
void DungeonMap::openDoor(int x, int y)
{
objectsMap[x][y] = MAPOBJ_DOOR_OPEN;
logicalMap[x][y] = LogicalFloor;
}
void DungeonMap::closeDoor(int x, int y)
{
objectsMap[x][y] = MAPOBJ_DOOR_CLOSED;
logicalMap[x][y] = LogicalWall;
}
bool DungeonMap::isDoor(int x, int y)
{
return objectsMap[x][y] == MAPOBJ_DOOR_OPEN || objectsMap[x][y] == MAPOBJ_DOOR_CLOSED;
}
void DungeonMap::makePatternTile(int x, int y)
{
if (map[x][y] < 24 * MAP_NB_FLOORS && (map[x][y] % 24) < 8) map[x][y] += 8;
else map[x][y] = floorOffset + 8 + rand() % 8;
}
void DungeonMap::initPattern(patternEnum n)
{
int i, j;
if (n == PatternSmallChecker)
{
for ( i = 2 ; i < width - 2 ; i++)
for ( j = 2 ; j < height - 2 ; j++)
{
if ((i + j) % 2 == 1) makePatternTile(i, j);
}
}
if (n == PatternBigChecker)
{
for ( i = 1 ; i < width - 1 ; i++)
for ( j = 1 ; j < height - 1 ; j++)
{
if ((i + j) % 2 == 1) makePatternTile(i, j);
}
}
if (n == PatternBorder)
{
for ( i = 1 ; i < width - 1 ; i++)
for ( j = 1 ; j < height - 1 ; j++)
{
if (i == 1 || j == 1 || i == width - 2 || j == height - 2)
makePatternTile(i, j);
}
}
if (n == PatternBigCircle)
{
for ( i = 2 ; i < width - 2 ; i++)
for ( j = 2 ; j < height - 2 ; j++)
{
if (i == 2 || j == 2 || i == width - 3 || j == height - 3)
makePatternTile(i, j);
}
}
if (n == PatternSmallCircle || n == PatternSmallStar)
{
for ( i = 5 ; i < 10 ; i++)
for ( j = 2 ; j < height - 2 ; j++)
{
if (i == 5 || i == 9 || j == 2 || j == height - 3)
makePatternTile(i, j);
}
}
if (n == PatternSmallStar)
{
makePatternTile(7, 1);
makePatternTile(7, height - 2);
makePatternTile(4, 4);
makePatternTile(10, 4);
}
if (n == PatternSmallDisc)
{
for ( i = 5 ; i < 10 ; i++)
for ( j = 2 ; j < height - 2 ; j++)
{
makePatternTile(i, j);
}
}
}
void DungeonMap::generateInselRoom()
{
for (int i = 1; i < MAP_WIDTH - 1; i++)
for (int j = 1; j < MAP_HEIGHT - 1; j++)
{
if (i != MAP_WIDTH / 2 && j != MAP_HEIGHT / 2
&& !(i == MAP_WIDTH / 2 - 1 && j == MAP_HEIGHT / 2 - 1)
&& !(i == MAP_WIDTH / 2 - 1 && j == MAP_HEIGHT / 2 + 1)
&& !(i == MAP_WIDTH / 2 + 1 && j == MAP_HEIGHT / 2 - 1)
&& !(i == MAP_WIDTH / 2 + 1 && j == MAP_HEIGHT / 2 + 1)
)
addHole(i, j);
}
objectsMap[MAP_WIDTH / 2 - 2][MAP_HEIGHT / 2 - 1] = MAPOBJ_WALL_SPECIAL;
objectsMap[MAP_WIDTH / 2 - 1][MAP_HEIGHT / 2 - 2] = MAPOBJ_WALL_SPECIAL;
logicalMap[MAP_WIDTH / 2 - 2][MAP_HEIGHT / 2 - 1] = LogicalObstacle;
logicalMap[MAP_WIDTH / 2 - 1][MAP_HEIGHT / 2 - 2] = LogicalObstacle;
objectsMap[MAP_WIDTH / 2 + 2][MAP_HEIGHT / 2 - 1] = MAPOBJ_WALL_SPECIAL + 1;
objectsMap[MAP_WIDTH / 2 + 1][MAP_HEIGHT / 2 - 2] = MAPOBJ_WALL_SPECIAL + 1;
logicalMap[MAP_WIDTH / 2 + 2][MAP_HEIGHT / 2 - 1] = LogicalObstacle;
logicalMap[MAP_WIDTH / 2 + 1][MAP_HEIGHT / 2 - 2] = LogicalObstacle;
objectsMap[MAP_WIDTH / 2 - 2][MAP_HEIGHT / 2 + 1] = MAPOBJ_WALL_SPECIAL + 2;
objectsMap[MAP_WIDTH / 2 - 1][MAP_HEIGHT / 2 + 2] = MAPOBJ_WALL_SPECIAL + 2;
logicalMap[MAP_WIDTH / 2 - 2][MAP_HEIGHT / 2 + 1] = LogicalObstacle;
logicalMap[MAP_WIDTH / 2 - 1][MAP_HEIGHT / 2 + 2] = LogicalObstacle;
objectsMap[MAP_WIDTH / 2 + 2][MAP_HEIGHT / 2 + 1] = MAPOBJ_WALL_SPECIAL + 3;
objectsMap[MAP_WIDTH / 2 + 1][MAP_HEIGHT / 2 + 2] = MAPOBJ_WALL_SPECIAL + 3;
logicalMap[MAP_WIDTH / 2 + 2][MAP_HEIGHT / 2 + 1] = LogicalObstacle;
logicalMap[MAP_WIDTH / 2 + 1][MAP_HEIGHT / 2 + 2] = LogicalObstacle;
if (!hasNeighbourUp())
addHole(MAP_WIDTH / 2, 1);
if (!hasNeighbourDown())
addHole(MAP_WIDTH / 2, MAP_HEIGHT - 2);
if (!hasNeighbourLeft())
for (int i = 0; i < 4; i++)
{
addHole(1 + i, MAP_HEIGHT / 2);
addHole(1 + i, MAP_HEIGHT / 2 + 1);
}
if (!hasNeighbourRight())
for (int i = 0; i < 4; i++)
{
addHole(MAP_WIDTH - 2 - i, MAP_HEIGHT / 2);
addHole(MAP_WIDTH - 2 - i, MAP_HEIGHT / 2 + 1);
}
addHole(MAP_WIDTH / 2 - 1 , MAP_HEIGHT - 2);
addHole(MAP_WIDTH / 2 + 1 , MAP_HEIGHT - 2);
addHole(MAP_WIDTH / 2 - 2 , MAP_HEIGHT - 3);
addHole(MAP_WIDTH / 2 + 2 , MAP_HEIGHT - 3);
if (rand() % 2 == 0) makePatternTile(MAP_WIDTH / 2, MAP_HEIGHT / 2);
}
Vector2D DungeonMap::generateBonusRoom()
{
int x0 = MAP_WIDTH / 2;
int y0 = MAP_HEIGHT / 2;
initRoom();
if (game().getLevel() == 1 || rand() % 3 > 0)
{
if (rand() % 3 == 0)
{
if (rand() % 2 == 0) initPattern(PatternSmallDisc);
else initPattern(PatternSmallStar);
}
objectsMap[x0 - 1][y0 - 1] = MAPOBJ_WALL_SPECIAL;
objectsMap[x0 - 1][y0 + 1] = MAPOBJ_WALL_SPECIAL + 2;
objectsMap[x0 + 1][y0 - 1] = MAPOBJ_WALL_SPECIAL + 1;
objectsMap[x0 + 1][y0 + 1] = MAPOBJ_WALL_SPECIAL + 3;
logicalMap[x0 - 1][y0 - 1] = LogicalObstacle;
logicalMap[x0 - 1][y0 + 1] = LogicalObstacle;
logicalMap[x0 + 1][y0 - 1] = LogicalObstacle;
logicalMap[x0 + 1][y0 + 1] = LogicalObstacle;
}
else
{
generateInselRoom();
}
generateRandomTiles();
return (Vector2D(x0 * TILE_WIDTH + TILE_WIDTH / 2, y0 * TILE_HEIGHT + TILE_HEIGHT / 2));
}
Vector2D DungeonMap::generateChestRoom()
{
int x0 = MAP_WIDTH / 2;
int y0 = MAP_HEIGHT / 2;
if (game().getLevel() == 1 || rand() % 3 > 0)
{
initRoom(); // (8 * 24, 2);
{
if (rand() % 2 == 0) initPattern(PatternSmallDisc);
else initPattern(PatternSmallStar);
}
objectsMap[x0 - 1][y0 - 1] = MAPOBJ_WALL_SPECIAL;
objectsMap[x0 - 1][y0 + 1] = MAPOBJ_WALL_SPECIAL + 2;
objectsMap[x0 + 1][y0 - 1] = MAPOBJ_WALL_SPECIAL + 1;
objectsMap[x0 + 1][y0 + 1] = MAPOBJ_WALL_SPECIAL + 3;
logicalMap[x0 - 1][y0 - 1] = LogicalObstacle;
logicalMap[x0 - 1][y0 + 1] = LogicalObstacle;
logicalMap[x0 + 1][y0 - 1] = LogicalObstacle;
logicalMap[x0 + 1][y0 + 1] = LogicalObstacle;
}
else
{
initRoom();
generateInselRoom();
}
generateRandomTiles();
return (Vector2D(x0 * TILE_WIDTH + TILE_WIDTH / 2, y0 * TILE_HEIGHT + TILE_HEIGHT / 2));
}
void DungeonMap::generateTemple(int x, int y, enumDivinityType type)
{
map[x][y] = MAP_TEMPLE + (int)type;
addHole(x - 1, y - 2);
addHole(x - 1, y - 1);
addHole(x - 1, y);
addHole(x + 1, y - 2);
addHole(x + 1, y - 1);
addHole(x + 1, y );
objectsMap[x][y - 2] = MAPOBJ_TEMPLE_WALL + (int)type;
objectsMap[x][y - 1] = MAPOBJ_TEMPLE_WALL + 10 + (int)type;
logicalMap[x][y - 2] = LogicalObstacle;
logicalMap[x][y - 1] = LogicalObstacle;
}
void DungeonMap::generateTempleRoom()
{
initRoom();
int x0 = MAP_WIDTH / 2;
int y0 = 1 + MAP_HEIGHT / 2;
if (rand() % 3 == 0)
{
if (rand() % 2 == 0) initPattern(PatternSmallDisc);
else initPattern(PatternSmallStar);
}
int d0, d1, d2;
d0 = rand() % NB_DIVINITY;
d1 = d0;
while (d0 == d1) d1 = rand() % NB_DIVINITY;
if (rand() % 2 == 0)
{
// three temple
d2 = d0;
while (d0 == d2 || d1 == d2) d2 = rand() % NB_DIVINITY;
generateTemple(x0 - 2, y0, (enumDivinityType)d0);
generateTemple(x0 + 2, y0, (enumDivinityType)d1);
generateTemple(x0, y0, (enumDivinityType)d2);
}
else
{
// two temples
generateTemple(x0 - 1, y0, (enumDivinityType)d0);
generateTemple(x0 + 1, y0, (enumDivinityType)d1);
}
// no random tiles in temples
//generateRandomTiles();
}
void DungeonMap::generateCarpet(int x0, int y0, int w, int h, int n)
{
int xf = x0 + w - 1;
int yf = y0 + h - 1;
map[x0][y0] = n;
map[x0][yf] = n + 6;
map[xf][y0] = n + 2;
map[xf][yf] = n + 8;
int i, j;
for (i = x0 + 1; i <= xf - 1; i++)
{
map[i][y0] = n + 1;
map[i][yf] = n + 7;
for (j = y0 + 1; j <= yf - 1; j++)
map[i][j] = n + 4;
}
for (j = y0 + 1; j <= yf - 1; j++)
{
map[x0][j] = n + 3;
map[xf][j] = n + 5;
}
}
void DungeonMap::generateTable(int x0, int y0, int w, int h, int n)
{
int xf = x0 + w - 1;
int yf = y0 + h - 1;
objectsMap[x0][y0] = n;
objectsMap[x0][yf] = n + 6;
objectsMap[xf][y0] = n + 2;
objectsMap[xf][yf] = n + 8;
int i, j;
for (i = x0 + 1; i <= xf - 1; i++)
{
objectsMap[i][y0] = n + 1;
objectsMap[i][yf] = n + 7;
for (j = y0 + 1; j <= yf - 1; j++)
objectsMap[i][j] = n + 4;
}
for (j = y0 + 1; j <= yf - 1; j++)
{
objectsMap[x0][j] = n + 3;
objectsMap[xf][j] = n + 5;
}
for (i = x0; i <= xf; i++)
for (j = y0; j <= yf; j++)
logicalMap[i][j] = LogicalObstacle;
}
void DungeonMap::generateLongObject(int x0, int y0, int w, int n)
{
int xf = x0 + w - 1;
objectsMap[x0][y0] = n;
logicalMap[x0][y0] = LogicalObstacle;
for (int i = x0 + 1; i <= xf - 1; i++)
{
objectsMap[i][y0] = n + 1;
logicalMap[i][y0] = LogicalObstacle;
}
objectsMap[xf][y0] = n + 2;
logicalMap[xf][y0] = LogicalObstacle;
}
Vector2D DungeonMap::generateMerchantRoom()
{
initRoom();
int x0 = MAP_WIDTH / 2;
int y0 = MAP_HEIGHT / 2;
for (int i = x0 - 3; i <= x0 + 3; i++)
{
if (i == x0 - 3) objectsMap[i][y0] = MAPOBJ_SHOP_LEFT;
else if (i == x0 + 3) objectsMap[i][y0] = MAPOBJ_SHOP_RIGHT;
else objectsMap[i][y0] = MAPOBJ_SHOP;
logicalMap[i][y0] = LogicalObstacle;
}
if (!hasNeighbourUp())
{
objectsMap[x0 - 1][0] = MAPOBJ_PNW;
objectsMap[x0][0] = MAPOBJ_PNW + 1;
objectsMap[x0 + 1][0] = MAPOBJ_PNW + 2;
}
else
{
objectsMap[x0 - 1][MAP_HEIGHT - 1] = MAPOBJ_PNW +3;
objectsMap[x0][MAP_HEIGHT - 1] = MAPOBJ_PNW + 4;
objectsMap[x0 + 1][MAP_HEIGHT - 1] = MAPOBJ_PNW + 5;
}
generateRandomTiles();
return (Vector2D(x0 * TILE_WIDTH + TILE_WIDTH / 2, y0 * TILE_HEIGHT + TILE_HEIGHT / 2));
}
Vector2D DungeonMap::generateKeyRoom()
{
initRoom();
int x0 = MAP_WIDTH / 2;
int y0 = MAP_HEIGHT / 2;
objectsMap[x0 - 1][y0 - 1] = MAPOBJ_WALL_SPECIAL;
objectsMap[x0 - 1][y0 + 1] = MAPOBJ_WALL_SPECIAL + 2;
objectsMap[x0 + 1][y0 - 1] = MAPOBJ_WALL_SPECIAL + 1;
objectsMap[x0 + 1][y0 + 1] = MAPOBJ_WALL_SPECIAL + 3;
logicalMap[x0 - 1][y0 - 1] = LogicalObstacle;
logicalMap[x0 - 1][y0 + 1] = LogicalObstacle;
logicalMap[x0 + 1][y0 - 1] = LogicalObstacle;
logicalMap[x0 + 1][y0 + 1] = LogicalObstacle;
if (rand() % 3 == 0)
{
if (rand() % 2 == 0) initPattern(PatternSmallCircle);
else initPattern(PatternSmallStar);
}
generateCarpet(x0 - 1, y0 - 1, 3, 3, MAP_CARPET);
generateRandomTiles();
return (Vector2D(x0 * TILE_WIDTH + TILE_WIDTH / 2, y0 * TILE_HEIGHT + TILE_HEIGHT / 2));
}
void DungeonMap::generateExitRoom()
{
initRoom();
int x0 = MAP_WIDTH / 2;
map[x0][0] = floorOffset;
map[x0 - 1][0] = floorOffset;
map[x0 + 1][0] = floorOffset;
logicalMap[x0][0] = LogicalFloor;
if (rand() % 3 == 0) initPattern(PatternBorder);
generateRandomTiles();
}
void DungeonMap::generateRoomRandom(int type)
{
if (rand() % 3 == 0) generateRoomWithHoles(type);
else generateRoomWithoutHoles(type);
}
void DungeonMap::generateRoomWithoutHoles(int type)
{
initRoom();
int x0 = MAP_WIDTH / 2;
int y0 = MAP_HEIGHT / 2;
int i, j, r;
if (type <= 0) // empty room
{
if (roomType == roomTypeStarting)
{
generateCarpet(5, 3, 5, 3, MAP_CARPET);
if (game().getLevel() > 1)
{
map[x0][MAP_HEIGHT - 1] = floorOffset;
}
}
else if (roomType == roomTypeBoss && (game().getLevel() == 2) ) // giant slime
{
// good ?
objectsMap[1][1] = MAPOBJ_GRID;
objectsMap[1][MAP_HEIGHT -2] = MAPOBJ_GRID;
objectsMap[MAP_WIDTH - 2][1] = MAPOBJ_GRID;
objectsMap[MAP_WIDTH - 2][MAP_HEIGHT -2] = MAPOBJ_GRID;
}
if (roomType == roomTypeStandard)
{
if (rand() % 3 > 0 && gameFloor->neighboorCount(x, y) > 1)
{
if (type == 0 && game().getLevel() < 6) generateCorridors();
}
else
{
if (rand() % 3 == 0) initPattern((patternEnum)(rand() % 4));
}
}
}
if (type == 1) // corner block
{
if (rand() % 3 == 0) initPattern(PatternSmallChecker);
int wallOffset = wallType * 24;
map[0][0] = MAP_WALL_X;
map[0][1] = wallOffset + MAP_WALL_7;
map[1][1] = wallOffset + MAP_WALL_77;
map[1][0] = wallOffset + MAP_WALL_7;
logicalMap[1][1] = LogicalWall;
map[0][MAP_HEIGHT - 1] = MAP_WALL_X;
map[0][MAP_HEIGHT - 2] = wallOffset + MAP_WALL_7;
map[1][MAP_HEIGHT - 2] = wallOffset + MAP_WALL_77;
map[1][MAP_HEIGHT - 1] = wallOffset + MAP_WALL_7;
logicalMap[1][MAP_HEIGHT -2] = LogicalWall;
map[MAP_WIDTH - 1][0] = MAP_WALL_X;
map[MAP_WIDTH - 1][1] = wallOffset + MAP_WALL_7;
map[MAP_WIDTH - 2][1] = wallOffset + MAP_WALL_77;
map[MAP_WIDTH - 2][0] = wallOffset + MAP_WALL_7;
logicalMap[MAP_WIDTH - 2][1] = LogicalWall;
map[MAP_WIDTH - 1][MAP_HEIGHT -1] = MAP_WALL_X;
map[MAP_WIDTH - 1][MAP_HEIGHT -2] = wallOffset + MAP_WALL_7;
map[MAP_WIDTH - 2][MAP_HEIGHT -2] = wallOffset + MAP_WALL_77;
map[MAP_WIDTH - 2][MAP_HEIGHT -1] = wallOffset + MAP_WALL_7;
logicalMap[MAP_WIDTH - 2][MAP_HEIGHT -2] = LogicalWall;
}
if (type == 2) // blocks in the middle
{
if (rand() % 3 == 0) initPattern(PatternBorder);
r = 1 + rand() % 3;
generateTable(x0 - r, y0 - 1, 1 + 2 * r, 3, MAPOBJ_BIG_OBSTACLE);
}
if (type == 3)
{
// big blocks in the corners
generateTable(2, 2, 2, 2, MAPOBJ_BIG_OBSTACLE);
generateTable(2, MAP_HEIGHT - 4, 2, 2, MAPOBJ_BIG_OBSTACLE);
generateTable(MAP_WIDTH - 4, MAP_HEIGHT - 4, 2, 2, MAPOBJ_BIG_OBSTACLE);
generateTable(MAP_WIDTH - 4, 2, 2, 2, MAPOBJ_BIG_OBSTACLE);
}
if (type == 4)
{
// objects
if (rand() % 2 == 0)
{
// type 1
if (rand() % 3 == 0) initPattern(PatternSmallChecker);
bool leftOriented = rand() % 2 == 0;
int bankType = rand() % 4;
if (bankType == 2)
{
int xPlayer = game().getPlayerPosition().x;
if (xPlayer > GAME_WIDTH / 2 - TILE_WIDTH && xPlayer < GAME_WIDTH / 2 + TILE_WIDTH)
bankType = rand() % 2;
}
int x0 = leftOriented ? 5 : 3;
if (leftOriented)
{
objectsMap[2][4] = MAPOBJ_CHURCH_FURN_L;
logicalMap[2][4] = LogicalObstacle;
}
else
{
objectsMap[12][4] = MAPOBJ_CHURCH_FURN_R;
logicalMap[12][4] = LogicalObstacle;
}
for (int i = 0; i < 3; i++)
{
int xPos = x0 + i * 3;
switch (bankType)
{
case 0:
objectsMap[xPos][2] = MAPOBJ_BANK_TOP;
objectsMap[xPos][3] = MAPOBJ_BANK_BOTTOM;
objectsMap[xPos][5] = MAPOBJ_BANK_TOP;
objectsMap[xPos][6] = MAPOBJ_BANK_BOTTOM;
for (int j = 2; j <= 6; j++) if (j != 4) logicalMap[xPos][j] = LogicalObstacle;
break;
case 1:
objectsMap[xPos][2] = MAPOBJ_BANK_TOP;
objectsMap[xPos][3] = MAPOBJ_BANK;
objectsMap[xPos][4] = MAPOBJ_BANK;
objectsMap[xPos][5] = MAPOBJ_BANK;
objectsMap[xPos][6] = MAPOBJ_BANK_BOTTOM;
for (int j = 2; j <= 6; j++) logicalMap[xPos][j] = LogicalObstacle;
break;
default:
objectsMap[xPos][1] = MAPOBJ_BANK_TOP;
objectsMap[xPos][2] = MAPOBJ_BANK;
objectsMap[xPos][3] = MAPOBJ_BANK_BOTTOM;
objectsMap[xPos][5] = MAPOBJ_BANK_TOP;
objectsMap[xPos][6] = MAPOBJ_BANK;
objectsMap[xPos][7] = MAPOBJ_BANK_BOTTOM;
for (int j = 1; j <= 7; j++) if (j != 4) logicalMap[xPos][j] = LogicalObstacle;
break;
}
}
}
else
{
initPattern(PatternSmallStar);
generateLongObject(2, 2, 3, MAPOBJ_LONG_LEFT);
generateLongObject(2, 6, 3, MAPOBJ_LONG_LEFT);
generateLongObject(10, 2, 3, MAPOBJ_LONG_LEFT);
generateLongObject(10, 6, 3, MAPOBJ_LONG_LEFT);
generateLongObject(6, 4, 3, MAPOBJ_LONG_LEFT);
}
}
if (type == ROOM_TYPE_CHECKER)
{
// "checker"
if (rand() % 3 == 0) initPattern(PatternSmallChecker);
for (i = 2; i < MAP_WIDTH - 2; i = i + 2)
for (j = 2; j < MAP_HEIGHT - 2; j = j + 2)
{
objectsMap[i][j] = game().getLevel() >= 6 ? MAPOBJ_TOMB : MAPOBJ_OBSTACLE;
logicalMap[i][j] = LogicalObstacle;
}
}
generateRandomTiles();
}
void DungeonMap::addHole(int x, int y)
{
int n = MAPOBJ_HOLE;
if (y > 0 && logicalMap[x][y - 1] == LogicalHole)
n = MAPOBJ_HOLE_BOTTOM;
else if (logicalMap[x - 1][y] == LogicalHole && logicalMap[x - 1][y - 1] == LogicalHole)
n = MAPOBJ_HOLE_LEFT;
else if (logicalMap[x + 1][y] == LogicalHole && logicalMap[x + 1][y - 1] == LogicalHole)
n = MAPOBJ_HOLE_RIGHT;
objectsMap[x][y] = n;
logicalMap[x][y] = LogicalHole;
if (logicalMap[x][y + 1] == LogicalHole && objectsMap[x - 1][y + 1] == MAPOBJ_HOLE_TOP)
objectsMap[x - 1][y + 1] = MAPOBJ_HOLE_LEFT;
if (logicalMap[x][y + 1] == LogicalHole && objectsMap[x + 1][y + 1] == MAPOBJ_HOLE_TOP)
objectsMap[x + 1][y + 1] = MAPOBJ_HOLE_RIGHT;
}
void DungeonMap::generateRoomWithHoles(int type)
{
initRoom();
int x0 = MAP_WIDTH / 2;
int y0 = MAP_HEIGHT / 2;
int i, j, r;
if (type == 0)
{
if (roomType == roomTypeStarting)
{
generateCarpet(5, 3, 5, 3, MAP_CARPET);
if (game().getLevel() > 1)
{
map[x0 - 1][MAP_HEIGHT - 1] = 62;
map[x0][MAP_HEIGHT - 1] = 63;
map[x0 + 1][MAP_HEIGHT - 1] = 64;
}
}
/*else if (rand() % 2 == 0)
{
for (int i = 1; i <= MAP_WIDTH - 2; i++)
{
if (i != MAP_WIDTH / 2 || !hasNeighbourUp()) addHole(i, 1);
}
for (int i = 2; i <= MAP_HEIGHT - 3; i++)
{
if (i != MAP_HEIGHT / 2 || !hasNeighbourLeft()) addHole(1, i);
if (i != MAP_HEIGHT / 2 || !hasNeighbourRight()) addHole(MAP_WIDTH - 2, i);
}
addHole(MAP_WIDTH - 2, MAP_HEIGHT - 2);
for (int i = 1; i <= MAP_WIDTH - 3; i++)
{
if (i != MAP_WIDTH / 2 || !hasNeighbourDown()) addHole(i, MAP_HEIGHT - 2);
}
}*/
}
else if (type == 1)
{
// corner hole
if (rand() % 3 == 0) initPattern(PatternSmallChecker);
addHole(1, 1);
addHole(MAP_WIDTH - 2, MAP_HEIGHT -2);
addHole(1, MAP_HEIGHT -2);
addHole(MAP_WIDTH - 2, 1);
}
else if (type == 2)
{
// blocks in the middle
if (rand() % 3 == 0) initPattern(PatternBorder);
/*if (false) //irregular // TO CORRECT
{
r = 1; //rand() % 2;
for (i = x0 - r; i <= x0 + r; i++)
{
if (rand() % 3 == 0) addHole(i, y0 - 1);
addHole(i, y0);
if (rand() % 3 == 0) addHole(i, y0 + 1);
}
for (j = y0 - 1; j <= y0 + 1; j++)
{
if (rand() % 3 == 0) addHole(x0 - r - 1, j);
if (rand() % 3 == 0) addHole(x0 + r + 1, j);
}
}
else*/
{
r = 1 + rand() % 2;
for (i = x0 - r; i <= x0 + r; i++)
for (j = y0 - 1; j <= y0 + 1; j++)
{
addHole(i, j);
}
}
}
else if (type == 3)
{
// 4 holes
addHole(2, 2);
addHole(2, 3);
addHole(3, 2);
addHole(3, 3);
addHole(MAP_WIDTH - 4, 2);
addHole(MAP_WIDTH - 4, 3);
addHole(MAP_WIDTH - 3, 2);
addHole(MAP_WIDTH - 3, 3);
addHole(2, MAP_HEIGHT - 4);
addHole(2, MAP_HEIGHT - 3);
addHole(3, MAP_HEIGHT - 4);
addHole(3, MAP_HEIGHT - 3);
addHole(MAP_WIDTH - 4, MAP_HEIGHT - 4);
addHole(MAP_WIDTH - 4, MAP_HEIGHT - 3);
addHole(MAP_WIDTH - 3, MAP_HEIGHT - 4);
addHole(MAP_WIDTH - 3, MAP_HEIGHT - 3);
}
else if (type == 4)
{
if (rand() % 2 == 0)
{
// holes and (sometimes) obstacles randomly
if (rand() % 3 == 0) initPattern(PatternBigCircle);
int r = 6 + rand()% 5;
int obstacleType = rand() % 2;
for (int i = 0; i < r; i++)
{
int rx = 1 + rand() % (MAP_WIDTH - 3);
int ry = 1 + rand() % (MAP_HEIGHT - 3);
bool ok = true;
bool isObstacle = (obstacleType == 1) && rand() % 2 == 0;
if ( (rx == 1 && ry == MAP_HEIGHT / 2)
|| (rx == MAP_WIDTH - 2 && ry == MAP_HEIGHT / 2)
|| (rx == MAP_WIDTH /2 && ry == MAP_HEIGHT - 2)
|| (rx == MAP_WIDTH /2 && ry == 1) )
{
ok = false;
}
else
{
for (int ix = -1; ix <= 1; ix++)
for (int iy = -1; iy <= 1; iy++)
{
ok = ok && logicalMap[rx + ix][ry + iy] != LogicalHole;
ok = ok && logicalMap[rx + ix][ry + iy] != LogicalObstacle;
}
}
if (ok)
{
if (!isObstacle)
{
addHole(rx, ry);
}
else
{
objectsMap[rx][ry] = MAPOBJ_OBSTACLE;
logicalMap[rx][ry] = LogicalObstacle;
}
}
else
{
i--;
}
}
}
else
{
// big holes left and right
bool holesNW = rand() % 2 == 0;
for (int i = 0; i < 5; i++)
{
if (holesNW)
{
addHole(1 + i, 1);
addHole(1 + i, 2);
addHole(MAP_WIDTH - 2 - i, MAP_HEIGHT - 3);
addHole(MAP_WIDTH - 2 - i, MAP_HEIGHT - 2);
}
else
{
addHole(1 + i, MAP_HEIGHT - 3);
addHole(1 + i, MAP_HEIGHT - 2);
addHole(MAP_WIDTH - 2 - i, 1);
addHole(MAP_WIDTH - 2 - i, 2);
}
}
}
}
else //if (type == 5)
{
// "checker"
for (i = 2; i < MAP_WIDTH - 2; i = i + 2)
for (j = 2; j < MAP_HEIGHT - 2; j = j + 2)
{
addHole(i, j);
}
}
generateRandomTiles();
}
void DungeonMap::addItem(int itemType, float x, float y, bool merch)
{
itemListElement ilm;
ilm.type = itemType;
ilm.x = x;
ilm.y = y;
ilm.merch = merch;
itemList.push_back(ilm);
}
void DungeonMap::addSprite(int spriteType, int frame, float x, float y, float scale)
{
spriteListElement slm;
slm.type = spriteType;
slm.frame = frame;
slm.x = x;
slm.y = y;
slm.scale = scale;
spriteList.push_back(slm);
}
void DungeonMap::addChest(int chestType, bool state, float x, float y)
{
chestListElement clm;
clm.type = chestType;
clm.state = state;
clm.x = x;
clm.y = y;
chestList.push_back(clm);
}
void DungeonMap::restoreItems()
{
ItemList::iterator it;
for (it = itemList.begin (); it != itemList.end ();)
{
itemListElement ilm = *it;
it++;
ItemEntity* itemEntity = new ItemEntity((enumItemType)(ilm.type), ilm.x, ilm.y);
itemEntity->setMerchandise(ilm.merch);
}
}
void DungeonMap::restoreSprites()
{
SpriteList::iterator it;
for (it = spriteList.begin (); it != spriteList.end ();)
{
spriteListElement ilm = *it;
it++;
if (ilm.type == ENTITY_BLOOD)
game().getCurrentMapEntity()->addBlood(ilm.x, ilm.y, ilm.frame, ilm.scale);
else if (ilm.type == ENTITY_CORPSE)
game().getCurrentMapEntity()->addCorpse(ilm.x, ilm.y, ilm.frame);
}
}
void DungeonMap::restoreChests()
{
ChestList::iterator it;
for (it = chestList.begin (); it != chestList.end ();)
{
chestListElement clm = *it;
it++;
new ChestEntity(clm.x, clm.y, clm.type, clm.state);
}
}
void DungeonMap::restoreMapObjects()
{
restoreItems();
restoreSprites();
restoreChests();
cleanMapObjects();
}
void DungeonMap::cleanMapObjects()
{
itemList.clear();
spriteList.clear();
chestList.clear();
}
void DungeonMap::addRandomGrids(int n)
{
int counter = n;
while (counter > 0)
{
int rx = 1 + rand() % (MAP_WIDTH - 2);
int ry = 1 + rand() % (MAP_HEIGHT - 2);
if (logicalMap[rx][ry] == LogicalFloor
|| objectsMap[rx][ry] == 0)
{
objectsMap[rx][ry] = MAPOBJ_GRID;
counter--;
}
}
}
void DungeonMap::generateCorridors()
{
int xCor = 1 + rand()% 4;
int yCor = 1 + rand()% 1;
int wallOffset = wallType * 24;
if (!hasNeighbourLeft())
{
for (int i = 0; i < xCor; i++)
for (int j = 0; j < MAP_HEIGHT; j++)
{
map[i][j] = MAP_WALL_X;
logicalMap[i][j] = LogicalWall;
}
}
if (!hasNeighbourRight())
{
for (int i = MAP_WIDTH - 1; i > MAP_WIDTH - 1 - xCor; i--)
for (int j = 0; j < MAP_HEIGHT; j++)
{
map[i][j] = MAP_WALL_X;
logicalMap[i][j] = LogicalWall;
}
}
if (!hasNeighbourUp())
{
for (int i = 0; i < MAP_WIDTH; i++)
for (int j = 0; j < yCor; j++)
{
map[i][j] = MAP_WALL_X;
logicalMap[i][j] = LogicalWall;
}
}
if (!hasNeighbourDown())
{
for (int i = 0; i < MAP_WIDTH; i++)
for (int j = MAP_HEIGHT - 1; j > MAP_HEIGHT - 1 - yCor; j--)
{
map[i][j] = MAP_WALL_X;
logicalMap[i][j] = LogicalWall;
}
}
//
for (int i = 0; i < MAP_WIDTH; i++)
{
for (int j = 0; j < MAP_HEIGHT; j++)
{
if (map[i][j] != MAP_WALL_X)
{
if (getTile(i - 1, j) == MAP_WALL_X)
{
if (j == 0 || getTile(i, j - 1) == MAP_WALL_X)
{
map[i][j] = wallOffset + MAP_WALL_7;
}
else if (j == MAP_HEIGHT - 1 || getTile(i, j + 1) == MAP_WALL_X)
{
map[i][j] = wallOffset + MAP_WALL_7;
}
else
{
if (j < MAP_HEIGHT / 2) map[i][j] = wallOffset + MAP_WALL_87 + rand() % 8;
else if (j > MAP_HEIGHT / 2) map[i][j] = wallOffset + MAP_WALL_87 + rand() % 8;
else map[i][j] = wallOffset + MAP_WALL_8;
}
logicalMap[i][j] = LogicalWall;
}
else if (getTile(i + 1, j) == MAP_WALL_X)
{
if (j == 0 || getTile(i, j - 1) == MAP_WALL_X)
{
map[i][j] = wallOffset + MAP_WALL_7;
map[i][j] = wallOffset + MAP_WALL_7;
}
else if (j == MAP_HEIGHT - 1 || getTile(i, j + 1) == MAP_WALL_X) map[i][j] = wallOffset + MAP_WALL_7;
else
{
if (j < MAP_HEIGHT / 2) map[i][j] = wallOffset + MAP_WALL_87 + rand() % 8;
else if (j > MAP_HEIGHT / 2) map[i][j] = wallOffset + MAP_WALL_87 + rand() % 8;
else map[i][j] = wallOffset + MAP_WALL_8;
}
logicalMap[i][j] = LogicalWall;
}
else if (getTile(i, j - 1) == MAP_WALL_X)
{
if (i == 0) map[i][j] = wallOffset + MAP_WALL_7;
else if (i == MAP_WIDTH - 1) map[i][j] = wallOffset + MAP_WALL_7;
else
{
if (i < MAP_WIDTH / 2) map[i][j] = wallOffset + MAP_WALL_87 + rand() % 8;
else if (i > MAP_WIDTH / 2) map[i][j] = wallOffset + MAP_WALL_87 + rand() % 8;
else map[i][j] = wallOffset + MAP_WALL_8;
}
logicalMap[i][j] = LogicalWall;
}
else if (getTile(i, j + 1) == MAP_WALL_X)
{
if (i == 0) map[i][j] = wallOffset + MAP_WALL_7;
else if (i == MAP_WIDTH - 1) map[i][j] = wallOffset + MAP_WALL_7;
else
{
if (i < MAP_WIDTH / 2) map[i][j] = wallOffset + MAP_WALL_87 + rand() % 8;
else if (i > MAP_WIDTH / 2) map[i][j] = wallOffset + MAP_WALL_87 + rand() % 8;
else map[i][j] = wallOffset + MAP_WALL_8;
}
logicalMap[i][j] = LogicalWall;
}
}
}
}
}
void DungeonMap::generateRandomTiles()
{
for (int i = 0; i < NB_RANDOM_TILES_IN_ROOM; i++)
generateRandomTile(i);
}
void DungeonMap::generateRandomTile(int index)
{
bool ok = false;
for (int i = 0; !ok && i < NB_RANDOM_TILE_TRY; i++)
{
int n = rand() % NB_RANDOM_TILES;
int xTile, yTile;
if (randomDungeonTiles[n].canBeOnWall)
{
xTile = rand() % (GAME_WIDTH - randomDungeonTiles[n].width);
yTile = rand() % (GAME_HEIGHT - randomDungeonTiles[n].height);
}
else
{
xTile = TILE_WIDTH + rand() % (GAME_WIDTH - 2 * TILE_WIDTH - randomDungeonTiles[n].width);
yTile = TILE_HEIGHT + rand() % (GAME_HEIGHT - 2 * TILE_HEIGHT - randomDungeonTiles[n].height);
}
int x0 = xTile / TILE_WIDTH;
int xf = (xTile + randomDungeonTiles[n].width) / TILE_WIDTH;
int y0 = yTile / TILE_HEIGHT;
int yf = (yTile + randomDungeonTiles[n].height) / TILE_HEIGHT;
ok = true;
// proceed rarity
if (randomDungeonTiles[n].rarity > 1 && (rand() % randomDungeonTiles[n].rarity) != 0 )
{
ok = false;
}
// each random sprite type should be present no more that once in a room
for (int j = 0; j < index; j++)
{
if (n == randomTileElements[j].type) ok = false;
}
if (!randomDungeonTiles[n].randomPlace || roomType == roomTypeKey)
{
for (int ix = x0; ix <= xf; ix++)
for (int iy = y0; iy <= yf; iy++)
{
ok = ok && isWalkable(ix, iy);
}
}
if (ok && !randomDungeonTiles[n].canBeOnWall)
{
for (int ix = x0; ix <= xf; ix++)
for (int iy = y0; iy <= yf; iy++)
{
ok = ok && isFlyable(ix, iy);
}
}
if (ok)
{
randomTileElements[index].type = n;
randomTileElements[index].x = xTile;
randomTileElements[index].y = yTile;
if (randomDungeonTiles[n].canRotate)
randomTileElements[index].rotation = rand()% 360;
else
randomTileElements[index].rotation = 0;
}
}
}
+
+bool DungeonMap::callRevelation()
+{
+ if (hasNeighbourRight() && !gameFloor->getMap(x + 1, y)->isRevealed())
+ {
+ map[MAP_WIDTH - 1][MAP_HEIGHT / 2] = floorOffset;
+ map[MAP_WIDTH - 1][MAP_HEIGHT / 2 - 1] = floorOffset;
+ map[MAP_WIDTH - 1][MAP_HEIGHT / 2 + 1] = floorOffset;
+
+ if (cleared)
+ openDoor(MAP_WIDTH - 1, MAP_HEIGHT / 2);
+ else
+ closeDoor(MAP_WIDTH - 1, MAP_HEIGHT / 2);
+
+ game().setDoorVisible(East);
+ gameFloor->getMap(x + 1, y)->setRevealed(true);
+ hasChanged = true;
+ }
+ else if (hasNeighbourLeft() && !gameFloor->getMap(x - 1, y)->isRevealed())
+ {
+ map[0][MAP_HEIGHT / 2] = floorOffset;
+ map[0][MAP_HEIGHT / 2 - 1] = floorOffset;
+ map[0][MAP_HEIGHT / 2 + 1] = floorOffset;
+
+ if (cleared)
+ openDoor(0, MAP_HEIGHT / 2);
+ else
+ closeDoor(0, MAP_HEIGHT / 2);
+
+ game().setDoorVisible(West);
+ gameFloor->getMap(x - 1, y)->setRevealed(true);
+ hasChanged = true;
+ }
+ else if (hasNeighbourUp() && !gameFloor->getMap(x, y - 1)->isRevealed())
+ {
+ map[MAP_WIDTH / 2][0] = floorOffset;
+ map[MAP_WIDTH / 2 - 1][0] = floorOffset;
+ map[MAP_WIDTH / 2 + 1][0] = floorOffset;
+
+ if (cleared)
+ openDoor(MAP_WIDTH / 2, 0);
+ else
+ closeDoor(MAP_WIDTH / 2, 0);
+
+ game().setDoorVisible(North);
+ gameFloor->getMap(x, y - 1)->setRevealed(true);
+ hasChanged = true;
+ }
+ else if (hasNeighbourDown() && !gameFloor->getMap(x, y + 1)->isRevealed())
+ {
+ map[MAP_WIDTH / 2][MAP_HEIGHT - 1] = floorOffset;
+ map[MAP_WIDTH / 2 - 1][MAP_HEIGHT - 1] = floorOffset;
+ map[MAP_WIDTH / 2 + 1][MAP_HEIGHT - 1] = floorOffset;
+
+ if (cleared)
+ openDoor(MAP_WIDTH / 2, MAP_HEIGHT -1);
+ else
+ closeDoor(MAP_WIDTH / 2, MAP_HEIGHT -1);
+
+ game().setDoorVisible(South);
+ gameFloor->getMap(x, y + 1)->setRevealed(true);
+ hasChanged = true;
+ }
+
+ return false;
+}
diff --git a/src/DungeonMap.h b/src/DungeonMap.h
index 35fdcc7..d88af7f 100644
--- a/src/DungeonMap.h
+++ b/src/DungeonMap.h
@@ -1,281 +1,289 @@
#ifndef MAGICMAP_H
#define MAGICMAP_H
#include "sfml_game/GameMap.h"
#include "sfml_game/MyTools.h"
#include "Constants.h"
#include "DoorEntity.h"
#include <list>
const int MAPOBJ_NONE = 0;
const int MAPOBJ_DOOR_OPEN = 1;
const int MAPOBJ_DOOR_CLOSED = 2;
const int MAPOBJ_OBSTACLE = 10;
const int MAPOBJ_BIG_OBSTACLE = 40;
const int MAPOBJ_TOMB = 49;
const int MAPOBJ_WALL_SPECIAL = 14;
const int MAPOBJ_GRID = 19;
const int MAPOBJ_BANK_TOP = 18;
const int MAPOBJ_BANK = 28;
const int MAPOBJ_BANK_BOTTOM = 38;
const int MAPOBJ_CHURCH_FURN_R = 29;
const int MAPOBJ_CHURCH_FURN_L = 39;
const int MAPOBJ_LONG_LEFT = 50;
const int MAPOBJ_LONG = 51;
const int MAPOBJ_LONG_RIGHT = 52;
const int MAPOBJ_PNW = 60;
const int MAPOBJ_HOLE = 3;
const int MAPOBJ_HOLE_TOP = MAPOBJ_HOLE;
const int MAPOBJ_HOLE_BOTTOM = MAPOBJ_HOLE + 1;
const int MAPOBJ_HOLE_LEFT = MAPOBJ_HOLE + 2;
const int MAPOBJ_HOLE_RIGHT = MAPOBJ_HOLE + 3;
const int MAPOBJ_TEMPLE_WALL = 20;
const int MAPOBJ_SHOP_BEGIN = 11;
const int MAPOBJ_SHOP_LEFT = 0 + MAPOBJ_SHOP_BEGIN;
const int MAPOBJ_SHOP = 1 + MAPOBJ_SHOP_BEGIN;
const int MAPOBJ_SHOP_RIGHT = 2 + MAPOBJ_SHOP_BEGIN;
const int MAPOBJ_BARREL = 1000;
const int MAPOBJ_BARREL_NO_DROP = 1010;
const int MAPOBJ_BARREL_EXPL = 1020;
const int MAP_NORMAL_FLOOR = 8;
const int MAP_NB_FLOORS = 10;
const int MAP_TEMPLE = MAP_NB_FLOORS * 24;
const int MAP_CARPET = MAP_TEMPLE + 8;
const int MAP_WALL_BEGIN = (MAP_NB_FLOORS + 3) * 24;
// walls
const int MAP_WALL_X = MAP_WALL_BEGIN - 1;
const int MAP_WALL_8 = 0 + MAP_WALL_BEGIN;
const int MAP_WALL_7 = 2 + MAP_WALL_BEGIN;
const int MAP_WALL_77 = 4 + MAP_WALL_BEGIN;
const int MAP_WALL_87 = 5 + MAP_WALL_BEGIN;
const int DOOR_WALL_SPRITE_X = 1344;
const int DOOR_WALL_SPRITE_Y = (MAP_NB_FLOORS + 3) * 64;
const int DOOR_GRID_SPRITE_X = 1280;
const int DOOR_GRID_SPRITE_Y = (MAP_NB_FLOORS + 2) * 64;
const int DOOR_STAIRS_SPRITE_X = 1088;
const int DOOR_STAIRS_SPRITE_Y = DOOR_GRID_SPRITE_Y;
const int DOOR_SHADOW_SPRITE_X = 896;
const int DOOR_SHADOW_SPRITE_Y = DOOR_GRID_SPRITE_Y;
const int ROOM_TYPE_CHECKER = 5;
const int ROOM_TYPE_ALL = 6;
enum logicalMapStateEnum
{
LogicalFloor,
LogicalWall,
LogicalObstacle,
LogicalHole,
LogicalDestroyable,
};
class GameFloor;
enum roomTypeEnum
{
roomTypeNULL,
roomTypeStandard,
roomTypeBoss,
roomTypeMerchant,
roomTypeKey,
roomTypeBonus,
roomTypeExit,
roomTypeStarting,
roomTypeChallenge,
- roomTypeTemple
+ roomTypeTemple,
+ roomTypeSecret
};
enum positionDirection
{
North, West, South, East,
};
struct randomDungeonTileStruct
{
int width;
int height;
int xOffset;
int yOffset;
bool canRotate;
bool canBeOnWall;
bool randomPlace;
int rarity;
};
const int NB_RANDOM_TILES = 21;
const int NB_RANDOM_TILE_TRY = 40;
const int NB_RANDOM_TILES_IN_ROOM = 4;
/** Array with all the items and data */
const randomDungeonTileStruct randomDungeonTiles[NB_RANDOM_TILES] =
{
{ 192, 192, 0, 0, true, true, true, 1},
{ 192, 192, 192, 0, true, true, true, 1},
{ 192, 192, 384, 0, true, true, true, 1},
{ 192, 192, 576, 0, true, true, true, 1},
{ 256, 256, 0, 192, true, true, true, 1},
{ 512, 256, 256, 192, true, true, true, 1},
{ 128, 128, 0, 448, true, false, true, 6},
{ 128, 128, 128, 448, true, false, true, 3},
{ 128, 128, 256, 448, true, false, true, 3},
{ 128, 128, 384, 448, false, false, false, 1},
{ 128, 128, 512, 448, false, false, false, 6},
{ 128, 128, 640, 448, false, false, false, 6},
{ 192, 192, 0, 576, true, true, true, 1},
{ 192, 192, 192, 576, true, true, true, 1},
{ 192, 192, 384, 576, true, true, true , 1},
{ 192, 192, 576, 576, true, true, true, 1},
{ 256, 256, 0, 768, true, true, true, 1},
{ 256, 256, 256, 768, true, true, true, 1},
{ 256, 192, 768, 0, true, true, true, 1},
{ 256, 192, 768, 192, true, true, true, 1},
{ 256, 192, 768, 384, true, true, true, 1},
};
class DungeonMap : public GameMap
{
public:
DungeonMap(int width, int height);
DungeonMap(GameFloor* gameFloor, int x, int y);
virtual ~DungeonMap();
void displayToConsole();
bool isVisited();
void setVisited(bool b);
bool isKnown();
void setKnown(bool b);
+ bool isRevealed();
+ void setRevealed(bool b);
bool isCleared();
void setCleared(bool b);
bool isWalkable(int x, int y);
bool isFlyable(int x, int y);
bool isShootable(int x, int y);
int getObjectTile(int x, int y);
logicalMapStateEnum getLogicalTile(int x, int y);
void setObjectTile(int x, int y, int n);
void setLogicalTile(int x, int y, logicalMapStateEnum state);
int getDivinity(int x, int y);
bool containsHealth();
roomTypeEnum getNeighbourLeft();
roomTypeEnum getNeighbourRight();
roomTypeEnum getNeighbourUp();
roomTypeEnum getNeighbourDown();
// 0 == no, 1 == yes, 2 == boss
int hasNeighbourLeft();
int hasNeighbourRight();
int hasNeighbourUp();
int hasNeighbourDown();
+ bool hasKnownNeighbour(int direction, bool mustBeRevealed);
+
virtual bool isDownBlocking(int x, int y);
virtual bool isUpBlocking(int x, int y);
virtual bool isLeftBlocking(int x, int y);
virtual bool isRightBlocking(int x, int y);
doorEnum getDoorType(int direction);
void setDoorType(int direction, doorEnum type);
virtual void randomize(int n);
void initRoom(int floorN = -1, int wallN = -1);
enum patternEnum { PatternSmallChecker, PatternBigChecker, PatternBorder, PatternBigCircle, PatternSmallCircle, PatternSmallStar, PatternSmallDisc};
void initPattern(patternEnum n);
void generateCarpet(int x0, int y0, int w, int h, int n);
void generateTable(int x0, int y0, int w, int h, int n);
void generateLongObject(int x0, int y0, int w, int n);
void generateRoomRandom(int type);
void generateRoomWithoutHoles(int type);
void generateRoomWithHoles(int type);
void generateExitRoom();
Vector2D generateBonusRoom();
Vector2D generateChestRoom();
Vector2D generateMerchantRoom();
Vector2D generateKeyRoom();
void generateTemple(int x, int y, enumDivinityType type);
void generateTempleRoom();
void generateInselRoom();
void addRandomGrids(int n);
void addItem(int itemType, float x, float y, bool merch);
void addSprite(int spriteType, int frame, float x, float y, float scale);
void addChest(int chestType, bool state, float x, float y);
void restoreMapObjects();
void cleanMapObjects();
roomTypeEnum getRoomType();
void setRoomType(roomTypeEnum roomType);
struct itemListElement { int type; float x; float y; bool merch; };
typedef std::list<itemListElement> ItemList;
struct spriteListElement { int type; int frame; float x; float y; float scale;};
typedef std::list<spriteListElement> SpriteList;
struct chestListElement { int type; bool state; float x; float y;};
typedef std::list<chestListElement> ChestList;
std::list<itemListElement> getItemList();
std::list<chestListElement> getChestList();
std::list<spriteListElement> getSpriteList();
struct RandomTileElement { int type; float x; float y; float rotation;};
RandomTileElement getRandomTileElement(int n);
void setRandomTileElement (int n, RandomTileElement rt);
void openDoor(int x, int y);
void closeDoor(int x, int y);
bool isDoor(int x, int y);
int getFloorOffset();
int getWallType();
void setFloorOffset(int n);
void setWallType(int n);
+ bool callRevelation();
+
protected:
private:
GameFloor* gameFloor;
int x, y;
bool visited;
bool known;
+ bool revealed;
bool cleared;
int objectsMap[MAP_WIDTH][MAP_HEIGHT];
logicalMapStateEnum logicalMap[MAP_WIDTH][MAP_HEIGHT];
roomTypeEnum roomType;
ItemList itemList;
SpriteList spriteList;
ChestList chestList;
RandomTileElement randomTileElements[NB_RANDOM_TILES_IN_ROOM];
void generateCorridors();
void generateRandomTile(int index);
void generateRandomTiles();
void restoreItems();
void restoreSprites();
void restoreChests();
void makePatternTile(int x, int y);
void addHole(int x, int y);
int floorOffset;
int wallType;
doorEnum doorType[4];
};
#endif // MAGICMAP_H
diff --git a/src/DungeonMapEntity.cpp b/src/DungeonMapEntity.cpp
index 57cb4ac..893cfcb 100644
--- a/src/DungeonMapEntity.cpp
+++ b/src/DungeonMapEntity.cpp
@@ -1,1219 +1,1219 @@
#include <iostream>
#include <sstream>
#include "WitchBlastGame.h"
#include "DungeonMapEntity.h"
#include "Constants.h"
#include "sfml_game/ImageManager.h"
DungeonMapEntity::DungeonMapEntity() : GameEntity (0.0f, 0.0f)
{
this->z = -1.0f;
type = 0;
hasChanged = true;
DungeonMapEntityPost* post = new DungeonMapEntityPost(this);
post->setZ(-0.2f);
post->setType(0);
DungeonMapEntityOverlay* over = new DungeonMapEntityOverlay(this);
over->setZ(1000);
over->setType(0);
overlaySprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_OVERLAY));
roomType = roomTypeStarting;
keyRoomEffect.delay = -1.0f;
for (int i = 0; i < NB_RANDOM_TILES_IN_ROOM; i++)
randomSprite[i].setTexture(*ImageManager::getInstance().getImage(IMAGE_RANDOM_DUNGEON));
shadowType = ShadowTypeStandard;
// doors fixed parts
for (int i = 0; i < 4; i++)
{
doorFrame[i].setTexture(*ImageManager::getInstance().getImage(IMAGE_DOORS));
doorFrame[i].setOrigin(96, 32);
isDoorFrame[i] = false;
doorShadow[i].setTexture(*ImageManager::getInstance().getImage(IMAGE_TILES));
doorShadow[i].setTextureRect(sf::IntRect(DOOR_SHADOW_SPRITE_X, DOOR_SHADOW_SPRITE_Y, 192, 64));
doorShadow[i].setOrigin(96, 32);
isDoorShadow[i] = false;
doorWall[i].setTexture(*ImageManager::getInstance().getImage(IMAGE_TILES));
doorWall[i].setOrigin(96, 32);
isDoorWall[i] = false;
doorKeyStone[i].setTexture(*ImageManager::getInstance().getImage(IMAGE_DOORS));
doorKeyStone[i].setOrigin(96, 32);
isDoorKeyStone[i] = false;
}
doorSpecial.setTexture(*ImageManager::getInstance().getImage(IMAGE_TILES));
doorSpecial.setOrigin(96, 32);
isDoorSpecial = false;
doorFrame[North].setPosition(TILE_WIDTH * MAP_WIDTH / 2, TILE_HEIGHT / 2);
doorShadow[North].setPosition(TILE_WIDTH * MAP_WIDTH / 2, TILE_HEIGHT / 2);
doorKeyStone[North].setPosition(TILE_WIDTH * MAP_WIDTH / 2, TILE_HEIGHT / 2);
doorWall[North].setPosition(TILE_WIDTH * MAP_WIDTH / 2, TILE_HEIGHT / 2);
doorFrame[South].setPosition(TILE_WIDTH * MAP_WIDTH / 2, TILE_HEIGHT * MAP_HEIGHT - TILE_HEIGHT / 2);
doorShadow[South].setPosition(TILE_WIDTH * MAP_WIDTH / 2, TILE_HEIGHT * MAP_HEIGHT - TILE_HEIGHT / 2);
doorKeyStone[South].setPosition(TILE_WIDTH * MAP_WIDTH / 2, TILE_HEIGHT * MAP_HEIGHT - TILE_HEIGHT / 2);
doorWall[South].setPosition(TILE_WIDTH * MAP_WIDTH / 2, TILE_HEIGHT * MAP_HEIGHT - TILE_HEIGHT / 2);
doorFrame[South].setRotation(180);
doorShadow[South].setRotation(180);
doorKeyStone[South].setRotation(180);
doorWall[South].setRotation(180);
doorFrame[West].setPosition(TILE_WIDTH / 2, TILE_HEIGHT * MAP_HEIGHT / 2);
doorShadow[West].setPosition(TILE_WIDTH / 2, TILE_HEIGHT * MAP_HEIGHT / 2);
doorKeyStone[West].setPosition(TILE_WIDTH / 2, TILE_HEIGHT * MAP_HEIGHT / 2);
doorWall[West].setPosition(TILE_WIDTH / 2, TILE_HEIGHT * MAP_HEIGHT / 2);
doorFrame[West].setRotation(270);
doorShadow[West].setRotation(270);
doorKeyStone[West].setRotation(270);
doorWall[West].setRotation(270);
doorFrame[East].setPosition(TILE_WIDTH * MAP_WIDTH - TILE_WIDTH / 2, TILE_HEIGHT * MAP_HEIGHT / 2);
doorShadow[East].setPosition(TILE_WIDTH * MAP_WIDTH - TILE_WIDTH / 2, TILE_HEIGHT * MAP_HEIGHT / 2);
doorKeyStone[East].setPosition(TILE_WIDTH * MAP_WIDTH - TILE_WIDTH / 2, TILE_HEIGHT * MAP_HEIGHT / 2);
doorWall[East].setPosition(TILE_WIDTH * MAP_WIDTH - TILE_WIDTH / 2, TILE_HEIGHT * MAP_HEIGHT / 2);
doorFrame[East].setRotation(90);
doorShadow[East].setRotation(90);
doorKeyStone[East].setRotation(90);
doorWall[East].setRotation(90);
}
void DungeonMapEntity::animate(float delay)
{
age += delay;
bool needCompute = getChanged() || game().getCurrentMap()->getChanged();
if (needCompute)
{
computeVertices();
computeOverVertices();
computeShadowVertices();
computeDoors();
}
// blood
bool moving = false;
for (unsigned int i = 0; i < blood.size(); i++)
{
if (blood[i].moving)
{
moving = true;
if (checkFalling(blood[i], 16, 16))
{
SpriteEntity* spriteEntity
= new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_BLOOD),
blood[i].x + 8,
blood[i].y + 8,
16, 16, 6);
spriteEntity->setAge(0.0f);
spriteEntity->setLifetime(3.0f);
spriteEntity->setShrinking(true);
spriteEntity->setFading(true);
spriteEntity->setFrame(blood[i].frame);
spriteEntity->setScale(blood[i].scale, blood[i].scale);
blood.erase(blood.begin() + i);
}
else if (blood[i].frame >= BaseCreatureEntity::BloodBarrel * 6
&& blood[i].frame < BaseCreatureEntity::BloodBarrelPowder * 6 + 6
&& collideWithWall(blood[i], 16, 16, true))
{
blood[i].moving = false;
blood[i].velocity.x = 0.0f;
blood[i].velocity.y = 0.0f;
}
else
{
animateParticle(blood[i], delay, 0.95f);
if ((game().getParameters().bloodSpread && ((blood[i].frame < 12) || blood[i].frame >= 36) && blood[i].frame < 42))
{
if (blood[i].velocity.x * blood[i].velocity.x + blood[i].velocity.y * blood[i].velocity.y > 80
&& rand() % 4 == 0)
{
addBlood(blood[i].x, blood[i].y, blood[i].frame, blood[i].scale);
blood[i].scale *= 0.85f;
bool xPos = blood[i].velocity.x > 0;
bool yPos = blood[i].velocity.y > 0;
float norm = sqrtf(blood[i].velocity.x * blood[i].velocity.x + blood[i].velocity.y * blood[i].velocity.y);
blood[i].velocity = Vector2D(norm);
if (xPos && blood[i].velocity.x < 0) blood[i].velocity.x = - blood[i].velocity.x;
else if (!xPos && blood[i].velocity.x > 0) blood[i].velocity.x = - blood[i].velocity.x;
if (yPos && blood[i].velocity.y < 0) blood[i].velocity.y = - blood[i].velocity.y;
else if (!yPos && blood[i].velocity.y > 0) blood[i].velocity.y = - blood[i].velocity.y;
}
}
}
}
}
if (moving) computeBloodVertices();
// corpses
int CorpsesBox = 38, CorpsesLargeBox = 76;
moving = false;
for (unsigned int i = 0; i < corpses.size(); i++)
{
if (corpses[i].moving)
{
moving = true;
if (corpses[i].frame != FRAME_CORPSE_SLIME_VIOLET
&& collideWithWall(corpses[i], CorpsesBox, CorpsesBox))
{
if (checkFalling(corpses[i], 48, 48))
{
SpriteEntity* spriteEntity
= new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_CORPSES),
corpses[i].x,
corpses[i].y,
64, 64, 10);
spriteEntity->setAge(0.0f);
spriteEntity->setLifetime(3.0f);
spriteEntity->setShrinking(true);
spriteEntity->setFading(true);
spriteEntity->setFrame(corpses[i].frame);
corpses.erase(corpses.begin() + i);
}
else
{
if (corpses[i].velocity.x < 15.0f && corpses[i].velocity.x > -15.0f
&& corpses[i].velocity.y < 15.0f && corpses[i].velocity.y > -15.0f)
autoSpeed(corpses[i], 200);
animateParticle(corpses[i], delay, 1.0f);
}
}
else
{
float oldx = corpses[i].x;
float oldy = corpses[i].y;
animateParticle(corpses[i], delay, 0.8f);
if (corpses[i].frame != FRAME_CORPSE_SLIME_VIOLET
&& collideWithWall(corpses[i], CorpsesBox, CorpsesBox))
{
corpses[i].x = oldx;
corpses[i].y = oldy;
moving = false;
}
}
}
}
for (unsigned int i = 0; i < corpsesLarge.size(); i++)
{
if (corpsesLarge[i].moving)
{
moving = true;
if (collideWithWall(corpsesLarge[i], CorpsesLargeBox, CorpsesLargeBox))
{
if (corpsesLarge[i].velocity.x < 15.0f && corpsesLarge[i].velocity.x > -15.0f
&& corpsesLarge[i].velocity.y < 15.0f && corpsesLarge[i].velocity.y > -15.0f)
autoSpeed(corpsesLarge[i], 200);
animateParticle(corpsesLarge[i], delay, 1.0f);
}
else
{
float oldx = corpsesLarge[i].x;
float oldy = corpsesLarge[i].y;
animateParticle(corpsesLarge[i], delay, 0.8f);
if (collideWithWall(corpsesLarge[i], CorpsesLargeBox, CorpsesLargeBox))
{
corpsesLarge[i].x = oldx;
corpsesLarge[i].y = oldy;
moving = false;
}
}
}
}
for (unsigned int i = 0; i < corpsesLarge.size(); i++)
{
if (corpsesLarge[i].moving)
{
moving = true;
animateParticle(corpsesLarge[i], delay, 0.95f);
}
}
if (moving) computeCorpsesVertices();
if (game().getCurrentMap()->getRoomType() == roomTypeKey && !game().getCurrentMap()->isCleared())
{
keyRoomEffect.delay -= delay;
if (keyRoomEffect.delay <= 0.0f)
{
keyRoomEffect.delay = KeyRoomFXDelay;
keyRoomEffect.amplitude = 120 + rand() % 100;
keyRoomEffect.isBlinking = false;
}
}
}
void DungeonMapEntity::animateParticle(displayEntityStruct &particle, float delay, float viscosity)
{
particle.velocity.x *= viscosity;
particle.velocity.y *= viscosity;
if (particle.velocity.x < -5 || particle.velocity.x > 5
|| particle.velocity.y < -5 || particle.velocity.y > 5)
{
particle.x += delay * particle.velocity.x;
particle.y += delay * particle.velocity.y;
}
else
particle.moving = false;
}
bool DungeonMapEntity::collideWithWall(displayEntityStruct &particle, int boxWidth, int boxHeight, bool canGoThroughObstacle)
{
float x0 = particle.x - boxWidth / 2;
float xf = particle.x + boxWidth / 2;
float y0 = particle.y - boxHeight / 2;
float yf = particle.y + boxHeight / 2;
if (particle.x < TILE_WIDTH && particle.velocity.x < -1.0f) particle.velocity.x = -particle.velocity.x;
else if (particle.x > TILE_WIDTH * (MAP_WIDTH - 2) && particle.velocity.x > 1.0f) particle.velocity.x = -particle.velocity.x;
if (particle.y < TILE_HEIGHT && particle.velocity.y < -1.0f) particle.velocity.y = -particle.velocity.y;
else if (particle.y > TILE_HEIGHT * (MAP_HEIGHT - 2) && particle.velocity.y > 1.0f) particle.velocity.y = -particle.velocity.y;
DungeonMap* iMap = game().getCurrentMap();
if (!canGoThroughObstacle)
{
collide[NordWest] = !iMap->isWalkable(x0 / TILE_WIDTH, y0 / TILE_HEIGHT);
collide[SudWest] = !iMap->isWalkable(x0 / TILE_WIDTH, yf / TILE_HEIGHT);
collide[NordEast] = !iMap->isWalkable(xf / TILE_WIDTH, y0 / TILE_HEIGHT);
collide[SudEast] = !iMap->isWalkable(xf / TILE_WIDTH, yf / TILE_HEIGHT);
}
else
{
collide[NordWest] = iMap->getLogicalTile(x0 / TILE_WIDTH, y0 / TILE_HEIGHT) == LogicalWall
|| iMap->getLogicalTile(x0 / TILE_WIDTH, y0 / TILE_HEIGHT) == LogicalObstacle;
collide[SudWest] = iMap->getLogicalTile(x0 / TILE_WIDTH, yf / TILE_HEIGHT) == LogicalWall
|| iMap->getLogicalTile(x0 / TILE_WIDTH, yf / TILE_HEIGHT) == LogicalObstacle;
collide[NordEast] = iMap->getLogicalTile(xf / TILE_WIDTH, y0 / TILE_HEIGHT) == LogicalWall
|| iMap->getLogicalTile(xf / TILE_WIDTH, y0 / TILE_HEIGHT) == LogicalObstacle;
collide[SudEast] = iMap->getLogicalTile(xf / TILE_WIDTH, yf / TILE_HEIGHT) == LogicalWall
|| iMap->getLogicalTile(xf / TILE_WIDTH, yf / TILE_HEIGHT) == LogicalObstacle;
}
return collide[NordWest] || collide[SudWest] || collide[NordEast] || collide[SudEast];
}
bool DungeonMapEntity::checkFalling(displayEntityStruct &particle, int boxWidth, int boxHeight)
{
int tilex = (particle.x + boxWidth / 2) / TILE_WIDTH;
int tiley = (particle.y + boxHeight / 2) / TILE_HEIGHT;
if (game().getCurrentMap()->getLogicalTile(tilex, tiley) != LogicalHole) return false;
tilex = (particle.x + boxWidth / 2 - boxWidth / 3) / TILE_WIDTH;
tiley = (particle.y + boxHeight / 2 - boxHeight / 3) / TILE_HEIGHT;
if (game().getCurrentMap()->getLogicalTile(tilex, tiley) != LogicalHole) return false;
tilex = (particle.x + boxWidth / 2 + boxWidth / 3) / TILE_WIDTH;
tiley = (particle.y + boxHeight / 2 + boxHeight / 3) / TILE_HEIGHT;
if (game().getCurrentMap()->getLogicalTile(tilex, tiley) != LogicalHole) return false;
return true;
}
void DungeonMapEntity::autoSpeed(displayEntityStruct &particle, float speed)
{
if (!collide[NordWest] && !collide[NordEast])
{
particle.velocity.x = 0;
particle.velocity.y = -speed;
}
else if (!collide[SudWest] && !collide[SudEast])
{
particle.velocity.x = 0;
particle.velocity.y = speed;
}
else if (!collide[SudWest] && !collide[NordWest])
{
particle.velocity.x = -speed;
particle.velocity.y = 0;
}
else if (!collide[SudEast] && !collide[NordEast])
{
particle.velocity.x = speed;
particle.velocity.y = 0;
}
else if (!collide[NordWest])
{
particle.velocity.x = -speed * 0.7f;
particle.velocity.y = -speed * 0.7f;
}
else if (!collide[NordEast])
{
particle.velocity.x = speed * 0.7f;
particle.velocity.y = -speed * 0.7f;
}
else if (!collide[SudWest])
{
particle.velocity.x = -speed * 0.7f;
particle.velocity.y = speed * 0.7f;
}
else if (!collide[SudEast])
{
particle.velocity.x = speed * 0.7f;
particle.velocity.y = speed * 0.7f;
}
else
particle.velocity = Vector2D(speed);
}
bool DungeonMapEntity::getChanged()
{
bool result = hasChanged;
hasChanged = false;
return result;
}
void DungeonMapEntity::render(sf::RenderTarget* app)
{
app->draw(vertices, ImageManager::getInstance().getImage(IMAGE_TILES));
// doors
renderDoors(app);
// random tile
for (int i = 0; i < NB_RANDOM_TILES_IN_ROOM; i++)
if ( game().getCurrentMap()->getRandomTileElement(i).type > -1) app->draw(randomSprite[i]);
// over tiles
app->draw(overVertices, ImageManager::getInstance().getImage(IMAGE_DUNGEON_OBJECTS));
if (game().getCurrentMap()->getRoomType() == roomTypeTemple)
{
for (int i = 1; i < MAP_WIDTH - 2 ; i++)
for (int j = 1; j < MAP_WIDTH - 2 ; j++)
if (game().getCurrentMap()->getTile(i, j) >= MAP_TEMPLE
&& game().getCurrentMap()->getTile(i, j) < MAP_TEMPLE + 10)
{
sf::Sprite tile;
tile.setTexture(*ImageManager::getInstance().getImage(IMAGE_TILES));
tile.setPosition(i * TILE_WIDTH, j * TILE_HEIGHT);
tile.setTextureRect(sf::IntRect((game().getCurrentMap()->getTile(i, j) % 24) * TILE_WIDTH,
(1 + game().getCurrentMap()->getTile(i, j) / 24) * TILE_HEIGHT,
TILE_WIDTH, TILE_HEIGHT));
int fade = 127 + 127 * (cosf(6.0f * game().getAbsolutTime()));
tile.setColor(sf::Color(255, 255, 255, fade));
app->draw(tile);
}
}
else if (game().getCurrentMap()->getRoomType() == roomTypeKey && !game().getCurrentMap()->isCleared())
{
int fade = 0;
if (keyRoomEffect.isBlinking)
{
fade = (int)(25.0f * game().getAbsolutTime()) % 2 == 0 ? 0 : 255;
}
else
{
if (keyRoomEffect.delay > KeyRoomFXDelay / 2)
fade = keyRoomEffect.amplitude - keyRoomEffect.amplitude * (keyRoomEffect.delay - KeyRoomFXDelay / 2) / KeyRoomFXDelay * 2;
else
fade = keyRoomEffect.amplitude - keyRoomEffect.amplitude * (KeyRoomFXDelay / 2 - keyRoomEffect.delay) / KeyRoomFXDelay * 2;
}
sf::Sprite tiles;
tiles.setTexture(*ImageManager::getInstance().getImage(IMAGE_KEY_AREA));
tiles.setPosition((MAP_WIDTH / 2 - 1) * TILE_WIDTH, (MAP_HEIGHT / 2 - 1) * TILE_HEIGHT);
tiles.setTextureRect(sf::IntRect(0, 0, 3 * TILE_WIDTH, 3 * TILE_HEIGHT));
app->draw(tiles);
tiles.setColor(sf::Color(255, 255, 255, fade));
tiles.setTextureRect(sf::IntRect(3 * TILE_WIDTH, 0, 3 * TILE_WIDTH, 3 * TILE_HEIGHT));
app->draw(tiles);
}
}
void DungeonMapEntity::renderKeyStone(sf::RenderTarget* app)
{
for (int i = 0; i < 4; i++)
if (isDoorKeyStone[i]) app->draw(doorKeyStone[i]);
}
void DungeonMapEntity::computeDoors()
{
DungeonMap* currentMap = game().getCurrentMap();
- if (currentMap->hasNeighbourUp() || currentMap->getRoomType() == roomTypeExit)
+ if (currentMap->hasKnownNeighbour(North, true) || currentMap->getRoomType() == roomTypeExit)
{
isDoorShadow[North] = true;
doorWall[North].setTextureRect(sf::IntRect(DOOR_WALL_SPRITE_X, currentMap->getWallType() * 64 + DOOR_WALL_SPRITE_Y, 192, 64));
isDoorWall[North] = true;
doorFrame[North].setTextureRect(sf::IntRect(64 + 256 * (currentMap->getDoorType(North) / DOORS_PRO_COLUMN),
64 + 192 * (currentMap->getDoorType(North) % DOORS_PRO_COLUMN),
192, 64));
isDoorFrame[North] = true;
doorKeyStone[North].setTextureRect(sf::IntRect(64 + 256 * (currentMap->getDoorType(North) / DOORS_PRO_COLUMN),
128 + 192 * (currentMap->getDoorType(North) % DOORS_PRO_COLUMN),
192, 64));
isDoorKeyStone[North] = true;
}
else
{
isDoorShadow[North] = false;
isDoorWall[North] = false;
isDoorFrame[North] = false;
isDoorKeyStone[North] = false;
}
- if (currentMap->hasNeighbourDown() || (game().getLevel() > 1 &&currentMap->getRoomType() == roomTypeStarting))
+ if (currentMap->hasKnownNeighbour(South, true) || ( (game().getLevel() > 1 && currentMap->getRoomType() == roomTypeStarting)))
{
isDoorShadow[South] = true;
doorWall[South].setTextureRect(sf::IntRect(DOOR_WALL_SPRITE_X, currentMap->getWallType() * 64 + DOOR_WALL_SPRITE_Y, 192, 64));
isDoorWall[South] = true;
doorFrame[South].setTextureRect(sf::IntRect(64 + 256 * (currentMap->getDoorType(South) / DOORS_PRO_COLUMN),
64 + 192 * (currentMap->getDoorType(South) % DOORS_PRO_COLUMN),
192, 64));
isDoorFrame[South] = true;
doorKeyStone[South].setTextureRect(sf::IntRect(64 + 256 * (currentMap->getDoorType(South) / DOORS_PRO_COLUMN),
128 + 192 * (currentMap->getDoorType(South) % DOORS_PRO_COLUMN),
192, 64));
isDoorKeyStone[South] = true;
}
else
{
isDoorShadow[South] = false;
isDoorWall[South] = false;
isDoorFrame[South] = false;
isDoorKeyStone[South] = false;
}
- if (currentMap->hasNeighbourLeft())
+ if (currentMap->hasKnownNeighbour(West, true))
{
isDoorShadow[West] = true;
doorWall[West].setTextureRect(sf::IntRect(DOOR_WALL_SPRITE_X, currentMap->getWallType() * 64 + DOOR_WALL_SPRITE_Y, 192, 64));
isDoorWall[West] = true;
doorFrame[West].setTextureRect(sf::IntRect(64 + 256 * (currentMap->getDoorType(West) / DOORS_PRO_COLUMN),
64 + 192 * (currentMap->getDoorType(West) % DOORS_PRO_COLUMN),
192, 64));
isDoorFrame[West] = true;
doorKeyStone[West].setTextureRect(sf::IntRect(64 + 256 * (currentMap->getDoorType(West) / DOORS_PRO_COLUMN),
128 + 192 * (currentMap->getDoorType(West) % DOORS_PRO_COLUMN),
192, 64));
isDoorKeyStone[West] = true;
}
else
{
isDoorShadow[West] = false;
isDoorWall[West] = false;
isDoorFrame[West] = false;
isDoorKeyStone[West] = false;
}
- if (currentMap->hasNeighbourRight())
+ if (currentMap->hasKnownNeighbour(East, true))
{
isDoorShadow[East] = true;
doorWall[East].setTextureRect(sf::IntRect(DOOR_WALL_SPRITE_X, currentMap->getWallType() * 64 + DOOR_WALL_SPRITE_Y, 192, 64));
isDoorWall[East] = true;
doorFrame[East].setTextureRect(sf::IntRect(64 + 256 * (currentMap->getDoorType(East) / DOORS_PRO_COLUMN),
64 + 192 * (currentMap->getDoorType(East) % DOORS_PRO_COLUMN), 192, 64));
isDoorFrame[East] = true;
doorKeyStone[East].setTextureRect(sf::IntRect(64 + 256 * (currentMap->getDoorType(East) / DOORS_PRO_COLUMN),
128 + 192 * (currentMap->getDoorType(East) % DOORS_PRO_COLUMN), 192, 64));
isDoorKeyStone[East] = true;
}
else
{
isDoorShadow[East] = false;
isDoorWall[East] = false;
isDoorFrame[East] = false;
isDoorKeyStone[East] = false;
}
if (currentMap->getRoomType() == roomTypeExit)
{
isDoorSpecial = true;
doorSpecial.setPosition(TILE_WIDTH * MAP_WIDTH / 2, TILE_HEIGHT / 2);
doorSpecial.setTextureRect(sf::IntRect(DOOR_STAIRS_SPRITE_X, DOOR_STAIRS_SPRITE_Y, 192, 64));
}
else if (game().getLevel() > 1 && currentMap->getRoomType() == roomTypeStarting)
{
isDoorSpecial = true;
doorSpecial.setPosition(TILE_WIDTH * MAP_WIDTH / 2, TILE_HEIGHT * MAP_HEIGHT - TILE_HEIGHT / 2);
doorSpecial.setTextureRect(sf::IntRect(DOOR_GRID_SPRITE_X, DOOR_GRID_SPRITE_Y, 192, 64));
}
else
isDoorSpecial = false;
}
void DungeonMapEntity::renderDoors(sf::RenderTarget* app)
{
// fading from doors
for (int i = 0; i < 4; i++)
if (isDoorShadow[i]) app->draw(doorShadow[i]);
// doors
game().renderDoors();
if (isDoorSpecial) app->draw(doorSpecial);
// walls around doors
for (int i = 0; i < 4; i++)
if (isDoorWall[i]) app->draw(doorWall[i]);
// frames
for (int i = 0; i < 4; i++)
if (isDoorFrame[i]) app->draw(doorFrame[i]);
}
void DungeonMapEntity::renderPost(sf::RenderTarget* app)
{
displayBlood(app);
displayCorpses(app);
switch (shadowType)
{
case ShadowTypeStandard:
app->draw(shadowVertices, ImageManager::getInstance().getImage(IMAGE_TILES_SHADOW));
break;
case ShadowTypeCorner:
app->draw(shadowVertices, ImageManager::getInstance().getImage(IMAGE_TILES_SHADOW_CORNER));
break;
case ShadowTypeSmall:
app->draw(shadowVertices, ImageManager::getInstance().getImage(IMAGE_TILES_SHADOW_SMALL));
break;
case ShadowTypeMedium:
app->draw(shadowVertices, ImageManager::getInstance().getImage(IMAGE_TILES_SHADOW_MEDIUM));
break;
}
}
void DungeonMapEntity::renderOverlay(sf::RenderTarget* app)
{
renderKeyStone(app);
app->draw(overlaySprite);
}
std::vector <displayEntityStruct> DungeonMapEntity::getBlood()
{
return blood;
}
std::vector <displayEntityStruct> DungeonMapEntity::getCorpses()
{
auto result = corpses;
result.insert( result.end(), corpsesLarge.begin(), corpsesLarge.end() );
return result;
}
void DungeonMapEntity::displayBlood(sf::RenderTarget* app)
{
app->draw(bloodVertices, ImageManager::getInstance().getImage(IMAGE_BLOOD));
}
void DungeonMapEntity::displayCorpses(sf::RenderTarget* app)
{
app->draw(corpsesVertices, ImageManager::getInstance().getImage(IMAGE_CORPSES));
app->draw(corpsesLargeVertices, ImageManager::getInstance().getImage(IMAGE_CORPSES_BIG));
}
void DungeonMapEntity::refreshMap()
{
hasChanged = true;
blood.clear();
corpses.clear();
corpsesLarge.clear();
computeBloodVertices();
computeCorpsesVertices();
}
bool DungeonMapEntity::shouldBeTransformed(int part)
{
part -= game().getCurrentMap()->getWallType() * 24;
if (part >= MAP_WALL_8 && part < MAP_WALL_8 + 24) return true;
else return false;
}
void DungeonMapEntity::computeVertices()
{
DungeonMap* gameMap = game().getCurrentMap();
int tilesProLine = 24;
int tileWidth = 64;
int tileHeight = 64;
int tileBoxWidth = 64;
int tileBoxHeight = 64;
vertices.setPrimitiveType(sf::Quads);
vertices.resize(gameMap->getWidth() * gameMap->getHeight() * 4);
for (int i = 0; i < gameMap->getWidth(); i++)
for (int j = 0; j < gameMap->getHeight(); j++)
{
int nx = gameMap->getTile(i, j) % tilesProLine;
int ny = gameMap->getTile(i, j) / tilesProLine;
sf::Vertex* quad = &vertices[(i + j * gameMap->getWidth()) * 4];
if (shouldBeTransformed(gameMap->getTile(i, j)))
{
if (j == 0 && i <= MAP_WIDTH / 2)
{
quad[0].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[1].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[2].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[3].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
else if (j == 0 && i > MAP_HEIGHT / 2)
{
quad[1].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[0].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[3].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[2].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
else if (j == MAP_HEIGHT - 1 && i <= MAP_WIDTH / 2)
{
quad[3].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[2].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[1].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[0].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
else if (j == MAP_HEIGHT - 1 && i > MAP_WIDTH / 2)
{
quad[2].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[3].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[0].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[1].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
else if (i == 0 && j <= MAP_HEIGHT / 2)
{
quad[0].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[3].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[2].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[1].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
else if (i == 0 && j > MAP_HEIGHT / 2)
{
quad[1].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[2].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[3].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[0].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
else if (i == MAP_WIDTH - 1 && j <= MAP_HEIGHT / 2)
{
quad[3].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[0].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[1].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[2].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
else if (i == MAP_WIDTH - 1 && j > MAP_HEIGHT / 2)
{
quad[2].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[1].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[0].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[3].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
// corridors
else if (i < MAP_WIDTH / 2 && j <= MAP_HEIGHT / 2 && gameMap->getTile(i, j - 1) != MAP_WALL_X)
{
quad[0].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[3].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[2].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[1].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
else if (i < MAP_WIDTH / 2 && j > MAP_HEIGHT / 2 && gameMap->getTile(i, j + 1) != MAP_WALL_X)
{
quad[1].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[2].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[3].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[0].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
else if (i > MAP_WIDTH / 2 && j <= MAP_HEIGHT / 2 && gameMap->getTile(i, j - 1) != MAP_WALL_X)
{
quad[3].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[0].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[1].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[2].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
else if (i > MAP_WIDTH / 2 && j > MAP_HEIGHT / 2 && gameMap->getTile(i, j + 1) != MAP_WALL_X)
{
quad[2].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[1].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[0].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[3].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
else if (j < MAP_HEIGHT / 2 && i <= MAP_WIDTH / 2)
{
quad[0].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[1].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[2].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[3].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
else if (j < MAP_HEIGHT / 2 && i > MAP_HEIGHT / 2)
{
quad[1].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[0].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[3].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[2].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
else if (j > MAP_HEIGHT / 2 && i <= MAP_WIDTH / 2)
{
quad[3].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[2].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[1].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[0].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
else if (j > MAP_HEIGHT / 2 && i > MAP_WIDTH / 2)
{
quad[2].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[3].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[0].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[1].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
}
else
{
quad[0].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[1].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[2].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[3].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
quad[0].texCoords = sf::Vector2f(nx * tileBoxWidth, ny * tileBoxHeight);
quad[1].texCoords = sf::Vector2f((nx + 1) * tileBoxWidth, ny * tileBoxHeight);
quad[2].texCoords = sf::Vector2f((nx + 1) * tileBoxWidth, (ny + 1) * tileBoxHeight);
quad[3].texCoords = sf::Vector2f(nx * tileBoxWidth, (ny + 1) * tileBoxHeight);
}
//if (roomType != game().getCurrentMap()->getRoomType())
{
std::stringstream ss;
roomType = game().getCurrentMap()->getRoomType();
switch (roomType)
{
case roomTypeChallenge:
ImageManager::getInstance().getImage(IMAGE_OVERLAY)->loadFromFile("media/overlay_boss_01.png");
break;
case roomTypeTemple:
ImageManager::getInstance().getImage(IMAGE_OVERLAY)->loadFromFile("media/overlay_temple.png");
break;
case roomTypeMerchant:
ImageManager::getInstance().getImage(IMAGE_OVERLAY)->loadFromFile("media/overlay_shop.png");
break;
case roomTypeBoss:
ss << "media/overlay_boss_0" << game().getLevel() << ".png";
ImageManager::getInstance().getImage(IMAGE_OVERLAY)->loadFromFile(ss.str());
break;
default:
if ( gameMap->getObjectTile(6, 2) == MAPOBJ_BANK_TOP
|| gameMap->getObjectTile(6, 2) == MAPOBJ_BANK
|| gameMap->getObjectTile(6, 2) == MAPOBJ_BANK_BOTTOM
|| gameMap->getObjectTile(8, 2) == MAPOBJ_BANK_TOP
|| gameMap->getObjectTile(8, 2) == MAPOBJ_BANK
|| gameMap->getObjectTile(8, 2) == MAPOBJ_BANK_BOTTOM
)
ImageManager::getInstance().getImage(IMAGE_OVERLAY)->loadFromFile("media/overlay_temple.png");
else
ImageManager::getInstance().getImage(IMAGE_OVERLAY)->loadFromFile("media/overlay_00.png");
break;
}
overlaySprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_OVERLAY));
}
for (int i = 0; i < NB_RANDOM_TILES_IN_ROOM; i++)
{
int n = game().getCurrentMap()->getRandomTileElement(i).type;
if ( n > -1)
{
randomSprite[i].setPosition(game().getCurrentMap()->getRandomTileElement(i).x + randomDungeonTiles[n].width / 2,
game().getCurrentMap()->getRandomTileElement(i).y + randomDungeonTiles[n].height / 2);
randomSprite[i].setOrigin(randomDungeonTiles[n].width / 2, randomDungeonTiles[n].height / 2);
randomSprite[i].setTextureRect(sf::IntRect(randomDungeonTiles[n].xOffset, randomDungeonTiles[n].yOffset, randomDungeonTiles[n].width, randomDungeonTiles[n].height));
randomSprite[i].setRotation(game().getCurrentMap()->getRandomTileElement(i).rotation);
}
}
}
void DungeonMapEntity::computeOverVertices()
{
DungeonMap* gameMap = game().getCurrentMap();
int tilesProLine = 10;
int tileWidth = 64;
int tileHeight = 64;
int tileBoxWidth = 64;
int tileBoxHeight = 64;
overVertices.setPrimitiveType(sf::Quads);
overVertices.resize(gameMap->getWidth() * gameMap->getHeight() * 4);
for (int i = 0; i < gameMap->getWidth(); i++)
for (int j = 0; j < gameMap->getHeight(); j++)
{
//if (gameMap->getObjectTile(i, j) > 2)
{
int nx = gameMap->getObjectTile(i, j) % tilesProLine;
int ny = gameMap->getObjectTile(i, j) / tilesProLine;
if (gameMap->getObjectTile(i, j) >= MAPOBJ_BARREL)
{
nx = 0;
ny = 0;
}
sf::Vertex* quad = &overVertices[(i + j * gameMap->getWidth()) * 4];
{
quad[0].position = sf::Vector2f(x + i * tileWidth, y + j * tileHeight);
quad[1].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + j * tileHeight);
quad[2].position = sf::Vector2f(x + (i + 1) * tileWidth + (tileBoxWidth -tileWidth), y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
quad[3].position = sf::Vector2f(x + i * tileWidth, y + (j + 1) * tileHeight + (tileBoxHeight - tileHeight));
}
quad[0].texCoords = sf::Vector2f(nx * tileBoxWidth, ny * tileBoxHeight);
quad[1].texCoords = sf::Vector2f((nx + 1) * tileBoxWidth, ny * tileBoxHeight);
quad[2].texCoords = sf::Vector2f((nx + 1) * tileBoxWidth, (ny + 1) * tileBoxHeight);
quad[3].texCoords = sf::Vector2f(nx * tileBoxWidth, (ny + 1) * tileBoxHeight);
}
}
}
void DungeonMapEntity::computeShadowVertices()
{
DungeonMap* gameMap = game().getCurrentMap();
int tileWidth = 64;
int tileHeight = 64;
int tileBoxWidth = 64;
int tileBoxHeight = 64;
int x0 = 0;
int y0 = 0;
int xf = MAP_WIDTH - 1;
int yf = MAP_HEIGHT - 1;
int xd = 4;
int yd = 4;
if (gameMap->getLogicalTile(1, 1) == LogicalWall
&& gameMap->getLogicalTile(2, 1) != LogicalWall
&& gameMap->getLogicalTile(1, 2) != LogicalWall)
{
// corner
shadowType = ShadowTypeCorner;
}
else
{
x0 = MAP_WIDTH / 2;
while (gameMap->getLogicalTile(x0, MAP_HEIGHT / 2 + 1) != LogicalWall) x0--;
xf = MAP_WIDTH / 2;
while (gameMap->getLogicalTile(xf, MAP_HEIGHT / 2 + 1) != LogicalWall) xf++;
y0 = MAP_HEIGHT / 2;
while (gameMap->getLogicalTile(MAP_WIDTH / 2 + 1, y0) != LogicalWall) y0--;
yf = MAP_HEIGHT / 2;
while (gameMap->getLogicalTile(MAP_WIDTH / 2 + 1, yf) != LogicalWall) yf++;
if (yf - y0 <= 4)
{
shadowType = ShadowTypeSmall;
xd = 3;
yd = 2;
}
else if (yf - y0 <= 6 || xf - x0 <= 6)
{
shadowType = ShadowTypeMedium;
xd = 3;
yd = 3;
}
else
{
shadowType = ShadowTypeStandard;
}
}
shadowVertices.setPrimitiveType(sf::Quads);
shadowVertices.resize(8 * 4);
int xm0 = x0 + xd;
int xmf = xf - xd;
int ym0 = y0 + yd;
int ymf = yf - yd;
// top left
{
sf::Vertex* quad = &shadowVertices[0 * 4];
quad[0].position = sf::Vector2f(x0 * tileWidth, y0 * tileHeight);
quad[1].position = sf::Vector2f((x0 + xd)* tileWidth, y0 * tileHeight);
quad[2].position = sf::Vector2f((x0 + xd) * tileWidth, (y0 + yd) * tileHeight);
quad[3].position = sf::Vector2f(x0 * tileWidth, (y0 + yd) * tileHeight);
quad[0].texCoords = sf::Vector2f(0 * tileBoxWidth, 0 * tileBoxHeight);
quad[1].texCoords = sf::Vector2f(xd * tileBoxWidth, 0 * tileBoxHeight);
quad[2].texCoords = sf::Vector2f(xd * tileBoxWidth, yd * tileBoxHeight);
quad[3].texCoords = sf::Vector2f(0 * tileBoxWidth, yd * tileBoxHeight);
}
// top
{
sf::Vertex* quad = &shadowVertices[1 * 4];
quad[0].position = sf::Vector2f(xm0 * tileWidth, y0 * tileHeight);
quad[1].position = sf::Vector2f((xmf + 1)* tileWidth, y0 * tileHeight);
quad[2].position = sf::Vector2f((xmf + 1) * tileWidth, (y0 + yd) * tileHeight);
quad[3].position = sf::Vector2f(xm0 * tileWidth, (y0 + yd) * tileHeight);
quad[0].texCoords = sf::Vector2f(xd * tileBoxWidth, 0 * tileBoxHeight);
quad[1].texCoords = sf::Vector2f((xd + 1) * tileBoxWidth, 0 * tileBoxHeight);
quad[2].texCoords = sf::Vector2f((xd + 1) * tileBoxWidth, yd * tileBoxHeight);
quad[3].texCoords = sf::Vector2f(xd * tileBoxWidth, yd * tileBoxHeight);
}
// top right
{
sf::Vertex* quad = &shadowVertices[2 * 4];
quad[0].position = sf::Vector2f((xf - xd + 1) * tileWidth, y0 * tileHeight);
quad[1].position = sf::Vector2f((xf + 1)* tileWidth, y0 * tileHeight);
quad[2].position = sf::Vector2f((xf + 1) * tileWidth, (y0 + yd) * tileHeight);
quad[3].position = sf::Vector2f((xf - xd + 1) * tileWidth, (y0 + yd) * tileHeight);
quad[0].texCoords = sf::Vector2f((xd + 1) * tileBoxWidth, 0 * tileBoxHeight);
quad[1].texCoords = sf::Vector2f((xd + xd + 1) * tileBoxWidth, 0 * tileBoxHeight);
quad[2].texCoords = sf::Vector2f((xd + xd + 1) * tileBoxWidth, yd * tileBoxHeight);
quad[3].texCoords = sf::Vector2f((xd + 1) * tileBoxWidth, yd * tileBoxHeight);
}
// left
{
sf::Vertex* quad = &shadowVertices[3 * 4];
quad[0].position = sf::Vector2f(x0 * tileWidth, ym0 * tileHeight);
quad[1].position = sf::Vector2f((x0 + xd) * tileWidth, ym0 * tileHeight);
quad[2].position = sf::Vector2f((x0 + xd) * tileWidth, (ymf + 1) * tileHeight);
quad[3].position = sf::Vector2f(x0 * tileWidth, (ymf + 1) * tileHeight);
quad[0].texCoords = sf::Vector2f(0 * tileBoxWidth, yd * tileBoxHeight);
quad[1].texCoords = sf::Vector2f(xd * tileBoxWidth, yd * tileBoxHeight);
quad[2].texCoords = sf::Vector2f(xd * tileBoxWidth, (yd + 1) * tileBoxHeight);
quad[3].texCoords = sf::Vector2f(0 * tileBoxWidth, (yd + 1) * tileBoxHeight);
}
// right
{
sf::Vertex* quad = &shadowVertices[4 * 4];
quad[0].position = sf::Vector2f((xf - xd + 1) * tileWidth, ym0 * tileHeight);
quad[1].position = sf::Vector2f((xf + 1) * tileWidth, ym0 * tileHeight);
quad[2].position = sf::Vector2f((xf + 1) * tileWidth, (ymf + 1) * tileHeight);
quad[3].position = sf::Vector2f((xf - xd + 1) * tileWidth, (ymf + 1) * tileHeight);
quad[0].texCoords = sf::Vector2f((xd + 1) * tileBoxWidth, yd * tileBoxHeight);
quad[1].texCoords = sf::Vector2f((xd + xd + 1) * tileBoxWidth, yd * tileBoxHeight);
quad[2].texCoords = sf::Vector2f((xd + xd + 1) * tileBoxWidth, (yd + 1) * tileBoxHeight);
quad[3].texCoords = sf::Vector2f((xd + 1) * tileBoxWidth, (yd + 1) * tileBoxHeight);
}
// bottom left
{
sf::Vertex* quad = &shadowVertices[5 * 4];
quad[0].position = sf::Vector2f(x0 * tileWidth, (yf - yd + 1) * tileHeight);
quad[1].position = sf::Vector2f((x0 + xd)* tileWidth, (yf - yd + 1) * tileHeight);
quad[2].position = sf::Vector2f((x0 + xd) * tileWidth, (1 + yf) * tileHeight);
quad[3].position = sf::Vector2f(x0 * tileWidth, (1 + yf) * tileHeight);
quad[0].texCoords = sf::Vector2f(0 * tileBoxWidth, (yd + 1) * tileBoxHeight);
quad[1].texCoords = sf::Vector2f(xd * tileBoxWidth, (yd + 1) * tileBoxHeight);
quad[2].texCoords = sf::Vector2f(xd * tileBoxWidth, (yd + yd + 1) * tileBoxHeight);
quad[3].texCoords = sf::Vector2f(0 * tileBoxWidth, (yd + yd + 1) * tileBoxHeight);
}
// bottom
{
sf::Vertex* quad = &shadowVertices[6 * 4];
quad[0].position = sf::Vector2f(xm0 * tileWidth, (yf - yd + 1) * tileHeight);
quad[1].position = sf::Vector2f((xmf + 1)* tileWidth, (yf - yd + 1) * tileHeight);
quad[2].position = sf::Vector2f((xmf + 1) * tileWidth, (1 + yf) * tileHeight);
quad[3].position = sf::Vector2f(xm0 * tileWidth, (1 + yf) * tileHeight);
quad[0].texCoords = sf::Vector2f(xd * tileBoxWidth, (yd + 1) * tileBoxHeight);
quad[1].texCoords = sf::Vector2f((xd + 1) * tileBoxWidth, (yd + 1) * tileBoxHeight);
quad[2].texCoords = sf::Vector2f((xd + 1) * tileBoxWidth, (yd + yd + 1) * tileBoxHeight);
quad[3].texCoords = sf::Vector2f(xd * tileBoxWidth, (yd + yd + 1) * tileBoxHeight);
}
// bottom right
{
sf::Vertex* quad = &shadowVertices[7 * 4];
quad[0].position = sf::Vector2f((xf - xd + 1) * tileWidth, (yf - yd + 1) * tileHeight);
quad[1].position = sf::Vector2f((xf + 1)* tileWidth, (yf - yd + 1) * tileHeight);
quad[2].position = sf::Vector2f((xf + 1) * tileWidth, (1 + yf) * tileHeight);
quad[3].position = sf::Vector2f((xf - xd + 1) * tileWidth, (1 + yf) * tileHeight);
quad[0].texCoords = sf::Vector2f((xd + 1) * tileBoxWidth, (yd + 1) * tileBoxHeight);
quad[1].texCoords = sf::Vector2f((xd + xd + 1) * tileBoxWidth, (yd + 1) * tileBoxHeight);
quad[2].texCoords = sf::Vector2f((xd + xd + 1) * tileBoxWidth, (yd + yd + 1) * tileBoxHeight);
quad[3].texCoords = sf::Vector2f((xd + 1) * tileBoxWidth, (yd + yd + 1) * tileBoxHeight);
}
}
void DungeonMapEntity::computeBloodVertices()
{
bloodVertices.setPrimitiveType(sf::Quads);
bloodVertices.resize(blood.size() * 4);
for (unsigned int i = 0; i < blood.size(); i++)
{
auto particle = blood[i];
sf::Vertex* quad = &bloodVertices[i * 4];
float middle = 8.0f * particle.scale;
int nx = particle.frame % 6;
int ny = particle.frame / 6;
quad[0].position = sf::Vector2f(particle.x - middle, particle.y - middle);
quad[1].position = sf::Vector2f(particle.x + middle, particle.y - middle);
quad[2].position = sf::Vector2f(particle.x + middle, particle.y + middle);
quad[3].position = sf::Vector2f(particle.x - middle, particle.y + middle);
quad[0].texCoords = sf::Vector2f(nx * 16, ny * 16);
quad[1].texCoords = sf::Vector2f((nx + 1) * 16, ny * 16);
quad[2].texCoords = sf::Vector2f((nx + 1) * 16, (ny + 1) * 16);
quad[3].texCoords = sf::Vector2f(nx * 16, (ny + 1) * 16);
}
}
void DungeonMapEntity::computeCorpsesVertices()
{
corpsesVertices.setPrimitiveType(sf::Quads);
corpsesVertices.resize(corpses.size() * 4);
for (unsigned int i = 0; i < corpses.size(); i++)
{
auto particle = corpses[i];
sf::Vertex* quad = &corpsesVertices[i * 4];
float middle = 32;
int nx = particle.frame % 10;
int ny = particle.frame / 10;
quad[0].position = sf::Vector2f(particle.x - middle, particle.y - middle);
quad[1].position = sf::Vector2f(particle.x + middle, particle.y - middle);
quad[2].position = sf::Vector2f(particle.x + middle, particle.y + middle);
quad[3].position = sf::Vector2f(particle.x - middle, particle.y + middle);
quad[0].texCoords = sf::Vector2f(nx * 64, ny * 64);
quad[1].texCoords = sf::Vector2f((nx + 1) * 64, ny * 64);
quad[2].texCoords = sf::Vector2f((nx + 1) * 64, (ny + 1) * 64);
quad[3].texCoords = sf::Vector2f(nx * 64, (ny + 1) * 64);
}
corpsesLargeVertices.setPrimitiveType(sf::Quads);
corpsesLargeVertices.resize(corpsesLarge.size() * 4);
for (unsigned int i = 0; i < corpsesLarge.size(); i++)
{
auto particle = corpsesLarge[i];
sf::Vertex* quad = &corpsesLargeVertices[i * 4];
float middle = 64;
int nx = (particle.frame - FRAME_CORPSE_KING_RAT) % 8;
int ny = (particle.frame - FRAME_CORPSE_KING_RAT) / 8;
quad[0].position = sf::Vector2f(particle.x - middle, particle.y - middle);
quad[1].position = sf::Vector2f(particle.x + middle, particle.y - middle);
quad[2].position = sf::Vector2f(particle.x + middle, particle.y + middle);
quad[3].position = sf::Vector2f(particle.x - middle, particle.y + middle);
quad[0].texCoords = sf::Vector2f(nx * 128, ny * 128);
quad[1].texCoords = sf::Vector2f((nx + 1) * 128, ny * 128);
quad[2].texCoords = sf::Vector2f((nx + 1) * 128, (ny + 1) * 128);
quad[3].texCoords = sf::Vector2f(nx * 128, (ny + 1) * 128);
}
}
displayEntityStruct& DungeonMapEntity::generateBlood(float x, float y, BaseCreatureEntity::enumBloodColor bloodColor)
{
displayEntityStruct bloodEntity;
int b0 = 0 + 6 * (int)bloodColor;
bloodEntity.frame = b0 + rand()%6;
bloodEntity.velocity = Vector2D(rand()%250);
bloodEntity.x = x;
bloodEntity.y = y;
bloodEntity.scale = /*bloodColor == 0 ?*/ 1.0f + (rand() % 10) * 0.1f /*: 1.0f*/;
bloodEntity.moving = true;
blood.push_back(bloodEntity);
return blood[blood.size() - 1];
}
void DungeonMapEntity::addBlood(float x, float y, int frame, float scale)
{
displayEntityStruct bloodEntity;
bloodEntity.frame = frame;
bloodEntity.x = x;
bloodEntity.y = y;
bloodEntity.velocity.x = 0;
bloodEntity.velocity.y = 0;
bloodEntity.scale = scale;
bloodEntity.moving = true;
blood.push_back(bloodEntity);
}
void DungeonMapEntity::addCorpse(float x, float y, int frame)
{
displayEntityStruct corpseEntity;
corpseEntity.frame = frame;
corpseEntity.x = x;
corpseEntity.y = y;
corpseEntity.velocity.x = 0;
corpseEntity.velocity.y = 0;
corpseEntity.scale = 0.0f;
corpseEntity.moving = true;
if (frame >= FRAME_CORPSE_KING_RAT)
{
corpsesLarge.push_back(corpseEntity);
}
else
{
corpses.push_back(corpseEntity);
}
}
void DungeonMapEntity::activateKeyRoomEffect()
{
keyRoomEffect.isBlinking = true;
keyRoomEffect.delay = 1.0f;
}
/////////////////////////////////////////////////////////////////////////
DungeonMapEntityPost::DungeonMapEntityPost(DungeonMapEntity* parent) : GameEntity (0.0f, 0.0f)
{
this->parent = parent;
}
void DungeonMapEntityPost::animate(float delay)
{
}
void DungeonMapEntityPost::render(sf::RenderTarget* app)
{
parent->renderPost(app);
}
/////////////////////////////////////////////////////////////////////////
DungeonMapEntityOverlay::DungeonMapEntityOverlay(DungeonMapEntity* parent) : GameEntity (0.0f, 0.0f)
{
this->parent = parent;
}
void DungeonMapEntityOverlay::animate(float delay)
{
}
void DungeonMapEntityOverlay::render(sf::RenderTarget* app)
{
parent->renderOverlay(app);
}
diff --git a/src/GameFloor.cpp b/src/GameFloor.cpp
index b658adf..3473bde 100644
--- a/src/GameFloor.cpp
+++ b/src/GameFloor.cpp
@@ -1,388 +1,426 @@
#include "GameFloor.h"
#include "Items.h"
#include "WitchBlastGame.h"
#include <time.h>
#include <cstdlib>
#include <stdio.h>
#include <iostream>
GameFloor::GameFloor()
{
this->level = 0;
forceShop = false;
// Init maps
for (int i=0; i < FLOOR_WIDTH; i++)
for (int j=0; j < FLOOR_HEIGHT; j++)
maps[i][j] = NULL;
}
GameFloor::GameFloor(int level)
{
forceShop = false;
// Init maps
for (int i=0; i < FLOOR_WIDTH; i++)
for (int j=0; j < FLOOR_HEIGHT; j++)
maps[i][j] = NULL;
this->level = level;
}
void GameFloor::setForceShop()
{
forceShop = true;
}
GameFloor::~GameFloor()
{
// Free maps
for (int i=0; i < FLOOR_WIDTH; i++)
for (int j=0; j < FLOOR_HEIGHT; j++)
if (maps[i][j] != NULL) delete (maps[i][j]);
}
roomTypeEnum GameFloor::getRoom(int x, int y)
{
if (x < 0 || y < 0 || x >= FLOOR_WIDTH || y >= FLOOR_HEIGHT) return roomTypeNULL;
return floor[x][y];
}
void GameFloor::setRoom(int x, int y, roomTypeEnum roomType)
{
floor[x][y] = roomType;
}
bool GameFloor::hasRoomOfType(roomTypeEnum roomType)
{
for (int i=0; i < FLOOR_WIDTH; i++)
for (int j=0; j < FLOOR_HEIGHT; j++)
if (floor[i][j] == roomType) return true;
return false;
}
DungeonMap* GameFloor::getMap(int x, int y)
{
if (x < 0 || y < 0 || x >= FLOOR_WIDTH || y >= FLOOR_HEIGHT) return NULL;
return maps[x][y];
}
void GameFloor::setMap(int x, int y, DungeonMap* map)
{
maps[x][y] = map;
}
DungeonMap* GameFloor::getAndVisitMap(int x, int y)
{
maps[x][y]->setVisited(true);
- if (x > 0 && floor[x-1][y] > 0) maps[x-1][y]->setKnown(true);
- if (x < FLOOR_WIDTH - 1 && floor[x+1][y] > 0) maps[x+1][y]->setKnown(true);;
- if (y > 0 && floor[x][y-1] > 0) maps[x][y-1]->setKnown(true);;
- if (y < FLOOR_HEIGHT - 1 && floor[x][y+1] > 0) maps[x][y+1]->setKnown(true);;
+ if (x > 0 && floor[x - 1][y] > 0 && getRoom(x - 1, y) != roomTypeSecret)
+ maps[x-1][y]->setKnown(true);
+ if (x < FLOOR_WIDTH - 1 && floor[x + 1][y] > 0 && getRoom(x + 1, y) != roomTypeSecret)
+ maps[x+1][y]->setKnown(true);;
+ if (y > 0 && floor[x][y - 1] > 0 && getRoom(x, y - 1) != roomTypeSecret)
+ maps[x][y-1]->setKnown(true);;
+ if (y < FLOOR_HEIGHT - 1 && floor[x][y + 1] > 0 && getRoom(x, y + 1) != roomTypeSecret)
+ maps[x][y+1]->setKnown(true);;
return maps[x][y];
}
void GameFloor::displayToConsole()
{
for (int j=0; j < FLOOR_HEIGHT; j++)
{
for (int i=0; i < FLOOR_WIDTH; i++)
{
switch (floor[i][j])
{
case roomTypeNULL:
printf(".");
break;
case roomTypeStandard:
printf("#");
break;
case roomTypeBoss:
printf("@");
break;
case roomTypeMerchant:
printf("$");
break;
case roomTypeKey:
- printf("!");
+ printf("k");
break;
case roomTypeBonus:
printf("*");
break;
case roomTypeExit:
printf("X");
break;
case roomTypeStarting:
printf("0");
break;
case roomTypeChallenge:
- printf("?");
+ printf("!");
break;
case roomTypeTemple:
printf("+");
break;
+ case roomTypeSecret:
+ printf("?");
+ break;
}
}
printf("\n");
}
}
int GameFloor::neighboorCount(int x, int y)
{
int count = 0;
if (x > 0 && floor[x-1][y] > 0) count++;
if (x < FLOOR_WIDTH - 1 && floor[x+1][y] > 0) count++;
if (y > 0 && floor[x][y-1] > 0) count++;
if (y < FLOOR_HEIGHT - 1 && floor[x][y+1] > 0) count++;
return count;
}
void GameFloor::reveal()
{
for (int i=0; i < FLOOR_WIDTH; i++)
for (int j=0; j < FLOOR_HEIGHT; j++)
{
if (floor[i][j] > roomTypeNULL)
{
if (!maps[i][j]->isCleared())
{
maps[i][j]->setKnown(true);
}
}
}
}
IntCoord GameFloor::getFirstNeighboor(int x, int y)
{
if (x > 0 && floor[x - 1][y] > 0) return IntCoord(x - 1, y);
if (x < FLOOR_WIDTH - 1 && floor[x + 1][y] > 0) return IntCoord(x + 1, y);
if (y > 0 && floor[x][y - 1] > 0) return IntCoord(x, y - 1);
if (y < FLOOR_HEIGHT - 1 && floor[x][y + 1] > 0) return IntCoord(x, y + 1);
return IntCoord(-1, -1);
}
std::vector<IntCoord> GameFloor::findSuperIsolated()
{
std::vector<IntCoord> results;
for (int i=0; i < FLOOR_WIDTH; i++)
for (int j=0; j < FLOOR_HEIGHT; j++)
{
if (floor[i][j] == roomTypeStandard && neighboorCount(i, j) == 1)
{
if (isSuperIsolated(i, j))
{
IntCoord result(i, j);
results.push_back(result);
}
}
}
return results;
}
+std::vector<IntCoord> GameFloor::findSecretRoom()
+{
+ std::vector<IntCoord> results;
+ for (int i=0; i < FLOOR_WIDTH; i++)
+ for (int j=0; j < FLOOR_HEIGHT; j++)
+ {
+ if (floor[i][j] == roomTypeNULL && neighboorCount(i, j) == 1)
+ {
+ IntCoord neighboor = getFirstNeighboor(i, j);
+ if (i >= 0
+ && floor[neighboor.x][neighboor.y] != roomTypeMerchant
+ && floor[neighboor.x][neighboor.y] != roomTypeExit)
+ {
+ IntCoord result(i, j);
+ results.push_back(result);
+ }
+ }
+ }
+ return results;
+}
+
bool GameFloor::isSuperIsolated(int x, int y)
{
if (neighboorCount(x, y) != 1) return false;
else
{
if (x > 0 && floor[x-1][y]==1 && neighboorCount(x-1, y) == 2) return true;
else if (x < FLOOR_WIDTH - 1 && floor[x+1][y]==1 && neighboorCount(x+1, y) == 2) return true;
else if (y < FLOOR_HEIGHT - 1 && floor[x][y+1]==1 && neighboorCount(x, y+1) == 2) return true;
}
return false;
}
bool GameFloor::finalize()
{
// step 1 : Exit and boss rooms
std::vector<IntCoord> superIsolatedVector = findSuperIsolated();
if (superIsolatedVector.size() == 0)
return false;
else
{
int index = rand() % superIsolatedVector.size();
floor[superIsolatedVector[index].x][superIsolatedVector[index].y] = roomTypeExit;
IntCoord bossCoord = getFirstNeighboor(superIsolatedVector[index].x, superIsolatedVector[index].y);
if (bossCoord.x == -1) return false;
floor[bossCoord.x][bossCoord.y] = roomTypeBoss;
}
// step 2 : bonus, key, etc...
std::vector<IntCoord> isolatedVector;
for (int i=0; i < FLOOR_WIDTH; i++)
for (int j=0; j < FLOOR_HEIGHT; j++)
if (floor[i][j] == 1 && neighboorCount(i, j) == roomTypeStandard)
{
IntCoord found(i, j);
isolatedVector.push_back(found);
}
int nbIsolatedRooms = isolatedVector.size();
if (nbIsolatedRooms < 2) return false;
int index;
// bonus
index = rand() % isolatedVector.size();
floor[isolatedVector[index].x][isolatedVector[index].y] = roomTypeBonus;
isolatedVector.erase(isolatedVector.begin() + index);
// key
index = rand() % isolatedVector.size();
floor[isolatedVector[index].x][isolatedVector[index].y] = roomTypeKey;
isolatedVector.erase(isolatedVector.begin() + index);
int nbIsolatedRoomsMin = 5;
if (level == 1) nbIsolatedRoomsMin = 2;
else if (level == 2) nbIsolatedRoomsMin = 4;
- //if (level > 2 && game().getPlayer()->getActiveSpell().spell == SpellNone) nbIsolatedRoomsMin = 4;
if (nbIsolatedRooms < nbIsolatedRoomsMin) return false;
if (nbIsolatedRooms < 3) return true;
// shop
index = rand() % isolatedVector.size();
floor[isolatedVector[index].x][isolatedVector[index].y] = roomTypeMerchant;
isolatedVector.erase(isolatedVector.begin() + index);
if (level == 1 || nbIsolatedRooms < 4) return true;
// temple
index = rand() % isolatedVector.size();
floor[isolatedVector[index].x][isolatedVector[index].y] = roomTypeTemple;
isolatedVector.erase(isolatedVector.begin() + index);
// challenge
if (isolatedVector.size() > 0)
{
index = rand() % isolatedVector.size();
floor[isolatedVector[index].x][isolatedVector[index].y] = roomTypeChallenge;
isolatedVector.erase(isolatedVector.begin() + index);
}
return true;
}
void GameFloor::createFloor()
{
bool ok=false;
while (!ok)
{
int i, j;
// Free maps
for (i=0; i < FLOOR_WIDTH; i++)
for (j=0; j < FLOOR_HEIGHT; j++)
if (maps[i][j] != NULL)
{
delete (maps[i][j]);
maps[i][j] = NULL;
}
generate();
ok = finalize();
+ if (ok)
+ {
+ // secret
+ std::vector<IntCoord> secretVector = findSecretRoom();
+ if (secretVector.size() > 0)
+ {
+ int index = rand() % secretVector.size();
+ floor[secretVector[index].x][secretVector[index].y] = roomTypeSecret;
+ }
+ }
+
int x0 = FLOOR_WIDTH / 2;
int y0 = FLOOR_HEIGHT / 2;
// Maps
for (i=0; i < FLOOR_WIDTH; i++)
for (j=0; j < FLOOR_HEIGHT; j++)
if (floor[i][j] > 0)
{
maps[i][j] = new DungeonMap(this, i, j);
if (i == x0 && j == y0)
maps[i][j]->setRoomType(roomTypeStarting);
else
maps[i][j]->setRoomType((roomTypeEnum)(floor[i][j]));
}
- //displayToConsole();
+ displayToConsole();
}
}
void GameFloor::generate()
{
int i, j;
int nbRooms;
int requiredRoms = 6 + level * 2;
if (requiredRoms > 18) requiredRoms = 18;
// Init
for (i=0; i < FLOOR_WIDTH; i++)
for (j=0; j < FLOOR_HEIGHT; j++)
{
floor[i][j] = roomTypeNULL;
}
// First room
int x0 = FLOOR_WIDTH / 2;
int y0 = FLOOR_HEIGHT / 2;
floor[x0][y0] = roomTypeStarting;
nbRooms = 1;
// neighboor
while (nbRooms == 1)
{
if (rand() % 3 == 0)
{
floor[x0-1][y0] = roomTypeStandard;
nbRooms++;
}
if (rand() % 3 == 0)
{
floor[x0+1][y0] = roomTypeStandard;
nbRooms++;
}
if (rand() % 3 == 0)
{
floor[x0][y0-1] = roomTypeStandard;
nbRooms++;
}
if (level == 1)
{
if (rand() % 3 == 0)
{
floor[x0][y0+1] = roomTypeStandard;
nbRooms++;
}
}
}
// others
while (nbRooms < requiredRoms)
for (int k = 0; k < 8; k++)
{
i = rand() % FLOOR_WIDTH;
j = rand() % FLOOR_HEIGHT;
if (floor[i][j] == 0 && ( (level == 1) || (i != x0 || j != y0 + 1) ))
{
int n = neighboorCount(i, j);
switch (n)
{
case 1:
{
floor[i][j] = roomTypeStandard;
nbRooms++;
break;
}
case 2:
{
if (rand()% 5 == 0)
{
floor[i][j] = roomTypeStandard;
nbRooms++;
}
break;
}
case 3:
{
if (rand()% 20 == 0)
{
floor[i][j] = roomTypeStandard;
nbRooms++;
}
break;
}
}
}
}
}
diff --git a/src/GameFloor.h b/src/GameFloor.h
index 8f9a12a..2c25cd4 100644
--- a/src/GameFloor.h
+++ b/src/GameFloor.h
@@ -1,69 +1,70 @@
#ifndef GAMEFLOOR_H
#define GAMEFLOOR_H
#include "Constants.h"
#include "DungeonMap.h"
#include <vector>
#include <iostream>
class GameFloor
{
public:
/*!
* \brief constructor of GameFloor (for level 0)
*/
GameFloor();
/*!
* \brief constructor of GameFloor for a given level
* \param level : the level of the floor
*/
GameFloor(int level);
virtual ~GameFloor();
void setForceShop();
void createFloor();
void displayToConsole();
/*!
* \brief returns the room type of the given position
* \param x : x coordinate of the room
* \param y : y coordinate of the room
* \return : the room type at the given position
*/
roomTypeEnum getRoom(int x, int y);
/*!
* \brief looks if a room type exists in this floor
* \param roomType : the room type we are looking for
* \return : true if the room type has been found
*/
bool hasRoomOfType(roomTypeEnum roomType);
void setRoom(int x, int y, roomTypeEnum roomType);
DungeonMap* getMap(int x, int y);
void setMap(int x, int y, DungeonMap* map);
DungeonMap* getAndVisitMap(int x, int y);
int neighboorCount(int x, int y);
void reveal();
protected:
private:
int level;
roomTypeEnum floor[FLOOR_WIDTH][FLOOR_HEIGHT];
IntCoord getFirstNeighboor(int x, int y);
bool isSuperIsolated(int x, int y);
std::vector<IntCoord> findSuperIsolated();
+ std::vector<IntCoord> findSecretRoom();
void generate();
bool finalize();
bool forceShop;
DungeonMap* maps[FLOOR_WIDTH][FLOOR_HEIGHT];
};
#endif // GAMEFLOOR_H
diff --git a/src/PlayerEntity.cpp b/src/PlayerEntity.cpp
index 6eaf685..2c57d9c 100644
--- a/src/PlayerEntity.cpp
+++ b/src/PlayerEntity.cpp
@@ -1,3391 +1,3392 @@
#include "PlayerEntity.h"
#include "SlimeEntity.h"
#include "SlimePetEntity.h"
#include "FallingRockEntity.h"
#include "BoltEntity.h"
#include "SpiderWebEntity.h"
#include "EvilFlowerEntity.h"
#include "EnemyBoltEntity.h"
#include "ItemEntity.h"
#include "FairyEntity.h"
#include "sfml_game/ImageManager.h"
#include "sfml_game/SoundManager.h"
#include "Constants.h"
#include "WitchBlastGame.h"
#include "TextEntity.h"
#include "TextMapper.h"
#include <iostream>
#include <sstream>
#define SPIRAL_STAIRCASE
const int xHalo[9][3] =
{
{ 13, 13, 18},
{ 47, 45, 37},
{ 48, 47, 44},
{ 15, 15, 16},
{ 45, 45, 45},
{ 46, 44, 42},
{ 13, 13, 13},
{ 13, 24, 36},
{ 13, 17, 13}
};
const int yHalo[9][3] =
{
{ 26, 25, 25},
{ 23, 23, 23},
{ 23, 24, 25},
{ 31, 32, 34},
{ 23, 23, 23},
{ 23, 22, 21},
{ 26, 26, 26},
{ 26, 15, 6},
{ 25, 27, 25}
};
const int KEYS_MOVE_TOLERANCE = 36;
PlayerEntity::PlayerEntity(float x, float y)
: BaseCreatureEntity (ImageManager::getInstance().getImage(IMAGE_PLAYER_0), x, y, 64, 96)
{
currentFireDelay = -1.0f;
randomFireDelay = -1.0f;
invincibleDelay = -1.0f;
divineInterventionDelay = -1.0f;
fireAnimationDelay = -1.0f;
fireAnimationDelayMax = 0.4f;
spellAnimationDelay = -1.0f;
spellAnimationDelayMax = 0.7f;
canFirePlayer = true;
type = ENTITY_PLAYER;
imagesProLine = 8;
playerStatus = playerStatusPlaying;
hp = INITIAL_PLAYER_HP;
#ifdef TEST_MODE
hp = INITIAL_PLAYER_HP * 100;
#endif // TEST_MODE
hpDisplay = hp;
hpMax = hp;
gold = 0;
deathAge = -1.0f;
hiccupDelay = HICCUP_DELAY;
idleAge = 0.0f;
boltLifeTime = INITIAL_BOLT_LIFE;
specialBoltTimer = -1.0f;
bloodColor = BloodRed;
canExplode = false;
// init the equipment (to empty)
for (int i = 0; i < NUMBER_EQUIP_ITEMS; i++) equip[i] = false;
collidingDirection = 5;
// init the shots (to none)
for (int i = 0; i < SPECIAL_SHOT_SLOTS; i++)
{
specialShots[i] = ShotTypeStandard;
specialShotLevel[i] = 0;
}
// init the consumibles
for (int i = 0; i < MAX_SLOT_CONSUMABLES; i++)
{
consumable[i] = 0;
consumableAmount[i] = 0;
}
specialShotIndex = 0;
needInitShotType = false;
computePlayer();
firingDirection = 5;
facingDirection = 2;
keyDirection = 5;
sprite.setOrigin(32, 80);
protection.active = false;
armor = 0.0f;
activeSpell.delay = -1.0f;
activeSpell.spell = SpellNone;
divinity.divinity = -1;
divinity.piety = 0;
divinity.level = 0;
divinity.interventions = 0;
divinity.percentsToNextLevels = 0.0f;
shouldBeSavedFromDivinity = false;
isRegeneration = false;
isFairyTransmuted = false;
itemToBuy = NULL;
}
void PlayerEntity::moveTo(float newX, float newY)
{
float dx = newX - x;
float dy = newY - y;
x = newX;
y = newY;
for(int unsigned i = 0; i < fairies.size(); i++)
{
fairies[i]->setX(fairies[i]->getX() + dx);
fairies[i]->setY(fairies[i]->getY() + dy);
}
}
int PlayerEntity::getFacingDirection()
{
return facingDirection;
}
void PlayerEntity::setFacingDirection(int facingDirection)
{
if (facingDirection == 4 || facingDirection == 6 || facingDirection == 2 || facingDirection == 8)
this->facingDirection = facingDirection;
}
float PlayerEntity::getPercentFireDelay()
{
if (canFirePlayer) return 1.0f;
else return (1.0f - currentFireDelay / fireDelay);
}
float PlayerEntity::getLightCone()
{
if (playerStatus == playerStatusPraying)
{
float result = 1.0f;
if (statusTimer < 0.25f)
result = 4 * statusTimer;
else if (statusTimer > WORSHIP_DELAY - 0.25f)
result = (WORSHIP_DELAY - statusTimer) * 4;
return result;
}
else if (divineInterventionDelay > 0.0f)
{
float result = 1.0f;
if (divineInterventionDelay < 0.25f)
result = 4 * divineInterventionDelay;
else if (divineInterventionDelay > WORSHIP_DELAY - 0.25f)
result = (WORSHIP_DELAY - divineInterventionDelay) * 4;
if (isRegeneration) result *= 0.4f;
return result;
}
else return -1.0f;
}
float PlayerEntity::getPercentSpellDelay()
{
if (activeSpell.spell == SpellNone)
return getPercentFireDelay();
else
{
if (activeSpell.delay <= 0.0f) return 1.0f;
else return (1.0f - activeSpell.delay / activeSpell.delayMax);
}
}
bool PlayerEntity::isPoisoned()
{
return (specialState[SpecialStatePoison].active);
}
int PlayerEntity::getCollidingDirection()
{
return collidingDirection;
}
PlayerEntity::playerStatusEnum PlayerEntity::getPlayerStatus()
{
return playerStatus;
}
void PlayerEntity::setPlayerStatus(PlayerEntity::playerStatusEnum playerStatus)
{
this->playerStatus = playerStatus;
}
bool PlayerEntity::isDead()
{
return playerStatus == playerStatusDead;
}
enemyTypeEnum PlayerEntity::getLastHurtingEnemy()
{
return lastHurtingEnemy;
}
sourceTypeEnum PlayerEntity::getLastHurtingSource()
{
return lastHurtingSource;
}
float PlayerEntity::getDeathAge()
{
return deathAge;
}
void PlayerEntity::setDeathAge(float deathAge)
{
this->deathAge = deathAge;
}
bool PlayerEntity::getFairyTransmuted()
{
return isFairyTransmuted;
}
divinityStruct PlayerEntity::getDivinity()
{
return divinity;
}
int PlayerEntity::getPiety()
{
return divinity.piety;
}
void PlayerEntity::stuck()
{
if (playerStatus != playerStatusEntering)
castTeleport();
}
void PlayerEntity::setEntering()
{
playerStatus = playerStatusEntering;
}
void PlayerEntity::setLeavingLevel()
{
playerStatus = playerStatusGoingNext;
}
void PlayerEntity::pay(int price)
{
gold -= price;
displayAcquiredGold(-price);
if (gold < 0) gold = 0;
SoundManager::getInstance().playSound(SOUND_PAY);
}
void PlayerEntity::acquireItemAfterStance()
{
if (acquiredItem >= FirstEquipItem)
{
equip[acquiredItem - FirstEquipItem] = true;
if (acquiredItem != ItemBossKey) game().proceedEvent(EventGetItem);
// familiar
if (items[acquiredItem].familiar != FamiliarNone)
{
setEquiped(acquiredItem - FirstEquipItem, true);
game().proceedEvent(EventGetFamiliar);
}
// shot types
else if (items[acquiredItem].specialShot != (ShotTypeStandard))
{
registerSpecialShot(acquiredItem);
game().proceedEvent(EventGetSpecialShot);
}
// spells
else if (items[acquiredItem].spell != SpellNone)
{
setActiveSpell(items[acquiredItem].spell, false);
game().proceedEvent(EventGetSpell);
}
// pet slime
else if (acquiredItem == ItemPetSlime)
{
new SlimePetEntity();
}
// floor item
else if (acquiredItem == ItemFloorMap)
game().revealFloor();
else if (acquiredItem == ItemAlcohol)
hiccupDelay = HICCUP_DELAY;
// acquirement
if (equip[EQUIP_DISPLACEMENT_GLOVES] && equip[EQUIP_LEATHER_BOOTS] && equip[EQUIP_MAGICIAN_HAT] && equip[EQUIP_MAGICIAN_ROBE])
game().registerAchievement(AchievementCompleteSet);
computePlayer();
}
else
{
if (acquiredItem == ItemBossHeart)
{
int hpBonus = 2 + rand() % 4;
hpMax += hpBonus;
hp += hpBonus;
hpDisplay += hpBonus;
SoundManager::getInstance().playSound(SOUND_EAT);
std::ostringstream oss;
oss << "HP Max +" << hpBonus;
TextEntity* text = new TextEntity(oss.str(), 15, x, y - 50.0f);
text->setColor(TextEntity::COLOR_FADING_GREEN);
text->setAlignment(ALIGN_CENTER);
text->setAge(-1.0f);
text->setLifetime(1.2f);
text->setWeight(-60.0f);
text->setType(ENTITY_FLYING_TEXT);
text->setZ(2000);
}
else if (acquiredItem == ItemBonusHealth)
{
hpMax += 1;
hp = hpMax;
SoundManager::getInstance().playSound(SOUND_EAT);
TextEntity* text = new TextEntity("HP Max + 1", 15, x, y - 50.0f);
text->setColor(TextEntity::COLOR_FADING_GREEN);
text->setAlignment(ALIGN_CENTER);
text->setAge(-1.0f);
text->setLifetime(1.2f);
text->setWeight(-60.0f);
text->setType(ENTITY_FLYING_TEXT);
text->setZ(2000);
}
}
spriteItem->setDying(true);
spriteItemStar->setDying(true);
playerStatus = playerStatusPlaying;
}
void PlayerEntity::resetFloorItem()
{
equip[EQUIP_BOSS_KEY] = false;
equip[EQUIP_FLOOR_MAP] = false;
equip[EQUIP_ALCOHOL] = false;
equip[EQUIP_FAIRY_POWDER] = false;
equip[EQUIP_LUCK] = false;
computePlayer();
}
void PlayerEntity::setItemToBuy(ItemEntity* item)
{
itemToBuy = item;
}
ItemEntity* PlayerEntity::getItemToBuy()
{
return itemToBuy;
}
void PlayerEntity::animate(float delay)
{
// shot timer
if (specialBoltTimer >= 0.0f)
{
specialBoltTimer -= delay;
if (specialBoltTimer <= 0.0f)
{
if (getShotType() == ShotTypeIce) SoundManager::getInstance().playSound(SOUND_ICE_CHARGE);
}
}
if (playerStatus == playerStatusGoingNext)
{
return;
}
if (playerStatus == playerStatusStairs)
{
x += velocity.x * delay;
y += velocity.y * delay;
age += delay;
frame = ((int)(age * 7.0f)) % 4;
if (frame == 3) frame = 1;
if (x < (MAP_WIDTH / 2) * TILE_WIDTH - TILE_WIDTH / 2)
{
facingDirection = 8;
game().moveToOtherMap(8);
}
return;
}
// rate of fire
if (!canFirePlayer)
{
currentFireDelay -= delay;
canFirePlayer = (currentFireDelay <= 0.0f);
}
if (randomFireDelay >= 0.0f) randomFireDelay -= delay;
// spells
if (activeSpell.spell != SpellNone && activeSpell.delay > 0.0f)
{
if (game().getCurrentMap()->isCleared())
activeSpell.delay -= 40 * delay;
else
activeSpell.delay -= delay;
if (activeSpell.spell == SpellProtection && protection.active)
activeSpell.delay = activeSpell.delayMax;
if (activeSpell.delay <= 0.0f) SoundManager::getInstance().playSound(SOUND_SPELL_CHARGE);
}
// protection
if (protection.active)
{
protection.timer -= delay;
if (protection.timer <= 0.0f)
{
protection.active = false;
computePlayer();
}
}
// acquisition animation
if (playerStatus == playerStatusAcquire)
{
statusTimer -= delay;
if (statusTimer <= 0.0f)
{
acquireItemAfterStance();
}
}
else if (equip[EQUIP_ALCOHOL] && playerStatus == playerStatusPlaying)
{
hiccupDelay -= delay;
if (hiccupDelay <= 0.0f)
{
hiccupDelay = 4.0f;
// hiccup
recoil.active = true;
recoil.stun = true;
recoil.velocity = Vector2D(350.0f);
recoil.timer = 0.4f;
for (int i = 0; i < 4; i++)
{
BoltEntity* bolt = new BoltEntity(x, getBolPositionY(), boltLifeTime, ShotTypePoison, 0);
bolt->setDamages(4);
bolt->setFlying(isFairyTransmuted);
//bolt->setVelocity(recoil.velocity.vectorTo(Vector2D(0, 0), fireVelocity));
bolt->setVelocity(Vector2D(fireVelocity));
}
TextEntity* text = new TextEntity("*hic*", 16, x, y - 30.0f);
text->setColor(TextEntity::COLOR_FADING_GREEN);
text->setAge(-0.6f);
text->setLifetime(0.3f);
text->setWeight(-60.0f);
text->setZ(2000);
text->setAlignment(ALIGN_CENTER);
text->setType(ENTITY_FLYING_TEXT);
SoundManager::getInstance().playSound(SOUND_HICCUP);
SoundManager::getInstance().playSound(SOUND_BLAST_STANDARD);
}
}
if (divineInterventionDelay > 0.0f) divineInterventionDelay -= delay;
if (fireAnimationDelay > 0.0f)
{
fireAnimationDelay -= delay;
if (fireAnimationDelay <= 0.0f) fireAnimationDelay = -1.0f;
}
if (spellAnimationDelay > 0.0f)
{
spellAnimationDelay -= delay;
if (spellAnimationDelay <= 0.0f) spellAnimationDelay = -1.0f;
}
// unlocking animation
else if (playerStatus == playerStatusUnlocking || playerStatus == playerStatusPraying)
{
statusTimer -= delay;
if (statusTimer <= 0.0f)
{
playerStatus = playerStatusPlaying;
}
}
if (playerStatus == playerStatusDead)
{
deathAge += delay;
velocity = Vector2D(0.0f, 0.0f);
}
else
testSpriteCollisions();
// key room collision
if (game().getCurrentMap()->getRoomType() == roomTypeKey && !game().getCurrentMap()->isCleared())
{
sf::IntRect col1;
col1.width = 198;
col1.height = 68;
col1.top = 254;
col1.left = 380;
sf::IntRect col2;
col2.width = 68;
col2.height = 198;
col2.top = 189;
col2.left = 445;
if (boundingBox.intersects(col1) || boundingBox.intersects(col2))
{
recoil.active = true;
recoil.stun = true;
recoil.velocity = Vector2D(GAME_WIDTH / 2, GAME_HEIGHT /2).vectorTo(Vector2D(x, y), 650.0f);
recoil.timer = 0.4f;
game().activateKeyRoomEffect(true);
}
}
//collidingDirection = 0;
BaseCreatureEntity::animate(delay);
if (firingDirection != 5)
facingDirection = firingDirection;
// find the frame
if (firingDirection != 5)
{
if (fireAnimationDelay < 0.0f)
fireAnimationDelay = fireAnimationDelayMax;
fireAnimationDirection = firingDirection;
}
else if (isMoving())
{
frame = ((int)(age * 7.0f)) % 4;
if (frame == 3) frame = 1;
}
else if (playerStatus == playerStatusAcquire || playerStatus == playerStatusUnlocking || playerStatus == playerStatusPraying)
frame = 3;
else if (playerStatus == playerStatusDead)
frame = 0;
else // standing
{
frame = 1;
}
if (playerStatus != playerStatusPlaying || isMoving() || firingDirection != 5)
idleAge = 0.0f;
else
idleAge += delay;
if (x < 0)
game().moveToOtherMap(4);
else if (x > MAP_WIDTH * TILE_WIDTH)
game().moveToOtherMap(6);
else if (y < 0)
game().moveToOtherMap(8);
else if (y > MAP_HEIGHT * TILE_HEIGHT)
game().moveToOtherMap(2);
#ifdef SPIRAL_STAIRCASE
else if (playerStatus == playerStatusPlaying
&& game().getCurrentMap()->getRoomType() == roomTypeExit && y < TILE_HEIGHT * 0.6f)
{
playerStatus = playerStatusStairs;
velocity.y = creatureSpeed / 12;
velocity.x = -creatureSpeed / 3;
facingDirection = 4;
SpriteEntity* exitDoorEntity = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_TILES),
(MAP_WIDTH / 2) * TILE_WIDTH - TILE_WIDTH / 2,
TILE_HEIGHT / 2, 64, 64, 1);
exitDoorEntity->setZ(TILE_HEIGHT);
exitDoorEntity->setImagesProLine(24);
exitDoorEntity->setFrame(MAP_WALL_BEGIN + 21 + 24 * game().getCurrentMap()->getWallType());
exitDoorEntity->setType(ENTITY_EFFECT);
SpriteEntity* exitDoorAroundEntity = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_DOORS),
(MAP_WIDTH / 2) * TILE_WIDTH - TILE_WIDTH / 2,
TILE_HEIGHT / 2, 64, 64, 1);
exitDoorAroundEntity->setZ(TILE_HEIGHT + 1);
exitDoorAroundEntity->setImagesProLine(8);
exitDoorAroundEntity->setFrame(5 + 7 * 8);
exitDoorAroundEntity->setType(ENTITY_EFFECT);
SpriteEntity* exitDoorEntityShadow = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_TILES_SHADOW),
(MAP_WIDTH / 2) * TILE_WIDTH - TILE_WIDTH / 2,
TILE_HEIGHT / 2, 64, 64, 1);
exitDoorEntityShadow->setZ(TILE_HEIGHT + 2);
exitDoorEntityShadow->setImagesProLine(10);
exitDoorEntityShadow->setFrame(4);
exitDoorEntityShadow->setType(ENTITY_EFFECT);
}
#endif
if (playerStatus == playerStatusEntering)
{
if (boundingBox.left > TILE_WIDTH
&& (boundingBox.left + boundingBox.width) < TILE_WIDTH * (MAP_WIDTH - 1)
&& boundingBox.top > TILE_HEIGHT
&& (boundingBox.top + boundingBox.height) < TILE_HEIGHT * (MAP_HEIGHT - 1))
{
playerStatus = playerStatusPlaying;
game().closeDoors();
}
else
{
if (x < 2 * TILE_WIDTH)
{
velocity.x = creatureSpeed;
velocity.y = 0.0f;
}
else if (x > (MAP_WIDTH - 3) * TILE_WIDTH)
{
velocity.x = -creatureSpeed;
velocity.y = 0.0f;
}
else if (y < 2 * TILE_HEIGHT)
{
velocity.y = creatureSpeed;
velocity.x = 0.0f;
}
else if (y > (MAP_HEIGHT - 3) * TILE_HEIGHT)
{
velocity.y = -creatureSpeed;
velocity.x = 0.0f;
}
}
}
if (playerStatus != playerStatusDead)
{
if (invincibleDelay >= 0.0f) invincibleDelay -= delay;
if (specialState[SpecialStateConfused].active)
SoundManager::getInstance().playSound(SOUND_VAMPIRE_HYPNOSIS, false);
}
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_BOOTS_ADVANCED] && playerStatus != playerStatusDead)
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (21 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (21 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
else if (equip[EQUIP_LEATHER_BOOTS] && playerStatus != playerStatusDead)
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (9 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (9 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_ROBE_ADVANCED] && playerStatus != playerStatusDead)
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (12 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (12 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (15 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (15 + frame) * width, spriteDy * height, width, height));
sprite.setColor(sf::Color(255, 255, 255, 100 + 100 * cosf(game().getAbsolutTime() * 3.5f)));
app->draw(sprite, sf::BlendAdd);
sprite.setColor(sf::Color(255, 255, 255, 255));
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
else if (equip[EQUIP_MAGICIAN_ROBE])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (12 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (12 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_GLOVES_ADVANCED] && playerStatus != playerStatusDead)
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (24 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (24 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
else if (equip[EQUIP_DISPLACEMENT_GLOVES])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (21 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (21 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_CRITICAL_ADVANCED])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (24 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (24 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
else if (equip[EQUIP_CRITICAL])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (18 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (18 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
if (equip[EQUIP_RAGE_AMULET])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (18 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (18 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_LEATHER_BELT])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (15 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (15 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
// staff
int frameDx = equip[EQUIP_MAHOGANY_STAFF] ? 6 : 3;
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (frameDx + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (frameDx + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
if (equip[EQUIP_BLOOD_SNAKE])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (27 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (27 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_REAR_SHOT])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
// shot type
if (getShotType() != ShotTypeStandard)
{
switch (getShotType())
{
case ShotTypeIce:
sprite.setColor(sf::Color(100, 220, 255, 255));
break;
case ShotTypeStone:
sprite.setColor(sf::Color(120, 120, 150, 255));
break;
case ShotTypeLightning:
sprite.setColor(sf::Color(255, 255, 0, 255));
break;
case ShotTypeIllusion:
sprite.setColor(sf::Color(240, 180, 250, 255));
break;
case ShotTypeStandard:
sprite.setColor(sf::Color(255, 255, 255, 0));
break;
case ShotTypeFire:
sprite.setColor(sf::Color(255, 180, 0, 255));
break;
case ShotTypePoison:
sprite.setColor(sf::Color(50, 255, 50, 255));
break;
default:
std::cout << "[WARNING] Can not render shot type: " << getShotType() << std::endl;
}
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (3 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (3 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setColor(savedColor);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
// hat
if (equip[EQUIP_HAT_ADVANCED] && playerStatus != playerStatusDead)
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (9 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (9 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
else if (equip[EQUIP_MAGICIAN_HAT] && playerStatus != playerStatusDead)
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (6 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (6 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
}
void PlayerEntity::renderHalo(sf::RenderTarget* app)
{
if (frame > 2 || spriteDy > 8) return;
// gems
if ((getShotType() == ShotTypeIce || getShotType() == ShotTypeLightning || getShotType() == ShotTypeFire || getShotType() == ShotTypePoison) && playerStatus != playerStatusDead)
{
int fade;
sf::Color savedColor = sprite.getColor();
if (getShotType() != ShotTypeIce || specialBoltTimer <= 0.0f) fade = 255;
else fade = ((STATUS_FROZEN_BOLT_DELAY[getShotLevel()] - specialBoltTimer) / STATUS_FROZEN_BOLT_DELAY[getShotLevel()]) * 128;
if (getShotType() == ShotTypeLightning)
fade = 150 + rand() % 105;
if (getShotType() == ShotTypeFire)
fade = 200 + rand() % 40;
if (getShotType() == ShotTypePoison)
fade = 150 + rand() % 40;
if (getShotType() == ShotTypeIce)
sprite.setTextureRect(sf::IntRect(448, 864, 20, 20));
else if (getShotType() == ShotTypeLightning)
sprite.setTextureRect(sf::IntRect(448 + 20, 864, 20, 20));
else if (getShotType() == ShotTypeFire)
sprite.setTextureRect(sf::IntRect(448 + 40, 864, 20, 20));
else if (getShotType() == ShotTypePoison)
sprite.setTextureRect(sf::IntRect(448, 864 + 20, 20, 20));
sprite.setColor(sf::Color(255, 255, 255, fade));
if (isMirroring)
sprite.setPosition(x - 10 + 64 - xHalo[spriteDy][frame], y - 10 + yHalo[spriteDy][frame]);
else
sprite.setPosition(x - 10 + xHalo[spriteDy][frame], y - 10 + yHalo[spriteDy][frame]);
sf::RenderStates r;
r.blendMode = sf::BlendAdd;
app->draw(sprite, r);
sprite.setPosition(x, y);
sprite.setColor(savedColor);
}
}
void PlayerEntity::render(sf::RenderTarget* app)
{
sprite.setPosition(x, y);
spriteDy = 0;
isMirroring = false;
if (idleAge > 8.5f)
{
idleAge -= 8.5f;
}
else if (idleAge >= 7.5)
{
spriteDy = 8;
frame = 2;
}
else if (idleAge >= 7.0)
{
spriteDy = 8;
frame = 1;
}
else if (idleAge >= 6.0)
{
spriteDy = 8;
frame = 0;
}
else if (idleAge >= 5.5f && facingDirection != 2)
{
facingDirection = 2;
idleAge -= 2.0f;
}
else if (fireAnimationDelay <= 0.0f && spellAnimationDelay <= 0.0f)
{
if (facingDirection == 6) spriteDy = 1;
else if (facingDirection == 8) spriteDy = 2;
else if (facingDirection == 4)
{
spriteDy = 1;
isMirroring = true;
}
}
else if (spellAnimationDelay >= 0.0f)
{
spriteDy = 7;
if (spellAnimationDelay < spellAnimationDelayMax * 0.1f) frame = 0;
else if (spellAnimationDelay < spellAnimationDelayMax * 0.2f) frame = 1;
else if (spellAnimationDelay < spellAnimationDelayMax * 0.7f) frame = 2;
else if (spellAnimationDelay < spellAnimationDelayMax * 0.85f) frame = 1;
else frame = 0;
}
else
{
if (fireAnimationDirection == 2) spriteDy = 3;
else if (fireAnimationDirection == 6) spriteDy = 4;
else if (fireAnimationDirection == 8) spriteDy = 5;
else if (fireAnimationDirection == 4)
{
spriteDy = 4;
isMirroring = true;
}
if (fireAnimationDelay < fireAnimationDelayMax * 0.2f) frame = 0;
else if (fireAnimationDelay < fireAnimationDelayMax * 0.4f) frame = 1;
else if (fireAnimationDelay < fireAnimationDelayMax * 0.6f) frame = 2;
else if (fireAnimationDelay < fireAnimationDelayMax * 0.8f) frame = 1;
else frame = 0;
}
if (playerStatus == playerStatusAcquire || playerStatus == playerStatusUnlocking)
{
spriteDy = 6;
frame = ((int)(age * 10.0f)) % 4;
if (frame == 3) frame = 1;
}
else if (playerStatus == playerStatusPraying)
{
spriteDy = 7;
frame = ((int)(age * 10.0f)) % 4;
if (frame == 3) frame = 1;
float delay = playerStatus == playerStatusPraying ? WORSHIP_DELAY : UNLOCK_DELAY;
if (statusTimer < delay * 0.1f) frame = 0;
else if (statusTimer < delay * 0.2f) frame = 1;
else if (statusTimer < delay * 0.7f) frame = 2;
else if (statusTimer < delay * 0.85f) frame = 1;
else frame = 0;
}
if (playerStatus == playerStatusDead)
{
frame = (int)(deathAge / 0.35f);
if (frame > 6) frame = 6;
spriteDy = 9;
sprite.setTextureRect(sf::IntRect( frame * width, spriteDy * height, width, height));
app->draw(sprite);
}
else
{
if (isFairyTransmuted)
{
frame = 0;
if (velocity.x * velocity.x + velocity.y * velocity.y > 400)
frame = ((int)(age * 24.0f)) % 2;
else
frame = ((int)(age * 18.0f)) % 2;
sf::Sprite fairySprite;
fairySprite.setColor(sprite.getColor());
fairySprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_FAIRY));
fairySprite.setPosition(sprite.getPosition());
fairySprite.setOrigin(26, 62);
switch (facingDirection)
{
case 8: fairySprite.setTextureRect(sf::IntRect( (2 + frame) * 48, 5 * 72, 48, 72)); break;
case 4: fairySprite.setTextureRect(sf::IntRect( (4 + frame) * 48, 5 * 72, 48, 72)); break;
case 6: fairySprite.setTextureRect(sf::IntRect( (5 + frame) * 48, 5 * 72, - 48, 72)); break;
default: fairySprite.setTextureRect(sf::IntRect( frame * 48, 5 * 72, 48, 72)); break;
}
app->draw(fairySprite);
}
else
{
renderHalo(app);
renderPlayer(app);
}
// shield
if (playerStatus != playerStatusStairs && (specialState[DivineStateProtection].active || protection.active))
{
int firstFrame = 8;
if (specialState[DivineStateProtection].active && divinity.divinity == DivinityStone) firstFrame = 16;
float timer = specialState[DivineStateProtection].active ? specialState[DivineStateProtection].timer : protection.timer;
sprite.setTextureRect(sf::IntRect( firstFrame * width, 9 * height, width, height));
app->draw(sprite);
sf::Color savedColor = sprite.getColor();
sprite.setColor(sf::Color(255, 255, 255, 100 + cos(age * (timer < 2.0f ? 25 : 10)) * 30 ));
sprite.setTextureRect(sf::IntRect( (firstFrame + 1) * width, 9 * height, width, height));
app->draw(sprite);
sprite.setColor(savedColor);
}
// divine field
if (divinity.level > 1)
{
bool displayField = false;
int fieldFrame;
int fieldFade;
switch (divinity.divinity)
{
case DivinityHealer:
{
displayField = true;
fieldFrame = 10;
fieldFade = 40 * (divinity.level - 1);
break;
}
case DivinityFighter:
{
displayField = true;
fieldFrame = 12;
fieldFade = 40 * (divinity.level - 1);
break;
}
case DivinityIce:
{
if (divinity.level > 2)
{
displayField = true;
fieldFrame = 14;
fieldFade = 80 * (divinity.level - 3);
}
break;
}
case DivinityStone:
{
if (divinity.level > 2)
{
displayField = true;
fieldFrame = 16;
fieldFade = 80 * (divinity.level - 3);
}
break;
}
case DivinityAir:
{
if (divinity.level > 1)
{
displayField = true;
fieldFrame = 18;
fieldFade = 40 * (divinity.level - 1);
}
break;
}
}
if (displayField)
{
sf::Color savedColor = sprite.getColor();
sprite.setColor(sf::Color(255, 255, 255, fieldFade ));
sprite.setTextureRect(sf::IntRect( fieldFrame * width, 9 * height, width, height));
app->draw(sprite);
if (divinity.divinity != DivinityStone && divinity.divinity != DivinityHealer)
{
sprite.setColor(sf::Color(255, 255, 255, 2 + fieldFade / 2 + cos(age * 15) * fieldFade / 2 ));
sprite.setTextureRect(sf::IntRect( (fieldFrame + 1) * width, 9 * height, width, height));
app->draw(sprite);
sprite.setColor(savedColor);
}
if (divinity.divinity == DivinityHealer && divineInterventionDelay > 0.0f && isRegeneration)
{
sprite.setTextureRect(sf::IntRect( (fieldFrame + 1) * width, 9 * height, width, height));
app->draw(sprite);
}
sprite.setColor(savedColor);
}
}
}
if (game().getShowLogical() && playerStatus != playerStatusDead)
{
displayBoundingBox(app);
displayCenterAndZ(app);
}
}
void PlayerEntity::calculateBB()
{
if (isFairyTransmuted)
{
boundingBox.left = (int)x - 10;
boundingBox.width = 20;
boundingBox.top = (int)y - 29;
boundingBox.height = 20;
}
else
{
boundingBox.left = (int)x - 10;
boundingBox.width = 20;
boundingBox.top = (int)y - 29;
boundingBox.height = 33;
}
}
void PlayerEntity::readCollidingEntity(CollidingSpriteEntity* entity)
{
if (playerStatus == playerStatusDead || !canCollide()) return;
EnemyBoltEntity* boltEntity = dynamic_cast<EnemyBoltEntity*>(entity);
if (collideWithEntity(entity))
{
if (boltEntity != NULL && !boltEntity->getDying())
{
boltEntity->collide();
// TODO bolt source
hurt(getHurtParams(boltEntity->getDamages(),
boltEntity->getBoltType(),
boltEntity->getLevel(),
boltEntity->isCritical(),
SourceTypeBolt,
boltEntity->getEnemyType(),
false));
game().generateBlood(x, y, bloodColor);
float xs = (x + boltEntity->getX()) / 2;
float ys = (y + boltEntity->getY()) / 2;
SpriteEntity* star = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_HURT_IMPACT), xs, ys);
star->setFading(true);
star->setZ(y+ 100);
star->setLifetime(0.7f);
star->setType(ENTITY_EFFECT);
star->setSpin(400.0f);
}
}
}
bool PlayerEntity::willCollideWithMap(int dx, int dy, bool checkMiddle)
{
float oldX = x, oldY = y;
bool collide = true;
x = oldX + dx;
y = oldY + dy;
if (!isCollidingWithMap())
collide = false;
else if (checkMiddle)
{
x = oldX + dx / 2;
y = oldY + dy / 2;
if (!isCollidingWithMap())
collide = false;
}
x = oldX;
y = oldY;
return collide;
}
void PlayerEntity::move(int direction)
{
float oldX = x, oldY = y;
bool touchUp, touchDown, touchLeft, touchRight;
x = oldX + 1;
touchRight = isCollidingWithMap();
x = oldX - 1;
touchLeft = isCollidingWithMap();
x = oldX;
y = oldY + 1;
touchDown = isCollidingWithMap();
y = oldY - 1;
touchUp = isCollidingWithMap();
y = oldY;
if (specialState[SpecialStateConfused].active)
{
switch (direction)
{
case 4: direction = 6; break;
case 6: direction = 4; break;
case 2: direction = 8; break;
case 8: direction = 2; break;
case 1: direction = 9; break;
case 9: direction = 1; break;
case 7: direction = 3; break;
case 3: direction = 7; break;
}
}
keyDirection = direction;
if (playerStatus == playerStatusAcquire && statusTimer < ACQUIRE_DELAY / 2)
{
acquireItemAfterStance();
}
if (playerStatus == playerStatusPlaying)
{
collidingDirection = 5;
switch (keyDirection)
{
case 1:
if (touchDown && touchLeft)
{
direction = 5;
collidingDirection = 1;
}
else if (touchDown)
{
direction = 4;
collidingDirection = 2;
}
else if (touchLeft)
{
direction = 2;
collidingDirection = 4;
}
break;
case 3:
if (touchDown && touchRight)
{
direction = 5;
collidingDirection = 3;
}
else if (touchDown)
{
direction = 6;
collidingDirection = 2;
}
else if (touchRight)
{
direction = 2;
collidingDirection = 6;
}
break;
case 7:
if (touchUp && touchLeft)
{
direction = 5;
collidingDirection = 7;
}
else if (touchUp)
{
direction = 4;
collidingDirection = 8;
}
else if (touchLeft)
{
direction = 8;
collidingDirection = 1;
}
break;
case 9:
if (touchUp && touchRight)
{
direction = 5;
collidingDirection = 9;
}
else if (touchUp)
{
direction = 6;
collidingDirection = 8;
}
else if (touchRight)
{
direction = 8;
collidingDirection = 6;
}
break;
case 4:
if (touchLeft)
{
x = oldX - 2;
if (!willCollideWithMap(0, KEYS_MOVE_TOLERANCE, true))
direction = 2;
else if (!willCollideWithMap(0, -KEYS_MOVE_TOLERANCE, true))
direction = 8;
else
{
direction = 5;
collidingDirection = 4;
}
x = oldX;
}
break;
case 6:
if (touchRight)
{
x = oldX + 2;
if (!willCollideWithMap(0, KEYS_MOVE_TOLERANCE, true))
direction = 2;
else if (!willCollideWithMap(0, -KEYS_MOVE_TOLERANCE, true))
direction = 8;
else
{
direction = 5;
collidingDirection = 6;
}
x = oldX;
}
break;
case 8:
if (touchUp)
{
y = oldY - 2;
if (!willCollideWithMap(KEYS_MOVE_TOLERANCE, 0, true))
direction = 6;
else if (!willCollideWithMap(-KEYS_MOVE_TOLERANCE, 0, true))
direction = 4;
else
{
direction = 5;
collidingDirection = 8;
}
y = oldY;
}
break;
case 2:
if (touchDown)
{
y = oldY + 2;
if (!willCollideWithMap(KEYS_MOVE_TOLERANCE, 0, true))
direction = 6;
else if (!willCollideWithMap(-KEYS_MOVE_TOLERANCE, 0, true))
direction = 4;
else
{
direction = 5;
collidingDirection = 2;
}
y = oldY;
}
break;
}
float speedx = 0.0f, speedy = 0.0f;
if (direction == 4)
speedx = - creatureSpeed;
else if (direction == 1 || direction == 7)
speedx = - creatureSpeed * 0.7f;
else if (direction == 6)
speedx = creatureSpeed;
else if (direction == 3 || direction == 9)
speedx = creatureSpeed * 0.7f;
if (direction == 2)
speedy = creatureSpeed;
else if (direction == 1 || direction == 3)
speedy = creatureSpeed * 0.7f;
else if (direction == 8)
speedy = - creatureSpeed;
else if (direction == 7 || direction == 9)
speedy = - creatureSpeed * 0.7f;
setVelocity(Vector2D(speedx, speedy));
if (firingDirection != 5)
facingDirection = firingDirection;
else
{
switch (keyDirection)
{
case 8:
facingDirection = 8;
break;
case 2:
facingDirection = 2;
break;
case 4:
facingDirection = 4;
break;
case 6:
facingDirection = 6;
break;
case 7:
if (facingDirection != 4 && facingDirection != 8) facingDirection = 4;
break;
case 1:
if (facingDirection != 4 && facingDirection != 2) facingDirection = 4;
break;
case 9:
if (facingDirection != 6 && facingDirection != 8) facingDirection = 6;
break;
case 3:
if (facingDirection != 6 && facingDirection != 2) facingDirection = 6;
break;
}
}
}
}
bool PlayerEntity::isMoving()
{
if (velocity.x < -1.0f || velocity.x > 1.0f) return true;
if (velocity.y < -1.0f || velocity.y > 1.0f) return true;
return false;
}
bool PlayerEntity::isEquiped(int eq)
{
return equip[eq];
}
bool* PlayerEntity::getEquipment()
{
return equip;
}
void PlayerEntity::setEquiped(int item, bool toggleEquipped)
{
equip[item] = toggleEquipped;
if (toggleEquipped && items[FirstEquipItem + item].familiar > FamiliarNone)
{
FairyEntity* fairy = new FairyEntity(x - 50.0f + rand() % 100,
y - 50.0f + rand() % 100,
items[FirstEquipItem + item].familiar);
fairies.push_back(fairy);
//if (fairies.size() == 3) game().registerAchievement(AchievementFairies);
}
computePlayer();
}
void PlayerEntity::generateBolt(float velx, float vely)
{
enumShotType boltType = ShotTypeStandard;
unsigned int shotLevel = 1;
switch (getShotType())
{
case ShotTypeIce:
if (getShotType() == ShotTypeIce)
{
if (specialBoltTimer <= 0.0f)
{
boltType = ShotTypeIce;
shotLevel = getShotLevel();
needInitShotType = true;
}
else boltType = ShotTypeCold;
}
break;
case ShotTypeStandard:
case ShotTypeIllusion:
case ShotTypeStone:
case ShotTypeLightning:
case ShotTypeFire:
case ShotTypePoison:
boltType = getShotType();
shotLevel = getShotLevel();
break;
default:
std::cout << "[WARNING] Can not generate shot type: " << getShotType() << std::endl;
}
BoltEntity* bolt = new BoltEntity(x, getBolPositionY(), boltLifeTime, boltType, shotLevel);
bolt->setFlying(isFairyTransmuted);
int boltDamage = fireDamages;
if (criticalChance > 0)
if (rand()% 100 < criticalChance)
{
boltDamage *= equip[EQUIP_CRITICAL_ADVANCED] ? 3 : 2;
bolt->setCritical(true);
}
bolt->setDamages(boltDamage);
if (equip[EQUIP_GLOVES_ADVANCED])
{
if (firingDirection == 2 || firingDirection == 8)
velx += velocity.x * 0.7f;
else if (firingDirection == 4 || firingDirection == 6)
vely += velocity.y * 0.7f;
}
bolt->setVelocity(Vector2D(velx, vely));
}
void PlayerEntity::rageFire()
{
for (int i = -1; i <= 1; i += 2)
for (int j = -1; j <= 1; j += 2)
{
BoltEntity* bolt = new BoltEntity(x, getBolPositionY(), boltLifeTime, ShotTypeFire, 0);
bolt->setDamages(10);
bolt->setFlying(isFairyTransmuted);
float velx = fireVelocity * i * 0.42f;
float vely = fireVelocity * j * 0.42f;
bolt->setVelocity(Vector2D(velx, vely));
if (hp <= hpMax / 5)
{
BoltEntity* bolt = new BoltEntity(x, getBolPositionY(), boltLifeTime, ShotTypeFire, 0);
bolt->setDamages(10);
bolt->setFlying(isFairyTransmuted);
float velx = 0.0f;
float vely = 0.0f;
if (i == -1 && j == -1) velx = -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)
{
if (age < 0.7f) return;
firingDirection = direction;
if (playerStatus != playerStatusDead)
for(int unsigned i = 0; i < fairies.size(); i++)
fairies[i]->fire(direction);
if (canFirePlayer && playerStatus != playerStatusDead && playerStatus != playerStatusAcquire)
{
switch (getShotType())
{
case ShotTypeCold:
case ShotTypeIce:
SoundManager::getInstance().playPitchModSound(SOUND_BLAST_ICE);
break;
case ShotTypeFire:
SoundManager::getInstance().playPitchModSound(SOUND_BLAST_FIRE);
break;
case ShotTypeIllusion:
SoundManager::getInstance().playPitchModSound(SOUND_BLAST_ILLUSION);
break;
case ShotTypeLightning:
SoundManager::getInstance().playPitchModSound(SOUND_BLAST_LIGHTNING);
break;
case ShotTypePoison:
SoundManager::getInstance().playPitchModSound(SOUND_BLAST_POISON);
break;
case ShotTypeStone:
SoundManager::getInstance().playPitchModSound(SOUND_BLAST_STONE);
break;
default:
SoundManager::getInstance().playPitchModSound(SOUND_BLAST_STANDARD);
break;
}
if (equip[EQUIP_BOOK_DUAL] || equip[EQUIP_BOOK_TRIPLE]
|| equip[EQUIP_BOOK_DUAL_QUICK] || equip[EQUIP_BOOK_TRIPLE_QUICK])
{
float shoot_angle = 0.2f;
if ((direction == 4 && velocity.x < -1.0f) || (direction == 6 && velocity.x > 1.0f)
|| (direction == 8 && velocity.y < -1.0f) || (direction == 2 && velocity.y > 1.0f))
shoot_angle = 0.1f;
else if ((direction == 6 && velocity.x < -1.0f) || (direction == 4 && velocity.x > 1.0f)
|| (direction == 2 && velocity.y < -1.0f) || (direction == 8 && velocity.y > 1.0f))
shoot_angle = (equip[EQUIP_BOOK_TRIPLE] || equip[EQUIP_BOOK_TRIPLE_QUICK]) ? 0.35f : 0.2f;
else if (!equip[EQUIP_BOOK_TRIPLE] && !equip[EQUIP_BOOK_TRIPLE_QUICK])
shoot_angle = 0.1f;
switch(direction)
{
case 4:
generateBolt(-fireVelocity * cos(shoot_angle), fireVelocity * sin(shoot_angle));
generateBolt(-fireVelocity * cos(shoot_angle), - fireVelocity * sin(shoot_angle));
break;
case 6:
generateBolt(fireVelocity * cos(shoot_angle), fireVelocity * sin(shoot_angle));
generateBolt(fireVelocity * cos(shoot_angle), - fireVelocity * sin(shoot_angle));
break;
case 8:
generateBolt(fireVelocity * sin(shoot_angle), -fireVelocity * cos(shoot_angle));
generateBolt(-fireVelocity * sin(shoot_angle), - fireVelocity * cos(shoot_angle));
break;
case 2:
generateBolt(fireVelocity * sin(shoot_angle), fireVelocity * cos(shoot_angle));
generateBolt(-fireVelocity * sin(shoot_angle), fireVelocity * cos(shoot_angle));
break;
}
}
if (equip[EQUIP_RAPID_SHOT])
{
Vector2D boltDirection;
switch(direction)
{
case 4:
boltDirection = Vector2D(0, 0).vectorNearlyTo(Vector2D(-1, 0), fireVelocity, 0.2f);
break;
case 6:
boltDirection = Vector2D(0, 0).vectorNearlyTo(Vector2D(1, 0), fireVelocity, 0.2f);
break;
case 8:
boltDirection = Vector2D(0, 0).vectorNearlyTo(Vector2D(0, -1), fireVelocity, 0.2f);
break;
case 2:
boltDirection = Vector2D(0, 0).vectorNearlyTo(Vector2D(0, 1), fireVelocity, 0.2f);
break;
}
generateBolt(boltDirection.x, boltDirection.y);
}
else if (!(equip[EQUIP_BOOK_DUAL] || equip[EQUIP_BOOK_DUAL_QUICK]) || (equip[EQUIP_BOOK_TRIPLE] || equip[EQUIP_BOOK_TRIPLE_QUICK]))
{
switch(direction)
{
case 4:
generateBolt(-fireVelocity, 0.0f);
break;
case 6:
generateBolt(fireVelocity, 0.0f);
break;
case 8:
generateBolt(0.0f, -fireVelocity);
break;
case 2:
generateBolt(0.0f, fireVelocity);
break;
}
}
if (equip[EQUIP_REAR_SHOT])
{
BoltEntity* bolt = new BoltEntity(x, getBolPositionY(), boltLifeTime, ShotTypeStandard, 0);
bolt->setDamages(fireDamages / 2);
bolt->setFlying(isFairyTransmuted);
float velx = 0.0f;
float vely = 0.0f;
switch (direction)
{
case 4:
velx = fireVelocity * 0.75f;
break;
case 6:
velx = -fireVelocity * 0.75f;
break;
case 2:
vely = -fireVelocity * 0.75f;
break;
case 8:
vely = fireVelocity * 0.75f;
break;
}
bolt->setVelocity(Vector2D(velx, vely));
}
if (equip[EQUIP_BOOK_RANDOM] && randomFireDelay <= 0.0f)
{
BoltEntity* bolt = new BoltEntity(x, getBolPositionY(), boltLifeTime, ShotTypeStandard, 0);
bolt->setDamages(fireDamages);
bolt->setFlying(isFairyTransmuted);
float shotAngle = rand() % 360;
bolt->setVelocity(Vector2D(fireVelocity * 0.75f * cos(shotAngle), fireVelocity * 0.75f * sin(shotAngle)));
randomFireDelay = fireDelay * 1.5f;
}
canFirePlayer = false;
currentFireDelay = fireDelay;
if (needInitShotType) initShotType();
}
}
bool PlayerEntity::canMove()
{
return (playerStatus == playerStatusPlaying
|| (playerStatus == playerStatusAcquire && statusTimer < ACQUIRE_DELAY / 2));
}
int PlayerEntity::hurt(StructHurt hurtParam)
{
if (playerStatus == playerStatusDead) return false;
if (isFairyTransmuted && hurtParam.hurtingType != ShotTypeDeterministic)
{
hurtParam.damage *= 2;
}
shouldBeSavedFromDivinity = false;
bool divinityInvoked = false;
if (hp - hurtParam.damage <= hpMax / 4 && divinity.divinity >= 0)
{
divinityInvoked = triggerDivinityBefore();
if (divinityInvoked)
{
game().testAndAddMessageToQueue((EnumMessages)(MsgInfoDivIntervention));
shouldBeSavedFromDivinity = true;
}
}
if (invincibleDelay <= 0.0f || hurtParam.hurtingType == ShotTypeDeterministic)
{
SoundManager::getInstance().playSound(SOUND_PLAYER_HIT);
int oldHp = hp;
if (BaseCreatureEntity::hurt(hurtParam) > 0)
{
if (hurtParam.hurtingType != ShotTypeDeterministic)
{
invincibleDelay = INVINCIBLE_DELAY;
if (equip[EQUIP_RAGE_AMULET]) rageFire();
game().generateBlood(x, y, bloodColor);
}
hurtingDelay = HURTING_DELAY * 2.0f;
game().generateBlood(x, y, bloodColor);
game().proceedEvent(EventBeingHurted);
lastHurtingEnemy = hurtParam.enemyType;
lastHurtingSource = hurtParam.sourceType;
// divinity
offerHealth(oldHp - hp);
if (!divinityInvoked && hp <= hpMax / 4 && divinity.divinity >= 0)
{
triggerDivinityAfter();
}
return true;
}
}
return false;
}
void PlayerEntity::setMap(GameMap* map, int tileWidth, int tileHeight, int offsetX, int offsetY)
{
CollidingSpriteEntity::setMap(map, tileWidth, tileHeight, offsetX, offsetY);
//if (slimePet != NULL) slimePet->setMap(map, tileWidth, tileHeight, offsetX, offsetY);
}
void PlayerEntity::loseItem(enumItemType itemType, bool isEquip)
{
CollidingSpriteEntity* itemSprite
= new CollidingSpriteEntity(ImageManager::getInstance().getImage(isEquip ? IMAGE_ITEMS_EQUIP : IMAGE_ITEMS), x, y, 32, 32);
itemSprite->setMap(map, TILE_WIDTH, TILE_HEIGHT, 0, 0);
itemSprite->setZ(-1);
itemSprite->setFrame(itemType);
itemSprite->setImagesProLine(10);
itemSprite->setType(ENTITY_BLOOD);
itemSprite->setVelocity(Vector2D(200 + rand()%450));
itemSprite->setViscosity(0.95f);
itemSprite->setSpin( (rand() % 700) - 350.0f);
}
void PlayerEntity::dying()
{
if (shouldBeSavedFromDivinity)
{
hp = 33 * hpMax / 100;
return;
}
else if (divinity.divinity > -1 && divinity.interventions < divinity.level - 1)
{
hp = 1;
return;
}
playerStatus = playerStatusDead;
deathAge = 0.0f;
hp = 0;
SoundManager::getInstance().playSound(SOUND_PLAYER_DIE);
setVelocity(Vector2D(0.0f, 0.0f));
int i;
for (i = 0; i < gold && i < 10; i++) loseItem(ItemCopperCoin, false);
for (i = 0; i < 5; i++) game().generateBlood(x, y, BloodRed);
for (i = 0; i < NUMBER_EQUIP_ITEMS; i++)
{
if (equip[i])
{
if (items[i + FirstEquipItem].familiar == FamiliarNone)
loseItem(enumItemType(i), true);
}
}
remove(SAVE_FILE.c_str());
game().calculateScore();
}
void PlayerEntity::displayAcquiredGold(int n)
{
std::ostringstream oss;
if (n > 0) oss << "+";
oss << n;
TextEntity* text = new TextEntity(oss.str(), 16, x, y - 30.0f);
text->setColor(TextEntity::COLOR_FADING_YELLOW);
text->setAge(-0.6f);
text->setLifetime(0.3f);
text->setWeight(-60.0f);
text->setZ(2000);
text->setAlignment(ALIGN_CENTER);
text->setType(ENTITY_FLYING_TEXT);
}
void PlayerEntity::acquireItem(enumItemType type)
{
if (items[type].generatesStance) acquireStance(type);
else if (items[type].consumable)
{
acquireConsumable(type);
}
else switch (type)
{
case ItemCopperCoin:
gold++;
displayAcquiredGold(1);
SoundManager::getInstance().playSound(SOUND_COIN_PICK_UP);
game().proceedEvent(EventGetCoin);
break;
case ItemSilverCoin:
gold = gold + 5;
displayAcquiredGold(5);
SoundManager::getInstance().playSound(SOUND_COIN_PICK_UP);
game().proceedEvent(EventGetCoin);
break;
case ItemGoldCoin:
gold = gold + 10;
displayAcquiredGold(10);
SoundManager::getInstance().playSound(SOUND_COIN_PICK_UP);
game().proceedEvent(EventGetCoin);
break;
case ItemHealthVerySmallPoison:
specialState[SpecialStatePoison].active = false;
case ItemHealthVerySmall:
heal(equip[EQUIP_MANUAL_HEALTH] ? 5 : 3);
SoundManager::getInstance().playSound(SOUND_EAT);
break;
case ItemHealthSmall:
heal(equip[EQUIP_MANUAL_HEALTH] ? 10 : 7);
SoundManager::getInstance().playSound(SOUND_EAT);
break;
case ItemHealth:
heal(equip[EQUIP_MANUAL_HEALTH] ? 22 : 15);
SoundManager::getInstance().playSound(SOUND_EAT);
break;
default:
break;
}
}
bool isUnidentified(enumItemType item)
{
return (item >= ItemPotion01 && item < ItemPotion01 + CONSUMABLE_MAX);
}
int PlayerEntity::getConsumable(int n)
{
if (n < 0 || n >= MAX_SLOT_CONSUMABLES) return -1;
else return consumable[n];
}
int PlayerEntity::getConsumableAmount(int n)
{
if (n < 0 || n >= MAX_SLOT_CONSUMABLES) return 0;
else return consumableAmount[n];
}
void PlayerEntity::setConsumable(int n, int type, int amount)
{
if (n < 0 || n >= MAX_SLOT_CONSUMABLES) return;
consumable[n] = type;
consumableAmount[n] = amount;
}
void PlayerEntity::dropConsumables(int n)
{
if (n < 0 || n >= MAX_SLOT_CONSUMABLES) return;
if (playerStatus != playerStatusPlaying) return;
if (consumable[n] > -1 && consumableAmount[n] > 0)
{
for (int i = 0; i < consumableAmount[n]; i++)
{
ItemEntity* newItem = new ItemEntity((enumItemType)(consumable[n]), x, y);
newItem->setVelocity(Vector2D(100.0f + rand()% 250));
newItem->setViscosity(0.96f);
newItem->setAge(-10.0f);
}
consumable[n] = -1;
consumableAmount[n] = 0;
}
}
void PlayerEntity::tryToConsume(int n)
{
if (n < 0 || n >= MAX_SLOT_CONSUMABLES) return;
if (playerStatus != playerStatusPlaying) return;
if (consumable[n] > -1 && consumableAmount[n] > 0)
{
// unidentified
if (isUnidentified((enumItemType)consumable[n]))
{
game().setPotionToKnown((enumItemType)consumable[n]);
consume(game().getPotion((enumItemType)consumable[n]));
}
else if (items[consumable[n]].consumable)
// known
{
consume((enumItemType)consumable[n]);
}
else
{
std::cout << "[ERROR] Trying to consume item: " << items[consumable[n]].name << std::endl;
}
}
consumableAmount[n] --;
// last ?
if (consumableAmount[n] < 1)
{
consumable[n] = -1;
}
}
void PlayerEntity::consume(enumItemType item)
{
switch(item)
{
case ItemScrollRevelation:
reveal();
break;
case ItemPotionHealth:
heal(equip[EQUIP_MANUAL_HEALTH] ? 28 : 18);
SoundManager::getInstance().playSound(SOUND_DRINK);
break;
case ItemPotionPoison:
specialState[SpecialStatePoison].active = true;
specialState[SpecialStatePoison].timer = POISON_TIMER[0];
specialState[SpecialStatePoison].param1 = POISON_DAMAGE[0];
specialState[SpecialStatePoison].param2 = POISON_DELAY[0];
specialState[SpecialStatePoison].param3 = POISON_DELAY[0];
displayFlyingText( x, y - 20.0f, 16, tools::getLabel("poison"), TextEntity::COLOR_FADING_RED);
SoundManager::getInstance().playSound(SOUND_DRINK);
break;
default:
std::cout << "[ERROR] Trying to consume item: " << items[item].name << std::endl;
break;
}
}
void PlayerEntity::reveal()
{
for (int i = 0; i < MAX_SLOT_CONSUMABLES; i++)
{
if (consumable[i] > -1 && consumableAmount[i] > 0)
{
if (isUnidentified((enumItemType)consumable[i]))
{
game().setPotionToKnown((enumItemType)consumable[i]);
consumable[i] = game().getPotion((enumItemType)consumable[i]);
}
}
}
+ game().getCurrentMap()->callRevelation();
}
bool PlayerEntity::canAquireConsumable(enumItemType type)
{
int nbConsumableSlot = equip[EQUIP_BAG] ? 4 : 2;
int found = -1;
int emptySlot = -1;
for (int i = 0; found == -1 && emptySlot == -1 && i < nbConsumableSlot; i++)
{
if (consumable[i] == type)
found = i;
else if (consumable[i] <= 0 || consumableAmount[i] <= 0)
if (emptySlot == -1) emptySlot = i;
}
return (found > -1 || emptySlot > -1);
}
void PlayerEntity::acquireConsumable(enumItemType type)
{
int nbConsumableSlot = equip[EQUIP_BAG] ? 4 : 2;
int found = -1;
int emptySlot = -1;
for (int i = 0; found == -1 && i < nbConsumableSlot; i++)
{
if (consumable[i] == type)
found = i;
else if (consumable[i] <= 0 || consumableAmount[i] <= 0)
if (emptySlot == -1) emptySlot = i;
}
if (found > -1)
{
consumableAmount[found]++;
}
else if (emptySlot > -1)
{
consumable[emptySlot] = type;
consumableAmount[emptySlot] = 1;
// events
game().proceedEvent(EventConsumable);
if (isUnidentified(type)) game().proceedEvent(EventPotion);
}
}
void PlayerEntity::onClearRoom()
{
if (divinity.divinity == DivinityHealer)
{
if (divinity.level > 1 && hp < hpMax)
{
divineInterventionDelay = WORSHIP_DELAY / 2;
isRegeneration = true;
if (divinity.level >= 5) heal(4);
else if (divinity.level >= 4) heal(3);
else if (divinity.level >= 3) heal(2);
else if (divinity.level >= 2) heal(1);
}
}
}
void PlayerEntity::computePlayer()
{
float boltLifeTimeBonus = 1.0f;
float fireDelayBonus = 1.0f;
float creatureSpeedBonus = 1.0f;
float fireVelocityBonus = 1.0f;
float fireDamagesBonus = 1.0f;
armor = 0.0f;
criticalChance = 0;
for (int i = 0; i < NB_RESISTANCES; i++) resistance[i] = ResistanceStandard;
if (equip[EQUIP_GLOVES_ADVANCED]) fireDelayBonus -= 0.15f;
else if (equip[EQUIP_DISPLACEMENT_GLOVES]) fireDelayBonus -= 0.10f;
if (equip[EQUIP_HAT_ADVANCED])
{
fireDelayBonus -= 0.3f;
resistance[ResistanceIce] = (enumStateResistance)(resistance[ResistanceIce] - 1);
resistance[ResistanceStone] = (enumStateResistance)(resistance[ResistanceStone] - 1);
resistance[ResistanceLightning] = (enumStateResistance)(resistance[ResistanceLightning] - 1);
resistance[ResistanceFire] = (enumStateResistance)(resistance[ResistanceFire] - 1);
}
else if (equip[EQUIP_MAGICIAN_HAT]) fireDelayBonus -= 0.2f;
if (equip[EQUIP_LEATHER_BELT]) fireDelayBonus -= 0.15f;
if (equip[EQUIP_BOOTS_ADVANCED]) creatureSpeedBonus += 0.25f;
else if (equip[EQUIP_LEATHER_BOOTS]) creatureSpeedBonus += 0.15f;
if (equip[EQUIP_BOOK_TRIPLE]) fireDelayBonus += 0.7f;
else if (equip[EQUIP_BOOK_DUAL]) fireDelayBonus += 0.5f;
if (equip[EQUIP_CRITICAL]) criticalChance += 5;
if (equip[EQUIP_MANUAL_STAFF]) boltLifeTimeBonus += 0.4f;
if (equip[EQUIP_MAHOGANY_STAFF])
{
fireVelocityBonus += 0.15f;
fireDamagesBonus += 0.5f;
}
if (equip[EQUIP_BLOOD_SNAKE]) fireDamagesBonus += 0.5f;
if (equip[EQUIP_ROBE_ADVANCED]) armor += 0.2f;
else if (equip[EQUIP_MAGICIAN_ROBE]) armor += 0.15f;
// divinity
switch (divinity.divinity)
{
case (DivinityHealer):
{
break;
}
case (DivinityFighter):
{
if (divinity.level >= 5)
fireDamagesBonus += 0.5f;
else if (divinity.level >= 4)
fireDamagesBonus += 0.375f;
else if (divinity.level >= 3)
fireDamagesBonus += 0.25f;
else if (divinity.level >= 2)
fireDamagesBonus += 0.125f;
break;
}
case (DivinityIce):
{
if (divinity.level >= 5) resistance[ResistanceFrozen] = ResistanceVeryHigh;
if (divinity.level >= 3) resistance[ResistanceIce] = (enumStateResistance)(resistance[ResistanceIce] - 1);
break;
}
case (DivinityStone):
{
if (divinity.level >= 5) resistance[ResistanceRecoil] = ResistanceVeryHigh;
if (divinity.level >= 3) resistance[ResistanceStone] = (enumStateResistance)(resistance[ResistanceStone] - 1);
break;
}
case (DivinityAir):
{
if (divinity.level > 1) creatureSpeedBonus += (divinity.level - 1) * 0.04f;
if (divinity.level >= 3) resistance[ResistanceLightning] = (enumStateResistance)(resistance[ResistanceLightning] - 1);
break;
}
}
fireDelay = INITIAL_PLAYER_FIRE_DELAY * fireDelayBonus;
creatureSpeed = INITIAL_PLAYER_SPEED * creatureSpeedBonus;
fireVelocity = INITIAL_BOLT_VELOCITY * fireVelocityBonus;
fireDamages = INITIAL_BOLT_DAMAGES * fireDamagesBonus;
boltLifeTime = INITIAL_BOLT_LIFE * boltLifeTimeBonus;
// gems
for (int i = 1; i < SPECIAL_SHOT_SLOTS; i++)
{
specialShotLevel[i] = 0;
switch (specialShots[i])
{
case ShotTypeIce:
if (equip[EQUIP_RING_ICE]) specialShotLevel[i]++;
if (divinity.divinity == DivinityIce && divinity.level >= 4) specialShotLevel[i]++;
break;
case ShotTypeStone:
if (equip[EQUIP_RING_STONE]) specialShotLevel[i]++;
if (divinity.divinity == DivinityStone && divinity.level >= 4) specialShotLevel[i]++;
break;
case ShotTypeLightning:
if (equip[EQUIP_RING_LIGHTNING]) specialShotLevel[i]++;
if (divinity.divinity == DivinityAir && divinity.level >= 4) specialShotLevel[i]++;
break;
case ShotTypeIllusion:
if (equip[EQUIP_RING_ILLUSION]) specialShotLevel[i]++;
break;
case ShotTypeFire:
if (equip[EQUIP_RING_FIRE]) specialShotLevel[i]++;
break;
case ShotTypePoison:
if (equip[EQUIP_RING_POISON]) specialShotLevel[i]++;
break;
default:
break;
}
}
if (getShotType() == ShotTypeIllusion) fireDamages *= ILLUSION_DAMAGE_DECREASE[getShotLevel()];
else if (getShotType() == ShotTypeFire) fireDamages *= FIRE_DAMAGE_INCREASE[getShotLevel()];
// divinity
if (specialState[DivineStateProtection].active)
armor += specialState[DivineStateProtection].param1;
// post-computation
if (equip[EQUIP_BOOK_TRIPLE_QUICK]) fireDamages *= 0.65f;
else if (equip[EQUIP_BOOK_DUAL_QUICK]) fireDamages *= 0.75f;
else if (equip[EQUIP_RAPID_SHOT])
{
fireDelay *= 0.20f;
fireDamages *= 0.25f;
}
if (equip[EQUIP_ALCOHOL]) fireDamages *= 1.25f;
// spells
if (protection.active) armor += protection.value;
if (armor > 1.0f) armor = 1.0f;
// fairy ?
if (isFairyTransmuted)
{
fireDamages *= 0.5f;
creatureSpeed *= 1.5f;
movingStyle = movFlying;
}
else
{
movingStyle = movWalking;
}
}
void PlayerEntity::acquireStance(enumItemType type)
{
velocity.x = 0.0f;
velocity.y = 0.0f;
playerStatus = playerStatusAcquire;
statusTimer = ACQUIRE_DELAY;
acquiredItem = (enumItemType)(type);
SoundManager::getInstance().playSound(SOUND_BONUS);
game().showArtefactDescription(type);
enumItemType itemFrame = type;
int itemImage = IMAGE_ITEMS;
if (itemFrame >= FirstEquipItem)
{
itemFrame = (enumItemType)(itemFrame - FirstEquipItem);
itemImage = IMAGE_ITEMS_EQUIP;
}
spriteItem = new SpriteEntity(
ImageManager::getInstance().getImage(itemImage),
x, y - 100.0f, ITEM_WIDTH, ITEM_HEIGHT);
spriteItem->setFrame((int)itemFrame);
spriteItem->setImagesProLine(10);
spriteItem->setZ(z);
spriteItem->setLifetime(ACQUIRE_DELAY);
spriteItemStar = new SpriteEntity(
ImageManager::getInstance().getImage(IMAGE_STAR),
x, y - 100.0f);
spriteItemStar->setScale(4.0f, 4.0f);
spriteItemStar->setZ(z-1.0f);
spriteItemStar->setLifetime(ACQUIRE_DELAY);
spriteItemStar->setSpin(50.0f);
}
void PlayerEntity::collideMapRight()
{
collidingDirection = 6;
if (recoil.active) recoil.velocity.x = -recoil.velocity.x * 0.7f;
}
void PlayerEntity::collideMapLeft()
{
collidingDirection = 4;
if (recoil.active) recoil.velocity.x = -recoil.velocity.x * 0.7f;
}
void PlayerEntity::collideMapTop()
{
collidingDirection = 8;
if (recoil.active) recoil.velocity.y= -recoil.velocity.y * 0.7f;
}
void PlayerEntity::collideMapBottom()
{
collidingDirection = 2;
if (recoil.active) recoil.velocity.y= -recoil.velocity.y * 0.7f;
}
void PlayerEntity::useBossKey()
{
velocity.x = 0.0f;
velocity.y = 0.0f;
playerStatus = playerStatusUnlocking;
statusTimer = UNLOCK_DELAY;
acquiredItem = (enumItemType)(type - FirstEquipItem);
SoundManager::getInstance().playSound(SOUND_DOOR_OPENING_BOSS);
equip[EQUIP_BOSS_KEY] = false;
SpriteEntity* spriteItem = new SpriteEntity(
ImageManager::getInstance().getImage(IMAGE_ITEMS_EQUIP),
x, y - 80.0f, ITEM_WIDTH, ITEM_HEIGHT);
spriteItem->setFrame(EQUIP_BOSS_KEY);
spriteItem->setZ(z);
spriteItem->setAge(-UNLOCK_DELAY * 0.5f);
spriteItem->setLifetime(UNLOCK_DELAY * 0.5f);
spriteItem->setFading(true);
spriteItem->setSpin(300);
}
enumShotType PlayerEntity::getShotType()
{
return specialShots[specialShotIndex];
}
int PlayerEntity::getShotIndex()
{
return specialShotIndex;
}
void PlayerEntity::setShotIndex(int index)
{
specialShotIndex = index;
}
enumShotType PlayerEntity::getShotType(int slot)
{
return specialShots[slot];
}
void PlayerEntity::setShotType(int slot, enumShotType shotType)
{
specialShots[slot] = shotType;
}
void PlayerEntity::registerSpecialShot(int item)
{
bool found = false;
int index = 1;
while (index < SPECIAL_SHOT_SLOTS && !found)
{
found = specialShots[index] == ShotTypeStandard;
if (!found) index++;
}
if (found)
{
this->specialShots[index] = items[item].specialShot;
specialShotIndex = index;
initShotType();
}
}
void PlayerEntity::selectNextShotType()
{
int index = specialShotIndex + 1;
bool found = false;
while (index < SPECIAL_SHOT_SLOTS && !found)
{
if (specialShots[index] == ShotTypeStandard) index++;
else found = true;
}
if (found)
{
specialShotIndex = index;
initShotType();
}
else
specialShotIndex = 0;
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
computePlayer();
}
void PlayerEntity::initShotType()
{
specialBoltTimer = STATUS_FROZEN_BOLT_DELAY[getShotLevel()];
needInitShotType = false;
if (getShotType() == ShotTypeLightning)
SoundManager::getInstance().playSound(SOUND_ELECTRIC_CHARGE);
}
unsigned int PlayerEntity::getShotLevel()
{
return specialShotLevel[specialShotIndex];
}
unsigned int PlayerEntity::getShotLevel(int index)
{
return specialShotLevel[index];
}
int PlayerEntity::getFairieNumber()
{
return fairies.size();
}
FairyEntity* PlayerEntity::getFairy(unsigned int n)
{
if (n < fairies.size())
return fairies[n];
else
return NULL;
}
bool PlayerEntity::canGetNewShot(bool advancedShot)
{
int nbSpecial =0;
int nbAdvanced =0;
for (int i = 1; i < SPECIAL_SHOT_SLOTS; i++)
{
switch (specialShots[i])
{
case ShotTypeIce:
case ShotTypeStone:
case ShotTypeLightning:
nbSpecial++;
break;
case ShotTypeFire:
case ShotTypeIllusion:
case ShotTypePoison:
nbAdvanced++;
break;
case ShotTypeStandard:
break;
default:
std::cout << "[WARNING] Can not register shot type: " << getShotType() << std::endl;
}
}
if (advancedShot)
return (nbAdvanced >= SPECIAL_SHOT_SLOTS_ADVANCED);
else
return (nbSpecial >= SPECIAL_SHOT_SLOTS_STANDARD);
}
void PlayerEntity::interact(EnumInteractionType interaction, int id)
{
if (playerStatus == playerStatusPlaying)
{
// praying at the temple
if (interaction == InteractionTypeTemple)
{
if (divinity.divinity == id)
{
// donation
if (gold >= 10)
{
donate(10);
}
}
else
{
worship((enumDivinityType)id);
}
}
else if (interaction == InteractionTypeMerchandise)
{
if (itemToBuy != NULL) itemToBuy->buy();
}
}
}
float PlayerEntity::getBolPositionY()
{
if (isFairyTransmuted)
return y - 25;
else
return y - 20;
}
bool PlayerEntity::collideWithMap(int direction)
{
if (playerStatus == playerStatusEntering)
return false;
else
return BaseCreatureEntity::collideWithMap(direction);
}
// DIVINITY
void PlayerEntity::donate(int n)
{
if (gold >= n)
{
gold -= n;
displayAcquiredGold(-n);
SoundManager::getInstance().playSound(SOUND_PAY);
// standard : 1 gold = 3 piety
int pietyProGold = 3;
if (divinity.divinity == DivinityHealer)
pietyProGold = 5;
addPiety(pietyProGold * n);
// check item invoke
bool divineGift = false;
enumItemType itemType = ItemCopperCoin;
if (divinity.level >= 3 && game().getItemsCount() == 0)
{
if (divinity.divinity == DivinityHealer && !equip[EQUIP_MANUAL_HEALTH])
{
// Healer + level 3 = Health manual
divineGift = true;
itemType = ItemManualHealth;
}
else if (divinity.divinity == DivinityIce && !equip[EQUIP_GEM_ICE])
{
divineGift = true;
itemType = ItemGemIce;
}
else if (divinity.divinity == DivinityStone && !equip[EQUIP_GEM_STONE])
{
divineGift = true;
itemType = ItemGemStone;
}
else if (divinity.divinity == DivinityAir && !equip[EQUIP_GEM_LIGHTNING])
{
divineGift = true;
itemType = ItemGemLightning;
}
}
if (divineGift)
{
float xItem = GAME_WIDTH / 2;
float yItem = GAME_HEIGHT * 0.8f;
new ItemEntity(itemType, xItem, yItem);
SoundManager::getInstance().playSound(SOUND_OM);
divineInterventionDelay = WORSHIP_DELAY / 2;
isRegeneration = false;
for (int i = 0; i < 8; i++)
{
game().generateStar(sf::Color::White, xItem, yItem);
game().generateStar(sf::Color(255, 255, 210), xItem, yItem);
}
game().testAndAddMessageToQueue((EnumMessages)(MsgInfoDivGift));
}
}
}
void PlayerEntity::offerMonster(enemyTypeEnum monster, enumShotType hurtingType)
{
if (divinity.divinity > -1)
{
// standard : 1 monster = 2 piety - 1 boss = 20 piety
int pietyProMonster = 2;
int pietyProBoss = 20;
switch (divinity.divinity)
{
case DivinityHealer:
if (monster == EnemyTypeGhost
|| monster == EnemyTypeZombie
|| monster == EnemyTypeZombieDark
|| monster == EnemyTypeImpBlue
|| monster == EnemyTypeImpRed
|| monster == EnemyTypeWitch
|| monster == EnemyTypeWitchRed
|| monster == EnemyTypeBogeyman)
pietyProMonster = 4;
else
pietyProMonster = 0;
break;
case DivinityFighter:
pietyProMonster = 3;
pietyProBoss = 30;
break;
case DivinityIce:
if (monster == EnemyTypeSlimeRed
|| monster == EnemyTypeImpRed
|| monster == EnemyTypeEvilFlowerFire)
pietyProMonster = 4;
if (hurtingType == ShotTypeCold || hurtingType == ShotTypeIce)
{
pietyProMonster *= 1.5f;
pietyProBoss = 25;
}
break;
case DivinityStone:
if (hurtingType == ShotTypeCold || hurtingType == ShotTypeIce)
{
pietyProMonster = 3;
pietyProBoss = 30;
}
else
{
pietyProBoss = 25;
}
break;
}
if (monster < EnemyTypeButcher) // normal or mini-boss
{
addPiety(pietyProMonster);
}
else if (monster < EnemyTypeBat_invocated) // boss
{
addPiety(pietyProBoss);
}
}
}
void PlayerEntity::offerHealth(int lostHp)
{
if (divinity.divinity == DivinityHealer)
{
addPiety(lostHp * 2.5f);
}
}
void PlayerEntity::offerChallenge()
{
if (divinity.divinity >= 0)
addPiety(30);
}
void PlayerEntity::divineFury()
{
enumShotType shotType = ShotTypeStandard;
if (divinity.divinity == DivinityIce) shotType = ShotTypeIce;
else if (divinity.divinity == DivinityStone) shotType = ShotTypeStone;
else if (divinity.divinity == DivinityAir) shotType = ShotTypeLightning;
int multBonus = 6;
if (divinity.divinity == DivinityFighter) multBonus = 8;
for (int i = 0; i < (divinity.divinity == DivinityAir ? 16 : 32); i ++)
{
BoltEntity* bolt = new BoltEntity(TILE_WIDTH * 1.5f + rand() % (MAP_WIDTH - 3) * TILE_WIDTH ,
TILE_HEIGHT * 1.5f + rand() % (MAP_HEIGHT - 3) * TILE_HEIGHT,
boltLifeTime, shotType, 0);
bolt->setDamages(8 + divinity.level * multBonus);
float velx = 400 * cos(i);
float vely = 400 * sin(i);
bolt->setVelocity(Vector2D(velx, vely));
if (divinity.divinity == DivinityAir)
{
bolt->setFlying(true);
bolt->setLifetime(-1.0f);
}
else
{
bolt->setLifetime(8.0f);
}
bolt->setViscosity(1.0f);
bolt->setGoThrough(true);
bolt->setFromPlayer(false);
}
}
void PlayerEntity::divineDestroyUndead()
{
game().destroyUndead(40);
}
void PlayerEntity::divineIce()
{
EntityManager::EntityList* entityList = EntityManager::getInstance().getList();
EntityManager::EntityList::iterator it;
for (it = entityList->begin (); it != entityList->end ();)
{
GameEntity *e = *it;
it++;
if (e->getType() >= ENTITY_ENEMY && e->getType() <= ENTITY_ENEMY_MAX)
{
EnemyEntity* enemy = dynamic_cast<EnemyEntity*>(e);
enemy->setSpecialState(SpecialStateIce, true, 10.0f, 0.1f, 0.0f);
}
}
}
void PlayerEntity::divineRepulse()
{
EntityManager::EntityList* entityList = EntityManager::getInstance().getList();
EntityManager::EntityList::iterator it;
for (it = entityList->begin (); it != entityList->end ();)
{
GameEntity *e = *it;
it++;
if (e->getType() >= ENTITY_ENEMY && e->getType() <= ENTITY_ENEMY_MAX)
{
EnemyEntity* enemy = dynamic_cast<EnemyEntity*>(e);
enemy->hurt(getHurtParams
(8,
ShotTypeStandard,
0,
false,
SourceTypeBolt,
EnemyTypeNone,
false));
enemy->giveRecoil(true, Vector2D(x, y).vectorTo(Vector2D(enemy->getX(), enemy->getY()), 700.0f), 2.0f);
}
}
// effect
for (int i = 0; i < 40; i++)
{
SpriteEntity* spriteRock = new SpriteEntity(
ImageManager::getInstance().getImage(IMAGE_CYCLOP),
x, y, 64, 64);
spriteRock->setZ(1000.0f);
spriteRock->setImagesProLine(20);
spriteRock->setFrame(rand() % 2 == 0 ? 38 : 58);
spriteRock->setSpin(-100 + rand()%200);
spriteRock->setVelocity(Vector2D(400 + rand()%400));
spriteRock->setFading(true);
spriteRock->setAge(-0.8f);
spriteRock->setLifetime(2.0f);
spriteRock->setType(ENTITY_EFFECT);
}
game().makeShake(1.0f);
SoundManager::getInstance().playSound(SOUND_EARTHQUAKE);
}
void PlayerEntity::divineProtection(float duration, float armorBonus)
{
setSpecialState(DivineStateProtection, true, 4.0f, 0.8f, 0.0f);
}
void PlayerEntity::divineHeal(int hpHealed)
{
hp += hpHealed;
if (hp > hpMax) hp = hpMax;
specialState[SpecialStatePoison].active = false;
divineInterventionDelay = WORSHIP_DELAY;
isRegeneration = false;
}
bool PlayerEntity::triggerDivinityBefore()
{
if (divinity.divinity > -1 && divinity.interventions < divinity.level - 1)
{
switch (divinity.divinity)
{
case DivinityHealer:
{
if (game().getUndeadCount() > 0 && rand() % 2 == 0)
{
SoundManager::getInstance().playSound(SOUND_OM);
incrementDivInterventions();
divineHeal(hpMax / 2);
divineDestroyUndead();
game().makeColorEffect(X_GAME_COLOR_WHITE, 0.45f);
return true;
}
break;
}
case DivinityFighter:
{
int r = rand() % 3;
if (r == 0) return false;
SoundManager::getInstance().playSound(SOUND_OM);
incrementDivInterventions();
divineHeal(hpMax / 3);
if (r == 1) divineProtection(10.0f, 0.8f);
else divineFury();
game().makeColorEffect(X_GAME_COLOR_RED, 0.45f);
return true;
break;
}
case DivinityIce:
{
int r = rand() % 3;
if (r == 0) return false;
SoundManager::getInstance().playSound(SOUND_OM);
incrementDivInterventions();
divineHeal(hpMax / 3);
if (r == 1)
{
divineIce();
game().makeColorEffect(X_GAME_COLOR_BLUE, 7.5f);
}
else
{
divineFury();
game().makeColorEffect(X_GAME_COLOR_BLUE, 0.5f);
}
return true;
break;
}
case DivinityStone:
{
int r = rand() % 2;
divineProtection(12.0f, 0.5f);
SoundManager::getInstance().playSound(SOUND_OM);
incrementDivInterventions();
divineHeal(hpMax / 3);
if (r == 0)
{
divineRepulse();
game().makeColorEffect(X_GAME_COLOR_BROWN, 3.0f);
}
else
{
divineFury();
game().makeColorEffect(X_GAME_COLOR_BROWN, 0.5f);
}
return true;
break;
}
case DivinityAir:
{
int r = rand() % 3;
if (r == 0) return false;
SoundManager::getInstance().playSound(SOUND_OM);
incrementDivInterventions();
divineHeal(hpMax / 3);
/*if (r == 1)
{
divineIce();
game().makeColorEffect(X_GAME_COLOR_BLUE, 7.5f);
}
else*/
{
divineFury();
game().makeColorEffect(X_GAME_COLOR_VIOLET, 0.5f);
}
return true;
break;
}
}
}
return false;
}
void PlayerEntity::triggerDivinityAfter()
{
if (divinity.divinity > -1 && divinity.interventions < divinity.level - 1)
{
switch (divinity.divinity)
{
case DivinityHealer:
{
SoundManager::getInstance().playSound(SOUND_OM);
incrementDivInterventions();
divineHeal(hpMax);
break;
}
//case DivinityFighter:
default:
{
SoundManager::getInstance().playSound(SOUND_OM);
incrementDivInterventions();
divineHeal(hpMax / 2);
break;
}
}
game().testAndAddMessageToQueue((EnumMessages)(MsgInfoDivIntervention));
}
}
void PlayerEntity::addPiety(int n)
{
if (n > 0 && equip[EQUIP_BOOK_PRAYER_I]) n *= 1.5f;
int oldLevel = divinity.level;
divinity.piety += n;
if (divinity.piety >= DIVINITY_LEVEL_TRESHOLD[MAX_DIVINITY_LEVEL - 1])
{
divinity.piety = DIVINITY_LEVEL_TRESHOLD[MAX_DIVINITY_LEVEL - 1];
divinity.percentsToNextLevels = 1.0f;
game().registerAchievement(AchievementPietyMax);
divinity.level = MAX_DIVINITY_LEVEL + 1;
}
else
{
int i = 0;
while (divinity.piety > DIVINITY_LEVEL_TRESHOLD[i] && i < (MAX_DIVINITY_LEVEL + 1)) i++;
divinity.level = i + 1;
if (divinity.level == 1)
divinity.percentsToNextLevels = (float)divinity.piety / (float)DIVINITY_LEVEL_TRESHOLD[0];
else
divinity.percentsToNextLevels
= (float)(divinity.piety - DIVINITY_LEVEL_TRESHOLD[divinity.level - 2])
/ (float)(DIVINITY_LEVEL_TRESHOLD[divinity.level - 1] - DIVINITY_LEVEL_TRESHOLD[divinity.level - 2]);
}
if (divinity.level > oldLevel)
{
SoundManager::getInstance().playSound(SOUND_OM);
divineInterventionDelay = WORSHIP_DELAY / 2;
isRegeneration = false;
pietyLevelUp();
computePlayer();
}
else if (divinity.level < oldLevel)
{
computePlayer();
}
}
void PlayerEntity::pietyLevelUp()
{
std::string label = "";
switch (divinity.divinity)
{
case DivinityFighter:
label = "div_fighter_lvl";
break;
case DivinityHealer:
if (divinity.level == 2) label = "div_healer_lvl_2";
else label = "div_healer_lvl_3";
break;
case DivinityIce:
if (divinity.level == 3) label = "div_ice_lvl_3";
else if (divinity.level == 4) label = "div_ice_lvl_4";
else if (divinity.level == 5) label = "div_ice_lvl_5";
break;
case DivinityStone:
if (divinity.level == 3) label = "div_stone_lvl_3";
else if (divinity.level == 4) label = "div_stone_lvl_4";
else if (divinity.level == 5) label = "div_stone_lvl_5";
break;
case DivinityAir:
if (divinity.level == 4) label = "div_air_lvl_4";
else label = "div_air_lvl";
break;
}
if (label.compare("") != 0) game().addDivLevelMessageToQueue(label);
}
void PlayerEntity::incrementDivInterventions()
{
divinity.interventions++;
addPiety(-divinity.piety * (equip[EQUIP_BOOK_PRAYER_II] ? 0.04f : 0.08f));
}
void PlayerEntity::worship(enumDivinityType id)
{
int oldPiety = divinity.piety;
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 SpellFairy:
activeSpell.delayMax = 10.0f;
activeSpell.frame = ItemSpellFairy - FirstEquipItem;
break;
case SpellNone:
break;
}
if (fromSaveInFight) activeSpell.delay = 1.0f;
else activeSpell.delay = activeSpell.delayMax;
}
void PlayerEntity::castSpell()
{
if (playerStatus != playerStatusPlaying) return;
if (canCastSpell())
{
activeSpell.delay = equip[EQUIP_BOOK_MAGIC_I] ? activeSpell.delayMax * 0.8f : activeSpell.delayMax;
switch (activeSpell.spell)
{
case SpellTeleport:
castTeleport();
break;
case SpellSlimeExplode:
castSummonsSlimeExplode();
break;
case SpellFireball:
castFireball();
break;
case SpellFreeze:
spellAnimationDelay = spellAnimationDelayMax;
castFreeze();
break;
case SpellEarthquake:
spellAnimationDelay = spellAnimationDelayMax;
castEarthquake();
break;
case SpellProtection:
spellAnimationDelay = spellAnimationDelayMax;
castProtection();
break;
case SpellWeb:
castWeb();
break;
case SpellFlower:
spellAnimationDelay = spellAnimationDelayMax;
castSummonsFlower();
break;
case SpellFairy:
castTransmuteFairy();
break;
case SpellNone:
break;
}
}
}
bool PlayerEntity::canCastSpell()
{
return activeSpell.spell != SpellNone && activeSpell.delay <= 0.0f;
}
void PlayerEntity::castTeleport()
{
bool ok = false;
int xm, ym;
float xNew = x, yNew = y;
invincibleDelay = equip[EQUIP_BOOK_MAGIC_II] ? 2.5f : 2.0f;
SoundManager::getInstance().playSound(SOUND_TELEPORT);
game().makeColorEffect(X_GAME_COLOR_VIOLET, 0.3f);
for(int i=0; i < 6; i++)
{
generateStar(sf::Color(50, 50, 255, 255));
generateStar(sf::Color(200, 200, 255, 255));
}
int counter = 150;
while (!ok && counter > 0)
{
counter--;
int distanceMin = 20000;
if (counter < 50) distanceMin = 30000;
else if (counter < 100) distanceMin = 25000;
xm = 1 +rand() % (MAP_WIDTH - 3);
ym = 1 +rand() % (MAP_HEIGHT - 3);
if (game().getCurrentMap()->isWalkable(xm, ym))
{
// enemy or bolt ?
EntityManager::EntityList* entityList =EntityManager::getInstance().getList();
EntityManager::EntityList::iterator it;
bool isBad = false;
xNew = xm * TILE_WIDTH + TILE_WIDTH * 0.5f;
yNew = ym * TILE_HEIGHT+ TILE_HEIGHT * 0.5f;
for (it = entityList->begin (); !isBad && it != entityList->end ();)
{
GameEntity *e = *it;
it++;
if ((e->getType() >= ENTITY_ENEMY && e->getType() <= ENTITY_ENEMY_MAX_COUNT) || e->getType() == ENTITY_ENEMY_BOLT)
isBad = Vector2D(xNew, yNew).distance2(Vector2D(e->getX(), e->getY())) < distanceMin;
}
if (!isBad)
{
x = xNew;
y = yNew;
}
}
}
for(int i=0; i < 6; i++)
{
generateStar(sf::Color(50, 50, 255, 255));
generateStar(sf::Color(200, 200, 255, 255));
}
}
void PlayerEntity::initFallingGrid()
{
for (int i = 0; i < MAP_WIDTH; i++)
for (int j = 0; j < MAP_HEIGHT; j++)
fallingGrid[i][j] = false;
}
void PlayerEntity::fallRock()
{
int rx, ry;
do
{
rx = 1 + rand() % (MAP_WIDTH - 2);
ry = 1 + rand() % (MAP_HEIGHT - 2);
}
while (fallingGrid[rx][ry]);
fallingGrid[rx][ry] = true;
new FallingRockEntity(rx * TILE_WIDTH + TILE_WIDTH / 2,
ry * TILE_HEIGHT + TILE_HEIGHT / 2,
rand() % 3,
true);
}
void PlayerEntity::castSummonsSlimeExplode()
{
SlimeEntity* slime = new SlimeEntity( ((int)(x) / TILE_WIDTH) * TILE_WIDTH + TILE_WIDTH * 0.5f,
y - 5, SlimeTypeViolet, true);
slime->makePet(facingDirection);
game().makeColorEffect(X_GAME_COLOR_VIOLET, 0.3f);
}
void PlayerEntity::castFireball()
{
SoundManager::getInstance().playSound(SOUND_FIREBALL);
game().makeColorEffect(X_GAME_COLOR_RED, 0.3f);
enumShotType boltType = ShotTypeFire;
unsigned int shotLevel = 2;
BoltEntity* bolt = new BoltEntity(x, getBolPositionY(), boltLifeTime + 0.5f, boltType, shotLevel);
int boltDamage = fireDamages * (equip[EQUIP_BOOK_MAGIC_II] ? 4 : 3);
if (equip[EQUIP_BOOK_MAGIC_II] && boltDamage < 32) boltDamage = 32;
else if (!equip[EQUIP_BOOK_MAGIC_II] && boltDamage < 24) boltDamage = 24;
bolt->setDamages(boltDamage);
bolt->setGoThrough(true);
float velx = 0.0f, vely = 0.0f;
if (facingDirection == 4) velx = -fireVelocity;
else if (facingDirection == 8) vely = -fireVelocity;
else if (facingDirection == 2) vely = fireVelocity;
else velx = fireVelocity;
bolt->setVelocity(Vector2D(velx, vely));
}
void PlayerEntity::castFreeze()
{
int iceLevel = equip[EQUIP_BOOK_MAGIC_II] ? 2 : 1;
for (float i = 0.0f; i < 2 * PI; i += PI / 8)
{
BoltEntity* bolt1 = new BoltEntity(x, getBolPositionY(), boltLifeTime, ShotTypeIce, iceLevel);
bolt1->setDamages(1);
float velx = fireVelocity * cos(i);
float vely = fireVelocity * sin(i);
bolt1->setVelocity(Vector2D(velx, vely));
}
game().makeColorEffect(X_GAME_COLOR_BLUE, 0.3f);
SoundManager::getInstance().playSound(SOUND_SPELL_FREEZE);
}
void PlayerEntity::castEarthquake()
{
initFallingGrid();
int nbIterations = equip[EQUIP_BOOK_MAGIC_II] ? 24 : 22;
for (int i = 0; i < nbIterations; i++) fallRock();
game().makeShake(0.25f);
game().makeColorEffect(X_GAME_COLOR_BROWN, 0.3f);
SoundManager::getInstance().playSound(SOUND_EARTHQUAKE);
}
void PlayerEntity::castProtection()
{
protection.active = true;
protection.value = equip[EQUIP_BOOK_MAGIC_II] ? 0.6f : 0.4f;
protection.timer = 10.0f;
computePlayer();
game().makeColorEffect(X_GAME_COLOR_BLUE, 0.3f);
SoundManager::getInstance().playSound(SOUND_SPELL_SHIELD);
}
void PlayerEntity::castWeb()
{
SoundManager::getInstance().playSound(SOUND_SPIDER_WEB);
int nbWeb = equip[EQUIP_BOOK_MAGIC_II] ? 4 : 3;
for (int i = 0; i < nbWeb; i++)
{
SpiderWebEntity* web = new SpiderWebEntity(x, y, true);
float webVel = 100 + rand()% 500;
float webAngle = -60 + rand() % 120;
webAngle = PI * webAngle / 180.0f;
if (facingDirection == 4) webAngle += PI;
else if (facingDirection == 8) webAngle -= PI * 0.5;
else if (facingDirection == 2) webAngle += PI * 0.5;
web->setVelocity(Vector2D(webVel * cos(webAngle), webVel * sin(webAngle)));
}
}
void PlayerEntity::castSummonsFlower()
{
SoundManager::getInstance().playSound(SOUND_INVOKE);
EvilFlowerEntity* flower = new EvilFlowerEntity(x, y, FlowerTypePet);
flower->setLifetime(equip[EQUIP_BOOK_MAGIC_II] ? 45 : 35);
if (equip[EQUIP_BOOK_MAGIC_II]) flower->setFireDelayMax(EVIL_FLOWER_FIRE_DELAY * 0.8f);
}
void PlayerEntity::castTransmuteFairy()
{
if (isFairyTransmuted)
{
movingStyle = movWalking;
if (isCollidingWithMap())
movingStyle = movFlying;
else
{
SoundManager::getInstance().playSound(SOUND_INVOKE);
isFairyTransmuted = false;
computePlayer();
for(int i=0; i < 6; i++)
{
generateStar(sf::Color(50, 50, 255, 255));
generateStar(sf::Color(200, 200, 255, 255));
}
}
}
else
{
SoundManager::getInstance().playSound(SOUND_INVOKE);
isFairyTransmuted = true;
computePlayer();
for(int i=0; i < 6; i++)
{
generateStar(sf::Color(50, 50, 255, 255));
generateStar(sf::Color(200, 200, 255, 255));
}
}
}
diff --git a/src/WitchBlastGame.cpp b/src/WitchBlastGame.cpp
index c2af83e..37751bc 100644
--- a/src/WitchBlastGame.cpp
+++ b/src/WitchBlastGame.cpp
@@ -1,6889 +1,6909 @@
/** This file is part of Witch Blast.
*
* Witch Blast is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Witch Blast is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Witch Blast. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WitchBlastGame.h"
#include "sfml_game/SpriteEntity.h"
#include "sfml_game/TileMapEntity.h"
#include "DungeonMap.h"
#include "sfml_game/ImageManager.h"
#include "sfml_game/SoundManager.h"
#include "sfml_game/EntityManager.h"
#include "Constants.h"
#include "RatEntity.h"
#include "BlackRatEntity.h"
#include "GreenRatEntity.h"
#include "KingRatEntity.h"
#include "CyclopsEntity.h"
#include "GiantSpiderEntity.h"
#include "GiantSlimeEntity.h"
#include "ButcherEntity.h"
#include "BatEntity.h"
#include "ImpEntity.h"
#include "SlimeEntity.h"
#include "LargeSlimeEntity.h"
#include "PumpkinEntity.h"
#include "ChestEntity.h"
#include "EvilFlowerEntity.h"
#include "BubbleEntity.h"
#include "ItemEntity.h"
#include "WitchEntity.h"
#include "CauldronEntity.h"
#include "SnakeEntity.h"
#include "GhostEntity.h"
#include "ZombieEntity.h"
#include "ZombieDarkEntity.h"
#include "BogeymanEntity.h"
#include "LittleSpiderEntity.h"
#include "SpiderEggEntity.h"
#include "FranckyEntity.h"
#include "VampireEntity.h"
#include "ObstacleEntity.h"
#include "ArtefactDescriptionEntity.h"
#include "PnjEntity.h"
#include "TextEntity.h"
#include "StandardRoomGenerator.h"
#include "Scoring.h"
#include "MessageGenerator.h"
#include "TextMapper.h"
#include "SlimePetEntity.h"
#include <iostream>
#include <sstream>
#include <fstream>
#include <ctime>
#include <algorithm>
#define ONLINE_MODE
#define LEVEL_TEST_MODE
#ifdef ONLINE_MODE
#include "OnlineScoring.h"
#endif // ONLINE_SCORING
const float PORTRAIT_DIAPLAY_TIME = 5.0f;
const unsigned int ACHIEV_LINES = 2;
static std::string intToString(int n)
{
std::ostringstream oss;
oss << n;
return oss.str();
}
static std::string keyToString(sf::Keyboard::Key key)
{
std::string s = "Unknown";
if (key >= sf::Keyboard::A && key <= sf::Keyboard::Z)
{
char c = 'A' + key - sf::Keyboard::A;
std::ostringstream oss;
oss << c;
s = oss.str();
}
else if (key >= sf::Keyboard::Num0 && key <= sf::Keyboard::Num9)
{
char c = '0' + key - sf::Keyboard::Num0;
std::ostringstream oss;
oss << c;
s = oss.str();
}
else if (key >= sf::Keyboard::Numpad0 && key <= sf::Keyboard::Numpad9)
{
char c = '0' + key - sf::Keyboard::Num0;
std::ostringstream oss;
oss << c << " (numpad)";
s = oss.str();
}
else if (key >= sf::Keyboard::F1 && key <= sf::Keyboard::F15)
{
std::ostringstream oss;
oss << "F" << (int)key - (int)sf::Keyboard::F1;
s = oss.str();
}
else if (key == sf::Keyboard::Escape) s = "Escape";
else if (key == sf::Keyboard::LControl) s = "Left Control";
else if (key == sf::Keyboard::LShift) s = "Left Shift";
else if (key == sf::Keyboard::LAlt) s = "Left Alt";
else if (key == sf::Keyboard::LSystem) s = "Left System";
else if (key == sf::Keyboard::RControl) s = "Right Control";
else if (key == sf::Keyboard::RShift) s = "Right Shift";
else if (key == sf::Keyboard::RAlt) s = "Right Alt";
else if (key == sf::Keyboard::RSystem) s = "Right System";
else if (key == sf::Keyboard::Space) s = "Space";
else if (key == sf::Keyboard::Tab) s = "Tab";
else if (key == sf::Keyboard::Left) s = "Left arrow";
else if (key == sf::Keyboard::Right) s = "Right arrow";
else if (key == sf::Keyboard::Up) s = "Up arrow";
else if (key == sf::Keyboard::Down) s = "Down arrow";
else if (key == sf::Keyboard::LBracket) s = "[";
else if (key == sf::Keyboard::RBracket) s = "]";
else if (key == sf::Keyboard::SemiColon) s = ";";
else if (key == sf::Keyboard::Comma) s = ",";
else if (key == sf::Keyboard::Period) s = ".";
else if (key == sf::Keyboard::Quote) s = "Quote";
else if (key == sf::Keyboard::Slash) s = "/";
else if (key == sf::Keyboard::BackSlash) s = "\\";
else if (key == sf::Keyboard::Tilde) s = "~";
else if (key == sf::Keyboard::Equal) s = "=";
else if (key == sf::Keyboard::Dash) s = "_";
else if (key == sf::Keyboard::Return) s = "Return";
else if (key == sf::Keyboard::BackSpace) s = "BackSpace";
else if (key == sf::Keyboard::PageUp) s = "Page Up";
else if (key == sf::Keyboard::PageDown) s = "Page Down";
else if (key == sf::Keyboard::End) s = "End";
else if (key == sf::Keyboard::Home) s = "Home";
else if (key == sf::Keyboard::Insert) s = "Insert";
else if (key == sf::Keyboard::Delete) s = "Delete";
else if (key == sf::Keyboard::Add) s = "+";
else if (key == sf::Keyboard::Subtract) s = "-";
else if (key == sf::Keyboard::Multiply) s = "*";
else if (key == sf::Keyboard::Divide) s = "/";
else if (key == sf::Keyboard::Pause) s = "Pause";
else if (key == sf::Keyboard::KeyCount) s = "Key Count";
return s;
}
std::map<EnumWorldEvents, EnumMessages> eventToMessage =
{
{ EventMeetRatsOrBats, MsgInfoRatsBats },
{ EventMeetSnakes, MsgInfoSnakes },
{ EventMeetWitches, MsgInfoWitches },
{ EventGetCoin, MsgInfoGold },
{ EventGetFamiliar, MsgInfoFamiliar },
{ EventBeingHurted, MsgTutoHeal },
{ EventFindShop, MsgTutoShops },
{ EventFindBossDoor, MsgTutoBossDoor },
{ EventFindChallengeDoor, MsgTutoChallengeDoor },
{ EventFindTemple, MsgTutoTemple },
{ EventGetItem, MsgTutoItems },
{ EventGetSpecialShot, MsgTutoShots },
{ EventGetSpell, MsgTutoSpell },
{ EventAchievement, MsgTutoAchievements },
{ EventConsumable, MsgTutoConsumables },
{ EventPotion, MsgTutoPotions },
};
// author: AFS
// source: https://github.com/LaurentGomila/SFML/wiki/Source:-Letterbox-effect-using-a-view
static sf::View getLetterboxView(sf::View view, int windowWidth, int windowHeight)
{
// Compares the aspect ratio of the window to the aspect ratio of the view,
// and sets the view's viewport accordingly in order to archieve a letterbox effect.
// A new view (with a new viewport set) is returned.
float windowRatio = windowWidth / (float) windowHeight;
float viewRatio = view.getSize().x / (float) view.getSize().y;
float sizeX = 1;
float sizeY = 1;
float posX = 0;
float posY = 0;
bool horizontalSpacing = true;
if (windowRatio < viewRatio)
horizontalSpacing = false;
// If horizontalSpacing is true, the black bars will appear on the left and right side.
// Otherwise, the black bars will appear on the top and bottom.
if (horizontalSpacing)
{
sizeX = viewRatio / windowRatio;
posX = (1 - sizeX) / 2.0;
}
else
{
sizeY = windowRatio / viewRatio;
posY = (1 - sizeY) / 2.0;
}
view.setViewport( sf::FloatRect(posX, posY, sizeX, sizeY) );
return view;
}
static sf::View getFullScreenLetterboxView(sf::View view, int clientWidth, int clientHeight)
{
sf::View returnView(sf::FloatRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
float clientRatio = clientWidth / (float) clientHeight;
float viewRatio = view.getSize().x / (float) view.getSize().y;
float sizeX = 1;
float sizeY = 1;
float posX = 0;
float posY = 0;
bool horizontalSpacing = true;
if (clientRatio > viewRatio)
horizontalSpacing = false;
// If horizontalSpacing is true, the black bars will appear on the left and right side.
// Otherwise, the black bars will appear on the top and bottom.
if (horizontalSpacing)
{
sizeX = clientRatio / viewRatio;
posX = (1 - sizeX) / 2.0;
}
else
{
sizeY = viewRatio / clientRatio;
posY = (1 - sizeY) / 2.0;
}
returnView.setViewport( sf::FloatRect(posX, posY, sizeX, sizeY) );
return returnView;
}
namespace
{
WitchBlastGame* gameptr;
}
WitchBlastGame::WitchBlastGame()
{
gameptr = this;
gameFromSaveFile = false;
configureFromFile();
if (parameters.vsync == false)
{
//app->setVerticalSyncEnabled(false);
app->setFramerateLimit(60);
}
// Fullscreen ?
if (parameters.fullscreen)
{
create(SCREEN_WIDTH, SCREEN_HEIGHT, APP_NAME + " V" + APP_VERSION, true, parameters.vsync);
sf::View view = app->getDefaultView();
view = getFullScreenLetterboxView( view, SCREEN_WIDTH, SCREEN_HEIGHT );
app->setView(view);
}
else
{
create(SCREEN_WIDTH, SCREEN_HEIGHT, APP_NAME + " V" + APP_VERSION, false, parameters.vsync);
}
// loading resources
const char *const images[] =
{
"media/player_0.png", "media/player_1.png",
"media/bolt.png", "media/tiles.png",
"media/rat.png", "media/minimap.png",
"media/map_background.png",
"media/items.png", "media/items_equip.png",
"media/items.png", "media/items_equip.png",
"media/chest.png", "media/bat.png",
"media/evil_flower.png", "media/slime.png",
"media/imp.png", "media/spider_egg.png",
"media/spider_web.png", "media/little_spider.png",
"media/bubble.png", "media/eyeball.png",
"media/witch.png",
"media/cauldron.png", "media/snake.png",
"media/pumpkin.png", "media/ghost.png",
"media/zombie.png", "media/bogeyman.png",
"media/butcher.png", "media/giant_slime.png",
"media/king_rat.png", "media/cyclops.png",
"media/giant_spider.png", "media/francky.png",
"media/vampire.png", "media/vampire_bat.png",
"media/vampire_part.png",
"media/blood.png",
"media/corpses.png", "media/corpses_big.png",
"media/star.png", "media/star2.png",
"media/hurt_impact.png",
"media/interface.png", "media/hud_shots.png",
"media/explosion.png", "media/keys_qwer.png",
"media/keys_azer.png", "media/message_icons.png",
"media/night.png", "media/title.png",
"media/overlay_00.png", "media/light_cone.png",
"media/divinity.png",
"media/pnj.png", "media/fairy.png",
"media/key_area.png",
"media/ui_life.png", "media/ui_mana.png",
"media/ui_spells.png", "media/ui_message.png",
"media/ui_top_layer.png", "media/ui_achiev.png",
"media/fog.png", "media/title_animation.png",
"media/splatter.png", "media/witch_intro.png",
"media/item_description.png", "media/death_certificate.png",
"media/achievements.png", "media/boss_pictures.png",
"media/portrait_part.png", "media/dungeon_random.png",
"media/dungeon_objects.png", "media/shadows_standard.png",
"media/shadows_corners.png", "media/shadows_medium.png",
"media/shadows_small.png", "media/doors.png",
"media/destroyable_objects.png",
};
for (const char *const filename : images)
ImageManager::getInstance().addImage(filename);
const char *const sounds[] =
{
"media/sound/blast00.ogg", "media/sound/blast01.ogg",
"media/sound/blast_elec.ogg", "media/sound/blast_fire.ogg",
"media/sound/blast_ice.ogg", "media/sound/blast_illusion.ogg",
"media/sound/blast_poison.ogg", "media/sound/blast_stone.ogg",
"media/sound/door_closing.ogg", "media/sound/door_opening.ogg",
"media/sound/chest_opening.ogg", "media/sound/impact.ogg",
"media/sound/bonus.ogg", "media/sound/drink.ogg",
"media/sound/eat.ogg", "media/sound/player_hit.ogg",
"media/sound/player_die.ogg", "media/sound/ennemy_dying.ogg",
"media/sound/coin.ogg", "media/sound/pay.ogg",
"media/sound/wall_impact.ogg", "media/sound/big_wall_impact.ogg",
"media/sound/king_rat_cry_1.ogg", "media/sound/king_rat_cry_2.ogg",
"media/sound/king_rat_die.ogg", "media/sound/slime_jump.ogg",
"media/sound/slime_impact.ogg", "media/sound/slime_impact_weak.ogg",
"media/sound/slime_impact_boss.ogg",
"media/sound/slime_smash.ogg", "media/sound/ice_charge.ogg",
"media/sound/electric.ogg", "media/sound/select.ogg",
"media/sound/heart.ogg", "media/sound/rat_die.ogg",
"media/sound/bat_die.ogg", "media/sound/imp_hurt.ogg",
"media/sound/imp_die.ogg", "media/sound/rock_impact.ogg",
"media/sound/rock_impact_medium.ogg", "media/sound/rock_impact_heavy.ogg",
"media/sound/throw.ogg", "media/sound/cyclop00.ogg",
"media/sound/cyclop_die.ogg", "media/sound/cyclops_impact.ogg",
"media/sound/butcher_00.ogg", "media/sound/butcher_01.ogg",
"media/sound/butcher_hurt.ogg", "media/sound/butcher_die.ogg",
"media/sound/vib.ogg",
"media/sound/boom_00.ogg", "media/sound/clang_00.ogg",
"media/sound/bubble_00.ogg", "media/sound/bubble_01.ogg",
"media/sound/trap.ogg", "media/sound/egg_smash_00.ogg",
"media/sound/egg_smash_01.ogg", "media/sound/spider_walking.ogg",
"media/sound/spider_web.ogg", "media/sound/spider_hurt.ogg",
"media/sound/spider_die.ogg", "media/sound/little_spider_die.ogg",
"media/sound/witch_00.ogg", "media/sound/witch_01.ogg",
"media/sound/witch_die_00.ogg", "media/sound/witch_die_01.ogg",
"media/sound/witch_02.ogg", "media/sound/invoke.ogg",
"media/sound/cauldron.ogg", "media/sound/cauldron_die.ogg",
"media/sound/snake_die.ogg", "media/sound/pumpkin_00.ogg",
"media/sound/pumpkin_01.ogg", "media/sound/pumpkin_die.ogg",
"media/sound/critical.ogg",
"media/sound/gong.ogg", "media/sound/teleport.ogg",
"media/sound/spell_charge.ogg", "media/sound/fireball.ogg",
"media/sound/message.ogg", "media/sound/earthquake.ogg",
"media/sound/spell_freeze.ogg", "media/sound/spell_shield.ogg",
"media/sound/heavy_step_00.ogg", "media/sound/heavy_step_01.ogg",
"media/sound/night.ogg", "media/sound/grumble.ogg",
"media/sound/zombie_00.ogg", "media/sound/zombie_01.ogg",
"media/sound/zombie_attack.ogg", "media/sound/zombie_die.ogg",
"media/sound/ghost.ogg", "media/sound/ghost_die.ogg",
"media/sound/electricity.ogg",
"media/sound/electric_blast.ogg", "media/sound/francky_00.ogg",
"media/sound/francky_01.ogg", "media/sound/francky_02.ogg",
"media/sound/francky_die.ogg", "media/sound/om.ogg",
"media/sound/glass.ogg", "media/sound/hiccup.ogg",
"media/sound/splatch.ogg", "media/sound/intro_witch.ogg",
"media/sound/force_field.ogg", "media/sound/door_opening_boss.ogg",
"media/sound/achievement.ogg",
"media/sound/vampire_flying.ogg", "media/sound/vampire_flap.ogg",
"media/sound/vampire_sonic.ogg", "media/sound/vampire_laughing.ogg",
"media/sound/vampire_transform_bolt.ogg", "media/sound/vampire_transform_bat.ogg",
"media/sound/vampire_hypnosis.ogg", "media/sound/vampire_cry.ogg",
"media/sound/vampire_dying.ogg", "media/sound/ice_block.ogg",
"media/sound/bogeyman_die.ogg", "media/sound/bogeyman_attack.ogg",
"media/sound/bogeyman_vortex_00.ogg", "media/sound/bogeyman_vortex_01.ogg",
"media/sound/barrel_hit.ogg", "media/sound/barrel_smash.ogg",
};
// AA in fullscreen
if (parameters.fullscreen) enableAA(true);
// game main client position in the UI
xOffset = OFFSET_X;
yOffset = OFFSET_Y;
SoundManager::getInstance().setVolume(parameters.soundVolume);
for (const char *const filename : sounds)
{
SoundManager::getInstance().addSound(filename);
}
if (font.loadFromFile("media/DejaVuSans-Bold.ttf"))
{
myText.setFont(font);
}
miniMap = NULL;
currentMap = NULL;
currentFloor = NULL;
lastScore.score = 0;
lastScore.name = "";
lastScore.level = 0;
int i;
for (i = 0; i < NB_X_GAME; i++) xGame[i].active = false;
for (i = 0; i < NUMBER_EQUIP_ITEMS; i++) equipNudeToDisplay[i] = false;
for (i = 0; i < NB_MESSAGES; i++) gameMessagesToSkip[i] = false;
for (i = 0; i < NB_ACHIEVEMENTS; i++) achievementState[i] = AchievementUndone;
for (i = 0; i < NB_ENEMY; i++) globalData.killedMonster[i] = 0;
saveInFight.monsters.clear();
showLogical = false;
showGameTime = false;
uiSprites.shotsSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_HUD_SHOTS));
uiSprites.topLayer.setTexture(*ImageManager::getInstance().getImage(IMAGE_UI_TOP_LAYER));
uiSprites.topLayer.setPosition(0, 602);
uiSprites.msgBoxSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_UI_MESSAGE));
uiSprites.iconSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_MESSAGE_ICONS));
uiSprites.iconSprite.setPosition(12, 614);
uiSprites.mapBgSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_MAP_BACKGROUND));
uiSprites.mapBgSprite.setPosition(342, 23);
introScreenSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_INTRO));
titleSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_TITLE));
titleSprite.setOrigin(titleSprite.getTextureRect().width / 2, titleSprite.getTextureRect().height / 2);
scoreState = ScoreOK;
loadGameData();
loadHiScores();
receiveScoreFromServer();
srand(time(NULL));
}
void WitchBlastGame::enableAA(bool enable)
{
for (int i = 0; i < NB_IMAGES; i++)
{
if (i != IMAGE_TILES && i != IMAGE_DUNGEON_OBJECTS
&& i != IMAGE_TILES_SHADOW && i != IMAGE_TILES_SHADOW_CORNER && i != IMAGE_TILES_SHADOW_MEDIUM
&& i != IMAGE_MINIMAP
&& i != IMAGE_DOORS
&& i != IMAGE_FOG
&& i != IMAGE_ITEMS_PRES && i != IMAGE_ITEMS_EQUIP_PRES && i != IMAGE_CORPSES
&& i != IMAGE_CORPSES_BIG)
ImageManager::getInstance().getImage(i)->setSmooth(enable);
}
}
WitchBlastGame::~WitchBlastGame()
{
// cleaning all entities
EntityManager::getInstance().clean();
// cleaning data
if (miniMap != NULL) delete (miniMap);
if (currentFloor != NULL) delete (currentFloor);
if (sendScoreThread.joinable()) sendScoreThread.join();
if (receiveScoreThread.joinable()) receiveScoreThread.join();
}
DungeonMap* WitchBlastGame::getCurrentMap()
{
return currentMap;
}
GameFloor* WitchBlastGame::getCurrentFloor()
{
return currentFloor;
}
int WitchBlastGame::getFloorX()
{
return floorX;
}
int WitchBlastGame::getFloorY()
{
return floorY;
}
DungeonMapEntity* WitchBlastGame::getCurrentMapEntity()
{
return dungeonEntity;
}
PlayerEntity* WitchBlastGame::getPlayer()
{
return player;
}
Vector2D WitchBlastGame::getPlayerPosition()
{
return Vector2D(player->getX(), player->getY());
}
int WitchBlastGame::getLevel()
{
return level;
}
int WitchBlastGame::getChallengeLevel()
{
return challengeLevel;
}
bool WitchBlastGame::getShowLogical()
{
return showLogical;
}
float WitchBlastGame::getDeltaTime()
{
return deltaTime;
}
float WitchBlastGame::getGameTime()
{
return gameTime;
}
void WitchBlastGame::onUpdate()
{
if (gameState == gameStatePlaying)
{
if (isPlayerAlive) player->setItemToBuy(NULL);
EntityManager::getInstance().animate(deltaTime);
if (isPressing(KeyTimeControl, false))
{
EntityManager::getInstance().animate(deltaTime);
SoundManager::getInstance().playSound(SOUND_VIB, false);
}
if (isPlayerAlive) gameTime += deltaTime;
for (int i = 0; i < NB_X_GAME; i++)
{
if (xGame[i].active)
{
xGame[i].timer -= deltaTime;
if (xGame[i].timer <= 0.0f)
{
xGame[i].active = false;
if (i == (int)xGameTypeFade && xGame[i].param == X_GAME_FADE_OUT)
{
if (player->getPlayerStatus() == PlayerEntity::playerStatusGoingNext)
{
level++;
startNewLevel();
}
else
startNewGame(false, 1);
}
}
}
}
if (isPlayerAlive)
{
if (player->getHp() <= 0)
{
isPlayerAlive = false;
playMusic(MusicEnding);
}
}
}
else if (gameState == gameStatePlayingDisplayBoss)
{
bossDisplayTimer += deltaTime;
if (bossDisplayTimer >= PORTRAIT_DIAPLAY_TIME) gameState = gameStatePlaying;
}
}
void WitchBlastGame::startNewGame(bool fromSaveFile, int startingLevel)
{
gameState = gameStateInit;
level = 1;
challengeLevel = 1;
gameTime = 0.0f;
initEvents();
scoreSaveFile = "";
interaction.active = false;
// cleaning all entities
EntityManager::getInstance().clean();
SoundManager::getInstance().stopSound(SOUND_NIGHT);
// cleaning the message queue
std::queue<messageStruct> empty;
std::swap( messagesQueue, empty );
// cleaning the achievements queue
std::queue<achievementStruct> empty2;
std::swap( achievementsQueue, empty2 );
// cleaning data
if (miniMap != NULL) delete (miniMap);
if (currentFloor != NULL) delete (currentFloor);
miniMap = NULL;
currentFloor = NULL;
// init in game menu
buildInGameMenu();
dungeonEntity = new DungeonMapEntity();
// the interface
uiSprites.gui.setTexture(*ImageManager::getInstance().getImage(IMAGE_INTERFACE));
// key symbol on the interface
uiSprites.keySprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEMS_EQUIP));
uiSprites.keySprite.setTextureRect(sf::IntRect(ITEM_WIDTH * EQUIP_BOSS_KEY, 0, ITEM_WIDTH, ITEM_HEIGHT));
uiSprites.keySprite.setPosition(737, 612);
miniMap = new GameMap(FLOOR_WIDTH, FLOOR_HEIGHT);
// minimap on the interface
miniMapEntity = new TileMapEntity(ImageManager::getInstance().getImage(IMAGE_MINIMAP), miniMap, 19, 15, 10);
miniMapEntity->setTileBox(20, 16);
miniMapEntity->setX(800);
miniMapEntity->setY(645);
miniMapEntity->setZ(10001.0f);
// doors
doorEntity[0] = new DoorEntity(8);
doorEntity[1] = new DoorEntity(4);
doorEntity[2] = new DoorEntity(2);
doorEntity[3] = new DoorEntity(6);
saveInFight.isFight = false;
if (fromSaveFile)
{
if (!loadGame())
{
fromSaveFile = false;
}
else
{
gameFromSaveFile = true;
playLevel(saveInFight.isFight);
}
}
if (!fromSaveFile)
{
gameFromSaveFile = false;
// the player
player = new PlayerEntity((TILE_WIDTH * MAP_WIDTH * 0.5f),
(TILE_HEIGHT * MAP_HEIGHT * 0.5f));
resetKilledEnemies();
randomizePotionMap();
if (startingLevel > 1)
{
for (int i = 1; i < startingLevel; i++)
{
level = i;
if (level == 3)
{
player->acquireItem(getItemSpell());
player->acquireItemAfterStance();
}
player->setHpMax(player->getHpMax() + 2 + rand() % 4);
item_equip_enum item = getRandomEquipItem(false, false);
player->acquireItem((enumItemType)(item + FirstEquipItem));
player->acquireItemAfterStance();
item = getRandomEquipItem(true, true);
player->acquireItem((enumItemType)(item + FirstEquipItem));
player->acquireItemAfterStance();
if (i % 2 == 0)
{
item = getRandomEquipItem(false, false);
player->acquireItem((enumItemType)(item + FirstEquipItem));
player->acquireItemAfterStance();
}
}
level++;
player->setHp(player->getHpMax());
player->setGold(8 + rand() % 45);
if (startingLevel > 2)
{
player->loadDivinity(rand() % NB_DIVINITY, (startingLevel - 2) * 200, 1, 0);
}
}
randomizePotionMap(); // TODO Load
startNewLevel();
}
}
void WitchBlastGame::startNewLevel()
{
// reset floor items
player->resetFloorItem();
// reset present items
resetPresentItems();
bool needShop = false;
// create the new level
if (currentFloor != NULL)
{
if (level > 1)
{
if (!currentFloor->hasRoomOfType(roomTypeMerchant)) needShop = true;
}
delete currentFloor;
}
currentFloor = new GameFloor(level);
if (needShop) currentFloor->setForceShop();
currentFloor->createFloor();
// center it
floorX = FLOOR_WIDTH / 2;
floorY = FLOOR_HEIGHT / 2;
// move the player
if (level == 1)
player->moveTo((TILE_WIDTH * MAP_WIDTH * 0.5f),
(TILE_HEIGHT * MAP_HEIGHT * 0.5f));
else
player->moveTo((TILE_WIDTH * MAP_WIDTH * 0.5f),
(TILE_HEIGHT * MAP_HEIGHT - 2 * TILE_HEIGHT));
// the boss room is closed
bossRoomOpened = false;
if (level <= 7) testAndAddMessageToQueue((EnumMessages)(MsgInfoLevel1 + level - 1));
if (level == 1)
{
testAndAddMessageToQueue(MsgTutoBasics);
testAndAddMessageToQueue(MsgTutoTips);
}
playLevel(false);
}
void WitchBlastGame::playLevel(bool isFight)
{
isPlayerAlive = true;
if (!isFight)
{
player->setVelocity(Vector2D(0.0f, 0.0f));
player->setPlayerStatus(PlayerEntity::playerStatusPlaying);
}
// first map is open
roomClosed = false;
// generate the map
refreshMap();
// items from save
currentMap->restoreMapObjects();
if (isFight)
{
checkEntering();
saveMapItems();
}
// populate with monsters
if (isFight)
{
auto monsters_save = saveInFight.monsters;
saveInFight.monsters.clear();
for (auto monster: monsters_save)
addMonster(monster.id, monster.x, monster.y);
if (currentMap->getRoomType() == roomTypeBoss) playMusic(MusicBoss);
else if (currentMap->getRoomType() == roomTypeChallenge) playMusic(MusicChallenge);
else playMusic(MusicDungeon);
}
else
playMusic(MusicDungeon);
// game time counter an state
lastTime = getAbsolutTime();
gameState = gameStatePlaying;
// fade in
xGame[xGameTypeFade].active = true;
xGame[xGameTypeFade].param = X_GAME_FADE_IN;
xGame[xGameTypeFade].timer = FADE_IN_DELAY;
float x0 = MAP_WIDTH * 0.5f * TILE_WIDTH;
float y0 = MAP_HEIGHT * 0.5f * TILE_HEIGHT + 40.0f;
std::ostringstream oss;
oss << tools::getLabel("level") << " " << level;
TextEntity* text = new TextEntity(oss.str(), 30, x0, y0);
text->setAlignment(ALIGN_CENTER);
text->setLifetime(2.5f);
text->setWeight(-36.0f);
text->setZ(1000);
text->setColor(TextEntity::COLOR_FADING_WHITE);
new ItemEntity(ItemScrollRevelation, 100, 100);
new ItemEntity(ItemScrollRevelation, 150, 100);
new ItemEntity(ItemPotion02, 200, 100);
new ItemEntity(ItemPotion01, 250, 100);
new ItemEntity(ItemBag, 450, 100);
+ new ItemEntity(ItemFloorMap, 500, 100);
}
void WitchBlastGame::prepareIntro()
{
EntityManager::getInstance().clean();
introSprites[0] = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_FOG));
introSprites[0]->setX(SCREEN_WIDTH / 2);
introSprites[0]->setY(SCREEN_HEIGHT - 202);
introSprites[1] = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_FOG));
introSprites[1]->setX(SCREEN_WIDTH / 2 + 970);
introSprites[1]->setY(SCREEN_HEIGHT - 202);
gameState = gameStateIntro;
gameTime = 0.0f;
introState = 0;
introSoundState = 0;
SoundManager::getInstance().playSound(SOUND_NIGHT);
}
void WitchBlastGame::updateIntro()
{
gameTime += deltaTime;
bool toMenu = false;
for (int i = 0; i < 2; i++)
{
introSprites[i]->setX(introSprites[i]->getX() - deltaTime * 35);
if (introSprites[i]->getX() < - SCREEN_WIDTH / 2) introSprites[i]->setX(introSprites[i]->getX() + 2 * SCREEN_WIDTH);
}
if (gameTime > 2.0f && introSoundState == 0)
{
SoundManager::getInstance().playSound(SOUND_INTRO_WITCH);
introSoundState++;
}
else if (gameTime > 7.0f && introSoundState == 1)
{
playMusic(MusicIntro);
introSoundState++;
}
if (introState == 0 && gameTime > 2.5f)
{
introState = 1;
introSprites[2] = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_TITLE_ANIM),
SCREEN_WIDTH / 2,
SCREEN_HEIGHT / 2,
310, 278, 3);
introSprites[2]->setZ(50);
}
else if (introState == 1)
{
int frame = (gameTime - 2.5f) * 8.0f;
if (frame > 16)
{
frame = 16;
introState = 2;
introSprites[3] = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_WITCH_INTRO));
introSprites[3]->setX(368 + 1000);
introSprites[3]->setY(424 - 480);
introSprites[3]->setZ(40);
EntityManager::getInstance().sortByZ();
}
introSprites[2]->setFrame(frame);
}
else if (introState == 2)
{
float xSprite = introSprites[3]->getX() - deltaTime * 800;
float ySprite = introSprites[3]->getY() + deltaTime * 400;
if (xSprite < 368)
{
introState = 3;
introSprites[3]->setDying(true);
EntityManager::getInstance().animate(deltaTime);
xSprite = 368;
ySprite = 424;
introSprites[4] = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_SPLATTER));
introSprites[4]->setX(368);
introSprites[4]->setY(424);
introSprites[4]->setZ(45);
introSprites[4]->setScale(0.5f, 0.5f);
EntityManager::getInstance().sortByZ();
SoundManager::getInstance().stopSound(SOUND_INTRO_WITCH);
SoundManager::getInstance().playSound(SOUND_SPLATCH);
}
else
{
introSprites[3]->setX(xSprite);
introSprites[3]->setY(ySprite);
introSprites[3]->setAngle(gameTime * 500);
}
}
else if (introState == 3)
{
float scale = introSprites[4]->getScaleX();
scale += deltaTime * 5.0f;
if (scale > 1.0f) scale = 1.0f;
introSprites[4]->setScale(scale, scale);
if (gameTime > 8.0f)
{
introState = 4;
introSprites[2]->setDying(true);
introSprites[4]->setDying(true);
EntityManager::getInstance().animate(deltaTime);
toMenu = true;
}
}
sf::Event event;
bool stopDemo = false;
while (app->pollEvent(event))
{
// Close window : exit
if (event.type == sf::Event::Closed)
{
//saveGameData();
app->close();
}
if (event.type == sf::Event::Resized)
{
enableAA(true);
sf::View view = app->getDefaultView();
view = getLetterboxView( view, event.size.width, event.size.height );
app->setView(view);
}
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::Escape) stopDemo = true;
}
}
if (isPressing(KeyFireDown, true)) stopDemo = true;
if (stopDemo)
{
if (introState < 4)
{
if (introState > 0) introSprites[2]->setDying(true);
if (introState == 2) introSprites[3]->setDying(true);
if (introState > 2) introSprites[4]->setDying(true);
EntityManager::getInstance().animate(deltaTime);
if (introState < 3)
{
SoundManager::getInstance().stopSound(SOUND_INTRO_WITCH);
SoundManager::getInstance().playSound(SOUND_SPLATCH);
}
}
toMenu = true;
}
if (toMenu)
{
if (introSoundState <= 1) playMusic(MusicIntro);
switchToMenu();
}
}
void WitchBlastGame::renderIntro()
{
app->draw(introScreenSprite);
titleSprite.setPosition(SCREEN_WIDTH / 2 - 15, 371);
if (introState == 4) app->draw(titleSprite);
EntityManager::getInstance().render(app);
}
void WitchBlastGame::updateRunningGame()
{
bool backToMenu = false;
bool escape = false;
// Process events
sf::Event event;
while (app->pollEvent(event))
{
// Close window : exit
if (event.type == sf::Event::Closed)
{
if (gameState == gameStatePlaying && !player->isDead()) saveGame();
saveGameData();
app->close();
}
if (event.type == sf::Event::Resized)
{
enableAA(true);
sf::View view = app->getDefaultView();
view = getLetterboxView( view, event.size.width, event.size.height );
app->setView(view);
}
if (event.type == sf::Event::MouseWheelMoved)
{
if (gameState == gameStatePlaying) player->selectNextShotType();
}
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::Escape)
{
escape = true;
}
if (event.key.code == sf::Keyboard::Return && gameState == gameStatePlaying)
{
if (!achievementsQueue.empty())
{
if (achievementsQueue.front().timer > 1.0f)
achievementsQueue.front().timer = 1.0f;
}
else if (!messagesQueue.empty())
{
if (messagesQueue.front().timer > 0.5f)
messagesQueue.front().timer = 0.5f;
}
}
if (event.key.code == sf::Keyboard::X)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LShift)) startNewGame(false, 1);
}
if (event.key.code >= sf::Keyboard::Num1 && event.key.code <= sf::Keyboard::Num8)
{
#ifdef LEVEL_TEST_MODE
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt) && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
{
startNewGame(false, event.key.code - sf::Keyboard::Num1 + 1);
}
else
#endif
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LShift))
{
player->dropConsumables(event.key.code - sf::Keyboard::Num1);
}
else
{
player->tryToConsume(event.key.code - sf::Keyboard::Num1);
}
}
if (event.key.code == sf::Keyboard::F1)
{
if (!isPlayerAlive && player->getDeathAge() > 3.5f)
{
if (scoreSaveFile.compare("") == 0) saveDeathScreen();
}
else
{
saveScreen();
}
}
if (event.key.code == sf::Keyboard::F2)
{
showLogical = !showLogical;
}
if (event.key.code == sf::Keyboard::F3)
{
showGameTime = !showGameTime;
}
// DEBUG
#ifdef TEST_MODE
/*if (event.key.code == sf::Keyboard::Delete)
{
StructHurt hurt;
hurt.critical = false;
hurt.damage = 1;
hurt.enemyType = EnemyTypeGhost; //EnemyTypeNone;
hurt.goThrough = false;
hurt.hurtingType = ShotTypeStandard;
hurt.level = 0;
hurt.sourceType = SourceTypeMelee;
player->hurt(hurt);
}*/
if (event.key.code == sf::Keyboard::F5)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
{
new BubbleEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 + 70,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2, BubbleTriple, 0);
new BubbleEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 - 70,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2, BubbleIce, 0);
}
else
{
initMonsterArray();
findPlaceMonsters(EnemyTypeRat, 1);
findPlaceMonsters(EnemyTypeRatBlack, 1);
findPlaceMonsters(EnemyTypeRatGreen, 1);
findPlaceMonsters(EnemyTypeRatHelmet, 1);
findPlaceMonsters(EnemyTypeRatBlackHelmet, 1);
}
}
if (event.key.code == sf::Keyboard::F6)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
{
new ButcherEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else
{
initMonsterArray();
findPlaceMonsters(EnemyTypeBat, 1);
findPlaceMonsters(EnemyTypeBatSkeleton, 2);
findPlaceMonsters(EnemyTypeImpBlue, 1);
findPlaceMonsters(EnemyTypeImpRed, 1);
}
}
if (event.key.code == sf::Keyboard::F7)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
{
new GiantSlimeEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else
{
initMonsterArray();
findPlaceMonsters(EnemyTypeEvilFlower, 1);
findPlaceMonsters(EnemyTypeEvilFlowerIce, 1);
findPlaceMonsters(EnemyTypeEvilFlowerFire, 1);
findPlaceMonsters(EnemyTypePumpkin, 1);
}
}
if (event.key.code == sf::Keyboard::F8)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
{
new CyclopsEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else
{
initMonsterArray();
findPlaceMonsters(EnemyTypeSlime, 1);
findPlaceMonsters(EnemyTypeSlimeBlue, 1);
findPlaceMonsters(EnemyTypeSlimeRed, 1);
findPlaceMonsters(EnemyTypeSlimeViolet, 1);
}
}
if (event.key.code == sf::Keyboard::F9)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
{
new KingRatEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else
{
initMonsterArray();
findPlaceMonsters(EnemyTypeSnake, 2);
findPlaceMonsters(EnemyTypeSnakeBlood, 2);
}
}
if (event.key.code == sf::Keyboard::F10)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
{
new GiantSpiderEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else
{
initMonsterArray();
findPlaceMonsters(EnemyTypeWitch, 1);
findPlaceMonsters(EnemyTypeWitchRed, 1);
findPlaceMonsters(EnemyTypeCauldron, 1);
findPlaceMonsters(EnemyTypeCauldronElemental, 1);
}
}
if (event.key.code == sf::Keyboard::F11)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
{
new FranckyEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else
{
initMonsterArray();
findPlaceMonsters(EnemyTypeSpiderEgg_invocated, 2);
findPlaceMonsters(EnemyTypeSpiderLittle_invocated, 2);
}
}
if (event.key.code == sf::Keyboard::F12)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
{
new VampireEntity(OFFSET_X + (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
OFFSET_Y + (MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else
{
initMonsterArray();
findPlaceMonsters(EnemyTypeZombie, 2);
findPlaceMonsters(EnemyTypeZombieDark, 2);
findPlaceMonsters(EnemyTypeGhost, 2);
findPlaceMonsters(EnemyTypeBogeyman, 2);
}
}
if (event.key.code == sf::Keyboard::F4)
{
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())
gameState = gameStatePlayingPause;
// POST EVENT
if (escape)
{
if (player->isDead()) backToMenu = true;
else if (gameState == gameStatePlaying) gameState = gameStatePlayingPause;
else if (gameState == gameStatePlayingPause) gameState = gameStatePlaying;
else if (gameState == gameStatePlayingDisplayBoss) gameState = gameStatePlaying;
}
if (player->isDead() && !xGame[xGameTypeFade].active && isPressing(KeyFireDown, true))
{
if (player->getDeathAge() < DEATH_CERTIFICATE_DELAY) player->setDeathAge(DEATH_CERTIFICATE_DELAY);
else backToMenu = true;
}
else if (gameState == gameStatePlayingPause)
{
if (isPressing(KeyDown, true))
{
menuInGame.index++;
if (menuInGame.index == menuInGame.items.size()) menuInGame.index = 0;
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
else if (isPressing(KeyUp, true))
{
if (menuInGame.index == 0) menuInGame.index = menuInGame.items.size() - 1;
else menuInGame.index--;
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
else if (isPressing(KeyFireDown, true))
{
switch (menuInGame.items[menuInGame.index].id)
{
case MenuStartNew:
case MenuStartOld:
case MenuKeys:
case MenuJoystick:
case MenuConfig:
case MenuTutoReset:
case MenuConfigBack:
case MenuLanguage:
case MenuCredits:
case MenuHiScores:
case MenuPlayerName:
case MenuVolumeMusic:
case MenuVolumeSound:
case MenuAchievements:
std::cout << "[ERROR] Bad Menu ID\n";
break;
case MenuExit:
backToMenu = true;
remove(SAVE_FILE.c_str());
break;
case MenuContinue:
gameState = gameStatePlaying;
break;
case MenuSaveAndQuit:
saveGame();
backToMenu = true;
break;
}
}
}
else if (gameState == gameStatePlaying)
{
if (player->canMove()) player->setVelocity(Vector2D(0.0f, 0.0f));
if (isPressing(KeyLeft, false))
{
if (isPressing(KeyUp, false))
player->move(7);
else if (isPressing(KeyDown, false))
player->move(1);
else
player->move(4);
}
else if (isPressing(KeyRight, false))
{
if (isPressing(KeyUp, false))
player->move(9);
else if (isPressing(KeyDown, false))
player->move(3);
else
player->move(6);
}
else if (isPressing(KeyUp, false))
{
player->move(8);
}
else if (isPressing(KeyDown, false))
{
player->move(2);
}
if (isPressing(KeyInteract, true))
{
if (!player->isDead() && interaction.active) player->interact(interaction.type, interaction.id);
}
if (isPressing(KeyFireSelect, true))
{
if (gameState == gameStatePlaying) player->selectNextShotType();
}
if (isPressing(KeySpell, true))
{
if (gameState == gameStatePlaying) player->castSpell();
}
player->resestFireDirection();
if (isPressing(KeyFireLeft, false))
player->fire(4);
else if (isPressing(KeyFireRight, false))
player->fire(6);
else if (isPressing(KeyFireUp, false))
player->fire(8);
else if (isPressing(KeyFireDown, false))
player->fire(2);
// alternative "one button" gameplay
else if (isPressing(KeyFire, false))
{
if (gameState == gameStatePlaying && isPressing(KeyFire, true))
firingDirection = player->getFacingDirection();
player->fire(firingDirection);
}
// alternative "firing with the mouse" gameplay
else if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
sf::Vector2i mousePosition = sf::Mouse::getPosition(*app);
int xm = mousePosition.x - player->getX();
int ym = mousePosition.y - player->getY();
if (abs(xm) >= abs(ym))
{
if (xm > 0) player->fire(6);
else player->fire(4);
}
else
{
if (ym > 0) player->fire(2);
else player->fire(8);
}
}
// spell (right click)
if (sf::Mouse::isButtonPressed(sf::Mouse::Right) && (gameState == gameStatePlaying))
{
sf::Vector2i mousePosition = sf::Mouse::getPosition(*app);
int xm = mousePosition.x - player->getX();
int ym = mousePosition.y - player->getY();
if (abs(xm) >= abs(ym))
{
if (xm > 0) player->setFacingDirection(6);
else player->setFacingDirection(4);
}
else
{
if (ym > 0) player->setFacingDirection(2);
else player->setFacingDirection(8);
}
player->castSpell();
}
// message queue
if (!messagesQueue.empty())
{
messagesQueue.front().timer -= deltaTime;
if (messagesQueue.front().timer < 0.0f)
{
messagesQueue.pop();
if (!messagesQueue.empty()) SoundManager::getInstance().playSound(SOUND_MESSAGE);
}
}
// achievement queue
if (!achievementsQueue.empty() && achievementsQueue.front().hasStarted)
{
achievementsQueue.front().timer -= deltaTime;
if (achievementsQueue.front().timer < 0.0f)
{
achievementsQueue.pop();
if (achievementsQueue.empty()) music.play();
}
}
}
else if (gameState == gameStatePlayingDisplayBoss)
{
if (isPressing(KeyFireDown, true)) gameState = gameStatePlaying;
}
onUpdate();
verifyDoorUnlocking();
checkInteraction();
if (roomClosed)
{
if (getEnemyCount() == 0)
{
currentMap->setCleared(true);
if (currentMap->getRoomType() == roomTypeKey)
new ItemEntity( (enumItemType)(ItemBossKey),
MAP_WIDTH / 2 * TILE_WIDTH + TILE_WIDTH / 2,
MAP_HEIGHT / 2 * TILE_HEIGHT + TILE_HEIGHT / 2);
player->onClearRoom();
openDoors();
remove(SAVE_FILE.c_str());
if (currentMap->getRoomType() == roomTypeBoss)
{
playMusic(MusicDungeon);
}
else if (currentMap->getRoomType() == roomTypeChallenge && !player->isDead())
{
ChestEntity* chest = new ChestEntity((TILE_WIDTH * MAP_WIDTH * 0.5f),
(TILE_HEIGHT * MAP_HEIGHT * 0.5f),
ChestChallenge, false);
chest->makeAppear();
// sound
SoundManager::getInstance().playSound(SOUND_GONG);
playMusic(MusicDungeon);
// text
float x0 = MAP_WIDTH * 0.5f * TILE_WIDTH;
float y0 = MAP_HEIGHT * 0.5f * TILE_HEIGHT + 40.0f;
TextEntity* text = new TextEntity("COMPLETE !", 30, x0, y0);
text->setAlignment(ALIGN_CENTER);
text->setLifetime(2.5f);
text->setWeight(-36.0f);
text->setZ(1200);
text->setColor(TextEntity::COLOR_FADING_WHITE);
challengeLevel++;
if (challengeLevel == 5) registerAchievement(AchievementChallenges);
player->offerChallenge();
}
}
}
if (backToMenu)
{
if (player->isDead())
{
EntityManager::getInstance().clean();
introSprites[0] = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_FOG));
introSprites[0]->setX(SCREEN_WIDTH / 2);
introSprites[0]->setY(SCREEN_HEIGHT - 202);
introSprites[1] = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_FOG));
introSprites[1]->setX(SCREEN_WIDTH / 2 + 970);
introSprites[1]->setY(SCREEN_HEIGHT - 202);
switchToMenu();
menuState = MenuStateHiScores;
#ifdef ONLINE_MODE
menuScoreIndex = 0;
#else
menuScoreIndex = 2;
#endif
}
else
{
prepareIntro();
}
}
}
void WitchBlastGame::addLifeBarToDisplay(std::string label, int hp, int hpMax)
{
lifeBar.toDisplay = true;
lifeBar.label = label;
lifeBar.hp = hp;
lifeBar.hpMax = hpMax;
}
void WitchBlastGame::renderBossPortrait()
{
if (gameState == gameStatePlayingDisplayBoss)
{
float transitionTime = 2.5f;
float endTime = PORTRAIT_DIAPLAY_TIME;
int xBoss = GAME_WIDTH / 2 - 267;
int fade = 255;
if (bossDisplayTimer < 0.25f)
{
xBoss += (0.25f - bossDisplayTimer) * 3000;
//fade = 255 - (0.25f - bossDisplayTimer) * 1000;
}
else if (bossDisplayTimer > endTime - 0.75f)
{
fade = (endTime - bossDisplayTimer) * 333;
if (fade < 0) fade = 0;
}
// background
sf::RectangleShape rectangle;
rectangle.setFillColor(sf::Color(0, 0, 0, fade));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH, MAP_HEIGHT * TILE_HEIGHT));
app->draw(rectangle);
// boss
if (bossDisplayTimer > transitionTime) // + 1.0f)
{
EnemyEntity* boss = getBoss();
if (boss)
{
sf::View view = app->getView();
view.move(-5, -5);
app->setView(view);
boss->render(app);
view.move(5, 5);
app->setView(view);
}
/*if (bossDisplayTimer < transitionTime + 1.5f)
{
rectangle.setFillColor(sf::Color(0, 0, 0, (1.5 - (bossDisplayTimer - transitionTime)) * 510));
app->draw(rectangle);
std::cout << 1.5 - (bossDisplayTimer - transitionTime) << " ";
}*/
//if (bossDisplayTimer < transitionTime + 2.0f)
{
//rectangle.setFillColor(sf::Color(0, 0, 0, (2.0 - (bossDisplayTimer - transitionTime)) * 255));
//app->draw(rectangle);
//std::cout << 1.5 - (bossDisplayTimer - transitionTime) << " ";
}
}
// boss portrait
if (bossDisplayTimer < transitionTime)
{
sf::Sprite bossSprite;
bossSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_BOSS_PICTURES));
bossSprite.setPosition(xBoss, 0);
app->draw(bossSprite);
}
else
{
if (bossDisplayState == 0)
{
SoundManager::getInstance().playSound(SOUND_BOOM_00);
for (int i = 0; i < 250; i++)
{
SpriteEntity* spriteStar = new SpriteEntity(
ImageManager::getInstance().getImage(IMAGE_PORTRAIT_PART),
GAME_WIDTH / 2 - 150 + rand() % 300, GAME_HEIGHT / 2 - 150 + rand() % 300);
spriteStar->setScale(5.0f, 5.0f);
spriteStar->setZ(7000.0f);
spriteStar->setSpin(-100 + rand()%200);
spriteStar->setVelocity(Vector2D(400 + rand()%800));
spriteStar->setFading(true);
spriteStar->setLifetime(4.1f + (rand() % 100) * 0.003f );
spriteStar->setColor(sf::Color(rand() % 255, rand() % 255, 255, 128));
spriteStar->setColor(sf::Color(40, 4, 40, 128));
spriteStar->setType(ENTITY_EFFECT);
if (rand()% 2 == 0) spriteStar->setRenderAdd();
}
bossDisplayState = 1;
}
else if (bossDisplayState == 1 && bossDisplayTimer > transitionTime + 0.2f)
{
bossDisplayState = 2;
for (int i = 0; i < 50; i++)
{
SpriteEntity* spriteStar = new SpriteEntity(
ImageManager::getInstance().getImage(IMAGE_PORTRAIT_PART),
GAME_WIDTH / 2 - 150 + rand() % 300, GAME_HEIGHT / 2 - 150 + rand() % 300);
spriteStar->setScale(4.0f, 4.0f);
spriteStar->setZ(7000.0f);
spriteStar->setSpin(-100 + rand()%200);
spriteStar->setVelocity(Vector2D(400 + rand()%800));
spriteStar->setFading(true);
spriteStar->setLifetime(4.1f + (rand() % 100) * 0.003f );
spriteStar->setColor(sf::Color(rand() % 255, rand() % 255, 255, 128));
spriteStar->setColor(sf::Color(20, 2, 20, 128));
spriteStar->setType(ENTITY_EFFECT);
spriteStar->setRenderAdd();
}
}
else if (bossDisplayState == 2 && bossDisplayTimer > transitionTime + 0.4f)
{
bossDisplayState = 3;
for (int i = 0; i < 50; i++)
{
SpriteEntity* spriteStar = new SpriteEntity(
ImageManager::getInstance().getImage(IMAGE_PORTRAIT_PART),
GAME_WIDTH / 2 - 150 + rand() % 300, GAME_HEIGHT / 2 - 150 + rand() % 300);
spriteStar->setScale(3.0f, 3.0f);
spriteStar->setZ(7000.0f);
spriteStar->setSpin(-100 + rand()%200);
spriteStar->setVelocity(Vector2D(400 + rand()%800));
spriteStar->setFading(true);
spriteStar->setLifetime(4.1f + (rand() % 100) * 0.003f );
spriteStar->setColor(sf::Color(rand() % 255, rand() % 255, 255, 128));
spriteStar->setColor(sf::Color(20, 2, 20, 128));
spriteStar->setType(ENTITY_EFFECT);
spriteStar->setRenderAdd();
}
}
animateEffects();
}
}
}
void WitchBlastGame::renderGame()
{
lifeBar.toDisplay = false;
EntityManager::getInstance().renderUnder(app, 5000);
EntityManager::getInstance().renderUnder(app, 5000);
}
void WitchBlastGame::generateUiParticle(float x, float y)
{
SpriteEntity* particle = new SpriteEntity(ImageManager::getInstance().getImage(IMAGE_BOLT),
x, y, BOLT_WIDTH, BOLT_HEIGHT);
particle->setFading(true);
particle->setImagesProLine(BOLT_PRO_LINE);
particle->setZ(10000);
particle->setLifetime(0.5f);
particle->setVelocity(Vector2D(30 + rand() % 50));
particle->setWeight(200);
particle->setType(ENTITY_EFFECT);
//particle->setFrame(BOLT_PRO_LINE + 2);
particle->setFrame(BOLT_PRO_LINE * 2 + 6);
particle->setRenderAdd();
particle->setScale(0.35f, 0.35f);
particle->setFading(true);
}
void WitchBlastGame::renderHud()
{
// boss life bar ?
if (lifeBar.toDisplay && gameState != gameStatePlayingDisplayBoss) renderLifeBar();
renderBossPortrait();
// achievements ?
if (!achievementsQueue.empty() && (currentMap->isCleared() || achievementsQueue.front().hasStarted) )
{
if (!achievementsQueue.front().hasStarted)
{
music.pause();
SoundManager::getInstance().playSound(SOUND_ACHIEVEMENT);
achievementsQueue.front().hasStarted = true;
achievementState[achievementsQueue.front().type] = AchievementDone;
saveGameData();
proceedEvent(EventAchievement);
// text
float x0 = MAP_WIDTH * 0.5f * TILE_WIDTH;
float y0 = MAP_HEIGHT * 0.5f * TILE_HEIGHT + 40.0f;
TextEntity* text = new TextEntity(tools::getLabel("achievement_complete"), 30, x0, y0);
text->setAlignment(ALIGN_CENTER);
text->setLifetime(2.5f);
text->setWeight(-36.0f);
text->setZ(1200);
text->setColor(TextEntity::COLOR_FADING_WHITE);
}
int xPos = 560;
int yPos = 4;
int opening = 384;
float achievAge = ACHIEVEMENT_DELAY_MAX - achievementsQueue.front().timer;
sf::Sprite spriteScroll;
if (achievAge < 1.0f)
opening = 32;
else if (achievAge < 2.0f)
opening = 32 + (achievAge - 1.0f) * (384 - 32);
else if (achievAge > ACHIEVEMENT_DELAY_MAX - 1.0f)
opening = 32 + (ACHIEVEMENT_DELAY_MAX - achievAge) * (384 - 32);
if (achievAge < 0.5f)
spriteScroll.setColor(sf::Color(255, 255, 255, 500 * achievAge));
else if (achievAge > ACHIEVEMENT_DELAY_MAX - 0.5f)
spriteScroll.setColor(sf::Color(255, 255, 255, 500 * (ACHIEVEMENT_DELAY_MAX - achievAge)));
spriteScroll.setTexture(*ImageManager::getInstance().getImage(IMAGE_UI_ACHIEV));
spriteScroll.setTextureRect(sf::IntRect(128 + 384 - opening, 0, opening, 64));
spriteScroll.setPosition(xPos + 384 - opening, yPos);
app->draw(spriteScroll);
if ((achievAge > 1.0f && achievAge < 2.0f) || achievAge > ACHIEVEMENT_DELAY_MAX - 1.0f)
spriteScroll.setTextureRect(sf::IntRect(32 * ((int)(achievAge * 8) % 4), 0, 32, 64));
else
spriteScroll.setTextureRect(sf::IntRect(0, 0, 32, 64));
spriteScroll.setPosition(xPos + 394 - opening - 16, yPos);
app->draw(spriteScroll);
if (achievAge > 2.0f && achievAge < ACHIEVEMENT_DELAY_MAX - 1.0f)
{
sf::Sprite icon;
icon.setTexture(*ImageManager::getInstance().getImage(IMAGE_ACHIEVEMENTS));
icon.setTextureRect(sf::IntRect( ((achievementsQueue.front().type + 1) % 10) * 64,
((achievementsQueue.front().type + 1) / 10) * 64, 64, 64));
icon.setPosition(xPos + 308, yPos + 9);
icon.setScale(0.7f, 0.7f);
app->draw(icon);
icon.setColor(sf::Color(255, 255, 255, 50 + 50 * cosf(getAbsolutTime() * 4)));
app->draw(icon, sf::BlendAdd);
game().write(achievementsQueue.front().message, 13, xPos + 34, yPos + 10, ALIGN_LEFT, sf::Color::Black, app, 0, 0);
if (achievements[achievementsQueue.front().type].unlockType == UnlockItem)
{
game().write(tools::getLabel(items[achievements[achievementsQueue.front().type].unlock].name),
13, xPos + 70, yPos + 34, ALIGN_LEFT, sf::Color::Black, app, 0, 0);
}
else if (achievements[achievementsQueue.front().type].unlockType == UnlockFunctionality)
{
game().write(tools::getLabel(functionalityLabel[achievements[achievementsQueue.front().type].unlock]),
13, xPos + 70, yPos + 34, ALIGN_LEFT, sf::Color::Black, app, 0, 0);
}
}
//if (achievAge < 1.0f)
{
int i = achievementsQueue.front().counter;
if (i < 64)
{
for (int j = 0; j < 2; j++)
{
generateUiParticle(xPos + 394 + 16 + 4 - 32 - 40, yPos - i + 64);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - 40, yPos - i + 64 + 1);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - 40, yPos - i + 64 + 2);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - 40, yPos - i + 64 + 3);
}
}
else if (i < 40 + 64)
{
for (int j = 0; j < 2; j++)
{
generateUiParticle(xPos + 394 + 16 + 4 - 32 - 40 + i - 64, yPos);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - 40 + i - 63, yPos);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - 40 + i - 62, yPos);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - 40 + i - 61, yPos);
}
}
else if (i < 40 + 64 + 64)
{
for (int j = 0; j < 2; j++)
{
generateUiParticle(xPos + 394 + 16 + 4 - opening, yPos + i - 40 - 64);
generateUiParticle(xPos + 394 + 16 + 4 - opening, yPos + i - 40 - 64 + 1);
generateUiParticle(xPos + 394 + 16 + 4 - opening, yPos + i - 40 - 64 + 2);
generateUiParticle(xPos + 394 + 16 + 4 - opening, yPos + i - 40 - 64 + 3);
}
}
else if (i < 40 + 64 + 40 + 64)
{
for (int j = 0; j < 2; j++)
{
generateUiParticle(xPos + 394 + 16 + 4 - 32 - i + 144, yPos + 64);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - i + 144 + 1, yPos + 64);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - i + 144 + 2, yPos + 64);
generateUiParticle(xPos + 394 + 16 + 4 - 32 - i + 144 + 3, yPos + 64);
}
}
achievementsQueue.front().counter += 4;
}
}
// interaction text ?
if (interaction.active)
{
if (interaction.type == InteractionTypeTemple)
write(interaction.label, 20, GAME_WIDTH / 2, 480, ALIGN_CENTER,sf::Color::White, app, 2, 2);
else if (interaction.type == InteractionTypeMerchandise)
write(interaction.label, 20, GAME_WIDTH / 2, 480, ALIGN_CENTER,sf::Color::White, app, 2, 2);
}
// light cone ?
float fade = player->getLightCone();
if (fade > 0.0f)
{
sf::Sprite cone;
cone.setTexture(*ImageManager::getInstance().getImage(IMAGE_LIGHT_CONE));
cone.setPosition(player->getX() - 64, player->getY() - 580);
cone.setColor(sf::Color(255, 255, 255, 255 * fade));
app->draw(cone, sf::BlendAdd);
}
app->draw(uiSprites.gui);
EntityManager::getInstance().renderAfter(app, 5000);
if (gameState == gameStatePlayingDisplayBoss)
{
// boss name
int fade = 255;
if (bossDisplayTimer < 0.25f)
{
fade = 255 - (0.25f - bossDisplayTimer) * 1000;
}
else if (bossDisplayTimer > PORTRAIT_DIAPLAY_TIME - 0.25f)
{
fade = (PORTRAIT_DIAPLAY_TIME - bossDisplayTimer) * 1000;
if (fade < 0) fade = 0;
}
write("THE COOK", 27, GAME_WIDTH / 2, 540, ALIGN_CENTER, sf::Color(255, 255, 255, fade), app, 0, 0);
}
}
void WitchBlastGame::renderLifeBar()
{
if (lifeBar.toDisplay)
{
float l = lifeBar.hp * ((MAP_WIDTH - 1) * TILE_WIDTH) / lifeBar.hpMax;
int label_dy = 0;
sf::RectangleShape rectangle(sf::Vector2f((MAP_WIDTH - 1) * TILE_WIDTH, 25));
rectangle.setFillColor(sf::Color(0, 0, 0,128));
rectangle.setPosition(sf::Vector2f(TILE_WIDTH / 2, label_dy + 22));
rectangle.setOutlineThickness(1);
rectangle.setOutlineColor(sf::Color(200, 200, 200, 200));
app->draw(rectangle);
rectangle.setSize(sf::Vector2f(l, 25));
rectangle.setFillColor(sf::Color(190, 20, 20));
rectangle.setOutlineThickness(0);
rectangle.setPosition(sf::Vector2f(TILE_WIDTH / 2, label_dy + 22));
app->draw(rectangle);
game().write( lifeBar.label,
18,
TILE_WIDTH / 2 + 10.0f,
label_dy + 23,
ALIGN_LEFT,
sf::Color(255, 255, 255),
app, 0 , 0);
}
}
void WitchBlastGame::renderRunningGame()
{
EntityManager::getInstance().sortByZ();
if (!isPlayerAlive)
{
sf::View view = app->getView();
sf::View viewSave = app->getView();
if (!parameters.zoom || player->getDeathAge() > 4.0f)
{
// do nothing
}
else if (player->getDeathAge() > 3.0f)
{
view.zoom(1.0f - 0.75f * (4.0f - player->getDeathAge()));
float xDiff = view.getCenter().x - player->getX();
float yDiff = view.getCenter().y - player->getY();
view.setCenter(view.getCenter().x - xDiff * (4.0f - player->getDeathAge()),
view.getCenter().y - yDiff * (4.0f - player->getDeathAge()));
}
else if (player->getDeathAge() > 1.0f)
{
view.zoom(0.25f);
view.setCenter(player->getX(), player->getY());
}
else
{
view.zoom(1.0f - 0.75f * (player->getDeathAge()));
float xDiff = view.getCenter().x - player->getX();
float yDiff = view.getCenter().y - player->getY();
view.setCenter(view.getCenter().x - xDiff * player->getDeathAge(),
view.getCenter().y - yDiff * player->getDeathAge());
}
view.move(-5, -5);
app->setView(view);
renderGame();
app->setView(viewSave);
renderHud();
}
else if (parameters.zoom && gameTime < 1.0f)
{
sf::View view = app->getView();
sf::View viewSave = app->getView();
view.zoom(0.25f + 0.75f * (gameTime));
view.move(-5, -5);
app->setView(view);
renderGame();
app->setView(viewSave);
renderHud();
}
else if (xGame[xGameTypeShake].active)
{
sf::View view = app->getView();
sf::View viewSave = app->getView();
view.move(-4 + rand() % 9, -4 + rand() % 9);
app->setView(view);
renderGame();
app->setView(viewSave);
renderHud();
}
else
{
sf::View view = app->getView();
sf::View viewSave = app->getView();
view.move(-OFFSET_X, -OFFSET_Y);
app->setView(view);
renderGame();
app->setView(viewSave);
renderHud();
}
sf::RectangleShape rectangle(sf::Vector2f(200, 25));
// effects
if (isPressing(KeyTimeControl, false) && gameState == gameStatePlaying)
{
// effect
int effectFade = 10 + 20 * (1.0f + cos(12.0f * getAbsolutTime())) * 0.5f;
rectangle.setFillColor(sf::Color(0, 255, 255, effectFade));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH , MAP_HEIGHT * TILE_HEIGHT));
sf::RenderStates r;
r.blendMode = sf::BlendAlpha ;
app->draw(rectangle, r);
}
if (xGame[xGameTypeFade].active && xGame[xGameTypeFade].param == X_GAME_FADE_IN)
{
// fade in
rectangle.setFillColor(sf::Color(0, 0, 0, 255 - ((FADE_IN_DELAY - xGame[xGameTypeFade].timer) / FADE_IN_DELAY) * 255));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH , MAP_HEIGHT * TILE_HEIGHT));
app->draw(rectangle);
}
else if (xGame[xGameTypeFade].active && xGame[xGameTypeFade].param == X_GAME_FADE_OUT)
{
// fade out
rectangle.setFillColor(sf::Color(0, 0, 0, ((FADE_IN_DELAY - xGame[xGameTypeFade].timer) / FADE_IN_DELAY) * 255));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH , MAP_HEIGHT * TILE_HEIGHT));
app->draw(rectangle);
}
if (player->isSpecialStateActive(BaseCreatureEntity::SpecialStateConfused))
{
BaseCreatureEntity::specialStateStuct specialState = player->getSpecialState(BaseCreatureEntity::SpecialStateConfused);
// effect
int effectFade = 150 + cos(3.0f * getAbsolutTime()) * 100;
// fade
int fade = 55;
if (specialState.timer < 0.4f)
fade = 55 - (0.4f - specialState.timer) / 0.4f * 55;
else if (specialState.timer > specialState.param1 - 0.4f)
fade = (specialState.param1 - specialState.timer) / 0.4f * 55;
if (fade < 0) fade = 0;
else if (fade > 55) fade = 55;
fade *= 1.5f;
rectangle.setFillColor(sf::Color(255 - effectFade, 0, effectFade, fade));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH , MAP_HEIGHT * TILE_HEIGHT));
sf::RenderStates r;
r.blendMode = sf::BlendAlpha ;
app->draw(rectangle, r);
}
else if (xGame[xGameTypeFadeColor].active)
{
// color fade
unsigned int r = 0, g = 0, b = 0;
switch (xGame[xGameTypeFadeColor].param)
{
case X_GAME_COLOR_RED:
r = 255;
g = 100;
break;
case X_GAME_COLOR_GREEN:
g = 255;
break;
case X_GAME_COLOR_BLUE:
b = 255;
break;
case X_GAME_COLOR_VIOLET:
r = 255;
b = 200;
break;
case X_GAME_COLOR_BROWN:
r = 200;
b = 100;
g = 150;
break;
case X_GAME_COLOR_WHITE:
r = 255;
b = 255;
g = 255;
break;
}
int alpha = xGame[xGameTypeFadeColor].timer * 200.0f / xGame[xGameTypeFadeColor].duration;
rectangle.setFillColor(sf::Color(r, g, b, alpha));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH , MAP_HEIGHT * TILE_HEIGHT));
app->draw(rectangle, sf::BlendAdd);
}
if (gameState != gameStatePlayingDisplayBoss) renderMessages();
app->draw(uiSprites.topLayer);
std::ostringstream oss;
oss << player->getGold();
write(oss.str(), 18, 518, 619, ALIGN_CENTER, sf::Color::White, app, 0, 0);
myText.setColor(sf::Color(0, 0, 0, 255));
myText.setCharacterSize(16);
oss.str("");
oss << tools::getLabel("level") << " " << level;
write(oss.str(), 16, 880, 610, ALIGN_CENTER, sf::Color::Black, app, 0, 0);
//if (gameState == gameStatePlaying)
{
// life
// if (player->isPoisoned()) TODO
sf::Sprite hpSprite;
hpSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_UI_LIFE));
int hpFade = 88.0f * (float)player->getHpDisplay() / (float)player->getHpMax();
if (hpFade < 0) hpFade = 0;
else if (hpFade > 88) hpFade = 88;
hpSprite.setPosition(170, 619 + 88 - hpFade);
hpSprite.setTextureRect(sf::IntRect(0, 88 - hpFade, 88, hpFade));
app->draw(hpSprite);
oss.str("");
oss << player->getHp() << "/" << player->getHpMax();
write(oss.str(), 16, 210, 654, ALIGN_CENTER, sf::Color::White, app, 0, 0);
// mana
sf::Sprite manaSprite;
manaSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_UI_MANA));
int manaFade = player->getPercentFireDelay() * 98;
manaSprite.setPosition(558, 614 + 98 - manaFade);
manaSprite.setTextureRect(sf::IntRect(0, 98 - manaFade, 98, manaFade));
app->draw(manaSprite);
if (player->getActiveSpell().spell != SpellNone)
{
//oss.str("");
//oss << tools::getLabel(spellLabel[player->getActiveSpell().spell]);
//if (player->isEquiped(EQUIP_BOOK_MAGIC_II)) oss << "+";
//write(oss.str(), 14, 95, 663, ALIGN_LEFT, sf::Color::White, app, 0, 0);
// TODO
sf::Sprite spellSprite;
spellSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_UI_SPELLS));
spellSprite.setPosition(568, 624);
int frame = player->getActiveSpell().spell;
spellSprite.setTextureRect(sf::IntRect(frame * 78, 78, 78, 78));
//spellSprite.scale(2.0f, 2.0f);
app->draw(spellSprite);
int spellFade = player->getPercentSpellDelay() * 78;
spellSprite.setPosition(568, 624 + 78 - spellFade);
spellSprite.setTextureRect(sf::IntRect(frame * 78, 78 - spellFade, 78, spellFade));
app->draw(spellSprite);
if (player->canCastSpell())
{
float fade = (cos(8.0f * getAbsolutTime()) + 1.0f) * 0.5f;
spellSprite .setColor(sf::Color(255, 255, 255, 255 * fade));
app->draw(spellSprite, sf::BlendAdd);
}
}
// drawing the key on the interface
if (player->isEquiped(EQUIP_BOSS_KEY)) app->draw(uiSprites.keySprite);
// drawing the level items
if (player->isEquiped(EQUIP_FLOOR_MAP))
{
sf::Sprite mapSprite;
mapSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEMS_EQUIP));
mapSprite.setTextureRect(sf::IntRect(ITEM_WIDTH * 3, ITEM_HEIGHT * 4, ITEM_WIDTH, ITEM_HEIGHT));
mapSprite.setPosition(737, 648);
app->draw(mapSprite);
}
if (player->isEquiped(EQUIP_ALCOHOL))
{
sf::Sprite alcSprite;
alcSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEMS_EQUIP));
alcSprite.setTextureRect(sf::IntRect(ITEM_WIDTH * 4, ITEM_HEIGHT * 4, ITEM_WIDTH, ITEM_HEIGHT));
alcSprite.setPosition(737, 681);
app->draw(alcSprite);
}
if (player->isEquiped(EQUIP_LUCK))
{
sf::Sprite alcSprite;
alcSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEMS_EQUIP));
alcSprite.setTextureRect(sf::IntRect(ITEM_WIDTH * 5, ITEM_HEIGHT * 4, ITEM_WIDTH, ITEM_HEIGHT));
alcSprite.setPosition(704, 681);
app->draw(alcSprite);
}
if (player->isEquiped(EQUIP_FAIRY_POWDER))
{
sf::Sprite alcSprite;
alcSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEMS_EQUIP));
alcSprite.setTextureRect(sf::IntRect(ITEM_WIDTH * 6, ITEM_HEIGHT * 4, ITEM_WIDTH, ITEM_HEIGHT));
alcSprite.setPosition(671, 681);
app->draw(alcSprite);
}
// drawing the consumable
if (!player->isEquiped(EQUIP_BAG))
{
sf::RectangleShape shadow(sf::Vector2f(70, 33));
shadow.setFillColor(sf::Color(0, 0, 0, 128));
shadow.setPosition(sf::Vector2f(386, 614));
app->draw(shadow);
}
for (int i = 0; i < MAX_SLOT_CONSUMABLES; i++)
{
if (player->getConsumable(i) > -1 && player->getConsumableAmount(i) > 0)
{
int n = player->getConsumable(i);
sf::Sprite consSprite;
consSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEMS));
consSprite.setTextureRect(sf::IntRect(ITEM_WIDTH * (n % 10), ITEM_HEIGHT * (n / 10), ITEM_WIDTH, ITEM_HEIGHT));
consSprite.setPosition(315 + 37 * i, 615);
app->draw(consSprite);
std::stringstream oss;
oss << "x";
oss << player->getConsumableAmount(i);
write(oss.str(), 9, 331 + 37 * i, 645, ALIGN_CENTER, sf::Color::White,app, 0, 0);
}
}
// drawing message icon
if (!messagesQueue.empty())
{
int fade = 255;
if (messagesQueue.front().timer < 0.5f)
{
fade = (2 * messagesQueue.front().timer) * 255;
}
else if (messagesQueue.front().timerMax - messagesQueue.front().timer < 0.5f)
{
fade = (2 * (messagesQueue.front().timerMax - messagesQueue.front().timer)) * 255;
}
uiSprites.iconSprite.setColor(sf::Color(255, 255, 255, fade));
uiSprites.iconSprite.setTextureRect(sf::IntRect((messagesQueue.front().icon % 10) * 72, (messagesQueue.front().icon / 10) * 96, 72, 96));
app->draw(uiSprites.iconSprite);
}
// drawing the divinity
if (player->getDivinity().divinity >= 0)
{
sf::Sprite divSprite;
divSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_DIVINITY));
divSprite.setPosition(100, 614);
divSprite.setTextureRect(sf::IntRect(player->getDivinity().divinity * 48, 0, 48, 85));
app->draw(divSprite);
float fade = player->getLightCone();
if (fade > 0.0f && player->getPlayerStatus() != PlayerEntity::playerStatusPraying)
{
divSprite.setTextureRect(sf::IntRect(player->getDivinity().divinity * 48, 85, 48, 85));
divSprite.setColor(sf::Color(255, 255, 255, 255 * fade));
app->draw(divSprite);
}
rectangle.setOutlineThickness(0);
if (player->getDivinity().interventions + 1 < player->getDivinity().level)
{
int fade = 50 + 50 * cosf(game().getAbsolutTime() * 8);
rectangle.setFillColor(sf::Color(100 + fade, 100 + fade, 200 + fade / 2, 255));
}
else
rectangle.setFillColor(sf::Color(100, 100, 200, 255));
rectangle.setPosition(sf::Vector2f(101, 689));
rectangle.setSize(sf::Vector2f(46 * player->getDivinity().percentsToNextLevels, 9));
app->draw(rectangle);
std::ostringstream oss;
if (player->getDivinity().level == MAX_DIVINITY_LEVEL + 1) oss << "MAX";
else oss << "lvl " << player->getDivinity().level;
write(oss.str(), 11, 122, 702, ALIGN_CENTER, sf::Color::White, app, 0, 0);
}
// render the shots
renderHudShots(app);
if (gameState == gameStatePlayingPause)
{
// background
rectangle.setFillColor(sf::Color(0, 0, 0, 200));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH, MAP_HEIGHT * TILE_HEIGHT));
app->draw(rectangle);
// minimap
int mapx = 350;
int mapy = 30;
// background
app->draw(rectangle);
app->draw(uiSprites.mapBgSprite);
// map
float miniX = miniMapEntity->getX();
float miniY = miniMapEntity->getY();
miniMapEntity->setX(mapx);
miniMapEntity->setY(mapy);
miniMapEntity->computeVertices();
miniMapEntity->render(app);
miniMapEntity->setX(miniX);
miniMapEntity->setY(miniY);
miniMapEntity->computeVertices();
float x = 200;
float y = 480;
// items
write(tools::getLabel("inventory"), 16, x, y, ALIGN_LEFT, sf::Color::White, app, 0, 0);
int n = 0;
for (auto i: sortedEquipement)
{
if (i != EQUIP_BOSS_KEY && player->isEquiped(i))
{
sf::Sprite itemSprite;
itemSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEMS_EQUIP));
itemSprite.setPosition(x + n * 32, y + 20);
itemSprite.setTextureRect(sf::IntRect((i % 10) * 32, (i / 10) * 32, 32, 32));
app->draw(itemSprite);
n++;
}
}
renderInGameMenu();
}
if (player->isDead())
{
float deathAge = player->getDeathAge();
if (deathAge > DEATH_CERTIFICATE_DELAY)
{
rectangle.setFillColor(sf::Color(0, 0, 0, 180));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH , MAP_HEIGHT * TILE_HEIGHT));
app->draw(rectangle);
renderDeathScreen(80, 110);
if (scoreSaveFile.compare("") == 0)
{
write(tools::getLabel("certificate_capture"), 16, 80, 430, ALIGN_LEFT, sf::Color::White, app, 0, 0);
}
else
{
std::stringstream ss;
ss << tools::getLabel("certificate_saved") << " " << scoreSaveFile;
write(ss.str(), 16, 80, 430, ALIGN_LEFT, sf::Color::White, app, 0, 0);
}
}
else if (deathAge > DEATH_CERTIFICATE_DELAY - 1.0f)
{
rectangle.setFillColor(sf::Color(0, 0, 0, 180 * (deathAge - 2.5f)));
rectangle.setPosition(sf::Vector2f(xOffset, yOffset));
rectangle.setSize(sf::Vector2f(MAP_WIDTH * TILE_WIDTH , MAP_HEIGHT * TILE_HEIGHT));
app->draw(rectangle);
renderDeathScreen(80 + (DEATH_CERTIFICATE_DELAY - deathAge) * 1000, 110);
}
}
else if (currentMap->getRoomType() == roomTypeExit && level >= LAST_LEVEL)
{
float x0 = (MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2;
write(tools::getLabel("congratulations_1"), 25, x0, 220, ALIGN_CENTER, sf::Color::White, app, 2, 2);
write(tools::getLabel("congratulations_2"), 23, x0, 250, ALIGN_CENTER, sf::Color::White, app, 2, 2);
write(tools::getLabel("congratulations_3"), 23, x0, 280, ALIGN_CENTER, sf::Color::White, app, 2, 2);
registerAchievement(AchievementWin);
}
}
// show game time
if (showGameTime)
{
int minutes = (int)gameTime / 60;
int secondes = (int)gameTime % 60;
std::stringstream ss;
if (minutes < 10) ss << "0";
ss << minutes;
ss << ":";
if (secondes < 10) ss << "0";
ss << secondes;
write(ss.str(), 14, 4, 4, ALIGN_LEFT, sf::Color::Green, app, 0,0);
}
}
void WitchBlastGame::renderMessages()
{
// message queue
if (!messagesQueue.empty())
{
int dy = 30;
if (messagesQueue.front().timer < 0.5f)
{
dy *= (2 * messagesQueue.front().timer);
}
else if (messagesQueue.front().timerMax - messagesQueue.front().timer < 0.5f)
{
dy *= (2 * (messagesQueue.front().timerMax - messagesQueue.front().timer));
}
uiSprites.msgBoxSprite.setPosition(0, 590 - dy);
app->draw(uiSprites.msgBoxSprite);
std::stringstream ss;
ss << messagesQueue.front().message[0];
ss << ": ";
ss << messagesQueue.front().message[1];
ss << std::endl;
ss << messagesQueue.front().message[2];
write(ss.str(), 16, 10, 592 - dy, ALIGN_LEFT, sf::Color::White, app, 0,0);
}
}
void WitchBlastGame::saveDeathScreen()
{
std::stringstream ss;
ss << "rip_";
time_t t = time(0); // get time now
struct tm * now = localtime( & t );
ss << (now->tm_year + 1900);
if (now->tm_mon < 9) ss << "0";
ss << (now->tm_mon + 1);
if (now->tm_mday < 9) ss << "0";
ss << now->tm_mday;
if (now->tm_hour <= 9) ss << "0";
ss << (now->tm_hour);
if (now->tm_min <= 9) ss << "0";
ss << (now->tm_min);
if (now->tm_sec <= 9) ss << "0";
ss << (now->tm_sec);
ss << ".png";
int width = 810, height = 300, border = 4;
int x = 80, y = 110;
sf::Image screenShot(app->capture());
sf::Image savedImage;
savedImage.create(width + border * 2, height + border * 2);
savedImage.copy(screenShot,0 , 0, sf::IntRect( x - border, y - border, width + border * 2, height + border * 2));
savedImage.saveToFile(ss.str());
}
void WitchBlastGame::saveScreen()
{
std::stringstream ss;
ss << "screenshot_";
time_t t = time(0); // get time now
struct tm * now = localtime( & t );
ss << (now->tm_year + 1900);
if (now->tm_mon < 9) ss << "0";
ss << (now->tm_mon + 1);
if (now->tm_mday < 9) ss << "0";
ss << now->tm_mday;
if (now->tm_hour <= 9) ss << "0";
ss << (now->tm_hour);
if (now->tm_min <= 9) ss << "0";
ss << (now->tm_min);
if (now->tm_sec <= 9) ss << "0";
ss << (now->tm_sec);
ss << ".png";
sf::Image screenShot(app->capture());
screenShot.saveToFile(ss.str());
}
void WitchBlastGame::renderDeathScreen(float x, float y)
{
int xRect = 810;
sf::Sprite rectangle;
rectangle.setTexture(*ImageManager::getInstance().getImage(IMAGE_DEATH_CERTIFICATE));
rectangle.setPosition(x - 4, y - 4);
app->draw(rectangle);
std::stringstream ss;
ss << parameters.playerName << " - " << tools::getLabel("dc_certificate");
write(ss.str(), 18, x + xRect / 2, y + 5, ALIGN_CENTER, sf::Color::Black, app, 0, 0);
ss.str(std::string());
ss.clear();
ss << tools::getLabel("dc_killed_by") << " " << sourceToString(player->getLastHurtingSource(), player->getLastHurtingEnemy()) << "." << std::endl;
int minutes = (int)gameTime / 60;
if (minutes < 1) minutes = 1;
ss << tools::getLabel("dc_died_level") << " " << level << " " << tools::getLabel("dc_after") << " " << minutes << " " << tools::getLabel("dc_minutes") << "." << std::endl;
ss << tools::getLabel("dc_killed_monsters") << ": " << bodyCount << std::endl;
ss << tools::getLabel("dc_gold") << ": " << player->getGold() << std::endl;
ss << tools::getLabel("dc_challenges") << ": " << challengeLevel - 1 << std::endl;
write(ss.str(), 16, x + 112, y + 50, ALIGN_LEFT, sf::Color::Black, app, 0, 0);
// player
renderPlayer(x + 40, y + 48, player->getEquipment(), player->getShotType(), 1, 0);
// items
write(tools::getLabel("inventory"), 16, x + 14, y + 165, ALIGN_LEFT, sf::Color::Black, app, 0, 0);
int n = 0;
for (auto i: sortedEquipement)
{
if (i != EQUIP_BOSS_KEY && player->isEquiped(i))
{
sf::Sprite itemSprite;
itemSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ITEMS_EQUIP));
itemSprite.setPosition(x + 14 + n * 32, y + 183);
itemSprite.setTextureRect(sf::IntRect((i % 10) * 32, (i / 10) * 32, 32, 32));
app->draw(itemSprite);
n++;
}
}
ss.str("");
ss.clear();
ss << "Score: " << score;
write(ss.str(), 24, x + xRect / 2, y + 240, ALIGN_CENTER, sf::Color::Black, app, 0, 0);
}
bool compareScores(WitchBlastGame::StructScore s1, WitchBlastGame::StructScore s2)
{
return s1.score > s2.score;
}
void WitchBlastGame::calculateScore()
{
score = 0;
bodyCount = 0;
for (int enemyType = EnemyTypeBat; enemyType < EnemyTypeRockFalling; enemyType++)
{
bodyCount += killedEnemies[enemyType];
score += killedEnemies[enemyType] * getMonsterScore((enemyTypeEnum)enemyType);
}
score += getChallengeScore(challengeLevel);
score += getGoldScore(player->getGold());
for (int i = 0; i < NUMBER_EQUIP_ITEMS; i++)
{
if (player->isEquiped(i)) score += getItemScore((item_equip_enum)i);
lastScore.equip[i] = player->isEquiped(i);
}
// to save
lastScore.name = parameters.playerName;
lastScore.score = score;
lastScore.level = level;
lastScore.shotType = player->getShotType();
scores.push_back(lastScore);
std::sort (scores.begin(), scores.end(), compareScores);
saveHiScores();
// Online
#ifdef ONLINE_MODE
if (!gameFromSaveFile)
{
sendScoreToServer();
}
else
{
receiveScoreFromServer();
}
#endif // ONLINE_MODE
}
void WitchBlastGame::switchToMenu()
{
gameState = gameStateMenu;
buildMenu(false);
if (!config.configFileExists())
{
menuState = MenuStateFirst;
menuFirst.index = 0;
menuKeyIndex = 0;
}
}
void WitchBlastGame::updateMenu()
{
SoundManager::getInstance().playSound(SOUND_NIGHT, false);
menuStuct* menu = NULL;
bool noMenu = false;
if (menuState == MenuStateMain)
menu = &menuMain;
else if (menuState == MenuStateConfig)
menu = &menuConfig;
else if (menuState == MenuStateFirst)
menu = &menuFirst;
else
noMenu = true;
bool escape = false;
EntityManager::getInstance().animate(deltaTime);
for (int i = 0; i < 2; i++)
{
introSprites[i]->setX(introSprites[i]->getX() - deltaTime * 35);
if (introSprites[i]->getX() < - SCREEN_WIDTH / 2) introSprites[i]->setX(introSprites[i]->getX() + 2 * SCREEN_WIDTH);
}
// Process events
sf::Event event;
while (app->pollEvent(event))
{
// Close window : exit
if (event.type == sf::Event::Closed)
{
saveGameData();
app->close();
}
if (event.type == sf::Event::Resized)
{
enableAA(true);
sf::View view = app->getDefaultView();
view = getLetterboxView( view, event.size.width, event.size.height );
app->setView(view);
}
if (event.type == sf::Event::TextEntered)
{
if (menuState == MenuStateChangeName)
{
if (event.text.unicode < 128)
{
char c = static_cast<char>(event.text.unicode);
if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')
parameters.playerName += static_cast<char>(event.text.unicode);
}
}
}
if (event.type == sf::Event::KeyPressed && menuState == MenuStateKeys)
{
bool alreadyUsed = false;
if (event.key.code == sf::Keyboard::Escape) alreadyUsed = true;
for (unsigned int i = 0; i < menuKeyIndex; i++)
if (input[i] == event.key.code) alreadyUsed = true;
// TODO more tests
if (!alreadyUsed)
{
input[menuKeyIndex] = event.key.code;
menuKeyIndex++;
if (menuKeyIndex == NumberKeys)
{
menuState = MenuStateConfig;
saveConfigurationToFile();
}
}
}
else if (menuState == MenuStateJoystick)
{
bool alreadyUsed = false;
int nbButtons = sf::Joystick::getButtonCount(0);
bool found = false;
JoystickInputStruct jInput;
// Escape = out
if (event.key.code == sf::Keyboard::Escape)
{
menuState = MenuStateConfig;
saveConfigurationToFile();
return;
}
// button pressed ?
for (int i = 0; !found && i < nbButtons; i++)
{
if (sf::Joystick::isButtonPressed(0, i))
{
jInput.isButton = true;
jInput.value = i;
jInput.axis = sf::Joystick::X;
found = true;
}
}
if (!found)
{
// axis ?
for (int i = sf::Joystick::X; i <= sf::Joystick::PovY; i++)
{
if (sf::Joystick::hasAxis(0, (sf::Joystick::Axis)i))
{
if (sf::Joystick::getAxisPosition(0, (sf::Joystick::Axis)i) < -50)
{
jInput.isButton = false;
jInput.value = -1;
jInput.axis = (sf::Joystick::Axis)i;
found = true;
}
else if (sf::Joystick::getAxisPosition(0, (sf::Joystick::Axis)i) > 50)
{
jInput.isButton = false;
jInput.value = 1;
jInput.axis = (sf::Joystick::Axis)i;
found = true;
}
}
}
}
if (found)
{
// already exist ?
for (unsigned int i = 0; i < menuKeyIndex; i++)
{
if (jInput.isButton && joystickInput[i].isButton
&& joystickInput[i].value == jInput.value)
alreadyUsed = true;
if (!jInput.isButton && !joystickInput[i].isButton
&& joystickInput[i].axis == jInput.axis
&& joystickInput[i].value == jInput.value)
alreadyUsed = true;
}
if (!alreadyUsed)
{
joystickInput[menuKeyIndex] = jInput;
menuKeyIndex++;
if (menuKeyIndex == NumberKeys)
{
menuState = MenuStateConfig;
saveConfigurationToFile();
}
}
}
}
else
{
if (event.type == sf::Event::KeyPressed)
{
if (menuState == MenuStateChangeName)
{
if (event.key.code == sf::Keyboard::Escape || event.key.code == sf::Keyboard::Return)
{
saveConfigurationToFile();
menuState = MenuStateMain;
}
else if (event.key.code == sf::Keyboard::BackSpace)
{
if (parameters.playerName.size() > 0)
parameters.playerName.erase(parameters.playerName.size() - 1);
}
}
else if (event.key.code == sf::Keyboard::Escape)
{
escape = true;
}
}
}
}
// END EVENT PROCESSING
if (menuState == MenuStateAchievements)
{
if (isPressing(KeyRight, true))
{
if (menuAchIndex % 8 < 7) menuAchIndex++;
}
else if (isPressing(KeyLeft, true))
{
if (menuAchIndex % 8 > 0) menuAchIndex--;
}
else if (isPressing(KeyDown, true))
{
if (menuAchIndex / 8 < ACHIEV_LINES) menuAchIndex += 8;
}
else if (isPressing(KeyUp, true))
{
if (menuAchIndex / 8 > 0) menuAchIndex -= 8;
}
else if (isPressing(KeyFireDown, true))
{
if (menuAchIndex / 8 >= ACHIEV_LINES) menuState = MenuStateMain;
}
if (escape) menuState = MenuStateMain;
}
else if (menuState == MenuStateCredits)
{
if (escape || isPressing(KeyFireDown, true)) menuState = MenuStateMain;
}
else if (menuState == MenuStateHiScores)
{
if (escape || isPressing(KeyFireDown, true))
{
menuScoreIndex++;
if (menuScoreIndex > 2)
{
menuState = MenuStateMain;
if (lastScore.level > 0)
{
lastScore.level = 0;
lastScore.score = 0;
playMusic(MusicIntro);
}
}
}
}
if (!noMenu)
{
if (escape)
{
saveGameData();
app->close();
}
else if (isPressing(KeyDown, true))
{
menu->index++;
if (menu->index == menu->items.size()) menu->index = 0;
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
else if (isPressing(KeyUp, true))
{
if (menu->index == 0) menu->index = menu->items.size() - 1;
else menu->index--;
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
else if (isPressing(KeyRight, true))
{
if (menu->items[menu->index].id == MenuLanguage)
{
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
parameters.language++;
if (parameters.language >= NB_LANGUAGES) parameters.language = 0;
if (menuState == MenuStateConfig) saveConfigurationToFile();
tools::setLanguage(languageString[parameters.language]);
buildMenu(true);
}
else if (menu->items[menu->index].id == MenuVolumeSound)
{
parameters.soundVolume = (parameters.soundVolume / 10) * 10 + 10;
if (parameters.soundVolume > 100) parameters.soundVolume = 100;
saveConfigurationToFile();
SoundManager::getInstance().setVolume(parameters.soundVolume);
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
else if (menu->items[menu->index].id == MenuVolumeMusic)
{
parameters.musicVolume = (parameters.musicVolume / 10) * 10 + 10;
if (parameters.musicVolume > 100) parameters.musicVolume = 100;
saveConfigurationToFile();
updateMusicVolume();
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
}
else if (isPressing(KeyLeft, true))
{
if (menu->items[menu->index].id == MenuLanguage)
{
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
parameters.language--;
if (parameters.language < 0) parameters.language = NB_LANGUAGES - 1;
if (menuState == MenuStateConfig) saveConfigurationToFile();
tools::setLanguage(languageString[parameters.language]);
buildMenu(true);
}
else if (menu->items[menu->index].id == MenuVolumeSound)
{
parameters.soundVolume = (parameters.soundVolume / 10) * 10 - 10;
if (parameters.soundVolume < 0) parameters.soundVolume = 0;
saveConfigurationToFile();
SoundManager::getInstance().setVolume(parameters.soundVolume);
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
else if (menu->items[menu->index].id == MenuVolumeMusic)
{
parameters.musicVolume = (parameters.musicVolume / 10) * 10 - 10;
if (parameters.musicVolume < 0) parameters.musicVolume = 0;
saveConfigurationToFile();
updateMusicVolume();
SoundManager::getInstance().playSound(SOUND_SHOT_SELECT);
}
}
else if (isPressing(KeyFireDown, true))
{
switch (menu->items[menu->index].id)
{
case MenuStartNew:
startNewGame(false, 1);
remove(SAVE_FILE.c_str());
break;
case MenuStartOld:
startNewGame(true, 1);
break;
case MenuKeys:
menuState = MenuStateKeys;
menuKeyIndex = 0;
break;
case MenuJoystick:
if (sf::Joystick::isConnected(0))
{
buildMenu(true);
menuState = MenuStateJoystick;
menuKeyIndex = 0;
}
else
buildMenu(true);
break;
case MenuCredits:
menuState = MenuStateCredits;
break;
case MenuHiScores:
menuState = MenuStateHiScores;
#ifdef ONLINE_MODE
menuScoreIndex = 0;
#else
menuScoreIndex = 2;
#endif
receiveScoreFromServer();
//loadHiScoresOnline(false);
//loadHiScoresOnline(true);
break;
case MenuAchievements:
menuState = MenuStateAchievements;
menuAchIndex = 0;
break;
case MenuPlayerName:
menuState = MenuStateChangeName;
break;
case MenuConfig:
menuState = MenuStateConfig;
break;
case MenuTutoReset:
for (int i = 0; i < NB_MESSAGES; i++) gameMessagesToSkip[i] = false;
SoundManager::getInstance().playSound(SOUND_SPELL_FREEZE);
saveGameData();
break;
case MenuConfigBack:
menuState = MenuStateMain;
break;
case MenuLanguage:
if (menuState == MenuStateFirst)
{
registerLanguage();
if (parameters.playerName.compare("") == 0 )
{
menuMain.index = 0;
menuState = MenuStateChangeName;
}
else
menuState = MenuStateMain;
}
break;
case MenuExit:
saveGameData();
app->close();
break;
case MenuVolumeSound:
case MenuVolumeMusic:
break;
case MenuContinue:
case MenuSaveAndQuit:
std::cout << "[ERROR] Bad Menu ID\n";
break;
}
}
}
}
void WitchBlastGame::renderMenu()
{
if (menuState == MenuStateCredits)
{
renderCredits();
return;
}
else if (menuState == MenuStateHiScores)
{
//renderHiScores();
if (menuScoreIndex == 0)
renderScores(scoresOnline, "Best Scores (ON-LINE)");
else if (menuScoreIndex == 1)
renderScores(scoresOnlineDay, "Best TODAY Scores (ON-LINE)");
else
renderScores(scores, "Best Scores (local)");
return;
}
else if (menuState == MenuStateAchievements)
{
renderAchievements();
return;
}
app->draw(introScreenSprite);
if (titleSprite.getPosition().y > 160) titleSprite.move(0, -8);
else if (titleSprite.getPosition().y < 160) titleSprite.setPosition(SCREEN_WIDTH / 2 - 15, 160);
app->draw(titleSprite);
EntityManager::getInstance().render(app);
menuStuct* menu = nullptr;
if (menuState == MenuStateMain || menuState == MenuStateChangeName)
menu = &menuMain;
else if (menuState == MenuStateConfig)
menu = &menuConfig;
else if (menuState == MenuStateFirst)
menu = &menuFirst;
int xAlign = 290;
int yTop = 320;
int yStep = 40;
if (menuState == MenuStateKeys)
{
// menu keys
if (config.configFileExists())
write(tools::getLabel("key_configuration"), 18, xAlign, 295, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 1, 1);
else
write(tools::getLabel("key_configuration_desc"), 18, xAlign, 295, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 1, 1);
for (unsigned int i = 0; i < NumberKeys; i++)
{
sf::Color itemColor;
if (menuKeyIndex == i) itemColor = sf::Color(255, 255, 255, 255);
else itemColor = sf::Color(180, 180, 180, 255);
std::ostringstream oss;
oss << tools::getLabel(inputKeyString[i]) << ": ";
if (menuKeyIndex == i) oss << tools::getLabel("key_configuration_insert");
else if (menuKeyIndex > i) oss << keyToString(input[i]);
write(oss.str(), 16, xAlign, 330 + i * 25, ALIGN_LEFT, itemColor, app, 1, 1);
}
}
else if (menuState == MenuStateJoystick)
{
// menu keys
if (config.configFileExists())
write(tools::getLabel("joystick_configuration"), 18, xAlign, 295, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 1, 1);
else
write(tools::getLabel("joystick_configuration_desc"), 18, xAlign, 295, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 1, 1);
for (unsigned int i = 0; i < NumberKeys; i++)
{
sf::Color itemColor;
if (menuKeyIndex == i) itemColor = sf::Color(255, 255, 255, 255);
else itemColor = sf::Color(180, 180, 180, 255);
std::ostringstream oss;
oss << tools::getLabel(inputKeyString[i]) << ": ";
if (menuKeyIndex == i) oss << tools::getLabel("joystick_configuration_insert");
else if (menuKeyIndex > i) oss << "OK";
write(oss.str(), 16, xAlign, 330 + i * 25, ALIGN_LEFT, itemColor, app, 1, 1);
}
}
else
{
// menu
for (unsigned int i = 0; i < menu->items.size(); i++)
{
sf::Color itemColor;
if (menu->index == i)
{
itemColor = sf::Color(255, 255, 255, 255);
sf::Sprite fairySprite;
fairySprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_FAIRY));
fairySprite.setTextureRect(sf::IntRect( 48 * ((int)(20 *getAbsolutTime()) % 2), 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-2015 - " << " Seby (code), Pierre \"dejam0rt\" Baron (2D art)";
write(oss.str(), 17, 5, 680, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 1, 1);
}
void WitchBlastGame::renderAchievements()
{
app->draw(introScreenSprite);
if (titleSprite.getPosition().y > 160) titleSprite.move(0, -8);
else if (titleSprite.getPosition().y < 160) titleSprite.setPosition(SCREEN_WIDTH / 2 - 15, 180);
app->draw(titleSprite);
// achievements
write(tools::getLabel("menu_achievements"), 30, 485, 280, ALIGN_CENTER, sf::Color(255, 255, 255, 255), app, 1, 1);
int achWidth = 64, achHeight = 64, x0 = 180, y0 = 380, xStep = 16, yStep = 16, nbProLine = 8;
if (menuAchIndex / 8 < ACHIEV_LINES)
{
sf::RectangleShape rectangle(sf::Vector2f(achWidth, achHeight));
rectangle.setPosition(x0 + (menuAchIndex % nbProLine) * (achWidth + xStep), y0 + (menuAchIndex / nbProLine) * (achHeight + yStep));
rectangle.setOutlineThickness(3);
rectangle.setOutlineColor(sf::Color(50, 255, 50));
app->draw(rectangle);
}
sf::Sprite sprite;
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_ACHIEVEMENTS));
for (int k : sortedAchievements)
{
int i = sortedAchievements[k];
sprite.setPosition(x0 + (k % nbProLine) * (achWidth + xStep), y0 + (k / nbProLine) * (achHeight + yStep));
if (achievementState[i] == AchievementDone)
{
sprite.setTextureRect(sf::IntRect( ((i + 1) % 10) * achWidth, ((i + 1) / 10) * achHeight, achWidth, achHeight));
}
else
{
sprite.setTextureRect(sf::IntRect(0, 0, achWidth, achHeight));
}
app->draw(sprite);
}
if (menuAchIndex / 8 >= ACHIEV_LINES)
{
write(tools::getLabel("config_back"), 17, 485, 550, ALIGN_CENTER, sf::Color(255, 255, 255, 255), app, 1, 1);
}
else
{
write(tools::getLabel("config_back"), 17, 485, 550, ALIGN_CENTER, sf::Color(180, 180, 180, 255), app, 1, 1);
sf::Color fontColor = sf::Color::White;
std::stringstream oss;
int achIndex = sortedAchievements[menuAchIndex];
if (!achievementState[achIndex] == AchievementDone && (
achIndex == AchievementGiantSlime
|| achIndex == AchievementCyclops
|| achIndex == AchievementRatKing
|| achIndex == AchievementGiantSpider
|| achIndex == AchievementFrancky
|| achIndex == AchievementVampire)
)
oss << "???";
else
oss << tools::getLabel(achievements[achIndex].label);
oss << ": ";
if (achievementState[achIndex] == AchievementDone)
{
oss << tools::getLabel(achievements[achIndex].label + "_desc");
if (achievements[achIndex].unlockType == UnlockItem && achievements[achIndex].unlock > -1)
oss << "\nUNLOCK: " << tools::getLabel(items[achievements[achIndex].unlock].name);
else if (achievements[achIndex].unlockType == UnlockFunctionality && achievements[achIndex].unlock > -1)
oss << "\nUNLOCK: " << tools::getLabel(functionalityLabel[achievements[achIndex].unlock]);
}
else
{
if (isFunctionalityLocked(FunctionalityAllAchievements))
oss << "???";
else
oss << tools::getLabel(achievements[achIndex].label + "_desc");
fontColor = sf::Color(150, 150, 150);
}
write(oss.str(), 19, 100, 650, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 1, 1);
}
}
void WitchBlastGame::renderCredits()
{
app->draw(introScreenSprite);
if (titleSprite.getPosition().y > 160) titleSprite.move(0, -8);
else if (titleSprite.getPosition().y < 160) titleSprite.setPosition(SCREEN_WIDTH / 2 - 15, 180);
app->draw(titleSprite);
// credits
write(tools::getLabel("credits"), 30, 485, 275, ALIGN_CENTER, sf::Color(255, 255, 255, 255), app, 1, 1);
int yCursorInit = 365;
int yStep = 30;
int xLeft = 30;
int xRight = 470;
int xMarging = 20;
int yCursor = yCursorInit;
write("Code", 22, xLeft, yCursor, ALIGN_LEFT, sf::Color(210, 210, 255, 255), app, 0,0);
yCursor += yStep;
int i = 0;
while (creditsCode[i] != "END")
{
write(creditsCode[i], 19, xLeft + xMarging, yCursor, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 0,0);
yCursor += yStep;
i++;
}
yCursor += yStep;
write("2D Art", 22, xLeft, yCursor, ALIGN_LEFT, sf::Color(210, 210, 255, 255), app, 0,0);
yCursor += yStep;
i = 0;
while (credits2D[i] != "END")
{
write(credits2D[i], 19, xLeft + xMarging, yCursor, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 0,0);
yCursor += yStep;
i++;
}
yCursor += yStep;
write("Sound", 22, xLeft, yCursor, ALIGN_LEFT, sf::Color(210, 210, 255, 255), app, 0,0);
yCursor += yStep;
i = 0;
while (creditsSound[i] != "END")
{
write(creditsSound[i], 19, xLeft + xMarging, yCursor, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 0,0);
yCursor += yStep;
i++;
}
yCursor += yStep;
////// RIGHT
yCursor = yCursorInit - yStep;
write("Music", 22, xRight, yCursor, ALIGN_LEFT, sf::Color(210, 210, 255, 255), app, 0,0);
yCursor += yStep;
i = 0;
while (creditsMusic[i] != "END")
{
write(creditsMusic[i], 19, xRight + xMarging, yCursor, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 0,0);
yCursor += yStep;
i++;
}
yCursor += yStep;
write("Translation", 22, xRight, yCursor, ALIGN_LEFT, sf::Color(210, 210, 255, 255), app, 0,0);
yCursor += yStep;
i = 0;
while (creditsTranslate[i] != "END")
{
write(creditsTranslate[i], 19, xRight + xMarging, yCursor, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 0,0);
yCursor += yStep;
i++;
}
yCursor += yStep;
}
void WitchBlastGame::renderScores(std::vector <StructScore> scoresToRender, std::string title)
{
sf::Sprite bgSprite;
bgSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_INTRO));
app->draw(bgSprite);
// hi-scores-title
write(title, 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 < scoresToRender.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 (scoresToRender[i].score == lastScore.score && scoresToRender[i].level == lastScore.level && scoresToRender[i].name == lastScore.name)
{
int fade = 1 + cosf(getAbsolutTime() * 8) * 63;
color = sf::Color(255, 128 + fade, 255);
}
renderPlayer(x1 + (i / 5) * xRight, y0 + yStep * index, scoresToRender[i].equip, scoresToRender[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 << scoresToRender[i].name << " (" << scoresToRender[i].level << ")";
write(ss.str(), 17, x2 + (i / 5) * xRight, y0 + 30 + yStep * index, ALIGN_LEFT, color, app, 1, 1);
write(intToString(scoresToRender[i].score), 17, x3 + (i / 5) * xRight, y0 + 30 + yStep * index, ALIGN_RIGHT, color, app, 1, 1);
}
// retrieving from DB ?
if ( (menuScoreIndex == 0 && scoreState == ScoreLoading)
|| (menuScoreIndex == 1 && ((scoreState == ScoreLoading) || (scoreState == ScoreLoadingDay))))
{
std::stringstream oss;
oss << "Loading";
int n = (int)(getAbsolutTime() * 3) % 3;
if (n == 0) oss << ".";
else if (n == 1) oss << "..";
else oss << "...";
write(oss.str(), 15, 20, 20, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 1, 1);
}
}
void WitchBlastGame::renderHiScores()
{
sf::Sprite bgSprite;
bgSprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_INTRO));
app->draw(bgSprite);
// hi-scores-title
write(tools::getLabel("hi_scores"), 30, 485, 20, ALIGN_CENTER, sf::Color(255, 255, 255, 255), app, 1, 1);
int x0 = 25;
int x1 = 70;
int x2 = 125;
int x3 = 430;
int y0 = 130;
int yStep = 100;
int xRight = SCREEN_WIDTH / 2;
sf::RectangleShape line(sf::Vector2f(2, 600));
line.setPosition(SCREEN_WIDTH / 2, 80);
app->draw(line);
for (unsigned int i = 0; i < scores.size() && i < SCORES_MAX; i++)
{
int index = i < SCORES_MAX / 2 ? i : i - SCORES_MAX / 2;
sf::Color color = sf::Color( 220, 220, 220);
if (scores[i].score == lastScore.score && scores[i].level == lastScore.level && scores[i].name == lastScore.name)
{
int fade = 1 + cosf(getAbsolutTime() * 8) * 63;
color = sf::Color(255, 128 + fade, 255);
}
renderPlayer(x1 + (i / 5) * xRight, y0 + yStep * index, scores[i].equip, scores[i].shotType, 1, 0);
write(intToString(i + 1), 24, x0 + (i / 5) * xRight, y0 + 30 + yStep * index, ALIGN_CENTER, color, app, 1, 1);
std::stringstream ss;
ss << scores[i].name << " (" << scores[i].level << ")";
write(ss.str(), 17, x2 + (i / 5) * xRight, y0 + 30 + yStep * index, ALIGN_LEFT, color, app, 1, 1);
write(intToString(scores[i].score), 17, x3 + (i / 5) * xRight, y0 + 30 + yStep * index, ALIGN_RIGHT, color, app, 1, 1);
}
}
void WitchBlastGame::renderInGameMenu()
{
menuStuct* menu = &menuInGame;
int xAlign = 290;
int yAlign = 200;
{
// menu
for (unsigned int i = 0; i < menu->items.size(); i++)
{
sf::Color itemColor;
if (menu->index == i)
{
itemColor = sf::Color(255, 255, 255, 255);
sf::Sprite fairySprite;
fairySprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_FAIRY));
fairySprite.setTextureRect(sf::IntRect( 48 * ((int)(8 *getAbsolutTime()) % 2), 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;
if (deltaTime < 0.008f)
{
float sleepTime = 1.0f / 60.0f - deltaTime;
sf::sleep(sf::seconds(sleepTime));
deltaTime = getAbsolutTime() - lastTime;
}
lastTime = getAbsolutTime();
if (deltaTime > 0.05f) deltaTime = 0.05f;
updateActionKeys();
switch (gameState)
{
case gameStateInit:
case gameStateKeyConfig:
case gameStateJoystickConfig:
case gameStateMenu:
updateMenu();
break;
case gameStateIntro:
updateIntro();
break;
case gameStatePlaying:
case gameStatePlayingPause:
case gameStatePlayingDisplayBoss:
updateRunningGame();
break;
}
onRender();
}
quitGame();
}
void WitchBlastGame::createFloor()
{
// TODO : extracts from createNewGame
}
void WitchBlastGame::closeDoors()
{
if (!currentMap->isCleared())
{
int i;
for(i = 0; i < MAP_WIDTH; i++)
{
if (currentMap->isDoor(i, 0)) currentMap->closeDoor(i, 0);
if (currentMap->isDoor(i, MAP_HEIGHT - 1)) currentMap->closeDoor(i, MAP_HEIGHT - 1);
}
for(i = 0; i < MAP_HEIGHT; i++)
{
if (currentMap->isDoor(0, i)) currentMap->closeDoor(0, i);
if (currentMap->isDoor(MAP_WIDTH - 1, i)) currentMap->closeDoor(MAP_WIDTH - 1, i);
}
roomClosed = true;
}
}
void WitchBlastGame::openDoors()
{
int i;
for(i = 0; i < MAP_WIDTH; i++)
{
if (currentMap->isDoor(i, 0)) currentMap->openDoor(i, 0);
if (currentMap->isDoor(i, MAP_HEIGHT - 1)) currentMap->openDoor(i, MAP_HEIGHT - 1);
}
for(i = 0; i < MAP_HEIGHT; i++)
{
if (currentMap->isDoor(0, i)) currentMap->openDoor(0, i);
if (currentMap->isDoor(MAP_WIDTH - 1, i)) currentMap->openDoor(MAP_WIDTH - 1, i);
}
roomClosed = false;
SoundManager::getInstance().playSound(SOUND_DOOR_OPENING);
if (currentMap->hasNeighbourUp() == 2 && !bossRoomOpened)
currentMap->closeDoor(MAP_WIDTH/2, 0);
- else
+ else if (currentMap->hasKnownNeighbour(North, true))
doorEntity[0]->openDoor();
if (currentMap->hasNeighbourLeft() == 2 && !bossRoomOpened)
currentMap->closeDoor(0, MAP_HEIGHT / 2);
- else
+ else if (currentMap->hasKnownNeighbour(West, true))
doorEntity[1]->openDoor();
if (currentMap->hasNeighbourDown() == 2 && !bossRoomOpened)
currentMap->closeDoor(MAP_WIDTH / 2, MAP_HEIGHT - 1);
- else
+ else if (currentMap->hasKnownNeighbour(South, true))
doorEntity[2]->openDoor();
if (currentMap->hasNeighbourRight() == 2 && !bossRoomOpened)
currentMap->closeDoor(MAP_WIDTH - 1, MAP_HEIGHT / 2);
- else
+ else if (currentMap->hasKnownNeighbour(East, true))
doorEntity[3]->openDoor();
}
EnemyEntity* WitchBlastGame::getBoss()
{
EntityManager::EntityList* entityList =EntityManager::getInstance().getList();
EntityManager::EntityList::iterator it;
for (it = entityList->begin (); it != entityList->end ();)
{
GameEntity *e = *it;
it++;
if (e->getType() == ENTITY_ENEMY_BOSS) return static_cast<EnemyEntity*> (e);
}
return NULL;
}
int WitchBlastGame::getEnemyCount()
{
int n=0;
EntityManager::EntityList* entityList =EntityManager::getInstance().getList();
EntityManager::EntityList::iterator it;
for (it = entityList->begin (); it != entityList->end ();)
{
GameEntity *e = *it;
it++;
if (e->getType() >= ENTITY_ENEMY && e->getType() <= ENTITY_ENEMY_MAX_COUNT) n++;
}
return n;
}
int WitchBlastGame::getUndeadCount()
{
int n=0;
EntityManager::EntityList* entityList =EntityManager::getInstance().getList();
EntityManager::EntityList::iterator it;
for (it = entityList->begin (); it != entityList->end ();)
{
GameEntity *e = *it;
it++;
if (e->getType() >= ENTITY_ENEMY && e->getType() <= ENTITY_ENEMY_MAX_COUNT)
{
EnemyEntity* enemy = dynamic_cast<EnemyEntity*>(e);
if (enemy->canCollide() && (enemy->getEnemyType() == EnemyTypeZombie || enemy->getEnemyType() == EnemyTypeZombieDark
|| enemy->getEnemyType() == EnemyTypeGhost || enemy->getEnemyType() == EnemyTypeVampire || enemy->getEnemyType() == EnemyTypeBat_invocated) )
n++;
}
}
return n;
}
void WitchBlastGame::killArtefactDescription()
{
EntityManager::EntityList* entityList =EntityManager::getInstance().getList();
EntityManager::EntityList::iterator it;
for (it = entityList->begin (); it != entityList->end ();)
{
GameEntity *e = *it;
it++;
if (e->getType() == ENTITY_ARTIFACT_DESCRIPTION)
{
e->setDying(true);
}
}
}
void WitchBlastGame::animateEffects()
{
EntityManager::EntityList* entityList =EntityManager::getInstance().getList();
EntityManager::EntityList::iterator it;
for (it = entityList->begin (); it != entityList->end ();)
{
GameEntity *e = *it;
it++;
if (e->getType() == ENTITY_EFFECT)
e->animate(deltaTime);
}
}
void WitchBlastGame::destroyUndead(int damage)
{
EntityManager::EntityList* entityList =EntityManager::getInstance().getList();
EntityManager::EntityList::iterator it;
for (it = entityList->begin (); it != entityList->end ();)
{
GameEntity *e = *it;
it++;
if (e->getType() >= ENTITY_ENEMY && e->getType() <= ENTITY_ENEMY_MAX_COUNT)
{
EnemyEntity* enemy = dynamic_cast<EnemyEntity*>(e);
if (enemy->canCollide() && (enemy->getEnemyType() == EnemyTypeZombie || enemy->getEnemyType() == EnemyTypeZombieDark
|| enemy->getEnemyType() == EnemyTypeGhost || enemy->getEnemyType() == EnemyTypeVampire || enemy->getEnemyType() == EnemyTypeBat_invocated) )
{
enemy->hurt(BaseCreatureEntity::getHurtParams(damage, ShotTypeStandard, 0, false, SourceTypeMelee, EnemyTypeNone, false));
SpriteEntity* spriteCone = new SpriteEntity(
ImageManager::getInstance().getImage(IMAGE_LIGHT_CONE),
enemy->getX(), enemy->getZ() - 290);
spriteCone->setZ(1000.0f);
spriteCone->setFading(true);
spriteCone->setAge(-1.2f);
spriteCone->setLifetime(2.4f);
spriteCone->setRenderAdd();
}
}
}
}
int WitchBlastGame::getItemsCount()
{
int n=0;
EntityManager::EntityList* entityList =EntityManager::getInstance().getList();
EntityManager::EntityList::iterator it;
for (it = entityList->begin (); it != entityList->end ();)
{
GameEntity *e = *it;
it++;
if (e->getType() == ENTITY_ITEM) n++;
}
return n;
}
Vector2D WitchBlastGame::getNearestEnemy(float x, float y)
{
Vector2D target(-100.0f, -100.0f);
float distanceMin = -1.0f;
EntityManager::EntityList* entityList =EntityManager::getInstance().getList();
EntityManager::EntityList::iterator it;
for (it = entityList->begin (); it != entityList->end ();)
{
GameEntity *e = *it;
it++;
if (e->getType() >= ENTITY_ENEMY && e->getType() <= ENTITY_ENEMY_MAX_COUNT)
{
// enemy
EnemyEntity* enemy = dynamic_cast<EnemyEntity*>(e);
if (enemy->canCollide())
{
float d2 = (x - enemy->getX()) * (x - enemy->getX()) + (y - enemy->getY()) * (y - enemy->getY());
if (target.x < -1.0f || d2 < distanceMin)
{
distanceMin = d2;
target.x = enemy->getX();
target.y = enemy->getY();
}
}
}
}
return target;
}
-void WitchBlastGame::checkDoor(int doorId, roomTypeEnum roomCurrent, roomTypeEnum roomNeighbour)
+void WitchBlastGame::setDoorVisible(int n)
+{
+ if (n >= 0 && n < 4)
+ doorEntity[n]->setVisible(true);
+}
+
+void WitchBlastGame::checkDoor(int doorId, roomTypeEnum roomCurrent, roomTypeEnum roomNeighbour, bool isNeighbourKnown)
{
if (roomNeighbour == roomTypeNULL)
{
doorEntity[doorId]->setVisible(false);
return;
}
- doorEntity[doorId]->setVisible(true);
+ doorEntity[doorId]->setVisible(isNeighbourKnown);
doorEntity[doorId]->setDoorType(currentMap->getDoorType(doorId));
if (roomNeighbour == roomTypeBoss && !bossRoomOpened)
{
doorEntity[doorId]->setOpen(false);
switch (doorId)
{
case 0:
currentMap->closeDoor(MAP_WIDTH/2, 0);
break;
case 1:
currentMap->closeDoor(0, MAP_HEIGHT / 2);
break;
case 2:
currentMap->closeDoor(MAP_WIDTH/2, MAP_HEIGHT - 1);
break;
case 3:
currentMap->closeDoor(MAP_WIDTH - 1, MAP_HEIGHT / 2);
break;
}
}
else
doorEntity[doorId]->setOpen(true);
}
void WitchBlastGame::refreshMap()
{
// clean the sprites from old map
EntityManager::getInstance().partialClean(10);
// if new map, it has to be randomized
bool generateMap = !(currentFloor->getMap(floorX, floorY)->isVisited());
currentMap = currentFloor->getAndVisitMap(floorX, floorY);
// load the map
dungeonEntity->refreshMap();
player->setMap(currentMap, TILE_WIDTH, TILE_HEIGHT, 0, 0);
refreshMinimap();
if(generateMap)
this->generateMap();
else
{
if (currentMap->getRoomType() == roomTypeMerchant)
{
new PnjEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2 - 1) * TILE_HEIGHT,
0);
}
}
// check doors
- checkDoor(0, currentMap->getRoomType(), currentMap->getNeighbourUp());
- checkDoor(1, currentMap->getRoomType(), currentMap->getNeighbourLeft());
- checkDoor(2, currentMap->getRoomType(), currentMap->getNeighbourDown());
- checkDoor(3, currentMap->getRoomType(), currentMap->getNeighbourRight());
+ checkDoor(0, currentMap->getRoomType(), currentMap->getNeighbourUp(), currentMap->hasKnownNeighbour(North, true));
+ checkDoor(1, currentMap->getRoomType(), currentMap->getNeighbourLeft(), currentMap->hasKnownNeighbour(West, true));
+ checkDoor(2, currentMap->getRoomType(), currentMap->getNeighbourDown(), currentMap->hasKnownNeighbour(South, true));
+ checkDoor(3, currentMap->getRoomType(), currentMap->getNeighbourRight(), currentMap->hasKnownNeighbour(East, true));
// pet slime
if (player->isEquiped(EQUIP_PET_SLIME) && currentMap->getRoomType() != roomTypeTemple) new SlimePetEntity();
// barrels
checkDestroyableObjects();
}
void WitchBlastGame::refreshMinimap()
{
for (int j=0; j < FLOOR_HEIGHT; j++)
for (int i=0; i < FLOOR_WIDTH; i++)
{
int 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 if (currentFloor->getRoom(i, j) == roomTypeTemple)
+ miniMap->setTile(i, j, 8);
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 roomTypeSecret:
+ miniMap->setTile(i, j, 18 );
+ break;
case roomTypeStandard:
case roomTypeStarting:
miniMap->setTile(i, j, 11);
break;
case roomTypeNULL:
miniMap->setTile(i, j, 0);
break;
}
}
else
miniMap->setTile(i, j, 0);
}
miniMap->setTile(floorX, floorY, 10);
int xMap = 760 + (6 - floorX) * 19;
if (xMap < 710) xMap = 710;
else if (xMap > 795) xMap = 795;
int yMap = 620 + (3 - floorY) * 15;
if (yMap < 596) yMap = 596;
else if (yMap > 640) yMap = 640;
miniMapEntity->setX(xMap);
miniMapEntity->setY(yMap);
}
void WitchBlastGame::checkEntering()
{
if (!currentMap->isCleared())
{
player->setEntering();
SoundManager::getInstance().playSound(SOUND_DOOR_CLOSING);
for (int i=0; i<4; i++)
doorEntity[i]->closeDoor();
}
}
void WitchBlastGame::saveMapItems()
{
currentMap->cleanMapObjects();
// blood
std::vector <displayEntityStruct> blood = dungeonEntity->getBlood();
for (auto particle: blood)
currentMap->addSprite(ENTITY_BLOOD, particle.frame, particle.x, particle.y, particle.scale);
// corpses
std::vector <displayEntityStruct> corpses = dungeonEntity->getCorpses();
for (auto particle: corpses)
currentMap->addSprite(ENTITY_CORPSE, particle.frame, particle.x, particle.y, particle.scale);
EntityManager::EntityList* entityList = EntityManager::getInstance().getList();
EntityManager::EntityList::iterator it;
for (it = entityList->begin (); it != entityList->end ();)
{
GameEntity* e = *it;
it++;
ItemEntity* itemEntity = dynamic_cast<ItemEntity*>(e);
ChestEntity* chestEntity = dynamic_cast<ChestEntity*>(e);
if (itemEntity != NULL && !itemEntity->getDying())
{
currentMap->addItem(itemEntity->getItemType(), itemEntity->getX(), itemEntity->getY(), itemEntity->getMerchandise());
} // endif
else if (chestEntity != NULL && !chestEntity->getDying())
{
currentMap->addChest(chestEntity->getChestType(), chestEntity->getOpened(), chestEntity->getX(), chestEntity->getY());
} // endif
} // end for
}
void WitchBlastGame::moveToOtherMap(int direction)
{
// stairs to next level
if (direction == 8 && currentMap->getRoomType() == roomTypeExit)
{
if (player->getPlayerStatus() != PlayerEntity::playerStatusGoingNext)
{
player->setLeavingLevel();
xGame[xGameTypeFade].active = true;
xGame[xGameTypeFade].param = X_GAME_FADE_OUT;
xGame[xGameTypeFade].timer = FADE_OUT_DELAY;
player->setVelocity(Vector2D(0.0f, - INITIAL_PLAYER_SPEED / 2));
}
}
// go to another room
else
{
saveMapItems();
switch (direction)
{
case (4):
floorX--;
player->moveTo((MAP_WIDTH * TILE_WIDTH), player->getY());
player->move(4);
break;
case (6):
floorX++;
player->moveTo(0, player->getY());
player->move(6);
break;
case (8):
floorY--;
player->moveTo(player->getX(), MAP_HEIGHT * TILE_HEIGHT);
player->move(8);
break;
case (2):
floorY++;
player->moveTo(player->getX(), 0);
break;
}
refreshMap();
checkEntering();
currentMap->restoreMapObjects();
saveInFight.x = player->getX();
saveInFight.y = player->getY();
saveInFight.direction = direction;
saveMapItems();
if (!currentMap->isCleared())
{
saveGame();
}
}
}
void WitchBlastGame::onRender()
{
// clear the view
app->clear(sf::Color::Black);
switch (gameState)
{
case gameStateInit:
case gameStateKeyConfig:
case gameStateJoystickConfig:
case gameStateMenu:
renderMenu();
break;
case gameStatePlaying:
case gameStatePlayingPause:
case gameStatePlayingDisplayBoss:
renderRunningGame();
break;
case gameStateIntro:
renderIntro();
break;
}
app->display();
}
void WitchBlastGame::renderHudShots(sf::RenderTarget* app)
{
int xHud = 277;
int yHud = 655;
int index = 0;
for (int i = 0; i < SPECIAL_SHOT_SLOTS; i++)
{
if (i == 0 || player->getShotType(i) != ShotTypeStandard)
{
int type_shot = player->getShotType(i);
uiSprites.shotsSprite.setPosition(xHud + 55 * index, yHud);
if (index == player->getShotIndex())
{
uiSprites.shotsSprite.setTextureRect(sf::IntRect(0, 0, 48, 48));
app->draw(uiSprites.shotsSprite);
}
uiSprites.shotsSprite.setTextureRect(sf::IntRect(48 * ( 1 + type_shot), 0, 48, 48));
app->draw(uiSprites.shotsSprite);
// level
if (i > 0)
{
std::ostringstream oss;
oss << "lvl " << player->getShotLevel(i) + 1;
write(oss.str(), 10, xHud + 55 * index + 10, yHud + 48, ALIGN_LEFT, sf::Color(255, 255, 255, 255), app, 0, 0);
}
index++;
}
}
}
void WitchBlastGame::generateBlood(float x, float y, BaseCreatureEntity::enumBloodColor bloodColor)
{
dungeonEntity->generateBlood(x, y, bloodColor);
// double blood if the "Blood Snake" object is equipped
if (player->isEquiped(EQUIP_BLOOD_SNAKE)) dungeonEntity->generateBlood(x, y, bloodColor);
}
void WitchBlastGame::addCorpse(float x, float y, int frame)
{
dungeonEntity->addCorpse(x, y, frame);
}
void WitchBlastGame::showArtefactDescription(enumItemType itemType)
{
killArtefactDescription();
new ArtefactDescriptionEntity(itemType);
}
void WitchBlastGame::generateMap()
{
saveInFight.monsters.clear();
if (currentMap->getRoomType() == roomTypeStandard)
generateStandardMap();
else if (currentMap->getRoomType() == roomTypeBonus)
{
currentMap->setCleared(true);
Vector2D v = currentMap->generateBonusRoom();
int bonusType = getRandomEquipItem(false, false);
if (items[FirstEquipItem + bonusType].familiar > FamiliarNone)
{
new ChestEntity(v.x, v.y, ChestFairy + items[FirstEquipItem + bonusType].familiar, false);
}
else
{
new ItemEntity( (enumItemType)(FirstEquipItem + bonusType), v.x ,v.y);
}
}
else if (currentMap->getRoomType() == roomTypeKey)
{
currentMap->generateKeyRoom();
initMonsterArray();
int x0 = MAP_WIDTH / 2;
int y0 = MAP_HEIGHT / 2;
monsterArray[x0][y0] = true;
if (level == 1)
{
findPlaceMonsters(EnemyTypeRat, 2);
findPlaceMonsters(EnemyTypeBat, 2);
}
else if (level < 6)
{
findPlaceMonsters(EnemyTypeRat, 5);
findPlaceMonsters(EnemyTypeBat, 5);
for (int i = 2; i < level; i++)
{
if (rand()%2 == 0)findPlaceMonsters(EnemyTypeImpBlue, 1);
else findPlaceMonsters(EnemyTypeImpRed, 1);
}
}
else
{
findPlaceMonsters(EnemyTypeZombie, 5);
findPlaceMonsters(EnemyTypeBat, 5);
for (int i = 5; i < level; i++)
{
if (rand()%2 == 0)findPlaceMonsters(EnemyTypeImpBlue, 1);
else findPlaceMonsters(EnemyTypeImpRed, 1);
}
}
}
else if (currentMap->getRoomType() == roomTypeMerchant)
{
currentMap->generateMerchantRoom();
ItemEntity* item1 = new ItemEntity(
ItemHealth,
(MAP_WIDTH / 2 - 1) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + 5);
item1->setMerchandise(true);
ItemEntity* item3 = new ItemEntity(
ItemHealthSmall,
(MAP_WIDTH / 2 + 1) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + 5);
item3->setMerchandise(true);
int bonusType = getRandomEquipItem(true, true);
ItemEntity* item2 = new ItemEntity(
(enumItemType)(FirstEquipItem + bonusType),
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + 5);
item2->setMerchandise(true);
// level item ?
if (rand() % 3 == 0)
{
int r = rand() % 4;
int item4Type = -1;
switch (r)
{
case 0:
if (!game().getPlayer()->isEquiped(EQUIP_FLOOR_MAP)) item4Type = ItemFloorMap;
break;
case 1:
if (!game().getPlayer()->isEquiped(EQUIP_ALCOHOL)) item4Type = ItemAlcohol;
break;
case 2:
if (!game().getPlayer()->isEquiped(EQUIP_LUCK)) item4Type = ItemLuck;
break;
default:
if (!game().getPlayer()->isEquiped(EQUIP_FAIRY_POWDER) && player->getFairieNumber() > 0) item4Type = ItemFairyPowder;
break;
}
if (item4Type > -1)
{
ItemEntity* item4 = new ItemEntity(
(enumItemType)(item4Type),
(MAP_WIDTH / 2 + 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + 5);
item4->setMerchandise(true);
}
}
new PnjEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2 - 1) * TILE_HEIGHT,
0);
currentMap->setCleared(true);
proceedEvent(EventFindShop);
}
else if (currentMap->getRoomType() == roomTypeChallenge)
{
currentMap->generateRoomWithoutHoles(0);
if (challengeLevel == 1)
{
addMonster(EnemyTypeBubble,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else
{
addMonster(challengeLevel >= 3 ? EnemyTypeBubbleIce : EnemyTypeBubble,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 - 80,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
addMonster(challengeLevel >= 4 ? EnemyTypeBubbleGreater : EnemyTypeBubble,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 + 80,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
playMusic(MusicChallenge);
}
else if (currentMap->getRoomType() == roomTypeBoss)
{
currentMap->generateRoomWithoutHoles(0);
if (level == 1)
{
findPlaceMonsters(EnemyTypeRat, 2);
addMonster(EnemyTypeButcher,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
testAndAddMessageToQueue(MsgInfoButcher);
}
else if (level == 2)
{
addMonster(EnemyTypeSlimeBoss,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
testAndAddMessageToQueue(MsgInfoGiantSlime);
}
else if (level == 3)
{
addMonster(EnemyTypeCyclops,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
testAndAddMessageToQueue(MsgInfoCyclops);
}
else if (level == 4)
{
addMonster(EnemyTypeRatKing,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
testAndAddMessageToQueue(MsgInfoWererat);
}
else if (level == 5)
{
addMonster(EnemyTypeSpiderGiant,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
testAndAddMessageToQueue(MsgInfoGiantSpiderBefore);
}
else if (level == 6)
{
addMonster(EnemyTypeFrancky,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
testAndAddMessageToQueue(MsgInfoFranky);
}
else if (level == 7)
{
addMonster(EnemyTypeVampire,
(MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
testAndAddMessageToQueue(MsgInfoVampire);
}
else if (level == 8)
{
// TODO
GiantSpiderEntity* b1 = new GiantSpiderEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 - 100,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
b1->setLabelDy(10);
FranckyEntity* b2 = new FranckyEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
b2->setLabelDy(-530);
KingRatEntity* b3 = new KingRatEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 + 100,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
b3->setLabelDy(-20);
new CyclopsEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 + 120,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
new CyclopsEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 - 120,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
}
else // level > 6
{
GiantSpiderEntity* b1 = new GiantSpiderEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 - 100,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
b1->setLabelDy(10);
GiantSlimeEntity* b2 = new GiantSlimeEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
b2->setLabelDy(-510);
KingRatEntity* b3 = new KingRatEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2 + 100,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
b3->setLabelDy(-20);
CyclopsEntity* b4 = new CyclopsEntity((MAP_WIDTH / 2) * TILE_WIDTH + TILE_WIDTH / 2,
(MAP_HEIGHT / 2) * TILE_HEIGHT + TILE_HEIGHT / 2);
b4->setLabelDy(-540);
findPlaceMonsters(EnemyTypeCauldron, 2);
findPlaceMonsters(EnemyTypeImpBlue, 4);
}
playMusic(MusicBoss);
// boss screen
if (parameters.displayBossPortrait)
{
gameState = gameStatePlayingDisplayBoss;
bossDisplayTimer = 0.0f;
bossDisplayState = 0;
dungeonEntity->animate(0.0f);
}
}
else if (currentMap->getRoomType() == roomTypeStarting)
{
currentMap->generateRoomWithoutHoles(0);
currentMap->setCleared(true);
}
else if (currentMap->getRoomType() == roomTypeExit)
{
currentMap->generateExitRoom();
currentMap->setCleared(true);
new ChestEntity((TILE_WIDTH * MAP_WIDTH * 0.5f),
(TILE_HEIGHT * MAP_HEIGHT * 0.5f),
ChestExit, false);
}
else if (currentMap->getRoomType() == roomTypeTemple)
{
currentMap->generateTempleRoom();
currentMap->setCleared(true);
proceedEvent(EventFindTemple);
}
+ else if (currentMap->getRoomType() == roomTypeSecret)
+ {
+ currentMap->generateRoomWithoutHoles(0);
+ currentMap->setCleared(true);
+ }
else // "normal" room
currentMap->randomize(currentMap->getRoomType());
}
void WitchBlastGame::write(std::string str, int size, float x, float y, int align, sf::Color color, sf::RenderTarget* app, int xShadow = 0, int yShadow = 0)
{
myText.setString(str);
myText.setString(sf::String::fromUtf8(str.begin(), str.end()));
myText.setCharacterSize(size);
float xFont = x;
if (align == ALIGN_CENTER)
xFont = x - myText.getLocalBounds().width / 2;
else if (align == ALIGN_RIGHT)
xFont = x - myText.getLocalBounds().width;
if (xShadow != 0 && yShadow != 0)
{
myText.setPosition(xFont + xShadow, y + yShadow);
myText.setColor(sf::Color(0, 0, 0, 255));
app->draw(myText);
}
myText.setPosition(xFont, y);
myText.setColor(color);
app->draw(myText);
}
void WitchBlastGame::initMonsterArray()
{
for (int i = 0; i < MAP_WIDTH; i++)
for (int j = 0; j < MAP_HEIGHT; j++)
monsterArray[i][j] = false;
}
void WitchBlastGame::addMonster(enemyTypeEnum monsterType, float xm, float ym)
{
StructMonster monster;
monster.id = monsterType;
monster.x = xm;
monster.y = ym;
saveInFight.monsters.push_back(monster);
switch (monsterType)
{
case EnemyTypeRat:
new RatEntity(xm, ym - 2, RatEntity::RatTypeNormal, false);
proceedEvent(EventMeetRatsOrBats);
break;
case EnemyTypeRatGreen:
new GreenRatEntity(xm, ym - 2);
proceedEvent(EventMeetRatsOrBats);
break;
case EnemyTypeRatBlack:
new BlackRatEntity(xm, ym - 5, BlackRatEntity::RatBlackTypeNormal);
break;
case EnemyTypeRatHelmet:
new RatEntity(xm, ym - 2, RatEntity::RatTypeHelmet, false);
break;
case EnemyTypeRatBlackHelmet:
new BlackRatEntity(xm, ym - 5, BlackRatEntity::RatBlackTypeHelmet);
break;
case EnemyTypeBat:
new BatEntity(xm, ym, BatStandard, false);
proceedEvent(EventMeetRatsOrBats);
break;
case EnemyTypeBatSkeleton:
new BatEntity(xm, ym, BatSkeleton, false);
break;
case EnemyTypeSnake:
new SnakeEntity(xm, ym, SnakeEntity::SnakeTypeNormal, false);
proceedEvent(EventMeetSnakes);
break;
case EnemyTypeSnakeBlood:
new SnakeEntity(xm, ym, SnakeEntity::SnakeTypeBlood, false);
proceedEvent(EventMeetSnakes);
break;
case EnemyTypeEvilFlower:
new EvilFlowerEntity(xm, ym - 2, FlowerTypeStandard);
break;
case EnemyTypeEvilFlowerIce:
new EvilFlowerEntity(xm, ym - 2, FlowerTypeIce);
break;
case EnemyTypeEvilFlowerFire:
new EvilFlowerEntity(xm, ym - 2, FlowerTypeFire);
break;
case EnemyTypeSlime:
new SlimeEntity(xm, ym, SlimeTypeStandard, false);
break;
case EnemyTypeImpRed:
new ImpEntity(xm, ym, ImpEntity::ImpTypeRed);
break;
case EnemyTypeImpBlue:
new ImpEntity(xm, ym, ImpEntity::ImpTypeBlue);
break;
case EnemyTypeSlimeRed:
new SlimeEntity(xm, ym, SlimeTypeRed, false);
break;
case EnemyTypeSlimeBlue:
new SlimeEntity(xm, ym, SlimeTypeBlue, false);
break;
case EnemyTypeSlimeViolet:
new SlimeEntity(xm, ym, SlimeTypeViolet, false);
break;
case EnemyTypePumpkin:
new PumpkinEntity(xm, ym, false);
break;
case EnemyTypeWitch:
new WitchEntity(xm, ym, WitchEntity::WitchTypeNormal);
proceedEvent(EventMeetWitches);
break;
case EnemyTypeWitchRed:
new WitchEntity(xm, ym, WitchEntity::WitchTypeRed);
proceedEvent(EventMeetWitches);
break;
case EnemyTypeCauldron:
new CauldronEntity(xm, ym, CauldronTypeStandard);
break;
case EnemyTypeCauldronElemental:
new CauldronEntity(xm, ym, CauldronTypeElemental);
break;
case EnemyTypeSpiderEgg:
new SpiderEggEntity(xm, ym, false);
break;
case 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 EnemyTypeBogeyman:
new BogeymanEntity(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 EnemyTypeSlimeLarge:
new LargeSlimeEntity(xm, ym, SlimeTypeStandard);
break;
case EnemyTypeSlimeBlueLarge:
new LargeSlimeEntity(xm, ym, SlimeTypeBlue);
break;
case EnemyTypeSlimeRedLarge:
new LargeSlimeEntity(xm, ym, SlimeTypeRed);
break;
case EnemyTypeSlimeVioletLarge:
new LargeSlimeEntity(xm, ym, SlimeTypeViolet);
break;
case EnemyTypeButcher:
new ButcherEntity(xm, ym);
break;
case EnemyTypeSlimeBoss:
new GiantSlimeEntity(xm, ym);
break;
case EnemyTypeCyclops:
new CyclopsEntity(xm, ym);
break;
case EnemyTypeRatKing:
new KingRatEntity(xm, ym);
break;
case EnemyTypeSpiderGiant:
new GiantSpiderEntity(xm, ym);
break;
case EnemyTypeFrancky:
new FranckyEntity(xm, ym);
break;
case EnemyTypeVampire:
new VampireEntity(xm, ym);
break;
default:
std::cout << "[WARNING] Enemy (" << monsterType << ") not handled in switch.\n";
}
}
void WitchBlastGame::findPlaceMonsters(enemyTypeEnum monsterType, int amount)
{
// find a suitable place
bool isMonsterFlying = monsterType == EnemyTypeBat
|| monsterType == EnemyTypeImpBlue
|| monsterType == EnemyTypeImpRed;
bool isMonsterLarge = monsterType == EnemyTypeSlimeLarge
|| monsterType == EnemyTypeSlimeBlueLarge
|| monsterType == EnemyTypeSlimeRedLarge
|| monsterType == EnemyTypeSlimeVioletLarge;
bool bOk;
int xm, ym;
float xMonster, yMonster;
for (int index = 0; index < amount; index++)
{
bOk = false;
int watchdog = 200;
while (!bOk && watchdog > 0)
{
bOk = true;
watchdog--;
if (isMonsterLarge)
{
xm = 2 +rand() % (MAP_WIDTH - 5);
ym = 2 +rand() % (MAP_HEIGHT - 5);
}
else
{
xm = 1 +rand() % (MAP_WIDTH - 3);
ym = 1 +rand() % (MAP_HEIGHT - 3);
}
if (monsterArray[xm][ym])
{
bOk = false;
}
if (bOk && !isMonsterFlying && !currentMap->isWalkable(xm, ym))
{
bOk = false;
}
if (bOk && isMonsterFlying && !currentMap->isFlyable(xm, ym))
{
bOk = false;
}
if (bOk)
{
xMonster = xm * TILE_WIDTH + TILE_WIDTH * 0.5f;
yMonster = ym * TILE_HEIGHT+ TILE_HEIGHT * 0.5f;
float dist2 = (xMonster - player->getX())*(xMonster - player->getX()) + (yMonster - player->getY())*(yMonster - player->getY());
if ( dist2 < 75000.0f)
{
bOk = false;
}
else
{
addMonster(monsterType, xMonster, yMonster);
monsterArray[xm][ym] = true;
}
}
}
}
}
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;
if (itemOk && presentItems[i]) itemOk = false;
// TODO item already in floor
if (itemOk && toSale && !items[eq].canBeSold) itemOk = false;
if (itemOk && !toSale && !items[eq].canBeFound) itemOk = false;
if (itemOk && items[eq].level > level) itemOk = false;
if (itemOk && isItemLocked((enumItemType)eq)) itemOk = false;
if (itemOk && items[eq].requirement >= FirstEquipItem
&& !player->isEquiped(items[eq].requirement - FirstEquipItem)) itemOk = false;
if (itemOk && toSale && level == 1 && items[eq].price > 25) itemOk = false;
if (itemOk && toSale && level == 2 && items[eq].price > 35) itemOk = false;
if (itemOk && (items[eq].specialShot != ShotTypeStandard && items[eq].level < 3) && player->canGetNewShot(false))
itemOk = false;
if (itemOk && (items[eq].specialShot != ShotTypeStandard && items[eq].level >= 3) && player->canGetNewShot(true))
itemOk = false;
if (itemOk && i == EQUIP_BOOK_DUAL && (player->isEquiped(EQUIP_BOOK_DUAL_QUICK) || player->isEquiped(EQUIP_RAPID_SHOT)))
itemOk = false;
if (itemOk && i == EQUIP_BOOK_DUAL_QUICK && (player->isEquiped(EQUIP_BOOK_DUAL) || player->isEquiped(EQUIP_RAPID_SHOT)))
itemOk = false;
if (itemOk && i == EQUIP_RAPID_SHOT && (player->isEquiped(EQUIP_BOOK_DUAL_QUICK) || player->isEquiped(EQUIP_BOOK_DUAL)))
itemOk = false;
if (itemOk && noFairy && items[eq].familiar != FamiliarNone) itemOk = false;
if (itemOk)
{
int n = 0;
switch (items[eq].rarity)
{
case RarityCommon:
n = 8;
break;
case RarityUncommon:
n = 4;
break;
case RarityRare:
n = 2;
break;
case RarityVeryRare:
n = 1;
break;
}
//if (itemOk && eq == ItemPetSlime) n = 15000;
for (int j = 0; j < n; j++)
{
bonusSet.push_back(i);
setSize++;
}
}
}
int bonusType = 0;
if (setSize > 0) bonusType = bonusSet[rand() % setSize];
//addPresentItem(bonusType);
return (item_equip_enum) bonusType;
}
enumItemType WitchBlastGame::getItemSpell()
{
bool ok = false;
enumItemType item = ItemMagicianHat;
while (!ok)
{
enumCastSpell n = (enumCastSpell)(rand() % SPELL_MAX);
if (player->getActiveSpell().spell != n) ok = true;
if (ok)
{
switch (n)
{
case SpellNone:
case SpellTeleport:
item = ItemSpellTeleport;
break;
case SpellSlimeExplode:
item = ItemSpellSlimeExplode;
break;
case SpellFireball:
item = ItemSpellFireball;
break;
case SpellFreeze:
item = ItemSpellFreeze;
break;
case SpellEarthquake:
item = ItemSpellEarthquake;
break;
case SpellProtection:
item = ItemSpellProtection;
break;
case SpellWeb:
item = ItemSpellWeb;
break;
case SpellFlower:
item = ItemSpellFlower;
break;
case SpellFairy:
item = ItemSpellFairy;
break;
}
ok = !isItemLocked(item);
}
}
return item;
}
void WitchBlastGame::generateChallengeBonus(float x, float y)
{
// loot
if (player->getActiveSpell().spell == SpellNone || rand() % 2 == 0)
{
enumItemType spell1 = getItemSpell();
ItemEntity* spellItem = new ItemEntity(spell1, x, y);
spellItem->setVelocity(Vector2D(100.0f + rand()% 250));
if (spellItem->getVelocity().y < 0.0f) spellItem->setVelocity(Vector2D(spellItem->getVelocity().x, -spellItem->getVelocity().y));
spellItem->setViscosity(0.96f);
if (!isFunctionalityLocked(FunctionalityDoubleSpellDrop))
{
enumItemType spell2 = spell1;
while (spell2 == spell1) spell2 = getItemSpell();
ItemEntity* spellItem2 = new ItemEntity(spell2, x, y);
spellItem2->setVelocity(Vector2D(100.0f + rand()% 250));
if (spellItem2->getVelocity().y < 0.0f) spellItem2->setVelocity(Vector2D(spellItem2->getVelocity().x, -spellItem2->getVelocity().y));
spellItem2->setViscosity(0.96f);
}
ItemEntity* healthItem1 = new ItemEntity(ItemHealthVerySmall, x, y);
healthItem1->setVelocity(Vector2D(100.0f + rand()% 250));
healthItem1->setViscosity(0.96f);
ItemEntity* healthItem2 = new ItemEntity(ItemHealthVerySmallPoison, x, y);
healthItem2->setVelocity(Vector2D(100.0f + rand()% 250));
healthItem2->setViscosity(0.96f);
}
else
{
ItemEntity* newItem;
if (challengeLevel < 4 || rand() % (player->isEquiped(EQUIP_LUCK) ? 5 : 8) > 0)
newItem = new ItemEntity(ItemBonusHealth, x, y);
else
newItem = new ItemEntity((enumItemType)(FirstEquipItem + getRandomEquipItem()), x, y);
if (newItem->getVelocity().y < 0.0f) newItem->setVelocity(Vector2D(newItem->getVelocity().x, -newItem->getVelocity().y));
newItem->setVelocity(Vector2D(100.0f + rand()% 250));
newItem->setViscosity(0.96f);
int gold = 2 + rand() % (player->isEquiped(EQUIP_LUCK) ? 9 : 14);
for (int i = 0; i < gold; i++)
{
ItemEntity* newItem = new ItemEntity(ItemCopperCoin, x, y);
newItem->setVelocity(Vector2D(90.0f + rand()% 150));
newItem->setViscosity(0.96f);
}
}
}
void WitchBlastGame::checkInteraction()
{
interaction.active = false;
if (player->getPlayerStatus() != PlayerEntity::playerStatusPlaying) return;
if (currentMap->getRoomType() == roomTypeTemple)
{
int divinity = currentMap->getDivinity(player->getX() / TILE_WIDTH, player->getZ() / TILE_HEIGHT);
if (divinity > -1)
{
interaction.active = true;
interaction.type = InteractionTypeTemple;
interaction.id = divinity;
std::stringstream ss;
ss << "[" << keyToString(input[KeyInteract]) << "] - ";
if (player->getDivinity().divinity == divinity)
{
ss << tools::getLabel("interact_donate");
if (player->getGold() < 10)
{
ss << " ";
ss << tools::getLabel("interact_donate_fail");
}
}
else
{
ss << tools::getLabel("interact_worship");
ss << " ";
ss << tools::getLabel(divinityLabel[divinity] + "_0");
}
interaction.label = ss.str();
}
}
else if (player->getItemToBuy() != NULL)
{
interaction.active = true;
interaction.type = InteractionTypeMerchandise;
interaction.id = player->getItemToBuy()->getItemType();
std::stringstream ss;
ss << tools::getLabel(items[interaction.id].name);
ss << ": ";
ss << tools::getLabel(items[interaction.id].description);
if (player->getItemToBuy()->canBePickedUp())
{
ss << std::endl;
ss << "[" << keyToString(input[KeyInteract]) << "] - ";
ss << tools::getLabel("interact_shop");
}
interaction.label = ss.str();
}
}
void WitchBlastGame::verifyDoorUnlocking()
{
int collidingDirection = (player->getCollidingDirection());
if (collidingDirection != 5 && currentMap->isCleared() && !bossRoomOpened && player->isEquiped(EQUIP_BOSS_KEY))
{
int xt = (player->getX()) / TILE_WIDTH;
int yt = (player->getY()) / TILE_HEIGHT;
if (yt <= 1 && xt >= MAP_WIDTH / 2 - 1 && xt <= MAP_WIDTH / 2 + 1 && currentMap->hasNeighbourUp() == 2)
{
doorEntity[0]->openDoor();
currentMap->openDoor(MAP_WIDTH / 2, 0);
SoundManager::getInstance().playSound(SOUND_DOOR_OPENING);
player->useBossKey();
bossRoomOpened = true;
}
if (yt >= MAP_HEIGHT - 2 && xt >= MAP_WIDTH / 2 - 1 &&xt <= MAP_WIDTH / 2 + 1 && currentMap->hasNeighbourDown() == 2)
{
doorEntity[2]->openDoor();
currentMap->openDoor(MAP_WIDTH / 2, MAP_HEIGHT - 1);
SoundManager::getInstance().playSound(SOUND_DOOR_OPENING);
player->useBossKey();
bossRoomOpened = true;
}
if (xt <= 1 && yt >= MAP_HEIGHT / 2 - 1 && yt <= MAP_HEIGHT / 2 + 1 && currentMap->hasNeighbourLeft() == 2)
{
doorEntity[1]->openDoor();
currentMap->openDoor(0, MAP_HEIGHT / 2);
SoundManager::getInstance().playSound(SOUND_DOOR_OPENING);
player->useBossKey();
bossRoomOpened = true;
}
if (xt >= MAP_WIDTH - 2 && yt >= MAP_HEIGHT / 2 - 1 && yt <= MAP_HEIGHT / 2 + 1 && currentMap->hasNeighbourRight() == 2)
{
doorEntity[3]->openDoor();
currentMap->openDoor(MAP_WIDTH - 1, MAP_HEIGHT / 2);
SoundManager::getInstance().playSound(SOUND_DOOR_OPENING);
player->useBossKey();
bossRoomOpened = true;
}
}
}
void WitchBlastGame::playMusic(musicEnum musicChoice)
{
music.stop();
if (parameters.musicVolume <= 0) return;
music.setLoop(true);
music.setVolume(parameters.musicVolume);
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)->isRevealed() << " "
<< currentFloor->getMap(i, j)->isCleared() << std::endl;
if (currentFloor->getMap(i, j)->isVisited())
{
for (l = 0; l < MAP_HEIGHT; l++)
{
for (k = 0; k < MAP_WIDTH; k++)
{
int tile = currentFloor->getMap(i, j)->getTile(k, l);
file << tile << " ";
tile = currentFloor->getMap(i, j)->getObjectTile(k, l);
if (tile == MAPOBJ_DOOR_CLOSED) tile = MAPOBJ_DOOR_OPEN;
file << tile << " ";
file << currentFloor->getMap(i, j)->getLogicalTile(k, l) << " ";
}
file << std::endl;
}
// style
file << currentFloor->getMap(i, j)->getFloorOffset() << " "
<< currentFloor->getMap(i, j)->getWallType() << std::endl;
// items, etc...
std::list<DungeonMap::itemListElement> itemList = currentFloor->getMap(i, j)->getItemList();
file << itemList.size() << std::endl;
std::list<DungeonMap::itemListElement>::iterator it;
for (it = itemList.begin (); it != itemList.end ();)
{
DungeonMap::itemListElement ilm = *it;
it++;
file << ilm.type << " " << ilm.x << " " << ilm.y << " " << ilm.merch << std::endl;
}
// chests
std::list<DungeonMap::chestListElement> chestList = currentFloor->getMap(i, j)->getChestList();
file << chestList.size() << std::endl;
std::list<DungeonMap::chestListElement>::iterator itc;
for (itc = chestList.begin (); itc != chestList.end ();)
{
DungeonMap::chestListElement ilm = *itc;
itc++;
file << ilm.type << " " << ilm.x << " " << ilm.y << " " << ilm.state << std::endl;
}
// sprites
std::list<DungeonMap::spriteListElement> spriteList = currentFloor->getMap(i, j)->getSpriteList();
file << spriteList.size() << std::endl;
std::list<DungeonMap::spriteListElement>::iterator its;
for (its = spriteList.begin (); its != spriteList.end ();)
{
DungeonMap::spriteListElement ilm = *its;
its++;
file << ilm.type << " " << ilm.frame << " " << ilm.x << " " << ilm.y << " " << ilm.scale << std::endl;
}
// doors
for (int k = 0; k < 4; k++)
file << currentFloor->getMap(i, j)->getDoorType(k) << " ";
file << std::endl;
// random sprite
for (int k = 0; k < NB_RANDOM_TILES_IN_ROOM; k++)
{
file << currentFloor->getMap(i, j)->getRandomTileElement(k).type
<< " " <<currentFloor->getMap(i, j)->getRandomTileElement(k).x
<< " " << currentFloor->getMap(i, j)->getRandomTileElement(k).y
<< " " << currentFloor->getMap(i, j)->getRandomTileElement(k).rotation << std::endl;
}
}
}
}
file << std::endl;
}
// game
file << floorX << " " << floorY << std::endl;
file << bossRoomOpened << std::endl;
// boss door !
// fight ?
if (currentMap->isCleared())
{
file << false << std::endl;
}
else
{
file << true << std::endl;
file << saveInFight.x << " " << saveInFight.y << " " << saveInFight.direction << std::endl;
file << saveInFight.monsters.size();
for (auto monster : saveInFight.monsters)
file << " " << monster.id << " " << monster.x << " " << monster.y;
file << std::endl;
}
// player
file << player->getHp() << " " << player->getHpMax() << " " << player->getGold() << std::endl;
for (i = 0; i < NUMBER_EQUIP_ITEMS; i++) file << player->isEquiped(i) << " ";
file << std::endl;
file << player->getX() << " " << player->getY() << std::endl;
file << player->getShotIndex();
for (i = 0; i < SPECIAL_SHOT_SLOTS; i++) file << " " << player->getShotType(i) << std::endl;
file << player->getActiveSpell().spell << std::endl;
for (i = 0; i < MAX_SLOT_CONSUMABLES; i++)
{
file << player->getConsumable(i) << " " << player->getConsumableAmount(i) << " ";
}
file << std::endl;
// divinity
file << player->getDivinity().divinity << " " << player->getDivinity().piety << " "
<< player->getDivinity().level << " " << player->getDivinity().interventions << std::endl;
// events
for (i = 0; i < NB_EVENTS; i++) file << worldEvent[i] << " ";
file.close();
}
else
{
std::cerr << "[ERROR] Saving the game..." << std::endl;
}
}
bool WitchBlastGame::loadGame()
{
resetPresentItems();
saveInFight.monsters.clear();
std::ifstream file(SAVE_FILE.c_str(), std::ios::in);
if (file)
{
int i, j, k, n;
// version
std::string v;
file >> v;
if (v != SAVE_VERSION)
{
file.close();
remove(SAVE_FILE.c_str());
return false;
}
// date an time
file >> v;
file >> v;
// floor
file >> level;
file >> challengeLevel;
file >> gameTime;
for (i = 0; i < NUMBER_EQUIP_ITEMS; i++)
{
bool eq;
file >> eq;
}
file >> n;
currentFloor = new GameFloor(level);
for (j = 0; j < FLOOR_HEIGHT; j++)
{
for (i = 0; i < FLOOR_WIDTH; i++)
{
int n;
file >> n;
currentFloor->setRoom(i, j, (roomTypeEnum)n);
}
}
// kill stats
for (int i = 0; i < NB_ENEMY; i++) file >> killedEnemies[i];
// 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->setRevealed(flag);
+ file >> flag;
iMap->setCleared(flag);
if (iMap->isVisited())
{
for (j = 0; j < MAP_HEIGHT; j++)
{
for (i = 0; i < MAP_WIDTH; i++)
{
file >> n;
iMap->setTile(i, j, n);
file >> n;
iMap->setObjectTile(i, j, n);
file >> n;
iMap->setLogicalTile(i, j, (logicalMapStateEnum)n);
}
}
// style
file >> n;
iMap->setFloorOffset(n);
file >> n;
iMap->setWallType(n);
// items int the map
file >> n;
for (i = 0; i < n; i++)
{
int t;
float x, y;
bool merc;
file >> t >> x >> y >> merc;
iMap->addItem(t, x, y, merc);
}
// chests in the map
file >> n;
for (i = 0; i < n; i++)
{
int t;
float x, y;
bool state;
file >> t >> x >> y >> state;
iMap->addChest(t, state, x, y);
}
// sprites in the map
file >> n;
for (i = 0; i < n; i++)
{
int t, f;
float x, y, scale;
file >> t >> f >> x >> y >> scale;
iMap->addSprite(t, f, x, y, scale);
}
// doors
for (int index = 0; index < 4; index++)
{
file >> n;
iMap->setDoorType(index, (doorEnum)n);
}
// random sprite
for (int index = 0; index < NB_RANDOM_TILES_IN_ROOM; index++)
{
DungeonMap::RandomTileElement rd;
file >> rd.type;
file >> rd.x;
file >> rd.y;
file >> rd.rotation;
iMap->setRandomTileElement(index, rd);
}
// random sprite
}
}
// game
file >> floorX >> floorY;
currentMap = currentFloor->getMap(floorX, floorY);
file >> bossRoomOpened;
// fight ?
file >> saveInFight.isFight;
if (saveInFight.isFight)
{
currentMap->setCleared(false);
file >> saveInFight.x;
file >> saveInFight.y;
file >> saveInFight.direction;
file >> n;
for (i = 0; i < n; i++)
{
StructMonster monster;
file >> j;
monster.id = (enemyTypeEnum)j;
file >> monster.x;
file >> monster.y;
saveInFight.monsters.push_back(monster);
}
}
// player
int hp, hpMax, gold;
file >> hp >> hpMax >> gold;
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);
for (i = 0; i < MAX_SLOT_CONSUMABLES; i++)
{
file >> n;
int amount;
file >> amount;
player->setConsumable(i, n, amount);
}
// divinity
{
int divinityId, piety, divLevel, interventions;
file >> divinityId;
file >> piety;
file >> divLevel;
file >> interventions;
player->loadDivinity(divinityId, piety, divLevel, interventions);
}
// events
for (i = 0; i < NB_EVENTS; i++)
{
bool event;
file >> event;
worldEvent[i] = event;
}
player->computePlayer();
file.close();
remove(SAVE_FILE.c_str());
}
else
{
return false;
}
return true;
}
WitchBlastGame::saveHeaderStruct WitchBlastGame::loadGameHeader()
{
saveHeaderStruct saveHeader;
saveHeader.ok = true;
std::ifstream file(SAVE_FILE.c_str(), std::ios::in);
if (file)
{
// version
std::string v;
file >> v;
if (v != SAVE_VERSION)
{
file.close();
remove(SAVE_FILE.c_str());
saveHeader.ok = false;
}
else
{
// date an time
file >> saveHeader.date;
file >> saveHeader.time;
// floor
file >> saveHeader.level;
int challengeLevel;
file >> challengeLevel;
file >> saveHeader.gameTime;
for (int i = 0; i < NUMBER_EQUIP_ITEMS; i++)
file >> equipToDisplay[i];
file >> saveHeader.shotType;
}
}
else
{
saveHeader.ok = false;
}
return saveHeader;
}
void WitchBlastGame::saveGameData()
{
// TODO
std::ofstream file(SAVE_DATA_FILE.c_str(), std::ios::out | std::ios::trunc);
if (file)
{
// version (for compatibility check)
file << SAVE_VERSION << std::endl;
int i;
// tuto
for (i = 0; i < NB_MESSAGES; i++)
{
messageStruct msg = getMessage((EnumMessages)i);
if (msg.messageType == MessageTypeTutorial)
{
file << gameMessagesToSkip[i] << " ";
}
else file << "0 ";
}
file << std::endl;
// achievements
for (i = 0; i < NB_ACHIEVEMENTS; i++)
{
if (achievementState[i] == AchievementDone) file << "1 ";
else file << "0 ";
}
file << std::endl;
// monsters
for (i = 0; i < NB_ENEMY; i++)
{
file << globalData.killedMonster[i] << " ";
}
file << std::endl;
file.close();
}
else
{
std::cout << "[ERROR] Impossible to open save data file.\n";
}
}
void WitchBlastGame::loadGameData()
{
std::ifstream file(SAVE_DATA_FILE.c_str(), std::ios::in);
int i;
if (file)
{
// version
std::string v;
file >> v;
if (v != SAVE_VERSION)
{
file.close();
remove(SAVE_DATA_FILE.c_str());
return;
}
// tuto
for (i = 0; i < NB_MESSAGES; i++)
{
file >> gameMessagesToSkip[i];
}
}
// Achievements
for (i = 0; i < NB_ACHIEVEMENTS; i++)
{
int n;
file >> n;
if (n == 1) achievementState[i] = AchievementDone;
else achievementState[i] = AchievementUndone;
}
// Monsters
for (i = 0; i < NB_ENEMY; i++)
file >> globalData.killedMonster[i];
}
void WitchBlastGame::addKey(int logicInput, std::string key)
{
int iKey = config.findInt(key);
if (iKey >= 0)
{
sf::Keyboard::Key k = (sf::Keyboard::Key)iKey;
input[logicInput] = k;
}
}
void WitchBlastGame::saveConfigurationToFile()
{
std::map<std::string, std::string> newMap;
// parameters
newMap["language"] = intToString(parameters.language);
newMap["player_name"] = parameters.playerName;
// audio volume
newMap["volume_sound"] = intToString(parameters.soundVolume);
newMap["volume_music"] = intToString(parameters.musicVolume);
newMap["zoom_enabled"] = parameters.zoom ? "1" : "0";
newMap["vsync_enabled"] = parameters.vsync ? "1" : "0";
newMap["blood_spreading"] = parameters.bloodSpread ? "1" : "0";
newMap["fullscreen"] = parameters.fullscreen ? "1" : "0";
newMap["display_boss_portrait"] = parameters.displayBossPortrait ? "1" : "0";
// Keys
newMap["keyboard_move_up"] = intToString(input[KeyUp]);
newMap["keyboard_move_down"] = intToString(input[KeyDown]);
newMap["keyboard_move_left"] = intToString(input[KeyLeft]);
newMap["keyboard_move_right"] = intToString(input[KeyRight]);
newMap["keyboard_fire_up"] = intToString(input[KeyFireUp]);
newMap["keyboard_fire_down"] = intToString(input[KeyFireDown]);
newMap["keyboard_fire_left"] = intToString(input[KeyFireLeft]);
newMap["keyboard_fire_right"] = intToString(input[KeyFireRight]);
newMap["keyboard_spell"] = intToString(input[KeySpell]);
newMap["keyboard_interact"] = intToString(input[KeyInteract]);
newMap["keyboard_fire"] = intToString(input[KeyFire]);
newMap["keyboard_time_control"] = intToString(input[KeyTimeControl]);
newMap["keyboard_fire_select"] = intToString(input[KeyFireSelect]);
// Joystick
for (unsigned int i = 0; i < NumberKeys; i++)
{
std::stringstream oss_button;
oss_button << "joy_" << inputKeyStr[i] << "_button";
std::stringstream oss_value;
oss_value << "joy_" << inputKeyStr[i] << "_value";
std::stringstream oss_axis;
oss_axis << "joy_" << inputKeyStr[i] << "_axis";
newMap[oss_button.str()] = joystickInput[i].isButton ? "1" : "0";
newMap[oss_value.str()] = intToString(joystickInput[i].value);
newMap[oss_axis.str()] = intToString(joystickInput[i].axis);
}
config.saveToFile(CONFIG_FILE, newMap);
}
void WitchBlastGame::configureFromFile()
{
// default
parameters.language = 0; // english
parameters.zoom = true;
parameters.vsync = true;
parameters.bloodSpread = true;
parameters.fullscreen = false;
parameters.musicVolume = 60;
parameters.soundVolume = 100;
parameters.playerName = "";
parameters.displayBossPortrait = false;
input[KeyUp] = sf::Keyboard::W;
input[KeyDown] = sf::Keyboard::S;
input[KeyLeft] = sf::Keyboard::A;
input[KeyRight] = sf::Keyboard::D;
input[KeyFireUp] = sf::Keyboard::Up;
input[KeyFireDown] = sf::Keyboard::Down;
input[KeyFireLeft] = sf::Keyboard::Left;
input[KeyFireRight] = sf::Keyboard::Right;
input[KeyFire] = sf::Keyboard::RControl;
input[KeySpell] = sf::Keyboard::Space;
input[KeyInteract] = sf::Keyboard::E;
input[KeyFireSelect] = sf::Keyboard::Tab;
input[KeyTimeControl] = sf::Keyboard::RShift;
// Joystick
joystickInput[KeyUp].isButton = false;
joystickInput[KeyUp].axis = sf::Joystick::Y;
joystickInput[KeyUp].value = -1;
joystickInput[KeyDown].isButton = false;
joystickInput[KeyDown].axis = sf::Joystick::Y;
joystickInput[KeyDown].value = 1;
joystickInput[KeyLeft].isButton = false;
joystickInput[KeyLeft].axis = sf::Joystick::X;
joystickInput[KeyLeft].value = -1;
joystickInput[KeyRight].isButton = false;
joystickInput[KeyRight].axis = sf::Joystick::X;
joystickInput[KeyRight].value = 1;
for (unsigned int i = KeyFireUp; i < NumberKeys; i++)
{
joystickInput[i].isButton = true;
joystickInput[i].axis = sf::Joystick::X;
joystickInput[i].value = i - 4;
}
// from file
addKey(KeyUp, "keyboard_move_up");
addKey(KeyDown, "keyboard_move_down");
addKey(KeyLeft, "keyboard_move_left");
addKey(KeyRight, "keyboard_move_right");
addKey(KeyFireUp, "keyboard_fire_up");
addKey(KeyFireDown, "keyboard_fire_down");
addKey(KeyFireLeft, "keyboard_fire_left");
addKey(KeyFireRight, "keyboard_fire_right");
addKey(KeyFire, "keyboard_fire");
addKey(KeySpell, "keyboard_spell");
addKey(KeyInteract, "keyboard_interact");
addKey(KeyTimeControl, "keyboard_time_control");
addKey(KeyFireSelect, "keyboard_fire_select");
// Joystick
for (unsigned int i = 0; i < NumberKeys; i++)
{
std::stringstream oss_button;
oss_button << "joy_" << inputKeyStr[i] << "_button";
std::stringstream oss_value;
oss_value << "joy_" << inputKeyStr[i] << "_value";
std::stringstream oss_axis;
oss_axis << "joy_" << inputKeyStr[i] << "_axis";
int isButton = config.findInt(oss_button.str());
if (isButton > -1000)
joystickInput[i].isButton = isButton;
int n = config.findInt(oss_value.str());
if (n > -1000)
joystickInput[i].value = n;
n = config.findInt(oss_axis.str());
if (n >= sf::Joystick::Axis::X && n <= sf::Joystick::Axis::PovY)
joystickInput[i].axis = (sf::Joystick::Axis)n;
}
int i = config.findInt("language");
if (i >= 0 && i < NB_LANGUAGES) parameters.language = i;
i = config.findInt("volume_sound");
if (i >= 0) parameters.soundVolume = i;
i = config.findInt("volume_music");
if (i >= 0) parameters.musicVolume = i;
i = config.findInt("vsync_enabled");
if (i >= 0) parameters.vsync = i;
i = config.findInt("zoom_enabled");
if (i >= 0) parameters.zoom = i;
i = config.findInt("blood_spreading");
if (i >= 0) parameters.bloodSpread = i;
i = config.findInt("fullscreen");
if (i >= 0) parameters.fullscreen = i;
i = config.findInt("display_boss_portrait");
if (i >= 0) parameters.displayBossPortrait = i;
std::string playerName = config.findString("player_name");
if (playerName.size() > 0) parameters.playerName = playerName;
tools::setLanguage(languageString[parameters.language]);
}
parameterStruct WitchBlastGame::getParameters()
{
return parameters;
}
void WitchBlastGame::buildMenu(bool rebuild)
{
menuMain.items.clear();
menuConfig.items.clear();
menuFirst.items.clear();
if (!rebuild)
{
menuState = MenuStateMain;
menuMain.age = 0.0f;
menuConfig.age = 0.0f;
menuConfig.index = 0;
}
saveHeader = loadGameHeader();
menuItemStuct itemName;
itemName.label = tools::getLabel("player_name");
itemName.description = tools::getLabel("player_name_desc");
itemName.id = MenuPlayerName;
menuMain.items.push_back(itemName);
if (saveHeader.ok)
{
menuItemStuct itemStart;
itemStart.label = tools::getLabel("start_new_game");
itemStart.description = tools::getLabel("start_desc");
itemStart.id = MenuStartNew;
menuMain.items.push_back(itemStart);
menuItemStuct itemLoad;
itemStart.label = tools::getLabel("restore");
std::ostringstream oss;
oss << saveHeader.date << " " << tools::getLabel("at") << " " << saveHeader.time << " - " << tools::getLabel("level") << " " << saveHeader.level;
itemStart.description = oss.str();
itemStart.id = MenuStartOld;
menuMain.items.push_back(itemStart);
if (!rebuild) menuMain.index = 2;
}
else
{
menuItemStuct itemStart;
itemStart.label = tools::getLabel("start_new_game");
itemStart.description = tools::getLabel("begin_journey");
itemStart.id = MenuStartNew;
menuMain.items.push_back(itemStart);
if (!rebuild) menuMain.index = 1;
}
if (parameters.playerName.compare("") == 0 && menuState == MenuStateMain)
{
menuMain.index = 0;
menuState = MenuStateChangeName;
}
menuItemStuct itemConfig;
itemConfig.label = tools::getLabel("configure_game");
itemConfig.description = tools::getLabel("configure_game_desc");
itemConfig.id = MenuConfig;
menuMain.items.push_back(itemConfig);
if (!isFunctionalityLocked(FunctionalityAchievementsScreen))
{
menuItemStuct itemAchiev;
std::ostringstream oss;
oss << tools::getLabel("menu_achievements");
oss << " (" << getAchievementsPercents() << "%)";
itemAchiev.label = oss.str();
itemAchiev.description = tools::getLabel("menu_achievements_desc");
itemAchiev.id = MenuAchievements;
menuMain.items.push_back(itemAchiev);
}
//if (scores.size() > 0)
{
menuItemStuct itemHiScores;
itemHiScores.label = tools::getLabel("hi_scores");
itemHiScores.description = tools::getLabel("hi_scores_desc");
itemHiScores.id = MenuHiScores;
menuMain.items.push_back(itemHiScores);
}
menuItemStuct itemCredits;
itemCredits.label = tools::getLabel("credits");
itemCredits.description = tools::getLabel("credits_desc");
itemCredits.id = MenuCredits;
menuMain.items.push_back(itemCredits);
menuItemStuct itemExit;
itemExit.label = tools::getLabel("exit_game");
itemExit.description = tools::getLabel("return_to_desktop");
itemExit.id = MenuExit;
menuMain.items.push_back(itemExit);
// configuration
menuItemStuct itemKeys;
itemKeys.label = tools::getLabel("config_keys");
itemKeys.description = tools::getLabel("redef_input");
itemKeys.id = MenuKeys;
menuConfig.items.push_back(itemKeys);
menuItemStuct itemJoystick;
itemJoystick.label = tools::getLabel("config_joystick");
if (sf::Joystick::isConnected(0))
itemJoystick.description = tools::getLabel("redef_joystick");
else
itemJoystick.description = tools::getLabel("joystick_not_found");
itemJoystick.id = MenuJoystick;
menuConfig.items.push_back(itemJoystick);
menuItemStuct itemLanguage;
itemLanguage.label = tools::getLabel("config_lang");
itemLanguage.description = tools::getLabel("config_lang_desc");
itemLanguage.id = MenuLanguage;
menuConfig.items.push_back(itemLanguage);
menuItemStuct itemVolumeSound;
itemVolumeSound.label = tools::getLabel("volume_sound");
itemVolumeSound.description = tools::getLabel("volume_sound_desc");
itemVolumeSound.id = MenuVolumeSound;
menuConfig.items.push_back(itemVolumeSound);
menuItemStuct itemVolumeMusic;
itemVolumeMusic.label = tools::getLabel("volume_music");
itemVolumeMusic.description = tools::getLabel("volume_sound_desc");
itemVolumeMusic.id = MenuVolumeMusic;
menuConfig.items.push_back(itemVolumeMusic);
menuItemStuct itemTutoReset;
itemTutoReset.label = tools::getLabel("tuto_reset");
itemTutoReset.description = tools::getLabel("tuto_reset_desc");
itemTutoReset.id = MenuTutoReset;
menuConfig.items.push_back(itemTutoReset);
menuItemStuct itemConfigBack;
itemConfigBack.label = tools::getLabel("config_back");
itemConfigBack.description = tools::getLabel("config_back_desc");
itemConfigBack.id = MenuConfigBack;
menuConfig.items.push_back(itemConfigBack);
//first time screen
menuFirst.items.push_back(itemLanguage);
}
void WitchBlastGame::buildInGameMenu()
{
menuInGame.items.clear();
menuItemStuct itemContinue;
itemContinue.label = tools::getLabel("menu_continue");
itemContinue.description = tools::getLabel("menu_continue_desc");
itemContinue.id = MenuContinue;
menuInGame.items.push_back(itemContinue);
menuItemStuct itemSaveQuit;
itemSaveQuit.label = tools::getLabel("menu_save_quit");
itemSaveQuit.description = tools::getLabel("menu_save_quit_desc");
itemSaveQuit.id = MenuSaveAndQuit;
menuInGame.items.push_back(itemSaveQuit);
menuItemStuct itemQuit;
itemQuit.label = tools::getLabel("menu_quit");
itemQuit.description = tools::getLabel("menu_quit_desc");
itemQuit.id = MenuExit;
menuInGame.items.push_back(itemQuit);
menuInGame.index = 0;
}
void WitchBlastGame::resetKilledEnemies()
{
for (int i = 0; i < NB_ENEMY; i++) killedEnemies[i] = 0;
}
void WitchBlastGame::addKilledEnemy(enemyTypeEnum enemyType, enumShotType hurtingType)
{
if(!player->isDead())
{
if (enemyType == NB_ENEMY)
std::cout << "[ERROR] No enemy type";
else
{
killedEnemies[enemyType]++;
globalData.killedMonster[enemyType]++;
player->offerMonster(enemyType, hurtingType);
// achievements
if (enemyType == EnemyTypeButcher) registerAchievement(AchievementButcher);
else if (enemyType == EnemyTypeSlimeBoss) registerAchievement(AchievementGiantSlime);
else if (enemyType == EnemyTypeCyclops) registerAchievement(AchievementCyclops);
else if (enemyType == EnemyTypeRatKing) registerAchievement(AchievementRatKing);
else if (enemyType == EnemyTypeSpiderGiant) registerAchievement(AchievementGiantSpider);
else if (enemyType == EnemyTypeFranckyHead) registerAchievement(AchievementFrancky);
else if (enemyType == EnemyTypeVampire) registerAchievement(AchievementVampire);
else if ((enemyType == EnemyTypeRat || enemyType == EnemyTypeRatHelmet || enemyType == EnemyTypeRat_invocated
|| enemyType == EnemyTypeRatBlack || enemyType == EnemyTypeRatBlackHelmet))
{
if (globalData.killedMonster[EnemyTypeRat] + globalData.killedMonster[EnemyTypeRatHelmet] + globalData.killedMonster[EnemyTypeRat_invocated]
+ globalData.killedMonster[EnemyTypeRatBlack] + globalData.killedMonster[EnemyTypeRatBlackHelmet] >= 250)
registerAchievement(AchievementRats);
}
else if (enemyType == EnemyTypeWitch || enemyType == EnemyTypeWitchRed)
{
if (globalData.killedMonster[EnemyTypeWitch] + globalData.killedMonster[EnemyTypeWitchRed] >= 50)
registerAchievement(AchievementWitches);
}
else if (enemyType == EnemyTypeSpiderEgg || enemyType == EnemyTypeSpiderEgg_invocated)
{
if (globalData.killedMonster[EnemyTypeSpiderEgg] + globalData.killedMonster[EnemyTypeSpiderEgg_invocated] >= 100)
registerAchievement(AchievementEggs);
}
}
}
}
void WitchBlastGame::registerLanguage()
{
// default keys
if (parameters.language == 1)
{
// french keyboard
input[KeyUp] = sf::Keyboard::Z;
input[KeyLeft] = sf::Keyboard::Q;
}
else
{
// QWERT / QWERTZ keyboard
input[KeyUp] = sf::Keyboard::W;
input[KeyLeft] = sf::Keyboard::A;
}
input[KeyDown] = sf::Keyboard::S;
input[KeyRight] = sf::Keyboard::D;
input[KeyFireUp] = sf::Keyboard::Up;
input[KeyFireDown] = sf::Keyboard::Down;
input[KeyFireLeft] = sf::Keyboard::Left;
input[KeyFireRight] = sf::Keyboard::Right;
input[KeyFire] = sf::Keyboard::RControl;
input[KeyFireSelect] = sf::Keyboard::Tab;
input[KeyTimeControl] = sf::Keyboard::RShift;
input[KeySpell] = sf::Keyboard::Space;
saveConfigurationToFile();
}
int WitchBlastGame::getAchievementsPercents()
{
int n = 0;
for (int i = 0; i < NB_ACHIEVEMENTS; i++)
if (achievementState[i] == AchievementDone) n++;
return (n * 100) / NB_ACHIEVEMENTS;
}
void WitchBlastGame::testAndAddMessageToQueue(EnumMessages type)
{
if (gameMessagesToSkip[type] == false)
{
if (messagesQueue.empty()) SoundManager::getInstance().playSound(SOUND_MESSAGE);
messageStruct msg = getMessage(type);
if (type == MsgInfoDivGift || type == MsgInfoDivIntervention)
{
std::stringstream ss;
ss << tools::getLabel(divinityLabel[player->getDivinity().divinity] + "_0");
ss << " ";
if (type == MsgInfoDivGift)
ss << tools::getLabel("divinity_gift_1");
else // (type == MsgInfoDivIntervention)
ss << tools::getLabel("divinity_intervention_1");
msg.message[1] = ss.str();
msg.icon = 2 + player->getDivinity().divinity;
}
messagesQueue.push(msg);
if (msg.messageType == MessageTypeTutorial)
{
gameMessagesToSkip[type] = true;
saveGameData();
}
}
}
void WitchBlastGame::addDivLevelMessageToQueue(std::string label)
{
if (label.compare("") == 0) return;
if (messagesQueue.empty()) SoundManager::getInstance().playSound(SOUND_MESSAGE);
messageStruct msg = getMessage(MsgInfoDivLevel);
std::stringstream ss;
ss << tools::getLabel(divinityLabel[player->getDivinity().divinity] + "_0");
ss << " ";
ss << tools::getLabel(label);
msg.message[1] = ss.str();
msg.icon = 2 + player->getDivinity().divinity;
messagesQueue.push(msg);
}
void WitchBlastGame::initEvents()
{
for (int i = 0; i < NB_EVENTS; i++)
worldEvent[i] = false;
}
void WitchBlastGame::proceedEvent(EnumWorldEvents event)
{
// achievements
if (event == EventGetCoin)
{
if (achievementState[Achievement100] == AchievementUndone && player->getGold() > 100)
registerAchievement(Achievement100);
}
else if (event == EventPietyMax)
{
if (achievementState[AchievementPietyMax] == AchievementUndone) registerAchievement(AchievementPietyMax);
}
else if (event == Event4Hits)
{
if (achievementState[Achievement4Hits] == AchievementUndone) registerAchievement(Achievement4Hits);
}
// message ?
if (worldEvent[event]) return;
worldEvent[event] = true;
testAndAddMessageToQueue(eventToMessage[event]);
}
void WitchBlastGame::renderPlayer(float x, float y,
bool equip[NUMBER_EQUIP_ITEMS], int shotType,
int frame, int spriteDy)
{
bool isMirroring = false;
sf::Sprite sprite;
if (equip[EQUIP_FAIRY_FIRE])
{
sprite.setPosition(x - 35, y - 25);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_FAIRY));
sprite.setTextureRect(sf::IntRect( 0, 144, 48, 60));
app->draw(sprite);
}
if (equip[EQUIP_FAIRY_ICE])
{
sprite.setPosition(x - 5, y - 25);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_FAIRY));
sprite.setTextureRect(sf::IntRect( 0, 216, 48, 60));
app->draw(sprite);
}
if (equip[EQUIP_FAIRY])
{
sprite.setPosition(x - 40, y);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_FAIRY));
sprite.setTextureRect(sf::IntRect( 0, 0, 48, 60));
app->draw(sprite);
}
if (equip[EQUIP_FAIRY_TARGET])
{
sprite.setPosition(x - 10, y);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_FAIRY));
sprite.setTextureRect(sf::IntRect( 0, 72, 48, 60));
app->draw(sprite);
}
if (equip[EQUIP_FAIRY_POISON])
{
sprite.setPosition(x + 20, y);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_FAIRY));
sprite.setTextureRect(sf::IntRect( 0, 288, 48, 60));
app->draw(sprite);
}
// slime
if (equip[EQUIP_PET_SLIME])
{
sprite.setPosition(x - 20, y + 24);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_SLIME));
sprite.setTextureRect(sf::IntRect( 64, 256, 64, 64));
app->draw(sprite);
}
sprite.setPosition(x, y);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
int width = 64;
int height = 96;
// body
if (isMirroring)
sprite.setTextureRect(sf::IntRect( frame * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( frame * width, spriteDy * height, width, height));
app->draw(sprite);
// boots
if (equip[EQUIP_BOOTS_ADVANCED])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (21 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (21 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
else if (equip[EQUIP_LEATHER_BOOTS])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (9 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (9 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_ROBE_ADVANCED])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (12 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (12 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
else if (equip[EQUIP_MAGICIAN_ROBE])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (12 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (12 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_GLOVES_ADVANCED])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (24 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (24 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
else if (equip[EQUIP_DISPLACEMENT_GLOVES])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (21 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (21 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_CRITICAL_ADVANCED])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (24 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (24 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
else if (equip[EQUIP_CRITICAL])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (18 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (18 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
if (equip[EQUIP_RAGE_AMULET])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (18 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (18 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_LEATHER_BELT])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (15 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (15 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
// hat
if (equip[EQUIP_HAT_ADVANCED])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (9 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (9 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
else if (equip[EQUIP_MAGICIAN_HAT])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (6 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (6 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
// staff
int frameDx = equip[EQUIP_MAHOGANY_STAFF] ? 6 : 3;
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (frameDx + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (frameDx + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
if (equip[EQUIP_BLOOD_SNAKE])
{
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (27 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (27 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
}
if (equip[EQUIP_REAR_SHOT])
{
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
// shot type
if (shotType != ShotTypeStandard)
{
switch (shotType)
{
case ShotTypeIce:
sprite.setColor(sf::Color(100, 220, 255, 255));
break;
case ShotTypeStone:
sprite.setColor(sf::Color(120, 120, 150, 255));
break;
case ShotTypeLightning:
sprite.setColor(sf::Color(255, 255, 0, 255));
break;
case ShotTypeIllusion:
sprite.setColor(sf::Color(240, 180, 250, 255));
break;
case ShotTypeStandard:
sprite.setColor(sf::Color(255, 255, 255, 0));
break;
case ShotTypeFire:
sprite.setColor(sf::Color(255, 180, 0, 255));
break;
default:
break;
}
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_1));
if (isMirroring)
sprite.setTextureRect(sf::IntRect( (3 + frame) * width + width, spriteDy * height, -width, height));
else
sprite.setTextureRect(sf::IntRect( (3 + frame) * width, spriteDy * height, width, height));
app->draw(sprite);
sprite.setTexture(*ImageManager::getInstance().getImage(IMAGE_PLAYER_0));
}
}
std::string WitchBlastGame::enemyToString(enemyTypeEnum enemyType)
{
std::string value = "unknown";
switch (enemyType)
{
case EnemyTypeBat_invocated:
case EnemyTypeBat:
value = "enemy_type_bat";
break;
case EnemyTypeBatSkeleton_invocated:
case EnemyTypeBatSkeleton:
value = "enemy_type_bat_skeleton";
break;
case EnemyTypeRat_invocated:
case EnemyTypeRat:
value = "enemy_type_rat";
break;
case EnemyTypeRatBlack:
value = "enemy_type_rat_black";
break;
case EnemyTypeRatHelmet_invocated:
case EnemyTypeRatHelmet:
value = "enemy_type_rat_helmet";
break;
case EnemyTypeRatBlackHelmet:
value = "enemy_type_rat_black_helmet";
break;
case EnemyTypeEvilFlower:
value = "enemy_type_evil_flower";
break;
case EnemyTypeEvilFlowerIce:
value = "enemy_type_evil_flower_ice";
break;
case EnemyTypeEvilFlowerFire:
value = "enemy_type_evil_flower_fire";
break;
case EnemyTypeSnake_invocated:
case EnemyTypeSnake:
value = "enemy_type_snake";
break;
case EnemyTypeSnakeBlood_invocated:
case EnemyTypeSnakeBlood:
value = "enemy_type_snake_blood";
break;
case EnemyTypeSlime_invocated:
case EnemyTypeSlime:
value = "enemy_type_slime";
break;
case EnemyTypeSlimeRed_invocated:
case EnemyTypeSlimeRed:
value = "enemy_type_slime_red";
break;
case EnemyTypeSlimeBlue_invocated:
case EnemyTypeSlimeBlue:
value = "enemy_type_slime_blue";
break;
case EnemyTypeSlimeViolet_invocated:
case EnemyTypeSlimeViolet:
value = "enemy_type_slime_violet";
break;
case EnemyTypeImpBlue:
value = "enemy_type_imp_blue";
break;
case EnemyTypeImpRed:
value = "enemy_type_imp_red";
break;
case EnemyTypePumpkin_invocated:
case EnemyTypePumpkin:
value = "enemy_type_pumpkin";
break;
case EnemyTypeWitch:
value = "enemy_type_witch";
break;
case EnemyTypeWitchRed:
value = "enemy_type_witch_red";
break;
case EnemyTypeCauldron:
value = "enemy_type_cauldron";
break;
case EnemyTypeCauldronElemental:
value = "enemy_type_cauldron_elemental";
break;
case EnemyTypeGhost:
value = "enemy_type_ghost";
break;
case EnemyTypeZombie_invocated:
case EnemyTypeZombie:
value = "enemy_type_zombie";
break;
case EnemyTypeZombieDark:
value = "enemy_type_zombie_dark";
break;
case EnemyTypeBogeyman:
value = "enemy_type_bogeyman";
break;
// mini boss
case EnemyTypeBubble:
value = "enemy_type_bubble";
break;
case EnemyTypeBubbleIce:
value = "enemy_type_bubble_ice";
break;
case EnemyTypeBubbleGreater:
value = "enemy_type_bubble_greater";
break;
case EnemyTypeSlimeLarge:
value = "enemy_type_slime_large";
break;
case EnemyTypeSlimeBlueLarge:
value = "enemy_type_slime_blue_large";
break;
case EnemyTypeSlimeRedLarge:
value = "enemy_type_slime_red_large";
break;
case EnemyTypeSlimeVioletLarge:
value = "enemy_type_slime_violet_large";
break;
// boss
case EnemyTypeButcher:
value = "enemy_type_boss_butcher";
break;
case EnemyTypeSlimeBoss:
value = "enemy_type_boss_slime_giant";
break;
case EnemyTypeCyclops:
value = "enemy_type_boss_cyclops";
break;
case EnemyTypeRatKing:
value = "enemy_type_boss_rat_king";
break;
case EnemyTypeSpiderGiant:
value = "enemy_type_boss_spider_giant";
break;
case EnemyTypeFranckyHand:
case EnemyTypeFranckyHead:
case EnemyTypeFranckyFoot:
case EnemyTypeFrancky:
value = "enemy_type_francky";
break;
case EnemyTypeVampire:
case EnemyTypeVampireDead:
value = "enemy_type_vampire";
break;
// invocated
case EnemyTypeRatGreen:
value = "enemy_type_green_rat";
break;
case EnemyTypeRockFalling:
value = "enemy_type_rock_falling";
break;
case EnemyTypeRockMissile:
value = "enemy_type_rock_missile";
break;
case EnemyTypeSpiderEgg:
case EnemyTypeSpiderEgg_invocated:
value = "enemy_type_spider_egg";
break;
case EnemyTypeSpiderLittle:
case EnemyTypeSpiderLittle_invocated:
value = "enemy_type_spider_little";
break;
case EnemyTypeSpiderWeb:
value = "enemy_type_spider_web";
break;
case EnemyTypeNone:
value = "enemy_type_himself";
break;
case EnemyTypeDestroyable:
value = "";
break;
case NB_ENEMY:
break;
}
return value;
}
std::string WitchBlastGame::sourceToString(sourceTypeEnum sourceType, enemyTypeEnum enemyType)
{
std::string value = "unknown";
switch (sourceType)
{
case SourceTypeBolt:
case SourceTypeMelee:
value = tools::getLabel(enemyToString(enemyType));
break;
case SourceTypeExplosion:
value = tools::getLabel("source_explosion");
break;
case SourceTypePoison:
value = tools::getLabel("source_poison");
}
return value;
}
std::string WitchBlastGame::equipToString(bool equip[NUMBER_EQUIP_ITEMS])
{
std::stringstream oss;
for (int i = 0; i < NUMBER_EQUIP_ITEMS; i++)
oss << (equip[i] ? 1 : 0);
return oss.str();
}
void WitchBlastGame::saveHiScores()
{
std::ofstream file(HISCORES_FILE.c_str(), std::ios::out | std::ios::trunc);
if (file)
{
// version (for compatibility check)
file << SAVE_VERSION << std::endl;
file << scores.size() << std::endl;
// tuto
for (unsigned int i = 0; i < scores.size() && i < SCORES_MAX; i++)
{
file << scores[i].name << " ";
file << scores[i].level << " ";
file << scores[i].score << " ";
file << scores[i].shotType << " ";
// 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.counter = 0;
ach.hasStarted = false;
achievementsQueue.push(ach);
}
}
bool WitchBlastGame::isItemLocked(enumItemType item)
{
for (int i = 0; i < NB_ACHIEVEMENTS; i++)
{
if (achievementState[i] == AchievementUndone)
{
if (achievements[i].unlockType == UnlockItem)
if (achievements[i].unlock == (int)item) return true;
}
}
return false;
}
bool WitchBlastGame::isFunctionalityLocked(enumFunctionalityType func)
{
for (int i = 0; i < NB_ACHIEVEMENTS; i++)
{
if (achievementState[i] == AchievementUndone)
{
if (achievements[i].unlockType == UnlockFunctionality)
if (achievements[i].unlock == (int)func) return true;
}
}
return false;
}
void WitchBlastGame::renderDoors()
{
for (int i = 0; i < 4; i++) doorEntity[i]->renderDoors(app);
}
void WitchBlastGame::resetPresentItems()
{
for (int i = 0; i < NUMBER_EQUIP_ITEMS; i++) presentItems[i] = false;
}
bool WitchBlastGame::isPresentItem(int n)
{
if (n >= 0 && n < NUMBER_EQUIP_ITEMS) return presentItems[n];
else return false;
}
void WitchBlastGame::addPresentItem(int n)
{
if (n >= 0 && n < NUMBER_EQUIP_ITEMS) presentItems[n] = true;
}
bool WitchBlastGame::isPressing(inputKeyEnum k, bool oneShot)
{
return (actionKey[k].isPressed && (!oneShot || actionKey[k].isTriggered));
}
bool WitchBlastGame::getPressingState(inputKeyEnum k)
{
// arrows in menu
if (gameState != gameStatePlaying || player->isDead())
{
if (k == KeyLeft && sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) return true;
if (k == KeyRight && sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) return true;
if (k == KeyUp && sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) return true;
if (k == KeyDown && sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) return true;
if (k == KeyFireDown && sf::Keyboard::isKeyPressed(sf::Keyboard::Return)) return true;
}
// keyboard
if (sf::Keyboard::isKeyPressed(input[k])) return true;
if (!sf::Joystick::isConnected(0)) return false;
// joystick
if (joystickInput[k].isButton)
{
// button
if (joystickInput[k].value >= 0)
if (sf::Joystick::isButtonPressed(0, joystickInput[k].value)) return true;
}
else
{
// axis
if (joystickInput[k].value < 0 && sf::Joystick::getAxisPosition(0, joystickInput[k].axis) < -40) return true;
else if (joystickInput[k].value > 0 && sf::Joystick::getAxisPosition(0, joystickInput[k].axis) > 40) return true;
}
return false;
}
void WitchBlastGame::updateActionKeys()
{
for (unsigned int i = 0; i < NumberKeys; i++)
{
bool oldState = actionKey[i].isPressed;
actionKey[i].isPressed = getPressingState((inputKeyEnum)i);
actionKey[i].isTriggered = actionKey[i].isPressed && !oldState;
}
}
void WitchBlastGame::sendScoreToServer()
{
if (sendScoreThread.joinable()) sendScoreThread.join();
sendScoreThread = std::thread(&WitchBlastGame::sendScoreToServerThread, this);
receiveScoreFromServer();
}
void WitchBlastGame::sendScoreToServerThread()
{
#ifdef ONLINE_MODE
sendScore(lastScore.score,
lastScore.level,
lastScore.name,
equipToString(lastScore.equip),
lastScore.shotType,
SCORE_VERSION);
#endif
}
void WitchBlastGame::receiveScoreFromServer()
{
#ifdef ONLINE_MODE
scoreState = ScoreLoading;
if (receiveScoreThread.joinable()) receiveScoreThread.join();
receiveScoreThread = std::thread(&WitchBlastGame::receiveScoreFromServerThread, this);
#endif
}
void WitchBlastGame::receiveScoreFromServerThread()
{
if (sendScoreThread.joinable()) sendScoreThread.join();
loadHiScoresOnline(false);
scoreState = ScoreLoadingDay;
loadHiScoresOnline(true);
scoreState = ScoreOK;
}
void WitchBlastGame::loadHiScoresOnline(bool fromDayOnly)
{
#ifdef ONLINE_MODE
std::vector <StructScore> scoresTemp;
std::vector<std::string> receivedScores = receiveScores(fromDayOnly);
int nbParameters = 5;
if (receivedScores.size() > 0
&& receivedScores.size() % nbParameters == 0
&& receivedScores.size() / nbParameters <= 10)
{
int nbScores = receivedScores.size() / nbParameters;
for (int i = 0; i < nbScores; i++)
{
StructScore score;
std::istringstream scoreStr(receivedScores[i * nbParameters]);
scoreStr >> score.score;
score.name = receivedScores[i * nbParameters + 1];
std::istringstream levelStr(receivedScores[i * nbParameters + 2]);
levelStr >> score.level;
for (int j = 0; j < NUMBER_EQUIP_ITEMS; j++)
{
score.equip[j] = (receivedScores[i * nbParameters + 3])[j] == '1';
}
std::istringstream shotStr(receivedScores[i * nbParameters + 4]);
shotStr >> score.shotType;
scoresTemp.push_back(score);
}
if (fromDayOnly)
{
scoresOnlineDay.clear();
scoresOnlineDay = scoresTemp;
}
else
{
scoresOnline.clear();
scoresOnline = scoresTemp;
}
}
#endif
}
void WitchBlastGame::checkDestroyableObjects()
{
for (int i = 0; i < MAP_WIDTH; i++)
for (int j = 0; j < MAP_HEIGHT; j++)
{
if (currentMap->getObjectTile(i, j) >= MAPOBJ_BARREL && currentMap->getObjectTile(i, j) < MAPOBJ_BARREL_EXPL + 3)
{
new ObstacleEntity(i * TILE_WIDTH + TILE_WIDTH / 2, j * TILE_HEIGHT + TILE_HEIGHT / 2, currentMap->getObjectTile(i, j));
}
}
}
void WitchBlastGame::randomizePotionMap()
{
potionMap.clear();
// TODO
potionMap[ItemPotion01] = structPotionMap { ItemPotionHealth, false};
potionMap[ItemPotion02] = structPotionMap { ItemPotionPoison, false};
}
void WitchBlastGame::addPotionToMap(enumItemType source, enumItemType effect, bool known)
{
potionMap[source] = structPotionMap { effect, known};
}
enumItemType WitchBlastGame::getPotion(enumItemType source)
{
return potionMap[source].effect;
}
bool WitchBlastGame::potionEffectKnown(enumItemType source)
{
return potionMap[source].known;
}
void WitchBlastGame::setPotionToKnown(enumItemType source)
{
potionMap[source].known = true;
// message
if (messagesQueue.empty()) SoundManager::getInstance().playSound(SOUND_MESSAGE);
messageStruct msg = getMessage(MsgInfoPotionId);
std::stringstream ss;
ss << msg.message[1];
ss << " ";
ss << tools::getLabel(items[getPotion(source)].name);
msg.message[1] = ss.str();
messagesQueue.push(msg);
}
WitchBlastGame &game()
{
return *gameptr;
}
diff --git a/src/WitchBlastGame.h b/src/WitchBlastGame.h
index 19b0ca7..6d1c62b 100644
--- a/src/WitchBlastGame.h
+++ b/src/WitchBlastGame.h
@@ -1,1072 +1,1073 @@
/** 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 WITCH_BLAST_GAME_H
#define WITCH_BLAST_GAME_H
#include "sfml_game/Game.h"
#include "sfml_game/TileMapEntity.h"
#include "PlayerEntity.h"
#include "DungeonMapEntity.h"
#include "EnemyEntity.h"
#include "DoorEntity.h"
#include "GameFloor.h"
#include "Config.h"
#include "Achievements.h"
#include <queue>
#include <thread>
// for tests
//#define TEST_MODE
const int ALIGN_LEFT = 0; /*!< Text alignment left */
const int ALIGN_RIGHT = 1; /*!< Text alignment right */
const int ALIGN_CENTER = 2; /*!< Text alignment centered */
const int X_GAME_FADE_IN = 0; /*!< Fade In effect ID */
const int X_GAME_FADE_OUT = 1; /*!< Fade out effect ID */
const int X_GAME_COLOR_RED = 0; /*!< Red light color effect ID */
const int X_GAME_COLOR_GREEN = 1; /*!< Green light color effect ID */
const int X_GAME_COLOR_BLUE = 2; /*!< Blue light color effect ID */
const int X_GAME_COLOR_VIOLET = 3; /*!< Violet light color effect ID */
const int X_GAME_COLOR_BROWN = 4; /*!< Brown light color effect ID */
const int X_GAME_COLOR_WHITE = 5; /*!< White light color effect ID */
unsigned const int NumberKeys = 13; /*!< Number of input keys on the game */
/** Input key string
* Keys in the config file.
*/
const std::string inputKeyString[NumberKeys] =
{
"key_move_up",
"key_move_down",
"key_move_left",
"key_move_right",
"key_fire_up",
"key_fire_down",
"key_fire_left",
"key_fire_right",
"key_fire_select",
"key_spell",
"key_interact",
"key_time",
"key_fire"
};
/** Credits: coder */
const std::string creditsCode[] =
{
"Seby",
"END"
};
/** Credits: 2D artists */
const std::string credits2D[] =
{
"Pierre \"dejam0rt\" Baron",
"END"
};
/** Credits: Sound */
const std::string creditsSound[] =
{
"www.freesound.org/",
"www.freesfx.co.uk/",
"www.universal-soundbank.com/",
"END"
};
/** Credits: Music */
const std::string creditsMusic[] =
{
"Michael Ghelfi",
"JappeJ",
"SteveSyz",
"CinTer",
"cazok",
"ET16",
"END"
};
/** Credits: Translation */
const std::string creditsTranslate[] =
{
"achpile (russian)",
"AFS (spanish)",
"Geheim (german)",
"END"
};
/** Struct for game parameters */
struct parameterStruct
{
int language; /*!< Language ID (english = 0) */
int musicVolume; /*!< music volume (0 to 100) */
int soundVolume; /*!< sound volume (0 to 100) */
bool zoom; /*!< zoom effect (false = disabled) */
bool vsync; /*!< monitor vsync (false = disabled) */
bool bloodSpread; /*!< blood spread (false = disabled) */
bool fullscreen; /*!< full screen (false = disabled) */
bool displayBossPortrait;
std::string playerName; /*!< player name */
};
struct structPotionMap
{
enumItemType effect;
bool known;
};
/*! \class WitchBlastGame
* \brief Main class of the game
*
* WitchBlastGame load the game ressources and do a large part of the game logic (game loop...),
* watches the input, manages the game states, ...
*/
class WitchBlastGame : public Game
{
public:
// DATA TYPES
/** Savegame header data */
struct saveHeaderStruct
{
bool ok; /**< Save game OK ? */
int level; /**< Level the save game */
float gameTime; /**< How long it has been played */
int shotType; /**< Current special shot type */
std::string date; /**< Date of the save game */
std::string time; /**< Time of the save game */
};
// PUBLIC METHODS
/*!
* \brief Constructor
*/
WitchBlastGame();
/*!
* \brief Destructor
*/
virtual ~WitchBlastGame();
/*!
* \brief Accessor on the current dungeon map
* \return a pointer to the current dungeon map
*/
DungeonMap* getCurrentMap();
GameFloor* getCurrentFloor();
int getFloorX();
int getFloorY();
/*!
* \brief Accessor on the current dungeon map entity
* \return a pointer to the current dungeon map entity
*/
DungeonMapEntity* getCurrentMapEntity();
/*!
* \brief Accessor on the player
* \return a pointer to the player
*/
PlayerEntity* getPlayer();
/*!
* \brief Accessor on the player's position
* \return a Vector2D of the player's position
*/
Vector2D getPlayerPosition();
/*!
* \brief accessor on the level
* \return : the level
*/
int getLevel();
/*!
* \brief accessor on the level
* \return : the challenge level
*/
int getChallengeLevel();
/*!
* \brief accessor on showLogical flag
* \return : the value of the flag
*/
bool getShowLogical();
float getDeltaTime();
/*!
* \brief accessor on the parameters
* \return : the parameters
*/
parameterStruct getParameters();
/*!
* \brief Start the game and the game loop
* This method starts the game and the game loop.
* The game loop watches the events, the inputs, update and draw the game elements.
*/
virtual void startGame();
/*!
* \brief Move the player to another map (room)
* Moves the player to another room of the dungeon.
* It's called when a player walk through an opened door.
* \param direction : direction of the new map. 4 = left, 8 = north, 6 = right, 2 = south
*/
void moveToOtherMap(int direction);
/*!
* \brief Closes the doors of the room
* Closes the doors of the room.
* It's called when the player enter in an area with monsters.
*/
void closeDoors();
/*!
* \brief Opens the doors of the room
* Opens the doors of the room.
* It's called when the player destroy the last monster of a room.
*/
void openDoors();
/*!
* \brief Count the enemies in the room
* Count the enemies in the room.
* It's called when the room is closed : 0 enemy = room is cleared and doors shall open.
* \return amount of enemies
*/
int getEnemyCount();
int getUndeadCount();
void animateEffects();
EnemyEntity* getBoss();
void destroyUndead(int damage);
int getItemsCount();
/*!
* \brief Return the position of the nearest enemy
* \param x : x position of the source
* \param y : y position of the source
* \return position of the nearest enemy (negative position when no enemy found)
*/
Vector2D getNearestEnemy(float x, float y);
/*!
* \brief Generates blood
* \param x : x position of the blood
* \param y : y position of the blood
* \param bloodColor : color of the blood (red; green, ...)
*/
void generateBlood(float x, float y, BaseCreatureEntity::enumBloodColor bloodColor);
/*!
* \brief Add a corpse on the map
* \param x : x position of the corpse
* \param y : y position of the corpse
* \param frame : frame of the corpse in the spritesheet
*/
void addCorpse(float x, float y, int frame);
/*!
* \brief Show a "popup" with artefact's description
* Show a "popup" with artefact's description.
* Artefact's description consists of zoomed picture of the item, name and description.
* It's called when a player get an equipment item.
* \param itemType : item identifier
*/
void showArtefactDescription(enumItemType itemType);
/*!
* \brief Make a "shake" effet
* \param duration : duration of the effect
*/
void makeShake(float duration);
/*!
* \brief Make a "color fade" effet
* \param color : the color of the effect
* \param duration : duration of the effect
*/
void makeColorEffect(int color, float duration);
/*!
* \brief Write a string on screen
* \param str : the string
* \param size : the character size
* \param x : x position
* \param y : y position
* \param align : alignment (ALIGN_LEFT, ALIGN_CENTER or ALIGN_RIGHT)
* \param color : color of the string
* \param app : the rendering target
* \param xShadow : offset of the shadow (x)
* \param yShadow : offset of the shadow (y)
*/
void write(std::string str, int size, float x, float y, int align, sf::Color color, sf::RenderTarget* app, int xShadow, int yShadow);
/*!
* \brief Save the game
* Save the game to file : complete floor and maps, items and blood position, player current equipment and stats....
*/
void saveGame();
/*!
* \brief Load the game
* Load the game from file. After restoring the game, the file is destroy.
* \return true if succeeded
*/
bool loadGame();
/*!
* \brief Save the game data (general)
*/
void saveGameData();
/*!
* \brief Load the game data (general)
*/
void loadGameData();
/*!
* \brief Load the savegame data
* \return the savegame data
*/
saveHeaderStruct loadGameHeader();
/*!
* \brief Returns a random equip object
*
* Returns a random equip object (not an object the player already possesses) .
* \param toSale : true if it's an item for sale
*
* \return the equipment item ID
*/
item_equip_enum getRandomEquipItem(bool toSale, bool noFairy);
/*!
* \brief Returns a random spell object
*/
enumItemType getItemSpell();
/*!
* \brief Generate a random challenge loot
*
* \param x : x position of the bonus
* \param y : y position of the bonus
*/
void generateChallengeBonus(float x, float y);
/*!
* \brief Adds monsters
*
* Adds monsters to the room in suitable places.
* \param monsterType : monster type
* \param amount : amount of monsters
*/
void findPlaceMonsters(enemyTypeEnum monsterType, int amount);
/*!
* \brief Add a monster to the "killed monsters" table
* \param enemyType : ID of the monster
*/
void addKilledEnemy(enemyTypeEnum enemyType, enumShotType damageType);
/*!
* \brief Proceed an event
* \param event : ID of the event
*/
void proceedEvent(EnumWorldEvents event);
/*!
* \brief Proceed a message
* \param event : ID of the message
*/
void testAndAddMessageToQueue(EnumMessages type);
/*!
* \brief Proceed a divinity level up message
* \param label : the message to proceed
*/
void addDivLevelMessageToQueue(std::string label);
std::string enemyToString(enemyTypeEnum enemyType);
std::string sourceToString(sourceTypeEnum sourceType, enemyTypeEnum enemyType);
void saveScreen();
void saveDeathScreen();
struct StructScore
{
std::string name;
int score;
int level;
int shotType;
bool equip[NUMBER_EQUIP_ITEMS];
};
void calculateScore();
void addLifeBarToDisplay(std::string label, int hp, int hpMax);
void revealFloor();
void activateKeyRoomEffect(bool withColorEffect);
void generateStar(sf::Color starColor, float xStar, float yStar);
void registerAchievement(enumAchievementType achievement);
void renderDoors();
+ void setDoorVisible(int n);
bool isPresentItem(int n);
void addPresentItem(int n);
/*!
* \brief Checks if player opens a door
*
* Checks if player opens a door (collide with the door and gets the key).
* If positive, opens the door.
*/
void verifyDoorUnlocking();
float getGameTime();
std::string equipToString(bool equip[NUMBER_EQUIP_ITEMS]);
enumItemType getPotion(enumItemType source);
bool potionEffectKnown(enumItemType source);
void setPotionToKnown(enumItemType source);
void addPotionToMap(enumItemType source, enumItemType effect, bool known);
protected:
/*!
* \brief Rendering method
*
* Render all the game objects to the screen.
* Called in the game loop.
*/
virtual void onRender();
/*!
* \brief Update method
*
* Update all the game objects to the screen.
* Called in the game loop.
*/
virtual void onUpdate();
/*!
* \brief render the HUD for shot types
*
* Render the HUD for shot types.
* Display the available shot types and highlight the current one.
*
* \param app : Rendering target
*/
void renderHudShots(sf::RenderTarget* app);
void killArtefactDescription();
private:
Config config;
float deltaTime;
// game logic / data
GameMap* miniMap; /*!< Pointer to the logical minimap */
DungeonMap* currentMap; /*!< Pointer to the logical current map */
GameFloor* currentFloor; /*!< Pointer to the logical floor (level) */
bool showLogical; /*!< True if showing bounding boxes, z and center */
bool showGameTime; /*!< True if showing the game time */
// game play
int level; /*!< Level (floor) */
int score; /*!< score (calculated at the end of the game) */
int bodyCount; /*!< killed monsters (calculated at the end of the game) */
int challengeLevel; /*!< Level (challenge) */
float gameTime; /*!< "age" of the current game */
int floorX; /*!< X position of the room in the level */
int floorY; /*!< Y position of the room in the level */
bool roomClosed; /*!< True if the room is closed */
bool bossRoomOpened; /*!< True if the boss gate has been opened in this level */
int firingDirection; /*!< Save the firing direction - for the "one button" gameplay */
bool isPlayerAlive; /*!< Dying sets this bool to false (trigger the ending music) */
bool monsterArray[MAP_WIDTH][MAP_HEIGHT]; /*!< use to remember if a case has a monster in monster spawn */
int killedEnemies[NB_ENEMY];
// game objects
PlayerEntity* player; /*!< Pointer to the player entity */
DungeonMapEntity* dungeonEntity; /*!< TileMap of the room (main game board) + blood, items, etc...*/
TileMapEntity* miniMapEntity;
// displaying objects
DoorEntity* doorEntity[4]; /*!< Pointers to the door graphical entity */
sf::Font font; /*!< The font used for displaying text */
sf::Text myText; /*!< The text to be displayed */
sf::Sprite introScreenSprite;
sf::Sprite titleSprite;
struct uiSpritesStruct
{
sf::Sprite gui;
sf::Sprite keySprite; /*!< A simple sprite with the boss key (displayed on the HUD) */
sf::Sprite shotsSprite; /*!< A simple sprite for the available shot types (displayed on the HUD) */
sf::Sprite topLayer;
sf::Sprite msgBoxSprite;
sf::Sprite iconSprite;
sf::Sprite mapBgSprite;
} uiSprites;
struct lifeBarStruct
{
bool toDisplay;
std::string label;
int hp;
int hpMax;
} lifeBar;
float xOffset, yOffset; /*!< Main game client position in the GUI */
sf::Music music; /*!< Current game music */
/** Music enum
* Identify the various music tracks of the game.
*/
enum musicEnum
{
MusicDungeon, /**< Main game music - played when playing the game */
MusicEnding, /**< Ending music - played when the player has died */
MusicBoss, /**< Boss music - for epic fights ! */
MusicIntro, /**< Main menu music */
MusicChallenge /**< Challenge music - for epic fights ! */
};
/** Game states enum
* Used for the different game states
*/
enum gameStateEnum
{
gameStateInit, /**< Game initialization */
gameStateIntro, /** < Intro animation */
gameStateMenu, /**< Menu */
gameStateKeyConfig, /**< Key config */
gameStateJoystickConfig, /**< Joystick config */
gameStatePlaying, /**< Playing */
gameStatePlayingPause, /**< Playing / Pause */
gameStatePlayingDisplayBoss, /**< Playing / DisplayBoss */
};
gameStateEnum gameState; /*!< Store the game state */
float bossDisplayTimer;
int bossDisplayState;
/** Special game states enum
* Used for effects such as fade in...
*/
enum xGameTypeEnum
{
xGameTypeFade, /**< Fade effect */
xGameTypeShake, /**< Shake effect */
xGameTypeFadeColor, /**< Color fade effect */
NB_X_GAME
};
struct xGameStruct
{
bool active;
int param;
float timer;
float duration;
} xGame[NB_X_GAME];
/** Input Keys enum
* Used for the input binding
*/
enum inputKeyEnum
{
KeyUp,
KeyDown,
KeyLeft,
KeyRight,
KeyFireUp,
KeyFireDown,
KeyFireLeft,
KeyFireRight,
KeyFireSelect,
KeySpell,
KeyInteract,
KeyTimeControl,
KeyFire
};
const std::string inputKeyStr[NumberKeys] =
{
"_move_up",
"_move_down",
"_move_left",
"_move_right",
"_fire_up",
"_fire_down",
"_fire_left",
"_fire_right",
"_spell",
"_interact",
"_fire",
"_time_control",
"_fire_select"
};
sf::Keyboard::Key input[NumberKeys]; /*!< Input key array */
struct JoystickInputStruct
{
bool isButton;
sf::Joystick::Axis axis;
int value;
};
JoystickInputStruct joystickInput[NumberKeys];
std::string scoreSaveFile;
/*!
* \brief Starts the game
*
* Start a new game or load it from file.
*
* \param fromSaveFile : true if we want to try to load the game from a file
*/
void startNewGame(bool fromSaveFile, int startingLevel);
/*!
* \brief Starts a new level
*
* Start a new level.
* Called for each level of the game.
*/
void startNewLevel();
/*!
* \brief Starts the level
*
* Starts the level.
* Called after loading the game or creating a new level.
* \param isFight : true if loading in fight
*/
void playLevel(bool isFight);
/*!
* \brief Creates a level
*
* Creates a random level (a level is a floor that consists of rooms).
*/
void createFloor();
/*!
* \brief Create or refresh the room
*
* Create a room (if this is a new one) or refresh it.
* Called when the player changes room.
* Checks the visibility of the doors and close it if there are monsters.
* Loads the map items and sprites.
*/
void refreshMap();
/*!
* \brief Check if a door is present, and its style
*
* \param doorId : index of the door
* \param roomCurrent : type of the current door
* \param roomNeighbour : type of the neighbour door
*/
- void checkDoor(int doorId, roomTypeEnum roomCurrent, roomTypeEnum roomNeighbour);
+ void checkDoor(int doorId, roomTypeEnum roomCurrent, roomTypeEnum roomNeighbour, bool isNeighbourKnown);
/*!
* \brief Refreshes the minimap
*
* Refresh the minimap.
* Called when the player changes room.
*/
void refreshMinimap();
/*!
* \brief Generates a room
*
* Generates a room.
* Called when the player moves to a room for the first time.
*/
void generateMap();
/*!
* \brief Generates a standard room
*
* Generates a standard room with monsters.
* Called during the generation when the map has no particular type.
*/
void generateStandardMap();
/*!
* \brief Checks if the room will be closed
*
* Checks if the room will be closed.
* Called when entering a room. If the room is not clear, closes the doors.
*/
void checkEntering();
/*!
* \brief Saves the map items
*
* Saves the map objects such as items, corpses, blood, chest.
* Called when leaving the door.
*/
void saveMapItems();
/*!
* \brief Initializes the monster array
*
* Initializes the monster array (to empty).
*/
void initMonsterArray();
/*!
* \brief Adds a monster
*
* Adds a monster to the room.
* \param monsterType : monster type
* \param xm : x position of the monster
* \param ym : y position of the monster
*/
void addMonster(enemyTypeEnum monsterType, float xm, float ym);
/*!
* \brief Checks if player can interact with something
*/
void checkInteraction();
/*!
* \brief Plays a music
*
* Plays a music.
*
* \param musicChoice : music track ID
*/
void playMusic(musicEnum musicChoice);
/*!
* \brief Update the music volume (with parameters.volumeMusic)
*/
void updateMusicVolume();
/*!
* \brief Add a key to the player input map from a string key (from file)
* \param logicInput : input function (move left, fire up, etc...)
* \param key : Key as string
*/
void addKey(int logicInput, std::string key);
/*!
* \brief Save configuration to "config.dat"
*/
void saveConfigurationToFile();
/*!
* \brief Configure with data from "config.dat"
*/
void configureFromFile();
/*!
* \brief Update the game
*/
void updateRunningGame();
/*!
* \brief Render the game
*/
void renderRunningGame();
void renderGame();
void renderHud();
void renderLifeBar();
void renderMessages();
void renderBossPortrait();
/*!
* \brief Update the menu
*/
void updateMenu();
/*!
* \brief Render the menu
*/
void renderMenu();
/*!
* \brief Render the menu
*/
void renderInGameMenu();
/*!
* \brief initialize the intro
*/
void prepareIntro();
/*!
* \brief Update the intro
*/
void updateIntro();
/*!
* \brief Render the intro
*/
void renderIntro();
/*!
* \brief Render the credits screen
*/
void renderCredits();
/*!
* \brief Render the achievements screen
*/
void renderAchievements();
/*!
* \brief Render the scores screen
*/
void renderHiScores();
void renderScores(std::vector <StructScore> scoresToRender, std::string title);
/** Menu keys enum
* Identify the various keys of the menu.
*/
enum menuItemEnum
{
MenuStartNew, /**< When starting the game */
MenuStartOld, /**< When restoring the game */
MenuConfig, /**< When configuring the game */
MenuKeys, /**< When configuring keys */
MenuJoystick, /**< When configuring joystick */
MenuConfigBack, /**< Back to the main menu */
MenuTutoReset, /**< Reset the tutorials */
MenuLanguage, /**< When configuring the language */
MenuExit, /**< When exiting the game */
MenuAchievements, /**< Display the Achievements */
MenuCredits, /**< Display the credits screen */
MenuHiScores, /**< Display the hi-scores screen */
MenuPlayerName, /**< To enter/change the player name */
MenuVolumeSound,
MenuVolumeMusic,
MenuContinue, /**< Continue the game */
MenuSaveAndQuit, /**< Save and return to main */
};
/** Menu states enum
* Identify the various states of the menu.
*/
enum menuStateEnum
{
MenuStateMain,
MenuStateConfig,
MenuStateKeys,
MenuStateJoystick,
MenuStateHiScores,
MenuStateChangeName,
MenuStateCredits,
MenuStateAchievements,
MenuStateFirst /**< First time, we choose language and keyboard */
};
menuStateEnum menuState;
/*!
* \brief Menu item structure
*/
struct menuItemStuct
{
menuItemEnum id; /**< Id of the action */
std::string label; /**< Label of the menu item */
std::string description; /**< Description of the menu item */
};
int menuScoreIndex;
/*!
* \brief Menu structure
*/
struct menuStuct
{
std::vector<menuItemStuct> items; /**< Menu items */
unsigned int index; /**< Position int the menu */
float age; /**< Age of the menu */
};
menuStuct menuMain;
menuStuct menuFirst;
menuStuct menuConfig;
menuStuct menuJoystick;
menuStuct menuInGame;
unsigned int menuKeyIndex;
unsigned int menuAchIndex;
/*!
* \brief Build the menu items
*/
void buildMenu(bool rebuild);
/*!
* \brief Build the menu items (in game)
*/
void buildInGameMenu();
/*!
* \brief Switch to the menu
*/
void switchToMenu();
/*!
* \brief Save language config and default keys configuration
*/
void registerLanguage();
parameterStruct parameters;
void resetKilledEnemies();
std::queue <messageStruct> messagesQueue;
bool worldEvent[NB_EVENTS];
void initEvents();
bool gameMessagesToSkip[NB_MESSAGES];
struct achievementStruct
{
enumAchievementType type;
std::string message;
float timer;
bool hasStarted;
int counter;
};
std::queue <achievementStruct> achievementsQueue;
void renderPlayer(float x, float y, bool equip[NUMBER_EQUIP_ITEMS], int shotType,
int frame, int spriteDy);
void renderDeathScreen(float x, float y);
bool equipToDisplay[NUMBER_EQUIP_ITEMS];
bool equipNudeToDisplay[NUMBER_EQUIP_ITEMS];
saveHeaderStruct saveHeader;
struct StructMonster
{
enemyTypeEnum id;
float x;
float y;
};
/*!
* \brief Data for "in fight" game saving
*/
struct StructSaveInFight
{
bool isFight; /**< True if loading during a fight */
float x; /**< Player x position */
float y; /**< Player y position */
int direction; /**< Player direction */
std::vector<StructMonster> monsters; /**< Monsters */
};
StructSaveInFight saveInFight; /**< Data for "in fight" game saving */
SpriteEntity* introSprites[8];
int introState;
int introSoundState;
std::vector <StructScore> scores;
std::vector <StructScore> scoresOnline;
std::vector <StructScore> scoresOnlineDay;
StructScore lastScore;
void loadHiScores();
void loadHiScoresOnline(bool fromDayOnly);
void saveHiScores();
enum enumNetworkScoreState
{
ScoreOK,
ScoreLoading,
ScoreLoadingDay
} scoreState;
struct StructInteraction
{
bool active;
EnumInteractionType type;
int id;
std::string label;
} interaction;
void enableAA(bool enable);
enum achievementStatus { AchievementDone, AchievementUndone, AchievementPending};
achievementStatus achievementState[NB_ACHIEVEMENTS];
bool isItemLocked(enumItemType item);
bool isFunctionalityLocked(enumFunctionalityType func);
int getAchievementsPercents();
struct globalDataStruct
{
int killedMonster[NB_ENEMY];
} globalData;
void generateUiParticle(float x, float y);
bool presentItems[NUMBER_EQUIP_ITEMS];
void resetPresentItems();
bool isPressing(inputKeyEnum k, bool oneShot);
bool getPressingState(inputKeyEnum k);
void updateActionKeys();
struct ActionKeyStruct
{
bool isPressed;
bool isTriggered;
} actionKey[NumberKeys];
bool isInputPressed[NumberKeys];
bool gameFromSaveFile;
// scoring server
std::thread sendScoreThread;
void sendScoreToServer();
void sendScoreToServerThread();
std::thread receiveScoreThread;
void receiveScoreFromServer();
void receiveScoreFromServerThread();
void checkDestroyableObjects();
std::map<enumItemType, structPotionMap> potionMap;
void randomizePotionMap();
};
/*!
* \brief Returns the game reference
*
* Returns the game reference.
*
* \return a reference to the game
*/
WitchBlastGame& game();
#endif // WITCH_BLAST_GAME_H

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 16, 12:25 AM (2 w, 1 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
70474
Default Alt Text
(455 KB)

Event Timeline