scummvm/engines/xeen/map.cpp
2016-10-09 14:59:58 +02:00

1582 lines
55 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program 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 2
* of the License, or (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "common/serializer.h"
#include "xeen/map.h"
#include "xeen/interface.h"
#include "xeen/resources.h"
#include "xeen/saves.h"
#include "xeen/screen.h"
#include "xeen/xeen.h"
namespace Xeen {
const int MAP_GRID_PRIOR_INDEX[] = { 0, 0, 0, 0, 1, 2, 3, 4, 0 };
const int MAP_GRID_PRIOR_DIRECTION[] = { 0, 1, 2, 3, 1, 2, 3, 0, 0 };
const int MAP_GRID_PRIOR_INDEX2[] = { 0, 0, 0, 0, 2, 3, 4, 1, 0 };
const int MAP_GRID_PRIOR_DIRECTION2[] = { 0, 1, 2, 3, 0, 1, 2, 3, 0 };
MonsterStruct::MonsterStruct() {
_experience = 0;
_hp = 0;
_accuracy = 0;
_speed = 0;
_numberOfAttacks = 0;
_hatesClass = CLASS_KNIGHT;
_strikes = 0;
_dmgPerStrike = 0;
_attackType = DT_PHYSICAL;
_specialAttack = SA_NONE;
_hitChance = 0;
_rangeAttack = 0;
_monsterType = MONSTER_0;
_fireResistence = 0;
_electricityResistence = 0;
_coldResistence = 0;
_poisonResistence = 0;
_energyResistence = 0;
_magicResistence = 0;
_phsyicalResistence = 0;
_field29 = 0;
_gold = 0;
_gems = 0;
_itemDrop = 0;
_flying = 0;
_imageNumber = 0;
_loopAnimation = 0;
_animationEffect = 0;
_fx = 0;
}
MonsterStruct::MonsterStruct(Common::String name, int experience, int hp, int accuracy,
int speed, int numberOfAttacks, CharacterClass hatesClass, int strikes,
int dmgPerStrike, DamageType attackType, SpecialAttack specialAttack,
int hitChance, int rangeAttack, MonsterType monsterType,
int fireResistence, int electricityResistence, int coldResistence,
int poisonResistence, int energyResistence, int magicResistence,
int phsyicalResistence, int field29, int gold, int gems, int itemDrop,
bool flying, int imageNumber, int loopAnimation, int animationEffect,
int fx, Common::String attackVoc):
_name(name), _experience(experience), _hp(hp), _accuracy(accuracy),
_speed(speed), _numberOfAttacks(numberOfAttacks), _hatesClass(hatesClass),
_strikes(strikes), _dmgPerStrike(dmgPerStrike), _attackType(attackType),
_specialAttack(specialAttack), _hitChance(hitChance), _rangeAttack(rangeAttack),
_monsterType(monsterType), _fireResistence(fireResistence),
_electricityResistence(electricityResistence), _coldResistence(coldResistence),
_poisonResistence(poisonResistence), _energyResistence(energyResistence),
_magicResistence(magicResistence), _phsyicalResistence(phsyicalResistence),
_field29(field29), _gold(gold), _gems(gems), _itemDrop(itemDrop),
_flying(flying), _imageNumber(imageNumber), _loopAnimation(loopAnimation),
_animationEffect(animationEffect), _fx(fx), _attackVoc(attackVoc) {
}
void MonsterStruct::synchronize(Common::SeekableReadStream &s) {
char name[16];
s.read(name, 16);
name[15] = '\0';
_name = Common::String(name);
_experience = s.readUint32LE();
_hp = s.readUint16LE();
_accuracy = s.readByte();
_speed = s.readByte();
_numberOfAttacks = s.readByte();
_hatesClass = (CharacterClass)s.readByte();
_strikes = s.readUint16LE();
_dmgPerStrike = s.readByte();
_attackType = (DamageType)s.readByte();
_specialAttack = (SpecialAttack)s.readByte();
_hitChance = s.readByte();
_rangeAttack = s.readByte();
_monsterType = (MonsterType)s.readByte();
_fireResistence = s.readByte();
_electricityResistence = s.readByte();
_coldResistence = s.readByte();
_poisonResistence = s.readByte();
_energyResistence = s.readByte();
_magicResistence = s.readByte();
_phsyicalResistence = s.readByte();
_field29 = s.readByte();
_gold = s.readUint16LE();
_gems = s.readByte();
_itemDrop = s.readByte();
_flying = s.readByte() != 0;
_imageNumber = s.readByte();
_loopAnimation = s.readByte();
_animationEffect = s.readByte();
_fx = s.readByte();
char attackVoc[10];
s.read(attackVoc, 9);
attackVoc[9] = '\0';
_attackVoc = Common::String(attackVoc);
}
MonsterData::MonsterData() {
push_back(MonsterStruct("", 0, 0, 0, 0, 0, CLASS_KNIGHT, 1, 1, DT_PHYSICAL,
SA_NONE, 1, 0, MONSTER_0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, false, 0, 0, 0, 100, "Slime"));
push_back(MonsterStruct("Whirlwind", 250000, 1000, 10, 250, 1, CLASS_15, 5,
100, DT_PHYSICAL, SA_CONFUSE, 250, 0, MONSTER_0, 100,
100, 100, 100, 0, 0, 100, 0, 0, 0, 0, false, 1, 0, 0, 176,
"airmon"));
push_back(MonsterStruct("Annihilator", 1000000, 1500, 40, 200, 12, CLASS_16, 5,
50, DT_ENERGY, SA_NONE, 1, 1, MONSTER_0, 80, 80, 100,
100, 0, 0, 80, 0, 0, 0, 0, false, 2, 0, 0, 102, "alien1"));
push_back(MonsterStruct("Autobot", 1000000, 2500, 100, 200, 2, CLASS_16, 5,
100, DT_ENERGY, SA_NONE, 1, 0, MONSTER_0, 50, 50, 100,
100, 0, 0, 50, 0, 0, 0, 0, true, 3, 0, 0, 101, "alien2"));
push_back(MonsterStruct("Sewer Stalker", 50000, 250, 30, 25, 1, CLASS_16, 3,
100, DT_PHYSICAL, SA_NONE, 50, 0, MONSTER_ANIMAL, 0,
0, 50, 50, 0, 0, 0, 0, 0, 0, 0, false, 4, 0, 0, 113,
"iguana"));
push_back(MonsterStruct("Armadillo", 60000, 800, 50, 15, 1, CLASS_16, 100, 6,
DT_PHYSICAL, SA_BREAKWEAPON, 60, 0, MONSTER_ANIMAL,
50, 0, 80, 80, 50, 0, 50, 0, 0, 0, 0, false, 5, 1, 0, 113,
"unnh"));
push_back(MonsterStruct("Barbarian", 5000, 50, 5, 40, 3, CLASS_SORCERER, 1, 20,
DT_PHYSICAL, SA_NONE, 20, 1, MONSTER_HUMANOID, 0, 0,
0, 0, 0, 0, 0, 0, 100, 0, 3, false, 6, 0, 0, 100,
"barbarch"));
push_back(MonsterStruct("Electrapede", 10000, 200, 10, 50, 1, CLASS_PALADIN,
50, 1, DT_ELECTRICAL, SA_PARALYZE, 1, 0,
MONSTER_INSECT, 50, 100, 50, 50, 50, 0, 0, 0, 0, 0, 0,
false, 7, 1, 0, 107, "centi"));
push_back(MonsterStruct("Cleric of Mok", 30000, 125, 10, 40, 1, CLASS_CLERIC,
250, 1, DT_ELECTRICAL, SA_NONE, 1, 1, MONSTER_HUMANOID,
10, 100, 10, 10, 10, 10, 0, 0, 0, 10, 0, false, 8, 0, 0,
117, "cleric"));
push_back(MonsterStruct("Mok Heretic", 50000, 150, 12, 50, 1, CLASS_CLERIC,
500, 1, DT_MAGICAL, SA_NONE, 1, 1, MONSTER_HUMANOID, 20, 50,
20, 20, 20, 30, 0, 0, 0, 25, 4, false, 8, 0, 0, 117,
"cleric"));
push_back(MonsterStruct("Mantis Ant", 40000, 300, 30, 40, 2, CLASS_16, 2, 100,
DT_PHYSICAL, SA_POISON, 30, 0, MONSTER_INSECT, 0, 0,
0, 100, 0, 0, 30, 0, 0, 0, 0, false, 10, 0, 0, 104,
"spell001"));
push_back(MonsterStruct("Cloud Dragon", 500000, 2000, 40, 150, 1, CLASS_15,
600, 1, DT_COLD, SA_NONE, 1, 1, MONSTER_DRAGON, 0, 50,
100, 100, 50, 25, 50, 0, 0, 10, 0, false, 11, 0, 0, 140,
"tiger1"));
push_back(MonsterStruct("Phase Dragon", 2000000, 4000, 80, 200, 1, CLASS_15,
750, 1, DT_COLD, SA_NONE, 1, 1, MONSTER_DRAGON, 0, 50,
100, 100, 80, 50, 50, 0, 0, 20, 0, false, 11, 0, 10, 140,
"Begger"));
push_back(MonsterStruct("Green Dragon", 500000, 2500, 50, 150, 1, CLASS_15,
500, 1, DT_FIRE, SA_NONE, 1, 1, MONSTER_DRAGON, 100,
50, 0, 100, 50, 25, 50, 0, 0, 10, 0, false, 13, 0, 0, 140,
"tiger1"));
push_back(MonsterStruct("Energy Dragon", 2000000, 5000, 100, 250, 1, CLASS_15,
1000, 1, DT_ENERGY, SA_NONE, 1, 1, MONSTER_DRAGON, 80,
80, 60, 100, 100, 30, 50, 0, 0, 20, 0, false, 13, 0, 7,
140, "begger"));
push_back(MonsterStruct("Dragon Mummy", 2000000, 3000, 30, 100, 1,
CLASS_CLERIC, 2000, 2, DT_PHYSICAL, SA_DISEASE, 200,
0, MONSTER_DRAGON, 0, 80, 100, 100, 0, 10, 90, 0, 0, 0,
0, false, 15, 0, 0, 140, "dragmum"));
push_back(MonsterStruct("Scraps", 2000000, 3000, 30, 100, 1, CLASS_16, 2000, 2,
DT_PHYSICAL, SA_NONE, 200, 0, MONSTER_DRAGON, 0, 80,
100, 100, 0, 10, 90, 0, 0, 0, 0, false, 15, 0, 0, 140,
"dragmum"));
push_back(MonsterStruct("Earth Blaster", 250000, 1000, 10, 100, 1, CLASS_15, 5,
100, DT_PHYSICAL, SA_NONE, 200, 0, MONSTER_0, 100, 90,
90, 100, 0, 0, 90, 0, 0, 0, 0, false, 17, 0, 0, 100,
"earthmon"));
push_back(MonsterStruct("Beholder Bat", 10000, 75, 15, 80, 1, CLASS_15, 5, 5,
DT_FIRE, SA_NONE, 1, 0, MONSTER_0, 100, 50, 0, 0, 0, 0,
0, 0, 0, 0, 0, true, 18, 0, 0, 120, "eyeball"));
push_back(MonsterStruct("Fire Blower", 250000, 1000, 20, 60, 1, CLASS_15, 5,
100, DT_FIRE, SA_NONE, 1, 0, MONSTER_0, 100, 50, 0,
100, 50, 0, 50, 0, 0, 0, 0, false, 19, 0, 0, 110, "fire"));
push_back(MonsterStruct("Hell Hornet", 50000, 250, 30, 50, 2, CLASS_DRUID, 2,
250, DT_POISON, SA_WEAKEN, 1, 0, MONSTER_INSECT, 50,
50, 50, 100, 50, 0, 50, 0, 0, 0, 0, true, 20, 0, 0, 123,
"insect"));
push_back(MonsterStruct("Gargoyle", 30000, 150, 35, 30, 2, CLASS_16, 5, 50,
DT_PHYSICAL, SA_NONE, 60, 0, MONSTER_0, 0, 0, 0, 0, 0,
20, 0, 0, 0, 0, 0, false, 21, 0, 10, 100, "gargrwl"));
push_back(MonsterStruct("Giant", 100000, 500, 25, 45, 2, CLASS_16, 100, 5,
DT_PHYSICAL, SA_UNCONSCIOUS, 100, 0, MONSTER_0, 0, 0,
0, 0, 0, 0, 0, 0, 1000, 0, 5, false, 22, 0, 0, 100,
"giant"));
push_back(MonsterStruct("Goblin", 1000, 10, 5, 30, 2, CLASS_16, 2, 6,
DT_PHYSICAL, SA_NONE, 1, 0, MONSTER_0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, false, 25, 0, 0, 131, "gremlin"));
push_back(MonsterStruct("Onyx Golem", 1000000, 10000, 50, 100, 1, CLASS_15, 2,
250, DT_MAGICAL, SA_DRAINSP, 1, 0, MONSTER_GOLEM, 100, 100,
100, 100, 100, 100, 50, 0, 0, 100, 0, true, 24, 0, 10,
100, "golem"));
push_back(MonsterStruct("Gremlin", 2000, 20, 7, 35, 2, CLASS_16, 2, 10,
DT_PHYSICAL, SA_NONE, 10, 0, MONSTER_0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, false, 26, 0, 0, 101, "gremlink"));
push_back(MonsterStruct("Gremlin Guard", 3000, 50, 10, 35, 2, CLASS_16, 6, 5,
DT_PHYSICAL, SA_NONE, 20, 0, MONSTER_0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, false, 26, 0, 0, 101, "gremlink"));
push_back(MonsterStruct("Griffin", 60000, 800, 35, 150, 2, CLASS_KNIGHT, 50, 6,
DT_PHYSICAL, SA_NONE, 150, 0, MONSTER_ANIMAL, 0, 0, 0,
0, 0, 80, 0, 0, 0, 0, 0, false, 27, 0, 0, 120, "screech"));
push_back(MonsterStruct("Gamma Gazer", 1000000, 5000, 60, 200, 7, CLASS_16, 10,
20, DT_ENERGY, SA_NONE, 1, 0, MONSTER_0, 100, 100, 0,
100, 100, 0, 60, 0, 0, 0, 0, false, 28, 0, 0, 140, "hydra"));
push_back(MonsterStruct("Iguanasaurus", 100000, 2500, 20, 30, 1, CLASS_16, 10,
50, DT_PHYSICAL, SA_INSANE, 150, 0, MONSTER_ANIMAL, 50,
50, 50, 50, 50, 0, 20, 0, 0, 0, 0, false, 29, 0, 0, 113,
"iguana"));
push_back(MonsterStruct("Slayer Knight", 50000, 500, 30, 50, 1, CLASS_PALADIN,
2, 250, DT_PHYSICAL, SA_NONE, 100, 0, MONSTER_HUMANOID,
50, 50, 50, 50, 50, 0, 0, 0, 50, 0, 5, false, 30, 0, 0,
141, "knight"));
push_back(MonsterStruct("Death Knight", 100000, 750, 50, 80, 2, CLASS_PALADIN,
2, 250, DT_PHYSICAL, SA_NONE, 150, 0, MONSTER_HUMANOID,
50, 50, 50, 50, 50, 10, 0, 0, 100, 0, 6, false, 30, 0, 0,
141, "knight"));
push_back(MonsterStruct("Lava Dweller", 500000, 1500, 30, 40, 1, CLASS_15, 5,
100, DT_FIRE, SA_NONE, 1, 0, MONSTER_0, 100, 100, 0,
100, 50, 0, 50, 0, 0, 0, 0, false, 19, 0, 0, 110, "fire"));
push_back(MonsterStruct("Lava Roach", 50000, 500, 20, 70, 1, CLASS_16, 5, 50,
DT_FIRE, SA_NONE, 1, 0, MONSTER_INSECT, 100, 100, 0,
100, 0, 0, 0, 0, 0, 0, 0, false, 33, 0, 0, 131, "Phantom"));
push_back(MonsterStruct("Power Lich", 200000, 500, 20, 60, 1, CLASS_15, 10, 10,
DT_MAGICAL, SA_UNCONSCIOUS, 1, 1, MONSTER_UNDEAD, 0, 0, 0, 0,
0, 80, 70, 0, 0, 0, 0, true, 34, 0, 0, 141, "lich"));
push_back(MonsterStruct("Mystic Mage", 100000, 200, 20, 70, 1, CLASS_15, 10,
20, DT_ELECTRICAL, SA_NONE, 1, 1, MONSTER_0, 50, 100,
50, 50, 50, 30, 0, 0, 0, 50, 0, true, 35, 0, 0, 163,
"monsterb"));
push_back(MonsterStruct("Magic Mage", 200000, 300, 25, 80, 1, CLASS_15, 10, 30,
DT_ELECTRICAL, SA_NONE, 1, 1, MONSTER_0, 50, 100, 50,
50, 50, 50, 0, 0, 0, 75, 0, true, 35, 0, 0, 163,
"monsterb"));
push_back(MonsterStruct("Minotaur", 250000, 3000, 80, 120, 1, CLASS_16, 100, 4,
DT_PHYSICAL, SA_AGING, 150, 0, MONSTER_0, 0, 0, 10, 0,
0, 50, 60, 0, 0, 0, 0, false, 37, 0, 0, 141, "stonegol"));
push_back(MonsterStruct("Gorgon", 250000, 4000, 90, 100, 1, CLASS_16, 100, 3,
DT_PHYSICAL, SA_STONE, 100, 0, MONSTER_0, 0, 0, 0, 0,
0, 60, 70, 0, 0, 0, 0, false, 37, 0, 0, 141, "stonegol"));
push_back(MonsterStruct("Higher Mummy", 100000, 400, 20, 60, 1, CLASS_CLERIC,
10, 40, DT_PHYSICAL, SA_CURSEITEM, 100, 0,
MONSTER_UNDEAD, 0, 50, 50, 100, 50, 20, 75, 0, 0, 0, 0,
false, 39, 0, 0, 141, "mummy"));
push_back(MonsterStruct("Orc Guard", 5000, 60, 10, 20, 1, CLASS_12, 3, 10,
DT_PHYSICAL, SA_NONE, 20, 0, MONSTER_HUMANOID, 0, 0,
0, 0, 0, 0, 0, 0, 50, 0, 2, false, 40, 0, 0, 125, "orc"));
push_back(MonsterStruct("Octopod", 250000, 2500, 40, 80, 1, CLASS_15, 2, 100,
DT_POISON, SA_POISON, 1, 0, MONSTER_ANIMAL, 0, 0, 50,
100, 0, 0, 0, 0, 0, 0, 0, true, 41, 0, 0, 101, "photon"));
push_back(MonsterStruct("Ogre", 10000, 100, 15, 30, 1, CLASS_16, 4, 10,
DT_PHYSICAL, SA_NONE, 30, 0, MONSTER_0, 0, 0, 0, 0, 0,
0, 0, 0, 100, 0, 0, false, 42, 0, 0, 136, "ogre"));
push_back(MonsterStruct("Orc Shaman", 10000, 50, 15, 30, 1, CLASS_15, 5, 5,
DT_COLD, SA_SLEEP, 1, 1, MONSTER_HUMANOID, 0, 0, 0, 0,
0, 10, 0, 0, 75, 10, 2, false, 43, 0, 0, 125, "fx7"));
push_back(MonsterStruct("Sabertooth", 10000, 100, 20, 60, 3, CLASS_16, 5, 10,
DT_PHYSICAL, SA_NONE, 30, 0, MONSTER_ANIMAL, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, false, 44, 1, 0, 101, "saber"));
push_back(MonsterStruct("Sand Flower", 10000, 100, 10, 50, 5, CLASS_16, 5, 5,
DT_PHYSICAL, SA_INLOVE, 50, 0, MONSTER_0, 0, 0, 0, 0,
0, 50, 50, 0, 0, 0, 0, false, 45, 0, 0, 106, "sand"));
push_back(MonsterStruct("Killer Cobra", 25000, 1000, 25, 100, 1, CLASS_16, 2,
100, DT_PHYSICAL, SA_AGING, 30, 0, MONSTER_ANIMAL, 0,
0, 0, 100, 0, 50, 0, 0, 0, 0, 0, false, 46, 0, 0, 100,
"hiss"));
push_back(MonsterStruct("Sewer Rat", 2000, 40, 5, 35, 1, CLASS_16, 3, 10,
DT_PHYSICAL, SA_NONE, 10, 0, MONSTER_ANIMAL, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, false, 47, 0, 0, 136, "rat"));
push_back(MonsterStruct("Sewer Slug", 1000, 25, 2, 25, 1, CLASS_16, 2, 10,
DT_PHYSICAL, SA_NONE, 5, 0, MONSTER_INSECT, 0, 0, 0,
100, 0, 0, 0, 0, 0, 0, 0, false, 48, 0, 0, 111, "zombie"));
push_back(MonsterStruct("Skeletal Lich", 500000, 2000, 30, 200, 1,
CLASS_SORCERER, 1000, 1, DT_ENERGY, SA_ERADICATE, 1, 1,
MONSTER_UNDEAD, 80, 70, 80, 100, 100, 50, 50, 0, 0, 0,
0, false, 49, 0, 0, 140, "elecbolt"));
push_back(MonsterStruct("Enchantress", 40000, 100, 25, 60, 1, CLASS_CLERIC, 3,
150, DT_ELECTRICAL, SA_NONE, 1, 1, MONSTER_HUMANOID,
10, 100, 10, 10, 10, 20, 0, 0, 0, 20, 0, false, 50, 0, 0,
163, "disint"));
push_back(MonsterStruct("Sorceress", 80000, 200, 30, 80, 1, CLASS_15, 2, 50,
DT_MAGICAL, SA_NONE, 1, 1, MONSTER_HUMANOID, 10, 20, 10, 10,
10, 80, 0, 0, 0, 50, 5, false, 50, 0, 0, 163, "disint"));
push_back(MonsterStruct("Arachnoid", 4000, 50, 10, 40, 1, CLASS_16, 3, 5,
DT_POISON, SA_POISON, 1, 0, MONSTER_INSECT, 0, 0, 0,
100, 0, 0, 0, 0, 0, 0, 0, false, 52, 0, 0, 104, "web"));
push_back(MonsterStruct("Medusa Sprite", 5000, 30, 5, 30, 1, CLASS_RANGER, 3,
3, DT_PHYSICAL, SA_STONE, 10, 0, MONSTER_0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, true, 53, 0, 0, 42, "hiss"));
push_back(MonsterStruct("Rogue", 5000, 50, 10, 30, 1, CLASS_ROBBER, 1, 60,
DT_PHYSICAL, SA_NONE, 10, 0, MONSTER_HUMANOID, 0, 0,
0, 0, 0, 0, 0, 0, 70, 0, 0, false, 54, 0, 0, 100, "thief"));
push_back(MonsterStruct("Thief", 10000, 100, 15, 40, 1, CLASS_ROBBER, 1, 100,
DT_PHYSICAL, SA_NONE, 20, 0, MONSTER_HUMANOID, 0, 0,
0, 0, 0, 0, 0, 0, 200, 0, 0, false, 54, 0, 0, 100,
"thief"));
push_back(MonsterStruct("Troll Grunt", 10000, 100, 5, 50, 1, CLASS_16, 2, 25,
DT_PHYSICAL, SA_NONE, 30, 0, MONSTER_0, 50, 50, 50,
50, 0, 0, 0, 0, 0, 0, 0, false, 56, 0, 0, 136, "troll"));
push_back(MonsterStruct("Vampire", 200000, 400, 30, 80, 1, CLASS_CLERIC, 10,
10, DT_PHYSICAL, SA_WEAKEN, 100, 0, MONSTER_UNDEAD, 50,
50, 50, 50, 50, 50, 50, 0, 0, 0, 0, false, 57, 0, 0, 42,
"vamp"));
push_back(MonsterStruct("Vampire Lord", 300000, 500, 35, 100, 1, CLASS_CLERIC,
10, 30, DT_PHYSICAL, SA_SLEEP, 120, 0, MONSTER_UNDEAD,
50, 50, 50, 50, 50, 50, 70, 0, 0, 0, 0, false, 58, 0, 0,
42, "vamp"));
push_back(MonsterStruct("Vulture Roc", 200000, 2500, 50, 150, 1, CLASS_16, 5,
60, DT_PHYSICAL, SA_NONE, 100, 0, MONSTER_ANIMAL, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, true, 59, 0, 0, 120, "vulture"));
push_back(MonsterStruct("Sewer Hag", 50000, 75, 10, 40, 1, CLASS_PALADIN, 10,
25, DT_ELECTRICAL, SA_INSANE, 1, 1, MONSTER_HUMANOID,
0, 100, 0, 100, 0, 20, 0, 0, 0, 10, 0, false, 62, 0, 0,
108, "elecspel"));
push_back(MonsterStruct("Tidal Terror", 500000, 1000, 10, 200, 1, CLASS_15, 5,
100, DT_COLD, SA_NONE, 1, 0, MONSTER_0, 100, 50, 50,
100, 50, 0, 100, 0, 0, 0, 0, true, 61, 0, 0, 101,
"splash3"));
push_back(MonsterStruct("Witch", 80000, 150, 15, 70, 1, CLASS_15, 10, 10,
DT_ELECTRICAL, SA_NONE, 1, 1, MONSTER_HUMANOID, 0, 100,
0, 20, 0, 20, 0, 0, 0, 10, 0, false, 63, 0, 0, 114,
"elecspel"));
push_back(MonsterStruct("Coven Leader", 120000, 250, 20, 100, 1, CLASS_15, 10,
15, DT_ENERGY, SA_DRAINSP, 1, 1, MONSTER_HUMANOID, 10,
100, 0, 50, 100, 50, 0, 0, 0, 20, 6, false, 63, 0, 10, 114,
"elecspel"));
push_back(MonsterStruct("Master Wizard", 120000, 500, 25, 150, 2, CLASS_KNIGHT,
10, 40, DT_FIRE, SA_NONE, 1, 1, MONSTER_HUMANOID, 100,
50, 50, 50, 50, 50, 0, 0, 0, 50, 0, false, 64, 0, 0, 163,
"boltelec"));
push_back(MonsterStruct("Wizard", 60000, 250, 20, 125, 1, CLASS_PALADIN, 10,
25, DT_MAGICAL, SA_NONE, 1, 1, MONSTER_HUMANOID, 50, 30, 30,
30, 30, 30, 0, 0, 0, 20, 0, false, 65, 0, 0, 163, "wizard"));
push_back(MonsterStruct("Dark Wolf", 10000, 70, 10, 70, 3, CLASS_16, 3, 8,
DT_PHYSICAL, SA_NONE, 10, 0, MONSTER_ANIMAL, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, false, 66, 1, 0, 100, "wolf"));
push_back(MonsterStruct("Screamer", 500000, 3000, 50, 200, 1, CLASS_15, 10, 20,
DT_POISON, SA_POISON, 1, 0, MONSTER_0, 0, 0, 0, 100, 0,
0, 60, 0, 0, 0, 0, false, 67, 0, 0, 110, "dragon"));
push_back(MonsterStruct("Cult Leader", 100000, 100, 20, 60, 1, CLASS_15, 10,
10, DT_ENERGY, SA_NONE, 1, 1, MONSTER_HUMANOID, 50, 50,
50, 50, 100, 50, 0, 0, 0, 100, 6, false, 8, 0, 0, 100,
"cleric"));
push_back(MonsterStruct("Mega Dragon", 100000000, 64000, 100, 200, 1, CLASS_15,
10, 200, DT_ENERGY, SA_ERADICATE, 1, 1, MONSTER_DRAGON,
100, 100, 100, 100, 100, 100, 90, 0, 0, 232, 0, false, 11,
0, 7, 100, "tiger1"));
push_back(MonsterStruct("Gettlewaithe", 5000, 100, 15, 35, 2, CLASS_16, 5, 5,
DT_PHYSICAL, SA_NONE, 10, 0, MONSTER_0, 0, 0, 0, 0, 0,
0, 0, 0, 2000, 0, 5, false, 25, 0, 0, 100, "gremlin"));
push_back(MonsterStruct("Doom Knight", 500000, 1000, 50, 100, 4, CLASS_PALADIN,
2, 250, DT_PHYSICAL, SA_DEATH, 150, 0,
MONSTER_HUMANOID, 80, 80, 80, 80, 80, 20, 0, 0, 200,
0, 7, false, 30, 0, 10, 100, "knight"));
push_back(MonsterStruct("Sandro", 200000, 1000, 20, 75, 1, CLASS_15, 10, 10,
DT_MAGICAL, SA_DEATH, 1, 1, MONSTER_UNDEAD, 0, 0, 0, 0, 0,
90, 80, 0, 0, 100, 7, true, 34, 0, 10, 100, "lich"));
push_back(MonsterStruct("Mega Mage", 500000, 500, 35, 100, 1, CLASS_15, 10, 40,
DT_ELECTRICAL, SA_NONE, 1, 1, MONSTER_0, 80, 100, 80,
80, 80, 80, 0, 0, 0, 100, 6, true, 35, 0, 11, 100,
"monsterb"));
push_back(MonsterStruct("Orc Elite", 15000, 200, 15, 40, 2, CLASS_12, 5, 10,
DT_PHYSICAL, SA_NONE, 20, 0, MONSTER_HUMANOID, 0, 0,
0, 0, 0, 0, 0, 0, 100, 0, 3, false, 40, 0, 0, 100, "orc"));
push_back(MonsterStruct("Shaalth", 20000, 300, 15, 50, 1, CLASS_15, 5, 10,
DT_COLD, SA_SLEEP, 1, 0, MONSTER_HUMANOID, 0, 0, 0, 0,
0, 20, 0, 0, 1000, 50, 5, false, 43, 0, 10, 100, "fx7"));
push_back(MonsterStruct("Rooka", 5000, 60, 5, 40, 1, CLASS_16, 3, 10,
DT_PHYSICAL, SA_DISEASE, 15, 0, MONSTER_ANIMAL, 0, 0,
0, 0, 0, 0, 0, 0, 0, 10, 4, false, 47, 0, 0, 100, "rat"));
push_back(MonsterStruct("Morgana", 200000, 300, 35, 100, 1, CLASS_15, 2, 60,
DT_ENERGY, SA_PARALYZE, 1, 1, MONSTER_HUMANOID, 50, 50,
50, 50, 100, 80, 0, 0, 0, 100, 6, false, 50, 0, 10, 100,
"disint"));
push_back(MonsterStruct("Master Thief", 20000, 100, 20, 50, 1, CLASS_ROBBER, 1,
250, DT_PHYSICAL, SA_NONE, 40, 0, MONSTER_HUMANOID, 0,
0, 0, 0, 0, 0, 0, 0, 250, 20, 4, false, 54, 0, 14, 100,
"thief"));
push_back(MonsterStruct("Royal Vampire", 400000, 750, 40, 125, 1, CLASS_CLERIC,
10, 50, DT_PHYSICAL, SA_CURSEITEM, 120, 0,
MONSTER_UNDEAD, 50, 50, 50, 50, 50, 50, 65, 0, 0, 0, 0,
false, 57, 0, 0, 100, "vamp"));
push_back(MonsterStruct("Ct. Blackfang", 2000000, 1500, 50, 150, 1,
CLASS_CLERIC, 10, 100, DT_PHYSICAL, SA_DEATH, 120, 0,
MONSTER_UNDEAD, 75, 75, 75, 75, 75, 75, 75, 0, 0, 0, 0,
false, 58, 0, 10, 100, "vamp"));
push_back(MonsterStruct("Troll Guard", 15000, 200, 10, 60, 1, CLASS_16, 2, 35,
DT_PHYSICAL, SA_NONE, 30, 0, MONSTER_0, 50, 50, 50,
50, 0, 0, 0, 0, 0, 0, 0, false, 56, 0, 0, 100, "troll"));
push_back(MonsterStruct("Troll Chief", 20000, 300, 15, 65, 1, CLASS_16, 2, 50,
DT_PHYSICAL, SA_NONE, 30, 0, MONSTER_0, 50, 50, 50,
50, 0, 0, 0, 0, 0, 0, 0, false, 56, 0, 0, 100, "troll"));
push_back(MonsterStruct("Hobstadt", 25000, 400, 20, 70, 1, CLASS_16, 2, 50,
DT_PHYSICAL, SA_NONE, 30, 0, MONSTER_0, 50, 50, 50,
50, 0, 0, 0, 0, 1000, 0, 4, false, 56, 0, 0, 100, "troll"));
push_back(MonsterStruct("Graalg", 20000, 200, 15, 50, 1, CLASS_16, 5, 10,
DT_PHYSICAL, SA_NONE, 30, 0, MONSTER_0, 0, 0, 0, 0, 0,
0, 0, 0, 1000, 0, 5, false, 42, 0, 0, 100, "ogre"));
push_back(MonsterStruct("Vampire King", 3000000, 10000, 60, 200, 1,
CLASS_CLERIC, 10, 250, DT_PHYSICAL, SA_ERADICATE, 150,
0, MONSTER_UNDEAD, 80, 80, 80, 80, 80, 80, 90, 0, 0, 0,
0, false, 58, 0, 0, 100, "vamp"));
push_back(MonsterStruct("Valio", 60000, 150, 15, 60, 1, CLASS_PALADIN, 10, 25,
DT_MAGICAL, SA_NONE, 1, 0, MONSTER_HUMANOID, 50, 30, 30, 30,
40, 30, 0, 0, 0, 0, 0, false, 65, 0, 0, 100, "wizard"));
push_back(MonsterStruct("Sky Golem", 200000, 1000, 50, 100, 1, CLASS_15, 2,
100, DT_COLD, SA_NONE, 1, 1, MONSTER_GOLEM, 50, 50,
100, 50, 50, 50, 50, 0, 0, 0, 0, true, 24, 0, 0, 100,
"golem"));
push_back(MonsterStruct("Gurodel", 100000, 750, 30, 60, 2, CLASS_16, 100, 6,
DT_PHYSICAL, SA_UNCONSCIOUS, 110, 0, MONSTER_0, 0, 0,
0, 0, 0, 0, 0, 0, 5000, 0, 6, false, 22, 0, 0, 100,
"giant"));
push_back(MonsterStruct("Yog", 25000, 100, 5, 60, 1, CLASS_SORCERER, 1, 30,
DT_PHYSICAL, SA_NONE, 25, 0, MONSTER_HUMANOID, 0, 0,
0, 0, 0, 0, 0, 0, 200, 0, 4, false, 6, 0, 10, 100,
"barbarch"));
push_back(MonsterStruct("Sharla", 10000, 50, 5, 50, 1, CLASS_RANGER, 3, 4,
DT_PHYSICAL, SA_NONE, 20, 0, MONSTER_0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, true, 53, 0, 0, 100, "hiss"));
push_back(MonsterStruct("Ghost Mummy", 500000, 500, 35, 175, 1, CLASS_CLERIC,
200, 5, DT_PHYSICAL, SA_AGING, 150, 0, MONSTER_UNDEAD,
0, 60, 80, 80, 80, 50, 80, 0, 0, 0, 0, false, 40, 0, 6,
100, "orc"));
push_back(MonsterStruct("Phase Mummy", 500000, 500, 35, 175, 1, CLASS_CLERIC,
200, 6, DT_PHYSICAL, SA_DRAINSP, 150, 0,
MONSTER_UNDEAD, 0, 70, 80, 80, 80, 60, 85, 0, 0, 0, 0,
false, 39, 0, 7, 100, "mummy"));
push_back(MonsterStruct("Xenoc", 250000, 700, 35, 175, 1, CLASS_15, 10, 50,
DT_ENERGY, SA_NONE, 1, 0, MONSTER_HUMANOID, 50, 50, 50,
50, 100, 50, 0, 0, 0, 100, 6, false, 64, 0, 0, 100,
"boltelec"));
push_back(MonsterStruct("Barkman", 4000000, 40000, 25, 100, 3, CLASS_16, 250,
1, DT_FIRE, SA_NONE, 1, 0, MONSTER_0, 100, 50, 0, 100,
0, 0, 0, 0, 0, 0, 6, false, 19, 0, 11, 100, "fire"));
}
void MonsterData::load(const Common::String &name) {
File f(name);
synchronize(f);
}
void MonsterData::synchronize(Common::SeekableReadStream &s) {
clear();
MonsterStruct spr;
while (!s.eos()) {
spr.synchronize(s);
push_back(spr);
}
}
/*------------------------------------------------------------------------*/
SurroundingMazes::SurroundingMazes() {
clear();
}
void SurroundingMazes::clear() {
_north = 0;
_east = 0;
_south = 0;
_west = 0;
}
void SurroundingMazes::synchronize(Common::SeekableReadStream &s) {
_north = s.readUint16LE();
_east = s.readUint16LE();
_south = s.readUint16LE();
_west = s.readUint16LE();
}
int &SurroundingMazes::operator[](int idx) {
switch (idx) {
case DIR_NORTH:
return _north;
case DIR_EAST:
return _east;
case DIR_SOUTH:
return _south;
default:
return _west;
}
}
/*------------------------------------------------------------------------*/
MazeDifficulties::MazeDifficulties() {
_unlockDoor = 0;
_unlockBox = 0;
_bashDoor = 0;
_bashGrate = 0;
_bashWall = 0;
}
void MazeDifficulties::synchronize(Common::SeekableReadStream &s) {
_wallNoPass = s.readByte();
_surfaceNoPass = s.readByte();
_unlockDoor = s.readByte();
_unlockBox = s.readByte();
_bashDoor = s.readByte();
_bashGrate = s.readByte();
_bashWall = s.readByte();
_chance2Run = s.readByte();
}
/*------------------------------------------------------------------------*/
MazeData::MazeData() {
clear();
}
void MazeData::clear() {
for (int y = 0; y < MAP_HEIGHT; ++y) {
for (int x = 0; x < MAP_WIDTH; ++x)
_wallData[y][x]._data = 0;
Common::fill(&_seenTiles[y][0], &_seenTiles[y][MAP_WIDTH], false);
Common::fill(&_steppedOnTiles[y][0], &_steppedOnTiles[y][MAP_WIDTH], false);
_wallTypes[y] = 0;
_surfaceTypes[y] = 0;
}
_mazeNumber = 0;
_surroundingMazes.clear();
_mazeFlags = _mazeFlags2 = 0;
_floorType = 0;
_trapDamage = 0;
_wallKind = 0;
_tavernTips = 0;
}
void MazeData::synchronize(Common::SeekableReadStream &s) {
for (int y = 0; y < MAP_HEIGHT; ++y) {
for (int x = 0; x < MAP_WIDTH; ++x)
_wallData[y][x]._data = s.readUint16LE();
}
for (int y = 0; y < MAP_HEIGHT; ++y) {
for (int x = 0; x < MAP_WIDTH; ++x) {
byte b = s.readByte();
_cells[y][x]._surfaceId = b & 7;
_cells[y][x]._flags = b & 0xF8;
}
}
_mazeNumber = s.readUint16LE();
_surroundingMazes.synchronize(s);
_mazeFlags = s.readUint16LE();
_mazeFlags2 = s.readUint16LE();
for (int i = 0; i < 16; ++i)
_wallTypes[i] = s.readByte();
for (int i = 0; i < 16; ++i)
_surfaceTypes[i] = s.readByte();
_floorType = s.readByte();
_runPosition.x = s.readByte();
_difficulties.synchronize(s);
_runPosition.y = s.readByte();
_trapDamage = s.readByte();
_wallKind = s.readByte();
_tavernTips = s.readByte();
Common::Serializer ser(&s, nullptr);
for (int y = 0; y < MAP_HEIGHT; ++y)
SavesManager::syncBitFlags(ser, &_seenTiles[y][0], &_seenTiles[y][MAP_WIDTH]);
for (int y = 0; y < MAP_HEIGHT; ++y)
SavesManager::syncBitFlags(ser, &_steppedOnTiles[y][0], &_steppedOnTiles[y][MAP_WIDTH]);
}
void MazeData::setAllTilesStepped() {
for (int y = 0; y < MAP_HEIGHT; ++y)
Common::fill(&_steppedOnTiles[y][0], &_steppedOnTiles[y][MAP_WIDTH], true);
}
void MazeData::clearCellSurfaces() {
for (int y = 0; y < MAP_HEIGHT; ++y) {
for (int x = 0; x < MAP_WIDTH; ++x)
_cells[y][x]._surfaceId = 0;
}
}
/*------------------------------------------------------------------------*/
MobStruct::MobStruct() {
_id = 0;
_direction = DIR_NORTH;
}
bool MobStruct::synchronize(XeenSerializer &s) {
s.syncAsSint8(_pos.x);
s.syncAsSint8(_pos.y);
s.syncAsByte(_id);
s.syncAsByte(_direction);
return _id != 0xff || _pos.x != -1 || _pos.y != -1;
}
/*------------------------------------------------------------------------*/
MazeObject::MazeObject() {
_id = 0;
_frame = 0;
_spriteId = 0;
_direction = DIR_NORTH;
_flipped = false;
_sprites = nullptr;
}
/*------------------------------------------------------------------------*/
MazeMonster::MazeMonster() {
_frame = 0;
_id = 0;
_spriteId = 0;
_isAttacking = false;
_damageType = DT_PHYSICAL;
_field9 = 0;
_fieldA = 0;
_hp = 0;
_effect1 = _effect2 = 0;
_effect3 = 0;
_sprites = nullptr;
_attackSprites = nullptr;
_monsterData = nullptr;
}
int MazeMonster::getTextColor() const {
if (_hp == _monsterData->_hp)
return 15;
else if (_hp >= (_monsterData->_hp / 2))
return 9;
else
return 32;
}
/*------------------------------------------------------------------------*/
MazeWallItem::MazeWallItem() {
_id = 0;
_frame = 0;
_spriteId = 0;
_direction = DIR_NORTH;
_sprites = nullptr;
}
/*------------------------------------------------------------------------*/
MonsterObjectData::MonsterObjectData(XeenEngine *vm): _vm(vm) {
}
void MonsterObjectData::synchronize(XeenSerializer &s, MonsterData &monsterData) {
Common::Array<MobStruct> mobStructs;
MobStruct mobStruct;
byte b;
if (s.isLoading()) {
_objectSprites.clear();
_monsterSprites.clear();
_monsterAttackSprites.clear();
_wallItemSprites.clear();
_objects.clear();
_monsters.clear();
_wallItems.clear();
}
for (uint i = 0; i < 16; ++i) {
b = (i >= _objectSprites.size()) ? 0xff : _objectSprites[i]._spriteId;
s.syncAsByte(b);
if (b != 0xff)
_objectSprites.push_back(SpriteResourceEntry(b));
}
for (uint i = 0; i < 16; ++i) {
b = (i >= _monsterSprites.size()) ? 0xff : _monsterSprites[i]._spriteId;
s.syncAsByte(b);
if (b != 0xff)
_monsterSprites.push_back(SpriteResourceEntry(b));
}
for (uint i = 0; i < 16; ++i) {
b = (i >= _wallItemSprites.size()) ? 0xff : _wallItemSprites[i]._spriteId;
s.syncAsByte(b);
if (b != 0xff)
_wallItemSprites.push_back(SpriteResourceEntry(b));
}
if (s.isSaving()) {
// Save objects
for (uint i = 0; i < _objects.size(); ++i) {
mobStruct._pos = _objects[i]._position;
mobStruct._id = _objects[i]._id;
mobStruct._direction = _objects[i]._direction;
mobStruct.synchronize(s);
}
mobStruct._pos.x = mobStruct._pos.y = -1;
mobStruct._id = 0xff;
mobStruct.synchronize(s);
// Save monsters
for (uint i = 0; i < _monsters.size(); ++i) {
mobStruct._pos = _monsters[i]._position;
mobStruct._id = _monsters[i]._id;
mobStruct._direction = DIR_NORTH;
mobStruct.synchronize(s);
}
mobStruct._pos.x = mobStruct._pos.y = -1;
mobStruct._id = 0xff;
mobStruct.synchronize(s);
// Save wall items
if (_wallItems.size() == 0) {
MobStruct nullStruct;
nullStruct.synchronize(s);
} else {
for (uint i = 0; i < _wallItems.size(); ++i) {
mobStruct._pos = _wallItems[i]._position;
mobStruct._id = _wallItems[i]._id;
mobStruct._direction = _wallItems[i]._direction;
mobStruct.synchronize(s);
}
}
mobStruct._pos.x = mobStruct._pos.y = -1;
mobStruct._id = 0xff;
mobStruct.synchronize(s);
} else {
// Load monster/obbject data and merge together with sprite Ids
// Merge together object data
mobStruct.synchronize(s);
do {
MazeObject obj;
obj._position = mobStruct._pos;
obj._id = mobStruct._id;
obj._direction = mobStruct._direction;
obj._frame = 100;
obj._spriteId = _objectSprites[obj._id]._spriteId;
obj._sprites = &_objectSprites[obj._id]._sprites;
_objects.push_back(obj);
mobStruct.synchronize(s);
} while (mobStruct._id != 255 || mobStruct._pos.x != -1);
// Merge together monster data
mobStruct.synchronize(s);
do {
MazeMonster mon;
mon._position = mobStruct._pos;
mon._id = mobStruct._id;
mon._spriteId = _monsterSprites[mon._id]._spriteId;
mon._sprites = &_monsterSprites[mon._id]._sprites;
mon._attackSprites = &_monsterSprites[mon._id]._attackSprites;
mon._monsterData = &monsterData[mon._spriteId];
mon._frame = _vm->getRandomNumber(7);
MonsterStruct &md = *mon._monsterData;
mon._hp = md._hp;
mon._effect1 = mon._effect2 = md._animationEffect;
if (md._animationEffect)
mon._effect3 = _vm->getRandomNumber(7);
_monsters.push_back(mon);
mobStruct.synchronize(s);
} while (mobStruct._id != 255 || mobStruct._pos.x != -1);
// Merge together wall item data
mobStruct.synchronize(s);
do {
if (mobStruct._id < (int)_wallItemSprites.size()) {
MazeWallItem wi;
wi._position = mobStruct._pos;
wi._id = mobStruct._id;
wi._direction = mobStruct._direction;
wi._spriteId = _wallItemSprites[wi._id]._spriteId;
wi._sprites = &_wallItemSprites[wi._id]._sprites;
_wallItems.push_back(wi);
}
mobStruct.synchronize(s);
} while (mobStruct._id != 255 || mobStruct._pos.x != -1);
}
}
/*------------------------------------------------------------------------*/
HeadData::HeadData() {
for (int y = 0; y < MAP_HEIGHT; ++y) {
for (int x = 0; x < MAP_WIDTH; ++x) {
_data[y][x]._left = _data[y][x]._right = 0;
}
}
}
void HeadData::synchronize(Common::SeekableReadStream &s) {
for (int y = 0; y < MAP_HEIGHT; ++y) {
for (int x = 0; x < MAP_WIDTH; ++x) {
_data[y][x]._left = s.readByte();
_data[y][x]._right = s.readByte();
}
}
}
/*------------------------------------------------------------------------*/
void AnimationEntry::synchronize(Common::SeekableReadStream &s) {
for (int i = 0; i < 4; ++i)
_frame1._frames[i] = s.readByte();
for (int i = 0; i < 4; ++i)
_flipped._flags[i] = s.readByte() != 0;
for (int i = 0; i < 4; ++i)
_frame2._frames[i] = s.readByte();
}
void AnimationInfo::synchronize(Common::SeekableReadStream &s) {
AnimationEntry entry;
clear();
while (s.pos() < s.size()) {
entry.synchronize(s);
push_back(entry);
}
}
void AnimationInfo::load(const Common::String &name) {
File f(name);
synchronize(f);
f.close();
}
/*------------------------------------------------------------------------*/
Map::Map(XeenEngine *vm) : _vm(vm), _mobData(vm) {
_loadDarkSide = false;
_sideTownPortal = 0;
_sideObjects = 0;
_sideMonsters = 0;
_sidePictures = 0;
_isOutdoors = false;
_mazeDataIndex = 0;
_currentSteppedOn = false;
_currentSurfaceId = 0;
_currentWall = 0;
_currentTile = 0;
_currentGrateUnlocked = false;
_currentCantRest = false;
_currentIsDrain = false;
_currentIsEvent = false;
_currentSky = 0;
_currentMonsterFlags = 0;
}
void Map::load(int mapId) {
Interface &intf = *_vm->_interface;
Screen &screen = *_vm->_screen;
IndoorDrawList &indoorList = _vm->_interface->_indoorList;
OutdoorDrawList &outdoorList = _vm->_interface->_outdoorList;
if (intf._falling) {
Window &w = screen._windows[9];
w.open();
w.writeString(Res.OOPS);
} else {
PleaseWait::show(_vm);
}
_vm->_party->_stepped = true;
_vm->_party->_mazeId = mapId;
_vm->_events->clearEvents();
_sideObjects = 1;
_sideMonsters = 1;
_sidePictures = 1;
if (mapId >= 113 && mapId <= 127) {
_sideTownPortal = 0;
} else {
_sideTownPortal = _loadDarkSide ? 1 : 0;
}
if (_vm->getGameID() == GType_WorldOfXeen) {
if (!_loadDarkSide) {
_animationInfo.load("clouds.dat");
_monsterData.load("xeen.mon");
_wallPicSprites.load("xeenpic.dat");
_sidePictures = 0;
_sideMonsters = 0;
_sideObjects = 0;
} else {
switch (mapId) {
case 113:
case 114:
case 115:
case 116:
case 128:
_animationInfo.load("clouds.dat");
_monsterData.load("dark.mon");
_wallPicSprites.load("darkpic.dat");
_sideObjects = 0;
break;
case 117:
case 118:
case 119:
case 120:
case 124:
_animationInfo.load("clouds.dat");
_monsterData.load("xeen.mon");
_wallPicSprites.load("darkpic.dat");
_sideObjects = 0;
_sideMonsters = 0;
break;
case 125:
case 126:
case 127:
_animationInfo.load("clouds.dat");
_monsterData.load("dark.mon");
_wallPicSprites.load("xeenpic.dat");
_sideObjects = 0;
_sidePictures = 0;
break;
default:
_animationInfo.load("dark.dat");
_monsterData.load("ddark.mon");
_wallPicSprites.load("darkpic.dat");
break;
}
}
}
// Load any events for the new map
loadEvents(mapId);
// Iterate through loading the given maze as well as the two successive
// mazes in each of the four cardinal directions
bool isDarkCc = _vm->getGameID() == GType_DarkSide;
MazeData *mazeDataP = &_mazeData[0];
bool textLoaded = false;
for (int idx = 0; idx < 9; ++idx, ++mazeDataP) {
mazeDataP->_mazeId = mapId;
if (mapId == 0) {
mazeDataP->clear();
} else {
// Load in the maze's data file
Common::String datName = Common::String::format("maze%c%03d.dat",
(mapId >= 100) ? 'x' : '0', mapId);
File datFile(datName);
mazeDataP->synchronize(datFile);
datFile.close();
if (isDarkCc && mapId == 50)
mazeDataP->setAllTilesStepped();
if (!isDarkCc && _vm->_party->_gameFlags[25] &&
(mapId == 42 || mapId == 43 || mapId == 4)) {
mazeDataP->clearCellSurfaces();
}
_isOutdoors = (mazeDataP->_mazeFlags2 & FLAG_IS_OUTDOORS) != 0;
// Handle loading text data
if (!textLoaded) {
textLoaded = true;
Common::String txtName = Common::String::format("%s%c%03d.txt",
isDarkCc ? "dark" : "xeen", mapId >= 100 ? 'x' : '0', mapId);
File fText(txtName);
char mazeName[33];
fText.read(mazeName, 33);
mazeName[32] = '\0';
_mazeName = Common::String(mazeName);
fText.close();
// Load the monster/object data
Common::String mobName = Common::String::format("maze%c%03d.mob",
(mapId >= 100) ? 'x' : '0', mapId);
File mobFile(mobName);
XeenSerializer sMob(&mobFile, nullptr);
_mobData.synchronize(sMob, _monsterData);
mobFile.close();
Common::String headName = Common::String::format("aaze%c%03d.hed",
(mapId >= 100) ? 'x' : '0', mapId);
File headFile(headName);
_headData.synchronize(headFile);
headFile.close();
if (!isDarkCc && _vm->_party->_mazeId)
_mobData._monsters.clear();
if (!isDarkCc && mapId == 15) {
if ((_mobData._monsters[0]._position.x > 31 || _mobData._monsters[0]._position.y > 31) &&
(_mobData._monsters[1]._position.x > 31 || _mobData._monsters[1]._position.y > 31) &&
(_mobData._monsters[2]._position.x > 31 || _mobData._monsters[2]._position.y > 31)) {
_vm->_party->_gameFlags[56] = true;
}
}
}
}
// Move to next surrounding maze
MazeData *baseMaze = &_mazeData[MAP_GRID_PRIOR_INDEX[idx]];
mapId = baseMaze->_surroundingMazes[MAP_GRID_PRIOR_DIRECTION[idx]];
if (!mapId) {
baseMaze = &_mazeData[MAP_GRID_PRIOR_INDEX2[idx]];
mapId = baseMaze->_surroundingMazes[MAP_GRID_PRIOR_DIRECTION2[idx]];
}
}
// TODO: Switch setting flags that don't seem to ever be used
// Reload the monster data for the main maze that we're loading
mapId = _vm->_party->_mazeId;
Common::String filename = Common::String::format("maze%c%03d.mob",
(mapId >= 100) ? 'x' : '0', mapId);
File mobFile(filename, *_vm->_saves);
XeenSerializer sMob(&mobFile, nullptr);
_mobData.synchronize(sMob, _monsterData);
mobFile.close();
// Load sprites for the objects
for (uint i = 0; i < _mobData._objectSprites.size(); ++i) {
if (_vm->_party->_cloudsEnd && _mobData._objectSprites[i]._spriteId == 85 &&
mapId == 27 && isDarkCc) {
_mobData._objects[29]._spriteId = 0;
_mobData._objects[29]._id = 8;
_mobData._objectSprites[i]._sprites.clear();
} else if (mapId == 12 && _vm->_party->_gameFlags[43] &&
_mobData._objectSprites[i]._spriteId == 118 && !isDarkCc) {
filename = "085.obj";
_mobData._objectSprites[0]._spriteId = 85;
} else {
filename = Common::String::format("%03d.%cbj",
_mobData._objectSprites[i]._spriteId,
_mobData._objectSprites[i]._spriteId >= 100 ? '0' : 'o');
}
// Read in the object sprites
_mobData._objectSprites[i]._sprites.load(filename,
_sideObjects ? ALTSIDE_ARCHIVE : GAME_ARCHIVE);
}
// Load sprites for the monsters
for (uint i = 0; i < _mobData._monsterSprites.size(); ++i) {
ArchiveType archiveType =
_mobData._monsterSprites[i]._spriteId == 91 && _vm->getGameID() == GType_WorldOfXeen ?
ALTSIDE_ARCHIVE : GAME_ARCHIVE;
filename = Common::String::format("%03d.mon", _mobData._monsterSprites[i]._spriteId);
_mobData._monsterSprites[i]._sprites.load(filename, archiveType);
filename = Common::String::format("%03d.att", _mobData._monsterSprites[i]._spriteId);
_mobData._monsterSprites[i]._attackSprites.load(filename, archiveType);
}
// Load wall picture sprite resources
for (uint i = 0; i < _mobData._wallItemSprites.size(); ++i) {
filename = Common::String::format("%03d.pic", _mobData._wallItems[i]._spriteId);
_mobData._wallItemSprites[i]._sprites.load(filename,
_sidePictures ? ALTSIDE_ARCHIVE : GAME_ARCHIVE);
}
// Handle loading miscellaneous sprites for the map
if (_isOutdoors) {
warning("TODO"); // Sound loading
_groundSprites.load("water.out");
_tileSprites.load("outdoor.til");
outdoorList._sky1._sprites = &_skySprites[0];
outdoorList._sky2._sprites = &_skySprites[0];
outdoorList._groundSprite._sprites = &_groundSprites;
for (int i = 0; i < TOTAL_SURFACES; ++i) {
_wallSprites._surfaces[i].clear();
if (_mazeData[0]._wallTypes[i] != 0) {
_wallSprites._surfaces[i].load(Common::String::format("%s.wal",
Res.SURFACE_TYPE_NAMES[_mazeData[0]._wallTypes[i]]));
}
_surfaceSprites[i].clear();
if (i != 0 && _mazeData[0]._surfaceTypes[i] != 0)
_surfaceSprites[i].load(Res.SURFACE_NAMES[_mazeData[0]._surfaceTypes[i]]);
}
} else {
warning("TODO"); // Sound loading
_skySprites[1].load(Common::String::format("%s.sky",
Res.TERRAIN_TYPES[_mazeData[0]._wallKind]));
_groundSprites.load(Common::String::format("%s.gnd",
Res.TERRAIN_TYPES[_mazeData[0]._wallKind]));
_tileSprites.load(Common::String::format("%s.til",
Res.TERRAIN_TYPES[_mazeData[0]._wallKind]));
for (int i = 0; i < TOTAL_SURFACES; ++i) {
_surfaceSprites[i].clear();
if (_mazeData[0]._surfaceTypes[i] != 0 || i == 4)
_surfaceSprites[i].load(Res.SURFACE_NAMES[_mazeData[0]._surfaceTypes[i]]);
}
for (int i = 0; i < TOTAL_SURFACES; ++i)
_wallSprites._surfaces[i].clear();
_wallSprites._fwl1.load(Common::String::format("f%s1.fwl",
Res.TERRAIN_TYPES[_mazeData[0]._wallKind]));
_wallSprites._fwl2.load(Common::String::format("f%s2.fwl",
Res.TERRAIN_TYPES[_mazeData[0]._wallKind]));
_wallSprites._fwl3.load(Common::String::format("f%s3.fwl",
Res.TERRAIN_TYPES[_mazeData[0]._wallKind]));
_wallSprites._fwl4.load(Common::String::format("f%s4.fwl",
Res.TERRAIN_TYPES[_mazeData[0]._wallKind]));
_wallSprites._swl.load(Common::String::format("s%s.swl",
Res.TERRAIN_TYPES[_mazeData[0]._wallKind]));
// Set entries in the indoor draw list to the correct sprites
// for drawing various parts of the background
indoorList._swl_0F1R._sprites = &_wallSprites._swl;
indoorList._swl_0F1L._sprites = &_wallSprites._swl;
indoorList._swl_1F1R._sprites = &_wallSprites._swl;
indoorList._swl_1F1L._sprites = &_wallSprites._swl;
indoorList._swl_2F2R._sprites = &_wallSprites._swl;
indoorList._swl_2F1R._sprites = &_wallSprites._swl;
indoorList._swl_2F1L._sprites = &_wallSprites._swl;
indoorList._swl_2F2L._sprites = &_wallSprites._swl;
indoorList._swl_3F1R._sprites = &_wallSprites._swl;
indoorList._swl_3F2R._sprites = &_wallSprites._swl;
indoorList._swl_3F3R._sprites = &_wallSprites._swl;
indoorList._swl_3F4R._sprites = &_wallSprites._swl;
indoorList._swl_3F1L._sprites = &_wallSprites._swl;
indoorList._swl_3F2L._sprites = &_wallSprites._swl;
indoorList._swl_3F3L._sprites = &_wallSprites._swl;
indoorList._swl_3F4L._sprites = &_wallSprites._swl;
indoorList._swl_4F4R._sprites = &_wallSprites._swl;
indoorList._swl_4F3R._sprites = &_wallSprites._swl;
indoorList._swl_4F2R._sprites = &_wallSprites._swl;
indoorList._swl_4F1R._sprites = &_wallSprites._swl;
indoorList._swl_4F1L._sprites = &_wallSprites._swl;
indoorList._swl_4F2L._sprites = &_wallSprites._swl;
indoorList._swl_4F3L._sprites = &_wallSprites._swl;
indoorList._swl_4F4L._sprites = &_wallSprites._swl;
indoorList._fwl_4F4R._sprites = &_wallSprites._fwl4;
indoorList._fwl_4F3R._sprites = &_wallSprites._fwl4;
indoorList._fwl_4F2R._sprites = &_wallSprites._fwl4;
indoorList._fwl_4F1R._sprites = &_wallSprites._fwl4;
indoorList._fwl_4F._sprites = &_wallSprites._fwl4;
indoorList._fwl_4F1L._sprites = &_wallSprites._fwl4;
indoorList._fwl_4F2L._sprites = &_wallSprites._fwl4;
indoorList._fwl_4F3L._sprites = &_wallSprites._fwl4;
indoorList._fwl_4F4L._sprites = &_wallSprites._fwl4;
indoorList._fwl_2F1R._sprites = &_wallSprites._fwl3;
indoorList._fwl_2F._sprites = &_wallSprites._fwl3;
indoorList._fwl_2F1L._sprites = &_wallSprites._fwl3;
indoorList._fwl_3F2R._sprites = &_wallSprites._fwl3;
indoorList._fwl_3F1R._sprites = &_wallSprites._fwl3;
indoorList._fwl_3F._sprites = &_wallSprites._fwl3;
indoorList._fwl_3F1L._sprites = &_wallSprites._fwl3;
indoorList._fwl_3F2L._sprites = &_wallSprites._fwl3;
indoorList._fwl_1F._sprites = &_wallSprites._fwl1;
indoorList._fwl_1F1R._sprites = &_wallSprites._fwl1;
indoorList._fwl_1F1L._sprites = &_wallSprites._fwl1;
indoorList._horizon._sprites = &_wallSprites._fwl1;
indoorList._ground._sprites = &_groundSprites;
// Don't show horizon for certain maps
if (_vm->_files->_isDarkCc) {
if ((mapId >= 89 && mapId <= 112) || mapId == 128 || mapId == 129)
indoorList._horizon._sprites = nullptr;
} else {
if (mapId >= 25 && mapId <= 27)
indoorList._horizon._sprites = nullptr;
}
}
loadSky();
}
int Map::mazeLookup(const Common::Point &pt, int layerShift, int wallMask) {
Common::Point pos = pt;
int mapId = _vm->_party->_mazeId;
if (pt.x < -16 || pt.y < -16 || pt.x >= 32 || pt.y >= 32)
error("Invalid coordinate");
// Find the correct maze data out of the set to use
_mazeDataIndex = 0;
while (_mazeData[_mazeDataIndex]._mazeId != _vm->_party->_mazeId)
++_mazeDataIndex;
// Handle map changing to the north or south as necessary
if (pos.y & 16) {
if (pos.y >= 0) {
pos.y -= 16;
mapId = _mazeData[_mazeDataIndex]._surroundingMazes._north;
} else {
pos.y += 16;
mapId = _mazeData[_mazeDataIndex]._surroundingMazes._south;
}
if (mapId) {
// Move to the correct map to north/south
_mazeDataIndex = 0;
while (_mazeData[_mazeDataIndex]._mazeId != mapId)
++_mazeDataIndex;
} else {
// No map, so reached outside indoor area or outer space outdoors
_currentSteppedOn = true;
return _isOutdoors ? SURFTYPE_SPACE : INVALID_CELL;
}
}
// Handle map changing to the east or west as necessary
if (pos.x & 16) {
if (pos.x >= 0) {
pos.x -= 16;
mapId = _mazeData[_mazeDataIndex]._surroundingMazes._east;
} else {
pos.x += 16;
mapId = _mazeData[_mazeDataIndex]._surroundingMazes._west;
}
if (mapId) {
_mazeDataIndex = 0;
while (_mazeData[_mazeDataIndex]._mazeId != mapId)
++_mazeDataIndex;
}
}
if (mapId) {
if (_isOutdoors) {
_currentSurfaceId = _mazeData[_mazeDataIndex]._wallData[pos.y][pos.x]._outdoors._surfaceId;
} else {
_currentSurfaceId = _mazeData[_mazeDataIndex]._cells[pos.y][pos.x]._surfaceId;
}
if (_currentSurfaceId == SURFTYPE_SPACE || _currentSurfaceId == SURFTYPE_SKY) {
_currentSteppedOn = true;
} else {
_currentSteppedOn = _mazeData[_mazeDataIndex]._steppedOnTiles[pos.y][pos.x];
}
return (_mazeData[_mazeDataIndex]._wallData[pos.y][pos.x]._data >> layerShift) & wallMask;
} else {
_currentSteppedOn = _isOutdoors;
return _isOutdoors ? SURFTYPE_SPACE : INVALID_CELL;
}
}
void Map::loadEvents(int mapId) {
// Load events
Common::String filename = Common::String::format("maze%c%03d.evt",
(mapId >= 100) ? 'x' : '0', mapId);
File fEvents(filename, *_vm->_saves);
XeenSerializer sEvents(&fEvents, nullptr);
_events.synchronize(sEvents);
fEvents.close();
// Load text data
filename = Common::String::format("aaze%c%03d.txt",
(mapId >= 100) ? 'x' : '0', mapId);
File fText(filename);
_events._text.clear();
while (fText.pos() < fText.size())
_events._text.push_back(fText.readString());
fText.close();
}
void Map::saveMaze() {
int mazeNum = _mazeData[0]._mazeNumber;
if (!mazeNum || (mazeNum == 85 && !_vm->_files->_isDarkCc))
return;
// Save the event data
Common::String filename = Common::String::format("maze%c%03d.evt",
(mazeNum >= 100) ? 'x' : '0', mazeNum);
OutFile fEvents(_vm, filename);
XeenSerializer sEvents(nullptr, &fEvents);
_events.synchronize(sEvents);
fEvents.finalize();
// Save the maze MOB file
filename = Common::String::format("maze%c%03d.mob",
(mazeNum >= 100) ? 'x' : '0', mazeNum);
OutFile fMob(_vm, filename);
XeenSerializer sMob(nullptr, &fEvents);
_mobData.synchronize(sMob, _monsterData);
fEvents.finalize();
}
void Map::cellFlagLookup(const Common::Point &pt) {
Common::Point pos = pt;
int mapId = _vm->_party->_mazeId;
_mazeDataIndex = 0;
while (_mazeData[_mazeDataIndex]._mazeId != mapId)
++_mazeDataIndex;
// Handle map changing to the north or south as necessary
if (pos.y & 16) {
if (pos.y >= 0) {
pos.y -= 16;
mapId = _mazeData[_mazeDataIndex]._surroundingMazes._north;
} else {
pos.y += 16;
mapId = _mazeData[_mazeDataIndex]._surroundingMazes._south;
}
_mazeDataIndex = 0;
while (_mazeData[_mazeDataIndex]._mazeId != mapId)
++_mazeDataIndex;
}
// Handle map changing to the east or west as necessary
if (pos.x & 16) {
if (pos.x >= 0) {
pos.x -= 16;
mapId = _mazeData[_mazeDataIndex]._surroundingMazes._east;
} else {
pos.x += 16;
mapId = _mazeData[_mazeDataIndex]._surroundingMazes._west;
}
_mazeDataIndex = 0;
while (_mazeData[_mazeDataIndex]._mazeId != mapId)
++_mazeDataIndex;
}
// Get the cell flags
const MazeCell &cell = _mazeData[_mazeDataIndex]._cells[pos.y][pos.x];
_currentGrateUnlocked = cell._flags & OUTFLAG_GRATE;
_currentCantRest = cell._flags & RESTRICTION_REST;
_currentIsDrain = cell._flags & OUTFLAG_DRAIN;
_currentIsEvent = cell._flags & FLAG_AUTOEXECUTE_EVENT;
_currentSky = (cell._flags & OUTFLAG_OBJECT_EXISTS) ? 1 : 0;
_currentMonsterFlags = cell._flags & 7;
}
void Map::setCellSurfaceFlags(const Common::Point &pt, int bits) {
mazeLookup(pt, 0);
Common::Point mapPos(pt.x & 15, pt.y & 15);
MazeCell &cell = _mazeData[_mazeDataIndex]._cells[mapPos.y][mapPos.x];
cell._flags |= bits & 0xF8;
}
void Map::setWall(const Common::Point &pt, Direction dir, int v) {
const int XOR_MASKS[4] = { 0xFFF, 0xF0FF, 0xFF0F, 0xFFF0 };
mazeLookup(pt, 0, 0);
Common::Point mapPos(pt.x & 15, pt.y & 15);
MazeWallLayers &wallLayer = _mazeData[_mazeDataIndex]._wallData[mapPos.y][mapPos.x];
wallLayer._data &= XOR_MASKS[dir];
wallLayer._data |= v << Res.WALL_SHIFTS[dir][2];
}
int Map::getCell(int idx) {
int mapId = _vm->_party->_mazeId;
Direction dir = _vm->_party->_mazeDirection;
Common::Point pt(
_vm->_party->_mazePosition.x + Res.SCREEN_POSITIONING_X[_vm->_party->_mazeDirection][idx],
_vm->_party->_mazePosition.y + Res.SCREEN_POSITIONING_Y[_vm->_party->_mazeDirection][idx]
);
if (pt.x > 31 || pt.y > 31) {
if (_vm->_files->_isDarkCc) {
if ((mapId >= 53 && mapId <= 88 && mapId != 73) || (mapId >= 74 && mapId <= 120) ||
mapId == 125 || mapId == 126 || mapId == 128 || mapId == 129) {
_currentSurfaceId = SURFTYPE_DESERT;
} else {
_currentSurfaceId = 0;
}
} else {
_currentSurfaceId = (mapId >= 25 && mapId <= 27) ? 7 : 0;
}
_currentWall = INVALID_CELL;
return INVALID_CELL;
}
_mazeDataIndex = 0;
while (_mazeData[_mazeDataIndex]._mazeId != mapId)
++_mazeDataIndex;
if (pt.y & 16) {
if (pt.y >= 0) {
pt.y -= 16;
mapId = _mazeData[_mazeDataIndex]._surroundingMazes._north;
} else {
pt.y += 16;
mapId = _mazeData[_mazeDataIndex]._surroundingMazes._south;
}
if (!mapId) {
if (_isOutdoors) {
_currentSurfaceId = SURFTYPE_SPACE;
_currentWall = 0;
return 0;
} else {
if (_vm->_files->_isDarkCc) {
if ((mapId >= 53 && mapId <= 88 && mapId != 73) || (mapId >= 74 && mapId <= 120) ||
mapId == 125 || mapId == 126 || mapId == 128 || mapId == 129) {
_currentSurfaceId = 6;
} else {
_currentSurfaceId = 0;
}
} else {
_currentSurfaceId = (mapId >= 25 && mapId <= 27) ? SURFTYPE_ROAD : SURFTYPE_DEFAULT;
}
_currentWall = INVALID_CELL;
return INVALID_CELL;
}
_mazeDataIndex = 0;
while (_mazeData[_mazeDataIndex]._mazeId != mapId)
++_mazeDataIndex;
}
}
if (pt.x & 16) {
if (pt.x >= 0) {
pt.x -= 16;
mapId = _mazeData[_mazeDataIndex]._surroundingMazes._east;
} else {
pt.x += 16;
mapId = _mazeData[_mazeDataIndex]._surroundingMazes._east;
}
if (!mapId) {
if (_isOutdoors) {
_currentSurfaceId = SURFTYPE_SPACE;
_currentWall = 0;
return 0;
} else {
if (_vm->_files->_isDarkCc) {
if ((mapId >= 53 && mapId <= 88 && mapId != 73) || (mapId >= 74 && mapId <= 120) ||
mapId == 125 || mapId == 126 || mapId == 128 || mapId == 129) {
_currentSurfaceId = 6;
} else {
_currentSurfaceId = 0;
}
} else {
_currentSurfaceId = (mapId >= 25 && mapId <= 27) ? SURFTYPE_ROAD : SURFTYPE_DEFAULT;
}
_currentWall = INVALID_CELL;
return INVALID_CELL;
}
}
_mazeDataIndex = 0;
while (_mazeData[_mazeDataIndex]._mazeId != mapId)
++_mazeDataIndex;
}
int wallData = _mazeData[_mazeDataIndex]._wallData[pt.y][pt.x]._data;
if (_isOutdoors) {
if (mapId) {
// TODO: tile is set to word of (wallLayers >> 8) && 0xff? Makes no sense
_currentTile = (wallData >> 8) & 0xFF;
_currentWall = (wallData >> 4) & 0xF;
_currentSurfaceId = wallData & 0xF;
} else {
_currentSurfaceId = SURFTYPE_DEFAULT;
_currentWall = 0;
_currentTile = 0;
}
} else {
if (!mapId)
return 0;
if (pt.x > 31 || pt.y > 31)
_currentSurfaceId = 7;
else
_currentSurfaceId = _mazeData[_mazeDataIndex]._cells[pt.y][pt.x]._surfaceId;
_currentWall = wallData;
return (_currentWall >> Res.WALL_SHIFTS[dir][idx]) & 0xF;
}
return _currentWall;
}
void Map::loadSky() {
Party &party = *_vm->_party;
party._isNight = party._minutes < (5 * 60) || party._minutes >= (21 * 60);
_skySprites[0].load(((party._mazeId >= 89 && party._mazeId <= 112) ||
party._mazeId == 128 || party._mazeId == 129) || !party._isNight
? "sky.sky" : "night.sky");
}
void Map::getNewMaze() {
Party &party = *_vm->_party;
Common::Point pt = party._mazePosition;
int mapId = party._mazeId;
// Get the correct map to use from the cached list
_mazeDataIndex = 0;
while (_mazeData[_mazeDataIndex]._mazeId == mapId)
++_mazeDataIndex;
// Adjust Y and X to be in the 0-15 range, and on the correct surrounding
// map if either value is < 0 or >= 16
if (pt.y & 16) {
if (pt.y >= 0) {
pt.y -= 16;
mapId = _mazeData[_mazeDataIndex]._surroundingMazes._north;
} else {
pt.y += 16;
mapId = _mazeData[_mazeDataIndex]._surroundingMazes._south;
}
if (mapId) {
_mazeDataIndex = 0;
while (_mazeData[_mazeDataIndex]._mazeId == mapId)
++_mazeDataIndex;
}
}
if (pt.x & 16) {
if (pt.x >= 0) {
pt.x -= 16;
mapId = _mazeData[_mazeDataIndex]._surroundingMazes._east;
} else {
pt.x += 16;
mapId = _mazeData[_mazeDataIndex]._surroundingMazes._west;
}
if (mapId) {
_mazeDataIndex = 0;
while (_mazeData[_mazeDataIndex]._mazeId == mapId)
++_mazeDataIndex;
}
}
// Save the adjusted (0,0)-(15,15) position and load the given map.
// This will make it the new center, with it's own surrounding mazees loaded
party._mazePosition = pt;
if (mapId)
load(mapId);
}
} // End of namespace Xeen