362 lines
11 KiB
Lua
362 lines
11 KiB
Lua
if SM64COOPDX_VERSION == nil then return end
|
|
|
|
ARENA_FLAG_INVALID_GLOBAL = 0xFF
|
|
---
|
|
|
|
gArenaFlagInfo = {}
|
|
sFlagScoreTimer = 0
|
|
|
|
define_custom_obj_fields({
|
|
oArenaFlagTeam = 'u32',
|
|
oArenaFlagHeldByGlobal = 'u32',
|
|
oArenaFlagAtBase = 'u32',
|
|
})
|
|
|
|
function bhv_arena_flag_init(obj)
|
|
local team = (obj.oBehParams >> 24) & 0xFF
|
|
|
|
obj.oFlags = OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE
|
|
obj.oOpacity = 255
|
|
obj.oArenaFlagTeam = team
|
|
obj.oArenaFlagHeldByGlobal = ARENA_FLAG_INVALID_GLOBAL
|
|
obj.oArenaFlagAtBase = 1
|
|
|
|
gArenaFlagInfo[team] = {
|
|
pos = { x = obj.oPosX, y = obj.oPosY, z = obj.oPosZ },
|
|
team = team,
|
|
obj = obj,
|
|
}
|
|
|
|
if team == 0 then
|
|
obj_set_model_extended(obj, E_MODEL_FLAG_WHITE)
|
|
elseif team == 1 then
|
|
obj_set_model_extended(obj, E_MODEL_FLAG_RED)
|
|
elseif team == 2 then
|
|
obj_set_model_extended(obj, E_MODEL_FLAG_BLUE)
|
|
else
|
|
obj_mark_for_deletion(obj)
|
|
end
|
|
|
|
network_init_object(obj, false, {
|
|
'oArenaFlagHeldByGlobal',
|
|
'oArenaFlagAtBase',
|
|
'oPosX',
|
|
'oPosY',
|
|
'oPosZ',
|
|
})
|
|
end
|
|
|
|
function bhv_arena_flag_update_pos_rot(obj)
|
|
-- spin
|
|
obj.oFaceAngleYaw = obj.oFaceAngleYaw - 600
|
|
obj.oFaceAngleRoll = 0
|
|
obj.oFaceAnglePitch = 0
|
|
|
|
local data = gArenaFlagInfo[obj.oArenaFlagTeam]
|
|
if obj.oArenaFlagAtBase == 1 then
|
|
-- set at base
|
|
obj.oPosX = data.pos.x
|
|
obj.oPosY = data.pos.y
|
|
obj.oPosZ = data.pos.z
|
|
return
|
|
end
|
|
|
|
if obj.oArenaFlagHeldByGlobal == ARENA_FLAG_INVALID_GLOBAL then
|
|
return
|
|
end
|
|
|
|
local np = network_player_from_global_index(obj.oArenaFlagHeldByGlobal)
|
|
if np == nil then
|
|
return
|
|
end
|
|
|
|
-- set at player
|
|
local m = gMarioStates[np.localIndex]
|
|
local awayMag = -50
|
|
local yOffset = 50
|
|
if np.localIndex ~= 0 then
|
|
yOffset = 150
|
|
awayMag = -30
|
|
end
|
|
obj.oPosX = m.pos.x + sins(m.faceAngle.y) * awayMag
|
|
obj.oPosY = m.pos.y + yOffset
|
|
obj.oPosZ = m.pos.z + coss(m.faceAngle.y) * awayMag
|
|
obj.oFaceAngleYaw = m.faceAngle.y + 0x4000
|
|
obj.oFaceAngleRoll = -0x400
|
|
end
|
|
|
|
function bhv_arena_flag_update_score(obj)
|
|
if gGlobalSyncTable.gameMode ~= GAME_MODE_FT and gGlobalSyncTable.gameMode ~= GAME_MODE_TFT then
|
|
return
|
|
end
|
|
|
|
if not network_is_server() then
|
|
return
|
|
end
|
|
|
|
if obj.oArenaFlagTeam ~= 0 then
|
|
return
|
|
end
|
|
|
|
if obj.oArenaFlagHeldByGlobal == ARENA_FLAG_INVALID_GLOBAL then
|
|
return
|
|
end
|
|
|
|
if gGlobalSyncTable.gameState ~= GAME_STATE_ACTIVE then
|
|
return
|
|
end
|
|
|
|
local np = network_player_from_global_index(obj.oArenaFlagHeldByGlobal)
|
|
if np == nil then
|
|
return
|
|
end
|
|
|
|
sFlagScoreTimer = sFlagScoreTimer + 1
|
|
if (sFlagScoreTimer % 30) == 0 then
|
|
local s = gPlayerSyncTable[np.localIndex]
|
|
s.score = s.score + 1
|
|
if gGlobalSyncTable.gameMode == GAME_MODE_TFT then
|
|
local teamScore = calculate_team_score(s.team)
|
|
if teamScore >= gGameModes[gGlobalSyncTable.gameMode].scoreCap then
|
|
round_end()
|
|
end
|
|
elseif s.score >= gGameModes[gGlobalSyncTable.gameMode].scoreCap then
|
|
round_end()
|
|
end
|
|
end
|
|
end
|
|
|
|
function bhv_arena_flag_update_rotation(obj)
|
|
if obj.oArenaFlagHeldByGlobal ~= ARENA_FLAG_INVALID_GLOBAL then
|
|
return
|
|
end
|
|
end
|
|
|
|
function bhv_arena_flag_return(obj, showMessage)
|
|
if obj.oArenaFlagAtBase == 1 then
|
|
return
|
|
end
|
|
local otherTeam = get_other_team(obj.oArenaFlagTeam)
|
|
local data = gArenaFlagInfo[obj.oArenaFlagTeam]
|
|
|
|
obj.oArenaFlagHeldByGlobal = ARENA_FLAG_INVALID_GLOBAL
|
|
obj.oArenaFlagAtBase = 1
|
|
obj.oPosX = data.pos.x
|
|
obj.oPosY = data.pos.y
|
|
obj.oPosZ = data.pos.z
|
|
network_send_object(obj, true)
|
|
if showMessage then
|
|
local msg = string.format('%sThe %s%s%s flag was returned!', team_color_str(otherTeam), team_color_str(obj.oArenaFlagTeam), team_name_str(obj.oArenaFlagTeam), team_color_str(otherTeam))
|
|
send_arena_flag(obj.oArenaFlagTeam, ARENA_FLAG_INVALID_GLOBAL, msg)
|
|
end
|
|
end
|
|
|
|
function bhv_arena_flag_collect(obj, m)
|
|
local data = gArenaFlagInfo[obj.oArenaFlagTeam]
|
|
local s = gPlayerSyncTable[m.playerIndex]
|
|
local np = gNetworkPlayers[m.playerIndex]
|
|
local e = gMarioStateExtras[m.playerIndex]
|
|
if e.levelTimer < 30 then
|
|
return false
|
|
end
|
|
|
|
if obj.oArenaFlagTeam > 0 and s.team == obj.oArenaFlagTeam then
|
|
if obj.oArenaFlagAtBase == 1 then
|
|
local otherTeam = get_other_team(obj.oArenaFlagTeam)
|
|
local otherData = gArenaFlagInfo[otherTeam]
|
|
local otherFlag = otherData.obj
|
|
if otherFlag.oArenaFlagHeldByGlobal == np.globalIndex then
|
|
-- capture flag
|
|
otherFlag.oArenaFlagHeldByGlobal = ARENA_FLAG_INVALID_GLOBAL
|
|
otherFlag.oArenaFlagAtBase = 1
|
|
otherFlag.oPosX = otherData.pos.x
|
|
otherFlag.oPosY = otherData.pos.y
|
|
otherFlag.oPosZ = otherData.pos.z
|
|
network_send_object(otherFlag, true)
|
|
local msg = string.format('%s%s captured the %s%s%s flag!', team_color_str(s.team), strip_colors(np.name), team_color_str(otherTeam), team_name_str(otherTeam), team_color_str(s.team))
|
|
send_arena_flag(otherFlag.oArenaFlagTeam, np.globalIndex, msg)
|
|
if gGlobalSyncTable.gameState == GAME_STATE_ACTIVE then
|
|
if s.team == 1 then
|
|
gGlobalSyncTable.capTeam1 = gGlobalSyncTable.capTeam1 + 1
|
|
if gGlobalSyncTable.capTeam1 >= gGameModes[gGlobalSyncTable.gameMode].scoreCap then
|
|
round_end()
|
|
end
|
|
elseif s.team == 2 then
|
|
gGlobalSyncTable.capTeam2 = gGlobalSyncTable.capTeam2 + 1
|
|
if gGlobalSyncTable.capTeam2 >= gGameModes[gGlobalSyncTable.gameMode].scoreCap then
|
|
round_end()
|
|
end
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- return flag
|
|
obj.oArenaFlagHeldByGlobal = ARENA_FLAG_INVALID_GLOBAL
|
|
obj.oArenaFlagAtBase = 1
|
|
obj.oPosX = data.pos.x
|
|
obj.oPosY = data.pos.y
|
|
obj.oPosZ = data.pos.z
|
|
network_send_object(obj, true)
|
|
local msg = string.format('%s%s returned the %s flag!', team_color_str(s.team), strip_colors(np.name), team_name_str(s.team))
|
|
send_arena_flag(obj.oArenaFlagTeam, np.globalIndex, msg)
|
|
return true
|
|
end
|
|
|
|
-- pick up flag
|
|
obj.oArenaFlagHeldByGlobal = np.globalIndex
|
|
obj.oArenaFlagAtBase = 0
|
|
obj.oTimer = 0
|
|
obj.oPosX = m.pos.x
|
|
obj.oPosY = m.pos.y
|
|
obj.oPosZ = m.pos.z
|
|
network_send_object(obj, true)
|
|
local msg = string.format('%s%s picked up the %s%s%s flag!', team_color_str(s.team), strip_colors(np.name), team_color_str(obj.oArenaFlagTeam), team_name_str(obj.oArenaFlagTeam), team_color_str(s.team))
|
|
send_arena_flag(obj.oArenaFlagTeam, np.globalIndex, msg)
|
|
return true
|
|
end
|
|
|
|
function bhv_arena_flag_check_collect(obj)
|
|
if not network_is_server() then
|
|
return
|
|
end
|
|
|
|
if obj.oArenaFlagHeldByGlobal ~= ARENA_FLAG_INVALID_GLOBAL then
|
|
return
|
|
end
|
|
|
|
for i = 0, MAX_PLAYERS - 1 do
|
|
local m = gMarioStates[i]
|
|
local player = m.marioObj
|
|
local yDist = math.abs(obj.oPosY - player.oPosY)
|
|
local xzDist = math.sqrt((obj.oPosX - player.oPosX) ^ 2 + (obj.oPosZ - player.oPosZ) ^ 2)
|
|
if active_player(m) and mario_health_float(m) > 0 and xzDist < 160 and yDist < 250 then
|
|
if bhv_arena_flag_collect(obj, m) then
|
|
return
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function bhv_arena_update_scale(obj)
|
|
local np = gNetworkPlayers[0]
|
|
if obj.oArenaFlagHeldByGlobal == np.globalIndex then
|
|
cur_obj_scale(0.4)
|
|
else
|
|
cur_obj_scale(1.0)
|
|
end
|
|
end
|
|
|
|
function bhv_arena_flag_check_drop(obj)
|
|
if not network_is_server() then
|
|
return
|
|
end
|
|
|
|
if obj.oArenaFlagHeldByGlobal == ARENA_FLAG_INVALID_GLOBAL then
|
|
return
|
|
end
|
|
|
|
local np = network_player_from_global_index(obj.oArenaFlagHeldByGlobal)
|
|
if np == nil then
|
|
bhv_arena_flag_return(obj, true)
|
|
return
|
|
end
|
|
|
|
local m = gMarioStates[np.localIndex]
|
|
local s = gPlayerSyncTable[np.localIndex]
|
|
if not active_player(m) then
|
|
bhv_arena_flag_return(obj, true)
|
|
return
|
|
end
|
|
|
|
if mario_health_float(m) <= 0 then
|
|
obj.oArenaFlagHeldByGlobal = ARENA_FLAG_INVALID_GLOBAL
|
|
obj.oArenaFlagAtBase = 0
|
|
obj.oTimer = 0
|
|
network_send_object(obj, true)
|
|
local msg = string.format('%s%s dropped the %s%s%s flag!', team_color_str(s.team), strip_colors(np.name), team_color_str(obj.oArenaFlagTeam), team_name_str(obj.oArenaFlagTeam), team_color_str(s.team))
|
|
send_arena_flag(obj.oArenaFlagTeam, ARENA_FLAG_INVALID_GLOBAL, msg)
|
|
return
|
|
end
|
|
end
|
|
|
|
function bhv_arena_flag_check_death(npVictim)
|
|
if not network_is_server() then
|
|
return
|
|
end
|
|
if npVictim == nil then
|
|
return
|
|
end
|
|
for teamNum = 0, 2 do
|
|
local data = gArenaFlagInfo[teamNum]
|
|
if data ~= nil and data.obj ~= nil and npVictim.globalIndex == data.obj.oArenaFlagHeldByGlobal then
|
|
bhv_arena_flag_return(data.obj, true)
|
|
end
|
|
end
|
|
end
|
|
|
|
function bhv_arena_flag_check_return(obj)
|
|
if not network_is_server() then
|
|
return
|
|
end
|
|
if obj.oArenaFlagHeldByGlobal ~= ARENA_FLAG_INVALID_GLOBAL then
|
|
return
|
|
end
|
|
if obj.oArenaFlagAtBase == 1 then
|
|
return
|
|
end
|
|
if obj.oTimer > 30 * 30 then
|
|
obj.oTimer = 0
|
|
bhv_arena_flag_return(obj, true)
|
|
end
|
|
end
|
|
|
|
function bhv_arena_flag_reset()
|
|
for teamNum = 0, 2 do
|
|
local data = gArenaFlagInfo[teamNum]
|
|
if data ~= nil and data.obj ~= nil then
|
|
bhv_arena_flag_return(data.obj, false)
|
|
end
|
|
end
|
|
end
|
|
|
|
function bhv_arena_flag_hide(obj)
|
|
if gGlobalSyncTable.gameMode == GAME_MODE_CTF and (obj.oArenaFlagTeam == 1 or obj.oArenaFlagTeam == 2) then
|
|
cur_obj_unhide()
|
|
return false
|
|
elseif (gGlobalSyncTable.gameMode == GAME_MODE_FT or gGlobalSyncTable.gameMode == GAME_MODE_TFT) and obj.oArenaFlagTeam == 0 then
|
|
cur_obj_unhide()
|
|
return false
|
|
else
|
|
cur_obj_hide()
|
|
return true
|
|
end
|
|
end
|
|
|
|
function is_holding_flag(m)
|
|
local np = gNetworkPlayers[m.playerIndex]
|
|
for teamNum = 0, 2 do
|
|
local data = gArenaFlagInfo[teamNum]
|
|
if data ~= nil and data.obj ~= nil and np.globalIndex == data.obj.oArenaFlagHeldByGlobal then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function bhv_arena_flag_loop(obj)
|
|
if bhv_arena_flag_hide(obj) then
|
|
return
|
|
end
|
|
bhv_arena_flag_update_pos_rot(obj)
|
|
bhv_arena_flag_update_score(obj)
|
|
bhv_arena_flag_check_collect(obj)
|
|
bhv_arena_update_scale(obj)
|
|
bhv_arena_flag_check_drop(obj)
|
|
bhv_arena_flag_check_return(obj)
|
|
end
|
|
|
|
id_bhvArenaFlag = hook_behavior(nil, OBJ_LIST_LEVEL, true, bhv_arena_flag_init, bhv_arena_flag_loop)
|