View Full Version : custom animated button

16-07-2017, 01:06 PM
Hi, it would be nice if someone can help me with this.
I try to script a func_button similar entity that uses animations. It's a wall mounted torch that can have serveral states:
flame goes off via animation,
idle in non burning state,
flame turning on via animation,
switch as button ( rotates by ~90°) also as animation,
stays switched horizontally
and switch back to a vertical orientation, via animation, too.

I spent a lot of time to make this model work fine and now I don't want to discard it for another solution, so my questions are:
- can I inherate from CBaseButton? And is there a list with the possible syntaxes of ScriptBase(Entity/PlayerWeaponEntity/...) I didn't found anything in the api.
- How to use the use types? Can I lock the torch for button uses while it's burning?
- how to fire the target of that entity via script?

BTW: At first I tried to change the animation sequences by map entities, the problem was, that the sequences not started at their first frame. Is there any solution to reset the frame of an sequence? If so, I could use this thing without a script.

This is my code till now, I know, it's not ready yet:

enum WallTorchAnimation

class CWallTorchButton : ScriptBaseEntity
bool m_bTurnFireOff = false;
bool m_bTurnFireOn = false;
void Spawn()
g_EntityFuncs.SetModel( self, "models/Che/props/walltorch.mdl" );
g_EntityFuncs.SetSize( self.pev, Vector(-4, -32, -20), Vector(4, 0, 32) );
g_EntityFuncs.SetOrigin( self, self.pev.origin );

self.pev.movetype = MOVETYPE_FLY;
self.pev.solid = SOLID_BBOX;
self.pev.nextthink = g_Engine.time + 0.1f;

SetThink( ThinkFunction(Burn) );

void Precache()
g_Game.PrecacheModel( "models/Che/props/walltorch.mdl" );

void Burn()
self.sequence = 0;
SetThink( ThinkFunction(TurnOff) );
self.pev.nextthink = g_Engine.time + 1;

void TurnOff()
self.sequence = 1;
SetThink( ThinkFunction(IdleOff) );
self.pev.nextthink = g_Engine.time + 1;

void IdleOff()
self.sequence = 2;
SetThink( ThinkFunction(TurnOn) );
// if(use in this state){
// apply BUTTON_SETON animation and fire the target there
// }
self.pev.nextthink = g_Engine.time + 0.2;

void TurnOn()
self.sequence = 3;
SetThink( ThinkFunction(Burn) );
self.pev.nextthink = g_Engine.time + 1;
// [...]
// button think functions with it's animations...
// [...]
void Use(CBaseEntity@ pActivator, CBaseEntity@ pCaller, USE_TYPE useType, float value)



03-08-2017, 05:12 PM
Better late than never?

- can I inherate from CBaseButton? And is there a list with the possible syntaxes of ScriptBase(Entity/PlayerWeaponEntity/...) I didn't found anything in the api.

No, I don't think you can inherit from CBaseButton. What do you mean by "possible syntaxes"?

- How to use the use types? Can I lock the torch for button uses while it's burning?
use types are either ON, OFF, or TOGGLE. Players can only TOGGLE things with the use key. You can lock uses by not doing anything in the Use() function when the torch is burning.

- how to fire the target of that entity via script?
g_EntityFuncs.FireTargets(target, null, null, USE_TOGGLE);

Is there any solution to reset the frame of an sequence? If so, I could use this thing without a script.
Try this (it works for players, idk about anything else):

self.pev.frame = 0;

03-08-2017, 08:14 PM
Skim read you AS code, and my 2 Cents, if you want it to Act/Work "like I think you probably do" :

self.pev.movetype = MOVETYPE_FLY; should be: self.pev.movetype = MOVETYPE_PUSH; // Allow Player interact with it.
self.pev.solid = SOLID_BBOX; should be: self.pev.solid = SOLID_BSP; // (BSP clip, touch on edge, block, i.e. Let player touch it, but also block/push if in way.)

This will make it Act like a "Lever" or func_rotating_button (A player should be able to "touch/E-Key it", rather than having to target via some other method.)

04-08-2017, 07:24 PM
Oh thanks =D this could help. I try these tipps when my exams are over, too much struggle with my studies at the moment @_@

11-09-2017, 03:37 PM
Ok, I figured out a solution:

// Filename: trigger_change_sequence.as
// Version: 0.1a
// Date: 12.September.2017
// Author: Sprengmeister (CheOfDoom)

// ---- Description ----
// This entity changes the model animation sequence of its target.

// Normaly when changing a sequence with a trigger_changevalue sometimes
// the new sequence doesn't start at the first frame.
// To prevent this I wrote this entity. For example you can create buttons or other stuff
// which switches properly through diffrent animations, depending on its state.
// Keep note, that this entity is hastily stitched together! So watch out while using it.

// Usage:
// The functionality is given with all kinds of CBaseMonster. So if you like to add a prop to your map
// which uses this entity, add a monster(_generic):
// - set up your prop-model as the monsters custom model
// - hit the flag for non-solid and prisoner
// - disable AI (this is important, because otherwise the animation returns to idle)
// every animation sequence you use needs a seperate trigger_change_sequence
// use a multimanager, wich triggers along the trigger_change_sequences depending on the time needed for each sequence
// Use an invisible button inside your prop model, which is the actual button (if you use this for a button)

// BTW.: my english could be a bit bad ^^

class trigger_change_sequence : ScriptBaseEntity
int iSequence;

CBaseMonster@ pTarget;

// reading the properties you set in the entity
bool KeyValue( const string& in szKey, const string& in szValue )
if (szKey == "sequence")
iSequence = atoi(szValue);
return true;
return BaseClass.KeyValue( szKey, szValue );

void Use(CBaseEntity@ pActivator, CBaseEntity@ pCaller, USE_TYPE useType, float flValue)
//find the target entity
@pTarget = cast<CBaseMonster@>(g_EntityFuncs.FindEntityByTargetname(null, self.pev.target));
if(pTarget !is null)
pTarget.pev.sequence = self.pev.sequence;
pTarget.pev.frame = 0;
//special thanks to W00tguy =)

void RegisterTriggerChangeSequence()
g_CustomEntityFuncs.RegisterCustomEntity( "trigger_change_sequence", "trigger_change_sequence" );

Here comes the fgd snippet for use in Hammer Editor:

@PointClass base(Targetname) size(-8 -8 -8, 8 8 8) color(0 150 50) = trigger_change_sequence : "Trigger Change Sequence"
target(string) : "Destination entity (should be a monster)"
sequence(string) : "New sequence number"

11-09-2017, 04:44 PM
Seems like a Good Solution & nice neat code. (plus an excellent tip/hint there from w00tguy123).

Off Topic: Are your Exams over, back to normal stress levels ? If so would love to see a video of your "wall mounted torch/button/model" in action.

12-09-2017, 02:07 PM
Thanks, yes my exams are over :D
It lasted half an eternity to find a recording program that works on my machine and to register on youtube, but finally I uploaded a video.
I also used the script for the treasure chest model I made a few nights ago ;)


12-09-2017, 02:31 PM
"yes my exams are over " -> Great back to more fun stuff then?

re Video: Looks good, nice torch model & flame, joins in wall/texture alignment well hidden, great ambient music/fits well, overall looks like it the sort of map I will want to play. Good work.

PS: Will have a look at your BreakLight flickering and see if I can spot anything obvious.

12-09-2017, 05:15 PM
Thank you, also for going to have a look at my breaklight plugin :)
I looked hours for the music and improved it a bit in audacity. I'm not fully satisfied with it, when I use it through the whole dungeon map, I think I have to dig out my synthesizer again :rolleyes:
This map is by the way just a testroom so I don't have to set cordon bounds and playerstarts all the time. The big dungeon is in work, as you may guess the focus lies on coop puzzles and riddles inspired by zelda and similar games. I also want to make a few weapons for it like a bow, with fire arrows to light up things and weapons that aren't weapons at all but weaponlike items, like a bucket of water to extinguish fire and stuff like this :D

.. my biggest problem is, that I usually just make snippets and don't bring projects over 70% :rolleyes: I made the descision to change that habbit with this project and include old snippets, too if they fit in ;)