Skip to content

Commit

Permalink
Team Loadout API for SCPUI (scp-fs2open#6096)
Browse files Browse the repository at this point in the history
* team loadout methods

* documentation

* address feedback

* better assertions
  • Loading branch information
Mike Nelson authored Apr 17, 2024
1 parent 002783c commit 7ae8c79
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 23 deletions.
40 changes: 29 additions & 11 deletions code/network/multiteamselect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,10 +348,6 @@ int Multi_ts_hotspot_index = -1;
#define TS_SWAP_PLAYER_PLAYER 4
#define TS_MOVE_PLAYER 5

// packet codes
#define TS_CODE_LOCK_TEAM 0 // the specified team's slots are locked
#define TS_CODE_PLAYER_UPDATE 1 // a player slot update for the specified team

// team data
#define MULTI_TS_FLAG_NONE -2 // slot is _always_ empty
#define MULTI_TS_FLAG_EMPTY -1 // flag is temporarily empty
Expand Down Expand Up @@ -1033,9 +1029,13 @@ void multi_ts_lock_pressed()
}

if(Netgame.type_flags & NG_TYPE_TEAM){
Assert(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN);
if (!(Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN)) {
return;
}
} else {
Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
if (!(Net_player->flags & NETINFO_FLAG_GAME_HOST)) {
return;
}
}
gamesnd_play_iface(InterfaceSounds::USER_SELECT);

Expand Down Expand Up @@ -1242,12 +1242,31 @@ void multi_ts_blit_wings()
}
}

bool multi_ts_is_player_in_slot(int slot_idx)
{
Assertion(slot_idx >= 0 && slot_idx < MAX_WSS_SLOTS, "Slot index is out of bounds!");
Assertion(Net_player != nullptr, "Cannot check the slot for the player because the player is null!");

return (Multi_ts_team[Net_player->p_info.team].multi_ts_player[slot_idx] != nullptr);
}

bool multi_ts_is_player_allowed_in_slot(int slot_idx)
{
Assertion(slot_idx >= 0 && slot_idx < MAX_WSS_SLOTS, "Slot index is out of bounds!");
Assertion(Net_player != nullptr, "Cannot check the slot for the player because the player is null!");

p_object * pobj = mission_parse_get_arrival_ship(Ships[Objects[Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[slot_idx]].instance].ship_name);
if ((pobj == NULL) || !(pobj->flags[Mission::Parse_Object_Flags::OF_Player_start])) {
return false;
}
return true;
}

// blit all of the player callsigns under the correct ships
void multi_ts_blit_wing_callsigns()
{
int idx,callsign_w;
char callsign[CALLSIGN_LEN+2];
p_object *pobj;

// blit them all blindly for now
for(idx=0;idx<MAX_WSS_SLOTS;idx++){
Expand All @@ -1257,13 +1276,12 @@ void multi_ts_blit_wing_callsigns()
}

// if there is a player in the slot
if(Multi_ts_team[Net_player->p_info.team].multi_ts_player[idx] != NULL){
if (multi_ts_is_player_in_slot(idx)) {
// make sure the string fits
strcpy_s(callsign,Multi_ts_team[Net_player->p_info.team].multi_ts_player[idx]->m_player->callsign);
} else {
// determine if this is a locked AI ship
pobj = mission_parse_get_arrival_ship(Ships[Objects[Multi_ts_team[Net_player->p_info.team].multi_ts_objnum[idx]].instance].ship_name);
if ((pobj == NULL) || !(pobj->flags[Mission::Parse_Object_Flags::OF_Player_start])) {
// determine if this is a locked AI ship
if (!multi_ts_is_player_allowed_in_slot(idx)) {
strcpy_s(callsign, NOX("<"));
strcat_s(callsign, XSTR("AI",738)); // [[ Artificial Intellegence ]]
strcat_s(callsign, NOX(">"));
Expand Down
10 changes: 10 additions & 0 deletions code/network/multiteamselect.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ extern int Multi_ts_inited;
extern int Multi_ts_deleted_objnums[MULTI_TS_MAX_TVT_TEAMS * MULTI_TS_NUM_SHIP_SLOTS];
extern int Multi_ts_num_deleted;

// packet codes
#define TS_CODE_LOCK_TEAM 0 // the specified team's slots are locked
#define TS_CODE_PLAYER_UPDATE 1 // a player slot update for the specified team

// ------------------------------------------------------------------------------------------------------
// TEAM SELECT FUNCTIONS
//
Expand Down Expand Up @@ -92,6 +96,12 @@ int multi_ts_is_locked();
// show a popup saying "only host and team captains can modify, etc, etc"
void multi_ts_maybe_host_only_popup();

// return if a player is currently in a loadout slot
bool multi_ts_is_player_in_slot(int slot_idx);

// return if a player is allowed in a loadout slot
bool multi_ts_is_player_allowed_in_slot(int slot_idx);

// ------------------------------------------------------------------------------------------------------
// TEAM SELECT PACKET HANDLERS
//
Expand Down
63 changes: 61 additions & 2 deletions code/scripting/api/libs/ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,15 @@ ADE_FUNC(startMusic, l_UserInterface_MainHall, nullptr, "Starts the mainhall mus
return ADE_RETURN_NIL;
}

ADE_FUNC(stopMusic, l_UserInterface_MainHall, "boolean Fade=false", "Stops the mainhall music. True to fade, false to stop immediately.", nullptr, "nothing")
{
bool fade = false;
if (!ade_get_args(L, "|b", &fade))
return ADE_RETURN_NIL;
main_hall_stop_music(fade);
return ADE_RETURN_NIL;
}

ADE_FUNC(toggleHelp,
l_UserInterface_MainHall,
"boolean",
Expand Down Expand Up @@ -1487,6 +1496,10 @@ ADE_INDEXER(l_Ship_Pool,
idx--; // Convert to Lua's 1 based index system

if (ADE_SETTING_VAR) {
if (Game_mode & GM_MULTIPLAYER) {
LuaError(L, "This property may not be modified in multiplayer.");
return ADE_RETURN_NIL;
}
if (amount < 0) {
Ss_pool[idx] = 0;
} else {
Expand Down Expand Up @@ -1521,6 +1534,10 @@ ADE_INDEXER(l_Weapon_Pool,
idx--; // Convert to Lua's 1 based index system

if (ADE_SETTING_VAR) {
if (Game_mode & GM_MULTIPLAYER) {
LuaError(L, "This property may not be modified in multiplayer.");
return ADE_RETURN_NIL;
}
if (amount < 0) {
Wl_pool[idx] = 0;
} else {
Expand Down Expand Up @@ -1609,6 +1626,48 @@ ADE_FUNC(__len, l_Loadout_Ships, nullptr, "The number of loadout ships", "number
return ade_set_args(L, "i", MAX_WING_BLOCKS*MAX_WING_SLOTS);
}

ADE_FUNC(sendShipRequestPacket,
l_UserInterface_ShipWepSelect,
"number FromType, number ToType, number FromSlotIndex, number ToSlotIndex, number ShipClassIndex",
"Sends a request to the host to change a ship slot. From/To types are 0 for Ship Slot, 1 for Player Slot, 2 for Pool",
nullptr,
nullptr)
{
int fromType; //2 for pool, 1 for player, 0 for slot
int toType; // 2 for pool, 1 for player, 0 for slot
int fromSlot;
int toSlot;
int shipClassIdx;
if (!ade_get_args(L, "iiiii", &fromType, &toType, &fromSlot, &toSlot, &shipClassIdx))
return ADE_RETURN_NIL;

// --revelant points to convert from lua indecies to c
multi_ts_drop(fromType, --fromSlot, toType, --toSlot, --shipClassIdx);

return ADE_RETURN_NIL;
}

ADE_FUNC(sendWeaponRequestPacket,
l_UserInterface_ShipWepSelect,
"number FromBank, number ToBank, number fromPoolWepIdx, number toPoolWepIdx, number shipSlot",
"Sends a request to the host to change a ship slot.",
nullptr,
nullptr)
{
int fromBank;
int toBank;
int fromList;
int toList;
int shipSlot;
if (!ade_get_args(L, "iiiii", &fromBank, &toBank, &fromList, &toList, &shipSlot))
return ADE_RETURN_NIL;

// --revelant points to convert from lua indecies to c
wl_drop(--fromBank, --fromList, --toBank, --toList, --shipSlot);

return ADE_RETURN_NIL;
}

//**********SUBLIBRARY: UserInterface/TechRoom
ADE_LIB_DERIV(l_UserInterface_TechRoom,
"TechRoom",
Expand Down Expand Up @@ -3363,14 +3422,14 @@ ADE_FUNC(closeMultiHostSetup,
int idx = -1;
if (Netgame.campaign_mode == MULTI_CREATE_SHOW_MISSIONS)
for (size_t i = 0; i < Multi_create_mission_list.size(); i++) {
if (strcmp(Multi_create_mission_list[i].filename, Netgame.mission_name) != 0) {
if (strcmp(Multi_create_mission_list[i].filename, Netgame.mission_name) == 0) {
idx = static_cast<int>(i);
break;
}
}
else {
for (size_t i = 0; i < Multi_create_campaign_list.size(); i++) {
if (strcmp(Multi_create_campaign_list[i].filename, Netgame.mission_name) != 0) {
if (strcmp(Multi_create_campaign_list[i].filename, Netgame.mission_name) == 0) {
idx = static_cast<int>(i);
break;
}
Expand Down
101 changes: 92 additions & 9 deletions code/scripting/api/objs/shipwepselect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "ship/ship.h"
#include "weapon/weapon.h"
#include "missionui/missionweaponchoice.h"
#include "network/multiteamselect.h"

namespace scripting {
namespace api {
Expand All @@ -17,8 +18,13 @@ ss_wing_info* ss_wing_info_h::getWing() const
return &Ss_wings[ss_wing];
}

int ss_wing_info_h::getWingIndex() const
{
return ss_wing;
}

ss_slot_info_h::ss_slot_info_h() {}
ss_slot_info_h::ss_slot_info_h(ss_slot_info* l_slots, int l_idx) : ss_slots(l_slots), ss_idx(l_idx) {}
ss_slot_info_h::ss_slot_info_h(ss_slot_info* l_slots, int l_idx, int l_wing) : ss_slots(l_slots), ss_idx(l_idx), ss_wing(l_wing) {}
bool ss_slot_info_h::isValid() const
{
return ss_slots != nullptr;
Expand All @@ -28,6 +34,16 @@ ss_slot_info* ss_slot_info_h::getSlot() const
return &ss_slots[ss_idx];
}

int ss_slot_info_h::getSlotIndex() const
{
return ss_idx;
}

int ss_slot_info_h::getWingIndex() const
{
return ss_wing;
}

wss_unit_wep_h::wss_unit_wep_h() : ss_unit(-1) {}
wss_unit_wep_h::wss_unit_wep_h(int l_unit) : ss_unit(l_unit) {}
bool wss_unit_wep_h::isValid() const
Expand All @@ -52,10 +68,6 @@ wss_unit* wss_unit_count_h::getBank() const
return &Wss_slots[ss_unit];
}

// HERE BE MY NOTES SIR!
// create_wings() in missionshipchoice.cpp seems to be what we want to finally use on Commit, maybe


//**********HANDLE: loadout wing
ADE_OBJ(l_Loadout_Wing_Slot, ss_slot_info_h, "loadout_wing_slot", "Loadout wing slot handle");

Expand Down Expand Up @@ -92,7 +104,7 @@ ADE_VIRTVAR(isWeaponLocked,
return ade_set_args(L, "b", (current.getSlot()->status & WING_SLOT_WEAPONS_DISABLED) != 0);
}

ADE_VIRTVAR(isDisabled, l_Loadout_Wing_Slot, nullptr, "If the slot is not used in the current mission", "boolean", "The slot disabled status")
ADE_VIRTVAR(isDisabled, l_Loadout_Wing_Slot, nullptr, "If the slot is not used in the current mission or disabled for the current player in multi", "boolean", "The slot disabled status")
{
ss_slot_info_h current;
if (!ade_get_args(L, "o", l_Loadout_Wing_Slot.Get(&current))) {
Expand All @@ -103,7 +115,13 @@ ADE_VIRTVAR(isDisabled, l_Loadout_Wing_Slot, nullptr, "If the slot is not used i
LuaError(L, "This property is read only.");
}

return ade_set_args(L, "b", !current.getSlot()->in_mission);
bool result = !current.getSlot()->in_mission;
if (Game_mode & GM_MULTIPLAYER) {
int index = (current.getWingIndex() * MAX_WING_SLOTS) + current.getSlotIndex();
result = multi_ts_disabled_slot(index);
}

return ade_set_args(L, "b", result);
}

ADE_VIRTVAR(isFilled, l_Loadout_Wing_Slot, "boolean", "If the slot is empty or filled. true if filled, false if empty", "boolean", "The slot filled status")
Expand All @@ -115,6 +133,10 @@ ADE_VIRTVAR(isFilled, l_Loadout_Wing_Slot, "boolean", "If the slot is empty or f
}

if (ADE_SETTING_VAR) {
if (Game_mode & GM_MULTIPLAYER) {
LuaError(L, "This property may not be modified in multiplayer.");
return ADE_RETURN_NIL;
}
if (!(current.getSlot()->status & WING_SLOT_DISABLED)) {
if (setv) {
current.getSlot()->status &= ~WING_SLOT_EMPTY;
Expand Down Expand Up @@ -142,8 +164,35 @@ ADE_VIRTVAR(isPlayer, l_Loadout_Wing_Slot, nullptr, "If the slot is a player shi
LuaError(L, "This property is read only.");
}

return ade_set_args(L, "b", (current.getSlot()->status & WING_SLOT_IS_PLAYER) != 0);
bool result = (current.getSlot()->status & WING_SLOT_IS_PLAYER) != 0;
if (Game_mode & GM_MULTIPLAYER) {
int index = (current.getWingIndex() * MAX_WING_SLOTS) + current.getSlotIndex();
result = multi_ts_is_player_in_slot(index);
}

return ade_set_args(L, "b", result);
}

ADE_VIRTVAR(isPlayerAllowed, l_Loadout_Wing_Slot, nullptr, "If the slot is allowed to have player ship. In single player this is functionally the same as isPlayer.", "boolean", "The slot player allowed status")
{
ss_slot_info_h current;
if (!ade_get_args(L, "o", l_Loadout_Wing_Slot.Get(&current))) {
return ADE_RETURN_NIL;
}

if (ADE_SETTING_VAR) {
LuaError(L, "This property is read only.");
}

bool result = (current.getSlot()->status & WING_SLOT_IS_PLAYER) != 0;
if (Game_mode & GM_MULTIPLAYER) {
int index = (current.getWingIndex() * MAX_WING_SLOTS) + current.getSlotIndex();
result = multi_ts_is_player_allowed_in_slot(index);
}

return ade_set_args(L, "b", result);
}

// Probably don't need this one!
ADE_VIRTVAR(ShipClassIndex,
l_Loadout_Wing_Slot,
Expand All @@ -164,6 +213,28 @@ ADE_VIRTVAR(ShipClassIndex,
return ade_set_args(L, "i", (current.getSlot()->original_ship_class + 1));
}

ADE_VIRTVAR(Callsign,
l_Loadout_Wing_Slot,
nullptr,
"The callsign of the ship slot. In multiplayer this may be the player's callsign.",
"string",
"the callsign")
{
ss_slot_info_h current;
if (!ade_get_args(L, "o", l_Loadout_Wing_Slot.Get(&current))) {
return ADE_RETURN_NIL;
}

if (ADE_SETTING_VAR) {
LuaError(L, "This property is read only.");
}

char name[NAME_LENGTH];
ss_return_name(current.getWingIndex(), current.getSlotIndex(), name);

return ade_set_args(L, "s", name);
}

//**********HANDLE: loadout amount
ADE_OBJ(l_Loadout_Amount, wss_unit_count_h, "loadout_amount", "Loadout handle");

Expand All @@ -188,6 +259,10 @@ ADE_INDEXER(l_Loadout_Amount,

idx--; // Convert from Lua
if (ADE_SETTING_VAR) {
if (Game_mode & GM_MULTIPLAYER) {
LuaError(L, "This property may not be modified in multiplayer.");
return ADE_RETURN_NIL;
}
ship_info* sip = &Ship_info[current.getBank()->ship_class];
int widx = current.getBank()->wep[idx];
if (widx >= 0 && widx < (int)Weapon_info.size()) {
Expand Down Expand Up @@ -255,6 +330,10 @@ ADE_INDEXER(l_Loadout_Weapon,
wepIndex--; // Convert from Lua
bank--; //Convert from Lua
if (ADE_SETTING_VAR) {
if (Game_mode & GM_MULTIPLAYER) {
LuaError(L, "This property may not be modified in multiplayer.");
return ADE_RETURN_NIL;
}
if (bankType == -1 || wepIndex > weapon_info_size()) {
LuaError(L, "The provided bank or weapon index is invalid!");
} else {
Expand Down Expand Up @@ -319,6 +398,10 @@ ADE_VIRTVAR(ShipClassIndex,
shipIndex--; //Convert from Lua

if (ADE_SETTING_VAR) {
if (Game_mode & GM_MULTIPLAYER) {
LuaError(L, "This property may not be modified in multiplayer.");
return ADE_RETURN_NIL;
}
if (shipIndex > -1) {
// If we're not trying to empty the slot then make sure it's a valid ship index
if (shipIndex > ship_info_size()) {
Expand Down Expand Up @@ -391,7 +474,7 @@ ADE_INDEXER(l_Loadout_Wing,
if (!ade_get_args(L, "oi", l_Loadout_Wing.Get(&current), &idx))
return ade_set_error(L, "s", "");
idx--; // Convert to Lua's 1 based index system
return ade_set_args(L, "o", l_Loadout_Wing_Slot.Set(ss_slot_info_h(current.getWing()->ss_slots, idx)));
return ade_set_args(L, "o", l_Loadout_Wing_Slot.Set(ss_slot_info_h(current.getWing()->ss_slots, idx, current.getWingIndex())));
}

//This seems superfluous because the loadout wing slots is always max but not only is it something scripters may expect,
Expand Down
Loading

0 comments on commit 7ae8c79

Please sign in to comment.