608 lines
15 KiB
Plaintext
608 lines
15 KiB
Plaintext
|
|
||
|
object hackable_objective {
|
||
|
void preinit();
|
||
|
void syncFields();
|
||
|
void destroy();
|
||
|
|
||
|
float vGetPliersProgressBarValue( float action );
|
||
|
boolean vCheckActionCode( entity p, float actionCode );
|
||
|
|
||
|
void vMakePrimaryObjective( boolean value );
|
||
|
|
||
|
void vCreateMission();
|
||
|
void vFreeMission();
|
||
|
void vCompleteMission();
|
||
|
|
||
|
void OnUpdateGui( entity p );
|
||
|
float OnActivate( entity p, float distance );
|
||
|
float OnUpdateCrosshairInfo( entity p );
|
||
|
|
||
|
boolean HasHackContext( entity other );
|
||
|
|
||
|
float GetActivateCode( entity p, float distance );
|
||
|
|
||
|
void OnHacked( entity p );
|
||
|
void OnHacked_Base( entity p );
|
||
|
|
||
|
void OnIsPrimaryObjectiveChanged();
|
||
|
void OnHackCountChanged();
|
||
|
|
||
|
void SetObjectiveIndicator();
|
||
|
void ClearObjectiveIndicator();
|
||
|
void UpdateObjectiveProgress();
|
||
|
float CalcObjectiveProgress();
|
||
|
void UpdateObjectiveThread();
|
||
|
void SetObjectiveReminderTime( float time );
|
||
|
|
||
|
void KillFizzleThread();
|
||
|
void CreateFizzleThread( float delay );
|
||
|
void OnFizzled();
|
||
|
void FizzleThread( float delay );
|
||
|
|
||
|
void SetObjectiveIndex( float index );
|
||
|
|
||
|
boolean AllowHack() { return true; }
|
||
|
|
||
|
void vHack( entity p );
|
||
|
|
||
|
string vGetObjectiveString() { return "hackObjective"; }
|
||
|
|
||
|
team_base baseTeam;
|
||
|
|
||
|
boolean isPrimaryObjective;
|
||
|
|
||
|
boolean vIsPrimaryObjective() { return isPrimaryObjective; }
|
||
|
|
||
|
void vOnContextDefend( entity p );
|
||
|
void vOnContextHack( entity p );
|
||
|
|
||
|
entity vGetSpectateEntity();
|
||
|
boolean vIsObjectiveComplete();
|
||
|
|
||
|
float hackCount;
|
||
|
float maxHackCount;
|
||
|
|
||
|
float objectiveIndex;
|
||
|
|
||
|
float objectiveGUI;
|
||
|
|
||
|
handle progressMessage;
|
||
|
float nextProgressMessageTime;
|
||
|
|
||
|
float infoToolTip;
|
||
|
float useMeToolTip1;
|
||
|
float useMeToolTip2;
|
||
|
|
||
|
handle objectName;
|
||
|
|
||
|
task missionTask;
|
||
|
|
||
|
float fizzleTime;
|
||
|
float fizzleEndTime;
|
||
|
boolean fizzleThreadActive;
|
||
|
boolean fizzling;
|
||
|
|
||
|
float hackProficiency;
|
||
|
|
||
|
entity hacker;
|
||
|
float lastHackTime;
|
||
|
boolean forceMessage;
|
||
|
|
||
|
float nextObjectiveReminderTime;
|
||
|
|
||
|
flashpoint_obj flashpoint;
|
||
|
}
|
||
|
|
||
|
void hackable_objective::preinit() {
|
||
|
setGameTeam( sys.getTeam( getKey( "team" ) ) );
|
||
|
|
||
|
hackProficiency = GetProficiency( getKey( "prof_hack" ) );
|
||
|
|
||
|
baseTeam = getGameTeam();
|
||
|
objectiveIndex = getFloatKeyWithDefault( "objective_index", -1 );
|
||
|
|
||
|
fizzleTime = getFloatKeyWithDefault( "fizzle_time", 60.f );
|
||
|
|
||
|
progressMessage = sys.localizeString( getKeyWithDefault( "progress_message", "maps/generic/obj_hacking" ) ); //"is hacking the objective!" );
|
||
|
|
||
|
maxHackCount = gameRules.GetFloatKeyWithSuffix( self, "hack_count", 100.f );
|
||
|
objectName = sys.localizeString( getKeyWithDefault( "object_name", "maps/generic/obj_hackable" ) );
|
||
|
|
||
|
forceMessage = false;
|
||
|
|
||
|
infoToolTip = GetToolTip( getKey( "tt_intro_info" ) );
|
||
|
useMeToolTip1 = GetToolTip( getKey( "tt_intro_use_me_1" ) );
|
||
|
useMeToolTip2 = GetToolTip( getKey( "tt_intro_use_me_2" ) );
|
||
|
|
||
|
objectiveGUI = -1;
|
||
|
if ( getIntKey( "use_objective_gui" ) ) {
|
||
|
if ( sys.doClientSideStuff() ) {
|
||
|
objectiveGUI = getGUI( "0" );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void hackable_objective::syncFields() {
|
||
|
syncBroadcast( "fizzling" );
|
||
|
sync( "hackCount" );
|
||
|
syncCallback( "hackCount", "OnHackCountChanged" );
|
||
|
}
|
||
|
|
||
|
void hackable_objective::destroy() {
|
||
|
vFreeMission();
|
||
|
|
||
|
if ( flashpoint != $null ) {
|
||
|
delete flashpoint;
|
||
|
}
|
||
|
|
||
|
if ( isPrimaryObjective ) {
|
||
|
ClearObjectiveIndicator();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void hackable_objective::OnIsPrimaryObjectiveChanged() {
|
||
|
ClearObjectiveIndicator();
|
||
|
|
||
|
if ( isPrimaryObjective ) {
|
||
|
SetObjectiveIndicator();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void hackable_objective::SetObjectiveReminderTime( float time ) {
|
||
|
if ( time > nextObjectiveReminderTime ) {
|
||
|
nextObjectiveReminderTime = time;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void hackable_objective::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 hackable_objective::SetObjectiveIndicator() {
|
||
|
UpdateObjectiveProgress();
|
||
|
|
||
|
thread UpdateObjectiveThread();
|
||
|
|
||
|
if ( sys.doClientSideStuff() ) {
|
||
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "hackObjective.active", 1.f );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void hackable_objective::ClearObjectiveIndicator() {
|
||
|
sys.killThread( "UpdateObjectiveThread_" + getName() );
|
||
|
|
||
|
if ( sys.doClientSideStuff() ) {
|
||
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "hackObjective.active", 0.f );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void hackable_objective::UpdateObjectiveProgress() {
|
||
|
if ( sys.doClientSideStuff() ) {
|
||
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "hackObjective.decaying", fizzling );
|
||
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "hackObjective.progress", CalcObjectiveProgress() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
float hackable_objective::CalcObjectiveProgress() {
|
||
|
return hackCount / maxHackCount;
|
||
|
}
|
||
|
|
||
|
|
||
|
void hackable_objective::vMakePrimaryObjective( boolean value ) {
|
||
|
isPrimaryObjective = value;
|
||
|
|
||
|
OnIsPrimaryObjectiveChanged();
|
||
|
}
|
||
|
|
||
|
|
||
|
boolean hackable_objective::vCheckActionCode( entity p, float actionCode ) {
|
||
|
if ( objManager.gameState != GS_GAMEON ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ( actionCode == AC_HACK && AllowHack() ) {
|
||
|
if ( p.getGameTeam() == baseTeam ) {
|
||
|
return false;
|
||
|
}
|
||
|
return getEntityAllegiance( p ) == TA_ENEMY;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void hackable_objective::OnHacked( entity p ) {
|
||
|
OnHacked_Base( p );
|
||
|
}
|
||
|
|
||
|
void hackable_objective::OnHacked_Base( entity p ) {
|
||
|
object newTeam = p.getGameTeam();
|
||
|
|
||
|
string statName = newTeam.getName();
|
||
|
if ( objectiveIndex != -1 ) {
|
||
|
statName = statName + "_primary";
|
||
|
} else {
|
||
|
statName = statName + "_secondary";
|
||
|
}
|
||
|
statName = statName + "_objective_hacked";
|
||
|
|
||
|
if ( p != $null_entity ) {
|
||
|
sys.increaseStatInt( sys.allocStatInt( statName ), p.getEntityNumber(), 1 );
|
||
|
sys.increaseStatInt( sys.allocStatInt( newTeam.getName() + "_hack_uses" ), p.getEntityNumber(), 1 );
|
||
|
sys.increaseStatInt( sys.allocStatInt( "total_objectives_completed" ), p.getEntityNumber(), 1 );
|
||
|
}
|
||
|
|
||
|
if ( objectiveIndex != -1 ) {
|
||
|
objManager.CompleteObjective( objectiveIndex, p );
|
||
|
}
|
||
|
objManager.OnHackComplete( self );
|
||
|
|
||
|
G_PlayObjectiveCompletedRollEnt( self );
|
||
|
objManager.PlaySound( getKey( "snd_finished_strogg" ), stroggTeam );
|
||
|
objManager.PlaySound( getKey( "snd_finished_gdf" ), gdfTeam );
|
||
|
|
||
|
setGameTeam( newTeam );
|
||
|
|
||
|
KillFizzleThread();
|
||
|
}
|
||
|
|
||
|
void hackable_objective::OnUpdateGui( entity p ) {
|
||
|
float guiHandle = getGUI( "0" );
|
||
|
if ( guiHandle == GUI_INVALID ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( self.getEntityAllegiance( p ) != TA_FRIEND ) {
|
||
|
sys.setGUIFloat( guiHandle, "disabled", 1 );
|
||
|
} else {
|
||
|
sys.setGUIFloat( guiHandle, "disabled", 0 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
boolean hackable_objective::HasHackContext( entity other ) {
|
||
|
object otherTeam = other.getGameTeam();
|
||
|
if ( otherTeam == baseTeam ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ( otherTeam == getGameTeam() ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ( !AllowHack() ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
float hackable_objective::GetActivateCode( entity p, float distance ) {
|
||
|
if ( objManager.gameState != GS_GAMEON ) {
|
||
|
return AK_INWARMUP;
|
||
|
}
|
||
|
|
||
|
if ( p.getViewingEntity() != p ) {
|
||
|
return AK_NONE;
|
||
|
}
|
||
|
|
||
|
if ( p.getHealth() <= 0 ) {
|
||
|
return AK_NONE;
|
||
|
}
|
||
|
|
||
|
float allegiance = getEntityAllegiance( p );
|
||
|
|
||
|
if ( p.getGameTeam() == baseTeam ) {
|
||
|
return AK_NONE;
|
||
|
}
|
||
|
|
||
|
if ( p.getGameTeam() == getGameTeam() ) {
|
||
|
return AK_NONE;
|
||
|
}
|
||
|
|
||
|
if ( distance < DISTANCE_FOR_ACTION ) {
|
||
|
if ( AllowHack() ) {
|
||
|
if ( p.hasAbility( "hack" ) ) {
|
||
|
return AK_HACK;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return AK_NONE;
|
||
|
}
|
||
|
|
||
|
float hackable_objective::OnUpdateCrosshairInfo( entity p ) {
|
||
|
if ( !sys.doClientSideStuff() ) {
|
||
|
return 1.f;
|
||
|
}
|
||
|
|
||
|
float allegiance = getEntityAllegiance( p );
|
||
|
vector color = GetAllegianceColor( allegiance );
|
||
|
float distance = chGetDistance();
|
||
|
float range = InchesToMetres( distance );
|
||
|
float health = getHealth();
|
||
|
|
||
|
chSetNumLines( 0 );
|
||
|
float index;
|
||
|
|
||
|
if ( p != $null_entity ) {
|
||
|
if ( p.isLocalPlayer() && objectiveIndex != -1 ) {
|
||
|
p.sendToolTip( infoToolTip );
|
||
|
}
|
||
|
|
||
|
// see if theres a valid action to perform
|
||
|
float code = GetActivateCode( p, distance );
|
||
|
if ( code != AK_NONE && p.vHasActionItem( code ) ) {
|
||
|
index = chAddLine();
|
||
|
chSetLineMaterial( index, p.vGetActionIcon( code ) );
|
||
|
chSetLineType( index, CI_IMAGE );
|
||
|
chSetLineSize( index, 64, 64 );
|
||
|
chSetLineColor( index, g_colorWhite, 0.9f );
|
||
|
|
||
|
if ( p.isLocalPlayer() ) {
|
||
|
if ( !p.isToolTipPlaying() ) {
|
||
|
if ( sys.getTime() - p.getCrosshairStartTime() > 1.f ) {
|
||
|
if ( p.getCurrentWeapon() != p.vGetActionItem( code ) ) {
|
||
|
p.sendToolTip( useMeToolTip1 );
|
||
|
} else {
|
||
|
p.sendToolTip( useMeToolTip2 );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else if ( code == AK_INWARMUP ) {
|
||
|
if ( p.isLocalPlayer() && distance < DISTANCE_FOR_ACTION ) {
|
||
|
team_base team = p.getGameTeam();
|
||
|
if ( team != $null_entity ) {
|
||
|
p.sendToolTip( GetToolTip( getKey( "tt_noobjective" ) ) );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
index = chAddLine();
|
||
|
chSetLineTextIndex( index, objectName );
|
||
|
chSetLineColor( index, color, 1.f );
|
||
|
chSetLineType( index, CI_TEXT );
|
||
|
chSetLineSize( index, 0, 0 );
|
||
|
|
||
|
return 1.f;
|
||
|
}
|
||
|
|
||
|
float hackable_objective::vGetPliersProgressBarValue( float action ) {
|
||
|
if ( action == AC_HACK ) {
|
||
|
return hackCount / maxHackCount;
|
||
|
}
|
||
|
|
||
|
return 0.f;
|
||
|
}
|
||
|
|
||
|
void hackable_objective::vHack( entity p ) {
|
||
|
float time = sys.getTime();
|
||
|
entity oldHacker = hacker;
|
||
|
if ( hacker == $null_entity || lastHackTime < time - 2 ) {
|
||
|
hacker = p;
|
||
|
if ( lastHackTime < time - 10 ) {
|
||
|
oldHacker = $null_entity;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( objectiveIndex != -1 || forceMessage ) {
|
||
|
if ( p == hacker ) {
|
||
|
if ( sys.getTime() > nextProgressMessageTime ) {
|
||
|
objManager.PushCPrintString( p.getUserName() );
|
||
|
objManager.CPrintEvent( progressMessage, $null );
|
||
|
nextProgressMessageTime = sys.getTime() + 5.f;
|
||
|
}
|
||
|
|
||
|
if ( hacker != oldHacker ) {
|
||
|
|
||
|
if ( !sys.isClient() ) {
|
||
|
objManager.setBotActionStateForEvent( ACTION_STATE_START_HACK, hacker ); //mal: let the bots know someone is hacking the obj!
|
||
|
}
|
||
|
|
||
|
objManager.PlaySound( getKey( "snd_hacking_strogg" ), stroggTeam );
|
||
|
objManager.PlaySound( getKey( "snd_hacking_gdf" ), gdfTeam );
|
||
|
|
||
|
SetObjectiveReminderTime( sys.getTime() + ( OBJECTIVEMESSAGE_WAIT_TIME * 0.5f ) );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
lastHackTime = time;
|
||
|
|
||
|
if ( hackCount >= maxHackCount ) {
|
||
|
hackCount = 0;
|
||
|
}
|
||
|
|
||
|
float count = 1;
|
||
|
team_base team = p.getGameTeam();
|
||
|
if ( team.HasFastHackBonus( p ) ) {
|
||
|
count = count * 1.25f;
|
||
|
}
|
||
|
|
||
|
hackCount = hackCount + count;
|
||
|
OnHackCountChanged();
|
||
|
|
||
|
if ( hackProficiency != -1 ) {
|
||
|
p.giveProficiency( hackProficiency, ( count / maxHackCount ), missionTask, "hacking objective" );
|
||
|
}
|
||
|
|
||
|
if ( !sys.isClient() ) {
|
||
|
if ( hackCount >= maxHackCount ) {
|
||
|
OnHacked( p );
|
||
|
} else {
|
||
|
if ( fizzleTime > 0.f ) {
|
||
|
CreateFizzleThread( fizzleTime );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
float hackable_objective::OnActivate( entity p, float distance ) {
|
||
|
if ( distance > 128.f ) {
|
||
|
return 0.0f;
|
||
|
}
|
||
|
|
||
|
if ( p.getViewingEntity() != p ) {
|
||
|
return 0.0f;
|
||
|
}
|
||
|
|
||
|
if ( vCheckActionCode( p, AC_HACK ) ) {
|
||
|
if ( p.isDisguised() ) {
|
||
|
p.disguise( $null_entity );
|
||
|
}
|
||
|
|
||
|
team_base team = p.getGameTeam();
|
||
|
team.SelectActionItem( p, AK_HACK );
|
||
|
}
|
||
|
|
||
|
return 1.f;
|
||
|
}
|
||
|
|
||
|
void hackable_objective::SetObjectiveIndex( float index ) {
|
||
|
objectiveIndex = index;
|
||
|
}
|
||
|
|
||
|
void hackable_objective::vCreateMission() {
|
||
|
vFreeMission();
|
||
|
missionTask = taskManager.allocEntityTask( GetPlayerTask( getKey( "task_hack" ) ), self );
|
||
|
}
|
||
|
|
||
|
void hackable_objective::vFreeMission() {
|
||
|
if ( missionTask != $null ) {
|
||
|
missionTask.free();
|
||
|
missionTask = $null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void hackable_objective::vCompleteMission() {
|
||
|
if ( missionTask != $null ) {
|
||
|
missionTask.complete();
|
||
|
missionTask.free();
|
||
|
missionTask = $null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void hackable_objective::KillFizzleThread() {
|
||
|
fizzling = false;
|
||
|
fizzleEndTime = 0;
|
||
|
sys.killThread( "FizzleThread_" + getName() );
|
||
|
fizzleThreadActive = false;
|
||
|
}
|
||
|
|
||
|
void hackable_objective::CreateFizzleThread( float delay ) {
|
||
|
KillFizzleThread();
|
||
|
|
||
|
fizzleEndTime = sys.getTime() + delay;
|
||
|
if ( !fizzleThreadActive ) {
|
||
|
thread FizzleThread( delay );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void hackable_objective::OnFizzled() {
|
||
|
float fizzleDuration = g_objectiveDecayTime.getFloatValue();
|
||
|
|
||
|
// fizzle over time
|
||
|
while ( hackCount > 0 ) {
|
||
|
fizzling = true;
|
||
|
float fizzleAmount = maxHackCount * ( sys.getFrameTime() / fizzleDuration );
|
||
|
hackCount = hackCount - fizzleAmount;
|
||
|
OnHackCountChanged();
|
||
|
sys.waitFrame();
|
||
|
}
|
||
|
fizzling = false;
|
||
|
|
||
|
hackCount = 0;
|
||
|
OnHackCountChanged();
|
||
|
|
||
|
if ( !sys.isClient() ) {
|
||
|
objManager.setBotActionStateForEvent( ACTION_STATE_HACK_FIZZLED, self ); //mal: let the bots know the hack has fizzled
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void hackable_objective::FizzleThread( float delay ) {
|
||
|
fizzling = false;
|
||
|
sys.threadName( "FizzleThread_" + getName() );
|
||
|
|
||
|
fizzleThreadActive = true;
|
||
|
while ( sys.getTime() < fizzleEndTime ) {
|
||
|
sys.wait( fizzleEndTime - sys.getTime() );
|
||
|
}
|
||
|
fizzleThreadActive = false;
|
||
|
if ( fizzleEndTime != 0 ) {
|
||
|
OnFizzled();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void hackable_objective::vOnContextDefend( entity p ) {
|
||
|
player local = sys.getLocalViewPlayer();
|
||
|
if ( local == $null_entity || p == $null_entity ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( flashpoint != $null ) {
|
||
|
delete flashpoint;
|
||
|
}
|
||
|
|
||
|
flashpoint = new flashpoint_obj;
|
||
|
flashpoint.SetOwner( self );
|
||
|
flashpoint.SetMaterial( getKey( "mtr_icon_flash_defend" ) );
|
||
|
}
|
||
|
|
||
|
void hackable_objective::vOnContextHack( entity p ) {
|
||
|
player local = sys.getLocalViewPlayer();
|
||
|
if ( local == $null_entity || p == $null_entity ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( flashpoint != $null ) {
|
||
|
delete flashpoint;
|
||
|
}
|
||
|
|
||
|
flashpoint = new flashpoint_obj;
|
||
|
flashpoint.SetOwner( self );
|
||
|
flashpoint.SetMaterial( getKey( "mtr_icon_flash" ) );
|
||
|
}
|
||
|
|
||
|
void hackable_objective::OnHackCountChanged() {
|
||
|
if ( objectiveGUI != -1 ) {
|
||
|
if ( sys.doClientSideStuff() ) {
|
||
|
sys.setGUIFloat( objectiveGUI, "progress", CalcObjectiveProgress() );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
entity hackable_objective::vGetSpectateEntity() {
|
||
|
float time = sys.getTime();
|
||
|
if ( lastHackTime >= time - 0.5f ) {
|
||
|
return hacker;
|
||
|
}
|
||
|
return $null_entity;
|
||
|
}
|
||
|
|
||
|
boolean hackable_objective::vIsObjectiveComplete() {
|
||
|
return hackCount >= maxHackCount;
|
||
|
}
|