diff options
author | drumsetmonkey <abelleisle@roadrunner.com> | 2016-03-08 21:14:47 -0500 |
---|---|---|
committer | drumsetmonkey <abelleisle@roadrunner.com> | 2016-03-08 21:14:47 -0500 |
commit | 98e08cb7c2ae6c61192bac73a1fc7254224452be (patch) | |
tree | 2ff5a4b9254b0dc9217795dc8a76365736fd40e4 | |
parent | 0a0766a186db892f7a8f28f0130a043fd9b9dff9 (diff) | |
parent | 82c75b0a97eba2f78206d3b97d47eaa580a82f0c (diff) |
Fixed incorrect language percentages
-rw-r--r-- | .gitattributes | 6 | ||||
-rw-r--r-- | Changelog | 74 | ||||
-rw-r--r-- | Makefile | 76 | ||||
-rw-r--r-- | assets/items/coin1.png | bin | 0 -> 255 bytes | |||
-rw-r--r-- | assets/items/coin2.png | bin | 0 -> 241 bytes | |||
-rw-r--r-- | assets/items/coin3.png | bin | 0 -> 242 bytes | |||
-rw-r--r-- | assets/style/classic/bg/moon.png | bin | 0 -> 2868 bytes | |||
-rw-r--r-- | assets/style/classic/stall.png | bin | 0 -> 778 bytes | |||
-rw-r--r-- | config/items.xml | 4 | ||||
-rw-r--r-- | include/Texture.h | 7 | ||||
-rw-r--r-- | include/common.h | 41 | ||||
-rw-r--r-- | include/entities.h | 47 | ||||
-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.h | 1 | ||||
-rw-r--r-- | include/threadpool.h | 53 | ||||
-rwxr-xr-x | include/tinyxml2.h | 7 | ||||
-rw-r--r-- | include/ui.h | 11 | ||||
-rw-r--r-- | include/world.h | 211 | ||||
-rw-r--r-- | main.cpp | 315 | ||||
-rw-r--r-- | setup.mk | 5 | ||||
-rw-r--r-- | src/Makefile | 18 | ||||
-rw-r--r-- | src/Quest.cpp | 37 | ||||
-rw-r--r-- | src/Texture.cpp | 109 | ||||
-rw-r--r-- | src/common.cpp | 61 | ||||
-rw-r--r-- | src/config.cpp | 1 | ||||
-rw-r--r-- | src/entities.cpp | 227 | ||||
-rw-r--r-- | src/gameplay.cpp | 56 | ||||
-rw-r--r-- | src/inventory.cpp | 22 | ||||
-rw-r--r-- | src/threadpool.cpp | 99 | ||||
-rwxr-xr-x | src/tinyxml2.cpp | 13 | ||||
-rw-r--r-- | src/ui.cpp | 309 | ||||
-rw-r--r-- | src/world.cpp | 1798 | ||||
-rw-r--r-- | xml/playerSpawnHill1.xml | 15 |
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 @@ -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 @@ -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 Binary files differnew file mode 100644 index 0000000..6b8ba8c --- /dev/null +++ b/assets/items/coin1.png diff --git a/assets/items/coin2.png b/assets/items/coin2.png Binary files differnew file mode 100644 index 0000000..5bfd622 --- /dev/null +++ b/assets/items/coin2.png diff --git a/assets/items/coin3.png b/assets/items/coin3.png Binary files differnew file mode 100644 index 0000000..61bf980 --- /dev/null +++ b/assets/items/coin3.png diff --git a/assets/style/classic/bg/moon.png b/assets/style/classic/bg/moon.png Binary files differnew file mode 100644 index 0000000..d9a5ab7 --- /dev/null +++ b/assets/style/classic/bg/moon.png diff --git a/assets/style/classic/stall.png b/assets/style/classic/stall.png Binary files differnew file mode 100644 index 0000000..1ac9844 --- /dev/null +++ b/assets/style/classic/stall.png 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 @@ -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() ) {
@@ -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> |