• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Ultimate Chat System v3.2

235220-albums7191-picture81061.png

235220-albums7191-picture81069.png

A smooth, full-featured, light-weight chat system that would improves any game performance. Supports various fascinating features. The goal of this system is replacing default warcraft III chat since it has many shortcomings. All features of this system will be mentioned below.

235220-albums7191-picture81070.png

  • Colorized chats: Gives any color to your message
  • Gradient chats: Gives any rainbow color effect to your message
  • Supports 5 kinds of message: All/Public, Team, Private/Whisper, System/Debug, Announcement
  • Anti-flood: Restricts player to send messages too often
  • Word restrictions: Keep players from cursing/swearing in your game
  • Chat history: Able to save more than 100 million messages, but it's uneededly practical
  • Scroll up & down: You are able to browse chat history from the beginning of the game. Except you have cleared them or saved message has reached the max amount
  • Time tag: Add time tag on each message
  • Reject messages: Reject any message from rejected player
  • Chat window outfit: You are able to add outfit/background for chat window

235220-albums7191-picture81068.png


235220-albums7191-picture81071.png

1. How to import
- Copy UltimateChat folder into your map
- You are able to change chat font size and hide default wc3 chat by importing this file or better follow this instructions

2. How to create your own outfit
- Download this psd file
- Edit it using photoshop
- Black layer is the chat window
- If you are not a pro, just don't resize it
- After you are done with editing, save as .tga file, select 32 bits/pixel
- Convert it to .blp file using this tool

3. How to add special commands

4. How to send whisper/private message

5. How to add a player to a reject list

6. How to solve bugs
a. Title disappeared
- Try to reduce WINDOW_SIZE
- Go to option, make sure SHOW_TITLE = true

7. How to appreciate the hardwork
Honestly, I always wanted to have some ratings for all of my resources, so any rating will be highly appreciated. And any suggestion is welcome​

235220-albums7191-picture81067.png

JASS:
library UltimateChat initializer onInit uses optional GradientText
    /***************************************************************************************************
    *                                                                                                  *
    *                                Ultimate Chat System v3.2                                         *
    *                                                   *****                                          *
    *                                               by Dalvengyr                                       *
    *                                                                                                  *
    * A smooth, full-featured, light-weight chat system that would improves your game performance and  *
    * make  it  more  elegant. Supports various advanced features, they are all explained in the main  *
    * thread.                                                                                          *
    *                                                                                                  *
    * Requirements:                                                                                    *
    *      - JNGP                                                                                      *
    *           hiveworkshop.com/forums/tools-560/jassnewgenpack-5d-227445/                            *
    *                                                                                                  *
    * Optional:                                                                                        *
    *      - GradientText by Dalvengyr                                                                 *
    *           hiveworkshop.com/forums/submissions-414/snippet-gradienttext-249151/                   *
    *                                                                                                  *
    * How to install:                                                                                  *
    *      - Copy UltimateChat folder at trigger editor into your map                                  *
    *      - Follow further instructions at:                                                           *
    *           hiveworkshop.com/forums/2499069-post2.html                                             *
    *                                                                                                  *
    * Link:                                                                                            *
    *           hiveworkshop.com/forums/spells-569/ultimate-chat-system-v1-4-a-249369/                 *
    *                                                                                                  *
    * APIs:                                                                                            *
    *                                                                                                  *
    * 1. Add a restricted word anytime                                                                 *
    * function AddRestrictedWord takes string s returns nothing                                        *
    *                                                                                                  *
    * 2. Force a player to open chat window                                                            *
    * function OpenUCSChatWindow takes integer pn returns nothing                                      *
    *                                                                                                  *
    * 3. Force a player to close chat window                                                           *
    * function CloseUCSChatWindow takes integer pn returns nothing                                     *
    *                                                                                                  *
    * 4. Send ALL message from a player                                                                *
    * function SendUCSChatAll takes integer sender, string msg returns nothing                         *
    *                                                                                                  *
    * 5. Send TEAM message from a player                                                               *
    * function SendUCSChatTeam takes integer sender, string msg returns nothing                        *
    *                                                                                                  *
    * 6. Send SYSTEM (debug) message to a player                                                       *
    * function SendUCSChatSystem takes integer reciever, string msg returns nothing                    *
    *                                                                                                  *
    * 7. Send PRIVATE message from & to a player                                                       *
    * function SendUCSChatPrivate takes integer sender, integer reciever, string msg returns nothing   *
    *                                                                                                  *
    * 8. Register event which fires when a player recieves a message                                   *
    * function TriggerRegisterUCSChatEvent takes trigger t, integer whichEvent returns nothing         *
    *                                                                                                  *
    * 9. Get sender on chat event                                                                      *
    * function GetUCSSender takes nothing returns player                                               *
    *                                                                                                  *
    * 10. Get recipient on chat event                                                                  *
    * function GetUCSReciever takes nothing returns player                                             *
    *                                                                                                  *
    * 11. Get sent message string on chat event                                                        *
    * function GetUCSMessage takes nothing returns string                                              *
    *                                                                                                  *
    ***************************************************************************************************/
    
    globals
        public                  string array    PLAYER_COLOR
        public                  string array    PLAYER_NAME
    
    /***************************************************************************************************
    *                                                                                                  *
    *          CONFIGURATIONS                                                                          *
    *                                                                                                  *
    * 1. Interfaces                                                                                    *
    *                                                                                                  */
        // Title will be shown at the top of chat window
        private     constant    string          TITLE               = "|cffffd800UltimateChatSystem v3.1|r"
        // Prefix for [PRIVATE] messages
        private     constant    string          PM_PREFIX           = "[|cffe6a200Private|r]"
        // Prefix for [SYSTEM] messages
        private     constant    string          SM_PREFIX           = "[|cffe6a200System|r]"
        // Prefix for [TEAM] messages
        private     constant    string          TM_PREFIX           = "[|cffe6a200Team|r]"
        // Prefix for [ALL] messages
        private     constant    string          AM_PREFIX           = "[|cffe6a200All|r]"
        // Time tag format: TIME_BRACKET1 + MINUTE + TIME_DEVIDER + SECOND + TIME_BRACKET2
        private     constant    string          TIME_BRACKET1       = "["
        private     constant    string          TIME_DEVIDER        = ":"
        private     constant    string          TIME_BRACKET2       = "]"
        // Symbol after chat sender name
        private     constant    string          EQUATION_SYMBOL     = ":"
   /*                                                                                                  *
    * 2. Commands                                                                                      *
    *                                                                                                  */
        // Prefix to identity a command. Ex: -reject2
        private     constant    string          CMD_PREFIX          = "-"
        // Command to open chat window
        private     constant    string          CMD_OPEN            = "open"
        // Command to close chat window
        private     constant    string          CMD_CLOSE           = "close"
        // Command to clear saved history
        private     constant    string          CMD_CLEAR           = "clear"
        // Command to add a player to reject list. The command must be followed by target player's number
        private     constant    string          CMD_BAN             = "reject"
        // Command to remove a player from reject list. The command must be followed by target player's number
        private     constant    string          CMD_UNBAN           = "unreject"
        // Another command for your personal needs. Ex: ^thetime
        private     constant    string          CMD_SPECIAL         = "^"
   /*                                                                                                  *
    * 3. Messagings                                                                                    *
    *                                                                                                  */
        // Prefix to identity a message target. Ex: *pm2
        private     constant    string          MSG_PREFIX          = "*"
        // To send a message to all players
        private     constant    string          MSG_ALL             = "all"
        // To send a message to all allies
        private     constant    string          MSG_TEAM            = "team"
        // To send a message to specific player
        private     constant    string          MSG_PRIVATE         = "pm"
   /*                                                                                                  *
    * 4. Options                                                                                       *
    *                                                                                                  */
        // X position of the chat window
        private     constant    real            WINDOW_X            = 0.0
        // Y position of the chat window
        private     constant    real            WINDOW_Y            = 0.0
        // Max messages that will be shown at screen
        private     constant    integer         WINDOW_SIZE         = 21
        // Max messages that will be saved
        private     constant    integer         MAX_SAVED           = 30
        // Maximum length of entered message
        private     constant    integer         MAX_LENGTH          = 128
        // True to attach time tag on each message
        private     constant    boolean         SHOW_TIME_TAG       = true
        // True to show title at the top of chat window
        private     constant    boolean         SHOW_TITLE          = true
        // True to allow player to scroll up/down
        private     constant    boolean         SCROLL_ENABLED      = true
        // Lock the camera when scrolling
        private     constant    boolean         SCROLL_LOCK_CAMERA  = true
        // Set the scroll rate
        private     constant    real            SCROLL_RATE         = 0.1
        // Delay before auto-scrolling started
        private     constant    real            SCROLL_DELAY        = 0.4
        // Timer to check flooding. 0 to disable anti-flood
        private     constant    integer         FLOOD_CHECK_TIMER   = 5
        // Max message every FLOOD_CHECK_TIMER seconds
        private     constant    integer         FLOOD_CHAT_MAX      = 5
   /*                                                                                                  *
    * 5. Notifications                                                                                 *
    *       (You may disable these notifications by setting them to null)                              *
    *                                                                                                  */
        // Will be shown when player enters invalid command
        private     constant    string          NOTIFICATION_1      = "|CFFFF0000INVALID COMMAND|r"
        // Will be shown when player enters too long message
        private     constant    string          NOTIFICATION_2      = "|CFFFF0000MESSAGE OVERSIZED|r"
        // Will be shown when pm target is unidentified
        private     constant    string          NOTIFICATION_3      = "|CFFFF0000INVALID RECIPIENT|r"
        // Will be shown when pm target is unavailable
        private     constant    string          NOTIFICATION_4      = "|CFFFF0000RECIPIENT IS UNAVAILABLE|r"
        // Will be shown when player floods
        private     constant    string          NOTIFICATION_5      = "|CFFFF0000DON'T FLOOD!|r"
        // Will be shown when player sends pm successfuly. Ex: "|CFF00FF00PRIVATE MESSAGE HAS BEEN SENT|r"
        private     constant    string          NOTIFICATION_6      = null
        // Will be shown if message contains one of restricted words
        private     constant    string          NOTIFICATION_7      = "|CFFFF0000MESSAGE CONTAINS RESTRICTED WORD(S)|r"
        // Will be shown if reject/unreject target is invalid
        private     constant    string          NOTIFICATION_8      = "|CFFFF0000UNABLE TO REJECT/UNREJECT TARGET|r"
        // Will be shown when target has been successfuly added/removed to reject list
        private     constant    string          NOTIFICATION_9      = "|CFF00FF00TARGET HAS BEEN ADDED/REMOVED TO/FROM REJECT LIST|r"
    endglobals
   /*                                                                                                  *
    * 6. Nickname colors                                                                               *
    *                                                                                                  */
    private function initName takes nothing returns nothing
        set PLAYER_COLOR[0] = "|CFFFF0303"  // Player 1
        set PLAYER_COLOR[1] = "|CFF0042FF"
        set PLAYER_COLOR[2] = "|CFF00FFFF"
        set PLAYER_COLOR[3] = "|CFF540081"
        set PLAYER_COLOR[4] = "|CFFFFFF01"
        set PLAYER_COLOR[5] = "|CFFFE8A0E"
        set PLAYER_COLOR[6] = "|CFF20C000"
        set PLAYER_COLOR[7] = "|CFFE55BB0"
        set PLAYER_COLOR[8] = "|CFF959697"
        set PLAYER_COLOR[9] = "|CFF7EBFF1"
        set PLAYER_COLOR[10] = "|CFF106246"
        set PLAYER_COLOR[11] = "|CFF4E2A04" // Player 12
    endfunction
   /*                                                                                                  *
    *          END OF CONFIGURATIONS                                                                   *
    *                                                                                                  *
    ***************************************************************************************************/
    
    private keyword Box
    
    globals
        private boolean array Open
        private force array RejectList
        private integer GameTime = 0
        private integer array ScrollInt
        private integer array ScrollDirection
        private integer array LastChatCtgry
        private integer array LastPMTarget
        private integer array FloodCounter
        private integer array FloodTimer
        private integer array MessageTotal
        private integer array CommandSize
        private player EVT_Reciever = null
        private player EVT_Sender = null
        private real EVT_Trigger = -1
        private real array ScrollDelay
        private string EVT_Message = ""
        private string GameTimes = "00" + TIME_DEVIDER + "00"
        private timer array SwearTimer[11]
        private trigger RestrictTrigger = CreateTrigger()
        private trigger ChatTrigger = CreateTrigger()
        private trigger ScrollTrigger = CreateTrigger()
        private unit array CameraLocker
        private Box array MessageBox[11]
        constant integer EVENT_CHAT_ANY = 0
        constant integer EVENT_CHAT_ALL = 1
        constant integer EVENT_CHAT_TEAM = 2
        constant integer EVENT_CHAT_PRIVATE = 3
        constant integer EVENT_CHAT_SYSTEM = 4
        private constant player PASSIVE = Player(PLAYER_NEUTRAL_PASSIVE)
    endglobals
    
    private struct Box
        string array str[MAX_SAVED]
        static method create takes nothing returns thistype
            return allocate()
        endmethod
    endstruct
    
    private function initSize takes nothing returns nothing
        set CommandSize[0] = StringLength(CMD_OPEN)
        set CommandSize[1] = StringLength(CMD_CLOSE)
        set CommandSize[2] = StringLength(CMD_CLEAR)
        set CommandSize[3] = StringLength(CMD_BAN)
        set CommandSize[4] = StringLength(CMD_UNBAN)
        set CommandSize[5] = StringLength(CMD_SPECIAL)
        set CommandSize[6] = StringLength(MSG_ALL)
        set CommandSize[7] = StringLength(MSG_TEAM)
        set CommandSize[8] = StringLength(MSG_PRIVATE)
        set CommandSize[10] = StringLength(CMD_PREFIX)
        set CommandSize[11] = StringLength(MSG_PREFIX)
    endfunction
        
    private function recycleInbox takes integer pn returns nothing
    
        local integer i = 1
        
        loop
            exitwhen i == MAX_SAVED
            set MessageBox[pn].str[i] = MessageBox[pn].str[i + 1]
            set i = i + 1
        endloop
        set MessageBox[pn].str[MAX_SAVED] = ""
    endfunction
    
    private function updateWindow takes integer pn returns nothing
    
        local integer i
        local integer ext
        local player p = Player(pn)
        
        if GetLocalPlayer() == p then
            call ClearTextMessages()
        endif
        
        static if SHOW_TITLE then
            call DisplayTimedTextToPlayer(p, WINDOW_X, WINDOW_Y, 0., TITLE)
        endif
        
        // Adding spaces between the first shown message and the title
        if MessageTotal[pn] < WINDOW_SIZE + ScrollInt[pn] then
            set i = 0
            set ext = WINDOW_SIZE - MessageTotal[pn] + ScrollInt[pn]
            loop
                exitwhen i >= ext
                call DisplayTimedTextToPlayer(p, WINDOW_X, WINDOW_Y, 0., " ")
                set i = i + 1
            endloop
        endif
        
        // This calculation is to determine the scroll position and to
        // avoid displaying the whole saved messages, so more effective
        set i = MessageTotal[pn] - WINDOW_SIZE + 1 - ScrollInt[pn]
        if i < 0 then
            set i = 0
        endif
        
        set ext = MessageTotal[pn] - ScrollInt[pn]
        // Display messages
        loop
            exitwhen i > ext
            if MessageBox[pn].str[i] != "" and MessageBox[pn].str[i] != null then
                call DisplayTimedTextToPlayer(p, WINDOW_X, WINDOW_Y, 0., MessageBox[pn].str[i])
            endif
            set i = i + 1
        endloop
    endfunction
    
    private function showDebug takes integer pn, string msg returns nothing
    
        local player rb
        local string mb
        
        // Why? Simply because AI can not read messages so just dont
        // process things if the target is AI, to save times
        if GetPlayerController(Player(pn)) == MAP_CONTROL_USER  then
            if MessageTotal[pn] >= MAX_SAVED then
                call recycleInbox(pn)
            else
                set MessageTotal[pn] = MessageTotal[pn] + 1
            endif
            
            // Process the message
            static if SHOW_TIME_TAG then
                set MessageBox[pn].str[MessageTotal[pn]] = SM_PREFIX + " " + TIME_BRACKET1 + GameTimes + TIME_BRACKET2 + " " + msg
            else
                set MessageBox[pn].str[MessageTotal[pn]] = SM_PREFIX + " " + msg
            endif
            
            if Open[pn] then
                call updateWindow(pn)
            endif
            // Generate the event
            set rb = EVT_Reciever
            set mb = EVT_Message
            set EVT_Reciever = Player(pn)
            set EVT_Message = msg
            
            set EVT_Trigger = EVENT_CHAT_SYSTEM
            set EVT_Trigger = EVENT_CHAT_ANY
            set EVT_Trigger = -1
            
            set EVT_Reciever = rb
            set EVT_Message = mb
        endif
    endfunction
    
    private function saveMessage takes integer ctgry, integer pn, string msg returns nothing
    
        local player rb = EVT_Reciever
        
        set EVT_Reciever = Player(pn)
        
        // Process things if only the target is player. Same reason
        // as above
        if GetPlayerController(EVT_Reciever) == MAP_CONTROL_USER  then
            if MessageTotal[pn] >= MAX_SAVED then
                call recycleInbox(pn)
            else
                set MessageTotal[pn] = MessageTotal[pn] + 1
            endif
            set MessageBox[pn].str[MessageTotal[pn]] = msg
            
            if Open[pn] then
                call updateWindow(pn)
            endif
        endif
        set EVT_Trigger = ctgry
        set EVT_Trigger = EVENT_CHAT_ANY
        set EVT_Trigger = -1
        set EVT_Reciever = rb
    endfunction
    
    private function processMessage takes integer ctgry, integer pn, string msg returns nothing
    
        local integer i = 0
        local player sb = EVT_Sender
        local string mb = EVT_Message
        
        set EVT_Sender = Player(pn)
        set EVT_Message = msg
        
        if ctgry == EVENT_CHAT_ALL then
            // If time tag is shown, then attach it
            static if SHOW_TIME_TAG then
                set msg = AM_PREFIX + " " + TIME_BRACKET1 + GameTimes + TIME_BRACKET2 + " " + PLAYER_NAME[pn] + EQUATION_SYMBOL + " " + msg
            else
                set msg = AM_PREFIX + " " + PLAYER_NAME[pn] + EQUATION_SYMBOL + " " + msg
            endif
            
            // Save the processed message to the recipients
            loop
                exitwhen i > 11
                if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then
                    if not IsPlayerInForce(EVT_Sender, RejectList[i]) then
                        call saveMessage(ctgry, i, msg)
                    endif
                endif
                set i = i + 1
            endloop
        elseif ctgry == EVENT_CHAT_PRIVATE then
            static if SHOW_TIME_TAG then
                set msg = PM_PREFIX + " " + TIME_BRACKET1 + GameTimes + TIME_BRACKET2 + " " + PLAYER_NAME[pn] + EQUATION_SYMBOL + " " + msg
            else
                set msg = PM_PREFIX + " " + PLAYER_NAME[pn] + EQUATION_SYMBOL + " " + msg
            endif
            
            if GetPlayerSlotState(Player(LastPMTarget[pn])) == PLAYER_SLOT_STATE_PLAYING then
                if not IsPlayerInForce(EVT_Sender, RejectList[LastPMTarget[pn]]) then
                    if NOTIFICATION_6 != null then
                        call showDebug(pn, NOTIFICATION_6)
                    endif
                    call saveMessage(ctgry, LastPMTarget[pn], msg)
                endif
            elseif NOTIFICATION_4 != null then
                call showDebug(pn, NOTIFICATION_4)
            endif
        elseif ctgry == EVENT_CHAT_TEAM then
            static if SHOW_TIME_TAG then
                set msg = TM_PREFIX + " " + TIME_BRACKET1 + GameTimes + TIME_BRACKET2 + " " + PLAYER_NAME[pn] + EQUATION_SYMBOL + " " + msg
            else
                set msg = TM_PREFIX + " " + PLAYER_NAME[pn] + EQUATION_SYMBOL + " " + msg
            endif
            
            loop
                exitwhen i > 11
                if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then
                    if not IsPlayerInForce(EVT_Sender, RejectList[i]) then
                        if IsPlayerAlly(EVT_Sender, Player(i)) then
                            call saveMessage(ctgry, i, msg)
                        endif
                    endif
                endif
                set i = i + 1
            endloop
        endif
        set EVT_Message = mb
        set EVT_Sender = sb
    endfunction
    
    private function checkWord takes nothing returns boolean
        
        local integer id = GetPlayerId(GetTriggerPlayer())
        
        if NOTIFICATION_7 != null and TimerGetRemaining(SwearTimer[id]) == 0 then
            call showDebug(id, NOTIFICATION_7)
        endif
        // Whithin this duration chatEvent function below won't be triggered
        call TimerStart(SwearTimer[id], .01, false, null)
        
        return false
    endfunction
    
    private function chatEvent takes nothing returns boolean
    
        local integer pn = GetPlayerId(GetTriggerPlayer())
        local integer len
        local integer t
        local string msg
        
        // If no forbidden word was detected
        if TimerGetRemaining(SwearTimer[pn]) == 0 then
            set msg = GetEventPlayerChatString()
            
            if SubString(msg, 0, CommandSize[10]) == CMD_PREFIX then
                set len = StringLength(CMD_PREFIX)
                
                if SubString(msg, len, len + CommandSize[0]) == CMD_OPEN then
                    set Open[pn] = true
                    call updateWindow(pn)
                elseif SubString(msg, len, len + CommandSize[1]) == CMD_CLOSE then
                    set Open[pn] = false
                    if GetLocalPlayer() == GetTriggerPlayer() then
                        call ClearTextMessages()
                    endif
                elseif SubString(msg, len, len + CommandSize[2]) == CMD_CLEAR then
                    set MessageTotal[pn] = 0
                    set ScrollInt[pn] = 0
                    if Open[pn] then
                        call updateWindow(pn)
                    endif
                elseif SubString(msg, len, len + CommandSize[3]) == CMD_BAN then
                    // Get the target's id
                    set t = S2I(SubString(msg, len + CommandSize[3], len + CommandSize[3] + 2))
                    
                    // If the target is valid
                    if t != pn and t > -1 and t < 12 then
                        if NOTIFICATION_9 != null then
                            call showDebug(pn, NOTIFICATION_9)
                        endif
                        call ForceAddPlayer(RejectList[pn], Player(t))
                    elseif NOTIFICATION_8 != null then
                        call showDebug(pn, NOTIFICATION_8)
                    endif
                elseif SubString(msg, len, len + CommandSize[4]) == CMD_UNBAN then
                    set t = S2I(SubString(msg, len + CommandSize[4], len + CommandSize[4] + 2))
                    
                    if t != pn and t > -1 and t < 12 then
                        if NOTIFICATION_9 != null then
                            call showDebug(pn, NOTIFICATION_9)
                        endif
                        call ForceRemovePlayer(RejectList[pn], Player(t))
                    elseif NOTIFICATION_8 != null then
                        call showDebug(pn, NOTIFICATION_8)
                    endif
                elseif NOTIFICATION_1 != null then
                    call showDebug(pn, NOTIFICATION_1)
                endif
            elseif SubString(msg, 0, CommandSize[11]) == MSG_PREFIX then
                set len = StringLength(MSG_PREFIX)
                if SubString(msg, len, len + CommandSize[6]) == MSG_ALL then
                    if StringLength(msg) - len - CommandSize[6] - 1 <= MAX_LENGTH then
                        // Generate the anti-flood
                        set FloodTimer[pn] = FLOOD_CHECK_TIMER
                        set FloodCounter[pn] = FloodCounter[pn] + 1
                        set LastChatCtgry[pn] = EVENT_CHAT_ALL
                        
                        // If flooding is not occured
                        if FloodCounter[pn] <= FLOOD_CHAT_MAX then
                            static if LIBRARY_GradientText then
                                set msg = GradientText(msg)
                            endif
                            // Pass the message to other function (process it)
                            call processMessage(EVENT_CHAT_ALL, pn, SubString(msg, len + CommandSize[6] + 1, StringLength(msg)))
                        elseif NOTIFICATION_5 != null then
                            call showDebug(pn, NOTIFICATION_5)
                        endif
                    elseif NOTIFICATION_2 != null then
                        call showDebug(pn, NOTIFICATION_2)
                    endif
                elseif SubString(msg, len, len + CommandSize[8]) == MSG_PRIVATE then
                    if StringLength(msg) - len - CommandSize[8] - 1 <= MAX_LENGTH then
                        set FloodTimer[pn] = FLOOD_CHECK_TIMER
                        set FloodCounter[pn] = FloodCounter[pn] + 1
                        set LastChatCtgry[pn] = EVENT_CHAT_PRIVATE
                        
                        if FloodCounter[pn] <= FLOOD_CHAT_MAX then
                            // Get target's id
                            set t = S2I(SubString(msg, len + CommandSize[8], len + CommandSize[8] + 2))
                            // If target is valid
                            if t != pn and t > -1 and t < 12 then
                                set LastPMTarget[pn] = t
                            
                                static if LIBRARY_GradientText then
                                    set msg = GradientText(msg)
                                endif
                                call processMessage(EVENT_CHAT_PRIVATE, pn, SubString(msg, len + CommandSize[8] + StringLength(I2S(t + 1)) + 1, StringLength(msg)))
                            elseif NOTIFICATION_3 != null then
                                call showDebug(pn, NOTIFICATION_3)
                            endif
                        elseif NOTIFICATION_5 != null then
                            call showDebug(pn, NOTIFICATION_5)
                        endif
                    elseif NOTIFICATION_2 != null then
                        call showDebug(pn, NOTIFICATION_2)
                    endif
                // If chat TEAM
                elseif SubString(msg, len, len + CommandSize[7]) == MSG_TEAM then
                    if StringLength(msg) - len - CommandSize[7] - 1 <= MAX_LENGTH then
                        set FloodTimer[pn] = FLOOD_CHECK_TIMER
                        set FloodCounter[pn] = FloodCounter[pn] + 1
                        set LastChatCtgry[pn] = EVENT_CHAT_TEAM
                        
                        if FloodCounter[pn] <= FLOOD_CHAT_MAX then
                            static if LIBRARY_GradientText then
                                set msg = GradientText(msg)
                            endif
                            call processMessage(EVENT_CHAT_TEAM, pn, SubString(msg, len + CommandSize[7] + 1, StringLength(msg)))
                        elseif NOTIFICATION_5 != null then
                            call showDebug(pn, NOTIFICATION_5)
                        endif
                    elseif NOTIFICATION_2 != null then
                        call showDebug(pn, NOTIFICATION_2)
                    endif
                elseif NOTIFICATION_1 != null then
                    call showDebug(pn, NOTIFICATION_1)
                endif
            // If message contains no command or messaging prefix.
            // Allows player to repeat previous messaging prefix
            elseif SubString(msg, 0, CommandSize[5]) != CMD_SPECIAL then
                if StringLength(msg) <= MAX_LENGTH then
                    set FloodCounter[pn] = FloodCounter[pn] + 1
                    set FloodTimer[pn] = FLOOD_CHECK_TIMER
                    
                    if FloodCounter[pn] <= FLOOD_CHAT_MAX then
                        static if LIBRARY_GradientText then
                            set msg = GradientText(msg)
                        endif
                        call processMessage(LastChatCtgry[pn], pn, msg)
                    elseif NOTIFICATION_5 != null then
                        call showDebug(pn, NOTIFICATION_5)
                    endif
                elseif NOTIFICATION_2 != null then
                    call showDebug(pn, NOTIFICATION_2)
                endif
            endif
        endif
        
        return false
    endfunction
    
    private function time takes nothing returns nothing
    
        local string s1
        local string s2
        local integer i
        
        // Process the anti-flood timer
        set i = 0
        loop
            exitwhen i > 11
            if FloodTimer[i] == 0 then
                set FloodCounter[i] = 0
            else
                set FloodTimer[i] = FloodTimer[i] - 1
            endif
            set i = i + 1
        endloop
        set GameTime = GameTime + 1
        set s1 = I2S(GameTime/60)
        set s2 = I2S(GameTime - (GameTime/60) * 60)
        
        if StringLength(s1) == 1 then
            set s1 = "0" + s1
        endif
        
        if StringLength(s2) == 1 then
            set s2 = "0" + s2
        endif
        set GameTimes = s1 + TIME_DEVIDER + s2
    endfunction
    
    private function scrollLoop takes nothing returns boolean
    
        local integer i = 0
        local integer c = 0
        
        loop
            exitwhen i > 11
            if ScrollDirection[i] > 0 then
                set c = c + ScrollDirection[i]
                
                if ScrollDelay[i] <= 0 then
                    if ScrollDirection[i] == 1 then
                        if ScrollInt[i] < MessageTotal[i] - 1 then
                            set ScrollInt[i] = ScrollInt[i] + 1
                        endif
                    elseif ScrollDirection[i] == 2 then
                        if ScrollInt[i] > 0 then
                            set ScrollInt[i] = ScrollInt[i] - 1
                        endif
                    endif
                    
                    if Open[i] then
                        call updateWindow(i)
                    endif
                else
                    set ScrollDelay[i] = ScrollDelay[i] - SCROLL_RATE
                endif
            endif
            set i = i + 1
        endloop
        
        // If no one is scrolling then turn off the trigger
        if c == 0 then
            call DisableTrigger(ScrollTrigger)
        endif
        
        return false
    endfunction
    
    private function scrollOn takes integer i returns nothing
    
        if Open[i] then
            call updateWindow(i)
        endif
        
        static if SCROLL_LOCK_CAMERA then
            call SetUnitX(CameraLocker[i], GetCameraTargetPositionX())
            call SetUnitY(CameraLocker[i], GetCameraTargetPositionY())
            
            if GetLocalPlayer() == GetTriggerPlayer() then
                call SetCameraTargetController(CameraLocker[i], 0, 0, false)
            endif
        endif
    endfunction
    
    private function scrollOff takes nothing returns boolean
    
        local integer pn = GetPlayerId(GetTriggerPlayer())
    
        set ScrollDirection[pn] = 0
        // Release camera without reseting any field
        call RemoveUnit(CameraLocker[pn])
        set CameraLocker[pn] = CreateUnit(PASSIVE, 'ewsp', 0, 0, 0)
        call ShowUnit(CameraLocker[pn], false)
        
        return false
    endfunction
    
    private function scrollUp takes nothing returns boolean
    
        local integer i = GetPlayerId(GetTriggerPlayer())
        
        if ScrollDirection[i] == 0 and Open[i] then
            set ScrollDirection[i] = 1
            set ScrollDelay[i] = SCROLL_DELAY
            
            if SCROLL_DELAY > 0 and ScrollInt[i] < MessageTotal[i] - 1 then
                set ScrollInt[i] = ScrollInt[i] + 1
            endif
            call scrollOn(i)
        endif
        
        if not IsTriggerEnabled(ScrollTrigger) then
            call EnableTrigger(ScrollTrigger)
        endif
        
        return false
    endfunction
    
    private function scrollDown takes nothing returns boolean
    
        local integer i = GetPlayerId(GetTriggerPlayer())
        
        if ScrollDirection[i] == 0 and Open[i] then
            set ScrollDirection[i] = 2
            set ScrollDelay[i] = SCROLL_DELAY
            if SCROLL_DELAY > 0 and ScrollInt[i] > 0 then
                set ScrollInt[i] = ScrollInt[i] - 1
            endif
            call scrollOn(i)
        endif
        
        if not IsTriggerEnabled(ScrollTrigger) then
            call EnableTrigger(ScrollTrigger)
        endif
        
        return false
    endfunction
    
    private function onInit takes nothing returns nothing
    
        local trigger t1 = CreateTrigger()
        local trigger t2 = CreateTrigger()
        local trigger t3 = CreateTrigger()
        local integer i = 0
        local player p
        
        call initName()
        call initSize()
        
        loop
            exitwhen i > 11
            set p = Player(i)
            if GetPlayerController(p) == MAP_CONTROL_USER and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
                static if SCROLL_ENABLED then
                    call TriggerRegisterPlayerEvent(t1, p, EVENT_PLAYER_ARROW_UP_DOWN)
                    call TriggerRegisterPlayerEvent(t2, p, EVENT_PLAYER_ARROW_DOWN_DOWN)
                    call TriggerRegisterPlayerEvent(t3, p, EVENT_PLAYER_ARROW_UP_UP)
                    call TriggerRegisterPlayerEvent(t3, p, EVENT_PLAYER_ARROW_DOWN_UP)
                    
                    static if SCROLL_LOCK_CAMERA then
                        set CameraLocker[i] = CreateUnit(PASSIVE, 'ewsp', 0., 0., 0.0)
                        call ShowUnit(CameraLocker[i], false)
                    endif
                endif
                call TriggerRegisterPlayerChatEvent(ChatTrigger, p, "", false)
                set SwearTimer[i] = CreateTimer()
                
                set FloodTimer[i] = 0
                set FloodCounter[i] = 0
                set LastChatCtgry[i] = EVENT_CHAT_ALL
                set MessageBox[i] = Box.create()
                
                set MessageTotal[i] = 0
                set RejectList[i] = CreateForce()
                set ScrollDirection[i] = 0
                set ScrollInt[i] = 0
            endif
            set Open[i] = false
            set PLAYER_NAME[i] = PLAYER_COLOR[i] + GetPlayerName(p) + "|R"
            set i = i + 1
        endloop
        
        static if SCROLL_ENABLED then
            call TriggerRegisterTimerEvent(ScrollTrigger, SCROLL_RATE, true)
            call TriggerAddCondition(ScrollTrigger, Condition(function scrollLoop))
            call TriggerAddCondition(t1, Condition(function scrollUp))
            
            call TriggerAddCondition(t2, Condition(function scrollDown))
            call TriggerAddCondition(t3, Condition(function scrollOff))
            call DisableTrigger(ScrollTrigger)
        else
            call DestroyTrigger(t1)
            call DestroyTrigger(t2)
            call DestroyTrigger(t3)
            
            set t1 = null
            set t2 = null
            set t3 = null
        endif
        call TriggerAddCondition(RestrictTrigger, Condition(function checkWord))
        call TriggerAddCondition(ChatTrigger, Condition(function chatEvent))
        call TimerStart(CreateTimer(), 1, true, function time)
    endfunction
    
    // API functions
    
    function AddRestrictedWord takes string s returns nothing
    
        local integer i = 0
        local player p
        
        call DestroyTrigger(ChatTrigger)
        set ChatTrigger = CreateTrigger()
        
        // Reset chat trigger. Indeed slower, but increase system's functionality
        loop
            exitwhen i > 11
            set p = Player(i)
            call TriggerRegisterPlayerChatEvent(RestrictTrigger, p, s, false)
            if GetPlayerController(p) == MAP_CONTROL_USER and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
                call TriggerRegisterPlayerChatEvent(ChatTrigger, p, "", false)
            endif
            set i = i + 1
        endloop
        call TriggerAddCondition(ChatTrigger, Condition(function chatEvent))
    endfunction
    
    function OpenUCSChatWindow takes integer pn returns nothing
        set Open[pn] = true
        call updateWindow(pn)
    endfunction
    
    function CloseUCSChatWindow takes integer pn returns nothing
        set Open[pn] = false
        if GetLocalPlayer() == Player(pn) then
            call ClearTextMessages()
        endif
    endfunction
    
    function SendUCSChatAll takes integer sender, string msg returns nothing
        call processMessage(EVENT_CHAT_ALL, sender, msg)
    endfunction
    
    function SendUCSChatPrivate takes integer sender, integer reciever, string msg returns nothing
        if sender != reciever and reciever >= 0 and reciever < 12 then
            set LastPMTarget[sender] = reciever
            call processMessage(EVENT_CHAT_PRIVATE, sender, msg)
        endif
    endfunction
    
    function SendUCSChatTeam takes integer sender, string msg returns nothing
        call processMessage(EVENT_CHAT_TEAM, sender, msg)
    endfunction
    
    function SendUCSChatSystem takes integer reciever, string msg returns nothing
        call showDebug(reciever, msg)
    endfunction
    
    function TriggerRegisterUCSChatEvent takes trigger t, integer whichEvent returns nothing
        call TriggerRegisterVariableEvent(t, SCOPE_PRIVATE + "EVT_Trigger", EQUAL, whichEvent)
    endfunction
    
    function GetUCSSender takes nothing returns player
        return EVT_Sender
    endfunction
    
    function GetUCSReciever takes nothing returns player
        return EVT_Reciever
    endfunction
    
    function GetUCSMessage takes nothing returns string
        return EVT_Message
    endfunction
    
endlibrary

Changelog

Keywords:
ultimate, chat, system
Contents

Ultimate Chat System (Map)

Reviews
10:26, 20th Sep 2014 TriggerHappy: Neat system. However the bot inside the demo is extremely limited and mostly annoys you by saying "I don't understand" every time you type something. I suggest improving or removing it. I noticed in your...

Moderator

M

Moderator

10:26, 20th Sep 2014
TriggerHappy:

Neat system.

However the bot inside the demo is extremely limited and mostly annoys you by saying "I don't understand" every time you type something. I suggest improving or removing it.

I noticed in your initializer that you're registering chat message events for all players. Other than that I didn't notice anything really wrong with the code.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
How to change font style/size


Changing Font Style
You may follow these instructions (recommended) or read this link
1. Go to Control Panel > Fonts then select your fonts there
2. Import that font into your map
3. Change the file path as you like
4. Go to Gameplay Interface, write imported font's file path at "Font - Ingame Messages"​



Changing Font Size
1. Use winMPQ, open your map and find war3mapMisc.txt then extract it (rename it to war3mapMisc2.txt)
2. Download this war3mapMisc.txt (designed especially for UCS)
3. Open it using notepad
4. Edit any font size there. There are some instructions there to help you
5. Open war3mapMisc2.txt, copy all text there and paste them in war3mapMisc.txt then save it
6. Import that saved war3mapMisc.txt into your map
7. Change the file path to war3mapMisc.txt (delete the "war3mapImported\")
!Once you use war3mapMisc.txt you may only configure gameplay constants by editing that war3mapMisc.txt using notepad
 

Attachments

  • ss1.jpg
    ss1.jpg
    574.9 KB · Views: 1,326
  • ss2.jpg
    ss2.jpg
    623.3 KB · Views: 916
  • ss3.jpg
    ss3.jpg
    615.2 KB · Views: 755
  • war3mapMisc.txt
    1.4 KB · Views: 977
  • 1.jpg
    1.jpg
    431.3 KB · Views: 815
  • outfit.psd
    288.2 KB · Views: 392
  • v2.jpg
    v2.jpg
    310.8 KB · Views: 888
Last edited:
Level 30
Joined
Nov 29, 2012
Messages
6,637
Wow, amazing chat system. It is definitely an improvement to the original chat system of Warcraft. It also features colored texts, chat history and some anti-flood/spam and etc.

Great job indeed. Must find a use for this, I really like this.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Changelog
v1.1
- GradientText is now optional
- Little improvements

v1.2
- Removed useless timer re-creating
- Improved some documentations

v1.3
- Spacefiller removed
- Fix some documentations

v1.4
- Previous version was quite buggy, and now I guarantee this version is almost bug-free (I have tested it in hours and can't find anything's wrong)
- So many improvements
- Now you are able to configure the chat window position
- Scroll event is no longer configurable

v1.5
- Anti-flood is now stronger and faster
- So much improvements and optimizations
- Improved scroll
- Fixed some bugs at scrolling and announcement message
- many more

v1.6
- Improved anything
- Window size is now constant

v1.7
- Added some outlines
- Bug at private message has been antisipated
- Improved scrolling, anti-flood, and word restrictions
- Some renaming
- Debug messages are changed to notifications

v1.8
- Now has used proper naming
- So many improvements
- New APIs
- Added outfit
- Added camera locker
- Fixed some possible bugs

v1.9
- Fixed bug at private message & announcement
- Fixed bug at chat event
- Fixed bug at clear command
- Some minor improvements

v2.0
- Improved trigger event API
- GradientText upgraded which you may have unlimited number gradation for one FC
- Improved many things

v2.1
- Little improvements and shortened code
- Updated GradientText

v2.2
- Many bug fixes and little improvement at cine hiding/unhiding

v2.3
- Updated GradientText
- Improved demo map

v2.4
- Updated GradientText
- Fixed bug at demo map
- Some improvements

v2.5
- bj_PLAYER_NEUTRAL_EXTRA => PLAYER_NEUTRAL_PASSIVE
- Smarter triggs
- What else? I suggest you to update GradientText (if needed) by yourself because I'm no longer update this one.

v2.6
- forget :p

v2.7
- Fixed possible bug at reject&unreject command
- Fixed possible bug at SendUCSPrivateMessage function
- Deleted some useless API functions
- Improved private messaging
- Deleted unused global variable declaration

v2.7b
- Fixed possible desync at scrollOff function

v2.8
- Announce feature deleted
- Host deleted
- Deleted some unused globals and locals
- ChatEvent function was much improved
- Fixed bug at "close" command
- Removed useless API functions

v2.9
- Fixed some documentations
- Some pedantic micro-optimizations
- MAX_SAVED is no longer a constant
- GetUCSNickname removed

v3.0
- Now it comes with some documentations
- Improved demos
- Some minor improvements

v3.1
- Removed my noobish coding style
- Fixed scrolling bug
- Improved demo. Works for multiplayer testing.
- Table is removed from requirements, sorry Mr Bribe.
- So many improvements

v3.2
- Now with valid msg length restricting
- Safer flood checking
- Much neater code
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
suggestion/review please?!

guys, what do you think about these lines?
JASS:
    private keyword chatevent

    globals
                                chatevent       EVENT_CHAT_ANY          = 0
                                chatevent       EVENT_CHAT_ALL          = 1
                                chatevent       EVENT_CHAT_TEAM         = 2
                                chatevent       EVENT_CHAT_PRIVATE      = 3
                                chatevent       EVENT_CHAT_SYSTEM       = 4
                                chatevent       EVENT_CHAT_ANNOUNCE     = 5
    endglobals
    
    private struct chatevent
    endstruct
 
Last edited:
Level 14
Joined
Jun 27, 2008
Messages
1,325
If you want to simulate something like a Enum do this:

JASS:
struct ChatEvent
    static thistype ANY
    static thistype ALL
    static thistype TEAM
    static thistype PRIVATE
    static thistype SYSTEM
    static thistype ANNOUNCE
endstruct

// Use
local ChatEvent event = ChatEvent.TEAM

Ugly code, but looks nice from the outside. Or just use wurst, which comes with build-in Enums ;)
 
Level 3
Joined
Dec 8, 2013
Messages
51
The problem is that I use a different JNPG ( Jass New Gen Pack (exp. 2) ) from xgm.ru :)
Your system is not working on it,but to change this JNPG I don't want)

But this is a good system!
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
you can set CMD_SPECIAL to ( - )
and CMD_PREFIX to another char :>

will they activate without any changes if I import this system?
yup, they will still activated, but the weird thing is that maybe a red notification (defaultly it's: invalid command) will be displayed at your screen/chat window, so to evade it, you should fix thing I have mentioned above, btw CMD_SPECIAL only makes entered chat string not displayed on chat window and not processed by the system as well..

thanks..
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
there is a big update for GradientText so I have decided to update this system which leads to accidental discovery of so many bugs, shortcomings, and inefficiencies on this system. So here is a big update with the following:
- Outfit is removed bcs is just troublesome feature and wasting space and disturbing gameplay so much
- Now you are completely able to add restricted words any time (in-game)
- So many repetitive fcs are now stored into globals
- INITIALLY_OPEN is removed, now you must manually open it yourself with available API
- Many uneeded public variables are changed to private
- Now you can use more than 1 character for command prefix
- Many renames both for variables and functions
- Chat scroll camera lock release is no longer disturbs current camera field

This update gives me a precious lesson: never be so sure that yours is perfect already.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
You can make an option to view messages for a period of time and not see the chat window all the time?

this system was inspired from Heroes-of-Newerth's chat system and I didn't see that feature. You can manually code/add that feature without touching the core system, by using available API. This is just example:
The chat window will be closed after 5 seconds after being opened (pressing 'esc')
JASS:
/*

    This is an example how to open/close chat window using another way. You can disabled default chat
    command by setting them to null. As example:
    
        // Command to open chat window
        private     constant    string          CMD_OPEN            = null

*/

globals
    timer DumTimer = CreateTimer()
endglobals

function close takes nothing returns nothing
        call CloseUCSChatWindow(0)
endfunction

function esc takes nothing returns boolean

    call OpenUCSChatWindow(0)
    call TimerStart(DumTimer, 5., false, function close)

    return false
endfunction

function InitTrig_Esc_OpenClose takes nothing returns nothing
    local trigger t = CreateTrigger()
    
    call TriggerRegisterPlayerEvent(t, Player(0), EVENT_PLAYER_END_CINEMATIC)
    call TriggerAddCondition(t, Condition(function esc))
endfunction

or you can manually type (in-game) "-open" to show the messages and "-close" to hide the message.

Thank you
 
Level 8
Joined
Jan 8, 2013
Messages
348
How do i make a new Layout? i editet the Photoshop file and converted it into blp BUT how do i import it into the System?
 
Level 11
Joined
Jul 4, 2016
Messages
627
Is it possible to localize chat with this system, as in only allow people within a certain range of the selected unit to be able to read your text, or within a region?
 
Last edited:
Top