~ubuntu-branches/debian/sid/minetest-mod-mobf-core/sid

« back to all changes in this revision

Viewing changes to mobf/mgen_follow/main_follow.lua

  • Committer: Package Import Robot
  • Author(s): Julien Puydt
  • Date: 2016-07-10 18:53:25 UTC
  • Revision ID: package-import@ubuntu.com-20160710185325-nyd59xd7m65mzfcn
Tags: upstream-2.5.1
ImportĀ upstreamĀ versionĀ 2.5.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
-------------------------------------------------------------------------------
 
2
-- Mob Framework Mod by Sapier
 
3
--
 
4
-- You may copy, use, modify or do nearly anything except removing this
 
5
-- copyright notice.
 
6
-- And of course you are NOT allow to pretend you have written it.
 
7
--
 
8
--! @file main_follow.lua
 
9
--! @brief component containing a targeted movement generator
 
10
--! @copyright Sapier
 
11
--! @author Sapier
 
12
--! @date 2012-08-09
 
13
--
 
14
--! @defgroup mgen_follow MGEN: follow movement generator
 
15
--! @brief A movement generator creating movement that trys to follow a moving
 
16
--! target or reach a given point on map
 
17
--! @ingroup framework_int
 
18
--! @{
 
19
-- Contact sapier a t gmx net
 
20
-------------------------------------------------------------------------------
 
21
 
 
22
--! @class mgen_follow
 
23
--! @brief a movement generator trying to follow or reach a target
 
24
 
 
25
--!@}
 
26
 
 
27
mgen_follow = {}
 
28
 
 
29
--! @brief movement generator identifier
 
30
--! @memberof mgen_follow
 
31
mgen_follow.name = "follow_mov_gen"
 
32
 
 
33
-------------------------------------------------------------------------------
 
34
-- name: identify_movement_state(ownpos,targetpos)
 
35
--
 
36
--! @brief check what situation we are
 
37
--! @memberof mgen_follow
 
38
--! @private
 
39
--
 
40
--! @param ownpos position of entity
 
41
--! @param targetpos position of target
 
42
--!
 
43
--! @return  "below_los"
 
44
--!          "below_no_los"
 
45
--!          "same_height_los"
 
46
--!          "same_height_no_los"
 
47
--!          "above_los"
 
48
--!          "above_no_los"
 
49
--!          "unknown"
 
50
-------------------------------------------------------------------------------
 
51
function mgen_follow.identify_movement_state(ownpos,targetpos)
 
52
        mobf_assert_backtrace(ownpos ~= nil)
 
53
        mobf_assert_backtrace(targetpos ~= nil)
 
54
 
 
55
        local same_height_delta = 0.1
 
56
 
 
57
        local los = mobf_line_of_sight(ownpos,targetpos)
 
58
 
 
59
        if ownpos.y > targetpos.y - same_height_delta and
 
60
                ownpos.y < targetpos.y + same_height_delta then
 
61
 
 
62
                if los then
 
63
                        return "same_height_los"
 
64
                else
 
65
                        return "same_height_no_los"
 
66
                end
 
67
        end
 
68
 
 
69
        if ownpos.y < targetpos.y then
 
70
                if los then
 
71
                        return "below_los"
 
72
                else
 
73
                        return "below_no_los"
 
74
                end
 
75
        end
 
76
 
 
77
        if ownpos.y > targetpos.y then
 
78
                if los then
 
79
                        return "above_los"
 
80
                else
 
81
                        return "above_no_los"
 
82
                end
 
83
        end
 
84
 
 
85
        return "unknown"
 
86
end
 
87
 
 
88
-------------------------------------------------------------------------------
 
89
-- name: handleteleport(entity,now)
 
90
--
 
91
--! @brief handle teleportsupport
 
92
--! @memberof mgen_follow
 
93
--! @private
 
94
--
 
95
--! @param entity mob to check for teleport
 
96
--! @param now current time
 
97
--! @param targetpos position of target
 
98
--!
 
99
--! @return true/false finish processing
 
100
-------------------------------------------------------------------------------
 
101
function mgen_follow.handleteleport(entity,now,targetpos)
 
102
 
 
103
        if (entity.dynamic_data.movement.last_next_to_target ~= nil ) then
 
104
                local time_since_next_to_target =
 
105
                        now - entity.dynamic_data.movement.last_next_to_target
 
106
 
 
107
                dbg_mobf.fmovement_lvl3("MOBF:   time since next to target: " .. time_since_next_to_target ..
 
108
                                                                        " delay: " .. dump(entity.data.movement.teleportdelay) ..
 
109
                                                                        " teleportsupport: " .. dump(entity.dynamic_data.movement.teleportsupport))
 
110
 
 
111
                if (entity.dynamic_data.movement.teleportsupport) and
 
112
                        time_since_next_to_target > entity.data.movement.teleportdelay then
 
113
 
 
114
                        --check targetpos try to playe above if not valid
 
115
                        local maxoffset = 5
 
116
                        local current_offset = 0
 
117
                        while (not environment.possible_pos(entity,{
 
118
                                                                                                x=targetpos.x,
 
119
                                                                                                y=targetpos.y + current_offset,
 
120
                                                                                                z=targetpos.z
 
121
                                                                                                })) and
 
122
                                current_offset < maxoffset do
 
123
                                dbg_mobf.fmovement_lvl2(
 
124
                                        "MOBF: teleport target within block trying above: " .. current_offset)
 
125
                                current_offset = current_offset +1
 
126
                        end
 
127
 
 
128
                        targetpos.y = targetpos.y + current_offset
 
129
 
 
130
                        --adjust to collisionbox of mob
 
131
                        if entity.collisionbox[2] < -0.5 then
 
132
                                targetpos.y = targetpos.y - (entity.collisionbox[2] + 0.49)
 
133
                        end
 
134
 
 
135
                        entity.object:setvelocity({x=0,y=0,z=0})
 
136
                        entity.object:setacceleration({x=0,y=0,z=0})
 
137
                        entity.object:moveto(targetpos)
 
138
                        entity.dynamic_data.movement.last_next_to_target = now
 
139
                        return true
 
140
                end
 
141
        end
 
142
        return false
 
143
end
 
144
 
 
145
-------------------------------------------------------------------------------
 
146
-- name: callback(entity,now)
 
147
--
 
148
--! @brief main callback to make a mob follow its target
 
149
--! @memberof mgen_follow
 
150
--
 
151
--! @param entity mob to generate movement for
 
152
--! @param now current time
 
153
-------------------------------------------------------------------------------
 
154
function mgen_follow.callback(entity,now)
 
155
 
 
156
        dbg_mobf.fmovement_lvl3("MOBF: Follow mgen callback called")
 
157
 
 
158
        if entity == nil then
 
159
                mobf_bug_warning(LOGLEVEL_ERROR,"MOBF BUG!!!: called movement gen without entity!")
 
160
                return
 
161
        end
 
162
 
 
163
        if entity.dynamic_data == nil or
 
164
                entity.dynamic_data.movement == nil then
 
165
                mobf_bug_warning(LOGLEVEL_ERROR,"MOBF BUG!!!: >" ..entity.data.name .. "< removed=" .. dump(entity.removed) .. " entity=" .. tostring(entity) .. " probab movement callback")
 
166
                return
 
167
        end
 
168
 
 
169
        local follow_speedup =  {x=10,y=2,z=10 }
 
170
 
 
171
        if entity.data.movement.follow_speedup ~= nil then
 
172
                if type(entity.data.movement.follow_speedup) == "table" then
 
173
                        follow_speedup = entity.data.movement.follow_speedup
 
174
                else
 
175
                        follow_speedup.x= entity.data.movement.follow_speedup
 
176
                        follow_speedup.z= entity.data.movement.follow_speedup
 
177
                end
 
178
        end
 
179
        
 
180
        --if speedup is disabled reset
 
181
        if not entity.dynamic_data.movement.follow_speedup then
 
182
                follow_speedup = { x=1, y=1, z=1}
 
183
        end
 
184
 
 
185
        --check max speed limit
 
186
        mgen_follow.checkspeed(entity)
 
187
 
 
188
 
 
189
        --check environment
 
190
        local basepos  = entity.getbasepos(entity)
 
191
        local pos_quality = environment.pos_quality(basepos,entity)
 
192
 
 
193
        if environment.evaluate_state(pos_quality, LT_GOOD_POS) or
 
194
                (entity.data.movement.canfly and
 
195
                        environment.evaluate_state(pos_quality,LT_GOOD_FLY_POS)) then
 
196
                local toset = {
 
197
                        x= basepos.x,
 
198
                        y= basepos.y - 0.5 - entity.collisionbox[2],
 
199
                        z= basepos.z }
 
200
                --save known good position
 
201
                entity.dynamic_data.movement.last_pos_in_env = toset
 
202
        end
 
203
 
 
204
        if pos_quality.media_quality == MQ_IN_AIR or                  -- wrong media
 
205
                pos_quality.media_quality == MQ_IN_WATER or               -- wrong media
 
206
                pos_quality.geometry_quality == GQ_NONE or               -- no ground contact (TODO this was drop above water before)
 
207
                pos_quality.surface_quality_min == SQ_WATER then         -- above water
 
208
 
 
209
 
 
210
                if entity.dynamic_data.movement.invalid_env_count == nil then
 
211
                        entity.dynamic_data.movement.invalid_env_count = 0
 
212
                end
 
213
 
 
214
                entity.dynamic_data.movement.invalid_env_count =
 
215
                        entity.dynamic_data.movement.invalid_env_count + 1
 
216
 
 
217
 
 
218
                --don't change at first invalid pos but give some steps to cleanup by
 
219
                --other less invasive mechanisms
 
220
                if entity.dynamic_data.movement.invalid_env_count > 10 then
 
221
                        dbg_mobf.fmovement_lvl1("MOBF: followed to wrong place " .. pos_quality.tostring(pos_quality))
 
222
                        if entity.dynamic_data.movement.last_pos_in_env ~= nil then
 
223
                                entity.object:moveto(entity.dynamic_data.movement.last_pos_in_env)
 
224
                                basepos  = entity.getbasepos(entity)
 
225
                        else
 
226
                                local newpos = environment.get_suitable_pos_same_level(basepos,1,entity,true)
 
227
 
 
228
                                if newpos == nil then
 
229
                                        newpos = environment.get_suitable_pos_same_level( {
 
230
                                                                                                                                                x=basepos.x,
 
231
                                                                                                                                                y=basepos.y-1,
 
232
                                                                                                                                                z=basepos.z }
 
233
                                                                                                                                                ,1,entity,true)
 
234
                                end
 
235
 
 
236
                                if newpos == nil then
 
237
                                        newpos = environment.get_suitable_pos_same_level( {
 
238
                                                                                                                                                x=basepos.x,
 
239
                                                                                                                                                y=basepos.y+1,
 
240
                                                                                                                                                z=basepos.z }
 
241
                                                                                                                                                ,1,entity,true)
 
242
                                end
 
243
 
 
244
                                if newpos == nil then
 
245
                                        dbg_mobf.fmovement_lvl1("MOBF: no way to fix it removing mob")
 
246
                                        spawning.remove(entity,"mgen_follow poscheck")
 
247
                                else
 
248
                                        newpos.y = newpos.y - (entity.collisionbox[2] + 0.49)
 
249
                                        entity.object:moveto(newpos)
 
250
                                        basepos  = entity.getbasepos(entity)
 
251
                                end
 
252
                        end
 
253
                end
 
254
        else
 
255
                entity.dynamic_data.movement.invalid_env_count = 0
 
256
        end
 
257
 
 
258
        local current_accel = entity.object:getacceleration()
 
259
 
 
260
        if pos_quality.level_quality ~= LQ_OK and
 
261
                entity.data.movement.canfly then
 
262
                
 
263
 
 
264
                if pos_quality.level_quality == LQ_ABOVE then
 
265
                        if current_accel.y >= 0 then
 
266
                                current_accel.y = - entity.data.movement.max_accel
 
267
                        end
 
268
                end
 
269
 
 
270
                if pos_quality.level_quality == LQ_BELOW then
 
271
                        local current_accel = entity.object:getacceleration()
 
272
                        if current_accel.y <= 0 then
 
273
                                current_accel.y = entity.data.movement.max_accel
 
274
                        end
 
275
                end
 
276
 
 
277
                entity.object:setacceleration(current_accel)
 
278
                return
 
279
        end
 
280
 
 
281
        --fixup height fixup
 
282
        if entity.data.movement.canfly then
 
283
                if current_accel.y ~= 0 then
 
284
                        current_accel.y = 0
 
285
                        entity.object:setacceleration(current_accel)
 
286
                end
 
287
        end
 
288
 
 
289
        if entity.dynamic_data.movement.target ~= nil or
 
290
                entity.dynamic_data.movement.guardspawnpoint then
 
291
                
 
292
                dbg_mobf.fmovement_lvl3("MOBF:   Target available")
 
293
                --calculate distance to target
 
294
                local targetpos = nil
 
295
 
 
296
                if entity.dynamic_data.movement.target ~= nil then
 
297
                        dbg_mobf.fmovement_lvl3("MOBF:   have moving target")
 
298
 
 
299
                        if not mobf_is_pos(entity.dynamic_data.movement.target) then
 
300
                                targetpos = entity.dynamic_data.movement.target:getpos()
 
301
                        else
 
302
                                targetpos = entity.dynamic_data.movement.target
 
303
                        end
 
304
                end
 
305
 
 
306
                if targetpos == nil and
 
307
                        entity.dynamic_data.movement.guardspawnpoint == true then
 
308
                        dbg_mobf.fmovement_lvl3("MOBF:   non target selected")
 
309
                        targetpos = entity.dynamic_data.spawning.spawnpoint
 
310
                end
 
311
 
 
312
                if targetpos == nil then
 
313
                        mobf_bug_warning(LOGLEVEL_ERROR,"MOBF: " .. entity.data.name
 
314
                        .. " don't have targetpos "
 
315
                        .. "SP: " .. dump(entity.dynamic_data.spawning.spawnpoint)
 
316
                        .. " TGT: " .. dump(entity.dynamic_data.movement.target))
 
317
                        return
 
318
                end
 
319
 
 
320
                local distance = nil
 
321
                local height_distance = nil
 
322
 
 
323
                if entity.data.movement.canfly then
 
324
                        --real pos is relevant not basepos for flying mobs
 
325
                        --target for flying mobs is always slightly above it's target
 
326
                        distance = mobf_calc_distance(entity.object:getpos(),
 
327
                                {x=targetpos.x, y=(targetpos.y+1), z=targetpos.z })
 
328
                        height_distance = entity.object:getpos().y - (targetpos.y+1)
 
329
                else
 
330
                        distance = mobf_calc_distance_2d(basepos,targetpos)
 
331
                end
 
332
 
 
333
                if mobf_line_of_sight({x=basepos.x,y=basepos.y+1,z=basepos.z},
 
334
                                                 {x=targetpos.x,y=targetpos.y+1,z=targetpos.z})  == false then
 
335
                        dbg_mobf.fmovement_lvl3("MOBF:   no line of sight")
 
336
                        --TODO teleport support?
 
337
                        --TODO other ways to handle this?
 
338
                        --return
 
339
                end
 
340
                --dbg_mobf.fmovement_lvl3("MOBF:   line of sight")
 
341
 
 
342
                local max_distance = entity.dynamic_data.movement.max_distance
 
343
 
 
344
                if max_distance == nil then
 
345
                        max_distance = 1
 
346
                end
 
347
 
 
348
                --check if mob needs to move towards target
 
349
                dbg_mobf.fmovement_lvl3("MOBF: max distance is set to : "
 
350
                                                                        .. max_distance .. " dist: " .. distance)
 
351
                if distance > max_distance then
 
352
                        entity.dynamic_data.movement.was_moving_last_step = true
 
353
 
 
354
                        if mgen_follow.handleteleport(entity,now,targetpos) then
 
355
                                return
 
356
                        end
 
357
 
 
358
                        dbg_mobf.fmovement_lvl3("MOBF:   distance:" .. distance)
 
359
 
 
360
                        local current_state =
 
361
                                mgen_follow.identify_movement_state(basepos,targetpos)
 
362
                        local handled = false
 
363
 
 
364
                        if handled == false and
 
365
                                (current_state == "same_height_los" or
 
366
                                current_state == "above_los" or
 
367
                                current_state == "above_no_los" ) then
 
368
                                dbg_mobf.fmovement_lvl3("MOBF: \t Case 1: " .. current_state)
 
369
                                local accel_to_set =
 
370
                                        movement_generic.get_accel_to(targetpos,entity,true)
 
371
 
 
372
                                handled =
 
373
                                        mgen_follow.set_acceleration(entity,
 
374
                                                                                                        accel_to_set,
 
375
                                                                                                        follow_speedup,
 
376
                                                                                                        basepos)
 
377
                        end
 
378
 
 
379
                        if handled == false and
 
380
                                (current_state == "below_los" or
 
381
                                 current_state == "below_no_los" or
 
382
                                 current_state == "same_height_no_los" ) then
 
383
                                dbg_mobf.fmovement_lvl3("MOBF: \t Case 2: " .. current_state)
 
384
                                local accel_to_set =
 
385
                                        movement_generic.get_accel_to(targetpos,entity)
 
386
 
 
387
                                --seems to be a flying mob
 
388
                                if (accel_to_set.y >0) then
 
389
                                        handled =
 
390
                                                mgen_follow.set_acceleration(entity,
 
391
                                                                                                        accel_to_set,
 
392
                                                                                                        follow_speedup,
 
393
                                                                                                        basepos)
 
394
                                else
 
395
                                        local current_velocity = entity.object:getvelocity()
 
396
                                        local predicted_pos =
 
397
                                                movement_generic.predict_next_block(basepos,
 
398
                                                                                                        current_velocity,
 
399
                                                                                                        accel_to_set)
 
400
 
 
401
                                        --TODO replace by quality based mechanism!!!!!!!------------
 
402
                                        local pos_state  =
 
403
                                                environment.pos_is_ok(predicted_pos,entity)
 
404
                                        if pos_state == "collision_jumpable" then
 
405
                                                local pos_to_set = entity.object:getpos()
 
406
                                                pos_to_set.y = pos_to_set.y + 1.1
 
407
                                                entity.object:moveto(pos_to_set)
 
408
                                                basepos.y=basepos.y+1.1
 
409
                                        end
 
410
                                        ------------------------------------------------------------
 
411
 
 
412
                                        dbg_mobf.fmovement_lvl3("MOBF:   setting acceleration to: "
 
413
                                                .. printpos(accel_to_set) .. " predicted_state: "
 
414
                                                .. pos_state);
 
415
                                        handled =
 
416
                                                mgen_follow.set_acceleration(entity,
 
417
                                                                                                        accel_to_set,
 
418
                                                                                                        follow_speedup,
 
419
                                                                                                        basepos)
 
420
                                end
 
421
                        end
 
422
 
 
423
                        if handled == false then
 
424
                                dbg_mobf.fmovement_lvl1(
 
425
                                        "MOBF: \t Unexpected or unhandled movement state: "
 
426
                                         .. current_state)
 
427
                                local yaccel = environment.get_default_gravity(basepos,
 
428
                                                        entity.environment.media,
 
429
                                                        entity.data.movement.canfly)
 
430
                                --entity.object:setvelocity({x=0,y=0,z=0})
 
431
                                entity.object:setacceleration({x=0,y=yaccel,z=0})
 
432
                        end
 
433
                        mgen_follow.update_animation(entity, "following")
 
434
                --nothing to do
 
435
                elseif height_distance ~= nil and math.abs(height_distance) > 0.1 then
 
436
                        mgen_follow.set_acceleration(entity,
 
437
                                                                                { x=0,y=(height_distance*-0.2),z=0},
 
438
                                                                                follow_speedup,
 
439
                                                                                basepos)
 
440
                        mgen_follow.update_animation(entity, "following")
 
441
                --we're next to target stop movement
 
442
                else
 
443
                        local yaccel = environment.get_default_gravity(basepos,
 
444
                                                        entity.environment.media,
 
445
                                                        entity.data.movement.canfly)
 
446
                                                        
 
447
                        if entity.dynamic_data.movement.was_moving_last_step == true or
 
448
                                current_accel.Y ~= yaccel then
 
449
 
 
450
                                dbg_mobf.fmovement_lvl3("MOBF: next to target")
 
451
                                entity.object:setvelocity({x=0,y=0,z=0})
 
452
                                entity.object:setacceleration({x=0,y=yaccel,z=0})
 
453
                                entity.dynamic_data.movement.last_next_to_target = now
 
454
                                mgen_follow.update_animation(entity, "ntt")
 
455
                        end
 
456
                end
 
457
 
 
458
        else
 
459
                --TODO evaluate if this is an error case
 
460
        end
 
461
end
 
462
 
 
463
-------------------------------------------------------------------------------
 
464
-- name: update_animation()
 
465
--
 
466
--! @brief update animation according to the follow movegen substate
 
467
--! @memberof mgen_follow
 
468
--! @public
 
469
-------------------------------------------------------------------------------
 
470
function mgen_follow.update_animation(entity, anim_state)
 
471
 
 
472
        -- no need to change
 
473
        if anim_state == entity.dynamic_data.movement.anim_selected then
 
474
                return
 
475
        end
 
476
 
 
477
        -- check if there's a animation specified for stand in this state
 
478
        local statename, state = entity:get_state()
 
479
        
 
480
        if anim_state == "following" then
 
481
                entity.dynamic_data.movement.anim_selected = "following"
 
482
                
 
483
                if state.animation_walk ~= nil  then
 
484
                        graphics.set_animation(entity, state.animation_walk)
 
485
                elseif state.animation ~= nil then
 
486
                        graphics.set_animation(entity, state.animation)
 
487
                end
 
488
        elseif anim_state == "ntt" then
 
489
                entity.dynamic_data.movement.anim_selected = "ntt"
 
490
                
 
491
                if state.animation_next_to_target ~= nil then
 
492
                        graphics.set_animation(entity, state.animation_next_to_target)
 
493
                end
 
494
        end
 
495
end
 
496
 
 
497
-------------------------------------------------------------------------------
 
498
-- name: next_block_ok()
 
499
--
 
500
--! @brief check quality of next block
 
501
--! @memberof mgen_follow
 
502
--! @public
 
503
-------------------------------------------------------------------------------
 
504
function mgen_follow.next_block_ok(entity,pos,acceleration,velocity)
 
505
        local current_velocity = velocity
 
506
 
 
507
        if current_velocity == nil then
 
508
                current_velocity = entity.object:getvelocity()
 
509
        end
 
510
 
 
511
        local predicted_pos = movement_generic.predict_next_block(pos,current_velocity,acceleration)
 
512
 
 
513
        local quality = environment.pos_quality(predicted_pos,entity)
 
514
 
 
515
        return (
 
516
                        (quality.media_quality == MQ_IN_MEDIA) and
 
517
                        (quality.level_quality == LQ_OK) and
 
518
                        (
 
519
                                (quality.surface_quality_min == Q_UNKNOWN) or
 
520
                                (quality.surface_quality_min >= SQ_WRONG)
 
521
                        )
 
522
                )
 
523
end
 
524
 
 
525
-------------------------------------------------------------------------------
 
526
-- name: initialize()
 
527
--
 
528
--! @brief initialize movement generator
 
529
--! @memberof mgen_follow
 
530
--! @public
 
531
-------------------------------------------------------------------------------
 
532
function mgen_follow.initialize(entity,now)
 
533
        --intentionally empty
 
534
end
 
535
 
 
536
-------------------------------------------------------------------------------
 
537
-- name: init_dynamic_data(entity,now)
 
538
--
 
539
--! @brief initialize dynamic data required by movement generator
 
540
--! @memberof mgen_follow
 
541
--! @public
 
542
--
 
543
--! @param entity mob to initialize dynamic data
 
544
--! @param now current time
 
545
-------------------------------------------------------------------------------
 
546
function mgen_follow.init_dynamic_data(entity,now)
 
547
 
 
548
        local pos = entity.object:getpos()
 
549
 
 
550
 
 
551
        local data = {
 
552
                        target = nil,
 
553
                        guardspawnpoint = false,
 
554
                        max_distance = entity.data.movement.max_distance,
 
555
                        invalid_env_count = 0,
 
556
                        follow_speedup = true,
 
557
                        }
 
558
 
 
559
        if entity.data.movement.guardspawnpoint ~= nil and
 
560
                entity.data.movement.guardspawnpoint then
 
561
                        dbg_mobf.fmovement_lvl3("MOBF: setting guard point to: " .. printpos(entity.dynamic_data.spawning.spawnpoint))
 
562
                        data.guardspawnpoint = true
 
563
                end
 
564
 
 
565
                if entity.data.movement.teleportdelay~= nil then
 
566
                        data.last_next_to_target = now
 
567
                        data.teleportsupport = true
 
568
                end
 
569
 
 
570
        entity.dynamic_data.movement = data
 
571
end
 
572
 
 
573
-------------------------------------------------------------------------------
 
574
-- name: checkspeed(entity)
 
575
--
 
576
--! @brief check if mobs speed is within it's limits and correct if necessary
 
577
--! @memberof mgen_follow
 
578
--! @private
 
579
--
 
580
--! @param entity mob to initialize dynamic data
 
581
-------------------------------------------------------------------------------
 
582
function mgen_follow.checkspeed(entity)
 
583
 
 
584
        local current_velocity = entity.object:getvelocity()
 
585
 
 
586
        local xzspeed =
 
587
                mobf_calc_scalar_speed(current_velocity.x,current_velocity.z)
 
588
 
 
589
        if (xzspeed > entity.data.movement.max_speed) then
 
590
 
 
591
                local direction = mobf_calc_yaw(current_velocity.x,
 
592
                                                                                current_velocity.z)
 
593
 
 
594
                --reduce speed to 90% of current speed
 
595
                local new_speed = mobf_calc_vector_components(direction,xzspeed*0.9)
 
596
 
 
597
                local current_accel = entity.object:getacceleration()
 
598
 
 
599
                new_speed.y = current_velocity.y
 
600
                entity.object:setvelocity(new_speed)
 
601
                entity.object:setacceleration({x=0,y=current_accel.y,z=0})
 
602
 
 
603
                return true
 
604
        end
 
605
 
 
606
        return false
 
607
end
 
608
 
 
609
-------------------------------------------------------------------------------
 
610
-- name: set_acceleration(entity,accel,speedup)
 
611
--
 
612
--! @brief apply acceleration to entity
 
613
--! @memberof mgen_follow
 
614
--! @private
 
615
--
 
616
--! @param entity mob to apply to
 
617
--! @param accel acceleration to set
 
618
--! @param speedup speedup factor
 
619
--! @param pos current position
 
620
-------------------------------------------------------------------------------
 
621
function mgen_follow.set_acceleration(entity,accel,speedup,pos)
 
622
 
 
623
        accel.x = accel.x*speedup.x
 
624
        accel.z = accel.z*speedup.z
 
625
 
 
626
        if entity.data.movement.canfly then
 
627
                accel.y = accel.y*speedup.y
 
628
        end
 
629
 
 
630
        if mgen_follow.next_block_ok(entity,pos,accel) then
 
631
                dbg_mobf.fmovement_lvl3("MOBF:   setting acceleration to: " .. printpos(accel));
 
632
                entity.object:setacceleration(accel)
 
633
                return true
 
634
        elseif mgen_follow.next_block_ok(entity,pos,{x=0,y=0,z=0}) then
 
635
                accel = {x=0,y=0,z=0}
 
636
                dbg_mobf.fmovement_lvl3("MOBF:   setting acceleration to: " .. printpos(accel));
 
637
                entity.object:setacceleration(accel)
 
638
                return true
 
639
        else
 
640
                local current_velocity = entity.object:getvelocity()
 
641
                current_velocity.y = 0
 
642
 
 
643
                if mgen_follow.next_block_ok(entity,pos,{x=0,y=0,z=0},current_velocity) then
 
644
                        accel = {x=0,y=0,z=0}
 
645
                        entity.object:setvelocity(current_velocity)
 
646
                        entity.object:setacceleration(accel)
 
647
                        return true
 
648
                end
 
649
        end
 
650
 
 
651
        dbg_mobf.fmovement_lvl1(
 
652
                "MOBF: \t acceleration " .. printpos(accel) ..
 
653
                " would result in invalid position not applying!")
 
654
 
 
655
        return false
 
656
end
 
657
 
 
658
-------------------------------------------------------------------------------
 
659
-- name: set_target(entity, target, follow_speedup, max_distance)
 
660
--
 
661
--! @brief set target for movgen
 
662
--! @memberof mgen_follow
 
663
--
 
664
--! @param entity mob to apply to
 
665
--! @param target to set
 
666
--! @param follow_speedup --unused here
 
667
--! @param max_distance maximum distance to target to be tried to reach
 
668
-------------------------------------------------------------------------------
 
669
function mgen_follow.set_target(entity,target, follow_speedup, max_distance)
 
670
        entity.dynamic_data.movement.target = target
 
671
        entity.dynamic_data.movement.max_distance = max_distance
 
672
        return true
 
673
end
 
674
 
 
675
--register this movement generator
 
676
registerMovementGen(mgen_follow.name,mgen_follow)
 
 
b'\\ No newline at end of file'