scummvm/engines/saga2/speldata.cpp

263 lines
11 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
* aint32 with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
* Based on the original sources
* Faery Tale II -- The Halls of the Dead
* (c) 1993-1996 The Wyrmkeep Entertainment Co.
*/
#include "saga2/std.h"
#include "saga2/objproto.h"
#include "saga2/spellbuk.h"
#include "saga2/spelshow.h"
#include "saga2/spellio.h"
#include "saga2/hresmgr.h"
namespace Saga2 {
//-------------------------------------------------------------------
// The initialization for spells is done in this module:
// - Display Effects are defined (ball spell, bolt spell, etc)
// - The spell definitions are loaded from the resource file
// - The spell internal effect definitions are loaded from disk
// and attached to the appropriate spell
// - Spell Color maps are loaded from the resource file
// - This file is also home to most of the global variables
// which relate to spell casting
//
/* ===================================================================== *
Constants
* ===================================================================== */
const uint32 spellSpriteID = MKTAG('S', 'P', 'F', 'X');
const int32 maxSpells = totalSpellBookPages;
const int32 maxSpellPrototypes = totalSpellBookPages;
const int32 maxEffectPrototypes = 16;
const int32 maxSpellColorMaps = 32;
/* const */ // For some reason, MVC can't handle constant static classes.
// ( Note: It would be better to use a SIN/COS table anyway than
// a table of points, since that allows more than 24 directions ).
TilePoint WallVectors[8] = {
TilePoint(2, 0, 0), TilePoint(1, 1, 0), TilePoint(0, 2, 0),
TilePoint(-1, 2, 0), TilePoint(-2, 0, 0), TilePoint(-1, -1, 0),
TilePoint(0, -2, 0), TilePoint(1, -1, 0)
};
TilePoint FireballVectors[24] = {
TilePoint(4, 0, 0), TilePoint(4, 1, 0), TilePoint(3, 2, 0),
TilePoint(3, 3, 0), TilePoint(2, 3, 0), TilePoint(1, 4, 0),
TilePoint(0, 4, 0), TilePoint(-1, 4, 0), TilePoint(-2, 3, 0),
TilePoint(-3, 3, 0), TilePoint(-3, 2, 0), TilePoint(-4, 1, 0),
TilePoint(-4, 0, 0), TilePoint(-4, -1, 0), TilePoint(-3, -2, 0),
TilePoint(-3, -3, 0), TilePoint(-2, -3, 0), TilePoint(-1, -4, 0),
TilePoint(0, -4, 0), TilePoint(1, -4, 0), TilePoint(2, -3, 0),
TilePoint(3, -3, 0), TilePoint(3, -2, 0), TilePoint(4, -1, 0)
};
TilePoint SquareSpellVectors[32] = {
TilePoint(4, 0, 0), TilePoint(4, 1, 0), TilePoint(4, 2, 0), TilePoint(4, 3, 0),
TilePoint(4, 4, 0), TilePoint(3, 4, 0), TilePoint(2, 4, 0), TilePoint(1, 4, 0),
TilePoint(0, 4, 0), TilePoint(-1, 4, 0), TilePoint(-2, 4, 0), TilePoint(-3, 4, 0),
TilePoint(-4, 4, 0), TilePoint(-4, 3, 0), TilePoint(-4, 2, 0), TilePoint(-4, 1, 0),
TilePoint(-4, 0, 0), TilePoint(-4, -1, 0), TilePoint(-4, -2, 0), TilePoint(-4, -3, 0),
TilePoint(-4, -4, 0), TilePoint(-3, -4, 0), TilePoint(-2, -4, 0), TilePoint(-1, -4, 0),
TilePoint(0, -4, 0), TilePoint(1, -4, 0), TilePoint(2, -4, 0), TilePoint(3, -4, 0),
TilePoint(4, -4, 0), TilePoint(4, -3, 0), TilePoint(4, -2, 0), TilePoint(4, -1, 0)
};
/* ===================================================================== *
Imports
* ===================================================================== */
extern hResContext *spriteRes; // sprite resource handle
extern hResContext *schemeRes; // sprite resource handle
extern ColorTable identityColors;
extern SpellDisplayList activeSpells;
/* ===================================================================== *
Global data
* ===================================================================== */
EffectDisplayPrototypeList EffectDisplayPrototypeList::edpList(maxEffectPrototypes);
SpellDisplayPrototypeList SpellDisplayPrototypeList::sdpList(maxSpellPrototypes);
SpriteSet *spellSprites; // longsword test sprites
SpellStuff spellBook[maxSpells];
ColorTable spellColorMaps[maxSpellColorMaps];
ColorSchemeList *spellSchemes;
int32 loadedColorMaps;
/* ===================================================================== *
prototypes
* ===================================================================== */
static void defineEffects(void);
static void loadMagicData(void);
/* ===================================================================== *
code
* ===================================================================== */
//-----------------------------------------------------------------------
// InitMagic called from main startup code
void initMagic(void) {
defineEffects();
loadMagicData();
const int colorSchemeSize = 44;
Common::SeekableReadStream *stream;
stream = loadResourceToStream(spriteRes, spellSpriteID, "spell sprites");
spellSprites = new SpriteSet(stream);
assert(spellSprites);
delete stream;
loadedColorMaps = schemeRes->size(spellSpriteID) / colorSchemeSize;
stream = loadResourceToStream(schemeRes, spellSpriteID, "scheme list");
spellSchemes = new ColorSchemeList(loadedColorMaps, stream);
assert(spellSchemes);
delete stream;
}
void cleanupMagic(void) {
activeSpells.cleanup();
for (int i = 0; i < maxSpells; i++) {
spellBook[i].killEffects();
}
SpellDisplayPrototypeList::sdpList.cleanup();
EffectDisplayPrototypeList::edpList.cleanup();
}
/* ===================================================================== *
Effect data
* ===================================================================== */
//-----------------------------------------------------------------------
// the macros make things more legible than the entire call
// Set up a display effect shape
#define ADD_EFFECT( n, p, s, f, h, b, i ) ( EffectDisplayPrototypeList::edpList.add( new EffectDisplayPrototype(n,&p,&s,&f,&h,&b,&i )))
// Chain another effect when done
#define SECOND_EFFECT( e, n, p, s, f, h, b, i ) ( EffectDisplayPrototypeList::edpList.append( new EffectDisplayPrototype(n,&p,&s,&f,&h,&b,&i ),e))
//-----------------------------------------------------------------------
static void defineEffects(void) {
int16 i;
ADD_EFFECT(1, invisibleSpellPos, invisibleSprites, invisibleSpellSta, ShortTillThere, ThinTillThere, invisibleSpellInit);
ADD_EFFECT(1, auraSpellPos, auraSprites, auraSpellSta, ShortTillThere, ThinTillThere, auraSpellInit);
ADD_EFFECT(1, projectileSpellPos, projectileSprites, projectileSpellSta, StaticHeight, StaticBreadth, projectileSpellInit);
ADD_EFFECT(12, exchangeSpellPos, exchangeSprites, exchangeSpellSta, StaticHeight, StaticBreadth, exchangeSpellInit);
ADD_EFFECT(36, boltSpellPos, boltSprites, boltSpellSta, StaticHeight, StaticBreadth, boltSpellInit);
ADD_EFFECT(24, coneSpellPos, coneSprites, coneSpellSta, GrowLinear, BulkLinear, coneSpellInit);
i = ADD_EFFECT(1, projectileSpellPos, projectileSprites, projectileSpellSta, StaticHeight, StaticBreadth, projectileSpellInit);
SECOND_EFFECT(i, 24, ballSpellPos, ballSprites, ballSpellSta, ShortTillThere, ThinTillThere, ballSpellInit);
i = ADD_EFFECT(1, projectileSpellPos, projectileSprites, projectileSpellSta, StaticHeight, StaticBreadth, projectileSpellInit);
SECOND_EFFECT(i, 32, squareSpellPos, squareSprites, squareSpellSta, StaticHeight, StaticBreadth, squareSpellInit);
ADD_EFFECT(24, waveSpellPos, waveSprites, waveSpellSta, GrowLinear, BulkLinear, waveSpellInit);
i = ADD_EFFECT(1, projectileSpellPos, projectileSprites, projectileSpellSta, StaticHeight, StaticBreadth, projectileSpellInit);
SECOND_EFFECT(i, 24, stormSpellPos, stormSprites, stormSpellSta, ShortTillThere, ThinTillThere, stormSpellInit);
i = ADD_EFFECT(1, projectileSpellPos, projectileSprites, projectileSpellSta, StaticHeight, StaticBreadth, projectileSpellInit);
SECOND_EFFECT(i, 1, glowSpellPos, auraSprites, auraSpellSta, ShortTillThere, ThinTillThere, glowSpellInit);
ADD_EFFECT(1, glowSpellPos, auraSprites, auraSpellSta, ShortTillThere, ThinTillThere, glowSpellInit);
ADD_EFFECT(20, beamSpellPos, beamSprites, beamSpellSta, StaticHeight, StaticBreadth, beamSpellInit);
ADD_EFFECT(8, wallSpellPos, wallSprites, wallSpellSta, StaticHeight, StaticBreadth, wallSpellInit);
}
//-----------------------------------------------------------------------
#define ADD_SHOW( e, a, b, c, d, f, g, m, i, s, n ) ( SpellDisplayPrototypeList::sdpList.add( new SpellDisplayPrototype( e, a, b, c, d, f, g, m, i, s, n )))
//-----------------------------------------------------------------------
// loadMagicData : reads magic related data from the resource file
static void loadMagicData(void) {
int16 i;
hResContext *spellRes;
// Get spell definitions
spellRes = auxResFile->newContext(
MKTAG('S', 'P', 'E', 'L'),
"spell resources");
if (spellRes == NULL || !spellRes->_valid)
error("Error accessing spell resource group.\n");
i = 1;
ADD_SHOW(eAreaInvisible, 0, 0, 0, 0, diFlagInc, ecFlagNone, 30, MKTAG('S', 'T', 'A', 0), 23, 24);
spellBook[0].setManaType(sManaIDSkill);
while (spellRes->size(
MKTAG('I', 'N', 'F', i)) > 0) {
ResourceSpellItem *rsi =
(ResourceSpellItem *)LoadResource(
spellRes,
MKTAG('I', 'N', 'F', i),
"spell");
if (rsi == NULL)
error("Unable to load data for spell %d", i);
spellBook[rsi->spell].setupFromResource(rsi);
SpellDisplayPrototypeList::sdpList.add(new SpellDisplayPrototype(rsi));
RDisposePtr(rsi);
i++;
}
assert(i > 1);
// get spell effects
i = 0;
while (spellRes->size(
MKTAG('E', 'F', 'F', i)) > 0) {
ResourceSpellEffect *rse =
(ResourceSpellEffect *)LoadResource(
spellRes,
MKTAG('E', 'F', 'F', i),
"spell effect");
if (rse == NULL)
error("Unable to load effects for spell %d", i);
if (rse->spell)
spellBook[rse->spell].addEffect(rse);
RDisposePtr(rse);
i++;
}
assert(i > 1);
// get spell color maps
memcpy(spellColorMaps[0], identityColors, sizeof(ColorTable));
auxResFile->disposeContext(spellRes);
}
} // end of namespace Saga2