+ Reply to Thread
Results 1 to 5 of 5
  1. #1
    Fenix

    Auto-Casting Spell (JASS) - Morphling

    Auto-Casting Spell

    Difficult Rating: 3/10 (Medium)
    Require: Advanced JASS Knowledge / CS_Cache or Handler System
    Version 1.00

    Download Here: http://www.thaicyberupload.com/get/qIVE7yOWVk

    ก่อนหน้านี้ผมไม่เคยทำ Spell ลักษณะนี้มาก่อนเลย แต่คิดว่ามันคงทำได้ยาก
    พอเอาเข้าจริงๆ ก็หน้ามืดตามัวเหมือนกัน ยกเว้นว่ามันเป็นแบบ Auto-Casting Attack
    ยังทำได้ง่ายกว่า เพราะมี Event แบบเจาะจงให้เข้าเงื่อนไขเลย ซึ่งก็คือ
    EVENT_PLAYER_UNIT_ATTACKED ผสมด้วย EVENT_UNIT_DAMAGED
    จากนั้นก็ตามมุขที่รู้ๆ กันอยู่ว่าจะใช้ CS_Cache หรือ Handler System
    เพื่อที่จะตั้ง Integer ขึ้นมาซักอันหนึ่งให้ตรงกับ Order On หรือ Off
    หรือเป็นการตั้ง EVENT_PLAYER_UNIT_SPELL_EFFECT ผสมด้วย เท่านี้ก็สมบูรณ์
    ถ้าหากว่าคุณเข้าใจในเรื่องของการทำ Auto-Casting Attack มาก่อนแล้ว
    Tutorial นี้สามารถที่จะอ่านผ่านๆ ได้เลยครับ

    แต่ถ้าไม่มีพื้นฐาน JASS หรือ ไม่เคยทำลักษณะนี้มาก่อน ขอบอกก่อนเลยครับว่า
    อ่านแล้วคงจะเข้าใจเพียงเล็กน้อย

    วิธีการสร้าง Auto-Casting Spell
    ก่อนที่จะเริ่มให้จำ ค่า Variable เหล่านี้เอาไว้เลยนะครับ
    จะได้ไม่สับสนในตอนหลังว่า มาจากไหน

    constant function DDId takes integer i returns string
    if i==1 then
    return "replenishlifeon"
    elseif i==2 then
    return "replenishmanaon"
    elseif i==3 then
    return "replenishmanaoff"
    elseif i==4 then
    return "replenishlifeoff"
    endif
    return null
    endfunction

    constant function DDIdSpell takes integer i returns integer
    if i==1 then
    return 'A004'
    elseif i==2 then
    return 'A003'
    elseif i==3 then
    return 'A005'
    endif
    return 0
    endfunction
    ขั้นแรกสร้าง Trigger ที่สร้างอีก Trigger หนึ่งขึ้นมา เพื่อเวลาใช้จะเจาะจงเฉพาะตัวนี้
    โดยจะมี Event เมื่อ Unit ตัวนั้นเรียนรู้ Skill

    function InitTrig_SoulSwap takes nothing returns nothing
    set gg_trg_SoulSwap = CreateTrigger( )
    call TriggerRegisterAnyUnitEventBJ(gg_trg_SoulSwap,EVENT_PLAYER_HERO_SKILL)
    call TriggerAddCondition(gg_trg_SoulSwap,Condition(function Trig_SoulSwap_Conditions))
    call TriggerAddAction(gg_trg_SoulSwap,function Trig_SoulSwap_Actions )
    endfunction
    ต่อมาจะเป็นเรื่องของการสร้าง Trigger ใหม่ขึ้นมาโดยมี unit เริ่มร่าย Spell กับ ยูนิตถูกสั่งทำอะไรซักอย่างหนึ่ง
    อย่าลืม null ทุกอย่างรวมทั้งใช้ฟังก์ชั่นทำลาย Trigger ของ emjlr3 ด้วยครับ เพราะไม่ต้องใช้แล้ว

    function Trig_SoulSwap_Conditions takes nothing returns boolean
    return GetLearnedSkill()==DDIdSpell(3)
    endfunction

    function Trig_SoulSwap_Actions takes nothing returns nothing
    local trigger r=GetTriggeringTrigger()
    local trigger t
    local triggeraction ta
    local triggercondition tc
    local event e1
    local event e2
    local unit u=GetTriggerUnit()

    set t=CreateTrigger()
    set e1=TriggerRegisterUnitEvent(t,u,EVENT_UNIT_SPELL_CAST)
    set e2=TriggerRegisterUnitEvent(t,u,EVENT_UNIT_ISSUED_ORDER)
    set tc=TriggerAddCondition(t,Condition(function ACSoulSwapConditions))
    set ta=TriggerAddAction(t,function ACSoulSwapActions)

    call DesTrig(r)
    set r=null
    set t=null
    set ta=null
    set tc=null
    set e1=null
    set e2=null
    endfunction
    เอาล่ะมาดูการทำงานของ Trigger ที่ถูกสร้างขึ้นมาใหม่
    ใน Conditions นั้น เป็นปัจจัยหลักสำคัญที่จะทำให้เกิดการเปลี่ยนแปลงค่า Stats
    ผมจะให้ดูควบคู่กับ Actions ไปเลยนะครับ พร้อมฟังก์ชั่นที่เปลี่ยน Stats

    function ModStatsSpell takes unit u, integer i returns nothing

    local integer l=GetUnitAbilityLevel(u,i)*2
    local real str=GetHeroStr(u,false)
    local real agi=GetHeroAgi(u,false)
    local real mana=GetUnitState(u,UNIT_STATE_MANA)

    if i==DDIdSpell(1) and str>l and mana>20 then

    call SetHeroStr(u,GetHeroStr(u,false)-l,true)
    call SetHeroAgi(u,GetHeroAgi(u,false)+l,true)
    call SetUnitState(u,UNIT_STATE_MANA,mana-20)

    elseif i==DDIdSpell(2) and agi>l and mana>20 then

    call SetHeroStr(u,GetHeroStr(u,false)+l,true)
    call SetHeroAgi(u,GetHeroAgi(u,false)-l,true)
    call SetUnitState(u,UNIT_STATE_MANA,mana-20)

    endif

    endfunction

    function ACSoulSwapConditions takes nothing returns boolean
    if GetTriggerEventId()==EVENT_UNIT_SPELL_CAST then
    return GetSpellAbilityId()==DDIdSpell(1) or GetSpellAbilityId()==DDIdSpell(2)

    elseif GetTriggerEventId()==EVENT_UNIT_ISSUED_ORDER then

    if GetIssuedOrderId()==OrderId(DDId(1)) then
    call SetHandleInt(GetTriggerUnit(),"DDon",1)
    return true

    elseif GetIssuedOrderId()==OrderId(DDId(2)) then
    call SetHandleInt(GetTriggerUnit(),"DDon",2)
    return true

    elseif GetIssuedOrderId()==OrderId(DDId(3)) or GetIssuedOrderId()==OrderId(DDId(4)) then
    call SetHandleInt(GetTriggerUnit(),"DDon",0)
    return false

    endif

    endif
    return false
    endfunction

    function ACSoulSwapActions takes nothing returns nothing
    local integer i=GetHandleInt(GetTriggerUnit(),"DDon")

    if GetTriggerEventId()==EVENT_UNIT_SPELL_CAST then
    call ModStatsSpell(GetTriggerUnit(),GetSpellAbilityId())

    elseif GetTriggerEventId()==EVENT_UNIT_ISSUED_ORDER then
    if i==1 then

    loop
    exitwhen GetHandleInt(GetTriggerUnit(),"DDon")!=1
    call ModStatsSpell(GetTriggerUnit(),DDIdSpell(1))
    call TriggerSleepAction(1)
    endloop

    elseif i==2 then

    loop
    exitwhen GetHandleInt(GetTriggerUnit(),"DDon")!=2
    call ModStatsSpell(GetTriggerUnit(),DDIdSpell(2))
    call TriggerSleepAction(1)
    endloop

    endif
    endif

    endfunction
    ในที่นี้ฟังก์ชั่น ModStatsSpell จะเป็นฟังก์ชั่นที่ใช้เปลี่ยน stat
    ซึ่งเราจะต้องหาวิธีที่จะทำให้ฟังก์ชั่นนี้ทำงานให้ได้ โดย Condition
    คุณจะไม่มีวันเห็นการใช้ Condition แบบนี้ใน GUI อย่างแน่นอน
    เพราะไม่มีการเช็ค Event ว่าเป็นลักษณะไหน และจะใช้ elseif ไม่ได้

    ขั้นแรก เมื่อยูนิตเริ่มร่าย Spell โดย EVENT_UNIT_SPELL_CAST
    ใน Conditions จะมีการเช็คอีกครั้งหนึ่งว่า Raw Code ของ Id ถูกหรือไม่

    โดย

    if GetTriggerEventId()==EVENT_UNIT_SPELL_CAST then
    return GetSpellAbilityId()==DDIdSpell(1) or GetSpellAbilityId()==DDIdSpell(2)
    ถ้าเงื่อนไขถูกต้อง ในส่วน Action ส่วนแรกจะทำงาน

    if GetTriggerEventId()==EVENT_UNIT_SPELL_CAST then
    call ModStatsSpell(GetTriggerUnit(),GetSpellAbilityId())
    และจะมีการเช็ค Raw Code อีกครั้งหนึ่งใน Function ModStatsSpell
    เพื่อที่จะตัดสินว่าจะเพิ่ม Str หรือ Agi และต้องเช็คด้วยว่ามี Mana สูงกว่า 20 หรือไม่
    แต่ในกรณีที่ Event เป็น EVENT_UNIT_ISSUED_ORDER
    เงื่อนไขใน Condtion ก็จะใช้ตัวนี้เป็นการเช็ค

    elseif GetTriggerEventId()==EVENT_UNIT_ISSUED_ORDER then

    if GetIssuedOrderId()==OrderId(DDId(1)) then
    call SetHandleInt(GetTriggerUnit(),"DDon",1)
    return true

    elseif GetIssuedOrderId()==OrderId(DDId(2)) then
    call SetHandleInt(GetTriggerUnit(),"DDon",2)
    return true

    elseif GetIssuedOrderId()==OrderId(DDId(3)) or GetIssuedOrderId()==OrderId(DDId(4)) then
    call SetHandleInt(GetTriggerUnit(),"DDon",0)
    return false
    ต่อจากนี้คือจุดสำคัญครับ ในเงื่อนไขแรกหลักจากผ่านการเช็ค Event แล้ว
    ขั้นตอนต่อมาจะเป็นการหา OrderId ซึ่งเป็น String
    ถ้า OrderId เป็น DDId(1) หรือ "replenishmanaon" ก็จะมีการตั้ง Integer ใน Handler ให้เป็น "1"
    ถ้า OrderId เป็น DDId(2) หรือ "replenishlifeon" ก็จะมีการตั้ง Integer ใน Handler ให้เป็น "2"
    แต่ถ้าเป็น DDId(3) หรือ DDId(4) ก็จะมีค่าเป็น 0 เหตุผลที่ต้องตั้งอย่างนี้ เราะจะมาดูในหัวข้อต่อไป

    คราวนี้จะมาพูดในส่วนของ Action แล้วนะครับ

    elseif GetTriggerEventId()==EVENT_UNIT_ISSUED_ORDER then
    if i==1 then

    loop
    exitwhen GetHandleInt(GetTriggerUnit(),"DDon")!=1
    call ModStatsSpell(GetTriggerUnit(),DDIdSpell(1))
    call TriggerSleepAction(1)
    endloop
    เหมือนอย่างด้านบนที่ต้องมีการเช็ค Id และนำ Integer จาก Hander มาโดย
    local integer i=GetHandleInt(GetTriggerUnit(),"DDon")
    ถ้า Integer ที่เรานำกลับมานั้นเป็น 1 ก็จะมีการตั้ง Loop ขึ้นมา
    โดย Loop ที่ว่านี้จะทำการเปลี่ยน Stat เหมือนกับ EVENT_UNIT_SPELL_CAST ทุกๆ 1 วินาที
    เงื่อนไขการจบ Loop ก็คือที่ "DDon" ไม่ใช่ 1 ยังงงอยู่ไหม? งั้นอธิบายต่อนะ
    สมมุติว่า Player สั่งปิด ตรง Condtion ก็จะตั้งให้ "DDon" เป็น 0 Loop ก็จบ
    หรืออยากจะสั่ง อีก Order หนึ่งขึ้นมา "DDon" ก็จะไม่ใช่ 1 อีก Loop ก็จบ
    ตรงกันข้าม ถ้า "DDon" เป็นตัวเลข 2 ก็จะทำการเปลี่ยนค่า Stat อีกแบบหนึ่ง

    ที่ต้องทำแบบนี้เพราะ Auto-Casting ใน WCIII Engine ที่ทำได้ครั้งละ 1 อัน เท่านั้น (เปิดซ้ำไม่ได้)
    อธิบายคงได้เท่านี้ ต่อให้ละเอียดกว่านี้ก็ไม่มีความหมาย จะงงเปล่าๆ
    ประเด็นสำคัญคือต้องอ่าน Script ให้เข้าใจ เพราะ 70% ของเนื้อหาอยู่ที่ Script

  2. #2
    Niagin

    Re: Auto-Casting Spell (JASS) - Morphling

    เจิม ~ :020:

  3. #3
    [SIN]_BlooD

    Re: Auto-Casting Spell (JASS) - Morphling

    เ่อ่อ ง่ายจริง - -

  4. #4
    Fenix

    Re: Auto-Casting Spell (JASS) - Morphling

    สารภาพ... จริงๆ แล้ววิธี Loop ในนี้มาจาก blizzard.j

    มาจากอันนี้น่ะ

    Wait until (DCOn Equal to 1), checking every 1.00 seconds

    ตอนสุดท้ายคิดไม่ออกว่าจะทำยังไงดี บังเอิญแปลงเป็น Jass Code แล้วปิ๊งไอเดียในทันที

    function Trig_UseSpecialItem_Func002001 takes nothing returns boolean
    return ( udg_DCOn == 1 )
    endfunction

    function Trig_UseSpecialItem_Actions takes nothing returns nothing
    loop
    exitwhen ( Trig_UseSpecialItem_Func002001() )
    call TriggerSleepAction(RMaxBJ(bj_WAIT_FOR_COND_MIN_INTERVAL, 1))
    endloop
    endfunction

    พอเปิดคู่มือภาษา C อ่านต่อมันก็หลักเขียนโปรแกรมง่ายๆ เลยนี่หว่า - -''''

  5. #5
    Junior Member
    Join Date
    May 2020
    Posts
    1

    READER

    Cyber games network update 1.26.1 is here, All paragon resumes reviews update is here and when we are checking game level that time we have to check network first and after that this update is really need for everyone who are checking this update version.
    Last edited by Naoranklin; 18-06-2020 at 01:41 PM.

Facebook Comments


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •