• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Preskooldude / donut3.5

Which is the best RPG battle system?


  • Total voters
    12
  • Poll closed .
Status
Not open for further replies.
Level 8
Joined
Jul 23, 2005
Messages
329
The Hive Workshop
Challenge Request

Instructions
1. Copy this form in its entirety.
2. Create a new thead in THW's Admin Contact forum. Title: Challenge Request.
3.Complete the information in each <field> below the underlined categories.
4. Do not alter the document in any other way.
5. Improperly completed requests may be rejected.
Challenge Arena Rules:

  • No memory leaks are allowed in triggers or scripts.
  • Challenge results must be bug-free.
  • Copy and paste techniques are not permitted.
  • No exports from other games are acceptable.
Challenge Theme:
(Triggering, scripting, texturing, modeling, terrianing, concept art, story writing, other.)
I will challenge Donut to an RPG battle system contest, (which he accepted to prior to the posting of this form). The challenge is to create a system that will fit in with any RPG, campaign or otherwise. The specifics to be judged upon will be stated below.


Challenger:
I, Preskooldude, challenge...


Opponent(s):
...Donut3.5 to a duel!


Challenge Duration:
(14 days maximum)
Infinite (Preaprroved by Wolvy


Proposed Reputation Award:
(20 points maximum)
Standard +20


Challenge judging:
(Poll or appointed judge)
Via Poll


Map-specific conditions:
Theme: RPG battle system

File size: Any size

Imports allowed: Any

Optimization/protection: Unprotected.

Other: Must be fully functional(Although thats a given)

Model-specific conditions:

File size: N/A

Polycount: N/A

Other: N/A


Texture-specific conditions:

File size: N/A

Other: N/A


Other challenge conditions:
Details: Is to be judged on ease of play/fun, and least amount of lag.
 
Level 32
Joined
Oct 23, 2006
Messages
5,291
[rainbow]WAY2GO Preskooldude!!!

This has become The Hive Workshop's first official challenge.[/rainbow]

The challenge has begin and will conclude on

[EDIT] 30 October, 2007 23:59 PM, GMT


  1. A poll will be added at the conclusion of the contest.

  2. The victor shall be awarded 20 reputation points.
    • Neg-rep penalties are at my discretion.

  3. ~ Thread moved from Admin Contact to Challenge Section.
 
Last edited:
Level 27
Joined
Feb 22, 2006
Messages
3,052
Last edited by a moderator:
Level 40
Joined
Dec 14, 2005
Messages
10,532
The popularity contest continues, the standings are currently in favor of do... are impartial.

I, am, of course, surely favoring do... am surely impartial.

(K, I'm just joking, you guys know I support both of you ;))

So does this RPG battle system have any theme, or is it just "something involving a battle," from Final Fantasy to Real-Time to Dungeons and Dragons?
 
Level 27
Joined
Feb 22, 2006
Messages
3,052
Well, its for a map that Preskool started but never finished, and we both had ideas for it (a single-player campaign) so we needed a way to see which was better. Now, both of us are extremely lazy and rarely complete projects, so, if we get lazy on this one -5 rep comes and bites us in the ass :p
But there isn't really a general theme, we don't really know much of what the other is doing.
--donut3.5--
 
Level 8
Joined
Jul 23, 2005
Messages
329
You mean <I> never finish projects. You actually managed to finish DCTD.

And I thought you already told me what you were doing around a week or so prior to the challenge being made:p
 
Level 20
Joined
Apr 22, 2007
Messages
1,960
[off-topic]I'd accept any challenge anyone would give me *hint*(as long as it has to do with triggering [/off-topic]

Can't wait to see the systems you guys will develop. Hopefully they will be original and not all like the Hero RPG system.
 
Level 27
Joined
Feb 22, 2006
Messages
3,052
Well... not impressively, I'm not going to lie. however, instead of doing my weekly routine of staying up til 5 doing a model, I'm going to devote that time to none other than coding. Hopefully some results will be produced after this weekend, I hope to get the skeleton done so over the next two weeks I can add in eye candy.
--donut3.5--
 
Level 9
Joined
Jun 18, 2004
Messages
565
Well... not impressively, I'm not going to lie.

Here's what it'd look like if you did.

Well...impressively, I'm not going to lie. however, instead of doing my weekly routine of staying up til 3 doing coding, I'm going to devote that time to none other posting my super results. Hopefully some funtastic times will be produced after this weekend, I hope to get the Purdy's done so over the next two weeks I can add in candy.
--donut3.5--

See how much better it is to lie?
 
Level 8
Joined
Jul 23, 2005
Messages
329
Extension requested and gotten:
The contest has been extended [2 Weeks, although Wolvy did a month, which I'm sure we don't need]. Instead, we will post an outline of our progress, and, if warranted, our maps as well, on the old due date. Wolvy's post has been updated.
 
Level 27
Joined
Feb 22, 2006
Messages
3,052
Bleh, I know its a day early, but I'm doing this just in case I don't have anything to do.
So far there isn't much going on in the screenie:
preview1.jpg
However, I'll attach some code bits. Criticism for efficiency is good!
JASS:
function Trig_GetWhichAttack_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local unit t = GetHandleUnit( u, "t" )
    local integer i = GetHandleInt( u, "i" )
    if GetSpellAbilityId() == 'A002' then
    call CreateUnit( GetOwningPlayer(u), 'H000', -1000000.00, -1000000.00, 0 )
    call SetHandleInt( u, "i", i+1 )
    call SetHandleHandle( u, ("q"+I2S(i)), GetLastCreatedUnit())
    call SetHandleString( u, ("a"+I2S(i)), "slash" )
    endif
    if GetSpellAbilityId() == 'A000' then
    call CreateUnit( GetOwningPlayer(u), 'H001', -1000000.00, -1000000.00, 0 )
    call SetHandleInt( u, "i", i+1 )
    call SetHandleHandle( u, ("q"+I2S(i)), GetLastCreatedUnit())
    call SetHandleString( u, ("a"+I2S(i)), "strike" )
    endif
    if GetSpellAbilityId() == 'A003' then
    call CreateUnit( GetOwningPlayer(u), 'H002', -1000000.00, -1000000.00, 0 )
    call SetHandleInt( u, "i", i+1 )
    call SetHandleHandle( u, ("q"+I2S(i)), GetLastCreatedUnit())
    call SetHandleString( u, ("a"+I2S(i)), "fierce" )
    endif
endfunction
JASS:
function FierceAttack takes nothing returns nothing
    local timer timeaction = GetExpiredTimer()
    local unit u = GetHandleUnit( timeaction, "u")
    local unit t = GetHandleUnit( u, "t")
    call DealDamage( 225.00, u, t ) 
    call SetUnitAnimation( u, "attack" )
    call TriggerSleepAction( 1.17 )  
    call ResetUnitAnimation(u)
    call Queue(u, GetHandleUnit(u, "q"+I2S(1)))
endfunction
function StrikeAttack takes nothing returns nothing
    local integer random = GetRandomInt(0,1)
    local timer timeaction = GetExpiredTimer()
    local unit u = GetHandleUnit( timeaction, "u")
    local unit t = GetHandleUnit( u, "t")
    call SetUnitAnimation( u, "stand" )
    if random == 1 then
    call DealDamage( 75.00, u, t ) 
    else
    call DealDamage( 150.00, u, t ) 
    endif
    call SetUnitAnimation( u, "attack" )
    call TriggerSleepAction( 1.17 )  
    call ResetUnitAnimation(u)
    call Queue(u, GetHandleUnit(u, "q"+I2S(1)))
endfunction
function SlashAttack takes nothing returns nothing
    local timer timeaction = GetExpiredTimer()
    local unit u = GetHandleUnit( timeaction, "u")
    local unit t = GetHandleUnit( u, "t")
    call DealDamage( 100.00, u, t ) 
    call SetUnitAnimation( u, "attack" )
    call TriggerSleepAction( 1.17 )  
    call ResetUnitAnimation(u)
    call Queue(u, GetHandleUnit(u, "q"+I2S(1)))
endfunction

function FightTurns takes nothing returns nothing
    local timer time = GetExpiredTimer()
    local timer timeaction = CreateTimer()
    local unit u = GetHandleUnit( time, "u")
    local string s = GetHandleString(u, "a"+I2S(1))
    call SetHandleHandle( timeaction, "u", u )
    if s == null then
    
    endif
    if s == "slash" then
    call TimerStart( timeaction, 0.01, false, function SlashAttack )
    endif
    if s == "strike" then
    call TimerStart( timeaction, 0.01, false, function StrikeAttack )
    endif
    if s == "fierce" then
    call TimerStart( timeaction, 0.01, false, function FierceAttack )
    endif
endfunction

function Trig_Acquire_Target_Actions takes nothing returns nothing
    local timer time = CreateTimer()
    call SetHandleInt( GetTriggerUnit(), "i", 1 )
    call SetUnitFacingToFaceUnitTimed( GetSpellTargetUnit(), GetTriggerUnit(), 0 )
    call SetHandleHandle( GetTriggerUnit(), "u", GetTriggerUnit() )
    call SetHandleHandle( time, "u", GetTriggerUnit() )
    call SetHandleHandle( GetTriggerUnit(), "t", GetSpellTargetUnit() )
    call SetHandleBoolean( GetTriggerUnit(), "a", true )
    call DisplayTextToPlayer(GetOwningPlayer(GetTriggerUnit()), 0, 0, "Combat initiated with " + GetUnitName(GetSpellTargetUnit()) + ". Each unit will have 5 seconds to make a starting queue.")
    call TriggerSleepAction(5.00)
    call TimerStart( time, 3.00, true, function FightTurns )
    set time = null
endfunction

The first code shown queues up the the ability, the second code runs the abilities once every 3.00 seconds. Oh yes, I'm quite well aware I haven't dealt with setting locals to null yet. And I don't need to hear about how much better structs would be, I didn't feel like learning them here :p... This last code I'm showing you Creates floating text according to how much damage is dealt, and deals the damage:
JASS:
function DealDamage takes real d, unit u, unit t returns nothing
    local texttag txt = CreateTextTag()
    call UnitDamageTarget(u, t, d, true, false, ATTACK_TYPE_MELEE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
    call SetTextTagText(txt, I2S(R2I((d))), .023)
    call SetTextTagPos(txt, GetUnitX(u), GetUnitY(u), 150.00)
    call SetTextTagColor(txt, 255, 0, 0, 255)
    call SetTextTagPermanent(txt, false)
    call SetTextTagFadepoint(txt, 0.60)
    call SetTextTagLifespan(txt, 0.80)
    call SetTextTagVelocity(txt, 0.00, 0.03328125)
    call SetTextTagVisibility(txt, true)
    set txt = null
endfunction
I do now show a custom function I use, Queue, because it is not functional as of now, I am looking to fix it though.
I await yours, Preskool, when you are ready ;)
--donut3.5--
 
Level 8
Joined
Jul 23, 2005
Messages
329
In the Map's Custom Script:
JASS:
globals
    constant integer BOOLARRAYSIZE = 34
    constant integer CELLLENGTH = 7
    constant real ZEROZEROX = -960
    constant real ZEROZEROY = 448
    constant integer DUMMYUNITID = 'h001'
endglobals

// ==================================== COMBAT SYSTEM ==============================================

function BattleFieldCreateUnit takes integer unitid, integer FieldPos, player Playa, integer Facing returns unit
    //Returns created unit
    local unit You
    if udg_SquareOccupied[ FieldPos ] == null then
        set You = CreateUnit( Playa, unitid, ZEROZEROX + ( ModuloInteger(FieldPos, CELLLENGTH) * 128 ), ZEROZEROY - ( (FieldPos / CELLLENGTH) * 128 ), 90 - (Facing * 45) )
        call GroupAddUnit( udg_MovingGroup, You )
        set udg_SquareOccupied[ FieldPos ] = You
        call SetHandleInt( You, "IsAt", FieldPos )
        return You
    endif
    return null 
endfunction

function DealDamage takes real Damage, unit Target, unit Attaquer, weapontype WeaponType returns nothing
    local unit Dummy
    call UnitDamageTarget( Attaquer, Target, Damage, true, true, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, WeaponType)
    set Dummy = CreateUnit( Player(11), DUMMYUNITID, GetUnitX( Target ), GetUnitY( Target ), 0)
    call IssueTargetOrder( Dummy, "thunderbolt", Target )
    call SetUnitAnimation( Attaquer, "attack" )
    call PolledWait( 0.5 )
    call RemoveUnit( Dummy )
    call PolledWait( 2 )
    call UnitRemoveAbility( Target, 'BPSE' )
endfunction
Trigger: Move Units:
JASS:
function ForGroupAction takes nothing returns nothing
    call GroupAddUnit(bj_groupAddGroupDest, GetEnumUnit())
endfunction

function MoveUnits takes nothing returns nothing
    local unit Target
    local real TargetX
    local real TargetY
    local integer PointValue
    local group TargetGroup = CreateGroup() //Temp Thingymobob
    local integer IsAt      //Temp Integer
    local integer WasAt     //Temp Integer
    local integer There     //Temp Integer
    local boolean Flag      //Temp Boolean
    local boolean IsMoving  //Temp Boolean
    
    set bj_groupAddGroupDest = TargetGroup
    call ForGroup( udg_MovingGroup, function ForGroupAction )
    set TargetGroup = bj_groupAddGroupDest

    loop
        set Target = FirstOfGroup( TargetGroup )
        exitwhen Target == null
        
        set PointValue = GetUnitUserData( Target )
        set IsAt = GetHandleInt( Target, "IsAt" )
        if udg_SquareOccupied[ GetHandleInt( Target, "WasAt" ) ] == Target then
            set udg_SquareOccupied[ GetHandleInt( Target, "WasAt" ) ] = null
        endif
        if ( PointValue != 0 ) then //Unit is going somewhere
            set Flag = false
            set IsMoving = false        
            call SetHandleInt( Target, "WasAt", IsAt )

            set TargetY = GetUnitY( Target )
            if ( PointValue <= 2 or PointValue == 8 ) then      //Headed in the UP direction
                set There = IsAt - (CELLLENGTH)
                if There >= 0 then
                    if udg_SquareOccupied[ There ] == null then
                        call SetHandleInt( Target, "IsAt", There ) //Normal Execution
                        set IsMoving = true
                    else
                        call SetHandleInt( Target, "WasAt", IsAt + CELLLENGTH ) //Unit in the way
                        set Flag = true
                    endif
                //else
                    //Do Nothing
                endif
            elseif ( PointValue <= 6 and PointValue >= 4 ) then //Headed in the DOWN direction
                set There = IsAt + (CELLLENGTH)
                if There <= BOOLARRAYSIZE then
                    if udg_SquareOccupied[ There ] == null then
                        call SetHandleInt( Target, "IsAt", There ) //Normal Execution
                        set IsMoving = true
                    else
                        call SetHandleInt( Target, "WasAt", IsAt - CELLLENGTH )
                        set Flag = true
                    endif
                //else
                    //Do Nothing
                endif
            endif
            
            set IsAt = GetHandleInt( Target, "IsAt" )

            set TargetX = GetUnitX( Target )   
            if ( PointValue >= 2 and PointValue <= 4 ) then     //Headed in the LEFT direction
                set There = IsAt - 1
                if There >= 0 and ModuloInteger( There, CELLLENGTH ) != 6 then
                    if udg_SquareOccupied[ There ] == null then                     
                        call SetHandleInt( Target, "IsAt", There )
                        set IsMoving = true
                    elseif Flag == true then
                        call SetHandleInt( Target, "WasAt", GetHandleInt( Target, "WasAt" ) - 1 )
                    else
                        call SetHandleInt( Target, "WasAt", IsAt - 1 )
                    endif
                //else
                    //Do Nothing
                endif
            elseif ( PointValue >= 6 and PointValue <= 8 ) then //Headed in the RIGHT direction (lol)
                set There = IsAt + 1
                if There <= BOOLARRAYSIZE  and ModuloInteger( There, CELLLENGTH ) != 0 then
                    if udg_SquareOccupied[ There ] == null then
                        call SetHandleInt( Target, "IsAt", There )
                        set IsMoving = true
                    elseif Flag == true then
                        call SetHandleInt( Target, "WasAt", GetHandleInt( Target, "WasAt" ) + 1 )
                    else
                        call SetHandleInt( Target, "WasAt", IsAt + 1 )
                    endif
                //else
                    //Do Nothing
                endif
            endif

            //Determine the point at "IsAt"
            set IsAt = GetHandleInt( Target, "IsAt" )
            set WasAt = GetHandleInt( Target, "WasAt" )
            set TargetY = ZEROZEROY - ( (IsAt / CELLLENGTH) * 128 )
            set TargetX = ZEROZEROX + ( ModuloInteger(IsAt, CELLLENGTH) * 128 )
                
            set udg_SquareOccupied[ IsAt ] = Target
            if IsMoving == true then
                call IssuePointOrder( Target, "move", TargetX, TargetY )
            endif
            //Angle between two points: Atan2( x1-x2, y1-y2 )
            call SetUnitFacing( Target, bj_RADTODEG * Atan2(  ( ( (IsAt - WasAt + IsAt ) / CELLLENGTH ) - ( IsAt / CELLLENGTH ) ), ModuloInteger( (IsAt - WasAt + IsAt), CELLLENGTH ) - ModuloInteger( IsAt, CELLLENGTH ) ) )
        endif
        
        call GroupRemoveUnit( TargetGroup, Target )    
    endloop           
    call DestroyGroup( TargetGroup )
endfunction

//===========================================================================
function InitTrig_Move takes nothing returns nothing
    set udg_MovementTimer = CreateTimer()
    call TimerStart( udg_MovementTimer, 0.4, true, function MoveUnits )
endfunction
The "slash" trigger, which enables a basic attack
JASS:
function Trig_Slash_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function Trig_Slash_Actions takes nothing returns nothing
    local unit Caster = GetHandleUnit( GetTriggerUnit(), "Controlled" )
    local integer IsAt = GetHandleInt( Caster, "IsAt" )
    local integer WasAt = GetHandleInt( Caster, "WasAt" )
    
    call IssueImmediateOrderBJ( GetTriggerUnit(), "stop" )
    if udg_SquareOccupied[ (IsAt - WasAt) + IsAt ] != null then
        call DealDamage( 10, udg_SquareOccupied[ (IsAt - WasAt) + IsAt ], Caster, WEAPON_TYPE_METAL_MEDIUM_SLICE)
    endif   
    
endfunction

//===========================================================================
function InitTrig_Slash takes nothing returns nothing
    local integer index

    set gg_trg_Slash = CreateTrigger(  )
    set index = 0
    loop
        call TriggerRegisterPlayerUnitEvent(gg_trg_Slash, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)

        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerAddCondition( gg_trg_Slash, Condition( function Trig_Slash_Conditions ) )
    call TriggerAddAction( gg_trg_Slash, function Trig_Slash_Actions )
endfunction
The ability for X-Defend, which allows the player to be safe from magic:
JASS:
function Trig_XDefend_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A005'
endfunction

function Trig_XDefend_Actions takes nothing returns nothing
    local unit Dummy = CreateUnit( Player(11), DUMMYUNITID, 0, 0, 0)
    call IssueTargetOrder( Dummy, "antimagicshell", GetHandleWidget( GetTriggerUnit(), "Controlled" ) )
endfunction

//===========================================================================
function InitTrig_XDefend takes nothing returns nothing
    local integer index

    set gg_trg_XDefend = CreateTrigger(  )
    
    set index = 0
    loop
        call TriggerRegisterPlayerUnitEvent(gg_trg_XDefend, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)

        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerAddCondition( gg_trg_XDefend, Condition( function Trig_XDefend_Conditions ) )
    call TriggerAddAction( gg_trg_XDefend, function Trig_XDefend_Actions )
endfunction
Perhaps an explanation would be necessary for some of the above triggers:

A unit's custom value defines where it is headed. All units in the battlefield are stored in a unit array and a unit group. The unit group is cycled through to get each individual unit, and then reads its custom value. It then sets its target to be in the direction headed. It ALSO sets the necessary value in the unit array: SquareOccupied[]. After the move is complete, SquareOccupied[] is removed. There is also two other values set: "IsAt", and "WasAt". "IsAt" defines where the unit currently is, and "WasAt" defines where the unit was. I use these two variables to determine where the unit is facing. Also: Pic below :D
 

Attachments

  • Attack.jpg
    Attack.jpg
    79.2 KB · Views: 159
Level 40
Joined
Dec 14, 2005
Messages
10,532
Donut;

  • indent more!! (like, inside if-statements and stuff)
  • don't bother with decimals longer than 3 - round after that
  • x.00 = x
  • For Random in Strike, instead of doing
    local var SomeVar = GetRandomInt(0,1)
    if random == 0 then
    do xxx with 75
    else
    do xxy with 150
    endif

    You can do

    do xxx with 75*GetRandomInt(1,2)
  • CreateUnit doesn't set GetLastCreatedUnit()! (which returns bj_lastCreatedUnit). You need to store the Created Unit to a variable.
  • if you plan on using something like GetTriggerUnit() more than 2 or 3 times, don't be afraid to store it in a variable.

Preskool;

  • in XDefend, you can inline CreateUnit and skip the unit variable
  • Root out BJs like IssueImmediateOrderBJ
  • You've forgotten to null handles!
  • ==true is unneeded.
  • Instead of the ForGroup that copies a group to save the old one, just remove from the original in the loop, and use GroupAddUnit to add to a temp group, then set the original to that temp group. It's a good deal faster.
  • Try to avoid TriggerSleepActions or things (like PolledWait) that use them
 
Level 8
Joined
Jul 23, 2005
Messages
329
Damnit.... missed that one bj...
And actually, I also need to remove that dummy in the X-Defend thingy.
'right thanks!

EDIT: Oh, and Donut, in your first trigger posted, you could actually place the
JASS:
call SetHandleHandle([ u, ("q"+I2S(i)), GetLastCreatedUnit())
outside of the 'if' statements, at the very bottom of the function. Just a tip.
 
Last edited:
Status
Not open for further replies.
Top