]> Chaos Git - vn/vndc.git/commitdiff
Initial commit
authorchaoskagami <chaos.kagami@gmail.com>
Fri, 22 Aug 2014 22:10:32 +0000 (18:10 -0400)
committerchaoskagami <chaos.kagami@gmail.com>
Fri, 22 Aug 2014 22:10:32 +0000 (18:10 -0400)
32 files changed:
build [new file with mode: 0755]
external/include/zero/AudioManager.hpp [new file with mode: 0644]
external/include/zero/ContextManager.hpp [new file with mode: 0644]
external/include/zero/TextManager.hpp [new file with mode: 0644]
external/include/zero/UDisplayable.hpp [new file with mode: 0644]
external/include/zero/Zero.hpp [new file with mode: 0644]
external/src/zero/AudioManager.cpp [new file with mode: 0644]
external/src/zero/ContextManager.cpp [new file with mode: 0644]
external/src/zero/TextManager.cpp [new file with mode: 0644]
external/src/zero/UDisplayable.cpp [new file with mode: 0644]
mk [new file with mode: 0755]
vndc/include/Data.hpp [new file with mode: 0644]
vndc/include/Funcs.hpp [new file with mode: 0644]
vndc/src/Data.cpp [new file with mode: 0644]
vndc/src/Loop.cpp [new file with mode: 0644]
vndc/src/Parse.cpp [new file with mode: 0644]
vndc/src/VNDC.cpp [new file with mode: 0644]
vndc/src/op_bgload.cpp [new file with mode: 0644]
vndc/src/op_choice.cpp [new file with mode: 0644]
vndc/src/op_cleartext.cpp [new file with mode: 0644]
vndc/src/op_delay.cpp [new file with mode: 0644]
vndc/src/op_fi.cpp [new file with mode: 0644]
vndc/src/op_goto.cpp [new file with mode: 0644]
vndc/src/op_gsetvar.cpp [new file with mode: 0644]
vndc/src/op_if.cpp [new file with mode: 0644]
vndc/src/op_jump.cpp [new file with mode: 0644]
vndc/src/op_music.cpp [new file with mode: 0644]
vndc/src/op_random.cpp [new file with mode: 0644]
vndc/src/op_setimg.cpp [new file with mode: 0644]
vndc/src/op_setvar.cpp [new file with mode: 0644]
vndc/src/op_sound.cpp [new file with mode: 0644]
vndc/src/op_text.cpp [new file with mode: 0644]

diff --git a/build b/build
new file mode 100755 (executable)
index 0000000..aa6e260
--- /dev/null
+++ b/build
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+ROOT=`pwd`
+SRC=$ROOT/
+LIB=$ROOT/external/lib
+BIN=$ROOT/bin
+
+source mk
+
+INCLUDE="-I$ROOT/external/include/zero -I$ROOT/vndc/include"
+
+newtd
+       mkmcc           external/src/zero
+       mkar            libZero 
+deltd
+
+LDFLAGS=-lZero
+
+newtd
+       mkmcc vndc/src
+       mkld            vndc
+deltd
diff --git a/external/include/zero/AudioManager.hpp b/external/include/zero/AudioManager.hpp
new file mode 100644 (file)
index 0000000..fd22d39
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef AUDIOMANAGER_HPP
+#define AUDIOMANAGER_HPP
+
+
+       class AudioManager {
+               public:
+                       // Ctors and dtors
+                       AudioManager();
+                       ~AudioManager();
+
+                       // Load index.
+                       int LoadSfx(char* fname);
+                       int LoadMusic(char* fname);
+
+                       // Playing functions.
+                       void PlaySfx(int index);
+                       void PlaySfx(int index, int count);
+                       void PlayMusic(int index);
+                       void PlayMusicLoop(int index);
+                       void PauseMusic();
+
+                       // Unload Functions
+                       void UnloadSfx(int index);
+                       void UnloadMusic(int index);
+
+                       // Complete unload functions
+                       void FlushSfx();
+                       void FlushMusic();
+               private:
+                       int SfxCount = 0, MusicCount = 0;
+                       Mix_Chunk** SfxStore = NULL;
+                       Mix_Music** MusicStore = NULL;
+       };
+
+
+#endif
diff --git a/external/include/zero/ContextManager.hpp b/external/include/zero/ContextManager.hpp
new file mode 100644 (file)
index 0000000..6d1f976
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef CONTEXTMANAGER_HPP
+#define CONTEXTMANAGER_HPP
+
+typedef void (*GameCallback)(bool);
+typedef void (*MouseCallback)(int, int, bool, bool, bool, bool); // X, Y, up/down, isLeft, isMiddle, isRight
+
+class TextManager; // Forward decl
+
+       // Input Mode enum. This is the max events allowed in one go.
+       typedef enum InMode_e {
+               Slow = 20,
+               Medium = 10,
+               Burst = 5
+       } InMode;
+
+       class ContextManager {
+               public:
+                       ContextManager();
+                       ContextManager(int scr_width, int scr_height, bool fulls, bool accel);
+
+                       // Initialization.
+                       void InitWindow(int width, int height, bool fulls, bool accel);
+                       void InitWindowLogical(int width, int height, int width_log, int height_log, bool fulls, bool accel);
+
+                       // Set window title
+                       void SetTitle(char* title);
+
+                       // Display related.
+                       void Clear();
+                       void Flush();
+
+                       void ClearOverlay();
+
+                       SDL_Surface* Surface();
+                       SDL_Renderer* Renderer();
+                       bool Accelerated();
+                       void Blit(void* inp, SDL_Rect* src, SDL_Rect* dst);
+                       void OverlayBlit(void* inp, SDL_Rect* src, SDL_Rect* dst);
+
+                       // Support funcs.
+                       int GetWidth();
+                       int GetHeight();
+
+                       // Get Input State and Modify input state.
+                       bool Input();
+
+                       // Abstract remappable key functions.
+                       int RegisterInput(SDL_Keycode key, GameCallback func);
+                       void RegisterMouse(MouseCallback func);
+                       bool GetInput(int index);
+                       void RemapKey(int index, SDL_Keycode to);
+                       void InputMode(InMode mode);
+
+                       // Gets the AudioManager & TextManager
+                       AudioManager* Audio();
+                       TextManager* Text();
+
+                       // Exit methods.
+                       void SetQuit();
+                       bool GetQuit();
+
+                       // Logic sync limiter.
+                       void StartSync();
+                       void EndSync();
+
+                       ~ContextManager();
+               private:
+                       // Lower init.
+                       // DELETEME - Software rendering doesn't work now.
+                       void _InitWindowSW(int width, int height, bool fulls);
+                       void _InitWindowAC(int width, int height, bool fulls);
+                       // DELETEME - Software rendering doesn't work now.
+                       void _InitWindowLogicalSW(int width_win, int height_win, int width_log, int height_log, bool fulls);
+                       void _InitWindowLogicalAC(int width_win, int height_win, int width_log, int height_log, bool fulls);
+
+                       InMode inputmode = Medium;
+                       SDL_Window* window = NULL;
+                       SDL_Surface* surface = NULL, *surface_o = NULL;
+                       SDL_Texture* texture = NULL, *texture_o = NULL;
+                       SDL_Renderer* renderer = NULL;
+                       // use logical size
+                       bool logicalRender = false;
+                       bool accelerate = false;
+
+                       bool StartQuit = false;
+
+                       AudioManager* audioMgr = NULL;
+                       TextManager* txtMgr = NULL;
+
+                       SDL_Keycode* inputMappings = NULL; // This can actually be used instead of InputList now. Weird.
+                       bool* inputStates = NULL;
+                       GameCallback* inputCallbacks = NULL;
+                       MouseCallback mouseCallback = NULL;
+
+                       int inputRegistered = 0;
+
+                       // Logic cap.
+                       int logicRate = 60;
+                       int timeElapsed = 0;
+                       int syncElapsed = 0;
+
+                       // Width and height
+                       int WIN_width = 0;
+                       int WIN_height = 0;
+                       int LOG_width = 0;
+                       int LOG_height = 0;
+       };
+
+#endif
diff --git a/external/include/zero/TextManager.hpp b/external/include/zero/TextManager.hpp
new file mode 100644 (file)
index 0000000..7e97530
--- /dev/null
@@ -0,0 +1,45 @@
+
+class TextManager {
+       public:
+               // Ctors & Dtors
+               TextManager(ContextManager* ct);
+               ~TextManager();
+
+               // Base font functions.
+               int LoadFont(char* fname);
+               void Render(char* text);
+               void Render(char* text, int x, int y);
+
+               int TestLen(char* text);
+               void Outline(int pixels);
+
+               // Property functions.
+               // void SetStyle(int style);
+               // void SetFontUsed(int font);
+               void SetColor(int r, int g, int b, int a);
+
+               // Complex functions.
+               // Like printf but with formatting codes. Also not varargs.
+               // Should support this subset of standards:
+               // %d %u %x %c %s %f %%
+               // It also should have the following:
+               // %t - Font Index. Switches to font index.
+               // %p - Style. Sets style to S.
+               // %m - Expects an SDL_Color. Sets the color.
+               // void fnoutf(char* text, void** data);
+
+               // Uses control codes, unline fnoutf. Mainly intended for scripts.
+               // These ops should be implemented:
+               // ^b (bold) ^i (italic) ^r (normal / reset) ^fI (font -> i)
+               // ^cNNN (color -> #NNN) ^n (next line) ^c (clear)
+               // void scoutf(char* text);
+
+       private:
+               TTF_Font** fonts = NULL;
+               int current_font = 0;
+               int fonts_loaded = 0;
+               SDL_Color color;
+               ContextManager* ctx = NULL;
+               bool outline = false;
+               int outline_px = 0;
+};
diff --git a/external/include/zero/UDisplayable.hpp b/external/include/zero/UDisplayable.hpp
new file mode 100644 (file)
index 0000000..076bdd8
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef UDISPLAYABLE_HPP
+#define UDISPLAYABLE_HPP
+
+typedef enum {
+       Normal=1,
+       Hitbox=2,
+       Docked=3,
+       HitboxDocked=4,
+       Anim=5, // nyi
+       AnimHitbox=6, // nyi
+       AnimDocked=7, // nyi
+       AnimHitboxDocked=8 // nyi
+} UDisplayableMode;
+
+       class UDisplayable {
+               public:
+                       UDisplayable(ContextManager* ctx, char* fname); // Sets up in normal mode.
+                       UDisplayable(ContextManager* ctx, UDisplayableMode mode, char* fname); // Sets up in specified mode; params not set
+                       UDisplayable(ContextManager* ctx, UDisplayableMode mode, void* memory, int mSize); // Sets up from memory block in mode
+
+                       // All modes can use the following.
+                       void SetXY(double x, double y);
+                       void ModXY(double xd, double yd);
+
+                       double GetX();
+                       double GetY();
+
+                       int GetXI();
+                       int GetYI();
+
+                       void Blit();
+
+                       int* GetHitbox();
+
+                       ~UDisplayable();
+
+                       // Only specific modes can use these. Otherwise, they nop.
+                       void SetHitbox(int x, int y, int w, int h);
+                       void SetDock(int x, int y, int w, int h);
+
+                       // Only animated Displayables can use these.
+                       void SetFrameWidth(int frameW);
+                       void NextFrame();
+                       void NextFrame(int f);
+                       void ResetFrame();
+                       void SetFrame(int f);
+
+
+               protected:
+                       double x, y;
+                       void* bitmap = NULL; // Will contain either a SDL_Surface or SDL_Texture
+                       SDL_Rect loc, clip;
+                       ContextManager* ctx;
+
+                       int bmp_w = 0, bmp_h = 0;
+
+                       // Used in docked mode
+                       int* frame = NULL;
+                       // Used in hitbox mode
+                       int* hitbox = NULL;
+
+                       // The current mode.
+                       UDisplayableMode dispMode = Normal;
+
+                       // Used by animated mode.
+                       int frameIndex = -1;
+                       int frameWidth;
+
+                       bool Error = false;
+       };
+#endif
diff --git a/external/include/zero/Zero.hpp b/external/include/zero/Zero.hpp
new file mode 100644 (file)
index 0000000..cfbdffe
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _ZERO_LIBRARY_HPP
+#define _ZERO_LIBRARY_HPP
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_image.h>
+#include <SDL2/SDL_mixer.h>
+#include <SDL2/SDL_ttf.h>
+
+#include "AudioManager.hpp"
+#include "ContextManager.hpp"
+#include "TextManager.hpp"
+#include "UDisplayable.hpp"
+
+#endif
diff --git a/external/src/zero/AudioManager.cpp b/external/src/zero/AudioManager.cpp
new file mode 100644 (file)
index 0000000..c3cadc8
--- /dev/null
@@ -0,0 +1,167 @@
+#include "Zero.hpp"
+
+       // Sets up.
+       AudioManager::AudioManager() {
+               int MixerFlags = MIX_INIT_OGG | MIX_INIT_FLAC | MIX_INIT_MP3;
+               if((Mix_Init(MixerFlags) & MixerFlags) != MixerFlags) {
+                       // Failed to load.
+                       fprintf(stderr, "[E] Failed on Mix_Init. Reported error:\n");
+                       fprintf(stderr, "[E] %s\n", Mix_GetError());
+                       fprintf(stderr, "[E] Fatal. Dying.\n");
+                       exit(-1);
+               }
+
+               uint16_t fmt = 0;
+               int freq = 0, chan = 0;
+               Mix_QuerySpec(&freq, &fmt, &chan);
+
+               if (Mix_OpenAudio(freq, fmt, chan, 1024)) {
+                       printf("[Mix:err] %s\n", Mix_GetError());
+                       exit(-7);
+               }
+
+               Mix_AllocateChannels(64); // 32 Sfx + 1 Music
+       }
+
+       // Cleans up everything.
+       AudioManager::~AudioManager() {
+               Mix_HaltChannel(-1);
+               Mix_HaltMusic();
+
+               while (SfxCount > 0) {
+                       Mix_FreeChunk(SfxStore[SfxCount-1]);
+                       --SfxCount;
+               }
+
+               while (MusicCount > 0) {
+                       Mix_FreeMusic(MusicStore[MusicCount-1]);
+                       --MusicCount;
+               }
+
+               free(SfxStore);
+               free(MusicStore);
+
+               Mix_CloseAudio();
+
+               while(Mix_Init(0))
+                       Mix_Quit();
+       }
+
+       int AudioManager::LoadSfx(char* fname) {
+               ++SfxCount;
+               SfxStore = (Mix_Chunk**)realloc(SfxStore, sizeof(Mix_Chunk*) * SfxCount);
+
+               memset(&SfxStore[SfxCount-1], 0, sizeof(Mix_Chunk*));
+
+               SfxStore[SfxCount-1] = NULL;
+
+               SfxStore[SfxCount-1] = Mix_LoadWAV(fname);
+
+               if(!SfxStore[SfxCount-1]) {
+                       --SfxCount;
+                       SfxStore = (Mix_Chunk**)realloc(SfxStore, sizeof(Mix_Chunk*) * SfxCount);
+                       return -1;
+               }
+
+               return SfxCount - 1;
+       }
+
+       int AudioManager::LoadMusic(char* fname) {
+               ++MusicCount;
+               MusicStore = (Mix_Music**)realloc(MusicStore, sizeof(Mix_Music*) * MusicCount);
+
+               memset(&MusicStore[MusicCount-1], 0, sizeof(Mix_Music*));
+
+               MusicStore[MusicCount-1] = NULL;
+
+               MusicStore[MusicCount-1] = Mix_LoadMUS(fname);
+
+               if(!MusicStore[MusicCount-1]) {
+                       --MusicCount;
+                       MusicStore = (Mix_Music**)realloc(MusicStore, sizeof(Mix_Music*) * MusicCount);
+                       return -1;
+               }
+
+               return MusicCount - 1;
+       }
+
+       void AudioManager::PlaySfx(int index) {
+               if(index == -1)
+                       return;
+
+               if (index > SfxCount-1)
+                       return; // Not a valid index. No-op.
+
+               Mix_PlayChannel(-1, SfxStore[index], 0);
+       }
+
+       void AudioManager::PlaySfx(int index, int count) {
+               if(index == -1)
+                       return;
+
+               if (index > SfxCount-1)
+                       return; // Not a valid index. No-op.
+
+               Mix_PlayChannel(-1, SfxStore[index], count);
+       }
+
+       void AudioManager::PlayMusic(int index) {
+               if(index == -1)
+                       return;
+
+               // FIXME - Implement this.
+               Mix_PlayMusic(MusicStore[index], 0);
+       }
+
+       void AudioManager::PlayMusicLoop(int index) {
+               if(index == -1)
+                       return;
+
+               // FIXME - Implement this.
+               Mix_PlayMusic(MusicStore[index], -1);
+       }
+
+       void AudioManager::PauseMusic() {
+               // FIXME - Implement this.
+               Mix_PauseMusic();
+       }
+
+       void AudioManager::UnloadSfx(int index) {
+               if(index == -1)
+                       return;
+
+               Mix_FreeChunk(SfxStore[index]);
+       }
+
+       void AudioManager::UnloadMusic(int index) {
+               if(index == -1)
+                       return;
+
+               Mix_FreeMusic(MusicStore[index]);
+       }
+
+       // Unload all sfx
+       void AudioManager::FlushSfx() {
+               Mix_HaltChannel(-1);
+
+               while (SfxCount > 0) {
+                       Mix_FreeChunk(SfxStore[SfxCount-1]);
+                       --SfxCount;
+               }
+
+               free(SfxStore);
+               SfxStore = NULL;
+       }
+
+       // Unload all music.
+       void AudioManager::FlushMusic() {
+               Mix_HaltMusic();
+
+               while (MusicCount > 0) {
+                       Mix_FreeMusic(MusicStore[MusicCount-1]);
+                       --MusicCount;
+               }
+
+               free(MusicStore);
+               MusicStore = NULL;
+       }
diff --git a/external/src/zero/ContextManager.cpp b/external/src/zero/ContextManager.cpp
new file mode 100644 (file)
index 0000000..a645cab
--- /dev/null
@@ -0,0 +1,453 @@
+#include "Zero.hpp"
+
+
+       // Initializes SDL and saves stuff into the context.
+
+       ContextManager::ContextManager(int scr_width, int scr_height, bool fulls, bool accel) {
+               if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) < 0) {
+                       #ifdef DEBUG_OVERKILL
+                       printf("[ContextManager~Ctor] SDL Init error w/ VIDEO|AUDIO. Msg rep: %s\n", SDL_GetError());
+                       #else
+                       printf("Error initializing SDL. Info:%s\n", SDL_GetError());
+                       #endif
+               }
+               else {
+                       this->InitWindow(scr_width, scr_height, fulls, accel);
+               }
+
+               audioMgr = new AudioManager();
+       }
+
+       // Delays window creation; Use InitWindow before doing anything.
+
+       ContextManager::ContextManager() {
+               if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) < 0) {
+                       #ifdef DEBUG_OVERKILL
+                       printf("[ContextManager~Ctor] SDL Init error w/ VIDEO|AUDIO. Msg rep: %s\n", SDL_GetError());
+                       #else
+                       printf("Error initializing SDL. Info:%s\n", SDL_GetError());
+                       #endif
+               }
+
+               audioMgr = new AudioManager();
+       }
+
+       // Creates a window.
+
+       void ContextManager::InitWindow(int width, int height, bool fulls, bool accel) {
+               this->WIN_width = width;
+               this->WIN_height = height;
+               this->LOG_width = width;
+               this->LOG_height = height;
+
+               #ifdef DEBUG_OVERKILL
+               printf("[ContextManager::InitWindow] Params: w:%d h:%d f:%d a:%d\n", width, height, fulls, accel);
+               #endif
+
+               if(accel) {
+                       _InitWindowAC(width, height, fulls);
+                       this->texture_o = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
+                       SDL_SetTextureBlendMode(this->texture_o, SDL_BLENDMODE_BLEND);
+               }
+               else {
+                       _InitWindowSW(width, height, fulls);
+                       this->surface_o = SDL_CreateRGBSurface(0, width, height, 32, 0, 0, 0, 0);
+               }
+
+               txtMgr = new TextManager(this);
+       }
+
+       void ContextManager::_InitWindowSW(int width, int height, bool fulls) {
+               // Add title setting function.
+               this->window = SDL_CreateWindow("Zero", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN);
+               if(this->window == NULL) {
+                       fprintf(stderr, "[E] Error creating window. Info:\n");
+                       fprintf(stderr, "[E] %s\n", SDL_GetError());
+                       fprintf(stderr, "[E] This is fatal. Dying.");
+                       exit(-1);
+               }
+               else {
+                       SDL_SetHintWithPriority(SDL_HINT_RENDER_VSYNC, "1", SDL_HINT_OVERRIDE);
+                       if(!SDL_CreateRenderer( this->window, -1, SDL_RENDERER_ACCELERATED )) {
+                               fprintf(stderr, "[E] Error creating renderer. Info:\n");
+                               fprintf(stderr, "[E] %s\n", SDL_GetError());
+                               fprintf(stderr, "[E] This is fatal. Dying.");
+                               exit(-1);
+                       }
+               }
+       }
+
+       void ContextManager::_InitWindowAC(int width, int height, bool fulls) {
+               this->accelerate = true;
+
+               this->window = SDL_CreateWindow("Zero", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN);
+               if(this->window == NULL) {
+                       fprintf(stderr, "[E] Error creating window. Info:\n");
+                       fprintf(stderr, "[E] %s\n", SDL_GetError());
+                       fprintf(stderr, "[E] This is fatal. Dying.");
+                       exit(-1);
+               }
+               else {
+                       this->renderer = SDL_CreateRenderer( this->window, -1, SDL_RENDERER_ACCELERATED );
+                       if(this->renderer == NULL) {
+                               fprintf(stderr, "[E] Error creating renderer. Info:\n");
+                               fprintf(stderr, "[E] %s\n", SDL_GetError());
+                               fprintf(stderr, "[E] This is fatal. Dying.");
+                               exit(-1);
+                       }
+                       else {
+                               this->logicalRender = true;
+
+                               this->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
+                       }
+               }
+       }
+
+       // Init window with a logical size and a real one. Determines which backend to use.
+       void ContextManager::InitWindowLogical(int width_win, int height_win, int width_log, int height_log, bool fulls, bool accel) {
+               this->LOG_width = width_log;
+               this->LOG_height = height_log;
+               this->WIN_width = width_win;
+               this->WIN_height = height_win;
+
+               #ifdef DEBUG_OVERKILL
+               printf("[ContextManager::InitWindowLogical] phyw:%d phyh:%d logw:%d logh:%d f:%d a:%d\n", width_win, height_win, width_log, height_log, fulls, accel);
+               #endif
+
+               if (accel) {
+                       _InitWindowLogicalAC(width_win, height_win, width_log, height_log, fulls);
+                       this->texture_o = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width_win, height_win);
+                       SDL_SetTextureBlendMode(this->texture_o, SDL_BLENDMODE_BLEND);
+               }
+               else {
+                       _InitWindowLogicalSW(width_win, height_win, width_log, height_log, fulls);
+                       this->surface_o = SDL_CreateRGBSurface(0, width_win, height_win, 32, 0, 0, 0, 0);
+               }
+
+               txtMgr = new TextManager(this);
+       }
+
+       // Init window with a logical size and a real one.
+       void ContextManager::_InitWindowLogicalSW(int width_win, int height_win, int width_log, int height_log, bool fulls) {
+               this->window = SDL_CreateWindow("Zero", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width_win, height_win, SDL_WINDOW_SHOWN);
+               if(this->window == NULL) {
+                       fprintf(stderr, "[E] Error creating window. Info:\n");
+                       fprintf(stderr, "[E] %s\n", SDL_GetError());
+                       fprintf(stderr, "[E] This is fatal. Dying.");
+                       exit(-1);
+               }
+               else {
+                       this->renderer = SDL_CreateRenderer( this->window, -1, SDL_RENDERER_ACCELERATED );
+                       if(this->renderer == NULL) {
+                               fprintf(stderr, "[E] Error creating renderer. Info:\n");
+                               fprintf(stderr, "[E] %s\n", SDL_GetError());
+                               fprintf(stderr, "[E] This is fatal. Dying.");
+                               exit(-1);
+                       }
+                       else {
+                               this->logicalRender = true;
+
+                               this->surface = SDL_CreateRGBSurface(0, width_log, height_log, 32, 0, 0, 0, 0);
+                       }
+               }
+       }
+
+               // Init window with a logical size and a real one.
+       void ContextManager::_InitWindowLogicalAC(int width_win, int height_win, int width_log, int height_log, bool fulls) {
+               this->accelerate = true;
+
+               this->window = SDL_CreateWindow("Zero", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width_win, height_win, SDL_WINDOW_SHOWN);
+               if(this->window == NULL) {
+                       fprintf(stderr, "[E] Error creating window. Info:\n");
+                       fprintf(stderr, "[E] %s\n", SDL_GetError());
+                       fprintf(stderr, "[E] This is fatal. Dying.");
+                       exit(-1);
+               }
+               else {
+                       this->renderer = SDL_CreateRenderer( this->window, -1, SDL_RENDERER_ACCELERATED );
+                       if(this->renderer == NULL) {
+                               fprintf(stderr, "[E] Error creating renderer. Info:\n");
+                               fprintf(stderr, "[E] %s\n", SDL_GetError());
+                               fprintf(stderr, "[E] This is fatal. Dying.");
+                               exit(-1);
+                       }
+                       else {
+                               this->logicalRender = true;
+
+                               this->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width_log, height_log);
+                       }
+               }
+       }
+
+       // Clears the display to black.
+
+       void ContextManager::Clear() {
+               if(this->StartQuit) return;
+
+               if (accelerate) {
+                       if (logicalRender) {
+                               SDL_SetRenderTarget(renderer, texture);
+                               SDL_RenderClear(renderer);
+                               SDL_SetRenderTarget(renderer, NULL);
+                       }
+
+                       SDL_SetRenderTarget(renderer, texture_o);
+                       SDL_RenderClear(renderer);
+                       SDL_SetRenderTarget(renderer, NULL);
+
+                       SDL_RenderClear(renderer);
+               }
+               else {
+                       if (logicalRender)
+                               SDL_FillRect(this->surface, NULL, SDL_MapRGB(this->surface->format, 0x0, 0x0, 0x0));
+                       SDL_FillRect(this->surface_o, NULL, SDL_MapRGB(this->surface_o->format, 0x0, 0x0, 0x0));
+
+                       SDL_FillRect(SDL_GetWindowSurface(this->window), NULL, SDL_MapRGB(SDL_GetWindowSurface(this->window)->format, 0x0, 0x0, 0x0));
+               }
+       }
+
+       // Clears the display to black.
+
+       void ContextManager::ClearOverlay() {
+               if(this->StartQuit) return;
+
+               if (accelerate) {
+                       SDL_SetRenderTarget(renderer, texture_o);
+                       SDL_RenderClear(renderer);
+                       SDL_SetRenderTarget(renderer, NULL);
+               }
+               else {
+                       SDL_FillRect(this->surface_o, NULL, SDL_MapRGB(this->surface_o->format, 0x0, 0x0, 0x0));
+               }
+       }
+
+       // Flush any changes in the surface to screen
+
+       void ContextManager::Flush() {
+               if(this->StartQuit) return;
+               if (accelerate) {
+                       if(logicalRender) {
+                               SDL_Rect dst, src;
+
+                               src.x = 0;
+                               src.y = 0;
+                               src.w = LOG_width;
+                               src.h = LOG_height;
+
+                               dst.x = 0;
+                               dst.y = 0;
+                               dst.w = WIN_width;
+                               dst.h = WIN_height;
+
+                               SDL_RenderCopy(renderer, texture, &src, &dst);
+                       }
+
+                       SDL_RenderCopy(renderer, texture_o, NULL, NULL);
+
+                       SDL_RenderPresent(renderer);
+               }
+               else {
+                       if(logicalRender)
+                               SDL_BlitScaled(this->surface, NULL, SDL_GetWindowSurface(this->window), NULL);
+
+                       SDL_BlitScaled(this->surface_o, NULL, SDL_GetWindowSurface(this->window), NULL);
+
+                       SDL_UpdateWindowSurface(this->window);
+               }
+       }
+
+       // Return the internal surface for external blits.
+       SDL_Surface* ContextManager::Surface() {
+               if(this->StartQuit) return NULL;
+               if(accelerate) return NULL;
+
+               if( logicalRender )
+                       return this->surface;
+
+               return SDL_GetWindowSurface(this->window);
+       }
+
+       // return the renderer.
+       SDL_Renderer* ContextManager::Renderer() {
+               return renderer;
+       }
+
+               // return the renderer.
+       bool ContextManager::Accelerated() {
+               return accelerate;
+       }
+
+       // Blit data via cast. inp should be a SDL_Surface or SDL_Texture.
+       void ContextManager::Blit(void* inp, SDL_Rect* src, SDL_Rect* dst) {
+               if(accelerate) {
+                       if (logicalRender) SDL_SetRenderTarget(renderer, texture);
+
+                       SDL_RenderCopy(renderer, (SDL_Texture*)inp, src, dst);
+
+                       if (logicalRender) SDL_SetRenderTarget(renderer, NULL);
+               }
+               else {
+                       SDL_BlitSurface((SDL_Surface*)inp, src, surface, dst);
+               }
+       }
+
+       // Blit data to overlay via cast. inp should be a SDL_Surface or SDL_Texture.
+       void ContextManager::OverlayBlit(void* inp, SDL_Rect* src, SDL_Rect* dst) {
+               // Recalculate src and dst based on upscale.
+               double OUTW_Ratio, OUTH_Ratio;
+               OUTW_Ratio = (double)WIN_width  / (double)LOG_width;
+               OUTH_Ratio = (double)WIN_height / (double)LOG_height;
+
+               dst->x = (int)(((double)dst->x) * OUTW_Ratio);
+               dst->y = (int)(((double)dst->y) * OUTH_Ratio);
+               dst->w = (int)(((double)dst->w) * OUTW_Ratio);
+               dst->h = (int)(((double)dst->h) * OUTH_Ratio);
+
+               if(accelerate) {
+                       if (logicalRender) SDL_SetRenderTarget(renderer, texture_o);
+
+                       SDL_RenderCopy(renderer, (SDL_Texture*)inp, src, dst);
+
+                       if (logicalRender) SDL_SetRenderTarget(renderer, NULL);
+               }
+               else {
+                       SDL_BlitSurface((SDL_Surface*)inp, src, surface_o, dst);
+               }
+       }
+
+       // Gets width of display
+       int ContextManager::GetWidth() {
+               return this->LOG_width;
+       }
+
+       // Gets height of display
+       int ContextManager::GetHeight() {
+               return this->LOG_height;
+       }
+
+       // Checks input events for matches and run callbacks.
+       bool ContextManager::Input() {
+               if(this->StartQuit) return this->StartQuit;
+
+               SDL_Event evt;
+               for(int i = 0; i < this->inputmode && SDL_PollEvent(&evt); i++) {
+                       for(int j = 0; j < inputRegistered; j++) {
+                               if(inputMappings[j] == evt.key.keysym.sym) {
+                                       bool down = false;
+                                       if(evt.type == SDL_KEYDOWN)
+                                               down = true;
+                                       inputStates[j] = down;
+                                       if((evt.type == SDL_KEYDOWN || evt.type == SDL_KEYUP) && inputCallbacks[j] != NULL) {
+                                               (inputCallbacks[j])(down);
+                                       }
+                               }
+                       }
+                       if((evt.type == SDL_MOUSEBUTTONDOWN || evt.type == SDL_MOUSEBUTTONUP) && mouseCallback != NULL) {
+                               if(evt.button.button == SDL_BUTTON_LEFT) {
+                                       (mouseCallback)(evt.button.x, evt.button.y, (evt.type == SDL_MOUSEBUTTONDOWN), true, false, false);
+                               }
+                               if(evt.button.button == SDL_BUTTON_MIDDLE) {
+                                       (mouseCallback)(evt.button.x, evt.button.y, (evt.type == SDL_MOUSEBUTTONDOWN), false, true, false);
+                               }
+                               if(evt.button.button == SDL_BUTTON_RIGHT) {
+                                       (mouseCallback)(evt.button.x, evt.button.y, (evt.type == SDL_MOUSEBUTTONDOWN), false, false, true);
+                               }
+                       }
+               }
+
+               return this->StartQuit;
+       }
+
+       // Changes the Input Mode used.
+       void ContextManager::InputMode(InMode in) {
+               inputmode = in;
+       }
+
+       // Register an abstract handler. Returns an int corresponding to the index for the mapping.
+       int ContextManager::RegisterInput(SDL_Keycode key, GameCallback func) {
+
+               // Apply input mappings.
+
+               ++inputRegistered;
+
+               // allocate space for current keys+1.
+               inputMappings = (SDL_Keycode*)realloc(inputMappings, sizeof(SDL_Keycode) * inputRegistered);
+               inputCallbacks = (GameCallback*)realloc(inputCallbacks, sizeof(GameCallback) * inputRegistered);
+               inputStates = (bool*)realloc(inputStates, sizeof(bool) * inputRegistered);
+
+               // Actually apply the new callback
+               inputMappings[inputRegistered-1] = key;
+               inputCallbacks[inputRegistered-1] = func;
+               inputStates[inputRegistered-1] = false;
+
+               // Return the index.
+               return inputRegistered-1;
+       }
+
+       void ContextManager::RegisterMouse(MouseCallback func) {
+               mouseCallback = func;
+       }
+
+       // Get input via abstract ID.
+       bool ContextManager::GetInput(int index) {
+               return inputStates[index];
+       }
+
+       // Remap abstract key.
+       void ContextManager::RemapKey(int index, SDL_Keycode to) {
+               // Check if something is already mapped to 'to'.
+               int reg = -1;
+               for(int i = 0; i < inputRegistered; i++) {
+                       if(inputMappings[i] == to) {
+                               reg = i;
+                       }
+               }
+               // Remap, swap if necessary.
+               if(reg > -1)
+                       inputMappings[reg] = inputMappings[index];
+               inputMappings[index] = to;
+       }
+
+       // Set Quit flag.
+       void ContextManager::SetQuit() {
+               this->StartQuit = true;
+       }
+
+       bool ContextManager::GetQuit() {
+               return this->StartQuit;
+       }
+
+       // Destroy context.
+
+       ContextManager::~ContextManager() {
+               delete audioMgr;
+               SDL_DestroyWindow(window);
+               SDL_Quit();
+       }
+
+       // Gets the audio manager.
+       AudioManager* ContextManager::Audio() {
+               return audioMgr;
+       }
+
+       // Gets the audio manager.
+       TextManager* ContextManager::Text() {
+               return txtMgr;
+       }
+
+       void ContextManager::StartSync() {
+               timeElapsed = SDL_GetTicks();
+       }
+
+       void ContextManager::EndSync() {
+               while (1) {
+                       double currentTime = SDL_GetTicks();
+                       if(currentTime - timeElapsed > 1000 / logicRate)
+                               return;
+                       SDL_Delay((1000 / logicRate) / 8);
+               }
+       }
+
+       void ContextManager::SetTitle(char* title) {
+               SDL_SetWindowTitle(window, title);
+       }
diff --git a/external/src/zero/TextManager.cpp b/external/src/zero/TextManager.cpp
new file mode 100644 (file)
index 0000000..4109597
--- /dev/null
@@ -0,0 +1,130 @@
+#include "Zero.hpp"
+
+TextManager::TextManager(ContextManager* ct) {
+       this->ctx = ct;
+
+       if(TTF_Init() == -1) {
+               printf("TTF Init failed. %s\n", TTF_GetError());
+               exit(-8);
+       }
+
+       LoadFont((char*)"default.ttf");
+
+       color.r = 255;
+       color.g = 255;
+       color.b = 255;
+       color.a = 255;
+
+}
+
+TextManager::~TextManager() {
+       while(fonts_loaded > 0) {
+               TTF_CloseFont(fonts[fonts_loaded-1]);
+               --fonts_loaded;
+       }
+
+       free(fonts);
+
+       TTF_Quit();
+}
+
+int TextManager::LoadFont(char* fname) {
+
+       ++fonts_loaded;
+
+       fonts = (TTF_Font**)realloc(fonts, sizeof(TTF_Font*) * fonts_loaded);
+
+       if ( !(fonts[fonts_loaded - 1] = TTF_OpenFont(fname, 20) ) ) {
+               printf("Font Open Failed. Load attempt: %s. Msg: %s\n", fname, TTF_GetError());
+       }
+
+       TTF_SetFontHinting(fonts[fonts_loaded - 1], TTF_HINTING_NONE);
+
+       return fonts_loaded - 1;
+}
+
+
+// Implement properly later with wrapped coordinates.
+void TextManager::Render(char* text) {
+       Render(text, 0, 0);
+}
+
+void TextManager::Render(char* text, int x, int y) {
+       if (text == NULL || fonts[current_font] == NULL)
+               return;
+
+       SDL_Surface *sf1 = NULL, *sf2 = NULL;
+       sf1 = TTF_RenderUTF8_Blended(fonts[current_font], text, color);
+       if(outline) {
+               SDL_Color n_color;
+               n_color.r = 255 - color.r;
+               n_color.g = 255 - color.g;
+               n_color.b = 255 - color.b;
+               n_color.a = color.a;
+               TTF_SetFontOutline(fonts[current_font], outline_px);
+               sf2 = TTF_RenderUTF8_Blended(fonts[current_font], text, n_color);
+               TTF_SetFontOutline(fonts[current_font], 0);
+       }
+
+       SDL_Texture *tmp1 = NULL, *tmp2 = NULL;
+
+       tmp1 = SDL_CreateTextureFromSurface(ctx->Renderer(), sf1);
+       if(outline)
+               tmp2 = SDL_CreateTextureFromSurface(ctx->Renderer(), sf2);
+
+       SDL_Rect src, dst, src2, dst2;
+       src.x = 0;
+       src.y = 0;
+       src.w = sf1->w;
+       src.h = sf1->h;
+
+       dst.x = x;
+       dst.y = y;
+       dst.w = src.w;
+       dst.h = src.h;
+
+       if(outline) {
+               src2.x = 0;
+               src2.y = 0;
+               src2.w = sf2->w;
+               src2.h = sf2->h;
+
+               dst2.x = x - (outline_px);
+               dst2.y = y - (outline_px);
+               dst2.w = src2.w;
+               dst2.h = src2.h;
+               SDL_FreeSurface(sf2);
+               ctx->OverlayBlit(tmp2, &src2, &dst2);
+               SDL_DestroyTexture(tmp2);
+       }
+
+       SDL_FreeSurface(sf1);
+       ctx->OverlayBlit(tmp1, &src, &dst);
+       SDL_DestroyTexture(tmp1);
+
+}
+
+int TextManager::TestLen(char* text) {
+       int w, h;
+       TTF_SizeText(fonts[current_font], text, &w, &h);
+
+       return w;
+}
+
+void TextManager::Outline(int pixels) {
+       if(pixels == 0) {
+               outline = false;
+       }
+       else {
+               outline = true;
+               outline_px = pixels;
+       }
+}
+
+void TextManager::SetColor(int r, int g, int b, int a)
+{
+       color.r = r;
+       color.g = g;
+       color.b = b;
+       color.a = a;
+}
diff --git a/external/src/zero/UDisplayable.cpp b/external/src/zero/UDisplayable.cpp
new file mode 100644 (file)
index 0000000..c85c925
--- /dev/null
@@ -0,0 +1,362 @@
+#include "Zero.hpp"
+
+       // Creates a new Displayable.
+       // The mode is already Normal if we do nothing, so this constructor doesn't have to change.
+       UDisplayable::UDisplayable(ContextManager* cx, char* fname) {
+
+               SDL_Surface* bitmap_tmp = IMG_Load(fname);
+
+               if(!bitmap_tmp) {
+                       printf("[UDisplayable::Ctor] File could not be loaded, this->Error set.\n");
+                       Error = true;
+               }
+               else {
+                       this->x = 0;
+                       this->y = 0;
+                       this->loc.x = 0;
+                       this->loc.y = 0;
+                       this->ctx = cx;
+                       this->frameWidth = bitmap_tmp->w;
+                       this->bmp_w = bitmap_tmp->w;
+                       this->bmp_h = bitmap_tmp->h;
+
+                       // We still allocate the two arrays, regardless.
+
+                       // These values are unused, but we'll default them so it will operate normally.
+                       hitbox = (int*)calloc(sizeof(int), 4);
+
+                       // By default, it will fill this with 0, 0, W, H.
+                       // This will behave identically to a displayable.
+                       hitbox[0] = 0;
+                       hitbox[1] = 0;
+                       hitbox[2] = bitmap_tmp->w;
+                       hitbox[3] = bitmap_tmp->h;
+
+                       this->loc.w = bitmap_tmp->w;
+                       this->loc.h = bitmap_tmp->w;
+
+                       frame = (int*)calloc(sizeof(int), 4);
+
+                       frame[0] = 0;
+                       frame[1] = 0;
+                       frame[2] = cx->GetWidth();
+                       frame[3] = cx->GetHeight();
+
+                       // Determine if we're on an accelerated context. If so, we create a texture out of the bitmap.
+                       // Then we store what we'll use to the void* bitmap, either Tex or Surf.
+
+                       if (cx->Accelerated()) {
+                               SDL_Texture* tex = SDL_CreateTextureFromSurface(ctx->Renderer(), bitmap_tmp);
+                               this->bitmap = (void*)tex;
+                               SDL_FreeSurface(bitmap_tmp);
+                       }
+                       else {
+                               this->bitmap = (void*)bitmap_tmp;
+                       }
+               }
+               #ifdef DEBUG_OVERKILL
+               printf("[UDisplayable~Ctor] accel:%d\n", cx->Accelerated());
+               #endif
+       }
+
+       // Sets the Displayable's mode.
+       UDisplayable::UDisplayable(ContextManager* cx, UDisplayableMode mode, char* fname) : UDisplayable(cx, fname) {
+               this->dispMode = mode;
+       }
+
+       // Load from memory.
+       UDisplayable::UDisplayable(ContextManager* cx, UDisplayableMode mode, void* memory, int mSize) {
+
+               SDL_RWops* rwo = SDL_RWFromMem(memory, mSize);
+               SDL_Surface* bitmap_tmp = IMG_LoadTyped_RW(rwo, 0, "PNG");
+               if(rwo == NULL || bitmap_tmp == NULL) {
+                       printf("Loading RWops failed. %s", SDL_GetError());
+                       while(1);
+                       //exit(-1);
+               }
+
+               this->x = 0;
+               this->y = 0;
+               this->loc.x = 0;
+               this->loc.y = 0;
+               this->ctx = cx;
+               this->frameWidth = bitmap_tmp->w;
+               this->bmp_w = bitmap_tmp->w;
+               this->bmp_h = bitmap_tmp->h;
+
+               // We still allocate the two arrays, regardless.
+
+               // These values are unused, but we'll default them so it will operate normally.
+               hitbox = (int*)calloc(sizeof(int), 4);
+
+               // By default, it will fill this with 0, 0, W, H.
+               // This will behave identically to a displayable.
+               hitbox[0] = 0;
+               hitbox[1] = 0;
+               hitbox[2] = bitmap_tmp->w;
+               hitbox[3] = bitmap_tmp->h;
+
+               this->loc.w = bitmap_tmp->w;
+               this->loc.h = bitmap_tmp->w;
+
+               frame = (int*)calloc(sizeof(int), 4);
+
+               frame[0] = 0;
+               frame[1] = 0;
+               frame[2] = cx->GetWidth();
+               frame[3] = cx->GetHeight();
+
+               // Determine if we're on an accelerated context. If so, we create a texture out of the bitmap.
+               // Then we store what we'll use to the void* bitmap, either Tex or Surf.
+
+               if (cx->Accelerated()) {
+                       SDL_Texture* tex = SDL_CreateTextureFromSurface(ctx->Renderer(), bitmap_tmp);
+                       this->bitmap = (void*)tex;
+                       SDL_FreeSurface(bitmap_tmp);
+               }
+               else {
+                       this->bitmap = (void*)bitmap_tmp;
+               }
+
+               this->dispMode = mode;
+       }
+
+       // Sets the position on screen.
+
+       void UDisplayable::SetXY(double x, double y) {
+               if (Error)
+                       return;
+               this->x = x;
+               this->y = y;
+
+               // Expand that logic above.
+
+               if(this->x < 0)
+                       this->x = 0;
+               if(this->y < 0)
+                       this->y = 0;
+
+               if(frameIndex == -1) {
+                       if(this->x > frame[2] - this->bmp_w)
+                               this->x = (double)(frame[2] - this->bmp_w);
+               }
+               else {
+                       if(this->x > frame[2] - this->frameWidth)
+                               this->x = (double)(frame[2] - this->frameWidth);
+               }
+
+               if(this->y > frame[3] - this->bmp_h)
+                       this->y = (double)(frame[3] - this->bmp_h);
+
+               this->loc.x = (int)this->x;
+               this->loc.y = (int)this->y;
+
+               #ifdef DEBUG_OVERKILL
+               printf("[UDisplayable::SetXY] x:%d y:%d w:%d h:%d\n", frame[0], frame[1], frame[2], frame[3]);
+               #endif
+       }
+
+       // Modifies the position on screen. Meant to avoid embedded retrievals.
+
+       void UDisplayable::ModXY(double x, double y) {
+               if (Error)
+                       return;
+
+               this->x += x;
+               this->y += y;
+
+               // Expand that logic above.
+
+               if(this->x < 0)
+                       this->x = 0;
+               if(this->y < 0)
+                       this->y = 0;
+
+               if(frameIndex == -1) {
+                       if(this->x > frame[2] - this->bmp_w)
+                               this->x = (double)(frame[2] - this->bmp_w);
+               }
+               else {
+                       if(this->x > frame[2] - this->frameWidth)
+                               this->x = (double)(frame[2] - this->frameWidth);
+               }
+
+               if(this->y > frame[3] - this->bmp_h)
+                       this->y = (double)(frame[3] - this->bmp_h);
+
+               this->loc.x = (int)this->x;
+               this->loc.y = (int)this->y;
+
+               #ifdef DEBUG_OVERKILL
+               printf("[UDisplayable::SetXY] x:%d y:%d w:%d h:%d\n", frame[0], frame[1], frame[2], frame[3]);
+               #endif
+       }
+
+       // Get X coord.
+
+       double UDisplayable::GetX() {
+               if (Error)
+                       return 0;
+
+               return this->x;
+       }
+
+       // Get Y coord.
+
+       double UDisplayable::GetY() {
+               if (Error)
+                       return 0;
+               return this->y;
+       }
+
+       // Get aligned X coord.
+
+       int UDisplayable::GetXI() {
+               if (Error)
+                       return 0;
+               return this->loc.x;
+       }
+
+       // Get aligned Y coord.
+
+       int UDisplayable::GetYI() {
+               if (Error)
+                       return 0;
+               return this->loc.y;
+       }
+
+       // Blit to an associated context.
+
+       void UDisplayable::Blit() {
+               if (Error)
+                       return;
+
+               // Copy loc and alter position.
+               SDL_Rect loc_adj;
+               loc_adj.x = loc.x + frame[0];
+               loc_adj.y = loc.y + frame[1];
+               loc_adj.w = frameWidth;
+               loc_adj.h = bmp_h;
+
+               #ifdef DEBUG_OVERKILL
+               printf("[UDisplayable::Blit]\n");
+               #endif
+
+               if (frameIndex == -1) {
+                       ctx->Blit(bitmap, NULL, &loc_adj);
+                       return;
+               }
+
+               SDL_Rect frameClip;
+
+               frameClip.x = frameWidth * frameIndex;
+               frameClip.y = 0;
+               frameClip.w = frameWidth;
+               frameClip.h = bmp_h;
+
+               ctx->Blit(bitmap, &frameClip, &loc_adj);
+       }
+
+       // Get SDL_Rect for collision calculation. In a base Displayable, it returns the image width.
+       // In a derived class, it may return only a hitbox.
+
+       int* UDisplayable::GetHitbox() {
+               if (Error)
+                       return NULL;
+               int* rect = (int*)calloc(sizeof(int), 4);
+
+               rect[0] = hitbox[0] + (int)this->x;
+               rect[1] = hitbox[1] + (int)this->y;
+               rect[2] = hitbox[2];
+               rect[3] = hitbox[3];
+
+               return rect;
+       }
+
+       // Destroy bitmap.
+
+       UDisplayable::~UDisplayable() {
+               if (Error)
+                       return;
+               if(ctx->Accelerated())
+                       SDL_DestroyTexture((SDL_Texture*)bitmap);
+               else
+                       SDL_FreeSurface((SDL_Surface*)bitmap);
+               free(hitbox);
+               free(frame);
+       }
+
+       void UDisplayable::SetHitbox(int x, int y, int w, int h) {
+               if (Error)
+                       return;
+               if(dispMode == Normal || dispMode == Docked || dispMode == Anim || dispMode == AnimDocked)
+                       return;
+
+               hitbox[0] = x;
+               hitbox[1] = y;
+               hitbox[2] = w;
+               hitbox[3] = h;
+       }
+
+       void UDisplayable::SetDock(int x, int y, int w, int h) {
+               if (Error)
+                       return;
+               if(dispMode == Normal || dispMode == Hitbox || dispMode == Anim || dispMode == AnimHitbox)
+                       return;
+               frame[0] = x;
+               frame[1] = y;
+               frame[2] = w;
+               frame[3] = h;
+       }
+
+       void UDisplayable::NextFrame() {
+               if (Error)
+                       return;
+               if (dispMode == Normal || dispMode == Hitbox || dispMode == Docked || dispMode == HitboxDocked)
+                       return;
+
+               ++frameIndex;
+
+               if(frameWidth * frameIndex >= bmp_w)
+                       frameIndex = 0;
+       }
+
+       void UDisplayable::NextFrame(int f) {
+               if (Error)
+                       return;
+               if (dispMode == Normal || dispMode == Hitbox || dispMode == Docked || dispMode == HitboxDocked)
+                       return;
+               frameIndex += f;
+
+               if(frameWidth * frameIndex >= bmp_w)
+                       frameIndex = 0;
+       }
+
+       void UDisplayable::ResetFrame() {
+               if (Error)
+                       return;
+               if (dispMode == Normal || dispMode == Hitbox || dispMode == Docked || dispMode == HitboxDocked)
+                       return;
+               frameIndex = 0;
+       }
+
+       void UDisplayable::SetFrame(int f) {
+               if (Error)
+                       return;
+               if (dispMode == Normal || dispMode == Hitbox || dispMode == Docked || dispMode == HitboxDocked)
+                       return;
+
+               frameIndex = f;
+       }
+
+       void UDisplayable::SetFrameWidth(int frameW) {
+               if (Error)
+                       return;
+               if (dispMode == Normal || dispMode == Hitbox || dispMode == Docked || dispMode == HitboxDocked)
+                       return;
+               this->frameWidth = frameW;
+
+               #ifdef DEBUG_OVERKILL
+               printf("[UDisplayable::SetFrameWidth] fW:%d\n", frameW);
+               #endif
+       }
diff --git a/mk b/mk
new file mode 100755 (executable)
index 0000000..a78c48a
--- /dev/null
+++ b/mk
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+# This is all auxillary functions to simplify the build script.
+# I hate makefiles, and cmake so shell scripts work.
+
+CXX="g++"
+CXXFLAGS="$CXXFLAGS -fPIC -std=gnu++11 -Wall -Werror -Wno-error=pointer-arith"
+LD="g++"
+LDFLAGS="-fPIC -L$LIB $LDFLAGS -lSDL2 -lSDL2_image -lSDL2_mixer -lSDL2_ttf"
+AR="ar rcs"
+GEN="/bin/bash ./gen.sh"
+
+CXX_CMD="$CXX $CXXFLAGS"
+LD_CMD="$LD $LDFLAGS"
+CA_CMD="$CXX $CXXFLAGS $LDFLAGS"
+
+FILES=$2
+
+function mkcc_ {
+       echo "CXX               $2"
+       $CXX_CMD $INCLUDE -c $1 -o $2
+}
+
+function mkld_ {
+       echo "LD                $2"
+       $LD_CMD $1 -o $2
+}
+
+function mkgen_ {
+       echo "GEN               $1"
+       bash -c "cd ../$1 && $GEN"
+}
+
+function mkcc {
+       mkcc_ $SRC/$1/$2.cpp $2.cpp.o
+}
+
+function mkmcc {
+       for f in `ls $SRC/$1/*.cpp`; do
+               mkcc_ $f $(basename $f).o
+       done
+}
+
+function mkld {
+       echo "LD                $1"
+       $LD_CMD ./*.o $LIB/*.a -o $BIN/$1
+}
+
+function mkar {
+       echo "AR                $1"
+       $AR $LIB/$1.a ./*.o
+}
+
+function newtd {
+       mkdir td
+       cd td
+}
+
+function deltd {
+       cd ..
+       rm -rf td
+}
diff --git a/vndc/include/Data.hpp b/vndc/include/Data.hpp
new file mode 100644 (file)
index 0000000..75deede
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef DATAGUARD_HPP
+#define DATAGUARD_HPP
+
+#include <map>
+#include <string>
+
+class DataContainer {
+       public:
+               ContextManager* ctx;
+               bool if_fail = false;
+               bool wait_input = false;
+               char current_scr[400], current_music[400], current_bg[400];
+               int screen_w = 800;
+               int screen_h = 600;
+               int physical_w = 800;
+               int physical_h = 600;
+               int render_x1 = screen_w / 15;
+               int render_y1 = screen_h / 15;
+               int render_x2 = screen_w / 15 * 14;
+               int render_y2 = screen_h / 15 * 13;
+               int text_x = render_x1;
+               int text_y = render_y1;
+               std::map<std::string, int> *g_flags = NULL;
+               std::map<std::string, int> *s_flags = NULL;
+               bool jumped = false;
+               int* choice_coords = NULL;
+               int choices = 0;
+               FILE* accessScriptHandle = NULL;
+               char** main_scr; // Default value.
+               bool vndc_enabled = true;
+               bool is_spoken_line = false;
+               bool debug_mode = false;
+               bool debug_to_shell = false;
+               bool verbose = false;
+               int currentLine = 0;
+               bool skip_key_on = false;
+               char* window_name;
+};
+
+DataContainer* GetData();
+void CreateDataContainer();
+void DumpSave(char* fname);
+void DumpSystemSave(char* fname);
+
+#endif
diff --git a/vndc/include/Funcs.hpp b/vndc/include/Funcs.hpp
new file mode 100644 (file)
index 0000000..21b5452
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef FUNCS_HPP
+#define FUNCS_HPP
+
+#include <cstdio>
+#include <cstdlib>
+#include <ctime>
+#include <cstring>
+
+#include "Data.hpp"
+
+void Parse();                          // This reads commands from files.
+void ParseShell();                     // This reads commands from the shell.
+void ParseCmd(char* line);     // This does the heavy lifting.
+void Loop();
+void Wait();
+void Setup();
+
+void InputAdvance(int x, int y, bool down, bool left, bool middle, bool right);
+void QuitKey(bool down);
+void NopKey(bool down);
+
+void op_bgload(char* file, int* fadetime);
+void op_cleartext();
+void op_delay(int* frames);
+void op_fi();
+void op_gsetvar(char* var, int *modifier, int *value);
+void op_if(char* var, int* op, int* val);
+void op_music(char* file);
+void op_random(char* var, int* low, int* high);
+void op_setimg(char* file, int* x, int* y);
+void op_setvar(char* var, int *modifier, int *value);
+void op_sound(char* file, int* times);
+void op_text(char* string);
+void op_jump(char* file, int* lineTo, bool isSave);
+void op_goto(char* label);
+void op_choice(char* choices);
+
+#endif
diff --git a/vndc/src/Data.cpp b/vndc/src/Data.cpp
new file mode 100644 (file)
index 0000000..ca78a49
--- /dev/null
@@ -0,0 +1,59 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+DataContainer* data = NULL;
+
+const char* loadup = "script/main.scr";
+
+void CreateDataContainer() {
+       data = new DataContainer();
+       GetData()->main_scr = (char**)calloc(sizeof(char*), 1);
+       GetData()->main_scr[0] = (char*)calloc(sizeof(char), 400);
+       strncpy(GetData()->main_scr[0], loadup, 400);
+}
+
+DataContainer* GetData() {
+       return &data[0];
+}
+
+void DumpSave(char* fname) {
+       // Dump variables.
+       // Dump script file.
+
+       // A save actually ends up as a mini-script.
+       // So, to load a save you load this as the
+       // main script
+       // For example:
+       // setvar data1 = 6
+       // setvar data2 = 9
+       // music mus
+       // bgload bg
+       // jump script.scr 60
+       // The call command runs a scr, and returns here.
+
+       FILE* save_to = fopen(fname, "w");
+
+       std::map<std::string, int> data_vals = GetData()->s_flags[0];
+
+       if(!data_vals.empty()) {
+               std::map<std::string, int>::iterator item = data_vals.begin();
+               while(item != data_vals.end()) {
+                       fprintf(save_to, "setvar %s = %d\n", item->first.c_str(), item->second);
+
+                       ++item;
+               }
+       }
+
+       fprintf(save_to, "music %s\n", &(GetData()->current_music[6]));
+       fprintf(save_to, "bgload %s\n", &(GetData()->current_bg[11]));
+       fprintf(save_to, "jump %s %d\n", &(GetData()->current_scr[7]), GetData()->currentLine - 1); // The text never completely displayed
+                                                                                                                                                                                               // So restore back one to replay
+
+       fclose(save_to);
+}
+void DumpSystemSave(char* fname) {
+       // A system save is simply a script
+       // with only gsetvar.
+       // It is automatically run if it exists
+}
diff --git a/vndc/src/Loop.cpp b/vndc/src/Loop.cpp
new file mode 100644 (file)
index 0000000..7be1d01
--- /dev/null
@@ -0,0 +1,66 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+void Wait() {
+       // If wait wasn't specified, don't halt.
+       // Don't even bother with extensions off.
+       // If we're currently in a quote, leave it alone.
+       // If the line is spoken, then halt previous spoken lines.
+       // If the skip key is held, just gogogo
+
+       bool stop_voice = GetData()->wait_input && GetData()->vndc_enabled;
+
+       while((GetData()->wait_input && !GetData()->ctx->GetQuit())) {
+               GetData()->ctx->Input();
+
+               GetData()->ctx->Flush();
+
+               if(GetData()->debug_to_shell)
+                       ParseShell();
+
+               if(GetData()->ctx->GetInput(1)) break;
+       }
+
+       if(stop_voice)
+               op_sound((char*)"~", NULL);
+
+}
+
+void Loop() {
+       if(GetData()->ctx->GetQuit()) return;
+               Parse();
+
+               // We don't clear. This system uses dirty blits. ;P
+               GetData()->ctx->Flush();
+
+       GetData()->ctx->StartSync();
+
+               Wait();
+
+       GetData()->ctx->EndSync();
+}
+
+void Setup() {
+       // Init window
+       GetData()->ctx->InitWindowLogical(GetData()->physical_w, GetData()->physical_h, GetData()->screen_w, GetData()->screen_h, false, true);
+
+       GetData()->window_name = (char*)calloc(sizeof(char), 400);
+       sprintf(GetData()->window_name, "%s", "VNDC Interpreter ");
+       GetData()->ctx->SetTitle(GetData()->window_name);
+
+       GetData()->ctx->InputMode(Burst);
+
+       // Input
+       GetData()->ctx->RegisterMouse(&InputAdvance);
+       GetData()->ctx->RegisterInput(SDLK_ESCAPE, &QuitKey);
+       GetData()->ctx->RegisterInput(SDLK_LCTRL, &NopKey);
+
+       GetData()->s_flags = new std::map<std::string, int>();
+       GetData()->g_flags = new std::map<std::string, int>();
+
+       GetData()->ctx->Text()->Outline(2);
+       GetData()->ctx->Text()->SetColor(255,255,255,255);
+
+       op_cleartext();
+}
diff --git a/vndc/src/Parse.cpp b/vndc/src/Parse.cpp
new file mode 100644 (file)
index 0000000..6b6d7d9
--- /dev/null
@@ -0,0 +1,268 @@
+#include "Zero.hpp"
+
+#include "Data.hpp"
+
+#include "Funcs.hpp"
+
+void ParseCmd(char* line) {
+
+       char *passthru_line = (char*)calloc(sizeof(char), 400);
+
+       char** tokens = NULL;
+
+       // Remove all '\n' from this string
+       for(int i=0; i < 400; i++) {
+               if (line[i] == '\n')
+                       line[i] = '\0';
+       }
+
+       strncpy(passthru_line, line, sizeof(char)*400);
+
+       if(GetData()->verbose) printf("[scr] %s\n", line);
+
+       int num = 1;
+       tokens = (char**)realloc(NULL, sizeof(char*) * (1));
+       tokens[num-1] = strtok(line, " ");
+
+       do {
+               #ifdef DEBUG_OVERKILL
+               printf("Loop: num = %d;\n", num);
+               #endif
+               ++num;
+               tokens = (char**)realloc(tokens, sizeof(char*) * (num));
+               tokens[num-1] = strtok(NULL, " ");
+       } while(tokens[num-1] != NULL);
+
+       --num;
+
+       //printf("Made it out of the loop.\n");
+       //for (int i = 0; i < num; i++) {
+               //printf("[param] %d = '%s'\n", i, tokens[i]);
+       //}
+
+       int value_1, value_2;
+
+       if(!strcmp(tokens[0], "bgload")) {
+               //printf("[OP::bgload] exec (params:%d)", num-1);
+               if (num > 2) {
+                       sscanf(tokens[2], "%d", &value_1);
+                       op_bgload(tokens[1], &value_1);
+               }
+               else
+                       op_bgload(tokens[1], NULL);
+       }
+       else if(!strcmp(tokens[0], "setimg")) {
+               sscanf(tokens[2], "%d", &value_1);
+               sscanf(tokens[3], "%d", &value_2);
+               op_setimg(tokens[1], &value_1, &value_2);
+       }
+       else if(!strcmp(tokens[0], "sound")) {
+               // Another ridiculous thing. Second parameter if not
+               // specified is implicity one
+               if(num > 2) {
+                       sscanf(tokens[2], "%d", &value_1);
+                       op_sound(tokens[1], &value_1);
+               }
+               else
+                       op_sound(tokens[1], NULL);
+       }
+       else if(!strcmp(tokens[0], "music"))
+               op_music(tokens[1]);
+       else if(!strcmp(tokens[0], "text")) {
+               // Because of *reasons* (lack of quotes) we use the copy of line,
+               // passthru_line and adjust the pointer to use that.
+               // strtok destroys the structure
+               // And there's the possibility of a zero-length string as well.
+               //printf("[op_text] Reconstructed string = '%s'\n", &passthru_line[5]);
+               op_text(&passthru_line[5]);
+       }
+       else if(!strcmp(tokens[0], "choice")) {
+               op_choice(&passthru_line[7]);
+       }
+       else if(!strcmp(tokens[0], "setvar")) {
+               if(num > 3) {
+                       if(!strcmp(tokens[2], "="))
+                               value_1 = 0;
+                       else if(!strcmp(tokens[2], "+"))
+                               value_1 = 1;
+                       else if(!strcmp(tokens[2], "-"))
+                               value_1 = -1;
+                       else if(!strcmp(tokens[2], "~")) // Apparently resets. UGH NOT DOC'D
+                               value_1 = -2;
+
+
+                       sscanf(tokens[3], "%d", &value_2);
+                       op_setvar(tokens[1], &value_1, &value_2);
+               }
+               else {
+                       value_1 = -2;
+                       op_setvar(tokens[1], &value_1, NULL);
+               }
+       }
+       else if(!strcmp(tokens[0], "gsetvar")) {
+               if(!strcmp(tokens[2], "="))
+                       value_1 = 0;
+               else if(!strcmp(tokens[2], "+"))
+                       value_1 = 1;
+               else if(!strcmp(tokens[2], "-"))
+                       value_1 = -1;
+
+               sscanf(tokens[3], "%d", &value_2);
+               op_gsetvar(tokens[1], &value_1, &value_2);
+       }
+       else if(!strcmp(tokens[0], "if")) {
+               if(!strcmp(tokens[2], "<="))
+                       value_1 = 0;
+               else if(!strcmp(tokens[2], "<"))
+                       value_1 = 1;
+               else if(!strcmp(tokens[2], "=="))
+                       value_1 = 2;
+               else if(!strcmp(tokens[2], "!="))
+                       value_1 = 3;
+               else if(!strcmp(tokens[2], ">"))
+                       value_1 = 4;
+               else if(!strcmp(tokens[2], ">="))
+                       value_1 = 5;
+
+               sscanf(tokens[3], "%d", &value_2);
+               op_if(tokens[1], &value_1, &value_2);
+       }
+       else if(!strcmp(tokens[0], "fi"))
+               op_fi();
+       else if(!strcmp(tokens[0], "jump")) {
+               if(num > 2) {
+                       sscanf(tokens[2], "%d", &value_1);
+                       op_jump(tokens[1], &value_1, false);
+               }
+               else
+                       op_jump(tokens[1], NULL, false);
+       }
+       else if(!strcmp(tokens[0], "delay")) {
+               sscanf(tokens[1], "%d", &value_1);
+               op_delay(&value_1);
+       }
+       else if(!strcmp(tokens[0], "random")) {
+               sscanf(tokens[2], "%d", &value_1);
+               sscanf(tokens[3], "%d", &value_2);
+               op_random(tokens[1], &value_1, &value_2);
+       }
+       else if(!strcmp(tokens[0], "goto"))
+               op_goto(tokens[1]);
+       else if(!strcmp(tokens[0], "label")) {}
+               // Nuthin.
+       else if(!strcmp(tokens[0], "cleartext"))
+               op_cleartext();
+
+       free(tokens);
+       free(passthru_line);
+}
+
+void ParseShell() {
+       bool DebugContinue = true;
+       char buffer[400];
+       while(DebugContinue) {
+               memset(buffer, 0, sizeof(char)*400);
+
+               printf("[scr command] $ ");
+               fgets(buffer, 400, stdin);
+
+               // Remove all '\n' from this string
+               for(int i=0; i < 400; i++) {
+                       if (buffer[i] == '\n')
+                               buffer[i] = '\0';
+               }
+
+               if(!strcmp(buffer, "help") || strlen(buffer) < 1) {
+                       printf("%s\n", "Commands available:");
+                       printf("\t%s\t\t\t%s\n", "(debug) stop", "Stops debug mode");
+                       printf("\t%s\t\t\t%s\n", "(debug) quit", "Quits game");
+                       printf("\t%s\t\t%s\n", "(debug) save [file]", "Saves immediately to file");
+                       printf("\t%s\t%s\n", "setvar [var] [mod] [val]", "Set save flag");
+                       printf("\t%s\t%s\n", "gsetvar [var] [mod] [val]", "Set system flag");
+                       printf("\t%s\t\t\t%s\n", "text [text] ...", "Display text");
+                       printf("\t%s\t\t%s\n", "sound [file] (num)", "Play sound num times");
+                       printf("\t%s\t\t\t%s\n", "music [file]", "Play music");
+                       printf("\t%s\t\t%s\n", "setimg [file] [x] [y]", "Display image at x,y");
+                       printf("\t%s\t%s\n", "random [var] [low] [high]", "Store random number in var");
+                       printf("\t%s\t\t%s\n", "jump [file.scr] {N}", "Switch to file.src (goto line N)");
+                       printf("\t%s\t\t\t%s\n", "goto [label]", "Goto label in current file");
+                       printf("\t%s\t\t%s\n", "if [var] [op] [val]", "Test condition, and execute till\n\t\t\t\t\tfi if true");
+                       printf("\t%s\t\t\t\t%s\n", "fi", "Stop computing if");
+                       printf("\t%s\t\t\t%s\n", "delay [frames]", "Delay frames (at 60fps)");
+                       printf("\t%s\t\t\t%s\n", "cleartext", "Clear text from screen");
+                       printf("\t%s\t%s\n", "choice [ch|ch|...] {<var}", "Get input for choice. Store to selected\n\t\t\t\t\t(or var if extensions are on)");
+                       printf("\t%s\t%s\n", "bgload [file] [fadeframes]", "Load background");
+               }
+               else if (!strcmp(buffer, "quit")) {
+                       printf("[debug] Setting quit status & stopping debug.\n");
+                       GetData()->ctx->SetQuit();
+                       DebugContinue = false;
+               }
+               else if (!strcmp(buffer, "stop")) {
+                       printf("[debug] Exiting debug shell and resuming.\n");
+                       DebugContinue = false;
+                       GetData()->wait_input = true;
+               }
+               else if (!strncmp(buffer, "save", 4)) {
+                       char* savefile = &buffer[5];
+                       printf("[debug] Saving to file '%s' NOW.\n", savefile);
+                       DumpSave(savefile);
+               }
+               else {
+                       ParseCmd(buffer);
+                       GetData()->ctx->Flush();
+                       GetData()->wait_input = false;
+               }
+       }
+       GetData()->debug_to_shell = false;
+}
+
+void Parse() {
+       if(GetData()->ctx->GetQuit()) return;
+
+       ++(GetData()->currentLine);
+
+       if (!GetData()->accessScriptHandle) {
+               fprintf(stderr, "Could not open script data\n");
+               exit(-8);
+       }
+
+       char *line = (char*)calloc(sizeof(char), 400);
+
+       fgets(line, 400, GetData()->accessScriptHandle);
+
+       ParseCmd(line);
+
+       free(line);
+
+       if(feof(GetData()->accessScriptHandle)) {
+               op_jump(GetData()->main_scr[0], NULL, true);
+       }
+
+       return;
+}
+
+void InputAdvance(int x, int y, bool down, bool left, bool middle, bool right) {
+       if(GetData()->choices > 0) {
+               // Choose an option.
+               for(int i=0; i<GetData()->choices; i++) {
+                       if(!down && y > GetData()->choice_coords[i*2] && y < GetData()->choice_coords[i*2+1])
+                       {
+                               GetData()->choices = -(i+1); // Negative indicates complete. This is just
+                                                            // for storage savings.
+                       }
+               }
+       }
+       else if(left && !down) {
+               GetData()->wait_input = false;
+       }
+}
+
+void QuitKey(bool down) {
+       // Flush data to save.scr
+       DumpSave((char*)"save.scr");
+
+       GetData()->ctx->SetQuit();
+}
+
+void NopKey(bool down) {}
diff --git a/vndc/src/VNDC.cpp b/vndc/src/VNDC.cpp
new file mode 100644 (file)
index 0000000..f3301a2
--- /dev/null
@@ -0,0 +1,115 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+#include <unistd.h>
+#include <signal.h>
+
+
+
+void DebugTrap(int sig) {
+       GetData()->debug_to_shell = true;
+}
+
+int main(int argc, char** argv) {
+       printf(" ___________________________________________________________ \n");
+       printf("| VNDC v0.0.1 - VNDC is Not a Direct Clone (of VNDS ;P)     |\n");
+       printf("| Interprets VNDS scripts with a few goodies and extensions |\n");
+       printf("| (C) Jonathan Feldman 2014 - Under the MIT license         |\n");
+       printf("|___________________________________________________________|\n\n");
+
+       char* chdir_to_dir = NULL;
+       char* main_script_override = NULL;
+       char* save_file = NULL;
+       bool vndc_extensions = true;
+       int width = 0, height = 0;
+       bool debug_enable = false;
+       bool enable_v = false;
+       char c;
+
+       while((c = getopt(argc, argv, "bvx:y:d:m:s:ch")) != -1) {
+               switch(c) {
+                       case 'v':
+                               printf("[info] Script commands will be echoed.\n");
+                               enable_v = true;
+                               break;
+                       case 'b':
+                               printf("[debug] Debug Mode enabled.\n");
+                               debug_enable = true;
+                               break;
+                       case 'd':
+                               printf("[info] Directory specified: %s\n", optarg);
+                               chdir_to_dir = optarg;
+                               break;
+                       case 'x':
+                               sscanf(optarg, "%d", &width);
+                               break;
+                       case 'y':
+                               sscanf(optarg, "%d", &height);
+                               chdir_to_dir = optarg;
+                               break;
+                       case 'm':
+                               printf("[debug] Main script overriden as: '%s'\n", optarg);
+                               main_script_override = optarg;
+                               break;
+                       case 's':
+                               printf("[info] Load save: '%s'\n", optarg);
+                               save_file = optarg;
+                               break;
+                       case 'c':
+                               printf("[debug] Compliant mode: all VNDC extensions off\n");
+                               vndc_extensions = false;
+                               break;
+                       case 'h':
+                               printf("-x size -y size\t\tSet display window to wxh\n");
+                               printf("-d dir\t\tChange to directory/Run game in directory\n");
+                               printf("-b\t\tDebug Mode. Hit Ctrl+C on console for shell\n");
+                               printf("-v\t\tVerbose. Echo script commands back as they execute\n");
+                               printf("-m .scr\t\tLoad .scr as main script\n");
+                               printf("-s .scr\t\tLoad save .scr\n");
+                               printf("-c\t\tCompliant mode; don't use VNDC extensions\n");
+                               printf("-h\t\tPrint this help message\n");
+                               return 0;
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       CreateDataContainer();
+
+       GetData()->ctx = new ContextManager();
+
+       if(chdir_to_dir)
+               chdir(chdir_to_dir);
+       if(main_script_override != NULL) {
+               printf("[debug] Note that in this mode, l_flags is not set.\n[debug] Expect bugs/gameover, this is normal.\n");
+               memset(GetData()->main_scr[0], 0, 399);
+               strncpy(GetData()->main_scr[0], main_script_override, 399);
+       }
+       GetData()->vndc_enabled = vndc_extensions;
+       GetData()->verbose = enable_v;
+       if(debug_enable) {
+               signal(SIGINT, DebugTrap);
+               GetData()->debug_mode = true;
+       }
+
+       if(width > 0 && height > 0) {
+               GetData()->physical_w = width;
+               GetData()->physical_h = height;
+       }
+
+       Setup();
+
+       if(!save_file)
+               op_jump(GetData()->main_scr[0], NULL, true);
+       else
+               op_jump(save_file, NULL, true);
+
+       while(!(GetData()->ctx->GetQuit())) {
+               Loop();
+       }
+
+       delete GetData()->ctx;
+       delete GetData();
+}
diff --git a/vndc/src/op_bgload.cpp b/vndc/src/op_bgload.cpp
new file mode 100644 (file)
index 0000000..a6ad33a
--- /dev/null
@@ -0,0 +1,45 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+/*
+ * Implements bgload vnds function.
+ * bgload file [fadetime] (default 16)
+ */
+
+void op_bgload(char* file, int* fadetime) {
+       if (GetData()->if_fail || GetData()->ctx->GetQuit())
+               return;
+
+       // Fadeout not implemented yet.
+
+       memset(GetData()->current_bg, 0, 400);
+
+       snprintf(GetData()->current_bg, 400, "background/%s", file);
+
+       //printf("Attempt to load file %s as BG\n", path);
+
+       // Load displayable.
+       SDL_Surface* sfc = IMG_Load(GetData()->current_bg);
+
+       uint8_t transp_incr = 16;
+       if(fadetime != NULL)
+               transp_incr = 255 / *fadetime;
+
+       // Transition effect.
+
+       SDL_Texture* tx = NULL;
+       tx = SDL_CreateTextureFromSurface(GetData()->ctx->Renderer(), sfc);
+       SDL_SetTextureBlendMode(tx, SDL_BLENDMODE_BLEND);
+
+       SDL_FreeSurface(sfc);
+
+       int delay = 1;
+       for(int tr = 0; tr < 255; tr += transp_incr) {
+               SDL_SetTextureAlphaMod(tx, tr);
+               GetData()->ctx->Blit(tx, NULL, NULL);
+               op_delay(&delay);
+       }
+
+       SDL_DestroyTexture(tx);
+}
diff --git a/vndc/src/op_choice.cpp b/vndc/src/op_choice.cpp
new file mode 100644 (file)
index 0000000..2c5e01e
--- /dev/null
@@ -0,0 +1,100 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+/*
+ * Implements choice vnds function.
+ * choice choicest1|choicest2|... [>var]
+ * [>var] is an extension of this dialect
+ * which stores the result into a specific variable
+ * The default will still be 'selected' if not specified
+ */
+
+void op_choice(char* line) {
+       if (GetData()->if_fail)
+               return;
+       // Strtok by the pipe '|' character
+
+       //printf("%s\n", line);
+
+       int num = 1;
+       char** tokens = (char**)realloc(NULL, sizeof(char*) * (1));
+       tokens[num-1] = strtok(line, "|");
+
+       do {
+               //printf("Loop: num = %d;\n", num);
+               ++num;
+               tokens = (char**)realloc(tokens, sizeof(char*) * (num));
+               tokens[num-1] = strtok(NULL, "|");
+       } while(tokens[num-1] != NULL);
+
+       --num;
+
+       /*for(int i=0; i<num; i++) {
+               printf("%s\n", tokens[i]);
+       }*/
+
+       // Scan thru the last token to see if a '>' is there.
+
+       char varname[400];
+       memset(varname, 0, 400);
+       int defaultname = 0;
+
+       if(GetData()->vndc_enabled) { // This is an extension.
+               for( int i = strlen(tokens[num-1]); i >= 0; i-- ) {
+                       if(tokens[num-1][i] == '>') {
+                               // Yes there is.
+                               defaultname = i + 1;
+                               tokens[num-1][i] = '\0';
+                               break;
+                       }
+               }
+       }
+
+       if(defaultname > 0) {
+               strncpy(varname, &tokens[num-1][defaultname], 400);
+       }
+       else {
+               strncpy(varname, "selected", 400);
+       }
+
+       // For each choice, we need to print text and make a click area. This will use the text function.
+       int *choices = (int*)calloc(sizeof(int), num * 2);
+
+       for(int i=0; i < num*2; i+=2) {
+               choices[i] = GetData()->text_y;
+               char* outarr = (char*)calloc(sizeof(char*), strlen(tokens[i/2])+3);
+               outarr[0] = '0' + (i/2);
+               outarr[1] = '.';
+               outarr[2] = ' ';
+               strncpy(&outarr[3], tokens[i/2], strlen(tokens[i/2]));
+               op_text(outarr);
+               free(outarr);
+               choices[i+1] = GetData()->text_y;
+       }
+
+       GetData()->choice_coords = choices;
+       GetData()->choices = num;
+
+       while(GetData()->choices > 0) {
+               if(GetData()->ctx->GetQuit()) goto killed;
+
+               GetData()->ctx->Flush();
+
+               GetData()->ctx->StartSync();
+                       GetData()->ctx->Input();
+               GetData()->ctx->EndSync();
+       }
+
+       // Get the chosen option and load it to a variable (abs of course)
+
+       GetData()->s_flags[0][std::string(varname)] = -(GetData()->choices);
+
+       // Clear after choices. Period.
+       op_cleartext();
+
+killed:
+
+       // Also reset the 'need to click' since we just did.
+       GetData()->wait_input = false;
+}
diff --git a/vndc/src/op_cleartext.cpp b/vndc/src/op_cleartext.cpp
new file mode 100644 (file)
index 0000000..d05f9cd
--- /dev/null
@@ -0,0 +1,52 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+void ct_transwindow() {
+
+       int width_dr = (GetData()->render_x2 - GetData()->render_x1 + 20);
+       int height_dr = (GetData()->render_y2 - GetData()->render_y1 + 30 + 20);
+
+       SDL_Surface* sfc = SDL_CreateRGBSurface(0, width_dr, height_dr, 32, 0, 0, 0, 0);
+       SDL_FillRect(sfc, NULL, SDL_MapRGBA(sfc->format, 0, 0, 0, 128));
+
+       SDL_Rect src;
+       src.x = 0;
+       src.y = 0;
+       src.w = sfc->w;
+       src.h = sfc->h;
+
+       SDL_Texture* dim = SDL_CreateTextureFromSurface(GetData()->ctx->Renderer(), sfc);
+       SDL_SetTextureBlendMode(dim, SDL_BLENDMODE_BLEND);
+       SDL_SetTextureAlphaMod(dim, 128);
+
+       SDL_FreeSurface(sfc);
+
+       SDL_Rect dst;
+       dst.x = GetData()->render_x1 - 10;
+       dst.y = GetData()->render_y1 - 10;
+       dst.w = src.w;
+       dst.h = src.h;
+
+       GetData()->ctx->OverlayBlit(dim, &src, &dst);
+
+       SDL_DestroyTexture(dim);
+}
+
+/*
+ * Implements cleartext vnds function.
+ * cleartext mod
+ * However, we ignore mod for now.
+ */
+
+void op_cleartext() {
+       if (GetData()->if_fail || GetData()->ctx->GetQuit())
+               return;
+
+       GetData()->text_x = GetData()->render_x1;
+       GetData()->text_y = GetData()->render_y1;
+       GetData()->ctx->ClearOverlay();
+
+       // Dim transparent overlay
+       ct_transwindow();
+}
diff --git a/vndc/src/op_delay.cpp b/vndc/src/op_delay.cpp
new file mode 100644 (file)
index 0000000..c032c10
--- /dev/null
@@ -0,0 +1,18 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+/*
+ * Implements delay vnds function.
+ * delay frames
+ */
+
+void op_delay(int* frames) {
+       if (GetData()->if_fail || GetData()->ctx->GetQuit())
+               return;
+       for(int i = 0; i < *frames; i++) {
+               // This is one frame.
+               GetData()->ctx->StartSync();
+               GetData()->ctx->EndSync();
+       }
+}
diff --git a/vndc/src/op_fi.cpp b/vndc/src/op_fi.cpp
new file mode 100644 (file)
index 0000000..ec4af94
--- /dev/null
@@ -0,0 +1,12 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+/*
+ * Implements fi vnds function.
+ * if var op val
+ */
+
+void op_fi() {
+       GetData()->if_fail = false;
+}
diff --git a/vndc/src/op_goto.cpp b/vndc/src/op_goto.cpp
new file mode 100644 (file)
index 0000000..d620e79
--- /dev/null
@@ -0,0 +1,50 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+/* Implements vnds goto function
+ * goto label
+ * File pointer is provided so we can rewind.
+ */
+
+void op_goto(char* label) {
+       FILE** infile = &(GetData()->accessScriptHandle);
+
+       if (GetData()->if_fail || GetData()->ctx->GetQuit())
+               return;
+       rewind(*infile);
+
+       char *line = (char*)calloc(sizeof(char), 400);
+
+       int line_to = 0;
+
+       bool found = false;
+       while(!found) {
+               line_to++;
+               fgets(line, 400, *infile);
+
+       // Remove all '\n' from this string
+               for(int i=0; i < 400; i++) {
+                       if (line[i] == '\n')
+                               line[i] = '\0';
+               }
+
+               int num = 1;
+               char** tokens = (char**)realloc(NULL, sizeof(char*) * (1));
+               tokens[num-1] = strtok(line, " ");
+
+               do {
+                       //printf("Loop: num = %d;\n", num);
+                       ++num;
+                       tokens = (char**)realloc(tokens, sizeof(char*) * (num));
+                       tokens[num-1] = strtok(NULL, " ");
+               } while(tokens[num-1] != NULL);
+
+               --num;
+
+               if(!strcmp(tokens[0], "label"))
+                       if(!strcmp(tokens[1], label))
+                               found = true;
+       }
+       GetData()->currentLine = line_to;
+}
diff --git a/vndc/src/op_gsetvar.cpp b/vndc/src/op_gsetvar.cpp
new file mode 100644 (file)
index 0000000..01f0bed
--- /dev/null
@@ -0,0 +1,25 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+/*
+ * Implements gsetvar vnds function.
+ * gsetvar var mod val
+ * Modifier is '=' '+' or '-' in script, simplify to ('-':-1, '=':0, '+':1).
+ * MAY need to be UTF8 friendly
+ */
+
+void op_gsetvar(char* var, int *modifier, int *value) {
+       if (GetData()->if_fail)
+               return;
+
+       if(*modifier == 0) {
+               GetData()->g_flags[0][std::string(var)] = value[0];
+       }
+       else if (*modifier == -1) {
+               GetData()->g_flags[0][std::string(var)] -= value[0];
+       }
+       else if (*modifier == 1) {
+               GetData()->g_flags[0][std::string(var)] += value[0];
+       }
+}
diff --git a/vndc/src/op_if.cpp b/vndc/src/op_if.cpp
new file mode 100644 (file)
index 0000000..e733ca2
--- /dev/null
@@ -0,0 +1,59 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+/*
+ * Implements if vnds function.
+ * if var op val
+ * op is a c-style compare
+ * ('<=':0 '<':1 '==':2 '!=':3 '>': '>=':5)
+ */
+
+void op_if(char* var, int* op, int* val) {
+       if (GetData()->if_fail)
+               return;
+
+       int var_val = GetData()->s_flags[0][std::string(var)];
+
+       //printf("op_if(%s, %d, %d)\n", var, op[0], val[0]);
+       //printf("GetData()->s_flags[0][%s] = %d\n", var, GetData()->s_flags[0][std::string(var)]);
+
+       switch (op[0]) {
+               case 0:
+                       if ( !(var_val <= val[0]) )
+                               GetData()->if_fail = true;
+                       else
+                               GetData()->if_fail = false;
+                       break;
+               case 1:
+                       if ( !(var_val < val[0]) )
+                               GetData()->if_fail = true;
+                       else
+                               GetData()->if_fail = false;
+                       break;
+               case 2:
+                       if ( !(var_val == val[0]) )
+                               GetData()->if_fail = true;
+                       else
+                               GetData()->if_fail = false;
+                       break;
+               case 3:
+                       if ( !(var_val != val[0]) )
+                               GetData()->if_fail = true;
+                       else
+                               GetData()->if_fail = false;
+                       break;
+               case 4:
+                       if ( !(var_val > val[0]) )
+                               GetData()->if_fail = true;
+                       else
+                               GetData()->if_fail = false;
+                       break;
+               case 5:
+                       if ( !(var_val >= val[0]) )
+                               GetData()->if_fail = true;
+                       else
+                               GetData()->if_fail = false;
+                       break;
+       }
+}
diff --git a/vndc/src/op_jump.cpp b/vndc/src/op_jump.cpp
new file mode 100644 (file)
index 0000000..98395ba
--- /dev/null
@@ -0,0 +1,47 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+/*
+ * Implements jump vnds function.
+ * jump file
+ * The parser actually does most of the work. This
+ * just kind of gives it a nudge ans says 'reload k'
+ */
+
+void op_jump(char* file, int* lineTo, bool isSave) {
+       if (GetData()->if_fail)
+               return;
+       memset(GetData()->current_scr, 0, 400);
+       if(!isSave)
+               snprintf(GetData()->current_scr, 400, "script/%s", file);
+       else
+               snprintf(GetData()->current_scr, 400, "%s", file);
+
+       if(GetData()->debug_mode) {
+               memset(&GetData()->window_name[16], 0, sizeof(char)*400);
+               snprintf(&GetData()->window_name[16], 400-16-3, " (%s)", file);
+               GetData()->ctx->SetTitle(GetData()->window_name);
+       }
+
+       if(GetData()->accessScriptHandle != NULL)
+               fclose(GetData()->accessScriptHandle);
+
+       GetData()->accessScriptHandle = fopen(GetData()->current_scr, "r");
+       if(GetData()->accessScriptHandle == NULL) {
+               printf("[error] Failed to open script file %s.\n", GetData()->current_scr);
+       }
+
+
+       if(lineTo != NULL) {
+               GetData()->currentLine = lineTo[0];
+               char *line = (char*)calloc(sizeof(char), 400);
+
+               while(--lineTo[0] > 0) {
+                       fgets(line, 400, GetData()->accessScriptHandle);
+               }
+       }
+       else {
+               GetData()->currentLine = 0;
+       }
+}
diff --git a/vndc/src/op_music.cpp b/vndc/src/op_music.cpp
new file mode 100644 (file)
index 0000000..a817896
--- /dev/null
@@ -0,0 +1,30 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+/*
+ * Implements music vnds function.
+ * music file
+ */
+
+void op_music(char* file) {
+       if (GetData()->if_fail || GetData()->ctx->GetQuit())
+               return;
+
+       memset(GetData()->current_music, 0, 400);
+
+       snprintf(GetData()->current_music, 400, "sound/%s", file);
+
+       // Halt command
+       if (!strcmp(file, "~")) {
+               GetData()->ctx->Audio()->FlushMusic();
+       }
+       // Play command
+       else {
+               GetData()->ctx->Audio()->FlushMusic();
+
+               int index = GetData()->ctx->Audio()->LoadMusic(GetData()->current_music);
+
+               GetData()->ctx->Audio()->PlayMusicLoop(index);
+       }
+}
diff --git a/vndc/src/op_random.cpp b/vndc/src/op_random.cpp
new file mode 100644 (file)
index 0000000..1607378
--- /dev/null
@@ -0,0 +1,21 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+/*
+ * Implements random vnds function.
+ * random var low high
+ */
+
+bool seeded = false;
+
+void op_random(char* var, int* low, int* high) {
+       if (GetData()->if_fail)
+               return;
+       if (seeded == false)
+               srand(time(NULL));
+
+       int num = *low + ( rand() % ( *high - *low ) );
+
+       GetData()->s_flags[0][std::string(var)] = num;
+}
diff --git a/vndc/src/op_setimg.cpp b/vndc/src/op_setimg.cpp
new file mode 100644 (file)
index 0000000..e2c9a21
--- /dev/null
@@ -0,0 +1,30 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+/*
+ * Implements setimg vnds function.
+ * bgload file x y
+ */
+
+void op_setimg(char* file, int* x, int* y) {
+       if (GetData()->if_fail || GetData()->ctx->GetQuit())
+               return;
+
+       // Fadeout not implemented yet.
+
+       char path[400];
+       memset(path, 0, 400);
+
+       snprintf(path, 400, "foreground/%s", file);
+
+       // Load displayable.
+       UDisplayable* fg_add = new UDisplayable(GetData()->ctx, Normal, path);
+
+       fg_add->SetXY(*x, *y);
+
+       fg_add->Blit();
+
+       // Delete fg_new. We're done with it.
+       delete fg_add;
+}
diff --git a/vndc/src/op_setvar.cpp b/vndc/src/op_setvar.cpp
new file mode 100644 (file)
index 0000000..b6477a9
--- /dev/null
@@ -0,0 +1,37 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+/*
+ * Implements gsetvar vnds function.
+ * gsetvar var mod val
+ * Modifier is '=' '+' or '-' in script, simplify to ('-':-1, '=':0, '+':1).
+ * MAY need to be UTF8 friendly
+ */
+
+void op_setvar(char* var, int* modifier, int* value) {
+       if (GetData()->if_fail)
+               return;
+
+       if(*modifier == 0) {
+               GetData()->s_flags[0][std::string(var)] = value[0];
+       }
+       else if (*modifier == -1) {
+               GetData()->s_flags[0][std::string(var)] -= value[0];
+       }
+       else if (*modifier == 1) {
+               GetData()->s_flags[0][std::string(var)] += value[0];
+       }
+       else if (*modifier == -2) {
+               // There's a rare case on program start where a resetall
+               // happens.
+
+               if(!strcmp(var, "~")) {
+                       // We'll handle it by doing a delete & new on s_local
+                       GetData()->s_flags[0].clear();
+                       return;
+               }
+
+               GetData()->s_flags[0][std::string(var)] = 0;
+       }
+}
diff --git a/vndc/src/op_sound.cpp b/vndc/src/op_sound.cpp
new file mode 100644 (file)
index 0000000..ec721cc
--- /dev/null
@@ -0,0 +1,44 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+/*
+ * Implements sound vnds function.
+ * sound file [times]
+ */
+
+void op_sound(char* file, int* times) {
+       if (GetData()->if_fail || GetData()->ctx->GetQuit())
+               return;
+
+       // Fadeout not implemented yet.
+
+       // Halt command
+       if (!strcmp(file, "~")) {
+               GetData()->ctx->Audio()->FlushSfx();
+               return;
+       }
+       // Play command
+       else {
+               int count = 1;
+               if (times != NULL)
+                       count = *times;
+
+               char path[400];
+               memset(path, 0, 400);
+
+               snprintf(path, 400, "sound/%s", file);
+
+               //printf("[op_sound] path: '%s'\n", path);
+
+               // Load displayable.
+               int sfxi = GetData()->ctx->Audio()->LoadSfx(path);
+
+               if (count == -1) {
+                       GetData()->ctx->Audio()->PlaySfx(sfxi, count);
+               }
+               else {
+                       GetData()->ctx->Audio()->PlaySfx(sfxi, count-1);
+               }
+       }
+}
diff --git a/vndc/src/op_text.cpp b/vndc/src/op_text.cpp
new file mode 100644 (file)
index 0000000..02a18d6
--- /dev/null
@@ -0,0 +1,119 @@
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+/*
+ * Implements text vnds function.
+ * text string
+ */
+
+void op_text(char* string) {
+       if (GetData()->if_fail || GetData()->ctx->GetQuit())
+               return;
+
+       // Search thru for vars and rebuild string.
+
+       // Linebreak on zero-length, and render size exceed.
+       if (GetData()->text_y > (GetData()->render_y2) || strlen(string) < 1)
+               op_cleartext();
+
+       if(strlen(string) < 1)
+               return;
+
+       // Improvised linebreak. Also, an extension.
+       if(GetData()->vndc_enabled && string[1] == '-' && string[2] == '-' && string[3] == '-') {
+                       op_cleartext();
+       }
+       // Improvised voice detect. Extension.
+       // This is based on toggling.
+       // If the quote is incomplete, it will be stopped on end.
+       // If not, it will continue voice until the next quoted line.
+       if(GetData()->vndc_enabled) {
+               GetData()->is_spoken_line = false;
+
+               int quotes = 0;
+               for(int i=0; i < (int)strlen(string); i++) {
+                       if(string[i] == '"') quotes++;
+               }
+               if(quotes > 0) GetData()->is_spoken_line = true;
+       }
+       // Wait for input, then blank
+       if(!strcmp(string, "!")) {
+               GetData()->wait_input = true;
+               Wait();
+               op_cleartext();
+       }
+       // Blank screen
+       else if(!strcmp(string, "~")) {
+               op_cleartext();
+       }
+       // Output
+       else {
+               bool noclick = false;
+               // No click required
+               if(string[0] == '@') {
+                       noclick = true;
+                       string = &string[1];
+               }
+
+
+               TextManager* txt = GetData()->ctx->Text();
+
+               if(txt->TestLen(string) > (GetData()->render_x2 - GetData()->render_x1)) {
+
+                       /* new algo */
+                       char** ptrs = NULL;
+                       int lines = 0;
+
+                       int len = strlen(string);
+
+                       int counted = 0;
+
+                       while(counted < len) {
+                               char* pt_start = &string[counted];
+                               char* pt_end = &pt_start[strlen(pt_start)];
+
+                               while(pt_end > pt_start && txt->TestLen(pt_start) > (GetData()->render_x2 - GetData()->render_x1)) {
+                                       *pt_end = ' ';
+                                       --pt_end;
+
+                                       while (*pt_end != ' ' && pt_end > pt_start) --pt_end;
+
+                                       *pt_end = '\0';
+                               }
+
+                               #ifdef DEBUG_OVERKILL
+                               printf("Reduced line %d: %s\n", lines, pt_start);
+                               #endif
+
+                               ptrs = (char**)realloc(ptrs, sizeof(char*)*(lines+1));
+
+                               ptrs[lines] = pt_start;
+
+                               counted += strlen(pt_start) + 1;
+
+                               ++lines;
+                       }
+
+                       if( ( lines * 35 + GetData()->text_y ) > GetData()->render_y2 )
+                               op_cleartext();
+
+                       for(int i=0; i < lines; i++) {
+                               //printf("[br] %s\n", ptrs[i]);
+                               txt->Render(ptrs[i], GetData()->text_x, GetData()->text_y);
+                               GetData()->text_y += 35;
+                       }
+
+                       free(ptrs);
+
+               }
+               else {
+                       txt->Render(string, GetData()->text_x, GetData()->text_y);
+                       GetData()->text_y += 35;
+               }
+
+               if(!noclick) {
+                       GetData()->wait_input = true;
+               }
+       }
+}