Files
2025-09-29 00:52:08 +02:00

302 lines
13 KiB
XML
Executable File

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Name: turret_manager_sup.sch //
// Description: "Private" support methods for the turret management system. Mostly contains server-side //
// methods to deal with client lock requests. //
// See turret_manager_core.sch for more details. //
// //
// Written by: Online Technical Team: Orlando C-H //
// Date: 05/09/2018 //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
USING "turret_manager_public.sch"
USING "turret_manager_def.sch"
USING "globals.sch"
USING "script_network.sch"
USING "net_include.sch"
/// PURPOSE:
/// Queries server data for a free turret index given a group and instance.
/// No ordering is taken into account.
///
/// Only guarenteed to be up to date for the freemode host.
/// Request use of a turret with TURRET_MANAGER_CREATE_LOCK_REQUEST.
/// PARAMS:
/// ref_iTurretId - Set to the turret index. Only valid if the function returns true.
/// RETURNS:
///
FUNC BOOL GET_ANY_FREE_TURRET_ID(TURRET_GROUP_TYPE eGroupType, INT iInstanceId, INT& ref_iTurretId)
INT iTurretCount = TURRET_GROUP_TURRET_COUNT(eGroupType)
IF iTurretCount > ci_MAX_TURRET_GROUP_SIZE
ASSERTLN("[ARENA_TURRET] GET_FIRST_FREE_TURRET_ID - INCREASE ci_MAX_TURRET_GROUP_SIZE")
RETURN FALSE
ENDIF
BOOL bInUse[ci_MAX_TURRET_GROUP_SIZE]
INT i
REPEAT COUNT_OF(GlobalServerBD.turrets.players) i
IF GlobalServerBD.turrets.players[i].iInstanceId = iInstanceId
AND GlobalServerBD.turrets.players[i].groupType = eGroupType
bInUse[GlobalServerBD.turrets.players[i].iTurretId] = TRUE
ENDIF
ENDREPEAT
REPEAT COUNT_OF(bInUse) i
IF NOT bInUse[i]
ref_iTurretId = i
CDEBUG1LN(DEBUG_NET_TURRET, "GET_ANY_FREE_TURRET_ID Found free turretId = ", ref_iTurretId)
RETURN TRUE
ENDIF
ENDREPEAT
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks the serverBd to see if a turret is free.
/// Only guarenteed to be up to date for the freemode host.
/// Request use of a turret with TURRET_MANAGER_CREATE_LOCK_REQUEST.
FUNC BOOL GET_NEXT_FREE_TURRET_ID(BOOL bForwards, TURRET_GROUP_TYPE eGroupType, INT iInstanceId, INT& ref_iTurretId)
INT iTurretCount = TURRET_GROUP_TURRET_COUNT(eGroupType)
IF iTurretCount > ci_MAX_TURRET_GROUP_SIZE
ASSERTLN("[ARENA_TURRET] GET_FIRST_FREE_TURRET_ID - INCREASE ci_MAX_TURRET_GROUP_SIZE")
RETURN FALSE
ENDIF
BOOL bInUse[ci_MAX_TURRET_GROUP_SIZE]
INT i
REPEAT COUNT_OF(GlobalServerBD.turrets.players) i
IF GlobalServerBD.turrets.players[i].iInstanceId = iInstanceId
AND GlobalServerBD.turrets.players[i].groupType = eGroupType
bInUse[GlobalServerBD.turrets.players[i].iTurretId] = TRUE
ENDIF
ENDREPEAT
INT iClosestId = ref_iTurretId
INT iClosestDist = ci_MAX_TURRET_GROUP_SIZE
IF bForwards
REPEAT COUNT_OF(bInUse) i
IF NOT bInUse[i]
AND ref_iTurretId <> i
INT iDist = i - ref_iTurretId
// Wrap distance around 0->max
IF iDist < 0
iDist += iTurretCount
ENDIF
IF iDist < iClosestDist
iClosestId = i
iClosestDist = iDist
ENDIF
ENDIF
ENDREPEAT
ELSE
REPEAT COUNT_OF(bInUse) i
IF NOT bInUse[i]
AND ref_iTurretId <> i
INT iDist = ref_iTurretId - i
// Wrap distance around 0->max
IF iDist < 0
iDist += iTurretCount
ENDIF
IF iDist < iClosestDist
iClosestId = i
iClosestDist = iDist
ENDIF
ENDIF
ENDREPEAT
ENDIF
IF iClosestId = ref_iTurretId
RETURN FALSE
ELSE
ref_iTurretId = iClosestId
RETURN TRUE
ENDIF
ENDFUNC
/// PURPOSE:
/// Checks the serverBd to see if a turret is free.
/// Only guarenteed to be up to date for the freemode host.
/// Request use of a turret with TURRET_MANAGER_CREATE_LOCK_REQUEST.
/// Returns -1 if turret is free.
FUNC PLAYER_INDEX GET_PLAYER_IN_TURRET(TURRET_GROUP_TYPE eGroupType, INT iInstanceId, INT iTurretId)
INT iPlayer
REPEAT COUNT_OF(GlobalServerBD.turrets.players) iPlayer
IF GlobalServerBD.turrets.players[iPlayer].groupType = eGroupType
AND GlobalServerBD.turrets.players[iPlayer].iInstanceId = iInstanceId
AND GlobalServerBD.turrets.players[iPlayer].iTurretId = iTurretId
RETURN INT_TO_NATIVE(PLAYER_INDEX, iPlayer)
ENDIF
ENDREPEAT
RETURN INT_TO_NATIVE(PLAYER_INDEX, -1)
ENDFUNC
/// PURPOSE:
/// Checks the serverBd to see if a turret is free.
/// Only guarenteed to be up to date for the freemode host.
/// Request use of a turret with TURRET_MANAGER_CREATE_LOCK_REQUEST.
FUNC BOOL IS_THIS_TURRET_ID_IS_FREE(TURRET_GROUP_TYPE eGroupType, INT iInstanceId, INT iTurretId)
PLAYER_INDEX player = GET_PLAYER_IN_TURRET(eGroupType, iInstanceId, iTurretId)
RETURN NATIVE_TO_INT(player) = -1
ENDFUNC
/// PURPOSE:
/// Returns FALSE if no turretId is free with matching eGroupType and iInstanceId.
FUNC BOOL IS_TURRET_FREE(INT& ref_iTurretId, INT iInstanceId, TURRET_GROUP_TYPE eGroupType, TURRET_LOCK_SEARCH_TYPE eSearchType)
CDEBUG1LN(DEBUG_NET_TURRET, "IS_TURRET_FREE eGroupType = ", ENUM_TO_INT(eGroupType), " iInstanceId = ",iInstanceId, " iTurretId = ", ref_iTurretId, " eSearchType = ", eSearchType)
SWITCH eSearchType
CASE TLST_THIS_TURRET_ONLY
RETURN IS_THIS_TURRET_ID_IS_FREE(eGroupType, iInstanceId, ref_iTurretId)
CASE TLST_ANY_TURRET
RETURN GET_ANY_FREE_TURRET_ID(eGroupType, iInstanceId, ref_iTurretId)
CASE TLST_ANY_TURRET_FORWARDS
RETURN GET_NEXT_FREE_TURRET_ID(TRUE, eGroupType, iInstanceId, ref_iTurretId)
CASE TLST_ANY_TURRET_BACKWARDS
RETURN GET_NEXT_FREE_TURRET_ID(FALSE, eGroupType, iInstanceId, ref_iTurretId)
DEFAULT
RETURN FALSE
ENDSWITCH
ENDFUNC
/// PURPOSE:
/// Save the arguments into global broadcast data for the turret management system.
PROC TURRET_MANAGER_SERVER_SET_DATA(PLAYER_INDEX player, TURRET_GROUP_TYPE eGroup, INT iInstanceId, INT iTurretId)
INT iPlayerIndex = NATIVE_TO_INT(player)
IF iPlayerIndex < 0
OR iPlayerIndex >= COUNT_OF(GlobalServerBD.turrets.players)
PRINTLN("TURRET_MANAGER_SERVER_SET_DATA [VALIDATE] - invalid player index in player: ", iPlayerIndex)
SCRIPT_ASSERT("TURRET_MANAGER_SERVER_SET_DATA [VALIDATE] - invalid player index in player")
EXIT
ENDIF
INT iTurretGroupType = ENUM_TO_INT(eGroup)
IF iTurretGroupType < 0
OR iTurretGroupType > ENUM_TO_INT(TGT_ARENA_CONTESTANT)
CDEBUG1LN(DEBUG_NET_TURRET, "TURRET_MANAGER_SERVER_SET_DATA [VALIDATE] - invalid TURRET_GROUP_TYPE in eGroup, expected value between 0 and TGT_ARENA_CONTESTANT, actual value: ", iTurretGroupType)
SCRIPT_ASSERT("TURRET_MANAGER_SERVER_SET_DATA [VALIDATE] - invalid TURRET_GROUP_TYPE in eGroup")
EXIT
ENDIF
IF iTurretId < 0
OR iTurretId >= ci_MAX_TURRET_GROUP_SIZE
CDEBUG1LN(DEBUG_NET_TURRET, "TURRET_MANAGER_SERVER_SET_DATA [VALIDATE] - invalid value in iTurretId, expected value between 0 and (ci_MAX_TURRET_GROUP_SIZE-1), actual value: ", iTurretId)
SCRIPT_ASSERT("TURRET_MANAGER_SERVER_SET_DATA [VALIDATE] - invalid value in iTurretId")
EXIT
ENDIF
GlobalServerBD.turrets.players[iPlayerIndex].groupType = eGroup
GlobalServerBD.turrets.players[iPlayerIndex].iInstanceId = iInstanceId
GlobalServerBD.turrets.players[iPlayerIndex].iTurretId = iTurretId
ENDPROC
/// PURPOSE:
/// This proc takes data from a request "ref_iRequestArray" and populates "ref_iResponseArray"
/// with data to send back to the player who requested a turret change.
///
/// This should only be handled by the player owning the turret serverBd (GlobalServerBD.turrets - freemode host).
PROC PROCESS_SERVER_RESPONSE_TO_TURRET_REQUEST(PLAYER_INDEX player, INT& ref_iRequestArray[], INT& ref_iResponseArray[])
CDEBUG1LN(DEBUG_NET_TURRET, "[SERVER] PROCESS_SERVER_RESPONSE_TO_TURRET_REQUEST for ", GET_PLAYER_NAME(player), " (", NATIVE_TO_INT(player),")")
TURRET_GROUP_TYPE eGroupTypeRequest = INT_TO_ENUM(TURRET_GROUP_TYPE, ref_iRequestArray[ci_TURRET_RQST_GRP])
TURRET_LOCK_SEARCH_TYPE eSearchType = INT_TO_ENUM(TURRET_LOCK_SEARCH_TYPE, ref_iRequestArray[ci_TURRET_RQST_SEARCH])
TURRET_GROUP_TYPE eCurrentGroupType = TURRET_MANAGER_GET_GROUP(player)
SWITCH eGroupTypeRequest
CASE TGT_NONE
CDEBUG1LN(DEBUG_NET_TURRET, "[SERVER] Setting player turret to TGT_NONE.")
// To release a turret simply set the group type to tgt_none & copy other data.
ref_iResponseArray[ci_TURRET_RQST_TURRET] = ref_iRequestArray[ci_TURRET_RQST_TURRET]
ref_iResponseArray[ci_TURRET_RQST_INST] = ref_iRequestArray[ci_TURRET_RQST_INST]
ref_iResponseArray[ci_TURRET_RQST_UID] = ref_iRequestArray[ci_TURRET_RQST_UID]
ref_iResponseArray[ci_TURRET_RQST_SEARCH] = ref_iRequestArray[ci_TURRET_RQST_SEARCH]
ref_iResponseArray[ci_TURRET_RQST_BS] = ref_iRequestArray[ci_TURRET_RQST_BS]
ref_iResponseArray[ci_TURRET_RQST_GRP] = ENUM_TO_INT(TGT_NONE)
BREAK
DEFAULT
// Defualt behaviour : Return requested turret details & set group type to TGT_NONE if
// the turret isn't free.
ref_iResponseArray[ci_TURRET_RQST_GRP] = ref_iRequestArray[ci_TURRET_RQST_GRP]
ref_iResponseArray[ci_TURRET_RQST_TURRET] = ref_iRequestArray[ci_TURRET_RQST_TURRET]
ref_iResponseArray[ci_TURRET_RQST_INST] = ref_iRequestArray[ci_TURRET_RQST_INST]
ref_iResponseArray[ci_TURRET_RQST_UID] = ref_iRequestArray[ci_TURRET_RQST_UID]
ref_iResponseArray[ci_TURRET_RQST_SEARCH] = ref_iRequestArray[ci_TURRET_RQST_SEARCH]
ref_iResponseArray[ci_TURRET_RQST_BS] = ref_iRequestArray[ci_TURRET_RQST_BS]
IF NOT IS_TURRET_FREE(ref_iResponseArray[ci_TURRET_RQST_TURRET], ref_iRequestArray[ci_TURRET_RQST_INST], eGroupTypeRequest, eSearchType)
IF eCurrentGroupType <> TGT_NONE
AND IS_BIT_SET(ref_iRequestArray[ci_TURRET_RQST_BS], ci_TURRET_LOCK_BS_DO_NOT_KICK)
CDEBUG1LN(DEBUG_NET_TURRET, "[SERVER] ci_TURRET_LOCK_BS_DO_NOT_KICK - not kicking player from their current turret.")
// Don't kick player form current turret on fail.
ref_iResponseArray[ci_TURRET_RQST_TURRET] = TURRET_MANAGER_GET_TURRET_ID(player)
ref_iResponseArray[ci_TURRET_RQST_GRP] = ENUM_TO_INT(eCurrentGroupType)
ref_iResponseArray[ci_TURRET_RQST_INST] = TURRET_MANAGER_GET_INSTANCE_ID(player)
ELSE
// Respond with fail & kick from turret if they're in one.
ref_iResponseArray[ci_TURRET_RQST_TURRET] = -1
ref_iResponseArray[ci_TURRET_RQST_GRP] = ENUM_TO_INT(TGT_NONE)
ENDIF
ENDIF
BREAK
ENDSWITCH
// Assign response to serverBd
PRINT_TURRET_RQST(ref_iResponseArray)
TURRET_MANAGER_SERVER_SET_DATA(player, INT_TO_ENUM(TURRET_GROUP_TYPE, ref_iResponseArray[ci_TURRET_RQST_GRP]), ref_iResponseArray[ci_TURRET_RQST_INST], ref_iResponseArray[ci_TURRET_RQST_TURRET])
ENDPROC
FUNC TURRET_OCCUPANCY_DATA CONVERT_TURRET_REQUEST_DATA(INT& ref_iRequestArray[])
TURRET_OCCUPANCY_DATA data
IF COUNT_OF(ref_iRequestArray) < ci_TURRET_RQST_COUNT
ASSERTLN("CONVERT_TURRET_REQUEST_DATA int array too small")
RETURN data
ENDIF
data.iInstanceId = ref_iRequestArray[ci_TURRET_RQST_INST]
data.groupType = INT_TO_ENUM(TURRET_GROUP_TYPE, ref_iRequestArray[ci_TURRET_RQST_GRP])
data.iTurretId = ref_iRequestArray[ci_TURRET_RQST_TURRET]
RETURN data
ENDFUNC
PROC SAVE_TURRET_LOCK_RESPONSE(INT& ref_iResponseArray[])
IF COUNT_OF(ref_iResponseArray) < ci_TURRET_RQST_COUNT
ASSERTLN("SET_TURRET_REQUEST_RESPONSE Response int array too small")
EXIT
ENDIF
g_turretLockResponse = CONVERT_TURRET_REQUEST_DATA(ref_iResponseArray)
g_iTurretLockResponseUid = INT_TO_ENUM(TURRET_LOCK_REQUEST_ID, ref_iResponseArray[ci_TURRET_RQST_UID])
// No need to save response search settings
CDEBUG1LN(DEBUG_NET_TURRET, "SAVE_TURRET_LOCK_RESPONSE: ")
PRINT_TURRET_RQST(ref_iResponseArray)
ENDPROC
/// PURPOSE:
/// Fill "ref_iRequestArray" with the data required for a turret request event.
///
PROC FILL_TURRET_REQUEST_DATA(TURRET_OCCUPANCY_DATA& ref_request, INT iUniqueId, TURRET_LOCK_SEARCH_TYPE eSearchType, INT iSettingsBs, INT& ref_iRequestArray[])
IF COUNT_OF(ref_iRequestArray) < ci_TURRET_RQST_COUNT
ASSERTLN("SET_TURRET_REQUEST_RESPONSE Request int array too small")
EXIT
ENDIF
ref_iRequestArray[ci_TURRET_RQST_UID] = iUniqueId
ref_iRequestArray[ci_TURRET_RQST_INST] = ref_request.iInstanceId
ref_iRequestArray[ci_TURRET_RQST_GRP] = ENUM_TO_INT(ref_request.groupType)
ref_iRequestArray[ci_TURRET_RQST_TURRET] = ref_request.iTurretId
ref_iRequestArray[ci_TURRET_RQST_SEARCH] = ENUM_TO_INT(eSearchType)
ref_iRequestArray[ci_TURRET_RQST_BS] = iSettingsBs
ENDPROC