1 #include "CTaskHandler.h"
2 
3 #include <iostream>
4 #include <sstream>
5 #include <string>
6 #include <math.h>
7 #include <limits>
8 
9 #include "CUnitTable.h"
10 #include "CPathfinder.h"
11 #include "CUnit.h"
12 #include "CGroup.h"
13 #include "CEconomy.h"
14 #include "CConfigParser.h"
15 #include "CThreatMap.h"
16 #include "CScopedTimer.h"
17 #include "CDefenseMatrix.h"
18 
19 
CTaskHandler(AIClasses * ai)20 CTaskHandler::CTaskHandler(AIClasses *ai): ARegistrar(500) {
21 	this->ai = ai;
22 
23 	statsMaxActiveTasks = 0;
24 	statsMaxTasks = 0;
25 }
26 
~CTaskHandler()27 CTaskHandler::~CTaskHandler() {
28 	//LOG_II("CTaskHandler::Stats MaxActiveTasks = " << statsMaxActiveTasks)
29 	LOG_II("CTaskHandler::Stats MaxTasks = " << statsMaxTasks)
30 
31 	std::list<ATask*>::iterator it;
32 	for (it = processQueue.begin(); it != processQueue.end(); ++it)
33 		delete *it;
34 }
35 
remove(ARegistrar & obj)36 void CTaskHandler::remove(ARegistrar &obj) {
37 	switch(obj.regtype()) {
38 		case ARegistrar::TASK: {
39 			ATask *task = dynamic_cast<ATask*>(&obj);
40 			LOG_II("CTaskHandler::remove " << (*task))
41 			for(std::list<CGroup*>::iterator it = task->groups.begin(); it != task->groups.end(); ++it) {
42 				CGroup *group = *it;
43 				group->unreg(*this);
44 				groupToTask.erase(group->key);
45 				if (task->isMoving)
46 					ai->pathfinder->remove(*group);
47 			}
48 			activeTasks[task->t].erase(task->key);
49 			obsoleteTasks.push(task);
50 			break;
51 		}
52 		case ARegistrar::GROUP: {
53 			CGroup *group = dynamic_cast<CGroup*>(&obj);
54 			LOG_II("CTaskHandler::remove " << (*group))
55 			groupToTask.erase(group->key);
56 			break;
57 		}
58 		default:
59 			assert(false);
60 	}
61 
62 	obj.unreg(*this);
63 }
64 
update()65 void CTaskHandler::update() {
66 	/* delete obsolete tasks from memory */
67 	while(!obsoleteTasks.empty()) {
68 		ATask *task = obsoleteTasks.top();
69 		processQueue.remove(task);
70 		obsoleteTasks.pop();
71 		// make sure task is really detached from groups
72 		assert(task->groups.size() == 0);
73 		delete task;
74 	}
75 
76 	/* Begin task updates */
77 	if (!processQueue.empty()) {
78 		ATask *task;
79 
80 		if (processQueue.size() == 1) {
81 			task = processQueue.front();
82 			if (task->active) task->update();
83 		}
84 		else {
85 			int c = 0; // active tasks counter
86 			std::list<ATask*>::iterator it = processQueue.begin();
87 			ATask *taskFirst = *it;
88 
89 			do {
90 				task = *it;
91 
92 				if (task->active) {
93 					task->update();
94 					c++;
95 				}
96 
97 				++it;
98 
99 				// imitate circle queue...
100 				processQueue.pop_front();
101 				processQueue.push_back(task);
102 
103 				assert(it != processQueue.end());
104 			} while (c < MAX_TASKS_PER_UPDATE && (*it)->key != taskFirst->key);
105 		}
106 
107 		statsMaxTasks = std::max<int>(statsMaxTasks, processQueue.size());
108 	}
109 }
110 
getPos(const CGroup & group)111 float3 CTaskHandler::getPos(const CGroup& group) {
112 	assert(groupToTask.find(group.key) != groupToTask.end());
113 	return groupToTask[group.key]->pos;
114 }
115 
getTask(const CGroup & group)116 ATask* CTaskHandler::getTask(const CGroup& group) {
117 	std::map<int, ATask*>::iterator i = groupToTask.find(group.key);
118 	if (i == groupToTask.end())
119 		return NULL;
120 	return i->second;
121 }
122 
getTaskByTarget(int uid)123 ATask* CTaskHandler::getTaskByTarget(int uid) {
124 	std::map<int, ATask*>::iterator i;
125 	for (i = activeTasks[TASK_ATTACK].begin(); i != activeTasks[TASK_ATTACK].end(); ++i) {
126 		if (((AttackTask*)i->second)->target == uid)
127 			return i->second;
128 	}
129 	return NULL;
130 }
131 
addTask(ATask * task,ATask::NPriority p)132 bool CTaskHandler::addTask(ATask* task, ATask::NPriority p) {
133 	if (task == NULL)
134 		return false;
135 
136 	assert(task->t != TASK_UNDEFINED);
137 
138 	task->priority = p;
139 
140 	std::list<CGroup*>::iterator it;
141 
142 	// NOTE: this is required because otherwise memory used by task will never
143 	// be freed
144 	task->reg(*this);
145 	processQueue.push_back(task);
146 	// NOTE: this is required because within ATask::onValidate() a path
147 	// (or even paths) can be added, which in its turn calls
148 	// CTaskHandler::getPos()
149 	for (it = task->groups.begin(); it != task->groups.end(); ++it) {
150 		(*it)->reg(*this);
151 		groupToTask[(*it)->key] = task;
152 	}
153 
154 	LOG_II((*task))
155 
156 	if (!task->onValidate()) {
157 		task->remove();
158 		return false;
159 	}
160 
161 	// TODO: after MoveTask is implemented remove the code below
162 	for(it = task->groups.begin(); it != task->groups.end(); ++it) {
163 		CGroup* group = *it;
164 		if (task->isMoving && !ai->pathfinder->pathAssigned(*group)) {
165 			if(!ai->pathfinder->addGroup(*group)) {
166 				task->remove();
167 				return false;
168 			}
169 		}
170 	}
171 
172 	activeTasks[task->t][task->key] = task;
173 
174 	task->active = true;
175 
176 	return true;
177 }
178 
onEnemyDestroyed(int enemy,int attacker)179 void CTaskHandler::onEnemyDestroyed(int enemy, int attacker) {
180 	std::list<ATask*>::iterator it = processQueue.begin();
181 	ATask *task;
182 	while (it != processQueue.end()) {
183 		task = *it;	++it;
184 		if (task->active)
185 			task->onEnemyDestroyed(enemy, attacker);
186 	}
187 }
188 
onUnitDestroyed(int uid,int attacker)189 void CTaskHandler::onUnitDestroyed(int uid, int attacker) {
190 	std::list<ATask*>::iterator it = processQueue.begin();
191 	ATask *task;
192 	while (it != processQueue.end()) {
193 		task = *it;	++it;
194 		if (task->active)
195 			task->onUnitDestroyed(uid, attacker);
196 	}
197 }
198