1186 lines
28 KiB
Text
1186 lines
28 KiB
Text
|
|
||
|
#include "script/items/item_states.include"
|
||
|
|
||
|
object carryable_item {
|
||
|
void preinit();
|
||
|
void init();
|
||
|
void destroy();
|
||
|
void syncFields();
|
||
|
|
||
|
void OnCarrierChanged();
|
||
|
void OnPickup( entity p );
|
||
|
void OnDrop( entity p );
|
||
|
void OnTouch( entity p, object traceObject );
|
||
|
void OnReturned( string playerName );
|
||
|
float OnUpdateCrosshairInfo( entity p );
|
||
|
void OnObjectiveEntChanged();
|
||
|
|
||
|
void CreateCMIcon();
|
||
|
void DestroyCMIcon();
|
||
|
|
||
|
void vFinishObjective() { DestroyCMIcon(); }
|
||
|
void vStartObjective() { CreateCMIcon(); }
|
||
|
|
||
|
float OnCollide( object traceObject, vector velocity, float bodyId );
|
||
|
|
||
|
void SetupTasks();
|
||
|
void SetupEffects();
|
||
|
void SetupDropReturn();
|
||
|
|
||
|
void DropReturnThread( float delay );
|
||
|
void KillDropReturnThread();
|
||
|
|
||
|
void CreatePickupTask();
|
||
|
void CreateDefendTask();
|
||
|
void CreateReturnTask();
|
||
|
void CreateDeliverTask();
|
||
|
void CreateDefendDeliverPointTask();
|
||
|
void CreateStopTask();
|
||
|
|
||
|
void Idle();
|
||
|
void IdleAtBase();
|
||
|
void Drop();
|
||
|
void Reset();
|
||
|
|
||
|
void SetAtBase( boolean value );
|
||
|
|
||
|
string vGetQuickChatString( entity p );
|
||
|
|
||
|
entity carrier;
|
||
|
entity oldCarrier;
|
||
|
|
||
|
handle itemname;
|
||
|
|
||
|
string objString;
|
||
|
|
||
|
string vGetObjectiveString() { return objString; }
|
||
|
entity vGetSpectateEntity();
|
||
|
|
||
|
boolean atBase;
|
||
|
vector startPos;
|
||
|
vector startAngles;
|
||
|
float waitTime;
|
||
|
float iconHandle;
|
||
|
string iconMaterial;
|
||
|
float iconPriority;
|
||
|
|
||
|
handle itemDroppedPlayer;
|
||
|
handle itemDroppedEmpty;
|
||
|
handle itemReturnedPlayer;
|
||
|
handle itemReturnedEmpty;
|
||
|
handle itemGrabbed;
|
||
|
handle itemCaptured;
|
||
|
|
||
|
float cmIconHandle;
|
||
|
|
||
|
string crosshairIcon;
|
||
|
|
||
|
entity vGetCarrier() { return carrier; }
|
||
|
|
||
|
entity objectiveEnt;
|
||
|
|
||
|
float pickupTaskDef;
|
||
|
float deliverTaskDef;
|
||
|
float defendDeliverPointTaskDef;
|
||
|
|
||
|
float returnTaskDef;
|
||
|
float defendTaskDef;
|
||
|
float stopTaskDef;
|
||
|
|
||
|
task pickupTask;
|
||
|
task deliverTask;
|
||
|
task defendDeliverPointTask;
|
||
|
|
||
|
task returnTask;
|
||
|
task defendTask;
|
||
|
task stopTask;
|
||
|
|
||
|
void UpdateObjectiveProgress();
|
||
|
void SetObjectiveIndicator();
|
||
|
void OnIsPrimaryObjectiveChanged();
|
||
|
void vMakePrimaryObjective( boolean value );
|
||
|
void UpdateObjectiveThread();
|
||
|
void ClearObjectiveIndicator();
|
||
|
void SetObjectiveReminderTime( float time );
|
||
|
|
||
|
boolean isPrimaryObjective;
|
||
|
|
||
|
boolean vIsPrimaryObjective() { return isPrimaryObjective; }
|
||
|
|
||
|
float GetState();
|
||
|
|
||
|
float nextObjectiveReminderTime;
|
||
|
|
||
|
handle padEffect;
|
||
|
handle dropEffect;
|
||
|
boolean deployed;
|
||
|
|
||
|
float returnProficiencyCount;
|
||
|
|
||
|
void vOnDeploy();
|
||
|
void OnPosSynced();
|
||
|
|
||
|
void FreePickupTask();
|
||
|
void FreeReturnTask();
|
||
|
void FreeDeliverTask();
|
||
|
void FreeDefendDeliverPointTask();
|
||
|
void FreeStopTask();
|
||
|
void FreeDefendTask();
|
||
|
|
||
|
void UpdateGUIThread();
|
||
|
void FreeUpdateGUIThread();
|
||
|
|
||
|
void vCaptured();
|
||
|
|
||
|
boolean vDisablePlantCharge() { return true; }
|
||
|
|
||
|
boolean initialised;
|
||
|
boolean isMultiPartObjective;
|
||
|
|
||
|
float updateGUIThread;
|
||
|
}
|
||
|
|
||
|
void carryable_item::FreePickupTask() {
|
||
|
if ( pickupTask != $null ) {
|
||
|
pickupTask.free();
|
||
|
pickupTask = $null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::FreeReturnTask() {
|
||
|
if ( returnTask != $null ) {
|
||
|
returnTask.free();
|
||
|
returnTask = $null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::FreeDeliverTask() {
|
||
|
if ( deliverTask != $null ) {
|
||
|
deliverTask.free();
|
||
|
deliverTask = $null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::FreeDefendDeliverPointTask() {
|
||
|
if ( defendDeliverPointTask != $null ) {
|
||
|
defendDeliverPointTask.free();
|
||
|
defendDeliverPointTask = $null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::FreeStopTask() {
|
||
|
if ( stopTask != $null ) {
|
||
|
stopTask.free();
|
||
|
stopTask = $null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::FreeDefendTask() {
|
||
|
if ( defendTask != $null ) {
|
||
|
defendTask.free();
|
||
|
defendTask = $null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Gordon: FIXME: I really don't like this
|
||
|
#define CARRYABLE_ITEM_START_UNDEFINED '6666666 6666666 6666666'
|
||
|
|
||
|
void carryable_item::preinit() {
|
||
|
itemname = sys.localizeString( getKey( "item_name" ) );
|
||
|
waitTime = getFloatKeyWithDefault( "wait_time", 30 );
|
||
|
|
||
|
itemDroppedPlayer = sys.localizeString( "maps/generic/item/dropped/player" );
|
||
|
itemDroppedEmpty = sys.localizeString( "maps/generic/item/dropped/empty" );
|
||
|
itemReturnedPlayer = sys.localizeString( "maps/generic/item/returned/player" );
|
||
|
itemReturnedEmpty = sys.localizeString( "maps/generic/item/returned/empty" );
|
||
|
itemGrabbed = sys.localizeString( "maps/generic/item/grabbed" );
|
||
|
itemCaptured = sys.localizeString( "maps/generic/item/captured" );
|
||
|
|
||
|
iconMaterial = getKey( "mtr_icon" );
|
||
|
iconPriority = getFloatKeyWithDefault( "icon_priority", 10 );
|
||
|
crosshairIcon = getKey( "mtr_crosshair_icon" );
|
||
|
|
||
|
pickupTaskDef = GetPlayerTask( getKey( "task_pickup" ) );
|
||
|
returnTaskDef = GetPlayerTask( getKey( "task_return" ) );
|
||
|
deliverTaskDef = GetPlayerTask( getKey( "task_deliver" ) );
|
||
|
defendDeliverPointTaskDef = GetPlayerTask( getKey( "task_defend_deliver_point" ) );
|
||
|
defendTaskDef = GetPlayerTask( getKey( "task_defend" ) );
|
||
|
stopTaskDef = GetPlayerTask( getKey( "task_stop" ) );
|
||
|
|
||
|
cmIconHandle = -1;
|
||
|
|
||
|
padEffect = 0;
|
||
|
dropEffect = 0;
|
||
|
|
||
|
objString = "docObjective";
|
||
|
|
||
|
returnProficiencyCount = getFloatKeyWithDefault( "return_prof_count", 1.f );
|
||
|
|
||
|
isMultiPartObjective= getIntKey( "multi_part_objective" );
|
||
|
|
||
|
updateGUIThread = -1;
|
||
|
|
||
|
// initialize startPos to a wacky number
|
||
|
startPos = CARRYABLE_ITEM_START_UNDEFINED;
|
||
|
|
||
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, objString + ".transmitProgress", 0 );
|
||
|
}
|
||
|
|
||
|
void carryable_item::init() {
|
||
|
string teamName = getKey( "team" );
|
||
|
if ( teamName == "" ) {
|
||
|
sys.error( "carryable_item::preinit no team specified" );
|
||
|
} else {
|
||
|
setGameTeam( sys.getTeam( teamName ) );
|
||
|
}
|
||
|
|
||
|
setContents( CONTENTS_TRIGGER );
|
||
|
setClipmask( MASK_SOLID | CONTENTS_PLAYERCLIP | CONTENTS_FORCEFIELD );
|
||
|
|
||
|
if ( !sys.isClient() ) {
|
||
|
startPos = getWorldOrigin();
|
||
|
startAngles = getAngles();
|
||
|
|
||
|
if ( sys.getTeam( teamName ) == gdfTeam ) { //mal: flag there being an carryable obj on the map, and setup who owns it.
|
||
|
objManager.setActionObjState( ACTION_STATE_OBJ_BORN, GDF, self, self );
|
||
|
} else {
|
||
|
objManager.setActionObjState( ACTION_STATE_OBJ_BORN, STROGG, self, self );
|
||
|
}
|
||
|
|
||
|
if ( objectiveEnt == $null_entity ) {
|
||
|
objectiveEnt = getEntityKey( "objective" );
|
||
|
if ( objectiveEnt != $null_entity ) {
|
||
|
OnObjectiveEntChanged();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
disableImpact();
|
||
|
disableKnockback();
|
||
|
|
||
|
initialised = true;
|
||
|
|
||
|
if ( !sys.isClient() ) {
|
||
|
SetAtBase( true );
|
||
|
} else {
|
||
|
SetAtBase( atBase );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::vSetObjectiveString( string message ) {
|
||
|
objString = message;
|
||
|
}
|
||
|
|
||
|
void carryable_item::SetAtBase( boolean value ) {
|
||
|
atBase = value;
|
||
|
if ( initialised ) {
|
||
|
if ( atBase ) {
|
||
|
freeze( true );
|
||
|
setState( "IdleAtBase" );
|
||
|
} else {
|
||
|
freeze( false );
|
||
|
setState( "Idle" );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::UpdateObjectiveProgress() {
|
||
|
if ( sys.doClientSideStuff() ) {
|
||
|
float state = GetState();
|
||
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, objString + ".progress", state );
|
||
|
|
||
|
float transmitProgress = 0.f;
|
||
|
if ( objectiveEnt != $null_entity ) {
|
||
|
transmitProgress = objectiveEnt.vGetTransmitProgress();
|
||
|
}
|
||
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, objString + ".transmitProgress", transmitProgress );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::SetObjectiveIndicator() {
|
||
|
UpdateObjectiveProgress();
|
||
|
|
||
|
if ( !isMultiPartObjective ) {
|
||
|
thread UpdateObjectiveThread();
|
||
|
}
|
||
|
|
||
|
if ( sys.doClientSideStuff() ) {
|
||
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, objString + ".isMultiPart", isMultiPartObjective );
|
||
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, objString + ".active", 1.f );
|
||
|
}
|
||
|
|
||
|
SetupTasks();
|
||
|
CreateCMIcon();
|
||
|
}
|
||
|
|
||
|
void carryable_item::OnIsPrimaryObjectiveChanged() {
|
||
|
ClearObjectiveIndicator();
|
||
|
|
||
|
if ( isPrimaryObjective ) {
|
||
|
SetObjectiveIndicator();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::vMakePrimaryObjective( boolean value ) {
|
||
|
isPrimaryObjective = value;
|
||
|
OnIsPrimaryObjectiveChanged();
|
||
|
}
|
||
|
|
||
|
void carryable_item::UpdateObjectiveThread() {
|
||
|
waitUntil( objManager.gameState == GS_GAMEON );
|
||
|
|
||
|
objManager.PlaySound( getKey( "snd_intro_strogg" ), stroggTeam );
|
||
|
objManager.PlaySound( getKey( "snd_intro_gdf" ), gdfTeam );
|
||
|
|
||
|
SetObjectiveReminderTime( sys.getTime() + OBJECTIVEMESSAGE_WAIT_TIME );
|
||
|
|
||
|
while ( true ) {
|
||
|
UpdateObjectiveProgress();
|
||
|
|
||
|
if ( !sys.isClient() ) {
|
||
|
if ( sys.getTime() >= nextObjectiveReminderTime ) {
|
||
|
if ( objManager.gameState == GS_GAMEON ) {
|
||
|
objManager.PlaySound( getKey( "snd_reminder_strogg" ), stroggTeam );
|
||
|
objManager.PlaySound( getKey( "snd_reminder_gdf" ), gdfTeam );
|
||
|
}
|
||
|
|
||
|
SetObjectiveReminderTime( sys.getTime() + OBJECTIVEMESSAGE_WAIT_TIME );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sys.waitFrame();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::ClearObjectiveIndicator() {
|
||
|
sys.killThread( "UpdateObjectiveThread_" + getName() );
|
||
|
|
||
|
if ( sys.doClientSideStuff() ) {
|
||
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, objString + ".active", 0.f );
|
||
|
}
|
||
|
|
||
|
FreePickupTask();
|
||
|
FreeReturnTask();
|
||
|
FreeDeliverTask();
|
||
|
FreeDefendDeliverPointTask();
|
||
|
}
|
||
|
|
||
|
void carryable_item::SetObjectiveReminderTime( float time ) {
|
||
|
if ( time > nextObjectiveReminderTime ) {
|
||
|
nextObjectiveReminderTime = time;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::CreatePickupTask() {
|
||
|
if ( pickupTask == $null ) {
|
||
|
pickupTask = taskManager.allocEntityTask( pickupTaskDef, self );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::CreateDefendTask() {
|
||
|
if ( defendTask == $null ) {
|
||
|
defendTask = taskManager.allocEntityTask( defendTaskDef, self );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::CreateReturnTask() {
|
||
|
if ( returnTask == $null ) {
|
||
|
returnTask = taskManager.allocEntityTask( returnTaskDef, self );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::CreateDeliverTask() {
|
||
|
if ( deliverTask == $null ) {
|
||
|
deliverTask = taskManager.allocEntityTask( deliverTaskDef, objectiveEnt );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::CreateDefendDeliverPointTask() {
|
||
|
if ( defendDeliverPointTask == $null ) {
|
||
|
defendDeliverPointTask = taskManager.allocEntityTask( defendDeliverPointTaskDef, objectiveEnt );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::CreateStopTask() {
|
||
|
if ( stopTask == $null ) {
|
||
|
stopTask = taskManager.allocEntityTask( stopTaskDef, objectiveEnt );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::SetupTasks() {
|
||
|
SetupEffects();
|
||
|
|
||
|
if ( !isPrimaryObjective ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( !isMultiPartObjective ) {
|
||
|
// ao: always show deliver task, makes it consistent with MCP task.
|
||
|
CreateDeliverTask();
|
||
|
CreateDefendDeliverPointTask();
|
||
|
}
|
||
|
|
||
|
if ( carrier == $null_entity ) {
|
||
|
FreeStopTask();
|
||
|
|
||
|
CreatePickupTask();
|
||
|
|
||
|
if ( atBase ) {
|
||
|
FreeReturnTask();
|
||
|
CreateDefendTask();
|
||
|
} else {
|
||
|
FreeDefendTask();
|
||
|
CreateReturnTask();
|
||
|
}
|
||
|
} else {
|
||
|
FreePickupTask();
|
||
|
FreeReturnTask();
|
||
|
FreeDefendTask();
|
||
|
|
||
|
if ( !isMultiPartObjective ) {
|
||
|
CreateStopTask();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::vOnDeploy() {
|
||
|
SetupTasks();
|
||
|
deployed = true;
|
||
|
}
|
||
|
|
||
|
void carryable_item::SetupEffects() {
|
||
|
if ( startPos == CARRYABLE_ITEM_START_UNDEFINED ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( carrier == $null_entity ) {
|
||
|
if ( atBase ) {
|
||
|
if ( !padEffect ) {
|
||
|
padEffect = playOriginEffect( "fx_pad", "", startPos, '0 0 1', 1 );
|
||
|
unBindEffectHandle( padEffect );
|
||
|
setEffectOrigin( padEffect, startPos );
|
||
|
setEffectAngles( padEffect, '-90 0 0' );
|
||
|
}
|
||
|
if ( dropEffect ) {
|
||
|
stopEffectHandle( dropEffect );
|
||
|
dropEffect = 0;
|
||
|
}
|
||
|
} else {
|
||
|
if ( padEffect ) {
|
||
|
stopEffectHandle( padEffect );
|
||
|
padEffect = 0;
|
||
|
}
|
||
|
if ( !dropEffect ) {
|
||
|
// I'm not sure if the nerve guys want the dropped effect or not,
|
||
|
// but the script is in place just in case
|
||
|
//dropEffect = playEffect( "fx_dropped", "", 1 );
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
if ( padEffect ) {
|
||
|
stopEffectHandle( padEffect );
|
||
|
}
|
||
|
if ( dropEffect ) {
|
||
|
stopEffectHandle( dropEffect );
|
||
|
}
|
||
|
|
||
|
padEffect = 0;
|
||
|
dropEffect = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::OnObjectiveEntChanged() {
|
||
|
SetupTasks();
|
||
|
}
|
||
|
|
||
|
void carryable_item::CreateCMIcon() {
|
||
|
DestroyCMIcon();
|
||
|
|
||
|
cmIconHandle = sys.allocCMIcon( self, -103 );
|
||
|
float commandMapSize = getFloatKeyWithDefault( "icon_size_cm", 16 );
|
||
|
sys.setCMIconSize( cmIconHandle, commandMapSize );
|
||
|
sys.setCMIconColorMode( cmIconHandle, CM_NORMAL );
|
||
|
sys.setCMIconMaterial( cmIconHandle, GetMaterial( iconMaterial ) );
|
||
|
sys.setCMIconFlag( cmIconHandle, CMF_ALWAYSKNOWN );
|
||
|
}
|
||
|
|
||
|
void carryable_item::DestroyCMIcon() {
|
||
|
if ( cmIconHandle != -1 ) {
|
||
|
sys.freeCMIcon( self, cmIconHandle );
|
||
|
cmIconHandle = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::vOnPlayerKilled( entity p ) {
|
||
|
if ( p == carrier ) {
|
||
|
Drop();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::Idle() {
|
||
|
playCycle( ANIMCHANNEL_ALL, "idle_onground" );
|
||
|
freeze( false );
|
||
|
}
|
||
|
|
||
|
void carryable_item::IdleAtBase() {
|
||
|
startSound( "snd_idle", SND_ANY );
|
||
|
playCycle( ANIMCHANNEL_ALL, "idle_atbase" );
|
||
|
while ( true ) {
|
||
|
sys.waitFrame();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::destroy() {
|
||
|
|
||
|
if ( !sys.isClient() ) { //mal: let the bots know it was delivered - useful for multi - obj maps.
|
||
|
objManager.setActionObjState( ACTION_STATE_OBJ_DELIVERED, NOTEAM, self, self );
|
||
|
}
|
||
|
|
||
|
if ( carrier != $null_entity ) {
|
||
|
carrier.setCarryingObjective( false );
|
||
|
carrier.freeIcon( iconHandle );
|
||
|
}
|
||
|
|
||
|
FreePickupTask();
|
||
|
FreeReturnTask();
|
||
|
FreeDeliverTask();
|
||
|
FreeDefendDeliverPointTask();
|
||
|
DestroyCMIcon();
|
||
|
|
||
|
if ( padEffect ) {
|
||
|
stopEffectHandle( padEffect );
|
||
|
}
|
||
|
if ( dropEffect ) {
|
||
|
stopEffectHandle( dropEffect );
|
||
|
}
|
||
|
|
||
|
if ( isPrimaryObjective ) {
|
||
|
ClearObjectiveIndicator();
|
||
|
}
|
||
|
|
||
|
entity p = sys.getLocalPlayer();
|
||
|
if ( p != $null_entity ) {
|
||
|
if ( p == carrier ) {
|
||
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.carryableItemActive", 0 );
|
||
|
FreeUpdateGUIThread();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
stopSound( SND_ANY );
|
||
|
}
|
||
|
|
||
|
void carryable_item::syncFields() {
|
||
|
syncBroadcast( "carrier" );
|
||
|
syncCallback( "carrier", "OnCarrierChanged" );
|
||
|
syncBroadcast( "startPos" );
|
||
|
syncCallback( "startPos", "OnPosSynced" );
|
||
|
syncBroadcast( "atBase" );
|
||
|
syncCallback( "atBase", "OnPosSynced" );
|
||
|
syncBroadcast( "objectiveEnt" );
|
||
|
syncCallback( "objectiveEnt", "OnObjectiveEntChanged" );
|
||
|
syncBroadcast( "deployed" );
|
||
|
syncCallback( "deployed", "vOnDeploy" );
|
||
|
}
|
||
|
|
||
|
void carryable_item::Drop() {
|
||
|
if ( stopTask != $null ) {
|
||
|
stopTask.complete();
|
||
|
stopTask.free();
|
||
|
stopTask = $null;
|
||
|
}
|
||
|
|
||
|
OnDrop( carrier );
|
||
|
|
||
|
activatePhysics();
|
||
|
|
||
|
carrier = $null_entity;
|
||
|
SetupTasks();
|
||
|
}
|
||
|
|
||
|
void carryable_item::Reset() {
|
||
|
if ( !sys.isClient() ) {
|
||
|
objManager.setActionObjState( ACTION_STATE_OBJ_RETURNED, NOTEAM, self, self );
|
||
|
}
|
||
|
|
||
|
SetAtBase( true );
|
||
|
setOrigin( startPos );
|
||
|
setAngles( startAngles );
|
||
|
|
||
|
SetupTasks();
|
||
|
|
||
|
// ao: Must be the last thing that happens in this function.
|
||
|
OnReturned( "" );
|
||
|
}
|
||
|
|
||
|
void carryable_item::SetupDropReturn() {
|
||
|
if ( sys.isClient() ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( waitTime <= 0 ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
thread DropReturnThread( waitTime );
|
||
|
}
|
||
|
|
||
|
void carryable_item::DropReturnThread( float delay ) {
|
||
|
sys.wait( delay );
|
||
|
Reset();
|
||
|
}
|
||
|
|
||
|
void carryable_item::OnCarrierChanged() {
|
||
|
if ( carrier != $null_entity ) {
|
||
|
OnPickup( carrier );
|
||
|
} else {
|
||
|
OnDrop( oldCarrier );
|
||
|
}
|
||
|
|
||
|
oldCarrier = carrier;
|
||
|
|
||
|
SetupEffects();
|
||
|
}
|
||
|
|
||
|
void carryable_item::KillDropReturnThread() {
|
||
|
sys.killThread( "DropReturnThread_" + getName() );
|
||
|
}
|
||
|
|
||
|
void carryable_item::OnPickup( entity p ) {
|
||
|
objManager.PushCPrintString( p.getUserName() );
|
||
|
objManager.PushCPrintHandle( itemname );
|
||
|
objManager.CPrintEvent( itemGrabbed, $null );
|
||
|
|
||
|
objManager.PlaySound( getKey( "snd_stolen_strogg" ), stroggTeam );
|
||
|
objManager.PlaySound( getKey( "snd_stolen_gdf" ), gdfTeam );
|
||
|
|
||
|
stopSound( SND_ANY );
|
||
|
|
||
|
// create the player icon
|
||
|
iconHandle = p.createIcon( iconMaterial, iconPriority, 0.f );
|
||
|
|
||
|
if ( !sys.isClient() ) {
|
||
|
if ( p.isDisguised() ) {
|
||
|
p.disguise( $null_entity );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
KillDropReturnThread();
|
||
|
|
||
|
setOrigin( p.getWorldOrigin() + '0 0 64' );
|
||
|
bind( p );
|
||
|
hide();
|
||
|
|
||
|
player pEnt = p;
|
||
|
pEnt.setCarryingObjective( true );
|
||
|
|
||
|
sys.setCMIconFlag( cmIconHandle, CMF_ENEMYALWAYSKNOWN );
|
||
|
sys.clearCMIconFlag( cmIconHandle, CMF_ALWAYSKNOWN );
|
||
|
|
||
|
if ( p.isLocalPlayer() ) {
|
||
|
p.sendToolTip( GetToolTip( getKey( "tt_pickup" ) ) );
|
||
|
|
||
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.carryableItemActive", 1 );
|
||
|
FreeUpdateGUIThread();
|
||
|
updateGUIThread = thread UpdateGUIThread();
|
||
|
}
|
||
|
|
||
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, objString + ".state", CARRYABLE_ITEM_CARRIER );
|
||
|
}
|
||
|
|
||
|
void carryable_item::OnDrop( entity p ) {
|
||
|
if ( p != $null_entity ) {
|
||
|
objManager.PushCPrintString( p.getUserName() );
|
||
|
objManager.PushCPrintHandle( itemname );
|
||
|
objManager.CPrintEvent( itemDroppedPlayer, $null );
|
||
|
} else {
|
||
|
objManager.PushCPrintHandle( itemname );
|
||
|
objManager.CPrintEvent( itemDroppedEmpty, $null );
|
||
|
}
|
||
|
|
||
|
objManager.PlaySound( getKey( "snd_dropped_strogg" ), stroggTeam );
|
||
|
objManager.PlaySound( getKey( "snd_dropped_gdf" ), gdfTeam );
|
||
|
|
||
|
startSound( "snd_idle", SND_ANY );
|
||
|
|
||
|
SetupDropReturn();
|
||
|
|
||
|
if ( p != $null_entity ) {
|
||
|
p.freeIcon( iconHandle );
|
||
|
|
||
|
player pEnt = p;
|
||
|
pEnt.setCarryingObjective( false );
|
||
|
}
|
||
|
|
||
|
if ( !sys.isClient() ) {
|
||
|
objManager.setActionObjState( ACTION_STATE_OBJ_DROPPED, NOTEAM, self, self );
|
||
|
}
|
||
|
|
||
|
unbind();
|
||
|
show();
|
||
|
|
||
|
sys.clearCMIconFlag( cmIconHandle, CMF_ENEMYALWAYSKNOWN );
|
||
|
sys.setCMIconFlag( cmIconHandle, CMF_ALWAYSKNOWN );
|
||
|
|
||
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, objString + ".state", CARRYABLE_ITEM_DROPPED );
|
||
|
|
||
|
if ( p.isLocalPlayer() ) {
|
||
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.carryableItemActive", 0 );
|
||
|
FreeUpdateGUIThread();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::OnTouch( entity p, object traceObject ) {
|
||
|
if ( carrier != $null_entity || sys.isClient() || p.getHealth() <= 0 ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
player test = p;
|
||
|
if ( test == $null_entity ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
float allegiance = getEntityAllegiance( p );
|
||
|
if ( allegiance == TA_ENEMY ) {
|
||
|
if ( p.vGetCarryableItem() != $null_entity ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( !sys.isClient() ) {
|
||
|
objManager.setActionObjState( ACTION_STATE_OBJ_STOLEN, NOTEAM, self, p );
|
||
|
}
|
||
|
|
||
|
SetAtBase( false );
|
||
|
carrier = p;
|
||
|
OnPickup( p );
|
||
|
if ( pickupTask != $null ) {
|
||
|
pickupTask.complete();
|
||
|
pickupTask.free();
|
||
|
pickupTask = $null;
|
||
|
}
|
||
|
SetupTasks();
|
||
|
} else if ( allegiance == TA_FRIEND ) {
|
||
|
if ( !atBase ) {
|
||
|
setOrigin( startPos );
|
||
|
setAngles( startAngles );
|
||
|
SetAtBase( true );
|
||
|
|
||
|
if ( !sys.isClient() ) {
|
||
|
objManager.setActionObjState( ACTION_STATE_OBJ_RETURNED, NOTEAM, self, p );
|
||
|
}
|
||
|
|
||
|
p.giveClassProficiency( returnProficiencyCount, "returned objective" );
|
||
|
|
||
|
OnReturned( p.getUserName() );
|
||
|
if ( returnTask != $null ) {
|
||
|
returnTask.complete();
|
||
|
returnTask.free();
|
||
|
returnTask = $null;
|
||
|
}
|
||
|
SetupTasks();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::OnReturned( string playerName ) {
|
||
|
objManager.PlaySound( getKey( "snd_returned_strogg" ), stroggTeam );
|
||
|
objManager.PlaySound( getKey( "snd_returned_gdf" ), gdfTeam );
|
||
|
|
||
|
if ( playerName != "" ) {
|
||
|
objManager.PushCPrintString( playerName );
|
||
|
objManager.PushCPrintHandle( itemname );
|
||
|
objManager.CPrintEvent( itemReturnedPlayer, $null );
|
||
|
} else {
|
||
|
objManager.PushCPrintHandle( itemname );
|
||
|
objManager.CPrintEvent( itemReturnedEmpty, $null );
|
||
|
}
|
||
|
|
||
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, objString + ".state", CARRYABLE_ITEM_HOME );
|
||
|
|
||
|
// ao: Must be the last thing that happens in this function
|
||
|
KillDropReturnThread();
|
||
|
}
|
||
|
|
||
|
float carryable_item::OnUpdateCrosshairInfo( entity p ) {
|
||
|
if ( !sys.doClientSideStuff() ) {
|
||
|
return 1.f;
|
||
|
}
|
||
|
|
||
|
float allegiance = getEntityAllegiance( p );
|
||
|
float distance = chGetDistance();
|
||
|
float range = InchesToMetres( distance );
|
||
|
|
||
|
chSetNumLines( 0 );
|
||
|
|
||
|
vector color = GetAllegianceColor( allegiance );
|
||
|
team_base team;
|
||
|
|
||
|
float index = chAddLine();
|
||
|
chSetLineTextIndex( index, itemname );
|
||
|
chSetLineColor( index, color, 1.f );
|
||
|
chSetLineType( index, CI_TEXT );
|
||
|
chSetLineSize( index, 0, 0 );
|
||
|
if ( ( range <= 25.f ) && ( range >= 5.f ) ) {
|
||
|
index = chAddLine();
|
||
|
chSetLineText( index, G_BuildRangeStr( range ) );
|
||
|
chSetLineColor( index, color, 1.f );
|
||
|
chSetLineType( index, CI_TEXT );
|
||
|
chSetLineSize( index, 0, 0 );
|
||
|
}
|
||
|
|
||
|
return 1.f;
|
||
|
}
|
||
|
|
||
|
void carryable_item::OnPosSynced() {
|
||
|
SetupEffects();
|
||
|
SetAtBase( atBase );
|
||
|
|
||
|
if ( atBase ) {
|
||
|
OnReturned( "" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
float carryable_item::OnCollide( object traceObject, vector velocity, float bodyId ) {
|
||
|
float shaderFlags;
|
||
|
entity collisionEnt;
|
||
|
|
||
|
shaderFlags = traceObject.getTraceSurfaceFlags();
|
||
|
if ( shaderFlags & SURF_NOIMPACT || shaderFlags & SURF_NOPLANT ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
collisionEnt = traceObject.getTraceEntity();
|
||
|
|
||
|
if ( collisionEnt != sys.getEntity( "worldspawn" ) ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// push the view out of the surface a bit
|
||
|
vector normal = traceObject.getTraceNormal();
|
||
|
if ( normal_z < 0.4f ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// align to the surface normal
|
||
|
alignToAxis( normal, Z_AXIS );
|
||
|
setOrigin( traceObject.getTracePoint() );
|
||
|
|
||
|
if ( !sys.isClient() ) {
|
||
|
putToRest();
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
string carryable_item::vGetQuickChatString( entity p ) {
|
||
|
if ( p.getGameTeam() == getGameTeam() ) {
|
||
|
if ( atBase ) {
|
||
|
return "quickchat/objectives/defend";
|
||
|
} else {
|
||
|
return "quickchat/objectives/return";
|
||
|
}
|
||
|
} else {
|
||
|
return "quickchat/objectives/take";
|
||
|
}
|
||
|
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
void carryable_item::UpdateGUIThread() {
|
||
|
while ( true ) {
|
||
|
sys.wait( 5.f );
|
||
|
sys.setGUIString( GUI_GLOBALS_HANDLE, "gameHud.bumpNotifyIcon", "carryableitem" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item::FreeUpdateGUIThread() {
|
||
|
if ( updateGUIThread != -1 ) {
|
||
|
sys.terminate( updateGUIThread );
|
||
|
updateGUIThread = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
float carryable_item::GetState() {
|
||
|
float state = IS_DEFAULT;
|
||
|
if ( carrier == $null_entity ) {
|
||
|
if ( !atBase ) {
|
||
|
state = IS_DROPPED;
|
||
|
}
|
||
|
} else {
|
||
|
state = IS_CARRIED;
|
||
|
}
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
|
||
|
void carryable_item::vCaptured() {
|
||
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, objString + ".transmitProgress", 1 );
|
||
|
}
|
||
|
|
||
|
entity carryable_item::vGetSpectateEntity() {
|
||
|
if ( carrier != $null_entity ) {
|
||
|
return carrier;
|
||
|
}
|
||
|
if ( !atBase ) {
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
return $null_entity;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
carryable_item_dropped
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
object carryable_item_dropped : carryable_item {
|
||
|
void syncFields();
|
||
|
void init();
|
||
|
|
||
|
boolean manualDeploy;
|
||
|
entity deployer;
|
||
|
};
|
||
|
|
||
|
void carryable_item_dropped::syncFields() {
|
||
|
syncBroadcast( "deployer" );
|
||
|
}
|
||
|
|
||
|
void carryable_item_dropped::init() {
|
||
|
if ( !manualDeploy && !sys.isClient() ) {
|
||
|
vOnDeploy();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item_dropped::vSetOwner( entity o ) {
|
||
|
deployer = o;
|
||
|
}
|
||
|
|
||
|
void carryable_item_dropped::vOnDeploy() {
|
||
|
deployed = true;
|
||
|
startPos = getWorldOrigin();
|
||
|
startAngles = getAngles();
|
||
|
|
||
|
if ( !sys.isClient() ) {
|
||
|
objectiveEnt = deployer.getEntityKey( "target_objective" );
|
||
|
OnObjectiveEntChanged();
|
||
|
|
||
|
setGameTeam( sys.getTeam( getKey( "deployteam" ) ) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void carryable_item_dropped::vSetManualDeploy() {
|
||
|
manualDeploy = true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
item_drop_pod
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
object item_drop_pod {
|
||
|
void preinit();
|
||
|
void syncFields();
|
||
|
void init();
|
||
|
|
||
|
void SmashThread();
|
||
|
void OnEffectOriginUpdate();
|
||
|
|
||
|
void vSetOwner( entity o );
|
||
|
|
||
|
void DeployAnimThread( entity item );
|
||
|
|
||
|
boolean manualDeploy;
|
||
|
boolean deployed;
|
||
|
|
||
|
string idleClosedAnim;
|
||
|
string idleOpenAnim;
|
||
|
string openAnim;
|
||
|
string defaultEffect;
|
||
|
|
||
|
// used for playing the crashing effects
|
||
|
// note that it can only play one effect per frame
|
||
|
entity lastEffectEntity;
|
||
|
vector lastEffectOrigin;
|
||
|
|
||
|
entity targetEnt;
|
||
|
|
||
|
float itemIndex;
|
||
|
}
|
||
|
|
||
|
void item_drop_pod::syncFields() {
|
||
|
syncBroadcast( "deployed" );
|
||
|
syncCallback( "deployed", "vOnDeploy" );
|
||
|
sync( "lastEffectEntity" );
|
||
|
sync( "lastEffectOrigin" );
|
||
|
syncCallback( "lastEffectOrigin", "OnEffectOriginUpdate" );
|
||
|
}
|
||
|
|
||
|
void item_drop_pod::preinit() {
|
||
|
defaultEffect = getKey( "fx_smash" );
|
||
|
if ( !sys.isClient() ) {
|
||
|
thread SmashThread();
|
||
|
}
|
||
|
|
||
|
itemIndex = getFloatKeyWithDefault( "item_index", -1 );
|
||
|
if ( itemIndex == -1 ) {
|
||
|
sys.warning( "item_drop_pod::preinit no item index set" );
|
||
|
}
|
||
|
}
|
||
|
void item_drop_pod::init() {
|
||
|
if ( !manualDeploy && !sys.isClient() ) {
|
||
|
vOnDeploy();
|
||
|
}
|
||
|
|
||
|
idleClosedAnim = getKeyWithDefault( "anim_idle_closed", "idle_closed" );
|
||
|
idleOpenAnim = getKeyWithDefault( "anim_idle_open", "idle_open" );
|
||
|
openAnim = getKeyWithDefault( "anim_open", "deploy" );
|
||
|
|
||
|
if ( !deployed ) {
|
||
|
playCycle( ANIMCHANNEL_ALL, idleClosedAnim );
|
||
|
|
||
|
disableImpact();
|
||
|
forceDisableClip();
|
||
|
} else {
|
||
|
playCycle( ANIMCHANNEL_ALL, idleOpenAnim );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void item_drop_pod::vSetOwner( entity o ) {
|
||
|
targetEnt = o.getEntityKey( "target" );
|
||
|
}
|
||
|
|
||
|
void item_drop_pod::vOnDeploy() {
|
||
|
deployed = true;
|
||
|
|
||
|
forceEnableClip();
|
||
|
putToRest();
|
||
|
disableImpact();
|
||
|
|
||
|
sys.killThread( "SmashThread_" + getName() );
|
||
|
|
||
|
entity item;
|
||
|
if ( !sys.isClient() ) {
|
||
|
// create the item, then open the pod up
|
||
|
float itemDef = GetEntityDef( getKey( "def_item" ) );
|
||
|
item = sys.spawnType( itemDef );
|
||
|
|
||
|
vector mins = item.getMins();
|
||
|
vector maxs = item.getMaxs();
|
||
|
|
||
|
// find the spawning point for the item
|
||
|
vector traceEnd = getWorldOrigin();
|
||
|
vector traceStart = traceEnd + '0 0 128';
|
||
|
|
||
|
sys.trace( traceStart, traceEnd, mins, maxs, CONTENTS_PLAYERCLIP, item );
|
||
|
vector spawnPoint = sys.getTraceEndPos();
|
||
|
item.setWorldOrigin( spawnPoint );
|
||
|
|
||
|
item.setAngles( getAngles() );
|
||
|
if ( itemIndex != -1 ) {
|
||
|
targetEnt.vOnItemDeployed( itemIndex, item );
|
||
|
}
|
||
|
|
||
|
// do some radius damage
|
||
|
sys.applyRadiusDamage( getWorldOrigin(), self, $null_entity, $null_entity, self, GetDamage( getKey( "dmg_landing" ) ), 1.0f, 1.0f );
|
||
|
}
|
||
|
|
||
|
thread DeployAnimThread( item );
|
||
|
}
|
||
|
|
||
|
void item_drop_pod::DeployAnimThread( entity item ) {
|
||
|
playAnim( ANIMCHANNEL_ALL, openAnim );
|
||
|
waitUntil( !isAnimating() );
|
||
|
playCycle( ANIMCHANNEL_ALL, idleOpenAnim );
|
||
|
|
||
|
if ( item != $null_entity ) {
|
||
|
item.vOnDeploy();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void item_drop_pod::vSetManualDeploy() {
|
||
|
manualDeploy = true;
|
||
|
}
|
||
|
|
||
|
void item_drop_pod::SmashThread() {
|
||
|
vector lastOrigin = getWorldOrigin();
|
||
|
eachFrame {
|
||
|
vector origin = getWorldOrigin();
|
||
|
|
||
|
// build a bounds with the last origin and this origin
|
||
|
vector mins = origin;
|
||
|
vector maxs = lastOrigin;
|
||
|
if ( mins_x > maxs_x ) {
|
||
|
mins_x = lastOrigin_x;
|
||
|
maxs_x = origin_x;
|
||
|
}
|
||
|
if ( mins_y > maxs_y ) {
|
||
|
mins_y = lastOrigin_y;
|
||
|
maxs_y = origin_y;
|
||
|
}
|
||
|
if ( mins_z > maxs_z ) {
|
||
|
mins_z = lastOrigin_z;
|
||
|
maxs_z = origin_z;
|
||
|
}
|
||
|
|
||
|
mins = mins - '16 16 16';
|
||
|
maxs = maxs + '16 16 16';
|
||
|
|
||
|
lastOrigin = origin;
|
||
|
|
||
|
// sys.debugBounds( '1 1 1', mins, maxs, 0.f );
|
||
|
|
||
|
float count = entitiesInBounds( mins, maxs, MASK_ALL, 1 );
|
||
|
float i;
|
||
|
boolean hasPlayedEffect = false;
|
||
|
for( i = 0; i < count; i++ ) {
|
||
|
entity ent = getBoundsCacheEntity( i );
|
||
|
if( ent == self || ent == $null_entity ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ( !hasPlayedEffect ) {
|
||
|
if ( ent.inCollection( "drop_pod_smash" ) ) {
|
||
|
ent.hide();
|
||
|
ent.forceDisableClip();
|
||
|
|
||
|
// show the showing target
|
||
|
entity showEnt = ent.getEntityKey( "target_show" );
|
||
|
if ( showEnt != $null_entity ) {
|
||
|
showEnt.show();
|
||
|
showEnt.forceEnableClip();
|
||
|
}
|
||
|
|
||
|
// set up the effect stuff
|
||
|
lastEffectEntity = ent;
|
||
|
lastEffectOrigin = ( origin + lastOrigin ) * 0.5f;
|
||
|
OnEffectOriginUpdate();
|
||
|
|
||
|
|
||
|
// NOTE - since it can only play one effect per frame,
|
||
|
// for consistency I'm not letting it hide multiple entities
|
||
|
// per frame either.
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void item_drop_pod::OnEffectOriginUpdate() {
|
||
|
if ( lastEffectEntity == $null_entity ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
string effect = lastEffectEntity.getKeyWithDefault( "fx_drop_pod_smash", defaultEffect );
|
||
|
|
||
|
// play the effect
|
||
|
if ( effect != "" ) {
|
||
|
sys.playWorldEffect( effect, '1 1 1', lastEffectOrigin, '0 0 1' );
|
||
|
}
|
||
|
}
|