--- /dev/null
+#!/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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+
+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;
+};
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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;
+ }
--- /dev/null
+#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);
+ }
--- /dev/null
+#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;
+}
--- /dev/null
+#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
+ }
--- /dev/null
+#!/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
+}
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
+}
--- /dev/null
+#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();
+}
--- /dev/null
+#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) {}
--- /dev/null
+#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();
+}
--- /dev/null
+#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);
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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();
+}
--- /dev/null
+#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();
+ }
+}
--- /dev/null
+#include "Zero.hpp"
+
+#include "Funcs.hpp"
+
+/*
+ * Implements fi vnds function.
+ * if var op val
+ */
+
+void op_fi() {
+ GetData()->if_fail = false;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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];
+ }
+}
--- /dev/null
+#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;
+ }
+}
--- /dev/null
+#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;
+ }
+}
--- /dev/null
+#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);
+ }
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+ }
+}
--- /dev/null
+#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);
+ }
+ }
+}
--- /dev/null
+#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;
+ }
+ }
+}