From 82a460ec90b4537926f31603219504bce8817ac2 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sun, 27 Nov 2011 04:31:05 +0200 Subject: [PATCH] Improve luaentity sprite functionality (and add some random stuff) --- data/mods/default/init.lua | 35 ++++++- src/collision.cpp | 13 ++- src/content_cao.cpp | 209 +++++++++++++++++++++++++++---------- src/content_inventory.cpp | 2 +- src/content_sao.cpp | 21 ++++ src/content_sao.h | 3 + src/luaentity_common.cpp | 15 ++- src/luaentity_common.h | 3 + src/scriptapi.cpp | 113 ++++++++++++++++++-- src/tile.cpp | 115 ++++---------------- src/utility.h | 52 +++++++++ 11 files changed, 413 insertions(+), 168 deletions(-) diff --git a/data/mods/default/init.lua b/data/mods/default/init.lua index 6ea15b4e..ea6bf3da 100644 --- a/data/mods/default/init.lua +++ b/data/mods/default/init.lua @@ -49,6 +49,9 @@ -- - setpos(pos); pos={x=num, y=num, z=num} -- - moveto(pos, continuous=false): interpolated move -- - add_to_inventory(itemstring): add an item to object inventory +-- - settexturemod(mod) +-- - setsprite(p={x=0,y=0}, num_frames=1, framelength=0.2, +-- - select_horiz_by_yawpitch=false) -- -- Registered entities: -- - Functions receive a "luaentity" as self: @@ -1171,8 +1174,6 @@ local TNT = { collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5}, visual = "cube", textures = {"tnt_top.png","tnt_bottom.png","tnt_side.png","tnt_side.png","tnt_side.png","tnt_side.png"}, - --visual = "single_sprite", - --textures = {"mese.png^[forcesingle"}, -- Initial value for our timer timer = 0, -- Number of punches required to defuse @@ -1227,6 +1228,36 @@ print("TNT dump: "..dump(TNT)) print("Registering TNT"); minetest.register_entity("TNT", TNT) + +minetest.register_entity("testentity", { + -- Static definition + physical = true, -- Collides with things + -- weight = 5, + collisionbox = {-0.7,-1.35,-0.7, 0.7,1.0,0.7}, + --collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5}, + visual = "sprite", + visual_size = {x=2, y=3}, + textures = {"dungeon_master.png^[makealpha:128,0,0^[makealpha:128,128,0"}, + spritediv = {x=6, y=5}, + initial_sprite_basepos = {x=0, y=0}, + + on_activate = function(self, staticdata) + print("testentity.on_activate") + self.object:setsprite({x=0,y=0}, 1, 0, true) + --self.object:setsprite({x=0,y=0}, 4, 0.3, true) + + -- Set gravity + self.object:setacceleration({x=0, y=-10, z=0}) + -- Jump a bit upwards + self.object:setvelocity({x=0, y=10, z=0}) + end, + + on_punch = function(self, hitter) + self.object:remove() + hitter:add_to_inventory('CraftItem testobject1 1') + end, +}) + -- -- Falling stuff -- diff --git a/src/collision.cpp b/src/collision.cpp index 24f1e9d1..3460b04f 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -72,11 +72,16 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef, /* Go through every node around the object - TODO: Calculate the range of nodes that need to be checked */ - for(s16 y = oldpos_i.Y - 1; y <= oldpos_i.Y + 2; y++) - for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++) - for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++) + s16 min_x = (box_0.MinEdge.X / BS) - 2; + s16 min_y = (box_0.MinEdge.Y / BS) - 2; + s16 min_z = (box_0.MinEdge.Z / BS) - 2; + s16 max_x = (box_0.MaxEdge.X / BS) + 1; + s16 max_y = (box_0.MaxEdge.Y / BS) + 1; + s16 max_z = (box_0.MaxEdge.Z / BS) + 1; + for(s16 y = oldpos_i.Y + min_y; y <= oldpos_i.Y + max_y; y++) + for(s16 z = oldpos_i.Z + min_z; z <= oldpos_i.Z + max_z; z++) + for(s16 x = oldpos_i.X + min_x; x <= oldpos_i.X + max_x; x++) { try{ // Object collides into walkable nodes diff --git a/src/content_cao.cpp b/src/content_cao.cpp index 984a216d..ba8739df 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -899,8 +899,8 @@ void MobV2CAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc) /*infostream<<"MobV2CAO::addToScene using texture_name="<< m_texture_name<getRootSceneNode(), smgr, -1, v3f(0,0,0), v2f(1,1)); @@ -1281,8 +1281,81 @@ private: float m_yaw; struct LuaEntityProperties *m_prop; SmoothTranslator pos_translator; + // Spritesheet/animation stuff + v2f m_tx_size; + v2s16 m_tx_basepos; + bool m_tx_select_horiz_by_yawpitch; + int m_anim_frame; + int m_anim_num_frames; + float m_anim_framelength; + float m_anim_timer; public: + CLuaEntityCAO(IGameDef *gamedef): + LuaEntityCAO(gamedef), + m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.), + m_meshnode(NULL), + m_spritenode(NULL), + m_position(v3f(0,10*BS,0)), + m_velocity(v3f(0,0,0)), + m_acceleration(v3f(0,0,0)), + m_yaw(0), + m_prop(new LuaEntityProperties), + m_tx_size(1,1), + m_tx_basepos(0,0), + m_tx_select_horiz_by_yawpitch(false), + m_anim_frame(0), + m_anim_num_frames(1), + m_anim_framelength(0.2), + m_anim_timer(0) + { + ClientActiveObject::registerType(getType(), create); + } + + void initialize(const std::string &data) + { + infostream<<"CLuaEntityCAO: Got init data"<deSerialize(prop_is); + + infostream<<"m_prop: "<dump()<collisionbox; + m_selection_box.MinEdge *= BS; + m_selection_box.MaxEdge *= BS; + + pos_translator.init(m_position); + + m_tx_size.X = 1.0 / m_prop->spritediv.X; + m_tx_size.Y = 1.0 / m_prop->spritediv.Y; + m_tx_basepos.X = m_tx_size.X * m_prop->initial_sprite_basepos.X; + m_tx_basepos.Y = m_tx_size.Y * m_prop->initial_sprite_basepos.Y; + + updateNodePos(); + } + + ~CLuaEntityCAO() + { + delete m_prop; + } + + static ClientActiveObject* create(IGameDef *gamedef) + { + return new CLuaEntityCAO(gamedef); + } + u8 getType() const { return ACTIVEOBJECT_TYPE_LUAENTITY; @@ -1296,30 +1369,6 @@ public: return pos_translator.vect_show; } - CLuaEntityCAO(IGameDef *gamedef): - LuaEntityCAO(gamedef), - m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.), - m_meshnode(NULL), - m_spritenode(NULL), - m_position(v3f(0,10*BS,0)), - m_velocity(v3f(0,0,0)), - m_acceleration(v3f(0,0,0)), - m_yaw(0), - m_prop(new LuaEntityProperties) - { - ClientActiveObject::registerType(getType(), create); - } - - ~CLuaEntityCAO() - { - delete m_prop; - } - - static ClientActiveObject* create(IGameDef *gamedef) - { - return new CLuaEntityCAO(gamedef); - } - void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc) { if(m_meshnode != NULL || m_spritenode != NULL) @@ -1327,7 +1376,7 @@ public: //video::IVideoDriver* driver = smgr->getVideoDriver(); - if(m_prop->visual == "single_sprite"){ + if(m_prop->visual == "sprite"){ infostream<<"CLuaEntityCAO::addToScene(): single_sprite"<getRootSceneNode(), smgr, -1, v3f(0,0,0), v2f(1,1)); @@ -1339,7 +1388,7 @@ public: m_spritenode->setMaterialFlag(video::EMF_FOG_ENABLE, true); m_spritenode->setColor(video::SColor(255,0,0,0)); m_spritenode->setVisible(false); /* Set visible when brightness is known */ - m_spritenode->setSize(v2f(1,1)*1.0*BS); + m_spritenode->setSize(m_prop->visual_size*BS); { const float txs = 1.0 / 1; const float tys = 1.0 / 1; @@ -1387,6 +1436,9 @@ public: for(u32 i=0; i<24; ++i){ vertices[i].Pos *= BS; + vertices[i].Pos.Y *= m_prop->visual_size.Y; + vertices[i].Pos.X *= m_prop->visual_size.X; + vertices[i].Pos.Z *= m_prop->visual_size.X; } u16 indices[6] = {0,1,2,2,3,0}; @@ -1487,6 +1539,66 @@ public: pos_translator.translate(dtime); updateNodePos(); } + + m_anim_timer += dtime; + if(m_anim_timer >= m_anim_framelength){ + m_anim_timer -= m_anim_framelength; + m_anim_frame++; + if(m_anim_frame >= m_anim_num_frames) + m_anim_frame = 0; + } + + updateTexturePos(); + } + + void updateTexturePos() + { + if(m_spritenode){ + scene::ICameraSceneNode* camera = + m_spritenode->getSceneManager()->getActiveCamera(); + if(!camera) + return; + v3f cam_to_entity = m_spritenode->getAbsolutePosition() + - camera->getAbsolutePosition(); + cam_to_entity.normalize(); + + int row = m_tx_basepos.Y; + int col = m_tx_basepos.X; + + if(m_tx_select_horiz_by_yawpitch) + { + if(cam_to_entity.Y > 0.75) + col += 5; + else if(cam_to_entity.Y < -0.75) + col += 4; + else{ + float mob_dir = atan2(cam_to_entity.Z, cam_to_entity.X) / PI * 180.; + float dir = mob_dir - m_yaw; + dir = wrapDegrees_180(dir); + //infostream<<"id="<deSerialize(prop_is); - - infostream<<"m_prop: "<dump()<collisionbox; - m_selection_box.MinEdge *= BS; - m_selection_box.MaxEdge *= BS; + else if(cmd == 2) // set sprite + { + v2s16 p = readV2S16(is); + int num_frames = readU16(is); + float framelength = readF1000(is); + bool select_horiz_by_yawpitch = readU8(is); - pos_translator.init(m_position); - - updateNodePos(); + m_tx_basepos = p; + m_anim_num_frames = num_frames; + m_anim_framelength = framelength; + m_tx_select_horiz_by_yawpitch = select_horiz_by_yawpitch; + + updateTexturePos(); + } } }; diff --git a/src/content_inventory.cpp b/src/content_inventory.cpp index 2a05b76f..21acad30 100644 --- a/src/content_inventory.cpp +++ b/src/content_inventory.cpp @@ -77,7 +77,7 @@ ServerActiveObject* item_craft_create_object(const std::string &subname, } else if(subname == "testobject1") { - ServerActiveObject *obj = new LuaEntitySAO(env, pos, "TNT", ""); + ServerActiveObject *obj = new LuaEntitySAO(env, pos, "testentity", ""); return obj; } diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 74824d57..b013069a 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -1748,6 +1748,11 @@ void LuaEntitySAO::setAcceleration(v3f acceleration) m_acceleration = acceleration; } +v3f LuaEntitySAO::getAcceleration() +{ + return m_acceleration; +} + void LuaEntitySAO::setTextureMod(const std::string &mod) { std::ostringstream os(std::ios::binary); @@ -1760,6 +1765,22 @@ void LuaEntitySAO::setTextureMod(const std::string &mod) m_messages_out.push_back(aom); } +void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength, + bool select_horiz_by_yawpitch) +{ + std::ostringstream os(std::ios::binary); + // command (2 = set sprite) + writeU8(os, 2); + // parameters + writeV2S16(os, p); + writeU16(os, num_frames); + writeF1000(os, framelength); + writeU8(os, select_horiz_by_yawpitch); + // create message and add to list + ActiveObjectMessage aom(getId(), false, os.str()); + m_messages_out.push_back(aom); +} + void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) { m_last_sent_move_precision = m_base_position.getDistanceFrom( diff --git a/src/content_sao.h b/src/content_sao.h index 6f5bab31..c5e1471b 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -219,7 +219,10 @@ public: /* LuaEntitySAO-specific */ void setVelocity(v3f velocity); void setAcceleration(v3f acceleration); + v3f getAcceleration(); void setTextureMod(const std::string &mod); + void setSprite(v2s16 p, int num_frames, float framelength, + bool select_horiz_by_yawpitch); private: void sendPosition(bool do_interpolate, bool is_movement_end); diff --git a/src/luaentity_common.cpp b/src/luaentity_common.cpp index 503083d0..cf1ac7be 100644 --- a/src/luaentity_common.cpp +++ b/src/luaentity_common.cpp @@ -22,12 +22,16 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "utility.h" #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" +#define PP2(x) "("<<(x).X<<","<<(x).Y<<")" LuaEntityProperties::LuaEntityProperties(): physical(false), weight(5), collisionbox(-0.5,-0.5,-0.5, 0.5,0.5,0.5), - visual("single_sprite") + visual("single_sprite"), + visual_size(1,1), + spritediv(1,1), + initial_sprite_basepos(0,0) { textures.push_back("unknown_object.png"); } @@ -39,11 +43,14 @@ std::string LuaEntityProperties::dump() os<<", weight="< read_aabbox3df32(lua_State *L, int index, f32 scale) return box; } +static v2s16 read_v2s16(lua_State *L, int index) +{ + v2s16 p; + luaL_checktype(L, index, LUA_TTABLE); + lua_getfield(L, index, "x"); + p.X = lua_tonumber(L, -1); + lua_pop(L, 1); + lua_getfield(L, index, "y"); + p.Y = lua_tonumber(L, -1); + lua_pop(L, 1); + return p; +} + +static v2f read_v2f(lua_State *L, int index) +{ + v2f p; + luaL_checktype(L, index, LUA_TTABLE); + lua_getfield(L, index, "x"); + p.X = lua_tonumber(L, -1); + lua_pop(L, 1); + lua_getfield(L, index, "y"); + p.Y = lua_tonumber(L, -1); + lua_pop(L, 1); + return p; +} + static bool getstringfield(lua_State *L, int table, const char *fieldname, std::string &result) { @@ -307,6 +345,14 @@ static int getintfield_default(lua_State *L, int table, return result; } +/*static float getfloatfield_default(lua_State *L, int table, + const char *fieldname, float default_) +{ + float result = default_; + getfloatfield(L, table, fieldname, result); + return result; +}*/ + static bool getboolfield_default(lua_State *L, int table, const char *fieldname, bool default_) { @@ -1235,6 +1281,18 @@ private: return 0; } + // getacceleration(self) + static int l_getacceleration(lua_State *L) + { + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; + // Do it + v3f v = co->getAcceleration(); + pushFloatPos(L, v); + return 1; + } + // add_to_inventory(self, itemstring) // returns: true if item was added, false otherwise static int l_add_to_inventory(lua_State *L) @@ -1272,6 +1330,30 @@ private: return 0; } + // setsprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2, + // select_horiz_by_yawpitch=false) + static int l_setsprite(lua_State *L) + { + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; + // Do it + v2s16 p(0,0); + if(!lua_isnil(L, 2)) + p = read_v2s16(L, 2); + int num_frames = 1; + if(!lua_isnil(L, 3)) + num_frames = lua_tonumber(L, 3); + float framelength = 0.2; + if(!lua_isnil(L, 4)) + framelength = lua_tonumber(L, 4); + bool select_horiz_by_yawpitch = false; + if(!lua_isnil(L, 5)) + select_horiz_by_yawpitch = lua_toboolean(L, 5); + co->setSprite(p, num_frames, framelength, select_horiz_by_yawpitch); + return 0; + } + public: ObjectRef(ServerActiveObject *object): m_object(object) @@ -1343,6 +1425,7 @@ const luaL_reg ObjectRef::methods[] = { method(ObjectRef, setacceleration), method(ObjectRef, add_to_inventory), method(ObjectRef, settexturemod), + method(ObjectRef, setsprite), {0,0} }; @@ -1859,25 +1942,24 @@ void scriptapi_luaentity_get_properties(lua_State *L, u16 id, luaentity_get(L, id); //int object = lua_gettop(L); - lua_getfield(L, -1, "physical"); - if(lua_isboolean(L, -1)) - prop->physical = lua_toboolean(L, -1); - lua_pop(L, 1); + /* Read stuff */ - lua_getfield(L, -1, "weight"); - prop->weight = lua_tonumber(L, -1); - lua_pop(L, 1); + getboolfield(L, -1, "physical", prop->physical); + + getfloatfield(L, -1, "weight", prop->weight); lua_getfield(L, -1, "collisionbox"); if(lua_istable(L, -1)) prop->collisionbox = read_aabbox3df32(L, -1, 1.0); lua_pop(L, 1); - lua_getfield(L, -1, "visual"); - if(lua_isstring(L, -1)) - prop->visual = lua_tostring(L, -1); - lua_pop(L, 1); + getstringfield(L, -1, "visual", prop->visual); + lua_getfield(L, -1, "visual_size"); + if(lua_istable(L, -1)) + prop->visual_size = read_v2f(L, -1); + lua_pop(L, 1); + lua_getfield(L, -1, "textures"); if(lua_istable(L, -1)){ prop->textures.clear(); @@ -1894,7 +1976,16 @@ void scriptapi_luaentity_get_properties(lua_State *L, u16 id, } } lua_pop(L, 1); + + lua_getfield(L, -1, "spritediv"); + if(lua_istable(L, -1)) + prop->spritediv = read_v2s16(L, -1); + lua_pop(L, 1); + lua_getfield(L, -1, "initial_sprite_basepos"); + if(lua_istable(L, -1)) + prop->initial_sprite_basepos = read_v2s16(L, -1); + lua_pop(L, 1); } void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime) diff --git a/src/tile.cpp b/src/tile.cpp index f7d577b1..206d8128 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -1361,14 +1361,14 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, } } /* - "[makealpha:R,G,B:filename.png" - Use an image with converting one color to transparent. + "[makealpha:R,G,B" + Convert one color to transparent. */ else if(part_of_name.substr(0,11) == "[makealpha:") { - if(baseimg != NULL) + if(baseimg == NULL) { - errorstream<<"generate_image(): baseimg!=NULL " + errorstream<<"generate_image(): baseimg==NULL " <<"for part_of_name=\""< dim = baseimg->getDimension(); - video::IImage *image = sourcecache->getOrLoad(filename, device); - - if(image == NULL) + /*video::IImage *oldbaseimg = baseimg; + baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); + oldbaseimg->copyTo(baseimg); + oldbaseimg->drop();*/ + + // Set alpha to full + for(u32 y=0; y dim = image->getDimension(); - baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); - - // Blit - image->copyTo(baseimg); - - image->drop(); - - for(u32 y=0; ygetPixel(x,y); - u32 r = c.getRed(); - u32 g = c.getGreen(); - u32 b = c.getBlue(); - if(!(r == r1 && g == g1 && b == b1)) - continue; - c.setAlpha(0); - baseimg->setPixel(x,y,c); - } - } - } - /* - "[makealpha2:R,G,B;R2,G2,B2:filename.png" - Use an image with converting two colors to transparent. - */ - else if(part_of_name.substr(0,12) == "[makealpha2:") - { - if(baseimg != NULL) - { - errorstream<<"generate_image(): baseimg!=NULL " - <<"for part_of_name=\""<getOrLoad(filename, device); - - if(image == NULL) - { - errorstream<<"generate_image(): Loading file \"" - < dim = image->getDimension(); - baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); - - // Blit - image->copyTo(baseimg); - - image->drop(); - - for(u32 y=0; ygetPixel(x,y); - u32 r = c.getRed(); - u32 g = c.getGreen(); - u32 b = c.getBlue(); - if(!(r == r1 && g == g1 && b == b1) && - !(r == r2 && g == g2 && b == b2)) - continue; - c.setAlpha(0); - baseimg->setPixel(x,y,c); - } + video::SColor c = baseimg->getPixel(x,y); + u32 r = c.getRed(); + u32 g = c.getGreen(); + u32 b = c.getBlue(); + if(!(r == r1 && g == g1 && b == b1)) + continue; + c.setAlpha(0); + baseimg->setPixel(x,y,c); } } /* diff --git a/src/utility.h b/src/utility.h index 935df4b2..97f902b9 100644 --- a/src/utility.h +++ b/src/utility.h @@ -148,6 +148,19 @@ inline v3f readV3F1000(u8 *data) return p; } +inline void writeV2F1000(u8 *data, v2f p) +{ + writeF1000(&data[0], p.X); + writeF1000(&data[4], p.Y); +} +inline v2f readV2F1000(u8 *data) +{ + v2f p; + p.X = (float)readF1000(&data[0]); + p.Y = (float)readF1000(&data[4]); + return p; +} + inline void writeV2S16(u8 *data, v2s16 p) { writeS16(&data[0], p.X); @@ -274,6 +287,45 @@ inline v3f readV3F1000(std::istream &is) return readV3F1000((u8*)buf); } +inline void writeV2F1000(std::ostream &os, v2f p) +{ + char buf[8]; + writeV2F1000((u8*)buf, p); + os.write(buf, 8); +} +inline v2f readV2F1000(std::istream &is) +{ + char buf[8]; + is.read(buf, 8); + return readV2F1000((u8*)buf); +} + +inline void writeV2S16(std::ostream &os, v2s16 p) +{ + char buf[4]; + writeV2S16((u8*)buf, p); + os.write(buf, 4); +} +inline v2s16 readV2S16(std::istream &is) +{ + char buf[4]; + is.read(buf, 4); + return readV2S16((u8*)buf); +} + +inline void writeV3S16(std::ostream &os, v3s16 p) +{ + char buf[6]; + writeV3S16((u8*)buf, p); + os.write(buf, 6); +} +inline v3s16 readV3S16(std::istream &is) +{ + char buf[6]; + is.read(buf, 6); + return readV3S16((u8*)buf); +} + /* None of these are used at the moment */