Skip to content

Commit 62ec9c3

Browse files
committed
set-guard-range
1 parent 5c2e5a2 commit 62ec9c3

5 files changed

Lines changed: 67 additions & 6 deletions

File tree

code/ai/aicode.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,18 @@ void ai_cleanup_dock_mode_objective(object *objp);
321321
// the "autopilot"
322322
object *Autopilot_flight_leader = NULL;
323323

324+
static inline float ai_guard_threshold(const object* guarded_objp, float threshold)
325+
{
326+
if (guarded_objp != nullptr && guarded_objp->type == OBJ_SHIP && guarded_objp->instance >= 0) {
327+
const float configured = Ships[guarded_objp->instance].max_guard_radius;
328+
if (configured > 0.0f) {
329+
return configured;
330+
}
331+
}
332+
333+
return threshold;
334+
}
335+
324336
/**
325337
* Sets the timestamp used to tell is it is a good time for this team to rearm.
326338
* Ends a 'bad rearm time'
@@ -5115,9 +5127,9 @@ int maybe_resume_previous_mode(object *objp, ai_info *aip)
51155127

51165128
// If guarding ship is far away from guardee and enemy is far away from guardee,
51175129
// then stop chasing and resume guarding.
5118-
if (dist > (MAX_GUARD_DIST + guard_objp->radius) * 6) {
5130+
if (dist > ai_guard_threshold(guard_objp, 6.0f)) {
51195131
if ((En_objp != NULL) && (En_objp->type == OBJ_SHIP)) {
5120-
if (vm_vec_dist_quick(&guard_objp->pos, &En_objp->pos) > (MAX_GUARD_DIST + guard_objp->radius) * 6) {
5132+
if (vm_vec_dist_quick(&guard_objp->pos, &En_objp->pos) > ai_guard_threshold(guard_objp, 6.0f)) {
51215133
Assert(aip->previous_mode == AIM_GUARD);
51225134
aip->mode = aip->previous_mode;
51235135
aip->submode = AIS_GUARD_PATROL;
@@ -10515,7 +10527,7 @@ int ai_guard_find_nearby_bomb(object *guarding_objp, object *guarded_objp)
1051510527

1051610528
dist = vm_vec_dist_quick(&bomb_objp->pos, &guarded_objp->pos);
1051710529

10518-
if (dist < (MAX_GUARD_DIST + guarded_objp->radius)*3) {
10530+
if (dist < ai_guard_threshold(guarded_objp, 3.0f)) {
1051910531
dist_to_guarding_obj = vm_vec_dist_quick(&bomb_objp->pos, &guarding_objp->pos);
1052010532
if ( dist_to_guarding_obj < closest_dist_to_guarding_obj ) {
1052110533
closest_dist_to_guarding_obj = dist_to_guarding_obj;
@@ -10559,11 +10571,11 @@ void ai_guard_find_nearby_ship(object *guarding_objp, object *guarded_objp)
1055910571
if (Ship_info[eshipp->ship_info_index].class_type >= 0 && (Ship_types[Ship_info[eshipp->ship_info_index].class_type].flags[Ship::Type_Info_Flags::AI_guards_attack]))
1056010572
{
1056110573
dist = vm_vec_dist_quick(&enemy_objp->pos, &guarded_objp->pos);
10562-
if (dist < (MAX_GUARD_DIST + guarded_objp->radius)*3)
10574+
if (dist < ai_guard_threshold(guarded_objp, 3.0f))
1056310575
{
1056410576
guard_object_was_hit(guarding_objp, enemy_objp);
1056510577
}
10566-
else if ((dist < 3000.0f) && (Ai_info[eshipp->ai_index].target_objnum == guarding_aip->guard_objnum))
10578+
else if ((dist < ai_guard_apply_clamp(guarded_objp, 3000.0f)) && (Ai_info[eshipp->ai_index].target_objnum == guarding_aip->guard_objnum))
1056710579
{
1056810580
guard_object_was_hit(guarding_objp, enemy_objp);
1056910581
}
@@ -10590,7 +10602,7 @@ void ai_guard_find_nearby_asteroid(object *guarding_objp, object *guarded_objp)
1059010602
if ( asteroid_objp->type == OBJ_ASTEROID ) {
1059110603
// Attack asteroid if near guarded ship
1059210604
dist = vm_vec_dist_quick(&asteroid_objp->pos, &guarded_objp->pos);
10593-
if ( dist < (MAX_GUARD_DIST + guarded_objp->radius)*2) {
10605+
if (dist < ai_guard_threshold(guarded_objp, 2.0f)) {
1059410606
dist_to_self = vm_vec_dist_quick(&asteroid_objp->pos, &guarding_objp->pos);
1059510607
if ( OBJ_INDEX(guarded_objp) == asteroid_collide_objnum(asteroid_objp) ) {
1059610608
if( dist_to_self < closest_danger_asteroid_dist ) {

code/parse/sexp.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,7 @@ SCP_vector<sexp_oper> Operators = {
524524
{ "ship-no-guardian", OP_SHIP_NO_GUARDIAN, 1, INT_MAX, SEXP_ACTION_OPERATOR, },
525525
{ "ship-guardian-threshold", OP_SHIP_GUARDIAN_THRESHOLD, 2, INT_MAX, SEXP_ACTION_OPERATOR, },
526526
{ "ship-subsys-guardian-threshold", OP_SHIP_SUBSYS_GUARDIAN_THRESHOLD, 3, INT_MAX, SEXP_ACTION_OPERATOR, },
527+
{ "set-guard-range", OP_SET_GUARD_RANGE, 2, INT_MAX, SEXP_ACTION_OPERATOR, }, // MjnMixael
527528
{ "self-destruct", OP_SELF_DESTRUCT, 1, INT_MAX, SEXP_ACTION_OPERATOR, },
528529
{ "destroy-instantly", OP_DESTROY_INSTANTLY, 1, INT_MAX, SEXP_ACTION_OPERATOR, }, // Admiral MS
529530
{ "destroy-instantly-with-debris", OP_DESTROY_INSTANTLY_WITH_DEBRIS, 1, INT_MAX, SEXP_ACTION_OPERATOR, }, // Asteroth
@@ -19467,6 +19468,29 @@ void sexp_ship_guardian_threshold(int node)
1946719468
}
1946819469
}
1946919470

19471+
// MjnMixael
19472+
void sexp_set_guard_range(int node)
19473+
{
19474+
int range, n = node;
19475+
bool is_nan, is_nan_forever;
19476+
19477+
range = eval_num(n, is_nan, is_nan_forever);
19478+
if (is_nan || is_nan_forever)
19479+
return;
19480+
n = CDR(n);
19481+
19482+
for (; n != -1; n = CDR(n)) {
19483+
auto ship_entry = eval_ship(n);
19484+
if (!ship_entry || !ship_entry->has_shipp()) {
19485+
continue;
19486+
}
19487+
19488+
// Intentionally no lower bound validation beyond disabling at <= 0.
19489+
// Mission authors may choose very small positive values for highly restrictive escort behavior.
19490+
ship_entry->shipp()->max_guard_radius = (range > 0) ? static_cast<float>(range) : -1.0f;
19491+
}
19492+
}
19493+
1947019494
// Goober5000
1947119495
void sexp_ship_subsys_guardian_threshold(int node)
1947219496
{
@@ -28860,6 +28884,11 @@ int eval_sexp(int cur_node, int referenced_node)
2886028884
sexp_val = SEXP_TRUE;
2886128885
break;
2886228886

28887+
case OP_SET_GUARD_RANGE:
28888+
sexp_set_guard_range(node);
28889+
sexp_val = SEXP_TRUE;
28890+
break;
28891+
2886328892
case OP_SHIP_SUBSYS_TARGETABLE:
2886428893
sexp_ship_deal_with_subsystem_flag(cur_node, node, Ship::Subsystem_Flags::Untargetable, true, false);
2886528894
sexp_val = SEXP_TRUE;
@@ -31597,6 +31626,7 @@ int query_operator_return_type(int op)
3159731626
case OP_SHIP_NO_GUARDIAN:
3159831627
case OP_SHIP_GUARDIAN_THRESHOLD:
3159931628
case OP_SHIP_SUBSYS_GUARDIAN_THRESHOLD:
31629+
case OP_SET_GUARD_RANGE:
3160031630
case OP_SHIP_VANISH:
3160131631
case OP_PROP_VANISH:
3160231632
case OP_DESTROY_INSTANTLY:
@@ -32308,6 +32338,12 @@ int query_operator_argument_type(int op, int argnum)
3230832338
else
3230932339
return OPF_SUBSYS_OR_GENERIC;
3231032340

32341+
case OP_SET_GUARD_RANGE:
32342+
if (argnum == 0)
32343+
return OPF_NUMBER;
32344+
else
32345+
return OPF_SHIP;
32346+
3231132347
case OP_SHIP_SUBSYS_TARGETABLE:
3231232348
case OP_SHIP_SUBSYS_UNTARGETABLE:
3231332349
if (argnum == 0)
@@ -36895,6 +36931,7 @@ int get_category(int op_id)
3689536931
case OP_JUMP_NODE_HIDE_JUMPNODE:
3689636932
case OP_SHIP_GUARDIAN_THRESHOLD:
3689736933
case OP_SHIP_SUBSYS_GUARDIAN_THRESHOLD:
36934+
case OP_SET_GUARD_RANGE:
3689836935
case OP_SET_SKYBOX_MODEL:
3689936936
case OP_SHIP_CREATE:
3690036937
case OP_PROP_CREATE:
@@ -37252,6 +37289,7 @@ int get_subcategory(int op_id)
3725237289

3725337290
case OP_ALTER_SHIP_FLAG:
3725437291
case OP_ALTER_WING_FLAG:
37292+
case OP_SET_GUARD_RANGE:
3725537293
case OP_PROTECT_SHIP:
3725637294
case OP_UNPROTECT_SHIP:
3725737295
case OP_BEAM_PROTECT_SHIP:
@@ -40447,6 +40485,14 @@ SCP_vector<sexp_help_struct> Sexp_help = {
4044740485
"\t2:\tShip housing the subsystem(s) (ships must be in-mission).\r\n"
4044840486
"\t3+:\tSubsystems to make unkillable." },
4044940487

40488+
// MjnMixael
40489+
{ OP_SET_GUARD_RANGE, "set-guard-range\r\n"
40490+
"\tSets the max range in meters at which any ships guarding this ship will engage with threats.\r\n"
40491+
"If the value is <= 0, regular dynamic guard range behavior will resume. Positive values are used as is with no size validation based on ship class.\r\n\r\n"
40492+
"Takes 2 or more arguments...\r\n"
40493+
"\t1:\tGuard range cap in meters (<= 0 disables cap).\r\n"
40494+
"\t2+:\tShip(s) to apply the cap to (ships must be in-mission)." },
40495+
4045040496
// Goober5000
4045140497
{ OP_SHIP_STEALTHY, "ship-stealthy\r\n"
4045240498
"\tCauses the ships listed in this sexpression to become stealth ships (i.e. invisible to radar).\r\n\r\n"

code/parse/sexp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,7 @@ enum : int {
695695
OP_JUMP_NODE_HIDE_JUMPNODE, // WMC
696696
OP_SHIP_GUARDIAN_THRESHOLD, // Goober5000
697697
OP_SHIP_SUBSYS_GUARDIAN_THRESHOLD, // Goober5000
698+
OP_SET_GUARD_RANGE, //MjnMixael
698699
OP_SET_SKYBOX_MODEL, // taylor
699700
OP_SHIP_CREATE,
700701
OP_PROP_CREATE, // MjnMixael

code/ship/ship.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7184,6 +7184,7 @@ void ship::clear()
71847184
ship_max_hull_strength = 0.0f;
71857185

71867186
ship_guardian_threshold = 0;
7187+
max_guard_radius = -1.0f;
71877188

71887189
ship_name[0] = 0;
71897190
display_name.clear();

code/ship/ship.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@ class ship
622622
float max_weapon_regen_per_second; // wookieejedi - make this a ship object variable
623623

624624
int ship_guardian_threshold; // Goober5000 - now also determines whether ship is guardian'd
625+
float max_guard_radius; // Optional clamp for guard engagement/resume ranges; <= 0 means unused
625626

626627

627628
char ship_name[NAME_LENGTH];

0 commit comments

Comments
 (0)