mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-05 17:20:30 +00:00
290 lines
8.3 KiB
C++
290 lines
8.3 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 3 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
|
|
*
|
|
*
|
|
* Based on the original sources
|
|
* Faery Tale II -- The Halls of the Dead
|
|
* (c) 1993-1996 The Wyrmkeep Entertainment Co.
|
|
*/
|
|
|
|
#include "saga2/saga2.h"
|
|
#include "saga2/weapons.h"
|
|
#include "saga2/spelshow.h"
|
|
#include "saga2/spellbuk.h"
|
|
#include "saga2/actor.h"
|
|
#include "saga2/spellio.h"
|
|
#include "saga2/hresmgr.h"
|
|
#include "saga2/combat.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
|
|
//
|
|
|
|
static void loadWeaponData();
|
|
|
|
ProtoEffect *createNewProtoEffect(Common::SeekableReadStream *stream) {
|
|
ProtoEffect *pe = nullptr;
|
|
|
|
/* int16 item = */stream->readSint16LE(); // spell ID
|
|
int16 effectGroup = stream->readSint16LE(); // effect group
|
|
|
|
int16 effectType = stream->readSint16LE(); // effect ID
|
|
int16 targeting = stream->readSint16LE(); // targeting
|
|
int16 baseDice = stream->readSint16LE(); // base dice
|
|
int16 skillDice = stream->readSint16LE(); // skill dice
|
|
int16 baseDamage = stream->readSint16LE(); // attrib change
|
|
int16 skillDamage = stream->readSint16LE(); // attrib change
|
|
int16 reserved0 = stream->readSint16LE(); // min enchant
|
|
int16 reserved1 = stream->readSint16LE(); // min enchant
|
|
int16 diceSides = stream->readSint16LE();
|
|
|
|
if (diceSides == 0)
|
|
diceSides = 6;
|
|
|
|
switch (effectGroup) {
|
|
case kEffectNone:
|
|
return nullptr;
|
|
|
|
case kEffectAttrib:
|
|
pe = new ProtoEnchantment(makeEnchantmentID(effectGroup, effectType, baseDamage), reserved0, reserved1);
|
|
break;
|
|
|
|
case kEffectResist:
|
|
case kEffectImmune:
|
|
case kEffectOthers:
|
|
case kEffectNonActor:
|
|
pe = new ProtoEnchantment(makeEnchantmentID(effectGroup, effectType, skillDamage), reserved0, reserved1);
|
|
break;
|
|
|
|
case kEffectDamage:
|
|
pe = new ProtoDamage(baseDice, diceSides, skillDice, baseDamage,
|
|
(effectDamageTypes)effectType, 0, targeting & kSpellTargCaster, skillDamage);
|
|
break;
|
|
|
|
case kEffectDrains:
|
|
pe = new ProtoDrainage(baseDice, diceSides, skillDice, baseDamage,
|
|
(effectDrainsTypes)effectType, 0, targeting & kSpellTargCaster);
|
|
break;
|
|
|
|
case kEffectPoison:
|
|
pe = new ProtoEnchantment(makeEnchantmentID(baseDamage), // poison
|
|
reserved0, reserved1);
|
|
break;
|
|
|
|
case kEffectTAG:
|
|
pe = new ProtoTAGEffect((effectTAGTypes)effectType, skillDamage, baseDamage);
|
|
break;
|
|
|
|
case kEffectLocation:
|
|
pe = new ProtoLocationEffect((kEffectLocationTypes)effectType, baseDamage);
|
|
break;
|
|
|
|
case kEffectSpecial:
|
|
pe = new ProtoSpecialEffect(SagaSpellCall, baseDamage);
|
|
break;
|
|
}
|
|
|
|
if (pe == nullptr)
|
|
error("failed to alloc protoEffect");
|
|
|
|
return pe;
|
|
}
|
|
|
|
void initWeapons() {
|
|
loadWeaponData();
|
|
}
|
|
|
|
void cleanupWeapons() {
|
|
for (int i = 0; i < kMaxWeapons; i++)
|
|
g_vm->_weaponRack[i].killEffects();
|
|
}
|
|
|
|
WeaponStuff &getWeapon(weaponID i) {
|
|
if (i < g_vm->_loadedWeapons)
|
|
return g_vm->_weaponRack[i];
|
|
return g_vm->_weaponRack[kNullWeapon];
|
|
}
|
|
|
|
GameObject *getShieldItem(GameObject *defender) {
|
|
assert(isActor(defender));
|
|
Actor *a = (Actor *) defender;
|
|
GameObject *obj;
|
|
|
|
a->defensiveObject(&obj);
|
|
return obj;
|
|
}
|
|
|
|
/* ===================================================================== *
|
|
WeaponProtoEffect member functions
|
|
* ===================================================================== */
|
|
WeaponProtoEffect::~WeaponProtoEffect() {
|
|
if (_effect != nullptr)
|
|
delete _effect;
|
|
}
|
|
|
|
void WeaponProtoEffect::implement(Actor *enactor, GameObject *target, GameObject *, uint8) {
|
|
SpellTarget targ(target);
|
|
|
|
if (_effect != nullptr)
|
|
_effect->implement(enactor, &targ);
|
|
}
|
|
|
|
/* ===================================================================== *
|
|
WeaponStrikeEffect member functions
|
|
* ===================================================================== */
|
|
void WeaponStrikeEffect::implement(Actor *enactor, GameObject *target, GameObject *strikingObj, uint8 strength) {
|
|
assert(isActor(enactor));
|
|
assert(isObject(target) || isActor(target));
|
|
assert(isObject(strikingObj) || isActor(strikingObj));
|
|
|
|
int8 totalDice, totalBase;
|
|
|
|
totalDice = _dice + strength * _skillDice;
|
|
totalBase = _base + strength * _skillBase;
|
|
|
|
target->acceptDamage(enactor->thisID(), totalBase, _type, totalDice, _sides);
|
|
}
|
|
|
|
WeaponStuff::WeaponStuff() {
|
|
_effects = nullptr;
|
|
_master = kNullWeapon;
|
|
}
|
|
|
|
WeaponStuff::~WeaponStuff() {
|
|
while (_effects != nullptr) {
|
|
WeaponEffect *curEffect = _effects;
|
|
|
|
_effects = _effects->_next;
|
|
delete curEffect;
|
|
}
|
|
_master = kNullWeapon;
|
|
}
|
|
|
|
void WeaponStuff::killEffects() {
|
|
while (_effects != nullptr) {
|
|
WeaponEffect *curEffect = _effects;
|
|
|
|
_effects = _effects->_next;
|
|
delete curEffect;
|
|
}
|
|
}
|
|
|
|
void WeaponStuff::addEffect(WeaponEffect *we) {
|
|
WeaponEffect *e = _effects;
|
|
if (_effects) {
|
|
while (e->_next)
|
|
e = e->_next;
|
|
e->_next = we;
|
|
} else {
|
|
_effects = we;
|
|
}
|
|
}
|
|
|
|
void WeaponStuff::addEffect(Common::SeekableReadStream *stream) {
|
|
WeaponEffect *we;
|
|
|
|
/*int16 item = */stream->readSint16LE(); // spell ID
|
|
int16 effectGroup = stream->readSint16LE(); // effect group
|
|
|
|
if (effectGroup == kEffectStrike) {
|
|
effectDamageTypes effectType = (effectDamageTypes)stream->readSint16LE(); // effect ID
|
|
/*int16 targeting = */stream->readSint16LE(); // targeting
|
|
int16 baseDice = stream->readSint16LE(); // base dice
|
|
int16 skillDice = stream->readSint16LE(); // skill dice
|
|
int16 baseDamage = stream->readSint16LE(); // attrib change
|
|
int16 skillDamage = stream->readSint16LE(); // attrib change
|
|
/*int16 reserved0 = */stream->readSint16LE(); // min enchant
|
|
/* int16 reserved1 = */stream->readSint16LE(); // min enchant
|
|
int16 diceSides = stream->readSint16LE();
|
|
|
|
if (diceSides == 0)
|
|
diceSides = 6;
|
|
|
|
we = new WeaponStrikeEffect(effectType, baseDice, diceSides, skillDice, baseDamage, skillDamage);
|
|
} else {
|
|
stream->seek(0);
|
|
we = new WeaponProtoEffect(stream);
|
|
}
|
|
|
|
if (we == nullptr)
|
|
error("failed to alloc weapon effect");
|
|
|
|
if (_effects == nullptr)
|
|
_effects = we;
|
|
else {
|
|
WeaponEffect *tail;
|
|
for (tail = _effects; tail->_next; tail = tail->_next)
|
|
;
|
|
tail->_next = we;
|
|
}
|
|
}
|
|
|
|
void WeaponStuff::implement(Actor *enactor, GameObject *target, GameObject *strikingObj, uint8 strength) {
|
|
for (WeaponEffect *we = _effects; we != nullptr; we = we->_next)
|
|
we->implement(enactor, target, strikingObj, strength);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
static void loadWeaponData() {
|
|
hResContext *spellRes = auxResFile->newContext(MKTAG('I', 'T', 'E', 'M'), "weapon resources");
|
|
if (spellRes == nullptr || !spellRes->_valid)
|
|
error("Error accessing weapon resource group.");
|
|
|
|
debugC(1, kDebugLoading, "Loading Weapon Data");
|
|
|
|
// get spell effects
|
|
int16 i = 0;
|
|
while (spellRes->size(MKTAG('E', 'F', 'F', i)) > 0) {
|
|
Common::SeekableReadStream *stream = loadResourceToStream(spellRes, MKTAG('E', 'F', 'F', i), "weapon effect");
|
|
|
|
if (stream == nullptr)
|
|
error("Unable to load weapon effect %d", i);
|
|
|
|
int16 id = stream->readSint16LE();
|
|
stream->seek(0);
|
|
|
|
if (id) {
|
|
g_vm->_weaponRack[id].setID(id);
|
|
g_vm->_weaponRack[id].addEffect(stream);
|
|
}
|
|
|
|
delete stream;
|
|
|
|
i++;
|
|
}
|
|
g_vm->_loadedWeapons = i;
|
|
assert(i > 1);
|
|
|
|
debugC(1, kDebugLoading, "Loading Weapon Data, loaded %d entries", i);
|
|
|
|
auxResFile->disposeContext(spellRes);
|
|
}
|
|
|
|
} // end of namespace Saga2
|