LibreWands/Source/engineMaps.c

555 lines
16 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/.
// Allocate memory for our internal map
int newMaps()
{
char buffer[1] = "";
// Allocate the needed memory
map = malloc(255 * sizeof(struct maps));
// On failure, report error.
if (map == NULL)
{
mvprintw(2, 0, "Unable to allocate memory.");
getnstr(buffer, 1);
return 1;
}
else
{
// Or else, record our new number of maps.
nMap = 255;
}
// Exit gracefully
return 0;
}
// Add a new Base tile
uint_fast8_t addBase(uint_fast16_t x, uint_fast16_t y, uint_fast8_t z, uint_fast8_t xmax,
uint_fast8_t ymax, uint_fast8_t t, uint_fast8_t c, uint_fast8_t walk)
{
// Allocate space for the new tile.
map[z].nBase++;
map[z].Base = realloc(map[z].Base, map[z].nBase * sizeof(struct Base));
// If this fails, do nothing.
if (map[z].Base == NULL)
{
map[z].nBase--;
return 1;
}
// Otherwise, set our values
map[z].Base[map[z].nBase - 1].x = x + (xmax / 2);
map[z].Base[map[z].nBase - 1].y = y + (ymax / 2);
map[z].Base[map[z].nBase - 1].t = t;
map[z].Base[map[z].nBase - 1].c = c;
map[z].Base[map[z].nBase - 1].walk = walk;
map[z].Base[map[z].nBase - 1].active = 1;
// End gracefully
return 0;
}
// Add a new info tile
int addInfo(uint_fast16_t x, uint_fast16_t y, uint_fast8_t z, uint_fast8_t xmax, uint_fast8_t ymax,
uint_fast8_t t, uint_fast8_t c, char dialog[255])
{
// Allocate space for the new tile.
map[z].nInfo++;
map[z].Info = realloc(map[z].Info, map[z].nInfo * sizeof(struct Info));
// If this fails, do nothing.
if (map[z].Info == NULL)
{
map[z].nInfo--;
return 1;
}
// Otherwise, set our values
map[z].Info[map[z].nInfo - 1].x = x + (xmax / 2);
map[z].Info[map[z].nInfo - 1].y = y + (ymax / 2);
map[z].Info[map[z].nInfo - 1].c = c;
map[z].Info[map[z].nInfo - 1].t = t;
strncpy(map[z].Info[map[z].nInfo - 1].dialog, dialog, 255);
map[z].Info[map[z].nInfo - 1].active = 1;
// End gracefully
return 0;
}
// Add a new item tile
int addItem(uint_fast16_t x, uint_fast16_t y, uint_fast8_t z, uint_fast8_t xmax, uint_fast8_t ymax,
uint_fast8_t t, uint_fast8_t c, uint_fast8_t ID)
{
// Allocate space for the new tile.
map[z].nItem++;
map[z].Item = realloc(map[z].Item, map[z].nItem * sizeof(struct Item));
// If this fails, do nothing.
if (map[z].Item == NULL)
{
map[z].nItem--;
return 1;
}
// Otherwise, set our values
map[z].Item[map[z].nItem - 1].x = x + (xmax / 2);
map[z].Item[map[z].nItem - 1].y = y + (ymax / 2);
map[z].Item[map[z].nItem - 1].t = t;
map[z].Item[map[z].nItem - 1].c = c;
map[z].Item[map[z].nItem - 1].ID = ID;
map[z].Item[map[z].nItem - 1].active = 1;
// End gracefully
return 0;
}
// Add a new door tile
int addDoor(uint_fast16_t x, uint_fast16_t y, uint_fast8_t z, uint_fast8_t xmax, uint_fast8_t ymax,
uint_fast8_t t, uint_fast8_t c, uint_fast8_t lock, uint_fast8_t ID, uint_fast8_t nx,
uint_fast8_t ny)
{
// Allocate space for the new tile.
map[z].nDoor++;
map[z].Door = realloc(map[z].Door, map[z].nDoor * sizeof(struct Door));
// If this fails, do nothing.
if (map[z].Door == NULL)
{
map[z].nDoor--;
return 1;
}
// Otherwise, set our values
map[z].Door[map[z].nDoor - 1].x = x + (xmax / 2);
map[z].Door[map[z].nDoor - 1].y = y + (ymax / 2);
map[z].Door[map[z].nDoor - 1].t = t;
map[z].Door[map[z].nDoor - 1].c = c;
map[z].Door[map[z].nDoor - 1].lock = lock;
map[z].Door[map[z].nDoor - 1].ID = ID;
map[z].Door[map[z].nDoor - 1].nx = nx;
map[z].Door[map[z].nDoor - 1].ny = ny;
map[z].Door[map[z].nDoor - 1].active = 1;
// End gracefully
return 0;
}
// Add a new char tile
int addChar(uint_fast16_t x, uint_fast16_t y, uint_fast8_t z, uint_fast8_t xmax, uint_fast8_t ymax,
uint_fast8_t t, uint_fast8_t c, uint_fast8_t type, uint_fast8_t move, char name[256],
char dialog1[256], char dialog2[256], struct mapmonster mons[5])
{
// Allocate space for the new tile.
map[z].nChar++;
map[z].Char = realloc(map[z].Char, map[z].nChar * sizeof(struct Char));
// If this fails, do nothing.
if (map[z].Char == NULL)
{
map[z].nChar--;
return 1;
}
// Otherwise, set our values
map[z].Char[map[z].nChar - 1].x = x + (xmax / 2);
map[z].Char[map[z].nChar - 1].y = y + (ymax / 2);
map[z].Char[map[z].nChar - 1].t = t;
map[z].Char[map[z].nChar - 1].c = c;
map[z].Char[map[z].nChar - 1].type = type;
map[z].Char[map[z].nChar - 1].move = move;
strncpy(map[z].Char[map[z].nChar - 1].name, name, 256);
strncpy(map[z].Char[map[z].nChar - 1].dialog1, dialog1, 256);
strncpy(map[z].Char[map[z].nChar - 1].dialog2, dialog2, 256);
map[z].Char[map[z].nChar - 1].mon[0].type = mons[0].type;
map[z].Char[map[z].nChar - 1].mon[1].type = mons[1].type;
map[z].Char[map[z].nChar - 1].mon[2].type = mons[2].type;
map[z].Char[map[z].nChar - 1].mon[3].type = mons[3].type;
map[z].Char[map[z].nChar - 1].mon[4].type = mons[4].type;
map[z].Char[map[z].nChar - 1].mon[0].level = mons[0].level;
map[z].Char[map[z].nChar - 1].mon[1].level = mons[1].level;
map[z].Char[map[z].nChar - 1].mon[2].level = mons[2].level;
map[z].Char[map[z].nChar - 1].mon[3].level = mons[3].level;
map[z].Char[map[z].nChar - 1].mon[4].level = mons[4].level;
map[z].Char[map[z].nChar - 1].active = 1;
// End gracefully
return 0;
}
// Deactivate any tiles that our cursor is over
int delTile(uint_fast16_t x, uint_fast16_t y, uint_fast8_t z, uint_fast8_t xmax, uint_fast8_t ymax)
{
// For every base tile
for (int C = 0; C < map[z].nBase; C++)
// If our cursor is over it,
if ((map[z].Base[C].x == x + (xmax / 2)) && (map[z].Base[C].y == y + (ymax / 2)))
// Deactivate it
map[z].Base[C].active = 0;
// For every info tile
for (int C = 0; C < map[z].nInfo; C++)
// If our cursor is over it,
if ((map[z].Info[C].x == x + (xmax / 2)) && (map[z].Info[C].y == y + (ymax / 2)))
// Deactivate it
map[z].Info[C].active = 0;
// For every item tile
for (int C = 0; C < map[z].nItem; C++)
// If our cursor is over it,
if ((map[z].Item[C].x == x + (xmax / 2)) && (map[z].Item[C].y == y + (ymax / 2)))
// Deactivate it
map[z].Item[C].active = 0;
// For every door tile
for (int C = 0; C < map[z].nDoor; C++)
// If our cursor is over it,
if ((map[z].Door[C].x == x + (xmax / 2)) && (map[z].Door[C].y == y + (ymax / 2)))
// Deactivate it
map[z].Door[C].active = 0;
// For every char tile
for (int C = 0; C < map[z].nChar; C++)
// If our cursor is over it,
if ((map[z].Char[C].x == x + (xmax / 2)) && (map[z].Char[C].y == y + (ymax / 2)))
// Deactivate it
map[z].Char[C].active = 0;
// Exit gracefully
return 0;
}
// Save our internal world map as an XML document.
int saveMaps(char filename[256])
{
// Open the file. Exit on failure.
FILE *fp = fopen(filename, "w");
if (fp == NULL)
return 1;
// Save our header, with the number of active maps.
fprintf(fp, "<document maps=\"%i\">\n", nMap);
// For every map
for (uint_fast8_t C = 0; C < nMap; C++)
{
// Print out a header giving valuable info for memory allocation.
fprintf(fp,
"\t<map bases=\"%li\" infos=\"%li\" items=\"%li\" doors=\"%li\" "
"chars=\"%li\">\n",
map[C].nBase, map[C].nInfo, map[C].nItem, map[C].nDoor, map[C].nChar);
// for every active base
for (uint_fast32_t B = 0; B < map[C].nBase; B++)
{
if (map[C].Base[B].active)
{
// Print out an XML tag with its info.
fprintf(fp,
"\t\t<base x=\"%li\" y=\"%li\" t=\"%i\" c=\"%i\" "
"walk=\"%i\" />\n",
map[C].Base[B].x, map[C].Base[B].y, map[C].Base[B].t,
map[C].Base[B].c, map[C].Base[B].walk);
}
}
// for every active info
for (uint_fast32_t B = 0; B < map[C].nInfo; B++)
{
if (map[C].Info[B].active)
{
// Print out an XML tag with its info.
fprintf(fp,
"\t\t<info x=\"%li\" y=\"%li\" t=\"%i\" c=\"%i\" "
"dialog=\"%s \" />\n",
map[C].Info[B].x, map[C].Info[B].y, map[C].Info[B].t,
map[C].Info[B].c, map[C].Info[B].dialog);
}
}
// for every active item
for (uint_fast32_t B = 0; B < map[C].nItem; B++)
{
if (map[C].Item[B].active)
{
// Print out an XML tag with its info.
fprintf(fp,
"\t\t<item x=\"%li\" y=\"%li\" t=\"%i\" c=\"%i\" ID=\"%i\" "
"/>\n",
map[C].Item[B].x, map[C].Item[B].y, map[C].Item[B].t,
map[C].Item[B].c, map[C].Item[B].ID);
}
}
// for every active door
for (uint_fast32_t B = 0; B < map[C].nDoor; B++)
{
if (map[C].Door[B].active)
{
// Print out an XML tag with its info.
fprintf(
fp,
"\t\t<door x=\"%li\" y=\"%li\" t=\"%i\" c=\"%i\" lock=\"%i\" "
"ID=\"%i\" nx=\"%li\" ny=\"%li\" />\n",
map[C].Door[B].x, map[C].Door[B].y, map[C].Door[B].t,
map[C].Door[B].c, map[C].Door[B].lock, map[C].Door[B].ID,
map[C].Door[B].nx, map[C].Door[B].ny);
}
}
// for every active char
for (uint_fast32_t B = 0; B < map[C].nChar; B++)
{
if (map[C].Char[B].active)
{
// Print out an XML tag with its info.
fprintf(
fp,
"\t\t<char x=\"%li\" y=\"%li\" t=\"%i\" c=\"%i\" type=\"%i\" "
"move=\"%i\" name=\"%s\" dialog1=\"%s\" dialog2=\"%s\">\n",
map[C].Char[B].x, map[C].Char[B].y, map[C].Char[B].t,
map[C].Char[B].c, map[C].Char[B].type, map[C].Char[B].move,
map[C].Char[B].name, map[C].Char[B].dialog1,
map[C].Char[B].dialog2);
// Add all the carried monsters
for (uint_fast8_t A = 0; A < 5; A++)
{
fprintf(fp, "\t\t\t<mon type=\"%i\" level=\"%i\" />\n",
map[C].Char[B].mon[A].type,
map[C].Char[B].mon[A].level);
}
fprintf(fp, "\t\t</char>\n");
}
}
fprintf(fp, "\t</map>\n");
}
fprintf(fp, "</document>\n");
// Exit gracefully
fclose(fp);
return 0;
}
// Load our world maps from an XML document.
int loadMaps(char filename[256])
{
int iMap = 0;
int iBase = 0;
int iInfo = 0;
int iItem = 0;
int iDoor = 0;
int iChar = 0;
char buffer[256] = "";
char substr[256] = "";
FILE *fp;
// Open file. Exit on failure
fp = fopen(filename, "r");
if (fp == NULL)
{
getnstr(buffer, 1);
return 1;
}
// While we haven't reached the end of our file
while (fgets(buffer, 256, fp) != NULL)
{
// If we're given a <document>
if (strcmp(strncpy(substr, buffer, 5), "<docu") == 0)
{
// Get our number of maps
sscanf(buffer, "<document maps=\"%hhi\">", &nMap);
// Allocate our memory
map = realloc(map, nMap * sizeof(struct maps));
if (map == NULL)
return 0;
// This makes it work for some reason.
strncpy(buffer, "", 256);
}
// If we're given a <map>
if (strcmp(strncpy(substr, buffer, 4), "\t<map") == 0)
{
// Get our bases, infos, items etc.
sscanf(buffer,
"\t<map bases=\"%li\" infos=\"%li\" items=\"%li\" doors=\"%li\""
" chars=\"%li\">",
&map[iMap].nBase, &map[iMap].nInfo, &map[iMap].nItem,
&map[iMap].nDoor, &map[iMap].nChar);
// Allocate our memory, return 1 on error.
map[iMap].Base =
realloc(map[iMap].Base, map[iMap].nBase * sizeof(struct Base));
if (map[iMap].Base == NULL)
return 1;
map[iMap].Info =
realloc(map[iMap].Info, map[iMap].nInfo * sizeof(struct Info));
if (map[iMap].Base == NULL)
return 1;
map[iMap].Item =
realloc(map[iMap].Item, map[iMap].nItem * sizeof(struct Item));
if (map[iMap].Item == NULL)
return 1;
map[iMap].Door =
realloc(map[iMap].Door, map[iMap].nDoor * sizeof(struct Door));
if (map[iMap].Door == NULL)
return 1;
map[iMap].Char =
realloc(map[iMap].Char, map[iMap].nChar * sizeof(struct Char));
if (map[iMap].Char == NULL)
return 1;
// This makes it work for some reason.
strncpy(buffer, "", 256);
}
// If we're given a </map>
if (strcmp(strncpy(substr, buffer, 7), "\t</map>") == 0)
{
// This makes it work for some reason.
strncpy(buffer, "", 256);
// Switch maps and reset our values
iMap++;
iBase = 0;
iInfo = 0;
iItem = 0;
iDoor = 0;
iChar = 0;
}
// If we're given a <base>
if (strcmp(strncpy(substr, buffer, 7), "\t\t<base") == 0)
{
// Get our x, y, t, c, etc.
sscanf(buffer,
"\t\t<base x=\"%li\" y=\"%li\" t=\"%hhi\" c=\"%hhi\" walk=\"%hhi\""
" />",
&map[iMap].Base[iBase].x, &map[iMap].Base[iBase].y,
&map[iMap].Base[iBase].t, &map[iMap].Base[iBase].c,
&map[iMap].Base[iBase].walk);
map[iMap].Base[iBase].active = 1;
// This makes it work for some reason.
strncpy(buffer, "", 256);
// Increment our values
iBase++;
}
// If we're given a <info>
if (strcmp(strncpy(substr, buffer, 7), "\t\t<info") == 0)
{
// Get our x, y, t, c, etc.
sscanf(buffer,
"\t\t<info x=\"%li\" y=\"%li\" t=\"%hhi\" c=\"%hhi\""
" dialog=\"%255[^\"]\" />",
&map[iMap].Info[iInfo].x, &map[iMap].Info[iInfo].y,
&map[iMap].Info[iInfo].t, &map[iMap].Info[iInfo].c,
map[iMap].Info[iInfo].dialog);
map[iMap].Info[iInfo].active = 1;
// Increment our values
iInfo++;
}
// If we're given a <item>
if (strcmp(strncpy(substr, buffer, 7), "\t\t<item") == 0)
{
// Get our x, y, t, c, etc.
sscanf(buffer,
"\t\t<item x=\"%li\" y=\"%li\" t=\"%hhi\" c=\"%hhi\" ID=\"%hhi\""
" />",
&map[iMap].Item[iItem].x, &map[iMap].Item[iItem].y,
&map[iMap].Item[iItem].t, &map[iMap].Item[iItem].c,
&map[iMap].Item[iItem].ID);
map[iMap].Item[iItem].active = 1;
// Increment our values
iItem++;
}
// If we're given a <door>
if (strcmp(strncpy(substr, buffer, 7), "\t\t<door") == 0)
{
// Get our x, y, t, c, etc.
sscanf(buffer,
"\t\t<door x=\"%li\" y=\"%li\" t=\"%hhi\" c=\"%hhi\" lock=\"%hhi\""
" ID=\"%hhi\" nx=\"%li\" ny=\"%li\" />",
&map[iMap].Door[iDoor].x, &map[iMap].Door[iDoor].y,
&map[iMap].Door[iDoor].t, &map[iMap].Door[iDoor].c,
&map[iMap].Door[iDoor].lock, &map[iMap].Door[iDoor].ID,
&map[iMap].Door[iDoor].nx, &map[iMap].Door[iDoor].ny);
map[iMap].Door[iDoor].active = 1;
// This makes it work for some reason.
strncpy(buffer, "", 256);
// Increment our values
iDoor++;
}
// If we're given a <char>
if (strcmp(strncpy(substr, buffer, 7), "\t\t<char") == 0)
{
// Get our x, y, t, c, etc.
sscanf(buffer,
"\t\t<char x=\"%li\" y=\"%li\" t=\"%hhi\" c=\"%hhi\" type=\"%hhi\""
" move=\"%hhi\" name=\"%255[^\"]\" dialog1=\"%255[^\"]\""
" dialog2=\"%255[^\"]\">",
&map[iMap].Char[iChar].x, &map[iMap].Char[iChar].y,
&map[iMap].Char[iChar].t, &map[iMap].Char[iChar].c,
&map[iMap].Char[iChar].type, &map[iMap].Char[iChar].move,
map[iMap].Char[iChar].name, map[iMap].Char[iChar].dialog1,
map[iMap].Char[iChar].dialog2);
map[iMap].Char[iChar].active = 1;
for (int C = 0; C < 5; C++)
{
// Get our new line
if (fgets(buffer, 256, fp) == NULL)
return 1;
// Get our type and level for each monster
sscanf(buffer, "\t\t\t<mon type=\"%hhi\" level=\"%hhi\" />",
&map[iMap].Char[iChar].mon[C].type,
&map[iMap].Char[iChar].mon[C].level);
}
// This makes things work for some reason.
strncpy(buffer, "", 256);
}
// If we get an </char>, increment our char value.
if (strcmp(strncpy(substr, buffer, 7), "\t\t</char>") == 0)
{
// This makes things work for some reason.
strncpy(buffer, "", 256);
iChar++;
}
// If we get an </document>,
if (strcmp(strncpy(substr, buffer, 7), "\t\t</docu") == 0)
{
// This makes things work for some reason.
strncpy(buffer, "", 256);
}
}
// Exit gracefully
return 0;
}