Hey everyone, just a simple animated announcement system, type word by word.
Server-Sideenum StreamType
{
Announce = 0x1
}
function onPlayerCommand( player, cmd, text )
{
if (cmd=="announce")
{
if (!text) return MessagePlayer("[#ff0000]Please use /announce <text>",player);
SendDataToClient( player, StreamType.Announce, text.tostring() );
}
else MessagePlayer("[#ff0000]Invalid cmd",player);
}
function onClientScriptData( player )
{
local stream = Stream.ReadByte();
switch ( stream )
{
case StreamType.Announce:
PlaySound(player.World, 50003, player.Pos);
break;
}
}
function SendDataToClient( player, ... )
{
if( vargv[0] )
{
local byte = vargv[0],
len = vargv.len();
if( 1 > len ) devprint( "ToClent <" + byte + "> No params specified." );
else
{
Stream.StartWrite();
Stream.WriteByte( byte );
for( local i = 1; i < len; i++ )
{
switch( typeof( vargv[i] ) )
{
case "integer": Stream.WriteInt( vargv[i] ); break;
case "string": Stream.WriteString( vargv[i] ); break;
case "float": Stream.WriteFloat( vargv[i] ); break;
}
}
if( player == null ) Stream.SendStream( null );
else if( typeof( player ) == "instance" ) Stream.SendStream( player );
else devprint( "ToClient <" + byte + "> Player is not online." );
}
}
else devprint( "ToClient: Even the byte wasn't specified..." );
}Client-Sideenum StreamType
{
Announce = 0x1
}
screenX <- GUI.GetScreenSize().X;
screenY <- GUI.GetScreenSize().Y;
local announceQueue = [0,1], typedChars = 0, typingTimer, announceSprite, announceLabel;
Timer <- {
Timers = {}
function Create(environment, listener, interval, repeat, ...)
{
vargv.insert(0, environment);
local TimerInfo = {
Environment = environment,
Listener = listener,
Interval = interval,
Repeat = repeat,
Args = vargv,
LastCall = Script.GetTicks(),
CallCount = 0
};
local hash = split(TimerInfo.tostring(), ":")[1].slice(3, -1).tointeger(16);
Timers.rawset(hash, TimerInfo);
return hash;
}
function Destroy(hash)
{
if (Timers.rawin(hash))
{
Timers.rawdelete(hash);
}
}
function Exists(hash)
{
return Timers.rawin(hash);
}
function Fetch(hash)
{
return Timers.rawget(hash);
}
function Clear()
{
Timers.clear();
}
function Process()
{
local CurrTime = Script.GetTicks();
foreach (hash, tm in Timers)
{
if (tm != null)
{
if (CurrTime - tm.LastCall >= tm.Interval)
{
tm.CallCount++;
tm.LastCall = CurrTime;
tm.Listener.pacall(tm.Args);
if (tm.Repeat != 0 && tm.CallCount >= tm.Repeat)
Timers.rawdelete(hash);
}
}
}
}
};
function Script::ScriptProcess()
{
Timer.Process();
}
function Server::ServerData( stream )
{
local type = stream.ReadByte();
switch( type )
{
case StreamType.Announce:
{
local announceText = stream.ReadString();
if (typingTimer == null)
{
if ( announceText.len() > 90 )
return Console.Print("You can't announce more than 90 characters");
typingTimer = "lock";
Console.Print("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
announceQueue.insert(0,announceText);
local centerY = screenY / 2, startY = centerY * 0.3;
announceSprite = GUISprite( "ann.png", VectorScreen( screenX / 2, startY ) );
announceSprite.Size = VectorScreen( screenX * 0.05, screenY * 0.06 );
announceSprite.Alpha = 255;
SendDataToServer(StreamType.Announce);
Timer.Create( this, MoveAnnouncementUp, 50, 15 );
Timer.Create( this, CreateAnnouncementLabel, 750, 1 );
Timer.Create( this, StartHorizontalMovement, 750, 1 );
}
else Console.Print("Wait until the first announcement disappears");
}
break;
}
}
function MoveAnnouncementUp()
{
local offset = screenY * -0.009;
announceSprite.Pos.Y += offset;
}
function StartHorizontalMovement()
{
Timer.Create( this, MoveAnnouncementLeft, 40, 15 );
}
function MoveAnnouncementLeft()
{
local offset = screenX * -0.032;
announceSprite.Pos.X += offset;
}
function CreateAnnouncementLabel()
{
announceLabel = GUILabel(VectorScreen( screenX * 0.047, screenY * 0.013 ), Colour( 0, 0, 0 ), "");
announceLabel.FontSize = screenY * 0.02;
announceSprite.AddChild(announceLabel);
typingTimer = Timer.Create( this, TypewriterEffect, 90, announceQueue[0].len() );
Timer.Create( this, DestroyAnnouncement, 10000, 1 );
}
function TypewriterEffect()
{
local pos = typedChars += 1, prev = pos-1, text = announceQueue[0];
announceLabel.Text += text.slice(prev,pos);
local shakeX = screenX * 0.002; // shake effect when typing
local shakeY = screenY * 0.002;
if (pos % 2 == 0)
{
announceSprite.Pos.X += shakeX;
announceSprite.Pos.Y += shakeY;
}
else
{
announceSprite.Pos.X -= shakeX;
announceSprite.Pos.Y -= shakeY;
}
}
function DestroyAnnouncement()
{
announceQueue.clear();
announceLabel = null;
announceSprite = null;
typedChars = 0;
Timer.Destroy(typingTimer);
typingTimer = null;
}
function SendDataToServer( ... )
{
if( vargv[0] )
{
local byte = vargv[0],
len = vargv.len();
if( 1 > len ) Console.Print( "ToClient <" + byte + "> No params specified." );
else
{
local stream = Stream();
stream.WriteByte( byte );
for( local i = 1; i < len; i++ )
{
switch( typeof( vargv[i] ) )
{
case "integer": stream.WriteInt( vargv[i] ); break;
case "string": stream.WriteString( vargv[i] ); break;
case "float": stream.WriteFloat( vargv[i] ); break;
}
}
Server.SendData( stream );
}
}
else Console.Print( "ToClient: Not even the byte was specified..." );
}Download sound and sprite from here (https://drive.google.com/file/d/1x_62Qp92-zHwYkhCMtx65OsQEB23gYRk/view) and put them in store folder. Enjoy !