2013-07-29 07:13:03 -04:00
// LuaWindow.cpp
// Implements the cLuaWindow class representing a virtual window that plugins may create and open for the player
# include "Globals.h"
# include "LuaWindow.h"
2013-12-08 06:17:54 -05:00
# include "../UI/SlotArea.h"
2013-08-09 09:15:56 -04:00
# include "PluginLua.h"
2014-07-17 16:15:34 -04:00
# include "lua/src/lauxlib.h" // Needed for LUA_REFNIL
2013-07-29 07:13:03 -04:00
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2013-07-29 07:13:03 -04:00
// cLuaWindow:
2016-06-10 15:30:07 -04:00
cLuaWindow : : cLuaWindow ( cLuaState & a_LuaState , cWindow : : WindowType a_WindowType , int a_SlotsX , int a_SlotsY , const AString & a_Title ) :
Super ( a_WindowType , a_Title ) ,
2013-07-29 07:13:03 -04:00
m_Contents ( a_SlotsX , a_SlotsY ) ,
2016-06-10 15:30:07 -04:00
m_LuaState ( a_LuaState . QueryCanonLuaState ( ) )
2013-07-29 07:13:03 -04:00
{
2016-06-10 15:30:07 -04:00
ASSERT ( m_LuaState ! = nullptr ) ; // We must have a valid Lua state; this assert fails only if there was no Canon Lua state
2013-07-29 07:13:03 -04:00
m_Contents . AddListener ( * this ) ;
m_SlotAreas . push_back ( new cSlotAreaItemGrid ( m_Contents , * this ) ) ;
2016-02-05 16:45:45 -05:00
2013-07-29 07:13:03 -04:00
// If appropriate, add an Armor slot area:
switch ( a_WindowType )
{
2013-10-28 08:30:24 -04:00
case cWindow : : wtInventory :
case cWindow : : wtWorkbench :
2013-07-29 07:13:03 -04:00
{
m_SlotAreas . push_back ( new cSlotAreaArmor ( * this ) ) ;
break ;
}
2013-12-09 09:17:39 -05:00
default :
{
break ;
}
2013-07-29 07:13:03 -04:00
}
m_SlotAreas . push_back ( new cSlotAreaInventory ( * this ) ) ;
m_SlotAreas . push_back ( new cSlotAreaHotBar ( * this ) ) ;
}
cLuaWindow : : ~ cLuaWindow ( )
{
2013-08-17 18:39:15 -04:00
m_Contents . RemoveListener ( * this ) ;
// Must delete slot areas now, because they are referencing this->m_Contents and would try to access it in cWindow's
// destructor, when the member is already gone.
for ( cSlotAreas : : iterator itr = m_SlotAreas . begin ( ) , end = m_SlotAreas . end ( ) ; itr ! = end ; + + itr )
{
delete * itr ;
}
m_SlotAreas . clear ( ) ;
2013-07-29 07:13:03 -04:00
ASSERT ( m_OpenedBy . empty ( ) ) ;
}
2016-06-27 14:49:59 -04:00
void cLuaWindow : : SetOnClosing ( cLuaState : : cCallbackPtr & & a_OnClosing )
2013-07-29 07:13:03 -04:00
{
2016-06-10 15:30:07 -04:00
// Only one Lua state can be a cLuaWindow object callback:
ASSERT ( a_OnClosing - > IsSameLuaState ( * m_LuaState ) ) ;
2013-07-29 07:13:03 -04:00
2016-06-10 15:30:07 -04:00
// Store the new reference, releasing the old one if appropriate:
2016-06-27 14:49:59 -04:00
m_OnClosing = std : : move ( a_OnClosing ) ;
2013-07-29 07:13:03 -04:00
}
2016-06-27 14:49:59 -04:00
void cLuaWindow : : SetOnSlotChanged ( cLuaState : : cCallbackPtr & & a_OnSlotChanged )
2013-07-29 07:13:03 -04:00
{
2016-06-10 15:30:07 -04:00
// Only one Lua state can be a cLuaWindow object callback:
ASSERT ( a_OnSlotChanged - > IsSameLuaState ( * m_LuaState ) ) ;
2016-02-05 16:45:45 -05:00
2016-06-10 15:30:07 -04:00
// Store the new reference, releasing the old one if appropriate:
2016-06-27 14:49:59 -04:00
m_OnSlotChanged = std : : move ( a_OnSlotChanged ) ;
2013-07-29 07:13:03 -04:00
}
2016-06-10 15:30:07 -04:00
void cLuaWindow : : OpenedByPlayer ( cPlayer & a_Player )
2013-07-29 07:13:03 -04:00
{
2016-06-10 15:30:07 -04:00
// If the first player is opening the window, create a Lua Reference to the window object so that Lua will not GC it until the last player closes the window:
if ( m_PlayerCount = = 0 )
2013-07-29 07:13:03 -04:00
{
2016-06-10 15:30:07 -04:00
m_LuaRef . CreateFromObject ( * m_LuaState , this ) ;
2013-07-29 07:13:03 -04:00
}
2016-02-05 16:45:45 -05:00
2016-06-10 15:30:07 -04:00
+ + m_PlayerCount ;
Super : : OpenedByPlayer ( a_Player ) ;
2013-07-29 07:13:03 -04:00
}
bool cLuaWindow : : ClosedByPlayer ( cPlayer & a_Player , bool a_CanRefuse )
{
// First notify the plugin through the registered callback:
2016-06-10 15:30:07 -04:00
if ( m_OnClosing ! = nullptr )
2013-07-29 07:13:03 -04:00
{
2016-06-10 15:30:07 -04:00
bool res ;
if (
m_OnClosing - > Call ( this , & a_Player , a_CanRefuse , cLuaState : : Return , res ) & & // The callback succeeded
res // The callback says not to close the window
)
2013-07-29 07:13:03 -04:00
{
// The callback disagrees (the higher levels check the CanRefuse flag compliance)
return false ;
}
}
2016-02-05 16:45:45 -05:00
2016-06-10 15:30:07 -04:00
// If the last player has closed the window, release the Lua reference, so that Lua may GC the object:
- - m_PlayerCount ;
if ( m_PlayerCount = = 0 )
{
m_LuaRef . UnRef ( ) ;
}
return Super : : ClosedByPlayer ( a_Player , a_CanRefuse ) ;
2013-07-29 07:13:03 -04:00
}
void cLuaWindow : : Destroy ( void )
{
2016-06-10 15:30:07 -04:00
Super : : Destroy ( ) ;
2016-02-05 16:45:45 -05:00
2015-05-09 05:16:56 -04:00
// Lua will take care of this object, it will garbage-collect it, so we must not delete it!
2013-07-29 07:13:03 -04:00
m_IsDestroyed = false ;
}
2015-05-09 05:16:56 -04:00
void cLuaWindow : : DistributeStack ( cItem & a_ItemStack , int a_Slot , cPlayer & a_Player , cSlotArea * a_ClickedArea , bool a_ShouldApply )
2014-12-17 13:14:01 -05:00
{
cSlotAreas Areas ;
2015-05-09 05:16:56 -04:00
for ( auto & & Area : m_SlotAreas )
2014-12-17 13:14:01 -05:00
{
if ( Area ! = a_ClickedArea )
{
Areas . push_back ( Area ) ;
}
}
2016-06-10 15:30:07 -04:00
Super : : DistributeStackToAreas ( a_ItemStack , a_Player , Areas , a_ShouldApply , false ) ;
2014-12-17 13:14:01 -05:00
}
2013-07-29 07:13:03 -04:00
void cLuaWindow : : OnSlotChanged ( cItemGrid * a_ItemGrid , int a_SlotNum )
{
if ( a_ItemGrid ! = & m_Contents )
{
ASSERT ( ! " Invalid ItemGrid in callback " ) ;
return ;
}
2016-02-05 16:45:45 -05:00
2013-07-29 07:13:03 -04:00
// If an OnSlotChanged callback has been registered, call it:
2016-06-10 15:30:07 -04:00
if ( m_OnSlotChanged ! = nullptr )
2013-07-29 07:13:03 -04:00
{
2016-06-10 15:30:07 -04:00
m_OnSlotChanged - > Call ( this , a_SlotNum ) ;
2013-07-29 07:13:03 -04:00
}
}