• 🏆 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!

[JASS] Custom Race

Status
Not open for further replies.
Level 7
Joined
Dec 30, 2008
Messages
72
Well, I wrote this script based off of the melee trigger Victory/Defeat, as I needed something to moniter victory, alliance changes and so on so forth for more than the initial 4 races. So I pulled apart the function and finally found where in the game's core little script, the townhall's were checked. After locating it I modified it to allow the user to add more townhalls into this area, and customise the warning message given when you are revealed. After working on this for a while, and having implemented it into my main current map, I decided to place it on hive in the spell's system section. However someone, who obviously doesn't make maps, reviewed it and deemed it useless so he rejected it. So, having emailed him and him being unwilling to change his mind, I decided to post the code here and ask what improvements I should make to ensure it is more user friendly, as that was one of his gripes and the only one I can fix without repairing his brain.

JASS:
// Written in part by Ross Dubery
// Modified from MeleeGameWinTrigger
// Version 1.10
//
// The global variables used need to be declared before this scipt runs
//
//   |udg_MaxRace| integer
//    is the exact number of races you will be having in the map
//      so the usual 4 + whatever you add
//
//   |udg_SetRace[Number of Players]| integer array
//    is the variable that will hold all the races numbers from 0 to MaxRace - 1
//    Human     - 0
//    Orc       - 1
//    Night Elf - 2
//    Undead    - 3
//    Your Race - 4 etc.
//
//   The first four are non-negotiable, and shouldn't be modified
//
//  |udg_TIMERTEXTNew[Number of new races - 1]| string array
//    this is the timer text that your races will use (that says "You'll be revealed in:")  
//
//  |udg_WARNINGNew[Number of new races - 1]| string array
//    this is the warning text that your races will use (that says 'Construct a KEY STRUCTURE before you are revealed')
//
//  |udg_KEYNew[Number of new races - 1]| unittype array
//    this is the unit type of the key structures of your race (example human is 'htow') this structure and therefore
//    this variable is vital to this trigger and is what causes your new races to be revealed in normal melee maps
//
//
//

// Controls the timer text for the crippled player depending on which race they are
function MeleeGetCrippledTimerMessageMod takes player whichPlayer returns string
    local integer r = udg_SetRace[GetPlayerId(whichPlayer)]
    local integer index = 4
    local integer maxRace = udg_MaxRace - 1

    if (r == 0) then
        return GetLocalizedString("CRIPPLE_TIMER_HUMAN")
    elseif (r == 1) then
        return GetLocalizedString("CRIPPLE_TIMER_ORC")
    elseif (r == 2) then
        return GetLocalizedString("CRIPPLE_TIMER_NIGHTELF")
    elseif (r == 3) then
        return GetLocalizedString("CRIPPLE_TIMER_UNDEAD")
    else
        loop
            exitwhen index > maxRace
            if (r == index) then
                return GetLocalizedString(udg_TIMERTEXTNew[index-4])
            endif    
            set index = index + 1
        endloop 
    endif
    return ""
endfunction

// returns a string prefixed version of the cripple timer
function MeleeGetCrippledRevealedMessageMod takes player whichPlayer returns string
    return GetLocalizedString("CRIPPLE_REVEALING_PREFIX") + GetPlayerName(whichPlayer) + GetLocalizedString("CRIPPLE_REVEALING_POSTFIX")
endfunction

// Controls the cripple text for the crippled player depending on which race they are
function MeleeGetCrippledWarningMessageMod takes player whichPlayer returns string
    local integer r = udg_SetRace[GetPlayerId(whichPlayer)]
    local integer index = 4
    local integer maxRace = udg_MaxRace - 1

    if (r == 0) then
        return GetLocalizedString("CRIPPLE_WARNING_HUMAN")
    elseif (r == 1) then
        return GetLocalizedString("CRIPPLE_WARNING_ORC")
    elseif (r == 2) then
        return GetLocalizedString("CRIPPLE_WARNING_NIGHTELF")
    elseif (r == 3) then
        return GetLocalizedString("CRIPPLE_WARNING_UNDEAD")
    else    
        loop
            exitwhen index > maxRace
            if (r == index) then
                return GetLocalizedString(udg_WARNINGNew[index-4])
            endif    
            set index = index + 1
        endloop 
    endif
    return ""
endfunction

// Counts the number of key structures held by the player and their allies
function MeleeGetAllyKeyStructureCountMod takes player whichPlayer returns integer
    local integer    playerIndex
    local player     indexPlayer
    local integer    keyStructs
    local integer    index
    local integer maxRace = udg_MaxRace - 1

    // Count the number of buildings controlled by all not-yet-defeated co-allies.
    set keyStructs = 0
    set playerIndex = 0
    loop
        set indexPlayer = Player(playerIndex)
        if (PlayersAreCoAllied(whichPlayer, indexPlayer)) then
            set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "townhall", true, true)
            set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "greathall", true, true)
            set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "treeoflife", true, true)
            set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "necropolis", true, true)
            //Add other key structures here
            set index = 4
            loop
                exitwhen index > maxRace
                set keyStructs = keyStructs + CountLivingPlayerUnitsOfTypeId(udg_KEYNew[index-4], indexPlayer)
                set index = index + 1
            endloop
        endif
            
        set playerIndex = playerIndex + 1
        exitwhen playerIndex == bj_MAX_PLAYERS
    endloop

    return keyStructs
endfunction

// Checks if a player is crippled
function MeleePlayerIsCrippledMod takes player whichPlayer returns boolean
    local integer allyStructures    = MeleeGetAllyStructureCount(whichPlayer)
    local integer allyKeyStructures = MeleeGetAllyKeyStructureCountMod(whichPlayer)

    // Dead teams are not considered to be crippled.
    return (allyStructures > 0) and (allyKeyStructures <= 0)
endfunction
 
// Determines if a player is crippled yet, and controls the timer
function MeleeCrippledPlayerTimeoutMod takes nothing returns nothing
    local timer expiredTimer = GetExpiredTimer()
    local integer playerIndex
    local player  exposedPlayer

    // Determine which player's timer expired.
    set playerIndex = 0
    loop
        if (bj_crippledTimer[playerIndex] == expiredTimer) then
            exitwhen true
        endif

        set playerIndex = playerIndex + 1
        exitwhen playerIndex == bj_MAX_PLAYERS
    endloop
    if (playerIndex == bj_MAX_PLAYERS) then
        return
    endif
    set exposedPlayer = Player(playerIndex)

    if (GetLocalPlayer() == exposedPlayer) then
        // Use only local code (no net traffic) within this block to avoid desyncs.

        // Hide the timer window for this player.
        call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], false)
    endif

    // Display a text message to all players, explaining the exposure.
    call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, MeleeGetCrippledRevealedMessageMod(exposedPlayer))

    // Expose the player.
    call MeleeExposePlayer(exposedPlayer, true)
endfunction
 
// Checks for crippled players
function MeleeCheckForCrippledPlayersMod takes nothing returns nothing
    local integer    playerIndex
    local player     indexPlayer
    local force      crippledPlayers = CreateForce()
    local boolean    isNowCrippled

    // The "finish soon" exposure of all players overrides any "crippled" exposure
    if bj_finishSoonAllExposed then
        return
    endif

    // Check each player to see if he or she has been crippled or uncrippled.
    set playerIndex = 0
    loop
        set indexPlayer = Player(playerIndex)
        set isNowCrippled = MeleePlayerIsCrippledMod(indexPlayer)

        if (not bj_playerIsCrippled[playerIndex] and isNowCrippled) then

            // Player became crippled; start their cripple timer.
            set bj_playerIsCrippled[playerIndex] = true
            call TimerStart(bj_crippledTimer[playerIndex], bj_MELEE_CRIPPLE_TIMEOUT, false, function MeleeCrippledPlayerTimeoutMod)

            if (GetLocalPlayer() == indexPlayer) then
                // Use only local code (no net traffic) within this block to avoid desyncs.

                // Show the timer window.
                call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], true)

                // Display a warning message.
                call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, MeleeGetCrippledWarningMessageMod(indexPlayer))
            endif

        elseif (bj_playerIsCrippled[playerIndex] and not isNowCrippled) then

            // Player became uncrippled; stop their cripple timer.
            set bj_playerIsCrippled[playerIndex] = false
            call PauseTimer(bj_crippledTimer[playerIndex])

            if (GetLocalPlayer() == indexPlayer) then
                // Use only local code (no net traffic) within this block to avoid desyncs.

                // Hide the timer window for this player.
                call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], false)

                // Display a confirmation message if the player's team is still alive.
                if (MeleeGetAllyStructureCount(indexPlayer) > 0) then
                    if (bj_playerIsExposed[playerIndex]) then
                        call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNREVEALED"))
                    else
                        call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNCRIPPLED"))
                    endif
                endif
            endif

            // If the player granted shared vision, deny that vision now.
            call MeleeExposePlayer(indexPlayer, false)

        endif
            
        set playerIndex = playerIndex + 1
        exitwhen playerIndex == bj_MAX_PLAYERS
    endloop
endfunction
 
// Checks if an alliance has changed which has caused a crippled player to be crippled/uncrippled
function MeleeTriggerActionAllianceChangeMod takes nothing returns nothing
    call MeleeCheckForLosersAndVictors()
    call MeleeCheckForCrippledPlayersMod()
endfunction
  
// Checks if a unit has been lost which has caused a crippled player to be crippled/uncrippled
function MeleeCheckLostUnitMod takes unit lostUnit returns nothing
    local player lostUnitOwner = GetOwningPlayer(lostUnit)

    // We only need to check for mortality if this was the last building.
    if (GetPlayerStructureCount(lostUnitOwner, true) <= 0) then
        call MeleeCheckForLosersAndVictors()
    endif

    // Check if the lost unit has crippled or uncrippled the player.
    // (A team with 0 units is dead, and thus considered uncrippled.)
    call MeleeCheckForCrippledPlayersMod()
endfunction
 
// Checks if a unit has been created which has caused a crippled player to be crippled/uncrippled
function MeleeCheckAddedUnitMod takes unit addedUnit returns nothing
    local player addedUnitOwner = GetOwningPlayer(addedUnit)

    // If the player was crippled, this unit may have uncrippled him/her.
    if (bj_playerIsCrippled[GetPlayerId(addedUnitOwner)]) then
        call MeleeCheckForCrippledPlayersMod()
    endif
endfunction
 
// Checks if a unit has died which has caused a crippled player to be crippled/uncrippled
function MeleeTriggerActionUnitDeathMod takes nothing returns nothing
    if (IsUnitType(GetDyingUnit(), UNIT_TYPE_STRUCTURE)) then
        call MeleeCheckLostUnitMod(GetDyingUnit())
    endif
endfunction
 
// Checks if a structure has been built which has caused a crippled player to be crippled/uncrippled
function MeleeTriggerActionUnitConstructionStartMod takes nothing returns nothing
    call MeleeCheckAddedUnitMod(GetConstructingStructure())
endfunction

//Prevents the player triggers from leaking
function AntiLeakFilterWinTrigger takes nothing returns boolean
    return true
endfunction
 
// Adds all the triggers that control this complex system
function BaseActions takes nothing returns nothing
    
    local trigger    trig
    local integer    index
    local player     indexPlayer
    local filterfunc filter
    
    set filter = Filter(function AntiLeakFilterWinTrigger)

    // Create a timer window for the "finish soon" timeout period, it has no timer
    // because it is driven by real time (outside of the game state to avoid desyncs)
    set bj_finishSoonTimerDialog = CreateTimerDialog(null)

    // Set a trigger to fire when we receive a "finish soon" game event
    set trig = CreateTrigger()
    call TriggerRegisterGameEvent(trig, EVENT_GAME_TOURNAMENT_FINISH_SOON)
    call TriggerAddAction(trig, function MeleeTriggerTournamentFinishSoon)

    // Set a trigger to fire when we receive a "finish now" game event
    set trig = CreateTrigger()
    call TriggerRegisterGameEvent(trig, EVENT_GAME_TOURNAMENT_FINISH_NOW)
    call TriggerAddAction(trig, function MeleeTriggerTournamentFinishNow)

    // Set up each player's mortality code.
    set index = 0
    loop
        set indexPlayer = Player(index)

        // Make sure this player slot is playing.
        if (GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING) then
            set bj_meleeDefeated[index] = false
            set bj_meleeVictoried[index] = false

            // Create a timer and timer window in case the player is crippled.
            set bj_playerIsCrippled[index] = false
            set bj_playerIsExposed[index] = false
            set bj_crippledTimer[index] = CreateTimer()
            set bj_crippledTimerWindows[index] = CreateTimerDialog(bj_crippledTimer[index])
            call TimerDialogSetTitle(bj_crippledTimerWindows[index], MeleeGetCrippledTimerMessageMod(indexPlayer))

            // Set a trigger to fire whenever a building is cancelled for this player.
            set trig = CreateTrigger()
            call TriggerRegisterPlayerUnitEvent(trig, indexPlayer, EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL, filter)
            call TriggerAddAction(trig, function MeleeTriggerActionConstructCancel)

            // Set a trigger to fire whenever a unit dies for this player.
            set trig = CreateTrigger()
            call TriggerRegisterPlayerUnitEvent(trig, indexPlayer, EVENT_PLAYER_UNIT_DEATH, filter)
            call TriggerAddAction(trig, function MeleeTriggerActionUnitDeathMod)

            // Set a trigger to fire whenever a unit begins construction for this player
            set trig = CreateTrigger()
            call TriggerRegisterPlayerUnitEvent(trig, indexPlayer, EVENT_PLAYER_UNIT_CONSTRUCT_START, filter)
            call TriggerAddAction(trig, function MeleeTriggerActionUnitConstructionStartMod)

            // Set a trigger to fire whenever this player defeats-out
            set trig = CreateTrigger()
            call TriggerRegisterPlayerEvent(trig, indexPlayer, EVENT_PLAYER_DEFEAT)
            call TriggerAddAction(trig, function MeleeTriggerActionPlayerDefeated)

            // Set a trigger to fire whenever this player leaves
            set trig = CreateTrigger()
            call TriggerRegisterPlayerEvent(trig, indexPlayer, EVENT_PLAYER_LEAVE)
            call TriggerAddAction(trig, function MeleeTriggerActionPlayerLeft)
            // Set a trigger to fire whenever this player changes his/her alliances.
            set trig = CreateTrigger()
            call TriggerRegisterPlayerAllianceChange(trig, indexPlayer, ALLIANCE_PASSIVE)
            call TriggerRegisterPlayerStateEvent(trig, indexPlayer, PLAYER_STATE_ALLIED_VICTORY, EQUAL, 1)
            call TriggerAddAction(trig, function MeleeTriggerActionAllianceChangeMod)
        else
            set bj_meleeDefeated[index] = true
            set bj_meleeVictoried[index] = false

            // Handle leave events for observers
            if (IsPlayerObserver(indexPlayer)) then
                // Set a trigger to fire whenever this player leaves
                set trig = CreateTrigger()
                call TriggerRegisterPlayerEvent(trig, indexPlayer, EVENT_PLAYER_LEAVE)
                call TriggerAddAction(trig, function MeleeTriggerActionPlayerLeft)
            endif
        endif

        set index = index + 1
        exitwhen index == bj_MAX_PLAYERS
    endloop
    
    call DestroyFilter(filter)
    set filter = null
    
    // Test for victory / defeat at startup, in case the user has already won / lost.
    // Allow for a short time to pass first, so that the map can finish loading.
    call TimerStart(CreateTimer(), 2.0, false, function MeleeTriggerActionAllianceChangeMod)  
endfunction

 
// Checks if an alliance has changed which has caused a crippled player to be crippled/uncrippled


//===========================================================================
function InitTrig_MeleeGameWinTriggerMod takes nothing returns nothing
    set gg_trg_MeleeGameWinTriggerMod = CreateTrigger()
    call TriggerAddAction(gg_trg_MeleeGameWinTriggerMod, function BaseActions)
endfunction

This code should be used in place of the melee trigger (which is run on initialisation) Victory/Defeat conditions, and the variables should be set before it is run

I have attatched a map that shows this in action, to see the map without it

Oh and I only use JASS, not vJASS
 

Attachments

  • WinMod.w3x
    72.4 KB · Views: 128
Status
Not open for further replies.
Top