aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClyne Sullivan <tullivan99@gmail.com>2016-05-31 08:49:48 -0400
committerClyne Sullivan <tullivan99@gmail.com>2016-05-31 08:49:48 -0400
commitb22860234ff7991c851211042a9832d88ccbb958 (patch)
tree255f72ca00a3567c69b7f8f0bc7889aa3b12689d
parent7dd64863c9ca613cf6969442f621849762b20115 (diff)
entitys can modify xml
-rw-r--r--Changelog9
-rw-r--r--assets/dialog_en-us15
-rw-r--r--brice.dat4
-rw-r--r--include/common.hpp2
-rw-r--r--include/entities.hpp25
-rw-r--r--include/mob.hpp14
-rw-r--r--include/world.hpp20
-rw-r--r--main.cpp45
-rw-r--r--src/common.cpp33
-rw-r--r--src/entities.cpp132
-rw-r--r--src/mob.cpp25
-rw-r--r--src/ui.cpp4
-rw-r--r--src/world.cpp250
-rw-r--r--xml/playerSpawnHill1.xml98
14 files changed, 404 insertions, 272 deletions
diff --git a/Changelog b/Changelog
index c81def9..1dd6ef3 100644
--- a/Changelog
+++ b/Changelog
@@ -1018,3 +1018,12 @@
- fixed grass squishing
- player sits on cat better
- world shading is good-er
+
+5/31/2016:
+==========
+
+ - fixed name generation-er
+ - move random dialogs to file
+ - entitys can modify their XMLs
+ - 'alive' XML attribute works
+ - lighting's pretty neat
diff --git a/assets/dialog_en-us b/assets/dialog_en-us
new file mode 100644
index 0000000..dfe7b03
--- /dev/null
+++ b/assets/dialog_en-us
@@ -0,0 +1,15 @@
+What a beautiful day it is.
+Have you ever went fast? I have.
+I heard if you complete a quest, you'll get a special reward.
+How much wood could a woodchuck chuck if a woodchuck could chuck wood?
+I don't think anyone has ever been able to climb up that hill.
+If you ever see a hole in the ground, watch out; it could mean the end for you.
+Did you know this game has over 5000 lines of code? I didn't. I didn't even know I was in a game until now...
+HELP MY CAPS LOCK IS STUCK
+You know, if anyone ever asked me who I wanted to be when I grow up, I would say Abby Ross.
+I want to have the wallpaper in our house changed. It doesn't really fit the environment.
+Frig.
+The sine of theta equals the opposite over the hypotenuese.
+Did you know the developers spelt brazier as brazzier.
+What's a bagel? I don't know because I'm mormon
+
diff --git a/brice.dat b/brice.dat
index bda8adc..4bfeac6 100644
--- a/brice.dat
+++ b/brice.dat
@@ -1,5 +1,5 @@
2
-canSprint
-1
canJump
1
+canSprint
+1
diff --git a/include/common.hpp b/include/common.hpp
index 934ede5..4fa74d7 100644
--- a/include/common.hpp
+++ b/include/common.hpp
@@ -265,6 +265,8 @@ void strVectorSortAlpha(std::vector<std::string> *v);
// reads the given file into a buffer and returns a pointer to the buffer
const char *readFile(const char *path);
+std::string readFile(const std::string& path);
+std::vector<std::string> readFileA(const std::string& path);
// aborts the program, printing the given error
void UserError(std::string reason);
diff --git a/include/entities.hpp b/include/entities.hpp
index ca4ef2b..5a8e19b 100644
--- a/include/entities.hpp
+++ b/include/entities.hpp
@@ -17,6 +17,10 @@
#include <inventory.hpp>
#include <texture.hpp>
+// local library includes
+#include <tinyxml2.h>
+using namespace tinyxml2;
+
/* ----------------------------------------------------------------------------
** Structures section
** --------------------------------------------------------------------------*/
@@ -187,6 +191,10 @@ protected:
// the max cooldown display
float maxHitDuration;
+
+ // the entity's XML element, for saving/loading stuff
+ XMLElement *xmle;
+
public:
// contains the entity's coordinates, in pixels
vec2 loc;
@@ -235,7 +243,7 @@ public:
int subtype;
// the entity's name, randomly generated on spawn
- char *name;
+ std::string name;
// the entity's gender
GENDER gender;
@@ -289,6 +297,9 @@ public:
// returns true if the coordinate is within the entity
bool isInside(vec2 coord) const;
+ // constructs the entity with an XML thing-thang
+ virtual void createFromXML(XMLElement *e, World *w=nullptr) =0;
+
// a common constructor, clears variables
Entity(void);
@@ -296,7 +307,7 @@ public:
virtual ~Entity(){}
};
-class Player : public Entity{
+class Player : public Entity {
public:
Entity *ride;
QuestHandler qh;
@@ -305,9 +316,10 @@ public:
~Player();
void save(void);
void sspawn(float x,float y);
+ void createFromXML(XMLElement *e, World *w);
};
-class Structures : public Entity{
+class Structures : public Entity {
public:
BUILD_SUB bsubtype;
World *inWorld;
@@ -318,6 +330,7 @@ public:
~Structures();
unsigned int spawn(BUILD_SUB, float, float);
+ void createFromXML(XMLElement *e, World *w);
};
@@ -340,6 +353,7 @@ public:
virtual void interact();
virtual void wander(int);
+ void createFromXML(XMLElement *e, World *w);
};
class Merchant : public NPC {
@@ -379,8 +393,9 @@ public:
void interact(void);
bool operator==(const Object &o) {
- return !strcmp(name, o.name) && (loc == o.loc);
+ return (name == o.name) && (loc == o.loc);
}
+ void createFromXML(XMLElement *e, World *w);
};
/**
@@ -414,6 +429,8 @@ public:
void makeFlame(void){
flame = true;
}
+
+ void createFromXML(XMLElement *e);
};
#include <mob.hpp>
diff --git a/include/mob.hpp b/include/mob.hpp
index 4425159..450cf69 100644
--- a/include/mob.hpp
+++ b/include/mob.hpp
@@ -20,6 +20,7 @@ using Drop = std::tuple<std::string, unsigned int, float>;
class Mob : public Entity {
protected:
+ XMLElement *xmle;
std::forward_list<Drop> drop;
unsigned int actCounter;
@@ -41,7 +42,6 @@ public:
virtual void onDeath(void);
virtual bool bindTex(void) =0;
- virtual void createFromXML(const XMLElement *e) =0;
};
constexpr Mob *Mobp(Entity *e) {
@@ -59,7 +59,7 @@ public:
void act(void);
void onHit(unsigned int);
bool bindTex(void);
- void createFromXML(const XMLElement *e);
+ void createFromXML(XMLElement *e, World *w) final;
};
class Door : public Mob {
@@ -69,7 +69,7 @@ public:
void act(void);
void onHit(unsigned int);
bool bindTex(void);
- void createFromXML(const XMLElement *e);
+ void createFromXML(XMLElement *e, World *w) final;
};
class Cat : public Mob {
@@ -79,7 +79,7 @@ public:
void act(void);
void onHit(unsigned int);
bool bindTex(void);
- void createFromXML(const XMLElement *e);
+ void createFromXML(XMLElement *e, World *w) final;
};
class Rabbit : public Mob {
@@ -89,7 +89,7 @@ public:
void act(void);
void onHit(unsigned int);
bool bindTex(void);
- void createFromXML(const XMLElement *e);
+ void createFromXML(XMLElement *e, World *w) final;
};
class Bird : public Mob {
@@ -101,7 +101,7 @@ public:
void act(void);
void onHit(unsigned int);
bool bindTex(void);
- void createFromXML(const XMLElement *e);
+ void createFromXML(XMLElement *e, World *w) final;
};
class Trigger : public Mob {
@@ -114,7 +114,7 @@ public:
void act(void);
void onHit(unsigned int);
bool bindTex(void);
- void createFromXML(const XMLElement *e);
+ void createFromXML(XMLElement *e, World *w) final;
};
#endif // MOB_H_
diff --git a/include/world.hpp b/include/world.hpp
index ce50244..f6a432d 100644
--- a/include/world.hpp
+++ b/include/world.hpp
@@ -15,7 +15,7 @@
* This enum contains all different possibilities for world backgrounds; used
* in World::setBackground() to select the appropriate images.
*/
-enum class WorldBGType : unsigned char {
+enum class WorldBGType : unsigned int {
Forest, /**< A forest theme. */
WoodHouse /**< An indoor wooden house theme. */
};
@@ -465,14 +465,14 @@ public:
void addMob(Mob *m, vec2 coord);
- void addNPC(float x, float y);
+ void addNPC(NPC *n);
void addObject(std::string in, std::string pickupDialog, float x, float y);
void addParticle(float x, float y, float w, float h, float vx, float vy, Color color, int dur);
void addParticle(float x, float y, float w, float h, float vx, float vy, Color color, int dur, unsigned char flags);
- void addStructure(BUILD_SUB subtype, float x, float y, std::string tex, std::string inside);
+ void addStructure(Structures *s);
Village *addVillage(std::string name, World *world);
};
@@ -549,6 +549,12 @@ public:
};
/**
+ * Constructs an XML object for accessing/modifying the current world's XML
+ * file.
+ */
+const XMLDocument& loadWorldXML(void);
+
+/**
* Loads the player into the world created by the given XML file. If a world is
* already loaded it will be saved before the transition is made.
*/
@@ -560,8 +566,16 @@ World *loadWorldFromXML(std::string path);
*/
World *loadWorldFromXMLNoSave(std::string path);
+/**
+ * Loads a world using a pointer to the current world (used for loading adjacent
+ * worlds that have already been read into memory.
+ */
World *loadWorldFromPtr(World *ptr);
+/**
+ * Casts a normal world to an indoor world, to access IndoorWorld-exclusive
+ * elements.
+ */
constexpr IndoorWorld *Indoorp(World *w)
{
return (IndoorWorld *)w;
diff --git a/main.cpp b/main.cpp
index 66cf12c..dc586df 100644
--- a/main.cpp
+++ b/main.cpp
@@ -226,33 +226,38 @@ int main(int argc, char *argv[]){
// load mouse texture, and other inventory textures
mouseTex = Texture::loadTexture("assets/mouse.png");
- // read in all XML file names in the folder
- std::vector<std::string> xmlFiles;
+ // spawn the player
+ player = new Player();
+ player->sspawn(0,100);
+
+ // get a world
if (xmlFolder.empty())
xmlFolder = "xml/";
- if (getdir(std::string("./" + xmlFolder).c_str(), xmlFiles))
- UserError("Error reading XML files!!!");
-
- // alphabetically sort files
- strVectorSortAlpha(&xmlFiles);
-
- // load the first valid XML file for the world
- for (const auto &xf : xmlFiles) {
- if (xf[0] != '.' && strcmp(&xf[xf.size() - 3], "dat")){
- // read it in
- std::cout << "File to load: " << xf << '\n';
- currentWorld = loadWorldFromXML(xf);
- break;
+
+ if (currentWorld == nullptr) {
+ // read in all XML file names in the folder
+ std::vector<std::string> xmlFiles;
+ if (getdir(std::string("./" + xmlFolder).c_str(), xmlFiles))
+ UserError("Error reading XML files!!!");
+
+ // alphabetically sort files
+ strVectorSortAlpha(&xmlFiles);
+
+ // load the first valid XML file for the world
+ for (const auto &xf : xmlFiles) {
+ if (xf[0] != '.' && strcmp(&xf[xf.size() - 3], "dat")){
+ // read it in
+ std::cout << "File to load: " << xf << '\n';
+ currentWorld = loadWorldFromXML(xf);
+ break;
+ }
}
}
// make sure the world was made
- if (currentWorld == NULL)
+ if (currentWorld == nullptr)
UserError("Plot twist: The world never existed...?");
- // spawn the player
- player = new Player();
- player->sspawn(0,100);
ui::menu::init();
currentWorld->bgmPlay(nullptr);
@@ -385,7 +390,7 @@ void render() {
* Call the world's draw function, drawing the player, the world, the background, and entities. Also
* draw the player's inventory if it exists.
*/
- //player->near = true; // allow player's name to be drawn
+ player->near = true; // allow player's name to be drawn
currentWorld->draw(player);
// draw the player's inventory
diff --git a/src/common.cpp b/src/common.cpp
index c643174..bb1ad1e 100644
--- a/src/common.cpp
+++ b/src/common.cpp
@@ -174,6 +174,39 @@ const char *readFile(const char *path)
return buf;
}
+std::string readFile(const std::string& path)
+{
+ std::ifstream in (path, std::ios::in);
+ std::string buffer;
+
+ if (!in.is_open())
+ UserError("Error reading file " + path);
+
+ in.seekg(0, in.end);
+ buffer.reserve(in.tellg());
+ in.seekg(0, in.beg);
+ in.read(&buffer[0], buffer.size());
+
+ in.close();
+ return buffer;
+}
+
+std::vector<std::string> readFileA(const std::string& path)
+{
+ std::ifstream in (path, std::ios::in);
+ std::vector<std::string> lines;
+ std::string line;
+
+ if (!in.is_open())
+ UserError("Error reading file " + path);
+
+ while(std::getline(in, line))
+ lines.push_back(line);
+
+ in.close();
+ return lines;
+}
+
void UserError(std::string reason)
{
std::cout << "User error: " << reason << "!\n";
diff --git a/src/entities.cpp b/src/entities.cpp
index 550748a..18c91ed 100644
--- a/src/entities.cpp
+++ b/src/entities.cpp
@@ -15,6 +15,7 @@ extern World *currentWorld; // main.cpp
extern unsigned int loops; // main.cpp
extern std::string xmlFolder;
+extern XMLDocument currentXMLDoc;
// a dynamic array of pointers to the NPC's that are being assigned the preloads
std::vector<NPC *> aipreload;
@@ -24,52 +25,17 @@ const unsigned int PLAYER_INV_SIZE = 43;
// the size of an NPC's inventory
const unsigned int NPC_INV_SIZE = 3;
-static const unsigned int RAND_DIALOG_COUNT = 14;
-const char *randomDialog[RAND_DIALOG_COUNT] = {
- "What a beautiful day it is.",
- "Have you ever went fast? I have.",
- "I heard if you complete a quest, you'll get a special reward.",
- "How much wood could a woodchuck chuck if a woodchuck could chuck wood?",
- "I don\'t think anyone has ever been able to climb up that hill.",
- "If you ever see a hole in the ground, watch out; it could mean the end for you.",
- "Did you know this game has over 5000 lines of code? I didn\'t. I didn't even know I was in a game until now...",
- "HELP MY CAPS LOCK IS STUCK",
- "You know, if anyone ever asked me who I wanted to be when I grow up, I would say Abby Ross.",
- "I want to have the wallpaper in our house changed. It doesn\'t really fit the environment.",
- "Frig.",
- "The sine of theta equals the opposite over the hdaypotenuese.",
- "Did you know the developers spelt brazier as brazzier.",
- "What's a bagel? I don't know because I'm mormon"
-};
-
-void randGetomName(Entity *e)
-{
- unsigned int tempNum,max=0;
- char *bufs;
-
- std::ifstream names ("assets/names_en-us",std::ios::in);
-
- names.seekg(0,names.beg);
-
- bufs = new char[32];
-
- for(;!names.eof();max++)
- names.getline(bufs,32);
+static std::vector<std::string> randomDialog (readFileA("assets/dialog_en-us"));
- tempNum = rand() % max;
- names.seekg(0,names.beg);
-
- for(unsigned int i=0;i<tempNum;i++)
- names.getline(bufs,32);
-
- names.close();
+void getRandomName(Entity *e)
+{
+ auto names = readFileA("assets/names_en-us");
+ auto name = names[randGet() % names.size()];
// gender is a binary construct
- e->gender = (bufs[0] == 'm') ? MALE : FEMALE;
-
- strcpy(e->name, bufs + 1);
+ e->gender = (name[0] == 'm') ? MALE : FEMALE;
- delete[] bufs;
+ e->name = &name[1];
}
Entity::Entity(void)
@@ -101,7 +67,6 @@ Entity::Entity(void)
hitDuration = maxHitDuration = 0;
inv = nullptr;
- name = nullptr;
}
// spawns the entity you pass to it based off of coords and global entity settings
@@ -114,11 +79,10 @@ void Entity::spawn(float x, float y)
health = maxHealth = 1;
// generate a name
- name = new char[32];
if (type == MOBT)
- strncpy(name, "mob", 3);
+ name = "mob";
else
- randGetomName(this);
+ getRandomName(this);
setCooldown(0);
}
@@ -168,6 +132,11 @@ void Entity::die(void)
{
alive = false;
health = 0;
+
+ if (xmle) {
+ xmle->SetAttribute("alive", false);
+ currentXMLDoc.SaveFile(currentXML.c_str(), false);
+ }
}
bool Entity::isAlive(void) const
@@ -218,7 +187,12 @@ Player::Player() : Entity()
Player::~Player()
{
delete inv;
- delete[] name;
+}
+
+void Player::createFromXML(XMLElement *e, World *w=nullptr)
+{
+ (void)e;
+ (void)w;
}
NPC::NPC() : Entity()
@@ -237,7 +211,7 @@ NPC::NPC() : Entity()
tex = TextureIterator({"assets/NPC.png"});
inv = new Inventory(NPC_INV_SIZE);
- randDialog = rand() % RAND_DIALOG_COUNT - 1;
+ randDialog = randGet() % randomDialog.size();
dialogIndex = 0;
dialogCount = 0;
@@ -249,7 +223,42 @@ NPC::NPC() : Entity()
NPC::~NPC()
{
delete inv;
- delete[] name;
+}
+
+void NPC::createFromXML(XMLElement *e, World *w=nullptr)
+{
+ std::string npcname;
+ bool dialog;
+ float spawnx, Xhealth;
+ unsigned int flooor;
+
+ // spawn at coordinates if desired
+ if (e->QueryFloatAttribute("x", &spawnx) == XML_NO_ERROR)
+ spawn(spawnx, 100);
+ else
+ spawn(0, 100);
+
+ // name override
+ if (!(npcname = e->StrAttribute("name")).empty())
+ name = npcname;
+
+ // dialog enabling
+ dialog = false;
+ if (e->QueryBoolAttribute("hasDialog", &dialog) == XML_NO_ERROR && dialog)
+ addAIFunc(false);
+ else
+ dialogIndex = 9999;
+
+
+ if (/*Indoor && */e->QueryUnsignedAttribute("floor", &flooor) == XML_NO_ERROR)
+ Indoorp(w)->moveToFloor(this, flooor);
+
+ // custom health value
+ if (e->QueryFloatAttribute("health", &Xhealth) == XML_NO_ERROR) {
+ health = maxHealth = Xhealth;
+ }
+
+ xmle = e;
}
Merchant::Merchant() : NPC()
@@ -283,8 +292,6 @@ Merchant::Merchant() : NPC()
Merchant::~Merchant()
{
- //delete inv;
- delete[] name;
}
Structures::Structures() : Entity()
@@ -295,7 +302,19 @@ Structures::Structures() : Entity()
Structures::~Structures()
{
- delete[] name;
+}
+
+void Structures::createFromXML(XMLElement *e, World *w)
+{
+ float spawnx;
+
+ inWorld = w;
+ inside = e->StrAttribute("inside");
+ textureLoc = e->StrAttribute("texture");
+
+ spawn(static_cast<BUILD_SUB>(e->UnsignedAttribute("type")),
+ e->QueryFloatAttribute("x", &spawnx) == XML_NO_ERROR ? spawnx : (randGet() % w->getTheWidth() / 2.0f),
+ 100);
}
Object::Object()
@@ -319,7 +338,12 @@ Object::Object(std::string in, std::string pd)
Object::~Object()
{
- delete[] name;
+}
+
+void Object::createFromXML(XMLElement *e, World *w=nullptr)
+{
+ (void)e;
+ (void)w;
}
void Object::reloadTexture(void)
@@ -773,7 +797,7 @@ void Merchant::wander(int timeRun) {
void Merchant::interact() {
std::thread([this]{
- ui::merchantBox(name, trade[currTrade], ":Accept:Good-Bye", false, toSay->c_str());
+ ui::merchantBox(name.c_str(), trade[currTrade], ":Accept:Good-Bye", false, toSay->c_str());
ui::waitForDialog();
// handle normal dialog options
diff --git a/src/mob.cpp b/src/mob.cpp
index d6df3fd..526d7b1 100644
--- a/src/mob.cpp
+++ b/src/mob.cpp
@@ -10,6 +10,7 @@ Mob::Mob(void)
type = MOBT;
inv = nullptr;
rider = nullptr;
+ xmle = nullptr;
canMove = true;
loc = 0;
}
@@ -53,8 +54,9 @@ bool Page::bindTex(void)
return true;
}
-void Page::createFromXML(const XMLElement *e)
+void Page::createFromXML(XMLElement *e, World *w=nullptr)
{
+ (void)w;
float Xlocx;
if (e->QueryFloatAttribute("x", &Xlocx) == XML_NO_ERROR)
loc.x = Xlocx;
@@ -91,8 +93,9 @@ bool Door::bindTex(void)
return true;
}
-void Door::createFromXML(const XMLElement *e)
+void Door::createFromXML(XMLElement *e, World *w=nullptr)
{
+ (void)w;
float Xlocx;
if (e->QueryFloatAttribute("x", &Xlocx) == XML_NO_ERROR)
loc.x = Xlocx;
@@ -148,8 +151,9 @@ bool Cat::bindTex(void)
return true;
}
-void Cat::createFromXML(const XMLElement *e)
+void Cat::createFromXML(XMLElement *e, World *w=nullptr)
{
+ (void)w;
float Xlocx;
if (e->QueryFloatAttribute("x", &Xlocx) == XML_NO_ERROR)
loc.x = Xlocx;
@@ -203,15 +207,19 @@ bool Rabbit::bindTex(void)
return true;
}
-void Rabbit::createFromXML(const XMLElement *e)
+void Rabbit::createFromXML(XMLElement *e, World *w=nullptr)
{
+ (void)w;
float Xlocx, Xhealth;
if (e->QueryFloatAttribute("x", &Xlocx) == XML_NO_ERROR)
loc.x = Xlocx;
if (e->QueryFloatAttribute("health", &Xhealth) == XML_NO_ERROR)
maxHealth = health = Xhealth;
- if (e->QueryBoolAttribute("aggressive", &aggressive) != XML_NO_ERROR)
+ if (e->QueryBoolAttribute("aggressive", &aggressive) != XML_NO_ERROR) {
aggressive = false;
+ }
+
+ xmle = e;
}
Bird::Bird(void) : Mob()
@@ -257,8 +265,9 @@ bool Bird::bindTex(void)
return true;
}
-void Bird::createFromXML(const XMLElement *e)
+void Bird::createFromXML(XMLElement *e, World *w=nullptr)
{
+ (void)w;
float Xlocx, Xhealth;
if (e->QueryFloatAttribute("x", &Xlocx) == XML_NO_ERROR)
loc.x = Xlocx;
@@ -333,8 +342,9 @@ bool Trigger::bindTex(void)
return false;
}
-void Trigger::createFromXML(const XMLElement *e)
+void Trigger::createFromXML(XMLElement *e, World *w=nullptr)
{
+ (void)w;
float Xlocx;
if (e->QueryFloatAttribute("x", &Xlocx) == XML_NO_ERROR)
loc.x = Xlocx;
@@ -344,7 +354,6 @@ void Trigger::createFromXML(const XMLElement *e)
Mob::~Mob()
{
delete inv;
- delete[] name;
}
extern World *currentWorld;
diff --git a/src/ui.cpp b/src/ui.cpp
index 7ae444c..5a7ada1 100644
--- a/src/ui.cpp
+++ b/src/ui.cpp
@@ -1408,7 +1408,9 @@ EXIT:
if (debug)
posFlag ^= true;
else {
- currentWorld->addStructure(FIRE_PIT, player->loc.x, player->loc.y, "", "");
+ auto s = new Structures();
+ s->spawn(FIRE_PIT, player->loc.x, player->loc.y);
+ currentWorld->addStructure(s);
currentWorld->addLight({player->loc.x + SCREEN_WIDTH/2, player->loc.y},{1.0f,1.0f,1.0f});
//currentWorld->getLastLight()->follow(currentWorld->build.back());
currentWorld->getLastLight()->makeFlame();
diff --git a/src/world.cpp b/src/world.cpp
index 2ecccec..f13c3b7 100644
--- a/src/world.cpp
+++ b/src/world.cpp
@@ -8,6 +8,7 @@
#include <algorithm>
#include <sstream>
#include <fstream>
+#include <memory>
// local game headers
#include <ui.hpp>
@@ -317,7 +318,7 @@ void World::drawBackgrounds(void)
if (worldShade > 0) {
auto xcoord = offset.x * 0.9f;
-
+
for (auto &s : star) {
*(si++) = s.x + xcoord;
*(si++) = s.y,
@@ -497,17 +498,17 @@ void World::draw(Player *p)
pOffset = (offset.x + p->width / 2 - worldStart) / HLINE;
// only draw world within player vision
- iStart = static_cast<int>(fmax(pOffset - (SCREEN_WIDTH / 2 / HLINE) - GROUND_HILLINESS, 0));
+ iStart = std::clamp(static_cast<int>(pOffset - (SCREEN_WIDTH / 2 / HLINE) - GROUND_HILLINESS),
+ 0, static_cast<int>(lineCount));
iEnd = std::clamp(static_cast<int>(pOffset + (SCREEN_WIDTH / 2 / HLINE)),
- static_cast<int>(GROUND_HILLINESS),
- static_cast<int>(worldData.size()));
+ 0, static_cast<int>(lineCount));
// draw the dirt
bgTex++;
std::vector<std::pair<vec2,vec3>> c;
for (int i = iStart; i < iEnd; i++) {
- if (worldData[i].groundHeight <= 0) {
+ if (worldData[i].groundHeight <= 0) { // TODO holes (andy)
worldData[i].groundHeight = GROUND_HEIGHT_MINIMUM - 1;
glColor4ub(0, 0, 0, 255);
} else {
@@ -1069,6 +1070,9 @@ getSTextureLocation(unsigned int index) const
vec2 World::
getStructurePos(int index)
{
+ if (build.empty())
+ return vec2 {0, 0};
+
if (index < 0)
return build.back()->loc;
else if ((unsigned)index >= build.size())
@@ -1431,13 +1435,9 @@ WorldSwitchInfo World::goInsideStructure(Player *p)
}
void World::
-addStructure(BUILD_SUB sub, float x,float y, std::string tex, std::string inside)
+addStructure(Structures *s)
{
- build.push_back(new Structures());
- build.back()->inWorld = this;
- build.back()->textureLoc = tex;
- build.back()->spawn(sub, x, y);
- build.back()->inside = inside;
+ build.push_back(s);
entity.push_back(build.back());
}
@@ -1457,11 +1457,9 @@ void World::addMob(Mob *m, vec2 coord)
}
void World::
-addNPC(float x, float y)
+addNPC(NPC *n)
{
- npc.push_back(new NPC());
- npc.back()->spawn(x, y);
-
+ npc.push_back(n);
entity.push_back(npc.back());
}
@@ -1897,37 +1895,63 @@ World *loadWorldFromPtr(World *ptr)
/**
* Loads a world from the given XML file.
*/
+
+static std::string currentXMLRaw;
+XMLDocument currentXMLDoc;
+
+const XMLDocument& loadWorldXML(void)
+{
+ static XMLDocument xml;
+ if (xml.Parse(currentXMLRaw.data()) != XML_NO_ERROR)
+ UserError("XML Error: Failed to parse file (not your fault though..?)");
+
+ return xml;
+}
+
World *
loadWorldFromXMLNoSave(std::string path) {
-XMLDocument currentXMLDoc;
+ XMLDocument *_currentXMLDoc;
+ std::string _currentXML,
+ _currentXMLRaw;
+
XMLElement *wxml;
XMLElement *vil;
World *tmp;
- float spawnx, randx;
- bool dialog,Indoor;
- unsigned int flooor;
+ Entity *newEntity;
+ float spawnx;
+ bool Indoor;
const char *ptr;
std::string name, sptr;
// no file? -> no world
if (path.empty())
- return NULL;
+ return nullptr;
- currentXML = std::string(xmlFolder + path);
- currentXMLDoc.LoadFile(currentXML.c_str());
+ _currentXML = xmlFolder + path;
+ _currentXMLRaw = readFile(_currentXML.c_str());
+
+ // create a temporary XMLDocument if this isn't the main world
+ if (!loadedLeft && !loadedRight)
+ _currentXMLDoc = &currentXMLDoc;
+ else
+ _currentXMLDoc = new XMLDocument();
+
+ // parse the file
+ if (_currentXMLDoc->Parse(_currentXMLRaw.data()) != XML_NO_ERROR)
+ UserError("XML Error: Failed to parse file (not your fault though..?)");
// attempt to load a <World> tag
- if ((wxml = currentXMLDoc.FirstChildElement("World"))) {
+ if ((wxml = _currentXMLDoc->FirstChildElement("World"))) {
wxml = wxml->FirstChildElement();
- vil = currentXMLDoc.FirstChildElement("World")->FirstChildElement("village");
+ vil = _currentXMLDoc->FirstChildElement("World")->FirstChildElement("village");
tmp = new World();
Indoor = false;
}
// attempt to load an <IndoorWorld> tag
- else if ((wxml = currentXMLDoc.FirstChildElement("IndoorWorld"))) {
+ else if ((wxml = _currentXMLDoc->FirstChildElement("IndoorWorld"))) {
wxml = wxml->FirstChildElement();
vil = NULL;
tmp = new IndoorWorld();
@@ -1936,10 +1960,11 @@ XMLDocument currentXMLDoc;
// error: can't load a world...
else
- UserError("XML Error: Cannot find a <World> or <IndoorWorld> tag in " + currentXML + "!");
+ UserError("XML Error: Cannot find a <World> or <IndoorWorld> tag in " + _currentXML + "!");
// iterate through world tags
while (wxml) {
+ newEntity = nullptr;
name = wxml->Name();
// world linkage
@@ -1951,10 +1976,12 @@ XMLDocument currentXMLDoc;
// load the left world if it isn't
if (!loadedLeft) {
- loadedLeft = true;
+ loadedRight = true;
currentWorldToLeft = loadWorldFromXMLNoSave(ptr);
- loadedLeft = false;
- }
+ loadedRight = false;
+ } else {
+ currentWorldToLeft = nullptr;
+ }
}
// links world to the right
@@ -1963,10 +1990,12 @@ XMLDocument currentXMLDoc;
// load the right world if it isn't
if (!loadedRight) {
- loadedRight = true;
+ loadedLeft = true;
currentWorldToRight = loadWorldFromXMLNoSave(ptr);
- loadedRight = false;
- }
+ loadedLeft = false;
+ } else {
+ currentWorldToRight = nullptr;
+ }
}
// tells what world is outside, if in a structure
@@ -1975,7 +2004,7 @@ XMLDocument currentXMLDoc;
// error, invalid link tag
else
- UserError("XML Error: Invalid <link> tag in " + currentXML + "!");
+ UserError("XML Error: Invalid <link> tag in " + _currentXML + "!");
}
@@ -1985,9 +2014,10 @@ XMLDocument currentXMLDoc;
tmp->setStyle(wxml->StrAttribute("folder"));
// set background folder
- if (wxml->QueryUnsignedAttribute("background", &flooor) != XML_NO_ERROR)
- UserError("XML Error: No background given in <style> in " + currentXML + "!");
- tmp->setBackground((WorldBGType)flooor);
+ unsigned int bgt;
+ if (wxml->QueryUnsignedAttribute("background", &bgt) != XML_NO_ERROR)
+ UserError("XML Error: No background given in <style> in " + _currentXML + "!");
+ tmp->setBackground(static_cast<WorldBGType>(bgt));
// set BGM file
tmp->setBGM(wxml->StrAttribute("bgm"));
@@ -2000,112 +2030,99 @@ XMLDocument currentXMLDoc;
tmp->generate(wxml->UnsignedAttribute("width"));
else {
if (Indoor)
- UserError("XML Error: <generation> tags can't be in <IndoorWorld> tags (in " + currentXML + ")!");
+ UserError("XML Error: <generation> tags can't be in <IndoorWorld> tags (in " + _currentXML + ")!");
else
- UserError("XML Error: Invalid <generation> tag in " + currentXML + "!");
+ UserError("XML Error: Invalid <generation> tag in " + _currentXML + "!");
}
}
// mob creation
- else if (name == "rabbit") {
- tmp->addMob(new Rabbit(), vec2 {0, 0});
- tmp->getLastMob()->createFromXML(wxml);
- } else if (name == "bird") {
- tmp->addMob(new Bird(), vec2 {0, 0});
- tmp->getLastMob()->createFromXML(wxml);
- } else if (name == "trigger") {
- tmp->addMob(new Trigger(), vec2 {0, 0});
- tmp->getLastMob()->createFromXML(wxml);
- } else if (name == "door") {
- tmp->addMob(new Door(), vec2 {0, 0});
- tmp->getLastMob()->createFromXML(wxml);
- } else if (name == "page") {
- tmp->addMob(new Page(), vec2 {0, 0});
- tmp->getLastMob()->createFromXML(wxml);
- } else if (name == "cat") {
- tmp->addMob(new Cat(), vec2 {0, 0});
- tmp->getLastMob()->createFromXML(wxml);
- }
+ else if (name == "rabbit") {
+ newEntity = new Rabbit();
+ } else if (name == "bird") {
+ newEntity = new Bird();
+ } else if (name == "trigger") {
+ newEntity = new Trigger();
+ } else if (name == "door") {
+ newEntity = new Door();
+ } else if (name == "page") {
+ newEntity = new Page();
+ } else if (name == "cat") {
+ newEntity = new Cat();
+ }
// npc creation
else if (name == "npc") {
- const char *npcname;
-
- // spawn at coordinates if desired
- if (wxml->QueryFloatAttribute("x", &spawnx) == XML_NO_ERROR)
- tmp->addNPC(spawnx, 100);
- else
- tmp->addNPC(0, 100);
-
- // name override
- if ((npcname = wxml->Attribute("name"))) {
- delete[] tmp->npc.back()->name;
- tmp->npc.back()->name = new char[strlen(npcname) + 1];
- strcpy(tmp->npc.back()->name, npcname);
- }
-
- // dialog enabling
- dialog = false;
- if (wxml->QueryBoolAttribute("hasDialog", &dialog) == XML_NO_ERROR && dialog) {
- tmp->npc.back()->addAIFunc(false);
- } else
- tmp->npc.back()->dialogIndex = 9999;
-
- if (Indoor && wxml->QueryUnsignedAttribute("floor", &flooor) == XML_NO_ERROR)
- Indoorp(tmp)->moveToFloor(tmp->npc.back(), flooor);
-
- // custom health value
- if (wxml->QueryFloatAttribute("health", &spawnx) == XML_NO_ERROR)
- tmp->npc.back()->health = tmp->npc.back()->maxHealth = spawnx;
+ newEntity = new NPC();
}
// structure creation
else if (name == "structure") {
- tmp->addStructure((BUILD_SUB) wxml->UnsignedAttribute("type"),
- wxml->QueryFloatAttribute("x", &spawnx) != XML_NO_ERROR ?
- randGet() % tmp->getTheWidth() / 2.0f : spawnx,
- 100,
- wxml->StrAttribute("texture"),
- wxml->StrAttribute("inside")
- );
- } else if (name == "hill") {
+ newEntity = new Structures();
+ }
+
+ // hill creation
+ else if (name == "hill") {
tmp->addHill(ivec2 { wxml->IntAttribute("peakx"), wxml->IntAttribute("peaky") }, wxml->UnsignedAttribute("width"));
- } else if (name == "time") {
+ }
+
+ // time setting
+ else if (name == "time") {
game::time::setTickCount(std::stoi(wxml->GetText()));
- } else if (Indoor && name == "floor") {
+ }
+
+ // floor adding
+ else if (Indoor && name == "floor") {
if (wxml->QueryFloatAttribute("start",&spawnx) == XML_NO_ERROR)
Indoorp(tmp)->addFloor(wxml->UnsignedAttribute("width"), spawnx);
else
Indoorp(tmp)->addFloor(wxml->UnsignedAttribute("width"));
}
+ if (newEntity != nullptr) {
+ bool alive = true;
+ if (wxml->QueryBoolAttribute("alive", &alive) != XML_NO_ERROR || alive) {
+ newEntity->createFromXML(wxml, tmp);
+
+ switch (newEntity->type) {
+ case NPCT:
+ tmp->addNPC(dynamic_cast<NPC *>(newEntity));
+ break;
+ case MOBT:
+ tmp->addMob(dynamic_cast<Mob *>(newEntity), vec2 {0, 0});
+ break;
+ case STRUCTURET:
+ tmp->addStructure(dynamic_cast<Structures *>(newEntity));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
spawnx = 0;
wxml = wxml->NextSiblingElement();
}
Village *vptr;
+ Structures *s;
if (vil) {
vptr = tmp->addVillage(vil->StrAttribute("name"), tmp);
vil = vil->FirstChildElement();
}
- std::cout << currentXML << ' ' << tmp->build.size() << '\n';
-
while(vil) {
name = vil->Name();
- randx = 0;
/**
* READS DATA ABOUT STRUCTURE CONTAINED IN VILLAGE
*/
if (name == "structure") {
- tmp->addStructure((BUILD_SUB)vil->UnsignedAttribute("type"),
- vil->QueryFloatAttribute("x", &spawnx) != XML_NO_ERROR ? randx : spawnx,
- 100,
- vil->StrAttribute("texture"),
- vil->StrAttribute("inside"));
+ s = new Structures();
+ s->createFromXML(vil, tmp);
+ tmp->addStructure(s);
} else if (name == "stall") {
sptr = vil->StrAttribute("type");
@@ -2113,23 +2130,17 @@ XMLDocument currentXMLDoc;
if (sptr == "market") {
// create a structure and a merchant, and pair them
- tmp->addStructure(STALL_MARKET,
- vil->QueryFloatAttribute("x", &spawnx) != XML_NO_ERROR ? randx : spawnx,
- 100,
- vil->StrAttribute("texture"),
- vil->StrAttribute("inside")
- );
+ s = new Structures();
+ s->createFromXML(vil, tmp);
+ tmp->addStructure(s);
tmp->addMerchant(0, 100, true);
}
// handle traders
else if (sptr == "trader") {
- tmp->addStructure(STALL_TRADER,
- vil->QueryFloatAttribute("x", &spawnx) != XML_NO_ERROR ? randx : spawnx,
- 100,
- vil->StrAttribute("texture"),
- vil->StrAttribute("inside")
- );
+ s = new Structures();
+ s->createFromXML(vil, tmp);
+ tmp->addStructure(s);
}
// loop through buy/sell/trade tags
@@ -2185,12 +2196,19 @@ XMLDocument currentXMLDoc;
vil = vil->NextSiblingElement();
}
- std::ifstream dat (((std::string)currentXML + ".dat").data());
+ std::ifstream dat ((_currentXML + ".dat").data());
if (dat.good()) {
dat.close();
tmp->load();
}
+ if (!loadedLeft && !loadedRight) {
+ currentXML = _currentXML;
+ currentXMLRaw = _currentXMLRaw;
+ } else {
+ delete _currentXMLDoc;
+ }
+
return tmp;
}
diff --git a/xml/playerSpawnHill1.xml b/xml/playerSpawnHill1.xml
index 7be0e08..13fa3db 100644
--- a/xml/playerSpawnHill1.xml
+++ b/xml/playerSpawnHill1.xml
@@ -1,39 +1,33 @@
<?xml version="1.0"?>
<World>
- <style background="0" bgm="assets/music/embark.wav" folder="assets/style/classic/" />
- <generation type="Random" width="500" />
- <link right="playerSpawnHill2.xml" />
- <time>12000</time>
-
- <hill peakx="0" peaky="1000" width="50" />
-
- <rabbit x="300" aggressive="false" health="100" />
- <bird y="500"/>
- <cat />
-
- <trigger x="-300" id="Test" />
-
- <npc name="Ralph" hasDialog="true" x="300" />
- <npc name="Johnny" hasDialog="false" x="300" />
- <npc name="Big Dave" hasDialog="true" x="300" />
-
- <page x="-200" id="assets/pages/gootaGoFast.png" cid="canSprint" cvalue="1" />
- <page x="-500" id="assets/pages/gootaJump.png" cid="canJump" cvalue="1" />
-
- <village name="Big Dave's bagel emporium! The greatest place on earth!">
- <structure type="0" x="-300" inside="playerSpawnHill1_Building1.xml"/>
- <structure type="5" x="-500" />
- <stall type="market" texture="assets/style/classic/stall.png">
- <text>
- <greet>Welcome to Smithy's! What would you like to purchase today?</greet>
- <accept>Thanks!</accept>
- <deny>Come back with more money to get this item!</deny>
- <leave>Have a great day, and watch out for my rabbit Mr. Cuddles, he might try to attack you.</leave>
- </text>
- <trade quantity="420" item="Dank MayMay" quantity1="1" item1="Wood Sword"/>
- <trade quantity="666" item="Wood Sword" quantity1="420" item1="Dank MayMay"/>
- </stall>
- </village>
+ <style background="0" bgm="assets/music/embark.wav" folder="assets/style/classic/"/>
+ <generation type="Random" width="500"/>
+ <link right="playerSpawnHill2.xml"/>
+ <time>12000</time>
+ <hill peakx="0" peaky="1000" width="50"/>
+ <rabbit x="300" aggressive="false" health="100" alive="0"/>
+ <bird y="500"/>
+ <cat/>
+ <trigger x="-300" id="Test"/>
+ <npc name="Ralph" hasDialog="true" x="300"/>
+ <npc name="Johnny" hasDialog="false" x="300"/>
+ <npc name="Big Dave" hasDialog="true" x="300"/>
+ <page x="-200" id="assets/pages/gootaGoFast.png" cid="canSprint" cvalue="1"/>
+ <page x="-500" id="assets/pages/gootaJump.png" cid="canJump" cvalue="1"/>
+ <village name="Big Dave&apos;s bagel emporium! The greatest place on earth!">
+ <structure type="0" x="-300" inside="playerSpawnHill1_Building1.xml"/>
+ <structure type="5" x="-500"/>
+ <stall type="market" texture="assets/style/classic/stall.png">
+ <text>
+ <greet>Welcome to Smithy's! What would you like to purchase today?</greet>
+ <accept>Thanks!</accept>
+ <deny>Come back with more money to get this item!</deny>
+ <leave>Have a great day, and watch out for my rabbit Mr. Cuddles, he might try to attack you.</leave>
+ </text>
+ <trade quantity="420" item="Dank MayMay" quantity1="1" item1="Wood Sword"/>
+ <trade quantity="666" item="Wood Sword" quantity1="420" item1="Dank MayMay"/>
+ </stall>
+ </village>
</World>
<Trigger id="Test">It was a dark and stormy night...
@@ -42,49 +36,39 @@ And it wasn't stormy.
...</Trigger>
<Dialog name="Ralph">
-
- <text id="0" nextid="1">
+ <text id="0" nextid="1">
Hello there! My name is Ralph.
- <gotox>300</gotox>
- </text>
-
- <text id="1" nextid="2" call="Johnny" callid="0" pause="true" >
+ <gotox>300</gotox>
+ </text>
+ <text id="1" nextid="2" call="Johnny" callid="0" pause="true">
You should go talk to my friend Johnny. He's a pretty chill dude.
</text>
-
- <text id="2" >
+ <text id="2">
Niice.
- <quest check="Your First Quest" fail="3" />
- </text>
-
- <text id="3">
+ <quest check="Your First Quest" fail="3"/></text>
+ <text id="3">
Go check out Johnny. He's cool.
</text>
</Dialog>
<Dialog name="Johnny">
- <text id="0" nextid="1" pause="true" >
+ <text id="0" nextid="1" pause="true">
Sup bro! Have a quest. To complete it, just go talk to Ralph again.
- <quest assign="Your First Quest" >
+ <quest assign="Your First Quest">
Dank MayMay,2
Wood Sword,1
</quest>
- </text>
-
- <text id="1" nextid="1" pause="true" >
+ </text>
+ <text id="1" nextid="1" pause="true">
Broooooooooooooo...
</text>
</Dialog>
<Dialog name="Big Dave">
- <text id="0" pause="true">
+ <text id="0" pause="true">
Hey friend! It's dangerous out there, here take these!
Wait, promise you'll stop by my stand in the local market!
- <give id="Wood Sword" count="1"/>
- <give id="Hunters Bow" count="1"/>
- <give id="Crude Arrow" count="110"/>
- <give id="Fried Chicken" count="1"/>
- </text>
+ <give id="Wood Sword" count="1"/> <give id="Hunters Bow" count="1"/> <give id="Crude Arrow" count="110"/> <give id="Fried Chicken" count="1"/></text>
</Dialog>