Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Formation #1

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
49dc096
Formation code for spawngroup
cyberium Dec 20, 2021
1d2e4b6
Improve waypoint movegen
cyberium Dec 20, 2021
916a121
Some improvement to formation
cyberium Dec 23, 2021
50d04ab
Enforce movement_template table for spawngroupÃ
cyberium Dec 23, 2021
53e9a80
Change script command to group target instead of formation
cyberium Dec 23, 2021
2dc7e33
Add possibility to assign dynamically a formation to a creature group
cyberium Dec 24, 2021
93ee4ad
Fix a little mistake npc formation switch command error message
cyberium Dec 24, 2021
0914fb7
Improve a bit the npc formation info command
cyberium Dec 24, 2021
b3a9b86
Removing some unneeded ingame command
cyberium Dec 24, 2021
5ccfc7a
Some more cleaning to formation code
cyberium Dec 24, 2021
1858c31
Set keep compact option from formation entry
cyberium Dec 24, 2021
b95981b
Temp hack to fix movetype for static group formation
cyberium Dec 25, 2021
89a2ed5
Merge FormationData constructors
cyberium Dec 25, 2021
4adab4d
remove duplicate code in FormationMovementGenerator::Update
cyberium Dec 25, 2021
2f1930e
Add change spread and change option script command
cyberium Dec 26, 2021
8c8bb06
some code style
cyberium Dec 26, 2021
10d2067
Use better method to get best position for followers
cyberium Dec 28, 2021
ebc7e0d
Implement followers check to master distance
cyberium Dec 28, 2021
3148be1
Fix movement type for formation in db
cyberium Jan 3, 2022
c489723
Prepare for release
cyberium Jan 3, 2022
5c5126b
Prepare SCRIPT_COMMAND_SPAWN_GROUP(51) for release
cyberium Jan 3, 2022
803a198
[s2439] Add Formation sql
cyberium Jan 3, 2022
3db02e9
Last fixes for release
cyberium Jan 3, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions doc/script_commands.txt
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ Defining a buddy could be done in several way:
* datalong3 = enum ForcedMovement
* data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL: teleport unit to position
* x/y/z/o
* dataint = 1 to init move to respawn position, 2 to init creature group member each in their respawn position.
no other data is needed. So ex: command 3 ... dataint=1 and creature should head to its respawn pos

4 SCRIPT_COMMAND_FLAG_SET source = any
* datalong = field_id
Expand Down Expand Up @@ -397,3 +399,15 @@ Defining a buddy could be done in several way:

50 SCRIPT_COMMAND_ZONE_PULSE Pulses zone for combat and attacks closest enemy

51 SCRIPT_COMMAND_SPAWN_GROUP Set of commands for creature spawn group
* datalong = command
only formation command(staring from 100) supported right now
- 100: switch formation shape.
datalong1 should have shape value
Random(0), Queue(1), Side bu side(2), Geese(3), Fanned out behind(4), Fanned out in front(5), Circle leader(6)
- 101: Set formation spread
Spread is set in x field as we need a float for it
- 102: Set formation options
Set flag 0x1 for keep compact option (after a member death)
Set flag 0x2 for disabling pathfinding (not impemented yet)

2 changes: 1 addition & 1 deletion sql/base/mangos.sql
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ DROP TABLE IF EXISTS `db_version`;
CREATE TABLE `db_version` (
`version` varchar(120) DEFAULT NULL,
`creature_ai_version` varchar(120) DEFAULT NULL,
`required_s2438_01_mangos_spawn_groups` bit(1) DEFAULT NULL
`required_s2439_01_mangos_groups_formation` bit(1) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Used DB version notes';

--
Expand Down
30 changes: 30 additions & 0 deletions sql/updates/mangos/s2439_01_mangos_groups_formation.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
ALTER TABLE db_version CHANGE COLUMN required_s2438_01_mangos_spawn_groups required_s2439_01_mangos_groups_formation bit;

ALTER TABLE `spawn_group_spawn` ADD COLUMN `SlotId` tinyint(4) NOT NULL DEFAULT -1 COMMENT '0 is the leader, -1 not part of the formation' AFTER `Guid`;

DROP TABLE IF EXISTS `spawn_group_formation`;
CREATE TABLE `spawn_group_formation` (
`SpawnGroupID` int(11) NOT NULL COMMENT 'Spawn group id',
`FormationType` tinyint(11) NOT NULL DEFAULT 0 COMMENT 'Formation shape 0..6',
`FormationSpread` float(11, 0) NOT NULL DEFAULT 0 COMMENT 'Distance between formation members',
`FormationOptions` int(11) NOT NULL DEFAULT 0 COMMENT 'Keep formation compact (bit 1)',
`MovementID` int(11) NOT NULL DEFAULT 0 COMMENT 'Id from waypoint_path path',
`MovementType` tinyint(11) NOT NULL COMMENT 'Same as creature table',
`Comment` varchar(255) NULL DEFAULT NULL,
PRIMARY KEY (`SpawnGroupID`)
);

DROP TABLE IF EXISTS `waypoint_path`;
CREATE TABLE `waypoint_path` (
`entry` mediumint(8) UNSIGNED NOT NULL COMMENT 'Creature entry',
`pathId` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Path ID for entry',
`point` mediumint(8) UNSIGNED NOT NULL DEFAULT 0,
`position_x` float NOT NULL DEFAULT 0,
`position_y` float NOT NULL DEFAULT 0,
`position_z` float NOT NULL DEFAULT 0,
`orientation` float NOT NULL DEFAULT 0,
`waittime` int(10) UNSIGNED NOT NULL DEFAULT 0,
`script_id` mediumint(8) UNSIGNED NOT NULL DEFAULT 0,
`comment` text NULL DEFAULT NULL,
PRIMARY KEY (`entry`, `pathId`, `point`)
);
16 changes: 14 additions & 2 deletions src/game/AI/PlayerAI/PlayerAI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,27 @@ void PlayerAI::ExecuteSpells()

void PlayerAI::JustGotCharmed(Unit* charmer)
{
m_player->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE, true);
if (charmer->GetFormationSlot())
{
charmer->GetFormationSlot()->GetFormationData()->Add(m_player);
}
else
m_player->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE, true);
AttackClosestEnemy();
}

void PlayerAI::EnterEvadeMode()
{
m_player->CombatStopWithPets(true);
if (Unit* charmer = m_player->GetCharmer())
m_player->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE, true);
{
if (charmer->GetFormationSlot())
{
charmer->GetFormationSlot()->GetFormationData()->Add(m_player);
}
else
m_player->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE, true);
Copy link

@killerwife killerwife Dec 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there is multiple of these, maybe handle it in MoveFollow? Player based quasi formation also needs the same logic, when you lets say have army of the dead in wotlk or multiple guardians and hunter pet, they should all dynamically calculate angle.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well first at this stage formation is a sub option for creaturegroup meaning that formation need a creature group absolutly and its designed only for creature as leader.
Thus some big change have to be done to be able to make a player as a master and more to have some other kind of group that will be attached to player.

Secondly you are asking for more than just adding it as exception of the movefollow we had a discussion about it with tobi and it seem that movefollow should even been replaced by some 'move in formation' with position computed depending of the player's followers.

}
}

void PlayerAI::AttackClosestEnemy()
Expand Down
24 changes: 24 additions & 0 deletions src/game/Chat/Chat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,28 @@ ChatCommand* ChatHandler::getCommandTable()
{ nullptr, 0, false, nullptr, "", nullptr }
};

static ChatCommand npcFormationCommandTable[] =
{
{ "info", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFormationInfoCommand, "", nullptr },
{ "reset", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFormationResetCommand, "", nullptr },
{ "switch", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFormationSwitchCommand, "", nullptr },
{ nullptr, 0, false, nullptr, "", nullptr }
};

// static ChatCommand npcGroupBehaviorCommandTable[] =
// {
// { "show", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcGroupBehaviorShowCommand, "", nullptr },
// { "set", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcGroupBehaviorSetCommand, "", nullptr },
// { nullptr, 0, false, nullptr, "", nullptr }
// };

static ChatCommand npcGroupCommandTable[] =
{
{ "info", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcGroupInfoCommand, "", nullptr },
//{ "behavior", SEC_GAMEMASTER, false, nullptr, "", npcGroupBehaviorCommandTable },
{ nullptr, 0, false, nullptr, "", nullptr }
};

static ChatCommand npcCommandTable[] =
{
{ "add", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddCommand, "", nullptr },
Expand Down Expand Up @@ -518,6 +540,8 @@ ChatCommand* ChatHandler::getCommandTable()
{ "showloot", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcShowLootCommand, "", nullptr },
{ "tempspawn", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcTempSpawn, "", nullptr },
{ "evade", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcEvade, "", nullptr },
{ "formation", SEC_GAMEMASTER, false, nullptr, "", npcFormationCommandTable },
{ "group", SEC_GAMEMASTER, false, nullptr, "", npcGroupCommandTable },

//{ TODO: fix or remove this commands
{ "addweapon", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcAddWeaponCommand, "", nullptr },
Expand Down
6 changes: 6 additions & 0 deletions src/game/Chat/Chat.h
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,12 @@ class ChatHandler
bool HandleNpcYellCommand(char* args);
bool HandleNpcTempSpawn(char* args);
bool HandleNpcEvade(char* args);
bool HandleNpcGroupInfoCommand(char* args);
//bool HandleNpcGroupBehaviorShowCommand(char* args);
//bool HandleNpcGroupBehaviorSetCommand(char* args);
bool HandleNpcFormationInfoCommand(char* args);
bool HandleNpcFormationResetCommand(char* args);
bool HandleNpcFormationSwitchCommand(char* args);

// TODO: NpcCommands that needs to be fixed :
bool HandleNpcAddWeaponCommand(char* args);
Expand Down
159 changes: 159 additions & 0 deletions src/game/Chat/Level2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2317,6 +2317,165 @@ bool ChatHandler::HandleNpcShowLootCommand(char* /*args*/)
return true;
}

// show detailed information of creature formation if exist
bool ChatHandler::HandleNpcGroupInfoCommand(char* /*args*/)
{
Creature* creature = getSelectedCreature();

if (!creature)
{
SendSysMessage(LANG_SELECT_CREATURE);
SetSentErrorMessage(true);
return false;
}

auto gData = creature->GetCreatureGroup();
if (!gData)
{
SendSysMessage("Creature is not in group");
return true;
}

PSendSysMessage("Group id[%u]", gData->GetGroupId());
PSendSysMessage("Group name: %s", gData->GetGroupEntry().Name.c_str());

Unit* master = nullptr;
if (gData->GetFormationData())
master = gData->GetFormationData()->GetMaster();

if (master)
{
if (master == creature)
SendSysMessage("Creature is formation leader");
else if (creature->GetFormationSlot())
SendSysMessage("Creature is in formation slot");
else
SendSysMessage("Error: unable to retrieve the slot of the creature.");
}

PSendSysMessage("%s", gData->to_string().c_str());
return true;
}

// show detailed information of group behavior
// bool ChatHandler::HandleNpcGroupBehaviorShowCommand(char* /*args*/)
// {
// Creature* creature = getSelectedCreature();
//
// if (!creature)
// {
// SendSysMessage(LANG_SELECT_CREATURE);
// SetSentErrorMessage(true);
// return false;
// }
//
//
// return true;
// }

// set behavior of targeted group
// bool ChatHandler::HandleNpcGroupBehaviorSetCommand(char* args)
// {
// Creature* creature = getSelectedCreature();
//
// if (!creature)
// {
// SendSysMessage(LANG_SELECT_CREATURE);
// SetSentErrorMessage(true);
// return false;
// }
//
// return true;
// }

// reset creature formation template
bool ChatHandler::HandleNpcFormationInfoCommand(char* /*args*/)
{
Creature* creature = getSelectedCreature();

if (!creature)
{
SendSysMessage(LANG_SELECT_CREATURE);
SetSentErrorMessage(true);
return false;
}

auto currSlot = creature->GetFormationSlot();
if (!currSlot)
{
SendSysMessage("Creature is not in formation");
return true;
}

PSendSysMessage("%s", currSlot->GetFormationData()->to_string().c_str());
return true;
}

// reset creature formation template
bool ChatHandler::HandleNpcFormationResetCommand(char* /*args*/)
{
Creature* creature = getSelectedCreature();

if (!creature)
{
SendSysMessage(LANG_SELECT_CREATURE);
SetSentErrorMessage(true);
return false;
}

auto currSlot = creature->GetFormationSlot();
if (!currSlot)
{
SendSysMessage("Creature is not in formation");
return true;
}

currSlot->GetFormationData()->Reset();

// need implementation
SendSysMessage("Formation is reset to default!");
return true;
}

// change creature formation template
bool ChatHandler::HandleNpcFormationSwitchCommand(char* args)
{
Creature* creature = getSelectedCreature();

if (!creature)
{
SendSysMessage(LANG_SELECT_CREATURE);
SetSentErrorMessage(true);
return false;
}

auto currSlot = creature->GetFormationSlot();
if (!currSlot)
{
SendSysMessage("Creature is not in formation");
return true;
}

uint32 formationId;
if (!ExtractUInt32(&args, formationId))
{
PSendSysMessage("Please provide a valid formation id!\n.npc formation switch #formationId");
return false;
}

if (formationId >= static_cast<uint32>(SpawnGroupFormationType::SPAWN_GROUP_FORMATION_TYPE_COUNT))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

primitives are best typecasted as c-style cast, since they arent really heresy. Curious choice of enum class, shauren loves them, buuuut historically in cmangos they seem out of place. Not really opposed to it tho.

{
PSendSysMessage("Formation shape id should be in 0..%u range!", static_cast<uint32>(SpawnGroupFormationType::SPAWN_GROUP_FORMATION_TYPE_COUNT) - 1);
return true;
}

if (!currSlot->GetFormationData()->SwitchFormation(static_cast<SpawnGroupFormationType>(formationId)))
PSendSysMessage("Failed to switch formation template!");
else
SendSysMessage("Formation shape changed.");
return true;
}

// TODO: NpcCommands that need to be fixed :

bool ChatHandler::HandleNpcNameCommand(char* /*args*/)
Expand Down
Loading