OpenGothic
Open source reimplementation of Gothic I and II
Loading...
Searching...
No Matches
abstracttrigger.cpp
Go to the documentation of this file.
1#include "abstracttrigger.h"
2
3#include <Tempest/Log>
4
5#include <zenkit/vobs/Trigger.hh>
6
7#include "world/objects/npc.h"
8#include "world/world.h"
9#include "game/serialize.h"
10
11using namespace Tempest;
12
13AbstractTrigger::AbstractTrigger(Vob* parent, World &world, const zenkit::VirtualObject& data, Flags flags)
14 : Vob(parent,world,data,flags & (~Flags::Static)), callback(this), vobName(data.vob_name) {
15 bboxSize = Vec3(data.bbox.max.x-data.bbox.min.x,data.bbox.max.y-data.bbox.min.y,data.bbox.max.z-data.bbox.min.z)*0.5f;
16 bboxOrigin = Vec3(data.bbox.max.x+data.bbox.min.x,data.bbox.max.y+data.bbox.min.y,data.bbox.max.z+data.bbox.min.z)*0.5f;
17 bboxOrigin = bboxOrigin - position();
18
19 box = world.physic()->bboxObj(&callback,data.bbox);
20 if(bboxSize!=Vec3()) {
21 boxNpc = CollisionZone(world,bboxOrigin+position(),bboxSize);
22 boxNpc.setCallback([this](Npc& npc){
23 this->onIntersect(npc);
24 });
25 }
26
27 using zenkit::VirtualObjectType;
28
29 if(data.type == VirtualObjectType::zCTrigger || data.type == VirtualObjectType::zCTriggerList ||
30 data.type == VirtualObjectType::oCTriggerScript || data.type == VirtualObjectType::zCMover ||
31 data.type == VirtualObjectType::oCTriggerChangeLevel || data.type == VirtualObjectType::oCCSTrigger) {
32 auto& trigger = reinterpret_cast<const zenkit::VTrigger&>(data);
33 if(data.type == VirtualObjectType::zCMover) {
34 maxActivationCount = (trigger.max_activation_count==0) ? 0 : uint32_t(-1);
35 } else {
36 fireDelay = uint64_t(trigger.fire_delay_sec*1000.f);
37 retriggerDelay = uint64_t(trigger.retrigger_delay_sec*1000.f);
38 maxActivationCount = uint32_t(trigger.max_activation_count);
39 sendUntrigger = trigger.send_untrigger;
40 }
41 target = trigger.target;
42 disabled = !trigger.start_enabled;
43 reactToOnTrigger = trigger.react_to_on_trigger;
44 reactToOnTouch = trigger.react_to_on_touch;
45 respondToNpc = trigger.respond_to_npc;
46 respondToPlayer = trigger.respond_to_pc;
47 respondToObject = trigger.respond_to_object;
48 }
49
50 world.addTrigger(this);
51 }
52
54
55std::string_view AbstractTrigger::name() const {
56 return vobName;
57 }
58
60 return !disabled;
61 }
62
64 if(!hasDelayedEvents())
65 return;
66 if(world.tickCount()<delayedEvent.timeBarrier)
67 return;
68 auto evt = std::move(delayedEvent);
69 delayedEvent = TriggerEvent();
71 }
72
74 if(hasDelayedEvents()) {
75 // discard, if already have pending
76 return;
77 }
78 if(0!=emitTimeLast && world.tickCount()<emitTimeLast+retriggerDelay) {
79 // need to discard event
80 return;
81 }
82 if(fireDelay>0) {
83 TriggerEvent ex(evt.target, evt.emitter, world.tickCount() + fireDelay, evt.type);
84 delayedEvent = std::move(ex);
86 return;
87 }
89 }
90
92 emitTimeLast = world.tickCount();
93 switch(evt.type) {
98 if(!reactToOnTouch && evt.type==TriggerEvent::T_Touch)
99 return;
100 if(!reactToOnTrigger && evt.type==TriggerEvent::T_Trigger)
101 return;
102 if(disabled)
103 return;
104 if(emitCount>=maxActivationCount)
105 return;
106 ++emitCount;
107 onTrigger(evt);
108 break;
110 if(disabled || !sendUntrigger)
111 return;
112 onUntrigger(evt);
113 break;
115 disabled = false;
116 break;
118 disabled = true;
119 break;
121 disabled = !disabled;
122 break;
124 onGotoMsg(evt);
125 };
126 }
127 }
128
130 Log::d("TODO: trigger[",name(),"]");
131 }
132
135
138
140 boxNpc.setPosition(position()+bboxOrigin);
141 }
142
144 return ticksEnabled;
145 }
146
148 if(vobType==zenkit::VirtualObjectType::zCMover || vobType==zenkit::VirtualObjectType::zCCSCamera)
149 return;
150 if((n.isPlayer() ? !respondToPlayer : !respondToNpc) || !reactToOnTouch)
151 return;
152 if(!isEnabled())
153 return;
154 if(boxNpc.intersections().size()>0) {
155 // enableTicks();
157 processEvent(e);
158 }
159 }
160
161void AbstractTrigger::tick(uint64_t) {
162 }
163
165 Vob::save(fout);
166 boxNpc.save(fout);
167 fout.write(emitCount,disabled);
168 fout.write(emitTimeLast);
169
170 delayedEvent.save(fout);
171 fout.write(ticksEnabled);
172 }
173
175 Vob::load(fin);
176 boxNpc.load(fin);
177 fin.read(emitCount,disabled);
178 fin.read(emitTimeLast);
179
180 if(fin.version()>=47) {
181 delayedEvent.load(fin);
182 if(hasDelayedEvents())
183 world.enableDefTrigger(*this);
184 }
185 if(fin.version()>=48) {
186 fin.read(ticksEnabled);
187 if(ticksEnabled)
188 world.enableTicks(*this);
189 }
190 }
191
193 return !delayedEvent.target.empty();
194 }
195
197 if(ticksEnabled)
198 return;
199 ticksEnabled = true;
200 world.enableTicks(*this);
201 }
202
204 if(!ticksEnabled)
205 return;
206 ticksEnabled = false;
207 world.disableTicks(*this);
208 }
209
210const std::vector<Npc*>& AbstractTrigger::intersections() const {
211 return boxNpc.intersections();
212 }
213
215 if(!tg->respondToObject || !tg->reactToOnTouch)
216 return;
217 if(b.isSpell())
218 return;
220 tg->processEvent(ex);
221 }
222
223void TriggerEvent::save(Serialize& fout) const {
224 fout.write(target,emitter,uint8_t(type),timeBarrier);
225 if(type==T_Move)
226 fout.write(uint8_t(move.msg),move.key);
227 }
228
230 fin.read(target,emitter,reinterpret_cast<uint8_t&>(type),timeBarrier);
231 if(type==T_Move)
232 fin.read(reinterpret_cast<uint8_t&>(move.msg),move.key);
233 }
const std::vector< Npc * > & intersections() const
void load(Serialize &fin) override
void save(Serialize &fout) const override
std::string vobName
virtual void onTrigger(const TriggerEvent &evt)
bool hasDelayedEvents() const
bool isEnabled() const
void moveEvent() override
virtual void onGotoMsg(const TriggerEvent &evt)
virtual ~AbstractTrigger()
AbstractTrigger(Vob *parent, World &world, const zenkit::VirtualObject &data, Flags flags)
bool hasTicksEnabled() const
virtual void onIntersect(Npc &n)
void implProcessEvent(const TriggerEvent &evt)
void processEvent(const TriggerEvent &evt)
virtual void tick(uint64_t dt)
virtual void onUntrigger(const TriggerEvent &evt)
std::string_view name() const
const std::vector< Npc * > & intersections() const
void setCallback(std::function< void(Npc &npc)> f)
void setPosition(const Tempest::Vec3 &p)
void load(Serialize &fin)
void save(Serialize &fout) const
BBoxBody bboxObj(BBoxCallback *cb, const zenkit::AxisAlignedBoundingBox &bbox)
Definition npc.h:25
bool isPlayer() const
Definition npc.cpp:539
void write(const Arg &... a)
Definition serialize.h:76
uint16_t version() const
Definition serialize.h:51
void read(Arg &... a)
Definition serialize.h:81
std::string target
void load(Serialize &fin)
std::string emitter
uint64_t timeBarrier
void save(Serialize &fout) const
Definition vob.h:11
virtual void save(Serialize &fout) const
Definition vob.cpp:258
zenkit::VirtualObjectType vobType
Definition vob.h:46
Flags
Definition vob.h:13
World & world
Definition vob.h:45
static std::unique_ptr< Vob > load(Vob *parent, World &world, const zenkit::VirtualObject &vob, Flags flags)
Definition vob.cpp:127
Tempest::Vec3 position() const
Definition vob.cpp:57
Definition world.h:31
DynamicWorld * physic() const
Definition world.h:81
uint64_t tickCount() const
Definition world.cpp:387
void enableTicks(AbstractTrigger &t)
Definition world.cpp:524
void disableTicks(AbstractTrigger &t)
Definition world.cpp:528
void addTrigger(AbstractTrigger *trigger)
Definition world.cpp:804
void enableDefTrigger(AbstractTrigger &t)
Definition world.cpp:520
void onCollide(DynamicWorld::BulletBody &other) override
AbstractTrigger * tg