aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordrumsetmonkey <abelleisle@roadrunner.com>2016-03-08 21:14:47 -0500
committerdrumsetmonkey <abelleisle@roadrunner.com>2016-03-08 21:14:47 -0500
commit98e08cb7c2ae6c61192bac73a1fc7254224452be (patch)
tree2ff5a4b9254b0dc9217795dc8a76365736fd40e4
parent0a0766a186db892f7a8f28f0130a043fd9b9dff9 (diff)
parent82c75b0a97eba2f78206d3b97d47eaa580a82f0c (diff)
Fixed incorrect language percentages
-rw-r--r--.gitattributes6
-rw-r--r--Changelog74
-rw-r--r--Makefile76
-rw-r--r--assets/items/coin1.pngbin0 -> 255 bytes
-rw-r--r--assets/items/coin2.pngbin0 -> 241 bytes
-rw-r--r--assets/items/coin3.pngbin0 -> 242 bytes
-rw-r--r--assets/style/classic/bg/moon.pngbin0 -> 2868 bytes
-rw-r--r--assets/style/classic/stall.pngbin0 -> 778 bytes
-rw-r--r--config/items.xml4
-rw-r--r--include/Texture.h7
-rw-r--r--include/common.h41
-rw-r--r--include/entities.h47
-rw-r--r--include/freetype/config/ftconfig.h (renamed from include/freetype2/config/ftconfig.h)0
-rw-r--r--include/freetype/config/ftheader.h (renamed from include/freetype2/config/ftheader.h)0
-rw-r--r--include/freetype/config/ftmodule.h (renamed from include/freetype2/config/ftmodule.h)0
-rw-r--r--include/freetype/config/ftoption.h (renamed from include/freetype2/config/ftoption.h)0
-rw-r--r--include/freetype/config/ftstdlib.h (renamed from include/freetype2/config/ftstdlib.h)0
-rw-r--r--include/freetype/freetype.h (renamed from include/freetype2/freetype.h)0
-rw-r--r--include/freetype/ft2build.h (renamed from include/freetype2/ft2build.h)4
-rw-r--r--include/freetype/ftadvanc.h (renamed from include/freetype2/ftadvanc.h)0
-rw-r--r--include/freetype/ftautoh.h (renamed from include/freetype2/ftautoh.h)0
-rw-r--r--include/freetype/ftbbox.h (renamed from include/freetype2/ftbbox.h)0
-rw-r--r--include/freetype/ftbdf.h (renamed from include/freetype2/ftbdf.h)0
-rw-r--r--include/freetype/ftbitmap.h (renamed from include/freetype2/ftbitmap.h)0
-rw-r--r--include/freetype/ftbzip2.h (renamed from include/freetype2/ftbzip2.h)0
-rw-r--r--include/freetype/ftcache.h (renamed from include/freetype2/ftcache.h)0
-rw-r--r--include/freetype/ftcffdrv.h (renamed from include/freetype2/ftcffdrv.h)0
-rw-r--r--include/freetype/ftchapters.h (renamed from include/freetype2/ftchapters.h)0
-rw-r--r--include/freetype/ftcid.h (renamed from include/freetype2/ftcid.h)0
-rw-r--r--include/freetype/fterrdef.h (renamed from include/freetype2/fterrdef.h)0
-rw-r--r--include/freetype/fterrors.h (renamed from include/freetype2/fterrors.h)0
-rw-r--r--include/freetype/ftgasp.h (renamed from include/freetype2/ftgasp.h)0
-rw-r--r--include/freetype/ftglyph.h (renamed from include/freetype2/ftglyph.h)0
-rw-r--r--include/freetype/ftgxval.h (renamed from include/freetype2/ftgxval.h)0
-rw-r--r--include/freetype/ftgzip.h (renamed from include/freetype2/ftgzip.h)0
-rw-r--r--include/freetype/ftimage.h (renamed from include/freetype2/ftimage.h)0
-rw-r--r--include/freetype/ftincrem.h (renamed from include/freetype2/ftincrem.h)0
-rw-r--r--include/freetype/ftlcdfil.h (renamed from include/freetype2/ftlcdfil.h)0
-rw-r--r--include/freetype/ftlist.h (renamed from include/freetype2/ftlist.h)0
-rw-r--r--include/freetype/ftlzw.h (renamed from include/freetype2/ftlzw.h)0
-rw-r--r--include/freetype/ftmac.h (renamed from include/freetype2/ftmac.h)0
-rw-r--r--include/freetype/ftmm.h (renamed from include/freetype2/ftmm.h)0
-rw-r--r--include/freetype/ftmodapi.h (renamed from include/freetype2/ftmodapi.h)0
-rw-r--r--include/freetype/ftmoderr.h (renamed from include/freetype2/ftmoderr.h)0
-rw-r--r--include/freetype/ftotval.h (renamed from include/freetype2/ftotval.h)0
-rw-r--r--include/freetype/ftoutln.h (renamed from include/freetype2/ftoutln.h)0
-rw-r--r--include/freetype/ftpfr.h (renamed from include/freetype2/ftpfr.h)0
-rw-r--r--include/freetype/ftrender.h (renamed from include/freetype2/ftrender.h)0
-rw-r--r--include/freetype/ftsizes.h (renamed from include/freetype2/ftsizes.h)0
-rw-r--r--include/freetype/ftsnames.h (renamed from include/freetype2/ftsnames.h)0
-rw-r--r--include/freetype/ftstroke.h (renamed from include/freetype2/ftstroke.h)0
-rw-r--r--include/freetype/ftsynth.h (renamed from include/freetype2/ftsynth.h)0
-rw-r--r--include/freetype/ftsystem.h (renamed from include/freetype2/ftsystem.h)0
-rw-r--r--include/freetype/fttrigon.h (renamed from include/freetype2/fttrigon.h)0
-rw-r--r--include/freetype/ftttdrv.h (renamed from include/freetype2/ftttdrv.h)0
-rw-r--r--include/freetype/fttypes.h (renamed from include/freetype2/fttypes.h)0
-rw-r--r--include/freetype/ftwinfnt.h (renamed from include/freetype2/ftwinfnt.h)0
-rw-r--r--include/freetype/ftxf86.h (renamed from include/freetype2/ftxf86.h)0
-rw-r--r--include/freetype/t1tables.h (renamed from include/freetype2/t1tables.h)0
-rw-r--r--include/freetype/ttnameid.h (renamed from include/freetype2/ttnameid.h)0
-rw-r--r--include/freetype/tttables.h (renamed from include/freetype2/tttables.h)0
-rw-r--r--include/freetype/tttags.h (renamed from include/freetype2/tttags.h)0
-rw-r--r--include/freetype/ttunpat.h (renamed from include/freetype2/ttunpat.h)0
-rw-r--r--include/inventory.h1
-rw-r--r--include/threadpool.h53
-rwxr-xr-xinclude/tinyxml2.h7
-rw-r--r--include/ui.h11
-rw-r--r--include/world.h211
-rw-r--r--main.cpp315
-rw-r--r--setup.mk5
-rw-r--r--src/Makefile18
-rw-r--r--src/Quest.cpp37
-rw-r--r--src/Texture.cpp109
-rw-r--r--src/common.cpp61
-rw-r--r--src/config.cpp1
-rw-r--r--src/entities.cpp227
-rw-r--r--src/gameplay.cpp56
-rw-r--r--src/inventory.cpp22
-rw-r--r--src/threadpool.cpp99
-rwxr-xr-xsrc/tinyxml2.cpp13
-rw-r--r--src/ui.cpp309
-rw-r--r--src/world.cpp1798
-rw-r--r--xml/playerSpawnHill1.xml15
83 files changed, 2017 insertions, 1610 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..b98fd9b
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,6 @@
+src/tinyxml2.cpp linguist-vendored
+src/threadpool.cpp linguist-vendored
+include/tinyxml2.h linguist-vendored
+include/threadpool.h linguist-vendored
+include/SDL2/* linguist-vendored
+include/freetype/* linguist-vendored
diff --git a/Changelog b/Changelog
index f3839a8..bac3a64 100644
--- a/Changelog
+++ b/Changelog
@@ -675,3 +675,77 @@
- volumes are better
~ 5 month Changelog anniversary!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+2/23/2016:
+==========
+
+ - began re-write of font rendering functions
+ - began documenting main.cpp
+ - improved game efficiency
+
+2/25/2016:
+==========
+
+ - very neatly documented/optimized ui.cpp (very neat)
+ - looked into better automated Makefiles
+ - improving villages, began work on shops
+
+2/26/2016:
+==========
+
+ - made fonts more memory-efficient
+ - C++-ified loaded texture handlers
+ - documented more stuff
+ - made merchant menu
+
+2/29/2016:
+==========
+
+ - renewed branch 'remake': re-wrote world.cpp and pushed
+ - fixed world linkage errors
+ - considered more formal coding? (as in documentation and indentation)
+ - fixed dialog boxes and options
+ - broke screenshots
+
+3/1/2016:
+=========
+
+ - merged 'remake' with 'master', fixed font issues and world stuffs
+ - continued work on merchant dialog
+
+3/2/2016,
+3/3/2016:
+=========
+
+ - made particle vector not pointers
+ - improved efficiency of code using newly learned C++11 tricks
+ - added StrAttribute() to TinyXML2
+ - more merchant stuff, trading????
+ - improved village XML loading
+
+3/4/2016:
+=========
+
+ - added following functionality to entities
+ - fixed some world shading issues
+ - re-added stars, but stars draw midday
+ - restarted work on arenas
+ - began implementing currency system
+ - made the moon!
+ - merchants are a-o-kay
+
+3/7/2016:
+=========
+
+ - player lighting works more
+ - arenas work
+ - cleaned up world codes
+ - andy got here
+
+ ~ Total of 7,379 lines of code!
+
+3/8/2016:
+=========
+
+ - fixed world draw shadings
+ - improved merchant menu
diff --git a/Makefile b/Makefile
index 81862c0..e49ff04 100644
--- a/Makefile
+++ b/Makefile
@@ -1,32 +1,44 @@
-LIBS = -lpthread -lGL -lGLEW -lSDL2 -lfreetype -lSDL2_image -lSDL2_mixer
-
-WIN_LIBS = -lopengl32 -lglew32 -lmingw32 -lSDL2main -lSDL2 -lSDL2_image -lSDL2_mixer -lfreetype
-
-FLAGS = -std=c++11 -Iinclude -Iinclude/freetype2 -Wall -Wextra -Werror
-
-MFLAGS64 = 64
-
-all:
- @echo "Building for 32-bit target"
- @rm -f out/*.o
- @cd src; $(MAKE) $(MFLAGS)
- @echo " CXX main.cpp"
- @g++ $(FLAGS) -m32 -o main main.cpp out/*.o $(LIBS) -lSDL2main
-
-64:
- @echo "Building for 64-bit target"
- @rm -f out64/*.o
- @cd src; $(MAKE) $(MFLAGS64)
- @echo " CXX main.cpp"
- @g++ $(FLAGS) -m64 -o main main.cpp out64/*.o $(LIBS)
-
-win32:
- @g++ $(FLAGS) -o main main.cpp src/*.cpp $(WIN_LIBS)
-
-clean:
- @echo " RM main"
- @-rm -f main
- @echo " RM out/*.o"
- @-rm -f out/*.o
- @echo " RM out64/*.o"
- @-rm -f out64/*.o
+include setup.mk
+
+CC = gcc
+CXX = g++
+
+ifeq ($(TARGET_OS),linux)
+ LIBS = -lpthread -lGL -lGLEW -lfreetype \
+ -lSDL2 -lSDL2_image -lSDL2_mixer -lSDL2main
+endif
+ifeq ($(TARGET_OS),win32)
+ LIBS = -lopengl32 -lglew32 -lmingw32 \
+ -lSDL2main -lSDL2 -lSDL2_image -lSDL2_mixer -lfreetype
+endif
+
+CXXFLAGS = -m$(TARGET_BITS) -std=c++14
+CXXINC = -Iinclude -Iinclude/freetype
+CXXWARN = -Wall -Wextra -Werror -pedantic-errors
+
+CXXSRCDIR = src
+CXXOUTDIR = out
+CXXSRC = $(wildcard $(CXXSRCDIR)/*.cpp)
+CXXOBJ = $(patsubst $(CXXSRCDIR)/%.cpp, $(CXXOUTDIR)/%.o, $(CXXSRC))
+
+EXEC = main
+
+all: $(EXEC)
+
+dirty:
+ rm -rf out/world.o
+
+clean:
+ rm -f $(EXEC)
+ rm -f out/*.o
+
+cleandata:
+ rm -rf xml/*.dat
+
+$(EXEC): $(CXXOUTDIR)/$(CXXOBJ) main.cpp
+ @echo " CXX/LD main"
+ @$(CXX) $(CXXFLAGS) $(CXXINC) $(CXXWARN) -o $(EXEC) main.cpp out/*.o $(LIBS)
+
+$(CXXOUTDIR)/%.o: $(CXXSRCDIR)/%.cpp
+ @echo " CXX " $<
+ @$(CXX) $(CXXFLAGS) $(CXXINC) $(CXXWARN) $(LIBS) -c $< -o $@
diff --git a/assets/items/coin1.png b/assets/items/coin1.png
new file mode 100644
index 0000000..6b8ba8c
--- /dev/null
+++ b/assets/items/coin1.png
Binary files differ
diff --git a/assets/items/coin2.png b/assets/items/coin2.png
new file mode 100644
index 0000000..5bfd622
--- /dev/null
+++ b/assets/items/coin2.png
Binary files differ
diff --git a/assets/items/coin3.png b/assets/items/coin3.png
new file mode 100644
index 0000000..61bf980
--- /dev/null
+++ b/assets/items/coin3.png
Binary files differ
diff --git a/assets/style/classic/bg/moon.png b/assets/style/classic/bg/moon.png
new file mode 100644
index 0000000..d9a5ab7
--- /dev/null
+++ b/assets/style/classic/bg/moon.png
Binary files differ
diff --git a/assets/style/classic/stall.png b/assets/style/classic/stall.png
new file mode 100644
index 0000000..1ac9844
--- /dev/null
+++ b/assets/style/classic/stall.png
Binary files differ
diff --git a/config/items.xml b/config/items.xml
index 02382d6..eddab3e 100644
--- a/config/items.xml
+++ b/config/items.xml
@@ -1,5 +1,9 @@
<?xml version="1.0"?>
+<currency name="Abe Lincoln" value="1" sprite="assets/items/coin1.png"/>
+<currency name="George Washington" value="25" sprite="assets/items/coin2.png"/>
+<currency name="Barack Hussein Obama" value="100" sprite="assets/items/coin3.png"/>
+
<item name="Debug" type="Tool" maxStackSize="1" width="1" height="1" sprite="assets/items/ITEM_TEST.png" />
<item name="Dank MayMay" type="Tool" maxStackSize="420" width="10" height="10" sprite="assets/items/ITEM_TEST.png" />
<item name="Your Bag" type="Equip" maxStackSize="1" width="5" height="5" sprite="assets/items/ITEM_TEST.png" />
diff --git a/include/Texture.h b/include/Texture.h
index c6376cb..7201a4c 100644
--- a/include/Texture.h
+++ b/include/Texture.h
@@ -27,13 +27,13 @@ namespace Texture{
* later referencing of the texture.
*/
- GLuint loadTexture(const char *fileName);
+ GLuint loadTexture(std::string fileName);
void freeTextures(void);
void initColorIndex();
vec2 getIndex(Color c);
- dim2 imageDim(const char *fileName);
+ dim2 imageDim(std::string fileName);
}
/**
@@ -58,7 +58,7 @@ public:
* Contains an array of the GLuints returned from Texture::loadTexture().
*/
- GLuint *image = NULL;
+ std::vector<GLuint> image;
/**
* Populates the image array from a list of strings, with each string as a
@@ -73,6 +73,7 @@ public:
Texturec(uint amt,const char **paths);
Texturec(std::vector<std::string>vec);
+ Texturec( std::initializer_list<std::string> l );
/**
* Frees memory taken by the image array.
diff --git a/include/common.h b/include/common.h
index a99e352..58d561f 100644
--- a/include/common.h
+++ b/include/common.h
@@ -8,16 +8,18 @@
#ifndef COMMON_H
#define COMMON_H
+// holy moly
#include <iostream>
#include <cstdlib>
#include <string>
#include <vector>
-#include <math.h>
#include <string>
#include <fstream>
#include <thread>
#include <mutex>
#include <future>
+#include <math.h>
+#include <threadpool.h>
#define GLEW_STATIC
#include <GL/glew.h>
@@ -46,13 +48,18 @@ N abso(N v){
return v;
}
-extern GLuint colorIndex;
+extern GLuint colorIndex; // Texture.cpp?
/**
* This structure contains a set of coordinates for ease of coding.
*/
typedef struct {
+ int x;
+ int y;
+} ivec2;
+
+typedef struct {
float x;
float y;
} vec2;
@@ -63,7 +70,7 @@ typedef struct {
float z;
} vec3;
-typedef vec2 dim2;
+typedef ivec2 dim2;
/**
* This structure contains two sets of coordinates for ray drawing.
@@ -74,7 +81,7 @@ typedef struct {
vec2 end;
} Ray;
-struct col{
+struct col {
float red;
float green;
float blue;
@@ -98,7 +105,7 @@ typedef col Color;
* Define the game's name (displayed in the window title).
*/
-#define GAME_NAME "Independent Study v.0.5 alpha - NOW WITH SOUND!"
+#define GAME_NAME "Independent Study v.0.6 alpha - NOW WITH more c++"
/**
* The desired width of the game window.
@@ -113,6 +120,8 @@ extern unsigned int SCREEN_WIDTH;
extern unsigned int SCREEN_HEIGHT;
extern bool FULLSCREEN;
+extern bool uiLoop;
+extern std::mutex mtx;
/**
* Define the length of a single HLINE.
@@ -143,6 +152,9 @@ extern float VOLUME_SFX;
#define getRand() rand()
+#define randGet rand
+#define randInit srand
+
/**
* Included in common.h is a prototype for DEBUG_prints, which writes a formatted
* string to the console containing the callee's file and line number. This macro simplifies
@@ -181,23 +193,6 @@ extern unsigned int loops;
extern GLuint shaderProgram;
/**
- * This class contains a string for identification and a value. It can be used to
- * save certain events for and decisions so that they can be recalled later.
- */
-
-class Condition {
-private:
- char *id;
- void *value;
-public:
- Condition(const char *_id,void *val);
- ~Condition();
-
- bool sameID(const char *s);
- void *getValue(void);
-};
-
-/**
* Prints a formatted debug message to the console, along with the callee's file and line
* number.
*/
@@ -239,6 +234,6 @@ int strCreateFunc(const char *equ);
template<typename N, size_t s>
size_t arrAmt(N (&)[s]){return s;}
-extern void *NULLPTR;
+void UserError(std::string reason);
#endif // COMMON_H
diff --git a/include/entities.h b/include/entities.h
index 926eeae..ef421f5 100644
--- a/include/entities.h
+++ b/include/entities.h
@@ -22,13 +22,13 @@ enum _TYPE {
STRUCTURET,
PLAYERT,
NPCT,
+ MERCHT,
MOBT
};
enum GENDER{
MALE,
- FEMALE,
- TRANSBULLSHIT
+ FEMALE
};
enum MOB_SUB {
@@ -47,7 +47,25 @@ enum BUILD_SUB{
HOUSE4 = 4,
FOUNTAIN = 5,
LAMP_POST = 6,
- FIRE_PIT = 7
+ FIRE_PIT = 7,
+ STALL_MARKET = 70,
+ STALL_TRADER = 71
+};
+
+class Trade{
+public:
+ std::string item[2];
+ int quantity[2];
+ Trade(int qo, const char* o, int qt, const char* t){
+ item[0] = o;
+ item[1] = t;
+
+ quantity[0] = qo;
+ quantity[1] = qt;
+
+ std::cout << "Trading: " << quantity[0] << " " << item[0] << " for " << quantity[1] << " " << item[1] << std::endl;
+ }
+ Trade(){}
};
class World;
@@ -112,6 +130,7 @@ void initEntity();
class Entity{
public:
+ Entity *followee;
Inventory *inv;
/*
@@ -166,6 +185,8 @@ public:
virtual void wander(int){}
virtual void interact(){}
+
+ void follow(Entity *e);
virtual ~Entity(){}
};
@@ -191,16 +212,26 @@ public:
void addAIFunc(int (*func)(NPC *),bool preload);
void clearAIFunc(void);
- void interact();
+ virtual void interact();
void wander(int);
};
+class Merchant : public NPC{
+public:
+ std::vector<Trade>trade;
+
+ void interact();
+
+ Merchant();
+ ~Merchant();
+};
+
class Structures : public Entity{
public:
BUILD_SUB bsubtype;
World *inWorld;
- char *inside;
- char *textureLoc;
+ std::string inside;
+ std::string textureLoc;
Structures();
~Structures();
@@ -225,11 +256,11 @@ class Object : public Entity{
private:
std::string iname;
public:
- char *pickupDialog;
+ std::string pickupDialog;
bool questObject = false;
Object();
- Object(std::string in,const char *pd);
+ Object(std::string in,std::string pd);
~Object();
void reloadTexture(void);
diff --git a/include/freetype2/config/ftconfig.h b/include/freetype/config/ftconfig.h
index 11d5d95..11d5d95 100644
--- a/include/freetype2/config/ftconfig.h
+++ b/include/freetype/config/ftconfig.h
diff --git a/include/freetype2/config/ftheader.h b/include/freetype/config/ftheader.h
index b623629..b623629 100644
--- a/include/freetype2/config/ftheader.h
+++ b/include/freetype/config/ftheader.h
diff --git a/include/freetype2/config/ftmodule.h b/include/freetype/config/ftmodule.h
index d1b938b..d1b938b 100644
--- a/include/freetype2/config/ftmodule.h
+++ b/include/freetype/config/ftmodule.h
diff --git a/include/freetype2/config/ftoption.h b/include/freetype/config/ftoption.h
index 84eb8d0..84eb8d0 100644
--- a/include/freetype2/config/ftoption.h
+++ b/include/freetype/config/ftoption.h
diff --git a/include/freetype2/config/ftstdlib.h b/include/freetype/config/ftstdlib.h
index b940efc..b940efc 100644
--- a/include/freetype2/config/ftstdlib.h
+++ b/include/freetype/config/ftstdlib.h
diff --git a/include/freetype2/freetype.h b/include/freetype/freetype.h
index 39a18af..39a18af 100644
--- a/include/freetype2/freetype.h
+++ b/include/freetype/freetype.h
diff --git a/include/freetype2/ft2build.h b/include/freetype/ft2build.h
index 6f8eb7f..419b80a 100644
--- a/include/freetype2/ft2build.h
+++ b/include/freetype/ft2build.h
@@ -4,7 +4,7 @@
/* */
/* FreeType 2 build and setup macros. */
/* */
-/* Copyright 1996-2001, 2006, 2013 by */
+/* Copyright 1996-2015 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -34,7 +34,7 @@
#ifndef __FT2BUILD_H__
#define __FT2BUILD_H__
-#include <config/ftheader.h>
+#include <freetype/config/ftheader.h>
#endif /* __FT2BUILD_H__ */
diff --git a/include/freetype2/ftadvanc.h b/include/freetype/ftadvanc.h
index 8f7e2fc..8f7e2fc 100644
--- a/include/freetype2/ftadvanc.h
+++ b/include/freetype/ftadvanc.h
diff --git a/include/freetype2/ftautoh.h b/include/freetype/ftautoh.h
index bf97b3f..bf97b3f 100644
--- a/include/freetype2/ftautoh.h
+++ b/include/freetype/ftautoh.h
diff --git a/include/freetype2/ftbbox.h b/include/freetype/ftbbox.h
index 8938841..8938841 100644
--- a/include/freetype2/ftbbox.h
+++ b/include/freetype/ftbbox.h
diff --git a/include/freetype2/ftbdf.h b/include/freetype/ftbdf.h
index 4f8baf8..4f8baf8 100644
--- a/include/freetype2/ftbdf.h
+++ b/include/freetype/ftbdf.h
diff --git a/include/freetype2/ftbitmap.h b/include/freetype/ftbitmap.h
index 7dbf5ba..7dbf5ba 100644
--- a/include/freetype2/ftbitmap.h
+++ b/include/freetype/ftbitmap.h
diff --git a/include/freetype2/ftbzip2.h b/include/freetype/ftbzip2.h
index 1bf81b1..1bf81b1 100644
--- a/include/freetype2/ftbzip2.h
+++ b/include/freetype/ftbzip2.h
diff --git a/include/freetype2/ftcache.h b/include/freetype/ftcache.h
index a5d7100..a5d7100 100644
--- a/include/freetype2/ftcache.h
+++ b/include/freetype/ftcache.h
diff --git a/include/freetype2/ftcffdrv.h b/include/freetype/ftcffdrv.h
index e4d039d..e4d039d 100644
--- a/include/freetype2/ftcffdrv.h
+++ b/include/freetype/ftcffdrv.h
diff --git a/include/freetype2/ftchapters.h b/include/freetype/ftchapters.h
index 4b1059a..4b1059a 100644
--- a/include/freetype2/ftchapters.h
+++ b/include/freetype/ftchapters.h
diff --git a/include/freetype2/ftcid.h b/include/freetype/ftcid.h
index 203a30c..203a30c 100644
--- a/include/freetype2/ftcid.h
+++ b/include/freetype/ftcid.h
diff --git a/include/freetype2/fterrdef.h b/include/freetype/fterrdef.h
index 76c7b9e..76c7b9e 100644
--- a/include/freetype2/fterrdef.h
+++ b/include/freetype/fterrdef.h
diff --git a/include/freetype2/fterrors.h b/include/freetype/fterrors.h
index 0fa3e4d..0fa3e4d 100644
--- a/include/freetype2/fterrors.h
+++ b/include/freetype/fterrors.h
diff --git a/include/freetype2/ftgasp.h b/include/freetype/ftgasp.h
index 453d4fa..453d4fa 100644
--- a/include/freetype2/ftgasp.h
+++ b/include/freetype/ftgasp.h
diff --git a/include/freetype2/ftglyph.h b/include/freetype/ftglyph.h
index 2d30ed9..2d30ed9 100644
--- a/include/freetype2/ftglyph.h
+++ b/include/freetype/ftglyph.h
diff --git a/include/freetype2/ftgxval.h b/include/freetype/ftgxval.h
index 6d38e32..6d38e32 100644
--- a/include/freetype2/ftgxval.h
+++ b/include/freetype/ftgxval.h
diff --git a/include/freetype2/ftgzip.h b/include/freetype/ftgzip.h
index 78e7269..78e7269 100644
--- a/include/freetype2/ftgzip.h
+++ b/include/freetype/ftgzip.h
diff --git a/include/freetype2/ftimage.h b/include/freetype/ftimage.h
index b66f036..b66f036 100644
--- a/include/freetype2/ftimage.h
+++ b/include/freetype/ftimage.h
diff --git a/include/freetype2/ftincrem.h b/include/freetype/ftincrem.h
index aaf689f..aaf689f 100644
--- a/include/freetype2/ftincrem.h
+++ b/include/freetype/ftincrem.h
diff --git a/include/freetype2/ftlcdfil.h b/include/freetype/ftlcdfil.h
index 39206f0..39206f0 100644
--- a/include/freetype2/ftlcdfil.h
+++ b/include/freetype/ftlcdfil.h
diff --git a/include/freetype2/ftlist.h b/include/freetype/ftlist.h
index 241e21e..241e21e 100644
--- a/include/freetype2/ftlist.h
+++ b/include/freetype/ftlist.h
diff --git a/include/freetype2/ftlzw.h b/include/freetype/ftlzw.h
index 00d4016..00d4016 100644
--- a/include/freetype2/ftlzw.h
+++ b/include/freetype/ftlzw.h
diff --git a/include/freetype2/ftmac.h b/include/freetype/ftmac.h
index 42874fe..42874fe 100644
--- a/include/freetype2/ftmac.h
+++ b/include/freetype/ftmac.h
diff --git a/include/freetype2/ftmm.h b/include/freetype/ftmm.h
index 837975a..837975a 100644
--- a/include/freetype2/ftmm.h
+++ b/include/freetype/ftmm.h
diff --git a/include/freetype2/ftmodapi.h b/include/freetype/ftmodapi.h
index 22878f8..22878f8 100644
--- a/include/freetype2/ftmodapi.h
+++ b/include/freetype/ftmodapi.h
diff --git a/include/freetype2/ftmoderr.h b/include/freetype/ftmoderr.h
index 5a27db1..5a27db1 100644
--- a/include/freetype2/ftmoderr.h
+++ b/include/freetype/ftmoderr.h
diff --git a/include/freetype2/ftotval.h b/include/freetype/ftotval.h
index bb52dc4..bb52dc4 100644
--- a/include/freetype2/ftotval.h
+++ b/include/freetype/ftotval.h
diff --git a/include/freetype2/ftoutln.h b/include/freetype/ftoutln.h
index 8c7c57d..8c7c57d 100644
--- a/include/freetype2/ftoutln.h
+++ b/include/freetype/ftoutln.h
diff --git a/include/freetype2/ftpfr.h b/include/freetype/ftpfr.h
index 0b7b7d4..0b7b7d4 100644
--- a/include/freetype2/ftpfr.h
+++ b/include/freetype/ftpfr.h
diff --git a/include/freetype2/ftrender.h b/include/freetype/ftrender.h
index dd0229b..dd0229b 100644
--- a/include/freetype2/ftrender.h
+++ b/include/freetype/ftrender.h
diff --git a/include/freetype2/ftsizes.h b/include/freetype/ftsizes.h
index 4167045..4167045 100644
--- a/include/freetype2/ftsizes.h
+++ b/include/freetype/ftsizes.h
diff --git a/include/freetype2/ftsnames.h b/include/freetype/ftsnames.h
index 88af440..88af440 100644
--- a/include/freetype2/ftsnames.h
+++ b/include/freetype/ftsnames.h
diff --git a/include/freetype2/ftstroke.h b/include/freetype/ftstroke.h
index a498e4a..a498e4a 100644
--- a/include/freetype2/ftstroke.h
+++ b/include/freetype/ftstroke.h
diff --git a/include/freetype2/ftsynth.h b/include/freetype/ftsynth.h
index 839ab5e..839ab5e 100644
--- a/include/freetype2/ftsynth.h
+++ b/include/freetype/ftsynth.h
diff --git a/include/freetype2/ftsystem.h b/include/freetype/ftsystem.h
index e07460c..e07460c 100644
--- a/include/freetype2/ftsystem.h
+++ b/include/freetype/ftsystem.h
diff --git a/include/freetype2/fttrigon.h b/include/freetype/fttrigon.h
index 65143cb..65143cb 100644
--- a/include/freetype2/fttrigon.h
+++ b/include/freetype/fttrigon.h
diff --git a/include/freetype2/ftttdrv.h b/include/freetype/ftttdrv.h
index 70ad3d5..70ad3d5 100644
--- a/include/freetype2/ftttdrv.h
+++ b/include/freetype/ftttdrv.h
diff --git a/include/freetype2/fttypes.h b/include/freetype/fttypes.h
index bd944a4..bd944a4 100644
--- a/include/freetype2/fttypes.h
+++ b/include/freetype/fttypes.h
diff --git a/include/freetype2/ftwinfnt.h b/include/freetype/ftwinfnt.h
index 0b67351..0b67351 100644
--- a/include/freetype2/ftwinfnt.h
+++ b/include/freetype/ftwinfnt.h
diff --git a/include/freetype2/ftxf86.h b/include/freetype/ftxf86.h
index 493cccd..493cccd 100644
--- a/include/freetype2/ftxf86.h
+++ b/include/freetype/ftxf86.h
diff --git a/include/freetype2/t1tables.h b/include/freetype/t1tables.h
index a14255e..a14255e 100644
--- a/include/freetype2/t1tables.h
+++ b/include/freetype/t1tables.h
diff --git a/include/freetype2/ttnameid.h b/include/freetype/ttnameid.h
index 9711d1d..9711d1d 100644
--- a/include/freetype2/ttnameid.h
+++ b/include/freetype/ttnameid.h
diff --git a/include/freetype2/tttables.h b/include/freetype/tttables.h
index bb49dc0..bb49dc0 100644
--- a/include/freetype2/tttables.h
+++ b/include/freetype/tttables.h
diff --git a/include/freetype2/tttags.h b/include/freetype/tttags.h
index d59aa19..d59aa19 100644
--- a/include/freetype2/tttags.h
+++ b/include/freetype/tttags.h
diff --git a/include/freetype2/ttunpat.h b/include/freetype/ttunpat.h
index a016275..a016275 100644
--- a/include/freetype2/ttunpat.h
+++ b/include/freetype/ttunpat.h
diff --git a/include/inventory.h b/include/inventory.h
index 8225ab2..69cf073 100644
--- a/include/inventory.h
+++ b/include/inventory.h
@@ -62,6 +62,7 @@ void initInventorySprites(void);
void destroyInventory(void);
const char *getItemTexturePath(std::string name);
+GLuint getItemTexture(std::string name);
float getItemWidth(std::string name);
float getItemHeight(std::string name);
diff --git a/include/threadpool.h b/include/threadpool.h
new file mode 100644
index 0000000..c341673
--- /dev/null
+++ b/include/threadpool.h
@@ -0,0 +1,53 @@
+#ifndef THREADPOOL_H
+#define THREADPOOL_H
+
+#include <vector>
+#include <queue>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <iostream>
+#include <unistd.h>
+
+using namespace std;
+
+class ThreadPool
+{
+public:
+
+ // Constructor.
+ ThreadPool(int threads);
+
+ // Destructor.
+ ~ThreadPool();
+
+ // Adds task to a task queue.
+ void Enqueue(function<void()> f);
+
+ // Shut down the pool.
+ void ShutDown();
+
+private:
+ // Thread pool storage.
+ vector<thread> threadPool;
+
+ // Queue to keep track of incoming tasks.
+ queue<function<void()>> tasks;
+
+ // Task queue mutex.
+ mutex tasksMutex;
+
+ // Condition variable.
+ condition_variable condition;
+
+ // Indicates that pool needs to be shut down.
+ bool terminate;
+
+ // Indicates that pool has been terminated.
+ bool stopped;
+
+ // Function that will be invoked by our threads.
+ void Invoke();
+};
+
+#endif //THRE \ No newline at end of file
diff --git a/include/tinyxml2.h b/include/tinyxml2.h
index fb7464a..4282642 100755
--- a/include/tinyxml2.h
+++ b/include/tinyxml2.h
@@ -38,6 +38,8 @@ distribution.
# include <cstring>
#endif
+#include <string>
+
/*
TODO: intern strings instead of allocation.
*/
@@ -1187,6 +1189,11 @@ public:
*/
const char* Attribute( const char* name, const char* value=0 ) const;
+ /** Functions the same as Attribute(), but returns the result
+ as a std::string.
+ */
+ std::string StrAttribute( const char* name, const char* value=0 ) const;
+
/** Given an attribute name, IntAttribute() returns the value
of the attribute interpreted as an integer. 0 will be
returned if there is an error. For a method with error
diff --git a/include/ui.h b/include/ui.h
index 6a81ff8..ed9fb94 100644
--- a/include/ui.h
+++ b/include/ui.h
@@ -22,7 +22,6 @@ typedef void(*menuFunc)();
struct menuItem{
int member;
union{
-
struct{
vec2 loc;
dim2 dim;
@@ -30,7 +29,6 @@ struct menuItem{
const char* text;
menuFunc func;
}button;
-
struct{
vec2 loc;
dim2 dim;
@@ -108,9 +106,9 @@ namespace ui {
extern bool posFlag;
extern unsigned char dialogOptChosen;
- extern bool dialogBoxExists;
- extern bool dialogImportant;
- extern bool dialogPassive;
+ extern bool dialogBoxExists;
+ extern bool dialogImportant;
+ extern bool dialogPassive;
extern unsigned int textWrapLimit;
@@ -148,6 +146,8 @@ namespace ui {
*/
void dialogBox(const char *name,const char *opt,bool passive,const char *text,...);
+ void merchantBox(const char *name,Trade trade,const char *opt,bool passive,const char *text,...);
+ void merchantBox();
void waitForDialog(void);
/*
@@ -186,7 +186,6 @@ namespace ui {
void toggleWhiteFast(void);
void waitForCover(void);
- void waitForNothing(unsigned int);
}
#endif // UI_H
diff --git a/include/world.h b/include/world.h
index f9e952e..a60eab6 100644
--- a/include/world.h
+++ b/include/world.h
@@ -11,24 +11,11 @@
#include <common.h>
#include <entities.h>
-/**
- * Defines at what interval y values should be calculated for the array 'line'.
- */
-
-#define GEN_INC 10
-
-/**
- * Defines the lowest possible y value for a world line.
- */
-
-#define GEN_MIN 80
-
-/**
- * Defines the highest possible y value for a randomly generated world line.
- */
-
-#define GEN_MAX 110
+#define GROUND_HEIGHT_INITIAL 80
+#define GROUND_HEIGHT_MINIMUM 60
+#define GROUND_HEIGHT_MAXIMUM 110
+#define GROUND_HILLINESS 10
/**
* Defines how many game ticks it takes for a day to elapse.
@@ -42,10 +29,10 @@
* in World::setBackground() to select the appropriate images.
*/
-typedef enum {
- BG_FOREST, /**< A forest theme. */
- BG_WOODHOUSE /**< An indoor wooden house theme. */
-} WORLD_BG_TYPE;
+enum class WorldBGType : unsigned char {
+ Forest, /**< A forest theme. */
+ WoodHouse /**< An indoor wooden house theme. */
+};
/**
* The weather type enum.
@@ -53,11 +40,11 @@ typedef enum {
* Weather is set by the world somewhere.
*/
-typedef enum {
- SUNNY = 0, /**< Sunny/daytime */
- DARK, /**< Nighttime */
- RAIN /**< Rain (to be implemented)*/
-} WEATHER;
+enum class WorldWeather : unsigned char {
+ Sunny = 0, /**< Sunny/daytime */
+ Dark, /**< Nighttime */
+ Rain /**< Rain (to be implemented)*/
+};
/**
* The light structure, used to store light coordinates and color.
@@ -74,31 +61,43 @@ typedef struct {
* lines. Dirt color and grass properties are also kept track of here.
*/
-typedef struct line_t {
- float y; /**< Height of this vertical line */
- bool gs; /**< Show grass */
- float gh[2]; /**< Height of glass (2 blades per line) */
- unsigned char color; /**< Lightness of dirt (brown) */
-} line_t;
+typedef struct {
+ bool grassUnpressed;
+ float grassHeight[2];
+ float groundHeight;
+ unsigned char groundColor;
+} WorldData;
-/*
- * Handle all logic that has to do with villages
+/**
+ * A value used by World::draw() for shading, ranges from -50 to 50 depending
+ * on the current time of day.
*/
+extern int worldShade;
+
+/**
+ * The path to the currently loaded XML file.
+ */
-struct Village{
+extern std::string currentXML;
+
+// prototype so Village can reference it
+class World;
+
+/**
+ * The village class, used to group structures into villages.
+ */
+
+class Village {
+public:
std::string name;
vec2 start;
vec2 end;
bool in;
-
std::vector<Structures *> build;
- Village(const char *meme){
- name = meme;
- end.x = -0xffffffff;
- start.x = 0xffffffff;
- in = false;
- }
+
+ Village(const char *meme, World *w);
+ ~Village(void){}
};
/**
@@ -113,7 +112,7 @@ protected:
* of elements provided by the function.
*/
- struct line_t *line;
+ std::vector<WorldData> worldData;
/**
* Starting x coordinate.
@@ -121,7 +120,7 @@ protected:
* calculate the width of the world.
*/
- int x_start;
+ int worldStart;
/**
* Handle physics for a single entity.
@@ -132,8 +131,6 @@ protected:
*/
void singleDetect(Entity *e);
-
- static void villageLogic(World *world);
/**
* Empties all entity vectors.
@@ -159,7 +156,7 @@ protected:
* An array of star coordinates.
*/
- vec2 *star;
+ std::vector<vec2> star;
/**
* The Texturec object that holds the background sprites for this world.
@@ -171,7 +168,7 @@ protected:
* Defines the set of background images that should be used for this world.
*/
- WORLD_BG_TYPE bgType;
+ WorldBGType bgType;
/**
* The Mix_Music object that holds the background soundtrack for the world.
@@ -183,7 +180,8 @@ protected:
* The file path of the song wished to be loaded by bgmObj.
*/
- char *bgm;
+ std::string bgm;
+
std::vector<std::string>bgFiles;
std::vector<std::string>bgFilesIndoors;
@@ -215,7 +213,6 @@ public:
char *setToRight(const char *file);
-
/**
* A vector of pointers to every NPC, Structure, Mob, and Object in this
* world.
@@ -228,6 +225,7 @@ public:
*/
std::vector<NPC *> npc;
+ std::vector<Merchant *> merchant;
/**
* A vector of all Structures in this world.
@@ -251,22 +249,22 @@ public:
* A vector of all particles in this world.
*/
- std::vector<Particles *> particles;
+ std::vector<Particles> particles;
+
+
+ std::vector<Village *> village;
/**
* A vector of all light elements in this world.
*/
- std::vector<Light > light;
+ std::vector<Light> light;
/**
* Vector of all building textures for the current world style
*/
- std::vector<std::string > sTexLoc;
-
- std::vector<Village>village;
-
+ std::vector<std::string> sTexLoc;
/**
* NULLifies pointers and allocates necessary memory. This should be
@@ -274,7 +272,7 @@ public:
* generate().
*/
- World(void);
+ World( void );
/**
* Frees resources taken by the world.
@@ -289,8 +287,7 @@ public:
* the structure.
*/
- void addStructure(BUILD_SUB subtype,float x,float y, char* tex, const char *inside);
- //void addVillage(int buildingCount, int npcMin, int npcMax,const char *inside);
+ void addStructure(BUILD_SUB subtype,float x,float y, std::string tex, std::string inside);
/**
* Adds a Mob to the world with the specified type and coordinates.
@@ -312,12 +309,18 @@ public:
void addNPC(float x,float y);
/**
+ * Adds a Merchant to the world at the specified coordinates.
+ */
+
+ void addMerchant(float x, float y);
+
+ /**
* Adds an object to the world with the specified item id and coordinates.
* If `pickupDialog` is not NULL, that string will display in a dialog box
* upon object interaction.
*/
- void addObject(/*ITEM_ID id*/std::string in,const char *pickupDialog, float x, float y);
+ void addObject( std::string in, std::string pickupDialog, float x, float y);
/**
* Adds a particle to the world with the specified coordinates, dimensions,
@@ -331,13 +334,6 @@ public:
*/
void addLight(vec2 xy, Color color);
-
- /**
- * Get the next NPC in the NPC vector that currently lacks a written dialog.
- * Could be used to assign random NPCs non-random dialogs.
- */
-
- NPC *getAvailableNPC(void);
/**
* Updates the coordinates of everything in the world that has coordinates
@@ -355,19 +351,11 @@ public:
virtual void generate(unsigned int width);
/**
- * Generates a world of the provided width using the given function to
- * determine ground coordinates. The given y coordinates from the function
- * are limited to a certain range, most likely from GEN_MIN to 2000.
- */
-
- void generateFunc(unsigned int width,float(*func)(float));
-
- /**
* Sets the background theme, collecting the required textures into a
* Texturec object.
*/
- void setBackground(WORLD_BG_TYPE bgt);
+ void setBackground(WorldBGType bgt);
/**
* Sets the background music for the world, required for the world to be
@@ -380,14 +368,14 @@ public:
* Sets the worlds style folder
*/
- void setStyle(const char* pre);
+ void setStyle(std::string pre);
/**
* Plays/stops this world's BGM. If `prev` is not NULL, that world's BGM
* will be faded out followed by the fading in of this world's BGM.
*/
- void bgmPlay(World *prev);
+ void bgmPlay(World *prev) const;
/**
* Draw the world and entities based on the player's coordinates.
@@ -437,20 +425,14 @@ public:
* Get's the world's width.
*/
- int getTheWidth(void);
+ int getTheWidth(void) const;
void save(void);
void load(void);
};
/*
- * Gets a good base y value for background rendering.
-*/
-
-float worldGetYBase(World *w);
-
-/*
- * IndoorWorld - Indoor settings stored in a World class ;)
+ * IndoorWorld - Indoor settings stored in a World class
*/
class IndoorWorld : public World {
@@ -462,21 +444,58 @@ public:
void draw(Player *p); // Draws the world (ignores layers)
};
+/**
+ * The arena class - creates an arena.
+ *
+ * This world, when created, expects a pointer to a Mob. This mob will be
+ * transported to a temporary world with the player, and the Mob will be
+ * killed upon exiting the arena.
+ */
+
class Arena : public World {
private:
- //vec2 pxy;
- //World *exit;
- Mob *mmob;
+
+ /**
+ * The mob that the player is fighting.
+ */
+
+ Mob *mmob;
+
public:
- Arena(World *leave,Player *p,Mob *m);
- ~Arena(void);
- World *exitArena(Player *p);
+
+ /**
+ * Creates a world with the player and mob, returning the player to the
+ * world `leave` upon exit.
+ */
+
+ Arena( World *leave, Player *p, Mob *m );
+
+ /**
+ * Frees resources taken by the arena.
+ */
+
+ ~Arena( void );
+
+ /**
+ * Attempts to exit the world, returning the player to the world they were
+ * last in.
+ */
+
+ World *exitArena( Player *p );
};
-extern int worldShade;
-extern char *currentXML;
+/**
+ * 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.
+ */
+
+World *loadWorldFromXML(std::string path);
+
+/**
+ * Loads the player into the XML-scripted world, but does not save data from the
+ * previous world if one was loaded.
+ */
-World *loadWorldFromXML(const char *path);
-World *loadWorldFromXMLNoSave(const char *path);
+World *loadWorldFromXMLNoSave(std::string path);
#endif // WORLD_H
diff --git a/main.cpp b/main.cpp
index f0b49ad..f9282c4 100644
--- a/main.cpp
+++ b/main.cpp
@@ -11,6 +11,9 @@
#include <istream>
#include <thread>
+#include <tinyxml2.h>
+using namespace tinyxml2;
+
/*
* Game includes
*/
@@ -21,9 +24,6 @@
#include <ui.h>
#include <entities.h>
-#include <tinyxml2.h>
-using namespace tinyxml2;
-
/**
* Defines how many game ticks should occur in one second, affecting how often
* game logic is handled.
@@ -37,147 +37,127 @@ using namespace tinyxml2;
#define MSEC_PER_TICK (1000/TICKS_PER_SEC)
+/**
+ * The window object returned by SDL when we create the main window.
+ */
+SDL_Window *window = NULL;
-/*
- * window & mainGLContext
- *
- * In order to draw using SDL and its openGL facilities SDL requires
- * an SDL_Window object, which spawns a window for the program to draw
- * to. Once the SDL_Window is initialized, an SDL_GLContext is made so
- * that openGL calls can be made to SDL. The game requires both of these
- * variables to initialize.
+/**
+ * Determines when the game should exit. This variable is set to true right
+ * before the main loop is entered, once set to false the game will exit/
+ * free resources.
*/
-SDL_Window *window = NULL;
-SDL_GLContext mainGLContext = NULL;
+bool gameRunning;
-/*
- * bgImage contains the GLuint returned when creating a texture for the
- * background image. Currently there is only one background image for the
- * main world; this will be changed and bgImage likely removed once better
- * backgrounds are implemented.
+/**
+ * TODO
*/
-GLuint bgDay, bgNight, bgMtn, bgTreesFront, bgTreesMid, bgTreesFar, invUI;
+GLuint invUI;
-/*
- * gameRunning
- *
- * This is one of the most important variables in the program. The main
- * loop of the game is set to break once this variable is set to false.
- * The only call to modify this variable is made in src/ui.cpp, where it
- * is set to false if either an SDL_QUIT message is received (the user
- * closes the window through their window manager) or if escape is pressed.
+/**
+ * Contains an angle based off of the player's location and the mouse's
+ * location.
*/
-bool gameRunning;
-
float handAngle;
-/*
- * currentWorld - This is a pointer to the current world that the player
- * is in. Most drawing/entity handling is done through this
- * variable. This should only be changed when layer switch
- * buttons are pressed (see src/ui.cpp), or when the player
- * enters a Structure/Indoor World (see src/ui.cpp again).
- *
- * player - This points to a Player object, containing everything for
- * the player. Most calls made with currentWorld require a
- * Player object as an argument, and glOrtho is set based
- * off of the player's coordinates. This is probably the one
- * Entity-derived object that is not pointed to in the entity
- * array.
- *
+/**
+ * Contains a pointer to the world that the player is currently in. All render/
+ * logic operations have to go access members of this object in order to work.
*/
World *currentWorld = NULL;
+
+/**
+ * The player object.
+ */
+
Player *player;
-/*
- * Tells if player is currently inside a structure.
-*/
+/**
+ * TODO
+ */
+
+extern Menu *currentMenu;
-extern bool worldInside;
+/**
+ * The current number of ticks, used for logic operations and day/night cycles.
+ */
-extern Menu* currentMenu;
+unsigned int tickCount = 0;
-/*
- * tickCount contains the number of ticks generated since main loop entrance.
- * This variable might be used anywhere.
- *
- * deltaTime is used for interpolation stuff.
- *
- * Pretty sure these variables are considered static as they might be externally
- * referenced somewhere.
-*/
+/**
+ * TODO
+ */
-unsigned int tickCount = DAY_CYCLE;
unsigned int deltaTime = 0;
-/*
- *
-*/
+/**
+ * TODO
+ */
GLuint fragShader;
+
+/**
+ * TODO
+ */
+
GLuint shaderProgram;
-GLuint colorIndex;
-GLuint mouseTex;
+
+/**
+ * Threads and various variables to be used when multithreading the game,
+ * mutex will prevent multiple threads from changing the same data,
+ * and the condition_variable will wait for threads to reach the same point
+ */
+
+std::mutex mtx;
+std::condition_variable cv;
+ThreadPool pool(10);
/*
* loops is used for texture animation. It is believed to be passed to entity
* draw functions, although it may be externally referenced instead.
*/
-unsigned int loops = 0; // Used for texture animation
+/**
+ * TODO
+ */
-/*
- * initEverything
- *
- * Before the main loop, things like the player, entities, and worlds should
- * be created. This game has not reached the point that these can be scripted
- * or programmed, so this function substitues for that. It is defined in
- * src/gameplay.cpp.
- *
-*/
+GLuint colorIndex;
-extern void initEverything(void);
+/**
+ * TODO
+ */
-/*
- * mainLoop is in fact the main loop, which runs 'infinitely' (as long as gameRunning
- *
- *
- *
- * is set). Each loop updates timing values (tickCount and deltaTime), runs logic()
- * if MSEC_PER_TICK milliseconds have passed, and then runs render().
- *
- * logic handles all user input and entity/world physics.
- *
- * render handles all drawing to the window, calling draw functions for everything.
- *
-*/
+GLuint mouseTex;
-void logic(void);
-void render(void);
-void mainLoop(void);
+/**
+ * Used for texture animation. It is externally referenced by ui.cpp
+ * and entities.cpp.
+ */
-/*
- * This offset is used as the player offset in the world drawing so
- * everything can be moved according to the player
-*/
+unsigned int loops = 0;
+
+/**
+ * Gives a coordinate based off of the player's location to allow for drawing to
+ * be in a constant 'absolute' place on the window.
+ */
-vec2 offset; /* OFFSET!!!!!!!!!!!!!!!!!!!! */
+vec2 offset;
Menu *currentMenu;
Menu optionsMenu;
Menu pauseMenu;
-extern WEATHER weather;
+extern WorldWeather weather;
-extern int fadeIntensity;
-extern bool fadeEnable;
-extern bool fadeWhite;
-extern bool fadeFast;
+extern int fadeIntensity; // ui.cpp
+extern bool fadeEnable; // ui.cpp
+extern bool fadeWhite; // ui.cpp
+extern bool fadeFast; // ui.cpp
unsigned int SCREEN_WIDTH;
unsigned int SCREEN_HEIGHT;
@@ -188,13 +168,44 @@ float VOLUME_MASTER;
float VOLUME_MUSIC;
float VOLUME_SFX;
+/**
+ * Defined in gameplay.cpp, should result in `currentWorld` containing a pointer
+ * to a valid World.
+ */
+
+extern void initEverything(void);
+
+/**
+ * The game logic function, should handle all logic-related operations for the
+ * game.
+ */
+
+void logic(void);
+
+/**
+ * The game render function, should handle all drawing to the window.
+ */
+
+void render(void);
+
+/**
+ * The main loop, calls logic(), render(), and does timing operations in the
+ * appropriate order.
+ */
+
+void mainLoop(void);
+
/*******************************************************************************
* MAIN ************************************************************************
*******************************************************************************/
-int main(/*int argc, char *argv[]*/){
- // *argv = (char *)argc;
+
+int main(int argc, char *argv[]){
+ (void)argc;
+ (void)argv;
+
+ static SDL_GLContext mainGLContext = NULL;
- gameRunning=false;
+ gameRunning = false;
/**
* (Attempt to) Initialize SDL libraries so that we can use SDL facilities and eventually
@@ -295,16 +306,7 @@ int main(/*int argc, char *argv[]*/){
if((err=glewInit()) != GLEW_OK){
std::cout << "GLEW was not able to initialize! Error: " << glewGetErrorString(err) << std::endl;
return -1;
- }
-
- /*
- * Initialize the FreeType libraries and select what font to use using functions from the ui
- * namespace, defined in include/ui.h and src/ui.cpp. These functions should abort with errors
- * if they have error.
- */
-
- //ui::initFonts();
- //ui::setFontFace("ttf/FreePixel.ttf"); // as in gamedev/ttf/<font>
+ }
/*
* Initialize the random number generator. At the moment, initRand is a macro pointing to libc's
@@ -321,7 +323,7 @@ int main(/*int argc, char *argv[]*/){
*/
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
- SDL_GL_SetSwapInterval(0);
+ //SDL_GL_SetSwapInterval(0);
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
@@ -409,6 +411,9 @@ int main(/*int argc, char *argv[]*/){
**************************/
std::cout << "Num threads: " << std::thread::hardware_concurrency() << std::endl;
+
+ //currentWorld->mob.back()->followee = player;
+
gameRunning = true;
while(gameRunning){
mainLoop();
@@ -451,7 +456,7 @@ void mainLoop(void){
currentTime = 0, //
prevPrevTime= 0; //
World *prev;
-
+
if(!currentTime) // Initialize currentTime if it hasn't been
currentTime=millis();
@@ -472,35 +477,44 @@ void mainLoop(void){
*/
prev = currentWorld;
- ui::handleEvents();
+
+ //pool.Enqueue(ui::handleEvents);
+ ui::handleEvents();
+
if(prev != currentWorld){
currentWorld->bgmPlay(prev);
ui::dialogBoxExists = false;
}
+
if(prevPrevTime + MSEC_PER_TICK <= currentTime){
+ //pool.Enqueue(logic);
logic();
prevPrevTime = currentTime;
}
-
+
/*
* Update player and entity coordinates.
*/
- currentWorld->update(player,deltaTime);
+ /*pool.Enqueue([](){
+ currentWorld->update(player,deltaTime);
+ });*/
+ currentWorld->update(player,deltaTime);
+
/*
* Update debug variables if necessary
*/
- if(++debugDiv==20)
+ if ( ++debugDiv == 20 ) {
debugDiv=0;
- if(deltaTime)
- fps=1000/deltaTime;
- else if(!(debugDiv%10))
- debugY = player->loc.y;
-
+ if ( deltaTime )
+ fps = 1000 / deltaTime;
+ else if(!(debugDiv%10))
+ debugY = player->loc.y;
+ }
MENU:
render();
}
@@ -522,7 +536,7 @@ void render(){
if(currentWorld->getTheWidth() < (int)SCREEN_WIDTH){
offset.x = 0;
- }else if(!worldInside){
+ }else{
if(player->loc.x - SCREEN_WIDTH/2 < currentWorld->getTheWidth() * -0.5f)
offset.x = ((currentWorld->getTheWidth() * -0.5f) + SCREEN_WIDTH / 2) + player->width / 2;
if(player->loc.x + player->width + SCREEN_WIDTH/2 > currentWorld->getTheWidth() * 0.5f)
@@ -608,6 +622,7 @@ void render(){
/*
* Calculate the player's hand angle.
*/
+
handAngle = atan((ui::mouse.y - (player->loc.y + player->height/2)) / (ui::mouse.x - player->loc.x + player->width/2))*180/PI;
if(ui::mouse.x < player->loc.x){
if(handAngle <= 0)
@@ -628,10 +643,6 @@ void render(){
player->inv->draw();
/*
- * Here we draw a black overlay if it's been requested.
- */
-
- /*
* Here we draw a black overlay if it's been requested.
*/
@@ -647,7 +658,7 @@ void render(){
offset.y+SCREEN_HEIGHT/2);
}else if(ui::fontSize != 16)
ui::setFontSize(16);
-
+
/*
* Draw UI elements. This includes the player's health bar and the dialog box.
*/
@@ -765,19 +776,12 @@ void logic(){
* that the NPC doesn't move when it talks to the player.
*/
-/*<<<<<<< HEAD
- if(n->canMove) n->wander((rand() % 120 + 30));
-
- if(!player->inv->usingi) n->hit = false;
- if(player->inv->usingi && !n->hit && player->inv->detectCollision(vec2{n->loc.x, n->loc.y},vec2{n->loc.x+n->width,n->loc.y+n->height})){
-=======*/
if(n->canMove)
n->wander((rand() % 120 + 30));
/*if(!player->inv->usingi) n->hit = false;
if(player->inv->usingi && !n->hit && player->inv->detectCollision((vec2){n->loc.x, n->loc.y},(vec2){n->loc.x+n->width,n->loc.y+n->height})){
->>>>>>> 7ab072caaaec09720ad79cfed5738e89bc60c44f
n->health -= 25;
n->hit = true;
for(int r = 0; r < (rand()%5);r++)
@@ -894,41 +898,16 @@ void logic(){
}
}
}
- /*for(auto &b : currentWorld->build){
- switch(b->bsubtype){
- case FOUNTAIN:
- for(int r = 0; r < (rand()%25)+10;r++){
- currentWorld->addParticle( rand()%HLINE*3 + b->loc.x + b->width/2,
- b->loc.y + b->height,
- HLINE*1.25,
- HLINE*1.25,
- rand()%2 == 0?-(rand()%7)*.01:(rand()%7)*.01,
- ((4+rand()%6)*.05),
- {0,0,255},
- 2500);
-
- currentWorld->particles.back()->fountain = true;
- }
- break;
- case FIRE_PIT:
- for(int r = 0; r < (rand()%20)+10;r++){
- currentWorld->addParticle(rand()%(int)(b->width/2) + b->loc.x+b->width/4, b->loc.y+3*HLINE, HLINE, HLINE, rand()%2 == 0?-(rand()%3)*.01:(rand()%3)*.01,((4+rand()%6)*.005), {255,0,0}, 400);
- currentWorld->particles.back()->gravity = false;
- currentWorld->particles.back()->behind = true;
- }
- break;
- default: break;
- }
- }*/
/*
* Switch between day and night (SUNNY and DARK) if necessary.
- */
+ */
+
if(!(tickCount%DAY_CYCLE)||!tickCount){
- if(weather==SUNNY){
- weather=DARK;
- }else{
- weather=SUNNY;
+ if ( weather == WorldWeather::Sunny )
+ weather = WorldWeather::Dark;
+ else {
+ weather = WorldWeather::Sunny;
Mix_Pause(2);
}
}
diff --git a/setup.mk b/setup.mk
new file mode 100644
index 0000000..89bb9c3
--- /dev/null
+++ b/setup.mk
@@ -0,0 +1,5 @@
+# Target OS, can be either 'linux' or 'win32'
+TARGET_OS = linux
+
+# Bits setting, 32 or 64
+TARGET_BITS = 32
diff --git a/src/Makefile b/src/Makefile
deleted file mode 100644
index 91743ef..0000000
--- a/src/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-LIBS = -lpthread -lGL -lSDL2 -lSDL2_image -lSDL2_mixer -lfreetype
-
-FLAGS = -std=c++11 -I../include -I../include/freetype2 -Wall -Wextra -Werror
-
-OUT = `echo "" $$(ls -c $(wildcard *.cpp)) | sed s/.cpp/.o/g | sed 's/ / ..\/out\//g'`
-OUT64 = `echo "" $$(ls -c $(wildcard *.cpp)) | sed s/.cpp/.o/g | sed 's/ / ..\/out64\//g'`
-
-../out/%.o:
- @echo " CXX " $(shell echo $@ | sed 's/..\/out\///g' | sed 's/\.o/\.cpp/')
- @g++ $(FLAGS) -m32 -o $@ -c $(shell echo $@ | sed 's/..\/out\///g' | sed 's/\.o/\.cpp/') $(LIBS) -lSDL2main
-
-../out64/%.o:
- @echo " CXX " $(shell echo $@ | sed 's/..\/out64\///g' | sed 's/\.o/\.cpp/')
- @g++ $(FLAGS) -m64 -o $@ -c $(shell echo $@ | sed 's/..\/out64\///g' | sed 's/\.o/\.cpp/') $(LIBS)
-
-all: $(shell echo $(OUT))
-
-64: $(shell echo $(OUT64))
diff --git a/src/Quest.cpp b/src/Quest.cpp
index 535afc5..8f3c33b 100644
--- a/src/Quest.cpp
+++ b/src/Quest.cpp
@@ -1,5 +1,6 @@
-#include <Quest.h>
+#include <algorithm>
+#include <Quest.h>
#include <entities.h>
extern Player *player;
@@ -34,38 +35,38 @@ int QuestHandler::assign(std::string title,std::string desc,std::string req){
}
int QuestHandler::drop(std::string title){
- for(unsigned int i=0;i<current.size();i++){
- if(current[i].title == title){
- current.erase(current.begin()+i);
- return 0;
- }
- }
- return -1;
+ current.erase( std::remove_if( current.begin(),
+ current.end(),
+ [&](Quest q){ return q.title == title; }),
+ current.end() );
+
+ return 0;
}
int QuestHandler::finish(std::string t){
- for(unsigned int i=0;i<current.size();i++){
- if(current[i].title == t){
- for(auto &n : current[i].need){
- if(player->inv->hasItem(n.name) < n.n)
+ for ( auto c = current.begin(); c != current.end(); c++ ) {
+ if ( (*c).title == t ) {
+ for ( auto &n : (*c).need ) {
+ if ( player->inv->hasItem( n.name ) < n.n )
return 0;
}
- for(auto &n : current[i].need){
- player->inv->takeItem(n.name,n.n);
- }
+ for ( auto &n : (*c).need )
+ player->inv->takeItem( n.name, n.n );
- current.erase(current.begin()+i);
+ current.erase( c );
return 1;
}
}
+
return 0;
}
bool QuestHandler::hasQuest(std::string t){
- for(unsigned int i=0;i<current.size();i++){
- if(current[i].title == t)
+ for ( auto &c : current ) {
+ if ( c.title == t )
return true;
}
+
return false;
}
diff --git a/src/Texture.cpp b/src/Texture.cpp
index 1487dcd..ed93af9 100644
--- a/src/Texture.cpp
+++ b/src/Texture.cpp
@@ -1,45 +1,64 @@
+#include <algorithm>
+#include <string>
+
#include <Texture.h>
-#include <string.h>
-struct texture_t {
- char *name;
- GLuint tex;
- dim2 dim;
-} __attribute__ ((packed));
+/**
+ * A structure for keeping track of loaded textures.
+ */
+
+typedef struct {
+ std::string name; /**< The file path of the texture. */
+ GLuint tex; /**< The GLuint for the loaded texture. */
+ dim2 dim; /**< The dimensions of the texture. */
+} texture_t;
-struct index_t{
+struct index_t {
Color color;
int indexx;
int indexy;
};
-struct texture_t *LoadedTexture[256];
-unsigned int LoadedTextureCounter = 0;
+/**
+ * A vector of all loaded textures.
+ *
+ * Should a texture be asked to be loaded twice, loadTexture() can reference
+ * this array and reuse GLuint's to save memory.
+ */
+
+static std::vector<texture_t> LoadedTexture;
namespace Texture{
Color pixels[8][4];
- GLuint loadTexture(const char *fileName){
+
+ GLuint loadTexture(std::string fileName){
SDL_Surface *image;
GLuint object = 0;
- for(unsigned int i=0;i<LoadedTextureCounter;i++){
- if(!strcmp(LoadedTexture[i]->name,fileName)){
+ // check if texture is already loaded
+ for(auto &t : LoadedTexture){
+ if(t.name == fileName){
+
#ifdef DEBUG
- DEBUG_printf("Reusing loaded texture for %s\n",fileName);
+ DEBUG_printf("Reusing loaded texture for %s\n", fileName.c_str());
#endif // DEBUG
- return LoadedTexture[i]->tex;
+
+ return t.tex;
}
}
- if(!fileName)
- return 0;
-
- if(!(image = IMG_Load(fileName)))
+ // load SDL_surface of texture
+ if(!(image = IMG_Load(fileName.c_str())))
return 0;
+
#ifdef DEBUG
- DEBUG_printf("Loaded image file: %s\n", fileName);
+ DEBUG_printf("Loaded image file: %s\n", fileName.c_str());
#endif // DEBUG
+ /*
+ * Load texture through OpenGL.
+ */
+
glGenTextures(1,&object); // Turns "object" into a texture
glBindTexture(GL_TEXTURE_2D,object); // Binds "object" to the top of the stack
glPixelStoref(GL_UNPACK_ALIGNMENT,1);
@@ -61,33 +80,27 @@ namespace Texture{
image->pixels
);
- LoadedTexture[LoadedTextureCounter] = new struct texture_t; //(struct texture_t *)malloc(sizeof(struct texture_t));
- LoadedTexture[LoadedTextureCounter]->name = new char[strlen(fileName)+1]; //(char *)malloc(safe_strlen(fileName));
- LoadedTexture[LoadedTextureCounter]->tex = object;
- strcpy(LoadedTexture[LoadedTextureCounter]->name,fileName);
- LoadedTexture[LoadedTextureCounter]->dim.x = image->w;
- LoadedTexture[LoadedTextureCounter]->dim.y = image->h;
- LoadedTextureCounter++;
+ // add texture to LoadedTexture
+ LoadedTexture.push_back(texture_t{fileName,object,{image->w,image->h}});
- SDL_FreeSurface(image); // Free the surface
+ // free the SDL_Surface
+ SDL_FreeSurface(image);
return object;
}
- dim2 imageDim(const char *fileName){
- for(unsigned int i=0;i<LoadedTextureCounter;i++){
- if(!strcmp(LoadedTexture[i]->name,fileName)){
- return LoadedTexture[i]->dim;
- }
+ dim2 imageDim(std::string fileName){
+ for(auto &t : LoadedTexture){
+ if(t.name == fileName)
+ return t.dim;
}
return {0,0};
}
void freeTextures(void){
- for(unsigned int i=0;i<LoadedTextureCounter;i++){
- glDeleteTextures(1,&LoadedTexture[i]->tex);
- delete[] LoadedTexture[i]->name;
- delete LoadedTexture[i];
+ while(!LoadedTexture.empty()){
+ glDeleteTextures(1, &LoadedTexture.back().tex);
+ LoadedTexture.pop_back();
}
}
@@ -162,32 +175,30 @@ namespace Texture{
Texturec::Texturec(uint amt, ...){
va_list fNames;
texState = 0;
- image = new GLuint[amt];
va_start(fNames, amt);
- for(unsigned int i = 0; i < amt; i++){
- image[i] = Texture::loadTexture(va_arg(fNames, char *));
- }
+ for(unsigned int i = 0; i < amt; i++)
+ image.push_back( Texture::loadTexture(va_arg(fNames, char *)) );
va_end(fNames);
}
+Texturec::Texturec( std::initializer_list<std::string> l )
+{
+ texState = 0;
+ std::for_each( l.begin(), l.end(), [&](std::string s){ image.push_back( Texture::loadTexture( s ) ); });
+}
+
Texturec::Texturec(std::vector<std::string>v){
texState = 0;
- image = new GLuint[v.size()];
- for(unsigned int i = 0; i < v.size(); i++){
- image[i] = Texture::loadTexture(v[i].c_str());
- }
+ std::for_each( v.begin(), v.end(), [&](std::string s){ image.push_back( Texture::loadTexture( s ) ); });
}
Texturec::Texturec(uint amt,const char **paths){
texState = 0;
- image = new GLuint[amt];
- for(unsigned int i = 0; i < amt; i++){
- image[i] = Texture::loadTexture(paths[i]);
- }
+ for(unsigned int i = 0; i < amt; i++)
+ image.push_back( Texture::loadTexture(paths[i]) );
}
Texturec::~Texturec(){
- delete[] image;
}
void Texturec::bind(unsigned int bn){
diff --git a/src/common.cpp b/src/common.cpp
index faa7012..1c9c2b5 100644
--- a/src/common.cpp
+++ b/src/common.cpp
@@ -1,16 +1,15 @@
-#include <common.h>
#include <cstring>
#include <cstdio>
#include <chrono>
#ifndef __WIN32__
-#include <sys/types.h>
-#include <dirent.h>
-#include <errno.h>
-#include <vector>
+# include <sys/types.h>
+# include <dirent.h>
+# include <errno.h>
+# include <vector>
#endif // __WIN32__
-void *NULLPTR = NULL;
+#include <common.h>
#ifndef __WIN32__
@@ -21,22 +20,6 @@ unsigned int millis(void){
#endif // __WIN32__
-Condition::Condition(const char *_id,void *val){
- id = new char[strlen(_id)+1];
- strcpy(id,_id);
- value = val;
-}
-Condition::~Condition(){
- delete[] id;
-}
-
-bool Condition::sameID(const char *s){
- return !strcmp(id,s);
-}
-void *Condition::getValue(void){
- return value;
-}
-
void DEBUG_prints(const char* file, int line, const char *s,...){
va_list args;
printf("%s:%d: ",file,line);
@@ -97,7 +80,7 @@ const char *readFile(const char *path){
std::ifstream in (path,std::ios::in);
unsigned int size;
GLchar *buf;
-
+
if(!in.is_open()){
std::cout<<"Error reading file "<<path<<"!"<<std::endl;
abort();
@@ -113,29 +96,9 @@ const char *readFile(const char *path){
return buf;
}
-/*int strCreateFunc(const char *equ){
- static unsigned int size;
- static char *filebuf;
- static FILE *file;
-
- size = 57 + strlen(equ) + 3;
-
- filebuf = new char[size];
- memset(filebuf,0,size);
-
- strcpy(filebuf,"#include <stdio.h>\n#include <math.h>\nint main(){return ");
- strcat(filebuf,equ);
- strcat(filebuf,";}");
-
- if(!(file = fopen("gen.tmp","w"))){
- abort();
- }
-
- fwrite(filebuf,size,sizeof(char),file);
- delete[] filebuf;
- fclose(file);
-
- system("
-
- return 0;
-}*/
+void
+UserError( std::string reason )
+{
+ std::cout << "User error: " << reason << "!" << std::endl;
+ abort();
+}
diff --git a/src/config.cpp b/src/config.cpp
index 72a071d..45bab3f 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -56,6 +56,7 @@ void readConfig(){
}
void updateConfig(){
+
Mix_Volume(0,VOLUME_MASTER);
Mix_Volume(1,VOLUME_SFX * (VOLUME_MASTER/100.0f));
Mix_VolumeMusic(VOLUME_MUSIC * (VOLUME_MASTER/100.0f));
diff --git a/src/entities.cpp b/src/entities.cpp
index 6c2da81..8a10428 100644
--- a/src/entities.cpp
+++ b/src/entities.cpp
@@ -1,20 +1,38 @@
-#include <entities.h>
-#include <ui.h>
-
#include <istream>
-#define RAND_DIALOG_COUNT 13
+#include <entities.h>
+#include <ui.h>
extern std::istream *names;
-extern unsigned int loops;
-extern World *currentWorld;
+extern Player *player; // main.cpp
+extern World *currentWorld; // main.cpp
+extern unsigned int loops; // main.cpp
+extern unsigned int tickCount; // main.cpp
-extern Player *player;
+GLuint waterTex;
-extern const char *itemName;
+std::vector<int (*)(NPC *)> AIpreload; // A dynamic array of AI functions that are being preloaded
+std::vector<NPC *> AIpreaddr; // A dynamic array of pointers to the NPC's that are being assigned the preloads
-GLuint waterTex;
+#define 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 hypotenuese.",
+ "Did you know the developers spelt brazier as brazzier.",
+ "My dad once said to me, \"Boy, you are in a game.\" I never knew what he meant by that."
+};
void initEntity(){
waterTex = Texture::loadTexture("assets/waterTex.png");
@@ -78,6 +96,8 @@ void Entity::spawn(float x, float y){ //spawns the entity you pass to it based o
name = new char[32];
getRandomName(this);
+
+ followee = NULL;
}
Player::Player(){ //sets all of the player specific traits on object creation
@@ -125,6 +145,7 @@ NPC::NPC(){ //sets all of the NPC specific traits on object creation
randDialog = rand() % RAND_DIALOG_COUNT - 1;
dialogIndex = 0;
}
+
NPC::~NPC(){
while(!aiFunc.empty()){
aiFunc.pop_back();
@@ -135,6 +156,38 @@ NPC::~NPC(){
delete[] name;
}
+Merchant::Merchant(){ //sets all of the Merchant specific traits on object creation
+ width = HLINE * 10;
+ height = HLINE * 16;
+
+ type = MERCHT; //sets type to merchant
+ subtype = 0;
+
+ health = maxHealth = 100;
+
+ maxHealth = health = 100;
+ canMove = true;
+
+ trade.reserve(100);
+
+ //tex = new Texturec(1,"assets/NPC.png");
+ //inv = new Inventory(NPC_INV_SIZE);
+ //inv = new Inventory(1);
+
+ //randDialog = rand() % RAND_DIALOG_COUNT - 1;
+ dialogIndex = 0;
+}
+
+Merchant::~Merchant(){
+ /*while(!aiFunc.empty()){
+ aiFunc.pop_back();
+ }*/
+
+ //delete inv;
+ //delete tex;
+ //delete[] name;
+}
+
Structures::Structures(){ //sets the structure type
health = maxHealth = 1;
@@ -143,15 +196,14 @@ Structures::Structures(){ //sets the structure type
name = NULL;
- inv = NULL;
+ //inv = NULL;
canMove = false;
}
Structures::~Structures(){
delete tex;
+
if(name)
delete[] name;
- if(inside)
- delete[] inside;
}
Mob::Mob(int sub){
@@ -211,18 +263,11 @@ Object::Object(){
inv = NULL;
}
-Object::Object(std::string in, const char *pd){
+Object::Object(std::string in, std::string pd){
iname = in;
- if(pd){
- pickupDialog = new char[strlen(pd)+1];
- strcpy(pickupDialog,pd);
- questObject = true;
- }else{
- pickupDialog = new char[1];
- *pickupDialog = '\0';
- questObject = false;
- }
+ pickupDialog = pd;
+ questObject = !pd.empty();
type = OBJECTT;
alive = true;
@@ -235,7 +280,6 @@ Object::Object(std::string in, const char *pd){
inv = NULL;
}
Object::~Object(){
- delete[] pickupDialog;
delete tex;
delete[] name;
}
@@ -252,6 +296,10 @@ void Object::reloadTexture(void){
void Entity::draw(void){ //draws the entities
glPushMatrix();
glColor3ub(255,255,255);
+
+ if ( !alive )
+ return;
+
if(type==NPCT){
if(NPCp(this)->aiFunc.size()){
glColor3ub(255,255,0);
@@ -338,43 +386,39 @@ NOPE:
if(near)ui::putStringCentered(loc.x+width/2,loc.y-ui::fontSize-HLINE/2,name);
}
-/*
- * NPC::wander, this makes the npcs wander around the near area
- *
- * timeRun This variable is the amount of gameloop ticks the entity will wander for
-*/
+/**
+ * Handles NPC movement, usually just random walking.
+ */
-void NPC::wander(int timeRun){
-
- /*
- * Direction is the variable that decides what direction the entity will travel in
- * the value is either -1, 0, or 1. -1 being left, 0 means that the npc will stay still
- * and a value of 1 makes the entity move to the right
- */
-
+void NPC::
+wander( int timeRun )
+{
static int direction;
- /*
- * Ticks to use is a variable in the entity class that counts the total ticks that need to be used
- *
- * This loop only runs when ticksToUse is 0, this means that the speed, direction, etc... Will be
- * calculated only after the npc has finished his current walking state
- */
-
- if(ticksToUse == 0){
+ if ( followee ) {
+ if ( loc.x < followee->loc.x - 40 )
+ direction = 1;
+ else if ( loc.x > followee->loc.x + 40 )
+ direction = -1;
+ else
+ direction = 0;
+
+ vel.x = .018 * HLINE * direction;
+ } else if ( ticksToUse == 0 ) {
ticksToUse = timeRun;
- vel.x = .008*HLINE; //sets the inital velocity of the entity
- direction = (getRand() % 3 - 1); //sets the direction to either -1, 0, 1
- //this lets the entity move left, right, or stay still
- if(direction==0)ticksToUse*=2;
- vel.x *= direction; //changes the velocity based off of the direction
+
+ vel.x = .008 * HLINE;
+ direction = (getRand() % 3 - 1);
+
+ if ( direction == 0 )
+ ticksToUse *= 2;
+
+ vel.x *= direction;
}
- ticksToUse--; //removes one off of the entities timer
+
+ ticksToUse--;
}
-std::vector<int (*)(NPC *)> AIpreload; // A dynamic array of AI functions that are being preloaded
-std::vector<NPC *> AIpreaddr; // A dynamic array of pointers to the NPC's that are being assigned the preloads
-
void NPC::addAIFunc(int (*func)(NPC *),bool preload){
if(preload){ // Preload AI functions so that they're given after
// the current dialog box is closed
@@ -388,22 +432,6 @@ void NPC::clearAIFunc(void){
aiFunc.clear();
}
-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 hypotenuese.",
- "Did you know the developers spelt brazier as brazzier."
-};
-
void NPC::interact(){ //have the npc's interact back to the player
int (*func)(NPC *);
loc.y += 5;
@@ -425,12 +453,24 @@ void NPC::interact(){ //have the npc's interact back to the player
canMove=true;
}
+void Merchant::interact(){
+ ui::merchantBox(name, trade.back(), ":Accept:Good-Bye", false, "Welcome to Smithy\'s. Buy your sausages here you freaking meme lording screw-face");
+ ui::waitForDialog();
+ if(ui::dialogOptChosen == 1){
+ std::cout << "Gimme ye' munny" << std::endl;
+ if(player->inv->takeItem(trade.back().item[1],trade.back().quantity[1]) >= 0)
+ player->inv->addItem(trade.back().item[0],trade.back().quantity[0]);
+ }else{
+ std::cout << "See ye!" << std::endl;
+ }
+}
+
void Object::interact(void){
if(questObject && alive){
- ui::dialogBox(player->name,":Yes:No",false,pickupDialog);
+ ui::dialogBox( player->name, ":Yes:No", false, pickupDialog.c_str());
ui::waitForDialog();
if(ui::dialogOptChosen == 1){
- player->inv->addItem(/*(ITEM_ID)(identifier)*/iname, 1);
+ player->inv->addItem( iname, 1 );
alive = false;
}
}else{
@@ -439,6 +479,12 @@ void Object::interact(void){
}
}
+void Entity::
+follow( Entity *e )
+{
+ followee = e;
+}
+
/*
* This spawns the structures
*
@@ -467,14 +513,26 @@ unsigned int Structures::spawn(BUILD_SUB sub, float x, float y){
*/
//unsigned int tempN = (getRand() % 5 + 2);
+
+ if ( textureLoc.empty() )
+ textureLoc = inWorld->sTexLoc[sub];
+
switch(sub){
+ case STALL_MARKET:
+ tex = new Texturec({ textureLoc });
+ dim = Texture::imageDim( textureLoc );
+ width = dim.x;
+ height = dim.y;
+ break;
default:
- tex = new Texturec(1, textureLoc ? textureLoc : inWorld->sTexLoc[sub].c_str());
- dim = Texture::imageDim(textureLoc ? textureLoc : inWorld->sTexLoc[sub].c_str());
+ tex = new Texturec({ textureLoc });
+ dim = Texture::imageDim( textureLoc );
width = dim.x;
height = dim.y;
+ inv = NULL;
break;
}
+
return 0;
}
@@ -489,12 +547,26 @@ void Mob::wander(int timeRun){
static unsigned int heya=0,hi=0;
static bool YAYA = false;
+ if ( followee ) {
+ if ( loc.x < followee->loc.x - 40 )
+ direction = 1;
+ else if ( loc.x > followee->loc.x + 40 )
+ direction = -1;
+ else
+ direction = 0;
+
+ vel.x = .018 * HLINE * direction;
+ return;
+ }
+
if(aggressive && !YAYA &&
player->loc.x + (width / 2) > loc.x && player->loc.x + (width / 2) < loc.x + width &&
player->loc.y + (height / 3) > loc.y && player->loc.y + (height / 3) < loc.y + height ){
Arena *a = new Arena(currentWorld,player,this);
- a->setBackground(BG_FOREST);
+ a->setStyle("");
+ a->setBackground( WorldBGType::Forest );
a->setBGM("assets/music/embark.wav");
+
ui::toggleWhiteFast();
YAYA = true;
ui::waitForCover();
@@ -559,12 +631,13 @@ void Player::save(void){
data.append(std::to_string((int)loc.y) + "\n");
data.append(std::to_string((int)health) + "\n");
data.append(std::to_string((int)maxHealth) + "\n");
+ data.append(std::to_string((int)tickCount) + "\n");
data.append(std::to_string((int)inv->items.size()) + "\n");
for(auto &i : inv->items)
data.append(std::to_string((int)i.count) + "\n" + std::to_string((int)i.id) + "\n");
- data.append((std::string)(currentXML+4) + "\n");
+ data.append((std::string)(currentXML.c_str() + 4) + "\n");
data.append("dOnE\0");
out.write(data.c_str(),data.size());
@@ -599,13 +672,15 @@ void Player::sspawn(float x,float y){
health = std::stoi(ddata);
std::getline(data,ddata);
maxHealth = std::stoi(ddata);
+ std::getline(data,ddata);
+ tickCount = std::stoi(ddata);
std::getline(data,ddata);
for(i = std::stoi(ddata);i;i--){
std::getline(data,ddata);
count = std::stoi(ddata);
std::getline(data,ddata);
- inv->items.push_back((item_t){count,(uint)std::stoi(ddata)});
+ inv->items.push_back(item_t{count,(uint)std::stoi(ddata)});
}
std::getline(data,ddata);
diff --git a/src/gameplay.cpp b/src/gameplay.cpp
index 4bbc672..0624067 100644
--- a/src/gameplay.cpp
+++ b/src/gameplay.cpp
@@ -4,30 +4,28 @@
#include <ui.h>
#include <tinyxml2.h>
-
using namespace tinyxml2;
-extern World *currentWorld;
-extern Player *player;
+extern Player *player; // main.cpp
+extern World *currentWorld; // main.cpp
-extern float shit;
-extern Menu* currentMenu;
-extern Menu pauseMenu;
-extern Menu optionsMenu;
+extern float shit;
+extern Menu *currentMenu;
+extern Menu pauseMenu;
+extern Menu optionsMenu;
-extern void mainLoop(void);
+extern void mainLoop(void); // main.cpp
-void segFault(){
- (*((int *)NULL))++;
-}
+extern std::vector<NPC *> AIpreaddr; // entities.cpp
+extern std::vector<int (*)(NPC *)> AIpreload; // entities.cpp
+std::vector<XMLElement *> dopt;
-typedef struct {
- NPC *npc;
- unsigned int index;
-} NPCDialog;
+void destroyEverything(void);
-std::vector<XMLElement *> dopt;
+void segFault(){
+ (*((int *)NULL))++;
+}
int commonAIFunc(NPC *speaker){
XMLDocument xml;
@@ -43,7 +41,7 @@ int commonAIFunc(NPC *speaker){
* Load the current world's XML file into memory for reading.
*/
- xml.LoadFile(currentXML);
+ xml.LoadFile(currentXML.c_str());
exml = xml.FirstChildElement("Dialog");
/*
@@ -68,12 +66,12 @@ int commonAIFunc(NPC *speaker){
*/
if((oxml = exml->FirstChildElement("quest"))){
- const char *qname;
+ std::string qname;
- while(oxml){
- if((qname = oxml->Attribute("assign")))
+ while ( oxml ) {
+ if ( !(qname = oxml->StrAttribute("assign")).empty() )
player->qh.assign(qname,"None",(std::string)oxml->GetText());
- else if((qname = oxml->Attribute("check"))){
+ else if( !(qname = oxml->StrAttribute("check")).empty() ){
if(player->qh.hasQuest(qname) && player->qh.finish(qname)){
goto CONT;
}else{
@@ -217,12 +215,11 @@ void commonTriggerFunc(Mob *callee){
XMLDocument xml;
XMLElement *exml;
- char *text,*pch;
-
+ char *text,*pch;
if(!lock){
lock = true;
- xml.LoadFile(currentXML);
+ xml.LoadFile(currentXML.c_str());
exml = xml.FirstChildElement("Trigger");
while(strcmp(exml->Attribute("id"),callee->heyid.c_str()))
@@ -253,7 +250,6 @@ void commonTriggerFunc(Mob *callee){
}
}
-void destroyEverything(void);
void initEverything(void){
std::vector<std::string> xmlFiles;
XMLDocument xml;
@@ -283,12 +279,12 @@ void initEverything(void){
/*
* Read in the XML file.
*/
-
- currentWorld = loadWorldFromXML(xmlFiles[i].c_str());
+
+ currentWorld = loadWorldFromXML(xmlFiles[i]);
break;
}
}
-
+
pauseMenu.items.push_back(ui::createParentButton({-256/2,0},{256,75},{0.0f,0.0f,0.0f}, "Resume"));
pauseMenu.items.push_back(ui::createChildButton({-256/2,-100},{256,75},{0.0f,0.0f,0.0f}, "Options"));
pauseMenu.items.push_back(ui::createButton({-256/2,-200},{256,75},{0.0f,0.0f,0.0f}, "Save and Quit", ui::quitGame));
@@ -315,12 +311,10 @@ void initEverything(void){
atexit(destroyEverything);
}
-extern std::vector<int (*)(NPC *)> AIpreload;
-extern std::vector<NPC *> AIpreaddr;
-
void destroyEverything(void){
currentWorld->save();
delete currentWorld;
+ //delete[] currentXML;
while(!AIpreload.empty())
AIpreload.pop_back();
diff --git a/src/inventory.cpp b/src/inventory.cpp
index b32b56f..e82d99e 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -14,6 +14,8 @@ static vec2 itemLoc;
Mix_Chunk* swordSwing;
static std::vector<Item *> itemMap;
+static GLuint *itemtex;
+void itemDraw(Player *p,uint id);
void items(void){
XMLDocument xml;
@@ -44,7 +46,7 @@ int Inventory::addItem(std::string name,uint count){
return 0;
}
}
- items.push_back((item_t){count,i});
+ items.push_back( item_t { count, i });
return 0;
}
}
@@ -66,7 +68,7 @@ int Inventory::takeItem(std::string name,uint count){
}
if(id == 999999)
- return -1;
+ return -1; //if no such item exists
/*
* Inventory lookup
@@ -108,9 +110,6 @@ int Inventory::hasItem(std::string name){
return 0;
}
-static GLuint *itemtex;
-void itemDraw(Player *p,uint id);
-
void initInventorySprites(void){
items();
@@ -142,6 +141,15 @@ const char *getItemTexturePath(std::string name){
return NULL;
}
+GLuint getItemTexture(std::string name){
+ for(auto &i : itemMap){
+ if(i->name == name)
+ return Texture::loadTexture(i->texloc);
+ }
+
+ return Texture::loadTexture("assets/items/ITEM_TEST.png");
+}
+
float getItemWidth(std::string name){
for(auto &i : itemMap){
if(i->name == name)
@@ -407,6 +415,8 @@ int Inventory::useItem(void){
}
bool Inventory::detectCollision(vec2 one, vec2 two){
+ (void)one;
+ (void)two;
//float i = 0.0f;
/*if(items.empty() || !items[sel].count)
@@ -433,6 +443,6 @@ bool Inventory::detectCollision(vec2 one, vec2 two){
i+=HLINE;
}
}*/
- return !(one.x == two.y);
+ return false;
}
diff --git a/src/threadpool.cpp b/src/threadpool.cpp
new file mode 100644
index 0000000..619f002
--- /dev/null
+++ b/src/threadpool.cpp
@@ -0,0 +1,99 @@
+#include "threadpool.h"
+
+/**
+ * Stolen from some guy.
+ */
+
+// Constructor.
+ThreadPool::ThreadPool(int threads) :
+ terminate(false),
+ stopped(false)
+{
+ // Create number of required threads and add them to the thread pool vector.
+ for(int i = 0; i < threads; i++)
+ {
+ threadPool.emplace_back(thread(&ThreadPool::Invoke, this));
+ }
+}
+
+void ThreadPool::Enqueue(function<void()> f)
+{
+ // Scope based locking.
+ {
+ // Put unique lock on task mutex.
+ unique_lock<mutex> lock(tasksMutex);
+
+ // Push task into queue.
+ tasks.push(f);
+ }
+
+ // Wake up one thread.
+ condition.notify_one();
+}
+
+void ThreadPool::Invoke() {
+
+ function<void()> task;
+ while(true)
+ {
+ // Scope based locking.
+ {
+ // Put unique lock on task mutex.
+ unique_lock<mutex> lock(tasksMutex);
+
+ // Wait until queue is not empty or termination signal is sent.
+ condition.wait(lock, [this]{ return !tasks.empty() || terminate; });
+
+ // If termination signal received and queue is empty then exit else continue clearing the queue.
+ if (terminate && tasks.empty())
+ {
+ return;
+ }
+
+ // Get next task in the queue.
+ task = tasks.front();
+
+ // Remove it from the queue.
+ tasks.pop();
+ }
+
+ // Execute the task.
+ task();
+ }
+}
+
+void ThreadPool::ShutDown()
+{
+ // Scope based locking.
+ {
+ // Put unique lock on task mutex.
+ unique_lock<mutex> lock(tasksMutex);
+
+ // Set termination flag to true.
+ terminate = true;
+ }
+
+ // Wake up all threads.
+ condition.notify_all();
+
+ // Join all threads.
+ for(thread &thread : threadPool)
+ {
+ thread.join();
+ }
+
+ // Empty workers vector.
+ threadPool.empty();
+
+ // Indicate that the pool has been shut down.
+ stopped = true;
+}
+
+// Destructor.
+ThreadPool::~ThreadPool()
+{
+ if (!stopped)
+ {
+ ShutDown();
+ }
+}
diff --git a/src/tinyxml2.cpp b/src/tinyxml2.cpp
index c4ea7cd..6198418 100755
--- a/src/tinyxml2.cpp
+++ b/src/tinyxml2.cpp
@@ -1400,6 +1400,18 @@ const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
return 0;
}
+std::string XMLElement::StrAttribute( const char* name, const char* value ) const
+{
+ std::string str;
+ const XMLAttribute* a = FindAttribute( name );
+ if ( a ) {
+ if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
+ str = a->Value();
+ return str;
+ }
+ }
+ return str;
+}
const char* XMLElement::Attribute( const char* name, const char* value ) const
{
@@ -1413,7 +1425,6 @@ const char* XMLElement::Attribute( const char* name, const char* value ) const
return 0;
}
-
const char* XMLElement::GetText() const
{
if ( FirstChild() && FirstChild()->ToText() ) {
diff --git a/src/ui.cpp b/src/ui.cpp
index 6e616a7..eb25e2e 100644
--- a/src/ui.cpp
+++ b/src/ui.cpp
@@ -12,7 +12,7 @@ extern SDL_Window *window;
/*
* External references for updating player coords / current world.
-*/
+ */
extern Player *player;
extern World *currentWorld;
@@ -30,6 +30,7 @@ extern std::vector<NPC *> AIpreaddr;
*/
extern bool gameRunning;
+extern unsigned int tickCount;
/*
* Freetype variables, and a GLuint for referencing rendered letters.
@@ -48,11 +49,16 @@ static unsigned char fontColor[3] = {255,255,255};
* Variables for dialog boxes / options.
*/
-static char dialogBoxText[512];
-static char *dialogOptText[4];
-static float dialogOptLoc[4][3];
+static char dialogBoxText[512];
+static char *dialogOptText[4];
+static float merchAOptLoc[2][3];
+static float dialogOptLoc[4][3];
static unsigned char dialogOptCount = 0;
-static bool typeOutDone = true;
+static bool typeOutDone = true;
+
+/*
+ * Menu-related objects
+ */
extern Menu* currentMenu;
extern Menu pauseMenu;
@@ -114,7 +120,9 @@ namespace ui {
bool debug=false;
bool posFlag=false;
bool dialogPassive = false;
+ bool dialogMerchant = false;
int dialogPassiveTime = 0;
+ Trade merchTrade;
/*
@@ -124,6 +132,7 @@ namespace ui {
bool dialogBoxExists = false;
bool dialogImportant = false;
unsigned char dialogOptChosen = 0;
+ unsigned char merchOptChosen = 0;
unsigned int textWrapLimit = 110;
@@ -183,7 +192,7 @@ namespace ui {
void setFontSize(unsigned int size){
unsigned int i,j;
- char *buf;
+ unsigned char *buf;
fontSize=size;
FT_Set_Pixel_Sizes(ftf,0,fontSize);
@@ -223,7 +232,7 @@ namespace ui {
* making it white-on-black.
*/
- buf = new char[ftf->glyph->bitmap.width * ftf->glyph->bitmap.rows * 4];
+ buf = new unsigned char[ftf->glyph->bitmap.width * ftf->glyph->bitmap.rows * 4];
for(j=0;j<ftf->glyph->bitmap.width*ftf->glyph->bitmap.rows;j++){
buf[j*4 ]=255;//fontColor[0];
@@ -306,6 +315,7 @@ namespace ui {
unsigned int i=0;
float xo=x,yo=y;
vec2 add;
+ //vec2 off = { (float)floor(x), (float)floor(y) };
/*
* Loop on each character:
@@ -318,6 +328,14 @@ namespace ui {
if(s[i] == ' ')
i++;
}
+ if(i && (i / (float)textWrapLimit == i / textWrapLimit)){
+ yo -= fontSize * 1.05;
+ xo = x;
+
+ // skip a space if it's there since we just newline'd
+ if(s[i] == ' ')
+ i++;
+ }
if(s[i] == '\n'){
yo-=fontSize*1.05;
xo=x;
@@ -447,6 +465,7 @@ namespace ui {
return width;
}
void dialogBox(const char *name,const char *opt,bool passive,const char *text,...){
+ textWrapLimit = 110;
va_list dialogArgs;
unsigned int len;
char *sopt,*soptbuf;
@@ -514,6 +533,78 @@ namespace ui {
if(ret)
ret[0] = '\0';
}
+
+
+ void merchantBox(const char *name,Trade trade,const char *opt,bool passive,const char *text,...){
+ std::cout << "Buying and selling on the bi-weekly!" << std::endl;
+ va_list dialogArgs;
+ size_t len;
+
+ dialogPassive = passive;
+
+ std::cout << "Market Trading: " << trade.quantity[0] << " " << trade.item[0] << " for " << trade.quantity[1] << " " << trade.item[1] << std::endl;
+
+ merchTrade = trade;
+
+ // clear the buffer
+ memset(dialogBoxText, '\0', 512);
+
+ // create the string
+ strcpy(dialogBoxText, name);
+ strcat(dialogBoxText, ": ");
+
+ len=strlen(dialogBoxText);
+ va_start(dialogArgs,text);
+ vsnprintf(dialogBoxText + len, 512 - len, text, dialogArgs);
+ va_end(dialogArgs);
+
+ // free old option text
+ while(dialogOptCount){
+ if(dialogOptText[dialogOptCount]){
+ delete[] dialogOptText[dialogOptCount];
+ dialogOptText[dialogOptCount] = NULL;
+ }
+
+ dialogOptCount--;
+ };
+
+ dialogOptChosen = 0;
+ memset(&dialogOptLoc, 0, sizeof(float) * 12);
+
+ // handle options if desired
+ if(opt){
+ //std::unique_ptr<char[]> soptbuf (new char[strlen(opt) + 1]);
+ char soptbuf[255];
+ strcpy(soptbuf, opt);
+ char *sopt = strtok(soptbuf, ":");
+
+ // cycle through options
+ while(sopt){
+ strcpy( (dialogOptText[dialogOptCount++] = new char[strlen(sopt) + 1]), sopt);
+ sopt = strtok(NULL,":");
+ }
+ }
+
+ // allow box to be displayed
+ dialogBoxExists = true;
+ dialogImportant = false;
+ dialogMerchant = true;
+ textWrapLimit = 50;
+
+ // kill the string created by typeOut if it contains something
+ if(ret)
+ *ret = '\0';
+ }
+
+ void merchantBox(){
+ textWrapLimit = 50;
+ dialogMerchant = true;
+ }
+
+ /**
+ * Wait for a dialog box to be dismissed.
+ */
+
void waitForDialog(void){
do{
mainLoop();
@@ -588,14 +679,114 @@ namespace ui {
putStringCentered(offset.x,offset.y,rtext);
setFontSize(16);
}
- }else{
-
- x=offset.x-SCREEN_WIDTH/2+HLINE*8;
+ }else if(dialogMerchant){
+ //static int dispItem;
+
+ x=offset.x-SCREEN_WIDTH/6;
y=(offset.y+SCREEN_HEIGHT/2)-HLINE*8;
glColor3ub(255,255,255);
glBegin(GL_LINE_STRIP);
+ glVertex2f(x-1 ,y+1);
+ glVertex2f(x+1+(SCREEN_WIDTH/3),y+1);
+ glVertex2f(x+1+(SCREEN_WIDTH/3),y-1-SCREEN_HEIGHT*.6);
+ glVertex2f(x-1,y-1-SCREEN_HEIGHT*.6);
+ glVertex2f(x,y+1);
+ glEnd();
+
+ glColor3ub(0,0,0);
+ glRectf(x,y,x+SCREEN_WIDTH/3,y-SCREEN_HEIGHT*.6);
+
+ // draw typeOut'd text
+ putString(x + HLINE, y - fontSize - HLINE, (rtext = typeOut(dialogBoxText)));
+
+ std::string itemString1 = std::to_string(merchTrade.quantity[0]);
+ itemString1 += "x";
+
+ std::string itemString2 = std::to_string(merchTrade.quantity[1]);
+ itemString2 += "x";
+
+ putStringCentered(offset.x - (SCREEN_WIDTH / 10) + 20, offset.y + (SCREEN_HEIGHT / 5) + 40 + (fontSize*2), itemString1.c_str());
+ putStringCentered(offset.x - (SCREEN_WIDTH / 10) + 20, offset.y + (SCREEN_HEIGHT / 5) + 40 + fontSize, merchTrade.item[0].c_str());
+
+ putStringCentered(offset.x + (SCREEN_WIDTH / 10) - 20, offset.y + (SCREEN_HEIGHT / 5) + 40 + (fontSize*2), itemString2.c_str());
+ putStringCentered(offset.x + (SCREEN_WIDTH / 10) - 20, offset.y + (SCREEN_HEIGHT / 5) + 40 + fontSize, merchTrade.item[1].c_str());
+
+ putStringCentered(offset.x,offset.y + (SCREEN_HEIGHT / 5) + 60, "for");
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, getItemTexture(merchTrade.item[0]));
+ glBegin(GL_QUADS);
+ glTexCoord2d(0,1);glVertex2f(offset.x - (SCREEN_WIDTH / 10) ,offset.y + (SCREEN_HEIGHT/5));
+ glTexCoord2d(1,1);glVertex2f(offset.x - (SCREEN_WIDTH / 10) + 40,offset.y + (SCREEN_HEIGHT/5));
+ glTexCoord2d(1,0);glVertex2f(offset.x - (SCREEN_WIDTH / 10) + 40,offset.y + (SCREEN_HEIGHT/5) + 40);
+ glTexCoord2d(0,0);glVertex2f(offset.x - (SCREEN_WIDTH / 10) ,offset.y + (SCREEN_HEIGHT/5) + 40);
+ glEnd();
+
+ glBindTexture(GL_TEXTURE_2D, getItemTexture(merchTrade.item[1]));
+ glBegin(GL_QUADS);
+ glTexCoord2d(0,1);glVertex2f(offset.x + (SCREEN_WIDTH / 10) - 40,offset.y + (SCREEN_HEIGHT/5));
+ glTexCoord2d(1,1);glVertex2f(offset.x + (SCREEN_WIDTH / 10) ,offset.y + (SCREEN_HEIGHT/5));
+ glTexCoord2d(1,0);glVertex2f(offset.x + (SCREEN_WIDTH / 10) ,offset.y + (SCREEN_HEIGHT/5) + 40);
+ glTexCoord2d(0,0);glVertex2f(offset.x + (SCREEN_WIDTH / 10) - 40,offset.y + (SCREEN_HEIGHT/5) + 40);
+ glEnd();
+ glDisable(GL_TEXTURE_2D);
+
+ merchAOptLoc[0][0] = offset.x - (SCREEN_WIDTH / 8.5) - 16;
+ merchAOptLoc[1][0] = offset.x + (SCREEN_WIDTH / 8.5) + 16;
+ merchAOptLoc[0][1] = offset.y + (SCREEN_HEIGHT *.2);
+ merchAOptLoc[1][1] = offset.y + (SCREEN_HEIGHT *.2);
+ merchAOptLoc[0][2] = offset.x - (SCREEN_WIDTH / 8.5);
+ merchAOptLoc[1][2] = offset.x + (SCREEN_WIDTH / 8.5);
+
+ for(i = 0; i < 2; i++){
+ if(((merchAOptLoc[i][0] < merchAOptLoc[i][2]) ?
+ (mouse.x > merchAOptLoc[i][0] && mouse.x < merchAOptLoc[i][2]) :
+ (mouse.x < merchAOptLoc[i][0] && mouse.x > merchAOptLoc[i][2])) &&
+ mouse.y > merchAOptLoc[i][1] - 8 && mouse.y < merchAOptLoc[i][1] + 8){
+ glColor3ub(255,255, 0);
+ }else{
+ glColor3ub(255,255,255);
+ }
+ glBegin(GL_TRIANGLES);
+ glVertex2f(merchAOptLoc[i][0],merchAOptLoc[i][1]);
+ glVertex2f(merchAOptLoc[i][2],merchAOptLoc[i][1]-8);
+ glVertex2f(merchAOptLoc[i][2],merchAOptLoc[i][1]+8);
+ glEnd();
+ }
+
+
+ // draw / handle dialog options if they exist
+ for(i = 0; i < dialogOptCount; i++){
+ setFontColor(255, 255, 255);
+
+ // draw option
+ tmp = putStringCentered(offset.x, dialogOptLoc[i][1], dialogOptText[i]);
+
+ // get coordinate information on option
+ dialogOptLoc[i][2] = offset.x + tmp;
+ dialogOptLoc[i][0] = offset.x - tmp;
+ dialogOptLoc[i][1] = y - SCREEN_HEIGHT / 2 - (fontSize + HLINE) * (i + 1);
+
+ // make text yellow if the mouse hovers over the text
+ if(mouse.x > dialogOptLoc[i][0] && mouse.x < dialogOptLoc[i][2] &&
+ mouse.y > dialogOptLoc[i][1] && mouse.y < dialogOptLoc[i][1] + 16 ){
+ setFontColor(255, 255, 0);
+ putStringCentered(offset.x, dialogOptLoc[i][1], dialogOptText[i]);
+ }
+ }
+
+ setFontColor(255, 255, 255);
+ }else{ //normal dialog box
+
+ x=offset.x-SCREEN_WIDTH/2+HLINE*8;
+ y=(offset.y+SCREEN_HEIGHT/2)-HLINE*8;
+
+ // draw white border
+ glColor3ub(255, 255, 255);
+
+ glBegin(GL_LINE_STRIP);
glVertex2f(x-1 ,y+1);
glVertex2f(x+1+SCREEN_WIDTH-HLINE*16,y+1);
glVertex2f(x+1+SCREEN_WIDTH-HLINE*16,y-1-SCREEN_HEIGHT/4);
@@ -941,7 +1132,8 @@ namespace ui {
}
void takeScreenshot(GLubyte* pixels){
- GLubyte bgr[SCREEN_WIDTH*SCREEN_HEIGHT*3];
+ std::vector<GLubyte> bgr (SCREEN_WIDTH * SCREEN_HEIGHT * 3, 0);
+
for(uint x = 0; x < SCREEN_WIDTH*SCREEN_HEIGHT*3; x+=3){
bgr[x] = pixels[x+2];
bgr[x+1] = pixels[x+1];
@@ -1022,16 +1214,18 @@ namespace ui {
}
}
DONE:
+
+
+ // handle important text
if(dialogImportant){
dialogImportant = false;
setFontSize(16);
- //toggleBlack();
}
- /*if(ui::fontSize != 16)
- setFontSize(16);*/
+ if(dialogMerchant) dialogMerchant = false;
dialogBoxExists = false;
}
+
void handleEvents(void){
static bool left=true,right=false;
static int heyOhLetsGo = 0;
@@ -1039,44 +1233,53 @@ DONE:
vec2 oldpos,tmppos;
SDL_Event e;
- mouse.x=premouse.x+offset.x-(SCREEN_WIDTH/2);
- mouse.y=(offset.y+SCREEN_HEIGHT/2)-premouse.y;
+ // update mouse coords
+ mouse.x = premouse.x + offset.x - ( SCREEN_WIDTH / 2 );
+ mouse.y = ( offset.y + SCREEN_HEIGHT / 2 ) - premouse.y;
while(SDL_PollEvent(&e)){
switch(e.type){
+
+ // escape - quit game
case SDL_QUIT:
gameRunning=false;
break;
+
+ // mouse movement - update mouse vector
case SDL_MOUSEMOTION:
premouse.x=e.motion.x;
premouse.y=e.motion.y;
break;
+
+ // mouse clicks
case SDL_MOUSEBUTTONDOWN:
- if((e.button.button & SDL_BUTTON_RIGHT) && dialogBoxExists)
+ // right click advances dialog
+ if ( ( e.button.button & SDL_BUTTON_RIGHT ) && dialogBoxExists )
dialogAdvance();
- if((e.button.button & SDL_BUTTON_LEFT) && !dialogBoxExists)
+ // left click uses item
+ if ( ( e.button.button & SDL_BUTTON_LEFT ) && !dialogBoxExists )
player->inv->usingi = true;
break;
- /*
- KEYDOWN
- */
+
+ // key presses
case SDL_KEYDOWN:
- /*if(SDL_KEY == SDLK_ESCAPE){
- //gameRunning = false;
- pMenu = true;
- return;
- }else */if(SDL_KEY == SDLK_SPACE){
- /*if(dialogBoxExists)
- dialogAdvance();
- else */if(player->ground){
- player->vel.y=.4;
- player->loc.y+=HLINE*2;
- player->ground=false;
+
+ // space - make player jump
+ if ( SDL_KEY == SDLK_SPACE ) {
+ if ( player->ground ) {
+ player->loc.y += HLINE * 2;
+ player->vel.y = .4;
+ player->ground = false;
}
break;
- }else if(!dialogBoxExists || dialogPassive){
+
+ // only let other keys be handled if dialog allows it
+ } else if ( !dialogBoxExists || dialogPassive ) {
tmp = currentWorld;
switch(SDL_KEY){
+ case SDLK_t:
+ tickCount += 50;
+ break;
case SDLK_a:
if(fadeEnable)break;
player->vel.x=-.15;
@@ -1255,7 +1458,7 @@ DONE:
//currentWorld->addVillage(player->loc.x, player->loc.y, 5, 10, 100, NULL);
break;
case SDLK_b:
- currentWorld->addStructure(FIRE_PIT, player->loc.x, player->loc.y, NULL, NULL);
+ currentWorld->addStructure(FIRE_PIT, player->loc.x, player->loc.y, "", "");
currentWorld->addLight({player->loc.x + SCREEN_WIDTH/2, player->loc.y},{1.0f,1.0f,1.0f});
break;
case SDLK_F12:
@@ -1264,10 +1467,10 @@ DONE:
pixels = new GLubyte[ 3 * SCREEN_WIDTH * SCREEN_HEIGHT];
glReadPixels(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels);
- static std::thread scr;
- scr = std::thread(takeScreenshot,pixels);
- scr.detach();
- //takeScreenshot(pixels);
+ //static std::thread scr;
+ //scr = std::thread(takeScreenshot,pixels);
+ //scr.detach();
+ takeScreenshot(pixels);
std::cout << "Took screenshot" << std::endl;
break;
@@ -1284,34 +1487,36 @@ DONE:
}
}
- if(!dialogBoxExists&&AIpreaddr.size()){ // Flush preloaded AI functions if necessary
- while(!AIpreaddr.empty()){
- AIpreaddr.front()->addAIFunc(AIpreload.front(),false);
- AIpreaddr.erase(AIpreaddr.begin());
- AIpreload.erase(AIpreload.begin());
+ // Flush preloaded AI functions if necessary
+ if ( !dialogBoxExists && AIpreaddr.size() ) {
+ while ( !AIpreaddr.empty() ) {
+ AIpreaddr.front()->addAIFunc( AIpreload.front(), false );
+ AIpreaddr.erase( AIpreaddr.begin() );
+ AIpreload.erase( AIpreload.begin() );
}
}
}
void toggleBlack(void){
fadeEnable ^= true;
- fadeWhite = false;
- fadeFast = false;
+ fadeWhite = false;
+ fadeFast = false;
}
void toggleBlackFast(void){
fadeEnable ^= true;
- fadeWhite = false;
- fadeFast = true;
+ fadeWhite = false;
+ fadeFast = true;
}
void toggleWhite(void){
fadeEnable ^= true;
- fadeWhite = true;
- fadeFast = false;
+ fadeWhite = true;
+ fadeFast = false;
}
void toggleWhiteFast(void){
fadeEnable ^= true;
- fadeWhite = true;
- fadeFast = true;
- Mix_PlayChannel(1,battleStart,0);
+ fadeWhite = true;
+ fadeFast = true;
+
+ Mix_PlayChannel( 1, battleStart, 0 );
}
}
diff --git a/src/world.cpp b/src/world.cpp
index b2e1cfb..5ce0b2d 100644
--- a/src/world.cpp
+++ b/src/world.cpp
@@ -1,158 +1,225 @@
+#include <algorithm>
+#include <sstream>
+
#include <world.h>
#include <ui.h>
-#define getWidth(w) ((w->lineCount-GEN_INC)*HLINE) // Calculates the width of world 'w'
+#include <tinyxml2.h>
+using namespace tinyxml2;
-#define GEN_INIT 60
+/**
+ * Defines how many HLINEs tall a blade of grass can be.
+ */
-#define GRASS_HEIGHT 4 // Defines how long the grass layer of a line should be in multiples of HLINE.
+#define GRASS_HEIGHT 4
+/**
+ * Defines the height of the floor in an IndoorWorld.
+ */
-#define DRAW_Y_OFFSET 50 // Defines how many pixels each layer should be offset from each other on the y axis when drawn.
-#define DRAW_SHADE 30 // Defines a shade increment for draw()
+#define INDOOR_FLOOR_HEIGHT 100
-#define INDOOR_FLOOR_HEIGHT 100 // Defines how high the base floor of an IndoorWorld should be
-bool worldInside = false; // True if player is inside a structure
+extern Player *player; // main.cpp?
+extern World *currentWorld; // main.cpp
+extern int commonAIFunc(NPC *); // entities.cpp
+extern void commonTriggerFunc(Mob *); // entities.cpp
+extern bool inBattle;
+
+extern unsigned int tickCount; // main.cpp
+
+int worldShade = 0;
-WEATHER weather = SUNNY;
+std::string currentXML;
+std::vector<std::string> inside; // tracks indoor worlds
+
+std::vector<World *> battleNest; // tracks arenas
+std::vector<vec2> battleNestLoc; // keeps arena locations
+
+/**
+ * Contains the current weather, used in many other places/files.
+ */
+
+WorldWeather weather = WorldWeather::Sunny;
const std::string bgPaths[2][9]={
- {"bg.png", // Daytime background
- "bgn.png", // Nighttime background
- "bgFarMountain.png", // Furthest layer
- "forestTileFar.png", // Furthest away Tree Layer
- "forestTileBack.png", // Closer layer
- "forestTileMid.png", // Near layer
- "forestTileFront.png", // Closest layer
- "dirt.png", // Dirt
- "grass.png"}, // Grass
- {"bgWoodTile.png",
- "bgWoodTile.png",
- "bgWoodTile.png",
- "bgWoodTile.png",
- "bgWoodTile.png",
- "bgWoodTile.png",
- "bgWoodTile.png",
- "bgWoodTile.png"}
+ {"bg.png", // Daytime background
+ "bgn.png", // Nighttime background
+ "bgFarMountain.png", // Furthest layer
+ "forestTileFar.png", // Furthest away Tree Layer
+ "forestTileBack.png", // Closer layer
+ "forestTileMid.png", // Near layer
+ "forestTileFront.png", // Closest layer
+ "dirt.png", // Dirt
+ "grass.png"}, // Grass
+ {"bgWoodTile.png",
+ "bgWoodTile.png",
+ "bgWoodTile.png",
+ "bgWoodTile.png",
+ "bgWoodTile.png",
+ "bgWoodTile.png",
+ "bgWoodTile.png",
+ "bgWoodTile.png"}
};
-const std::string buildPaths[] = { "townhall.png",
- "house1.png",
- "house2.png",
- "house1.png",
- "house1.png",
- "fountain1.png",
- "lampPost1.png",
- "brazzier.png"};
+const std::string buildPaths[] = {
+ "townhall.png",
+ "house1.png",
+ "house2.png",
+ "house1.png",
+ "house1.png",
+ "fountain1.png",
+ "lampPost1.png",
+ "brazzier.png"
+};
+
+/**
+ * Constants used for layer drawing in World::draw(), releated to transparency.
+ */
const float bgDraw[4][3]={
- {100,240,.6 },
- {150,250,.4 },
- {200,255,.25},
- {255,255,.1}
+ { 100, 240, 0.6 },
+ { 150, 250, 0.4 },
+ { 200, 255, 0.25 },
+ { 255, 255, 0.1 }
};
-float worldGetYBase(World *w){
-// World *tmp = w;
- float base = GEN_MIN;
-/* while(tmp->infront){
- tmp = tmp->infront;
- base -= DRAW_Y_OFFSET;
- }*/
- if(!w)return 0;
- return base;
-}
-
-void World::setBackground(WORLD_BG_TYPE bgt){
- bgType = bgt;
- switch(bgt){
- case BG_FOREST:
- bgTex = new Texturec(bgFiles);
+/**
+ * Sets the desired theme for the world's background.
+ *
+ * The images chosen for the background layers are selected depending on the
+ * world's background type.
+ */
+
+void World::
+setBackground( WorldBGType bgt )
+{
+ // load textures with a limit check
+ switch ( (bgType = bgt) ) {
+ case WorldBGType::Forest:
+ bgTex = new Texturec( bgFiles );
break;
- case BG_WOODHOUSE:
- bgTex = new Texturec(bgFilesIndoors);
+
+ case WorldBGType::WoodHouse:
+ bgTex = new Texturec( bgFilesIndoors );
break;
+
+ default:
+ UserError( "Invalid world background type" );
+ break;
}
}
-void World::setStyle(const char* pre){
- std::string prefix = pre ? pre : "assets/style/classic/";
- for(uint i = 0; i < arrAmt(buildPaths);i++){
- sTexLoc.push_back(prefix);
- sTexLoc.back() += buildPaths[i];
- //std::cout << sTexLoc.back() << std::endl;
- }
+/**
+ * Sets the world's style.
+ *
+ * The world's style will determine what sprites are used for things like\
+ * generic structures.
+ */
+
+void World::
+setStyle( std::string pre )
+{
+ unsigned int i;
+
+ // get folder prefix
+ std::string prefix = pre.empty() ? "assets/style/classic/" : pre;
+
+ for ( i = 0; i < arrAmt(buildPaths); i++ )
+ sTexLoc.push_back( prefix + buildPaths[i] );
+
prefix += "bg/";
- for(uint i = 0; i < arrAmt(bgPaths[0]);i++){
- bgFiles.push_back(prefix);
- bgFiles.back() += bgPaths[0][i];
- //std::cout << bgFiles.back() << std::endl;
- }
- for(uint i = 0; i < arrAmt(bgPaths[1]);i++){
- bgFilesIndoors.push_back(prefix);
- bgFilesIndoors.back() += bgPaths[1][i];
- //std::cout << bgFilesIndoors.back() << std::endl;
- }
+
+ for ( i = 0; i < arrAmt(bgPaths[0]); i++ )
+ bgFiles.push_back( prefix + bgPaths[0][i] );
+
+ for ( i = 0; i < arrAmt(bgPaths[1]); i++ )
+ bgFilesIndoors.push_back( prefix + bgPaths[1][i] );
}
-World::World(void){
-
- bgm = NULL;
- bgmObj = NULL;
-
- toLeft =
- toRight = NULL;
-
- /*
- * Allocate and clear an array for star coordinates.
- */
-
- star = new vec2[100];
- memset(star,0,100 * sizeof(vec2));
+/**
+ * Creates a world object.
+ *
+ * Note that all this does is nullify pointers, to prevent as much disaster as
+ * possible. Functions like setBGM(), setStyle() and generate() should be called
+ * before the World is actually put into use.
+ */
+
+World::
+World( void )
+{
+ bgmObj = NULL;
+
+ toLeft = NULL;
+ toRight = NULL;
}
-void World::deleteEntities(void){
- while(!mob.empty()){
+/**
+ * The entity vector destroyer.
+ *
+ * This function will free all memory used by all entities, and then empty the
+ * vectors they were stored in.
+ */
+
+void World::
+deleteEntities( void )
+{
+ // free mobs
+ while ( !mob.empty() ) {
delete mob.back();
mob.pop_back();
}
+
+ merchant.clear();
while(!npc.empty()){
delete npc.back();
npc.pop_back();
}
- while(!build.empty()){
+
+ // free structures
+ while ( !build.empty() ) {
delete build.back();
build.pop_back();
}
- while(!object.empty()){
+
+ // free objects
+ while ( !object.empty() ) {
delete object.back();
object.pop_back();
}
- while(!entity.empty()){
- entity.pop_back();
- }
- while(!particles.empty()){
- delete particles.back();
- particles.pop_back();
- }
- while(!light.empty()){
- light.pop_back();
+
+ // clear entity array
+ entity.clear();
+
+ // free particles
+ particles.clear();
+
+ // clear light array
+ light.clear();
+
+ // free villages
+ while ( !village.empty() ) {
+ delete village.back();
+ village.pop_back();
}
}
-World::~World(void){
- /*if(behind != NULL)
- delete behind;*/
-
+/**
+ * The world destructor.
+ *
+ * This will free objects used by the world itself, then free the vectors of
+ * entity-related objects.
+ */
+
+World::
+~World( void )
+{
+ // sdl2_mixer's object
if(bgmObj)
Mix_FreeMusic(bgmObj);
- if(bgm)
- delete[] bgm;
+
delete bgTex;
- delete[] star;
- delete[] line;
delete[] toLeft;
delete[] toRight;
@@ -160,634 +227,464 @@ World::~World(void){
deleteEntities();
}
-void World::generate(unsigned int width){ // Generates the world and sets all variables contained in the World class.
- unsigned int i;
- float inc;
-
- /*
- * Calculate the world's real width. The current form of generation fails to generate
- * the last GEN_INC lines, so we offset those making the real real width what was passed
- * to this function.
- *
- * Abort if the width is invalid.
- *
- */
-
- if(width <= 0)
- abort();
+/**
+ * Generates a world of the specified width.
+ *
+ * This will mainly populate the WorldData array, mostly preparing the World
+ * object for usage.
+ */
+
+void World::
+generate( unsigned int width )
+{
+ // iterator for `for` loops
+ std::vector<WorldData>::iterator wditer;
+
+ // see below for description
+ float geninc = 0;
+
+ // check for valid width
+ if ( (int)width <= 0 )
+ UserError("Invalid world dimensions");
+
+ // allocate space for world
+ worldData = std::vector<WorldData> (width + GROUND_HILLINESS, WorldData { false, {0,0}, 0, 0 });
+ lineCount = worldData.size();
+
+ // prepare for generation
+ worldData.front().groundHeight = GROUND_HEIGHT_INITIAL;
+ wditer = worldData.begin();
+
+ // give every GROUND_HILLINESSth entry a groundHeight value
+ for(unsigned int i = GROUND_HILLINESS; i < worldData.size(); i += GROUND_HILLINESS, wditer += GROUND_HILLINESS)
+ worldData[i].groundHeight = (*wditer).groundHeight + (randGet() % 8 - 4);
+
+ // create slopes from the points that were just defined, populate the rest of the WorldData structure
+
+ for(wditer = worldData.begin(); wditer != worldData.end(); wditer++){
+ if ((*wditer).groundHeight)
+ // wditer + GROUND_HILLINESS can go out of bounds (invalid read)
+ geninc = ( (*(wditer + GROUND_HILLINESS)).groundHeight - (*wditer).groundHeight ) / (float)GROUND_HILLINESS;
+ else
+ (*wditer).groundHeight = (*(wditer - 1)).groundHeight + geninc;
+
+ (*wditer).groundColor = randGet() % 32 / 8;
+ (*wditer).grassUnpressed = true;
+ (*wditer).grassHeight[0] = (randGet() % 16) / 3 + 2;
+ (*wditer).grassHeight[1] = (randGet() % 16) / 3 + 2;
+
+ // bound checks
+ if ( (*wditer).groundHeight < GROUND_HEIGHT_MINIMUM )
+ (*wditer).groundHeight = GROUND_HEIGHT_MINIMUM;
+ else if ( (*wditer).groundHeight > GROUND_HEIGHT_MAXIMUM )
+ (*wditer).groundHeight = GROUND_HEIGHT_MAXIMUM;
- lineCount = (width + GEN_INC) / HLINE;
-
- /*
- * Allocate enough memory for the world to be stored.
- */
-
- line = new struct line_t[lineCount];
- memset(line,0,lineCount * sizeof(struct line_t));
-
- /*
- * Set an initial y to base generation off of, as generation references previous lines.
- */
-
- line[0].y = GEN_INIT;
-
- /*
- * Populate every GEN_INCth line structure. The remaining lines will be based off of these.
- */
-
- for(i = GEN_INC;i < lineCount;i += GEN_INC){
-
- /*
- * Generate a y value, ensuring it stays within a reasonable range.
- */
-
- line[i].y = rand() % 8 - 4 + line[i - GEN_INC].y; // Add +/- 4 to the previous line
-
- if(line[i].y < GEN_MIN)line[i].y = GEN_MIN; // Minimum bound
- else if(line[i].y > GEN_MAX)line[i].y = GEN_MAX; // Maximum bound
-
- }
-
- /*
- * Generate values for the remaining lines here.
- */
-
- for(i = 0;i < lineCount - GEN_INC;i++){
-
- /*
- * Every GEN_INCth line calculate the slope between the current line and the one
- * GEN_INC lines before it. This value is then divided into an increment that is
- * added to lines between these two points resulting in a smooth slope.
- *
- */
-
- if(!(i % GEN_INC))
-
- inc = (line[i + GEN_INC].y - line[i].y) / (float)GEN_INC;
-
- /*
- * Add the increment to create the smooth slope.
- */
-
- else line[i].y = line[i - 1].y + inc;
-
- /*
- * Generate a color value for the line. This will be referenced in World->draw(),
- * by setting an RGB value of color (red), color - 50 (green), color - 100 (blue).
- */
-
- line[i].color = rand() % 32 / 8; // 100 to 120
+ if( (*wditer).groundHeight <= 0 )
+ (*wditer).groundHeight = GROUND_HEIGHT_MINIMUM;
- /*
- * Each line has two 'blades' of grass, here we generate random heights for them.
- */
-
- line[i].gh[0] = (getRand() % 16) / 3.5 + 2; // Not sure what the range resolves to here...
- line[i].gh[1] = (getRand() % 16) / 3.5 + 2; //
-
- line[i].gs = true; // Show the blades of grass (modified by the player)
-
- }
-
- /*
- * Calculate the x coordinate to start drawing this world from so that it is centered at (0,0).
- */
-
- x_start = 0 - getWidth(this) / 2;
+ }
+
+ // define x-coordinate of world's leftmost 'line'
+ worldStart = (width - GROUND_HILLINESS) * HLINE / 2 * -1;
- /*
- * Assign coordinates for the stars, seen at nighttime.
- */
-
- for(i = 0;i < 100;i++){
- star[i].x = getRand() % getTheWidth() - getTheWidth() / 2;
- star[i].y = getRand() % SCREEN_HEIGHT + 100;
+ // create empty star array, should be filled here as well...
+ star = std::vector<vec2> (100, vec2 { 0, 400 } );
+ for ( auto &s : star ) {
+ s.x = (getRand() % (-worldStart * 2)) + worldStart;
+ s.y = (getRand() % SCREEN_HEIGHT) + 100.0f;
}
}
-void World::generateFunc(unsigned int width,float(*func)(float)){
- unsigned int i;
-
- /*
- * Check for a valid width.
- */
-
- if((lineCount = width) <= 0)
- abort();
-
- /*
- * Allocate memory for the line array.
- */
-
- line = new struct line_t[lineCount];
- memset(line,0,lineCount*sizeof(struct line_t));
-
- /*
- * Populate entries in the line array, using `func` to get y values.
- */
-
- for(i = 0;i < lineCount;i++){
- line[i].y = func(i);
-
- if(line[i].y < 0)line[i].y = 0; // Minimum bound
- if(line[i].y > 2000)line[i].y = 2000; // Maximum bound
-
- line[i].color = rand() % 20 + 100;
-
- line[i].gh[0] = (getRand() % 16) / 3.5 + 2;
- line[i].gh[1] = (getRand() % 16) / 3.5 + 2;
-
- line[i].gs = true;
- }
-
- x_start = 0 - getWidth(this) / 2;
-
- for(i = 0;i < 100;i++){
- star[i].x = getRand() % getTheWidth() - getTheWidth() / 2;
- star[i].y = getRand() % SCREEN_HEIGHT + 100;
- }
-}
+/**
+ * Updates all entity and player coordinates with their velocities.
+ *
+ * Also handles music fading, although that could probably be placed elsewhere.
+ */
-void World::update(Player *p,unsigned int delta){
-
- /*
- * Update the player's coordinates.
- */
-
+void World::
+update( Player *p, unsigned int delta )
+{
+ // update player coords
p->loc.y += p->vel.y * delta;
p->loc.x +=(p->vel.x * p->speed) * delta;
- /*
- * Update coordinates of all entities except for structures.
- */
-
- for(auto &e : entity){
+ // update entity coords
+ for ( auto &e : entity ) {
e->loc.y += e->vel.y * delta;
- if(e->type != STRUCTURET && e->canMove){
+ // dont let structures move?
+ if ( e->type != STRUCTURET && e->canMove ) {
e->loc.x += e->vel.x * delta;
- if(e->vel.x < 0)e->left = true;
- else if(e->vel.x > 0)e->left = false;
+ // update boolean directions
+ if ( e->vel.x < 0 )
+ e->left = true;
+ else if ( e->vel.x > 0 )
+ e->left = false;
}
}
+ // iterate through particles
+ particles.erase( std::remove_if( particles.begin(), particles.end(), [&delta](Particles &part){return part.kill(delta);}), particles.end());
+ for ( auto part = particles.begin(); part != particles.end(); part++ ) {
+ if ( (*part).canMove ) {
+ (*part).loc.y += (*part).vely * delta;
+ (*part).loc.x += (*part).velx * delta;
+
+ for ( auto &b : build ) {
+ if ( b->bsubtype == FOUNTAIN ) {
+ if ( (*part).loc.x >= b->loc.x && (*part).loc.x <= b->loc.x + b->width ) {
+ if ( (*part).loc.y <= b->loc.y + b->height * .25)
+ particles.erase( part );
- for(unsigned int i=0;i<particles.size();i++){
- if(particles[i]->kill(delta)){
- delete particles[i];
- particles.erase(particles.begin()+i);
- }else if(particles[i]->canMove){
- particles[i]->loc.y += particles[i]->vely * delta;
- particles[i]->loc.x += particles[i]->velx * delta;
-
- for(auto &b : build){
- if(b->bsubtype==FOUNTAIN){
- if(particles[i]->loc.x >= b->loc.x && particles[i]->loc.x <= b->loc.x + b->width){
- if(particles[i]->loc.y <= b->loc.y + b->height * .25){
- delete particles[i];
- particles.erase(particles.begin()+i);
- }
}
}
}
}
}
- if(ui::dialogImportant){
+ // handle music fades
+ if ( ui::dialogImportant )
Mix_FadeOutMusic(2000);
- }else if(!Mix_PlayingMusic()){
+ else if( !Mix_PlayingMusic() )
Mix_FadeInMusic(bgmObj,-1,2000);
- }
}
-void World::setBGM(std::string path){
- bgm = new char[path.size() + 1];
- strcpy(bgm,path.c_str());
- bgmObj = Mix_LoadMUS(bgm);
+/**
+ * Set the world's BGM.
+ *
+ * This will load a sound file to be played while the player is in this world.
+ * If no file is found, no music should play.
+ */
+
+void World::
+setBGM( std::string path )
+{
+ if( !path.empty() )
+ bgmObj = Mix_LoadMUS( (bgm = path).c_str() );
}
-void World::bgmPlay(World *prev){
- if(prev){
- if(bgm != prev->bgm){
- Mix_FadeOutMusic(800);
- //Mix_VolumeMusic(50);
- Mix_PlayMusic(bgmObj,-1); // Loop infinitely
+/**
+ * Toggle play/stop of the background music.
+ *
+ * If new music is to be played a crossfade will occur, otherwise... uhm.
+ */
+
+void World::
+bgmPlay( World *prev ) const
+{
+ if ( prev ) {
+ if ( bgm != prev->bgm ) {
+ // new world, new music
+ Mix_FadeOutMusic( 800 );
+ Mix_PlayMusic( bgmObj, -1 );
}
- }else{
- Mix_FadeOutMusic(800);
- //Mix_VolumeMusic(50);
- Mix_PlayMusic(bgmObj,-1); // Loop infinitely
+ } else {
+ // first call
+ Mix_FadeOutMusic( 800 );
+ Mix_PlayMusic( bgmObj, -1 );
}
}
-int worldShade = 0;
-
-extern vec2 offset;
-extern unsigned int tickCount;
-
-void World::draw(Player *p){
- static float yoff=DRAW_Y_OFFSET; // Initialize stuff
- static int shade,bgshade;
- static World *current=this;
- unsigned int i;
- int is,ie,v_offset,cx_start,width;
- struct line_t *cline;
- float base;
-
- bgshade = worldShade << 1; // *2
- base = worldGetYBase(this);
+/**
+ * The world draw function.
+ *
+ * This function will draw the background layers, entities, and player to the
+ * screen.
+ */
+
+void World::
+draw( Player *p )
+{
+ // iterators
+ int i, iStart, iEnd;
+
+ // shade value for draws -- may be unnecessary
+ int shadeBackground = -worldShade;
+
+ // player's offset in worldData[]
+ int pOffset;
+
+ // world width in pixels
+ int width = worldData.size() * HLINE;
+
+ // shade value for GLSL
+ float shadeAmbient = -worldShade / 50.0f + 0.5f; // -0.5f to 1.5f
+ if ( shadeAmbient < 0 )
+ shadeAmbient = 0;
+ else if ( shadeAmbient > 0.9f )
+ shadeAmbient = 1;
/*
- * Draw the background images in the appropriate order.
- */
+ * Draw background images.
+ */
-//LLLOOP:
- /*if(current->infront){
- current=current->infront;
- goto LLLOOP;
- }*/
+ glEnable( GL_TEXTURE_2D );
- if(current->x_start < SCREEN_WIDTH * -.5 )
- cx_start = current->x_start * 1.5;
- else
- cx_start = (int)(SCREEN_WIDTH * -.5);
-
- width = (-cx_start) << 1;
+ // the sunny wallpaper is faded with the night depending on tickCount
- glEnable(GL_TEXTURE_2D);
-
- bgTex->bind(0);
- safeSetColorA(255,255,255,255 - worldShade * 4);
- glBegin(GL_QUADS);
- glTexCoord2i(0,0);glVertex2i( cx_start,SCREEN_HEIGHT);
- glTexCoord2i(1,0);glVertex2i(-cx_start,SCREEN_HEIGHT);
- glTexCoord2i(1,1);glVertex2i(-cx_start,0);
- glTexCoord2i(0,1);glVertex2i( cx_start,0);
+ bgTex->bind( 0 );
+ safeSetColorA( 255, 255, 255, 255 - worldShade * 4 );
+
+ glBegin( GL_QUADS );
+ glTexCoord2i( 0, 0 ); glVertex2i( worldStart, SCREEN_HEIGHT );
+ glTexCoord2i( 1, 0 ); glVertex2i( -worldStart, SCREEN_HEIGHT );
+ glTexCoord2i( 1, 1 ); glVertex2i( -worldStart, 0 );
+ glTexCoord2i( 0, 1 ); glVertex2i( worldStart, 0 );
glEnd();
bgTex->bindNext();
- safeSetColorA(255,255,255,worldShade * 4);
- glBegin(GL_QUADS);
- glTexCoord2i(0,0);glVertex2i( cx_start,SCREEN_HEIGHT);
- glTexCoord2i(1,0);glVertex2i(-cx_start,SCREEN_HEIGHT);
- glTexCoord2i(1,1);glVertex2i(-cx_start,0);
- glTexCoord2i(0,1);glVertex2i( cx_start,0);
+ safeSetColorA( 255, 255, 255, worldShade * 4 );
+
+ glBegin( GL_QUADS );
+ glTexCoord2i( 0, 0 ); glVertex2i( worldStart, SCREEN_HEIGHT );
+ glTexCoord2i( 1, 0 ); glVertex2i( -worldStart, SCREEN_HEIGHT );
+ glTexCoord2i( 1, 1 ); glVertex2i( -worldStart, 0 );
+ glTexCoord2i( 0, 1 ); glVertex2i( worldStart, 0 );
glEnd();
- glDisable(GL_TEXTURE_2D);
-
- /*
- * Draws stars if it is an appropriate time of day for them.
- */
+
+ glDisable( GL_TEXTURE_2D );
+
+ // draw the stars if the time deems it appropriate
+
+ //if (((( weather == WorldWeather::Dark ) & ( tickCount % DAY_CYCLE )) < DAY_CYCLE / 2) ||
+ // ((( weather == WorldWeather::Sunny ) & ( tickCount % DAY_CYCLE )) > DAY_CYCLE * .75) ){
+ if ( worldShade > 0 ) {
- if((((weather==DARK )&(tickCount%DAY_CYCLE))<DAY_CYCLE/2) ||
- (((weather==SUNNY)&(tickCount%DAY_CYCLE))>DAY_CYCLE*.75) ){
-
- if(tickCount % DAY_CYCLE){ // The above if statement doesn't check for exact midnight.
-
- safeSetColorA(255,255,255,bgshade + getRand() % 30 - 15);
- for(i = 0; i < 100; i++){
- glRectf(star[i].x+offset.x*.9,
- star[i].y,
- star[i].x+offset.x*.9+HLINE,
- star[i].y+HLINE
- );
- }
-
+ safeSetColorA( 255, 255, 255, 255 - (getRand() % 30 - 15) );
+
+ for ( i = 0; i < 100; i++ ) {
+ glRectf(star[i].x + offset.x * .9,
+ star[i].y,
+ star[i].x + offset.x * .9 + HLINE,
+ star[i].y + HLINE
+ );
}
- }
-
+ }
- glEnable(GL_TEXTURE_2D);
-
- /*
- * Draw the mountains.
- */
- bgTex->bindNext();
- safeSetColorA(150-bgshade,150-bgshade,150-bgshade,220);
+ // draw remaining background items
- glBegin(GL_QUADS);
- for(int i = 0; i <= width/1920; i++){
- glTexCoord2i(0,1);glVertex2i(width/-2+(1920*i )+offset.x*.85,base);
- glTexCoord2i(1,1);glVertex2i(width/-2+(1920*(i+1))+offset.x*.85,base);
- glTexCoord2i(1,0);glVertex2i(width/-2+(1920*(i+1))+offset.x*.85,base+1080);
- glTexCoord2i(0,0);glVertex2i(width/-2+(1920*i )+offset.x*.85,base+1080);
+ glEnable( GL_TEXTURE_2D );
+
+ bgTex->bindNext();
+ safeSetColorA( 150 + shadeBackground * 2, 150 + shadeBackground * 2, 150 + shadeBackground * 2, 255 );
+
+ glBegin( GL_QUADS );
+ for ( i = 0; i <= (int)(worldData.size() * HLINE / 1920); i++ ) {
+ glTexCoord2i( 0, 1 ); glVertex2i( width / 2 * -1 + (1920 * i ) + offset.x * .85, GROUND_HEIGHT_MINIMUM );
+ glTexCoord2i( 1, 1 ); glVertex2i( width / 2 * -1 + (1920 * (i + 1)) + offset.x * .85, GROUND_HEIGHT_MINIMUM );
+ glTexCoord2i( 1, 0 ); glVertex2i( width / 2 * -1 + (1920 * (i + 1)) + offset.x * .85, GROUND_HEIGHT_MINIMUM + 1080 );
+ glTexCoord2i( 0, 0 ); glVertex2i( width / 2 * -1 + (1920 * i ) + offset.x * .85, GROUND_HEIGHT_MINIMUM + 1080 );
}
glEnd();
- /*
- * Draw four layers of trees.
- */
-
- for(i = 0; i < 4; i++){
+ for ( i = 0; i < 4; i++ ) {
bgTex->bindNext();
- safeSetColorA(bgDraw[i][0]-bgshade,bgDraw[i][0]-bgshade,bgDraw[i][0]-bgshade,bgDraw[i][1]);
-
- glBegin(GL_QUADS);
- for(int j = cx_start; j <= -cx_start; j += 600){
- glTexCoord2i(0,1);glVertex2i( j +offset.x*bgDraw[i][2],base);
- glTexCoord2i(1,1);glVertex2i((j+600)+offset.x*bgDraw[i][2],base);
- glTexCoord2i(1,0);glVertex2i((j+600)+offset.x*bgDraw[i][2],base+400);
- glTexCoord2i(0,0);glVertex2i( j +offset.x*bgDraw[i][2],base+400);
+ safeSetColorA( bgDraw[i][0] + shadeBackground * 2, bgDraw[i][0] + shadeBackground * 2, bgDraw[i][0] + shadeBackground * 2, bgDraw[i][1] );
+
+ glBegin( GL_QUADS );
+ for( int j = worldStart; j <= -worldStart; j += 600 ){
+ glTexCoord2i( 0, 1 ); glVertex2i( j + offset.x * bgDraw[i][2], GROUND_HEIGHT_MINIMUM );
+ glTexCoord2i( 1, 1 ); glVertex2i( (j + 600) + offset.x * bgDraw[i][2], GROUND_HEIGHT_MINIMUM );
+ glTexCoord2i( 1, 0 ); glVertex2i( (j + 600) + offset.x * bgDraw[i][2], GROUND_HEIGHT_MINIMUM + 400 );
+ glTexCoord2i( 0, 0 ); glVertex2i( j + offset.x * bgDraw[i][2], GROUND_HEIGHT_MINIMUM + 400 );
}
glEnd();
}
- glDisable(GL_TEXTURE_2D);
+ glDisable( GL_TEXTURE_2D );
- glColor3ub(0,0,0);
- glRectf(cx_start,GEN_MIN,-cx_start,0);
+ // draw black under backgrounds
- /*
- * World drawing is done recursively, meaning that this function jumps
- * back as many 'layers' as it can and then draws, eventually coming
- * back to the initial or 'root' layer. LOOP1 does the recursion back
- * to the furthest behind layer, modifying shade and y offsets as it
- * does.
- *
- */
+ glColor3ub( 0, 0, 0 );
+ glRectf( worldStart, GROUND_HEIGHT_MINIMUM, -worldStart, 0 );
- current=this;
- shade=worldShade;
+ pOffset = (offset.x + p->width / 2 - worldStart) / HLINE;
-//LOOP1:
+ /*
+ * Prepare for world ground drawing.
+ */
+
+ // only draw world within player vision
+
+ if ((iStart = pOffset - (SCREEN_WIDTH / 2 / HLINE) - GROUND_HILLINESS) < 0)
+ iStart = 0;
- //if(current->behind){
-
- /*
- * Add to the y offset and shade values (explained further below)
- * and recurse.
- *
- */
-
- /*yoff+=DRAW_Y_OFFSET;
- shade+=DRAW_SHADE;
- current=current->behind;
- goto LOOP1;
- }*/
-
- /*
- * Here is where the actual world drawing begins. A goto is made to
- * LOOP2 once the current layer is drawn and the function shifts to
- * draw the next closest layer.
- */
-
-//LOOP2:
+ if ((iEnd = pOffset + (SCREEN_WIDTH / 2 / HLINE) + GROUND_HILLINESS + HLINE) > (int)worldData.size())
+ iEnd = worldData.size();
+ else if (iEnd < GROUND_HILLINESS)
+ iEnd = GROUND_HILLINESS;
- /*
- * Calculate the offset in the line array that the player is (or would)
- * currently be on. This function then calculates reasonable values for
- * the 'for' loop below that draws the layer.
- */
+ // draw particles and buildings
- v_offset=(offset.x + p->width / 2 - current->x_start) / HLINE;
-
- // is -> i start
+ std::for_each( particles.begin(), particles.end(), [](Particles part) { if ( part.behind ) part.draw(); });
- is=v_offset - (SCREEN_WIDTH / 2 / HLINE) - GEN_INC;
- if(is<0)is=0; // Minimum bound
+ for ( auto &b : build )
+ b->draw();
+
+ // draw light elements?
- // ie -> i end
+ glEnable( GL_TEXTURE_2D );
+
+ glActiveTexture( GL_TEXTURE0 );
+ bgTex->bindNext();
- ie=v_offset + (SCREEN_WIDTH / 2 / HLINE) + GEN_INC + HLINE;
- if(ie>(int)current->lineCount)ie=current->lineCount; // Maximum bound
- else if(ie < GEN_INC)ie = GEN_INC;
+ std::unique_ptr<GLfloat[]> pointArrayBuf = std::make_unique<GLfloat[]> (2 * (light.size() + p->light));
+ auto pointArray = pointArrayBuf.get();
- /*
- * Make more direct variables for quicker referencing.
- */
+ for ( i = 0; i < (int)light.size(); i++ ) {
+ pointArray[2 * i ] = light[i].loc.x - offset.x;
+ pointArray[2 * i + 1] = light[i].loc.y;
+ }
- cline =current->line;
- cx_start=current->x_start;
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
- /*
- * Invert shading if desired.
- */
+ glUseProgram( shaderProgram );
+ glUniform1i( glGetUniformLocation( shaderProgram, "sampler"), 0 );
+ glUniform1f( glGetUniformLocation( shaderProgram, "amb" ), shadeAmbient );
- shade*=-1;
+ if ( p->light ) {
+ pointArray[2 * (light.size() + 1) ] = (float)( p->loc.x + SCREEN_WIDTH / 2 );
+ pointArray[2 * (light.size() + 1) + 1] = (float)( p->loc.y );
+ }
- /*
- * Draw structures. We draw structures behind the dirt/grass so that the building's
- * corners don't stick out.
- */
-
- for(auto &part : particles){
- if(part->behind)
- part->draw();
+ if ( light.size() + (int)p->light == 0)
+ glUniform1i( glGetUniformLocation( shaderProgram, "numLight"), 0);
+ else {
+ glUniform1i ( glGetUniformLocation( shaderProgram, "numLight" ), light.size() + (int)p->light );
+ glUniform2fv( glGetUniformLocation( shaderProgram, "lightLocation"), light.size() + (int)p->light, pointArray );
+ glUniform3f ( glGetUniformLocation( shaderProgram, "lightColor" ), 1.0f, 1.0f, 1.0f );
}
- for(auto &b : current->build){
- b->draw();
- }
- /*
- * Draw the layer up until the grass portion, which is done later.
- */
-
- bool hey=false;
- glEnable(GL_TEXTURE_2D);
- glActiveTexture(GL_TEXTURE0);
- bgTex->bindNext();
+
+ /*
+ * Draw the dirt.
+ */
+
+ glBegin( GL_QUADS );
+
+ // faulty
+ /*glTexCoord2i(0 ,0);glVertex2i(pOffset - (SCREEN_WIDTH / 1.5),0);
+ glTexCoord2i(64,0);glVertex2i(pOffset + (SCREEN_WIDTH / 1.5),0);
+ glTexCoord2i(64,1);glVertex2i(pOffset + (SCREEN_WIDTH / 1.5),GROUND_HEIGHT_MINIMUM);
+ glTexCoord2i(0 ,1);glVertex2i(pOffset - (SCREEN_WIDTH / 1.5),GROUND_HEIGHT_MINIMUM);*/
- GLfloat pointArray[light.size() + (int)p->light][2];
- for(uint w = 0; w < light.size(); w++){
- pointArray[w][0] = light[w].loc.x - offset.x;
- pointArray[w][1] = light[w].loc.y;
- }
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); //for the s direction
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); //for the t direction
- glUseProgram(shaderProgram);
- glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0);
- glUniform1f(glGetUniformLocation(shaderProgram, "amb"), float(shade+50.0f)/100.0f);
- if(p->light){
- //glUniform1i(glGetUniformLocation(shaderProgram, "numLight"), 1);
- //glUniform2f(glGetUniformLocation(shaderProgram, "lightLocation"), p->loc.x - offset.x+SCREEN_WIDTH/2, p->loc.y);
- //glUniform3f(glGetUniformLocation(shaderProgram, "lightColor"), 1.0f,1.0f,1.0f);
- pointArray[light.size()+1][0] = (float)(p->loc.x + SCREEN_WIDTH/2);
- pointArray[light.size()+1][1] = (float)(p->loc.y);
- }
- if(light.size()+(int)p->light == 0){
- glUniform1i(glGetUniformLocation(shaderProgram, "numLight"), 0);
- }else{
- glUniform1i (glGetUniformLocation(shaderProgram, "numLight"), light.size()+(int)p->light);
- glUniform2fv(glGetUniformLocation(shaderProgram, "lightLocation"), light.size()+(int)p->light, (GLfloat *)&pointArray);
- glUniform3f (glGetUniformLocation(shaderProgram, "lightColor"), 1.0f,1.0f,1.0f);
- }
+ for ( i = iStart; i < iEnd; i++ ) {
+ if ( worldData[i].groundHeight <= 0 ) {
+ worldData[i].groundHeight = GROUND_HEIGHT_MINIMUM - 1;
+ glColor4ub( 0, 0, 0, 255 );
+ } else
+ safeSetColorA( 150, 150, 150, 255 );
- glBegin(GL_QUADS);
+ glTexCoord2i( 0, 0 ); glVertex2i(worldStart + i * HLINE , worldData[i].groundHeight - GRASS_HEIGHT );
+ glTexCoord2i( 1, 0 ); glVertex2i(worldStart + i * HLINE + HLINE , worldData[i].groundHeight - GRASS_HEIGHT );
+
+ glTexCoord2i( 1, (int)(worldData[i].groundHeight / 64) + worldData[i].groundColor ); glVertex2i(worldStart + i * HLINE + HLINE, 0 );
+ glTexCoord2i( 0, (int)(worldData[i].groundHeight / 64) + worldData[i].groundColor ); glVertex2i(worldStart + i * HLINE , 0 );
+
+ if ( worldData[i].groundHeight == GROUND_HEIGHT_MINIMUM - 1 )
+ worldData[i].groundHeight = 0;
+ }
- glTexCoord2i(0 ,0);glVertex2i(v_offset - (SCREEN_WIDTH / 1.5),0);
- glTexCoord2i(64,0);glVertex2i(v_offset + (SCREEN_WIDTH / 1.5),0);
- glTexCoord2i(64,1);glVertex2i(v_offset + (SCREEN_WIDTH / 1.5),base);
- glTexCoord2i(0 ,1);glVertex2i(v_offset - (SCREEN_WIDTH / 1.5),base);
-
- for(i=is;i<(unsigned)ie-GEN_INC;i++){
- cline[i].y+=(yoff-DRAW_Y_OFFSET); // Add the y offset
- if(!cline[i].y){
- cline[i].y=base;
- hey=true;
- glColor4ub(0,0,0,255);
- }else safeSetColorA(150+shade*2,150+shade*2,150+shade*2,255);
- glTexCoord2i(0,0); glVertex2i(cx_start+i*HLINE ,cline[i].y-GRASS_HEIGHT);
- glTexCoord2i(1,0); glVertex2i(cx_start+i*HLINE+HLINE,cline[i].y-GRASS_HEIGHT);
- glTexCoord2i(1,(int)(cline[i].y/64)+cline[i].color);glVertex2i(cx_start+i*HLINE+HLINE,0);
- glTexCoord2i(0,(int)(cline[i].y/64)+cline[i].color);glVertex2i(cx_start+i*HLINE ,0);
- cline[i].y-=(yoff-DRAW_Y_OFFSET); // Restore the line's y value
- if(hey){
- hey=false;
- cline[i].y=0;
- }
- }
glEnd();
+
glUseProgram(0);
glDisable(GL_TEXTURE_2D);
- /*
- * Draw grass on every line.
- */
- float cgh[2];
+ /*
+ * Draw the grass/the top of the ground.
+ */
- glEnable(GL_TEXTURE_2D);
- glActiveTexture(GL_TEXTURE0);
+ glEnable( GL_TEXTURE_2D );
+
+ glActiveTexture( GL_TEXTURE0 );
bgTex->bindNext();
- glUseProgram(shaderProgram);
- glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0);
- //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); //for the s direction
- //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); //for the t direction
- //glBegin(GL_QUADS);
+
+ glUseProgram( shaderProgram );
+ glUniform1i( glGetUniformLocation( shaderProgram, "sampler"), 0);
- for(i=is;i<(unsigned)ie-GEN_INC;i++){
-
- /*
- * Load the current line's grass values
- */
-
- if(cline[i].y)memcpy(cgh,cline[i].gh,2*sizeof(float));
- else memset(cgh,0 ,2*sizeof(float));
-
-
-
- /*
- * Flatten the grass if the player is standing on it.
- */
+ float cgh[2];
+ for ( i = iStart; i < iEnd - GROUND_HILLINESS; i++ ) {
- if(!cline[i].gs){
- cgh[0]/=4;
- cgh[1]/=4;
+ // load the current line's grass values
+ if ( worldData[i].groundHeight )
+ memcpy( cgh, worldData[i].grassHeight, 2 * sizeof( float ));
+ else
+ memset( cgh, 0 , 2 * sizeof( float ));
+
+ // flatten the grass if the player is standing on it.
+ if( !worldData[i].grassUnpressed ){
+ cgh[0] /= 4;
+ cgh[1] /= 4;
}
- /*
- * Actually draw the grass.
- */
+ // actually draw the grass.
- cline[i].y+=(yoff-DRAW_Y_OFFSET);
- safeSetColorA(255,255,255,255);
- glBegin(GL_QUADS);
- glTexCoord2i(0,0);glVertex2i(cx_start+i*HLINE ,cline[i].y+cgh[0]);
- glTexCoord2i(1,0);glVertex2i(cx_start+i*HLINE+HLINE/2,cline[i].y+cgh[0]);
- glTexCoord2i(1,1);glVertex2i(cx_start+i*HLINE+HLINE/2,cline[i].y-GRASS_HEIGHT);
- glTexCoord2i(0,1);glVertex2i(cx_start+i*HLINE ,cline[i].y-GRASS_HEIGHT);
- glEnd();
-
- glBegin(GL_QUADS);
- glTexCoord2i(0,0);glVertex2i(cx_start+i*HLINE+HLINE/2,cline[i].y+cgh[1]);
- glTexCoord2i(1,0);glVertex2i(cx_start+i*HLINE+HLINE ,cline[i].y+cgh[1]);
- glTexCoord2i(1,1);glVertex2i(cx_start+i*HLINE+HLINE ,cline[i].y-GRASS_HEIGHT);
- glTexCoord2i(0,1);glVertex2i(cx_start+i*HLINE+HLINE/2,cline[i].y-GRASS_HEIGHT);
+ safeSetColorA( 255, 255, 255, 255 );
+
+ glBegin( GL_QUADS );
+ glTexCoord2i( 0, 0 ); glVertex2i( worldStart + i * HLINE , worldData[i].groundHeight + cgh[0] );
+ glTexCoord2i( 1, 0 ); glVertex2i( worldStart + i * HLINE + HLINE / 2, worldData[i].groundHeight + cgh[0] );
+ glTexCoord2i( 1, 1 ); glVertex2i( worldStart + i * HLINE + HLINE / 2, worldData[i].groundHeight - GRASS_HEIGHT );
+ glTexCoord2i( 0, 1 ); glVertex2i( worldStart + i * HLINE , worldData[i].groundHeight - GRASS_HEIGHT );
+ glTexCoord2i( 0, 0 ); glVertex2i( worldStart + i * HLINE + HLINE / 2, worldData[i].groundHeight + cgh[1] );
+ glTexCoord2i( 1, 0 ); glVertex2i( worldStart + i * HLINE + HLINE , worldData[i].groundHeight + cgh[1] );
+ glTexCoord2i( 1, 1 ); glVertex2i( worldStart + i * HLINE + HLINE , worldData[i].groundHeight - GRASS_HEIGHT );
+ glTexCoord2i( 0, 1 ); glVertex2i( worldStart + i * HLINE + HLINE / 2, worldData[i].groundHeight - GRASS_HEIGHT );
glEnd();
-
- cline[i].y-=(yoff-DRAW_Y_OFFSET);
}
- //glEnd();
+
glUseProgram(0);
glDisable(GL_TEXTURE_2D);
/*
- * Draw non-structure entities.
- */
- for(auto &part : particles){if(!part->behind)part->draw();}
- for(auto &n : current->npc){
- n->loc.y+=(yoff-DRAW_Y_OFFSET);
+ * Draw remaining entities.
+ */
+
+ std::for_each( particles.begin(), particles.end(), [](Particles part) { if ( !part.behind ) part.draw(); });
+
+ for ( auto &n : npc )
n->draw();
- n->loc.y-=(yoff-DRAW_Y_OFFSET);
- }
- for(auto &m : current->mob){
- m->loc.y+=(yoff-DRAW_Y_OFFSET);
+
+ for ( auto &m : mob )
m->draw();
- m->loc.y-=(yoff-DRAW_Y_OFFSET);
- }
- for(auto &o : current->object){
- if(o->alive){
- o->loc.y+=(yoff-DRAW_Y_OFFSET);
- o->draw();
- o->loc.y-=(yoff-DRAW_Y_OFFSET);
- }
- }
-
- /*
- * If we're drawing the closest/last world, handle and draw the player.
- */
+
+ for ( auto &o : object )
+ o->draw();
- if(current==this){
-
- /*
- * Calculate the line that the player is on
- */
-
- unsigned int ph = (p->loc.x + p->width / 2 - x_start) / HLINE;
-
- /*
- * If the player is on the ground, flatten the grass where the player is standing
- * by setting line.gs to false.
- */
-
- if(p->ground==1){
- for(i=0;i<lineCount-GEN_INC;i++){
- if(i < ph + 6 &&
- i > ph - 6 )
- cline[i].gs=false;
- else cline[i].gs=true;
- }
- }else{
- for(i=0;i<lineCount-GEN_INC;i++){
- cline[i].gs=true;
- }
- }
-
- /*
- * Draw the player.
- */
-
- p->draw();
-
+ /*
+ * Handle grass-squishing.
+ */
+
+ // calculate the line that the player is on
+ int ph = ( p->loc.x + p->width / 2 - worldStart ) / HLINE;
+
+ // flatten grass under the player if the player is on the ground
+ if ( p->ground ) {
+ for ( i = 0; i < (int)(worldData.size() - GROUND_HILLINESS); i++ )
+ worldData[i].grassUnpressed = !( i < ph + 6 && i > ph - 6 );
+ } else {
+ for ( i = 0; i < (int)(worldData.size() - GROUND_HILLINESS); i++ )
+ worldData[i].grassUnpressed = true;
}
-
- /*
- * Restore the inverted shading if it was inverted above.
- */
-
- shade*=-1;
-
+
/*
- * Draw the next closest world if it exists.
- */
-
- /*if(current->infront){
- yoff -= DRAW_Y_OFFSET;
- shade -= DRAW_SHADE;
-
- current=current->infront;
- goto LOOP2;
-
- }else{*/
-
- /*
- * If finished, reset the yoff and shade variables for the next call.
- */
-
- yoff=DRAW_Y_OFFSET;
- shade=0;
- //}
+ * Draw the player.
+ */
+
+ p->draw();
}
-void World::singleDetect(Entity *e){
+/**
+ * Handles physics and such for a single entity.
+ *
+ * This function is kept private, as World::detect() should be used instead to
+ * handle stuffs for all entities at once.
+ */
+
+void World::
+singleDetect( Entity *e )
+{
+ std::string killed;
unsigned int i,j;
int l;
@@ -795,12 +692,12 @@ void World::singleDetect(Entity *e){
* Kill any dead entities.
*/
- if(!e->alive||e->health<=0){
- for(i=0;i<entity.size();i++){
- if(entity[i]==e){
- switch(e->type){
+ if ( !e->alive || e->health <= 0 ) {
+ for ( i = 0; i < entity.size(); i++) {
+ if ( entity[i] == e ){
+ switch ( e->type ) {
case STRUCTURET:
- std::cout<<"Killed a building..."<<std::endl;
+ killed = "structure";
for(j=0;j<build.size();j++){
if(build[j]==e){
delete build[j];
@@ -810,7 +707,7 @@ void World::singleDetect(Entity *e){
}
break;
case NPCT:
- std::cout<<"Killed an NPC..."<<std::endl;
+ killed = "NPC";
for(j=0;j<npc.size();j++){
if(npc[j]==e){
delete npc[j];
@@ -820,7 +717,7 @@ void World::singleDetect(Entity *e){
}
break;
case MOBT:
- std::cout<<"Killed a mob..."<<std::endl;
+ killed = "mob";
/*for(j=0;j<mob.size();j++){
if(mob[j]==e){
delete mob[j];
@@ -830,7 +727,7 @@ void World::singleDetect(Entity *e){
}*/
break;
case OBJECTT:
- std::cout<<"Killed an object..."<<std::endl;
+ killed = "object";
for(j=0;j<object.size();j++){
if(object[j]==e){
delete object[j];
@@ -842,6 +739,7 @@ void World::singleDetect(Entity *e){
default:
break;
}
+ std::cout << "Killed a " << killed << "..." << std::endl;
entity.erase(entity.begin()+i);
return;
}
@@ -853,16 +751,17 @@ void World::singleDetect(Entity *e){
/*
* Handle only living entities.
*/
-
+
if(e->alive){
- if(e->type == MOBT && Mobp(e)->subtype == MS_TRIGGER)return;
+ if ( e->type == MOBT && Mobp(e)->subtype == MS_TRIGGER )
+ return;
/*
* Calculate the line that this entity is currently standing on.
*/
- l=(e->loc.x + e->width / 2 - x_start) / HLINE;
+ l=(e->loc.x + e->width / 2 - worldStart) / HLINE;
if(l < 0) l=0;
i = l;
if(i > lineCount-1) i=lineCount-1;
@@ -871,39 +770,11 @@ void World::singleDetect(Entity *e){
* If the entity is under the world/line, pop it back to the surface.
*/
- if(e->loc.y < line[i].y){
-
- /*
- * Check that the entity isn't trying to run through a wall.
- */
-
- //if(e->loc.y + e->height > line[i-(int)e->width/2/HLINE].y &&
- // e->loc.y + e->height > line[i+(int)e->width/2/HLINE].y ){
-
- e->loc.y=line[i].y - .001 * deltaTime;
- e->ground=true;
- e->vel.y=0;
-
- //}else{
-
- /*
- * Push the entity out of the wall if it's trying to go through it.
- */
-
- /*do{
- e->loc.x+=.001 * e->vel.x>0?-1:1;
-
- l=(e->loc.x - e->width / 2 - x_start) / HLINE;
- if(l < 0){
- std::cout<<"push kill lol "<<e->type<<std::endl;
- e->alive = false; return; }
- i = l;
- if(i > lineCount-1){
- std::cout<<"push kill lol "<<e->type<<std::endl;
- e->alive = false; return; }
- }while(line[i].y>e->loc.y+ e->height);
-
- }*/
+ if ( e->loc.y < worldData[i].groundHeight ) {
+
+ e->loc.y= worldData[i].groundHeight - .001 * deltaTime;
+ e->ground=true;
+ e->vel.y=0;
/*
* Handle gravity if the entity is above the line.
@@ -912,7 +783,7 @@ void World::singleDetect(Entity *e){
}else{
if(e->type == STRUCTURET && e->loc.y > 2000){
- e->loc.y = line[i].y;
+ e->loc.y = worldData[i].groundHeight;
e->vel.y = 0;
e->ground = true;
return;
@@ -924,129 +795,126 @@ void World::singleDetect(Entity *e){
* Insure that the entity doesn't fall off either edge of the world.
*/
- if(e->loc.x < x_start){ // Left bound
+ if(e->loc.x < worldStart){ // Left bound
e->vel.x=0;
- e->loc.x=(float)x_start + HLINE / 2;
+ e->loc.x=(float)worldStart + HLINE / 2;
- }else if(e->loc.x + e->width + HLINE > x_start + getWidth(this)){ // Right bound
+ }else if(e->loc.x + e->width + HLINE > worldStart + worldStart * -2){ // Right bound
e->vel.x=0;
- e->loc.x=x_start + getWidth(this) - e->width - HLINE;
+ e->loc.x=worldStart + worldStart * -2 - e->width - HLINE;
}
}
}
-void World::detect(Player *p){
-
- /*
- * Handle the player.
- */
+/**
+ * Handle entity logic for the world.
+ *
+ * This function runs World::singleDetect() for the player and every entity
+ * currently in a vector of this world. Particles and village entrance/exiting
+ * are also handled here.
+ */
+
+void World::
+detect( Player *p )
+{
+ int l;
- //auto pl = std::async(&World::singleDetect,this,p);
- std::thread(&World::singleDetect,this, p).detach();
+ // handle the player
+ std::thread( &World::singleDetect, this, p).detach();
- /*
- * Handle all remaining entities in this world.
- */
-
-//LOOOOP:
- for(auto &e : entity)
+ // handle other entities
+ for ( auto &e : entity )
std::thread(&World::singleDetect,this,e).detach();
- //hey->singleDetect(e);
- for(auto &part : particles){
- int l;
- unsigned int i;
- l=(part->loc.x + part->width / 2 - x_start) / HLINE;
- if(l < 0) l=0;
- i = l;
- if(i > lineCount-1) i=lineCount-1;
- if(part->loc.y < line[i].y){
- part->loc.y = line[i].y;
- part->vely = 0;
- part->velx = 0;
- part->canMove = false;
- }else{
- if(part->gravity && part->vely > -2)part->vely-=.003 * deltaTime;
- }
- }
- for(auto &b : build){
- switch(b->bsubtype){
- case FOUNTAIN:
- for(int r = 0; r < (rand()%25)+10;r++){
- addParticle( rand()%HLINE*3 + b->loc.x + b->width/2,
- b->loc.y + b->height,
- HLINE*1.25,
- HLINE*1.25,
- rand()%2 == 0?-(rand()%7)*.01:(rand()%7)*.01,
- ((4+rand()%6)*.05),
- {0,0,255},
- 2500);
-
- particles.back()->fountain = true;
- }
- break;
- case FIRE_PIT:
- for(int r = 0; r < (rand()%20)+10;r++){
- addParticle(rand()%(int)(b->width/2) + b->loc.x+b->width/4, b->loc.y+3*HLINE, HLINE, HLINE, rand()%2 == 0?-(rand()%3)*.01:(rand()%3)*.01,((4+rand()%6)*.005), {255,0,0}, 400);
- particles.back()->gravity = false;
- particles.back()->behind = true;
- }
- break;
- default: break;
+
+ // handle particles
+ for ( auto &part : particles ) {
+
+ // get particle's current world line
+ l = (part.loc.x + part.width / 2 - worldStart) / HLINE;
+
+ if ( l < 0 )
+ l = 0;
+
+ if ( l > (int)(lineCount - 1) )
+ l = lineCount - 1;
+
+ // handle ground collision
+ if ( part.loc.y < worldData[l].groundHeight ) {
+ part.loc.y = worldData[l].groundHeight;
+ part.vely = 0;
+ part.velx = 0;
+ part.canMove = false;
+ } else if ( part.gravity && part.vely > -2 )
+ part.vely -= .003 * deltaTime;
+ }
+
+ // handle particle creation
+ for ( auto &b : build ) {
+ switch ( b->bsubtype ) {
+ case FOUNTAIN:
+ for ( unsigned int r = (randGet() % 25) + 11; r--; ) {
+ addParticle(randGet() % HLINE * 3 + b->loc.x + b->width / 2, // x
+ b->loc.y + b->height, // y
+ HLINE * 1.25, // width
+ HLINE * 1.25, // height
+ randGet() % 7 * .01 * (randGet() % 2 == 0 ? -1 : 1), // vel.x
+ (4 + randGet() % 6) * .05, // vel.y
+ { 0, 0, 255 }, // RGB color
+ 2500 // duration (ms)
+ );
+
+ particles.back().fountain = true;
+ }
+ break;
+
+ case FIRE_PIT:
+ for(unsigned int r = (randGet() % 20) + 11; r--; ) {
+ addParticle(randGet() % (int)(b->width / 2) + b->loc.x + b->width / 4, // x
+ b->loc.y + 3 * HLINE, // y
+ HLINE, // width
+ HLINE, // height
+ randGet() % 3 * .01 * (randGet() % 2 == 0 ? -1 : 1), // vel.x
+ (4 + randGet() % 6) * .005, // vel.y
+ { 255, 0, 0 }, // RGB color
+ 400 // duration (ms)
+ );
+
+ particles.back().gravity = false;
+ particles.back().behind = true;
+ }
+ break;
+
+ default:
+ break;
}
}
- for(auto &v : village){
- if(p->loc.x > v.start.x && p->loc.x < v.end.x){
- if(!v.in){
- ui::passiveImportantText(5000,"Welcome to %s",v.name.c_str());
- v.in = true;
+ // draws the village welcome message if the player enters the village bounds
+ for ( auto &v : village ) {
+ if ( p->loc.x > v->start.x && p->loc.x < v->end.x ) {
+ if ( !v->in ) {
+ ui::passiveImportantText( 5000, "Welcome to %s", v->name.c_str() );
+ v->in = true;
}
- }else{
- v.in = false;
- }
+ } else
+ v->in = false;
}
-
- /*if(hey->infront){
- hey = hey->infront;
- goto LOOOOP;
- }*/
}
-void World::addStructure(BUILD_SUB sub, float x,float y, char *tex, const char *inside){
+void World::addStructure(BUILD_SUB sub, float x,float y, std::string tex, std::string inside){
build.push_back(new Structures());
build.back()->inWorld = this;
build.back()->textureLoc = tex;
+
build.back()->spawn(sub,x,y);
-
- if(inside)
- strcpy((build.back()->inside = new char[1 + strlen(inside)]),inside);
- else
- strcpy((build.back()->inside = new char[1]),"\0");
-
- //strcpy((build.back()->outside = new char[1 + strlen((char *)(currentXML+4))]),(char *)(currentXML+4));
+ build.back()->inside = inside;
+
entity.push_back(build.back());
}
-
-/*void World::addVillage(int bCount, int npcMin, int npcMax,const char *inside){
- std::cout << npcMin << ", " << npcMax << std::endl;
- //int xwasd;
- for(int i = 0; i < bCount; i++){
- addStructure(HOUSE,x_start + (i * 300),100,inside);
- std::cout<<"1\n";
- HERE:
- xwasd = (rand()%(int)x+1000*HLINE);
- for(auto &bu : build){
- if(xwasd > bu->loc.x && xwasd < bu->loc.x+bu->width)goto HERE;
- }
- std::cout<<"2\n";
- addStructure(t,HOUSE,xwasd,y,inside);
- std::cout<<"3\n";
- }
-}*/
void World::addMob(int t,float x,float y){
mob.push_back(new Mob(t));
@@ -1070,55 +938,37 @@ void World::addNPC(float x,float y){
entity.push_back(npc.back());
}
-void World::addObject(/*ITEM_ID i*/std::string in,const char *p, float x, float y){
+void World::addMerchant(float x, float y){
+ merchant.push_back(new Merchant());
+ merchant.back()->spawn(x,y);
+
+ npc.push_back(merchant.back());
+ entity.push_back(npc.back());
+}
+
+void World::addObject( std::string in, std::string p, float x, float y){
object.push_back(new Object(in,p));
object.back()->spawn(x,y);
entity.push_back(object.back());
}
-void World::addParticle(float x, float y, float w, float h, float vx, float vy, Color color, int d){
- particles.push_back(new Particles(x,y,w,h,vx,vy,color,d));
- particles.back()->canMove = true;
+void World::
+addParticle( float x, float y, float w, float h, float vx, float vy, Color color, int d )
+{
+ particles.emplace_back( x, y, w, h, vx, vy, color, d );
+ particles.back().canMove = true;
}
void World::addLight(vec2 loc, Color color){
+ Light l;
if(light.size() < 64){
- light.push_back(Light());
- light.back().loc = loc;
- light.back().color = color;
+ l.loc = loc;
+ l.color = color;
+ light.push_back(l);
}
}
-/*void World::removeObject(Object i){
- object.delete[](i);
-}*/
-
-/*
- * The rest of these functions are explained well enough in world.h ;)
-*/
-
-/*void World::addLayer(unsigned int width){
- if(behind){
- behind->addLayer(width);
- return;
- }
- behind=new World();
- behind->generate(width);
- behind->infront=this;
- behind->star=star;
- behind->bgmObj=bgmObj;
- behind->bgTex=bgTex;
-}*/
-
-NPC *World::getAvailableNPC(void){
- for(auto &n : npc){
- if(n->aiFunc.empty())
- return n;
- }
- return (NPC *)NULL;
-}
-
char *World::setToLeft(const char *file){
if(toLeft)
delete[] toLeft;
@@ -1138,13 +988,20 @@ char *World::setToRight(const char *file){
return toRight;
}
-World *World::goWorldLeft(Player *p){
+World *World::
+goWorldLeft( Player *p )
+{
World *tmp;
- if(toLeft && p->loc.x < x_start + (int)HLINE * 15){
+
+ // check if player is at world edge
+ if(toLeft && p->loc.x < worldStart + HLINE * 15.0f){
+
+ // load world (`toLeft` conditional confirms existance)
tmp = loadWorldFromXML(toLeft);
- p->loc.x = -tmp->x_start - HLINE * 10;
- p->loc.y = tmp->line[tmp->lineCount - 1].y;
+ // adjust player location
+ p->loc.x = tmp->worldStart - HLINE * -10.0f;
+ p->loc.y = tmp->worldData[tmp->lineCount - 1].groundHeight;
return tmp;
}
@@ -1154,43 +1011,29 @@ World *World::goWorldLeft(Player *p){
World *World::goWorldRight(Player *p){
World *tmp;
- if(toRight && p->loc.x + p->width > -x_start - HLINE * 15){
+ if(toRight && p->loc.x + p->width > -worldStart - HLINE * 15){
tmp = loadWorldFromXML(toRight);
- p->loc.x = tmp->x_start + (int)HLINE * 10;
- p->loc.y = tmp->line[0].y;
+ p->loc.x = tmp->worldStart + HLINE * 10;
+ p->loc.y = GROUND_HEIGHT_MINIMUM;
return tmp;
}
return this;
}
-/*World *World::goWorldBack(Player *p){
- if(behind&&p->loc.x>(int)(0-getWidth(behind)/2)&&p->loc.x<getWidth(behind)/2){
- return behind;
- }
- return this;
-}
-
-World *World::goWorldFront(Player *p){
- if(infront&&p->loc.x>(int)(0-getWidth(infront)/2)&&p->loc.x<getWidth(infront)/2){
- return infront;
- }
- return this;
-}*/
-
-std::vector<char *>inside;
-World *World::goInsideStructure(Player *p){
+World *World::
+goInsideStructure( Player *p )
+{
World *tmp;
char *current;
if(inside.empty()){
for(auto &b : build){
if(p->loc.x > b->loc.x &&
p->loc.x + p->width < b->loc.x + b->width ){
- inside.push_back(new char[1 + strlen(currentXML)]);
- strcpy(inside.back(),(char *)(currentXML+4));
+ inside.push_back((std::string)(currentXML.c_str() + 4));
- tmp = loadWorldFromXML(b->inside);
+ tmp = loadWorldFromXML(b->inside.c_str());
ui::toggleBlackFast();
ui::waitForCover();
@@ -1200,16 +1043,17 @@ World *World::goInsideStructure(Player *p){
}
}
}else{
- strcpy((current = new char[strlen((char *)(currentXML + 4)) + 1]),(char *)(currentXML + 4));
- tmp = loadWorldFromXML(inside.back());
+ strcpy((current = new char[strlen((const char *)(currentXML.c_str() + 4)) + 1]),(const char *)(currentXML.c_str() + 4));
+ tmp = loadWorldFromXML(inside.back().c_str());
for(auto &b : tmp->build){
- if(!strcmp(current,b->inside)){
- p->loc.x = b->loc.x + (b->width / 2);
- delete[] inside.back();
+ if(!strcmp(current,b->inside.c_str())){
inside.pop_back();
ui::toggleBlackFast();
ui::waitForCover();
+
+ p->loc.x = b->loc.x + (b->width / 2);
+
ui::toggleBlackFast();
return tmp;
@@ -1223,18 +1067,14 @@ World *World::goInsideStructure(Player *p){
void World::addHole(unsigned int start,unsigned int end){
unsigned int i;
for(i=start;i<end;i++){
- line[i].y=0;
+ worldData[i].groundHeight = 0;
}
}
-int World::getTheWidth(void){
- World *hey=this;
-/*LOOP:
- if(hey->infront){
- hey=hey->infront;
- goto LOOP;
- }*/
- return -hey->x_start*2;
+int World::
+getTheWidth( void ) const
+{
+ return worldStart * -2;
}
void World::save(void){
@@ -1268,11 +1108,6 @@ void World::save(void){
out.close();
}
-#include <sstream>
-
-extern int commonAIFunc(NPC *);
-extern void commonTriggerFunc(Mob *);
-
void World::load(void){
std::string save,data,line;
const char *filedata;
@@ -1331,26 +1166,17 @@ IndoorWorld::IndoorWorld(void){
IndoorWorld::~IndoorWorld(void){
delete bgTex;
- delete[] star;
- delete[] line;
deleteEntities();
}
void IndoorWorld::generate(unsigned int width){ // Generates a flat area of width 'width'
- unsigned int i; // Used for 'for' loops
- lineCount=width+GEN_INC; // Sets line count to the desired width plus GEN_INC to remove incorrect line calculations.
+ lineCount=width+GROUND_HILLINESS; // Sets line count to the desired width plus GEN_INC to remove incorrect line calculations.
if(lineCount<=0)abort();
- line = new struct line_t[lineCount]; //(struct line_t *)calloc(lineCount,sizeof(struct line_t)); // Allocate memory for the array 'line'
- memset(line,0,lineCount*sizeof(struct line_t));
+ worldData = std::vector<WorldData> (lineCount, WorldData { false, {0,0}, INDOOR_FLOOR_HEIGHT, 0 });
- for(i=0;i<lineCount;i++){ // Indoor areas don't have to be directly on the ground (i.e. 0)...
- line[i].y=INDOOR_FLOOR_HEIGHT;
- }
- //behind=infront=NULL; // Set pointers to other worlds to NULL
- //toLeft=toRight=NULL; // to avoid accidental calls to goWorld... functions
- x_start=0-getWidth(this)/2+GEN_INC/2*HLINE; // Calculate x_start (explained in world.h)
+ worldStart = (width - GROUND_HILLINESS) * HLINE / 2 * -1;
}
void IndoorWorld::draw(Player *p){
@@ -1364,24 +1190,32 @@ void IndoorWorld::draw(Player *p){
glEnable(GL_TEXTURE_2D);
- GLfloat pointArray[light.size()][2];
- for(uint w = 0; w < light.size(); w++){
- pointArray[w][0] = light[w].loc.x - offset.x;
- pointArray[w][1] = light[w].loc.y;
+ std::unique_ptr<GLfloat[]> pointArrayBuf = std::make_unique<GLfloat[]> (2 * (light.size() + p->light));
+ auto pointArray = pointArrayBuf.get();
+
+ for ( i = 0; i < light.size(); i++ ) {
+ pointArray[2 * i ] = light[i].loc.x - offset.x;
+ pointArray[2 * i + 1] = light[i].loc.y;
}
- glUseProgram(shaderProgram);
- glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0);
- glUniform1f(glGetUniformLocation(shaderProgram, "amb"), 0.0f);
- if(p->light){
- glUniform1i(glGetUniformLocation(shaderProgram, "numLight"), 1);
- glUniform2f(glGetUniformLocation(shaderProgram, "lightLocation"), p->loc.x - offset.x+SCREEN_WIDTH/2, p->loc.y);
- glUniform3f(glGetUniformLocation(shaderProgram, "lightColor"), 1.0f,1.0f,1.0f);
- }else if(!light.size()){
- glUniform1i(glGetUniformLocation(shaderProgram, "numLight"), 0);
- }else{
- glUniform1i(glGetUniformLocation(shaderProgram, "numLight"), light.size());
- glUniform2fv(glGetUniformLocation(shaderProgram, "lightLocation"), light.size(), (GLfloat *)&pointArray);
- glUniform3f(glGetUniformLocation(shaderProgram, "lightColor"), 1.0f,1.0f,1.0f);
+
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+
+ glUseProgram( shaderProgram );
+ glUniform1i( glGetUniformLocation( shaderProgram, "sampler"), 0 );
+ glUniform1f( glGetUniformLocation( shaderProgram, "amb" ), 0.3f );
+
+ if ( p->light ) {
+ pointArray[2 * (light.size() + 1) ] = (float)( p->loc.x + SCREEN_WIDTH / 2 );
+ pointArray[2 * (light.size() + 1) + 1] = (float)( p->loc.y );
+ }
+
+ if ( light.size() + (int)p->light == 0)
+ glUniform1i( glGetUniformLocation( shaderProgram, "numLight"), 0);
+ else {
+ glUniform1i ( glGetUniformLocation( shaderProgram, "numLight" ), light.size() + (int)p->light );
+ glUniform2fv( glGetUniformLocation( shaderProgram, "lightLocation"), light.size() + (int)p->light, pointArray );
+ glUniform3f ( glGetUniformLocation( shaderProgram, "lightColor" ), 1.0f, 1.0f, 1.0f );
}
bgTex->bind(0);
@@ -1389,13 +1223,11 @@ void IndoorWorld::draw(Player *p){
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); //for the t direction
glColor4ub(255,255,255,255);
- glBegin(GL_QUADS);
- //for(j = x_start - SCREEN_WIDTH / 2;j < -x_start + SCREEN_WIDTH / 2; j += 512){
- glTexCoord2i(0,1); glVertex2i( x_start - SCREEN_WIDTH / 2,0);
- glTexCoord2i((-x_start*2+SCREEN_WIDTH)/512,1);glVertex2i(-x_start + SCREEN_WIDTH / 2,0);
- glTexCoord2i((-x_start*2+SCREEN_WIDTH)/512,0);glVertex2i(-x_start + SCREEN_WIDTH / 2,SCREEN_HEIGHT);
- glTexCoord2i(0,0); glVertex2i( x_start - SCREEN_WIDTH / 2,SCREEN_HEIGHT);
- //}
+ glBegin(GL_QUADS);
+ glTexCoord2i(0,1); glVertex2i( worldStart - SCREEN_WIDTH / 2,0);
+ glTexCoord2i((-worldStart*2+SCREEN_WIDTH)/512,1);glVertex2i(-worldStart + SCREEN_WIDTH / 2,0);
+ glTexCoord2i((-worldStart*2+SCREEN_WIDTH)/512,0);glVertex2i(-worldStart + SCREEN_WIDTH / 2,SCREEN_HEIGHT);
+ glTexCoord2i(0,0); glVertex2i( worldStart - SCREEN_WIDTH / 2,SCREEN_HEIGHT);
glEnd();
glUseProgram(0);
@@ -1422,14 +1254,14 @@ void IndoorWorld::draw(Player *p){
glUseProgram(shaderProgram);
glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0);
glBegin(GL_QUADS);
- for(;i < ie - GEN_INC;i++){
+ for(;i < ie - GROUND_HILLINESS;i++){
safeSetColor(150,100,50);
- x = x_start + i * HLINE;
- glVertex2i(x ,line[i].y);
- glVertex2i(x + HLINE,line[i].y);
- glVertex2i(x + HLINE,line[i].y - 50);
- glVertex2i(x ,line[i].y - 50);
+ x = worldStart + i * HLINE;
+ glVertex2i(x ,worldData[i].groundHeight);
+ glVertex2i(x + HLINE,worldData[i].groundHeight);
+ glVertex2i(x + HLINE,worldData[i].groundHeight - 50);
+ glVertex2i(x ,worldData[i].groundHeight - 50);
}
glEnd();
glUseProgram(0);
@@ -1438,15 +1270,14 @@ void IndoorWorld::draw(Player *p){
* Draw all entities.
*/
- for(auto &part : particles) part->draw();
- for(auto &e : entity) e->draw();
- p->draw();
-}
+ for ( auto &part : particles )
+ part.draw();
-extern bool inBattle;
+ for ( auto &e : entity )
+ e->draw();
-std::vector<World *> battleNest;
-std::vector<vec2> battleNestLoc;
+ p->draw();
+}
Arena::Arena(World *leave,Player *p,Mob *m){
generate(800);
@@ -1454,24 +1285,16 @@ Arena::Arena(World *leave,Player *p,Mob *m){
inBattle = true;
mmob = m;
- //exit = leave;
- //pxy = p->loc;
+ mmob->aggressive = false;
mob.push_back(m);
entity.push_back(m);
battleNest.push_back(leave);
battleNestLoc.push_back(p->loc);
-
- star = new vec2[100];
- memset(star,0,100 * sizeof(vec2));
}
Arena::~Arena(void){
- delete bgTex;
- delete[] star;
- delete[] line;
-
deleteEntities();
}
@@ -1488,30 +1311,29 @@ World *Arena::exitArena(Player *p){
p->loc = battleNestLoc.back();
battleNestLoc.pop_back();
- //mmob->alive = false;
+
+ mob.clear();
+ mmob->alive = false;
+
return tmp;
}else{
return this;
}
}
-#include <tinyxml2.h>
-using namespace tinyxml2;
-
-char *currentXML = NULL;
-
-extern World *currentWorld;
-
-World *loadWorldFromXML(const char *path){
- if(currentXML){
+World *loadWorldFromXML(std::string path){
+ if ( !currentXML.empty() )
currentWorld->save();
- delete[] currentXML;
- }
-
+
return loadWorldFromXMLNoSave(path);
}
-World *loadWorldFromXMLNoSave(const char *path){
+/**
+ * Loads a world from the given XML file.
+ */
+
+World *
+loadWorldFromXMLNoSave( std::string path ) {
XMLDocument xml;
XMLElement *wxml;
XMLElement *vil;
@@ -1521,59 +1343,55 @@ World *loadWorldFromXMLNoSave(const char *path){
bool dialog,Indoor;
const char *ptr,*name;
-
- unsigned int size = 5 + strlen(path);
+
+ currentXML = (std::string)"xml/" + path;
- if(currentXML)
- delete[] currentXML;
- memset((currentXML = new char[size]),0,size);
- strcpy(currentXML,"xml/");
- strcat(currentXML,path);
-
- xml.LoadFile(currentXML);
+ xml.LoadFile(currentXML.c_str());
wxml = xml.FirstChildElement("World");
- vil = xml.FirstChildElement("World")->FirstChildElement("village");
if(wxml){
wxml = wxml->FirstChildElement();
+ vil = xml.FirstChildElement("World")->FirstChildElement("village");
Indoor = false;
tmp = new World();
}else if((wxml = xml.FirstChildElement("IndoorWorld"))){
wxml = wxml->FirstChildElement();
+ vil = NULL;
Indoor = true;
tmp = new IndoorWorld();
}
while(wxml){
name = wxml->Name();
+
if(!strcmp(name,"link")){
if((ptr = wxml->Attribute("left")))
tmp->setToLeft(ptr);
else if((ptr = wxml->Attribute("right")))
tmp->setToRight(ptr);
- else abort();
+ else
+ abort();
}else if(!strcmp(name,"style")){
- tmp->setStyle(wxml->Attribute("folder"));
- tmp->setBackground((WORLD_BG_TYPE)wxml->UnsignedAttribute("background"));
- tmp->setBGM(wxml->Attribute("bgm"));
+ tmp->setStyle(wxml->StrAttribute("folder"));
+ tmp->setBackground((WorldBGType)wxml->UnsignedAttribute("background"));
+ tmp->setBGM(wxml->StrAttribute("bgm"));
}else if(!strcmp(name,"generation")){
if(!strcmp(wxml->Attribute("type"),"Random")){
if(Indoor)
((IndoorWorld *)tmp)->generate(wxml->UnsignedAttribute("width"));
- else
+ else {
+
tmp->generate(wxml->UnsignedAttribute("width"));
- }else if(Indoor){
+ }
+ }else if(Indoor)
abort();
- }
}else if(!strcmp(name,"mob")){
unsigned int type;
-
type = wxml->UnsignedAttribute("type");
if(wxml->QueryFloatAttribute("x",&spawnx) != XML_NO_ERROR)
- tmp->addMob(type,getRand() % tmp->getTheWidth() / 2,100);
+ tmp->addMob(type,0,100);
else
tmp->addMob(type,spawnx,wxml->FloatAttribute("y"));
-
if(wxml->QueryBoolAttribute("aggressive",&dialog) == XML_NO_ERROR)
tmp->mob.back()->aggressive = dialog;
@@ -1581,7 +1399,7 @@ World *loadWorldFromXMLNoSave(const char *path){
const char *npcname;
if(wxml->QueryFloatAttribute("x",&spawnx) != XML_NO_ERROR)
- tmp->addNPC(getRand() % tmp->getTheWidth() / 2.0f,100);
+ tmp->addNPC(0,100);
else
tmp->addNPC(spawnx,wxml->FloatAttribute("y"));
@@ -1598,14 +1416,13 @@ World *loadWorldFromXMLNoSave(const char *path){
else tmp->npc.back()->dialogIndex = 9999;
}else if(!strcmp(name,"structure")){
- ptr = wxml->Attribute("inside");
tmp->addStructure((BUILD_SUB)wxml->UnsignedAttribute("type"),
wxml->QueryFloatAttribute("x",&spawnx) != XML_NO_ERROR ?
getRand() % tmp->getTheWidth() / 2.0f :
spawnx,
100,
- (char*)wxml->Attribute("texture"),
- ptr);
+ wxml->StrAttribute("texture"),
+ wxml->StrAttribute("inside"));
}else if(!strcmp(name,"trigger")){
tmp->addMob(MS_TRIGGER,wxml->FloatAttribute("x"),0,commonTriggerFunc);
tmp->mob.back()->heyid = wxml->Attribute("id");
@@ -1614,35 +1431,74 @@ World *loadWorldFromXMLNoSave(const char *path){
wxml = wxml->NextSiblingElement();
}
+ Village *vptr;
+
if(vil){
- tmp->village.push_back(vil->Attribute("name"));
+ tmp->village.push_back(new Village(vil->Attribute("name"), tmp));
+ vptr = tmp->village.back();
vil = vil->FirstChildElement();
}
while(vil){
name = vil->Name();
- randx = getRand() % tmp->getTheWidth() - (tmp->getTheWidth() / 2.0f);
+ randx = 0;
+ //static BuySell bs;
/**
* READS DATA ABOUT STRUCTURE CONTAINED IN VILLAGE
*/
+
if(!strcmp(name,"structure")){
- ptr = vil->Attribute("inside");
tmp->addStructure((BUILD_SUB)vil->UnsignedAttribute("type"),
+ vil->QueryFloatAttribute("x", &spawnx) != XML_NO_ERROR ? randx : spawnx,
+ 100,
+ vil->StrAttribute("texture"),
+ vil->StrAttribute("inside"));
+ }else if(!strcmp(name, "stall")){
+ if(!strcmp(vil->Attribute("type"),"market")){
+ std::cout << "Market" << std::endl;
+ tmp->addStructure((BUILD_SUB)70,
vil->QueryFloatAttribute("x", &spawnx) != XML_NO_ERROR ?
randx : spawnx,
100,
- (char*)vil->Attribute("texture"),
- ptr);
+ vil->StrAttribute("texture"),
+ vil->StrAttribute("inside"));
+ tmp->addMerchant(0,100);
+ if(vil->FirstChildElement("buy")){
+ std::cout << "Buy" << std::endl;
+ //Trade goodMeme(1,"Dank MayMay",1,"Sword");
+ //tmp->merchant.back()->trade.push_back(Trade());
+ }if(vil->FirstChildElement("sell")){
+ std::cout << "Sell" << std::endl;
+ }if(vil->FirstChildElement("trade")){
+ std::cout << "Trade" << std::endl;
+ tmp->merchant.back()->trade.push_back(Trade(vil->FirstChildElement("trade")->IntAttribute("quantity"),
+ vil->FirstChildElement("trade")->Attribute("item"),
+ vil->FirstChildElement("trade")->IntAttribute("quantity1"),
+ vil->FirstChildElement("trade")->Attribute("item1")));
+ }
+ strcpy(tmp->merchant.back()->name,"meme");
- tmp->village.back().build.push_back(tmp->build.back());
+ }else if(!strcmp(vil->Attribute("type"),"trader")){
+ std::cout << "Trader" << std::endl;
+ tmp->addStructure((BUILD_SUB)71,
+ vil->QueryFloatAttribute("x", &spawnx) != XML_NO_ERROR ?
+ randx : spawnx,
+ 100,
+ vil->StrAttribute("texture"),
+ vil->StrAttribute("inside"));
+ }
}
- if(tmp->village.back().build.back()->loc.x < tmp->village.back().start.x){
- tmp->village.back().start.x = tmp->village.back().build.back()->loc.x;
+
+ vptr->build.push_back(tmp->build.back());
+
+ if(vptr->build.back()->loc.x < vptr->start.x){
+ vptr->start.x = vptr->build.back()->loc.x;
}
- if(tmp->village.back().build.back()->loc.x + tmp->village.back().build.back()->width > tmp->village.back().end.x){
- tmp->village.back().end.x = tmp->village.back().build.back()->loc.x + tmp->village.back().build.back()->width;
+
+ if(vptr->build.back()->loc.x + vptr->build.back()->width > vptr->end.x){
+ vptr->end.x = vptr->build.back()->loc.x + vptr->build.back()->width;
}
//go to the next element in the village block
@@ -1656,4 +1512,12 @@ World *loadWorldFromXMLNoSave(const char *path){
}
return tmp;
-} \ No newline at end of file
+
+}
+
+Village::Village(const char *meme, World *w){
+ name = meme;
+ start.x = w->getTheWidth() / 2.0f;
+ end.x = -start.x;
+ in = false;
+}
diff --git a/xml/playerSpawnHill1.xml b/xml/playerSpawnHill1.xml
index 269b393..2e8b2aa 100644
--- a/xml/playerSpawnHill1.xml
+++ b/xml/playerSpawnHill1.xml
@@ -1,19 +1,24 @@
<?xml version="1.0"?>
<World>
<style background="0" bgm="assets/music/embark.wav" folder="assets/style/classic/" />
- <generation type="Random" width="1600" />
+ <generation type="Random" width="500" />
<link left="playerSpawnHill2.xml" />
- <mob type="1" aggressive="false" />
+ <mob x="300" type="1" aggressive="true" />
<trigger x="-300" id="Test" />
<npc name="Ralph" hasDialog="true" />
<npc name="Johnny" hasDialog="false" />
- <!-- <structure type="5" inside="playerSpawnHill1_Building1.xml" /> -->
- <village name="Meme-Town">
- <structure type="0" x="-100" inside="playerSpawnHill1_Building1.xml"/>
+ <village name="the Cranmore Tubing Park">
+ <structure type="0" x="-300" inside="playerSpawnHill1_Building1.xml"/>
<structure type="5" x="-500" inside="playerSpawnHill1_Building1.xml"/>
+ <stall type="market" texture="assets/style/classic/stall.png">
+ <buy item="Dank MayMay" cost="420"/>
+ <sell item="Dank MayMay" cost="666"/>
+ <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>