From a9a9777190086bd2ce2aa54e20a1101509614463 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan <tullivan99@gmail.com> Date: Tue, 29 Mar 2016 08:48:52 -0400 Subject: began reworking indoors --- Changelog | 22 ++++ Makefile | 2 +- include/Quest.h | 72 ------------- include/Texture.h | 103 ------------------ include/common.h | 3 +- include/config.h | 16 ++- include/entities.h | 6 +- include/inventory.h | 2 +- include/quest.h | 66 ++++++++++++ include/texture.h | 103 ++++++++++++++++++ include/world.h | 13 ++- main.cpp | 6 +- src/Quest.cpp | 72 ------------- src/Texture.cpp | 215 ------------------------------------- src/config.cpp | 101 +++++++++-------- src/gameplay.cpp | 6 +- src/inventory.cpp | 4 +- src/quest.cpp | 69 ++++++++++++ src/texture.cpp | 215 +++++++++++++++++++++++++++++++++++++ src/ui.cpp | 29 +++-- src/world.cpp | 170 ++++++++++++++--------------- xml/playerSpawnHill1.xml | 2 +- xml/playerSpawnHill1_Building1.xml | 7 +- 23 files changed, 670 insertions(+), 634 deletions(-) delete mode 100644 include/Quest.h delete mode 100644 include/Texture.h create mode 100644 include/quest.h create mode 100644 include/texture.h delete mode 100644 src/Quest.cpp delete mode 100644 src/Texture.cpp create mode 100644 src/quest.cpp create mode 100644 src/texture.cpp diff --git a/Changelog b/Changelog index 1a54ec3..00ba578 100644 --- a/Changelog +++ b/Changelog @@ -821,3 +821,25 @@ - found brazzier glitch - merchants inside stalls - z renders???? + +3/25/2016: +========== + + - relocated detect() to main loop, better thing handling now + - implemented rain, snow + - added weather to debug overlay thing + +3/28/2016: +========== + + - fixed bug with quest assignment + - made file names consistent + - namespace'd config stuff + - began work on improving rendering stuff + +3/29/2016: +========== + + - prevented structures from moving + - began making indoor worlds good + - inventory slots are actually being used diff --git a/Makefile b/Makefile index 4c56fb6..c8b09e3 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ ifeq ($(TARGET_OS),win32) -lSDL2main -lSDL2 -lSDL2_image -lSDL2_mixer -lfreetype endif -CXXFLAGS = -m$(TARGET_BITS) -std=c++14 +CXXFLAGS = -m$(TARGET_BITS) -std=c++1z CXXINC = -Iinclude -Iinclude/freetype CXXWARN = -Wall -Wextra -Werror -pedantic-errors diff --git a/include/Quest.h b/include/Quest.h deleted file mode 100644 index 8b1e142..0000000 --- a/include/Quest.h +++ /dev/null @@ -1,72 +0,0 @@ -/** @file Quest.h - * @brief The quest handling system. - * - * This file contains Quest and QuestHandler, used to manage quests inside the - * game. - */ - -#ifndef QUEST_H -#define QUEST_H - -#include <cstring> - -#include <common.h> -#include <inventory.h> - -/** - * When defined, DEBUG allows extra messages to be printed to the terminal for - * debugging purposes. - */ - -#define DEBUG - -struct need_t { - std::string name; - int n; -}; - -typedef struct { - std::string title; - std::string desc; - struct item_t reward; - std::vector<struct need_t> need; -} Quest; - -/** - * The Quest Handler class. - * - * This class handles quests, including the assigning, dropping, and completing - * of the quests. - */ - -class QuestHandler { -public: - std::vector<Quest>current; - - /** - * Adds a quest to the current quest vector by its title. - */ - - int assign(std::string title,std::string desc,std::string req); - - /** - * Drops a quest through its title. - */ - - int drop(std::string title); - - /** - * Finishes a quest through it's title, also giving a pointer to the Entity - * that gave the quest originally. - */ - - int finish(std::string t); - - /** - * Returns true if this handler is currently taking the quest. - */ - - bool hasQuest(std::string t); -}; - -#endif // QUEST_H diff --git a/include/Texture.h b/include/Texture.h deleted file mode 100644 index 816a8bf..0000000 --- a/include/Texture.h +++ /dev/null @@ -1,103 +0,0 @@ -/** @file Texture.h - * @brief Defines a method for loading textures. - * - * This file gives facilities for easily loading and binding textures. - */ - -#ifndef TEXTURE_H -#define TEXTURE_H - -#include <common.h> - -/** - * When defined, DEBUG allows extra messages to be printed to the terminal for - * debugging purposes. - */ - -#define DEBUG - -/** - * Texture functions are given a namespace for better organization. - */ - -namespace Texture { - - /** - * Loads a texture from the given file name, returning the GLuint used for - * later referencing of the texture. - */ - - GLuint loadTexture(std::string fileName); - - void freeTextures(void); - - void initColorIndex(); - vec2 getIndex(Color c); - dim2 imageDim(std::string fileName); -} - -/** - * The Texturec class. - * - * This class can handle an array of textures and allows easy binding of those - * textures. - */ - -class Texturec{ -private: - - /** - * Contains the index in the image array of the currently loaded texture. - */ - - unsigned int texState; - -public: - - /** - * Contains an array of the GLuints returned from Texture::loadTexture(). - */ - - std::vector<GLuint> image; - - /** - * Populates the image array from a list of strings, with each string as a - * separate argument. - */ - - Texturec(uint amt, ...); - - /** - * Populates the image array from an array of strings. - */ - - 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. - */ - - ~Texturec(); - - /** - * Binds the next texture in the array, incrementing texState. - */ - - void bindNext(); - - /** - * Binds the previous texture in the array, decrementing texState. - */ - - void bindPrev(); - - /** - * Binds the texture with the provided index. - */ - - void bind(unsigned int); -}; - -#endif //TEXTURE_H diff --git a/include/common.h b/include/common.h index 6f453b0..216dc01 100644 --- a/include/common.h +++ b/include/common.h @@ -117,7 +117,7 @@ typedef col Color; * Define the game's name (displayed in the window title). */ -#define GAME_NAME "Independent Study v.0.6 alpha - NOW WITH more c++" +#define GAME_NAME "Independent Study v0.7 alpha - NOW WITH lights and snow and stuff" /** * The desired width of the game window. @@ -176,6 +176,7 @@ extern float VOLUME_SFX; */ #define DEBUG_printf( message, ...) DEBUG_prints(__FILE__, __LINE__, message, __VA_ARGS__ ) +#define C(x) std::cout << x << std::endl; /** * Defines pi for calculations that need it. diff --git a/include/config.h b/include/config.h index 4d56d9c..e2f7239 100644 --- a/include/config.h +++ b/include/config.h @@ -1,14 +1,10 @@ #ifndef CONFIG_H #define CONFIG_H -#include <iostream> -#include <SDL2/SDL_mixer.h> -#include <tinyxml2.h> +namespace config { + void read( void ); + void update( void ); + void save( void ); +} -void readConfig(void); - -void updateConfig(void); - -void saveConfig(); - -#endif //CONFIG_H \ No newline at end of file +#endif //CONFIG_H diff --git a/include/entities.h b/include/entities.h index 1250708..f455726 100644 --- a/include/entities.h +++ b/include/entities.h @@ -2,9 +2,9 @@ #define ENTITIES_H #include <common.h> -#include <Quest.h> +#include <quest.h> #include <inventory.h> -#include <Texture.h> +#include <texture.h> #include <sstream> @@ -14,7 +14,7 @@ #define Structurep(n) ((Structures *)n) #define Mobp(n) ((Mob *)n) -#define PLAYER_INV_SIZE 30 // The size of the player's inventory +#define PLAYER_INV_SIZE 43 // The size of the player's inventory #define NPC_INV_SIZE 3 // Size of an NPC's inventory enum _TYPE { diff --git a/include/inventory.h b/include/inventory.h index 7369642..08a145e 100644 --- a/include/inventory.h +++ b/include/inventory.h @@ -4,7 +4,7 @@ #include <common.h> #include <string.h> -#include <Texture.h> +#include <texture.h> #define DEBUG diff --git a/include/quest.h b/include/quest.h new file mode 100644 index 0000000..4da38bf --- /dev/null +++ b/include/quest.h @@ -0,0 +1,66 @@ +/** @file Quest.h + * @brief The quest handling system. + * + * This file contains Quest and QuestHandler, used to manage quests inside the + * game. + */ + +#ifndef QUEST_H +#define QUEST_H + +#include <string> + +#include <inventory.h> + +/** + * When defined, DEBUG allows extra messages to be printed to the terminal for + * debugging purposes. + */ + +#define DEBUG + +typedef struct { + std::string title; + std::string desc; + struct item_t reward; + std::vector<std::pair<std::string,int>> need; +} Quest; + +/** + * The Quest Handler class. + * + * This class handles quests, including the assigning, dropping, and completing + * of the quests. + */ + +class QuestHandler { +public: + std::vector<Quest>current; + + /** + * Adds a quest to the current quest vector by its title. + */ + + int assign(std::string title,std::string desc,std::string req); + + /** + * Drops a quest through its title. + */ + + int drop(std::string title); + + /** + * Finishes a quest through it's title, also giving a pointer to the Entity + * that gave the quest originally. + */ + + int finish(std::string t); + + /** + * Returns true if this handler is currently taking the quest. + */ + + bool hasQuest(std::string t); +}; + +#endif // QUEST_H diff --git a/include/texture.h b/include/texture.h new file mode 100644 index 0000000..816a8bf --- /dev/null +++ b/include/texture.h @@ -0,0 +1,103 @@ +/** @file Texture.h + * @brief Defines a method for loading textures. + * + * This file gives facilities for easily loading and binding textures. + */ + +#ifndef TEXTURE_H +#define TEXTURE_H + +#include <common.h> + +/** + * When defined, DEBUG allows extra messages to be printed to the terminal for + * debugging purposes. + */ + +#define DEBUG + +/** + * Texture functions are given a namespace for better organization. + */ + +namespace Texture { + + /** + * Loads a texture from the given file name, returning the GLuint used for + * later referencing of the texture. + */ + + GLuint loadTexture(std::string fileName); + + void freeTextures(void); + + void initColorIndex(); + vec2 getIndex(Color c); + dim2 imageDim(std::string fileName); +} + +/** + * The Texturec class. + * + * This class can handle an array of textures and allows easy binding of those + * textures. + */ + +class Texturec{ +private: + + /** + * Contains the index in the image array of the currently loaded texture. + */ + + unsigned int texState; + +public: + + /** + * Contains an array of the GLuints returned from Texture::loadTexture(). + */ + + std::vector<GLuint> image; + + /** + * Populates the image array from a list of strings, with each string as a + * separate argument. + */ + + Texturec(uint amt, ...); + + /** + * Populates the image array from an array of strings. + */ + + 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. + */ + + ~Texturec(); + + /** + * Binds the next texture in the array, incrementing texState. + */ + + void bindNext(); + + /** + * Binds the previous texture in the array, decrementing texState. + */ + + void bindPrev(); + + /** + * Binds the texture with the provided index. + */ + + void bind(unsigned int); +}; + +#endif //TEXTURE_H diff --git a/include/world.h b/include/world.h index 0b87134..f730715 100644 --- a/include/world.h +++ b/include/world.h @@ -165,7 +165,7 @@ protected: * World::detect(), which is why it is declared private. */ - void singleDetect( Entity *e ); + virtual void singleDetect( Entity *e ); /** * Empties all entity vectors. @@ -386,7 +386,7 @@ public: * half-width to positive half-width. */ - virtual void generate(unsigned int width); + void generate(unsigned int width); /** * Sets the background theme, collecting the required textures into a @@ -482,11 +482,18 @@ public: */ class IndoorWorld : public World { +private: + + std::vector<std::vector<float>> floor; + + void singleDetect( Entity *e ); + public: IndoorWorld(void); ~IndoorWorld(void); - void generate(unsigned int width); // Generates a flat world of width 'width' + void addFloor( unsigned int width ); + void draw(Player *p); // Draws the world (ignores layers) }; diff --git a/main.cpp b/main.cpp index f4a0005..4140ac7 100644 --- a/main.cpp +++ b/main.cpp @@ -243,8 +243,10 @@ int main(int argc, char *argv[]){ std::cout << "SDL_mixer could not initialize! Error: " << Mix_GetError() << std::endl; return -1; } + Mix_AllocateChannels(8); - updateConfig(); + + config::update(); // Run Mix_Quit when main returns atexit(Mix_Quit); @@ -253,7 +255,7 @@ int main(int argc, char *argv[]){ * Load saved settings into the game (see config/settings.xml) */ - readConfig(); + config::read(); /* * Create a window for SDL to draw to. Most parameters are the default, except for the diff --git a/src/Quest.cpp b/src/Quest.cpp deleted file mode 100644 index 8f3c33b..0000000 --- a/src/Quest.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include <algorithm> - -#include <Quest.h> -#include <entities.h> - -extern Player *player; - -int QuestHandler::assign(std::string title,std::string desc,std::string req){ - Quest tmp; - char *tok; - - tmp.title = title; - tmp.desc = desc; - - std::unique_ptr<char[]> buf (new char[req.size()]); - - strcpy(buf.get(),req.c_str()); - tok = strtok(buf.get(),"\n\r\t,"); - tmp.need.push_back({"\0",0}); - - while(tok){ - if(tmp.need.back().name != "\0"){ - tmp.need.back().n = atoi(tok); - tmp.need.push_back({"\0",0}); - }else - tmp.need.back().name = tok; - - tok = strtok(NULL,"\n\r\t,"); - } - - tmp.need.pop_back(); - current.push_back(tmp); - - return 0; -} - -int QuestHandler::drop(std::string title){ - 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 ( 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 : (*c).need ) - player->inv->takeItem( n.name, n.n ); - - current.erase( c ); - return 1; - } - } - - return 0; -} - -bool QuestHandler::hasQuest(std::string t){ - for ( auto &c : current ) { - if ( c.title == t ) - return true; - } - - return false; -} diff --git a/src/Texture.cpp b/src/Texture.cpp deleted file mode 100644 index 1ae5567..0000000 --- a/src/Texture.cpp +++ /dev/null @@ -1,215 +0,0 @@ -#include <algorithm> -#include <string> - -#include <Texture.h> - -/** - * 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 { - Color color; - int indexx; - int indexy; -}; - -/** - * 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(std::string fileName){ - SDL_Surface *image; - GLuint object = 0; - - // 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.c_str()); -#endif // DEBUG - - return t.tex; - } - } - - // load SDL_surface of texture - if(!(image = IMG_Load(fileName.c_str()))) - return 0; - -#ifdef DEBUG - 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); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Sets the "min" filter - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // The the "max" filter of the stack - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // Wrap the texture to the matrix - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // - - glTexImage2D(GL_TEXTURE_2D, // Sets the texture to the image file loaded above - 0, - GL_RGBA, - image->w, - image->h, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - image->pixels - ); - - // add texture to LoadedTexture - LoadedTexture.push_back(texture_t{fileName,object,{image->w,image->h}}); - - // free the SDL_Surface - SDL_FreeSurface(image); - - return object; - } - - dim2 imageDim(std::string fileName){ - for(auto &t : LoadedTexture){ - if(t.name == fileName) - return t.dim; - } - return {0,0}; - } - - void freeTextures(void){ - while(!LoadedTexture.empty()){ - glDeleteTextures(1, &LoadedTexture.back().tex); - LoadedTexture.pop_back(); - } - } - - #define CINDEX_WIDTH (8*4*3) - void initColorIndex(){ - unsigned int i; - GLubyte *buffer; - GLfloat *bufferf; - - buffer = new GLubyte[CINDEX_WIDTH]; - bufferf = new GLfloat[CINDEX_WIDTH]; - - colorIndex = loadTexture("assets/colorIndex.png"); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, colorIndex); - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer); - - for(i = 0; i < CINDEX_WIDTH; i++) - bufferf[i] = (float)buffer[i] / 255.0f; - - i = 0; - for(unsigned int y = 0; y < 8; y++){ - for(unsigned int x = 0; x < 4; x++){ - if(i >= CINDEX_WIDTH){ - delete[] buffer; - delete[] bufferf; - return; - } - pixels[y][x].red = buffer[i++]; - pixels[y][x].green = buffer[i++]; - pixels[y][x].blue = buffer[i++]; - } - } - delete[] buffer; - delete[] bufferf; - } - - //sqrt((255-145)^2+(90-145)^2+(0-0)^2); - std::vector<index_t>ind; - vec2 getIndex(Color c){ - for(auto &i : ind){ - if(c.red == i.color.red && c.green == i.color.green && c.blue == i.color.blue){ - //std::cout << float(i.indexy) << "," << float(i.indexx) << std::endl; - return {float(i.indexx), float(i.indexy)}; - } - } - uint buf[2]; - float buff = 999; - float shit = 999; - for(uint y = 0; y < 8; y++){ - for(uint x = 0; x < 4; x++){ - //std::cout << y << "," << x << ":" << pixels[y][x].red << "," << pixels[y][x].green << "," << pixels[y][x].blue << std::endl; - buff = sqrt(pow((pixels[y][x].red- c.red), 2)+ - pow((pixels[y][x].green-c.green),2)+ - pow((pixels[y][x].blue- c.blue), 2)); - //std::cout << buff << std::endl; - if(buff < shit){ - shit = buff; - buf[0] = y; - buf[1] = x; - } - // - //std::cout << shit << std::endl; - } - } - ind.push_back({c, (int)buf[1], (int)buf[0]}); - //std::cout << float(buf[1]) << ", " << float(buf[0]) << std::endl; - return {float(buf[1]),float(buf[0])}; - } -} - -Texturec::Texturec(uint amt, ...){ - va_list fNames; - texState = 0; - va_start(fNames, amt); - 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; - 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; - for(unsigned int i = 0; i < amt; i++) - image.push_back( Texture::loadTexture(paths[i]) ); -} - -Texturec::~Texturec(){ -} - -void Texturec::bind(unsigned int bn){ - texState = bn; - glBindTexture(GL_TEXTURE_2D,image[(int)texState]); -} - -void Texturec::bindNext(){ - bind(++texState); -} - -void Texturec::bindPrev(){ - bind(--texState); -} diff --git a/src/config.cpp b/src/config.cpp index 45bab3f..e076528 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -1,5 +1,10 @@ #include <config.h> +#include <iostream> + +#include <SDL2/SDL_mixer.h> + +#include <tinyxml2.h> #include <ui.h> using namespace tinyxml2; @@ -17,55 +22,57 @@ XMLDocument xml; XMLElement *scr; XMLElement *vol; -void readConfig(){ - unsigned int uval; - float fval; - bool bval; - - xml.LoadFile("config/settings.xml"); - scr = xml.FirstChildElement("screen"); - - if(scr->QueryUnsignedAttribute("width",&uval) == XML_NO_ERROR) - SCREEN_WIDTH = uval; - else SCREEN_WIDTH = 1280; - if(scr->QueryUnsignedAttribute("height",&uval) == XML_NO_ERROR) - SCREEN_HEIGHT = uval; - else SCREEN_HEIGHT = 800; - if(scr->QueryBoolAttribute("fullscreen",&bval) == XML_NO_ERROR) - FULLSCREEN = bval; - else FULLSCREEN = false; - if(xml.FirstChildElement("hline")->QueryUnsignedAttribute("size",&uval) == XML_NO_ERROR) - HLINE = uval; - else HLINE = 3; - - vol = xml.FirstChildElement("volume"); - - if(vol->FirstChildElement("master")->QueryFloatAttribute("volume",&fval) == XML_NO_ERROR) - VOLUME_MASTER = fval; - else VOLUME_MASTER = 50; - if(vol->FirstChildElement("music")->QueryFloatAttribute("volume",&fval) == XML_NO_ERROR) - VOLUME_MUSIC = fval; - else VOLUME_MUSIC = 50; - if(vol->FirstChildElement("sfx")->QueryFloatAttribute("volume",&fval) == XML_NO_ERROR) - VOLUME_SFX = fval; - else VOLUME_SFX = 50; - - ui::initFonts(); - ui::setFontFace(xml.FirstChildElement("font")->Attribute("path")); - updateConfig(); -} +namespace config { -void updateConfig(){ + void read( void ) { + unsigned int uval; + float fval; + bool bval; - Mix_Volume(0,VOLUME_MASTER); - Mix_Volume(1,VOLUME_SFX * (VOLUME_MASTER/100.0f)); - Mix_VolumeMusic(VOLUME_MUSIC * (VOLUME_MASTER/100.0f)); -} + xml.LoadFile("config/settings.xml"); + scr = xml.FirstChildElement("screen"); + + if(scr->QueryUnsignedAttribute("width",&uval) == XML_NO_ERROR) + SCREEN_WIDTH = uval; + else SCREEN_WIDTH = 1280; + if(scr->QueryUnsignedAttribute("height",&uval) == XML_NO_ERROR) + SCREEN_HEIGHT = uval; + else SCREEN_HEIGHT = 800; + if(scr->QueryBoolAttribute("fullscreen",&bval) == XML_NO_ERROR) + FULLSCREEN = bval; + else FULLSCREEN = false; + if(xml.FirstChildElement("hline")->QueryUnsignedAttribute("size",&uval) == XML_NO_ERROR) + HLINE = uval; + else HLINE = 3; + + vol = xml.FirstChildElement("volume"); + + if(vol->FirstChildElement("master")->QueryFloatAttribute("volume",&fval) == XML_NO_ERROR) + VOLUME_MASTER = fval; + else VOLUME_MASTER = 50; + if(vol->FirstChildElement("music")->QueryFloatAttribute("volume",&fval) == XML_NO_ERROR) + VOLUME_MUSIC = fval; + else VOLUME_MUSIC = 50; + if(vol->FirstChildElement("sfx")->QueryFloatAttribute("volume",&fval) == XML_NO_ERROR) + VOLUME_SFX = fval; + else VOLUME_SFX = 50; + + ui::initFonts(); + ui::setFontFace(xml.FirstChildElement("font")->Attribute("path")); + config::update(); + } + + void update( void ) { + Mix_Volume(0,VOLUME_MASTER); + Mix_Volume(1,VOLUME_SFX * (VOLUME_MASTER/100.0f)); + Mix_VolumeMusic(VOLUME_MUSIC * (VOLUME_MASTER/100.0f)); + } -void saveConfig(){ - vol->FirstChildElement("master")->SetAttribute("volume",VOLUME_MASTER); - vol->FirstChildElement("music")->SetAttribute("volume",VOLUME_MUSIC); - vol->FirstChildElement("sfx")->SetAttribute("volume", VOLUME_SFX); + void save( void ) { + vol->FirstChildElement("master")->SetAttribute("volume",VOLUME_MASTER); + vol->FirstChildElement("music")->SetAttribute("volume",VOLUME_MUSIC); + vol->FirstChildElement("sfx")->SetAttribute("volume", VOLUME_SFX); - xml.SaveFile("config/settings.xml", false); + xml.SaveFile("config/settings.xml", false); + } } diff --git a/src/gameplay.cpp b/src/gameplay.cpp index 075aec3..3c98461 100644 --- a/src/gameplay.cpp +++ b/src/gameplay.cpp @@ -212,13 +212,13 @@ CONT: void commonPageFunc( Mob *callee ) { static bool lock = false; - + if ( !lock ) { lock = true; - + ui::drawPage( callee->heyid ); ui::waitForDialog(); - + callee->alive = false; lock = false; } diff --git a/src/inventory.cpp b/src/inventory.cpp index 7ba5909..d9ff756 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -9,9 +9,8 @@ extern Player *player; extern GLuint invUI; static float hangle = 0.0f; static bool swing = false; -//static float xc,yc; static vec2 itemLoc; -static const unsigned char numSlot = 7; +static const unsigned int numSlot = 2000; Mix_Chunk* swordSwing; static std::vector<Item *> itemMap; @@ -190,7 +189,6 @@ void Inventory::setSelectionDown(){ void Inventory::draw(void){ static unsigned int lop = 0; - //const unsigned int numSlot = 7; static std::vector<int>dfp(numSlot); static std::vector<Ray>iray(numSlot); static std::vector<vec2>curCoord(numSlot); diff --git a/src/quest.cpp b/src/quest.cpp new file mode 100644 index 0000000..ba35c40 --- /dev/null +++ b/src/quest.cpp @@ -0,0 +1,69 @@ +#include <algorithm> + +#include <quest.h> +#include <entities.h> + +extern Player *player; + +int QuestHandler::assign(std::string title,std::string desc,std::string req){ + Quest tmp; + char *tok; + + tmp.title = title; + tmp.desc = desc; + + tok = strtok( &req[0], "\n\r\t," ); + tmp.need.emplace_back( "", 0 ); + + while ( tok ) { + if ( !tmp.need.back().first.empty() ) { + tmp.need.back().second = atoi( tok ); + tmp.need.emplace_back( "", 0 ); + } else + tmp.need.back().first = tok; + + tok = strtok( NULL, "\n\r\t," ); + } + + tmp.need.pop_back(); + current.push_back( tmp ); + + return 0; +} + +int QuestHandler::drop(std::string title){ + 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 ( auto c = current.begin(); c != current.end(); c++ ) { + if ( (*c).title == t ) { + for ( auto &n : (*c).need ) { + if ( player->inv->hasItem( n.first ) < n.second ) + return 0; + } + + for ( auto &n : (*c).need ) + player->inv->takeItem( n.first, n.second ); + + current.erase( c ); + return 1; + } + } + + return 0; +} + +bool QuestHandler::hasQuest(std::string t){ + for ( auto &c : current ) { + if ( c.title == t ) + return true; + } + + return false; +} diff --git a/src/texture.cpp b/src/texture.cpp new file mode 100644 index 0000000..35d7b80 --- /dev/null +++ b/src/texture.cpp @@ -0,0 +1,215 @@ +#include <algorithm> +#include <string> + +#include <texture.h> + +/** + * 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 { + Color color; + int indexx; + int indexy; +}; + +/** + * 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(std::string fileName){ + SDL_Surface *image; + GLuint object = 0; + + // 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.c_str()); +#endif // DEBUG + + return t.tex; + } + } + + // load SDL_surface of texture + if(!(image = IMG_Load(fileName.c_str()))) + return 0; + +#ifdef DEBUG + 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); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Sets the "min" filter + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // The the "max" filter of the stack + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // Wrap the texture to the matrix + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // + + glTexImage2D(GL_TEXTURE_2D, // Sets the texture to the image file loaded above + 0, + GL_RGBA, + image->w, + image->h, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + image->pixels + ); + + // add texture to LoadedTexture + LoadedTexture.push_back(texture_t{fileName,object,{image->w,image->h}}); + + // free the SDL_Surface + SDL_FreeSurface(image); + + return object; + } + + dim2 imageDim(std::string fileName){ + for(auto &t : LoadedTexture){ + if(t.name == fileName) + return t.dim; + } + return {0,0}; + } + + void freeTextures(void){ + while(!LoadedTexture.empty()){ + glDeleteTextures(1, &LoadedTexture.back().tex); + LoadedTexture.pop_back(); + } + } + + #define CINDEX_WIDTH (8*4*3) + void initColorIndex(){ + unsigned int i; + GLubyte *buffer; + GLfloat *bufferf; + + buffer = new GLubyte[CINDEX_WIDTH]; + bufferf = new GLfloat[CINDEX_WIDTH]; + + colorIndex = loadTexture("assets/colorIndex.png"); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, colorIndex); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer); + + for(i = 0; i < CINDEX_WIDTH; i++) + bufferf[i] = (float)buffer[i] / 255.0f; + + i = 0; + for(unsigned int y = 0; y < 8; y++){ + for(unsigned int x = 0; x < 4; x++){ + if(i >= CINDEX_WIDTH){ + delete[] buffer; + delete[] bufferf; + return; + } + pixels[y][x].red = buffer[i++]; + pixels[y][x].green = buffer[i++]; + pixels[y][x].blue = buffer[i++]; + } + } + delete[] buffer; + delete[] bufferf; + } + + //sqrt((255-145)^2+(90-145)^2+(0-0)^2); + std::vector<index_t>ind; + vec2 getIndex(Color c){ + for(auto &i : ind){ + if(c.red == i.color.red && c.green == i.color.green && c.blue == i.color.blue){ + //std::cout << float(i.indexy) << "," << float(i.indexx) << std::endl; + return {float(i.indexx), float(i.indexy)}; + } + } + uint buf[2]; + float buff = 999; + float shit = 999; + for(uint y = 0; y < 8; y++){ + for(uint x = 0; x < 4; x++){ + //std::cout << y << "," << x << ":" << pixels[y][x].red << "," << pixels[y][x].green << "," << pixels[y][x].blue << std::endl; + buff = sqrt(pow((pixels[y][x].red- c.red), 2)+ + pow((pixels[y][x].green-c.green),2)+ + pow((pixels[y][x].blue- c.blue), 2)); + //std::cout << buff << std::endl; + if(buff < shit){ + shit = buff; + buf[0] = y; + buf[1] = x; + } + // + //std::cout << shit << std::endl; + } + } + ind.push_back({c, (int)buf[1], (int)buf[0]}); + //std::cout << float(buf[1]) << ", " << float(buf[0]) << std::endl; + return {float(buf[1]),float(buf[0])}; + } +} + +Texturec::Texturec(uint amt, ...){ + va_list fNames; + texState = 0; + va_start(fNames, amt); + 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; + 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; + for(unsigned int i = 0; i < amt; i++) + image.push_back( Texture::loadTexture(paths[i]) ); +} + +Texturec::~Texturec(){ +} + +void Texturec::bind(unsigned int bn){ + texState = bn; + glBindTexture(GL_TEXTURE_2D,image[(int)texState]); +} + +void Texturec::bindNext(){ + bind(++texState); +} + +void Texturec::bindPrev(){ + bind(--texState); +} diff --git a/src/ui.cpp b/src/ui.cpp index c646458..69fe1bf 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -99,7 +99,7 @@ static GLuint pageTex = 0; void Menu::gotoParent(){ if(parent == NULL){ currentMenu = NULL; - updateConfig(); + config::update(); }else{ currentMenu = parent; } @@ -881,8 +881,8 @@ namespace ui { dialogBoxExists = false; currentMenu = NULL; gameRunning = false; - updateConfig(); - saveConfig(); + config::update(); + config::save(); } menuItem createButton(vec2 l, dim2 d, Color c, const char* t, menuFunc f){ @@ -955,7 +955,7 @@ namespace ui { void drawMenu(Menu *menu){ setFontSize(24); - updateConfig(); + config::update(); SDL_Event e; mouse.x=premouse.x+offset.x-(SCREEN_WIDTH/2); @@ -1311,13 +1311,20 @@ EXIT: if ( ( e.button.button & SDL_BUTTON_LEFT ) && !dialogBoxExists ) player->inv->usingi = true; - for ( auto &e : currentWorld->entity ) { - if( mouse.x > e->loc.x && mouse.x < e->loc.x + e->width && - mouse.y > e->loc.y && mouse.y < e->loc.y + e->height ) { - e->vel.y = .05; - fr = mouse; - ig = e; - break; + if( mouse.x > player->loc.x && mouse.x < player->loc.x + player->width && + mouse.y > player->loc.y && mouse.y < player->loc.y + player->height ) { + player->vel.y = .05; + fr = mouse; + ig = player; + } else { + for ( auto &e : currentWorld->entity ) { + if( mouse.x > e->loc.x && mouse.x < e->loc.x + e->width && + mouse.y > e->loc.y && mouse.y < e->loc.y + e->height ) { + e->vel.y = .05; + fr = mouse; + ig = e; + break; + } } } diff --git a/src/world.cpp b/src/world.cpp index d8fd2d3..623c1c2 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -17,7 +17,8 @@ using namespace tinyxml2; * Defines the height of the floor in an IndoorWorld. */ -#define INDOOR_FLOOR_HEIGHT 100 +#define INDOOR_FLOOR_THICKNESS 50 +#define INDOOR_FLOOR_HEIGHTT 400 /** * Gravity thing @@ -316,21 +317,19 @@ update( Player *p, unsigned int delta ) // update entity coords for ( auto &e : entity ) { - e->loc.y += e->vel.y * delta; // dont let structures move? - if ( e->type == STRUCTURET ) - e->canMove = true; - - if ( e->canMove ) { + if ( e->type != STRUCTURET && e->canMove ) { e->loc.x += e->vel.x * delta; + e->loc.y += e->vel.y * delta; // update boolean directions if ( e->vel.x < 0 ) e->left = true; else if ( e->vel.x > 0 ) e->left = false; - } + } else if ( e->vel.y < 0 ) + e->loc.y += e->vel.y * delta; } // iterate through particles particles.erase( std::remove_if( particles.begin(), particles.end(), [&delta](Particles &part){return part.kill(delta);}), particles.end()); @@ -1250,41 +1249,63 @@ IndoorWorld::~IndoorWorld(void){ deleteEntities(); } -void IndoorWorld::generate(unsigned int width){ // Generates a flat area of width 'width' - lineCount=width+GROUND_HILLINESS; // Sets line count to the desired width plus GEN_INC to remove incorrect line calculations. - if(lineCount<=0)abort(); +void IndoorWorld:: +addFloor( unsigned int width ) +{ + if ( floor.empty() ) + generate( width ); + floor.emplace_back( width, floor.size() * INDOOR_FLOOR_HEIGHTT + INDOOR_FLOOR_THICKNESS ); +} - worldData = std::vector<WorldData> (lineCount, WorldData { false, {0,0}, INDOOR_FLOOR_HEIGHT, 0 }); +void IndoorWorld:: +singleDetect( Entity *e ) +{ + if ( !e->alive ) + return; + if ( e->type == MOBT && Mobp(e)->subtype == MS_TRIGGER ) + return; + + for ( auto &f : floor ) { + if ( f[0] + INDOOR_FLOOR_HEIGHTT < e->loc.y ) { + C("floor"); + if ( e->loc.y < f[0] ) { + e->loc.y = f[0]; + e->vel.y = 0; + e->ground = true; + } else if ( e->vel.y > -2 ) + e->vel.y -= GRAVITY_CONSTANT * deltaTime; + break; + } + } + + if(e->loc.x < worldStart){ // Left bound + e->vel.x=0; + e->loc.x=(float)worldStart + HLINE / 2; + }else if(e->loc.x + e->width + HLINE > worldStart + worldStart * -2){ // Right bound + e->vel.x=0; + e->loc.x=worldStart + worldStart * -2 - e->width - HLINE; + } - worldStart = (width - GROUND_HILLINESS) * HLINE / 2 * -1; } -void IndoorWorld::draw(Player *p){ - unsigned int i,ie; - //int j,x,v_offset; +void IndoorWorld:: +draw( Player *p ) +{ + unsigned int i; int x; - /* - * Draw the background. - */ - - //glEnable(GL_TEXTURE_2D); - - for(auto &l : light){ - if(l.belongsTo){ - l.loc.x = l.following->loc.x + SCREEN_WIDTH/2; + // draw lights + for ( auto &l : light ) { + if ( l.belongsTo ) { + l.loc.x = l.following->loc.x + SCREEN_WIDTH / 2; l.loc.y = l.following->loc.y; } - if(l.flame){ - l.fireFlicker = .9+((rand()%2)/10.0f); - l.fireLoc.x = l.loc.x + (rand()%2-1)*3; - l.fireLoc.y = l.loc.y + (rand()%2-1)*3; - - //std::cout << l.fireLoc.x << "," << l.fireLoc.y << std::endl; - //std::cout << l.loc.x << "," << l.loc.y << std::endl << std::endl; - }else{ + if ( l.flame ) { + l.fireFlicker = .9 + ( (rand() % 2) / 10.0f ); + l.fireLoc.x = l.loc.x + (rand() % 2 - 1) * 3; + l.fireLoc.y = l.loc.y + (rand() % 2 - 1) * 3; + } else l.fireFlicker = 1.0f; - } } std::unique_ptr<GLfloat[]> pointArrayBuf = std::make_unique<GLfloat[]> (2 * (light.size())); @@ -1301,9 +1322,8 @@ void IndoorWorld::draw(Player *p){ } } - for(i = 0; i < light.size(); i++){ + for(i = 0; i < light.size(); i++) flameArray[i] = light[i].fireFlicker; - } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); @@ -1312,7 +1332,7 @@ void IndoorWorld::draw(Player *p){ glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0); glUniform1f(glGetUniformLocation(shaderProgram, "amb" ), 0.02f + light.size()/50.0f); - if ( light.size() == 0) + if ( light.empty() ) glUniform1i(glGetUniformLocation(shaderProgram, "numLight"), 0); else { glUniform1i (glGetUniformLocation(shaderProgram, "numLight" ), light.size()); @@ -1321,53 +1341,38 @@ void IndoorWorld::draw(Player *p){ glUniform1fv(glGetUniformLocation(shaderProgram, "fireFlicker"), light.size(), flameArray); } - //delete[] flameArray; - bgTex->bind(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 glColor4ub(255,255,255,255); - 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); - //glDisable(GL_TEXTURE_2D); - - /* - * Calculate the starting and ending points to draw the ground from. - */ - - /*v_offset = (p->loc.x - x_start) / HLINE; - j = v_offset - (SCREEN_WIDTH / 2 / HLINE) - GEN_INC; - if(j < 0)j = 0; - i = j; - - ie = v_offset + (SCREEN_WIDTH / 2 / HLINE) - GEN_INC; - if(ie > lineCount)ie = lineCount;*/ + 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(); - i = 0; - ie = lineCount; + glUseProgram(0); /* * Draw the ground. */ - glUseProgram(shaderProgram); - glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0); - glBegin(GL_QUADS); - for(;i < ie - GROUND_HILLINESS;i++){ - safeSetColor(150,100,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); - } + + glUseProgram( shaderProgram ); + glUniform1i( glGetUniformLocation(shaderProgram, "sampler"), 0 ); + glBegin( GL_QUADS ); + safeSetColor( 150, 100, 50 ); + for ( auto &f : floor ) { + i = 0; + for ( h : f ) { + x = worldStart + i++ * HLINE; + glVertex2i( x , h ); + glVertex2i( x + HLINE, h ); + glVertex2i( x + HLINE, h - INDOOR_FLOOR_THICKNESS ); + glVertex2i( x , h - INDOOR_FLOOR_THICKNESS ); + } + } glEnd(); glUseProgram(0); @@ -1533,14 +1538,9 @@ loadWorldFromXMLNoSave( std::string path ) { tmp->setBackground((WorldBGType)wxml->UnsignedAttribute("background")); tmp->setBGM(wxml->StrAttribute("bgm")); } else if ( name == "generation" ) { - if(!strcmp(wxml->Attribute("type"),"Random")){ - if(Indoor) - ((IndoorWorld *)tmp)->generate(wxml->UnsignedAttribute("width")); - else { - - tmp->generate(wxml->UnsignedAttribute("width")); - } - }else if(Indoor) + if ( !Indoor && !strcmp(wxml->Attribute("type"),"Random") ) + tmp->generate(wxml->UnsignedAttribute("width")); + else if ( Indoor ) abort(); } else if ( name == "mob" ) { unsigned int type; @@ -1588,9 +1588,11 @@ loadWorldFromXMLNoSave( std::string path ) { tmp->mob.back()->heyid = wxml->Attribute("id"); } else if ( name == "hill" ) { tmp->addHill( ivec2 { wxml->IntAttribute("peakx"), wxml->IntAttribute("peaky") }, wxml->UnsignedAttribute("width") ); - } else if ( name == "time") { - tickCount = std::stoi( wxml->GetText() ); - } + } else if ( name == "time" ) { + tickCount = std::stoi( wxml->GetText() ); + } else if ( Indoor && name == "floor" ) { + ((IndoorWorld *)tmp)->addFloor( wxml->UnsignedAttribute("width") ); + } wxml = wxml->NextSiblingElement(); } diff --git a/xml/playerSpawnHill1.xml b/xml/playerSpawnHill1.xml index d3b5db4..a67a932 100644 --- a/xml/playerSpawnHill1.xml +++ b/xml/playerSpawnHill1.xml @@ -18,7 +18,7 @@ <village name="Scrub Lawd"> <structure type="0" x="-300" inside="playerSpawnHill1_Building1.xml"/> - <structure type="5" x="-500" inside="playerSpawnHill1_Building1.xml"/> + <structure type="5" x="-500" /> <stall type="market" texture="assets/style/classic/stall.png"> <buy item="Dank MayMay" cost="420"/> <sell item="Dank MayMay" cost="666"/> diff --git a/xml/playerSpawnHill1_Building1.xml b/xml/playerSpawnHill1_Building1.xml index f0c8a21..8fad154 100644 --- a/xml/playerSpawnHill1_Building1.xml +++ b/xml/playerSpawnHill1_Building1.xml @@ -1,9 +1,12 @@ <?xml version="1.0"?> <IndoorWorld> <style background="1" bgm="assets/music/theme_jazz.wav" /> - <generation type="Random" width="300" /> - <npc name="Bob" hasDialog="true" /> + <floor width="300"> + <npc name="Bob" hasDialog="true" /> + </floor> + + <floor width="200" /> </IndoorWorld> -- cgit v1.2.3