@ -25,14 +25,10 @@ local solid_drawtypes = {
glasslike_framed = true ,
}
local S = ( " S " ) : byte ( 1 )
local W = ( " W " ) : byte ( 1 )
local E = ( " E " ) : byte ( 1 )
local C = ( " C " ) : byte ( 1 )
--[[
E : empty
E : air
E_ : other empty
Etype : territory marker of some type
Stype : a go stone of some type
W : full block wall
WE0 - WE3 : edge concrete
@ -40,6 +36,11 @@ WC0-WC3: corner concrete
--]]
local function _check_position_uncached ( pos )
local node = minetest.get_node ( pos )
if node.name == " air " then
return " E "
end
local reg_item = minetest.registered_items [ node.name ]
if not reg_item then
@ -50,6 +51,10 @@ local function _check_position_uncached(pos)
return " S " .. reg_item.go_team
end
if reg_item.groups and reg_item.groups . go_territory_marker then
return " E " .. reg_item.go_team
end
if reg_item.pattern_def then
if reg_item.pattern_def . name == " edgy " then
return " WE " .. node.param2
@ -61,7 +66,7 @@ local function _check_position_uncached(pos)
if solid_drawtypes [ reg_item.drawtype ] and not reg_item.groups . falling_node then
return " W "
else
return " E "
return " E_ "
end
end
@ -80,8 +85,8 @@ end
local function edge_check ( pos , dir , terminate )
local under = check_position ( pos + down )
if under : byte ( 1 ) == W and under : len ( ) == 3 then
local corner = ( under : byte ( 2 ) == C )
if under : su b( 1 , 1 ) == " W" and under : len ( ) == 3 then
local corner = ( under : su b( 2 , 2 ) == " C" )
local edge_dir = tonumber ( under : sub ( 3 , 3 ) )
if ( dir == edge_dir ) or ( corner and ( dir == ( edge_dir + 1 ) % 4 ) ) then
@ -106,7 +111,7 @@ local function neighbor_dirs(pos)
local neighbors = { }
for i , v in pairs ( directions ) do
if not edge_check ( pos , i ) then
if not ( check_position ( pos + directions [ i ] ) : byte ( 1 ) == W ) then
if check_position ( pos + directions [ i ] ) : su b( 1 , 1 ) ~= " W " then
neighbors [ # neighbors + 1 ] = i
end
end
@ -115,16 +120,11 @@ local function neighbor_dirs(pos)
return neighbors
end
--[[
Scans for a connected group , until enumerating the whole group , or
finding a liberty . Returns list of captured nodes , or empty list if
no captures .
--]]
local function check_captures ( pos )
local function connected_search ( pos , final_result , early_termination_filter )
local group = { pos }
local stones = { [ minetest.hash_node_position ( pos ) ] = pos }
local checked = { }
local team = check_position ( pos ) : sub ( 2 , - 1 )
local piece = check_position ( pos )
local probe = 0
while probe < # group do
@ -138,10 +138,14 @@ local function check_captures(pos)
if ( not stones [ newhash ] ) and ( not checked [ newhash ] ) then
local newnode = check_position ( newpos )
if newnode : byte ( 1 ) == E then
return { capture = false , stones = stones }
elseif newnode : byte ( 1 ) == S and
newnode : sub ( 2 , - 1 ) == team then
local filter_result
if early_termination_filter then
filter_result = early_termination_filter ( newnode )
end
if filter_result then
filter_result.stones = stones
return filter_result
elseif newnode == piece then
stones [ newhash ] = newpos
group [ # group + 1 ] = newpos
else
@ -151,7 +155,61 @@ local function check_captures(pos)
end
end
return { capture = true , stones = stones }
final_result = final_result ( )
final_result.stones = stones
return final_result
end
local function _check_captures_filter ( node )
if node : sub ( 1 , 1 ) == " E " then
return { capture = false }
end
end
local function _check_captures_final ( )
return { capture = true }
end
local function check_captures ( pos )
return connected_search ( pos , _check_captures_final , _check_captures_filter )
end
local function _connected_group_final ( )
return { }
end
local function connected_group ( pos )
return connected_search ( pos , _connected_group_final )
end
local function territory_search ( pos , max )
if check_position ( pos ) ~= " E " then
return { }
end
local team
return connected_search ( pos ,
function ( )
return { team = team }
end ,
function ( node )
if node == " E " then
max = max - 1
if max <= 0 then
return { }
end
elseif node ~= " E_ " and ( ( node : sub ( 1 , 1 ) == " E " ) or ( node : sub ( 1 , 1 ) == " S " ) ) and node : len ( ) > 1 then
node = node : sub ( 2 , - 1 )
if team then
if team ~= node then
return { }
end
else
team = node
end
end
end
)
end
function lc_liberties . handle_placement ( pos )
@ -160,7 +218,7 @@ function lc_liberties.handle_placement(pos)
--nodecore.node_sound(pos, "dug")
local our_stone = check_position ( pos )
if not ( our_stone : byte ( 1 ) == S ) then
if our_stone : sub ( 1 , 1 ) ~= " S " then
return
end
our_stone = our_stone : sub ( 2 , - 1 )
@ -181,7 +239,7 @@ function lc_liberties.handle_placement(pos)
if not checked then
local node = check_position ( new_pos )
if ( node : byte ( 1 ) == S ) and ( not ( node : sub ( 2 , - 1 ) == our_stone ) ) then
if ( node : su b( 1 , 1 ) == " S " ) and ( node : sub ( 2 , - 1 ) ~= our_stone ) then
local captures = check_captures ( new_pos )
captured = captured or captures.capture
captureses [ # captureses + 1 ] = captures
@ -226,4 +284,39 @@ function lc_liberties.handle_placement(pos)
end
end
function lc_liberties . handle_territory_fill ( itemstack , placer , pointed_thing )
cache = { }
if placer.get_player_control and placer : get_player_control ( ) . aux1 then
return minetest.item_place ( itemstack , placer , pointed_thing )
end
if pointed_thing and pointed_thing.above then
local territories = territory_search ( pointed_thing.above , itemstack : get_count ( ) )
if territories.team then
local piece = modname .. " :territory_ " .. territories.team
local count = 0
for i , v in pairs ( territories.stones ) do
nodecore.set_loud ( v , { name = piece } )
count = count + 1
end
itemstack : set_count ( itemstack : get_count ( ) - count )
end
end
return itemstack
end
function lc_liberties . handle_dig ( pos , node , digger )
cache = { }
if digger.get_player_control and digger : get_player_control ( ) . aux1 then
for i , v in pairs ( connected_group ( pos ) . stones ) do
minetest.node_dig ( v , node , digger )
end
return true
else
return minetest.node_dig ( pos , node , digger )
end
end