Skip to content

Commit 46f8d75

Browse files
authored
Directed Bot Jumping (mangoszero#276)
1 parent c924060 commit 46f8d75

File tree

8 files changed

+211
-2
lines changed

8 files changed

+211
-2
lines changed

src/game/Object/Unit.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,11 @@ class MovementInfo
671671
};
672672

673673
JumpInfo const& GetJumpInfo() const { return jump; }
674+
void SetJumpInfo(float vel, float sinA, float cosA, float xyspd)
675+
{
676+
jump.velocity = vel; jump.sinAngle = sinA; jump.cosAngle = cosA; jump.xyspeed = xyspd;
677+
}
678+
void SetFallTime(uint32 t) { fallTime = t; }
674679
private:
675680
// common
676681
uint32 moveFlags; // see enum MovementFlags

src/modules/Bots/playerbot/PlayerbotAI.cpp

Lines changed: 141 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,12 @@ void PacketHandlingHelper::AddPacket(const WorldPacket& packet)
7878
*/
7979
PlayerbotAI::PlayerbotAI() : PlayerbotAIBase(), bot(NULL), aiObjectContext(NULL),
8080
currentEngine(NULL), chatHelper(this), chatFilter(this), accountId(0), security(NULL), master(NULL), currentState(BOT_STATE_NON_COMBAT),
81-
m_eatingUntil(0), m_drinkingUntil(0)
81+
m_eatingUntil(0), m_drinkingUntil(0),
82+
m_isJumping(false), m_jumpStartTime(0),
83+
m_jumpStartX(0.f), m_jumpStartY(0.f), m_jumpStartZ(0.f),
84+
m_jumpSinAngle(0.f), m_jumpCosAngle(1.f), m_jumpXYSpeed(0.f),
85+
m_pendingJump(false), m_jumpRequestTime(0),
86+
m_jumpTargetX(0.f), m_jumpTargetY(0.f), m_jumpTargetZ(0.f), m_jumpTargetO(0.f)
8287
{
8388
for (int i = 0 ; i < BOT_STATE_MAX; i++)
8489
{
@@ -92,7 +97,12 @@ PlayerbotAI::PlayerbotAI() : PlayerbotAIBase(), bot(NULL), aiObjectContext(NULL)
9297
*/
9398
PlayerbotAI::PlayerbotAI(Player* bot) :
9499
PlayerbotAIBase(), chatHelper(this), chatFilter(this), security(bot), master(NULL),
95-
m_eatingUntil(0), m_drinkingUntil(0)
100+
m_eatingUntil(0), m_drinkingUntil(0),
101+
m_isJumping(false), m_jumpStartTime(0),
102+
m_jumpStartX(0.f), m_jumpStartY(0.f), m_jumpStartZ(0.f),
103+
m_jumpSinAngle(0.f), m_jumpCosAngle(1.f), m_jumpXYSpeed(0.f),
104+
m_pendingJump(false), m_jumpRequestTime(0),
105+
m_jumpTargetX(0.f), m_jumpTargetY(0.f), m_jumpTargetZ(0.f), m_jumpTargetO(0.f)
96106
{
97107
this->bot = bot;
98108

@@ -162,6 +172,132 @@ PlayerbotAI::~PlayerbotAI()
162172
}
163173
}
164174

175+
static const float BOT_JUMP_VELOCITY = 7.9557f;
176+
static const float BOT_JUMP_GRAVITY = 19.2911f;
177+
178+
void PlayerbotAI::RequestJump()
179+
{
180+
if (m_pendingJump || m_isJumping)
181+
return;
182+
183+
Player* master = GetMaster();
184+
if (!master)
185+
return;
186+
187+
m_jumpTargetX = master->GetPositionX();
188+
m_jumpTargetY = master->GetPositionY();
189+
m_jumpTargetZ = master->GetPositionZ();
190+
m_jumpTargetO = master->GetOrientation();
191+
m_pendingJump = true;
192+
m_jumpRequestTime = getMSTime();
193+
}
194+
195+
void PlayerbotAI::StartJump(bool forward, float orientation)
196+
{
197+
if (m_isJumping || bot->IsDead())
198+
return;
199+
200+
bot->GetMotionMaster()->Clear();
201+
bot->GetMotionMaster()->MoveIdle();
202+
203+
m_jumpStartTime = getMSTime();
204+
m_jumpStartX = bot->GetPositionX();
205+
m_jumpStartY = bot->GetPositionY();
206+
m_jumpStartZ = bot->GetPositionZ();
207+
208+
float o = (orientation >= 0.f) ? orientation : bot->GetOrientation();
209+
m_jumpCosAngle = cosf(o);
210+
m_jumpSinAngle = sinf(o);
211+
m_jumpXYSpeed = forward ? bot->GetSpeed(MOVE_RUN) : 0.f;
212+
m_isJumping = true;
213+
214+
bot->SetFallInformation(0, m_jumpStartZ);
215+
216+
bot->m_movementInfo.SetMovementFlags(MOVEFLAG_FALLING);
217+
if (forward)
218+
bot->m_movementInfo.AddMovementFlag(MOVEFLAG_FORWARD);
219+
bot->m_movementInfo.SetFallTime(0);
220+
bot->m_movementInfo.SetJumpInfo(-BOT_JUMP_VELOCITY, m_jumpCosAngle, m_jumpSinAngle, m_jumpXYSpeed);
221+
bot->m_movementInfo.ChangePosition(m_jumpStartX, m_jumpStartY, m_jumpStartZ, o);
222+
bot->m_movementInfo.UpdateTime(m_jumpStartTime);
223+
224+
WorldPacket data(MSG_MOVE_JUMP, 64);
225+
data << bot->GetPackGUID();
226+
bot->m_movementInfo.Write(data);
227+
bot->SendMessageToSet(&data, false);
228+
}
229+
230+
void PlayerbotAI::UpdateJump()
231+
{
232+
if (m_pendingJump && !m_isJumping)
233+
{
234+
if (getMSTime() - m_jumpRequestTime > 10000)
235+
{
236+
m_pendingJump = false;
237+
}
238+
else
239+
{
240+
float dx = m_jumpTargetX - bot->GetPositionX();
241+
float dy = m_jumpTargetY - bot->GetPositionY();
242+
float dist2d = sqrtf(dx * dx + dy * dy);
243+
if (dist2d <= 0.5f)
244+
{
245+
m_pendingJump = false;
246+
StartJump(true, m_jumpTargetO);
247+
}
248+
else
249+
{
250+
bot->GetMotionMaster()->MovePoint(0, m_jumpTargetX, m_jumpTargetY, m_jumpTargetZ);
251+
}
252+
}
253+
return;
254+
}
255+
256+
if (!m_isJumping)
257+
return;
258+
259+
uint32 now = getMSTime();
260+
uint32 fallTimeMs = now - m_jumpStartTime;
261+
float t = fallTimeMs / 1000.f;
262+
263+
float z = m_jumpStartZ + BOT_JUMP_VELOCITY * t - 0.5f * BOT_JUMP_GRAVITY * t * t;
264+
float x = m_jumpStartX + m_jumpCosAngle * m_jumpXYSpeed * t;
265+
float y = m_jumpStartY + m_jumpSinAngle * m_jumpXYSpeed * t;
266+
267+
float maxDuration = 2.f * BOT_JUMP_VELOCITY / BOT_JUMP_GRAVITY * 1000.f + 100.f;
268+
bool landed = fallTimeMs > 200 && ((z <= m_jumpStartZ + 0.05f) || (float(fallTimeMs) >= maxDuration));
269+
270+
bot->m_movementInfo.UpdateTime(now);
271+
bot->m_movementInfo.SetFallTime(fallTimeMs);
272+
bot->m_movementInfo.ChangePosition(x, y, z, bot->GetOrientation());
273+
274+
if (landed)
275+
{
276+
m_isJumping = false;
277+
278+
float landZ = m_jumpStartZ;
279+
if (Map* map = bot->GetMap())
280+
{
281+
float terrainZ = map->GetHeight(x, y, z > m_jumpStartZ ? z : m_jumpStartZ);
282+
if (terrainZ > INVALID_HEIGHT)
283+
landZ = terrainZ;
284+
}
285+
286+
bot->m_movementInfo.RemoveMovementFlag(MovementFlags(MOVEFLAG_FALLING | MOVEFLAG_FORWARD));
287+
bot->m_movementInfo.ChangePosition(x, y, landZ, bot->GetOrientation());
288+
289+
WorldPacket data(MSG_MOVE_FALL_LAND, 64);
290+
data << bot->GetPackGUID();
291+
bot->m_movementInfo.Write(data);
292+
bot->SendMessageToSet(&data, false);
293+
294+
bot->SetFallInformation(fallTimeMs, landZ);
295+
bot->GetMotionMaster()->Clear();
296+
bot->GetMotionMaster()->MoveIdle();
297+
bot->GetMap()->PlayerRelocation(bot, x, y, landZ, bot->GetOrientation());
298+
}
299+
}
300+
165301
void PlayerbotAI::UpdateAI(uint32 elapsed)
166302
{
167303
if (bot->IsBeingTeleported())
@@ -206,6 +342,9 @@ void PlayerbotAI::UpdateAI(uint32 elapsed)
206342
}
207343
}
208344

345+
if (m_isJumping || m_pendingJump)
346+
UpdateJump();
347+
209348
PlayerbotAIBase::UpdateAI(elapsed);
210349
}
211350

src/modules/Bots/playerbot/PlayerbotAI.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,11 @@ class PlayerbotAI : public PlayerbotAIBase
180180
static bool IsOpposing(uint8 race1, uint8 race2);
181181
PlayerbotSecurity* GetSecurity() { return &security; }
182182

183+
void StartJump(bool forward, float orientation = -1.f);
184+
void RequestJump();
185+
bool IsJumping() const { return m_isJumping; }
186+
bool IsPendingJump() const { return m_pendingJump; }
187+
183188
bool IsEating() const
184189
{
185190
return m_eatingUntil && time(0) <= m_eatingUntil
@@ -213,5 +218,15 @@ class PlayerbotAI : public PlayerbotAIBase
213218
PlayerbotSecurity security;
214219
time_t m_eatingUntil;
215220
time_t m_drinkingUntil;
221+
222+
bool m_isJumping;
223+
uint32 m_jumpStartTime;
224+
float m_jumpStartX, m_jumpStartY, m_jumpStartZ;
225+
float m_jumpSinAngle, m_jumpCosAngle, m_jumpXYSpeed;
226+
bool m_pendingJump;
227+
uint32 m_jumpRequestTime;
228+
float m_jumpTargetX, m_jumpTargetY, m_jumpTargetZ, m_jumpTargetO;
229+
230+
void UpdateJump();
216231
};
217232

src/modules/Bots/playerbot/strategy/actions/ActionContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ namespace ai
6666
creators["set facing"] = &ActionContext::set_facing;
6767
creators["attack duel opponent"] = &ActionContext::attack_duel_opponent;
6868
creators["drop target"] = &ActionContext::drop_target;
69+
creators["jump"] = &ActionContext::jump;
70+
creators["jump up"] = &ActionContext::jump_up;
6971
}
7072

7173
private:
@@ -112,5 +114,7 @@ namespace ai
112114
static Action* healthstone(PlayerbotAI* ai) { return new UseItemAction(ai, "healthstone"); }
113115
static Action* move_out_of_enemy_contact(PlayerbotAI* ai) { return new MoveOutOfEnemyContactAction(ai); }
114116
static Action* set_facing(PlayerbotAI* ai) { return new SetFacingTargetAction(ai); }
117+
static Action* jump(PlayerbotAI* ai) { return new JumpAction(ai); }
118+
static Action* jump_up(PlayerbotAI* ai) { return new JumpInPlaceAction(ai); }
115119
};
116120
};

src/modules/Bots/playerbot/strategy/actions/MovementActions.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,3 +626,21 @@ bool SetFacingTargetAction::isUseful()
626626
{
627627
return !AI_VALUE2(bool, "facing", "current target");
628628
}
629+
630+
bool JumpAction::Execute(Event event)
631+
{
632+
if (ai->IsJumping() || ai->IsPendingJump())
633+
return false;
634+
635+
ai->RequestJump();
636+
return ai->IsPendingJump();
637+
}
638+
639+
bool JumpInPlaceAction::Execute(Event event)
640+
{
641+
if (ai->IsJumping())
642+
return false;
643+
644+
ai->StartJump(false);
645+
return true;
646+
}

src/modules/Bots/playerbot/strategy/actions/MovementActions.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,18 @@ namespace ai
9595
virtual bool isUseful();
9696
};
9797

98+
class JumpAction : public MovementAction
99+
{
100+
public:
101+
JumpAction(PlayerbotAI* ai) : MovementAction(ai, "jump") {}
102+
virtual bool Execute(Event event);
103+
};
104+
105+
class JumpInPlaceAction : public MovementAction
106+
{
107+
public:
108+
JumpInPlaceAction(PlayerbotAI* ai) : MovementAction(ai, "jump up") {}
109+
virtual bool Execute(Event event);
110+
};
111+
98112
}

src/modules/Bots/playerbot/strategy/generic/ChatCommandHandlerStrategy.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,14 @@ void ChatCommandHandlerStrategy::InitTriggers(std::list<TriggerNode*> &triggers)
131131
triggers.push_back(new TriggerNode(
132132
"attackers",
133133
NextAction::array(0, new NextAction("tell attackers", relevance), NULL)));
134+
135+
triggers.push_back(new TriggerNode(
136+
"jump",
137+
NextAction::array(0, new NextAction("jump", relevance), NULL)));
138+
139+
triggers.push_back(new TriggerNode(
140+
"jump up",
141+
NextAction::array(0, new NextAction("jump up", relevance), NULL)));
134142
}
135143

136144

@@ -173,4 +181,6 @@ ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* ai) : PassTr
173181
supported.push_back("summon");
174182
supported.push_back("who");
175183
supported.push_back("save mana");
184+
supported.push_back("jump");
185+
supported.push_back("jump up");
176186
}

src/modules/Bots/playerbot/strategy/triggers/ChatTriggerContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,14 @@ namespace ai
7171
creators["save mana"] = &ChatTriggerContext::save_mana;
7272
creators["max dps"] = &ChatTriggerContext::max_dps;
7373
creators["attackers"] = &ChatTriggerContext::attackers;
74+
creators["jump"] = &ChatTriggerContext::jump;
75+
creators["jump up"] = &ChatTriggerContext::jump_up;
7476
}
7577

7678
private:
7779
static Trigger* attackers(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "attackers"); }
80+
static Trigger* jump(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "jump"); }
81+
static Trigger* jump_up(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "jump up"); }
7882
static Trigger* max_dps(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "max dps"); }
7983
static Trigger* save_mana(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "save mana"); }
8084
static Trigger* who(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "who"); }

0 commit comments

Comments
 (0)