38 |
#include <numeric> |
#include <numeric> |
39 |
#include <cassert> |
#include <cassert> |
40 |
|
|
41 |
|
// remove comment from define below to switch on verbose messaging |
42 |
|
// note: VERBOSE_MESSAGES is defined in multiple source files! |
43 |
|
// #define VERBOSE_MESSAGES |
44 |
|
|
45 |
using namespace std; |
using namespace std; |
46 |
using namespace world; |
using namespace world; |
47 |
using namespace px; |
using namespace px; |
72 |
class Signal { |
class Signal { |
73 |
public: |
public: |
74 |
virtual ~Signal() {}; |
virtual ~Signal() {}; |
75 |
virtual void emit_from (Object *source, int value) = 0; |
virtual void emit_from(Object *source, int value) = 0; |
76 |
|
virtual Object *get_target() = 0; |
77 |
|
virtual Object *get_source() = 0; |
78 |
}; |
}; |
79 |
|
|
80 |
class SimpleSignal : public Signal { |
class SimpleSignal : public Signal { |
83 |
: source (src), destloc(dstloc), message(msg) |
: source (src), destloc(dstloc), message(msg) |
84 |
{} |
{} |
85 |
|
|
86 |
|
Object *get_target() { |
87 |
|
return GetObject(destloc); |
88 |
|
} |
89 |
|
Object *get_source() { |
90 |
|
return source; |
91 |
|
} |
92 |
|
|
93 |
void emit_from (Object *src, int value) { |
void emit_from (Object *src, int value) { |
94 |
if (source == src) { |
if (source == src) { |
95 |
Object *dst = GetObject (destloc); |
Object *dst = get_target(); |
96 |
|
|
97 |
|
#if defined(VERBOSE_MESSAGES) |
98 |
|
src->warning("emit_from: msg='%s' dest=%i/%i obj=%p", |
99 |
|
message.c_str(), |
100 |
|
destloc.pos.x, destloc.pos.y, |
101 |
|
dst); |
102 |
|
#endif // VERBOSE_MESSAGES |
103 |
|
|
104 |
SendMessage (dst, message, value); |
SendMessage (dst, message, value); |
105 |
} |
} |
106 |
|
#if defined(VERBOSE_MESSAGES) |
107 |
|
// else { |
108 |
|
// fprintf(stderr, |
109 |
|
// "emit_from source object does not match -- signal '%s' dropped (expected=%p=%s found=%p=%s)\n", |
110 |
|
// message.c_str(), source, source->get_kind(), src, src->get_kind()); |
111 |
|
// } |
112 |
|
#endif // VERBOSE_MESSAGES |
113 |
} |
} |
114 |
private: |
private: |
115 |
Object *source; |
Object *source; |
131 |
void add (Signal *sig) { m_signals.push_back(sig); } |
void add (Signal *sig) { m_signals.push_back(sig); } |
132 |
|
|
133 |
void emit_from (Object *source, int value) { |
void emit_from (Object *source, int value) { |
134 |
for (unsigned i=0; i<m_signals.size(); ++i) { |
// signals may have side effects. To minimize them |
135 |
m_signals[i]->emit_from (source, value); |
// 1. collect all targets and then |
136 |
|
// 2. emit signals to targets |
137 |
|
|
138 |
|
size_t size = m_signals.size(); |
139 |
|
vector<Object*> targets; |
140 |
|
targets.resize(size); |
141 |
|
|
142 |
|
for (unsigned i=0; i<size; ++i) { |
143 |
|
targets[i] = m_signals[i]->get_target(); |
144 |
|
} |
145 |
|
|
146 |
|
for (unsigned i=0; i<size; ++i) { |
147 |
|
if (m_signals[i]->get_target() == targets[i]) |
148 |
|
m_signals[i]->emit_from (source, value); |
149 |
} |
} |
150 |
} |
} |
151 |
|
|
152 |
|
Object *find_single_destination(Object *src) { |
153 |
|
Object *found = 0; |
154 |
|
size_t size = m_signals.size(); |
155 |
|
|
156 |
|
for (unsigned i = 0; i<size; ++i) { |
157 |
|
if (m_signals[i]->get_source() == src) { |
158 |
|
Object *candidate = m_signals[i]->get_target(); |
159 |
|
if (candidate) { |
160 |
|
if (!found) |
161 |
|
found = candidate; |
162 |
|
else if (candidate != found) { |
163 |
|
found = 0; // multiple targets |
164 |
|
break; |
165 |
|
} |
166 |
|
} |
167 |
|
} |
168 |
|
} |
169 |
|
|
170 |
|
return found; |
171 |
|
} |
172 |
}; |
}; |
173 |
} |
} |
174 |
|
|
1056 |
|
|
1057 |
void world::AddSignal (GridLoc srcloc, GridLoc dstloc, const string &msg) |
void world::AddSignal (GridLoc srcloc, GridLoc dstloc, const string &msg) |
1058 |
{ |
{ |
1059 |
|
#if defined(VERBOSE_MESSAGES) |
1060 |
|
fprintf(stderr, "AddSignal src=%i/%i dest=%i/%i msg='%s'\n", |
1061 |
|
srcloc.pos.x, srcloc.pos.y, dstloc.pos.x, dstloc.pos.y, msg.c_str()); |
1062 |
|
#endif // VERBOSE_MESSAGES |
1063 |
|
|
1064 |
if (Object *src = GetObject(srcloc)) { |
if (Object *src = GetObject(srcloc)) { |
1065 |
src->set_attrib("action", "signal"); |
src->set_attrib("action", "signal"); |
1066 |
level->signals.add (new SimpleSignal (src, dstloc, msg)); |
level->signals.add (new SimpleSignal (src, dstloc, msg)); |
1076 |
level->signals.emit_from (src, value); |
level->signals.emit_from (src, value); |
1077 |
} |
} |
1078 |
|
|
1079 |
|
// searches all signals for a signal starting at 'src' |
1080 |
|
// returns the target object. |
1081 |
|
// if multiple signals start from 'src' this function |
1082 |
|
// returns 0 if more than one target objects exists. |
1083 |
|
Object *world::FindSignalDestination(Object *src) |
1084 |
|
{ |
1085 |
|
return level->signals.find_single_destination(src); |
1086 |
|
} |
1087 |
|
|
1088 |
namespace |
namespace |
1089 |
{ |
{ |
1090 |
//---------------------------------------- |
//---------------------------------------- |