1 #include "cController.h"
2 
3 #include "cObject.h"
4 #include "cWorld.h"
5 
6 #include <cstdlib>
7 #include <cassert>
8 #include <iostream>
9 
10 using std::cout;
11 using std::endl;
12 using std::string;
13 
14 #define debug_state !true
15 #define debug_transitions !true
16 #define debug_step !true
17 
18 // -------------------------------------------------------------
19 
cController(cObject * entity,bool enabled)20 cController::cController(cObject* entity, bool enabled) {
21     mDevice = entity;
22     mEnabled = enabled;
23 }
24 
~cController()25 cController::~cController() {
26     while (!mStack.empty()) mStack.pop_back();
27 }
28 
printState()29 void cController::printState() {
30     int framesize = getFrameSize();
31     string framename = getFrameName();
32     cout << "CtrlSt of " << mDevice->nameable->name.c_str() << "#" << mDevice->base->oid << "  Frame: " << framename << "  Framesize:" << framesize << "  Stack: " << mStack.size() << endl;
33 }
34 
getFrameName()35 string cController::getFrameName() {
36     //cout << "getFrameName()\n";
37     const char* names[] = {
38         "WAIT", "ATTACK", "FOLLOW", "GOTO", "REPEAT",
39         "NOSTATENAME"
40     };
41     unsigned int i = mStack.back();
42     i = (i < OPCODE_MAX) ? i : OPCODE_MAX - 1;
43     string s = string(names[i]);
44     return s;
45 };
46 
getFrameSizeOf(int opcode)47 unsigned int cController::getFrameSizeOf(int opcode) {
48     switch (opcode) {
49         case WAIT: return 3;
50         case ATTACK: return 2;
51         case FOLLOW: return 3;
52         case GOTO: return 5;
53         case REPEAT : return 2;
54         default: return 2;
55     }
56 }
57 
getFrameSize()58 unsigned int cController::getFrameSize() {
59     return getFrameSizeOf(mStack.back());
60 }
61 
getParameter(int offset)62 OID cController::getParameter(int offset) {
63     return mStack[mStack.size() - offset - 1];
64 }
65 
setParameter(int offset,OID value)66 void cController::setParameter(int offset, OID value) {
67     mStack[mStack.size() - offset - 1] = value;
68 }
69 
push(OID value)70 void cController::push(OID value) {
71     mStack.push_back(value);
72 }
73 
pop()74 void cController::pop() {
75     if (debug_transitions) {
76         cout << mDevice->nameable->name.c_str() << "#" << mDevice->base->oid << ".pop()\n";
77     }
78     int size = getFrameSize(); // Important: eval outside loop-condition!
79     loopi(size) mStack.pop_back();
80     if (debug_transitions) {
81         printState();
82     }
83 }
84 
process(float spf)85 void cController::process(float spf) {
86     if (debug_state) cout << "cController::process()\n";
87 
88     if (!mEnabled) return;
89     if (mDevice == NULL) return;
90 
91     if (mStack.empty()) pushWaitEvent();
92 
93     if (debug_step) printState();
94 
95     switch (mStack.back()) {
96         case WAIT: waitEvent();
97             break;
98         case ATTACK: attackEnemy();
99             break;
100         case FOLLOW: followLeader();
101             break;
102         case GOTO: gotoDestination();
103             break;
104         case REPEAT: repeatInstructions();
105             break;
106         default: cout << "Invalid Instruction Request!\n";
107             break;
108     }
109     if (debug_step) {
110         cout << "=> ";
111         printState();
112     }
113 }
114 
115 
116 // -------------------------------------------------------------
117 
pushWaitEvent(long mseconds,bool patrol)118 void cController::pushWaitEvent(long mseconds, bool patrol) {
119     push(patrol);
120     push(mseconds);
121     push(WAIT);
122 }
123 
waitEvent()124 void cController::waitEvent() {
125     //OID opcode = getParameter(0);
126     long mseconds = getParameter(1);
127     bool patrol = getParameter(2);
128 
129     {
130         mDevice->do_idle();
131     }
132 
133     if (patrol) {
134         OID enemy = 0;
135         if (enemy == 0) enemy = mDevice->disturbedBy();
136         if (enemy == 0) enemy = mDevice->enemyNearby();
137         if (enemy) {
138             {
139                 OID self = mDevice->base->oid;
140                 cWorld::instance->sendMessage(0, 0, "#%llu: Intruder!\n", self);
141             }
142             pushAttackEnemy(enemy);
143         }
144     }
145 
146     if (mseconds > 0) {
147         mseconds -= 1000/40;
148         setParameter(1, mseconds);
149         if (mseconds <= 0) {
150             pop();
151             return;
152         }
153     }
154 }
155 
156 // -------------------------------------------------------------
157 
pushAttackEnemy(OID entity)158 void cController::pushAttackEnemy(OID entity) {
159     if (debug_transitions) {
160         cout << mDevice->nameable->name.c_str() << "#" << mDevice->base->oid << ".pushAttackEnemy( " << entity << " )\n";
161     }
162     {
163         //OID self = mDevice->mSerial;
164         //cWorld::instance->sendMessage("@%llu: All ur base belongs to us.\n", entity);
165     }
166     push(entity);
167     push(ATTACK);
168 }
169 
attackEnemy()170 void cController::attackEnemy() {
171     //OID opcode = getParameter(0);
172     OID entity = getParameter(1);
173 
174     {
175         mDevice->do_moveFor(NULL);
176         mDevice->do_aimFor(entity);
177         mDevice->do_moveNear();
178         mDevice->do_aimAt();
179         if (mDevice->inWeaponRange() > 0.5) mDevice->do_fireAt();
180         //((cMech*)mDevice)->Pattern(tf, "nrnlln");
181     }
182 
183     cObject* target = cWorld::instance->mIndex[entity];
184     if (mDevice->inTargetRange() < 0.01) {
185         mDevice->do_aimFor(0);
186         pop();
187         return;
188     }
189     if (target == NULL) { // Target disappeared
190         mDevice->do_aimFor(0);
191         pop();
192         return;
193     } else if (target->hasRole(DEAD)) {
194         mDevice->do_aimFor(0);
195         pop();
196         return;
197     }
198 
199 }
200 
201 // -------------------------------------------------------------
202 
pushFollowLeader(OID entity,bool patrol)203 void cController::pushFollowLeader(OID entity, bool patrol) {
204     if (debug_transitions) {
205         cout << mDevice->nameable->name.c_str() << "#" << mDevice->base->oid << ".pushFollowLeader( " << entity << ", " << patrol << " )\n";
206     }
207     push(patrol ? 1 : 0);
208     push(entity);
209     push(FOLLOW);
210 }
211 
followLeader()212 void cController::followLeader() {
213     //OID opcode = getParameter(0);
214     OID entity = getParameter(1);
215     OID patrol = getParameter(2);
216 
217     {
218         mDevice->do_aimFor(entity);
219         mDevice->do_moveFor(NULL);
220         mDevice->do_moveNear();
221         mDevice->do_aimAt();
222     }
223 
224     if (patrol) {
225         OID nearby = mDevice->enemyNearby();
226         if (nearby) {
227             pushAttackEnemy(nearby);
228             return;
229         }
230     }
231 }
232 
233 // -------------------------------------------------------------
234 
pushGotoDestination(float * v,bool patrol)235 void cController::pushGotoDestination(float* v, bool patrol) {
236     if (v == NULL) return;
237     if (debug_transitions) {
238         cout << mDevice->nameable->name.c_str() << "#" << mDevice->base->oid << ".pushGotoDestination( <" << v[0] << "," << v[1] << "," << v[2] << ">, " << patrol << " )\n";
239     }
240     unsigned long *p = (unsigned long*) v;
241     push(patrol ? !0 : 0);
242     push(p[2]);
243     push(p[1]);
244     push(p[0]);
245     push(GOTO);
246 }
247 
gotoDestination()248 void cController::gotoDestination() {
249     //OID opcode = getParameter(0);
250     OID v0 = getParameter(1);
251     OID v1 = getParameter(2);
252     OID v2 = getParameter(3);
253     OID patrol = getParameter(4);
254     unsigned long p[] = {
255         v0, v1, v2
256     };
257     float* v = (float*) p;
258 
259     {
260         if (debug_state) cout << "going " << ((patrol > 0) ? "patrolling" : "directly") << " to <" << v[0] << "," << v[1] << "," << v[2] << " >\n";
261         mDevice->do_moveFor(v);
262         //mDevice->do_aimFor(0);
263         mDevice->do_aimAt();
264         mDevice->do_moveTowards();
265     }
266 
267     float range = mDevice->inDestinationRange();
268     if (debug_state) cout << "DestinationRange " << range << endl;
269     if (range > 0.0f) {
270         pop();
271         return;
272     }
273 
274     if (patrol) {
275         OID nearby = mDevice->enemyNearby();
276         if (nearby) {
277             pushAttackEnemy(nearby);
278             return;
279         }
280     }
281 }
282 
283 // -------------------------------------------------------------
284 
pushRepeatInstructions(int n)285 void cController::pushRepeatInstructions(int n) {
286     if (debug_transitions) {
287         cout << mDevice->nameable->name.c_str() << "#" << mDevice->base->oid << ".pushRepeatInstructions( " << n << " )\n";
288     }
289     push(n);
290     push(REPEAT);
291 }
292 
repeatInstructions()293 void cController::repeatInstructions() {
294     OID opcode = getParameter(0);
295     OID n = getParameter(1);
296 
297     if (debug_state) {
298         printState();
299     }
300 
301     unsigned int first = getFrameSize();
302     if (debug_state) cout << "first " << first << " -> opcode " << opcode << endl;
303     unsigned int last = first;
304     loopi(n) {
305         int opcode = getParameter(last);
306         last += getFrameSizeOf(opcode);
307         if (debug_state) cout << "last " << last << " -> opcode " << opcode << endl;
308     }
309 
310     int size = last - first;
311     if (debug_state) cout << size << " = " << last << " - " << first << endl;
312 
313     loopi(size) {
314         push(getParameter(last - 1));
315     }
316 }
317 
318 
319