Scripting WIP: dynamic object stuff

This commit is contained in:
Perttu Ahola 2011-11-12 17:37:14 +02:00
parent 0b97ad8384
commit 1320d07068
11 changed files with 274 additions and 95 deletions

@ -162,6 +162,8 @@ end
-- Called when object is punched -- Called when object is punched
function TNT:on_punch(hitter) function TNT:on_punch(hitter)
print("TNT:on_punch()") print("TNT:on_punch()")
self.object:remove()
hitter:add_to_inventory("CraftItem testobject1 1")
end end
-- Called when object is right-clicked -- Called when object is right-clicked

@ -237,14 +237,24 @@ InventoryItem * ItemSAO::createInventoryItem()
} }
} }
void ItemSAO::rightClick(Player *player) void ItemSAO::punch(ServerActiveObject *puncher)
{
InventoryItem *item = createInventoryItem();
bool fits = puncher->addToInventory(item);
if(fits)
m_removed = true;
else
delete item;
}
void ItemSAO::rightClick(ServerActiveObject *clicker)
{ {
infostream<<__FUNCTION_NAME<<std::endl; infostream<<__FUNCTION_NAME<<std::endl;
InventoryItem *item = createInventoryItem(); InventoryItem *item = createInventoryItem();
if(item == NULL) if(item == NULL)
return; return;
bool to_be_deleted = item->use(m_env, player); bool to_be_deleted = item->use(m_env, clicker);
if(to_be_deleted) if(to_be_deleted)
m_removed = true; m_removed = true;
@ -252,7 +262,7 @@ void ItemSAO::rightClick(Player *player)
// Reflect changes to the item here // Reflect changes to the item here
m_inventorystring = item->getItemString(); m_inventorystring = item->getItemString();
delete item; delete item; // Delete temporary item
} }
/* /*
@ -435,11 +445,15 @@ std::string RatSAO::getStaticData()
return os.str(); return os.str();
} }
InventoryItem* RatSAO::createPickedUpItem() void RatSAO::punch(ServerActiveObject *puncher)
{ {
std::istringstream is("CraftItem rat 1", std::ios_base::binary); std::istringstream is("CraftItem rat 1", std::ios_base::binary);
InventoryItem *item = InventoryItem::deSerialize(is); InventoryItem *item = InventoryItem::deSerialize(is);
return item; bool fits = puncher->addToInventory(item);
if(fits)
m_removed = true;
else
delete item;
} }
/* /*
@ -684,9 +698,17 @@ std::string Oerkki1SAO::getStaticData()
return os.str(); return os.str();
} }
u16 Oerkki1SAO::punch(const std::string &toolname, v3f dir, void Oerkki1SAO::punch(ServerActiveObject *puncher)
const std::string &playername)
{ {
v3f dir = (getBasePosition() - puncher->getBasePosition()).normalize();
std::string toolname = "";
InventoryItem *item = puncher->getWieldedItem();
if(item && (std::string)item->getName() == "ToolItem"){
ToolItem *titem = (ToolItem*)item;
toolname = titem->getToolName();
}
m_speed_f += dir*12*BS; m_speed_f += dir*12*BS;
u16 amount = 5; u16 amount = 5;
@ -704,7 +726,8 @@ u16 Oerkki1SAO::punch(const std::string &toolname, v3f dir,
if(toolname == "SteelPick") if(toolname == "SteelPick")
amount = 7; amount = 7;
doDamage(amount); doDamage(amount);
return 65536/100;
puncher->damageWieldedItem(65536/100);
} }
void Oerkki1SAO::doDamage(u16 d) void Oerkki1SAO::doDamage(u16 d)
@ -1351,10 +1374,20 @@ void MobV2SAO::step(float dtime, bool send_recommended)
} }
} }
u16 MobV2SAO::punch(const std::string &toolname, v3f dir, void MobV2SAO::punch(ServerActiveObject *puncher)
const std::string &playername)
{ {
assert(m_env); v3f dir = (getBasePosition() - puncher->getBasePosition()).normalize();
std::string toolname = "";
InventoryItem *item = puncher->getWieldedItem();
if(item && (std::string)item->getName() == "ToolItem"){
ToolItem *titem = (ToolItem*)item;
toolname = titem->getToolName();
}
// A quick hack; SAO description is player name for player
std::string playername = puncher->getDescription();
Map *map = &m_env->getMap(); Map *map = &m_env->getMap();
actionstream<<playername<<" punches mob id="<<m_id actionstream<<playername<<" punches mob id="<<m_id
@ -1396,7 +1429,8 @@ u16 MobV2SAO::punch(const std::string &toolname, v3f dir,
if(toolname == "SteelPick") if(toolname == "SteelPick")
amount = 3; amount = 3;
doDamage(amount); doDamage(amount);
return 65536/100;
puncher->damageWieldedItem(65536/100);
} }
bool MobV2SAO::isPeaceful() bool MobV2SAO::isPeaceful()
@ -1629,18 +1663,20 @@ InventoryItem* LuaEntitySAO::createPickedUpItem()
return item; return item;
} }
u16 LuaEntitySAO::punch(const std::string &toolname, v3f dir, void LuaEntitySAO::punch(ServerActiveObject *puncher)
const std::string &playername)
{
return 0;
}
void LuaEntitySAO::rightClick(Player *player)
{ {
if(!m_registered) if(!m_registered)
return; return;
lua_State *L = m_env->getLua(); lua_State *L = m_env->getLua();
scriptapi_luaentity_rightclick_player(L, m_id, player->getName()); scriptapi_luaentity_punch(L, m_id, puncher);
}
void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
{
if(!m_registered)
return;
lua_State *L = m_env->getLua();
scriptapi_luaentity_rightclick(L, m_id, clicker);
} }
void LuaEntitySAO::setPos(v3f pos) void LuaEntitySAO::setPos(v3f pos)

@ -50,9 +50,8 @@ public:
std::string getClientInitializationData(); std::string getClientInitializationData();
std::string getStaticData(); std::string getStaticData();
InventoryItem* createInventoryItem(); InventoryItem* createInventoryItem();
InventoryItem* createPickedUpItem(){return createInventoryItem();} void punch(ServerActiveObject *puncher);
void rightClick(Player *player); void rightClick(ServerActiveObject *clicker);
float getMinimumSavedMovement(){ return 0.1*BS; } float getMinimumSavedMovement(){ return 0.1*BS; }
private: private:
std::string m_inventorystring; std::string m_inventorystring;
@ -72,7 +71,7 @@ public:
void step(float dtime, bool send_recommended); void step(float dtime, bool send_recommended);
std::string getClientInitializationData(); std::string getClientInitializationData();
std::string getStaticData(); std::string getStaticData();
InventoryItem* createPickedUpItem(); void punch(ServerActiveObject *puncher);
private: private:
bool m_is_active; bool m_is_active;
IntervalLimiter m_inactive_interval; IntervalLimiter m_inactive_interval;
@ -98,8 +97,7 @@ public:
std::string getClientInitializationData(); std::string getClientInitializationData();
std::string getStaticData(); std::string getStaticData();
InventoryItem* createPickedUpItem(){return NULL;} InventoryItem* createPickedUpItem(){return NULL;}
u16 punch(const std::string &toolname, v3f dir, void punch(ServerActiveObject *puncher);
const std::string &playername);
bool isPeaceful(){return false;} bool isPeaceful(){return false;}
private: private:
void doDamage(u16 d); void doDamage(u16 d);
@ -159,8 +157,7 @@ public:
std::string getClientInitializationData(); std::string getClientInitializationData();
void step(float dtime, bool send_recommended); void step(float dtime, bool send_recommended);
InventoryItem* createPickedUpItem(){return NULL;} InventoryItem* createPickedUpItem(){return NULL;}
u16 punch(const std::string &toolname, v3f dir, void punch(ServerActiveObject *puncher);
const std::string &playername);
bool isPeaceful(); bool isPeaceful();
private: private:
void sendPosition(); void sendPosition();
@ -214,10 +211,8 @@ public:
std::string getClientInitializationData(); std::string getClientInitializationData();
std::string getStaticData(); std::string getStaticData();
InventoryItem* createPickedUpItem(); InventoryItem* createPickedUpItem();
u16 punch(const std::string &toolname, v3f dir, void punch(ServerActiveObject *puncher);
const std::string &playername); void rightClick(ServerActiveObject *clicker);
void rightClick(Player *player);
void setPos(v3f pos); void setPos(v3f pos);
void moveTo(v3f pos, bool continuous); void moveTo(v3f pos, bool continuous);
float getMinimumSavedMovement(); float getMinimumSavedMovement();

@ -205,22 +205,23 @@ InventoryItem *CraftItem::createCookResult() const
return item_craft_create_cook_result(m_subname); return item_craft_create_cook_result(m_subname);
} }
bool CraftItem::use(ServerEnvironment *env, Player *player) bool CraftItem::use(ServerEnvironment *env, ServerActiveObject *user)
{ {
if(item_craft_is_eatable(m_subname)) if(!item_craft_is_eatable(m_subname))
{ return false;
u16 result_count = getCount() - 1; // Eat one at a time
s16 hp_change = item_craft_eat_hp_change(m_subname);
if(player->hp + hp_change > 20)
player->hp = 20;
else
player->hp += hp_change;
if(result_count < 1) u16 result_count = getCount() - 1; // Eat one at a time
return true; s16 hp_change = item_craft_eat_hp_change(m_subname);
else s16 hp = user->getHP();
setCount(result_count); hp += hp_change;
} if(hp < 0)
hp = 0;
user->setHP(hp);
if(result_count < 1)
return true;
setCount(result_count);
return false; return false;
} }

@ -36,7 +36,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class ServerActiveObject; class ServerActiveObject;
class ServerEnvironment; class ServerEnvironment;
class Player;
class InventoryItem class InventoryItem
{ {
@ -117,7 +116,7 @@ public:
// Called when item is right-clicked when lying on ground. // Called when item is right-clicked when lying on ground.
// If returns true, item shall be deleted. // If returns true, item shall be deleted.
virtual bool use(ServerEnvironment *env, virtual bool use(ServerEnvironment *env,
Player *player){return false;} ServerActiveObject *user){return false;}
protected: protected:
u16 m_count; u16 m_count;
@ -263,7 +262,7 @@ public:
bool isCookable() const; bool isCookable() const;
InventoryItem *createCookResult() const; InventoryItem *createCookResult() const;
bool use(ServerEnvironment *env, Player *player); bool use(ServerEnvironment *env, ServerActiveObject *user);
/* /*
Special methods Special methods

@ -164,6 +164,70 @@ void Player::deSerialize(std::istream &is)
inventory.deSerialize(is); inventory.deSerialize(is);
} }
/*
ServerRemotePlayer
*/
/* ServerActiveObject interface */
InventoryItem* ServerRemotePlayer::getWieldedItem()
{
InventoryList *list = inventory.getList("main");
if (list)
return list->getItem(m_selected_item);
return NULL;
}
void ServerRemotePlayer::damageWieldedItem(u16 amount)
{
infostream<<"Damaging "<<getName()<<"'s wielded item for amount="
<<amount<<std::endl;
InventoryList *list = inventory.getList("main");
if(!list)
return;
InventoryItem *item = list->getItem(m_selected_item);
if(item && (std::string)item->getName() == "ToolItem"){
ToolItem *titem = (ToolItem*)item;
bool weared_out = titem->addWear(amount);
if(weared_out)
list->deleteItem(m_selected_item);
}
}
bool ServerRemotePlayer::addToInventory(InventoryItem *item)
{
infostream<<"Adding "<<item->getName()<<" into "<<getName()
<<"'s inventory"<<std::endl;
InventoryList *ilist = inventory.getList("main");
if(ilist == NULL)
return false;
// In creative mode, just delete the item
if(g_settings->getBool("creative_mode")){
return false;
}
// Skip if inventory has no free space
if(ilist->roomForItem(item) == false)
{
infostream<<"Player inventory has no free space"<<std::endl;
return false;
}
// Add to inventory
InventoryItem *leftover = ilist->addItem(item);
assert(!leftover);
return true;
}
void ServerRemotePlayer::setHP(s16 hp_)
{
hp = hp_;
}
s16 ServerRemotePlayer::getHP()
{
return hp;
}
/* /*
RemotePlayer RemotePlayer
*/ */

@ -216,11 +216,19 @@ public:
ServerActiveObject::setBasePosition(position); ServerActiveObject::setBasePosition(position);
} }
/* /* ServerActiveObject interface */
ServerActiveObject interface
*/
u8 getType() const u8 getType() const
{return ACTIVEOBJECT_TYPE_PLAYER;} {return ACTIVEOBJECT_TYPE_PLAYER;}
virtual std::string getDescription(){return getName();}
// Returns a reference
virtual InventoryItem* getWieldedItem();
virtual void damageWieldedItem(u16 amount);
// If all fits, eats item and returns true. Otherwise returns false.
virtual bool addToInventory(InventoryItem *item);
virtual void setHP(s16 hp_);
virtual s16 getHP();
private: private:
}; };

@ -368,6 +368,14 @@ private:
// Exported functions // Exported functions
// garbage collector
static int gc_object(lua_State *L) {
ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
//infostream<<"ObjectRef::gc_object: o="<<o<<std::endl;
delete o;
return 0;
}
// remove(self) // remove(self)
static int l_remove(lua_State *L) static int l_remove(lua_State *L)
{ {
@ -427,12 +435,25 @@ private:
return 0; return 0;
} }
static int gc_object(lua_State *L) { // add_to_inventory(self, itemstring)
//ObjectRef *o = checkobject(L, 1); // returns: true if item was added, false otherwise
ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1)); static int l_add_to_inventory(lua_State *L)
//infostream<<"ObjectRef::gc_object: o="<<o<<std::endl; {
delete o; ObjectRef *ref = checkobject(L, 1);
return 0; luaL_checkstring(L, 2);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
// itemstring
const char *itemstring = lua_tostring(L, 2);
infostream<<"ObjectRef::l_add_to_inventory(): id="<<co->getId()
<<" itemstring=\""<<itemstring<<"\""<<std::endl;
// Do it
std::istringstream is(itemstring, std::ios::binary);
InventoryItem *item = InventoryItem::deSerialize(is);
bool fits = co->addToInventory(item);
// Return
lua_pushboolean(L, fits);
return 1;
} }
public: public:
@ -502,9 +523,20 @@ const luaL_reg ObjectRef::methods[] = {
method(ObjectRef, getpos), method(ObjectRef, getpos),
method(ObjectRef, setpos), method(ObjectRef, setpos),
method(ObjectRef, moveto), method(ObjectRef, moveto),
method(ObjectRef, add_to_inventory),
{0,0} {0,0}
}; };
// Creates a new anonymous reference if id=0
static void objectref_get_or_create(lua_State *L, ServerActiveObject *cobj)
{
if(cobj->getId() == 0){
ObjectRef::create(L, cobj);
} else {
objectref_get(L, cobj->getId());
}
}
/* /*
Main export function Main export function
*/ */
@ -570,6 +602,7 @@ void scriptapi_add_environment(lua_State *L, ServerEnvironment *env)
lua_setfield(L, -2, "env"); lua_setfield(L, -2, "env");
} }
#if 0
// Dump stack top with the dump2 function // Dump stack top with the dump2 function
static void dump2(lua_State *L, const char *name) static void dump2(lua_State *L, const char *name)
{ {
@ -581,6 +614,7 @@ static void dump2(lua_State *L, const char *name)
if(lua_pcall(L, 2, 0, 0)) if(lua_pcall(L, 2, 0, 0))
script_error(L, "error: %s\n", lua_tostring(L, -1)); script_error(L, "error: %s\n", lua_tostring(L, -1));
} }
#endif
/* /*
object_reference object_reference
@ -815,8 +849,9 @@ void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime)
script_error(L, "error running function 'step': %s\n", lua_tostring(L, -1)); script_error(L, "error running function 'step': %s\n", lua_tostring(L, -1));
} }
void scriptapi_luaentity_rightclick_player(lua_State *L, u16 id, // Calls entity:on_punch(ObjectRef puncher)
const char *playername) void scriptapi_luaentity_punch(lua_State *L, u16 id,
ServerActiveObject *puncher)
{ {
realitycheck(L); realitycheck(L);
assert(lua_checkstack(L, 20)); assert(lua_checkstack(L, 20));
@ -827,12 +862,36 @@ void scriptapi_luaentity_rightclick_player(lua_State *L, u16 id,
luaentity_get(L, id); luaentity_get(L, id);
int object = lua_gettop(L); int object = lua_gettop(L);
// State: object is at top of stack // State: object is at top of stack
// Get step function // Get function
lua_getfield(L, -1, "on_punch");
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object); // self
objectref_get_or_create(L, puncher); // Clicker reference
// Call with 2 arguments, 0 results
if(lua_pcall(L, 2, 0, 0))
script_error(L, "error running function 'on_punch': %s\n", lua_tostring(L, -1));
}
// Calls entity:on_rightclick(ObjectRef clicker)
void scriptapi_luaentity_rightclick(lua_State *L, u16 id,
ServerActiveObject *clicker)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
StackUnroller stack_unroller(L);
// Get minetest.luaentities[id]
luaentity_get(L, id);
int object = lua_gettop(L);
// State: object is at top of stack
// Get function
lua_getfield(L, -1, "on_rightclick"); lua_getfield(L, -1, "on_rightclick");
luaL_checktype(L, -1, LUA_TFUNCTION); luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object); // self lua_pushvalue(L, object); // self
// Call with 1 arguments, 0 results objectref_get_or_create(L, clicker); // Clicker reference
if(lua_pcall(L, 1, 0, 0)) // Call with 2 arguments, 0 results
script_error(L, "error running function 'step': %s\n", lua_tostring(L, -1)); if(lua_pcall(L, 2, 0, 0))
script_error(L, "error running function 'on_rightclick': %s\n", lua_tostring(L, -1));
} }

@ -42,8 +42,10 @@ std::string scriptapi_luaentity_get_state(lua_State *L, u16 id);
void scriptapi_luaentity_get_properties(lua_State *L, u16 id, void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
LuaEntityProperties *prop); LuaEntityProperties *prop);
void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime); void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime);
void scriptapi_luaentity_rightclick_player(lua_State *L, u16 id, void scriptapi_luaentity_punch(lua_State *L, u16 id,
const char *playername); ServerActiveObject *clicker);
void scriptapi_luaentity_rightclick(lua_State *L, u16 id,
ServerActiveObject *clicker);
#endif #endif

@ -2300,9 +2300,22 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
//TODO: Check that object is reasonably close //TODO: Check that object is reasonably close
// Left click, pick object up (usually) // Get ServerRemotePlayer
ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
// Update wielded item
srp->wieldItem(item_i);
// Left click, pick/punch
if(button == 0) if(button == 0)
{ {
actionstream<<player->getName()<<" punches object "
<<obj->getId()<<std::endl;
// Do stuff
obj->punch(srp);
#if 0
/* /*
Try creating inventory item Try creating inventory item
*/ */
@ -2371,6 +2384,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
SendInventory(player->peer_id); SendInventory(player->peer_id);
} }
} }
#endif
} }
// Right click, do something with object // Right click, do something with object
if(button == 1) if(button == 1)
@ -2378,18 +2392,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
actionstream<<player->getName()<<" right clicks object " actionstream<<player->getName()<<" right clicks object "
<<obj->getId()<<std::endl; <<obj->getId()<<std::endl;
// Track hp changes super-crappily
u16 oldhp = player->hp;
// Do stuff // Do stuff
obj->rightClick(player); obj->rightClick(srp);
// Send back stuff
if(player->hp != oldhp)
{
SendPlayerHP(player);
}
} }
/*
Update player state to client
*/
SendPlayerHP(player);
UpdateCrafting(player->peer_id);
SendInventory(player->peer_id);
} }
else if(command == TOSERVER_GROUND_ACTION) else if(command == TOSERVER_GROUND_ACTION)
{ {

@ -71,6 +71,7 @@ public:
/* /*
Some more dynamic interface Some more dynamic interface
*/ */
virtual void setPos(v3f pos) virtual void setPos(v3f pos)
{ setBasePosition(pos); } { setBasePosition(pos); }
// continuous: if true, object does not stop immediately at pos // continuous: if true, object does not stop immediately at pos
@ -81,6 +82,10 @@ public:
virtual float getMinimumSavedMovement() virtual float getMinimumSavedMovement()
{ return 2.0*BS; } { return 2.0*BS; }
virtual bool isPeaceful(){return true;}
virtual std::string getDescription(){return "SAO";}
/* /*
Step object in time. Step object in time.
Messages added to messages are sent to client over network. Messages added to messages are sent to client over network.
@ -106,25 +111,21 @@ public:
*/ */
virtual std::string getStaticData(){return "";} virtual std::string getStaticData(){return "";}
/* virtual void punch(ServerActiveObject *puncher){}
Item that the player gets when this object is picked up. virtual void rightClick(ServerActiveObject *clicker){}
If NULL, object cannot be picked up.
*/
virtual InventoryItem* createPickedUpItem(){return NULL;}
/* // Returns a reference
If the object doesn't return an item, this will be called. virtual InventoryItem* getWieldedItem()
Return value is tool wear. { return NULL; }
*/ virtual void damageWieldedItem(u16 amount)
virtual u16 punch(const std::string &toolname, v3f dir, {}
const std::string &playername) // If all fits, eats item and returns true. Otherwise returns false.
{return 0;} virtual bool addToInventory(InventoryItem *item)
{return false;}
/* virtual void setHP(s16 hp)
*/ {}
virtual void rightClick(Player *player){} virtual s16 getHP()
{return 0;}
virtual bool isPeaceful(){return true;}
/* /*
Number of players which know about this object. Object won't be Number of players which know about this object. Object won't be