diff options
author | Clyne Sullivan <tullivan99@gmail.com> | 2019-02-25 18:47:55 -0500 |
---|---|---|
committer | Clyne Sullivan <tullivan99@gmail.com> | 2019-02-25 18:47:55 -0500 |
commit | d7bae41fab5570bdac547a46463974adb4723f96 (patch) | |
tree | 37b0567300f2e3d0a74ceae5861272f4ff970558 | |
parent | 58774909a78f06b8de3cb60e2f010e8ceccbf3a6 (diff) |
mem leak patches; world ground from image
-rw-r--r-- | assets/testground.png | bin | 0 -> 6902 bytes | |||
-rw-r--r-- | include/systems/light.hpp | 5 | ||||
-rw-r--r-- | include/systems/movement.hpp | 22 | ||||
-rw-r--r-- | include/texture.hpp | 15 | ||||
-rw-r--r-- | include/world.hpp | 7 | ||||
-rw-r--r-- | src/systems/light.cpp | 28 | ||||
-rw-r--r-- | src/systems/movement.cpp | 24 | ||||
-rw-r--r-- | src/texture.cpp | 54 | ||||
-rw-r--r-- | src/world.cpp | 235 | ||||
-rw-r--r-- | xml/!town.xml | 18 | ||||
-rw-r--r-- | xml/bobshouse.xml | 18 |
11 files changed, 166 insertions, 260 deletions
diff --git a/assets/testground.png b/assets/testground.png Binary files differnew file mode 100644 index 0000000..1d79cad --- /dev/null +++ b/assets/testground.png diff --git a/include/systems/light.hpp b/include/systems/light.hpp index ba91113..02c7eed 100644 --- a/include/systems/light.hpp +++ b/include/systems/light.hpp @@ -21,6 +21,11 @@ class LightSystem : public entityx::System<LightSystem> { private: static std::vector<Light> lights; + static GLfloat *colorData; + static GLfloat *coordData; + + static void resizeLights(void); + public: void update(entityx::EntityManager& en, entityx::EventManager& ev, entityx::TimeDelta dt) override; diff --git a/include/systems/movement.hpp b/include/systems/movement.hpp index fd37665..745fa9b 100644 --- a/include/systems/movement.hpp +++ b/include/systems/movement.hpp @@ -2,10 +2,32 @@ #define SYSTEM_MOVEMENT_HPP_ #include <entityx/entityx.h> +#include <attack.hpp> class MovementSystem : public entityx::System<MovementSystem> { +private: + constexpr static const char *hitPlayerScript = "\ + effect = function()\n \ + flash(255, 0, 0)\n \ + damage(1)\n \ + end\n \ + hit = function()\n \ + xrange = 5\n \ + end"; + static LuaScript hitPlayer; + static Attack playerAttack; + public: + MovementSystem(void) { + hitPlayer = LuaScript(hitPlayerScript); + AttackSystem::initLua(hitPlayer); + playerAttack = { vec2(), vec2(5, 5), vec2(), vec2(), + hitPlayer, TextureIterator() }; + } + void update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) override; + + static int doAttack(lua_State *); }; #endif // SYSTEM_MOVEMENT_HPP_ diff --git a/include/texture.hpp b/include/texture.hpp index d4bcfa9..db16357 100644 --- a/include/texture.hpp +++ b/include/texture.hpp @@ -174,4 +174,19 @@ public: */ void unloadTextures(void); +class ObjectTexture : public Texture { +private: + std::vector<bool> solidMap; + bool valid; + +public: + ObjectTexture(const std::string filename = ""); + + int getHeight(int index); + bool isInsideObject(vec2 coord) const; + inline bool isValid(void) { + return valid; + } +}; + #endif //TEXTURE_HPP_ diff --git a/include/world.hpp b/include/world.hpp index 0bfe078..d53a40b 100644 --- a/include/world.hpp +++ b/include/world.hpp @@ -69,7 +69,7 @@ constexpr const unsigned int INDOOR_FLOOR_HEIGHT = (INDOOR_FLOOR_HEIGHTT + INDOO struct WorldData2 { // Data variables - std::vector<WorldData> data; /**< The world's ground data. */ + ObjectTexture ground; float startX; /**< The furthest left coordinate of the world. */ // Indoor variables @@ -125,8 +125,6 @@ private: static std::vector<vec2> stars; - static int getLineIndex(float x); - public: static std::thread thAmbient; @@ -159,7 +157,8 @@ public: static void goWorldRight(Position& p, Solid &d); static void goWorldPortal(Position& p); - static void generate(LuaScript& script); + static void generate(const char *file); + static float getGroundHeight(float x); static bool save(void); static void load(const std::string& file); diff --git a/src/systems/light.cpp b/src/systems/light.cpp index 51a6702..b7c62aa 100644 --- a/src/systems/light.cpp +++ b/src/systems/light.cpp @@ -6,6 +6,17 @@ std::vector<Light> LightSystem::lights; +GLfloat *LightSystem::colorData = nullptr; +GLfloat *LightSystem::coordData = nullptr; + +void LightSystem::resizeLights(void) +{ + delete colorData; + delete coordData; + colorData = new GLfloat[lights.size() * 4]; + coordData = new GLfloat[lights.size() * 4]; +} + void LightSystem::update(entityx::EntityManager& en, entityx::EventManager& ev, entityx::TimeDelta dt) { (void)ev; (void)dt; @@ -20,23 +31,20 @@ void LightSystem::update(entityx::EntityManager& en, entityx::EventManager& ev, } void LightSystem::render(void) { - auto coords = new GLfloat[lights.size() * 4]; - auto colors = new GLfloat[lights.size() * 4]; - unsigned int offset = 0; for (const auto& l : lights) { - coords[offset] = l.pos.x, coords[offset + 1] = l.pos.y, - coords[offset + 2] = -5, coords[offset + 3] = l.radius; - colors[offset] = l.color.red, colors[offset + 1] = l.color.green, - colors[offset + 2] = l.color.blue, colors[offset + 3] = 1.0f; + coordData[offset] = l.pos.x, coordData[offset + 1] = l.pos.y, + coordData[offset + 2] = -5, coordData[offset + 3] = l.radius; + colorData[offset] = l.color.red, colorData[offset + 1] = l.color.green, + colorData[offset + 2] = l.color.blue, colorData[offset + 3] = 1.0f; offset += 4; } Render::worldShader.use(); Render::worldShader.enable(); - glUniform4fv(Render::worldShader.uniform[WU_light], lights.size(), coords); - glUniform4fv(Render::worldShader.uniform[WU_light_color], lights.size(), colors); + glUniform4fv(Render::worldShader.uniform[WU_light], lights.size(), coordData); + glUniform4fv(Render::worldShader.uniform[WU_light_color], lights.size(), colorData); glUniform1i(Render::worldShader.uniform[WU_light_size], lights.size()); Render::worldShader.disable(); @@ -45,6 +53,7 @@ void LightSystem::render(void) { int LightSystem::addLight(vec2 pos, float radius, Color color) { lights.emplace_back(pos, radius, color); + resizeLights(); return lights.size() - 1; } @@ -56,5 +65,6 @@ void LightSystem::updateLight(int index, vec2 pos, float radius) { void LightSystem::removeLight(int index) { lights.erase(lights.begin() + index); + resizeLights(); } diff --git a/src/systems/movement.cpp b/src/systems/movement.cpp index 642fa6a..b2c95c5 100644 --- a/src/systems/movement.cpp +++ b/src/systems/movement.cpp @@ -10,11 +10,21 @@ #include <thread> -#include <attack.hpp> #include <events.hpp> #include <player.hpp> #include <ui.hpp> +LuaScript MovementSystem::hitPlayer; +Attack MovementSystem::playerAttack; + +int MovementSystem::doAttack(lua_State* s) +{ + vec2 pos (lua_tonumber(s, 1), lua_tonumber(s, 2)); + game::events.emit<AttackEvent>(AttackEvent(pos, + playerAttack, false)); + return 0; +} + void MovementSystem::update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) { //bool fight = false; @@ -72,18 +82,6 @@ void MovementSystem::update(entityx::EntityManager &en, entityx::EventManager &e } } - static auto doAttack = [](lua_State* s) -> int { - vec2 pos (lua_tonumber(s, 1), lua_tonumber(s, 2)); - LuaScript script ("effect = function()\nflash(255,0,0)\ndamage(1)\nend\n\ - hit = function()\nxrange = 5\nend"); - AttackSystem::initLua(script); - Attack attack = {vec2(), vec2(5, 5), vec2(), vec2(), - script, TextureIterator()}; - game::events.emit<AttackEvent>(AttackEvent(pos, - attack, false)); - return 0; - }; - // make the entity wander // TODO initialX and range? if (entity.has_component<Wander>()) { diff --git a/src/texture.cpp b/src/texture.cpp index 19aae3f..422f013 100644 --- a/src/texture.cpp +++ b/src/texture.cpp @@ -11,6 +11,60 @@ #include <error.hpp> #include <gif_lib.h> +ObjectTexture::ObjectTexture(const std::string filename) +{ + valid = !filename.empty(); + if (!valid) + return; + + auto image = IMG_Load(filename.c_str()); + + // format: RGBA8 + solidMap.resize(image->w * image->h); + auto rgba = ((uint8_t *)image->pixels) + 3; + auto iter = solidMap.begin(); + for (int i = 0; i < image->w * image->h; i++) { + *iter++ = *rgba > 0; + rgba += 4; + } + + GLuint object; + 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, 0, GL_RGBA, image->w, image->h, 0, + GL_RGBA, GL_UNSIGNED_BYTE, image->pixels); + + name = filename; + tex = object; + dim = vec2 {(float)image->w, (float)image->h}; + + // free the SDL_Surface + SDL_FreeSurface(image); +} + +int ObjectTexture::getHeight(int index) +{ + if (index < 0 || index > dim.x) + return 100; + + unsigned int h; + for (h = 0; h < dim.y; h++) { + if (solidMap[h * dim.x + index]) + return dim.y - h; + } + return 0; +} + +bool ObjectTexture::isInsideObject(vec2 coord) const { + coord /= 2; + return solidMap[(int)coord.y * (int)dim.x + (int)coord.x]; +} + namespace Colors { ColorTex white; diff --git a/src/world.cpp b/src/world.cpp index 0cfa725..a608384 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -54,45 +54,30 @@ WorldSystem::~WorldSystem(void) { } -int WorldSystem::getLineIndex(float x) +void WorldSystem::generate(const char *file) { - return std::clamp(static_cast<int>((x - world.startX) / game::HLINE), - 0, static_cast<int>(world.data.size())); -} - -void WorldSystem::generate(LuaScript& script) -{ - int i = 0; - world.data.clear(); - do { - float h, g[2]; - script("ground", {LuaVariable("height", h)}); - if (h == -1.0f) - break; - if (h > 5000) - h = 5000; - script("grass", {LuaVariable("height", g[0])}); - script("grass", {LuaVariable("height", g[1])}); - world.data.push_back(WorldData {true, {g[0], g[1]}, h, - static_cast<unsigned char>(randGet() % 32 / 8)}); - } while (++i); - - // define x-coordinate of world's leftmost 'line' - world.startX = HLINES(i * -0.5); + world.ground = ObjectTexture(file); + auto width = world.ground.getDim().x; + world.startX = width / -2; // gen. star coordinates if (stars.empty()) { stars.resize(game::SCREEN_WIDTH / 30); for (auto& s : stars) { - s.x = world.startX + (randGet() % (int)HLINES(i)); + s.x = world.startX + (randGet() % (int)width); s.y = game::SCREEN_HEIGHT - (randGet() % (int)HLINES(game::SCREEN_HEIGHT / 1.3f)); } } } +float WorldSystem::getGroundHeight(float x) +{ + return world.ground.getHeight((int)(x - world.startX)); +} + float WorldSystem::isAboveGround(const vec2& p) { - const auto& gh = world.data[getLineIndex(p.x)].groundHeight; + auto gh = getGroundHeight(p.x); return p.y >= gh ? 0 : gh; } @@ -255,8 +240,7 @@ void WorldSystem::loader(void) // world generation else if (tagName == "generation") { - LuaScript script (wxml->GetText()); - generate(script); + generate(wxml->GetText()); } // indoor stuff @@ -421,10 +405,8 @@ void WorldSystem::render(void) const vector2<int> backgroundOffset (static_cast<int>(SCREEN_WIDTH) / 2, static_cast<int>(SCREEN_HEIGHT) / 2); - int iStart, iEnd, pOffset; - // world width in pixels - int width = HLINES(world.data.size()); + int width = world.ground.getDim().x; static std::once_flag init; std::call_once(init, [&](void) { @@ -557,176 +539,30 @@ void WorldSystem::render(void) delete[] bgItems; } + vec2 dim; if (world.indoor) { world.indoorTex.use(); - auto dim = world.indoorTex.getDim() * game::HLINE; - GLfloat verts[] = { - world.startX, 0, z, 0, 0, - world.startX + dim.x, 0, z, 1, 0, - world.startX + dim.x, dim.y, z, 1, 1, - world.startX + dim.x, dim.y, z, 1, 1, - world.startX, dim.y, z, 0, 1, - world.startX, 0, z, 0, 0, - }; - - glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), verts); - glVertexAttribPointer(Render::worldShader.tex , 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), verts + 3); - glDrawArrays(GL_TRIANGLES, 0, 6); - } - - //glUniform1f(Render::worldShader.uniform[WU_light_impact], 0.075f + (0.2f * i)); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - - // get the line that the player is currently standing on - pOffset = (offset.x - world.startX) / game::HLINE; - - // only draw world within player vision - iStart = std::clamp(static_cast<int>(pOffset - (SCREEN_WIDTH / 2 / game::HLINE)), - 0, static_cast<int>(world.data.size())); - iEnd = std::clamp(static_cast<int>(pOffset + (SCREEN_WIDTH / 2 / game::HLINE) + 2), - 0, static_cast<int>(world.data.size())); - - // draw the dirt - waitToSwap = true; - - bgTex++; - z = Render::ZRange::Ground; - - static std::vector<GLfloat> dirt; - if (dirt.size() != world.data.size() * 30) { - dirt.clear(); - dirt.resize(world.data.size() * 30); - } - - GLfloat *dirtp = &dirt[0]; - for (int i = iStart; i < iEnd; i++) { - int ty = world.data[i].groundHeight / 64 + world.data[i].groundColor; - GLfloat five[5] = { - 0, 0, world.startX + HLINES(i), world.data[i].groundHeight, z - 0.1f - }; - - push5(dirtp, five); - five[0]++, five[2] += game::HLINE; - push5(dirtp, five); - five[1] += ty, five[3] = 0; - push5(dirtp, five); - push5(dirtp, five); - five[0]--, five[2] -= game::HLINE; - push5(dirtp, five); - five[1] = 0, five[3] = world.data[i].groundHeight; - push5(dirtp, five); - } - - glUniform1f(Render::worldShader.uniform[WU_light_impact], 0.45f); - - glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &dirt[2]); - glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &dirt[0]); - glDrawArrays(GL_TRIANGLES, 0 , dirt.size() / 5); - - Render::worldShader.disable(); - Render::worldShader.unuse(); - - bgTex++; - - static std::vector<GLfloat> grass; - if (grass.size() != world.data.size() * 60) { - grass.clear(); - grass.resize(world.data.size() * 60); - } - - GLfloat *grassp = &grass[0]; - for (int i = iStart; i < iEnd; i++) { - auto wd = world.data[i]; - auto gh = wd.grassHeight; - - // flatten the grass if the player is standing on it. - if (!world.indoor && !wd.grassUnpressed) { - gh[0] /= 4; - gh[1] /= 4; - } - - // actually draw the grass. - if (wd.groundHeight) { - float five[5] = { - 0, 1, world.startX + HLINES(i), wd.groundHeight + gh[0], z - 0.2f - }; - - push5(grassp, five); - five[0]++, five[1]--, five[2] += HLINES(0.5f); - push5(grassp, five); - five[1]++, five[3] = wd.groundHeight; - push5(grassp, five); - push5(grassp, five); - five[0]--, five[2] -= HLINES(0.5f); - push5(grassp, five); - five[1]--, five[3] = wd.groundHeight + gh[0]; - push5(grassp, five); - five[1]++; - - five[2] = world.startX + HLINES(i + 0.5), five[3] = wd.groundHeight + gh[1]; - - push5(grassp, five); - five[0]++, five[1]--, five[2] += HLINES(0.5f) + 1; - push5(grassp, five); - five[1]++, five[3] = wd.groundHeight; - push5(grassp, five); - push5(grassp, five); - five[0]--, five[2] -= HLINES(0.5f) + 1; - push5(grassp, five); - five[1]--, five[3] = wd.groundHeight + gh[1]; - push5(grassp, five); - } + dim = world.indoorTex.getDim(); + } else { + world.ground.use(); + dim = world.ground.getDim(); } - Render::worldShader.use(); - glUniform1f(Render::worldShader.uniform[WU_light_impact], 1.0f); - - Render::worldShader.enable(); - - glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &grass[2]); - glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &grass[0]); - glDrawArrays(GL_TRIANGLES, 0 , grass.size() / 5); - - // the starting pixel of the world - static const float s = -(static_cast<float>(SCREEN_WIDTH) / 2.0f); - // the ending pixel of the world - static const float e = static_cast<float>(SCREEN_WIDTH) / 2.0f; - static const float sheight = static_cast<float>(SCREEN_HEIGHT); - - auto yOffset = offset.y - static_cast<float>(SCREEN_HEIGHT) / 2.0f; - GLfloat blackBar[] = { - s, yOffset, z - 0.3f, 0.0f, 0.0f, - world.startX, yOffset, z - 0.3f, 1.0f, 0.0f, - world.startX, yOffset + sheight, z - 0.3f, 1.0f, 1.0f, - world.startX, yOffset + sheight, z - 0.3f, 1.0f, 1.0f, - s, yOffset + sheight, z - 0.3f, 0.0f, 1.0f, - s, yOffset, z - 0.3f, 0.0f, 0.0f + GLfloat verts[] = { + world.startX, 0, z, 0, 0, + world.startX + dim.x, 0, z, 1, 0, + world.startX + dim.x, dim.y, z, 1, 1, + world.startX + dim.x, dim.y, z, 1, 1, + world.startX, dim.y, z, 0, 1, + world.startX, 0, z, 0, 0, }; - if (offset.x + world.startX > s) { - Colors::black.use(); - glUniform1f(Render::worldShader.uniform[WU_light_impact], 0.0f); - glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, blackBar); - glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, blackBar + 3); - glDrawArrays(GL_TRIANGLES, 0, 6); - } - - if (offset.x - world.startX < e) { - blackBar[0] = blackBar[20] = blackBar[25] = -world.startX; - blackBar[5] = blackBar[10] = blackBar[15] = e; - - Colors::black.use(); - glUniform1f(Render::worldShader.uniform[WU_light_impact], 0.0f); - glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, blackBar); - glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, blackBar + 3); - glDrawArrays(GL_TRIANGLES, 0, 6); - } + glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), verts); + glVertexAttribPointer(Render::worldShader.tex , 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), verts + 3); + glDrawArrays(GL_TRIANGLES, 0, 6); Render::worldShader.disable(); Render::worldShader.unuse(); - - waitToSwap = false; } bool WorldSystem::receive(const BGMToggleEvent &bte) @@ -781,7 +617,7 @@ void WorldSystem::detect(entityx::TimeDelta dt) (void)e; if (!g.grounded) { // make sure entity is above ground - auto height = world.data[getLineIndex(loc.x + dim.width / 2)].groundHeight; + auto height = getGroundHeight(loc.x + dim.width / 2); if (loc.y != height) { loc.y = height; e.remove<Grounded>(); @@ -800,25 +636,24 @@ void WorldSystem::detect(entityx::TimeDelta dt) game::entities.each<Position, Direction, Solid>( [&](entityx::Entity e, Position &loc, Direction &vel, Solid &dim) { (void)e; - // get the line the entity is on - auto line = getLineIndex(loc.x + dim.width / 2); // make sure entity is above ground - if (loc.y < world.data[line].groundHeight) { - int dir = vel.x < 0 ? -1 : 1; + auto height = getGroundHeight(loc.x + dim.width / 2); + if (loc.y < height) { + /*int dir = vel.x < 0 ? -1 : 1; auto near = std::clamp(line + dir * 2, 0, static_cast<int>(world.data.size())); if (world.data[near].groundHeight - 30 > world.data[line + dir].groundHeight) { loc.x -= (PLAYER_SPEED_CONSTANT + 2.7f) * dir * 2; vel.x = 0; - } else { - loc.y = world.data[line].groundHeight - 0.001f * dt; + } else {*/ + loc.y = height - 0.001f * dt; vel.y = 0; if (!vel.grounded) { vel.grounded = true; ParticleSystem::addMultiple(20, ParticleType::SmallPoof, [&](){ return vec2(loc.x + randGet() % static_cast<int>(dim.width), loc.y); }, 500, 30); } - } + //} } diff --git a/xml/!town.xml b/xml/!town.xml index b2d96a5..1b1d527 100644 --- a/xml/!town.xml +++ b/xml/!town.xml @@ -12,22 +12,7 @@ <layer path="bg/dirt.png"/> <layer path="bg/grass.png"/> </style> - <generation> - x = 0 - - ground = function() - if (x == 320) then - height = -1 - else - height = 1 / math.pow(2, (x - 50) / 2) + 60 - end - x = x + 1 - end - - grass = function() - height = math.random(2, 7) - end - </generation> + <generation>assets/testground.png</generation> <weather>Sunny</weather> <link right="!town2.xml"/> <spawnx>-300</spawnx> @@ -37,7 +22,6 @@ <structure type="1" position="300.0,100.0"/> <structure inside="bobshouse.xml" type="1" position="10.0,100.0"/> <skirl /> - <birb position="-300.0,100.0" /> <firefly /> </World> diff --git a/xml/bobshouse.xml b/xml/bobshouse.xml index 9160ef0..384af4f 100644 --- a/xml/bobshouse.xml +++ b/xml/bobshouse.xml @@ -13,23 +13,7 @@ <layer path="bg/carpet.png"/> </style> <house width="800" texture="assets/style/classic/bg/insideWoodHouse.png"/> - <generation> - x = 0 - - ground = function() - if (x == 320) then - height = -1 - else - height = 60 - end - - x = x + 1 - end - - grass = function() - height = 2 - end - </generation> + <generation>testground.png</generation> <time>6000</time> <!--<link outside="town.xml"/>--> <npc name="Bob" hasDialog="true" spawnx="30"/> |