Skip to content
Snippets Groups Projects
Select Git revision
  • next default protected
  • wad-start-and-end-from-srb2classic
  • fix-emerald-hunt
  • woof-midi-port
  • fix-1425
  • expose-path-traverse
  • can-hurt-self-score-fix
  • post-mobj-thinker
  • hms-useragent
  • gitlab-ci
  • nightshoopsanity
  • fullscreen-toggle
  • next-test
  • bbox
  • cmake-enable-cxx
  • master
  • more-use-afters-frees
  • cmake-clang-tidy
  • cmake-valgrind
  • font_drawer
  • SRB2_release_2.2.10
  • SRB2_release_2.2.9
  • SRB2_release_2.2.8
  • SRB2_release_2.2.7
  • SRB2_release_2.2.6
  • SRB2_release_2.2.5
  • SRB2_release_2.2.4
  • SRB2_release_2.2.3
  • SRB2_release_2.2.2
  • SRB2_release_2.2.1
  • SRB2_release_2.2.0
  • SRB2_release_2.1.25
  • SRB2_release_2.1.24
  • SRB2_release_2.1.23
  • SRB2_release_2.1.22
  • SRB2_release_2.1.21
  • SRB2_release_2.1.20
  • SRB2_release_2.1.19
  • SRB2_release_2.1.18
  • td-release-v1.0.0
40 results

lua_blockmaplib.c

Blame
  • Forked from STJr / SRB2
    217 commits behind, 2 commits ahead of the upstream repository.
    Lactozilla's avatar
    Lactozilla authored
    This was added by the Doom developers to work around the issue where
    objects were not linked into all blockmap cells they were touching, and
    instead just the one at the object's center. Since this is no longer
    the case after commit 41613d89,
    this adjustment is no longer necessary.
    e7f581a9
    History
    lua_blockmaplib.c 8.65 KiB
    // SONIC ROBO BLAST 2
    //-----------------------------------------------------------------------------
    // Copyright (C) 2016-2023 by Iestyn "Monster Iestyn" Jealous.
    // Copyright (C) 2016-2023 by Sonic Team Junior.
    //
    // This program is free software distributed under the
    // terms of the GNU General Public License, version 2.
    // See the 'LICENSE' file for more details.
    //-----------------------------------------------------------------------------
    /// \file  lua_blockmaplib.c
    /// \brief blockmap library for Lua scripting
    
    #include "doomdef.h"
    #include "p_local.h"
    #include "r_main.h" // validcount
    #include "p_polyobj.h"
    #include "lua_script.h"
    #include "lua_libs.h"
    //#include "lua_hud.h" // hud_running errors
    
    static const char *const search_opt[] = {
    	"objects",
    	"lines",
    	"polyobjs",
    	NULL};
    
    // a quickly-made function pointer typedef used by lib_searchBlockmap...
    // return values:
    // 0 - normal, no interruptions
    // 1 - stop search through current block
    // 2 - stop search completely
    typedef UINT8 (*blockmap_func)(lua_State *, INT32, INT32, mobj_t *);
    
    static boolean blockfuncerror = false; // errors should only print once per search blockmap call
    
    // Helper function for "objects" search
    static UINT8 lib_searchBlockmap_Objects(lua_State *L, mobj_t *thing, mobj_t *mobj)
    {
    	lua_pushvalue(L, 1); // push function
    	LUA_PushUserdata(L, thing, META_MOBJ);
    	LUA_PushUserdata(L, mobj, META_MOBJ);
    	if (lua_pcall(gL, 2, 1, 0)) {
    		if (!blockfuncerror || cv_debug & DBG_LUA)
    			CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
    		lua_pop(gL, 1);
    		blockfuncerror = true;
    		return 0; // *shrugs*
    	}
    	if (!lua_isnil(gL, -1))
    	{ // if nil, continue
    		if (lua_toboolean(gL, -1))
    			return 2; // stop whole search
    		else
    			return 1; // stop block search
    	}
    	lua_pop(gL, 1);
    	if (P_MobjWasRemoved(thing)) // func just popped our thing, cannot continue.
    		return P_MobjWasRemoved(thing) ? 2 : 1;
    	return 0;
    }
    
    // Helper function for "lines" search
    static UINT8 lib_searchBlockmap_Lines(lua_State *L, INT32 x, INT32 y, mobj_t *thing)
    {
    	INT32 offset;
    	const INT32 *list; // Big blockmap
    	polymaplink_t *plink; // haleyjd 02/22/06
    	line_t *ld;
    
    	if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
    		return 0;
    
    	offset = y*bmapwidth + x;
    
    	// haleyjd 02/22/06: consider polyobject lines
    	plink = polyblocklinks[offset];
    
    	while (plink)
    	{
    		polyobj_t *po = plink->po;
    
    		if (po->validcount != validcount) // if polyobj hasn't been checked
    		{
    			size_t i;
    			po->validcount = validcount;
    
    			for (i = 0; i < po->numLines; ++i)
    			{
    				if (po->lines[i]->validcount == validcount) // line has been checked
    					continue;
    				po->lines[i]->validcount = validcount;
    
    				lua_pushvalue(L, 1);
    				LUA_PushUserdata(L, thing, META_MOBJ);
    				LUA_PushUserdata(L, po->lines[i], META_LINE);
    				if (lua_pcall(gL, 2, 1, 0)) {
    					if (!blockfuncerror || cv_debug & DBG_LUA)
    						CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
    					lua_pop(gL, 1);
    					blockfuncerror = true;
    					return 0; // *shrugs*
    				}
    				if (!lua_isnil(gL, -1))
    				{ // if nil, continue
    					if (lua_toboolean(gL, -1))
    						return 2; // stop whole search
    					else
    						return 1; // stop block search
    				}
    				lua_pop(gL, 1);
    				if (P_MobjWasRemoved(thing))
    					return 2;
    			}
    		}
    		plink = (polymaplink_t *)(plink->link.next);
    	}
    
    	offset = *(blockmap + offset); // offset = blockmap[y*bmapwidth+x];
    
    	// First index is really empty, so +1 it.
    	for (list = blockmaplump + offset + 1; *list != -1; list++)
    	{
    		ld = &lines[*list];
    
    		if (ld->validcount == validcount)
    			continue; // Line has already been checked.
    
    		ld->validcount = validcount;
    
    		lua_pushvalue(L, 1);
    		LUA_PushUserdata(L, thing, META_MOBJ);
    		LUA_PushUserdata(L, ld, META_LINE);
    		if (lua_pcall(gL, 2, 1, 0)) {
    			if (!blockfuncerror || cv_debug & DBG_LUA)
    				CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
    			lua_pop(gL, 1);
    			blockfuncerror = true;
    			return 0; // *shrugs*
    		}
    		if (!lua_isnil(gL, -1))
    		{ // if nil, continue
    			if (lua_toboolean(gL, -1))
    				return 2; // stop whole search
    			else
    				return 1; // stop block search
    		}
    		lua_pop(gL, 1);
    		if (P_MobjWasRemoved(thing))
    			return 2;
    	}
    	return 0; // Everything was checked.
    }
    
    // Helper function for "polyobjs" search
    static UINT8 lib_searchBlockmap_PolyObjs(lua_State *L, INT32 x, INT32 y, mobj_t *thing)
    {
    	INT32 offset;
    	polymaplink_t *plink; // haleyjd 02/22/06
    
    	if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
    		return 0;
    
    	offset = y*bmapwidth + x;
    
    	// haleyjd 02/22/06: consider polyobject lines
    	plink = polyblocklinks[offset];
    
    	while (plink)
    	{
    		polyobj_t *po = plink->po;
    
    		if (po->validcount != validcount) // if polyobj hasn't been checked
    		{
    			po->validcount = validcount;
    
    			lua_pushvalue(L, 1);
    			LUA_PushUserdata(L, thing, META_MOBJ);
    			LUA_PushUserdata(L, po, META_POLYOBJ);
    			if (lua_pcall(gL, 2, 1, 0)) {
    				if (!blockfuncerror || cv_debug & DBG_LUA)
    					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
    				lua_pop(gL, 1);
    				blockfuncerror = true;
    				return 0; // *shrugs*
    			}
    			if (!lua_isnil(gL, -1))
    			{ // if nil, continue
    				if (lua_toboolean(gL, -1))
    					return 2; // stop whole search
    				else
    					return 1; // stop block search
    			}
    			lua_pop(gL, 1);
    			if (P_MobjWasRemoved(thing))
    				return 2;
    		}
    		plink = (polymaplink_t *)(plink->link.next);
    	}
    
    	return 0; // Everything was checked.
    }
    
    // The searchBlockmap function
    // arguments: searchBlockmap(searchtype, function, mobj, [x1, x2, y1, y2])
    // return value:
    //   true = search completely uninteruppted,
    //   false = searching of at least one block stopped mid-way (including if the whole search was stopped)
    static int lib_searchBlockmap(lua_State *L)
    {
    	int searchtype = luaL_checkoption(L, 1, "objects", search_opt);
    	int n;
    	mobj_t *mobj;
    	INT32 xl, xh, yl, yh, bx, by;
    	fixed_t x1, x2, y1, y2;
    	boolean retval = true;
    	UINT8 funcret = 0;
    	blockmap_func searchFunc;
    	boolean searchObjects = false;
    
    	lua_remove(L, 1); // remove searchtype, stack is now function, mobj, [x1, x2, y1, y2]
    	luaL_checktype(L, 1, LUA_TFUNCTION);
    
    	switch (searchtype)
    	{
    		case 0: // "objects"
    		default:
    			searchObjects = true;
    			searchFunc = NULL;
    			break;
    		case 1: // "lines"
    			searchFunc = lib_searchBlockmap_Lines;
    			break;
    		case 2: // "polyobjs"
    			searchFunc = lib_searchBlockmap_PolyObjs;
    			break;
    	}
    
    	// the mobj we are searching around, the "calling" mobj we could say
    	mobj = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
    	if (!mobj)
    		return LUA_ErrInvalid(L, "mobj_t");
    
    	n = lua_gettop(L);
    
    	if (n > 2) // specific x/y ranges have been supplied
    	{
    		if (n < 6)
    			return luaL_error(L, "arguments 4 to 6 not all given (expected 4 fixed-point integers)");
    
    		x1 = luaL_checkfixed(L, 3);
    		x2 = luaL_checkfixed(L, 4);
    		y1 = luaL_checkfixed(L, 5);
    		y2 = luaL_checkfixed(L, 6);
    	}
    	else // mobj and function only - search around mobj's radius by default
    	{
    		x1 = mobj->x - mobj->radius;
    		x2 = mobj->x + mobj->radius;
    		y1 = mobj->y - mobj->radius;
    		y2 = mobj->y + mobj->radius;
    	}
    	lua_settop(L, 2); // pop everything except function, mobj
    
    	xl = (unsigned)(x1 - bmaporgx)>>MAPBLOCKSHIFT;
    	xh = (unsigned)(x2 - bmaporgx)>>MAPBLOCKSHIFT;
    	yl = (unsigned)(y1 - bmaporgy)>>MAPBLOCKSHIFT;
    	yh = (unsigned)(y2 - bmaporgy)>>MAPBLOCKSHIFT;
    
    	BMBOUNDFIX(xl, xh, yl, yh);
    
    	blockfuncerror = false; // reset
    
    	if (!searchObjects) {
    		validcount++;
    
    		for (bx = xl; bx <= xh; bx++)
    			for (by = yl; by <= yh; by++)
    			{
    				funcret = searchFunc(L, bx, by, mobj);
    
    				// return value of searchFunc determines searchFunc's return value and/or when to stop
    				if (funcret == 2) { // stop whole search
    					lua_pushboolean(L, false); // return false
    					return 1;
    				}
    				else if (funcret == 1) // search was interrupted for this block
    					retval = false; // this changes the return value, but doesn't stop the whole search
    
    				// else don't do anything, continue as normal
    				if (P_MobjWasRemoved(mobj)) { // ...unless the original object was removed
    					lua_pushboolean(L, false); // in which case we have to stop now regardless
    					return 1;
    				}
    			}
    	}
    	else {
    		bthingit_t *it = P_NewBlockThingsIterator(xl, yl, xh, yh);
    		if (!it) {
    			lua_pushboolean(L, false);
    			return 1;
    		}
    
    		mobj_t *itmobj = NULL;
    
    		do
    		{
    			itmobj = P_BlockThingsIteratorNext(it, false);
    			if (itmobj)
    			{
    				if (mobj == itmobj)
    					continue; // our thing just found itself, so move on
    
    				funcret = lib_searchBlockmap_Objects(L, mobj, itmobj);
    				if (funcret == 2 || P_MobjWasRemoved(mobj)) {
    					retval = false;
    					break;
    				}
    				else if (funcret == 1)
    					retval = false;
    			}
    		}
    		while (itmobj != NULL);
    
    		P_FreeBlockThingsIterator(it);
    	}
    
    	lua_pushboolean(L, retval);
    	return 1;
    }
    
    int LUA_BlockmapLib(lua_State *L)
    {
    	lua_register(L, "searchBlockmap", lib_searchBlockmap);
    	return 0;
    }