Skip to content

Core/Scripting: Initial support for AIGroup - #32024

Draft
offl wants to merge 31 commits into
TrinityCore:3.3.5from
offl:AIGroup
Draft

offl wants to merge 31 commits into
TrinityCore:3.3.5from
offl:AIGroup

Conversation

@offl

@offl offl commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Changes proposed:

This is initial support for AIGroup. Credit for providing a lot of info goes to xvwyh, he is also the author of PerformEmote function.

Why not SAI? SAI and any other existing DB or C++ scripting system is not how this game was created, AIGroup is. It was used since Alpha to current days. I'm in doubts that SAI can be updated step-by-step to behave like AIGroup. Scripts cannot be converted from SAI to AIGroup using a tool, like it was with EAI to SAI conversion.
However my AIGroup is partially based on SAI because of my poor C++ knowledge. This is not and this will be not a 100% copy of Blizz's AIGroup since our scripting engine is different, it simply doesn't allow to use it the way Blizz uses it, we also simply don't have systems to support AIGroup the way it is handled in retail. It is named AIGroup for a reason. Blizz scripts groups of creatures. And currently we don't have correct spawn groups implementation.
When I said it will be not a 100% copy, I meant that we simply don't want to use it the way Blizz does. AIGroup is quite tricky. It has its own limitations. For example actions without StringId autotargets invoker of action set and that cannot be changed. I plan to use it the same way but keep the possibility to use old target types as fallback option. We simply don't have enough data to use it the way Blizz uses it, for example we don't have all serverside spells and in majority of cases we don't know how existing ones are used. So, let's say it's something between SAI and AIGroup. Also I'm aware that in master spells can start action sets, also AIGroup is defined as object and in sniffs we can see packets with AIGroup. Not sure if current implementation can use any of it, probably not or not in all cases.

Comparing to SAI, there are a lot of fundamental changes:

  1. Now we update AI even if creature is dead. This allows to execute sets of actions using timers, now we can script at least one case where creature uses action set with timers after death
  2. Now we have original action set flags, such as Looping. More will be implemented
  3. Now we can run multiple action sets using original priority. Creature will temporarily stop performing action set with lower priority and start action set with higher priority
  4. Action triggers system. Now we have posibility to change base script during runtime. We also can assign same base script to multiple creatures. I guess this should fully replace phases system. Blizz doesn't use phases, there's no functionality to set phase, instead they change base script
  5. Currently NYI random action set system. It's a table with multiple action sets with possibility to add probability to action sets. No more limited SAI's Run Random Script action. No more limited actions with only 5 params to play random emote or random sound

I have to aware you that I used a lot of AI since I'm not good at C++. Well, implementation of some things can be changed.
Right now I don't know where this will lead us, will it be used or not. This system is incomplete and a lot of things are missing before it can be used. Right now it can contain everything, crashes, memory leaks, some things may be too expensive, many things are missing and also there are bugs I'm aware of and there are bugs I will need to discover. Some things may be sloppy. Some things are temporary. Also I constantly change implementation of some things because I don't have some kind of roadmap in my head, only understandings how this thing should be handled in general and how some parts of it should be handled.

Some basic testing examples I used.

UPDATE `creature_template` SET `AIName` = 'AIGroup', `TriggersId` = 12800 WHERE `entry` = 128;

DELETE FROM `action_triggers_name` WHERE `Id` IN (12800,12801);
INSERT INTO `action_triggers_name` (`Id`,`Name`) VALUES
(12800,"Angry Programmer Tweedle Dee - Test"),
(12801,"Angry Programmer Tweedle Dee - Test 2");

DELETE FROM `action_triggers` WHERE `Id` IN (12800,12801);
INSERT INTO `action_triggers` (`Id`,`Index`,`Chance`,`Flags`,`CombatCondition`,`TriggerId`,`TriggerParam1`,`TriggerParam2`,`ActionSetId`,`RepeatMin`,`RepeatMax`,`Comment`) VALUES
(12800,0,100,2,-1,7,0,0,3,0,0,"Angry Programmer Tweedle Dee - OnDeath"),
(12800,1,100,2,-1,8,33373,0,1,5000,5000,"Angry Programmer Tweedle Dee - OnSpell"),
(12800,2,100,2,-1,11,17,0,2,5000,5000,"Angry Programmer Tweedle Dee - OnEmote"); -- /bow

DELETE FROM `action_set_name` WHERE `Id` IN (1,2,3);
INSERT INTO `action_set_name` (`Id`,`Flags`,`Priority`,`Name`) VALUES
(1,2,4,"Angry Programmer's Set - Id 1 - High Priority"),
(2,2,3,"Angry Programmer's Set - Id 2 - MidToHigh Priority"),
(3,2,4,"Angry Programmer's Set - Id 3 - High Priority");

DELETE FROM `action_set` WHERE `Id` IN (1,2,3);
INSERT INTO `action_set` (`Id`,`Index`,`Type`,`Unit`,`Point`,`Path`,`TimeA`,`MoveSpeed`,`StringId`,`TimeB`,`LinearPath`,`CircularPath`,`FlightPath`,`Extra0`,`Extra1`,`Extra2`,`Extra3`,`Extra4`,`TargetType`,`TargetParam1`,`TargetParam2`,`TargetParam3`,`TargetParam4`,`Comment`) VALUES
(1,0,1,0,0,0,5000,0,'',5000,0,0,0,0,0,0,0,0,0,0,0,0,0,"Idle"),
(1,1,44,0,0,0,0,0,'',0,0,0,0,0,0,29259,0,0,0,0,0,0,0,"Unit(s) yell something"),
(1,2,1,0,0,0,5000,0,'',5000,0,0,0,0,0,0,0,0,0,0,0,0,0,"Idle"),
(1,3,44,0,0,0,0,0,'',0,0,0,0,0,0,29260,0,0,0,0,0,0,0,"Unit(s) yell something"),
(1,4,1,0,0,0,5000,0,'',5000,0,0,0,0,0,0,0,0,0,0,0,0,0,"Idle"),
(1,5,44,0,0,0,0,0,'',0,0,0,0,0,0,29261,0,0,0,0,0,0,0,"Unit(s) yell something"),

(2,0,1,0,0,0,5000,0,'',5000,0,0,0,0,0,0,0,0,0,0,0,0,0,"Idle"),
(2,1,15,0,0,0,0,0,'',0,0,0,0,0,0,56158,0,0,0,0,0,0,0,"Unit(s) say something"),
(2,2,1,0,0,0,5000,0,'',5000,0,0,0,0,0,0,0,0,0,0,0,0,0,"Idle"),
(2,3,15,0,0,0,0,0,'',0,0,0,0,0,0,56159,0,0,0,0,0,0,0,"Unit(s) say something"),
(2,4,4,0,0,0,10000,0,'',0,0,0,0,0,10,0,0,0,0,0,0,0,0,"Wander"),

(3,0,48,0,0,0,0,0,'',0,0,0,0,0,0,18836,0,0,0,0,0,0,0,"Unit(s) chat emote something"),
(3,1,48,0,0,0,0,0,'',0,0,0,0,0,0,18836,0,0,0,0,0,0,0,"Unit(s) chat emote something"),
(3,2,48,0,0,0,0,0,'',0,0,0,0,0,0,18836,0,0,0,0,0,0,0,"Unit(s) chat emote something"),
(3,3,48,0,0,0,0,0,'',0,0,0,0,0,0,18836,0,0,0,0,0,0,0,"Unit(s) chat emote something"),
(3,4,48,0,0,0,0,0,'',0,0,0,0,0,0,18836,0,0,0,0,0,0,0,"Unit(s) chat emote something"),
(3,5,1,0,0,0,5000,0,'',5000,0,0,0,0,0,0,0,0,0,0,0,0,0,"Idle"),
(3,6,48,0,0,0,0,0,'',0,0,0,0,0,0,18836,0,0,0,0,0,0,0,"Unit(s) chat emote something");

I managed to script this escort. As you can see, we no longer use creature_text. Prior to 3.3.0 emotes and sounds linked to texts were handled manually using scripts. In 3.3.0 and later patches emotes and sounds are handled in broadcast_text. We can argue what is better but for my experience creature_text is pain in many cases. For example when you need to script creature with tens texts and each has its own sound and emote. However the way it is done on retail prior to 3.3.0 is not great too in specific cases. Any way, I think this particular case looks much better without creature_text.
This script is two times bigger than SAI script because we handle emotes inside script and because of Idle action. But now we have just one action set instead of multiple. Also we have now one base script with one event.
Unfortunately sometimes creature doesn't play Talk emote, I tried with SAI and it looks almost the same. Maybe better.

--
DELETE FROM `creature_text` WHERE `CreatureID` = 20129;

DELETE FROM `smart_scripts` WHERE `entryorguid` = 20129 AND `source_type` = 0;
DELETE FROM `smart_scripts` WHERE `entryorguid` BETWEEN 2012900 AND 2012906 AND `source_type` = 9;

UPDATE `creature_template` SET `AIName` = 'AIGroup', `TriggersId` = 2012900 WHERE `entry` = 20129;

DELETE FROM `action_triggers_name` WHERE `Id` = 2012900;
INSERT INTO `action_triggers_name` (`Id`,`Name`) VALUES
(2012900,"Tanaris - Custodian of Time");

DELETE FROM `action_triggers` WHERE `Id` = 2012900;
INSERT INTO `action_triggers` (`Id`,`Index`,`Chance`,`Flags`,`CombatCondition`,`TriggerId`,`TriggerParam1`,`TriggerParam2`,`ActionSetId`,`RepeatMin`,`RepeatMax`,`Comment`) VALUES
(2012900,0,100,0,-1,10,0,0,2012900,0,0,"Custodian of Time - OnSpawn");

DELETE FROM `action_set_name` WHERE `Id` = 2012900;
INSERT INTO `action_set_name` (`Id`,`Flags`,`Priority`,`Name`) VALUES
(2012900,0,5,"Custodian of Time - Escort - Medium Priority");

DELETE FROM `action_set` WHERE `Id` = 2012900;
INSERT INTO `action_set` (`Id`,`Index`,`Type`,`Unit`,`Point`,`Path`,`TimeA`,`MoveSpeed`,`StringId`,`TimeB`,`LinearPath`,`CircularPath`,`FlightPath`,`Extra0`,`Extra1`,`Extra2`,`Extra3`,`Extra4`,`TargetType`,`TargetParam1`,`TargetParam2`,`TargetParam3`,`TargetParam4`,`Comment`) VALUES
(2012900,0,0,0,0,0,0,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Spawn"),
(2012900,1,23,1,0,0,0,0,'',0,0,0,0,0,0,0,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) face a unit or game object or point"),
(2012900,2,16,1,0,0,0,0,'',0,0,0,0,0,0,17321,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) cast a spell - 'Spirit Spawn-in'"),
(2012900,3,1,0,0,0,2000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,4,24,1,0,0,0,0,'',0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 1"),
(2012900,5,95,1,0,0,0,0,'',0,0,0,0,0,0,17656,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17656"),
(2012900,6,1,0,0,0,10000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,7,24,1,0,0,0,0,'',0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 1"),
(2012900,8,95,1,0,0,0,0,'',0,0,0,0,0,0,17657,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17657"),
(2012900,9,1,0,0,0,15000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,10,24,1,0,0,0,0,'',0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 1"),
(2012900,11,95,1,0,0,0,0,'',0,0,0,0,0,0,17658,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17658"),
(2012900,12,1,0,0,0,11000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,13,24,1,0,0,0,0,'',0,0,0,0,0,0,273,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 273"),
(2012900,14,95,1,0,0,0,0,'',0,0,0,0,0,0,17668,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17668"),
(2012900,15,1,0,0,0,2000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,16,8,0,0,16103201,0,0,'',0,1,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Follow a path - 16103201"),
(2012900,17,1,0,0,0,2000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,18,23,1,0,0,0,0,'',0,0,0,0,0,0,0,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) face a unit or game object or point"),
(2012900,19,1,0,0,0,1000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,20,24,1,0,0,0,0,'',0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 1"),
(2012900,21,95,1,0,0,0,0,'',0,0,0,0,0,0,17667,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17667"),
(2012900,22,1,0,0,0,10000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,23,24,1,0,0,0,0,'',0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 1"),
(2012900,24,95,1,0,0,0,0,'',0,0,0,0,0,0,17659,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17659"),
(2012900,25,1,0,0,0,15000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,26,24,1,0,0,0,0,'',0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 1"),
(2012900,27,95,1,0,0,0,0,'',0,0,0,0,0,0,17660,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17660"),
(2012900,28,1,0,0,0,10000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,29,22,1,0,0,0,0,'',0,0,0,0,0,0,1.46607,0,0,0,0,0,0,0,"Custodian of Time - Unit(s) face a particular angle"),
(2012900,30,1,0,0,0,1000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,31,24,1,0,0,0,0,'',0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 1"),
(2012900,32,95,1,0,0,0,0,'',0,0,0,0,0,0,17661,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17661"),
(2012900,33,1,0,0,0,6000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,34,24,1,0,0,0,0,'',0,0,0,0,0,0,25,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 25"),
(2012900,35,1,0,0,0,12000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,36,24,1,0,0,0,0,'',0,0,0,0,0,0,25,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 25"),
(2012900,37,95,1,0,0,0,0,'',0,0,0,0,0,0,17663,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17663"),
(2012900,38,1,0,0,0,7000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,39,23,1,0,0,0,0,'',0,0,0,0,0,0,0,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) face a unit or game object or point"),
(2012900,40,1,0,0,0,1000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,41,24,1,0,0,0,0,'',0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 1"),
(2012900,42,1,0,0,0,14000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,43,24,1,0,0,0,0,'',0,0,0,0,0,0,273,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 273"),
(2012900,44,95,1,0,0,0,0,'',0,0,0,0,0,0,17668,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17668"),
(2012900,45,1,0,0,0,6000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,46,8,0,0,16103209,0,0,'',0,1,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Follow a path - 16103209"),
(2012900,47,22,1,0,0,0,0,'',0,0,0,0,0,0,2.58308,0,0,0,0,0,0,0,"Custodian of Time - Unit(s) face a particular angle"),
(2012900,48,1,0,0,0,2000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,49,24,1,0,0,0,0,'',0,0,0,0,0,0,25,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 25"),
(2012900,50,1,0,0,0,2000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,51,23,1,0,0,0,0,'',0,0,0,0,0,0,0,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) face a unit or game object or point"),
(2012900,52,1,0,0,0,1000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,53,24,1,0,0,0,0,'',0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 1"),
(2012900,54,95,1,0,0,0,0,'',0,0,0,0,0,0,17664,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17664"),
(2012900,55,1,0,0,0,10000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,56,24,1,0,0,0,0,'',0,0,0,0,0,0,273,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 273"),
(2012900,57,95,1,0,0,0,0,'',0,0,0,0,0,0,17668,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17668"),
(2012900,58,1,0,0,0,6000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,59,8,0,0,16103217,0,0,'',0,1,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Follow a path - 16103217"),
(2012900,60,22,1,0,0,0,0,'',0,0,0,0,0,0,3.92699,0,0,0,0,0,0,0,"Custodian of Time - Unit(s) face a particular angle"),
(2012900,61,1,0,0,0,1000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,62,24,1,0,0,0,0,'',0,0,0,0,0,0,25,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 25"),
(2012900,63,95,1,0,0,0,0,'',0,0,0,0,0,0,17669,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17669"),
(2012900,64,1,0,0,0,3000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,65,24,1,0,0,0,0,'',0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 1"),
(2012900,66,1,0,0,0,6000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,67,8,0,0,16103225,0,0,'',0,1,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Follow a path - 16103225"),
(2012900,68,1,0,0,0,1000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,69,23,1,0,0,0,0,'',0,0,0,0,0,0,0,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) face a unit or game object or point"),
(2012900,70,1,0,0,0,2000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,71,24,1,0,0,0,0,'',0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 1"),
(2012900,72,95,1,0,0,0,0,'',0,0,0,0,0,0,17662,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17662"),
(2012900,73,1,0,0,0,20000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,74,24,1,0,0,0,0,'',0,0,0,0,0,0,273,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 273"),
(2012900,75,95,1,0,0,0,0,'',0,0,0,0,0,0,17668,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17668"),
(2012900,76,1,0,0,0,6000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,77,8,0,0,16103233,0,0,'',0,1,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Follow a path - 16103233"),
(2012900,78,22,1,0,0,0,0,'',0,0,0,0,0,0,0.19198,0,0,0,0,0,0,0,"Custodian of Time - Unit(s) face a particular angle"),
(2012900,79,1,0,0,0,1000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,80,24,1,0,0,0,0,'',0,0,0,0,0,0,25,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 25"),
(2012900,81,95,1,0,0,0,0,'',0,0,0,0,0,0,17665,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17665"),
(2012900,82,1,0,0,0,10000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,83,24,1,0,0,0,0,'',0,0,0,0,0,0,273,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 273"),
(2012900,84,95,1,0,0,0,0,'',0,0,0,0,0,0,17668,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17668"),
(2012900,85,1,0,0,0,6000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,86,8,0,0,16103241,0,0,'',0,1,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Follow a path - 16103241"),
(2012900,87,1,0,0,0,1000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,88,23,1,0,0,0,0,'',0,0,0,0,0,0,0,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) face a unit or game object or point"),
(2012900,89,1,0,0,0,1000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,90,24,1,0,0,0,0,'',0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Custodian of Time - Perform an emote - 1"),
(2012900,91,95,1,0,0,0,0,'',0,0,0,0,0,0,17666,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) whisper to a player - 17666"),
(2012900,92,16,1,0,0,0,0,'',0,0,0,0,0,0,34883,0,0,23,0,0,0,0,"Custodian of Time - Unit(s) cast a spell - 'QID 10277'"),
(2012900,93,1,0,0,0,6000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Idle"),
(2012900,94,19,0,0,0,0,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Custodian of Time - Despawn");

Issues addressed:

none

Tests performed:

in progress

@Nyr97

Nyr97 commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Though I like this for many reasons, and so far, it's a great implementation to start with, AIGroup is more than a script type registered as a CreatureAI factory. It's an entity, with its own object type, its own ObjectGuid and its own mirror class, like any other spawnable entity (Unit, GameObject, AreaTrigger...). Units carry their own spawnGroupID, tied to spawn events and trigger action sets. To stay close to retail this should be a standalone class that is spawnable and can control several entities at once.

@offl

offl commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

I know. Not sure if I have enough experience to implement it this way. As I said, it's something in between AIGroup and SAI. Also I want to keep this PR relatively small to make it reviewable. Also right now I have no idea how to implement some basic things and how to script some already existing scripts with this system. If I will not resolve these problems, quite possible it will be abandoned and if so, I prefer to abandon it without investing months on it

@offl

offl commented Sep 27, 2026

Copy link
Copy Markdown
Contributor Author

Random action sets are now implemented. The problem is I don't know how exactly they should be started. Currently they are started using same method and same container as regular action sets, meaning in order to make random action set run inside a big action set, priority of random action set should be greater than priority of main action set. Otherwise action set will be started only when main action set is finished.

I think random action sets are used for every boss with random on death and on kill emotes. Otherwise I can't imagine how that is scripted, I don't see the other way. For each random text with sound we need to add sound and text actions to one set, then add that set to random set. After 3.3.0 it is way much easier - we just need broadcast texts, add them to single npc_text, then call random say\yell with that npc_text as action param.
Quite possible random action sets use High priority type. But that would mean every other action set boss performs should have priority lower than High in order to always sucessfuly perform emote after killing player. In theory that is possible if we use Medium priority for everything else. But I think that is a big limitation. Maybe we should ignore priority completely while performing random action sets...

There are actions Perform actionset and Push Actionset. I believe Perform actionset is the oldest method, it allows to run action set inside action set that was also called by action triggers, using same method. But there is also Push Actionset action, what it does is unknown.

--
UPDATE `creature_template` SET `AIName` = 'AIGroup', `TriggersId` = 12900 WHERE `entry` = 129;

DELETE FROM `action_triggers_name` WHERE `Id` IN (12900);
INSERT INTO `action_triggers_name` (`Id`,`Name`) VALUES
(12900,"Angry Programmer Tweedle Dum - Test");

DELETE FROM `action_triggers` WHERE `Id` IN (12900);
INSERT INTO `action_triggers` (`Id`,`Index`,`Chance`,`Flags`,`CombatCondition`,`TriggerId`,`TriggerParam1`,`TriggerParam2`,`ActionSetId`,`RepeatMin`,`RepeatMax`,`Comment`) VALUES
(12900,0,100,0,-1,10,0,0,105,0,0,"Angry Programmer Tweedle Dum - OnSpawn");

DELETE FROM `action_set_name` WHERE `Id` IN (100,101,102,103,104,105);
INSERT INTO `action_set_name` (`Id`,`Flags`,`Priority`,`Name`) VALUES
(100,2,1,"Angry Programmer Tweedle Dum - Id 1 - Low Priority"),
(101,2,1,"Angry Programmer Tweedle Dum - Id 2 - Low Priority"),
(102,2,1,"Angry Programmer Tweedle Dum - Id 3 - Low Priority"),
(103,2,1,"Angry Programmer Tweedle Dum - Id 4 - Low Priority"),
(104,2,1,"Angry Programmer Tweedle Dum - Id 5 - Low Priority"),
(105,2,5,"Angry Programmer Tweedle Dum - Id 6 - Medium Priority");

DELETE FROM `action_set` WHERE `Id` IN (100,101,102,103,104,105);
INSERT INTO `action_set` (`Id`,`Index`,`Type`,`Unit`,`Point`,`Path`,`TimeA`,`MoveSpeed`,`StringId`,`TimeB`,`LinearPath`,`CircularPath`,`FlightPath`,`Extra0`,`Extra1`,`Extra2`,`Extra3`,`Extra4`,`TargetType`,`TargetParam1`,`TargetParam2`,`TargetParam3`,`TargetParam4`,`Comment`) VALUES
(100,0,16,1,0,0,0,0,'',0,0,0,0,0,0,34703,0,0,0,0,0,0,0,"Unit(s) cast a spell"),
(101,0,16,1,0,0,0,0,'',0,0,0,0,0,0,34704,0,0,0,0,0,0,0,"Unit(s) cast a spell"),
(102,0,16,1,0,0,0,0,'',0,0,0,0,0,0,34705,0,0,0,0,0,0,0,"Unit(s) cast a spell"),
(103,0,16,1,0,0,0,0,'',0,0,0,0,0,0,34707,0,0,0,0,0,0,0,"Unit(s) cast a spell"),
(104,0,16,1,0,0,0,0,'',0,0,0,0,0,0,34710,0,0,0,0,0,0,0,"Unit(s) cast a spell"),

(105,0,1,0,0,0,5000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Idle"),
(105,1,124,0,0,0,0,0,'',0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Perform a random set of actions"),
(105,2,1,0,0,0,5000,0,'',0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Idle");

DELETE FROM `random_action_set` WHERE `Id` IN (1);
INSERT INTO `random_action_set` (`Id`,`Index`,`Probability`,`ActionSetId`) VALUES
(1,0,1,100),
(1,1,1,101),
(1,2,1,102),
(1,3,1,103),
(1,4,1,104);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants