1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

[Spells] Added basic support for icons and sounds

* few changes in spell format
* save format changed
This commit is contained in:
alexvins 2014-03-10 16:00:58 +00:00
parent 9f01a92f4c
commit 065b8366fb
22 changed files with 404 additions and 501 deletions

View File

@ -9,8 +9,10 @@ ADVENTURE MAP:
BATTLES:
SPELLS:
* New configuration format: http://wiki.vcmi.eu/index.php?title=Spell_Format
MODS:
* Mods cas now add new (offensive, buffs, debuffs) spells and change existing
0.94 -> 0.95 (Mar 01 2014)
GENERAL:

View File

@ -185,6 +185,7 @@ void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode *
{
creatureArtifact = nullptr; //may be set later
artifactImage = nullptr;
spellEffectsPics = nullptr;
stack = Stack;
c = stack->type;
if(!StackNode)
@ -411,28 +412,35 @@ void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode *
passArtToHero = new CAdventureMapButton(std::string(), std::string(), boost::bind (&CCreatureWindow::passArtifactToHero, this), 437, 148, "OVBUTN1.DEF", SDLK_HOME);
}
}
if (battleStack) //only during battle
{
spellEffectsPics = new CAnimation("SpellInt.def");
//spell effects
int printed=0; //how many effect pics have been printed
std::vector<si32> spells = battleStack->activeSpells();
for(si32 effect : spells)
{
const si32 imageIndex = effect+1; //there is "null" frame with index 0 in SpellInt.def
std::string spellText;
if (effect < graphics->spellEffectsPics->ourImages.size()) //not all effects have graphics (for eg. Acid Breath)
spellEffectsPics->load(imageIndex);
IImage * effectIcon = spellEffectsPics->getImage(imageIndex,0,false); //todo: better way to determine presence of icon
spellEffectsPics->unload(imageIndex);
if (effectIcon != nullptr) //not all effects have graphics (for eg. Acid Breath)
{
spellText = CGI->generaltexth->allTexts[610]; //"%s, duration: %d rounds."
boost::replace_first (spellText, "%s", CGI->spellh->objects[effect]->name);
int duration = battleStack->getBonusLocalFirst(Selector::source(Bonus::SPELL_EFFECT,effect))->turnsRemain;
boost::replace_first (spellText, "%d", boost::lexical_cast<std::string>(duration));
new CAnimImage("SpellInt", effect + 1, 0, 20 + 52 * printed, 184);
new CAnimImage("SpellInt.def", imageIndex, 0, 20 + 52 * printed, 184);
spellEffects.push_back(new LRClickableAreaWText(Rect(20 + 52 * printed, 184, 50, 38), spellText, spellText));
if (++printed >= 10) //we can fit only 10 effects
break;
}
}
//print current health
printLine (5, CGI->generaltexth->allTexts[200], battleStack->firstHPleft);
}
@ -689,6 +697,9 @@ CCreatureWindow::~CCreatureWindow()
for (auto & elem : upgResCost)
delete elem;
bonusItems.clear();
if(spellEffectsPics!=nullptr)
delete spellEffectsPics;
}
CBonusItem::CBonusItem()

View File

@ -65,7 +65,8 @@ public:
CAdventureMapButton *dismiss, *upgrade, *ok;
CAdventureMapButton * leftArtRoll, * rightArtRoll; //artifact selection
CAdventureMapButton * passArtToHero;
CAnimImage *artifactImage;
CAnimImage * artifactImage;
CAnimation * spellEffectsPics; //bitmaps representing spells affecting a stack in battle
//commander level-up
int selectedOption; //index for upgradeOptions

View File

@ -145,7 +145,7 @@ void init()
loadDLLClasses();
const_cast<CGameInfo*>(CGI)->setFromLib();
CCS->soundh->initSpellsSounds(CGI->spellh->objects);
logGlobal->infoStream()<<"Initializing VCMI_Lib: "<<tmh.getDiff();
pomtime.getDiff();

View File

@ -177,28 +177,6 @@ Mix_Chunk *CSoundHandler::GetSoundChunk(std::string &sound)
}
}
void CSoundHandler::initSpellsSounds(const std::vector< ConstTransitivePtr<CSpell> > &spells)
{
const JsonNode config(ResourceID("config/sp_sounds.json"));
if (!config["spell_sounds"].isNull())
{
for(const JsonNode &node : config["spell_sounds"].Vector())
{
int spellid = node["id"].Float();
const CSpell *s = CGI->spellh->objects[spellid];
if (vstd::contains(spellSounds, s))
logGlobal->errorStream() << "Spell << " << spellid << " already has a sound";
std::string sound = node["soundfile"].String();
if (sound.empty())
logGlobal->errorStream() << "Error: invalid sound for id "<< spellid;
spellSounds[s] = sound;
}
}
}
// Plays a sound, and return its channel so we can fade it out later
int CSoundHandler::playSound(soundBase::soundID soundID, int repeats)
{

View File

@ -57,7 +57,6 @@ public:
void init();
void release();
void initSpellsSounds(const std::vector< ConstTransitivePtr<CSpell> > &spells);
void setVolume(ui32 percent);
// Sounds
@ -69,8 +68,6 @@ public:
void setCallback(int channel, std::function<void()> function);
void soundFinishedCallback(int channel);
std::map<const CSpell*, std::string> spellSounds;
// Sets
std::vector<soundBase::soundID> pickupSounds;
std::vector<soundBase::soundID> horseSounds;

View File

@ -2203,8 +2203,10 @@ void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellI
eraseCurrentPathOf(caster, false);
}
const CSpell * spell = CGI->spellh->objects[spellID];
if (vstd::contains(CCS->soundh->spellSounds, spell))
CCS->soundh->playSound(CCS->soundh->spellSounds[spell]);
auto castSoundPath = spell->getCastSound();
if (!castSoundPath.empty())
CCS->soundh->playSound(castSoundPath);
}
void CPlayerInterface::eraseCurrentPathOf( const CGHeroInstance * ho, bool checkForExistanceOfPath /*= true */ )

View File

@ -147,7 +147,9 @@ CSpellWindow::CSpellWindow(const SDL_Rect &, const CGHeroInstance * _myHero, CPl
leftCorner = BitmapHandler::loadBitmap("SpelTrnL.bmp", true);
rightCorner = BitmapHandler::loadBitmap("SpelTrnR.bmp", true);
spells = CDefHandler::giveDef("Spells.def");
spells = new CAnimation("Spells.def");
spellTab = CDefHandler::giveDef("SpelTab.def");
schools = CDefHandler::giveDef("Schools.def");
schoolBorders[0] = CDefHandler::giveDef("SplevA.def");
@ -222,6 +224,7 @@ CSpellWindow::~CSpellWindow()
{
SDL_FreeSurface(leftCorner);
SDL_FreeSurface(rightCorner);
spells->unload();
delete spells;
delete spellTab;
delete schools;
@ -775,7 +778,7 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[124]);
else
GH.pushInt (new CObjectListWindow(availableTowns,
new CPicture(graphics->spellscr->ourImages[spell].bitmap, 0, 0, false),
new CAnimImage("SPELLSCR",spell),
CGI->generaltexth->jktexts[40], CGI->generaltexth->jktexts[41],
boost::bind (&CSpellWindow::teleportTo, owner, _1, h)));
}
@ -835,9 +838,16 @@ void CSpellWindow::SpellArea::showAll(SDL_Surface * to)
if(mySpell < 0)
return;
const CSpell * spell = mySpell.toSpell();
const CSpell * spell = mySpell.toSpell();
owner->spells->load(mySpell);
IImage * icon = owner->spells->getImage(mySpell,0,false);
if(icon != nullptr)
icon->draw(to, pos.x, pos.y);
else
logGlobal->errorStream() << __FUNCTION__ << ": failed to load spell icon for spell with id " << mySpell;
blitAt(owner->spells->ourImages[mySpell].bitmap, pos.x, pos.y, to);
blitAt(owner->schoolBorders[owner->selectedTab >= 4 ? whichSchool : owner->selectedTab]->ourImages[schoolLevel].bitmap, pos.x, pos.y, to); //printing border (indicates level of magic school)
SDL_Color firstLineColor, secondLineColor;

View File

@ -51,6 +51,7 @@ private:
int spellCost;
CSpellWindow * owner;
SpellArea(SDL_Rect pos, CSpellWindow * owner);
void setSpell(SpellID spellID);
@ -62,8 +63,10 @@ private:
};
SDL_Surface * leftCorner, * rightCorner;
CDefHandler * spells, //pictures of spells
* spellTab, //school select
CAnimation * spells; //pictures of spells
CDefHandler * spellTab, //school select
* schools, //schools' pictures
* schoolBorders [4]; //schools' 'borders': [0]: air, [1]: fire, [2]: water, [3]: earth

View File

@ -1841,7 +1841,7 @@ void CObjectListWindow::CItem::clickLeft(tribool down, bool previousState)
parent->changeSelection(index);
}
CObjectListWindow::CObjectListWindow(const std::vector<int> &_items, CPicture * titlePic, std::string _title, std::string _descr,
CObjectListWindow::CObjectListWindow(const std::vector<int> &_items, CIntObject * titlePic, std::string _title, std::string _descr,
std::function<void(int)> Callback):
CWindowObject(PLAYER_COLORED, "TPGATE"),
onSelect(Callback)
@ -1855,7 +1855,7 @@ CObjectListWindow::CObjectListWindow(const std::vector<int> &_items, CPicture *
init(titlePic, _title, _descr);
}
CObjectListWindow::CObjectListWindow(const std::vector<std::string> &_items, CPicture * titlePic, std::string _title, std::string _descr,
CObjectListWindow::CObjectListWindow(const std::vector<std::string> &_items, CIntObject * titlePic, std::string _title, std::string _descr,
std::function<void(int)> Callback):
CWindowObject(PLAYER_COLORED, "TPGATE"),
onSelect(Callback)
@ -1868,7 +1868,7 @@ CObjectListWindow::CObjectListWindow(const std::vector<std::string> &_items, CPi
init(titlePic, _title, _descr);
}
void CObjectListWindow::init(CPicture * titlePic, std::string _title, std::string _descr)
void CObjectListWindow::init(CIntObject * titlePic, std::string _title, std::string _descr)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;

View File

@ -537,21 +537,21 @@ class CObjectListWindow : public CWindowObject
CLabel * title;
CLabel * descr;
CListBox *list;
CPicture *titleImage;//title image (castle gate\town portal picture)
CListBox * list;
CIntObject * titleImage;//title image (castle gate\town portal picture)
CAdventureMapButton *ok, *exit;
std::vector< std::pair<int, std::string> > items;//all items present in list
void init(CPicture * titlePic, std::string _title, std::string _descr);
void init(CIntObject * titlePic, std::string _title, std::string _descr);
public:
size_t selected;//index of currently selected item
/// Callback will be called when OK button is pressed, returns id of selected item. initState = initially selected item
/// Image can be nullptr
///item names will be taken from map objects
CObjectListWindow(const std::vector<int> &_items, CPicture * titlePic, std::string _title, std::string _descr,
CObjectListWindow(const std::vector<int> &_items, CIntObject * titlePic, std::string _title, std::string _descr,
std::function<void(int)> Callback);
CObjectListWindow(const std::vector<std::string> &_items, CPicture * titlePic, std::string _title, std::string _descr,
CObjectListWindow(const std::vector<std::string> &_items, CIntObject * titlePic, std::string _title, std::string _descr,
std::function<void(int)> Callback);
CIntObject *genItem(size_t index);

View File

@ -17,12 +17,14 @@
#include "../lib/CCreatureHandler.h"
#include "CBitmapHandler.h"
#include "../lib/CObjectHandler.h"
#include "../lib/CSpellHandler.h"
#include "../lib/CDefObjInfoHandler.h"
#include "../lib/CGameState.h"
#include "../lib/JsonNode.h"
#include "../lib/vcmi_endian.h"
#include "../lib/GameConstants.h"
#include "../lib/CStopWatch.h"
#include "CAnimation.h"
using namespace boost::assign;
using namespace CSDL_Ext;
@ -115,9 +117,7 @@ void Graphics::initializeBattleGraphics()
}
battleACToDef[ACid] = toAdd;
}
spellEffectsPics = CDefHandler::giveDefEss("SpellInt.def");
}
}
Graphics::Graphics()
{
@ -128,8 +128,7 @@ Graphics::Graphics()
tasks += boost::bind(&Graphics::initializeBattleGraphics,this);
tasks += boost::bind(&Graphics::loadErmuToPicture,this);
tasks += boost::bind(&Graphics::initializeImageLists,this);
tasks += GET_DEF_ESS(resources32,"RESOURCE.DEF");
tasks += GET_DEF_ESS(spellscr,"SPELLSCR.DEF");
tasks += GET_DEF_ESS(resources32,"RESOURCE.DEF");
tasks += GET_DEF_ESS(heroMoveArrows,"ADAG.DEF");
CThreadHelper th(&tasks,std::max((ui32)1,boost::thread::hardware_concurrency()));
@ -411,4 +410,12 @@ void Graphics::initializeImageLists()
addImageListEntry(info.icons[1][1] + 2, "ITPA", info.iconSmall[1][1]);
}
}
for(const CSpell * spell : CGI->spellh->objects)
{
addImageListEntry(spell->id, "SPELLS", spell->iconBook);
addImageListEntry(spell->id+1, "SPELLINT", spell->iconEffect);
addImageListEntry(spell->id, "SPELLBON", spell->iconScenarioBonus);
addImageListEntry(spell->id, "SPELLSCR", spell->iconScroll);
}
}

View File

@ -26,6 +26,7 @@ struct InfoAboutHero;
struct InfoAboutTown;
class CGObjectInstance;
class ObjectTemplate;
class CAnimation;
enum EFonts
{
@ -41,7 +42,7 @@ public:
//Fonts
static const int FONTS_NUMBER = 9;
IFont * fonts[FONTS_NUMBER];
\
//various graphics
SDL_Color * playerColors; //array [8]
SDL_Color * neutralColor;
@ -66,9 +67,6 @@ public:
//for battles
std::vector< std::vector< std::string > > battleBacks; //battleBacks[terType] - vector of possible names for certain terrain type
std::map< int, std::vector < std::string > > battleACToDef; //maps AC format to vector of appropriate def names
CDefEssential * spellEffectsPics; //bitmaps representing spells affecting a stack in battle
//spells
CDefEssential *spellscr; //spell on the scroll 83x61
//functions
Graphics();
void initializeBattleGraphics();

View File

@ -1230,8 +1230,10 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
std::vector< std::string > anims; //for magic arrow and ice bolt
if (vstd::contains(CCS->soundh->spellSounds, &spell))
CCS->soundh->playSound(CCS->soundh->spellSounds[&spell]);
const std::string& castSoundPath = spell.getCastSound();
if(!castSoundPath.empty())
CCS->soundh->playSound(castSoundPath);
switch(sc->id)
{

View File

@ -1,4 +1,4 @@
{
{
"type":"object",
"$schema": "http://json-schema.org/draft-04/schema",
@ -96,7 +96,7 @@
},
"defaultGainChance":{
"type": "nomber",
"type": "number",
"description": "Gain chance by default for all factions"
},
@ -115,7 +115,7 @@
},
"anim":{
"type": "number",
"description": "Main effect animation (AC format), -1 - none",
"description": "Main effect animation (AC format), -1 - none, deprecated",
"minimum": -1
},
"counters":{
@ -175,14 +175,45 @@
"additionalProperties" : false,
"properties":{
"iconImmune":{
"type":"string",
"description":"Resourse path of icon for SPELL_IMMUNITY bonus (relative to DATA or SPRITES)",
"type": "string",
"description": "Resourse path of icon for SPELL_IMMUNITY bonus (relative to DATA or SPRITES)",
"format" : "imageFile"
},
"iconScenarioBonus":{
"type": "string",
"description": "Resourse path of icon for scenario bonus" ,
"format" : "imageFile"
},
"iconEffect":{
"type": "string",
"description": "Resourse path of icon for spell effects during battle" ,
"format" : "imageFile"
},
"iconBook":{
"type": "string",
"description":"Resourse path of icon for spellbook" ,
"format" : "imageFile"
},
"iconScroll":{
"type": "string",
"description": "Resourse path of icon for spell scrolls",
"format": "imageFile"
}
}
},
"sounds":{
"type": "object",
"additionalProperties" : false,
"properties":{
"cast":{
"type": "string",
"description": "Resourse path of cast sound"
}
}
},
"levels":{
"type": "object",
"additionalProperties" : false,

View File

@ -1,415 +1,3 @@
// Sounds associated with spells
// "name" is not currently used in game
{
"spell_sounds":
[
{
"id": 0 ,
"name":"Summon boat",
"soundfile":"SUMMBOAT.wav"
},
{
"id": 1 ,
"name":"Scuttle boat",
"soundfile":"SCUTBOAT.wav"
},
{
"id": 2 ,
"name":"Visions",
"soundfile":"VISIONS.wav"
},
{
"id": 3 ,
"name":"View Earth",
"soundfile":"VIEW.wav"
},
{
"id": 4 ,
"name":"Disguise",
"soundfile":"DISGUISE.wav"
},
{
"id": 5 ,
"name":"View Air",
"soundfile":"VIEW.wav"
},
{
"id": 6 ,
"name":"Fly",
"soundfile":"FLYSPELL.wav"
},
{
"id": 7 ,
"name":"Water walking",
"soundfile":"WATRWALK.wav"
},
{
"id": 8 ,
"name":"Dimension doors",
"soundfile":"TELPTOUT.wav"
},
{
"id": 9 ,
"name":"Town Portal",
"soundfile":"TELPTOUT.wav"
},
{
"id": 10 ,
"name":"Quick sands",
"soundfile":"QUIKSAND.wav"
},
{
"id": 12 ,
"name":"Force field",
"soundfile":"FORCEFLD.wav"
},
{
"id": 13 ,
"name":"Fire wall",
"soundfile":"FIREWALL.wav"
},
{
"id": 14 ,
"name":"Earthquake",
"soundfile":"ERTHQUAK.wav"
},
{
"id": 15,
"soundfile": "MAGICBLT.wav",
"name": "magic arrow"
},
{
"id": 16,
"soundfile": "ICERAY.wav",
"name": "ice bolt"
},
{
"id": 17,
"soundfile": "LIGHTBLT.wav",
"name": "lightning bolt"
},
{
"id": 18 ,
"name":"Implosion",
"soundfile":"DECAY.wav"
},
{
"id": 19 ,
"name":"Chaon lighting",
"soundfile":"CHAINLTE.wav"
},
{
"id": 20,
"soundfile": "FROSTING.wav",
"name": "frost ring"
},
{
"id": 21,
"soundfile": "FIREBALL.wav",
"name": "fireball"
},
{
"id": 22 ,
"name":"Inferno",
"soundfile":"FIREBLST.wav"
},
{
"id": 23,
"soundfile": "METEOR.wav",
"name": "meteor shower"
},
{
"id": 24,
"soundfile": "DEATHRIP.wav",
"name": "death ripple"
},
{
"id": 25 ,
"name":"Destroy undead",
"soundfile":"COLDRING.wav"
},
{
"id": 26,
"soundfile": "ARMGEDN.wav",
"name": "armageddon"
},
{
"id": 27,
"soundfile": "SHIELD.wav",
"name": "shield "
},
{
"id": 28,
"soundfile": "AIRSHELD.wav",
"name": "air shield"
},
{
"id": 29 ,
"name":"fireshield cast",
"soundfile":"FIRESHIE.wav"
},
// It looks that fireshield has two separate souds. Disabling one of them for now
// {
// "id": 29 ,
// "name":"fireshield effect",
// "soundfile":"FIRESHLD.wav"
// },
{
"id": 30,
"soundfile": "PROTECTA.wav",
"name": "protection from air"
},
{
"id": 31,
"soundfile": "PROTECTF.wav",
"name": "protection from fire"
},
{
"id": 32,
"soundfile": "PROTECTW.wav",
"name": "protection from water"
},
{
"id": 33,
"soundfile": "PROTECTE.wav",
"name": "protection from earth"
},
{
"id": 34,
"soundfile": "ANIMDEAD.wav"
},
{
"id": 35,
"soundfile": "DISPELL.wav",
"name": "dispell"
},
{
"id": 36 ,
"name":"Magic mirror",
"soundfile":"BACKLASH.wav"
},
{
"id": 37 ,
"name":"Cure",
"soundfile":"CURE.wav"
},
{
"id": 38 ,
"name":"Resurrect",
"soundfile":"RESURECT.wav"
},
{
"id": 39,
"soundfile": "ANIMDEAD.wav"
},
{
"id": 40 ,
"name":"Sacrifice",
"soundfile":"SACRIF1.wav"
},
{
"id": 41,
"soundfile": "BLESS.wav",
"name": "bless"
},
{
"id": 42,
"soundfile": "CURSE.wav",
"name": "curse"
},
{
"id": 43,
"soundfile": "BLOODLUS.wav",
"name": "bloodlust"
},
{
"id": 44,
"soundfile": "PRECISON.wav",
"name": "precision"
},
{
"id": 45,
"soundfile": "WEAKNESS.wav",
"name": "weakness"
},
{
"id": 46,
"soundfile": "TUFFSKIN.wav",
"name": "stone skin"
},
{
"id": 47,
"soundfile": "DISRUPTR.wav",
"name": "disrupting ray"
},
{
"id": 48,
"soundfile": "PRAYER.wav",
"name": "prayer"
},
{
"id": 49,
"soundfile": "MIRTH.wav",
"name": "mirth"
},
{
"id": 50,
"soundfile": "SORROW.wav",
"name": "sorrow"
},
{
"id": 51,
"soundfile": "FORTUNE.wav",
"name": "fortune"
},
{
"id": 52,
"soundfile": "MISFORT.wav",
"name": "misfortune"
},
{
"id": 53,
"soundfile": "HASTE.wav",
"name": "haste"
},
{
"id": 54,
"soundfile": "MUCKMIRE.wav",
"name": "slow"
},
{
"id": 55,
"soundfile": "SLAYER.wav",
"name": "slayer"
},
{
"id": 56,
"soundfile": "FRENZY.wav",
"name": "frenzy"
},
{
"id": 57 ,
"name":"Titan Bolt",
"soundfile":"LIGHTBLT.wav"
},
{
"id": 58 ,
"name":"Counterstrike",
"soundfile":"CNTRSTRK.wav"
},
{
"id": 59 ,
"name":"Berserk",
"soundfile":"BERSERK.wav"
},
{
"id": 60,
"soundfile": "HYPNOTIZ.wav",
"name": "forgetfulness"
},
{
"id": 61,
"soundfile": "FORGET.wav",
"name": "forgetfulness"
},
{
"id": 62,
"soundfile": "BLIND.wav"
},
{
"id": 63 ,
"name":"Teleport",
"soundfile":"TELPTOUT.wav"
},
{
"id": 64 ,
"name":"Remove obstacle",
"soundfile":"REMOVEOB.wav"
},
{
"id": 65 ,
"name":"Clone",
"soundfile":"CLONE.wav"
},
{
"id": 66 ,
"name":"Summon elementals",
"soundfile":"SUMNELM.wav"
},
{
"id": 67 ,
"name":"Summon elementals",
"soundfile":"SUMNELM.wav"
},
{
"id": 68 ,
"name":"Summon elementals",
"soundfile":"SUMNELM.wav"
},
{
"id": 69 ,
"name":"Summon elementals",
"soundfile":"SUMNELM.wav"
},
{
"id": 70,
"soundfile": "PARALYZE.wav",
"name": "stone gaze and paralyze"
},
{
"id": 71,
"soundfile": "POISON.wav",
"name": "poison"
},
{
"id": 72,
"soundfile": "BIND.wav",
"name": " bind"
},
{
"id": 73,
"soundfile": "DISEASE.wav",
"name": ""
},
{
"id": 74,
"soundfile": "PARALYZE.wav",
"name": ""
},
{
"id": 75,
"soundfile": "AGE.wav",
"name": "aging"
},
{
"id": 76,
"soundfile": "DEATHCLD.wav",
"name": "death cloud"
},
{
"id": 77,
"soundfile": "LIGHTBLT.wav",
"name": "thunder"
},
{
"id": 78,
"soundfile": "DISPELL.wav",
"name": "dispell helpful spells"
},
{
"id": 79,
"soundfile": "DEATHSTR.wav",
"name": "Death Stare"
},
{
"id": 80,
"soundfile": "ACID.wav",
"name": " Acid breath / defence piercing"
}
]
}
// Several probably missing sounds of creature abilities
// ACID.WAV Acid breath Rust Dragons

View File

@ -2,17 +2,20 @@
"summonBoat" : {
"index" : 0,
"anim" : -1,
"sounds": {
"cast": "SUMMBOAT"
},
"levels" :{
"none":{
"none":{
"range" : "X"
},
"basic":{
"basic":{
"range" : "X"
},
"advanced":{
"advanced":{
"range" : "X"
},
"expert":{
"expert":{
"range" : "X"
}
},
@ -23,18 +26,20 @@
"scuttleBoat" : {
"index" : 1,
"anim" : -1,
"levels" :
{
"none": {
"sounds": {
"cast": "SCUTBOAT"
},
"levels" : {
"none": {
"range" : "X"
},
"basic":{
"basic":{
"range" : "X"
},
"advanced":{
"advanced":{
"range" : "X"
},
"expert":{
"expert":{
"range" : "X"
}
},
@ -45,6 +50,9 @@
"visions" : {
"index" : 2,
"anim" : -1,
"sounds": {
"cast": "VISIONS"
},
"levels" : {
"none":{
"range" : "X"
@ -66,6 +74,9 @@
"viewEarth" : {
"index" : 3,
"anim" : -1,
"sounds": {
"cast": "VIEW"
},
"levels" : {
"none":{
"range" : "X"
@ -87,6 +98,9 @@
"disguise" : {
"index" : 4,
"anim" : -1,
"sounds": {
"cast": "DISGUISE"
},
"levels" : {
"none":{
"range" : "X"
@ -108,6 +122,9 @@
"viewAir" : {
"index" : 5,
"anim" : -1,
"sounds": {
"cast": "VIEW"
},
"levels" : {
"none":{
"range" : "X"
@ -129,6 +146,9 @@
"fly" : {
"index" : 6,
"anim" : -1,
"sounds": {
"cast": "FLYSPELL"
},
"levels" : {
"none":{
"range" : "X"
@ -150,6 +170,9 @@
"waterWalk" : {
"index" : 7,
"anim" : -1,
"sounds": {
"cast": "WATRWALK"
},
"levels" : {
"none":{
"range" : "X"
@ -171,6 +194,9 @@
"dimensionDoor" : {
"index" : 8,
"anim" : -1,
"sounds": {
"cast": "TELPTOUT"
},
"levels" : {
"none":{
"range" : "X"
@ -192,6 +218,9 @@
"townPortal" : {
"index" : 9,
"anim" : -1,
"sounds": {
"cast": "TELPTOUT"
},
"levels" : {
"none":{
"range" : "X"
@ -213,6 +242,9 @@
"quicksand" : {
"index" : 10,
"anim" : -1,
"sounds": {
"cast": "QUIKSAND"
},
"levels" : {
"none":{
"range" : "X"
@ -234,6 +266,9 @@
"landMine" : {
"index" : 11,
"anim" : -1,
"sounds": {
"cast": ""
},
"levels" : {
"none":{
"range" : "X"
@ -259,6 +294,9 @@
"forceField" : {
"index" : 12,
"anim" : -1,
"sounds": {
"cast": "FORCEFLD"
},
"levels" : {
"none":{
"range" : "0"
@ -280,6 +318,9 @@
"fireWall" : {
"index" : 13,
"anim" : -1,
"sounds": {
"cast": "FIREWALL"
},
"levels" : {
"none":{
"range" : "0"
@ -305,6 +346,9 @@
"earthquake" : {
"index" : 14,
"anim" : -1,
"sounds": {
"cast": "ERTHQUAK"
},
"levels" : {
"none":{
"range" : "X"
@ -326,6 +370,9 @@
"magicArrow" : {
"index" : 15,
"anim" : 64,
"sounds": {
"cast": "MAGICBLT"
},
"levels" : {
"none":{
"range" : "0"
@ -352,6 +399,9 @@
"iceBolt" : {
"index" : 16,
"anim" : 46,
"sounds": {
"cast": "ICERAY"
},
"levels" : {
"none":{
"range" : "0"
@ -378,6 +428,9 @@
"lightningBolt" : {
"index" : 17,
"anim" : 38,
"sounds": {
"cast": "LIGHTBLT"
},
"levels" : {
"none":{
"range" : "0"
@ -404,6 +457,9 @@
"implosion" : {
"index" : 18,
"anim" : 10,
"sounds": {
"cast": "DECAY"
},
"levels" : {
"none":{
"range" : "0"
@ -431,6 +487,9 @@
"chainLightning" : {
"index" : 19,
"anim" : 38,
"sounds": {
"cast": "CHAINLTE"
},
"levels" : {
"none":{
"range" : "0"
@ -454,6 +513,9 @@
"frostRing" : {
"index" : 20,
"anim" : 45,
"sounds": {
"cast": "FROSTING"
},
"levels" : {
"none":{
"range" : "1"
@ -480,6 +542,9 @@
"fireball" : {
"index" : 21,
"anim" : 53,
"sounds": {
"cast": "FIREBALL"
},
"levels" : {
"none":{
"range" : "0,1"
@ -506,6 +571,9 @@
"inferno" : {
"index" : 22,
"anim" : 9,
"sounds": {
"cast": "FIREBLST"
},
"levels" : {
"none":{
"range" : "0-2"
@ -532,6 +600,9 @@
"meteorShower" : {
"index" : 23,
"anim" : 16,
"sounds": {
"cast": "METEOR"
},
"levels" : {
"none":{
"range" : "0,1"
@ -558,6 +629,9 @@
"deathRipple" : {
"index" : 24,
"anim" : 8,
"sounds": {
"cast": "DEATHRIP"
},
"levels" : {
"none":{
"range" : "X"
@ -586,6 +660,9 @@
"destroyUndead" : {
"index" : 25,
"anim" : 29,
"sounds": {
"cast": "COLDRING"
},
"levels" : {
"none":{
"range" : "X"
@ -615,6 +692,9 @@
"armageddon" : {
"index" : 26,
"anim" : 12,
"sounds": {
"cast": "ARMGEDN"
},
"levels" : {
"none":{
"range" : "X"
@ -641,6 +721,9 @@
"shield" : {
"index" : 27,
"anim" : 27,
"sounds": {
"cast": "SHIELD"
},
"levels" : {
"none":{
"range" : "0",
@ -690,6 +773,9 @@
"airShield" : {
"index" : 28,
"anim" : 2,
"sounds": {
"cast": "AIRSHELD"
},
"levels" : {
"none":{
"range" : "0",
@ -739,6 +825,12 @@
"fireShield" : {
"index" : 29,
"anim" : 11,
"sounds": {
"cast": "FIRESHIE"
},
// It looks that fireshield has two separate sounds
// "soundfile":"FIRESHLD.wav"
//
"levels" : {
"none":{
"range" : "0",
@ -784,6 +876,9 @@
"protectAir" : {
"index" : 30,
"anim" : 22,
"sounds": {
"cast": "PROTECTA"
},
"levels" : {
"none":{
"range" : "0",
@ -833,6 +928,9 @@
"protectFire" : {
"index" : 31,
"anim" : 24,
"sounds": {
"cast": "PROTECTF"
},
"levels" : {
"none":{
"range" : "0",
@ -882,6 +980,9 @@
"protectWater" : {
"index" : 32,
"anim" : 23,
"sounds": {
"cast": "PROTECTW"
},
"levels" : {
"none":{
"range" : "0",
@ -931,6 +1032,9 @@
"protectEarth" : {
"index" : 33,
"anim" : 26,
"sounds": {
"cast": "PROTECTE"
},
"levels" : {
"none":{
"range" : "0",
@ -980,6 +1084,9 @@
"antiMagic" : {
"index" : 34,
"anim" : 5,
"sounds": {
"cast": "ANTIMAGK"
},
"levels" : {
"none":{
"range" : "0",
@ -1033,6 +1140,9 @@
"dispel" : {
"index" : 35,
"anim" : 41,
"sounds": {
"cast": "DISPELL"
},
"levels" : {
"none":{
"range" : "0"
@ -1054,6 +1164,9 @@
"magicMirror" : {
"index" : 36,
"anim" : 3,
"sounds": {
"cast": "BACKLASH"
},
"levels" : {
"none":{
"range" : "0",
@ -1103,6 +1216,9 @@
"cure" : {
"index" : 37,
"anim" : 39,
"sounds": {
"cast": "CURE"
},
"levels" : {
"none":{
"range" : "0"
@ -1124,6 +1240,9 @@
"resurrection" : {
"index" : 38,
"anim" : 79,
"sounds": {
"cast": "RESURECT"
},
"levels" : {
"none":{
"range" : "0"
@ -1150,6 +1269,9 @@
"animateDead" : {
"index" : 39,
"anim" : 79,
"sounds": {
"cast": "ANIMDEAD"
},
"levels" : {
"none":{
"range" : "0"
@ -1175,6 +1297,9 @@
"sacrifice" : {
"index" : 40,
"anim" : 79,
"sounds": {
"cast": "SACRIF1"
},
"levels" : {
"none":{
"range" : "0"
@ -1201,6 +1326,9 @@
"bless" : {
"index" : 41,
"anim" : 36,
"sounds": {
"cast": "BLESS"
},
"levels" : {
"none":{
"range" : "0",
@ -1264,6 +1392,9 @@
"curse" : {
"index" : 42,
"anim" : 40,
"sounds": {
"cast": "CURSE"
},
"levels" : {
"none":{
"range" : "0",
@ -1331,6 +1462,9 @@
"bloodlust" : {
"index" : 43,
"anim" : 4,
"sounds": {
"cast": "BLOODLUS"
},
"levels" : {
"none":{
"range" : "0",
@ -1391,6 +1525,9 @@
"precision" : {
"index" : 44,
"anim" : 25,
"sounds": {
"cast": "PRECISON"
},
"levels" : {
"none":{
"range" : "0",
@ -1451,6 +1588,9 @@
"weakness" : {
"index" : 45,
"anim" : 56,
"sounds": {
"cast": "WEAKNESS"
},
"levels" : {
"none":{
"range" : "0",
@ -1507,6 +1647,9 @@
"stoneSkin" : {
"index" : 46,
"anim" : 54,
"sounds": {
"cast": "TUFFSKIN"
},
"levels" : {
"none":{
"range" : "0",
@ -1559,8 +1702,11 @@
},
"disruptingRay" : {
"index" : 47,
"targetType" : "CREATURE", //fix, dont remove
"targetType" : "CREATURE", //fix, dont remove
"anim" : 14,
"sounds": {
"cast": "DISRUPTR"
},
"levels" : {
"none":{
"range" : "0",
@ -1618,6 +1764,9 @@
"prayer" : {
"index" : 48,
"anim" : 0,
"sounds": {
"cast": "PRAYER"
},
"levels" : {
"none":{
"range" : "0",
@ -1719,6 +1868,9 @@
"mirth" : {
"index" : 49,
"anim" : 20,
"sounds": {
"cast": "MIRTH"
},
"levels" : {
"none":{
"range" : "0",
@ -1771,6 +1923,9 @@
"sorrow" : {
"index" : 50,
"anim" : 30,
"sounds": {
"cast": "SORROW"
},
"levels" : {
"none":{
"range" : "0",
@ -1828,6 +1983,9 @@
"fortune" : {
"index" : 51,
"anim" : 18,
"sounds": {
"cast": "FORTUNE"
},
"levels" : {
"none":{
"range" : "0",
@ -1880,6 +2038,9 @@
"misfortune" : {
"index" : 52,
"anim" : 48,
"sounds": {
"cast": "MISFORT"
},
"levels" : {
"none":{
"range" : "0",
@ -1932,6 +2093,9 @@
"haste" : {
"index" : 53,
"anim" : 31,
"sounds": {
"cast": "HASTE"
},
"levels" : {
"none":{
"range" : "0",
@ -1991,6 +2155,9 @@
"slow" : {
"index" : 54,
"anim" : 19,
"sounds": {
"cast": "MUCKMIRE"
},
"levels" : {
"none":{
"range" : "0",
@ -2055,6 +2222,9 @@
"slayer" : {
"index" : 55,
"anim" : 28,
"sounds": {
"cast": "SLAYER"
},
"levels" : {
"none":{
"range" : "0",
@ -2104,6 +2274,9 @@
"frenzy" : {
"index" : 56,
"anim" : 17,
"sounds": {
"cast": "FRENZY"
},
"levels" : {
"none":{
"range" : "0",
@ -2153,6 +2326,9 @@
"titanBolt" : {
"index" : 57,
"anim" : 38,
"sounds": {
"cast": "LIGHTBLT"
},
"levels" : {
"none":{
"range" : "0"
@ -2171,12 +2347,15 @@
"damage": true,
"offensive": true,
"negative": true,
"special": true
"special": true
}
},
"counterstrike" : {
"index" : 58,
"anim" : 7,
"sounds": {
"cast": "CNTRSTRK"
},
"levels" : {
"none":{
"range" : "0",
@ -2226,6 +2405,9 @@
"berserk" : {
"index" : 59,
"anim" : 35,
"sounds": {
"cast": "BERSERK"
},
"levels" : {
"none":{
"range" : "0",
@ -2281,6 +2463,9 @@
"hypnotize" : {
"index" : 60,
"anim" : 21,
"sounds": {
"cast": "HYPNOTIZ"
},
"levels" : {
"none":{
"range" : "0",
@ -2335,8 +2520,11 @@
},
"forgetfulness" : {
"index" : 61,
"targetType" : "CREATURE_EXPERT_MASSIVE", //fix dont remove
"targetType" : "CREATURE_EXPERT_MASSIVE", //fix dont remove
"anim" : 42,
"sounds": {
"cast": "FORGET"
},
"levels" : {
"none":{
"range" : "0",
@ -2394,6 +2582,9 @@
"blind" : {
"index" : 62,
"anim" : 6,
"sounds": {
"cast": "BLIND"
},
"levels" : {
"none":{
"range" : "0",
@ -2513,6 +2704,9 @@
"teleport" : {
"index" : 63,
"anim" : -1,
"sounds": {
"cast": "TELPTOUT"
},
"levels" : {
"none":{
"range" : "0"
@ -2537,6 +2731,9 @@
"removeObstacle" : {
"index" : 64,
"anim" : -1,
"sounds": {
"cast": "REMOVEOB"
},
"levels" : {
"none":{
"range" : "X"
@ -2558,6 +2755,9 @@
"clone" : {
"index" : 65,
"anim" : -1,
"sounds": {
"cast": "CLONE"
},
"levels" : {
"none":{
"range" : "0"
@ -2582,6 +2782,9 @@
"fireElemental" : {
"index" : 66,
"anim" : -1,
"sounds": {
"cast": "SUMNELM"
},
"levels" : {
"none":{
"range" : "X"
@ -2603,6 +2806,9 @@
"earthElemental" : {
"index" : 67,
"anim" : -1,
"sounds": {
"cast": "SUMNELM"
},
"levels" : {
"none":{
"range" : "X"
@ -2624,6 +2830,9 @@
"waterElemental" : {
"index" : 68,
"anim" : -1,
"sounds": {
"cast": "SUMNELM"
},
"levels" : {
"none":{
"range" : "X"
@ -2645,6 +2854,9 @@
"airElemental" : {
"index" : 69,
"anim" : -1,
"sounds": {
"cast": "SUMNELM"
},
"levels" : {
"none":{
"range" : "X"
@ -2666,6 +2878,9 @@
"stoneGaze" : {
"index" : 70,
"anim" : 70,
"sounds": {
"cast": "PARALYZE"
},
"levels" : {
"none":{
"range" : "0",
@ -2751,6 +2966,9 @@
"poison" : {
"index" : 71,
"anim" : 67,
"sounds": {
"cast": "POISON"
},
"levels" : {
"none":{
"range" : "0",
@ -2832,6 +3050,9 @@
"bind" : {
"index" : 72,
"anim" : 68,
"sounds": {
"cast": "BIND"
},
"levels" : {
"none":{
"range" : "0",
@ -2885,6 +3106,9 @@
"disease" : {
"index" : 73,
"anim" : 69,
"sounds": {
"cast": "DISEASE"
},
"levels" : {
"none":{
"range" : "0",
@ -2966,6 +3190,9 @@
"paralyze" : {
"index" : 74,
"anim" : 70,
"sounds": {
"cast": "PARALYZE"
},
"levels" : {
"none":{
"range" : "0",
@ -3051,6 +3278,9 @@
"age" : {
"index" : 75,
"anim" : 71,
"sounds": {
"cast": "AGE"
},
"levels" : {
"none":{
"range" : "0",
@ -3108,6 +3338,9 @@
"deathCloud" : {
"index" : 76,
"anim" : 72,
"sounds": {
"cast": "DEATHCLD"
},
"levels" : {
"none":{
"range" : "0-1"
@ -3133,6 +3366,9 @@
"thunderbolt" : {
"index" : 77,
"anim" : 38,
"sounds": {
"cast": "LIGHTBLT"
},
"levels" : {
"none":{
"range" : "0"
@ -3156,6 +3392,9 @@
"dispelHelpful" : {
"index" : 78,
"anim" : 41,
"sounds": {
"cast": "DISPELL"
},
"levels" : {
"none":{
"range" : "0"
@ -3178,6 +3417,9 @@
"deathStare" : {
"index" : 79,
"anim" : 80,
"sounds": {
"cast": "DEATHSTR"
},
"levels" : {
"none":{
"range" : "0"
@ -3203,6 +3445,9 @@
"acidBreath" : {
"index" : 80,
"anim" : 81,
"sounds": {
"cast": "ACID"
},
"levels" : {
"none":{
"range" : "0",
@ -3260,6 +3505,9 @@
"acidBreathDamage" : {
"index" : 81,
"anim" : 81,
"sounds": {
"cast": "ACID"
},
"levels" : {
"none":{
"range" : "0"

View File

@ -2063,7 +2063,7 @@ std::set<const CStack*> CBattleInfoCallback::getAffectedCreatures(const CSpell *
{
if(const CStack * st = battleGetStackByPos(hex, onlyAlive))
{
if (spell->id == 76) //Death Cloud //TODO: fireball and fire immunity
if (spell->id == SpellID::DEATH_CLOUD) //Death Cloud //TODO: fireball and fire immunity
{
if (st->isLiving() || st->coversPos(destinationTile)) //directly hit or alive
{

View File

@ -313,6 +313,13 @@ const std::string& CSpell::getIconImmune() const
return iconImmune;
}
const std::string& CSpell::getCastSound() const
{
return castSound;
}
si32 CSpell::getCost(const int skillLevel) const
{
return costs[skillLevel];
@ -693,11 +700,6 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
//by default all flags are set to false in constructor
if(flags["summoning"].Bool())
{
logGlobal->warnStream() << spell->name << ": summoning flag in unimplemented";
}
spell->isDamage = flags["damage"].Bool(); //do this before "offensive"
if(flags["offensive"].Bool())
@ -767,6 +769,16 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
const JsonNode & graphicsNode = json["graphics"];
spell->iconImmune = graphicsNode["iconImmune"].String();
spell->iconBook = graphicsNode["iconBook"].String();
spell->iconEffect = graphicsNode["iconEffect"].String();
spell->iconScenarioBonus = graphicsNode["iconScenarioBonus"].String();
spell->iconScroll = graphicsNode["iconScroll"].String();
const JsonNode & soundsNode = json["sounds"];
spell->castSound = soundsNode["cast"].String();
//load level attributes

View File

@ -102,6 +102,8 @@ public:
* Returns resource name of icon for SPELL_IMMUNITY bonus
*/
const std::string& getIconImmune() const;
const std::string& getCastSound() const;
template <typename Handler> void serialize(Handler &h, const int version)
{
@ -114,8 +116,12 @@ public:
h & absoluteImmunities & defaultProbability;
h & isSpecial;
h & castSound & iconBook & iconEffect & iconScenarioBonus & iconScroll ;
}
friend class CSpellHandler;
friend class Graphics;
private:
void setIsOffensive(const bool val);
@ -147,9 +153,14 @@ private:
///graphics related stuff
std::string iconImmune;
std::string iconBook;
std::string iconEffect;
std::string iconScenarioBonus;
std::string iconScroll;
///sound related stuff
std::string castSound;
};

View File

@ -28,7 +28,7 @@
#include "mapping/CCampaignHandler.h" //for CCampaignState
#include "rmg/CMapGenerator.h" // for CMapGenOptions
const ui32 version = 746;
const ui32 version = 747;
const ui32 minSupportedVersion = version;
class CConnection;

View File

@ -4127,7 +4127,8 @@ void CGameHandler::handleSpellCasting( SpellID spellID, int spellLvl, BattleHex
++chainLightningModifier;
}
}
else if (spell->hasEffects())
if (spell->hasEffects())
{
int stackSpellPower = 0;
if (stack && mode != ECastingMode::MAGIC_MIRROR)
@ -4142,7 +4143,7 @@ void CGameHandler::handleSpellCasting( SpellID spellID, int spellLvl, BattleHex
CStack::stackEffectToFeature(sse.effect, pseudoBonus);
if (spellID == SpellID::SHIELD || spellID == SpellID::AIR_SHIELD)
{
sse.effect.back().val = (100 - sse.effect.back().val); //fix to original config: shiled should display damage reduction
sse.effect.back().val = (100 - sse.effect.back().val); //fix to original config: shield should display damage reduction
}
if (spellID == SpellID::BIND && stack)//bind
{
@ -4209,7 +4210,8 @@ void CGameHandler::handleSpellCasting( SpellID spellID, int spellLvl, BattleHex
sendAndApply(&sse);
}
else if (spell->isRisingSpell() || spell->id == SpellID::CURE)
if (spell->isRisingSpell() || spell->id == SpellID::CURE)
{
int hpGained = 0;
if (stack)
@ -4275,7 +4277,7 @@ void CGameHandler::handleSpellCasting( SpellID spellID, int spellLvl, BattleHex
sendAndApply(&bsr);
}
}
else
switch (spellID)
{
case SpellID::QUICKSAND:
@ -4370,7 +4372,7 @@ void CGameHandler::handleSpellCasting( SpellID spellID, int spellLvl, BattleHex
if (!clonedStack)
{
complain ("No target stack to clone!");
return;
break;
}
BattleStackAdded bsa;