[EO] NPC Spells v.2.0.0

This is a tutorial for Eclipse Origins v.2 Beta. It will allow NPCs to cast spells as determined in the NPC Editor. This is based on my previous tutorial with a few edits and improvements here and there. Hopefully, this will help you further your project.

Notes

*** Now Works with v.2.0.0**

*** Note: AoE Spells have not been tested, but are still included.**

*** If you have an NPC that has an animation already, the NPC’s animation will show with the spell animation. I’ll look into this later.**

How It Works:

A NPC will have a number of spells as determined in the NPC Editor and a max number as determined in the source. A NPC will cast spells on a player if the player is in the Spell’s range and only after the casting time of the spell. If the spell is a healing spell, the NPC will heal itself. An NPC will only use a healing spell after it’s HP has dropped to 30% or lower. A NPC can only heal itself a certain amount of times based on how high it’s intelligence is. The damage and vital effect of an NPC is also dependent on the NPC’s intelligence. The higher the intelligence of the NPC, the more effective it is with spells. AoE spells will hit all players on the map within the area of effect. All healing AoE spells will heal all NPCs on the map within the area of effect. An NPC can cast multiple spells, but must respect the Cooldown and cast times of each individual spell. An NPC can attack and cast spells simultaneously.

The Code:

==============

Server Side

==============

In modConstants

Find:

Public Const MAX_PARTY_MEMBERS As Long = 4

Underneath it, add:

' NPC Spells

Public Const MAX_NPC_SPELLS As Long = 5

*** This is the max amount of spells an NPC can have.**

In modTypes

Find : Private Type NpcRec

Add this to the bottom of Private Type NpcRec (before End Type)

    ' Npc Spells

    Spell(1 To MAX_NPC_SPELLS) As Long

Find : Private Type MapNpcRec

Add this to the bottom of Private Type MapNpcRec (before End Type)

' Npc spells

    SpellTimer(1 To MAX_NPC_SPELLS) As Long

    Heals As Integer

In modGameLogic

Find : Sub NpcAttackPlayer

Below the entire sub, add this:

Sub NpcSpellPlayer(ByVal MapNpcNum As Long, ByVal Victim As Long, SpellSlotNum As Long)

    Dim mapnum As Long

    Dim i As Long

    Dim n As Long

    Dim SpellNum As Long

    Dim Buffer As clsBuffer

    Dim InitDamage As Long

    Dim Damage As Long

    Dim MaxHeals As Long

    ' Check for subscript out of range

    If MapNpcNum <= 0 Or MapNpcNum > MAX_MAP_NPCS Or IsPlaying(Victim) = False Then

        Exit Sub

    End If

    ' Check for subscript out of range

    If MapNpc(GetPlayerMap(Victim)).Npc(MapNpcNum).Num <= 0 Then

        Exit Sub

    End If

    If SpellSlotNum <= 0 Or SpellSlotNum > MAX_NPC_SPELLS Then Exit Sub

    ' The Variables

    mapnum = GetPlayerMap(Victim)

    SpellNum = Npc(MapNpc(mapnum).Npc(MapNpcNum).Num).Spell(SpellSlotNum)

    ' Send this packet so they can see the person attacking

    Set Buffer = New clsBuffer

    Buffer.WriteLong SNpcAttack

    Buffer.WriteLong MapNpcNum

    SendDataToMap mapnum, Buffer.ToArray()

    Set Buffer = Nothing

    ' CoolDown Time

    If MapNpc(mapnum).Npc(MapNpcNum).SpellTimer(SpellSlotNum) > GetTickCount Then Exit Sub

    ' Spell Types

        Select Case Spell(SpellNum).Type

            ' AOE Healing Spells

            Case SPELL_TYPE_HEALHP

            ' Make sure an npc waits for the spell to cooldown

            MaxHeals = 1 + Npc(MapNpc(mapnum).Npc(MapNpcNum).Num).Stat(Stats.intelligence) \ 25

            If MapNpc(mapnum).Npc(MapNpcNum).Heals >= MaxHeals Then Exit Sub

                If MapNpc(mapnum).Npc(MapNpcNum).Vital(Vitals.HP) <= Npc(MapNpc(mapnum).Npc(MapNpcNum).Num).HP * 0.3 Then

                    If Spell(SpellNum).IsAoE Then

                        For i = 1 To MAX_MAP_NPCS

                            If MapNpc(mapnum).Npc(i).Num > 0 Then

                                If MapNpc(mapnum).Npc(i).Vital(Vitals.HP) > 0 Then

                                    If isInRange(Spell(SpellNum).AoE, MapNpc(mapnum).Npc(MapNpcNum).x, MapNpc(mapnum).Npc(MapNpcNum).y, MapNpc(mapnum).Npc(i).x, MapNpc(mapnum).Npc(i).y) Then

                                        InitDamage = Spell(SpellNum).Vital + (Npc(MapNpc(mapnum).Npc(MapNpcNum).Num).Stat(Stats.intelligence) / 2)

                                        MapNpc(mapnum).Npc(i).Vital(Vitals.HP) = MapNpc(mapnum).Npc(i).Vital(Vitals.HP) + InitDamage

                                        SendActionMsg mapnum, "+" & InitDamage, BrightGreen, 1, (MapNpc(mapnum).Npc(i).x * 32), (MapNpc(mapnum).Npc(i).y * 32)

                                        Call SendAnimation(mapnum, Spell(SpellNum).SpellAnim, 0, 0, TARGET_TYPE_NPC, MapNpcNum)

                                        If MapNpc(mapnum).Npc(i).Vital(Vitals.HP) > Npc(MapNpc(mapnum).Npc(i).Num).HP Then

                                            MapNpc(mapnum).Npc(i).Vital(Vitals.HP) = Npc(MapNpc(mapnum).Npc(i).Num).HP

                                        End If

                                        MapNpc(mapnum).Npc(MapNpcNum).Heals = MapNpc(mapnum).Npc(MapNpcNum).Heals + 1

                                        MapNpc(mapnum).Npc(MapNpcNum).SpellTimer(SpellSlotNum) = GetTickCount + Spell(SpellNum).CDTime * 1000

                                        Exit Sub

                                    End If

                                End If

                            End If

                        Next

                    Else

                    ' Non AOE Healing Spells

                        InitDamage = Spell(SpellNum).Vital + (Npc(MapNpc(mapnum).Npc(MapNpcNum).Num).Stat(Stats.intelligence) / 2)

                        MapNpc(mapnum).Npc(MapNpcNum).Vital(Vitals.HP) = MapNpc(mapnum).Npc(MapNpcNum).Vital(Vitals.HP) + InitDamage

                        SendActionMsg mapnum, "+" & InitDamage, BrightGreen, 1, (MapNpc(mapnum).Npc(MapNpcNum).x * 32), (MapNpc(mapnum).Npc(MapNpcNum).y * 32)

                        Call SendAnimation(mapnum, Spell(SpellNum).SpellAnim, 0, 0, TARGET_TYPE_NPC, MapNpcNum)

                        If MapNpc(mapnum).Npc(MapNpcNum).Vital(Vitals.HP) > Npc(MapNpc(mapnum).Npc(MapNpcNum).Num).HP Then

                            MapNpc(mapnum).Npc(MapNpcNum).Vital(Vitals.HP) = Npc(MapNpc(mapnum).Npc(MapNpcNum).Num).HP

                        End If

                        MapNpc(mapnum).Npc(MapNpcNum).Heals = MapNpc(mapnum).Npc(MapNpcNum).Heals + 1

                        MapNpc(mapnum).Npc(MapNpcNum).SpellTimer(SpellSlotNum) = GetTickCount + Spell(SpellNum).CDTime * 1000

                        Exit Sub

                    End If

                End If

            ' AOE Damaging Spells

            Case SPELL_TYPE_DAMAGEHP

            ' Make sure an npc waits for the spell to cooldown

                If Spell(SpellNum).IsAoE Then

                    For i = 1 To Player_HighIndex

                        If IsPlaying(i) Then

                            If GetPlayerMap(i) = mapnum Then

                                If isInRange(Spell(SpellNum).AoE, MapNpc(mapnum).Npc(MapNpcNum).x, MapNpc(mapnum).Npc(MapNpcNum).y, GetPlayerX(i), GetPlayerY(i)) Then

                                    InitDamage = Spell(SpellNum).Vital + (Npc(MapNpc(mapnum).Npc(MapNpcNum).Num).Stat(Stats.intelligence) / 2)

                                    Damage = InitDamage - Player(i).Stat(Stats.willpower)

                                        If Damage <= 0 Then

                                            SendActionMsg GetPlayerMap(i), "RESIST!", Pink, 1, (GetPlayerX(i) * 32), (GetPlayerY(i) * 32)

                                            Exit Sub

                                        Else

                                            NpcAttackPlayer MapNpcNum, i, Damage

                                            SendAnimation mapnum, Spell(SpellNum).SpellAnim, 0, 0, TARGET_TYPE_PLAYER, MapNpcNum

                                            MapNpc(mapnum).Npc(MapNpcNum).SpellTimer(SpellSlotNum) = GetTickCount + Spell(SpellNum).CDTime * 1000

                                            Exit Sub

                                        End If

                                End If

                            End If

                        End If

                    Next

                ' Non AoE Damaging Spells

                Else

                    If isInRange(Spell(SpellNum).Range, MapNpc(mapnum).Npc(MapNpcNum).x, MapNpc(mapnum).Npc(MapNpcNum).y, GetPlayerX(Victim), GetPlayerY(Victim)) Then

                    InitDamage = Spell(SpellNum).Vital + (Npc(MapNpc(mapnum).Npc(MapNpcNum).Num).Stat(Stats.intelligence) / 2)

                    Damage = InitDamage - Player(Victim).Stat(Stats.willpower)

                        If Damage <= 0 Then

                            SendActionMsg GetPlayerMap(Victim), "RESIST!", Pink, 1, (GetPlayerX(Victim) * 32), (GetPlayerY(Victim) * 32)

                            Exit Sub

                        Else

                            NpcAttackPlayer MapNpcNum, Victim, Damage

                            SendAnimation mapnum, Spell(SpellNum).SpellAnim, 0, 0, TARGET_TYPE_PLAYER, Victim

                            MapNpc(mapnum).Npc(MapNpcNum).SpellTimer(SpellSlotNum) = GetTickCount + Spell(SpellNum).CDTime * 1000

                            Exit Sub

                        End If

                    End If

                End If

            End Select

End Sub

In modServerLoop

Find these three lines:

Else

                            ' lol no npc combat ![:(](http://www.touchofdeathforums.com/community/public/style_emoticons/<#EMO_DIR#>/sad.png)

                        End If

And delete them.

Find this:

                ' ////////////////////////////////////////////

                ' // This is used for regenerating NPC's HP //

                ' ////////////////////////////////////////////

Above, add this:

                            ' Spell Casting

                                For i = 1 To MAX_NPC_SPELLS

                                    If Npc(npcNum).Spell(i) > 0 Then

                                        If MapNpc(mapnum).Npc(x).SpellTimer(i) + (Spell(Npc(npcNum).Spell(i)).CastTime * 1000) < GetTickCount Then

                                            NpcSpellPlayer x, target, i

                                        End If

                                    End If

                                Next

                            End If

Client Side

In modTypes

Find : Private Type NpcRec

Add this to the bottom of Private Type NpcRec (before End Type)

    ' Npc Spells

    Spell(1 To MAX_NPC_SPELLS) As Long

In modGameEditors

Find: Public Sub NpcEditorInit

Find this line:

        .txtDamage.text = Npc(EditorIndex).Damage

Underneath it, add:

        .scrlSpellNum.Max = MAX_NPC_SPELLS

        .scrlSpellNum.Value = 1

Form Work:

I’ve included an frmEditor_NPC that you can use and copy from.

That’s should be all. Congrats, NPCs will now cast spells. Look through the code and modify it to your liking, I encourage you to do so. Have fun with the tutorial folks.

Looks great man.

If no one else replies by some time tomorrow. I’ll try it out and report any feedback I have.

Okay… I put it all in.
One issue.
If you don’t have a spell in slot 2, you will get a “subscript out of range error”. For the most part. Seems to work well. Good job.

Find this piece of code I posted above:

                            ' Are they in range?  if so GET'M!
                            If DistanceX <= n And DistanceY <= n Then
                                If Npc(NpcNum).Stat(Stats.intelligence) > 0 Then
                                    If Npc(NpcNum).Spell1 > 0 Or Npc(NpcNum).Spell2 > 0 Then
                                        If Spell(Npc(NpcNum).Spell1).Type = SPELL_TYPE_DAMAGEHP Or Spell(Npc(NpcNum).Spell2).Type = SPELL_TYPE_HEALHP Then
                                            Call NpcSpellPlayer(x, Target)
                                        End If
                                    End If
                                End If
                            End If

And replace it with:

                            ' Are they in range?  if so GET'M!
                            If DistanceX <= n And DistanceY <= n Then
                                If Npc(NpcNum).Stat(Stats.intelligence) > 0 Then
                                    If Npc(NpcNum).Spell1 > 0 Or Npc(NpcNum).Spell2 > 0 Then
                                            Call NpcSpellPlayer(x, Target)
                                        End If
                                    End If
                                End If
  • This has been added to the original post.

Thanks so much man! I added it all in, and it works perfect. Ill be using this for sure to build on a boss system for NPC’s. Ill be sure to add you in the credits as well.

-Irhymer

Nice work on this ^^ how could you make it so that the spells can also hit other npcs whilst useing the npc vs npc source 😛

Qwerty, seriously learn to program! It’s easy… Just need to modify a few pieces of code he has up there… :rolleyes: You really do expect other people to program your entire game don’t you? ;D

Dang, she told you… xD.

When I compile the client, I get

Compile error:
Ambiguous name detected: scrlSpell2_Change
```:/

@Im_Mad_1337:

When I compile the client, I get

Compile error:
Ambiguous name detected: scrlSpell2_Change
```:/

That just means you have multiple scrlSpell2_Change subs in your code. Find and delete the other one(s) to make sure there is only one of these subs in your entire game.

@DJMaxus:

That just means you have multiple scrlSpell2_Change subs in your code. Find and delete the other one(s) to make sure there is only one of these subs in your entire game.

Thanks, but I doubt I did any of the “frmEditor_NPC” correctly, I’m very new to this, and just guessed what most of it meant XD

Try redoing the whole tut from the start, I cleaned up a few things.

Works almost perfect here. 🙂 Great script!
This makes fights more realistic.

Ok just set the Max in the Hscroll bars to 4924.
That will avoid the client crash. 🙂

So this would also work with AOE spells for the NPC if I’m not wrong?
If so I will use this! Great feature anyways!

I wonder if Robin is going to implement this code in the next version of EO…
I hope he does, and adds some of the others codes as well, but I don’t mind adding them manually.  XD

No. These are tutorials.

@Robin:

No. These are tutorials.

@Robin:

No. These are tutorials.

Ok. Thanks for the reply.  😉

I really love this script though, makes boss monsters much funner! 😄

I am so happy. Now let me see if i can make it work.
i just add the codes with VB6 than compile them?

Follow the tutorial.
There is written where to put what code. SImple copy and paste.
And if you are done, compile.

Log in to reply