Immediate smoke puff when a normal entity is punched to death
authorPerttu Ahola <celeron55@gmail.com>
Fri, 9 Mar 2012 23:38:48 +0000 (01:38 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Sat, 10 Mar 2012 09:28:14 +0000 (11:28 +0200)
12 files changed:
data/clienttextures/smoke_puff.png [new file with mode: 0644]
data/mods/experimental/init.lua
src/CMakeLists.txt
src/clientsimpleobject.h [new file with mode: 0644]
src/content_cao.cpp
src/content_cso.cpp [new file with mode: 0644]
src/content_cso.h [new file with mode: 0644]
src/content_sao.cpp
src/environment.cpp
src/environment.h
src/scriptapi.cpp
src/scriptapi.h

diff --git a/data/clienttextures/smoke_puff.png b/data/clienttextures/smoke_puff.png
new file mode 100644 (file)
index 0000000..e346d20
Binary files /dev/null and b/data/clienttextures/smoke_puff.png differ
index 76b787031bebcdbfa1ccf184cf881f538b2f67bd..1ee3fdc2ed79eb77e8f95e2e622470c1885869f9 100644 (file)
@@ -378,10 +378,9 @@ minetest.register_alias("TNT", "experimental:tnt")
 -- The dummyball!
 --
 
-minetest.register_alias("dummyball", "experimental:dummyball")
-
 minetest.register_entity("experimental:dummyball", {
        -- Static definition
+       hp_max = 20,
        physical = false,
        collisionbox = {-0.4,-0.4,-0.4, 0.4,0.4,0.4},
        visual = "sprite",
@@ -419,6 +418,32 @@ minetest.register_entity("experimental:dummyball", {
        end,
 })
 
+minetest.register_on_chat_message(function(name, message)
+       local cmd = "/dummyball"
+       if message:sub(0, #cmd) == cmd then
+               if not minetest.get_player_privs(name)["give"] then
+                       minetest.chat_send_player(name, "you don't have permission to spawn (give)")
+                       return true -- Handled chat message
+               end
+               if not minetest.get_player_privs(name)["interact"] then
+                       minetest.chat_send_player(name, "you don't have permission to interact")
+                       return true -- Handled chat message
+               end
+               local player = minetest.env:get_player_by_name(name)
+               if player == nil then
+                       print("Unable to spawn entity, player is nil")
+                       return true -- Handled chat message
+               end
+               local entityname = "experimental:dummyball"
+               local p = player:getpos()
+               p.y = p.y + 1
+               minetest.env:add_entity(p, entityname)
+               minetest.chat_send_player(name, '"'..entityname
+                               ..'" spawned.');
+               return true -- Handled chat message
+       end
+end)
+
 --
 -- A test entity for testing animated and yaw-modulated sprites
 --
index 8607227127a9ef7da45bace93a0a6c5335165b83..d72128e018e934f796f646d5a15ce35ffb958865 100644 (file)
@@ -157,6 +157,7 @@ endif()
 # Client sources
 set(minetest_SRCS
        ${common_SRCS}
+       content_cso.cpp
        content_mapblock.cpp
        content_cao.cpp
        mesh.cpp
diff --git a/src/clientsimpleobject.h b/src/clientsimpleobject.h
new file mode 100644 (file)
index 0000000..ad0abfe
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+Minetest-c55
+Copyright (C) 2012 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef CLIENTSIMPLEOBJECT_HEADER
+#define CLIENTSIMPLEOBJECT_HEADER
+
+#include "irrlichttypes.h"
+class ClientEnvironment;
+
+class ClientSimpleObject
+{
+protected:
+public:
+       bool m_to_be_removed;
+
+       ClientSimpleObject(): m_to_be_removed(false) {}
+       virtual ~ClientSimpleObject(){}
+       virtual void step(float dtime){}
+};
+
+#endif
+
index 01f13df4ef2d0244b5b9fc9377fc30420d632d40..3aba4c7cb2cd94afb45a7fed76d4e8ac8c2f95f0 100644 (file)
@@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "utility.h" // For IntervalLimiter
 #include "itemdef.h"
 #include "tool.h"
+#include "content_cso.h"
 class Settings;
 struct ToolCapabilities;
 
@@ -538,6 +539,7 @@ void ItemCAO::initialize(const std::string &data)
 class LuaEntityCAO : public ClientActiveObject
 {
 private:
+       scene::ISceneManager *m_smgr;
        core::aabbox3d<f32> m_selection_box;
        scene::IMeshSceneNode *m_meshnode;
        scene::IBillboardSceneNode *m_spritenode;
@@ -562,6 +564,7 @@ private:
 public:
        LuaEntityCAO(IGameDef *gamedef, ClientEnvironment *env):
                ClientActiveObject(0, gamedef, env),
+               m_smgr(NULL),
                m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.),
                m_meshnode(NULL),
                m_spritenode(NULL),
@@ -646,6 +649,8 @@ public:
        void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
                        IrrlichtDevice *irr)
        {
+               m_smgr = smgr;
+
                if(m_meshnode != NULL || m_spritenode != NULL)
                        return;
                
@@ -701,15 +706,16 @@ public:
 
        void updateLight(u8 light_at_pos)
        {
+               bool is_visible = (m_hp != 0);
                u8 li = decode_light(light_at_pos);
                video::SColor color(255,li,li,li);
                if(m_meshnode){
                        setMeshColor(m_meshnode->getMesh(), color);
-                       m_meshnode->setVisible(true);
+                       m_meshnode->setVisible(is_visible);
                }
                if(m_spritenode){
                        m_spritenode->setColor(color);
-                       m_spritenode->setVisible(true);
+                       m_spritenode->setVisible(is_visible);
                }
        }
 
@@ -947,12 +953,19 @@ public:
                
                if(result.did_punch && result.damage != 0)
                {
-                       if(result.damage < m_hp)
+                       if(result.damage < m_hp){
                                m_hp -= result.damage;
-                       else
+                       } else {
                                m_hp = 0;
+                               // TODO: Execute defined fast response
+                               // As there is no definition, make a smoke puff
+                               ClientSimpleObject *simple = createSmokePuff(
+                                               m_smgr, m_env, m_position,
+                                               m_prop->visual_size * BS);
+                               m_env->addSimpleObject(simple);
+                       }
                        // TODO: Execute defined fast response
-                       // I guess flashing is fine as of now
+                       // Flashing shall suffice as there is no definition
                        updateTextures("^[brighten");
                        m_reset_textures_timer = 0.1;
                }
diff --git a/src/content_cso.cpp b/src/content_cso.cpp
new file mode 100644 (file)
index 0000000..ce6ce0a
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+Minetest-c55
+Copyright (C) 2012 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "content_cso.h"
+#include <IBillboardSceneNode.h>
+#include "tile.h"
+#include "environment.h"
+#include "gamedef.h"
+#include "log.h"
+
+static void setBillboardTextureMatrix(scene::IBillboardSceneNode *bill,
+               float txs, float tys, int col, int row)
+{
+       video::SMaterial& material = bill->getMaterial(0);
+       core::matrix4& matrix = material.getTextureMatrix(0);
+       matrix.setTextureTranslate(txs*col, tys*row);
+       matrix.setTextureScale(txs, tys);
+}
+
+class SmokePuffCSO: public ClientSimpleObject
+{
+       float m_age;
+       scene::IBillboardSceneNode *m_spritenode;
+public:
+       SmokePuffCSO(scene::ISceneManager *smgr,
+                       ClientEnvironment *env, v3f pos, v2f size):
+               m_age(0),
+               m_spritenode(NULL)
+       {
+               infostream<<"SmokePuffCSO: constructing"<<std::endl;
+               m_spritenode = smgr->addBillboardSceneNode(
+                               NULL, v2f(1,1), pos, -1);
+               m_spritenode->setMaterialTexture(0,
+                               env->getGameDef()->tsrc()->getTextureRaw("smoke_puff.png"));
+               m_spritenode->setMaterialFlag(video::EMF_LIGHTING, false);
+               m_spritenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
+               //m_spritenode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
+               m_spritenode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL);
+               m_spritenode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
+               m_spritenode->setColor(video::SColor(255,0,0,0));
+               m_spritenode->setVisible(true);
+               m_spritenode->setSize(size);
+               /* Update brightness */
+               u8 light = 64;
+               try{
+                       MapNode n = env->getMap().getNode(floatToInt(pos, BS));
+                       light = decode_light(n.getLightBlend(env->getDayNightRatio(),
+                                       env->getGameDef()->ndef()));
+               }
+               catch(InvalidPositionException &e){}
+               video::SColor color(255,light,light,light);
+               m_spritenode->setColor(color);
+       }
+       virtual ~SmokePuffCSO()
+       {
+               infostream<<"SmokePuffCSO: destructing"<<std::endl;
+               m_spritenode->remove();
+       }
+       void step(float dtime)
+       {
+               m_age += dtime;
+               if(m_age > 1.0){
+                       m_to_be_removed = true;
+               }
+       }
+};
+
+ClientSimpleObject* createSmokePuff(scene::ISceneManager *smgr,
+               ClientEnvironment *env, v3f pos, v2f size)
+{
+       return new SmokePuffCSO(smgr, env, pos, size);
+}
+
diff --git a/src/content_cso.h b/src/content_cso.h
new file mode 100644 (file)
index 0000000..127107c
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+Minetest-c55
+Copyright (C) 2012 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef CONTENT_CSO_HEADER
+#define CONTENT_CSO_HEADER
+
+#include "common_irrlicht.h"
+#include "clientsimpleobject.h"
+
+ClientSimpleObject* createSmokePuff(scene::ISceneManager *smgr,
+               ClientEnvironment *env, v3f pos, v2f size);
+
+#endif
+
index 568e4b1da67cf7681636de9a07ec532fc5255776..b04f03f267eab63e9fe5a0171a81954bbb495a46 100644 (file)
@@ -381,42 +381,45 @@ void LuaEntitySAO::addedToEnvironment()
 {
        ServerActiveObject::addedToEnvironment();
        
-       // Create entity from name and state
+       // Create entity from name
        lua_State *L = m_env->getLua();
-       m_registered = scriptapi_luaentity_add(L, m_id, m_init_name.c_str(),
-                       m_init_state.c_str());
+       m_registered = scriptapi_luaentity_add(L, m_id, m_init_name.c_str());
        
        if(m_registered){
                // Get properties
                scriptapi_luaentity_get_properties(L, m_id, m_prop);
+               // Initialize HP from properties
+               m_hp = m_prop->hp_max;
        }
+       
+       // Activate entity, supplying serialized state
+       scriptapi_luaentity_activate(L, m_id, m_init_state.c_str());
 }
 
 ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
                const std::string &data)
 {
-       std::istringstream is(data, std::ios::binary);
-       // read version
-       u8 version = readU8(is);
        std::string name;
        std::string state;
        s16 hp = 1;
        v3f velocity;
        float yaw = 0;
-       // check if version is supported
-       if(version == 0){
-               name = deSerializeString(is);
-               state = deSerializeLongString(is);
-       }
-       else if(version == 1){
-               name = deSerializeString(is);
-               state = deSerializeLongString(is);
-               hp = readS16(is);
-               velocity = readV3F1000(is);
-               yaw = readF1000(is);
-       }
-       else{
-               return NULL;
+       if(data != ""){
+               std::istringstream is(data, std::ios::binary);
+               // read version
+               u8 version = readU8(is);
+               // check if version is supported
+               if(version == 0){
+                       name = deSerializeString(is);
+                       state = deSerializeLongString(is);
+               }
+               else if(version == 1){
+                       name = deSerializeString(is);
+                       state = deSerializeLongString(is);
+                       hp = readS16(is);
+                       velocity = readV3F1000(is);
+                       yaw = readF1000(is);
+               }
        }
        // create object
        infostream<<"LuaEntitySAO::create(name=\""<<name<<"\" state=\""
@@ -581,6 +584,9 @@ int LuaEntitySAO::punch(v3f dir,
                        ActiveObjectMessage aom(getId(), true, os.str());
                        m_messages_out.push_back(aom);
                }
+
+               if(getHP() == 0)
+                       m_removed = true;
        }
 
        lua_State *L = m_env->getLua();
index 6f1d8ff551ee6bbdd11fb013deda75eed6f0fb01..6a8943d12a06a887f6c055ddadeb18e642995019 100644 (file)
@@ -1806,6 +1806,8 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
 
 #ifndef SERVER
 
+#include "clientsimpleobject.h"
+
 /*
        ClientEnvironment
 */
@@ -1831,6 +1833,12 @@ ClientEnvironment::~ClientEnvironment()
                delete i.getNode()->getValue();
        }
 
+       for(core::list<ClientSimpleObject*>::Iterator
+                       i = m_simple_objects.begin(); i != m_simple_objects.end(); i++)
+       {
+               delete *i;
+       }
+
        // Drop/delete map
        m_map->drop();
 }
@@ -2108,6 +2116,22 @@ void ClientEnvironment::step(float dtime)
                        obj->updateLight(light);
                }
        }
+
+       /*
+               Step and handle simple objects
+       */
+       for(core::list<ClientSimpleObject*>::Iterator
+                       i = m_simple_objects.begin(); i != m_simple_objects.end();)
+       {
+               ClientSimpleObject *simple = *i;
+               core::list<ClientSimpleObject*>::Iterator cur = i;
+               i++;
+               simple->step(dtime);
+               if(simple->m_to_be_removed){
+                       delete simple;
+                       m_simple_objects.erase(cur);
+               }
+       }
 }
 
 void ClientEnvironment::updateMeshes(v3s16 blockpos)
@@ -2119,6 +2143,11 @@ void ClientEnvironment::expireMeshes(bool only_daynight_diffed)
 {
        m_map->expireMeshes(only_daynight_diffed);
 }
+       
+void ClientEnvironment::addSimpleObject(ClientSimpleObject *simple)
+{
+       m_simple_objects.push_back(simple);
+}
 
 ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
 {
index 89c9fd67640a63771d1e955661bc4f26235f6e3b..fcd16e2967bebd271303940541af8894a08f991f 100644 (file)
@@ -356,6 +356,7 @@ private:
 #ifndef SERVER
 
 #include "clientobject.h"
+class ClientSimpleObject;
 
 /*
        The client-side environment.
@@ -424,6 +425,12 @@ public:
                }
        }
 
+       /*
+               ClientSimpleObjects
+       */
+
+       void addSimpleObject(ClientSimpleObject *simple);
+
        /*
                ActiveObjects
        */
@@ -469,6 +476,7 @@ private:
        IGameDef *m_gamedef;
        IrrlichtDevice *m_irr;
        core::map<u16, ClientActiveObject*> m_active_objects;
+       core::list<ClientSimpleObject*> m_simple_objects;
        Queue<ClientEnvEvent> m_client_event_queue;
        IntervalLimiter m_active_object_light_update_interval;
        IntervalLimiter m_lava_hurt_interval;
index 541baa61c0b860fc47d30a4721d54d3e75631f82..7bdf7a9f4ca9b248231ea85150674ff51ac4b432 100644 (file)
@@ -4226,8 +4226,7 @@ void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp)
        luaentity
 */
 
-bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,
-               const std::string &staticdata)
+bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name)
 {
        realitycheck(L);
        assert(lua_checkstack(L, 20));
@@ -4274,6 +4273,21 @@ bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,
        lua_pushvalue(L, object); // Copy object to top of stack
        lua_settable(L, -3);
        
+       return true;
+}
+
+void scriptapi_luaentity_activate(lua_State *L, u16 id,
+               const std::string &staticdata)
+{
+       realitycheck(L);
+       assert(lua_checkstack(L, 20));
+       infostream<<"scriptapi_luaentity_activate: id="<<id<<std::endl;
+       StackUnroller stack_unroller(L);
+       
+       // Get minetest.luaentities[id]
+       luaentity_get(L, id);
+       int object = lua_gettop(L);
+       
        // Get on_activate function
        lua_pushvalue(L, object);
        lua_getfield(L, -1, "on_activate");
@@ -4283,11 +4297,9 @@ bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,
                lua_pushlstring(L, staticdata.c_str(), staticdata.size());
                // Call with 2 arguments, 0 results
                if(lua_pcall(L, 2, 0, 0))
-                       script_error(L, "error running function %s:on_activate: %s\n",
-                                       name, lua_tostring(L, -1));
+                       script_error(L, "error running function on_activate: %s\n",
+                                       lua_tostring(L, -1));
        }
-       
-       return true;
 }
 
 void scriptapi_luaentity_rm(lua_State *L, u16 id)
index aa2d9d4c72a7c480b1c5d7691c5a185a902c8ca8..f63cab3681c45971fcf5e6a9d93d29b17c517de1 100644 (file)
@@ -75,7 +75,8 @@ bool scriptapi_node_on_dig(lua_State *L, v3s16 p, MapNode node,
 
 /* luaentity */
 // Returns true if succesfully added into Lua; false otherwise.
-bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,
+bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name);
+void scriptapi_luaentity_activate(lua_State *L, u16 id,
                const std::string &staticdata);
 void scriptapi_luaentity_rm(lua_State *L, u16 id);
 std::string scriptapi_luaentity_get_staticdata(lua_State *L, u16 id);