Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
563 lines
14 KiB
Plaintext
563 lines
14 KiB
Plaintext
library mwfunc;
|
|
|
|
const
|
|
|
|
#include_ "mwconst.abi"
|
|
|
|
type
|
|
#include_ "mwtype.abi"
|
|
|
|
var
|
|
static ObjectID last_sound_played;
|
|
static Boolean any_sounds_played;
|
|
|
|
//------------------------------------------------------------------------------------
|
|
|
|
function init;
|
|
code
|
|
any_sounds_played = FALSE;
|
|
|
|
|
|
endfunction;
|
|
|
|
function getRelativeAlignment (ObjectID p1,ObjectID p2) : integer;
|
|
|
|
var
|
|
|
|
integer align1;
|
|
integer align2;
|
|
|
|
code
|
|
align1 = getAlignment (p1);
|
|
align2 = getAlignment (p2);
|
|
|
|
if align2 == NEUTRAL_ALIGNMENT then
|
|
return (NEUTRAL);
|
|
endif;
|
|
if align1 <> align2 then
|
|
return (ENEMY);
|
|
endif;
|
|
return (FRIENDLY);
|
|
|
|
endfunction;
|
|
|
|
function SnapToGround(ObjectID obj);
|
|
var
|
|
LocPoint l;
|
|
|
|
code
|
|
getLocation(obj,l);
|
|
l[1] = -1;
|
|
teleport(obj,l);
|
|
endfunction;
|
|
|
|
function ProtectAGroup(integer group_num) : integer;
|
|
// This one may or may not work. Needs testing.
|
|
var
|
|
|
|
code
|
|
|
|
if (isShot (GroupObjectId(group_num))) then
|
|
if (getRelativeAlignment(me,WhoShot(GroupObjectId(group_num))) == ENEMY) then
|
|
setTarget(me,WhoShot(GroupObjectId(group_num)));
|
|
return (1);
|
|
endif;
|
|
endif;
|
|
|
|
return (0);
|
|
endfunction;
|
|
|
|
|
|
function GeneralPlayChatter(ObjectId sound,
|
|
integer which_timer, integer what_delay, integer what_chance);
|
|
// if Timer which_timer is over what_delay, there is a chance what_chance
|
|
// that the sound sound is played. After this, the timer is reset.
|
|
// use this function for easy handling of radio chatter.
|
|
// what_chance is a number from 0 to 1000. The percentage chance of the sound playing is
|
|
// what_chance / 10
|
|
var
|
|
|
|
code
|
|
if (any_sounds_played == TRUE) then
|
|
if (last_sound_played == sound) then
|
|
what_chance = -1;
|
|
endif;
|
|
endif;
|
|
|
|
if (TimeGreater(which_timer,what_delay)) then
|
|
if (Rand(0,1000) <= what_chance) then
|
|
PlaySound(sound);
|
|
last_sound_played = sound;
|
|
any_sounds_played = TRUE;
|
|
ResetTimer(which_timer);
|
|
endif;
|
|
|
|
endif;
|
|
endfunction;
|
|
|
|
function SetMyTarget(integer searchrange) : boolean;
|
|
|
|
var
|
|
|
|
integer foe;
|
|
|
|
code
|
|
foe = FindObject(ME,FA_ENEMY,FT_DEFAULT,FC_BEST_TARGET,FF_WHO_SHOT + FF_SEEPLAYER,searchrange);
|
|
|
|
if (foe <> no_unit) then
|
|
SetTarget (me,foe);
|
|
return (true);
|
|
endif;
|
|
|
|
return (false);
|
|
|
|
endfunction;
|
|
|
|
function FindEnemy(integer searchrange, integer flags) : boolean;
|
|
|
|
var
|
|
integer foe;
|
|
|
|
code
|
|
foe = FindObject(ME,FA_ENEMY,flags,FC_BEST_TARGET,FF_WHO_SHOT + FF_SEEPLAYER,searchrange);
|
|
|
|
if (foe <> no_unit) then
|
|
SetTarget (me,foe);
|
|
return (true);
|
|
endif;
|
|
|
|
return (false);
|
|
|
|
endfunction;
|
|
|
|
function Bot_FindEnemy(integer searchrange) : boolean;
|
|
|
|
var
|
|
integer foe;
|
|
|
|
code
|
|
foe = FindObject(ME,FA_ENEMY,FT_DEFAULT,FC_BEST_TARGET,FF_WHO_SHOT + FF_SEEPLAYER + FF_LOOK_EVERYWHERE,searchrange);
|
|
|
|
if (foe <> no_unit) then
|
|
SetTarget (me,foe);
|
|
return (true);
|
|
endif;
|
|
|
|
return (false);
|
|
|
|
endfunction;
|
|
|
|
function LeaveAttackState(integer withdrawrange) : boolean;
|
|
|
|
var
|
|
|
|
integer target;
|
|
|
|
code
|
|
|
|
target = gettarget(me);
|
|
|
|
//1. I somehow got here without a legitimate target
|
|
if (target < 0) then
|
|
return(true);
|
|
else
|
|
//2. My target is dead
|
|
if (isDead (target) == TRUE) then
|
|
return(true);
|
|
else
|
|
//3. My target has gotten too far from me
|
|
if ((isWithin(target,me,withdrawrange)) == FALSE) then
|
|
if (WhoShot(me) <> target) then
|
|
return(true);
|
|
endif;
|
|
endif;
|
|
endif;
|
|
endif;
|
|
|
|
|
|
return (false);
|
|
|
|
endfunction;
|
|
|
|
|
|
|
|
function PlayChatter(ObjectID who_speaks, ObjectId sound,
|
|
integer which_timer, integer what_delay, integer what_chance, Boolean check_combat);
|
|
// if Timer which_timer is over what_delay and unit who_speaks is
|
|
// alive, there is a chance what_chance
|
|
// that the sound sound is played. After this, the timer is reset.
|
|
// If check_combat is TRUE, the sound is only played if who_speaks is involved in a fight.
|
|
// use this function for easy handling of radio chatter.
|
|
// what_chance is a number from 0 to 1000. The percentage chance of the sound playing is
|
|
// what_chance / 10
|
|
var
|
|
|
|
code
|
|
if (any_sounds_played == TRUE) then
|
|
if (last_sound_played == sound) then
|
|
what_chance = -1;
|
|
endif;
|
|
endif;
|
|
|
|
|
|
if ((IsDead(who_speaks) == FALSE) and (TimeGreater(which_timer,what_delay))) then
|
|
if (Rand(0,1000) <= what_chance) then
|
|
if ((check_combat == FALSE) or
|
|
((check_combat == TRUE) and (IsShot(who_speaks)))) then
|
|
PlaySound(sound);
|
|
last_sound_played = sound;
|
|
any_sounds_played = TRUE;
|
|
ResetTimer(which_timer);
|
|
endif;
|
|
endif;
|
|
endif;
|
|
endfunction;
|
|
|
|
|
|
function GroupPlayChatter(integer group_who_speaks, ObjectId sound,
|
|
integer which_timer, integer what_delay, integer what_chance, Boolean check_combat);
|
|
// if Timer which_timer is over what_delay and group group_who_speaks is
|
|
// alive, there is a chance what_chance
|
|
// that the sound sound is played. After this, the timer is reset.
|
|
// If check_combat is TRUE, the sound is only played if the group is involved in a fight.
|
|
// use this function for easy handling of radio chatter.
|
|
// what_chance is a number from 0 to 1000. The percentage chance of the sound playing is
|
|
// what_chance / 10
|
|
var
|
|
|
|
code
|
|
if (any_sounds_played == TRUE) then
|
|
if (last_sound_played == sound) then
|
|
what_chance = -1;
|
|
endif;
|
|
endif;
|
|
|
|
|
|
if ((GroupAllDead(GroupObjectId(group_who_speaks)) == FALSE) and (TimeGreater(which_timer,what_delay))
|
|
and (Rand(0,1000) <= what_chance)) then
|
|
if ((check_combat == FALSE) or
|
|
((check_combat == TRUE) and (IsShot(GroupObjectId(group_who_speaks))))) then
|
|
PlaySound(sound);
|
|
last_sound_played = sound;
|
|
any_sounds_played = TRUE;
|
|
ResetTimer(which_timer);
|
|
endif;
|
|
endif;
|
|
|
|
endfunction;
|
|
|
|
|
|
// Cinema_ZoomOut():
|
|
// Does a generic zoom-out camera animation suitable for mission victory or failure cut scenes.
|
|
// "who" is the unit to zoom out from; it must be a single unit (typically the player's 'Mech).
|
|
// "unique_timer_id" is the ID of a timer that the function can use that's not used for anything
|
|
// else in any of the ABL scripts related to this mission.
|
|
// "duration" is how long the zoom-out sequence will last. 10 to 20 seconds is generally
|
|
// recommended, though this may be anything above 0. Since the distance to zoom out
|
|
// is fixed, a longer duration will mean a slower zoom-out.
|
|
|
|
function Cinema_ZoomOut(ObjectID who, integer unique_timer_id, real duration) : Boolean;
|
|
var
|
|
real time_remaining;
|
|
|
|
code
|
|
if (Not TimeGreater(unique_timer_id,0)) then
|
|
StartTimer(unique_timer_id);
|
|
|
|
Targetfollowobject(who);
|
|
camerafollowobject(who);
|
|
SetCameraFootShake(who,100);
|
|
|
|
TargetOffset(0.0,5.0,0.0,0.0,true);
|
|
CameraOffset(0.0,5.0,30.0,0.0,true);
|
|
|
|
return (false);
|
|
endif;
|
|
|
|
if (TimeGreater(unique_timer_id,duration)) then
|
|
return (true);
|
|
endif;
|
|
|
|
if (duration > 2.0) then
|
|
if (TimeGreater(unique_timer_id,2.0)) then
|
|
time_remaining = duration - 2.0;
|
|
TargetOffset(0.0,9.0,-20.0,time_remaining,true);
|
|
CameraOffset(0.0,40.0,150.0,time_remaining,true);
|
|
endif;
|
|
endif;
|
|
|
|
return (false);
|
|
endfunction;
|
|
|
|
|
|
// IsShotOrDead():
|
|
// Returns true if the unit was shot recently or is destroyed.
|
|
|
|
function IsShotOrDead(ObjectID who) : Boolean;
|
|
var
|
|
|
|
code
|
|
if (IsDead(who)) then
|
|
return (true);
|
|
endif;
|
|
|
|
return (IsShot(who));
|
|
endfunction;
|
|
|
|
|
|
// WhoShotOrKilled():
|
|
// Indicates who shot or destroyed a given unit
|
|
|
|
function WhoShotOrKilled(ObjectID who) : ObjectID;
|
|
var
|
|
|
|
code
|
|
if (IsDead(who)) then
|
|
return (WhoDestroyed(who));
|
|
endif;
|
|
|
|
if (IsShot(who) == false) then
|
|
return (WhoShot(who));
|
|
endif;
|
|
|
|
return (NO_UNIT);
|
|
endfunction;
|
|
|
|
|
|
// ReachedNav():
|
|
// Indicates whether a unit (or group or team) IsWithin() a nav point
|
|
|
|
function ReachedNav(ObjectID who, ObjectID nav) : Boolean;
|
|
var
|
|
|
|
code
|
|
return (IsWithin(who,nav,150));
|
|
|
|
endfunction;
|
|
|
|
|
|
function AddStandardBuckets;
|
|
var
|
|
|
|
code
|
|
TrackBucket(Bucket_KILLS,0,true);
|
|
TrackBucket(Bucket_DEATHS,0,true);
|
|
|
|
TrackBucket(Bucket_CUSTOM,0,true);
|
|
endfunction;
|
|
|
|
function SetupScoring_Attrition;
|
|
var
|
|
|
|
code
|
|
SetFlagsEnabled(FLAGS_HIDE);
|
|
SetCustomBucketNameIndex(843);
|
|
AddStandardBuckets;
|
|
AddCustomBucketParameter(Bucket_ENEMY_DAMAGE_INFLICT,1);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_DAMAGE_INFLICT,-1);
|
|
AddCustomBucketParameter(Bucket_ENEMY_KILLS,500);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_KILLS,-500);
|
|
AddCustomBucketParameter(Bucket_SUICIDES,-500);
|
|
AddCustomBucketParameter(Bucket_ENEMY_KILLS_BY_TONNAGE,5);
|
|
AddCustomBucketParameter(Bucket_ENEMY_COMPONENT_KILLS,50);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_COMPONENT_KILLS,-50);
|
|
endfunction;
|
|
|
|
function SetupScoring_Cthulu;
|
|
var
|
|
|
|
code
|
|
SetFlagsEnabled(FLAGS_HIDE);
|
|
SetCustomBucketNameIndex(843);
|
|
AddStandardBuckets;
|
|
AddCustomBucketParameter(Bucket_ENEMY_DAMAGE_INFLICT,1);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_DAMAGE_INFLICT,-1);
|
|
AddCustomBucketParameter(Bucket_SUICIDES,-500);
|
|
AddCustomBucketParameter(Bucket_ENEMY_KILLS_BY_TONNAGE,5);
|
|
AddCustomBucketParameter(Bucket_ENEMY_COMPONENT_KILLS,50);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_COMPONENT_KILLS,-50);
|
|
endfunction;
|
|
|
|
function SetupScoring_TeamAttrition;
|
|
var
|
|
|
|
code
|
|
SetFlagsEnabled(FLAGS_HIDE);
|
|
SetCustomBucketNameIndex(844);
|
|
AddStandardBuckets;
|
|
AddCustomBucketParameter(Bucket_ENEMY_DAMAGE_INFLICT,1);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_DAMAGE_INFLICT,-1);
|
|
AddCustomBucketParameter(Bucket_ENEMY_KILLS,500);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_KILLS,-500);
|
|
AddCustomBucketParameter(Bucket_SUICIDES,-500);
|
|
AddCustomBucketParameter(Bucket_ENEMY_KILLS_BY_TONNAGE,5);
|
|
AddCustomBucketParameter(Bucket_ENEMY_COMPONENT_KILLS,50);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_COMPONENT_KILLS,-50);
|
|
endfunction;
|
|
|
|
function SetupScoring_Destruction;
|
|
var
|
|
|
|
code
|
|
SetFlagsEnabled(FLAGS_HIDE);
|
|
SetCustomBucketNameIndex(845);
|
|
AddStandardBuckets;
|
|
AddCustomBucketParameter(Bucket_ENEMY_KILLS,1);
|
|
AddCustomBucketParameter(Bucket_SUICIDES,-1);
|
|
endfunction;
|
|
|
|
function SetupScoring_TeamDestruction;
|
|
var
|
|
|
|
code
|
|
SetFlagsEnabled(FLAGS_HIDE);
|
|
SetCustomBucketNameIndex(846);
|
|
AddStandardBuckets;
|
|
AddCustomBucketParameter(Bucket_ENEMY_KILLS,1);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_KILLS,-1);
|
|
AddCustomBucketParameter(Bucket_SUICIDES,-1);
|
|
endfunction;
|
|
|
|
function SetupScoring_STB;
|
|
var
|
|
|
|
code
|
|
SetFlagsEnabled(FLAGS_UNIVERSAL_ONLY);
|
|
SetFlagCaptureEnabled(false);
|
|
ShowFlagsAsNavPoints(TRUE);
|
|
SetCustomBucketNameIndex(850);
|
|
AddStandardBuckets;
|
|
AddCustomBucketParameter(Bucket_FLAG_HOLD_TIME,1);
|
|
endfunction;
|
|
|
|
function SetupScoring_KOTH(ObjectID hill, integer radius);
|
|
var
|
|
|
|
code
|
|
SetFlagsEnabled(FLAGS_HIDE);
|
|
if (hill <> -1) then
|
|
TrackObjectBucket(Bucket_OBJECTIVE_CONTESTED,hill,radius,false);
|
|
TrackObjectBucket(Bucket_OBJECTIVE_UNCONTESTED,hill,radius,false);
|
|
endif;
|
|
SetCustomBucketNameIndex(848);
|
|
AddStandardBuckets;
|
|
AddCustomBucketParameter(Bucket_OBJECTIVE_CONTESTED,1);
|
|
AddCustomBucketParameter(Bucket_OBJECTIVE_UNCONTESTED,5);
|
|
endfunction;
|
|
|
|
function SetupScoring_TKOTH(ObjectID hill, integer radius);
|
|
var
|
|
|
|
code
|
|
SetFlagsEnabled(FLAGS_HIDE);
|
|
if (hill <> -1) then
|
|
TrackObjectBucket(Bucket_OBJECTIVE_CONTESTED,hill,radius,false);
|
|
TrackObjectBucket(Bucket_OBJECTIVE_UNCONTESTED,hill,radius,false);
|
|
endif;
|
|
SetCustomBucketNameIndex(849);
|
|
AddStandardBuckets;
|
|
AddCustomBucketParameter(Bucket_OBJECTIVE_CONTESTED,1);
|
|
AddCustomBucketParameter(Bucket_OBJECTIVE_UNCONTESTED,5);
|
|
endfunction;
|
|
|
|
function SetupScoring_CTF;
|
|
var
|
|
|
|
code
|
|
SetFlagsEnabled(FLAGS_TEAM_ONLY);
|
|
ShowFlagsAsNavPoints(TRUE);
|
|
SetCustomBucketNameIndex(847);
|
|
AddStandardBuckets;
|
|
AddCustomBucketParameter(Bucket_FLAGS_CAPTURED,1000);
|
|
AddCustomBucketParameter(Bucket_ENEMY_KILLS,250);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_KILLS,-25);
|
|
AddCustomBucketParameter(Bucket_SUICIDES,-25);
|
|
endfunction;
|
|
|
|
function SetupScoring_Territories(ObjectID hill, integer radius);
|
|
var
|
|
|
|
code
|
|
SetFlagsEnabled(FLAGS_HIDE);
|
|
if (hill <> -1) then
|
|
TrackObjectBucket(Bucket_OBJECTIVE_UNCONTESTED,hill,radius,false);
|
|
endif;
|
|
SetCustomBucketNameIndex(852);
|
|
AddStandardBuckets;
|
|
AddCustomBucketParameter(Bucket_OBJECTIVE_UNCONTESTED,1);
|
|
endfunction;
|
|
|
|
function SetupScoring_CaptureBase;
|
|
var
|
|
|
|
code
|
|
SetFlagsEnabled(FLAGS_HIDE);
|
|
SetCustomBucketNameIndex(853);
|
|
AddStandardBuckets;
|
|
AddCustomBucketParameter(Bucket_ENEMY_KILLS,25);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_KILLS,-25);
|
|
AddCustomBucketParameter(Bucket_SUICIDES,-25);
|
|
endfunction;
|
|
|
|
function SetupScoring_DestroyObjective;
|
|
var
|
|
|
|
code
|
|
SetFlagsEnabled(FLAGS_HIDE);
|
|
SetCustomBucketNameIndex(854);
|
|
AddStandardBuckets;
|
|
// TODO: add scoring for objective destruction
|
|
AddCustomBucketParameter(Bucket_ENEMY_KILLS,25);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_KILLS,-25);
|
|
AddCustomBucketParameter(Bucket_SUICIDES,-25);
|
|
endfunction;
|
|
|
|
function SetupScoring_Escort;
|
|
var
|
|
|
|
code
|
|
SetFlagsEnabled(FLAGS_HIDE);
|
|
SetCustomBucketNameIndex(851);
|
|
AddStandardBuckets;
|
|
AddCustomBucketParameter(Bucket_ENEMY_KILLS,500);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_KILLS,-500);
|
|
AddCustomBucketParameter(Bucket_SUICIDES,-500);
|
|
endfunction;
|
|
|
|
function SetupScoring_SiegeAssault;
|
|
var
|
|
|
|
code
|
|
SetFlagsEnabled (FLAGS_HIDE);
|
|
SetCustomBucketNameIndex (862);
|
|
AddStandardBuckets;
|
|
AddCustomBucketParameter(Bucket_ENEMY_KILLS,25);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_KILLS,-25);
|
|
AddCustomBucketParameter(Bucket_SUICIDES,-25);
|
|
AddCustomBucketParameter(Bucket_ENEMY_BUILDING_KILLS,350);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_BUILDING_KILLS,-350);
|
|
AddCustomBucketParameter(Bucket_ENEMY_TURRET_KILLS,25);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_TURRET_KILLS,-25);
|
|
endfunction;
|
|
|
|
function SetupScoring_MasterTrial;
|
|
var
|
|
|
|
code
|
|
SetFlagsEnabled(FLAGS_HIDE);
|
|
SetCustomBucketNameIndex(861);
|
|
AddStandardBuckets;
|
|
AddCustomBucketParameter(Bucket_ENEMY_DAMAGE_INFLICT,1);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_DAMAGE_INFLICT,-1);
|
|
AddCustomBucketParameter(Bucket_ENEMY_KILLS,500);
|
|
AddCustomBucketParameter(Bucket_FRIENDLY_KILLS,-500);
|
|
AddCustomBucketParameter(Bucket_SUICIDES,-500);
|
|
endfunction;
|
|
|
|
code
|
|
|
|
print("mwfunc");
|
|
|
|
endlibrary.
|
|
|