Created
July 11, 2014 00:17
-
-
Save voided/fb565c6032a3b1fbe264 to your computer and use it in GitHub Desktop.
example plugin using SM transitional API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma semicolon 1 | |
#include <sourcemod> | |
#include <sdktools> | |
#include <tf2> | |
#include <thelpers> | |
// require transitional api | |
#pragma newdecls required | |
#include "config.sp" | |
public void OnPluginStart() | |
{ | |
if ( !Config_Load() ) | |
SetFailState( "Unable to load config" ); | |
if ( Config_GetNumHats() == 0 ) | |
SetFailState( "No hats defined in config" ); | |
HookEvent( "player_builtobject", OnObjectBuilt ); | |
HookEvent( "player_carryobject", OnObjectPickedUp ); | |
HookEvent( "player_dropobject", OnObjectDropped ); | |
HookEvent( "player_upgradedobject", OnObjectUpgraded ); | |
} | |
public Action OnObjectBuilt( Handle event, const char[] name, bool dontBroadcast ) | |
{ | |
TFObject objectEnt = TFObject( GetEventInt( event, "index" ) ); | |
if ( !IsHattableObject( objectEnt ) ) | |
return; | |
Entity hatProp = GetObjectHat( objectEnt ); | |
if ( hatProp.IsValid ) | |
{ | |
// this object already has a hat, we don't want to attach another | |
return; | |
} | |
int hatIndex = GetRandomInt( 0, Config_GetNumHats() - 1 ); | |
char hatModel[ PLATFORM_MAX_PATH ]; | |
float modelScale, modelOffset; | |
Config_GetHat( hatIndex, hatModel, modelScale, modelOffset ); | |
GiveObjectHat( objectEnt, hatModel ); | |
} | |
public Action OnObjectPickedUp( Handle event, const char[] name, bool dontBroadcast ) | |
{ | |
TFObject objectEnt = TFObject( GetEventInt( event, "index" ) ); | |
if ( !IsHattableObject( objectEnt ) ) | |
return; | |
Entity hatProp = GetObjectHat( objectEnt ); | |
if ( hatProp.IsValid ) | |
{ | |
hatProp.AcceptInput( "TurnOff" ); | |
} | |
} | |
public Action OnObjectDropped( Handle event, const char[] name, bool dontBroadcast ) | |
{ | |
TFObject objectEnt = TFObject( GetEventInt( event, "index" ) ); | |
if ( !IsHattableObject( objectEnt ) ) | |
return; | |
Entity hatProp = GetObjectHat( objectEnt ); | |
if ( hatProp.IsValid ) | |
{ | |
hatProp.AcceptInput( "TurnOn" ); | |
} | |
} | |
public Action OnObjectUpgraded( Handle event, const char[] name, bool dontBroadcast ) | |
{ | |
TFObject objectEnt = TFObject( GetEventInt( event, "index" ) ); | |
if ( !IsHattableObject( objectEnt ) ) | |
return; | |
if ( objectEnt.ObjectType == TFObject_Dispenser && objectEnt.UpgradeLevel == 1 ) | |
{ | |
// don't need to re-parent hat if we're sitting on a level 1 dispenser as the attachment point doesn't move | |
return; | |
} | |
Entity hatProp = GetObjectHat( objectEnt ); | |
if ( hatProp.IsValid ) | |
{ | |
// hide the hat while we re-parent it to the new model | |
hatProp.AcceptInput( "TurnOff" ); | |
// need to delay some time for the upgrade animation to complete | |
CreateTimer( 2.0, Timer_ReparentHat, hatProp, TIMER_FLAG_NO_MAPCHANGE ); | |
} | |
} | |
public Action Timer_ReparentHat( Handle hTimer, int data ) | |
{ | |
Entity hatProp = Entity:data; | |
if ( !hatProp.IsValid ) | |
{ | |
// hat prop disappeared | |
return; | |
} | |
TFObject objectEnt = TFObject:hatProp.GetParent(); | |
if ( !objectEnt.IsValid ) | |
return; | |
ParentHat( hatProp, objectEnt ); | |
// display the hat again | |
hatProp.AcceptInput( "TurnOn" ); | |
} | |
stock void GiveObjectHat( TFObject objectEnt, const char hatModel[ PLATFORM_MAX_PATH ] ) | |
{ | |
Entity hatProp = Entity_CreateByName( "prop_dynamic_override" ); | |
if ( hatProp.IsValid ) | |
{ | |
hatProp.SetModel( hatModel ); | |
hatProp.Spawn(); | |
ParentHat( hatProp, objectEnt ); | |
} | |
} | |
stock Entity GetObjectHat( TFObject objectEnt ) | |
{ | |
Entity ent; | |
while ( ( ent = Entity_FindByClassname( ent, "prop_dynamic" ) ).IsValid ) | |
{ | |
Entity parent = ent.GetParent(); | |
if ( parent == objectEnt ) | |
{ | |
// prop is parented to our object, so it's most likely our hat | |
return ent; | |
} | |
} | |
return INVALID_ENTITY; | |
} | |
stock void ParentHat( Entity hatProp, TFObject objectEnt ) | |
{ | |
char hatModel[ PLATFORM_MAX_PATH ]; | |
hatProp.GetModel( hatModel, sizeof( hatModel ) ); | |
float modelScale = 1.0; | |
float modelOffset = 0.0; | |
if ( !Config_GetHatByModel( hatModel, modelOffset, modelScale ) ) | |
{ | |
LogError( "Unable to find hat config for hat: %s", hatModel ); | |
return; | |
} | |
hatProp.Skin = objectEnt.Builder.Team - 2; | |
hatProp.ModelScale = modelScale; | |
char attachmentName[ 128 ]; | |
GetAttachmentName( objectEnt, attachmentName, sizeof( attachmentName ) ); | |
hatProp.SetParent( objectEnt ); | |
hatProp.SetParentAttachment( attachmentName ); | |
float vecPos[ 3 ]; float angRot[ 3 ]; | |
hatProp.GetLocalOrigin( vecPos ); | |
hatProp.GetLocalAngles( angRot ); | |
// apply z offset | |
vecPos[ 2 ] += modelOffset; | |
// apply position/angle fixes based on object type | |
OffsetAttachmentPosition( objectEnt, vecPos, angRot ); | |
hatProp.Teleport( vecPos, angRot, NULL_VECTOR ); | |
} | |
stock void GetAttachmentName( TFObject objectEnt, char[] attachmentBuffer, int maxBuffer ) | |
{ | |
switch ( objectEnt.ObjectType ) | |
{ | |
case TFObject_Dispenser: | |
strcopy( attachmentBuffer, maxBuffer, "build_point_0" ); | |
case TFObject_Sentry: | |
{ | |
if ( objectEnt.UpgradeLevel < 3 ) | |
{ | |
strcopy( attachmentBuffer, maxBuffer, "build_point_0" ); | |
} | |
else | |
{ | |
// for level 3 sentries we can use the rocket launcher attachment | |
strcopy( attachmentBuffer, maxBuffer, "rocket_r" ); | |
} | |
} | |
} | |
} | |
stock void OffsetAttachmentPosition( TFObject objectEnt, float pos[ 3 ], float ang[ 3 ] ) | |
{ | |
switch ( objectEnt.ObjectType ) | |
{ | |
case TFObject_Dispenser: | |
{ | |
pos[ 2 ] += 13.0; // build_point_0 is a little low on the dispenser, bring it up | |
ang[ 1 ] += 180.0; // turn the hat around to face the builder | |
if ( objectEnt.UpgradeLevel == 3 ) | |
pos[ 2 ] += 8.0; // level 3 dispenser is even taller | |
} | |
case TFObject_Sentry: | |
{ | |
if ( objectEnt.UpgradeLevel == 3 ) | |
{ | |
pos[ 2 ] += 6.5; | |
pos[ 0 ] -= 11.0; | |
} | |
} | |
} | |
} | |
stock bool IsHattableObject( TFObject objectEnt ) | |
{ | |
// only parent hats to sentries and dispensers | |
return objectEnt.ObjectType == TFObject_Sentry || objectEnt.ObjectType == TFObject_Dispenser; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment