503 lines
14 KiB
C
503 lines
14 KiB
C
// This file is part of LibreWands.
|
|
|
|
// LibreWands is free software: you can redistribute it and/or modify it under the terms of the
|
|
// GNU General Public License as published by the Free Software Foundation, either version 3 of
|
|
// the License, or (at your option) any later version.
|
|
|
|
// LibreWands is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
|
// the GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License along with LibreWands. If
|
|
// not, see https://www.gnu.org/licenses/.
|
|
|
|
#include <ncurses.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "engineCore.c"
|
|
|
|
// Our selected tool and tooltip for base tiles
|
|
uint_fast8_t continuousPainting = 0;
|
|
uint_fast16_t Btip = '#';
|
|
uint_fast8_t BtipColor = 0;
|
|
uint_fast8_t BtipWalk = 0;
|
|
|
|
// Show a menu where the user can select their colour
|
|
int colorPick()
|
|
{
|
|
// Declared Variables
|
|
char buffer1[8] = "";
|
|
char buffer2[8] = "";
|
|
uint_fast8_t a;
|
|
uint_fast8_t b;
|
|
|
|
echo();
|
|
clear();
|
|
// Prompt for foreground colour
|
|
mvprintw(0, 0, "Foreground:");
|
|
mvprintw(1, 0, "Black) 0");
|
|
mvprintw(2, 0, "Red) 1");
|
|
mvprintw(3, 0, "Green) 2");
|
|
mvprintw(4, 0, "Yellow) 3");
|
|
mvprintw(5, 0, "Blue) 4");
|
|
mvprintw(6, 0, "Magenta) 5");
|
|
mvprintw(7, 0, "Cyan) 6");
|
|
mvprintw(8, 0, "White) 7\n");
|
|
|
|
getnstr(buffer1, 8);
|
|
|
|
// Prompt for background colour
|
|
mvprintw(10, 0, "Background:");
|
|
mvprintw(11, 0, "Black) 0");
|
|
mvprintw(12, 0, "Red) 1");
|
|
mvprintw(13, 0, "Green) 2");
|
|
mvprintw(14, 0, "Yellow) 3");
|
|
mvprintw(15, 0, "Blue) 4");
|
|
mvprintw(16, 0, "Magenta) 5");
|
|
mvprintw(17, 0, "Cyan) 6");
|
|
mvprintw(18, 0, "White) 7\n");
|
|
|
|
getnstr(buffer2, 8);
|
|
|
|
a = atoi(buffer1);
|
|
b = atoi(buffer2);
|
|
|
|
return 10 * (b) + (a + 1);
|
|
}
|
|
|
|
// Change our tooltip for a different one
|
|
int turnTip()
|
|
{
|
|
// Declared Variables
|
|
char buffer1[1] = "";
|
|
char buffer2[1] = "";
|
|
uint_fast8_t walk = 0;
|
|
|
|
echo();
|
|
|
|
// Ask our necessary details.
|
|
mvprintw(5, 0, "What character would you like to print? ");
|
|
getnstr(buffer1, 1);
|
|
mvprintw(6, 0, "Are these tiles walkable? (1 = yes, 0 = no) ");
|
|
getnstr(buffer2, 1);
|
|
walk = atoi(buffer2);
|
|
|
|
// Set our variables to our aquired values
|
|
BtipColor = colorPick();
|
|
BtipWalk = walk;
|
|
Btip = buffer1[0];
|
|
|
|
// end gracefully
|
|
return 0;
|
|
}
|
|
|
|
// Show a help screen for the user
|
|
int help()
|
|
{
|
|
char buffer[1] = "";
|
|
|
|
clear();
|
|
mvprintw(0, 0,
|
|
"Tile types:\nb - Basic tile\ni - Information sign\no - Collectable Object\nd - "
|
|
"Door\np - Person\n\nKeyboard functions:\nF5 - Save\nF6 - Load\nF8 - Continuous "
|
|
"Painting\nBackspace - Erase\n\nSee documentation for details and extra "
|
|
"goodies!\nPress enter to escape this screen.");
|
|
|
|
getnstr(buffer, 1);
|
|
return 0;
|
|
}
|
|
|
|
// Map editor for our game
|
|
int main()
|
|
{
|
|
// Our current map
|
|
uint_fast8_t aMap = 0;
|
|
|
|
// Our screen size
|
|
uint_fast16_t xmax = 0;
|
|
uint_fast16_t ymax = 0;
|
|
|
|
// Our cursor location
|
|
uint_fast16_t x = 0;
|
|
uint_fast16_t y = 0;
|
|
|
|
// Our keypress
|
|
uint_fast16_t k = 0;
|
|
|
|
// Animated tiles
|
|
char tile_W[8] = {'~', '.', ' ', ' ', ' ', '.', '~', '^'};
|
|
|
|
// Potential tile values
|
|
uint_fast8_t c = 0;
|
|
uint_fast8_t t = 0;
|
|
char dialog[256] = "";
|
|
uint_fast8_t ID = 0;
|
|
uint_fast8_t lock = 0;
|
|
uint_fast8_t nx = 0;
|
|
uint_fast8_t ny = 0;
|
|
uint_fast8_t type = 0;
|
|
uint_fast8_t move = 0;
|
|
char name[256] = "";
|
|
char text1[256] = "";
|
|
char text2[256] = "";
|
|
struct mapmonster mon[5];
|
|
|
|
// Text buffers
|
|
char buffer1[256] = "";
|
|
char buffer2[256] = "";
|
|
char buffer3[256] = "";
|
|
char buffer4[256] = "";
|
|
char buffer5[256] = "";
|
|
char buffer6[256] = "";
|
|
char buffer7[256] = "";
|
|
char buffer8[256] = "";
|
|
char buffer9[256] = "";
|
|
char bufferA[256] = "";
|
|
char bufferB[256] = "";
|
|
char bufferC[256] = "";
|
|
char bufferD[256] = "";
|
|
|
|
// Start our game engine and start a blank map
|
|
initEngine();
|
|
newMaps();
|
|
|
|
// Run through our animation cycle while we draw our tiles. Get and control our input.
|
|
for (uint_fast8_t A = 0;; A++)
|
|
{
|
|
// Init
|
|
getmaxyx(stdscr, ymax, xmax);
|
|
noecho();
|
|
halfdelay(2);
|
|
clear();
|
|
|
|
// For all existing base tiles, draw them.
|
|
for (int C = 0; C < map[aMap].nBase; C++)
|
|
{
|
|
// If this tile is active, unwalkable, invisible and white-on-blue
|
|
if ((map[aMap].Base[C].active) && (map[aMap].Base[C].walk == 0) &&
|
|
(map[aMap].Base[C].t == ' ') && (map[aMap].Base[C].c == 48))
|
|
{
|
|
// Draw an animated water tile
|
|
attron(COLOR_PAIR(map[aMap].Base[C].c));
|
|
mvprintw(map[aMap].Base[C].y - y, map[aMap].Base[C].x - x, "%c",
|
|
tile_W[A % 8]);
|
|
attroff(COLOR_PAIR(map[aMap].Base[C].c));
|
|
}
|
|
// If this tile isn't all-of-the-above
|
|
else if (map[aMap].Base[C].active)
|
|
{
|
|
// Draw it normally
|
|
attron(COLOR_PAIR(map[aMap].Base[C].c));
|
|
mvprintw(map[aMap].Base[C].y - y, map[aMap].Base[C].x - x, "%c",
|
|
map[aMap].Base[C].t);
|
|
attroff(COLOR_PAIR(map[aMap].Base[C].c));
|
|
}
|
|
// If we're hovering over this base tile and it's active
|
|
if ((map[aMap].Base[C].x - (xmax / 2) == x) && (map[aMap].Base[C].active) &&
|
|
(map[aMap].Base[C].y - (ymax / 2) == y))
|
|
{
|
|
// Print out useful info in the bottom-left screen
|
|
mvprintw(ymax - 2, 0, "Walkable: %s\nColor: %i",
|
|
map[aMap].Base[C].walk ? "True" : "False",
|
|
map[aMap].Base[C].c);
|
|
}
|
|
}
|
|
|
|
// For all existing info tiles, draw them.
|
|
for (int C = 0; C < map[aMap].nInfo; C++)
|
|
{
|
|
// If the given info tile is active
|
|
if (map[aMap].Info[C].active)
|
|
{
|
|
// Draw it with the appropriate character and colour
|
|
attron(COLOR_PAIR(map[aMap].Info[C].c));
|
|
mvprintw(map[aMap].Info[C].y - y, map[aMap].Info[C].x - x, "%c",
|
|
map[aMap].Info[C].t);
|
|
attroff(COLOR_PAIR(map[aMap].Info[C].c));
|
|
}
|
|
|
|
// If we're hovering over the given info tile and it's active
|
|
if ((map[aMap].Info[C].x - (xmax / 2) == x) && (map[aMap].Info[C].active) &&
|
|
(map[aMap].Info[C].y - (ymax / 2) == y))
|
|
{
|
|
// Print out its dialog in the bottom left of the screen
|
|
mvprintw(ymax - 1, 0, "%s", map[aMap].Info[C].dialog);
|
|
}
|
|
}
|
|
|
|
// For all existing item tiles, draw them.
|
|
for (int C = 0; C < map[aMap].nItem; C++)
|
|
{
|
|
// If the given item tile is active
|
|
if (map[aMap].Item[C].active)
|
|
{
|
|
// Draw it with the appropriate character and colour
|
|
attron(COLOR_PAIR(map[aMap].Item[C].c));
|
|
mvprintw(map[aMap].Item[C].y - y, map[aMap].Item[C].x - x, "%c",
|
|
map[aMap].Item[C].t);
|
|
attroff(COLOR_PAIR(map[aMap].Item[C].c));
|
|
}
|
|
|
|
// If we're hovering over the given item tile and it's active
|
|
if ((map[aMap].Item[C].x - (xmax / 2) == x) && (map[aMap].Item[C].active) &&
|
|
(map[aMap].Item[C].y - (ymax / 2) == y))
|
|
{
|
|
// Print out its the item ID in the bottom left of the screen
|
|
mvprintw(ymax - 1, 0, "ID#: %i", map[aMap].Item[C].ID);
|
|
}
|
|
}
|
|
|
|
// For all existing door tiles, draw them.
|
|
for (int C = 0; C < map[aMap].nDoor; C++)
|
|
{
|
|
// If the given door tile is active
|
|
if (map[aMap].Door[C].active)
|
|
{
|
|
// Draw it with the appropriate character and colour
|
|
attron(COLOR_PAIR(map[aMap].Door[C].c));
|
|
mvprintw(map[aMap].Door[C].y - y, map[aMap].Door[C].x - x, "%c",
|
|
map[aMap].Door[C].t);
|
|
attroff(COLOR_PAIR(map[aMap].Door[C].c));
|
|
}
|
|
|
|
// If we're hovering over the given item tile and it's active
|
|
if ((map[aMap].Door[C].x - (xmax / 2) == x) && (map[aMap].Door[C].active) &&
|
|
(map[aMap].Door[C].y - (ymax / 2) == y))
|
|
{
|
|
// Print out useful info in the bottom-left screen
|
|
mvprintw(ymax - 2, 0, "Status: %s\nMap: %i X: %li Y: %li",
|
|
map[aMap].Door[C].lock ? "Locked" : "Unlocked",
|
|
map[aMap].Door[C].ID, map[aMap].Door[C].nx,
|
|
map[aMap].Door[C].ny);
|
|
}
|
|
}
|
|
|
|
// For all existing character tiles, draw them.
|
|
for (int C = 0; C < map[aMap].nChar; C++)
|
|
{
|
|
// If the given char tile is active
|
|
if (map[aMap].Char[C].active)
|
|
{
|
|
// Draw it with the appropriate text character and colour
|
|
attron(COLOR_PAIR(map[aMap].Char[C].c));
|
|
mvprintw(map[aMap].Char[C].y - y, map[aMap].Char[C].x - x, "%c",
|
|
map[aMap].Char[C].t);
|
|
attroff(COLOR_PAIR(map[aMap].Char[C].c));
|
|
}
|
|
|
|
// If we're hovering over the given char tile and it's active
|
|
if ((map[aMap].Char[C].x - (xmax / 2) == x) && (map[aMap].Char[C].active) &&
|
|
(map[aMap].Char[C].y - (ymax / 2) == y))
|
|
{
|
|
// Print out useful info in the bottom-left screen
|
|
mvprintw(ymax - 1, 0, "Name: %s - Type: %s - Moves: %s",
|
|
map[aMap].Char[C].name,
|
|
map[aMap].Char[C].type ? "Aggressive" : "Passive",
|
|
map[aMap].Char[C].move ? "Yes" : "No");
|
|
mvprintw(ymax - 2, 0, "Dialogue 1: %s", map[aMap].Char[C].dialog1);
|
|
mvprintw(ymax - 3, 0, "Dialogue 2: %s", map[aMap].Char[C].dialog2);
|
|
mvprintw(
|
|
ymax - 4, 0, "Monsters: %i-%i %i-%i %i-%i %i-%i %i-%i",
|
|
map[aMap].Char[C].mon[0].type, map[aMap].Char[C].mon[0].level,
|
|
map[aMap].Char[C].mon[1].type, map[aMap].Char[C].mon[1].level,
|
|
map[aMap].Char[C].mon[2].type, map[aMap].Char[C].mon[2].level,
|
|
map[aMap].Char[C].mon[3].type, map[aMap].Char[C].mon[3].level,
|
|
map[aMap].Char[C].mon[4].type, map[aMap].Char[C].mon[4].level);
|
|
}
|
|
}
|
|
|
|
// Display coordinates and tool/tips in the top left.
|
|
attron(COLOR_PAIR(0));
|
|
mvprintw(0, 0, "Map: %i X: %li Y: %li", aMap, x, y);
|
|
mvprintw(1, 0, "Tooltip: %c Color: %i Walkable: %s", (char)Btip, BtipColor,
|
|
BtipWalk ? "True" : "False");
|
|
mvprintw(2, 0, "Press 'h' for help.");
|
|
|
|
// Display our cursor based on what tool we're using.
|
|
switch (continuousPainting)
|
|
{
|
|
// If continuous painting is off
|
|
case 0:
|
|
mvprintw(ymax / 2, xmax / 2, "!");
|
|
break;
|
|
// If continuous painting is on
|
|
case 1:
|
|
mvprintw(ymax / 2, xmax / 2, "#");
|
|
break;
|
|
}
|
|
|
|
// Get and process our user input.
|
|
k = getch();
|
|
if (k == KEY_UP)
|
|
y--;
|
|
if (k == KEY_DOWN)
|
|
y++;
|
|
if (k == KEY_LEFT)
|
|
x--;
|
|
if (k == KEY_RIGHT)
|
|
x++;
|
|
if (k == KEY_F(5))
|
|
{
|
|
echo();
|
|
// Get our save name
|
|
mvprintw(4, 0, "Save name: ");
|
|
getnstr(buffer1, 256);
|
|
|
|
saveMaps(buffer1);
|
|
}
|
|
if (k == KEY_F(6))
|
|
{
|
|
echo();
|
|
// Get our load name
|
|
mvprintw(4, 0, "Load name: ");
|
|
getnstr(buffer1, 256);
|
|
|
|
loadMaps(buffer1);
|
|
}
|
|
// if(k == KEY_F(7))
|
|
// copyMap();
|
|
if (k == KEY_F(8))
|
|
// Toggle continuous painting
|
|
continuousPainting = !continuousPainting;
|
|
if (k == 'b')
|
|
// Change our tooltip
|
|
turnTip();
|
|
if (k == ' ')
|
|
addBase(x, y, aMap, xmax, ymax, Btip, BtipColor, BtipWalk);
|
|
if (continuousPainting == 1)
|
|
{
|
|
// If continuous painting is on
|
|
addBase(x, y, aMap, xmax, ymax, Btip, BtipColor, BtipWalk);
|
|
}
|
|
if (k == 'i')
|
|
{
|
|
echo();
|
|
// Prompt for our info
|
|
mvprintw(5, 0, "Which character would you like to print? ");
|
|
getnstr(buffer1, 1);
|
|
t = buffer1[0];
|
|
mvprintw(6, 0, "What would you like the sign to say? ");
|
|
getnstr(dialog, 256);
|
|
|
|
c = colorPick();
|
|
|
|
addInfo(x, y, aMap, xmax, ymax, t, c, dialog);
|
|
}
|
|
if (k == 'o')
|
|
{
|
|
echo();
|
|
// Prompt for our info
|
|
mvprintw(5, 0, "Which character would you like to print? ");
|
|
getnstr(buffer1, 1);
|
|
t = buffer1[0];
|
|
mvprintw(6, 0, "Which item is this? ");
|
|
getnstr(buffer2, 8);
|
|
ID = atoi(buffer2);
|
|
|
|
c = colorPick();
|
|
|
|
addItem(x, y, aMap, xmax, ymax, t, c, ID);
|
|
}
|
|
if (k == 'd')
|
|
{
|
|
echo();
|
|
// Prompt for our info
|
|
mvprintw(5, 0, "Which character would you like to print? ");
|
|
getnstr(buffer1, 1);
|
|
t = buffer1[0];
|
|
mvprintw(6, 0, "Is the door locked? (1 = YES/0 = NO) ");
|
|
getnstr(buffer2, 1);
|
|
lock = atoi(buffer2);
|
|
mvprintw(7, 0, "Which map does this door go to? (#) ");
|
|
getnstr(buffer3, 8);
|
|
ID = atoi(buffer3);
|
|
mvprintw(8, 0, "Which X value does this door go to? (#) ");
|
|
getnstr(buffer4, 8);
|
|
nx = atoi(buffer4);
|
|
mvprintw(9, 0, "Which Y value does this door go to? (#) ");
|
|
getnstr(buffer5, 8);
|
|
ny = atoi(buffer5);
|
|
|
|
c = colorPick();
|
|
|
|
addDoor(x, y, aMap, xmax, ymax, t, c, lock, ID, nx, ny);
|
|
}
|
|
if (k == 'p')
|
|
{
|
|
echo();
|
|
// Prompt for our info
|
|
mvprintw(5, 0, "Which character would you like to print? ");
|
|
getnstr(buffer1, 1);
|
|
t = buffer1[0];
|
|
|
|
mvprintw(6, 0, "Is this character aggressive? (1 = YES/0 = NO) ");
|
|
getnstr(buffer2, 1);
|
|
type = atoi(buffer2);
|
|
|
|
mvprintw(7, 0, "Does this character wander? (1 = YES/0 = NO) ");
|
|
getnstr(buffer3, 1);
|
|
move = atoi(buffer3);
|
|
|
|
mvprintw(8, 0, "What is their name? ");
|
|
getnstr(name, 256);
|
|
|
|
mvprintw(9, 0, "What do they say when they want to fight? ");
|
|
getnstr(text1, 256);
|
|
|
|
mvprintw(10, 0, "What do they say when they don't want to fight? ");
|
|
getnstr(text2, 256);
|
|
|
|
mvprintw(11, 0, "What type is their 1st monster? ");
|
|
getnstr(buffer4, 8);
|
|
mon[0].type = atoi(buffer4);
|
|
mvprintw(12, 0, "What type is their 2nd monster? ");
|
|
getnstr(buffer5, 8);
|
|
mon[1].type = atoi(buffer5);
|
|
mvprintw(13, 0, "What type is their 3rd monster? ");
|
|
getnstr(buffer6, 8);
|
|
mon[2].type = atoi(buffer6);
|
|
mvprintw(14, 0, "What type is their 4th monster? ");
|
|
getnstr(buffer7, 8);
|
|
mon[3].type = atoi(buffer7);
|
|
mvprintw(15, 0, "What type is their 5th monster? ");
|
|
getnstr(buffer8, 8);
|
|
mon[4].type = atoi(buffer8);
|
|
|
|
mvprintw(16, 0, "What level is their 1st monster? ");
|
|
getnstr(buffer9, 8);
|
|
mon[0].level = atoi(buffer9);
|
|
mvprintw(17, 0, "What level is their 2nd monster? ");
|
|
getnstr(bufferA, 8);
|
|
mon[1].level = atoi(bufferA);
|
|
mvprintw(18, 0, "What level is their 3rd monster? ");
|
|
getnstr(bufferB, 8);
|
|
mon[2].level = atoi(bufferB);
|
|
mvprintw(19, 0, "What level is their 4th monster? ");
|
|
getnstr(bufferC, 8);
|
|
mon[3].level = atoi(bufferC);
|
|
mvprintw(20, 0, "What level is their 5th monster? ");
|
|
getnstr(bufferD, 8);
|
|
mon[4].level = atoi(bufferD);
|
|
|
|
c = colorPick();
|
|
|
|
addChar(x, y, aMap, xmax, ymax, t, c, type, move, name, text1, text2, mon);
|
|
}
|
|
if (k == 'h')
|
|
help();
|
|
if (k == KEY_BACKSPACE)
|
|
delTile(x, y, aMap, xmax, ymax);
|
|
if ((k == KEY_PPAGE) && (aMap < (nMap - 1)))
|
|
aMap++;
|
|
if ((k == KEY_NPAGE) && (aMap > 0))
|
|
aMap--;
|
|
}
|
|
|
|
// Shutdown properly if needed
|
|
endwin();
|
|
return 0;
|
|
}
|