Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Player general orders #5638

Merged
merged 11 commits into from
Oct 26, 2023
163 changes: 160 additions & 3 deletions code/ai/ailua.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,134 @@ const player_order_lua* ai_lua_find_player_order(int sexp_op) {
return &aiLuaOrder->second;
}

int ai_lua_get_num_general_orders() {
int count = 0;

for (const auto& order : Lua_player_orders) {
if (order.second.generalOrder) {
count++;
}
}

return count;
}

SCP_vector<SCP_string> ai_lua_get_general_order_categories(bool enabled_only)
{
SCP_vector<SCP_string> list;

for (const auto& order : Lua_player_orders) {
const SCP_string &cat = order.second.category;

// If it's not a general order then move on
if (!order.second.generalOrder) {
continue;
}

// If the order is not enabled then move on
if (enabled_only && !order.second.cur_enabled) {
continue;
}

Assertion((cat.length() > 0), "Lua general orders category name must be longer than 0 characters!");

for (size_t i = 0; i <= list.size(); i++) {

// reached the end of the list, so add it
if (i == list.size()) {
list.push_back(cat);
break;
}

// if it's already in the list then don't add it
if (cat == list[i]) {
break;
}
}
}

return list;
}

SCP_vector<SCP_string> ai_lua_get_general_orders(bool onlyEnabled, bool onlyValid, const SCP_string& category)
{
SCP_vector<SCP_string> list;

for (auto order : Lua_player_orders) {
if (order.second.generalOrder) {
bool add = false;

// Only enabled orders
if (onlyEnabled && order.second.cur_enabled) {
add = true;

// Only valid orders
} else if (onlyValid && order.second.cur_valid) {
add = true;

// Only orders that match the category requested
} else if ((!category.empty()) && (order.second.category == category)) {
add = true;

// All general orders
} else {
add = true;
}

if (add) {
list.push_back(order.second.parseText);
}
}
}

return list;
}

int ai_lua_find_general_order_id(const SCP_string& name) {
for (const auto& order : Lua_player_orders) {
if (order.second.parseText == name) {
return order.first;
}
}

return -1;
}

void ai_lua_enable_general_order(int sexp_op, bool enable) {
auto aiLuaOrder = Lua_player_orders.find(sexp_op);

if (aiLuaOrder == Lua_player_orders.end())
return;
else
aiLuaOrder->second.cur_enabled = enable;
}

void ai_lua_validate_general_order(int sexp_op, bool validity)
{
auto aiLuaOrder = Lua_player_orders.find(sexp_op);

if (aiLuaOrder == Lua_player_orders.end())
return;
else
aiLuaOrder->second.cur_valid = validity;
}

void ai_lua_reset_general_orders() {
for (auto order : Lua_player_orders) {
ai_lua_enable_general_order(order.first, false);
ai_lua_validate_general_order(order.first, false);
}
}

bool ai_lua_is_general_order(int sexp_op) {
auto aiLuaOrder = Lua_player_orders.find(sexp_op);

if (aiLuaOrder == Lua_player_orders.end())
return false;

return aiLuaOrder->second.generalOrder;
}

void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua_ai, ai_info* aip) {
if (!action.isValid()) {
Error(LOCATION,
Expand All @@ -56,7 +184,11 @@ void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua
}

luacpp::LuaValueList luaParameters;
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h(&Objects[Ships[aip->shipnum].objnum]))));
if (aip->shipnum >= 0){
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h(&Objects[Ships[aip->shipnum].objnum]))));
} else {
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h())));
}
if (lua_ai.needsTarget) {
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(aip->lua_ai_target.target)));
}
Expand All @@ -67,8 +199,13 @@ void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);

if (!retVals.empty() && retVals[0].getValueType() == luacpp::ValueType::BOOLEAN) {
if (retVals[0].getValue<bool>())
ai_mission_goal_complete(aip);
if (retVals[0].getValue<bool>()) {

// If we don't have a ship then it's a general order and we have nothing else to do
if (aip->shipnum >= 0) {
ai_mission_goal_complete(aip);
}
}
}
}

Expand Down Expand Up @@ -103,6 +240,26 @@ void ai_lua_start(ai_goal* aigp, object* objp){
run_ai_lua_action(action, lua_ai, aip);
}

// For sending general orders that don't run on a ship.
// Essentially just runs arbitrary lua script when the command is called
void ai_lua_start_general(int lua_sexp_id, int target_objnum)
{
//Create a dummy aip to pass the target data
ai_info aip;
aip.shipnum = -1;

if (target_objnum >= 0) {
aip.lua_ai_target = {object_ship_wing_point_team(&Ships[Objects[target_objnum].instance]), {}};
}

const auto& lua_ai = ai_lua_find_mode(lua_sexp_id);

const auto& lua_ai_sexp = lua_ai->sexp;
const auto& action = lua_ai_sexp.getActionEnter();

run_ai_lua_action(action, *lua_ai, &aip);
}

bool ai_lua_is_valid_target_intrinsic(int sexp_op, int target_objnum, ship* self) {
ship* target = &Ships[Objects[target_objnum].instance];

Expand Down
13 changes: 13 additions & 0 deletions code/ai/ailua.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ struct player_order_lua {
int ai_message = MESSAGE_YESSIR;
SCP_string parseText = "";
SCP_string displayText = "";
bool generalOrder = false;
SCP_string category = "";
bool cur_enabled = false;
bool cur_valid = false;
enum class target_restrictions : int { TARGET_ALLIES, TARGET_ALL, TARGET_OWN, TARGET_ENEMIES, TARGET_SAME_WING, TARGET_PLAYER_WING, TARGET_ALL_CAPS, TARGET_ALLIED_CAPS, TARGET_ENEMY_CAPS, TARGET_NOT_SELF } targetRestrictions = target_restrictions::TARGET_ALL;
enum class ship_restrictions : int { ANY, WING, IN_PLAYER_WING, PLAYER_WING } shipRestrictions = ship_restrictions::ANY;
};
Expand All @@ -29,8 +33,17 @@ bool ai_lua_add_order(int sexp_op, player_order_lua order);
bool ai_lua_has_mode(int sexp_op);
const ai_mode_lua* ai_lua_find_mode(int sexp_op);
const player_order_lua* ai_lua_find_player_order(int sexp_op);
SCP_vector<SCP_string> ai_lua_get_general_order_categories(bool enabled_only = true);
int ai_lua_get_num_general_orders();
SCP_vector<SCP_string> ai_lua_get_general_orders(bool onlyEnabled = false, bool onlyValid = false, const SCP_string& category = "");
int ai_lua_find_general_order_id(const SCP_string& name);
void ai_lua_enable_general_order(int sexp_op, bool enable);
void ai_lua_validate_general_order(int sexp_op, bool validity);
void ai_lua_reset_general_orders();
bool ai_lua_is_general_order(int sexp_op);
void ai_lua(ai_info* aip);
void ai_lua_start(ai_goal* aigp, object* objp);
void ai_lua_start_general(int lua_sexp_id, int target_objnum);
bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self, size_t order);
bool ai_lua_is_valid_ship(int sexp_op, bool isWing, ship* self);
ai_achievability ai_lua_is_achievable(const ai_goal* aigp, int objnum);
102 changes: 85 additions & 17 deletions code/hud/hudsquadmsg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,11 @@ typedef struct mmode_item {
SCP_string text; // text to display on the menu
} mmode_item;

#define MAX_MENU_ITEMS 50 // max number of items in the menu
#define MAX_MENU_DISPLAY 10 // max number that can be displayed

char Squad_msg_title[256] = "";
mmode_item MsgItems[MAX_MENU_ITEMS];
int Num_menu_items = -1; // number of items for a message menu
int First_menu_item= -1; // index of first item in the menu
SCP_string Lua_sqd_msg_cat;

// -----------
// following set of vars/defines are used to store/restore key bindings for keys that
Expand Down Expand Up @@ -139,17 +137,6 @@ int keys_used[] = { KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_
#define ID1 1
#define ID2 2

// following are defines and character strings that are used as part of messaging mode

#define NUM_COMM_ORDER_TYPES 6

#define TYPE_SHIP_ITEM 0
#define TYPE_WING_ITEM 1
#define TYPE_ALL_FIGHTERS_ITEM 2
#define TYPE_REINFORCEMENT_ITEM 3
#define TYPE_REPAIR_REARM_ITEM 4
#define TYPE_REPAIR_REARM_ABORT_ITEM 5


SCP_string Comm_order_types[NUM_COMM_ORDER_TYPES];

Expand Down Expand Up @@ -1630,13 +1617,26 @@ void hud_squadmsg_type_select( )
{
int k, i;

int num_order_types = NUM_COMM_ORDER_TYPES;

int lua_order_count = 0;

// Now get a list of all lua categories to add. Meow.
SCP_vector<SCP_string> lua_cat_list = ai_lua_get_general_order_categories();

num_order_types += (int)lua_cat_list.size();

// Add the items
for (i = 0; i < NUM_COMM_ORDER_TYPES; i++)
for (i = 0; i < num_order_types; i++)
{
MsgItems[i].text = Comm_order_types[i];
if (i < NUM_COMM_ORDER_TYPES) {
MsgItems[i].text = Comm_order_types[i];
} else {
MsgItems[i].text = lua_cat_list[i - NUM_COMM_ORDER_TYPES];
}
MsgItems[i].active = 1; // assume active
}
Num_menu_items = NUM_COMM_ORDER_TYPES;
Num_menu_items = num_order_types;


// check to see if the player is a traitor. If so, then he will not
Expand Down Expand Up @@ -1667,6 +1667,13 @@ void hud_squadmsg_type_select( )
MsgItems[TYPE_REPAIR_REARM_ITEM].active = 1; // this item will always be available (I think)
MsgItems[TYPE_REPAIR_REARM_ABORT_ITEM].active = 0;

for(const auto& cat : lua_cat_list){
if (ai_lua_get_general_orders(false, false, cat).size() == 0) {
MsgItems[NUM_COMM_ORDER_TYPES + lua_order_count].active = 0;
}
lua_order_count++;
}

// AL: 10/13/97
// If the player ship communications are severely damaged, then the player
// will only be able to call for repair/rearm ships
Expand Down Expand Up @@ -1734,6 +1741,9 @@ void hud_squadmsg_type_select( )
hud_squadmsg_do_mode( SM_MODE_REPAIR_REARM );
} else if ( k == TYPE_REPAIR_REARM_ABORT_ITEM ) {
hud_squadmsg_do_mode( SM_MODE_REPAIR_REARM_ABORT );
} else if (k >= NUM_COMM_ORDER_TYPES) {
Lua_sqd_msg_cat = lua_cat_list[k - NUM_COMM_ORDER_TYPES];
hud_squadmsg_do_mode( SM_MODE_GENERAL );
}
}
}
Expand Down Expand Up @@ -2078,6 +2088,60 @@ void hud_squadmsg_ship_command()
}
}

void hud_squadmsg_msg_general()
{
int k;

Num_menu_items = 0;
for (size_t order_id = 0; order_id < Player_orders.size(); order_id++) {
Assert(Num_menu_items < MAX_MENU_ITEMS);

if (Player_orders[order_id].lua_id <= 0) {
continue;
}

auto lua_porder = ai_lua_find_player_order(Player_orders[order_id].lua_id);

//If it's not a general order then do not add it.
if (!lua_porder->generalOrder) {
continue;
}

//If it's not part of the selected category then do not add it.
if (lua_porder->category != Lua_sqd_msg_cat) {
continue;
}
Comment on lines +2111 to +2113
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is player_order number of string comparisons each frame.
Not pretty, but it might be sufficient for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. Definitely worth some thought and maybe a follow-up.


//Only add it if it is enabled for the mission
if (lua_porder->cur_enabled) {

MsgItems[Num_menu_items].text = Player_orders[order_id].localized_name;
MsgItems[Num_menu_items].instance = Player_orders[order_id].lua_id;
MsgItems[Num_menu_items].active = (int)lua_porder->cur_valid;

// do some other checks to possibly gray out other items.
// if no target, remove any items which are associated with the players target
if (!hud_squadmsg_is_target_order_valid(order_id, nullptr))
MsgItems[Num_menu_items].active = 0;

Num_menu_items++;
}
}

strcpy_s(Squad_msg_title, XSTR("What Command", 321));
k = hud_squadmsg_get_key();

// when we get a valid goal, we must add the goal to the ai ship's goal list

if (k != -1) {
Assert(k < Num_menu_items);

ai_lua_start_general(MsgItems[k].instance, Player_ai->target_objnum);

hud_squadmsg_toggle();
}
}

// function to display list of command for a wing
void hud_squadmsg_wing_command()
{
Expand Down Expand Up @@ -2414,6 +2478,10 @@ int hud_squadmsg_do_frame( )
hud_squadmsg_msg_all_fighters();
break;

case SM_MODE_GENERAL:
hud_squadmsg_msg_general();
break;

default:
Int3(); // get allender -- invalid mode in messaging system
break;
Expand Down
Loading
Loading