cmangos / issues

This repository is used as a centralized point for all issues regarding CMaNGOS.
180 stars 47 forks source link

Script engine improvements #409

Closed xfurry closed 9 years ago

xfurry commented 10 years ago

Hi,

During the last couple of weeks I received a few requests for improvements on the script engine.

I will post all the requested patches here, so everyone can share the feedback and input before I commit them to master.

1 Script Command Modify Unit Flags This was requested by @grz3s and allows changing the unit flag of a creature from DB scripts.

diff --git a/doc/script_commands.txt b/doc/script_commands.txt
index c346610..21bd7aa 100644
--- a/doc/script_commands.txt
+++ b/doc/script_commands.txt
@@ -289,3 +289,7 @@ Where "A  ->  B" means that the command is executed from A with B as target.
 34 SCRIPT_COMMAND_TERMINATE_COND            * datalong = condition_id, datalong2 = fail-quest (if provided this quest will be failed for a player)
                                             * !(data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL): terminate when condition is true
                                                 data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL:  terminate when condition is false
+
+35 SCRIPT_COMMAND_MODIFY_UNIT_FLAGS         resultingSource = Creature
+                                            * datalong=Unit_Flags
+                                            * datalong2= 0x00=toggle, 0x01=add, 0x02=remove
diff --git a/src/game/ScriptMgr.cpp b/src/game/ScriptMgr.cpp
index 049cd72..9732bc8 100644
--- a/src/game/ScriptMgr.cpp
+++ b/src/game/ScriptMgr.cpp
@@ -678,6 +678,8 @@ void ScriptMgr::LoadScripts(ScriptMapMapName& scripts, const char* tablename)
                 }
                 break;
             }
+            case SCRIPT_COMMAND_MODIFY_UNIT_FLAGS:          // 35
+                break;
             default:
             {
                 sLog.outErrorDb("Table `%s` unknown command %u, skipping.", tablename, tmp.command);
@@ -1796,6 +1798,28 @@ bool ScriptAction::HandleScriptStep()
             }
             return terminateResult;
         }
+        case SCRIPT_COMMAND_MODIFY_UNIT_FLAGS:               // 35
+        {
+            if (LogIfNotCreature(pSource))
+                break;
+
+            // Add Flags
+            if (m_script->unitFlag.change_flag & 0x01)
+                pSource->SetFlag(UNIT_FIELD_FLAGS, m_script->unitFlag.flag);
+            // Remove Flags
+            else if (m_script->unitFlag.change_flag & 0x02)
+                pSource->RemoveFlag(UNIT_FIELD_FLAGS, m_script->unitFlag.flag);
+            // Toggle Flags
+            else
+            {
+                if (pSource->HasFlag(UNIT_FIELD_FLAGS, m_script->unitFlag.flag))
+                    pSource->RemoveFlag(UNIT_FIELD_FLAGS, m_script->unitFlag.flag);
+                else
+                    pSource->SetFlag(UNIT_FIELD_FLAGS, m_script->unitFlag.flag);
+            }
+
+            break;
+        }
         default:
             sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u unknown command used.", m_table, m_script->id, m_script->command);
             break;
diff --git a/src/game/ScriptMgr.h b/src/game/ScriptMgr.h
index ffae118..e9f9a04 100644
--- a/src/game/ScriptMgr.h
+++ b/src/game/ScriptMgr.h
@@ -100,6 +100,9 @@ enum ScriptCommand                                          // resSource, resTar
     SCRIPT_COMMAND_XP_USER                  = 33,           // source or target with Player, datalong = bool (0=off, 1=on)
     SCRIPT_COMMAND_TERMINATE_COND           = 34,           // datalong = condition_id, datalong2 = if != 0 then quest_id of quest that will be failed for player's group if the script is terminated
                                                             // data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL terminate when condition is false ELSE terminate when condition is true
+    SCRIPT_COMMAND_MODIFY_UNIT_FLAGS        = 35,           // resSource = Creature
+                                                            // datalong = Unit_Flags
+                                                            // datalong2:0x00 = toggle, 0x01 = add, 0x02 = remove
 };

 #define MAX_TEXT_ID 4                                       // used for SCRIPT_COMMAND_TALK
@@ -323,6 +326,12 @@ struct ScriptInfo
             uint32 failQuest;                               // datalong2
         } terminateCond;

+        struct                                              // case SCRIPT_COMMAND_MODIFY_UNIT_FLAGS (35)
+        {
+            uint32 flag;                                    // datalong
+            uint32 change_flag;                             // datalong2
+        } unitFlag;
+
         struct
         {
             uint32 data[2];

2 Allow DBscripts_on_spell to run for missing triggered missile spells. Also requested by @grz3s. The only problem with this one is that the error still appears even if the dbscript runs fine.

diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp
index 41f1745..be95192 100644
--- a/src/game/SpellEffects.cpp
+++ b/src/game/SpellEffects.cpp
@@ -3997,7 +3997,16 @@ void Spell::EffectTriggerMissileSpell(SpellEffectIndex effect_idx)

     if (!spellInfo)
     {
-        sLog.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u",
+        // No previous Effect might have started a script
+        bool startDBScript = ScriptMgr::CanSpellEffectStartDBScript(m_spellInfo, effect_idx);
+        if (startDBScript)
+        {
+            DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell ScriptStart spellid %u in EffectTriggerMissileSpell", m_spellInfo->Id);
+            startDBScript = m_caster->GetMap()->ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
+        }
+
+        if (!startDBScript)
+            sLog.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u",
                       m_spellInfo->Id, effect_idx, triggered_spell_id);
         return;
     }

3 Add condition Creature_in_range. This was requested by @Schmoozerd in this thread: https://github.com/scriptdev2/scriptdev2/issues/93

diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp
index 74576a0..87f19f6 100755
--- a/src/game/ObjectMgr.cpp
+++ b/src/game/ObjectMgr.cpp
@@ -45,6 +45,10 @@
 #include "GossipDef.h"
 #include "Mail.h"
 #include "InstanceData.h"
+#include "Cell.h"
+#include "CellImpl.h"
+#include "GridNotifiers.h"
+#include "GridNotifiersImpl.h"

 #include <limits>

@@ -7997,6 +8001,16 @@ bool PlayerCondition::Meets(Player const* player, Map const* map, WorldObject co
                 case 3:                                     // Creature source is dead
                     return !source || source->GetTypeId() != TYPEID_UNIT || !((Unit*)source)->isAlive();
             }
+        case CONDITION_CREATURE_IN_RANGE:
+        {
+            Creature* creature = NULL;
+
+            MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck creature_check(*player, m_value1, true, false, m_value2, true);
+            MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(creature, creature_check);
+            Cell::VisitGridObjects(player, searcher, m_value2);
+
+            return creature;
+        }
         default:
             return false;
     }
@@ -8452,6 +8466,19 @@ bool PlayerCondition::IsValid(uint16 entry, ConditionType condition, uint32 valu
             }
             break;
         }
+        case CONDITION_CREATURE_IN_RANGE:
+        {
+            if (!sCreatureStorage.LookupEntry<CreatureInfo> (value1))
+            {
+                sLog.outErrorDb("Creature in range condition (entry %u, type %u) has an invalid value in value1. (Creature %u does not exist in the database), skipping.", entry, condition, value1);
+                return false;
+            }
+            if (value2 <= 0)
+            {
+                sLog.outErrorDb("Creature in range condition (entry %u, type %u) has an invalid value in value2. (Range %u must be greater than 0), skipping.", entry, condition, value2);
+                return false;
+            }
+        }
         case CONDITION_NONE:
             break;
         default:
diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h
index 34b745f..f5665da 100755
--- a/src/game/ObjectMgr.h
+++ b/src/game/ObjectMgr.h
@@ -403,6 +403,7 @@ enum ConditionType
     CONDITION_GENDER                = 35,                   // 0=male, 1=female, 2=none (see enum Gender)
     CONDITION_DEAD_OR_AWAY          = 36,                   // value1: 0=player dead, 1=player is dead (with group dead), 2=player in instance are dead, 3=creature is dead
                                                             // value2: if != 0 only consider players in range of this value
+    CONDITION_CREATURE_IN_RANGE     = 37,                   // value1: creature entry; value2: range; returns only alive creatures
 };

 enum ConditionSource                                        // From where was the condition called?

4 The last feature allows AI event sending to all units, not only to those which are able to assist. This will make interaction between not friendly units, or not selectable units more easy. Feature requested by @ulduar

diff --git a/src/game/CreatureAI.cpp b/src/game/CreatureAI.cpp
index a584092..8087c80 100644
--- a/src/game/CreatureAI.cpp
+++ b/src/game/CreatureAI.cpp
@@ -218,9 +218,18 @@ void CreatureAI::SendAIEventAround(AIEventType eventType, Unit* pInvoker, uint32
         std::list<Creature*> receiverList;

         // Use this check here to collect only assitable creatures in case of CALL_ASSISTANCE, else be less strict
-        MaNGOS::AnyAssistCreatureInRangeCheck u_check(m_creature, eventType == AI_EVENT_CALL_ASSISTANCE ? pInvoker : NULL, fRadius);
-        MaNGOS::CreatureListSearcher<MaNGOS::AnyAssistCreatureInRangeCheck> searcher(receiverList, u_check);
-        Cell::VisitGridObjects(m_creature, searcher, fRadius);
+        if (eventType == AI_EVENT_CALL_ASSISTANCE)
+        {
+            MaNGOS::AnyAssistCreatureInRangeCheck u_check(m_creature, pInvoker, fRadius);
+            MaNGOS::CreatureListSearcher<MaNGOS::AnyAssistCreatureInRangeCheck> searcher(receiverList, u_check);
+            Cell::VisitGridObjects(m_creature, searcher, fRadius);
+        }
+        else
+        {
+            MaNGOS::AnyUnitInObjectRangeCheck u_check(m_creature, fRadius);
+            MaNGOS::CreatureListSearcher<MaNGOS::AnyUnitInObjectRangeCheck> searcher(receiverList, u_check);
+            Cell::VisitGridObjects(m_creature, searcher, fRadius);
+        }

         if (!receiverList.empty())
         {

As I said in the beginning, please share your feedback on these improvements.

xfurry commented 9 years ago

I think I remember now... @Grz3s could you please share a movie of those DK area npcs. I need to see exactly how they behave in order to make this right. I think I know what needs to be done, but a video will spare some testing time on my side.

xfurry commented 9 years ago

Here is the updated version: http://paste2.org/b1xfseIB This will make everything work. Only one question remains: do we want to have the addUnitState(UNIT_STAT_IGNORE_PATHFINDING) together with the fly command or should we make it separate. Please confirm if it makes sense to have it as a separate command.

xfurry commented 9 years ago

Poke @Grz3s and @cala about the comment above. I'd like to get this implemented and closed asap.

Grz3s commented 9 years ago

hey @xfurry .. i just came back from my 2 weeks holliday..I'll look at this ASAP. about your question ... is this not the same https://github.com/cmangos/mangos-wotlk/commit/c4a46d896dcf18d5ea599888caf6c9173140811e ? BTW: what happened with Respawn command?:)

cala commented 9 years ago

I'll also look at it ASAP but I'm leaving to holidays next week, so I can't promise full testing. Regarding the flag, I have no clear opinion on the matter since no example comes to my mind. I would say that separated is better.

xfurry commented 9 years ago

what happened with Respawn command?:)

Will open a new topic about that. We might need to add some extra data_flag to target dead creatures.

Grz3s commented 9 years ago

hey @xfurry patch tested

-- TESTS for new command 40 - DESPAWN OBJECT
DELETE FROM dbscripts_on_creature_movement WHERE id = 2140904; 
INSERT INTO dbscripts_on_creature_movement (id, delay, command, datalong, datalong2, buddy_entry, search_radius, data_flags, dataint, dataint2, dataint3, dataint4, x, y, z, o, comments) VALUES
(2140904,1,28,8,0,0,0,0,0,0,0,0,0,0,0,0,'STATE_KNEEL'),
(2140904,6,0,2,0,0,0,0,2000005488,0,0,0,0,0,0,0,''),
(2140904,7,25,0,0,0,0,0,0,0,0,0,0,0,0,0,'RUN OFF'),
-- echo.TEST ON
(2140904,7,40,0,0,184798,50,7,0,0,0,0,0,0,0,0,'despawn object'),
-- echo.TEST OFF 
(2140904,8,28,0,0,0,0,0,0,0,0,0,0,0,0,0,'STATE_STAND');
 -- TESTS for new command 39 - FLY
DELETE FROM dbscripts_on_creature_movement WHERE id IN (2840602,2840603);
INSERT INTO dbscripts_on_creature_movement (id, delay, command, datalong, datalong2, buddy_entry, search_radius, data_flags, dataint, dataint2, dataint3, dataint4, x, y, z, o, comments) VALUES
(2840602,1,24,26308,0,0,0,0x08,0,0,0,0,0,0,0,0,'mount'),
-- echo.TEST ON -- levitate
(2840602,2,39,1,0,0,0,0,0,0,0,0,0,0,0,0,'fly ON'),  
(2840603,2,39,0,0,0,0,0,0,0,0,0,0,0,0,0,'fly OFF'),
-- echo.TEST OFF 
-- echo.TEST ON -- fly
-- (2840602,2,39,1,0,0,0,0x08,0,0,0,0,0,0,0,0,'ignore pathfinding ON'), 
-- (2840603,2,39,0,0,0,0,0x08,0,0,0,0,0,0,0,0,'ignore pathfinding OFF'),
-- echo.TEST OFF
(2840603,3,24,0,0,0,0,0x08,0,0,0,0,0,0,0,0,'unmount');

:+1:

xfurry commented 9 years ago

So, let me understand: we don't need that ignore pathfinding option?

Grz3s commented 9 years ago

if u'll explain what this should do..(or what will not work without it) than i can tell you.. :).. anyway as i said before ... fly worked well without using it.

xfurry commented 9 years ago

Well, technically, that flag should make the creature not use the move maps. Sometimes flying creatures have issues on this. I will run a few tests myself first, before pushing this.

xfurry commented 9 years ago

@Grz3s here is a proposal for respawn command: http://paste2.org/GFZ9jJOt Here is the updated version of previous patch: http://paste2.org/tmxJ93hK

Schmoozerd commented 9 years ago

Hi guys :) I just stumbled about this topic and naturally i read it ;)

@xfurry nice patches, please add a little bit more documentation to hte SEND_AI_EVENT command (to be clear to the user about sender, invoker and receiver)

For the second patch, i have one concern: be sure the database fields for the data_flags are big enough for 0x80-1

xfurry commented 9 years ago

Hi @Schmoozerd I will check the DB field. Still waiting for the final sign off from @Grz3s

Since you are here, maybe you would also have some thoughts on https://github.com/cmangos/issues/issues/260 :grin:

Grz3s commented 9 years ago

I thought that i explained all on irc.. Not much to say here: all new commands work on tests that i showed you. even updated ver. for respawn (one that u gave me on irc) -- so even despawned buddys can be respawned

BTW: script_commands.txt should contain some info about:

40 SCRIPT_COMMAND_DESPAWN_GO -- cannot be used on gobjects Type=1 buttons ...(command doesnt work on them - they shouldnt despawn at all - and thats correct ;)

41 SCRIPT_COMMAND_RESPAWN_SELF: (your second patch - not above one)

cala commented 9 years ago

@xfurry : I tested your latest patch this evening. Both FLY and DESPAWN GO commands are working very well (tested on WotLK core), as said Grz3s. Very good job. :+1:

ghost commented 9 years ago

Why closed? Although already unimportant