fix line endings
authorStan_Lewry <stanley.jml@gmail.com>
Fri, 30 Aug 2024 17:43:09 +0000 (18:43 +0100)
committerStan_Lewry <stanley.jml@gmail.com>
Fri, 30 Aug 2024 17:43:09 +0000 (18:43 +0100)
combat.cpp
combat.h
globals.cpp
globals.h
main.cpp
main_menu.cpp
main_menu.h
tilemap.cpp
tilemap.h
ui.cpp
ui.h

index 755988d..a69026f 100644 (file)
-#define _CRT_SECURE_NO_WARNINGS\r
-\r
-#include "combat.h"\r
-#include "globals.h"\r
-#include "ui.h"\r
-#include "tilemap.h"\r
-\r
-#include <cmath>\r
-#include <algorithm>\r
-\r
-\r
-struct Character {\r
-       bool allied;\r
-       std::string name;\r
-       int currentHP;\r
-       int maxHP;\r
-       int currentMP;\r
-       int maxMP;\r
-       int attack;\r
-       float agility; // to determine move order\r
-       float moveDist;\r
-\r
-       // animation stuff?\r
-       SDL_Texture* texture;\r
-       S2DE::Vec2<float> position;\r
-       // direction vector?\r
-       // how to handle "moves"\r
-       S2DE::Vec2<float> combatMoveDestination = { 0.0f, 0.0f };\r
-\r
-       int basicAttackRange = 1.0f;\r
-\r
-       bool canMove = true;\r
-       bool canAttack = true;\r
-\r
-       bool alive = true;\r
-};\r
-\r
-std::vector<Character> combatants;\r
-int currentCombatantIndex = -1;\r
-Character* activeCombatant;\r
-\r
-std::vector<Character*> targets;\r
-int currentTargetIdx = 0;\r
-\r
-enum CombatState {\r
-       TURN_ORDER,\r
-       ACTION_SELECT,\r
-       PLAYER_MOVE,\r
-       SELECT_TARGET,\r
-       DO_ATTACK,\r
-       ENEMY_MOVE,\r
-       MOVE_TO_POSITION,\r
-};\r
-\r
-CombatState currentCombatState = TURN_ORDER;\r
-\r
-enum Spell {\r
-       BASIC_ATTACK\r
-};\r
-\r
-Spell currentSpell = BASIC_ATTACK;\r
-\r
-static double frameTimer = 0;\r
-static const double frameTime = 1.0f / 60.0f;\r
-\r
-//bool playerTurn = true;\r
-\r
-SDL_Texture* arrowSprite = nullptr;\r
-SDL_Texture* indicatorSprite = nullptr;\r
-SDL_Texture* indicatorRedSprite = nullptr;\r
-\r
-static constexpr int arenaWidth = 100;\r
-static constexpr int arenaHeight = 100;\r
-WorldCell** arena;\r
-WorldCell** fogLayer;\r
-S2DE::Camera combatCam = { 23.5, 11.5 };\r
-\r
-S2DE::Vec2<float> moveCursorPos;\r
-S2DE::Vec2<float> arenaCenter = { 23, 11 };\r
-\r
-//S2DE::Vec2<float>* currentMoveDest = &moveCursorPos;\r
-\r
-static const int numActions = 4;\r
-static const char* actions[numActions] = {"Move", "Attack", "End", "FLEE"};\r
-int currentAction = 0;\r
-\r
-SDL_Colour hpColour = { 136, 8, 8, 255 };\r
-SDL_Colour mpColour = { 0, 150, 255, 255 };\r
-\r
-void renderCombat();\r
-\r
-void renderUIFull();\r
-void renderActionsPanel();\r
-void renderCombatants();\r
-void renderStatsPanel();\r
-\r
-// lerp functions\r
-float interpolatePosition(S2DE::Vec2<float>* entityPos, S2DE::Vec2<float> destination, float t, float speed);\r
-void moveToPosition(Character* c, S2DE::Vec2<float> destination, float speed);\r
-\r
-void runStateFunction(CombatState state, double delta);\r
-void actionSelectState(double delta);\r
-void playerMoveActionState(double delta);\r
-void enemyMoveActionState(double delta);\r
-void movingCharacterState(double delta);\r
-void determineNextTurnState(double delta);\r
-void selectAttackTarget(double delta);\r
-void doAttack(double delta); // plays attack animation, resolves and applies damage.\r
-\r
-void runStateFunction(CombatState state, double delta) {\r
-       switch (state) {\r
-       case TURN_ORDER: determineNextTurnState(delta);         break;\r
-       case ACTION_SELECT: actionSelectState(delta);           break;\r
-       case PLAYER_MOVE: playerMoveActionState(delta);         break;\r
-       case SELECT_TARGET: selectAttackTarget(delta);          break;\r
-       case ENEMY_MOVE: enemyMoveActionState(delta);           break;\r
-       case MOVE_TO_POSITION: movingCharacterState(delta);     break;\r
-       case DO_ATTACK: doAttack(delta);                                        break;\r
-       default: assert(false); break;\r
-       }\r
-}\r
-\r
-float distance(S2DE::Vec2<float> p1, S2DE::Vec2<float> p2) {\r
-       return std::sqrt(std::pow(p2.x - p1.x, 2) + std::powf(p2.y - p1.y, 2));\r
-}\r
-\r
-void renderMeter(int x, int y, int width, int height, float percentage, SDL_Colour fillColour, int style) {\r
-       if (style == 1) {\r
-               SDL_SetRenderDrawColor(renderer, 0, 0, 0, 180);\r
-               SDL_Rect bgRect = { x, y, width, height };\r
-               SDL_RenderFillRect(renderer, &bgRect);\r
-       }\r
-       else if (style == 2) {\r
-               SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);\r
-               SDL_RenderDrawLine(renderer, x, y, x + width, y);\r
-               SDL_RenderDrawLine(renderer, x, y + height, x + width, y + height);\r
-               \r
-               SDL_RenderDrawLine(renderer, x, y, x, y + height);\r
-               SDL_RenderDrawLine(renderer, x + width, y, x + width, y + height);\r
-       }\r
-\r
-       SDL_SetRenderDrawColor(renderer, fillColour.r, fillColour.g, fillColour.b, fillColour.a);\r
-       int panelWidth = width * percentage;\r
-       SDL_Rect fillRect = { x+1, y+1, panelWidth -1, height-1 };\r
-       SDL_RenderFillRect(renderer, &fillRect);\r
-}\r
-\r
-void renderStatsPanel() {\r
-       int panelWidth = 300;\r
-       int panelHeight = 200;\r
-       int outerPad = 2;\r
-       int innerPad = 16;\r
-\r
-       int panelX = WINDOW_WIDTH - panelWidth - outerPad;\r
-       int panelY = WINDOW_HEIGHT - panelHeight - outerPad;\r
-\r
-       renderBasicPanel(panelX, panelY, panelWidth, panelHeight);\r
-       renderString(panelX + innerPad, panelY + innerPad, activeCombatant->name.c_str());\r
-\r
-       int portraitWidth = 80;\r
-       int portraitHeight = 80;\r
-\r
-       int portraitX = panelX + 16;\r
-       int portraitY = panelY + 50;\r
-       renderBasicPanel(portraitX, portraitY, portraitWidth, portraitHeight);\r
-       SDL_Rect characterDRect = { portraitX + 8, portraitY + 8, portraitWidth - 16, portraitHeight - 16};\r
-       SDL_Rect characterSRect = { 0 , 0, 32, 32 };\r
-       SDL_Texture* portraitTexture = activeCombatant->texture;\r
-       S2DE::renderTexture(&renderer, &portraitTexture, &characterSRect, &characterDRect);\r
-\r
-\r
-       renderString(portraitX + portraitWidth + innerPad, portraitY, "HP:");\r
-       int valPad = 100;\r
-       char hpStr[10];\r
-       sprintf(hpStr, "%d/%d", activeCombatant->currentHP, activeCombatant->maxHP);\r
-       renderString(portraitX + portraitWidth + innerPad + valPad, portraitY, hpStr);\r
-\r
-       float hpLvl = (float)activeCombatant->currentHP / (float)activeCombatant->maxHP;\r
-       renderMeter(portraitX + portraitWidth + innerPad, portraitY + innerPad, panelWidth - (innerPad * 3) - portraitWidth, 20, hpLvl, hpColour, 2);\r
-\r
-       renderString(portraitX + portraitWidth + innerPad, portraitY + innerPad + 22, "MP:");\r
-\r
-       char mpStr[10];\r
-       sprintf(mpStr, "%d/%d", activeCombatant->currentMP, activeCombatant->maxMP);\r
-       renderString(portraitX + portraitWidth + innerPad + valPad, portraitY + innerPad + 22, mpStr);\r
-       \r
-       float mpLvl = (float)activeCombatant->currentMP / (float)activeCombatant->maxMP;\r
-       renderMeter(portraitX + portraitWidth + innerPad, portraitY + innerPad + 42, panelWidth - (innerPad * 3) - portraitWidth, 20, mpLvl, mpColour, 2);\r
-       \r
-}\r
-\r
-void renderActionsPanel() {\r
-       int panelWidth = 150;\r
-       int panelHeight = 150;\r
-\r
-       //int panelX = WINDOW_WIDTH / 2 - panelWidth / 2;\r
-       int panelX = 100;\r
-       int panelY = WINDOW_HEIGHT - panelHeight - 2;\r
-\r
-       renderBasicPanel(panelX, panelY, panelWidth, panelHeight);\r
-\r
-       int leftPad = 40;\r
-       int topPad = 20;\r
-       int itemSpacing = 30;\r
-\r
-       for (int i = 0; i < numActions; ++i) {\r
-               // a bit of a brittle way of doing this\r
-               if (i == 0 && !activeCombatant->canMove) {\r
-                       renderString(panelX + leftPad, panelY + topPad + itemSpacing * i, actions[i], font_grey);\r
-               }\r
-               else if (i == 1 && !activeCombatant->canAttack) {\r
-                       renderString(panelX + leftPad, panelY + topPad + itemSpacing * i, actions[i], font_grey);\r
-               }\r
-               else {\r
-                       renderString(panelX + leftPad, panelY + topPad + itemSpacing * i, actions[i]);\r
-               }\r
-       }\r
-\r
-       renderString(panelX + 20, panelY + topPad + (itemSpacing * currentAction), ">");\r
-}\r
-\r
-void renderUIFull() {\r
-       renderActionsPanel();\r
-       renderStatsPanel();\r
-}\r
-\r
-void renderCombat() {\r
-       renderTilemap(arena, arenaWidth, arenaHeight, combatCam);\r
-       renderCombatants();\r
-       renderTilemap(fogLayer, arenaWidth, arenaHeight, combatCam); // render the fog layer\r
-}\r
-\r
-void renderCombatants() {\r
-\r
-       for (Character c : combatants) {\r
-\r
-               if (c.alive) {\r
-                       S2DE::Vec2<float> pos = c.position;\r
-                       S2DE::Rect charDRect = S2DE::worldToScreenRect(&combatCam, &pos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32);\r
-                       S2DE::Rect charSRect = { 0, 0, 32, 32 };\r
-\r
-                       // disabled for now\r
-                       //if (c.allied) {\r
-                       //      // do the looking logic only for allied characters\r
-                       //      int playerFrame = 1;\r
-                       //      int playerDir = 0;\r
-\r
-                       //      Character enemy = combatants.at(1);\r
-\r
-                       //      int lookDeltaX = (enemy.position.x + 0.5) - (c.position.x + 0.5);\r
-                       //      int lookDeltaY = (enemy.position.y + 0.5) - (c.position.y + 0.5);\r
-\r
-                       //      if (abs(lookDeltaX) > abs(lookDeltaY)) {\r
-                       //              if (lookDeltaX > 0) playerDir = 2;\r
-                       //              else playerDir = 6;\r
-                       //      }\r
-                       //      else {\r
-                       //              if (lookDeltaY > 0) playerDir = 4;\r
-                       //              else playerDir = 0;\r
-                       //      }\r
-\r
-                       //      charSRect = { playerFrame * 32, playerDir * 32, 32, 32 };\r
-                       //}\r
-\r
-                       SDL_Texture* texture = c.texture;\r
-                       S2DE::renderTexture(&renderer, &texture, &charSRect, &charDRect);\r
-\r
-                       float hpLvl = (float)c.currentHP / (float)c.maxHP;\r
-                       renderMeter(charDRect.x + 6, charDRect.y - 6, charDRect.w - 12, 6, hpLvl, hpColour, 1);\r
-               }\r
-       }\r
-\r
-       // render the little arrow\r
-       S2DE::Vec2<float> arrowPos = activeCombatant->position;\r
-               \r
-       arrowPos.y -= 0.7;\r
-       S2DE::Rect arrowDRect = S2DE::worldToScreenRect(&combatCam, &arrowPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32);\r
-       S2DE::renderTexture(&renderer, &indicatorSprite, NULL, &arrowDRect);\r
-}\r
-\r
-void initCombatScene()\r
-{\r
-       // I think all resources should be initialized and cleaned up in the globals tbh\r
-       arena = new WorldCell * [arenaHeight];\r
-       for (int i = 0; i < arenaHeight; ++i) arena[i] = new WorldCell[arenaWidth];\r
-       \r
-       fogLayer = new WorldCell * [arenaHeight];\r
-       for (int i = 0; i < arenaHeight; ++i) fogLayer[i] = new WorldCell[arenaWidth];\r
-\r
-       loadWorld("maps/combat_arena_1.tmj", arena, arenaWidth, arenaHeight);\r
-       loadWorld("maps/combat_arena_1_fog.tmj", fogLayer, arenaWidth, arenaHeight);\r
-\r
-       arrowSprite = S2DE::loadTexture("assets/arrow.png", &renderer);\r
-       indicatorSprite = S2DE::loadTexture("assets/little_indicator.png", &renderer);\r
-       indicatorRedSprite = S2DE::loadTexture("assets/little_indicator_red.png", &renderer);\r
-\r
-       //Character player = { true, "Player", 100, 100, 50, 50, 10.0f, 3.0f, player_sheet, { 23.0f, 13.0f } };\r
-       Character player;\r
-       player.allied = true;\r
-       player.name = "Player";\r
-       player.maxHP = 100;\r
-       player.currentHP = player.maxHP;\r
-       player.maxMP = 50;\r
-       player.currentMP = player.maxMP;\r
-       player.agility = 10.0f;\r
-       player.moveDist = 3.0f;\r
-       player.texture = player_forward_texture;\r
-       player.position = { arenaCenter.x, arenaCenter.y + 2 };\r
-       player.attack = 5;\r
-\r
-\r
-       Character monica;\r
-       monica.allied = true;\r
-       monica.name = "Monica";\r
-       monica.maxHP = 100;\r
-       monica.currentHP = monica.maxHP;\r
-       monica.maxMP = 50;\r
-       monica.currentMP = monica.maxMP;\r
-       monica.agility = 8.0f;\r
-       monica.moveDist = 6.0f;\r
-       monica.texture = monica_texture;\r
-       monica.position = { player.position.x - 2, player.position.y };\r
-       monica.attack = 6;\r
-\r
-       Character enemy;\r
-       enemy.allied = false;\r
-       enemy.name = "Bird";\r
-       enemy.maxHP = 25;\r
-       enemy.currentHP = enemy.maxHP;\r
-       enemy.maxMP = 10;\r
-       enemy.currentMP = enemy.maxMP;\r
-       enemy.agility = 5.0f;\r
-       enemy.moveDist = 1.5f;\r
-       enemy.texture = bird;\r
-       enemy.position = { arenaCenter.x, arenaCenter.y - 2 };\r
-       enemy.attack = 2;\r
-\r
-       Character frog;\r
-       frog.allied = false;\r
-       frog.name = "Frog";\r
-       frog.currentHP = frog.maxHP = 10;\r
-       frog.currentMP = frog.maxMP = 10;\r
-       frog.agility = 2;\r
-       frog.moveDist = 2.0f;\r
-       frog.texture = frog_texture;\r
-       frog.position = { arenaCenter.x - 1, arenaCenter.y - 2 };\r
-       frog.attack = 2;\r
-\r
-       combatants.push_back(player);\r
-       combatants.push_back(monica);\r
-       combatants.push_back(enemy);\r
-       combatants.push_back(frog);\r
-\r
-\r
-       // calculates turn order. Can expand the lambda to support other things\r
-       std::sort(combatants.begin(), combatants.end(), [](const Character& a, const Character& b) {return a.agility > b.agility; });\r
-\r
-       activeCombatant = &combatants.at(0);\r
-       moveCursorPos = activeCombatant->position;\r
-}\r
-\r
-\r
-void interpolatePosition(S2DE::Vec2<float>* entityPos, S2DE::Vec2<float> destination, float* t, float speed) {\r
-       *t += speed;\r
-\r
-       entityPos->x = (1.0f - *t) * entityPos->x + *t * destination.x;\r
-       entityPos->y = (1.0f - *t) * entityPos->y + *t * destination.y;\r
-}\r
-\r
-void moveToPosition(Character* c, S2DE::Vec2<float> destination, float speed) {\r
-       float dist = distance(c->position, destination);\r
-\r
-       S2DE::Vec2<float> direction {destination.x - c->position.x, destination.y - c->position.y};\r
-\r
-       direction.x /= dist;\r
-       direction.y /= dist;\r
-\r
-       if (dist <= speed) {\r
-               c->position.x = destination.x;\r
-               c->position.y = destination.y;\r
-       }\r
-       else {\r
-               c->position.x += direction.x * speed;\r
-               c->position.y += direction.y * speed;\r
-       }\r
-}\r
-\r
-void actionSelectState(double delta) {\r
-       S2DE::updateInputState(&inputState);\r
-\r
-       // handle inputs\r
-       if (inputState.up) {\r
-               inputState.up = false;\r
-               currentAction--;\r
-               if (currentAction < 0) currentAction = numActions - 1;\r
-       }\r
-       else if (inputState.down) {\r
-               inputState.down = false;\r
-               currentAction++;\r
-               if (currentAction > numActions - 1) currentAction = 0;\r
-       }\r
-       else if (inputState.rtrn) {\r
-               inputState.rtrn = false;\r
-               switch (currentAction) {\r
-               case 0:\r
-                       if (activeCombatant->canMove) {\r
-                               currentCombatState = PLAYER_MOVE;\r
-                               moveCursorPos = activeCombatant->position;\r
-                       }\r
-                       break;\r
-               case 1: // attack selected\r
-                       if (activeCombatant->canAttack) {\r
-                               // filter the targets - Have to do it here too in case the player attacks without moving?\r
-                               targets.clear();\r
-                               for (auto& c : combatants) {\r
-                                       if (!c.allied && c.alive) {\r
-                                               float dist = distance(activeCombatant->position, c.position);\r
-                                               if (dist <= activeCombatant->basicAttackRange) {\r
-                                                       targets.push_back(&c);\r
-                                               }\r
-                                       }\r
-                               }\r
-\r
-                               currentCombatState = SELECT_TARGET;\r
-                       }\r
-                       break;\r
-               case 2: // end selected\r
-                       currentCombatState = TURN_ORDER;\r
-                       break;\r
-\r
-               default:\r
-                       inputState.quit = true;\r
-                       break;\r
-               }\r
-       }\r
-\r
-       SDL_RenderClear(renderer);\r
-       renderCombat();\r
-       renderUIFull();\r
-       SDL_RenderPresent(renderer);\r
-}\r
-\r
-void playerMoveActionState(double delta) {\r
-       S2DE::updateInputState(&inputState);\r
-\r
-       frameTimer += delta;\r
-       \r
-       Character player = *activeCombatant;\r
-\r
-       if (frameTimer > frameTime) {\r
-\r
-               frameTimer = 0;\r
-\r
-               float cursorSpeed = 0.05;\r
-\r
-               S2DE::Vec2<float> newCursorPos = moveCursorPos;\r
-\r
-               float newY = moveCursorPos.y;\r
-               float newX = moveCursorPos.x;\r
-\r
-               if (inputState.right) {\r
-                       newX += cursorSpeed;\r
-               }\r
-               if (inputState.left) {\r
-                       newX -= cursorSpeed;\r
-               }\r
-               if (inputState.up) {\r
-                       newY -= cursorSpeed;\r
-               }\r
-               if (inputState.down) {\r
-                       newY += cursorSpeed;\r
-               }\r
-\r
-               if (inputState.rtrn) {\r
-                       inputState.rtrn = false;\r
-\r
-                       activeCombatant->combatMoveDestination = moveCursorPos;\r
-                       currentCombatState = MOVE_TO_POSITION;\r
-               }\r
-\r
-               if (distance({ moveCursorPos.x, newY }, player.position) <= player.moveDist\r
-                       && checkCollisionPoint({ moveCursorPos.x + 0.5f, newY + 0.5f }, arena) == false) {\r
-                       moveCursorPos.y = newY;\r
-               }\r
-               if (distance({ newX, moveCursorPos.y }, player.position) <= player.moveDist\r
-                       && checkCollisionPoint({ newX + 0.5f, moveCursorPos.y + 0.5f }, arena) == false) {\r
-                       moveCursorPos.x = newX;\r
-               }\r
-\r
-       }\r
-\r
-\r
-       // compute characters in melee range\r
-       targets.clear();\r
-       for (auto& c : combatants) {\r
-               if (!c.allied && c.alive) {\r
-                       float dist = distance(moveCursorPos, c.position);\r
-                       if (dist <= activeCombatant->basicAttackRange) {\r
-                               targets.push_back(&c);\r
-                       }\r
-               }\r
-       }\r
-\r
-\r
-       SDL_RenderClear(renderer);\r
-\r
-       renderTilemap(arena, arenaWidth, arenaHeight, combatCam);\r
-\r
-       \r
-       S2DE::Vec2<float> playerCenterWorld = { player.position.x + 0.5, player.position.y + 0.5 };\r
-       S2DE::Vec2<int> playerCenterScreen = S2DE::worldToScreenPoint(&combatCam, &playerCenterWorld, 64, WINDOW_WIDTH, WINDOW_HEIGHT);\r
-\r
-       S2DE::renderCircle(&renderer, playerCenterScreen, (player.moveDist) * 64, { 0, 255, 255, 125 });\r
-\r
-\r
-       S2DE::Vec2<float> lineEndWorld = { moveCursorPos.x + 0.5, moveCursorPos.y + 0.5 };\r
-       S2DE::Vec2<int> lineEndPos = S2DE::worldToScreenPoint(&combatCam, &lineEndWorld, 64, WINDOW_WIDTH, WINDOW_HEIGHT);\r
-\r
-       SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);\r
-       SDL_RenderDrawLine(renderer, playerCenterScreen.x, playerCenterScreen.y, lineEndPos.x, lineEndPos.y);\r
-\r
-       // render lines to targets in range\r
-       SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);\r
-       for (auto t : targets) {\r
-               S2DE::Vec2<float> targetCenter = { t->position.x + 0.5, t->position.y + 0.5 };\r
-               S2DE::Vec2<int> targetCenterScreen = S2DE::worldToScreenPoint(&combatCam, &targetCenter, 64, WINDOW_WIDTH, WINDOW_HEIGHT);\r
-               SDL_RenderDrawLine(renderer, lineEndPos.x, lineEndPos.y, targetCenterScreen.x, targetCenterScreen.y);\r
-       }\r
-\r
-\r
-       renderCombatants();\r
-\r
-       S2DE::Rect cursorDRect = S2DE::worldToScreenRect(&combatCam, &moveCursorPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32);\r
-       S2DE::renderTexture(&renderer, &arrowSprite, NULL, &cursorDRect);\r
-\r
-       renderTilemap(fogLayer, arenaWidth, arenaHeight, combatCam); // draw the fog layer\r
-\r
-       renderActionsPanel();\r
-       renderStatsPanel();\r
-       SDL_RenderPresent(renderer);\r
-}\r
-\r
-void selectAttackTarget(double delta) {\r
-       S2DE::updateInputState(&inputState);\r
-\r
-       frameTimer += delta;\r
-\r
-       if (frameTimer > frameTime) {\r
-               frameTimer = 0;\r
-               if (inputState.rtrn) {\r
-                       inputState.rtrn = false;\r
-                       if (targets.size() > 0) {\r
-                               currentSpell = BASIC_ATTACK;\r
-                               currentCombatState = DO_ATTACK;\r
-                       }\r
-                       else {\r
-                               currentCombatState = ACTION_SELECT;\r
-                       }\r
-\r
-               }\r
-\r
-               if (inputState.right) {\r
-                       // cycle up through targets\r
-                       inputState.right = false; // gotta find a better way to do this\r
-\r
-                       currentTargetIdx += 1;\r
-                       if (currentTargetIdx > targets.size() - 1) currentTargetIdx = 0;\r
-               }\r
-               else if (inputState.left) {\r
-                       inputState.left = false;\r
-                       // cycle "down"through targets\r
-                       currentTargetIdx -= 1;\r
-                       if (currentTargetIdx < 0) currentTargetIdx = targets.size() - 1;\r
-               }\r
-       }\r
-\r
-       SDL_RenderClear(renderer);\r
-       \r
-\r
-       renderTilemap(arena, arenaWidth, arenaHeight, combatCam);\r
-\r
-       renderCombatants();\r
-\r
-       // render the little red arrow above all valid targets\r
-       if (targets.size() > 0) {\r
-               S2DE::Vec2<float> arrowPos = targets.at(currentTargetIdx)->position;\r
-\r
-               arrowPos.y -= 0.7;\r
-               S2DE::Rect arrowDRect = S2DE::worldToScreenRect(&combatCam, &arrowPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32);\r
-               S2DE::renderTexture(&renderer, &indicatorRedSprite, NULL, &arrowDRect);\r
-       }\r
-       \r
-\r
-       renderTilemap(fogLayer, arenaWidth, arenaHeight, combatCam); // draw the fog layer\r
-\r
-\r
-\r
-       renderUIFull();\r
-       renderString(10, 10, "SELECT TARGET STATE", debug_font);\r
-\r
-\r
-       if (targets.size() == 0) {\r
-               renderString(10, 64, "NO TARGETS IN RANGE", debug_font);\r
-       }\r
-       else {\r
-               int num_targets = targets.size();\r
-               char str[22];\r
-               sprintf(str, "AVAILABLE_TARGETS: %i", num_targets);\r
-               renderString(10, 64, str, debug_font);\r
-       }\r
-\r
-       SDL_RenderPresent(renderer);\r
-\r
-}\r
-\r
-void doAttack(double delta) {\r
-       // for now just subtract the combatants' dmg from the targets hp and move on\r
-       \r
-\r
-       if (currentTargetIdx == -1) {\r
-               // AOE, apply to all targets in range ?\r
-       }\r
-       else {\r
-               Character* target = targets.at(currentTargetIdx);\r
-               target->currentHP -= activeCombatant->attack;\r
-\r
-               if (target->currentHP <= 0) {\r
-                       target->alive = false;\r
-                       target->currentHP = 0;\r
-               }\r
-       }\r
-\r
-\r
-\r
-       targets.clear();\r
-       currentCombatState = ACTION_SELECT;\r
-       activeCombatant->canAttack = false;\r
-}\r
-\r
-\r
-void enemyMoveActionState(double delta) {\r
-       S2DE::updateInputState(&inputState);\r
-\r
-       Character enemy = *activeCombatant;\r
-\r
-       // implicitly grabs the character with the highest agility for now\r
-       Character agro = *std::find_if(combatants.begin(), combatants.end(), [](const Character& c) {return c.allied; });\r
-\r
-       S2DE::Vec2<float> dirToAgro = { agro.position.x - enemy.position.x, agro.position.y - enemy.position.y };\r
-       float distToAgro = distance(enemy.position, agro.position);\r
-\r
-       dirToAgro.x /= distToAgro;\r
-       dirToAgro.y /= distToAgro;\r
-\r
-       S2DE::Vec2<float> movePos = { enemy.position.x + dirToAgro.x * enemy.moveDist, enemy.position.y + dirToAgro.y * enemy.moveDist};\r
-\r
-       activeCombatant->combatMoveDestination = movePos;\r
-       currentCombatState = MOVE_TO_POSITION;\r
-}\r
-\r
-void movingCharacterState(double delta) {\r
-       S2DE::updateInputState(&inputState);\r
-\r
-       frameTimer += delta;\r
-\r
-       if (frameTimer > frameTime) {\r
-               frameTimer = 0;\r
-\r
-               static float speed = 0.05f;\r
-\r
-               if (inputState.rtrn) {\r
-                       // skip\r
-                       inputState.rtrn = false;\r
-                       activeCombatant->position = activeCombatant->combatMoveDestination;\r
-               }\r
-\r
-               moveToPosition(activeCombatant, activeCombatant->combatMoveDestination, speed);\r
-\r
-               if (activeCombatant->position.x == activeCombatant->combatMoveDestination.x && activeCombatant->position.y == activeCombatant->combatMoveDestination.y) {\r
-                       // move completed. if allied, return to select action\r
-                       if (activeCombatant->allied) {\r
-                               activeCombatant->canMove = false; // TODO: support characters that can move twice?\r
-                               currentCombatState = ACTION_SELECT;\r
-                       }\r
-                       else {\r
-                               currentCombatState = TURN_ORDER;\r
-                       }\r
-               }\r
-\r
-               // TODO: Ensure all rendering is happening at the same FPS\r
-               SDL_RenderClear(renderer);\r
-               renderCombat();\r
-               // dont show the ui in this state\r
-               SDL_RenderPresent(renderer);\r
-       }\r
-\r
-}\r
-\r
-\r
-void determineNextTurnState(double delta) {\r
-\r
-       currentCombatantIndex += 1;\r
-\r
-       // WARNING: this system does not support the case where agility changes mid-fight. will need to re-sort if that happens\r
-       if (currentCombatantIndex > combatants.size() - 1) currentCombatantIndex = 0;\r
-\r
-       activeCombatant = &combatants.at(currentCombatantIndex);\r
-\r
-       if (activeCombatant->alive) { // skip dead characters\r
-               if (activeCombatant->allied) {\r
-                       // reset combatants actions\r
-                       activeCombatant->canAttack = true;\r
-                       activeCombatant->canMove = true;\r
-                       currentAction = 0;\r
-                       currentCombatState = ACTION_SELECT;\r
-               }\r
-               else {\r
-                       //currentCombatState = ENEMY_MOVE;\r
-               }\r
-       }\r
-\r
-}\r
-\r
-\r
-void runCombat(double delta) {\r
-       \r
-       static double frameTimer = 0;\r
-       static const double frameTime = 1.0f / 60.0f;\r
-\r
-       runStateFunction(currentCombatState, delta);\r
-\r
+#define _CRT_SECURE_NO_WARNINGS
+
+#include "combat.h"
+#include "globals.h"
+#include "ui.h"
+#include "tilemap.h"
+
+#include <cmath>
+#include <algorithm>
+
+
+struct Character {
+       bool allied;
+       std::string name;
+       int currentHP;
+       int maxHP;
+       int currentMP;
+       int maxMP;
+       int attack;
+       float agility; // to determine move order
+       float moveDist;
+
+       // animation stuff?
+       SDL_Texture* texture;
+       S2DE::Vec2<float> position;
+       // direction vector?
+       // how to handle "moves"
+       S2DE::Vec2<float> combatMoveDestination = { 0.0f, 0.0f };
+
+       int basicAttackRange = 1.0f;
+
+       bool canMove = true;
+       bool canAttack = true;
+
+       bool alive = true;
+};
+
+std::vector<Character> combatants;
+int currentCombatantIndex = -1;
+Character* activeCombatant;
+
+std::vector<Character*> targets;
+int currentTargetIdx = 0;
+
+enum CombatState {
+       TURN_ORDER,
+       ACTION_SELECT,
+       PLAYER_MOVE,
+       SELECT_TARGET,
+       DO_ATTACK,
+       ENEMY_MOVE,
+       MOVE_TO_POSITION,
+};
+
+CombatState currentCombatState = TURN_ORDER;
+
+enum Spell {
+       BASIC_ATTACK
+};
+
+Spell currentSpell = BASIC_ATTACK;
+
+static double frameTimer = 0;
+static const double frameTime = 1.0f / 60.0f;
+
+//bool playerTurn = true;
+
+SDL_Texture* arrowSprite = nullptr;
+SDL_Texture* indicatorSprite = nullptr;
+SDL_Texture* indicatorRedSprite = nullptr;
+
+static constexpr int arenaWidth = 100;
+static constexpr int arenaHeight = 100;
+WorldCell** arena;
+WorldCell** fogLayer;
+S2DE::Camera combatCam = { 23.5, 11.5 };
+
+S2DE::Vec2<float> moveCursorPos;
+S2DE::Vec2<float> arenaCenter = { 23, 11 };
+
+//S2DE::Vec2<float>* currentMoveDest = &moveCursorPos;
+
+static const int numActions = 4;
+static const char* actions[numActions] = {"Move", "Attack", "End", "FLEE"};
+int currentAction = 0;
+
+SDL_Colour hpColour = { 136, 8, 8, 255 };
+SDL_Colour mpColour = { 0, 150, 255, 255 };
+
+void renderCombat();
+
+void renderUIFull();
+void renderActionsPanel();
+void renderCombatants();
+void renderStatsPanel();
+
+// lerp functions
+float interpolatePosition(S2DE::Vec2<float>* entityPos, S2DE::Vec2<float> destination, float t, float speed);
+void moveToPosition(Character* c, S2DE::Vec2<float> destination, float speed);
+
+void runStateFunction(CombatState state, double delta);
+void actionSelectState(double delta);
+void playerMoveActionState(double delta);
+void enemyMoveActionState(double delta);
+void movingCharacterState(double delta);
+void determineNextTurnState(double delta);
+void selectAttackTarget(double delta);
+void doAttack(double delta); // plays attack animation, resolves and applies damage.
+
+void runStateFunction(CombatState state, double delta) {
+       switch (state) {
+       case TURN_ORDER: determineNextTurnState(delta);         break;
+       case ACTION_SELECT: actionSelectState(delta);           break;
+       case PLAYER_MOVE: playerMoveActionState(delta);         break;
+       case SELECT_TARGET: selectAttackTarget(delta);          break;
+       case ENEMY_MOVE: enemyMoveActionState(delta);           break;
+       case MOVE_TO_POSITION: movingCharacterState(delta);     break;
+       case DO_ATTACK: doAttack(delta);                                        break;
+       default: assert(false); break;
+       }
+}
+
+float distance(S2DE::Vec2<float> p1, S2DE::Vec2<float> p2) {
+       return std::sqrt(std::pow(p2.x - p1.x, 2) + std::powf(p2.y - p1.y, 2));
+}
+
+void renderMeter(int x, int y, int width, int height, float percentage, SDL_Colour fillColour, int style) {
+       if (style == 1) {
+               SDL_SetRenderDrawColor(renderer, 0, 0, 0, 180);
+               SDL_Rect bgRect = { x, y, width, height };
+               SDL_RenderFillRect(renderer, &bgRect);
+       }
+       else if (style == 2) {
+               SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
+               SDL_RenderDrawLine(renderer, x, y, x + width, y);
+               SDL_RenderDrawLine(renderer, x, y + height, x + width, y + height);
+               
+               SDL_RenderDrawLine(renderer, x, y, x, y + height);
+               SDL_RenderDrawLine(renderer, x + width, y, x + width, y + height);
+       }
+
+       SDL_SetRenderDrawColor(renderer, fillColour.r, fillColour.g, fillColour.b, fillColour.a);
+       int panelWidth = width * percentage;
+       SDL_Rect fillRect = { x+1, y+1, panelWidth -1, height-1 };
+       SDL_RenderFillRect(renderer, &fillRect);
+}
+
+void renderStatsPanel() {
+       int panelWidth = 300;
+       int panelHeight = 200;
+       int outerPad = 2;
+       int innerPad = 16;
+
+       int panelX = WINDOW_WIDTH - panelWidth - outerPad;
+       int panelY = WINDOW_HEIGHT - panelHeight - outerPad;
+
+       renderBasicPanel(panelX, panelY, panelWidth, panelHeight);
+       renderString(panelX + innerPad, panelY + innerPad, activeCombatant->name.c_str());
+
+       int portraitWidth = 80;
+       int portraitHeight = 80;
+
+       int portraitX = panelX + 16;
+       int portraitY = panelY + 50;
+       renderBasicPanel(portraitX, portraitY, portraitWidth, portraitHeight);
+       SDL_Rect characterDRect = { portraitX + 8, portraitY + 8, portraitWidth - 16, portraitHeight - 16};
+       SDL_Rect characterSRect = { 0 , 0, 32, 32 };
+       SDL_Texture* portraitTexture = activeCombatant->texture;
+       S2DE::renderTexture(&renderer, &portraitTexture, &characterSRect, &characterDRect);
+
+
+       renderString(portraitX + portraitWidth + innerPad, portraitY, "HP:");
+       int valPad = 100;
+       char hpStr[10];
+       sprintf(hpStr, "%d/%d", activeCombatant->currentHP, activeCombatant->maxHP);
+       renderString(portraitX + portraitWidth + innerPad + valPad, portraitY, hpStr);
+
+       float hpLvl = (float)activeCombatant->currentHP / (float)activeCombatant->maxHP;
+       renderMeter(portraitX + portraitWidth + innerPad, portraitY + innerPad, panelWidth - (innerPad * 3) - portraitWidth, 20, hpLvl, hpColour, 2);
+
+       renderString(portraitX + portraitWidth + innerPad, portraitY + innerPad + 22, "MP:");
+
+       char mpStr[10];
+       sprintf(mpStr, "%d/%d", activeCombatant->currentMP, activeCombatant->maxMP);
+       renderString(portraitX + portraitWidth + innerPad + valPad, portraitY + innerPad + 22, mpStr);
+       
+       float mpLvl = (float)activeCombatant->currentMP / (float)activeCombatant->maxMP;
+       renderMeter(portraitX + portraitWidth + innerPad, portraitY + innerPad + 42, panelWidth - (innerPad * 3) - portraitWidth, 20, mpLvl, mpColour, 2);
+       
+}
+
+void renderActionsPanel() {
+       int panelWidth = 150;
+       int panelHeight = 150;
+
+       //int panelX = WINDOW_WIDTH / 2 - panelWidth / 2;
+       int panelX = 100;
+       int panelY = WINDOW_HEIGHT - panelHeight - 2;
+
+       renderBasicPanel(panelX, panelY, panelWidth, panelHeight);
+
+       int leftPad = 40;
+       int topPad = 20;
+       int itemSpacing = 30;
+
+       for (int i = 0; i < numActions; ++i) {
+               // a bit of a brittle way of doing this
+               if (i == 0 && !activeCombatant->canMove) {
+                       renderString(panelX + leftPad, panelY + topPad + itemSpacing * i, actions[i], font_grey);
+               }
+               else if (i == 1 && !activeCombatant->canAttack) {
+                       renderString(panelX + leftPad, panelY + topPad + itemSpacing * i, actions[i], font_grey);
+               }
+               else {
+                       renderString(panelX + leftPad, panelY + topPad + itemSpacing * i, actions[i]);
+               }
+       }
+
+       renderString(panelX + 20, panelY + topPad + (itemSpacing * currentAction), ">");
+}
+
+void renderUIFull() {
+       renderActionsPanel();
+       renderStatsPanel();
+}
+
+void renderCombat() {
+       renderTilemap(arena, arenaWidth, arenaHeight, combatCam);
+       renderCombatants();
+       renderTilemap(fogLayer, arenaWidth, arenaHeight, combatCam); // render the fog layer
+}
+
+void renderCombatants() {
+
+       for (Character c : combatants) {
+
+               if (c.alive) {
+                       S2DE::Vec2<float> pos = c.position;
+                       S2DE::Rect charDRect = S2DE::worldToScreenRect(&combatCam, &pos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32);
+                       S2DE::Rect charSRect = { 0, 0, 32, 32 };
+
+                       // disabled for now
+                       //if (c.allied) {
+                       //      // do the looking logic only for allied characters
+                       //      int playerFrame = 1;
+                       //      int playerDir = 0;
+
+                       //      Character enemy = combatants.at(1);
+
+                       //      int lookDeltaX = (enemy.position.x + 0.5) - (c.position.x + 0.5);
+                       //      int lookDeltaY = (enemy.position.y + 0.5) - (c.position.y + 0.5);
+
+                       //      if (abs(lookDeltaX) > abs(lookDeltaY)) {
+                       //              if (lookDeltaX > 0) playerDir = 2;
+                       //              else playerDir = 6;
+                       //      }
+                       //      else {
+                       //              if (lookDeltaY > 0) playerDir = 4;
+                       //              else playerDir = 0;
+                       //      }
+
+                       //      charSRect = { playerFrame * 32, playerDir * 32, 32, 32 };
+                       //}
+
+                       SDL_Texture* texture = c.texture;
+                       S2DE::renderTexture(&renderer, &texture, &charSRect, &charDRect);
+
+                       float hpLvl = (float)c.currentHP / (float)c.maxHP;
+                       renderMeter(charDRect.x + 6, charDRect.y - 6, charDRect.w - 12, 6, hpLvl, hpColour, 1);
+               }
+       }
+
+       // render the little arrow
+       S2DE::Vec2<float> arrowPos = activeCombatant->position;
+               
+       arrowPos.y -= 0.7;
+       S2DE::Rect arrowDRect = S2DE::worldToScreenRect(&combatCam, &arrowPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32);
+       S2DE::renderTexture(&renderer, &indicatorSprite, NULL, &arrowDRect);
+}
+
+void initCombatScene()
+{
+       // I think all resources should be initialized and cleaned up in the globals tbh
+       arena = new WorldCell * [arenaHeight];
+       for (int i = 0; i < arenaHeight; ++i) arena[i] = new WorldCell[arenaWidth];
+       
+       fogLayer = new WorldCell * [arenaHeight];
+       for (int i = 0; i < arenaHeight; ++i) fogLayer[i] = new WorldCell[arenaWidth];
+
+       loadWorld("maps/combat_arena_1.tmj", arena, arenaWidth, arenaHeight);
+       loadWorld("maps/combat_arena_1_fog.tmj", fogLayer, arenaWidth, arenaHeight);
+
+       arrowSprite = S2DE::loadTexture("assets/arrow.png", &renderer);
+       indicatorSprite = S2DE::loadTexture("assets/little_indicator.png", &renderer);
+       indicatorRedSprite = S2DE::loadTexture("assets/little_indicator_red.png", &renderer);
+
+       //Character player = { true, "Player", 100, 100, 50, 50, 10.0f, 3.0f, player_sheet, { 23.0f, 13.0f } };
+       Character player;
+       player.allied = true;
+       player.name = "Player";
+       player.maxHP = 100;
+       player.currentHP = player.maxHP;
+       player.maxMP = 50;
+       player.currentMP = player.maxMP;
+       player.agility = 10.0f;
+       player.moveDist = 3.0f;
+       player.texture = player_forward_texture;
+       player.position = { arenaCenter.x, arenaCenter.y + 2 };
+       player.attack = 5;
+
+
+       Character monica;
+       monica.allied = true;
+       monica.name = "Monica";
+       monica.maxHP = 100;
+       monica.currentHP = monica.maxHP;
+       monica.maxMP = 50;
+       monica.currentMP = monica.maxMP;
+       monica.agility = 8.0f;
+       monica.moveDist = 6.0f;
+       monica.texture = monica_texture;
+       monica.position = { player.position.x - 2, player.position.y };
+       monica.attack = 6;
+
+       Character enemy;
+       enemy.allied = false;
+       enemy.name = "Bird";
+       enemy.maxHP = 25;
+       enemy.currentHP = enemy.maxHP;
+       enemy.maxMP = 10;
+       enemy.currentMP = enemy.maxMP;
+       enemy.agility = 5.0f;
+       enemy.moveDist = 1.5f;
+       enemy.texture = bird;
+       enemy.position = { arenaCenter.x, arenaCenter.y - 2 };
+       enemy.attack = 2;
+
+       Character frog;
+       frog.allied = false;
+       frog.name = "Frog";
+       frog.currentHP = frog.maxHP = 10;
+       frog.currentMP = frog.maxMP = 10;
+       frog.agility = 2;
+       frog.moveDist = 2.0f;
+       frog.texture = frog_texture;
+       frog.position = { arenaCenter.x - 1, arenaCenter.y - 2 };
+       frog.attack = 2;
+
+       combatants.push_back(player);
+       combatants.push_back(monica);
+       combatants.push_back(enemy);
+       combatants.push_back(frog);
+
+
+       // calculates turn order. Can expand the lambda to support other things
+       std::sort(combatants.begin(), combatants.end(), [](const Character& a, const Character& b) {return a.agility > b.agility; });
+
+       activeCombatant = &combatants.at(0);
+       moveCursorPos = activeCombatant->position;
+}
+
+
+void interpolatePosition(S2DE::Vec2<float>* entityPos, S2DE::Vec2<float> destination, float* t, float speed) {
+       *t += speed;
+
+       entityPos->x = (1.0f - *t) * entityPos->x + *t * destination.x;
+       entityPos->y = (1.0f - *t) * entityPos->y + *t * destination.y;
+}
+
+void moveToPosition(Character* c, S2DE::Vec2<float> destination, float speed) {
+       float dist = distance(c->position, destination);
+
+       S2DE::Vec2<float> direction {destination.x - c->position.x, destination.y - c->position.y};
+
+       direction.x /= dist;
+       direction.y /= dist;
+
+       if (dist <= speed) {
+               c->position.x = destination.x;
+               c->position.y = destination.y;
+       }
+       else {
+               c->position.x += direction.x * speed;
+               c->position.y += direction.y * speed;
+       }
+}
+
+void actionSelectState(double delta) {
+       S2DE::updateInputState(&inputState);
+
+       // handle inputs
+       if (inputState.up) {
+               inputState.up = false;
+               currentAction--;
+               if (currentAction < 0) currentAction = numActions - 1;
+       }
+       else if (inputState.down) {
+               inputState.down = false;
+               currentAction++;
+               if (currentAction > numActions - 1) currentAction = 0;
+       }
+       else if (inputState.rtrn) {
+               inputState.rtrn = false;
+               switch (currentAction) {
+               case 0:
+                       if (activeCombatant->canMove) {
+                               currentCombatState = PLAYER_MOVE;
+                               moveCursorPos = activeCombatant->position;
+                       }
+                       break;
+               case 1: // attack selected
+                       if (activeCombatant->canAttack) {
+                               // filter the targets - Have to do it here too in case the player attacks without moving?
+                               targets.clear();
+                               for (auto& c : combatants) {
+                                       if (!c.allied && c.alive) {
+                                               float dist = distance(activeCombatant->position, c.position);
+                                               if (dist <= activeCombatant->basicAttackRange) {
+                                                       targets.push_back(&c);
+                                               }
+                                       }
+                               }
+
+                               currentCombatState = SELECT_TARGET;
+                       }
+                       break;
+               case 2: // end selected
+                       currentCombatState = TURN_ORDER;
+                       break;
+
+               default:
+                       inputState.quit = true;
+                       break;
+               }
+       }
+
+       SDL_RenderClear(renderer);
+       renderCombat();
+       renderUIFull();
+       SDL_RenderPresent(renderer);
+}
+
+void playerMoveActionState(double delta) {
+       S2DE::updateInputState(&inputState);
+
+       frameTimer += delta;
+       
+       Character player = *activeCombatant;
+
+       if (frameTimer > frameTime) {
+
+               frameTimer = 0;
+
+               float cursorSpeed = 0.05;
+
+               S2DE::Vec2<float> newCursorPos = moveCursorPos;
+
+               float newY = moveCursorPos.y;
+               float newX = moveCursorPos.x;
+
+               if (inputState.right) {
+                       newX += cursorSpeed;
+               }
+               if (inputState.left) {
+                       newX -= cursorSpeed;
+               }
+               if (inputState.up) {
+                       newY -= cursorSpeed;
+               }
+               if (inputState.down) {
+                       newY += cursorSpeed;
+               }
+
+               if (inputState.rtrn) {
+                       inputState.rtrn = false;
+
+                       activeCombatant->combatMoveDestination = moveCursorPos;
+                       currentCombatState = MOVE_TO_POSITION;
+               }
+
+               if (distance({ moveCursorPos.x, newY }, player.position) <= player.moveDist
+                       && checkCollisionPoint({ moveCursorPos.x + 0.5f, newY + 0.5f }, arena) == false) {
+                       moveCursorPos.y = newY;
+               }
+               if (distance({ newX, moveCursorPos.y }, player.position) <= player.moveDist
+                       && checkCollisionPoint({ newX + 0.5f, moveCursorPos.y + 0.5f }, arena) == false) {
+                       moveCursorPos.x = newX;
+               }
+
+       }
+
+
+       // compute characters in melee range
+       targets.clear();
+       for (auto& c : combatants) {
+               if (!c.allied && c.alive) {
+                       float dist = distance(moveCursorPos, c.position);
+                       if (dist <= activeCombatant->basicAttackRange) {
+                               targets.push_back(&c);
+                       }
+               }
+       }
+
+
+       SDL_RenderClear(renderer);
+
+       renderTilemap(arena, arenaWidth, arenaHeight, combatCam);
+
+       
+       S2DE::Vec2<float> playerCenterWorld = { player.position.x + 0.5, player.position.y + 0.5 };
+       S2DE::Vec2<int> playerCenterScreen = S2DE::worldToScreenPoint(&combatCam, &playerCenterWorld, 64, WINDOW_WIDTH, WINDOW_HEIGHT);
+
+       S2DE::renderCircle(&renderer, playerCenterScreen, (player.moveDist) * 64, { 0, 255, 255, 125 });
+
+
+       S2DE::Vec2<float> lineEndWorld = { moveCursorPos.x + 0.5, moveCursorPos.y + 0.5 };
+       S2DE::Vec2<int> lineEndPos = S2DE::worldToScreenPoint(&combatCam, &lineEndWorld, 64, WINDOW_WIDTH, WINDOW_HEIGHT);
+
+       SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
+       SDL_RenderDrawLine(renderer, playerCenterScreen.x, playerCenterScreen.y, lineEndPos.x, lineEndPos.y);
+
+       // render lines to targets in range
+       SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
+       for (auto t : targets) {
+               S2DE::Vec2<float> targetCenter = { t->position.x + 0.5, t->position.y + 0.5 };
+               S2DE::Vec2<int> targetCenterScreen = S2DE::worldToScreenPoint(&combatCam, &targetCenter, 64, WINDOW_WIDTH, WINDOW_HEIGHT);
+               SDL_RenderDrawLine(renderer, lineEndPos.x, lineEndPos.y, targetCenterScreen.x, targetCenterScreen.y);
+       }
+
+
+       renderCombatants();
+
+       S2DE::Rect cursorDRect = S2DE::worldToScreenRect(&combatCam, &moveCursorPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32);
+       S2DE::renderTexture(&renderer, &arrowSprite, NULL, &cursorDRect);
+
+       renderTilemap(fogLayer, arenaWidth, arenaHeight, combatCam); // draw the fog layer
+
+       renderActionsPanel();
+       renderStatsPanel();
+       SDL_RenderPresent(renderer);
+}
+
+void selectAttackTarget(double delta) {
+       S2DE::updateInputState(&inputState);
+
+       frameTimer += delta;
+
+       if (frameTimer > frameTime) {
+               frameTimer = 0;
+               if (inputState.rtrn) {
+                       inputState.rtrn = false;
+                       if (targets.size() > 0) {
+                               currentSpell = BASIC_ATTACK;
+                               currentCombatState = DO_ATTACK;
+                       }
+                       else {
+                               currentCombatState = ACTION_SELECT;
+                       }
+
+               }
+
+               if (inputState.right) {
+                       // cycle up through targets
+                       inputState.right = false; // gotta find a better way to do this
+
+                       currentTargetIdx += 1;
+                       if (currentTargetIdx > targets.size() - 1) currentTargetIdx = 0;
+               }
+               else if (inputState.left) {
+                       inputState.left = false;
+                       // cycle "down"through targets
+                       currentTargetIdx -= 1;
+                       if (currentTargetIdx < 0) currentTargetIdx = targets.size() - 1;
+               }
+       }
+
+       SDL_RenderClear(renderer);
+       
+
+       renderTilemap(arena, arenaWidth, arenaHeight, combatCam);
+
+       renderCombatants();
+
+       // render the little red arrow above all valid targets
+       if (targets.size() > 0) {
+               S2DE::Vec2<float> arrowPos = targets.at(currentTargetIdx)->position;
+
+               arrowPos.y -= 0.7;
+               S2DE::Rect arrowDRect = S2DE::worldToScreenRect(&combatCam, &arrowPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32);
+               S2DE::renderTexture(&renderer, &indicatorRedSprite, NULL, &arrowDRect);
+       }
+       
+
+       renderTilemap(fogLayer, arenaWidth, arenaHeight, combatCam); // draw the fog layer
+
+
+
+       renderUIFull();
+       renderString(10, 10, "SELECT TARGET STATE", debug_font);
+
+
+       if (targets.size() == 0) {
+               renderString(10, 64, "NO TARGETS IN RANGE", debug_font);
+       }
+       else {
+               int num_targets = targets.size();
+               char str[22];
+               sprintf(str, "AVAILABLE_TARGETS: %i", num_targets);
+               renderString(10, 64, str, debug_font);
+       }
+
+       SDL_RenderPresent(renderer);
+
+}
+
+void doAttack(double delta) {
+       // for now just subtract the combatants' dmg from the targets hp and move on
+       
+
+       if (currentTargetIdx == -1) {
+               // AOE, apply to all targets in range ?
+       }
+       else {
+               Character* target = targets.at(currentTargetIdx);
+               target->currentHP -= activeCombatant->attack;
+
+               if (target->currentHP <= 0) {
+                       target->alive = false;
+                       target->currentHP = 0;
+               }
+       }
+
+
+
+       targets.clear();
+       currentCombatState = ACTION_SELECT;
+       activeCombatant->canAttack = false;
+}
+
+
+void enemyMoveActionState(double delta) {
+       S2DE::updateInputState(&inputState);
+
+       Character enemy = *activeCombatant;
+
+       // implicitly grabs the character with the highest agility for now
+       Character agro = *std::find_if(combatants.begin(), combatants.end(), [](const Character& c) {return c.allied; });
+
+       S2DE::Vec2<float> dirToAgro = { agro.position.x - enemy.position.x, agro.position.y - enemy.position.y };
+       float distToAgro = distance(enemy.position, agro.position);
+
+       dirToAgro.x /= distToAgro;
+       dirToAgro.y /= distToAgro;
+
+       S2DE::Vec2<float> movePos = { enemy.position.x + dirToAgro.x * enemy.moveDist, enemy.position.y + dirToAgro.y * enemy.moveDist};
+
+       activeCombatant->combatMoveDestination = movePos;
+       currentCombatState = MOVE_TO_POSITION;
+}
+
+void movingCharacterState(double delta) {
+       S2DE::updateInputState(&inputState);
+
+       frameTimer += delta;
+
+       if (frameTimer > frameTime) {
+               frameTimer = 0;
+
+               static float speed = 0.05f;
+
+               if (inputState.rtrn) {
+                       // skip
+                       inputState.rtrn = false;
+                       activeCombatant->position = activeCombatant->combatMoveDestination;
+               }
+
+               moveToPosition(activeCombatant, activeCombatant->combatMoveDestination, speed);
+
+               if (activeCombatant->position.x == activeCombatant->combatMoveDestination.x && activeCombatant->position.y == activeCombatant->combatMoveDestination.y) {
+                       // move completed. if allied, return to select action
+                       if (activeCombatant->allied) {
+                               activeCombatant->canMove = false; // TODO: support characters that can move twice?
+                               currentCombatState = ACTION_SELECT;
+                       }
+                       else {
+                               currentCombatState = TURN_ORDER;
+                       }
+               }
+
+               // TODO: Ensure all rendering is happening at the same FPS
+               SDL_RenderClear(renderer);
+               renderCombat();
+               // dont show the ui in this state
+               SDL_RenderPresent(renderer);
+       }
+
+}
+
+
+void determineNextTurnState(double delta) {
+
+       currentCombatantIndex += 1;
+
+       // WARNING: this system does not support the case where agility changes mid-fight. will need to re-sort if that happens
+       if (currentCombatantIndex > combatants.size() - 1) currentCombatantIndex = 0;
+
+       activeCombatant = &combatants.at(currentCombatantIndex);
+
+       if (activeCombatant->alive) { // skip dead characters
+               if (activeCombatant->allied) {
+                       // reset combatants actions
+                       activeCombatant->canAttack = true;
+                       activeCombatant->canMove = true;
+                       currentAction = 0;
+                       currentCombatState = ACTION_SELECT;
+               }
+               else {
+                       //currentCombatState = ENEMY_MOVE;
+               }
+       }
+
+}
+
+
+void runCombat(double delta) {
+       
+       static double frameTimer = 0;
+       static const double frameTime = 1.0f / 60.0f;
+
+       runStateFunction(currentCombatState, delta);
+
 }
\ No newline at end of file
index 71bd349..613bd3e 100644 (file)
--- a/combat.h
+++ b/combat.h
@@ -1,5 +1,5 @@
-#pragma once\r
-\r
-void initCombatScene();\r
-\r
+#pragma once
+
+void initCombatScene();
+
 void runCombat(double deltaTime);
\ No newline at end of file
index e3db2d1..7689f2f 100644 (file)
@@ -1,41 +1,41 @@
-#include "globals.h"\r
-\r
-SDL_Texture* environment_sheet = nullptr;\r
-SDL_Texture* player_sheet = nullptr;\r
-SDL_Texture* water_test_sheet = nullptr;\r
-SDL_Texture* font_sheet = nullptr;\r
-SDL_Texture* debug_font = nullptr;\r
-SDL_Texture* font_grey = nullptr;\r
-SDL_Texture* ui_frame_sheet = nullptr;\r
-SDL_Texture* bird = nullptr;\r
-SDL_Texture* monica_texture = nullptr;\r
-SDL_Texture* player_forward_texture = nullptr;\r
-SDL_Texture* frog_texture = nullptr;\r
-Mix_Music* background_music = nullptr;\r
-\r
-\r
-static const char* environment_sheet_path = "assets/dragon_survivors_environment_1.png";\r
-static const char* player_sheet_path = "assets/player.png";\r
-static const char* water_test_sheet_path = "assets/water_test.png";\r
-static const char* font_sheet_path = "assets/simple_6x8_black.png";\r
-static const char* ui_frame_sheet_path = "assets/frame.png";\r
-static const char* bird_path = "assets/bird_32.png";\r
-static const char* bg_mus_path = "assets/TownTheme.mp3";\r
-\r
-void initResources()\r
-{\r
-       environment_sheet = S2DE::loadTexture(environment_sheet_path, &renderer);\r
-       player_sheet = S2DE::loadTexture(player_sheet_path, &renderer);\r
-       water_test_sheet = S2DE::loadTexture(water_test_sheet_path, &renderer);\r
-       font_sheet = S2DE::loadTexture(font_sheet_path, &renderer);\r
-       debug_font = S2DE::loadTexture("assets/simple_6x8_red.png", &renderer);\r
-       font_grey = S2DE::loadTexture("assets/simple_6x8_grey.png", &renderer);\r
-       ui_frame_sheet = S2DE::loadTexture(ui_frame_sheet_path, &renderer);\r
-       bird = S2DE::loadTexture(bird_path, &renderer);\r
-\r
-       monica_texture = S2DE::loadTexture("assets/Monica_sprite.png", &renderer);\r
-       player_forward_texture = S2DE::loadTexture("assets/player_forward.png", &renderer);\r
-       frog_texture = S2DE::loadTexture("assets/Frog_sprite.png", &renderer);\r
-       background_music = Mix_LoadMUS(bg_mus_path);\r
-}\r
-\r
+#include "globals.h"
+
+SDL_Texture* environment_sheet = nullptr;
+SDL_Texture* player_sheet = nullptr;
+SDL_Texture* water_test_sheet = nullptr;
+SDL_Texture* font_sheet = nullptr;
+SDL_Texture* debug_font = nullptr;
+SDL_Texture* font_grey = nullptr;
+SDL_Texture* ui_frame_sheet = nullptr;
+SDL_Texture* bird = nullptr;
+SDL_Texture* monica_texture = nullptr;
+SDL_Texture* player_forward_texture = nullptr;
+SDL_Texture* frog_texture = nullptr;
+Mix_Music* background_music = nullptr;
+
+
+static const char* environment_sheet_path = "assets/dragon_survivors_environment_1.png";
+static const char* player_sheet_path = "assets/player.png";
+static const char* water_test_sheet_path = "assets/water_test.png";
+static const char* font_sheet_path = "assets/simple_6x8_black.png";
+static const char* ui_frame_sheet_path = "assets/frame.png";
+static const char* bird_path = "assets/bird_32.png";
+static const char* bg_mus_path = "assets/TownTheme.mp3";
+
+void initResources()
+{
+       environment_sheet = S2DE::loadTexture(environment_sheet_path, &renderer);
+       player_sheet = S2DE::loadTexture(player_sheet_path, &renderer);
+       water_test_sheet = S2DE::loadTexture(water_test_sheet_path, &renderer);
+       font_sheet = S2DE::loadTexture(font_sheet_path, &renderer);
+       debug_font = S2DE::loadTexture("assets/simple_6x8_red.png", &renderer);
+       font_grey = S2DE::loadTexture("assets/simple_6x8_grey.png", &renderer);
+       ui_frame_sheet = S2DE::loadTexture(ui_frame_sheet_path, &renderer);
+       bird = S2DE::loadTexture(bird_path, &renderer);
+
+       monica_texture = S2DE::loadTexture("assets/Monica_sprite.png", &renderer);
+       player_forward_texture = S2DE::loadTexture("assets/player_forward.png", &renderer);
+       frog_texture = S2DE::loadTexture("assets/Frog_sprite.png", &renderer);
+       background_music = Mix_LoadMUS(bg_mus_path);
+}
+
index 9d25677..4d743e9 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -1,57 +1,57 @@
-#pragma once\r
-\r
-#include <SDL.h>\r
-#include <SDL_image.h>\r
-#include <SDL_mixer.h>\r
-#include <2DEngine.h>\r
-\r
-\r
-#define WINDOW_WIDTH 1280\r
-#define WINDOW_HEIGHT 720\r
-\r
-extern SDL_Window* window;\r
-extern SDL_Renderer* renderer;\r
-\r
-\r
-// maybe a resources.h? \r
-extern SDL_Texture* environment_sheet;\r
-extern SDL_Texture* player_sheet;\r
-extern SDL_Texture* water_test_sheet;\r
-extern SDL_Texture* font_sheet;\r
-extern SDL_Texture* debug_font;\r
-extern SDL_Texture* font_grey;\r
-extern SDL_Texture* ui_frame_sheet;\r
-extern SDL_Texture* bird;\r
-extern SDL_Texture* monica_texture;\r
-extern SDL_Texture* player_forward_texture;\r
-extern SDL_Texture* frog_texture;\r
-\r
-extern Mix_Music* background_music;\r
-\r
-void initResources();\r
-\r
-extern S2DE::InputState inputState;\r
-\r
-// These things should be defined in the overworld\r
-extern S2DE::Vec2<float> playerPos;\r
-extern int playerFrame;\r
-extern int playerDir;\r
-\r
-extern S2DE::Vec2<float> birdPos;\r
-extern bool enemyDirection; // 0 = left, 1 = right\r
-\r
-#define WORLD_HEIGHT 200\r
-#define WORLD_WIDTH 200\r
-\r
-//extern WorldCell world[WORLD_HEIGHT][WORLD_WIDTH];\r
-\r
-extern S2DE::Camera camera;\r
-\r
-enum GameState\r
-{\r
-       MAIN_MENU,\r
-       OVERWORLD,\r
-       COMBAT\r
-};\r
-\r
+#pragma once
+
+#include <SDL.h>
+#include <SDL_image.h>
+#include <SDL_mixer.h>
+#include <2DEngine.h>
+
+
+#define WINDOW_WIDTH 1280
+#define WINDOW_HEIGHT 720
+
+extern SDL_Window* window;
+extern SDL_Renderer* renderer;
+
+
+// maybe a resources.h? 
+extern SDL_Texture* environment_sheet;
+extern SDL_Texture* player_sheet;
+extern SDL_Texture* water_test_sheet;
+extern SDL_Texture* font_sheet;
+extern SDL_Texture* debug_font;
+extern SDL_Texture* font_grey;
+extern SDL_Texture* ui_frame_sheet;
+extern SDL_Texture* bird;
+extern SDL_Texture* monica_texture;
+extern SDL_Texture* player_forward_texture;
+extern SDL_Texture* frog_texture;
+
+extern Mix_Music* background_music;
+
+void initResources();
+
+extern S2DE::InputState inputState;
+
+// These things should be defined in the overworld
+extern S2DE::Vec2<float> playerPos;
+extern int playerFrame;
+extern int playerDir;
+
+extern S2DE::Vec2<float> birdPos;
+extern bool enemyDirection; // 0 = left, 1 = right
+
+#define WORLD_HEIGHT 200
+#define WORLD_WIDTH 200
+
+//extern WorldCell world[WORLD_HEIGHT][WORLD_WIDTH];
+
+extern S2DE::Camera camera;
+
+enum GameState
+{
+       MAIN_MENU,
+       OVERWORLD,
+       COMBAT
+};
+
 extern GameState gameState;
\ No newline at end of file
index fe47b97..a86bab2 100644 (file)
--- a/main.cpp
+++ b/main.cpp
-#include <iostream>\r
-#include <fstream>\r
-#include <SDL.h>\r
-#include <SDL_image.h>\r
-#include <SDL_mixer.h>\r
-#include <nlohmann/json.hpp>\r
-\r
-#include <2DEngine.h>\r
-\r
-#include "globals.h"\r
-#include "main_menu.h"\r
-#include "combat.h"\r
-#include "tilemap.h"\r
-\r
-GameState gameState = MAIN_MENU;\r
-//GameState gameState = COMBAT;\r
-\r
-using json = nlohmann::json;\r
-\r
-SDL_Window* window = nullptr;\r
-SDL_Renderer* renderer = nullptr;\r
-\r
-S2DE::InputState inputState;\r
-\r
-\r
-WorldCell** world;\r
-\r
-S2DE::Camera camera;\r
-\r
-// These things should be defined in the overworld\r
-S2DE::Vec2<float> playerPos = { 30, 19 };\r
-int playerFrame = 0;\r
-int playerDir = 4;\r
-\r
-S2DE::Vec2<float> birdPos = { 31, 16 };\r
-bool enemyDirection = 0; // 0 = left, 1 = right\r
-\r
-//void loadWorld(const char* worldPath, WorldCell world[WORLD_HEIGHT][WORLD_WIDTH]);\r
-\r
-//S2DE::Rect renderString(int startX, int startY, const char* string);\r
-void renderWorld();\r
-//void renderUI();\r
-\r
-//bool checkCollision(S2DE::Vec2<float> worldPos);\r
-\r
-\r
-void renderWorld()\r
-{\r
-\r
-       // render enemy\r
-\r
-       S2DE::Rect enemyDRect = S2DE::worldToScreenRect(&camera, &birdPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32);\r
-       S2DE::Rect enemySRect = { 0, 32 * enemyDirection, 32, 32 };\r
-       S2DE::renderTexture(&renderer, &bird, &enemySRect, &enemyDRect);\r
-\r
-\r
-       // render player\r
-\r
-       S2DE::Rect playerDRect = S2DE::worldToScreenRect(&camera, &playerPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32);\r
-\r
-       S2DE::Rect playerSRect = { playerFrame * 32, playerDir * 32, 32, 32 };\r
-       S2DE::renderTexture(&renderer, &player_sheet, &playerSRect, &playerDRect);\r
-\r
-}\r
-\r
-int main(int argc, char** args)\r
-{\r
-       S2DE::initRendering("Dragon Survivors", WINDOW_WIDTH, WINDOW_HEIGHT, &window, &renderer);\r
-       initResources();\r
-       initCombatScene();\r
-\r
-       world = new WorldCell * [WORLD_HEIGHT];\r
-       for (int i = 0; i < WORLD_HEIGHT; ++i) world[i] = new WorldCell[WORLD_WIDTH];\r
-\r
-       loadWorld("maps/overworld_1.tmj", world, WORLD_WIDTH, WORLD_HEIGHT);\r
-\r
-       bool running = true;\r
-\r
-       double currentTime = 0.0;\r
-       double last = 0.0;\r
-       double delta = 0.0;\r
-\r
-       double frameCounter = 0;\r
-       double frameTime = 1.0 / 60; // 60 hrz\r
-\r
-       double animCounter = 0;\r
-       double animTime = 1.0 / 3;\r
-\r
-\r
-       double enemyWalkTime = 0.5; // walks each dir for 2 seconds\r
-       double enemyWalkTimer = 0;\r
-       \r
-\r
-       Mix_VolumeMusic(MIX_MAX_VOLUME / 4);\r
-       //Mix_PlayMusic(background_music, -1);\r
-\r
-       while (inputState.quit != true)\r
-       {\r
-               currentTime = SDL_GetTicks();\r
-               delta = (currentTime - last) / 1000.0f;\r
-               last = currentTime;\r
-\r
-               if (gameState == MAIN_MENU)\r
-               {\r
-                       mainMenu(delta);        \r
-               }\r
-               else if (gameState == OVERWORLD)\r
-               {\r
-\r
-                       frameCounter += delta;\r
-                       animCounter += delta;\r
-\r
-                       enemyWalkTimer += delta;\r
-\r
-                       S2DE::updateInputState(&inputState);\r
-\r
-                       if (frameCounter > frameTime)\r
-                       {\r
-                               frameCounter = 0;\r
-\r
-                               // update player\r
-                               float walkSpeed = 0.08;\r
-\r
-                               float newX = playerPos.x;\r
-                               float newY = playerPos.y;\r
-                               float finalX = newX;\r
-                               float finalY = newY;\r
-\r
-                               if (inputState.right) {\r
-                                       newX += walkSpeed;\r
-                                       playerDir = 2;\r
-                               }\r
-                               if (inputState.left) {\r
-                                       newX -= walkSpeed;\r
-                                       playerDir = 6;\r
-                               }\r
-                               if (inputState.up) {\r
-                                       newY -= walkSpeed;\r
-                                       playerDir = 0;\r
-                               }\r
-                               if (inputState.down) {\r
-                                       newY += walkSpeed;\r
-                                       playerDir = 4;\r
-                               }\r
-\r
-                               if (!checkCollisionRect({ playerPos.x, newY }, world))\r
-                               {\r
-                                       // can move on the y\r
-                                       finalY = newY;\r
-                               }\r
-\r
-                               if (!checkCollisionRect({ newX, playerPos.y }, world))\r
-                               {\r
-                                       // can move on the X\r
-                                       finalX = newX;\r
-                               }\r
-\r
-                               playerPos.x = finalX;\r
-                               playerPos.y = finalY;\r
-\r
-                               camera = playerPos;\r
-\r
-                               if (enemyWalkTimer > enemyWalkTime)\r
-                               {\r
-                                       // flip the direction and reset the timer\r
-                                       enemyDirection = !enemyDirection;\r
-                                       enemyWalkTimer = 0;\r
-                               }\r
-\r
-                               float enemyWalkSpeed = 0.04;\r
-                               if (enemyDirection) // true == 1 == going right\r
-                               {\r
-                                       birdPos.x += enemyWalkSpeed;\r
-                               }\r
-                               else // going left\r
-                               {\r
-                                       birdPos.x -= enemyWalkSpeed;\r
-                               }\r
-\r
-                       }\r
-                       \r
-\r
-                       static bool forward = true;\r
-                       if (animCounter >= animTime)\r
-                       {\r
-                               animCounter = 0;\r
-\r
-                               if (forward)\r
-                               {\r
-                                       playerFrame += 1;\r
-                                       if (playerFrame >= 2)\r
-                                       {\r
-                                               forward = false;\r
-                                       }\r
-                               }\r
-                               else\r
-                               {\r
-                                       playerFrame -= 1;\r
-                                       if (playerFrame <= 0)\r
-                                       {\r
-                                               forward = true;\r
-                                       }\r
-                               }\r
-                       }\r
-\r
-                       SDL_RenderClear(renderer);\r
-                       {\r
-                               renderTilemap(world, WORLD_WIDTH, WORLD_HEIGHT, camera);\r
-                               renderWorld();\r
-                       }\r
-                       SDL_RenderPresent(renderer);\r
-               }\r
-               else if (gameState == COMBAT) {\r
-                       runCombat(delta);\r
-               }\r
-       }\r
-\r
-\r
-       for (int i = 0; i < WORLD_HEIGHT; ++i) delete[] world[i];\r
-       delete[] world;\r
-\r
-       S2DE::quitRendering(&renderer, &window);\r
-       Mix_Quit();\r
-\r
-       SDL_DestroyTexture(environment_sheet);\r
-       // destroy the other shit here\r
-       // add mix_quit to dll\r
-       return 0;\r
+#include <iostream>
+#include <fstream>
+#include <SDL.h>
+#include <SDL_image.h>
+#include <SDL_mixer.h>
+#include <nlohmann/json.hpp>
+
+#include <2DEngine.h>
+
+#include "globals.h"
+#include "main_menu.h"
+#include "combat.h"
+#include "tilemap.h"
+
+GameState gameState = MAIN_MENU;
+//GameState gameState = COMBAT;
+
+using json = nlohmann::json;
+
+SDL_Window* window = nullptr;
+SDL_Renderer* renderer = nullptr;
+
+S2DE::InputState inputState;
+
+
+WorldCell** world;
+
+S2DE::Camera camera;
+
+// These things should be defined in the overworld
+S2DE::Vec2<float> playerPos = { 30, 19 };
+int playerFrame = 0;
+int playerDir = 4;
+
+S2DE::Vec2<float> birdPos = { 31, 16 };
+bool enemyDirection = 0; // 0 = left, 1 = right
+
+//void loadWorld(const char* worldPath, WorldCell world[WORLD_HEIGHT][WORLD_WIDTH]);
+
+//S2DE::Rect renderString(int startX, int startY, const char* string);
+void renderWorld();
+//void renderUI();
+
+//bool checkCollision(S2DE::Vec2<float> worldPos);
+
+
+void renderWorld()
+{
+
+       // render enemy
+
+       S2DE::Rect enemyDRect = S2DE::worldToScreenRect(&camera, &birdPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32);
+       S2DE::Rect enemySRect = { 0, 32 * enemyDirection, 32, 32 };
+       S2DE::renderTexture(&renderer, &bird, &enemySRect, &enemyDRect);
+
+
+       // render player
+
+       S2DE::Rect playerDRect = S2DE::worldToScreenRect(&camera, &playerPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32);
+
+       S2DE::Rect playerSRect = { playerFrame * 32, playerDir * 32, 32, 32 };
+       S2DE::renderTexture(&renderer, &player_sheet, &playerSRect, &playerDRect);
+
+}
+
+int main(int argc, char** args)
+{
+       S2DE::initRendering("Dragon Survivors", WINDOW_WIDTH, WINDOW_HEIGHT, &window, &renderer);
+       initResources();
+       initCombatScene();
+
+       world = new WorldCell * [WORLD_HEIGHT];
+       for (int i = 0; i < WORLD_HEIGHT; ++i) world[i] = new WorldCell[WORLD_WIDTH];
+
+       loadWorld("maps/overworld_1.tmj", world, WORLD_WIDTH, WORLD_HEIGHT);
+
+       bool running = true;
+
+       double currentTime = 0.0;
+       double last = 0.0;
+       double delta = 0.0;
+
+       double frameCounter = 0;
+       double frameTime = 1.0 / 60; // 60 hrz
+
+       double animCounter = 0;
+       double animTime = 1.0 / 3;
+
+
+       double enemyWalkTime = 0.5; // walks each dir for 2 seconds
+       double enemyWalkTimer = 0;
+       
+
+       Mix_VolumeMusic(MIX_MAX_VOLUME / 4);
+       //Mix_PlayMusic(background_music, -1);
+
+       while (inputState.quit != true)
+       {
+               currentTime = SDL_GetTicks();
+               delta = (currentTime - last) / 1000.0f;
+               last = currentTime;
+
+               if (gameState == MAIN_MENU)
+               {
+                       mainMenu(delta);        
+               }
+               else if (gameState == OVERWORLD)
+               {
+
+                       frameCounter += delta;
+                       animCounter += delta;
+
+                       enemyWalkTimer += delta;
+
+                       S2DE::updateInputState(&inputState);
+
+                       if (frameCounter > frameTime)
+                       {
+                               frameCounter = 0;
+
+                               // update player
+                               float walkSpeed = 0.08;
+
+                               float newX = playerPos.x;
+                               float newY = playerPos.y;
+                               float finalX = newX;
+                               float finalY = newY;
+
+                               if (inputState.right) {
+                                       newX += walkSpeed;
+                                       playerDir = 2;
+                               }
+                               if (inputState.left) {
+                                       newX -= walkSpeed;
+                                       playerDir = 6;
+                               }
+                               if (inputState.up) {
+                                       newY -= walkSpeed;
+                                       playerDir = 0;
+                               }
+                               if (inputState.down) {
+                                       newY += walkSpeed;
+                                       playerDir = 4;
+                               }
+
+                               if (!checkCollisionRect({ playerPos.x, newY }, world))
+                               {
+                                       // can move on the y
+                                       finalY = newY;
+                               }
+
+                               if (!checkCollisionRect({ newX, playerPos.y }, world))
+                               {
+                                       // can move on the X
+                                       finalX = newX;
+                               }
+
+                               playerPos.x = finalX;
+                               playerPos.y = finalY;
+
+                               camera = playerPos;
+
+                               if (enemyWalkTimer > enemyWalkTime)
+                               {
+                                       // flip the direction and reset the timer
+                                       enemyDirection = !enemyDirection;
+                                       enemyWalkTimer = 0;
+                               }
+
+                               float enemyWalkSpeed = 0.04;
+                               if (enemyDirection) // true == 1 == going right
+                               {
+                                       birdPos.x += enemyWalkSpeed;
+                               }
+                               else // going left
+                               {
+                                       birdPos.x -= enemyWalkSpeed;
+                               }
+
+                       }
+                       
+
+                       static bool forward = true;
+                       if (animCounter >= animTime)
+                       {
+                               animCounter = 0;
+
+                               if (forward)
+                               {
+                                       playerFrame += 1;
+                                       if (playerFrame >= 2)
+                                       {
+                                               forward = false;
+                                       }
+                               }
+                               else
+                               {
+                                       playerFrame -= 1;
+                                       if (playerFrame <= 0)
+                                       {
+                                               forward = true;
+                                       }
+                               }
+                       }
+
+                       SDL_RenderClear(renderer);
+                       {
+                               renderTilemap(world, WORLD_WIDTH, WORLD_HEIGHT, camera);
+                               renderWorld();
+                       }
+                       SDL_RenderPresent(renderer);
+               }
+               else if (gameState == COMBAT) {
+                       runCombat(delta);
+               }
+       }
+
+
+       for (int i = 0; i < WORLD_HEIGHT; ++i) delete[] world[i];
+       delete[] world;
+
+       S2DE::quitRendering(&renderer, &window);
+       Mix_Quit();
+
+       SDL_DestroyTexture(environment_sheet);
+       // destroy the other shit here
+       // add mix_quit to dll
+       return 0;
 }
\ No newline at end of file
index cc3608f..b821faf 100644 (file)
@@ -1,66 +1,66 @@
-#include "main_menu.h"\r
-#include "globals.h"\r
-#include "ui.h"\r
-\r
-static const char* menuItems[] = { "Overworld", "Combat", "Load Game", "Options", "Quit" };\r
-static constexpr int numMenuItems = 5;\r
-int currentMenuItem = 0;\r
-\r
-\r
-void renderMainPanel();\r
-\r
-void renderMainPanel() {\r
-\r
-       int panelWidth = 200;\r
-       int panelHeight = 150;\r
-\r
-       int panelX = WINDOW_WIDTH / 2 - panelWidth / 2;\r
-       int panelY = WINDOW_HEIGHT / 2 - panelHeight / 2;\r
-\r
-       renderBasicPanel(panelX, panelY, panelWidth, panelHeight);\r
-       \r
-       int leftPad = 40;\r
-       int topPad = 20;\r
-       int itemSpacing = 30;\r
-\r
-       for (int i = 0; i < numMenuItems; ++i) {\r
-               renderString(panelX + leftPad, panelY + topPad + itemSpacing * i, menuItems[i]);\r
-       }\r
-\r
-       renderString(panelX + 20, panelY + topPad + (itemSpacing * currentMenuItem), ">");\r
-\r
-}\r
-\r
-void mainMenu(double deltaTime) {\r
-       S2DE::updateInputState(&inputState);\r
-\r
-       if (inputState.up) {\r
-               inputState.up = false;\r
-               currentMenuItem--;\r
-               if (currentMenuItem < 0) currentMenuItem = numMenuItems - 1;\r
-       }\r
-       else if (inputState.down) {\r
-               inputState.down = false;\r
-               currentMenuItem++;\r
-               if (currentMenuItem > numMenuItems - 1) currentMenuItem = 0;\r
-       }\r
-       else if (inputState.rtrn) {\r
-               inputState.rtrn = false;\r
-               // select the current menu item\r
-               switch (currentMenuItem) {\r
-               case 0:\r
-                       gameState = OVERWORLD;\r
-                       break;\r
-               case 1:\r
-                       gameState = COMBAT;\r
-                       break;\r
-               default:\r
-                       inputState.quit = true;\r
-                       break;\r
-               }\r
-       }\r
-\r
-       SDL_RenderClear(renderer);\r
-       renderMainPanel();\r
-       SDL_RenderPresent(renderer);\r
+#include "main_menu.h"
+#include "globals.h"
+#include "ui.h"
+
+static const char* menuItems[] = { "Overworld", "Combat", "Load Game", "Options", "Quit" };
+static constexpr int numMenuItems = 5;
+int currentMenuItem = 0;
+
+
+void renderMainPanel();
+
+void renderMainPanel() {
+
+       int panelWidth = 200;
+       int panelHeight = 150;
+
+       int panelX = WINDOW_WIDTH / 2 - panelWidth / 2;
+       int panelY = WINDOW_HEIGHT / 2 - panelHeight / 2;
+
+       renderBasicPanel(panelX, panelY, panelWidth, panelHeight);
+       
+       int leftPad = 40;
+       int topPad = 20;
+       int itemSpacing = 30;
+
+       for (int i = 0; i < numMenuItems; ++i) {
+               renderString(panelX + leftPad, panelY + topPad + itemSpacing * i, menuItems[i]);
+       }
+
+       renderString(panelX + 20, panelY + topPad + (itemSpacing * currentMenuItem), ">");
+
+}
+
+void mainMenu(double deltaTime) {
+       S2DE::updateInputState(&inputState);
+
+       if (inputState.up) {
+               inputState.up = false;
+               currentMenuItem--;
+               if (currentMenuItem < 0) currentMenuItem = numMenuItems - 1;
+       }
+       else if (inputState.down) {
+               inputState.down = false;
+               currentMenuItem++;
+               if (currentMenuItem > numMenuItems - 1) currentMenuItem = 0;
+       }
+       else if (inputState.rtrn) {
+               inputState.rtrn = false;
+               // select the current menu item
+               switch (currentMenuItem) {
+               case 0:
+                       gameState = OVERWORLD;
+                       break;
+               case 1:
+                       gameState = COMBAT;
+                       break;
+               default:
+                       inputState.quit = true;
+                       break;
+               }
+       }
+
+       SDL_RenderClear(renderer);
+       renderMainPanel();
+       SDL_RenderPresent(renderer);
 }
\ No newline at end of file
index 5e48827..ce1eff3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once\r
-\r
-\r
+#pragma once
+
+
 void mainMenu(double deltaTime);
\ No newline at end of file
index abe76d6..1d505c0 100644 (file)
@@ -1,83 +1,83 @@
-#include "tilemap.h"\r
-#include "globals.h"\r
-\r
-\r
-using json = nlohmann::json;\r
-\r
-void loadWorld(const char* mapPath, WorldCell** world, int worldWidth, int worldHeight)\r
-{\r
-       json jsonData = S2DE::loadJson(mapPath);\r
-\r
-       json groundData = jsonData["layers"][0]["data"];\r
-\r
-       for (int y = 0; y < worldHeight; ++y)\r
-       {\r
-               for (int x = 0; x < worldWidth; ++x)\r
-               {\r
-                       int jsonIdx = (y * worldHeight) + x;\r
-\r
-                       int groundType = groundData[jsonIdx];\r
-\r
-                       bool solid = groundType > 30; // lazy hack\r
-\r
-                       world[y][x] = { groundType, solid };\r
-               }\r
-       }\r
-}\r
-\r
-void renderTilemap(WorldCell** world, int worldWidth, int worldHeight, S2DE::Camera camera)\r
-{\r
-       for (int y = 0; y < worldHeight; ++y)\r
-       {\r
-               for (int x = 0; x < worldWidth; ++x)\r
-               {\r
-\r
-                       float scale = 4;\r
-                       S2DE::Vec2<float> worldPos = { x, y };\r
-                       SDL_Rect dRect = S2DE::worldToScreenRect(&camera, &worldPos, scale, WINDOW_WIDTH, WINDOW_HEIGHT, 16, 16);\r
-\r
-                       //if (dRect.x >= 0 && dRect.x + dRect.w <= WINDOW_WIDTH - (16 * scale) && dRect.y  >= 0 && dRect.y + dRect.h <= WINDOW_HEIGHT - (16 * scale))\r
-                       if (world[y][x].ground != 160 && dRect.x + dRect.w >= 0 && dRect.x <= WINDOW_WIDTH && dRect.y + dRect.h >= 0 && dRect.y <= WINDOW_HEIGHT)\r
-                       {\r
-\r
-                               if (world[y][x].ground == 71)\r
-                               {\r
-                                       // render water animated\r
-\r
-                                       S2DE::Rect waterSRect = { playerFrame * 16, 0, 16, 16 };\r
-\r
-                                       S2DE::renderTexture(&renderer, &water_test_sheet, &waterSRect, &dRect);\r
-                               }\r
-                               else\r
-                               {\r
-\r
-                                       int tile_idx = world[y][x].ground - 1;\r
-\r
-                                       int sheet_width = 10;\r
-\r
-                                       int tile_x = (tile_idx % sheet_width);\r
-                                       int tile_y = (tile_idx / sheet_width);\r
-\r
-                                       SDL_Rect sRect = { tile_x * 16, tile_y * 16, 16, 16 };\r
-\r
-\r
-                                       S2DE::renderTexture(&renderer, &environment_sheet, &sRect, &dRect);\r
-                               }\r
-\r
-                       }\r
-\r
-               }\r
-       }\r
-}\r
-\r
-bool checkCollisionRect(S2DE::Vec2<float> worldPos, WorldCell** world) {\r
-       return (world[(int)(worldPos.y + 0.55)][(int)(worldPos.x + 0.25)].solid ||\r
-               world[(int)(worldPos.y + 0.55)][(int)(worldPos.x + 0.75)].solid ||\r
-               world[(int)(worldPos.y + 0.95)][(int)(worldPos.x + 0.25)].solid ||\r
-               world[(int)(worldPos.y + 0.95)][(int)(worldPos.x + 0.75)].solid);\r
-\r
-}\r
-\r
-bool checkCollisionPoint(S2DE::Vec2<float> worldPos, WorldCell** world) {\r
-       return world[(int)worldPos.y][(int)worldPos.x].solid;\r
+#include "tilemap.h"
+#include "globals.h"
+
+
+using json = nlohmann::json;
+
+void loadWorld(const char* mapPath, WorldCell** world, int worldWidth, int worldHeight)
+{
+       json jsonData = S2DE::loadJson(mapPath);
+
+       json groundData = jsonData["layers"][0]["data"];
+
+       for (int y = 0; y < worldHeight; ++y)
+       {
+               for (int x = 0; x < worldWidth; ++x)
+               {
+                       int jsonIdx = (y * worldHeight) + x;
+
+                       int groundType = groundData[jsonIdx];
+
+                       bool solid = groundType > 30; // lazy hack
+
+                       world[y][x] = { groundType, solid };
+               }
+       }
+}
+
+void renderTilemap(WorldCell** world, int worldWidth, int worldHeight, S2DE::Camera camera)
+{
+       for (int y = 0; y < worldHeight; ++y)
+       {
+               for (int x = 0; x < worldWidth; ++x)
+               {
+
+                       float scale = 4;
+                       S2DE::Vec2<float> worldPos = { x, y };
+                       SDL_Rect dRect = S2DE::worldToScreenRect(&camera, &worldPos, scale, WINDOW_WIDTH, WINDOW_HEIGHT, 16, 16);
+
+                       //if (dRect.x >= 0 && dRect.x + dRect.w <= WINDOW_WIDTH - (16 * scale) && dRect.y  >= 0 && dRect.y + dRect.h <= WINDOW_HEIGHT - (16 * scale))
+                       if (world[y][x].ground != 160 && dRect.x + dRect.w >= 0 && dRect.x <= WINDOW_WIDTH && dRect.y + dRect.h >= 0 && dRect.y <= WINDOW_HEIGHT)
+                       {
+
+                               if (world[y][x].ground == 71)
+                               {
+                                       // render water animated
+
+                                       S2DE::Rect waterSRect = { playerFrame * 16, 0, 16, 16 };
+
+                                       S2DE::renderTexture(&renderer, &water_test_sheet, &waterSRect, &dRect);
+                               }
+                               else
+                               {
+
+                                       int tile_idx = world[y][x].ground - 1;
+
+                                       int sheet_width = 10;
+
+                                       int tile_x = (tile_idx % sheet_width);
+                                       int tile_y = (tile_idx / sheet_width);
+
+                                       SDL_Rect sRect = { tile_x * 16, tile_y * 16, 16, 16 };
+
+
+                                       S2DE::renderTexture(&renderer, &environment_sheet, &sRect, &dRect);
+                               }
+
+                       }
+
+               }
+       }
+}
+
+bool checkCollisionRect(S2DE::Vec2<float> worldPos, WorldCell** world) {
+       return (world[(int)(worldPos.y + 0.55)][(int)(worldPos.x + 0.25)].solid ||
+               world[(int)(worldPos.y + 0.55)][(int)(worldPos.x + 0.75)].solid ||
+               world[(int)(worldPos.y + 0.95)][(int)(worldPos.x + 0.25)].solid ||
+               world[(int)(worldPos.y + 0.95)][(int)(worldPos.x + 0.75)].solid);
+
+}
+
+bool checkCollisionPoint(S2DE::Vec2<float> worldPos, WorldCell** world) {
+       return world[(int)worldPos.y][(int)worldPos.x].solid;
 }
\ No newline at end of file
index 8aed93f..fee94ee 100644 (file)
--- a/tilemap.h
+++ b/tilemap.h
@@ -1,18 +1,18 @@
-#pragma once\r
-\r
-#include <2DEngine.h>\r
-\r
-// same here \r
-struct WorldCell\r
-{\r
-       int ground;\r
-       bool solid;\r
-};\r
-\r
-\r
-void loadWorld(const char* mapPath, WorldCell** world, int worldWidth, int worldHeight);\r
-\r
-void renderTilemap(WorldCell** world, int worldWidth, int worldHeight, S2DE::Camera camera);\r
-\r
-bool checkCollisionRect(S2DE::Vec2<float> worldPos, WorldCell** world);\r
+#pragma once
+
+#include <2DEngine.h>
+
+// same here 
+struct WorldCell
+{
+       int ground;
+       bool solid;
+};
+
+
+void loadWorld(const char* mapPath, WorldCell** world, int worldWidth, int worldHeight);
+
+void renderTilemap(WorldCell** world, int worldWidth, int worldHeight, S2DE::Camera camera);
+
+bool checkCollisionRect(S2DE::Vec2<float> worldPos, WorldCell** world);
 bool checkCollisionPoint(S2DE::Vec2<float> worldPos, WorldCell** world);
\ No newline at end of file
diff --git a/ui.cpp b/ui.cpp
index 80070cd..79e9147 100644 (file)
--- a/ui.cpp
+++ b/ui.cpp
@@ -1,91 +1,91 @@
-#include "ui.h"\r
-#include "globals.h"\r
-\r
-\r
-\r
-static constexpr int panelDrawSize = 16 * 2;\r
-\r
-S2DE::Rect topLeftCorner = { 0, 0, 16, 16 };\r
-S2DE::Rect topRightCorner = { 32, 0, 16, 16 };\r
-S2DE::Rect bottomLeftCorner = { 0, 32, 16, 16 };\r
-S2DE::Rect bottomRightCorner = { 32, 32, 16, 16 };\r
-S2DE::Rect leftSide = { 0, 16, 16, 1 };\r
-S2DE::Rect rightSide = { 32, 16, 16, 1 };\r
-S2DE::Rect topSide = { 16, 0, 1, 16 };\r
-S2DE::Rect bottomSide = { 16, 32, 1, 16 };\r
-S2DE::Rect fill = { 10, 10, 1, 1 };\r
-\r
-S2DE::Rect renderString(int startX, int startY, const char* string, SDL_Texture* font) {\r
-       // this part should be in DLL\r
-\r
-       //SDL_Texture* fontTX = debugFont ? debug_font : font_sheet;\r
-       if (!font) {\r
-               font = font_sheet;\r
-       }\r
-\r
-       int glyphWidth = 6;\r
-       int glyphHeight = 8;\r
-\r
-       int glyphScale = 2;\r
-\r
-       S2DE::Rect finalRect = { startX, startY, 0, glyphHeight * glyphScale };\r
-\r
-       int i = 0;\r
-       while (string[i] != '\0')\r
-       {\r
-               int sheetX = (int)string[i] - 32;\r
-\r
-\r
-               S2DE::Rect sRect = { sheetX * glyphWidth, 0, glyphWidth, glyphHeight };\r
-               S2DE::Rect dRect = { startX + (i * glyphWidth * glyphScale), startY, glyphWidth * glyphScale, glyphHeight * glyphScale };\r
-\r
-               S2DE::renderTexture(&renderer, &font, &sRect, &dRect);\r
-\r
-               i++;\r
-       }\r
-\r
-       finalRect.w = i * glyphWidth * glyphScale;\r
-\r
-       return finalRect;\r
-}\r
-\r
-void renderBasicPanel(int x, int y, int width, int height) {\r
-       // smallest supported size? 40?\r
-       if (width < 40) width = 40;\r
-       if (height < 40) height = 40;\r
-       \r
-       S2DE::Rect dRect;\r
-\r
-       // top left corner\r
-       dRect = { x, y, panelDrawSize, panelDrawSize };\r
-       S2DE::renderTexture(&renderer, &ui_frame_sheet, &topLeftCorner, &dRect);\r
-\r
-       // top right corner\r
-       dRect = { x + (width - panelDrawSize), y, panelDrawSize, panelDrawSize };\r
-       S2DE::renderTexture(&renderer, &ui_frame_sheet, &topRightCorner, &dRect);\r
-\r
-       // bottom left\r
-       dRect = { x, y + height - panelDrawSize, panelDrawSize, panelDrawSize };\r
-       S2DE::renderTexture(&renderer, &ui_frame_sheet, &bottomLeftCorner, &dRect);\r
-\r
-       // bottom right\r
-       dRect = { x + width - panelDrawSize, y + height - panelDrawSize, panelDrawSize, panelDrawSize };\r
-       S2DE::renderTexture(&renderer, &ui_frame_sheet, &bottomRightCorner, &dRect);\r
-\r
-       // sides\r
-       dRect = { x, y + panelDrawSize, panelDrawSize, height - 2 * panelDrawSize};\r
-       S2DE::renderTexture(&renderer, &ui_frame_sheet, &leftSide, &dRect);\r
-\r
-       dRect = { x + width - panelDrawSize, y + panelDrawSize, panelDrawSize, height - 2 * panelDrawSize };\r
-       S2DE::renderTexture(&renderer, &ui_frame_sheet, &rightSide, &dRect);\r
-\r
-       dRect = { x + panelDrawSize, y, width - 2 * panelDrawSize, panelDrawSize };\r
-       S2DE::renderTexture(&renderer, &ui_frame_sheet, &topSide, &dRect);\r
-\r
-       dRect = { x + panelDrawSize, y + height - panelDrawSize, width - 2 * panelDrawSize, panelDrawSize };\r
-       S2DE::renderTexture(&renderer, &ui_frame_sheet, &bottomSide, &dRect);\r
-\r
-       // fill\r
-       dRect = { x + panelDrawSize, y + panelDrawSize, width - 2 * panelDrawSize, height - 2 * panelDrawSize};\r
-       S2DE::renderTexture(&renderer, &ui_frame_sheet, &fill, &dRect);\r
+#include "ui.h"
+#include "globals.h"
+
+
+
+static constexpr int panelDrawSize = 16 * 2;
+
+S2DE::Rect topLeftCorner = { 0, 0, 16, 16 };
+S2DE::Rect topRightCorner = { 32, 0, 16, 16 };
+S2DE::Rect bottomLeftCorner = { 0, 32, 16, 16 };
+S2DE::Rect bottomRightCorner = { 32, 32, 16, 16 };
+S2DE::Rect leftSide = { 0, 16, 16, 1 };
+S2DE::Rect rightSide = { 32, 16, 16, 1 };
+S2DE::Rect topSide = { 16, 0, 1, 16 };
+S2DE::Rect bottomSide = { 16, 32, 1, 16 };
+S2DE::Rect fill = { 10, 10, 1, 1 };
+
+S2DE::Rect renderString(int startX, int startY, const char* string, SDL_Texture* font) {
+       // this part should be in DLL
+
+       //SDL_Texture* fontTX = debugFont ? debug_font : font_sheet;
+       if (!font) {
+               font = font_sheet;
+       }
+
+       int glyphWidth = 6;
+       int glyphHeight = 8;
+
+       int glyphScale = 2;
+
+       S2DE::Rect finalRect = { startX, startY, 0, glyphHeight * glyphScale };
+
+       int i = 0;
+       while (string[i] != '\0')
+       {
+               int sheetX = (int)string[i] - 32;
+
+
+               S2DE::Rect sRect = { sheetX * glyphWidth, 0, glyphWidth, glyphHeight };
+               S2DE::Rect dRect = { startX + (i * glyphWidth * glyphScale), startY, glyphWidth * glyphScale, glyphHeight * glyphScale };
+
+               S2DE::renderTexture(&renderer, &font, &sRect, &dRect);
+
+               i++;
+       }
+
+       finalRect.w = i * glyphWidth * glyphScale;
+
+       return finalRect;
+}
+
+void renderBasicPanel(int x, int y, int width, int height) {
+       // smallest supported size? 40?
+       if (width < 40) width = 40;
+       if (height < 40) height = 40;
+       
+       S2DE::Rect dRect;
+
+       // top left corner
+       dRect = { x, y, panelDrawSize, panelDrawSize };
+       S2DE::renderTexture(&renderer, &ui_frame_sheet, &topLeftCorner, &dRect);
+
+       // top right corner
+       dRect = { x + (width - panelDrawSize), y, panelDrawSize, panelDrawSize };
+       S2DE::renderTexture(&renderer, &ui_frame_sheet, &topRightCorner, &dRect);
+
+       // bottom left
+       dRect = { x, y + height - panelDrawSize, panelDrawSize, panelDrawSize };
+       S2DE::renderTexture(&renderer, &ui_frame_sheet, &bottomLeftCorner, &dRect);
+
+       // bottom right
+       dRect = { x + width - panelDrawSize, y + height - panelDrawSize, panelDrawSize, panelDrawSize };
+       S2DE::renderTexture(&renderer, &ui_frame_sheet, &bottomRightCorner, &dRect);
+
+       // sides
+       dRect = { x, y + panelDrawSize, panelDrawSize, height - 2 * panelDrawSize};
+       S2DE::renderTexture(&renderer, &ui_frame_sheet, &leftSide, &dRect);
+
+       dRect = { x + width - panelDrawSize, y + panelDrawSize, panelDrawSize, height - 2 * panelDrawSize };
+       S2DE::renderTexture(&renderer, &ui_frame_sheet, &rightSide, &dRect);
+
+       dRect = { x + panelDrawSize, y, width - 2 * panelDrawSize, panelDrawSize };
+       S2DE::renderTexture(&renderer, &ui_frame_sheet, &topSide, &dRect);
+
+       dRect = { x + panelDrawSize, y + height - panelDrawSize, width - 2 * panelDrawSize, panelDrawSize };
+       S2DE::renderTexture(&renderer, &ui_frame_sheet, &bottomSide, &dRect);
+
+       // fill
+       dRect = { x + panelDrawSize, y + panelDrawSize, width - 2 * panelDrawSize, height - 2 * panelDrawSize};
+       S2DE::renderTexture(&renderer, &ui_frame_sheet, &fill, &dRect);
 }
\ No newline at end of file
diff --git a/ui.h b/ui.h
index 9ef01bf..dfa3d1c 100644 (file)
--- a/ui.h
+++ b/ui.h
@@ -1,7 +1,7 @@
-#pragma once\r
-\r
-#include <2DEngine.h>\r
-\r
-S2DE::Rect renderString(int startX, int startY, const char* string, SDL_Texture* font = nullptr);\r
-\r
+#pragma once
+
+#include <2DEngine.h>
+
+S2DE::Rect renderString(int startX, int startY, const char* string, SDL_Texture* font = nullptr);
+
 void renderBasicPanel(int x, int y, int width, int height);
\ No newline at end of file