From: Daniel Karbach Date: Mon, 3 Sep 2012 19:58:28 +0000 (+0200) Subject: Merge branch 'loader' X-Git-Url: http://git.localhorst.tv/?a=commitdiff_plain;h=d5959073b2c413ba1bd6f3d14bc8bcf59304e488;hp=520af5a8ef4fdfd4156377d4fccd93eecd450f0f;p=l2e.git Merge branch 'loader' This introduces the capability of loading l2 formatted source files. The syntax for those is described here: http://luke.redirectme.net/redmine/projects/l2e/wiki/LoaderSource Please note that this method of loading data is very inefficient, but convenient. Efficiency issues will be adressed by a binary file format which mentioned source files can be compiled to. Also, some representations have been adapted to a more link-friendly structure and most of the configuration code in main has been moved to their respective l2s files residing in /test-data/ . --- diff --git a/Debug/makefile b/Debug/makefile index 571f839..13878f3 100644 --- a/Debug/makefile +++ b/Debug/makefile @@ -9,6 +9,7 @@ RM := rm -rf # All of the sources participating in the build are defined here -include sources.mk -include src/sdl/subdir.mk +-include src/loader/subdir.mk -include src/graphics/subdir.mk -include src/common/subdir.mk -include src/battle/states/subdir.mk diff --git a/Debug/sources.mk b/Debug/sources.mk index a9593d6..7aaa6cf 100644 --- a/Debug/sources.mk +++ b/Debug/sources.mk @@ -25,6 +25,7 @@ C_UPPER_DEPS := SUBDIRS := \ src/sdl \ src \ +src/loader \ src/graphics \ src/common \ src/battle/states \ diff --git a/Debug/src/loader/subdir.mk b/Debug/src/loader/subdir.mk new file mode 100644 index 0000000..19b1d87 --- /dev/null +++ b/Debug/src/loader/subdir.mk @@ -0,0 +1,36 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/loader/Interpreter.cpp \ +../src/loader/ParsedSource.cpp \ +../src/loader/Parser.cpp \ +../src/loader/Tokenizer.cpp \ +../src/loader/utility.cpp + +OBJS += \ +./src/loader/Interpreter.o \ +./src/loader/ParsedSource.o \ +./src/loader/Parser.o \ +./src/loader/Tokenizer.o \ +./src/loader/utility.o + +CPP_DEPS += \ +./src/loader/Interpreter.d \ +./src/loader/ParsedSource.d \ +./src/loader/Parser.d \ +./src/loader/Tokenizer.d \ +./src/loader/utility.d + + +# Each subdirectory must supply rules for building sources it contributes +src/loader/%.o: ../src/loader/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: GCC C++ Compiler' + g++ -I/usr/include/SDL -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/Release/makefile b/Release/makefile index 571f839..13878f3 100644 --- a/Release/makefile +++ b/Release/makefile @@ -9,6 +9,7 @@ RM := rm -rf # All of the sources participating in the build are defined here -include sources.mk -include src/sdl/subdir.mk +-include src/loader/subdir.mk -include src/graphics/subdir.mk -include src/common/subdir.mk -include src/battle/states/subdir.mk diff --git a/Release/sources.mk b/Release/sources.mk index a9593d6..7aaa6cf 100644 --- a/Release/sources.mk +++ b/Release/sources.mk @@ -25,6 +25,7 @@ C_UPPER_DEPS := SUBDIRS := \ src/sdl \ src \ +src/loader \ src/graphics \ src/common \ src/battle/states \ diff --git a/Release/src/loader/subdir.mk b/Release/src/loader/subdir.mk new file mode 100644 index 0000000..c619e85 --- /dev/null +++ b/Release/src/loader/subdir.mk @@ -0,0 +1,36 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/loader/Interpreter.cpp \ +../src/loader/ParsedSource.cpp \ +../src/loader/Parser.cpp \ +../src/loader/Tokenizer.cpp \ +../src/loader/utility.cpp + +OBJS += \ +./src/loader/Interpreter.o \ +./src/loader/ParsedSource.o \ +./src/loader/Parser.o \ +./src/loader/Tokenizer.o \ +./src/loader/utility.o + +CPP_DEPS += \ +./src/loader/Interpreter.d \ +./src/loader/ParsedSource.d \ +./src/loader/Parser.d \ +./src/loader/Tokenizer.d \ +./src/loader/utility.d + + +# Each subdirectory must supply rules for building sources it contributes +src/loader/%.o: ../src/loader/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: GCC C++ Compiler' + g++ -I/usr/include/SDL -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/src/battle/BattleState.cpp b/src/battle/BattleState.cpp index 5ba60d6..d958663 100644 --- a/src/battle/BattleState.cpp +++ b/src/battle/BattleState.cpp @@ -80,9 +80,9 @@ void BattleState::Resize(int w, int h) { void BattleState::EnterState(Application &ctrl, SDL_Surface *screen) { for (int i(0); i < 4; ++i) { heroes[i].Position() = heroesLayout->CalculatePosition(i, background->w, background->h); - heroes[i].SpellMenu() = res->spellMenuPrototype; + heroes[i].SpellMenu() = *res->spellMenuProperties; heroes[i].UpdateSpellMenu(); - heroes[i].IkariMenu() = res->ikariMenuPrototype; + heroes[i].IkariMenu() = *res->ikariMenuProperties; heroes[i].UpdateIkariMenu(res); heroTags[i] = HeroTag(this, i); smallHeroTags[i] = SmallHeroTag(this, i); @@ -109,7 +109,7 @@ void BattleState::EnterState(Application &ctrl, SDL_Surface *screen) { smallHeroTagPositions[2] = Vector(xOffset + tagWidth, yOffset); smallHeroTagPositions[3] = Vector(xOffset + 3 * tagWidth, yOffset); - itemMenu = res->itemMenuPrototype; + itemMenu = *res->itemMenuProperties; LoadInventory(); } @@ -422,7 +422,7 @@ void BattleState::RenderSmallHeroTags(SDL_Surface *screen, const Vector &of SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, 0, 0, 0)); rect.y += res->normalFont->CharHeight() / 8; rect.h -= res->normalFont->CharHeight() / 4; - SDL_FillRect(screen, &rect, res->heroesBgColor); + SDL_FillRect(screen, &rect, res->heroesBgColor.MapRGB(screen->format)); for (int i(0); i < numHeroes; ++i) { smallHeroTags[i].Render(screen, tagWidth, tagHeight, smallHeroTagPositions[i] + offset); diff --git a/src/battle/Resources.h b/src/battle/Resources.h index 49d30c1..719eec4 100644 --- a/src/battle/Resources.h +++ b/src/battle/Resources.h @@ -8,7 +8,7 @@ #ifndef BATTLE_RESOURCES_H_ #define BATTLE_RESOURCES_H_ -#include "../graphics/Menu.h" +#include "../graphics/Color.h" #include @@ -60,14 +60,14 @@ struct Resources { graphics::Sprite *itemTargetCursor; const char *spellMenuHeadline; - graphics::Menu spellMenuPrototype; + graphics::MenuProperties *spellMenuProperties; common::Inventory *inventory; const char *itemMenuHeadline; - graphics::Menu itemMenuPrototype; + graphics::MenuProperties *itemMenuProperties; const char *ikariMenuHeadline; - graphics::Menu ikariMenuPrototype; + graphics::MenuProperties *ikariMenuProperties; const char *noEquipmentText; const char *escapeText; @@ -95,7 +95,7 @@ struct Resources { int ikariLabelCol; int ikariLabelRow; - Uint32 heroesBgColor; + graphics::Color heroesBgColor; Resources() @@ -130,9 +130,12 @@ struct Resources { , itemTargetCursor(0) , spellMenuHeadline("") + , spellMenuProperties(0) , inventory(0) , itemMenuHeadline("") + , itemMenuProperties(0) , ikariMenuHeadline("") + , ikariMenuProperties(0) , noEquipmentText("") , escapeText("") @@ -159,7 +162,6 @@ struct Resources { , ikariLabelCol(0) , ikariLabelRow(0) - , heroesBgColor(0) { } }; diff --git a/src/battle/Stats.h b/src/battle/Stats.h index b935e02..ae885bf 100644 --- a/src/battle/Stats.h +++ b/src/battle/Stats.h @@ -27,6 +27,14 @@ public: Uint8 Gut() const { return gut; } Uint16 MagicResistance() const { return magicResistance; } + void SetAttack(Uint16 a) { attack = a; } + void SetDefense(Uint16 d) { defense = d; } + void SetStrength(Uint16 s) { strength = s; } + void SetAgility(Uint16 a) { agility = a; } + void SetIntelligence(Uint16 i) { intelligence = i; } + void SetGut(Uint8 g) { gut = g; } + void SetMagicResistance(Uint16 m) { magicResistance = m; } + private: Uint16 attack; Uint16 defense; diff --git a/src/common/TargetingMode.h b/src/common/TargetingMode.h index 5376d13..9041448 100644 --- a/src/common/TargetingMode.h +++ b/src/common/TargetingMode.h @@ -24,6 +24,12 @@ public: bool TargetsMultiple() const { return (mode & COUNT_MASK) == MULTIPLE; } bool TargetsSingle() const { return (mode & COUNT_MASK) == SINGLE; } + void TargetAll() { mode = (mode & FACTION_MASK) | ALL; } + void TargetMultiple() { mode = (mode & FACTION_MASK) | MULTIPLE; } + void TargetSingle() { mode = (mode & FACTION_MASK) | SINGLE; } + void TargetAlly() { mode = ALLY | (mode & COUNT_MASK); } + void TargetEnemy() { mode = ENEMY | (mode & COUNT_MASK); } + void TargetAllEnemies() { mode = ENEMY | ALL; } void TargetMultipleEnemies() { mode = ENEMY | MULTIPLE; } void TargetSingleEnemy() { mode = ENEMY | SINGLE; } diff --git a/src/graphics/Animation.h b/src/graphics/Animation.h index 208f6bd..2696694 100644 --- a/src/graphics/Animation.h +++ b/src/graphics/Animation.h @@ -28,11 +28,15 @@ public: virtual ~Animation() { }; public: - const Sprite *GetSprite() const { return sprite; } int FrameTime() const { return frameTime; } bool Repeat() const { return repeat; } +public: + void SetSprite(const Sprite *s) { sprite = s; } + void SetFrameTime(int t) { frameTime = t; } + void SetRepeat(bool r) { repeat = r; } + public: virtual int NumFrames() const = 0; virtual int Col(int frame) const = 0; diff --git a/src/graphics/Color.h b/src/graphics/Color.h new file mode 100644 index 0000000..42cbc89 --- /dev/null +++ b/src/graphics/Color.h @@ -0,0 +1,42 @@ +/* + * Color.h + * + * Created on: Sep 1, 2012 + * Author: holy + */ + +#ifndef GRAPHICS_COLOR_H_ +#define GRAPHICS_COLOR_H_ + +#include + +namespace graphics { + +class Color { + +public: + Color() :r(0), g(0), b(0), a(255) { } + Color(Uint8 r, Uint8 g, Uint8 b, Uint8 a = 255) : r(r), g(g), b(b), a(a) { } + +public: + Uint8 RedChannel() const { return r; } + Uint8 GreenChannel() const { return g; } + Uint8 BlueChannel() const { return b; } + Uint8 AlphaChannel() const { return a; } + + Uint32 MapRGB(SDL_PixelFormat *f) const { return SDL_MapRGB(f, r, g, b); } + Uint32 MapRGBA(SDL_PixelFormat *f) const { return SDL_MapRGBA(f, r, g, b, a); } + + void SetRedChannel(Uint8 i) { r = i; } + void SetGreenChannel(Uint8 i) { g = i; } + void SetBlueChannel(Uint8 i) { b = i; } + void SetAlphaChannel(Uint8 i) { a = i; } + +private: + Uint8 r, g, b, a; + +}; + +} + +#endif /* GRAPHICS_COLOR_H_ */ diff --git a/src/graphics/ComplexAnimation.h b/src/graphics/ComplexAnimation.h index 2eeea94..815e9c5 100644 --- a/src/graphics/ComplexAnimation.h +++ b/src/graphics/ComplexAnimation.h @@ -32,20 +32,24 @@ public: } } -protected: - virtual int NumFrames() const { return frames.size(); }; - virtual int Col(int frame) const { return frames[frame].col; } - virtual int Row(int frame) const { return frames[frame].row; } - virtual geometry::Vector Offset(int frame) const { return frames[frame].disposition; } - -private: +public: struct FrameProp { + FrameProp() : col(0), row(0) { } FrameProp(int col, int row, const geometry::Vector &disposition) : col(col), row(row), disposition(disposition) {} int col; int row; geometry::Vector disposition; }; + void AddFrame(const FrameProp &f) { frames.push_back(f); } + +protected: + virtual int NumFrames() const { return frames.size(); }; + virtual int Col(int frame) const { return frames[frame].col; } + virtual int Row(int frame) const { return frames[frame].row; } + virtual geometry::Vector Offset(int frame) const { return frames[frame].disposition; } + +private: std::vector frames; }; diff --git a/src/graphics/Font.cpp b/src/graphics/Font.cpp index a118500..ca06a07 100644 --- a/src/graphics/Font.cpp +++ b/src/graphics/Font.cpp @@ -8,6 +8,7 @@ #include "Font.h" #include +#include using geometry::Vector; using std::pow; @@ -15,12 +16,16 @@ using std::pow; namespace graphics { void Font::DrawChar(char c, SDL_Surface *dest, const Vector &position) const { + if (!sprite) return; + int col(colOffset + (c % 0x10)); int row(rowOffset + (c / 0x10)); sprite->Draw(dest, position, col, row); } void Font::DrawString(const char *s, SDL_Surface *dest, const Vector &positionIn, int maxChars) const { + if (!sprite) return; + Vector position(positionIn); Vector step(CharWidth(), 0); for (int i(0); s[i] && (maxChars <= 0 || i < maxChars); ++i, position += step) { @@ -29,10 +34,14 @@ void Font::DrawString(const char *s, SDL_Surface *dest, const Vector &posit } void Font::DrawDigit(int digit, SDL_Surface *dest, const Vector &position) const { + if (!sprite) return; + DrawChar(digit + 0x30, dest, position); } void Font::DrawNumber(int numberIn, SDL_Surface *dest, const Vector &positionIn, int digits) const { + if (!sprite) return; + int number(numberIn); if (digits > 0 && numberIn >= pow(10.0, digits)) { numberIn = pow(10.0, digits) - 1; diff --git a/src/graphics/Font.h b/src/graphics/Font.h index 8644802..571431d 100644 --- a/src/graphics/Font.h +++ b/src/graphics/Font.h @@ -18,7 +18,7 @@ namespace graphics { class Font { public: - explicit Font(const Sprite *sprite, int colOffset = 0, int rowOffset = 0) + explicit Font(const Sprite *sprite = 0, int colOffset = 0, int rowOffset = 0) : sprite(sprite), colOffset(colOffset), rowOffset(rowOffset) { } @@ -31,6 +31,11 @@ public: void DrawDigit(int d, SDL_Surface *dest, const geometry::Vector &position) const; void DrawNumber(int n, SDL_Surface *dest, const geometry::Vector &position, int digits = 0) const; +public: + void SetSprite(const Sprite *s) { sprite = s; } + void SetColOffset(int n) { colOffset = n; } + void SetRowOffset(int n) { rowOffset = n; } + private: const Sprite *sprite; int colOffset; diff --git a/src/graphics/Frame.cpp b/src/graphics/Frame.cpp index a152ee7..1485607 100644 --- a/src/graphics/Frame.cpp +++ b/src/graphics/Frame.cpp @@ -13,6 +13,15 @@ namespace graphics { // TODO: maybe create a cache for frames? void Frame::Draw(SDL_Surface *dest, const Vector &position, int width, int height) const { + if (!surface) { + SDL_Rect rect; + rect.x = position.X(); + rect.y = position.Y(); + rect.w = width; + rect.h = height; + SDL_FillRect(dest, &rect, SDL_MapRGB(dest->format, 0xFF, 0x00, 0x00)); + return; + } // top-left corner SDL_Rect srcRect; srcRect.x = offset.X(); diff --git a/src/graphics/Frame.h b/src/graphics/Frame.h index 09674cc..59aa1fb 100644 --- a/src/graphics/Frame.h +++ b/src/graphics/Frame.h @@ -17,7 +17,7 @@ namespace graphics { class Frame { public: - Frame(SDL_Surface *s, int borderWidth, int borderHeight, int repeatWidth = 1, int repeatHeight = 1, int xOffset = 0, int yOffset = 0) + explicit Frame(SDL_Surface *s = 0, int borderWidth = 1, int borderHeight = 1, int repeatWidth = 1, int repeatHeight = 1, int xOffset = 0, int yOffset = 0) : surface(s), borderSize(borderWidth, borderHeight), repeatSize(repeatWidth, repeatHeight), offset(xOffset, yOffset) { } public: @@ -31,6 +31,12 @@ public: const geometry::Vector RepeatSize() const { return repeatSize; } void Draw(SDL_Surface *dest, const geometry::Vector &position, int width, int height) const; +public: + void SetSurface(SDL_Surface *s) { surface = s; } + void SetBorderSize(const geometry::Vector &s) { borderSize = s; } + void SetRepeatSize(const geometry::Vector &s) { repeatSize = s; } + void SetOffset(const geometry::Vector &o) { offset = o; } + private: SDL_Surface *surface; geometry::Vector borderSize; diff --git a/src/graphics/Gauge.cpp b/src/graphics/Gauge.cpp index eda9942..0d72ac0 100644 --- a/src/graphics/Gauge.cpp +++ b/src/graphics/Gauge.cpp @@ -17,6 +17,18 @@ void Gauge::Draw(SDL_Surface *dest, const Vector &position, int width, Uint int filledWidth = fill * (width - startWidth - endWidth) / 255; int emptyWidth = (255 - fill) * (width - startWidth - endWidth) / 255; + if (!surface) { + destRect.x = position.X(); + destRect.y = position.Y(); + destRect.w = filledWidth + startWidth; + destRect.h = height; + SDL_FillRect(dest, &destRect, SDL_MapRGB(dest->format, 0x00, 0xFF, 0x00)); + destRect.x += destRect.w; + destRect.w = emptyWidth + endWidth; + SDL_FillRect(dest, &destRect, SDL_MapRGB(dest->format, 0xFF, 0x00, 0x00)); + return; + } + // start srcRect.w = startWidth; srcRect.h = height; @@ -24,28 +36,28 @@ void Gauge::Draw(SDL_Surface *dest, const Vector &position, int width, Uint destRect.y = position.Y(); // full part if (fill == 0) { - srcRect.x = emptyX; - srcRect.y = emptyY; + srcRect.x = emptyOffset.X(); + srcRect.y = emptyOffset.Y(); SDL_BlitSurface(surface, &srcRect, dest, &destRect); } else { - srcRect.x = fullX; - srcRect.y = fullY; + srcRect.x = fullOffset.X(); + srcRect.y = fullOffset.Y(); SDL_BlitSurface(surface, &srcRect, dest, &destRect); } destRect.x = position.X() + startWidth; // fill - srcRect.x = fullX + startWidth; - srcRect.y = fullY; + srcRect.x = fullOffset.X() + startWidth; + srcRect.y = fullOffset.Y(); srcRect.w = repeatWidth; while (filledWidth > repeatWidth) { SDL_BlitSurface(surface, &srcRect, dest, &destRect); destRect.x += repeatWidth; filledWidth -= repeatWidth; } - srcRect.x = emptyX + startWidth; - srcRect.y = emptyY; + srcRect.x = emptyOffset.X() + startWidth; + srcRect.y = emptyOffset.Y(); while (emptyWidth > repeatWidth) { SDL_BlitSurface(surface, &srcRect, dest, &destRect); destRect.x += repeatWidth; @@ -55,12 +67,12 @@ void Gauge::Draw(SDL_Surface *dest, const Vector &position, int width, Uint // end srcRect.w = endWidth; if (fill == 255) { - srcRect.x = fullX + startWidth + repeatWidth; - srcRect.y = fullY; + srcRect.x = fullOffset.X() + startWidth + repeatWidth; + srcRect.y = fullOffset.Y(); SDL_BlitSurface(surface, &srcRect, dest, &destRect); } else { - srcRect.x = emptyX + startWidth + repeatWidth; - srcRect.y = emptyY; + srcRect.x = emptyOffset.X() + startWidth + repeatWidth; + srcRect.y = emptyOffset.Y(); SDL_BlitSurface(surface, &srcRect, dest, &destRect); } diff --git a/src/graphics/Gauge.h b/src/graphics/Gauge.h index fd81877..3251ec2 100644 --- a/src/graphics/Gauge.h +++ b/src/graphics/Gauge.h @@ -17,20 +17,27 @@ namespace graphics { class Gauge { public: - Gauge(SDL_Surface *s, int fullX, int fullY, int emptyX, int emptyY, int height, int startWidth, int repeatWidth, int endWidth) - : surface(s), fullX(fullX), fullY(fullY), emptyX(emptyX), emptyY(emptyY), height(height), startWidth(startWidth), repeatWidth(repeatWidth), endWidth(endWidth) { } + explicit Gauge(SDL_Surface *s = 0, int fullX = 0, int fullY = 0, int emptyX = 0, int emptyY = 0, int height = 1, int startWidth = 0, int repeatWidth = 1, int endWidth = 0) + : surface(s), fullOffset(fullX, fullY), emptyOffset(emptyX, emptyY), height(height), startWidth(startWidth), repeatWidth(repeatWidth), endWidth(endWidth) { } public: int MinWidth() const { return startWidth + endWidth; } int Height() const { return height; } void Draw(SDL_Surface *dest, const geometry::Vector &position, int width, Uint8 fill) const; +public: + void SetSurface(SDL_Surface *s) { surface = s; } + void SetFullOffset(const geometry::Vector &o) { fullOffset = o; } + void SetEmptyOffset(const geometry::Vector &o) { emptyOffset = o; } + void SetHeight(int h) { height = h; } + void SetStartWidth(int w) { startWidth = w; } + void SetRepeatWidth(int w) { repeatWidth = w; } + void SetEndWidth(int w) { endWidth = w; } + private: SDL_Surface *surface; - int fullX; - int fullY; - int emptyX; - int emptyY; + geometry::Vector fullOffset; + geometry::Vector emptyOffset; int height; int startWidth; int repeatWidth; diff --git a/src/graphics/Menu.h b/src/graphics/Menu.h index 02a88c0..175a711 100644 --- a/src/graphics/Menu.h +++ b/src/graphics/Menu.h @@ -19,11 +19,39 @@ namespace graphics { class Sprite; +struct MenuProperties { + const Font *font; + const Font *disabledFont; + const Sprite *cursor; + int charsPerEntry; + int rows; + int rowGap; + int iconSpace; + int cols; + int colGap; + int charsPerNumber; + int charsPerAdditionalText; + int additionalTextGap; + char delimiter; + + MenuProperties() + : font(0), disabledFont(0), cursor(0) + , charsPerEntry(0), rows(0), rowGap(0) + , iconSpace(0), cols(0), colGap(0) + , charsPerNumber(0), charsPerAdditionalText(0) + , additionalTextGap(0), delimiter(':') { } + + MenuProperties(const Font *font, const Font *disabledFont, const Sprite *cursor, int charsPerEntry, int rows, int rowGap, int iconSpace, int cols, int colGap, int charsPerNumber, char delimiter, int charsPerAdditionalText, int additionalTextGap) + : font(font), disabledFont(disabledFont), cursor(cursor), charsPerEntry(charsPerEntry), rows(rows), rowGap(rowGap), iconSpace(iconSpace), cols(cols), colGap(colGap), charsPerNumber(charsPerNumber), charsPerAdditionalText(charsPerAdditionalText), additionalTextGap(additionalTextGap), delimiter(delimiter) { } +}; + template -class Menu { +class Menu +: private MenuProperties { public: Menu(); + Menu(const MenuProperties &); Menu(const Font *font, const Font *disabledFont, const Sprite *cursor, int charsPerEntry, int rows, int rowGap = 0, int iconSpace = 0, int cols = 1, int colGap = 0, int charsPerNumber = 0, char delimiter = ':', int charsPerAdditionalText = 0, int additionalTextGap = 0); public: @@ -75,63 +103,41 @@ private: T value; bool enabled; }; - const Font *font; - const Font *disabledFont; - const Sprite *cursor; std::vector entries; - int charsPerEntry; - int rows; - int rowGap; - int iconSpace; - int cols; - int colGap; int selected; int topRow; - int charsPerNumber; - int charsPerAdditionalText; - int additionalTextGap; - char delimiter; }; template Menu::Menu() -: font(0) -, disabledFont(0) -, cursor(0) -, charsPerEntry(0) -, rows(0) -, rowGap(0) -, iconSpace(0) -, cols(0) -, colGap(0) +: MenuProperties() +, selected(0) +, topRow(0) { + +} + +template +Menu::Menu(const MenuProperties &p) +: MenuProperties(p) , selected(0) -, topRow(0) -, charsPerNumber(0) -, charsPerAdditionalText(0) -, additionalTextGap(0) -, delimiter(':') { +, topRow(0) { } template Menu::Menu(const Font *font, const Font *disabledFont, const Sprite *cursor, int charsPerEntry, int rows, int rowGap, int iconSpace, int cols, int colGap, int charsPerNumber, char delimiter, int charsPerAdditionalText, int additionalTextGap) -: font(font) -, disabledFont(disabledFont ? disabledFont : font) -, cursor(cursor) -, charsPerEntry(charsPerEntry) -, rows(rows) -, rowGap(rowGap) -, iconSpace(iconSpace) -, cols(cols) -, colGap(colGap) +: MenuProperties( + font, disabledFont ? disabledFont : font, + cursor, charsPerEntry, + rows, rowGap, iconSpace, + cols, colGap, charsPerNumber, + delimiter, + charsPerAdditionalText, + additionalTextGap) , selected(0) -, topRow(0) -, charsPerNumber(charsPerNumber) -, charsPerAdditionalText(charsPerAdditionalText) -, additionalTextGap(additionalTextGap) -, delimiter(delimiter) { +, topRow(0) { } diff --git a/src/graphics/SimpleAnimation.h b/src/graphics/SimpleAnimation.h index d15c1d9..003a031 100644 --- a/src/graphics/SimpleAnimation.h +++ b/src/graphics/SimpleAnimation.h @@ -21,6 +21,11 @@ public: SimpleAnimation(const Sprite *sprite, int frameTime, int numFrames, int col = 0, int row = 0, bool repeat = false) : Animation(sprite, frameTime, repeat), numFrames(numFrames), col(col), row(row) { } +public: + void SetNumFrames(int n) { numFrames = n; } + void SetCol(int c) { col = c; } + void SetRow(int r) { row = r; } + protected: virtual int NumFrames() const { return numFrames; }; virtual int Col(int frame) const { return col; } diff --git a/src/graphics/Sprite.h b/src/graphics/Sprite.h index f6f3b7b..2af95f8 100644 --- a/src/graphics/Sprite.h +++ b/src/graphics/Sprite.h @@ -17,6 +17,7 @@ namespace graphics { class Sprite { public: + Sprite() : surface(0), size(64, 64), offset() { } Sprite(SDL_Surface *s, int width, int height, int xOffset = 0, int yOffset = 0) : surface(s), size(width, height), offset(xOffset, yOffset) { } @@ -37,6 +38,11 @@ public: Draw(dest, position + offset, col, row); } +public: + void SetSurface(SDL_Surface *s) { surface = s; } + void SetSize(const geometry::Vector &s) { size = s; } + void SetOffset(const geometry::Vector &o) { offset = o; } + private: SDL_Surface *surface; geometry::Vector size; diff --git a/src/loader/Interpreter.cpp b/src/loader/Interpreter.cpp new file mode 100644 index 0000000..fcfe473 --- /dev/null +++ b/src/loader/Interpreter.cpp @@ -0,0 +1,1249 @@ +/* + * Interpreter.cpp + * + * Created on: Aug 26, 2012 + * Author: holy + */ + +#include "Interpreter.h" + +#include "ParsedSource.h" +#include "../battle/Hero.h" +#include "../battle/Monster.h" +#include "../battle/PartyLayout.h" +#include "../battle/Resources.h" +#include "../common/Ikari.h" +#include "../common/Item.h" +#include "../common/Spell.h" +#include "../common/TargetingMode.h" +#include "../graphics/ComplexAnimation.h" +#include "../graphics/Font.h" +#include "../graphics/Frame.h" +#include "../graphics/Gauge.h" +#include "../graphics/Menu.h" +#include "../graphics/SimpleAnimation.h" +#include "../graphics/Sprite.h" + +#include +#include +#include + +using battle::Hero; +using battle::Monster; +using battle::PartyLayout; +using battle::Stats; +using common::Ikari; +using common::Item; +using common::Spell; +using common::TargetingMode; +using graphics::Animation; +using graphics::Color; +using graphics::Font; +using graphics::Frame; +using graphics::Gauge; +using graphics::ComplexAnimation; +using graphics::SimpleAnimation; +using graphics::Sprite; +using geometry::Vector; +using std::make_pair; +using std::map; +using std::set; +using std::string; +using std::vector; + +namespace loader { + +Interpreter::~Interpreter() { + for (vector::const_iterator i(battleResources.begin()), end(battleResources.end()); i != end; ++i) { + delete *i; + } + for (vector::const_iterator i(complexAnimations.begin()), end(complexAnimations.end()); i != end; ++i) { + delete *i; + } + for (vector::const_iterator i(fonts.begin()), end(fonts.end()); i != end; ++i) { + delete *i; + } + for (vector::const_iterator i(frames.begin()), end(frames.end()); i != end; ++i) { + delete *i; + } + for (vector::const_iterator i(gauges.begin()), end(gauges.end()); i != end; ++i) { + delete *i; + } + for (vector::const_iterator i(heroes.begin()), end(heroes.end()); i != end; ++i) { + delete *i; + } + for (vector::const_iterator i(ikaris.begin()), end(ikaris.end()); i != end; ++i) { + delete *i; + } + for (vector::const_iterator i(images.begin()), end(images.end()); i != end; ++i) { + SDL_FreeSurface(*i); + } + for (vector::const_iterator i(items.begin()), end(items.end()); i != end; ++i) { + delete *i; + } + for (vector::const_iterator i(menuProperties.begin()), end(menuProperties.end()); i != end; ++i) { + delete *i; + } + for (vector::const_iterator i(monsters.begin()), end(monsters.end()); i != end; ++i) { + delete *i; + } + for (vector::const_iterator i(partyLayouts.begin()), end(partyLayouts.end()); i != end; ++i) { + delete *i; + } + for (vector::const_iterator i(simpleAnimations.begin()), end(simpleAnimations.end()); i != end; ++i) { + delete *i; + } + for (vector::const_iterator i(spells.begin()), end(spells.end()); i != end; ++i) { + delete *i; + } + for (vector::const_iterator i(sprites.begin()), end(sprites.end()); i != end; ++i) { + delete *i; + } + for (vector::const_iterator i(strings.begin()), end(strings.end()); i != end; ++i) { + delete *i; + } + for (vector::const_iterator i(targetingModes.begin()), end(targetingModes.end()); i != end; ++i) { + delete *i; + } +} + + +Animation *Interpreter::GetAnimation(const std::string &name) { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == COMPLEX_ANIMATION) { + return complexAnimations[i->second.index]; + } else if (i->second.type == SIMPLE_ANIMATION) { + return simpleAnimations[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to Animation"); + } + } else { + throw Error("access to undefined Animation " + name); + } +} + +battle::Resources *Interpreter::GetBattleResources(const std::string &name) { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == BATTLE_RESOURCES) { + return battleResources[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to BattleResources"); + } + } else { + throw Error("access to undefined BattleResources " + name); + } +} + +bool Interpreter::GetBoolean(const std::string &name) const { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == BOOLEAN) { + return booleans[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to Boolean"); + } + } else { + throw Error("access to undefined Boolean " + name); + } +} + +const Color &Interpreter::GetColor(const std::string &name) const { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == COLOR) { + return colors[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to Color"); + } + } else { + throw Error("access to undefined Color " + name); + } +} + +Font *Interpreter::GetFont(const std::string &name) { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == FONT) { + return fonts[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to Font"); + } + } else { + throw Error("access to undefined Font " + name); + } +} + +Frame *Interpreter::GetFrame(const std::string &name) { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == FRAME) { + return frames[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to Frame"); + } + } else { + throw Error("access to undefined Frame " + name); + } +} + +Gauge *Interpreter::GetGauge(const std::string &name) { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == GAUGE) { + return gauges[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to Gauge"); + } + } else { + throw Error("access to undefined Gauge " + name); + } +} + +Hero *Interpreter::GetHero(const std::string &name) { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == HERO) { + return heroes[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to Hero"); + } + } else { + throw Error("access to undefined Hero " + name); + } +} + +Ikari *Interpreter::GetIkari(const std::string &name) { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == IKARI) { + return ikaris[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to Ikari"); + } + } else { + throw Error("access to undefined Ikari " + name); + } +} + +Item *Interpreter::GetItem(const std::string &name) { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == ITEM) { + return items[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to Item"); + } + } else { + throw Error("access to undefined Item " + name); + } +} + +graphics::MenuProperties *Interpreter::GetMenuProperties(const std::string &name) { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == MENU_PROPERTIES) { + return menuProperties[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to MenuProperties"); + } + } else { + throw Error("access to undefined MenuProperties " + name); + } +} + +Monster *Interpreter::GetMonster(const std::string &name) { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == MONSTER) { + return monsters[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to Monster"); + } + } else { + throw Error("access to undefined Monster " + name); + } +} + +int Interpreter::GetNumber(const std::string &name) const { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == NUMBER) { + return numbers[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to Number"); + } + } else { + throw Error("access to undefined Number " + name); + } +} + +PartyLayout *Interpreter::GetPartyLayout(const std::string &name) { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == PARTY_LAYOUT) { + return partyLayouts[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to PartyLayout"); + } + } else { + throw Error("access to undefined PartyLayout " + name); + } +} + +const char *Interpreter::GetPath(const std::string &name) const { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == PATH) { + return strings[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to Path"); + } + } else { + throw Error("access to undefined Path " + name); + } +} + +Spell *Interpreter::GetSpell(const std::string &name) { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == SPELL) { + return spells[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to Spell"); + } + } else { + throw Error("access to undefined Spell " + name); + } +} + +Sprite *Interpreter::GetSprite(const std::string &name) { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == SPRITE) { + return sprites[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to Sprite"); + } + } else { + throw Error("access to undefined Sprite " + name); + } +} + +const char *Interpreter::GetString(const std::string &name) const { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + // TODO: enable path to string casting some time + if (i->second.type == STRING /* || i->second.type == PATH */) { + return strings[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to String"); + } + } else { + throw Error("access to undefined String " + name); + } +} + +TargetingMode *Interpreter::GetTargetingMode(const std::string &name) { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == TARGETING_MODE) { + return targetingModes[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to TargetingMode"); + } + } else { + throw Error("access to undefined TargetingMode " + name); + } +} + +Vector Interpreter::GetVector(const std::string &name) const { + map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + if (i->second.type == VECTOR) { + return vectors[i->second.index]; + } else { + throw Error("cannot cast " + i->second.dfn->TypeName() + " to Vector"); + } + } else { + throw Error("access to undefined Vector " + name); + } +} + + +void Interpreter::ReadSource() { + for (set::const_iterator i(source.Exports().begin()), end(source.Exports().end()); i != end; ++i) { + ReadDefinition(source.GetDefinition(*i)); + } +} + +void Interpreter::ReadDefinition(const Definition &dfn) { + if (parsedDefinitions.find(dfn.Identifier()) != parsedDefinitions.end()) { + return; + } + if (dfn.HasLiteralValue()) { + ReadLiteral(dfn); + } else { + ReadObject(dfn); + } +} + +void Interpreter::ReadLiteral(const Definition &dfn) { + switch (dfn.GetLiteral()->GetType()) { + case Literal::ARRAY_VALUES: + valueArrays.push_back(dfn.GetLiteral()->GetValues()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, VALUE_ARRAY, valueArrays.size() - 1))); + break; + case Literal::ARRAY_PROPS: + propertyListArrays.push_back(dfn.GetLiteral()->GetPropertyLists()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, PROPERTY_LIST_ARRAY, propertyListArrays.size() - 1))); + break; + case Literal::BOOLEAN: + booleans.push_back(dfn.GetLiteral()->GetBoolean()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, BOOLEAN, booleans.size() - 1))); + break; + case Literal::COLOR: + colors.push_back(Color(dfn.GetLiteral()->GetRed(), dfn.GetLiteral()->GetGreen(), dfn.GetLiteral()->GetBlue(), dfn.GetLiteral()->GetAlpha())); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, COLOR, colors.size() - 1))); + break; + case Literal::NUMBER: + numbers.push_back(dfn.GetLiteral()->GetNumber()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, NUMBER, numbers.size() - 1))); + break; + case Literal::PATH: + { + char *str(new char[dfn.GetLiteral()->GetString().size() + 1]); + std::memcpy(str, dfn.GetLiteral()->GetString().c_str(), dfn.GetLiteral()->GetString().size()); + str[dfn.GetLiteral()->GetString().size()] = '\0'; + strings.push_back(str); + } + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, PATH, strings.size() - 1))); + break; + case Literal::STRING: + { + char *str(new char[dfn.GetLiteral()->GetString().size() + 1]); + std::memcpy(str, dfn.GetLiteral()->GetString().c_str(), dfn.GetLiteral()->GetString().size()); + str[dfn.GetLiteral()->GetString().size()] = '\0'; + strings.push_back(str); + } + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, STRING, strings.size() - 1))); + break; + case Literal::VECTOR: + vectors.push_back(Vector(dfn.GetLiteral()->GetX(), dfn.GetLiteral()->GetY())); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, VECTOR, vectors.size() - 1))); + break; + case Literal::OBJECT: + ReadObject(dfn); + break; + } +} + +Animation *Interpreter::GetAnimation(const Value &v) { + if (v.IsLiteral()) { + if (v.GetLiteral().GetTypeName() == "ComplexAnimation") { + ComplexAnimation *a(new ComplexAnimation); + ReadComplexAnimation(*a, *v.GetLiteral().GetProperties()); + complexAnimations.push_back(a); + return a; + } else { + SimpleAnimation *a(new SimpleAnimation); + ReadSimpleAnimation(*a, *v.GetLiteral().GetProperties()); + simpleAnimations.push_back(a); + return a; + } + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetAnimation(v.GetIdentifier()); + } +} + +battle::Resources *Interpreter::GetBattleResources(const Value &v) { + if (v.IsLiteral()) { + battle::Resources *r(new battle::Resources); + ReadBattleResources(*r, *v.GetLiteral().GetProperties()); + return r; + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetBattleResources(v.GetIdentifier()); + } +} + +bool Interpreter::GetBoolean(const Value &v) { + if (v.IsLiteral()) { + return v.GetLiteral().GetBoolean(); + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetBoolean(v.GetIdentifier()); + } +} + +Color Interpreter::GetColor(const Value &v) { + if (v.IsLiteral()) { + return Color(v.GetLiteral().GetRed(), v.GetLiteral().GetGreen(), v.GetLiteral().GetBlue(), v.GetLiteral().GetAlpha()); + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetColor(v.GetIdentifier()); + } +} + +Font *Interpreter::GetFont(const Value &v) { + if (v.IsLiteral()) { + Font *f(new Font); + ReadFont(*f, *v.GetLiteral().GetProperties()); + return f; + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetFont(v.GetIdentifier()); + } +} + +Frame *Interpreter::GetFrame(const Value &v) { + if (v.IsLiteral()) { + Frame *f(new Frame); + ReadFrame(*f, *v.GetLiteral().GetProperties()); + return f; + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetFrame(v.GetIdentifier()); + } +} + +Gauge *Interpreter::GetGauge(const Value &v) { + if (v.IsLiteral()) { + Gauge *g(new Gauge); + ReadGauge(*g, *v.GetLiteral().GetProperties()); + return g; + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetGauge(v.GetIdentifier()); + } +} + +Hero *Interpreter::GetHero(const Value &v) { + if (v.IsLiteral()) { + Hero *h(new Hero); + ReadHero(*h, *v.GetLiteral().GetProperties()); + return h; + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetHero(v.GetIdentifier()); + } +} + +Ikari *Interpreter::GetIkari(const Value &v) { + if (v.IsLiteral()) { + Ikari *i(new Ikari); + ReadIkari(*i, *v.GetLiteral().GetProperties()); + return i; + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetIkari(v.GetIdentifier()); + } +} + +SDL_Surface *Interpreter::GetImage(const Value &v) { + string path(GetPath(v)); + map::const_iterator i(imageCache.find(path)); + if (i == imageCache.end()) { + SDL_Surface *image(IMG_Load(path.c_str())); + images.push_back(image); + imageCache.insert(make_pair(path, image)); + return image; + } else { + return i->second; + } +} + +Item *Interpreter::GetItem(const Value &v) { + if (v.IsLiteral()) { + Item *i(new Item); + ReadItem(*i, *v.GetLiteral().GetProperties()); + return i; + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetItem(v.GetIdentifier()); + } +} + +graphics::MenuProperties *Interpreter::GetMenuProperties(const Value &v) { + if (v.IsLiteral()) { + graphics::MenuProperties *m(new graphics::MenuProperties); + ReadMenuProperties(*m, *v.GetLiteral().GetProperties()); + return m; + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetMenuProperties(v.GetIdentifier()); + } +} + +Monster *Interpreter::GetMonster(const Value &v) { + if (v.IsLiteral()) { + Monster *m(new Monster); + ReadMonster(*m, *v.GetLiteral().GetProperties()); + return m; + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetMonster(v.GetIdentifier()); + } +} + +int Interpreter::GetNumber(const Value &v) { + if (v.IsLiteral()) { + return v.GetLiteral().GetNumber(); + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetNumber(v.GetIdentifier()); + } +} + +PartyLayout *Interpreter::GetPartyLayout(const Value &v) { + if (v.IsLiteral()) { + PartyLayout *l(new PartyLayout); + ReadPartyLayout(*l, *v.GetLiteral().GetProperties()); + return l; + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetPartyLayout(v.GetIdentifier()); + } +} + +const char *Interpreter::GetPath(const Value &v) { + if (v.IsLiteral()) { + return v.GetLiteral().GetString().c_str(); + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetPath(v.GetIdentifier()); + } +} + +const PropertyList *Interpreter::GetPropertyList(const Value &v) { + if (v.IsLiteral()) { + return v.GetLiteral().GetProperties(); + } else { + throw Error("cannot reference property lists"); + } +} + +const vector &Interpreter::GetPropertyListArray(const Value &v) { + if (v.IsLiteral()) { + return v.GetLiteral().GetPropertyLists(); + } else { + throw Error("cannot reference property list arrays"); + } +} + +Spell *Interpreter::GetSpell(const Value &v) { + if (v.IsLiteral()) { + Spell *s(new Spell); + ReadSpell(*s, *v.GetLiteral().GetProperties()); + return s; + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetSpell(v.GetIdentifier()); + } +} + +Sprite *Interpreter::GetSprite(const Value &v) { + if (v.IsLiteral()) { + Sprite *s(new Sprite); + ReadSprite(*s, *v.GetLiteral().GetProperties()); + return s; + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetSprite(v.GetIdentifier()); + } +} + +const char *Interpreter::GetString(const Value &v) { + if (v.IsLiteral()) { + return v.GetLiteral().GetString().c_str(); + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetString(v.GetIdentifier()); + } +} + +TargetingMode *Interpreter::GetTargetingMode(const Value &v) { + if (v.IsLiteral()) { + TargetingMode *t(new TargetingMode); + ReadTargetingMode(*t, *v.GetLiteral().GetProperties()); + return t; + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetTargetingMode(v.GetIdentifier()); + } +} + +Vector Interpreter::GetVector(const Value &v) { + if (v.IsLiteral()) { + return Vector(v.GetLiteral().GetX(), v.GetLiteral().GetY()); + } else { + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetVector(v.GetIdentifier()); + } +} + +const vector &Interpreter::GetValueArray(const Value &v) { + if (v.IsLiteral()) { + return v.GetLiteral().GetValues(); + } else { + throw Error("cannot reference value arrays"); + } +} + + +void Interpreter::ReadObject(const Definition &dfn) { + if (dfn.TypeName() == "BattleResources") { + battle::Resources *res(new battle::Resources); + int index(battleResources.size()); + battleResources.push_back(res); + ReadBattleResources(*res, *dfn.GetProperties()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, BATTLE_RESOURCES, index))); + } else if (dfn.TypeName() == "ComplexAnimation") { + ComplexAnimation *animation(new ComplexAnimation); + int index(complexAnimations.size()); + complexAnimations.push_back(animation); + ReadComplexAnimation(*animation, *dfn.GetProperties()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, COMPLEX_ANIMATION, index))); + } else if (dfn.TypeName() == "Font") { + Font *font(new Font); + int index(fonts.size()); + fonts.push_back(font); + ReadFont(*font, *dfn.GetProperties()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, FONT, index))); + } else if (dfn.TypeName() == "Frame") { + Frame *frame(new Frame); + int index(frames.size()); + frames.push_back(frame); + ReadFrame(*frame, *dfn.GetProperties()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, FRAME, index))); + } else if (dfn.TypeName() == "Gauge") { + Gauge *gauge(new Gauge); + int index(gauges.size()); + gauges.push_back(gauge); + ReadGauge(*gauge, *dfn.GetProperties()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, GAUGE, index))); + } else if (dfn.TypeName() == "Hero") { + Hero *hero(new Hero); + int index(heroes.size()); + heroes.push_back(hero); + ReadHero(*hero, *dfn.GetProperties()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, HERO, index))); + } else if (dfn.TypeName() == "Ikari") { + Ikari *ikari(new Ikari); + int index(ikaris.size()); + ikaris.push_back(ikari); + ReadIkari(*ikari, *dfn.GetProperties()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, IKARI, index))); + } else if (dfn.TypeName() == "Item") { + Item *item(new Item); + int index(items.size()); + items.push_back(item); + ReadItem(*item, *dfn.GetProperties()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, ITEM, index))); + } else if (dfn.TypeName() == "MenuProperties") { + graphics::MenuProperties *mprops(new graphics::MenuProperties); + int index(menuProperties.size()); + menuProperties.push_back(mprops); + ReadMenuProperties(*mprops, *dfn.GetProperties()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, MENU_PROPERTIES, index))); + } else if (dfn.TypeName() == "Monster") { + Monster *monster(new Monster); + int index(monsters.size()); + monsters.push_back(monster); + ReadMonster(*monster, *dfn.GetProperties()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, MONSTER, index))); + } else if (dfn.TypeName() == "PartyLayout") { + PartyLayout *layout(new PartyLayout); + int index(partyLayouts.size()); + partyLayouts.push_back(layout); + ReadPartyLayout(*layout, *dfn.GetProperties()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, PARTY_LAYOUT, index))); + } else if (dfn.TypeName() == "SimpleAnimation") { + SimpleAnimation *animation(new SimpleAnimation); + int index(simpleAnimations.size()); + simpleAnimations.push_back(animation); + ReadSimpleAnimation(*animation, *dfn.GetProperties()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, SIMPLE_ANIMATION, index))); + } else if (dfn.TypeName() == "Spell") { + Spell *spell(new Spell); + int index(spells.size()); + spells.push_back(spell); + ReadSpell(*spell, *dfn.GetProperties()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, SPELL, index))); + } else if (dfn.TypeName() == "Sprite") { + Sprite *sprite(new Sprite); + int index(sprites.size()); + sprites.push_back(sprite); + ReadSprite(*sprite, *dfn.GetProperties()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, SPRITE, index))); + } else if (dfn.TypeName() == "TargetingMode") { + TargetingMode *mode(new TargetingMode); + int index(targetingModes.size()); + targetingModes.push_back(mode); + ReadTargetingMode(*mode, *dfn.GetProperties()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, TARGETING_MODE, index))); + } else { + throw Error("unhandled object type: " + dfn.TypeName()); + } +} + + +void Interpreter::ReadBattleResources(battle::Resources &res, const PropertyList &props) { + for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { + if (i->first == "swapCursor") { + res.swapCursor = GetSprite(*i->second); + } else if (i->first == "moveIcons") { + res.moveIcons = GetSprite(*i->second); + } else if (i->first == "attackIcons") { + res.attackIcons = GetSprite(*i->second); + } else if (i->first == "attackChoiceIcons") { + res.attackChoiceIcons = GetSprite(*i->second); + } else if (i->first == "titleFrame") { + res.titleFrame = GetFrame(*i->second); + } else if (i->first == "titleFont") { + res.titleFont = GetFont(*i->second); + } else if (i->first == "heroTagFrame") { + res.heroTagFrame = GetFrame(*i->second); + } else if (i->first == "activeHeroTagFrame") { + res.activeHeroTagFrame = GetFrame(*i->second); + } else if (i->first == "smallHeroTagFrame") { + res.smallHeroTagFrame = GetFrame(*i->second); + } else if (i->first == "lastSmallHeroTagFrame") { + res.lastSmallHeroTagFrame = GetFrame(*i->second); + } else if (i->first == "heroTagFont") { + res.heroTagFont = GetFont(*i->second); + } else if (i->first == "heroTagLabels") { + res.heroTagLabels = GetSprite(*i->second); + } else if (i->first == "healthGauge") { + res.healthGauge = GetGauge(*i->second); + } else if (i->first == "manaGauge") { + res.manaGauge = GetGauge(*i->second); + } else if (i->first == "ikariGauge") { + res.ikariGauge = GetGauge(*i->second); + } else if (i->first == "selectFrame") { + res.selectFrame = GetFrame(*i->second); + } else if (i->first == "normalFont") { + res.normalFont = GetFont(*i->second); + } else if (i->first == "disabledFont") { + res.disabledFont = GetFont(*i->second); + } else if (i->first == "menuCursor") { + res.menuCursor = GetSprite(*i->second); + } else if (i->first == "weaponTargetCursor") { + res.weaponTargetCursor = GetSprite(*i->second); + } else if (i->first == "magicTargetCursor") { + res.magicTargetCursor = GetSprite(*i->second); + } else if (i->first == "itemTargetCursor") { + res.itemTargetCursor = GetSprite(*i->second); + } else if (i->first == "spellMenuHeadline") { + res.spellMenuHeadline = GetString(*i->second); + } else if (i->first == "spellMenuProperties") { + res.spellMenuProperties = GetMenuProperties(*i->second); + } else if (i->first == "itemMenuHeadline") { + res.itemMenuHeadline = GetString(*i->second); + } else if (i->first == "itemMenuProperties") { + res.itemMenuProperties = GetMenuProperties(*i->second); + } else if (i->first == "ikariMenuHeadline") { + res.ikariMenuHeadline = GetString(*i->second); + } else if (i->first == "ikariMenuProperties") { + res.ikariMenuProperties = GetMenuProperties(*i->second); + } else if (i->first == "noEquipmentText") { + res.noEquipmentText = GetString(*i->second); + } else if (i->first == "escapeText") { + res.escapeText = GetString(*i->second); + } else if (i->first == "numberAnimationPrototype") { + res.numberAnimationPrototype = GetAnimation(*i->second); + } else if (i->first == "bigNumberSprite") { + res.bigNumberSprite = GetSprite(*i->second); + } else if (i->first == "greenNumberSprite") { + res.greenNumberSprite = GetSprite(*i->second); + } else if (i->first == "weaponMenuIcon") { + res.weaponMenuIcon = GetSprite(*i->second); + } else if (i->first == "armorMenuIcon") { + res.armorMenuIcon = GetSprite(*i->second); + } else if (i->first == "shieldMenuIcon") { + res.shieldMenuIcon = GetSprite(*i->second); + } else if (i->first == "helmetMenuIcon") { + res.helmetMenuIcon = GetSprite(*i->second); + } else if (i->first == "ringMenuIcon") { + res.ringMenuIcon = GetSprite(*i->second); + } else if (i->first == "jewelMenuIcon") { + res.jewelMenuIcon = GetSprite(*i->second); + } else if (i->first == "levelLabelCol") { + res.levelLabelCol = GetNumber(*i->second); + } else if (i->first == "levelLabelRow") { + res.levelLabelRow = GetNumber(*i->second); + } else if (i->first == "healthLabelCol") { + res.healthLabelCol = GetNumber(*i->second); + } else if (i->first == "healthLabelRow") { + res.healthLabelRow = GetNumber(*i->second); + } else if (i->first == "manaLabelCol") { + res.manaLabelCol = GetNumber(*i->second); + } else if (i->first == "manaLabelRow") { + res.manaLabelRow = GetNumber(*i->second); + } else if (i->first == "moveLabelCol") { + res.moveLabelCol = GetNumber(*i->second); + } else if (i->first == "moveLabelRow") { + res.moveLabelRow = GetNumber(*i->second); + } else if (i->first == "ikariLabelCol") { + res.ikariLabelCol = GetNumber(*i->second); + } else if (i->first == "ikariLabelRow") { + res.ikariLabelRow = GetNumber(*i->second); + } else if (i->first == "heroesBgColor") { + res.heroesBgColor = GetColor(*i->second); + } else { + throw Error("unknown BattleResources property: " + i->first); + } + } +} + +void Interpreter::ReadComplexAnimation(ComplexAnimation &a, const PropertyList &props) { + for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { + if (i->first == "sprite") { + a.SetSprite(GetSprite(*i->second)); + } else if (i->first == "frametime") { + a.SetFrameTime(GetNumber(*i->second)); + } else if (i->first == "repeat") { + a.SetRepeat(GetBoolean(*i->second)); + } else if (i->first == "frames") { + const vector &values(GetPropertyListArray(*i->second)); + for (vector::const_iterator i(values.begin()), end(values.end()); i != end; ++i) { + ComplexAnimation::FrameProp frame; + ReadComplexAnimationFrame(frame, **i); + a.AddFrame(frame); + } + } else { + throw Error("unknown ComplexAnimation property: " + i->first); + } + } +} + +void Interpreter::ReadComplexAnimationFrame(ComplexAnimation::FrameProp &f, const PropertyList &props) { + for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { + if (i->first == "column") { + f.col = GetNumber(*i->second); + } else if (i->first == "row") { + f.row = GetNumber(*i->second); + } else if (i->first == "disposition") { + f.disposition = GetVector(*i->second); + } else { + throw Error("unknown ComplexAnimationFrame property: " + i->first); + } + } +} + +void Interpreter::ReadFont(Font &f, const PropertyList &props) { + for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { + if (i->first == "sprite") { + f.SetSprite(GetSprite(*i->second)); + } else if (i->first == "columnoffset") { + f.SetColOffset(GetNumber(*i->second)); + } else if (i->first == "rowoffset") { + f.SetRowOffset(GetNumber(*i->second)); + } else { + throw Error("unknown Font property: " + i->first); + } + } +} + +void Interpreter::ReadFrame(Frame &f, const PropertyList &props) { + for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { + if (i->first == "image") { + f.SetSurface(GetImage(*i->second)); + } else if (i->first == "border") { + f.SetBorderSize(GetVector(*i->second)); + } else if (i->first == "repeat") { + f.SetRepeatSize(GetVector(*i->second)); + } else if (i->first == "offset") { + f.SetOffset(GetVector(*i->second)); + } else { + throw Error("unknown Frame property: " + i->first); + } + } +} + +void Interpreter::ReadGauge(Gauge &g, const PropertyList &props) { + for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { + if (i->first == "image") { + g.SetSurface(GetImage(*i->second)); + } else if (i->first == "full") { + g.SetFullOffset(GetVector(*i->second)); + } else if (i->first == "empty") { + g.SetEmptyOffset(GetVector(*i->second)); + } else if (i->first == "height") { + g.SetHeight(GetNumber(*i->second)); + } else if (i->first == "start") { + g.SetStartWidth(GetNumber(*i->second)); + } else if (i->first == "repeat") { + g.SetRepeatWidth(GetNumber(*i->second)); + } else if (i->first == "end") { + g.SetEndWidth(GetNumber(*i->second)); + } else { + throw Error("unknown Gauge property: " + i->first); + } + } +} + +void Interpreter::ReadIkari(Ikari &ikari, const PropertyList &props) { + for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { + if (i->first == "name") { + ikari.SetName(GetString(*i->second)); + } else if (i->first == "cost") { + ikari.SetCost(GetNumber(*i->second)); + } else if (i->first == "targets") { + ikari.GetTargetingMode() = *GetTargetingMode(*i->second); + } else if (i->first == "magical") { + if (GetBoolean(*i->second)) { + ikari.SetMagical(); + } + } else if (i->first == "physical") { + if (GetBoolean(*i->second)) { + ikari.SetPhysical(); + } + } else { + throw Error("unknown Ikari property: " + i->first); + } + } +} + +void Interpreter::ReadItem(Item &item, const PropertyList &props) { + for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { + if (i->first == "name") { + item.SetName(GetString(*i->second)); + } else if (i->first == "menuicon") { + item.SetMenuIcon(GetSprite(*i->second)); + } else if (i->first == "battle") { + if (GetBoolean(*i->second)) { + item.SetUsableInBattle(); + } + } else if (i->first == "targets") { + item.GetTargetingMode() = *GetTargetingMode(*i->second); + } else if (i->first == "ikari") { + item.SetIkari(GetIkari(*i->second)); + } else if (i->first == "attackanimation") { + item.SetAttackAnimation(GetAnimation(*i->second)); + } else { + throw Error("unknown Item property: " + i->first); + } + } +} + +void Interpreter::ReadHero(Hero &h, const PropertyList &props) { + for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { + if (i->first == "name") { + h.SetName(GetString(*i->second)); + } else if (i->first == "sprite") { + h.SetSprite(GetSprite(*i->second)); + } else if (i->first == "level") { + h.SetLevel(GetNumber(*i->second)); + } else if (i->first == "maxHealth") { + h.SetMaxHealth(GetNumber(*i->second)); + } else if (i->first == "health") { + h.SetHealth(GetNumber(*i->second)); + } else if (i->first == "maxMana") { + h.SetMaxMana(GetNumber(*i->second)); + } else if (i->first == "mana") { + h.SetMana(GetNumber(*i->second)); + } else if (i->first == "ip") { + h.SetIP(GetNumber(*i->second)); + } else if (i->first == "stats") { + battle::Stats stats; + ReadStats(stats, *GetPropertyList(*i->second)); + h.SetStats(stats); + } else if (i->first == "attackAnimation") { + h.SetAttackAnimation(GetAnimation(*i->second)); + } else if (i->first == "spellAnimation") { + h.SetSpellAnimation(GetAnimation(*i->second)); + } else if (i->first == "meleeAnimation") { + h.SetMeleeAnimation(GetAnimation(*i->second)); + } else { + throw Error("unknown Hero property: " + i->first); + } + } +} + +void Interpreter::ReadMenuProperties(graphics::MenuProperties &mprops, const PropertyList &props) { + for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { + if (i->first == "font") { + mprops.font = GetFont(*i->second); + } else if (i->first == "disabledFont") { + mprops.disabledFont = GetFont(*i->second); + } else if (i->first == "cursor") { + mprops.cursor = GetSprite(*i->second); + } else if (i->first == "charsPerEntry") { + mprops.charsPerEntry = GetNumber(*i->second); + } else if (i->first == "rows") { + mprops.rows = GetNumber(*i->second); + } else if (i->first == "rowGap") { + mprops.rowGap = GetNumber(*i->second); + } else if (i->first == "iconSpace") { + mprops.iconSpace = GetNumber(*i->second); + } else if (i->first == "cols") { + mprops.cols = GetNumber(*i->second); + } else if (i->first == "colGap") { + mprops.colGap = GetNumber(*i->second); + } else if (i->first == "delimiter") { + mprops.delimiter = *GetString(*i->second); + } else if (i->first == "charsPerNumber") { + mprops.charsPerNumber = GetNumber(*i->second); + } else if (i->first == "charsPerAdditionalText") { + mprops.charsPerAdditionalText = GetNumber(*i->second); + } else if (i->first == "additionalTextGap") { + mprops.additionalTextGap = GetNumber(*i->second); + } else { + throw Error("unknown MenuProperties property: " + i->first); + } + } +} + +void Interpreter::ReadMonster(Monster &m, const PropertyList &props) { + for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { + if (i->first == "name") { + m.SetName(GetString(*i->second)); + } else if (i->first == "sprite") { + m.SetSprite(GetSprite(*i->second)); + } else if (i->first == "level") { + m.SetLevel(GetNumber(*i->second)); + } else if (i->first == "maxHealth") { + m.SetMaxHealth(GetNumber(*i->second)); + } else if (i->first == "health") { + m.SetHealth(GetNumber(*i->second)); + } else if (i->first == "maxMana") { + m.SetMaxMana(GetNumber(*i->second)); + } else if (i->first == "mana") { + m.SetMana(GetNumber(*i->second)); + } else if (i->first == "stats") { + battle::Stats stats; + ReadStats(stats, *GetPropertyList(*i->second)); + m.SetStats(stats); + } else if (i->first == "attackAnimation") { + m.SetAttackAnimation(GetAnimation(*i->second)); + } else if (i->first == "meleeAnimation") { + m.SetMeleeAnimation(GetAnimation(*i->second)); + } else { + throw Error("unknown Monster property: " + i->first); + } + } +} + +void Interpreter::ReadPartyLayout(PartyLayout &p, const PropertyList &props) { + for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { + if (i->first == "positions") { + const vector &positions(GetValueArray(*i->second)); + for (vector::const_iterator j(positions.begin()), end(positions.end()); j != end; ++j) { + p.AddPosition(GetVector(**j)); + } + } else { + throw Error("unknown PartyLayout property: " + i->first); + } + } +} + +void Interpreter::ReadSimpleAnimation(SimpleAnimation &a, const PropertyList &props) { + for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { + if (i->first == "sprite") { + a.SetSprite(GetSprite(*i->second)); + } else if (i->first == "frametime") { + a.SetFrameTime(GetNumber(*i->second)); + } else if (i->first == "repeat") { + a.SetRepeat(GetBoolean(*i->second)); + } else if (i->first == "framecount") { + a.SetNumFrames(GetNumber(*i->second)); + } else if (i->first == "col") { + a.SetCol(GetNumber(*i->second)); + } else if (i->first == "row") { + a.SetRow(GetNumber(*i->second)); + } else { + throw Error("unknown SimpleAnimation property: " + i->first); + } + } +} + +void Interpreter::ReadSpell(Spell &s, const PropertyList &props) { + for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { + if (i->first == "name") { + s.SetName(GetString(*i->second)); + } else if (i->first == "cost") { + s.SetCost(GetNumber(*i->second)); + } else if (i->first == "battle") { + if (GetBoolean(*i->second)) { + s.SetUsableInBattle(); + } + } else if (i->first == "targets") { + s.GetTargetingMode() = *GetTargetingMode(*i->second); + } else { + throw Error("unknown Spell property: " + i->first); + } + } +} + +void Interpreter::ReadSprite(Sprite &s, const PropertyList &props) { + for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { + if (i->first == "image") { + s.SetSurface(GetImage(*i->second)); + } else if (i->first == "size") { + s.SetSize(GetVector(*i->second)); + } else if (i->first == "offset") { + s.SetOffset(GetVector(*i->second)); + } else { + throw Error("unknown Sprite property: " + i->first); + } + } +} + +void Interpreter::ReadStats(Stats &s, const PropertyList &props) { + for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { + if (i->first == "atp") { + s.SetAttack(GetNumber(*i->second)); + } else if (i->first == "dfp") { + s.SetDefense(GetNumber(*i->second)); + } else if (i->first == "str") { + s.SetStrength(GetNumber(*i->second)); + } else if (i->first == "agl") { + s.SetAgility(GetNumber(*i->second)); + } else if (i->first == "int") { + s.SetIntelligence(GetNumber(*i->second)); + } else if (i->first == "gut") { + s.SetGut(GetNumber(*i->second)); + } else if (i->first == "mgr") { + s.SetMagicResistance(GetNumber(*i->second)); + } else { + throw Error("unknown Stats property: " + i->first); + } + } +} + +void Interpreter::ReadTargetingMode(TargetingMode &t, const PropertyList &props) { + for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { + if (i->first == "ally") { + if (GetBoolean(*i->second)) { + t.TargetAlly(); + } else { + t.TargetEnemy(); + } + } else if (i->first == "enemy") { + if (GetBoolean(*i->second)) { + t.TargetEnemy(); + } else { + t.TargetAlly(); + } + } else if (i->first == "all") { + if (GetBoolean(*i->second)) { + t.TargetAll(); + } + } else if (i->first == "multiple") { + if (GetBoolean(*i->second)) { + t.TargetMultiple(); + } + } else if (i->first == "single") { + if (GetBoolean(*i->second)) { + t.TargetSingle(); + } + } else { + throw Error("unknown TargetingMode property: " + i->first); + } + } +} + +} diff --git a/src/loader/Interpreter.h b/src/loader/Interpreter.h new file mode 100644 index 0000000..044a3c0 --- /dev/null +++ b/src/loader/Interpreter.h @@ -0,0 +1,232 @@ +/* + * Interpreter.h + * + * Created on: Aug 26, 2012 + * Author: holy + */ + +#ifndef LOADER_INTERPRETER_H_ +#define LOADER_INTERPRETER_H_ + +#include "../geometry/Vector.h" +#include "../graphics/Color.h" +#include "../graphics/ComplexAnimation.h" + +#include +#include +#include +#include +#include + +namespace battle { + class Hero; + class Monster; + class PartyLayout; + struct Resources; + class Stats; +} + +namespace common { + class Ikari; + class Item; + class Spell; + class TargetingMode; +} + +namespace graphics { + class Animation; + class Font; + class Frame; + class Gauge; + struct MenuProperties; + class SimpleAnimation; + class Sprite; +} + +namespace loader { + +class Definition; +class ParsedSource; +class PropertyList; +class Value; + +class Interpreter { + +public: + class Error: public std::runtime_error { + public: + Error(const std::string &msg) : std::runtime_error("interpreter error: " + msg) { } + }; + +public: + Interpreter(const ParsedSource &source) : source(source) { } + ~Interpreter(); +private: + Interpreter(const Interpreter &); + Interpreter &operator =(const Interpreter &); + +public: + void ReadSource(); + +public: + graphics::Animation *GetAnimation(const std::string &name); + battle::Resources *GetBattleResources(const std::string &name); + bool GetBoolean(const std::string &name) const; + const graphics::Color &GetColor(const std::string &name) const; + graphics::Font *GetFont(const std::string &name); + graphics::Frame *GetFrame(const std::string &name); + graphics::Gauge *GetGauge(const std::string &name); + battle::Hero *GetHero(const std::string &name); + common::Ikari *GetIkari(const std::string &name); + common::Item *GetItem(const std::string &name); + graphics::MenuProperties *GetMenuProperties(const std::string &name); + battle::Monster *GetMonster(const std::string &name); + int GetNumber(const std::string &name) const; + battle::PartyLayout *GetPartyLayout(const std::string &name); + const char *GetPath(const std::string &name) const; + common::Spell *GetSpell(const std::string &name); + graphics::Sprite *GetSprite(const std::string &name); + const char *GetString(const std::string &name) const; + common::TargetingMode *GetTargetingMode(const std::string &name); + geometry::Vector GetVector(const std::string &name) const; + +public: + const std::vector &BattleResources() const { return battleResources; } + const std::vector &Booleans() const { return booleans; } + const std::vector &Colors() const { return colors; } + const std::vector &ComplexAnimations() const { return complexAnimations; } + const std::vector &Fonts() const { return fonts; } + const std::vector &Frames() const { return frames; } + const std::vector &Gauges() const { return gauges; } + const std::vector &Heroes() const { return heroes; } + const std::vector &Ikaris() const { return ikaris; } + const std::vector &Images() const { return images; } + const std::vector &Items() const { return items; } + const std::vector &MenuProperties() const { return menuProperties; } + const std::vector &Monsters() const { return monsters; } + const std::vector &Numbers() const { return numbers; } + const std::vector &PartyLayouts() const { return partyLayouts; } + const std::vector &SimpleAnimations() const { return simpleAnimations; } + const std::vector &Spells() const { return spells; } + const std::vector &Sprites() const { return sprites; } + const std::vector &Strings() const { return strings; } + const std::vector &TargetingModes() const { return targetingModes; } + const std::vector > &Vectors() const { return vectors; } + +private: + void ReadDefinition(const Definition &); + void ReadLiteral(const Definition &); + void ReadObject(const Definition &); + + graphics::Animation *GetAnimation(const Value &); + battle::Resources *GetBattleResources(const Value &); + graphics::Color GetColor(const Value &); + bool GetBoolean(const Value &); + graphics::Font *GetFont(const Value &); + graphics::Frame *GetFrame(const Value &); + graphics::Gauge *GetGauge(const Value &); + battle::Hero *GetHero(const Value &); + common::Ikari *GetIkari(const Value &); + SDL_Surface *GetImage(const Value &); + common::Item *GetItem(const Value &); + graphics::MenuProperties *GetMenuProperties(const Value &); + battle::Monster *GetMonster(const Value &); + int GetNumber(const Value &); + battle::PartyLayout *GetPartyLayout(const Value &); + const PropertyList *GetPropertyList(const Value &); + const std::vector &GetPropertyListArray(const Value &); + const char *GetPath(const Value &); + common::Spell *GetSpell(const Value &); + graphics::Sprite *GetSprite(const Value &); + const char *GetString(const Value &); + common::TargetingMode *GetTargetingMode(const Value &); + const std::vector &GetValueArray(const Value &); + geometry::Vector GetVector(const Value &); + + void ReadBattleResources(battle::Resources &, const PropertyList &); + void ReadComplexAnimation(graphics::ComplexAnimation &, const PropertyList &); + void ReadComplexAnimationFrame(graphics::ComplexAnimation::FrameProp &, const PropertyList &); + void ReadFont(graphics::Font &, const PropertyList &); + void ReadFrame(graphics::Frame &, const PropertyList &); + void ReadGauge(graphics::Gauge &, const PropertyList &); + void ReadHero(battle::Hero &, const PropertyList &); + void ReadIkari(common::Ikari &, const PropertyList &); + void ReadItem(common::Item &, const PropertyList &); + void ReadMenuProperties(graphics::MenuProperties &, const PropertyList &); + void ReadMonster(battle::Monster &, const PropertyList &); + void ReadPartyLayout(battle::PartyLayout &, const PropertyList &); + void ReadSimpleAnimation(graphics::SimpleAnimation &, const PropertyList &); + void ReadSpell(common::Spell &, const PropertyList &); + void ReadSprite(graphics::Sprite &, const PropertyList &); + void ReadStats(battle::Stats &, const PropertyList &); + void ReadTargetingMode(common::TargetingMode &, const PropertyList &); + +private: + const ParsedSource &source; + enum Type { + BATTLE_RESOURCES, + BOOLEAN, + COLOR, + COMPLEX_ANIMATION, + FONT, + FRAME, + GAUGE, + HERO, + IKARI, + IMAGE, + ITEM, + MENU_PROPERTIES, + MONSTER, + NUMBER, + PARTY_LAYOUT, + PATH, + PROPERTY_LIST_ARRAY, + SIMPLE_ANIMATION, + SPELL, + SPRITE, + STRING, + TARGETING_MODE, + VECTOR, + VALUE_ARRAY, + }; + struct ParsedDefinition { + ParsedDefinition(const Definition *dfn, Type type, int index) + : dfn(dfn), type(type), index(index) { } + const Definition *dfn; + Type type; + int index; + }; + std::map parsedDefinitions; + + std::map imageCache; + + std::vector battleResources; + std::vector booleans; + std::vector colors; + std::vector complexAnimations; + std::vector fonts; + std::vector frames; + std::vector gauges; + std::vector heroes; + std::vector ikaris; + std::vector images; + std::vector items; + std::vector menuProperties; + std::vector monsters; + std::vector numbers; + std::vector partyLayouts; + std::vector propertyLists; + std::vector > propertyListArrays; + std::vector simpleAnimations; + std::vector spells; + std::vector sprites; + std::vector strings; + std::vector targetingModes; + std::vector > valueArrays; + std::vector > vectors; + +}; + +} + +#endif /* LOADER_INTERPRETER_H_ */ diff --git a/src/loader/ParsedSource.cpp b/src/loader/ParsedSource.cpp new file mode 100644 index 0000000..c0d3a41 --- /dev/null +++ b/src/loader/ParsedSource.cpp @@ -0,0 +1,479 @@ +/* + * ParsedSource.cpp + * + * Created on: Aug 26, 2012 + * Author: holy + */ + +#include "ParsedSource.h" + +#include "utility.h" + +#include +#include + +using std::map; +using std::runtime_error; +using std::string; +using std::vector; + +namespace loader { + +ParsedSource::~ParsedSource() { + for (map::const_iterator i(declarations.begin()), end(declarations.end()); i != end; ++i) { + delete i->second; + } +} + +void ParsedSource::AddDeclaration(Declaration *d) { + map::iterator i(declarations.find(d->Identifier())); + if (i != declarations.end()) { + if (d->TypeName() != i->second->TypeName()) { + throw runtime_error("invalid redeclaration of " + i->second->TypeName() + " " + d->Identifier()); + } + } else { + declarations.insert(std::make_pair(d->Identifier(), d)); + } +} + +void ParsedSource::AddDefinition(Definition *d) { + map::iterator i(definitions.find(d->Identifier())); + if (i != definitions.end()) { + throw runtime_error("redefinition of " + i->second->TypeName() + " " + d->Identifier()); + } else { + definitions.insert(std::make_pair(d->Identifier(), d)); + } +} + +void ParsedSource::ExportDeclaration(Declaration *d) { + AddDeclaration(d); + exports.insert(d->Identifier()); +} + +void ParsedSource::ExportIdentifier(const std::string &i) { + if (declarations.count(i)) { + exports.insert(i); + } else { + throw runtime_error("cannot export undeclared identifier " + i); + } +} + + +bool ParsedSource::IsDeclared(const std::string &name) const { + return declarations.count(name); +} + +Declaration &ParsedSource::GetDeclaration(const std::string &name) { + map::const_iterator i(declarations.find(name)); + if (i != declarations.end()) { + return *i->second; + } else { + throw runtime_error("undeclared identifier " + name); + } +} + +const Declaration &ParsedSource::GetDeclaration(const std::string &name) const { + map::const_iterator i(declarations.find(name)); + if (i != declarations.end()) { + return *i->second; + } else { + throw runtime_error("undeclared identifier " + name); + } +} + +bool ParsedSource::IsDefined(const std::string &name) const { + return definitions.count(name); +} + +Definition &ParsedSource::GetDefinition(const std::string &name) { + map::const_iterator i(definitions.find(name)); + if (i != definitions.end()) { + return *i->second; + } else { + string msg("undefined identifier " + name); + map::const_iterator i(declarations.find(name)); + if (i != declarations.end()) { + msg += ", declared as " + i->second->TypeName(); + } else { + msg += ", not declared"; + } + throw runtime_error(msg); + } +} + +const Definition &ParsedSource::GetDefinition(const std::string &name) const { + map::const_iterator i(definitions.find(name)); + if (i != definitions.end()) { + return *i->second; + } else { + string msg("undefined identifier " + name); + map::const_iterator i(declarations.find(name)); + if (i != declarations.end()) { + msg += ", declared as " + i->second->TypeName(); + } else { + msg += ", not declared"; + } + throw runtime_error(msg); + } +} + +void ParsedSource::WriteHeader(std::ostream &out) const { + for (std::set::const_iterator i(exports.begin()), end(exports.end()); i != end; ++i) { + out << GetDeclaration(*i).TypeName() << ' ' << *i << std::endl; + } +} + + +Definition::~Definition() { + if (isLiteral) { + delete reinterpret_cast(value); + } else { + delete reinterpret_cast(value); + } +} + +void Definition::SetValue(Literal *v) { + value = v; + isLiteral = true; +} + +void Definition::SetValue(PropertyList *v) { + value = v; + isLiteral = false; +} + +Literal *Definition::GetLiteral() { + if (isLiteral) { + return reinterpret_cast(value); + } else { + throw runtime_error("tried to access properties as literal"); + } +} + +const Literal *Definition::GetLiteral() const { + if (isLiteral) { + return reinterpret_cast(value); + } else { + throw runtime_error("tried to access properties as literal"); + } +} + +PropertyList *Definition::GetProperties() { + if (!isLiteral) { + return reinterpret_cast(value); + } else { + throw runtime_error("tried to access literal value as property list"); + } +} + +const PropertyList *Definition::GetProperties() const { + if (!isLiteral) { + return reinterpret_cast(value); + } else if (GetLiteral()->GetType() == Literal::OBJECT) { + return GetLiteral()->GetProperties(); + } else { + throw runtime_error("tried to access literal value as property list"); + } +} + + +PropertyList::~PropertyList() { + for (map::iterator i(props.begin()), end(props.end()); i != end; ++i) { + delete i->second; + } +} + + +Literal::Literal(const vector &v) +: props(0) +, values(v) +, i1(0), i2(0) +, i3(0), i4(0) +, b(false) +, type(ARRAY_VALUES) { + +} + +Literal::Literal(const std::vector &pls) +: props(0) +, propertyLists(pls) +, i1(0), i2(0) +, i3(0), i4(0) +, b(false) +, type(ARRAY_PROPS) { + +} + +Literal::Literal(bool b) +: props(0) +, i1(0), i2(0) +, i3(0), i4(0) +, b(b) +, type(BOOLEAN) { + +} + +Literal::Literal(int r, int g, int b, int a) +: props(0) +, i1(r), i2(g) +, i3(b), i4(a) +, b(false) +, type(COLOR) { + +} + +Literal::Literal(int number) +: props(0) +, i1(number), i2(0) +, i3(0), i4(0) +, b(false) +, type(NUMBER) { + +} + +Literal::Literal(const string &dir, const string &path) +: props(0) +, str(CatPath(dir, path)) +, i1(0), i2(0) +, i3(0), i4(0) +, b(false) +, type(STRING) { + +} + +Literal::Literal(const string &str) +: props(0) +, str(str) +, i1(0), i2(0) +, i3(0), i4(0) +, b(false) +, type(STRING) { + +} + +Literal::Literal(int x, int y) +: props(0) +, i1(x), i2(y) +, i3(0), i4(0) +, b(false) +, type(VECTOR) { + +} + +Literal::Literal(const string &typeName, PropertyList *properties) +: props(properties) +, str(typeName) +, i1(0), i2(0) +, i3(0), i4(0) +, b(false) +, type(OBJECT) { + +} + +Literal::~Literal() { + switch (type) { + case ARRAY_VALUES: + for (vector::const_iterator i(values.begin()), end(values.end()); i != end; ++i) { + delete *i; + } + break; + case ARRAY_PROPS: + for (vector::const_iterator i(propertyLists.begin()), end(propertyLists.end()); i != end; ++i) { + delete *i; + } + break; + case OBJECT: + delete props; + break; + default: + break; + } +} + + +const vector &Literal::GetValues() const { + if (type == ARRAY_VALUES) { + return values; + } else { + throw runtime_error("tried to access values of non-array literal"); + } +} + +const vector &Literal::GetPropertyLists() const { + if (type == ARRAY_PROPS) { + return propertyLists; + } else { + throw runtime_error("tried to access property lists of non-array literal"); + } +} + +bool Literal::GetBoolean() const { + if (type == BOOLEAN) { + return b; + } else { + throw runtime_error("tried to access boolean value of non-boolean literal"); + } +} + +int Literal::GetRed() const { + if (type == COLOR) { + return i1; + } else { + throw runtime_error("tried to access red component of non-color literal"); + } +} + +int Literal::GetGreen() const { + if (type == COLOR) { + return i2; + } else { + throw runtime_error("tried to access green component of non-color literal"); + } +} + +int Literal::GetBlue() const { + if (type == COLOR) { + return i3; + } else { + throw runtime_error("tried to access blue component of non-color literal"); + } +} + +int Literal::GetAlpha() const { + if (type == COLOR) { + return i4; + } else { + throw runtime_error("tried to access alpha component of non-color literal"); + } +} + +int Literal::GetNumber() const { + if (type == NUMBER) { + return i1; + } else { + throw runtime_error("tried to access numerical value of non-number literal"); + } +} + +const string &Literal::GetString() const { + if (type == STRING) { + return str; + } else { + throw runtime_error("tried to access string value of non-color literal"); + } +} + +int Literal::GetX() const { + if (type == VECTOR) { + return i1; + } else { + throw runtime_error("tried to access x component of non-vector literal"); + } +} + +int Literal::GetY() const { + if (type == VECTOR) { + return i2; + } else { + throw runtime_error("tried to access y component of non-vector literal"); + } +} + +const string &Literal::GetTypeName() const { + if (type == OBJECT) { + return str; + } else { + throw runtime_error("tried to access type name of non-object literal"); + } +} + +const PropertyList *Literal::GetProperties() const { + if (type == OBJECT) { + return props; + } else { + throw runtime_error("tried to access properties of non-object literal"); + } +} + + +Value::~Value() { + if (isLiteral) { + delete literal; + } +} + +const Literal &Value::GetLiteral() const { + if (isLiteral) { + return *literal; + } else { + throw runtime_error("tried to access literal of identifier value"); + } +} + +const std::string &Value::GetIdentifier() const { + if (!isLiteral) { + return identifier; + } else { + throw runtime_error("tried to access identifier of literal value"); + } +} + +} + + +namespace std { + +ostream &operator <<(ostream &out, const loader::ParsedSource &source) { + out << "parsed source file" << endl; + out << "declared objects: " << endl; + for (map::const_iterator i(source.Declarations().begin()), end(source.Declarations().end()); i != end; ++i) { + out << " - " << i->first << " of type " << i->second->TypeName() << endl; + } + out << "defined objects: " << endl; + for (map::const_iterator i(source.Definitions().begin()), end(source.Definitions().end()); i != end; ++i) { + out << " - " << i->first << " of type " << i->second->TypeName() << endl; + if (i->second->HasLiteralValue()) { + out << " literal value: " << *i->second->GetLiteral() << endl; + } + } + out << "exported objects: " << endl; + for (set::const_iterator i(source.Exports().begin()), end(source.Exports().end()); i != end; ++i) { + out << " - " << *i << endl; + } + return out; +} + +ostream &operator <<(ostream &out, const loader::Literal &l) { + switch (l.GetType()) { + case loader::Literal::ARRAY_VALUES: + out << "array of values"; + break; + case loader::Literal::ARRAY_PROPS: + out << "array of property lists"; + break; + case loader::Literal::BOOLEAN: + out << "boolean, " << (l.GetBoolean() ? "true" : "false"); + break; + case loader::Literal::COLOR: + out << "color, (" << l.GetRed() << ',' << l.GetGreen() << ',' << l.GetBlue() << ',' << l.GetAlpha() << ')'; + break; + case loader::Literal::NUMBER: + out << "number, " << l.GetNumber(); + break; + case loader::Literal::PATH: + out << "path, \"" << l.GetString() << '"'; + break; + case loader::Literal::STRING: + out << "string, \"" << l.GetString() << '"'; + break; + case loader::Literal::VECTOR: + out << "vector, <" << l.GetX() << ',' << l.GetY() << '>'; + break; + case loader::Literal::OBJECT: + out << "object of type " << l.GetTypeName(); + break; + } + return out; +} + +} diff --git a/src/loader/ParsedSource.h b/src/loader/ParsedSource.h new file mode 100644 index 0000000..98ecd84 --- /dev/null +++ b/src/loader/ParsedSource.h @@ -0,0 +1,229 @@ +/* + * ParsedSource.h + * + * Created on: Aug 26, 2012 + * Author: holy + */ + +#ifndef LOADER_PARSEDSOURCE_H_ +#define LOADER_PARSEDSOURCE_H_ + +#include +#include +#include +#include +#include + +namespace loader { + +class PropertyList; +class Value; + +class Literal { + +public: + enum Type { + ARRAY_VALUES, + ARRAY_PROPS, + BOOLEAN, + COLOR, + NUMBER, + PATH, + STRING, + VECTOR, + OBJECT + }; + +public: + explicit Literal(const std::vector &); + explicit Literal(const std::vector &); + explicit Literal(bool); + Literal(int r, int g, int b, int a = 255); + explicit Literal(int number); + Literal(const std::string &dir, const std::string &path); + Literal(const std::string &); + Literal(int x, int y); + Literal(const std::string &typeName, PropertyList *properties); + ~Literal(); +private: + Literal(const Literal &); + Literal &operator =(const Literal &); + +public: + Type GetType() const { return type; } + + const std::vector &GetValues() const; + const std::vector &GetPropertyLists() const; + bool GetBoolean() const; + int GetRed() const; + int GetGreen() const; + int GetBlue() const; + int GetAlpha() const; + int GetNumber() const; + const std::string &GetString() const; + int GetX() const; + int GetY() const; + const std::string &GetTypeName() const; + const PropertyList *GetProperties() const; + +private: + PropertyList *props; + std::string str; + std::vector values; + std::vector propertyLists; + int i1, i2, i3, i4; + bool b; + Type type; + +}; + + +class Value { + +public: + explicit Value(const std::string &identifier) + : literal(0), identifier(identifier), isLiteral(false) { } + explicit Value(Literal *literal) + : literal(literal), isLiteral(true) { } + ~Value(); +private: + Value(const Value &); + Value &operator =(const Value &); + +public: + bool IsLiteral() const { return isLiteral; } + const Literal &GetLiteral() const; + const std::string &GetIdentifier() const; + +private: + Literal *literal; + std::string identifier; + bool isLiteral; + +}; + + +class PropertyList { + +public: + PropertyList() { } + ~PropertyList(); +private: + PropertyList(const PropertyList &); + PropertyList &operator =(const PropertyList &); + +public: + void SetProperty(const std::string &name, Value *value) { + props[name] = value; + } + + typedef std::map::iterator Iterator; + typedef std::map::const_iterator ConstIterator; + Iterator Begin() { return props.begin(); } + ConstIterator Begin() const { return props.begin(); } + Iterator End() { return props.end(); } + ConstIterator End() const { return props.end(); } + +private: + std::map props; + +}; + + +class Declaration { + +public: + Declaration(const std::string &typeName, const std::string &identifier) + : typeName(typeName), identifier(identifier) { } + virtual ~Declaration() { } +private: + Declaration(const Declaration &); + Declaration &operator =(const Declaration &); + +public: + const std::string &TypeName() const { return typeName; } + const std::string &Identifier() const { return identifier; } + +private: + std::string typeName; + std::string identifier; + +}; + + +class Definition +: public Declaration { + +public: + Definition(const std::string &typeName, const std::string &identifier) + : Declaration(typeName, identifier), value(0), isLiteral(false) { } + virtual ~Definition(); +private: + Definition(const Definition &); + Definition &operator =(const Definition &); + +public: + void SetValue(Literal *); + void SetValue(PropertyList *); + + bool HasLiteralValue() const { return isLiteral && value; } + bool HasProperties() const { return !isLiteral && value; } + Literal *GetLiteral(); + const Literal *GetLiteral() const; + PropertyList *GetProperties(); + const PropertyList *GetProperties() const; + +private: + void *value; + bool isLiteral; + +}; + + +class ParsedSource { + +public: + ParsedSource() { } + ~ParsedSource(); +private: + ParsedSource(const ParsedSource &); + ParsedSource &operator =(const ParsedSource &); + +public: + void AddDeclaration(Declaration *); + void AddDefinition(Definition *); + void ExportDeclaration(Declaration *); + void ExportIdentifier(const std::string &); + + bool IsDeclared(const std::string &) const; + Declaration &GetDeclaration(const std::string &); + const Declaration &GetDeclaration(const std::string &) const; + bool IsDefined(const std::string &) const; + Definition &GetDefinition(const std::string &); + const Definition &GetDefinition(const std::string &) const; + + const std::map &Declarations() const { return declarations; } + const std::map &Definitions() const { return definitions; } + const std::set &Exports() const { return exports; } + +public: + void WriteHeader(std::ostream &) const; + +private: + std::map declarations; + std::map definitions; + std::set exports; + +}; + +} + + +namespace std { + +ostream &operator <<(ostream &, const loader::ParsedSource &); +ostream &operator <<(ostream &, const loader::Literal &); + +} + +#endif /* LOADER_PARSEDSOURCE_H_ */ diff --git a/src/loader/Parser.cpp b/src/loader/Parser.cpp new file mode 100644 index 0000000..aa770ff --- /dev/null +++ b/src/loader/Parser.cpp @@ -0,0 +1,354 @@ +/* + * Parser.cpp + * + * Created on: Aug 26, 2012 + * Author: holy + */ + +#include "Parser.h" + +#include "utility.h" + +#include +#include + +using std::auto_ptr; +using std::ifstream; +using std::string; +using std::vector; + +namespace loader { + +Parser::Parser(const string &file, ParsedSource &product) +: file(file) +, dirname(Dirname(file)) +, in(this->file.c_str()) +, tok(in) +, product(product) { + if (!in) { + throw Error(file, 0, "unable to read file"); + } +} + +void Parser::Parse() { + while (tok.HasMore()) { + ParseStatement(); + } +} + +void Parser::ParseStatement() { + Tokenizer::Token t(GetToken()); + switch (t.type) { + case Tokenizer::Token::KEYWORD_EXPORT: + ParseExportDirective(); + break; + case Tokenizer::Token::KEYWORD_INCLUDE: + ParseIncludeDirective(); + break; + case Tokenizer::Token::TYPE_NAME: + tok.Putback(t); + { + Declaration *decl(ProbeDefinition()); + product.AddDeclaration(decl); + } + break; + default: + throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type)); + } +} + +Tokenizer::Token Parser::GetToken() try { + return tok.GetNext(); +} catch (Tokenizer::LexerError &e) { + throw Error(file, e.Line(), e.what()); +} + +void Parser::ParseExportDirective() { + Tokenizer::Token t(GetToken()); + if (t.type != Tokenizer::Token::IDENTIFIER) { + tok.Putback(t); + Declaration *decl(ProbeDefinition()); + product.ExportDeclaration(decl); + } else { + product.ExportIdentifier(t.str); + } +} + +void Parser::ParseIncludeDirective() { + Tokenizer::Token t(GetToken()); + AssertTokenType(t.type, Tokenizer::Token::STRING); + Parser sub(CatPath(dirname, t.str), product); + sub.Parse(); +} + +Declaration *Parser::ProbeDefinition() { + string typeName(ParseTypeName()); + string identifier(ParseIdentifier()); + + if (tok.HasMore()) { + Tokenizer::Token t(GetToken()); + tok.Putback(t); + if (BeginOfPropertyList(t)) { + auto_ptr propertyList(ParsePropertyList()); + auto_ptr dfn(new Definition(typeName, identifier)); + dfn->SetValue(propertyList.release()); + product.AddDefinition(dfn.get()); + return dfn.release(); + } else if (BeginningOfPrimitiveLiteral(t)) { + auto_ptr literal(ParseLiteral()); + auto_ptr dfn(new Definition(typeName, identifier)); + dfn->SetValue(literal.release()); + product.AddDefinition(dfn.get()); + return dfn.release(); + } + } + return new Declaration(typeName, identifier); +} + +bool Parser::BeginningOfLiteral(const Tokenizer::Token &t) const { + switch (t.type) { + case Tokenizer::Token::CHEVRON_OPEN: + case Tokenizer::Token::COLON: + case Tokenizer::Token::BRACKET_OPEN: + case Tokenizer::Token::PARENTHESIS_OPEN: + case Tokenizer::Token::NUMBER: + case Tokenizer::Token::STRING: + case Tokenizer::Token::KEYWORD_FALSE: + case Tokenizer::Token::KEYWORD_TRUE: + case Tokenizer::Token::TYPE_NAME: + return true; + default: + return false; + } +} + +bool Parser::BeginningOfPrimitiveLiteral(const Tokenizer::Token &t) const { + switch (t.type) { + case Tokenizer::Token::CHEVRON_OPEN: + case Tokenizer::Token::COLON: + case Tokenizer::Token::BRACKET_OPEN: + case Tokenizer::Token::PARENTHESIS_OPEN: + case Tokenizer::Token::NUMBER: + case Tokenizer::Token::STRING: + case Tokenizer::Token::KEYWORD_FALSE: + case Tokenizer::Token::KEYWORD_TRUE: + return true; + default: + return false; + } +} + +bool Parser::BeginOfPropertyList(const Tokenizer::Token &t) const { + return t.type == Tokenizer::Token::ANGLE_BRACKET_OPEN; +} + +Definition *Parser::ParseDefinition() { + string typeName(ParseTypeName()); + string identifier(ParseIdentifier()); + + Tokenizer::Token t(GetToken()); + tok.Putback(t); + if (BeginOfPropertyList(t)) { + PropertyList *propertyList(ParsePropertyList()); + Definition *dfn(new Definition(typeName, identifier)); + dfn->SetValue(propertyList); + return dfn; + } else if (BeginningOfLiteral(t)) { + Literal *literal(ParseLiteral()); + Definition *dfn(new Definition(typeName, identifier)); + dfn->SetValue(literal); + return dfn; + } else { + throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected property-list or literal"); + } +} + +string Parser::ParseIdentifier() { + Tokenizer::Token t(GetToken()); + AssertTokenType(t.type, Tokenizer::Token::IDENTIFIER); + return t.str; +} + +string Parser::ParseTypeName() { + Tokenizer::Token t(GetToken()); + AssertTokenType(t.type, Tokenizer::Token::TYPE_NAME); + return t.str; +} + +PropertyList *Parser::ParsePropertyList() { + Tokenizer::Token t(GetToken()); + AssertTokenType(t.type, Tokenizer::Token::ANGLE_BRACKET_OPEN); + + auto_ptr props(new PropertyList); + + while (t.type != Tokenizer::Token::ANGLE_BRACKET_CLOSE) { + Tokenizer::Token name(GetToken()); + AssertTokenType(name.type, Tokenizer::Token::IDENTIFIER); + + t = GetToken(); + AssertTokenType(t.type, Tokenizer::Token::COLON); + + Value *value(ParseValue()); + props->SetProperty(name.str, value); + + t = GetToken(); + if (t.type != Tokenizer::Token::ANGLE_BRACKET_CLOSE && t.type != Tokenizer::Token::COMMA) { + throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or }"); + } + } + + return props.release(); +} + +Value *Parser::ParseValue() { + Tokenizer::Token t(GetToken()); + if (t.type == Tokenizer::Token::IDENTIFIER) { + return new Value(t.str); + } else if (BeginningOfLiteral(t)) { + tok.Putback(t); + Literal *literal(ParseLiteral()); + return new Value(literal); + } else { + throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected literal or identifier"); + } +} + +Literal *Parser::ParseLiteral() { + Tokenizer::Token t(GetToken()); + if (t.type == Tokenizer::Token::TYPE_NAME) { + PropertyList *props(ParsePropertyList()); + return new Literal(t.str, props); + } else if (BeginningOfLiteral(t)) { + switch (t.type) { + case Tokenizer::Token::CHEVRON_OPEN: + tok.Putback(t); + return ParseVector(); + case Tokenizer::Token::COLON: + t = GetToken(); + AssertTokenType(t.type, Tokenizer::Token::STRING); + return new Literal(dirname, t.str); + case Tokenizer::Token::BRACKET_OPEN: + tok.Putback(t); + return ParseArray(); + case Tokenizer::Token::PARENTHESIS_OPEN: + tok.Putback(t); + return ParseColor(); + case Tokenizer::Token::NUMBER: + return new Literal(t.number); + case Tokenizer::Token::STRING: + return new Literal(t.str); + case Tokenizer::Token::KEYWORD_FALSE: + return new Literal(false); + case Tokenizer::Token::KEYWORD_TRUE: + return new Literal(true); + default: + throw std::logic_error("literal switch reached impossible default branch oO"); + } + } else { + throw new Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected type-name or primitive"); + } +} + +Literal *Parser::ParseArray() { + Tokenizer::Token t(GetToken()); + AssertTokenType(t.type, Tokenizer::Token::BRACKET_OPEN); + + Tokenizer::Token probe(GetToken()); + tok.Putback(probe); + + if (probe.type == Tokenizer::Token::ANGLE_BRACKET_OPEN) { + vector values; + while (t.type != Tokenizer::Token::BRACKET_CLOSE) { + PropertyList *value(ParsePropertyList()); + values.push_back(value); + + t = GetToken(); + if (t.type != Tokenizer::Token::BRACKET_CLOSE && t.type != Tokenizer::Token::COMMA) { + throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]"); + } + } + return new Literal(values); + } else { + vector values; + while (t.type != Tokenizer::Token::BRACKET_CLOSE) { + Value *value(ParseValue()); + values.push_back(value); + + t = GetToken(); + if (t.type != Tokenizer::Token::BRACKET_CLOSE && t.type != Tokenizer::Token::COMMA) { + throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]"); + } + } + return new Literal(values); + } +} + +Literal *Parser::ParseColor() { + string msg("error parsing color"); + Tokenizer::Token t(GetToken()); + AssertTokenType(t.type, Tokenizer::Token::PARENTHESIS_OPEN, msg); + + Tokenizer::Token red(GetToken()); + AssertTokenType(red.type, Tokenizer::Token::NUMBER, "error parsing red component of color"); + + t = GetToken(); + AssertTokenType(t.type, Tokenizer::Token::COMMA, msg); + + Tokenizer::Token green(GetToken()); + AssertTokenType(green.type, Tokenizer::Token::NUMBER, "error parsing green component of color"); + + t = GetToken(); + AssertTokenType(t.type, Tokenizer::Token::COMMA, msg); + + Tokenizer::Token blue(GetToken()); + AssertTokenType(blue.type, Tokenizer::Token::NUMBER, "error parsing blue component of color"); + + t = GetToken(); + if (t.type == Tokenizer::Token::PARENTHESIS_CLOSE) { + return new Literal(red.number, green.number, blue.number); + } else if (t.type != Tokenizer::Token::COMMA) { + Tokenizer::Token alpha(GetToken()); + AssertTokenType(alpha.type, Tokenizer::Token::NUMBER, "error parsing alpha component of color"); + + t = GetToken(); + AssertTokenType(t.type, Tokenizer::Token::PARENTHESIS_CLOSE, msg); + + return new Literal(red.number, green.number, blue.number, alpha.number); + } else { + throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]"); + } +} + +Literal *Parser::ParseVector() { + std::string msg("error parsing vector"); + Tokenizer::Token t(GetToken()); + AssertTokenType(t.type, Tokenizer::Token::CHEVRON_OPEN, msg); + + Tokenizer::Token x(GetToken()); + AssertTokenType(x.type, Tokenizer::Token::NUMBER, "error parsing x component of vector"); + + t = GetToken(); + AssertTokenType(t.type, Tokenizer::Token::COMMA, msg); + + Tokenizer::Token y(GetToken()); + AssertTokenType(y.type, Tokenizer::Token::NUMBER, "error parsing y component of vector"); + + t = GetToken(); + AssertTokenType(t.type, Tokenizer::Token::CHEVRON_CLOSE, msg); + + return new Literal(x.number, y.number); +} + +void Parser::AssertTokenType(Tokenizer::Token::Type actual, Tokenizer::Token::Type expected) { + if (expected != actual) { + throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected)); + } +} + +void Parser::AssertTokenType(Tokenizer::Token::Type actual, Tokenizer::Token::Type expected, const string &msg) { + if (expected != actual) { + throw Error(file, tok.Line(), msg + ": unexpected token " + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected)); + } +} + +} diff --git a/src/loader/Parser.h b/src/loader/Parser.h new file mode 100644 index 0000000..fd8f2cf --- /dev/null +++ b/src/loader/Parser.h @@ -0,0 +1,88 @@ +/* + * Parser.h + * + * Created on: Aug 26, 2012 + * Author: holy + */ + +#ifndef LOADER_PARSER_H_ +#define LOADER_PARSER_H_ + +#include "ParsedSource.h" +#include "Tokenizer.h" + +#include +#include +#include +#include + +namespace loader { + +class Declaration; +class Definition; +class Literal; +class PropertyList; + +class Parser { + +public: + Parser(const std::string &file, ParsedSource &product); + ~Parser() { } +private: + Parser(const Parser &); + Parser &operator =(const Parser &); + +public: + void Parse(); + +public: + class Error: public std::runtime_error { + public: + Error(const std::string &file, int line, const std::string &msg) + : std::runtime_error(msg), file(file), line(line) { }; + ~Error() throw() { } + const std::string &File() const { return file; } + int Line() const { return line; } + private: + std::string file; + int line; + }; + +private: + Tokenizer::Token GetToken(); + void ParseStatement(); + void ParseExportDirective(); + void ParseIncludeDirective(); + + Declaration *ProbeDefinition(); + Definition *ParseDefinition(); + + std::string ParseIdentifier(); + std::string ParseTypeName(); + + Value *ParseValue(); + PropertyList *ParsePropertyList(); + Literal *ParseLiteral(); + Literal *ParseArray(); + Literal *ParseColor(); + Literal *ParseVector(); + +private: + void AssertTokenType(Tokenizer::Token::Type actual, Tokenizer::Token::Type expected); + void AssertTokenType(Tokenizer::Token::Type actual, Tokenizer::Token::Type expected, const std::string &msg); + bool BeginningOfLiteral(const Tokenizer::Token &) const; + bool BeginningOfPrimitiveLiteral(const Tokenizer::Token &) const; + bool BeginOfPropertyList(const Tokenizer::Token &) const; + +private: + std::string file; + std::string dirname; + std::ifstream in; + Tokenizer tok; + ParsedSource &product; + +}; + +} + +#endif /* LOADER_PARSER_H_ */ diff --git a/src/loader/Tokenizer.cpp b/src/loader/Tokenizer.cpp new file mode 100644 index 0000000..6acda5f --- /dev/null +++ b/src/loader/Tokenizer.cpp @@ -0,0 +1,247 @@ +/* + * Tokenizer.cpp + * + * Created on: Aug 26, 2012 + * Author: holy + */ + +#include "Tokenizer.h" + +#include + +namespace loader { + +bool Tokenizer::HasMore() { + if (isPutback) return true; + ScanSpace(); + if (!in) return false; + + putback = ReadToken(); + isPutback = true; + if (!skipComments || putback.type != Token::COMMENT) return true; + + while (in && putback.type == Token::COMMENT) { + putback = ReadToken(); + ScanSpace(); + } + return putback.type != Token::COMMENT; +} + +void Tokenizer::ScanSpace() { + std::istream::char_type c; + in.get(c); + while (in && std::isspace(c)) { + if (c == '\n') { + ++line; + } + in.get(c); + } + if (in) { + in.putback(c); + } +} + +void Tokenizer::Putback(const Token &t) { + if (isPutback) { + throw LexerError(line, "Tokenizer: double putback not supported"); + } else { + putback = t; + isPutback = true; + } +} + +const Tokenizer::Token &Tokenizer::Peek() { + if (!isPutback) { + putback = GetNext(); + isPutback = true; + } + return putback; +} + +Tokenizer::Token Tokenizer::GetNext() { + if (!HasMore()) { + throw LexerError(line, "read beyond last token"); + } + if (isPutback) { + isPutback = false; + return putback; + } else { + return ReadToken(); + } +} + +Tokenizer::Token Tokenizer::ReadToken() { + ScanSpace(); + std::istream::char_type c; + in.get(c); + switch (c) { + case Token::ANGLE_BRACKET_OPEN: + case Token::ANGLE_BRACKET_CLOSE: + case Token::CHEVRON_OPEN: + case Token::CHEVRON_CLOSE: + case Token::COLON: + case Token::COMMA: + case Token::BRACKET_OPEN: + case Token::BRACKET_CLOSE: + case Token::PARENTHESIS_OPEN: + case Token::PARENTHESIS_CLOSE: + return Token ((Token::Type) c); + case '+': case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + in.putback(c); + return ReadNumber(); + case '"': + in.putback(c); + return ReadString(); + case '/': + { + std::istream::char_type c2; + in.get(c2); + if (c2 == '/') { + return ReadComment(); + } else if (c2 == '*') { + return ReadMultilineComment(); + } else { + throw LexerError(line, std::string("Tokenizer: cannot parse token: ") + c + c2 + ": expected / or *"); + } + } + break; + default: + in.putback(c); + { + Token t(ReadIdentifier()); + if (std::isupper(c)) { + t.type = Token::TYPE_NAME; + } else if (std::islower(c)) { + CheckKeyword(t); + } else { + throw LexerError(line, std::string("Tokenizer: cannot parse token: ") + c); + } + return t; + } + } +} + +Tokenizer::Token Tokenizer::ReadNumber() { + Token t(Token::NUMBER); + bool isNegative(false); + + std::istream::char_type c; + in.get(c); + if (c == '-') { + isNegative = true; + } else if (c != '+') { + in.putback(c); + } + + while (in.get(c)) { + if (!std::isdigit(c)) { + in.putback(c); + break; + } + t.number *= 10; + t.number += c - '0'; + } + + if (isNegative) t.number *= -1; + + return t; +} + +Tokenizer::Token Tokenizer::ReadString() { + Token t(Token::STRING); + bool escape(false); + + std::istream::char_type c; + in.get(c); + if (c != '"') { + throw LexerError(line, "Tokenizer: strings must begin with '\"'"); + } + + while (in.get(c)) { + if (escape) { + escape = false; + switch (c) { + case 'n': + t.str.push_back('\n'); + break; + case 'r': + t.str.push_back('\r'); + break; + case 't': + t.str.push_back('\t'); + break; + default: + t.str.push_back(c); + break; + } + } else if (c == '"') { + break; + } else if (c == '\\') { + escape = true; + } else { + t.str.push_back(c); + } + } + + return t; +} + +Tokenizer::Token Tokenizer::ReadIdentifier() { + Token t(Token::IDENTIFIER); + + std::istream::char_type c; + while (in.get(c)) { + if (std::isalnum(c) || c == '_') { + t.str.push_back(c); + } else { + in.putback(c); + break; + } + } + + return t; +} + +Tokenizer::Token Tokenizer::ReadComment() { + std::istream::char_type c; + while (in.get(c) && c != '\n'); + ++line; + return Token(Token::COMMENT); +} + +Tokenizer::Token Tokenizer::ReadMultilineComment() { + std::istream::char_type c; + while (in.get(c)) { + if (c == '*') { + std::istream::char_type c2; + if (in.get(c2) && c2 == '/') { + break; + } + } else if (c == '\n') { + ++line; + } + } + return Token(Token::COMMENT); +} + +bool Tokenizer::CheckKeyword(Token &t) { + if (t.str == "export") { + t.type = Token::KEYWORD_EXPORT; + return true; + } else if (t.str == "false") { + t.type = Token::KEYWORD_FALSE; + return true; + } else if (t.str == "include") { + t.type = Token::KEYWORD_INCLUDE; + return true; + } else if (t.str == "true") { + t.type = Token::KEYWORD_TRUE; + return true; + } else { + return false; + } +} + +} diff --git a/src/loader/Tokenizer.h b/src/loader/Tokenizer.h new file mode 100644 index 0000000..dff96fc --- /dev/null +++ b/src/loader/Tokenizer.h @@ -0,0 +1,150 @@ +/* + * Tokenizer.h + * + * Created on: Aug 26, 2012 + * Author: holy + */ + +#ifndef LOADER_TOKENIZER_H_ +#define LOADER_TOKENIZER_H_ + +#include +#include +#include +#include + +namespace loader { + +class Tokenizer { + +public: + explicit Tokenizer(std::istream &in) + : in(in), line(1), isPutback(false), skipComments(true) { } + ~Tokenizer() { } +private: + Tokenizer(const Tokenizer &); + Tokenizer &operator =(const Tokenizer &); + +public: + struct Token { + + enum Type { + UNKNOWN = 0, + ANGLE_BRACKET_OPEN = '{', + ANGLE_BRACKET_CLOSE = '}', + CHEVRON_OPEN = '<', + CHEVRON_CLOSE = '>', + COLON = ':', + COMMA = ',', + BRACKET_OPEN = '[', + BRACKET_CLOSE = ']', + PARENTHESIS_OPEN = '(', + PARENTHESIS_CLOSE = ')', + NUMBER = '0', + STRING = '"', + KEYWORD_EXPORT = 'e', + KEYWORD_FALSE = 'f', + KEYWORD_INCLUDE = 'i', + KEYWORD_TRUE = 't', + IDENTIFIER = 'x', + TYPE_NAME = 'n', + COMMENT = 'c' + }; + + Token() : type(UNKNOWN), number(0) { } + explicit Token(Type t) : type(t), number(0) { } + + Type type; + std::string str; + int number; + + }; + + class LexerError: public std::runtime_error { + public: + LexerError(int line, const std::string &msg) + : std::runtime_error(msg), line(line) { } + int Line() const { return line; } + private: + int line; + }; + + bool HasMore(); + Token GetNext(); + const Token &Peek(); + void Putback(const Token &); + int Line() const { return line; } + +private: + void ScanSpace(); + Token ReadToken(); + + Token ReadNumber(); + Token ReadString(); + Token ReadIdentifier(); + + Token ReadComment(); + Token ReadMultilineComment(); + + bool CheckKeyword(Token &); + +private: + std::istream ∈ + Token putback; + int line; + bool isPutback; + bool skipComments; + +}; + +inline const char *TokenTypeToString(Tokenizer::Token::Type t) { + switch (t) { + case Tokenizer::Token::ANGLE_BRACKET_OPEN: + return "ANGLE_BRACKET_OPEN"; + case Tokenizer::Token::ANGLE_BRACKET_CLOSE: + return "ANGLE_BRACKET_CLOSE"; + case Tokenizer::Token::CHEVRON_OPEN: + return "CHEVRON_OPEN"; + case Tokenizer::Token::CHEVRON_CLOSE: + return "CHEVRON_CLOSE"; + case Tokenizer::Token::COLON: + return "COLON"; + case Tokenizer::Token::COMMA: + return "COMMA"; + case Tokenizer::Token::BRACKET_OPEN: + return "BRACKET_OPEN"; + case Tokenizer::Token::BRACKET_CLOSE: + return "BRACKET_CLOSE"; + case Tokenizer::Token::PARENTHESIS_OPEN: + return "PARENTHESIS_OPEN"; + case Tokenizer::Token::PARENTHESIS_CLOSE: + return "PARENTHESIS_CLOSE"; + case Tokenizer::Token::NUMBER: + return "NUMBER"; + case Tokenizer::Token::STRING: + return "STRING"; + case Tokenizer::Token::KEYWORD_EXPORT: + return "KEYWORD_EXPORT"; + case Tokenizer::Token::KEYWORD_FALSE: + return "KEYWORD_FALSE"; + case Tokenizer::Token::KEYWORD_INCLUDE: + return "KEYWORD_INCLUDE"; + case Tokenizer::Token::KEYWORD_TRUE: + return "KEYWORD_TRUE"; + case Tokenizer::Token::IDENTIFIER: + return "IDENTIFIER"; + case Tokenizer::Token::TYPE_NAME: + return "TYPE_NAME"; + default: + return "UNKNOWN"; + } +} + +inline std::ostream &operator <<(std::ostream &out, Tokenizer::Token::Type t) { + out << TokenTypeToString(t); + return out; +} + +} + +#endif /* LOADER_TOKENIZER_H_ */ diff --git a/src/loader/utility.cpp b/src/loader/utility.cpp new file mode 100644 index 0000000..ee88ea0 --- /dev/null +++ b/src/loader/utility.cpp @@ -0,0 +1,41 @@ +/* + * utility.cpp + * + * Created on: Sep 1, 2012 + * Author: holy + */ + +#include "utility.h" + +#include +#include + +using std::string; + +namespace loader { + +string Dirname(const string &path) { + // unix version + char *str(new char[path.size() + 1]); + std::memcpy(str, path.c_str(), path.size()); + str[path.size()] = '\0'; + string dn(dirname(str)); + delete str; + return dn; +} + +string CatPath(const string &lhs, const string &rhs) { + // unix version + string path(lhs); + if (!path.empty() && path[path.size() - 1] != '/') { + path += '/'; + } + if (!rhs.empty() && rhs[0] == '/') { + path.append(rhs, 1, string::npos); + } else { + path += rhs; + } + return path; +} + +} diff --git a/src/loader/utility.h b/src/loader/utility.h new file mode 100644 index 0000000..b8ccd10 --- /dev/null +++ b/src/loader/utility.h @@ -0,0 +1,21 @@ +/* + * utility.h + * + * Created on: Sep 1, 2012 + * Author: holy + */ + +#ifndef LOADER_UTILITY_H_ +#define LOADER_UTILITY_H_ + +#include + +namespace loader { + +std::string Dirname(const std::string &path); + +std::string CatPath(const std::string &lhs, const std::string &rhs); + +} + +#endif /* LOADER_UTILITY_H_ */ diff --git a/src/main.cpp b/src/main.cpp index 3dc37d8..4280985 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,6 +25,9 @@ #include "graphics/Menu.h" #include "graphics/SimpleAnimation.h" #include "graphics/Sprite.h" +#include "loader/Interpreter.h" +#include "loader/ParsedSource.h" +#include "loader/Parser.h" #include "sdl/InitImage.h" #include "sdl/InitScreen.h" #include "sdl/InitSDL.h" @@ -55,6 +58,9 @@ using graphics::Gauge; using graphics::Menu; using graphics::SimpleAnimation; using graphics::Sprite; +using loader::Interpreter; +using loader::ParsedSource; +using loader::Parser; using sdl::InitImage; using sdl::InitScreen; using sdl::InitSDL; @@ -68,638 +74,92 @@ int main(int argc, char **argv) { const int width = 800; const int height = 480; - const int framerate = 33; - // std::srand(std::time(0)); try { InitSDL sdl; InitImage image(IMG_INIT_PNG); + + ParsedSource source; + Parser("test-data/test.l2s", source).Parse(); + Parser("test-data/ikaris.l2s", source).Parse(); + Parser("test-data/items.l2s", source).Parse(); + Parser("test-data/spells.l2s", source).Parse(); + Interpreter intp(source); + intp.ReadSource(); + InitScreen screen(width, height); // temporary test data SDL_Surface *bg(IMG_Load("test-data/battle-bg.png")); - PartyLayout monstersLayout; - monstersLayout.AddPosition(Vector(88, 88)); - monstersLayout.AddPosition(Vector(128, 88)); - monstersLayout.AddPosition(Vector(168, 88)); - monstersLayout.AddPosition(Vector(208, 88)); - PartyLayout heroesLayout; - heroesLayout.AddPosition(Vector(48, 136)); - heroesLayout.AddPosition(Vector(128, 136)); - heroesLayout.AddPosition(Vector(80, 152)); - heroesLayout.AddPosition(Vector(160, 152)); - - SDL_Surface *monsterImg(IMG_Load("test-data/monster.png")); - Sprite monsterSprite(monsterImg, 64, 64); - Monster monster; - monster.SetName("Lizard"); - monster.SetSprite(&monsterSprite); - monster.SetLevel(1); - monster.SetMaxHealth(8); - monster.SetHealth(8); - monster.SetStats(Stats(14, 6, 6, 6, 6, 6, 6)); - monster.SetReward(3, 5); - ComplexAnimation monsterAttackAnimation(&monsterSprite, 4 * framerate); - monsterAttackAnimation.AddFrame(0, 1, Vector(0, 16)); - monsterAttackAnimation.AddFrame(0, 0, Vector(0, 16)); - monsterAttackAnimation.AddFrame(0, 1, Vector(0, 16)); - monster.SetAttackAnimation(&monsterAttackAnimation); - SDL_Surface *monsterMeleeImg(IMG_Load("test-data/attack-monster.png")); - Sprite monsterMeleeSprite(monsterMeleeImg, 96, 64); - SimpleAnimation monsterMeleeAnimation(&monsterMeleeSprite, framerate, 14); - monster.SetMeleeAnimation(&monsterMeleeAnimation); - - SDL_Surface *maximImg(IMG_Load("test-data/maxim.png")); - Sprite maximSprite(maximImg, 64, 64); - Hero maxim; - maxim.SetName("Maxim"); - maxim.SetLevel(1); - maxim.SetSprite(&maximSprite); - maxim.SetMaxHealth(33); - maxim.SetHealth(33); - maxim.SetMaxMana(20); - maxim.SetMana(20); - maxim.SetIP(0); - maxim.SetStats(Stats(28, 22, 28, 17, 14, 100, 10)); - ComplexAnimation maximAttackAnimation(&maximSprite, framerate); - maximAttackAnimation.AddFrames(1, 0, Vector(0, 0), 7); - maximAttackAnimation.AddFrames(1, 0, Vector(4, -1), 2); - maximAttackAnimation.AddFrames(2, 0, Vector(4, -2), 2); - maximAttackAnimation.AddFrames(2, 0, Vector(6, -2), 2); - maximAttackAnimation.AddFrames(2, 1, Vector(6, -1), 1); - maximAttackAnimation.AddFrames(2, 1, Vector(3, -1), 2); - maximAttackAnimation.AddFrames(2, 1, Vector(0, 0), 1); - maximAttackAnimation.AddFrames(2, 2, Vector(0, 0), 2); - maximAttackAnimation.AddFrames(2, 2, Vector(2, 0), 1); - maximAttackAnimation.AddFrames(1, 0, Vector(0, 0), 7); - maxim.SetAttackAnimation(&maximAttackAnimation); - ComplexAnimation maximSpellAnimation(&maximSprite, 5 * framerate); - maximSpellAnimation.AddFrames(3, 0, Vector(), 2); - maximSpellAnimation.AddFrame(3, 1); - maxim.SetSpellAnimation(&maximSpellAnimation); - SDL_Surface *maximMeleeImg(IMG_Load("test-data/melee-maxim.png")); - Sprite maximMeleeSprite(maximMeleeImg, 96, 96); - SimpleAnimation maximMeleeAnimation(&maximMeleeSprite, 2 * framerate, 4); - maxim.SetMeleeAnimation(&maximMeleeAnimation); - - SDL_Surface *selanImg(IMG_Load("test-data/selan.png")); - Sprite selanSprite(selanImg, 64, 64); - Hero selan; - selan.SetName("Selan"); - selan.SetLevel(1); - selan.SetSprite(&selanSprite); - selan.SetMaxHealth(28); - selan.SetHealth(28); - selan.SetMaxMana(23); - selan.SetMana(23); - selan.SetIP(0); - selan.SetStats(Stats(23, 21, 23, 19, 22, 80, 13)); - ComplexAnimation selanAttackAnimation(&selanSprite, framerate); - selanAttackAnimation.AddFrames(1, 0, Vector(4, 0), 2); - selanAttackAnimation.AddFrame(1, 0, Vector(8, 2)); - selanAttackAnimation.AddFrame(2, 0, Vector(10, 4)); - selanAttackAnimation.AddFrame(2, 0, Vector(14, 4)); - selanAttackAnimation.AddFrames(2, 0, Vector(12, 2), 3); - selanAttackAnimation.AddFrames(2, 1, Vector(14, 2), 2); - selanAttackAnimation.AddFrame(2, 1, Vector(2, 0)); - selanAttackAnimation.AddFrame(2, 2, Vector(-2, -4)); - selanAttackAnimation.AddFrame(2, 2, Vector(-8, -8)); - selanAttackAnimation.AddFrame(2, 2); - selan.SetAttackAnimation(&selanAttackAnimation); - ComplexAnimation selanSpellAnimation(&selanSprite, framerate); - selanSpellAnimation.AddFrames(2, 0, Vector(), 3); - selanSpellAnimation.AddFrames(2, 1, Vector(), 2); - selanSpellAnimation.AddFrames(2, 2, Vector(), 3); - selanSpellAnimation.AddFrames(2, 3, Vector(), 2); - selan.SetSpellAnimation(&selanSpellAnimation); - SDL_Surface *selanMeleeImg(IMG_Load("test-data/melee-selan.png")); - Sprite selanMeleeSprite(selanMeleeImg, 96, 96); - SimpleAnimation selanMeleeAnimation(&selanMeleeSprite, 2 * framerate, 4); - selan.SetMeleeAnimation(&selanMeleeAnimation); - - SDL_Surface *guyImg(IMG_Load("test-data/guy.png")); - Sprite guySprite(guyImg, 64, 64); - Hero guy; - guy.SetName("Guy"); - guy.SetLevel(1); - guy.SetSprite(&guySprite); - guy.SetMaxHealth(38); - guy.SetHealth(38); - guy.SetMaxMana(0); - guy.SetMana(0); - guy.SetIP(0); - guy.SetStats(Stats(38, 25, 38, 13, 8, 90, 8)); - ComplexAnimation guyAttackAnimation(&guySprite, framerate); - guyAttackAnimation.AddFrames(1, 0, Vector(-4, 0), 2); - guyAttackAnimation.AddFrames(1, 0, Vector(-8, 0), 2); - guyAttackAnimation.AddFrames(2, 0, Vector(-8, 0), 2); - guyAttackAnimation.AddFrame(2, 0, Vector(-4, 0)); - guyAttackAnimation.AddFrames(2, 0, Vector(), 2); - guyAttackAnimation.AddFrame(2, 1); - guyAttackAnimation.AddFrame(2, 1, Vector(4, 0)); - guyAttackAnimation.AddFrame(2, 1, Vector(10, 0)); - guyAttackAnimation.AddFrame(2, 2, Vector(10, 0)); - guyAttackAnimation.AddFrame(2, 2); - guy.SetAttackAnimation(&guyAttackAnimation); - SDL_Surface *guyMeleeImg(IMG_Load("test-data/melee-guy.png")); - Sprite guyMeleeSprite(guyMeleeImg, 96, 96); - SimpleAnimation guyMeleeAnimation(&guyMeleeSprite, 2 * framerate, 4); - guy.SetMeleeAnimation(&guyMeleeAnimation); - - SDL_Surface *dekarImg(IMG_Load("test-data/dekar.png")); - Sprite dekarSprite(dekarImg, 64, 64); - Hero dekar; - dekar.SetName("Dekar"); - dekar.SetLevel(1); - dekar.SetSprite(&dekarSprite); - dekar.SetMaxHealth(38); - dekar.SetHealth(38); - dekar.SetMaxMana(0); - dekar.SetMana(0); - dekar.SetIP(0); - dekar.SetStats(Stats(46, 29, 46, 13, 7, 100, 5)); - ComplexAnimation dekarAttackAnimation(&dekarSprite, framerate); - dekarAttackAnimation.AddFrame(1, 0, Vector(4, 0)); - dekarAttackAnimation.AddFrame(1, 0, Vector(8, 2)); - dekarAttackAnimation.AddFrame(2, 0, Vector(12, 4)); - dekarAttackAnimation.AddFrame(2, 0, Vector(16, 4)); - dekarAttackAnimation.AddFrames(2, 0, Vector(10, 2), 4); - dekarAttackAnimation.AddFrame(2, 1, Vector(6, 2)); - dekarAttackAnimation.AddFrame(2, 1, Vector()); - dekarAttackAnimation.AddFrame(2, 2, Vector(-2, 0)); - dekarAttackAnimation.AddFrames(2, 2, Vector(0, 0), 3); - dekar.SetAttackAnimation(&dekarAttackAnimation); - ComplexAnimation dekarSpellAnimation(&dekarSprite, framerate); - dekarSpellAnimation.AddFrames(2, 0, Vector(), 6); - dekarSpellAnimation.AddFrames(2, 1, Vector(), 2); - dekarSpellAnimation.AddFrames(2, 2, Vector(), 3); - dekar.SetSpellAnimation(&dekarSpellAnimation); - SDL_Surface *dekarMeleeImg(IMG_Load("test-data/melee-dekar.png")); - Sprite dekarMeleeSprite(dekarMeleeImg, 96, 96); - SimpleAnimation dekarMeleeAnimation(&dekarMeleeSprite, 2 * framerate, 4); - dekar.SetMeleeAnimation(&dekarMeleeAnimation); - - battle::Resources battleRes; - - SDL_Surface *swapCursorImg(IMG_Load("test-data/swap-cursor.png")); - Sprite swapCursorSprite(swapCursorImg, 32, 32); - battleRes.swapCursor = &swapCursorSprite; - SDL_Surface *attackIconsImg(IMG_Load("test-data/attack-type-icons.png")); - Sprite attackIconsSprite(attackIconsImg, 32, 32); - battleRes.attackIcons = &attackIconsSprite; - SDL_Surface *attackChoiceIconsImg(IMG_Load("test-data/attack-choice-icons.png")); - Sprite attackChoiceIconsSprite(attackChoiceIconsImg, 16, 16); - battleRes.attackChoiceIcons = &attackChoiceIconsSprite; - SDL_Surface *moveIconsImg(IMG_Load("test-data/move-icons.png")); - Sprite moveIconsSprite(moveIconsImg, 32, 32); - battleRes.moveIcons = &moveIconsSprite; - - SDL_Surface *titleFrameImg(IMG_Load("test-data/title-frame.png")); - Frame titleFrame(titleFrameImg, 16, 16); - battleRes.titleFrame = &titleFrame; - - SDL_Surface *largeFontImg(IMG_Load("test-data/large-font.png")); - Sprite largeFontSprite(largeFontImg, 16, 32); - Font largeFont(&largeFontSprite, 0, -2); - battleRes.titleFont = &largeFont; - - ComplexAnimation numberAnimationPrototype(0, framerate); - numberAnimationPrototype.AddFrame(0, 0); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -26)); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -42)); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -48)); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -42)); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -26)); - numberAnimationPrototype.AddFrame(0, 0); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -12)); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -20)); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -24)); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -20)); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -12)); - numberAnimationPrototype.AddFrame(0, 0); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -6)); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -10)); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -12)); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -10)); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -6)); - numberAnimationPrototype.AddFrames(0, 0, Vector(), 14); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -36)); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -32)); - numberAnimationPrototype.AddFrame(0, 0, Vector(0, -18)); - battleRes.numberAnimationPrototype = &numberAnimationPrototype; - - SDL_Surface *bigNumbersImg(IMG_Load("test-data/big-numbers.png")); - Sprite bigNumbersSprite(bigNumbersImg, 16, 32); - battleRes.bigNumberSprite = &bigNumbersSprite; - SDL_Surface *bigGreenNumbersImg(IMG_Load("test-data/big-green-numbers.png")); - Sprite bigGreenNumbersSprite(bigGreenNumbersImg, 16, 32); - battleRes.greenNumberSprite = &bigGreenNumbersSprite; - - SDL_Surface *heroTagImg(IMG_Load("test-data/hero-tag-sprites.png")); - Sprite heroTagSprite(heroTagImg, 32, 16); - battleRes.heroTagLabels = &heroTagSprite; - battleRes.levelLabelCol = 0; - battleRes.levelLabelRow = 0; - battleRes.healthLabelCol = 0; - battleRes.healthLabelRow = 1; - battleRes.manaLabelCol = 0; - battleRes.manaLabelRow = 2; - battleRes.moveLabelCol = 0; - battleRes.moveLabelRow = 3; - battleRes.ikariLabelCol = 0; - battleRes.ikariLabelRow = 4; - - SDL_Surface *numbersImg(IMG_Load("test-data/numbers.png")); - Sprite numbersSprite(numbersImg, 16, 16); - Font heroTagFont(&numbersSprite, 0, -3); - battleRes.heroTagFont = &heroTagFont; - SDL_Surface *tagFramesImg(IMG_Load("test-data/tag-frames.png")); - Frame heroTagFrame(tagFramesImg, 16, 16, 1, 1, 0, 33); - battleRes.heroTagFrame = &heroTagFrame; - Frame activeHeroTagFrame(tagFramesImg, 16, 16); - battleRes.activeHeroTagFrame = &activeHeroTagFrame; - SDL_Surface *smallTagFrameImg(IMG_Load("test-data/small-tag-frame.png")); - Frame smallTagFrame(smallTagFrameImg, 8, 16); - battleRes.smallHeroTagFrame = &smallTagFrame; - Frame lastSmallTagFrame(smallTagFrameImg, 8, 16, 1, 1, 0, 33); - battleRes.lastSmallHeroTagFrame = &lastSmallTagFrame; - battleRes.heroesBgColor = SDL_MapRGB(screen.Screen()->format, 0x18, 0x28, 0x31); - - SDL_Surface *gauges(IMG_Load("test-data/gauges.png")); - Gauge healthGauge(gauges, 0, 16, 0, 0, 16, 6, 1, 6); - battleRes.healthGauge = &healthGauge; - Gauge manaGauge(gauges, 0, 32, 0, 0, 16, 6, 1, 6); - battleRes.manaGauge = &manaGauge; - Gauge ikariGauge(gauges, 0, 48, 0, 0, 16, 6, 1, 6); - battleRes.ikariGauge = &ikariGauge; - - SDL_Surface *selectFrameImg(IMG_Load("test-data/select-frame.png")); - Frame selectFrame(selectFrameImg, 16, 16); - battleRes.selectFrame = &selectFrame; - - SDL_Surface *normalFontImg(IMG_Load("test-data/normal-font.png")); - Sprite normalFontSprite(normalFontImg, 16, 16); - Font normalFont(&normalFontSprite, 0, -2); - battleRes.normalFont = &normalFont; - - SDL_Surface *disabledFontImg(IMG_Load("test-data/disabled-font.png")); - Sprite disabledFontSprite(disabledFontImg, 16, 16); - Font disabledFont(&disabledFontSprite, 0, -2); - battleRes.disabledFont = &disabledFont; - - SDL_Surface *handCursorImg(IMG_Load("test-data/cursor-hand.png")); - Sprite handCursorSprite(handCursorImg, 32, 32); - battleRes.menuCursor = &handCursorSprite; - - SDL_Surface *targetingIconsImg(IMG_Load("test-data/targeting-icons.png")); - Sprite weaponTargetCursor(targetingIconsImg, 32, 32); - Sprite magicTargetCursor(targetingIconsImg, 32, 32, 0, 32); - Sprite itemTargetCursor(targetingIconsImg, 32, 32, 0, 64); - battleRes.weaponTargetCursor = &weaponTargetCursor; - battleRes.magicTargetCursor = &magicTargetCursor; - battleRes.itemTargetCursor = &itemTargetCursor; - - Spell resetSpell; - resetSpell.SetName("Reset"); - maxim.AddSpell(&resetSpell); - Spell strongSpell; - strongSpell.SetName("Strong"); - strongSpell.SetCost(3); - strongSpell.SetUsableInBattle(); - strongSpell.GetTargetingMode().TargetMultipleAllies(); - maxim.AddSpell(&strongSpell); - selan.AddSpell(&strongSpell); - Spell strongerSpell; - strongerSpell.SetName("Stronger"); - strongerSpell.SetCost(8); - strongerSpell.SetUsableInBattle(); - strongerSpell.GetTargetingMode().TargetMultipleAllies(); - maxim.AddSpell(&strongerSpell); - selan.AddSpell(&strongerSpell); - Spell championSpell; - championSpell.SetName("Champion"); - championSpell.SetCost(16); - championSpell.SetUsableInBattle(); - championSpell.GetTargetingMode().TargetMultipleAllies(); - maxim.AddSpell(&championSpell); - selan.AddSpell(&championSpell); - Spell rallySpell; - rallySpell.SetName("Rally"); - rallySpell.SetCost(10); - rallySpell.SetUsableInBattle(); - rallySpell.GetTargetingMode().TargetMultipleAllies(); - maxim.AddSpell(&rallySpell); - selan.AddSpell(&rallySpell); - Spell escapeSpell; - escapeSpell.SetName("Escape"); - escapeSpell.SetCost(8); - selan.AddSpell(&escapeSpell); - Spell valorSpell; - valorSpell.SetName("Valor"); - valorSpell.SetCost(30); - valorSpell.SetUsableInBattle(); - valorSpell.GetTargetingMode().TargetMultipleAllies(); - maxim.AddSpell(&valorSpell); - selan.AddSpell(&valorSpell); - - battleRes.spellMenuHeadline = "Please choose a spell."; - battleRes.spellMenuPrototype = Menu(&normalFont, &disabledFont, &handCursorSprite, 9, 6, 8, 0, 2, 32, 2, ':'); - - SDL_Surface *itemIcons(IMG_Load("test-data/item-icons.png")); - Sprite potionIcon(itemIcons, 16, 16); - Sprite ballIcon(itemIcons, 16, 16, 0, 16); - Sprite crankIcon(itemIcons, 16, 16, 0, 32); - Sprite spearIcon(itemIcons, 16, 16, 0, 48); - Sprite swordIcon(itemIcons, 16, 16, 0, 64); - Sprite axIcon(itemIcons, 16, 16, 0, 80); - Sprite rodIcon(itemIcons, 16, 16, 0, 96); - Sprite armorIcon(itemIcons, 16, 16, 0, 112); - Sprite shieldIcon(itemIcons, 16, 16, 0, 128); - Sprite helmetIcon(itemIcons, 16, 16, 0, 144); - Sprite ringIcon(itemIcons, 16, 16, 0, 160); - Sprite jewelIcon(itemIcons, 16, 16, 0, 176); - - battleRes.weaponMenuIcon = &swordIcon; - battleRes.armorMenuIcon = &armorIcon; - battleRes.shieldMenuIcon = &shieldIcon; - battleRes.helmetMenuIcon = &helmetIcon; - battleRes.ringMenuIcon = &ringIcon; - battleRes.jewelMenuIcon = &jewelIcon; + PartyLayout monstersLayout(*intp.GetPartyLayout("monstersLayout")); + PartyLayout heroesLayout(*intp.GetPartyLayout("heroesLayout")); + + Monster monster(*intp.GetMonster("lizard")); + Hero maxim(*intp.GetHero("maxim")); + Hero selan(*intp.GetHero("selan")); + Hero guy(*intp.GetHero("guy")); + Hero dekar(*intp.GetHero("dekar")); + + battle::Resources *battleRes(intp.GetBattleResources("battleResources")); + + maxim.AddSpell(intp.GetSpell("resetSpell")); + Spell *strongSpell(intp.GetSpell("strongSpell")); + maxim.AddSpell(strongSpell); + selan.AddSpell(strongSpell); + Spell *strongerSpell(intp.GetSpell("strongerSpell")); + maxim.AddSpell(strongerSpell); + selan.AddSpell(strongerSpell); + Spell *championSpell(intp.GetSpell("championSpell")); + maxim.AddSpell(championSpell); + selan.AddSpell(championSpell); + Spell *rallySpell(intp.GetSpell("rallySpell")); + maxim.AddSpell(rallySpell); + selan.AddSpell(rallySpell); + selan.AddSpell(intp.GetSpell("escapeSpell")); + Spell *valorSpell(intp.GetSpell("valorSpell")); + maxim.AddSpell(valorSpell); + selan.AddSpell(valorSpell); Inventory inventory; - Item antidote; - antidote.SetName("Antidote"); - antidote.SetMenuIcon(&potionIcon); - antidote.SetUsableInBattle(); - antidote.GetTargetingMode().TargetSingleAlly(); - inventory.Add(&antidote, 9); - Item magicJar; - magicJar.SetName("Magic jar"); - magicJar.SetMenuIcon(&potionIcon); - magicJar.SetUsableInBattle(); - magicJar.GetTargetingMode().TargetSingleAlly(); - inventory.Add(&magicJar, 4); - Item hiPotion; - hiPotion.SetName("Hi-Potion"); - hiPotion.SetMenuIcon(&potionIcon); - hiPotion.SetUsableInBattle(); - hiPotion.GetTargetingMode().TargetSingleAlly(); - inventory.Add(&hiPotion, 4); - Item powerPotion; - powerPotion.SetName("Power potion"); - powerPotion.SetMenuIcon(&potionIcon); - inventory.Add(&powerPotion, 4); - Item escape; - escape.SetName("Escape"); - inventory.Add(&escape, 2); - Item sleepBall; - sleepBall.SetName("Sleep ball"); - sleepBall.SetMenuIcon(&ballIcon); - sleepBall.SetUsableInBattle(); - sleepBall.GetTargetingMode().TargetSingleEnemy(); - inventory.Add(&sleepBall, 1); - Item multiBall; - multiBall.SetName("Multi-ball!"); - multiBall.SetMenuIcon(&ballIcon); - multiBall.SetUsableInBattle(); - multiBall.GetTargetingMode().TargetMultipleEnemies(); - inventory.Add(&multiBall, 1); - Item figgoru; - figgoru.SetName("Figgoru"); - figgoru.SetMenuIcon(&crankIcon); - figgoru.GetTargetingMode().TargetAllEnemies(); - inventory.Add(&figgoru, 1); - battleRes.inventory = &inventory; - - battleRes.itemMenuHeadline = "Please choose an item."; - battleRes.itemMenuPrototype = Menu(&normalFont, &disabledFont, &handCursorSprite, 15, 6, 8, 16, 1, 32, 2, ':'); - - SDL_Surface *swordAttackImg(IMG_Load("test-data/attack-sword.png")); - Sprite swordAttackSprite(swordAttackImg, 96, 96); - SimpleAnimation swordAttackAnimation(&swordAttackSprite, 2 * framerate, 4); - - Item zircoSword; - zircoSword.SetName("Zirco sword"); - zircoSword.SetMenuIcon(&swordIcon); - zircoSword.GetTargetingMode().TargetSingleEnemy(); - Ikari firestorm; - firestorm.SetName("Firestorm"); - firestorm.SetCost(224); - firestorm.GetTargetingMode().TargetAllEnemies(); - firestorm.SetPhysical(); - zircoSword.SetIkari(&firestorm); - zircoSword.SetAttackAnimation(&swordAttackAnimation); - maxim.SetWeapon(&zircoSword); - Item zirconArmor; - zirconArmor.SetName("Zircon armor"); - zirconArmor.SetMenuIcon(&armorIcon); - Ikari magicCure; - magicCure.SetName("Magic cure"); - magicCure.SetCost(128); - magicCure.GetTargetingMode().TargetSingleAlly(); - magicCure.SetMagical(); - zirconArmor.SetIkari(&magicCure); - maxim.SetArmor(&zirconArmor); - Item holyShield; - holyShield.SetName("Holy shield"); - holyShield.SetMenuIcon(&shieldIcon); - Ikari lightGuard; - lightGuard.SetName("Light guard"); - lightGuard.SetCost(128); - lightGuard.GetTargetingMode().TargetAllAllies(); // actually only targets self - lightGuard.SetMagical(); - holyShield.SetIkari(&lightGuard); - maxim.SetShield(&holyShield); - Item legendHelm; - legendHelm.SetName("Legend helm"); - legendHelm.SetMenuIcon(&helmetIcon); - Ikari boomerang; - boomerang.SetName("Boomerang"); - boomerang.SetCost(164); - boomerang.GetTargetingMode().TargetAllAllies(); // actually only targets self - boomerang.SetMagical(); - legendHelm.SetIkari(&boomerang); - maxim.SetHelmet(&legendHelm); - Item sProRing; - sProRing.SetName("S-pro ring"); - sProRing.SetMenuIcon(&ringIcon); - Ikari courage; - courage.SetName("Courage"); - courage.SetCost(64); - courage.GetTargetingMode().TargetMultipleAllies(); - courage.SetMagical(); - sProRing.SetIkari(&courage); - maxim.SetRing(&sProRing); - Item evilJewel; - evilJewel.SetName("Evil jewel"); - evilJewel.SetMenuIcon(&jewelIcon); - Ikari gloomy; - gloomy.SetName("Gloomy"); - gloomy.SetCost(164); - gloomy.GetTargetingMode().TargetAllEnemies(); - gloomy.SetMagical(); - evilJewel.SetIkari(&gloomy); - maxim.SetJewel(&evilJewel); - - Item zircoWhip; - zircoWhip.SetName("Zirco whip"); - zircoWhip.SetMenuIcon(&rodIcon); - zircoWhip.GetTargetingMode().TargetSingleEnemy(); - Ikari thundershriek; - thundershriek.SetName("Thundershriek"); - thundershriek.SetCost(224); - thundershriek.GetTargetingMode().TargetAllEnemies(); - thundershriek.SetPhysical(); - zircoWhip.SetIkari(&thundershriek); -// selan.SetWeapon(&zircoWhip); - Item zirconPlate; - zirconPlate.SetName("Zircon plate"); - zirconPlate.SetMenuIcon(&armorIcon); - Ikari suddenCure; - suddenCure.SetName("Sudden cure"); - suddenCure.SetCost(96); - suddenCure.GetTargetingMode().TargetAllAllies(); - suddenCure.SetMagical(); - zirconPlate.SetIkari(&suddenCure); - selan.SetArmor(&zirconPlate); - Item zircoGloves; - zircoGloves.SetName("Zirco gloves"); - zircoGloves.SetMenuIcon(&shieldIcon); - Ikari forcefield; - forcefield.SetName("Forcefield"); - forcefield.SetCost(64); - forcefield.GetTargetingMode().TargetAllAllies(); - forcefield.SetMagical(); - zircoGloves.SetIkari(&forcefield); - selan.SetShield(&zircoGloves); - Item holyCap; - holyCap.SetName("Holy cap"); - holyCap.SetMenuIcon(&helmetIcon); - Ikari vulnerable; - vulnerable.SetName("Vulnerable"); - vulnerable.SetCost(196); - vulnerable.GetTargetingMode().TargetAllEnemies(); - vulnerable.SetPhysical(); - holyCap.SetIkari(&vulnerable); - selan.SetHelmet(&holyCap); - Item ghostRing; - ghostRing.SetName("Ghost ring"); - ghostRing.SetMenuIcon(&ringIcon); - Ikari destroy; - destroy.SetName("Destroy"); - destroy.SetCost(128); - destroy.GetTargetingMode().TargetMultipleEnemies(); - destroy.SetMagical(); - ghostRing.SetIkari(&destroy); - selan.SetRing(&ghostRing); - Item eagleRock; - eagleRock.SetName("Eagle rock"); - eagleRock.SetMenuIcon(&jewelIcon); - Ikari dive; - dive.SetName("Dive"); - dive.SetCost(128); - dive.GetTargetingMode().TargetSingleEnemy(); - dive.SetPhysical(); - eagleRock.SetIkari(&dive); - selan.SetJewel(&eagleRock); - - Item zircoAx; - zircoAx.SetName("Zirco ax"); - zircoAx.SetMenuIcon(&axIcon); - zircoAx.GetTargetingMode().TargetSingleEnemy(); - Ikari torrent; - torrent.SetName("Torrent"); - torrent.SetCost(224); - torrent.GetTargetingMode().TargetAllEnemies(); - torrent.SetPhysical(); - zircoAx.SetIkari(&torrent); -// guy.SetWeapon(&zircoAx); - guy.SetArmor(&zirconArmor); - Item megaShield; - megaShield.SetName("Mega shield"); - megaShield.SetMenuIcon(&shieldIcon); - Ikari ironBarrier; - ironBarrier.SetName("Iron barrier"); - ironBarrier.SetCost(255); - ironBarrier.GetTargetingMode().TargetAllAllies(); // actually only targets self - ironBarrier.SetMagical(); - megaShield.SetIkari(&ironBarrier); - guy.SetShield(&megaShield); - Item zircoHelmet; - zircoHelmet.SetName("Zirco helmet"); - zircoHelmet.SetMenuIcon(&helmetIcon); - Ikari slow; - slow.SetName("Slow"); - slow.SetCost(196); - slow.GetTargetingMode().TargetAllEnemies(); - slow.SetPhysical(); - zircoHelmet.SetIkari(&slow); - guy.SetHelmet(&zircoHelmet); - Item powerRing; - powerRing.SetName("Power ring"); - powerRing.SetMenuIcon(&ringIcon); - Ikari trick; - trick.SetName("Trick"); - trick.SetCost(32); - trick.GetTargetingMode().TargetAllEnemies(); - trick.SetMagical(); - zircoHelmet.SetIkari(&trick); - guy.SetRing(&powerRing); - guy.SetJewel(&evilJewel); + inventory.Add(intp.GetItem("antidoteItem"), 9); + inventory.Add(intp.GetItem("magicJarItem"), 4); + inventory.Add(intp.GetItem("hiPotionItem"), 4); + inventory.Add(intp.GetItem("powerPotionItem"), 4); + inventory.Add(intp.GetItem("escapeItem"), 2); + inventory.Add(intp.GetItem("sleepBallItem"), 1); + battleRes->inventory = &inventory; + + maxim.SetWeapon(intp.GetItem("zircoSwordItem")); + maxim.SetArmor(intp.GetItem("zirconArmorItem")); + maxim.SetShield(intp.GetItem("holyShieldItem")); + maxim.SetHelmet(intp.GetItem("legendHelmItem")); + maxim.SetRing(intp.GetItem("sProRingItem")); + maxim.SetJewel(intp.GetItem("evilJewelItem")); + +// selan.SetWeapon(intp.GetItem("zircoWhipItem")); + selan.SetArmor(intp.GetItem("zirconPlateItem")); + selan.SetShield(intp.GetItem("zircoGlovesItem")); + selan.SetHelmet(intp.GetItem("holyCapItem")); + selan.SetRing(intp.GetItem("ghostRingItem")); + selan.SetJewel(intp.GetItem("eagleRockItem")); + +// guy.SetWeapon(intp.GetItem("zircoAxItem")); + guy.SetArmor(intp.GetItem("zirconArmorItem")); + guy.SetShield(intp.GetItem("megaShieldItem")); + guy.SetHelmet(intp.GetItem("zircoHelmetItem")); + guy.SetRing(intp.GetItem("powerRingItem")); + guy.SetJewel(intp.GetItem("evilJewelItem")); // NOTE: this is actually Artea equipment - Item lizardBlow; - lizardBlow.SetName("Lizard blow"); - lizardBlow.SetMenuIcon(&swordIcon); - lizardBlow.GetTargetingMode().TargetSingleEnemy(); - Ikari dragonRush; - dragonRush.SetName("Dragon rush"); - dragonRush.SetCost(164); - dragonRush.GetTargetingMode().TargetSingleEnemy(); - dragonRush.SetPhysical(); - lizardBlow.SetIkari(&dragonRush); -// dekar.SetWeapon(&lizardBlow); - Item holyRobe; - holyRobe.SetName("Holy robe"); - holyRobe.SetMenuIcon(&armorIcon); - Ikari crisisCure; - crisisCure.SetName("Crisis cure"); - crisisCure.SetCost(164); - crisisCure.GetTargetingMode().TargetAllAllies(); - crisisCure.SetMagical(); - holyRobe.SetIkari(&crisisCure); - dekar.SetArmor(&holyRobe); - dekar.SetShield(&zircoGloves); - dekar.SetHelmet(&holyCap); - Item rocketRing; - rocketRing.SetName("Rocket ring"); - rocketRing.SetMenuIcon(&ringIcon); - Ikari fake; - fake.SetName("Fake"); - fake.SetCost(32); - fake.GetTargetingMode().TargetSingleAlly(); - fake.SetMagical(); - rocketRing.SetIkari(&fake); - dekar.SetRing(&rocketRing); - Item krakenRock; - krakenRock.SetName("Kraken rock"); - krakenRock.SetMenuIcon(&jewelIcon); - Ikari tenLegger; - tenLegger.SetName("Ten-legger"); - tenLegger.SetCost(164); - tenLegger.GetTargetingMode().TargetAllEnemies(); - tenLegger.SetPhysical(); - rocketRing.SetIkari(&tenLegger); - dekar.SetJewel(&krakenRock); - - battleRes.ikariMenuHeadline = "Please choose equipment."; - battleRes.noEquipmentText = "No equip"; - battleRes.ikariMenuPrototype = Menu(&normalFont, &disabledFont, &handCursorSprite, 12, 6, normalFont.CharHeight() / 2, normalFont.CharWidth(), 1, normalFont.CharWidth() * 2, 0, ':', 12, normalFont.CharWidth()); - - battleRes.escapeText = "Escapes."; - - BattleState *battleState(new BattleState(bg, monstersLayout, heroesLayout, &battleRes)); +// dekar.SetWeapon(intp.GetItem("lizardBlowItem")); + dekar.SetArmor(intp.GetItem("holyRobeItem")); + dekar.SetShield(intp.GetItem("zircoGlovesItem")); + dekar.SetHelmet(intp.GetItem("holyCapItem")); + dekar.SetRing(intp.GetItem("rocketRingItem")); + dekar.SetJewel(intp.GetItem("krakenRockItem")); + + BattleState *battleState(new BattleState(bg, monstersLayout, heroesLayout, battleRes)); battleState->AddMonster(monster); battleState->AddMonster(monster); battleState->AddMonster(monster); @@ -724,6 +184,9 @@ int main(int argc, char **argv) { app.Run(); return 0; + } catch (Parser::Error &e) { + cerr << "parsing exception in file " << e.File() << " on line " << e.Line() << ": " << e.what() << endl; + return 1; } catch (exception &e) { cerr << "exception in main(): " << e.what() << endl; return 1; diff --git a/test-data/ikaris.l2h b/test-data/ikaris.l2h new file mode 100644 index 0000000..f55cc91 --- /dev/null +++ b/test-data/ikaris.l2h @@ -0,0 +1,20 @@ +Ikari boomerangIkari +Ikari courageIkari +Ikari crisisCureIkari +Ikari destroyIkari +Ikari diveIkari +Ikari dragonRushIkari +Ikari fakeIkari +Ikari firestormIkari +Ikari forcefieldIkari +Ikari gloomyIkari +Ikari ironBarrierIkari +Ikari lightGuardIkari +Ikari magicCureIkari +Ikari slowIkari +Ikari suddenCureIkari +Ikari tenLeggerIkari +Ikari thundershriekIkari +Ikari torrentIkari +Ikari trickIkari +Ikari vulnerableIkari diff --git a/test-data/ikaris.l2s b/test-data/ikaris.l2s new file mode 100644 index 0000000..e76414d --- /dev/null +++ b/test-data/ikaris.l2s @@ -0,0 +1,180 @@ +export Ikari boomerangIkari { + name: "Boomerang", + cost: 164, + targets: TargetingMode { + ally: true, + all: true + }, + magical: true +} +export Ikari courageIkari { + name: "Courage", + cost: 64, + targets: TargetingMode { + ally: true, + multiple: true + }, + magical: true +} +export Ikari crisisCureIkari { + name: "Crisis cure", + cost: 164, + targets: TargetingMode { + ally: true, + all: true + }, + magical: true +} +export Ikari destroyIkari { + name: "Destroy", + cost: 128, + targets: TargetingMode { + enemy: true, + multiple: true + }, + magical: true +} +export Ikari diveIkari { + name: "Dive", + cost: 128, + targets: TargetingMode { + enemy: true, + single: true + }, + physical: true +} +export Ikari dragonRushIkari { + name: "Dragon rush", + cost: 164, + targets: TargetingMode { + enemy: true, + single: true + }, + physical: true +} +export Ikari fakeIkari { + name: "Fake", + cost: 32, + targets: TargetingMode { + ally: true, + single: true + }, + magical: true +} +export Ikari firestormIkari { + name: "Firestorm", + cost: 224, + targets: TargetingMode { + enemy: true, + all: true + }, + physical: true +} +export Ikari forcefieldIkari { + name: "Forcefield", + cost: 64, + targets: TargetingMode { + ally: true, + all: true + }, + magical: true +} +export Ikari gloomyIkari { + name: "Gloomy", + cost: 164, + targets: TargetingMode { + enemy: true, + all: true + }, + magical: true +} +export Ikari ironBarrierIkari { + name: "Iron barrier", + cost: 255, + targets: TargetingMode { + ally: true, + all: true + }, + magical: true +} +export Ikari lightGuardIkari { + name: "Light guard", + cost: 128, + targets: TargetingMode { + ally: true, + all: true + }, + magical: true +} +export Ikari magicCureIkari { + name: "Magic cure", + cost: 128, + targets: TargetingMode { + ally: true, + single: true + }, + magical: true +} +export Ikari slowIkari { + name: "Slow", + cost: 196, + targets: TargetingMode { + enemy: true, + all: true + }, + physical: true +} +export Ikari suddenCureIkari { + name: "Sudden cure", + cost: 96, + targets: TargetingMode { + ally: true, + all: true + }, + magical: true +} +export Ikari tenLeggerIkari { + name: "Ten-legger", + cost: 164, + targets: TargetingMode { + enemy: true, + all: true + }, + physical: true +} +export Ikari thundershriekIkari { + name: "Thundershriek", + cost: 224, + targets: TargetingMode { + enemy: true, + all: true + }, + physical: true +} +export Ikari torrentIkari { + name: "Torrent", + cost: 224, + targets: TargetingMode { + enemy: true, + all: true + }, + physical: true +} +export Ikari trickIkari { + name: "Trick", + cost: 32, + targets: TargetingMode { + enemy: true, + all: true + }, + magical: true +} +export Ikari vulnerableIkari { + name: "Vulnerable", + cost: 196, + targets: TargetingMode { + enemy: true, + all: true + }, + physical: true +} diff --git a/test-data/items.l2h b/test-data/items.l2h new file mode 100644 index 0000000..c2461ec --- /dev/null +++ b/test-data/items.l2h @@ -0,0 +1,39 @@ +Item antidoteItem +Sprite armorIcon +Sprite axIcon +Sprite ballIcon +Sprite crankIcon +Item eagleRockItem +Item escapeItem +Item evilJewelItem +Item ghostRingItem +Sprite helmetIcon +Item hiPotionItem +Item holyCapItem +Item holyRobeItem +Item holyShieldItem +Sprite jewelIcon +Item krakenRockItem +Item legendHelmItem +Item lizardBlowItem +Item magicJarItem +Item megaShieldItem +Sprite potionIcon +Item powerPotionItem +Item powerRingItem +Sprite ringIcon +Item rocketRingItem +Sprite rodIcon +Item sProRingItem +Sprite shieldIcon +Item sleepBallItem +Sprite spearIcon +SimpleAnimation swordAttackAnimation +Sprite swordIcon +Item zircoAxItem +Item zircoGlovesItem +Item zircoHelmetItem +Item zircoSwordItem +Item zircoWhipItem +Item zirconArmorItem +Item zirconPlateItem diff --git a/test-data/items.l2s b/test-data/items.l2s new file mode 100644 index 0000000..76dd5aa --- /dev/null +++ b/test-data/items.l2s @@ -0,0 +1,236 @@ +include "ikaris.l2h" + +export Sprite potionIcon { + image: :"item-icons.png", + size: <16,16> +} +export Sprite ballIcon { + image: :"item-icons.png", + size: <16,16>, + offset: <0,16> +} +export Sprite crankIcon { + image: :"item-icons.png", + size: <16,16>, + offset: <0,32> +} +export Sprite spearIcon { + image: :"item-icons.png", + size: <16,16>, + offset: <0,48> +} +export Sprite swordIcon { + image: :"item-icons.png", + size: <16,16>, + offset: <0,64> +} +export Sprite axIcon { + image: :"item-icons.png", + size: <16,16>, + offset: <0,80> +} +export Sprite rodIcon { + image: :"item-icons.png", + size: <16,16>, + offset: <0,96> +} +export Sprite armorIcon { + image: :"item-icons.png", + size: <16,16>, + offset: <0,112> +} +export Sprite shieldIcon { + image: :"item-icons.png", + size: <16,16>, + offset: <0,128> +} +export Sprite helmetIcon { + image: :"item-icons.png", + size: <16,16>, + offset: <0,144> +} +export Sprite ringIcon { + image: :"item-icons.png", + size: <16,16>, + offset: <0,160> +} +export Sprite jewelIcon { + image: :"item-icons.png", + size: <16,16>, + offset: <0,176> +} + +export SimpleAnimation swordAttackAnimation { + sprite: Sprite { + image: :"attack-sword.png", + size: <96,96> + }, + frametime: twoFramesTime, + repeat: false, + framecount: 4 +} + +export Item antidoteItem { + name: "Antidote", + menuicon: potionIcon, + battle: true, + targets: TargetingMode { + ally: true, + single: true + } +} +export Item eagleRockItem { + name: "Eagle rock", + menuicon: jewelIcon, + ikari: diveIkari +} +export Item escapeItem { + name: "Escape", + battle: false +} +export Item evilJewelItem { + name: "Evil jewel", + menuicon: jewelIcon, + ikari: gloomyIkari +} +export Item ghostRingItem { + name: "Ghost ring", + menuicon: ringIcon, + ikari: destroyIkari +} +export Item hiPotionItem { + name: "Hi-Potion", + menuicon: potionIcon, + battle: true, + targets: TargetingMode { + ally: true, + single: true + } +} +export Item holyCapItem { + name: "Holy cap", + menuicon: helmetIcon, + ikari: vulnerableIkari +} +export Item holyRobeItem { + name: "Holy robe", + menuicon: armorIcon, + ikari: crisisCureIkari +} +export Item holyShieldItem { + name: "Holy shield", + menuicon: shieldIcon, + ikari: lightGuardIkari +} +export Item krakenRockItem { + name: "Kraken rock", + menuicon: jewelIcon, + ikari: tenLeggerIkari +} +export Item legendHelmItem { + name: "Legend helm", + menuicon: helmetIcon, + ikari: boomerangIkari +} +export Item lizardBlowItem { + name: "Lizard blow", + menuicon: swordIcon, + ikari: dragonRushIkari, + targets: TargetingMode { + enemy: true, + single: true + } +} +export Item magicJarItem { + name: "Magic jar", + menuicon: potionIcon, + battle: true, + targets: TargetingMode { + ally: true, + single: true + } +} +export Item megaShieldItem { + name: "Mega shield", + menuicon: shieldIcon, + ikari: ironBarrierIkari +} +export Item powerPotionItem { + name: "Power potion", + menuicon: potionIcon, + battle: false +} +export Item powerRingItem { + name: "Power ring", + menuicon: ringIcon, + ikari: trickIkari +} +export Item rocketRingItem { + name: "Rocket ring", + menuicon: ringIcon, + ikari: fakeIkari +} +export Item sleepBallItem { + name: "Sleep ball", + menuicon: ballIcon, + battle: true, + targets: TargetingMode { + enemy: true, + single: true + } +} +export Item sProRingItem { + name: "S-pro ring", + menuicon: ringIcon, + ikari: courageIkari +} +export Item zircoAxItem { + name: "Zirco ax", + menuicon: axIcon, + ikari: torrentIkari, + targets: TargetingMode { + enemy: true, + single: true + } +} +export Item zircoGlovesItem { + name: "Zirco gloves", + menuicon: shieldIcon, + ikari: forcefieldIkari +} +export Item zircoHelmetItem { + name: "Zirco helmet", + menuicon: helmetIcon, + ikari: slowIkari +} +export Item zirconArmorItem { + name: "Zircon armor", + menuicon: armorIcon, + battle: false, + ikari: magicCureIkari +} +export Item zirconPlateItem { + name: "Zircon plate", + menuicon: armorIcon, + ikari: suddenCureIkari +} +export Item zircoSwordItem { + name: "Zirco sword", + menuicon: swordIcon, + battle: false, + targets: TargetingMode { + enemy: true, + single: true + }, + ikari: firestormIkari, + attackanimation: swordAttackAnimation +} +export Item zircoWhipItem { + name: "Zirco whip", + menuicon: rodIcon, + targets: TargetingMode { + enemy: true, + single: true + }, + ikari: thundershriekIkari +} diff --git a/test-data/spells.l2h b/test-data/spells.l2h new file mode 100644 index 0000000..2da4057 --- /dev/null +++ b/test-data/spells.l2h @@ -0,0 +1,7 @@ +Spell championSpell +Spell escapeSpell +Spell rallySpell +Spell resetSpell +Spell strongSpell +Spell strongerSpell +Spell valorSpell diff --git a/test-data/spells.l2s b/test-data/spells.l2s new file mode 100644 index 0000000..ec3f1c8 --- /dev/null +++ b/test-data/spells.l2s @@ -0,0 +1,61 @@ +export Spell championSpell { + name: "Champion", + cost: 16, + battle: true, + targets: TargetingMode { + ally: true, + multiple: true + } +} + +export Spell escapeSpell { + name: "Escape", + cost: 8, + battle: false +} + +export Spell rallySpell { + name: "Rally", + cost: 10, + battle: true, + targets: TargetingMode { + ally: true, + multiple: true + } +} + +export Spell resetSpell { + name: "Reset", + cost: 0, + battle: false +} + +export Spell strongSpell { + name: "Strong", + cost: 3, + battle: true, + targets: TargetingMode { + ally: true, + multiple: true + } +} + +export Spell strongerSpell { + name: "Stronger", + cost: 8, + battle: true, + targets: TargetingMode { + ally: true, + multiple: true + } +} + +export Spell valorSpell { + name: "Valor", + cost: 30, + battle: true, + targets: TargetingMode { + ally: true, + multiple: true + } +} diff --git a/test-data/test.l2s b/test-data/test.l2s new file mode 100644 index 0000000..48817f4 --- /dev/null +++ b/test-data/test.l2s @@ -0,0 +1,590 @@ +include "ikaris.l2h" +include "items.l2h" +include "spells.l2h" + +Number frameTime 33 +Number twoFramesTime 66 +Number fourFramesTime 132 +Number fiveFramesTime 165 // darn, i really need to implement expressions + +export PartyLayout monstersLayout { + positions: [ + < 88, 88>, + <128, 88>, + <168, 88>, + <208, 88> + ] +} +export PartyLayout heroesLayout { + positions: [ + < 48,136>, + <128,136>, + < 80,152>, + <160,152> + ] +} + +Sprite lizardSprite { + image: :"monster.png", + size: <64,64> +} + +export Monster lizard { + name: "Lizard", + sprite: lizardSprite, + level: 1, + maxHealth: 8, + health: 8, + stats: Stats { + atp: 14, + dfp: 6, + str: 6, + agl: 6, + int: 6, + gut: 6, + mgr: 6 + }, + attackAnimation: ComplexAnimation { + sprite: lizardSprite, + frametime: fourFramesTime, + repeat: false, + frames: [ + { column: 0, row: 1, disposition: < 0, 16> }, + { column: 0, row: 0, disposition: < 0, 16> }, + { column: 0, row: 1, disposition: < 0, 16> }, + { column: 0, row: 0, disposition: < 0, 16> } + ] + }, + meleeAnimation: SimpleAnimation { + sprite: Sprite { + image: :"attack-monster.png", + size: <96,64> + }, + frametime: frameTime, + framecount: 14 + } +} + +Sprite maximSprite { + image: :"maxim.png", + size: <64,64> +} +export Hero maxim { + name: "Maxim", + level: 1, + sprite: maximSprite, + maxHealth: 33, + health: 33, + maxMana: 20, + mana: 20, + ip: 0, + stats: Stats { + atp: 28, + dfp: 22, + str: 28, + agl: 17, + int: 14, + gut: 100, + mgr: 10 + }, + attackAnimation: ComplexAnimation { + sprite: maximSprite, + frametime: frameTime, + repeat: false, + frames: [ + { column: 1, row: 0, disposition: < 0, 0> }, + { column: 1, row: 0, disposition: < 0, 0> }, + { column: 1, row: 0, disposition: < 0, 0> }, + { column: 1, row: 0, disposition: < 0, 0> }, + { column: 1, row: 0, disposition: < 0, 0> }, + { column: 1, row: 0, disposition: < 0, 0> }, + { column: 1, row: 0, disposition: < 0, 0> }, + { column: 1, row: 0, disposition: < 4,-1> }, + { column: 1, row: 0, disposition: < 4,-1> }, + { column: 2, row: 0, disposition: < 4,-2> }, + { column: 2, row: 0, disposition: < 4,-2> }, + { column: 2, row: 0, disposition: < 6,-2> }, + { column: 2, row: 0, disposition: < 6,-2> }, + { column: 2, row: 1, disposition: < 6,-1> }, + { column: 2, row: 1, disposition: < 3,-1> }, + { column: 2, row: 1, disposition: < 3,-1> }, + { column: 2, row: 1, disposition: < 0, 0> }, + { column: 2, row: 2, disposition: < 0, 0> }, + { column: 2, row: 2, disposition: < 0, 0> }, + { column: 2, row: 2, disposition: < 2, 0> }, + { column: 1, row: 0, disposition: < 0, 0> }, + { column: 1, row: 0, disposition: < 0, 0> }, + { column: 1, row: 0, disposition: < 0, 0> }, + { column: 1, row: 0, disposition: < 0, 0> }, + { column: 1, row: 0, disposition: < 0, 0> }, + { column: 1, row: 0, disposition: < 0, 0> }, + { column: 1, row: 0, disposition: < 0, 0> } + ] + }, + spellAnimation: ComplexAnimation { + sprite: maximSprite, + frametime: fiveFramesTime, + repeat: false, + frames: [ + { column: 3, row: 0, disposition: < 0, 0> }, + { column: 3, row: 0, disposition: < 0, 0> }, + { column: 3, row: 1, disposition: < 0, 0> } + ] + }, + meleeAnimation: SimpleAnimation { + sprite: Sprite { + image: :"melee-maxim.png", + size: <96,96> + }, + frametime: twoFramesTime, + framecount: 4 + } +} + +Sprite selanSprite { + image: :"selan.png", + size: <64,64> +} +export Hero selan { + name: "Selan", + level: 1, + sprite: selanSprite, + maxHealth: 28, + health: 28, + maxMana: 23, + mana: 23, + ip: 0, + stats: Stats { + atp: 23, + dfp: 21, + str: 23, + agl: 19, + int: 22, + gut: 80, + mgr: 13 + }, + attackAnimation: ComplexAnimation { + sprite: selanSprite, + frametime: frameTime, + repeat: false, + frames: [ + { column: 1, row: 0, disposition: < 4, 0> }, + { column: 1, row: 0, disposition: < 4, 0> }, + { column: 1, row: 0, disposition: < 8, 2> }, + { column: 2, row: 0, disposition: <10, 4> }, + { column: 2, row: 0, disposition: <14, 4> }, + { column: 2, row: 0, disposition: <12, 2> }, + { column: 2, row: 0, disposition: <12, 2> }, + { column: 2, row: 0, disposition: <12, 2> }, + { column: 2, row: 1, disposition: <14, 2> }, + { column: 2, row: 1, disposition: <14, 2> }, + { column: 2, row: 1, disposition: < 2, 0> }, + { column: 2, row: 2, disposition: <-2,-4> }, + { column: 2, row: 2, disposition: <-8,-8> }, + { column: 2, row: 2, disposition: < 0, 0> } + ] + }, + spellAnimation: ComplexAnimation { + sprite: selanSprite, + frametime: frameTime, + repeat: false, + frames: [ + { column: 3, row: 0, disposition: < 0, 0> }, + { column: 3, row: 0, disposition: < 0, 0> }, + { column: 3, row: 0, disposition: < 0, 0> }, + { column: 3, row: 1, disposition: < 0, 0> }, + { column: 3, row: 1, disposition: < 0, 0> }, + { column: 3, row: 2, disposition: < 0, 0> }, + { column: 3, row: 2, disposition: < 0, 0> }, + { column: 3, row: 2, disposition: < 0, 0> }, + { column: 3, row: 3, disposition: < 0, 0> }, + { column: 3, row: 3, disposition: < 0, 0> } + ] + }, + meleeAnimation: SimpleAnimation { + sprite: Sprite { + image: :"melee-selan.png", + size: <96,96> + }, + frametime: twoFramesTime, + framecount: 4 + } +} + +Sprite guySprite { + image: :"guy.png", + size: <64,64> +} +export Hero guy { + name: "Guy", + level: 1, + sprite: guySprite, + maxHealth: 38, + health: 38, + maxMana: 0, + mana: 0, + ip: 0, + stats: Stats { + atp: 38, + dfp: 25, + str: 38, + agl: 13, + int: 8, + gut: 90, + mgr: 8 + }, + attackAnimation: ComplexAnimation { + sprite: guySprite, + frametime: frameTime, + repeat: false, + frames: [ + { column: 1, row: 0, disposition: <-4, 0> }, + { column: 1, row: 0, disposition: <-4, 0> }, + { column: 1, row: 0, disposition: <-8, 0> }, + { column: 1, row: 0, disposition: <-8, 0> }, + { column: 2, row: 0, disposition: <-8, 0> }, + { column: 2, row: 0, disposition: <-8, 0> }, + { column: 2, row: 0, disposition: <-4, 0> }, + { column: 2, row: 0, disposition: < 0, 0> }, + { column: 2, row: 0, disposition: < 0, 0> }, + { column: 2, row: 1, disposition: < 0, 0> }, + { column: 2, row: 1, disposition: < 4, 0> }, + { column: 2, row: 1, disposition: <10, 0> }, + { column: 2, row: 2, disposition: <10, 0> }, + { column: 2, row: 2, disposition: < 0, 0> } + ] + }, + meleeAnimation: SimpleAnimation { + sprite: Sprite { + image: :"melee-guy.png", + size: <96,96> + }, + frametime: fourFramesTime, + framecount: 4 + } +} + +Sprite dekarSprite { + image: :"dekar.png", + size: <64,64> +} +export Hero dekar { + name: "Dekar", + level: 1, + sprite: dekarSprite, + maxHealth: 38, + health: 38, + maxMana: 0, + mana: 0, + ip: 0, + stats: Stats { + atp: 46, + dfp: 29, + str: 46, + agl: 13, + int: 7, + gut: 100, + mgr: 5 + }, + attackAnimation: ComplexAnimation { + sprite: dekarSprite, + frametime: frameTime, + repeat: false, + frames: [ + { column: 1, row: 0, disposition: < 4, 0> }, + { column: 1, row: 0, disposition: < 8, 2> }, + { column: 2, row: 0, disposition: <12, 4> }, + { column: 2, row: 0, disposition: <16, 4> }, + { column: 2, row: 0, disposition: <10, 2> }, + { column: 2, row: 0, disposition: <10, 2> }, + { column: 2, row: 0, disposition: <10, 2> }, + { column: 2, row: 0, disposition: <10, 2> }, + { column: 2, row: 1, disposition: < 6, 2> }, + { column: 2, row: 1, disposition: < 0, 0> }, + { column: 2, row: 2, disposition: <-2, 0> }, + { column: 2, row: 2, disposition: < 0, 0> }, + { column: 2, row: 2, disposition: < 0, 0> }, + { column: 2, row: 2, disposition: < 0, 0> } + ] + }, + spellAnimation: ComplexAnimation { + sprite: dekarSprite, + frametime: twoFramesTime, + repeat: false, + frames: [ + { column: 3, row: 0, disposition: < 0, 0> }, + { column: 3, row: 0, disposition: < 0, 0> }, + { column: 3, row: 0, disposition: < 0, 0> }, + { column: 3, row: 0, disposition: < 0, 0> }, + { column: 3, row: 0, disposition: < 0, 0> }, + { column: 3, row: 0, disposition: < 0, 0> }, + { column: 3, row: 1, disposition: < 0, 0> }, + { column: 3, row: 1, disposition: < 0, 0> }, + { column: 3, row: 2, disposition: < 0, 0> }, + { column: 3, row: 2, disposition: < 0, 0> }, + { column: 3, row: 2, disposition: < 0, 0> } + ] + }, + meleeAnimation: SimpleAnimation { + sprite: Sprite { + image: :"melee-dekar.png", + size: <96,96> + }, + frametime: twoFramesTime, + framecount: 4 + } +} + +Sprite handCursor { + image: :"cursor-hand.png", + size: <32,32> +} + +Font normalFont { + sprite: Sprite { + image: :"normal-font.png", + size: <16,16> + }, + rowoffset: -2 +} + +Font disabledFont { + sprite: Sprite { + image: :"disabled-font.png", + size: <16,16> + }, + rowoffset: -2 +} + +export BattleResources battleResources { + swapCursor: Sprite { + image: :"swap-cursor.png", + size: <32,32> + }, + attackIcons: Sprite { + image: :"attack-type-icons.png", + size: <32,32> + }, + attackChoiceIcons: Sprite { + image: :"attack-choice-icons.png", + size: <16,16> + }, + moveIcons: Sprite { + image: :"move-icons.png", + size: <32,32> + }, + + titleFrame: Frame { + image: :"title-frame.png", + border: <16,16> + }, + titleFont: Font { + sprite: Sprite { + image: :"large-font.png", + size: <16,32> + }, + rowoffset: -2 + }, + + numberAnimationPrototype: ComplexAnimation { + frametime: frameTime, + repeat: false, + frames: [ + { column: 0, row: 0, disposition: < 0, 0> }, + { column: 0, row: 0, disposition: < 0,-26> }, + { column: 0, row: 0, disposition: < 0,-42> }, + { column: 0, row: 0, disposition: < 0,-48> }, + { column: 0, row: 0, disposition: < 0,-42> }, + { column: 0, row: 0, disposition: < 0,-26> }, + { column: 0, row: 0, disposition: < 0, 0> }, + { column: 0, row: 0, disposition: < 0,-12> }, + { column: 0, row: 0, disposition: < 0,-20> }, + { column: 0, row: 0, disposition: < 0,-24> }, + { column: 0, row: 0, disposition: < 0,-20> }, + { column: 0, row: 0, disposition: < 0,-12> }, + { column: 0, row: 0, disposition: < 0, 0> }, + { column: 0, row: 0, disposition: < 0, -6> }, + { column: 0, row: 0, disposition: < 0,-10> }, + { column: 0, row: 0, disposition: < 0,-12> }, + { column: 0, row: 0, disposition: < 0,-10> }, + { column: 0, row: 0, disposition: < 0, -6> }, + { column: 0, row: 0, disposition: < 0, 0> }, + { column: 0, row: 0, disposition: < 0, 0> }, + { column: 0, row: 0, disposition: < 0, 0> }, + { column: 0, row: 0, disposition: < 0, 0> }, + { column: 0, row: 0, disposition: < 0, 0> }, + { column: 0, row: 0, disposition: < 0, 0> }, + { column: 0, row: 0, disposition: < 0, 0> }, + { column: 0, row: 0, disposition: < 0, 0> }, + { column: 0, row: 0, disposition: < 0, 0> }, + { column: 0, row: 0, disposition: < 0, 0> }, + { column: 0, row: 0, disposition: < 0, 0> }, + { column: 0, row: 0, disposition: < 0, 0> }, + { column: 0, row: 0, disposition: < 0, 0> }, + { column: 0, row: 0, disposition: < 0, 0> }, + { column: 0, row: 0, disposition: < 0,-36> }, + { column: 0, row: 0, disposition: < 0,-32> }, + { column: 0, row: 0, disposition: < 0,-18> } + ] + }, + bigNumberSprite: Sprite { + image: :"big-numbers.png", + size: <16,32> + }, + greenNumberSprite: Sprite { + image: :"big-green-numbers.png", + size: <16,32> + }, + + heroTagLabels: Sprite { + image: :"hero-tag-sprites.png", + size: <32,16> + }, + levelLabelCol: 0, + levelLabelRow: 0, + healthLabelCol: 0, + healthLabelRow: 1, + manaLabelCol: 0, + manaLabelRow: 2, + moveLabelCol: 0, + moveLabelRow: 3, + ikariLabelCol: 0, + ikariLabelRow: 4, + heroTagFont: Font { + sprite: Sprite { + image: :"numbers.png", + size: <16,16> + }, + rowoffset: -3 + }, + + activeHeroTagFrame: Frame { + image: :"tag-frames.png", + border: <16,16> + }, + heroTagFrame: Frame { + image: :"tag-frames.png", + border: <16,16>, + offset: < 0,33> + }, + + smallHeroTagFrame: Frame { + image: :"small-tag-frame.png", + border: <8,16> + }, + lastSmallHeroTagFrame: Frame { + image: :"small-tag-frame.png", + border: <8,16>, + offset: <0,33> + }, + heroesBgColor: (24, 40, 49), + + healthGauge: Gauge { + image: :"gauges.png", + full: <0,16>, + empty: <0, 0>, + height: 16, + start: 6, + repeat: 1, + end: 6 + }, + manaGauge: Gauge { + image: :"gauges.png", + full: <0,32>, + empty: <0, 0>, + height: 16, + start: 6, + repeat: 1, + end: 6 + }, + ikariGauge: Gauge { + image: :"gauges.png", + full: <0,48>, + empty: <0, 0>, + height: 16, + start: 6, + repeat: 1, + end: 6 + }, + + selectFrame: Frame { + image: :"select-frame.png", + border: <16,16> + }, + normalFont: normalFont, + disabledFont: disabledFont, + menuCursor: Sprite { + image: :"cursor-hand.png", + size: <32,32> + }, + + weaponTargetCursor: Sprite { + image: :"targeting-icons.png", + size: <32,32> + }, + magicTargetCursor: Sprite { + image: :"targeting-icons.png", + size: <32,32>, + offset: <0,32> + }, + itemTargetCursor: Sprite { + image: :"targeting-icons.png", + size: <32,32>, + offset: <0,64> + }, + + weaponMenuIcon: swordIcon, + armorMenuIcon: armorIcon, + shieldMenuIcon: shieldIcon, + helmetMenuIcon: helmetIcon, + ringMenuIcon: ringIcon, + jewelMenuIcon: jewelIcon, + + spellMenuHeadline: "Please choose a spell.", + spellMenuProperties: MenuProperties { + font: normalFont, + disabledFont: disabledFont, + cursor: handCursor, + charsPerEntry: 9, + rows: 6, + rowGap: 8, + iconSpace: 0, + cols: 2, + colGap: 32, + charsPerNumber: 2, + delimiter: ":" + }, + + itemMenuHeadline: "Please choose an item.", + itemMenuProperties: MenuProperties { + font: normalFont, + disabledFont: disabledFont, + cursor: handCursor, + charsPerEntry: 15, + rows: 6, + rowGap: 8, + iconSpace: 16, + cols: 1, + colGap: 32, + charsPerNumber: 2, + delimiter: ":" + }, + + ikariMenuHeadline: "Please choose equipment.", + ikariMenuProperties: MenuProperties { + font: normalFont, + disabledFont: disabledFont, + cursor: handCursor, + charsPerEntry: 12, + rows: 6, + rowGap: 8, + iconSpace: 16, + cols: 1, + colGap: 32, + charsPerAdditionalText: 12, + additionalTextGap: 16 + }, + noEquipmentText: "No equip", + + escapeText: "Escapes." +} \ No newline at end of file