1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3 #include <boost/cstdint.hpp>
4
5 #include <cmath>
6 #include <SDL_keycode.h>
7
8 #include "GroupHandler.h"
9 #include "Group.h"
10 #include "Game/SelectedUnitsHandler.h"
11 #include "Game/CameraHandler.h"
12 #include "System/creg/STL_Set.h"
13 #include "System/Log/ILog.h"
14 #include "System/Input/KeyInput.h"
15 #include "System/EventHandler.h"
16
17 std::vector<CGroupHandler*> grouphandlers;
18
19 CR_BIND(CGroupHandler, (0))
20 CR_REG_METADATA(CGroupHandler, (
21 CR_MEMBER(groups),
22 CR_MEMBER(team),
23 CR_MEMBER(freeGroups),
24 CR_MEMBER(firstUnusedGroup),
25 CR_MEMBER(changedGroups)
26 ))
27
28 //////////////////////////////////////////////////////////////////////
29 // Construction/Destruction
30 //////////////////////////////////////////////////////////////////////
31
CGroupHandler(int teamId)32 CGroupHandler::CGroupHandler(int teamId)
33 : team(teamId),
34 firstUnusedGroup(FIRST_SPECIAL_GROUP)
35 {
36 for (int g = 0; g < FIRST_SPECIAL_GROUP; ++g) {
37 groups.push_back(new CGroup(g, this));
38 }
39 }
40
~CGroupHandler()41 CGroupHandler::~CGroupHandler()
42 {
43 for (int g = 0; g < firstUnusedGroup; ++g) {
44 delete groups[g];
45 }
46 }
47
Update()48 void CGroupHandler::Update()
49 {
50 {
51 for (std::vector<CGroup*>::iterator gi = groups.begin(); gi != groups.end(); ++gi) {
52 if ((*gi) != NULL) {
53 // Update may invoke RemoveGroup, but this will only NULL the element, so there will be no iterator invalidation here
54 (*gi)->Update();
55 }
56 }
57 }
58
59 std::set<int> grpChg;
60 {
61 if (changedGroups.empty())
62 return;
63
64 changedGroups.swap(grpChg);
65 }
66 // this batching mechanism is to prevent lua related readlocks for MT
67 for (std::set<int>::iterator i = grpChg.begin(); i != grpChg.end(); ++i) {
68 eventHandler.GroupChanged(*i);
69 }
70 }
71
GroupCommand(int num)72 bool CGroupHandler::GroupCommand(int num)
73 {
74 std::string cmd = "";
75
76 if (KeyInput::GetKeyModState(KMOD_CTRL)) {
77 if (!KeyInput::GetKeyModState(KMOD_SHIFT)) {
78 cmd = "set";
79 } else {
80 cmd = "add";
81 }
82 } else if (KeyInput::GetKeyModState(KMOD_SHIFT)) {
83 cmd = "selectadd";
84 } else if (KeyInput::GetKeyModState(KMOD_ALT)) {
85 cmd = "selecttoggle";
86 }
87
88 return GroupCommand(num, cmd);
89 }
90
GroupCommand(int num,const std::string & cmd)91 bool CGroupHandler::GroupCommand(int num, const std::string& cmd)
92 {
93 CGroup* group = groups[num];
94
95 if ((cmd == "set") || (cmd == "add")) {
96 if (cmd == "set") {
97 group->ClearUnits();
98 }
99 const CUnitSet& selUnits = selectedUnitsHandler.selectedUnits;
100 CUnitSet::const_iterator ui;
101 for(ui = selUnits.begin(); ui != selUnits.end(); ++ui) {
102 (*ui)->SetGroup(group);
103 }
104 }
105 else if (cmd == "selectadd") {
106 // do not select the group, just add its members to the current selection
107 CUnitSet::const_iterator ui;
108 for (ui = group->units.begin(); ui != group->units.end(); ++ui) {
109 selectedUnitsHandler.AddUnit(*ui);
110 }
111 return true;
112 }
113 else if (cmd == "selectclear") {
114 // do not select the group, just remove its members from the current selection
115 CUnitSet::const_iterator ui;
116 for (ui = group->units.begin(); ui != group->units.end(); ++ui) {
117 selectedUnitsHandler.RemoveUnit(*ui);
118 }
119 return true;
120 }
121 else if (cmd == "selecttoggle") {
122 // do not select the group, just toggle its members with the current selection
123 const CUnitSet& selUnits = selectedUnitsHandler.selectedUnits;
124 CUnitSet::const_iterator ui;
125 for (ui = group->units.begin(); ui != group->units.end(); ++ui) {
126 if (selUnits.find(*ui) == selUnits.end()) {
127 selectedUnitsHandler.AddUnit(*ui);
128 } else {
129 selectedUnitsHandler.RemoveUnit(*ui);
130 }
131 }
132 return true;
133 }
134
135 if (group->units.empty())
136 return false;
137
138 if (selectedUnitsHandler.IsGroupSelected(num)) {
139 const float3 groupCenter = group->CalculateCenter();
140 camHandler->CameraTransition(0.5f);
141 camHandler->GetCurrentController().SetPos(groupCenter);
142 }
143
144 selectedUnitsHandler.SelectGroup(num);
145 return true;
146 }
147
CreateNewGroup()148 CGroup* CGroupHandler::CreateNewGroup()
149 {
150 if (freeGroups.empty()) {
151 CGroup* group = new CGroup(firstUnusedGroup++, this);
152 groups.push_back(group);
153 return group;
154 } else {
155 int id = freeGroups.back();
156 freeGroups.pop_back();
157 CGroup* group = new CGroup(id, this);
158 groups[id] = group;
159 return group;
160 }
161 }
162
RemoveGroup(CGroup * group)163 void CGroupHandler::RemoveGroup(CGroup* group)
164 {
165 if (group->id < FIRST_SPECIAL_GROUP) {
166 LOG_L(L_WARNING, "Trying to remove hot-key group %i", group->id);
167 return;
168 }
169 if (selectedUnitsHandler.IsGroupSelected(group->id)) {
170 selectedUnitsHandler.ClearSelected();
171 }
172 groups[group->id] = NULL;
173 freeGroups.push_back(group->id);
174 delete group;
175 }
176
PushGroupChange(int id)177 void CGroupHandler::PushGroupChange(int id)
178 {
179 changedGroups.insert(id);
180 }
181
182