Skip to content

Commit

Permalink
Merge pull request #130 from Sparker95/cmdr-ai
Browse files Browse the repository at this point in the history
CivilWarGameMode and some map changes
  • Loading branch information
billw2012 authored May 31, 2019
2 parents 3993774 + 942ed9f commit 987b623
Show file tree
Hide file tree
Showing 28 changed files with 2,631 additions and 1,943 deletions.
12 changes: 6 additions & 6 deletions Project_0.Altis/AI/CmdrAI/CmdrAI.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ CLASS("CmdrAI", "")
// Must be on our side and not involved in another action
GETV(_x, "side") == _side and
// Must be at a location
{ !IS_NULL_OBJECT(CALLM(_potentialSrcGarr, "getLocation", [])) } and
{ !IS_NULL_OBJECT(CALLM(_x, "getLocation", [])) } and
{ !CALLM(_x, "isBusy", []) } and
{
private _overDesiredEff = CALLM(_worldNow, "getOverDesiredEff", [_x]);
Expand Down Expand Up @@ -227,7 +227,7 @@ CLASS("CmdrAI", "")
};

// Take tgt locations from future, so we take into account all in progress actions.
private _tgtLocations = CALLM(_worldFuture, "getLocations", [["base" ARG "outpost" ARG "roadblock"]]) select {
private _tgtLocations = CALLM(_worldFuture, "getLocations", [[LOCATION_TYPE_BASE ARG LOCATION_TYPE_OUTPOST ARG LOCATION_TYPE_ROADBLOCK]]) select {
// Must not have any of our garrisons already present (or this would be reinforcement action)
IS_NULL_OBJECT(CALLM(_x, "getGarrison", [_side]))
};
Expand All @@ -241,7 +241,7 @@ CLASS("CmdrAI", "")
private _tgtPos = GETV(_x, "pos");
private _tgtType = GETV(_x, "type");
private _dist = _srcPos distance _tgtPos;
if((_tgtType == "roadblock" and _dist < 3000) or (_tgtType != "roadblock" and _dist < 10000)) then {
if((_tgtType == LOCATION_TYPE_ROADBLOCK and _dist < 3000) or (_tgtType != LOCATION_TYPE_ROADBLOCK and _dist < 10000)) then {
private _params = [_srcId, _tgtId];
_actions pushBack (NEW("TakeLocationCmdrAction", _params));
};
Expand Down Expand Up @@ -294,7 +294,7 @@ CLASS("CmdrAI", "")
private _srcPos = GETV(_x, "pos");

// Take tgt locations from future, so we take into account all in progress actions.
private _tgtLocations = CALLM(_worldNow, "getNearestLocations", [_srcPos ARG 2000 ARG ["city"]]) apply {
private _tgtLocations = CALLM(_worldNow, "getNearestLocations", [_srcPos ARG 2000 ARG [LOCATION_TYPE_CITY]]) apply {
_x params ["_dist", "_loc"];
[_srcPos getDir GETV(_loc, "pos"), GETV(_loc, "id")]
};
Expand Down Expand Up @@ -458,8 +458,8 @@ CLASS("CmdrAI", "")
if(_priority != -1) then {
// Sync before planning
CALLM(_world, "sync", []);

CALLM(_world, "updateThreatMaps", []);
// Update grids etc.
CALLM(_world, "update", []);
T_CALLM("_plan", [_world ARG _priority]);

// Make it after planning so we get a gap
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ CLASS("AST_GarrisonAttackTarget", "ActionStateTransition")
if(CALLM(_garr, "isDead", [])) exitWith {
OOP_WARNING_MSG("[w %1 a %2] Garrison %3 is dead so can't attack target", [_world ARG _action ARG LABEL(_garr)]);
if(_clearing and GETV(_world, "type") == WORLD_TYPE_REAL) then {
CALLM(_garr, "cancelClearAreaActual", []);
T_SETV("clearing", false);
};
T_GETV("garrDeadState")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ CLASS("AST_MoveGarrison", "ActionStateTransition")

if(CALLM(_garr, "isDead", [])) exitWith {
if(_moving and GETV(_world, "type") == WORLD_TYPE_REAL) then {
CALLM(_garr, "cancelMoveActual", []);
T_SETV("moving", false);
};
T_GETV("failGarrisonDead")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,32 +41,40 @@ CLASS("AST_SelectFallbackTarget", "ActionStateTransition")
private _newTarget = [];
if(!IS_NULL_OBJECT(_srcGarr) and {!CALLM(_srcGarr, "isDead", [])}) then {
_newTarget = [TARGET_TYPE_GARRISON, _srcGarrId];
OOP_INFO_MSG_REAL_ONLY(_world, "Selected new fallback target for %1: %2", [LABEL(_garr)]+[LABEL(_srcGarr)]);
OOP_INFO_MSG_REAL_ONLY(_world, "Selected new fallback target for %1: %2", [LABEL(_garr) ARG LABEL(_srcGarr)]);
} else {
private _pos = GETV(_garr, "pos");

// select the nearest friendly garrison
private _nearGarrs = CALLM(_world, "getNearestGarrisons", [_pos]+[4000]) select { !CALLM(_x, "isBusy", []) and (GETV(_x, "locationId") != MODEL_HANDLE_INVALID) };
private _nearGarrs = CALLM(_world, "getNearestGarrisons", [_pos ARG 4000]) select {
_x params ["_dist", "_garr"];
!CALLM(_garr, "isBusy", []) and (GETV(_garr, "locationId") != MODEL_HANDLE_INVALID)
};
if(count _nearGarrs == 0) then {
// Check further
_nearGarrs = CALLM(_world, "getNearestGarrisons", [_pos]) select { !CALLM(_x, "isBusy", []) and (GETV(_x, "locationId") != MODEL_HANDLE_INVALID) };
_nearGarrs = CALLM(_world, "getNearestGarrisons", [_pos]) select {
_x params ["_dist", "_garr"];
!CALLM(_garr, "isBusy", []) and (GETV(_garr, "locationId") != MODEL_HANDLE_INVALID)
};
};

// If we found one then target it
if(count _nearGarrs > 0) then {
private _nearGarr = _nearGarrs#0;
private _nearDistGarr = _nearGarrs#0;
_nearDistGarr params ["_dist", "_nearGarr"];
_newTarget = [TARGET_TYPE_GARRISON, GETV(_nearGarr, "id")];
OOP_INFO_MSG_REAL_ONLY(_world, "Selected new fallback target for %1: %2", [LABEL(_garr)]+[LABEL(_nearGarr)]);
OOP_INFO_MSG_REAL_ONLY(_world, "Selected new fallback target for %1: %2", [LABEL(_garr) ARG LABEL(_nearGarr)]);
} else {
// Otherwise find a nearby empty location and go there
private _nearLocs = CALLM(_world, "getNearestLocations", [_pos]+[4000]) select { CALLM(_x, "isEmpty", []) };
private _nearLocs = CALLM(_world, "getNearestLocations", [_pos ARG 4000]) select { CALLM(_x, "isEmpty", []) };
if(count _nearLocs == 0) then {
_nearLocs = CALLM(_world, "getNearestLocations", [_pos]);
};
if(count _nearLocs > 0) then {
private _nearLoc = _nearLocs#0;
private _nearLocGarr = _nearGarrs#0;
_nearLocGarr params ["_dist", "_nearLoc"];
_newTarget = [TARGET_TYPE_LOCATION, GETV(_nearLoc, "id")];
OOP_INFO_MSG_REAL_ONLY(_world, "Selected new fallback target for %1: %2", [LABEL(_garr)]+[LABEL(_nearLoc)]);
OOP_INFO_MSG_REAL_ONLY(_world, "Selected new fallback target for %1: %2", [LABEL(_garr) ARG LABEL(_nearLoc)]);
} else {
OOP_ERROR_MSG("Couldn't find any location on map, this should be impossible!", []);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ CLASS("TakeLocationCmdrAction", "TakeOrJoinCmdrAction")
};

// switch do {
// case "roadblock": { "mil_triangle" };
// case "base": { "mil_circle" };
// case "outpost": { "mil_box" };
// case LOCATION_TYPE_ROADBLOCK: { "mil_triangle" };
// case LOCATION_TYPE_BASE: { "mil_circle" };
// case LOCATION_TYPE_OUTPOST: { "mil_box" };
// default { "mil_dot" };
// }
// Resource is how much src is *over* composition, scaled by distance (further is lower)
Expand Down Expand Up @@ -115,55 +115,10 @@ CLASS("TakeLocationCmdrAction", "TakeOrJoinCmdrAction")
CALLM(_srcGarr, "transportationScore", [_detachEff])
};

// TODO: implement priority score for TakeLocationCmdrAction
// TODO:OPT cache these scores!
private _tgtLocType = GETV(_tgtLoc, "type");

private _strategy = CALL_STATIC_METHOD("AICommander", "getCmdrStrategy", [_side]);

private _tgtLocTypeDistanceBias = 1;
private _tgtLocTypePriorityBias = 1;

private _activity = log (0.09 * CALLM(_worldNow, "getActivity", [_tgtLocPos ARG 2000]) + 1);

switch(_tgtLocType) do {
case "outpost": {
// We want these a bit, but more if there is activity in the area
_tgtLocTypePriorityBias = GETV(_strategy, "takeLocOutpostPriority") +
GETV(_strategy, "takeLocOutpostPriorityActivityCoeff") * _activity;
};
case "base": {
// We want these a normal amount but are willing to go further to capture them.
// TODO: work out how to weight taking bases vs other stuff?
// Probably high priority when we are losing? This is a gameplay question.
_tgtLocTypeDistanceBias = GETV(_strategy, "takeLocBasePriority") +
GETV(_strategy, "takeLocBasePriorityActivityCoeff") * _activity;
};
case "roadblock": {
// We want these if there is local activity.
_tgtLocTypePriorityBias = GETV(_strategy, "takeLocRoadBlockPriority") +
GETV(_strategy, "takeLocRoadBlockPriorityActivityCoeff") * _activity;

if(_tgtLocTypePriorityBias > 0) then {
private _locs = CALLM(_worldNow, "getNearestLocations", [_tgtLocPos ARG 2000 ARG ["base" ARG "outpost"]]) select {
_x params ["_dist", "_loc"];
!IS_NULL_OBJECT(CALLM(_loc, "getGarrison", [_side]))
};
// We build these quick if we have an outpost or base nearby, prioritized by distance
if(count _locs > 0) then {
private _distF = 0.0004 * (_locs#0#0);
private _distCoeff = 1 / (1 + (_distF * _distF));
_tgtLocTypeDistanceBias = 2 * _distCoeff;
} else {
_tgtLocTypeDistanceBias = 0;
};
};
};
default { 0.5 }; // TODO: dunno what it is, better add more here?
};

private _scoreResource = _detachEffStrength * _distCoeff * _tgtLocTypeDistanceBias * _transportationScore;
private _scorePriority = 1 * _tgtLocTypePriorityBias;
private _scoreResource = _detachEffStrength * _distCoeff * _transportationScore;
private _scorePriority = CALLM(_strategy, "getLocationDesirability", [_worldNow ARG _tgtLoc ARG _side]);

// Work out time to start based on how much force we mustering and distance we are travelling.
// https://www.desmos.com/calculator/mawpkr88r3 * https://www.desmos.com/calculator/0vb92pzcz8
Expand Down
42 changes: 42 additions & 0 deletions Project_0.Altis/AI/CmdrAI/CmdrStrategy/CmdrStrategy.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,48 @@ CLASS("CmdrStrategy", "")
T_SETV("takeLocRoadBlockPriorityActivityCoeff", 2);
} ENDMETHOD;

METHOD("getLocationDesirability") {
params [P_THISOBJECT, P_OOP_OBJECT("_worldNow"), P_OOP_OBJECT("_loc"), P_SIDE("_side")];
private _locPos = GETV(_loc, "pos");
private _activity = log (0.09 * CALLM(_worldNow, "getActivity", [_locPos ARG 2000]) + 1);

private _priority = 1;
switch(GETV(_loc, "type")) do {
case LOCATION_TYPE_OUTPOST: {
// We want these a bit, but more if there is activity in the area
_priority = T_GETV("takeLocOutpostPriority") + T_GETV("takeLocOutpostPriorityActivityCoeff") * _activity;
};
case LOCATION_TYPE_BASE: {
// We want these a normal amount but are willing to go further to capture them.
// TODO: work out how to weight taking bases vs other stuff?
// Probably high priority when we are losing? This is a gameplay question.
_priority = T_GETV("takeLocBasePriority") + T_GETV("takeLocBasePriorityActivityCoeff") * _activity;
};
case LOCATION_TYPE_ROADBLOCK: {
// We want these if there is local activity.
_priority = T_GETV("takeLocRoadBlockPriority") +
T_GETV("takeLocRoadBlockPriorityActivityCoeff") * _activity;

if(_priority > 0) then {
private _locs = CALLM(_worldNow, "getNearestLocations", [_locPos ARG 2000 ARG [LOCATION_TYPE_BASE ARG LOCATION_TYPE_OUTPOST]]) select {
_x params ["_dist", "_loc"];
!IS_NULL_OBJECT(CALLM(_loc, "getGarrison", [_side]))
};
// We build these quick if we have an outpost or base nearby, prioritized by distance
if(count _locs > 0) then {
private _distF = 0.0004 * (_locs#0#0);
private _distCoeff = 1 / (1 + (_distF * _distF));
_priority = _priority * 2 * _distCoeff;
} else {
_priority = 0;
};
};
};
default { _priority = 0.5 }; // TODO: dunno what it is, better add more here?
};
_priority
} ENDMETHOD;

// Default QRF behaviour is to send QRFs always,
// from any location that can spare the entire required efficiency.
/* virtual */ METHOD("getQRFScore") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ CLASS("PassiveCmdrStrategy", "CmdrStrategy")

// // Occupying road blocks is allowed, but other locations
// // are not.
// if(GETV(_tgtLoc, "type") == "roadBlock") then {
// if(GETV(_tgtLoc, "type") == LOCATION_TYPE_ROADBLOCK) then {
// APPLY_SCORE_STRATEGY(_defaultScore, 1)
// } else {
// APPLY_SCORE_STRATEGY(_defaultScore, 0)
Expand Down
2 changes: 1 addition & 1 deletion Project_0.Altis/AI/CmdrAI/Model/GarrisonModel.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,7 @@ CLASS("GarrisonModel", "ModelBase")
OOP_INFO_MSG("Joined %1 to %2", [LABEL(_thisObject) ARG LABEL(_location)]);

private _locType = GETV(_location, "type");
if(_locType == "roadblock") then {
if(_locType == LOCATION_TYPE_ROADBLOCK) then {
// TODO: BUILD ROADBLOCK? This would be temporary, not sure what proper way to do it is...
};

Expand Down
5 changes: 2 additions & 3 deletions Project_0.Altis/AI/CmdrAI/Model/LocationModel.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ CLASS("LocationModel", "ModelBase")
// Radius of the location
VARIABLE("radius");

VARIABLE("desirability");

METHOD("new") {
params [P_THISOBJECT, P_STRING("_world"), P_STRING("_actual")];
T_SETV("pos", []);
Expand All @@ -31,6 +29,7 @@ CLASS("LocationModel", "ModelBase")
T_SETV("spawn", false);
T_SETV("staging", false);
T_SETV("radius", 0);

if(!IS_NULL_OBJECT(_actual)) then {
T_CALLM("sync", []);
};
Expand Down Expand Up @@ -72,7 +71,7 @@ CLASS("LocationModel", "ModelBase")
params [P_THISOBJECT];

T_PRVAR(actual);
// If we have an assigned Reak Object then sync from it
// If we have an assigned Real Object then sync from it
if(!IS_NULL_OBJECT(_actual)) then {
ASSERT_OBJECT_CLASS(_actual, "Location");

Expand Down
Loading

0 comments on commit 987b623

Please sign in to comment.