Implemented combat; disabled palace for now
This commit is contained in:
@@ -4,8 +4,17 @@ var raycast_queue = []
|
||||
var blood = preload("res://scenes/decals/blood.tscn")
|
||||
var blood_decal = preload("res://scenes/decals/blood1-decal.gltf")
|
||||
var rnd
|
||||
var initialized = false
|
||||
func init():
|
||||
assert(!initialized)
|
||||
if initialized:
|
||||
return
|
||||
var root = get_character()
|
||||
if !root:
|
||||
return
|
||||
var cam = root.get_viewport().get_camera()
|
||||
if !cam.has_meta("player"):
|
||||
return
|
||||
var queue = [root]
|
||||
var hurtboxes = []
|
||||
assert(root.has_meta("skeleton"))
|
||||
@@ -20,15 +29,12 @@ func init():
|
||||
e.connect("area_entered", self, "area_hit", [e])
|
||||
rnd = RandomNumberGenerator.new()
|
||||
rnd.randomize()
|
||||
initialized = true
|
||||
func area_hit(area, e):
|
||||
var root = get_character()
|
||||
if area.is_in_group("weapon_hit"):
|
||||
var mo = area.get_meta("owner")
|
||||
if mo == root:
|
||||
# var cam = get_character().get_viewport().get_camera()
|
||||
# var pl = cam.get_meta("player")
|
||||
# print(mo.name, " ", root.name, " ", e.name)
|
||||
# print(mo, " ", root, " ", " ", pl)
|
||||
return
|
||||
print("HIT")
|
||||
var bi = blood.instance()
|
||||
@@ -49,36 +55,49 @@ func area_hit(area, e):
|
||||
offt.y = 0
|
||||
org += xoff + offt
|
||||
raycast_queue.push_back(org)
|
||||
assert(area.has_meta("item_name"))
|
||||
combat.emit_signal("event", "damage", [mo, area.get_meta("item_name")])
|
||||
yield(root.get_tree().create_timer(8), "timeout")
|
||||
# TODO: add delay
|
||||
bi.queue_free()
|
||||
|
||||
func update_physics(delta):
|
||||
assert(initialized)
|
||||
var root = get_character()
|
||||
if !root:
|
||||
assert(!initialized)
|
||||
return FAILED
|
||||
var space_state: PhysicsDirectSpaceState = root.get_world().direct_space_state
|
||||
var offsets = [Vector3(0, -2, 0)]
|
||||
var cam = root.get_viewport().get_camera()
|
||||
if !cam.has_meta("player"):
|
||||
return
|
||||
assert(!initialized)
|
||||
return FAILED
|
||||
var player = cam.get_meta("player")
|
||||
while raycast_queue.size() > 0:
|
||||
var item = raycast_queue.pop_front()
|
||||
var a = item
|
||||
for boff in offsets:
|
||||
var b = a + boff
|
||||
var result = {}
|
||||
if root is PhysicsBody:
|
||||
result = space_state.intersect_ray(a, b, [root, player])
|
||||
else:
|
||||
result = space_state.intersect_ray(a, b)
|
||||
if result.has("collider"):
|
||||
var body = result.collider
|
||||
var normal = result.normal
|
||||
var position = result.position
|
||||
var decal = blood_decal.instance()
|
||||
decal.add_to_group("blood")
|
||||
body.add_child(decal)
|
||||
decal.global_transform.origin = position
|
||||
var scale = 0.5 + rnd.randf() * 2.0
|
||||
var rot = PI * 2.0 * rnd.randf()
|
||||
decal.global_transform.basis = Basis(normal).scaled(Vector3(scale, 1.0, scale)).rotated(normal, rot)
|
||||
raycast_queue.clear()
|
||||
# while raycast_queue.size() > 0:
|
||||
# var item = raycast_queue.pop_front()
|
||||
# var a = item
|
||||
# for boff in offsets:
|
||||
# var b = a + boff
|
||||
# var result = {}
|
||||
# if root is PhysicsBody:
|
||||
# result = space_state.intersect_ray(a, b, [root, player])
|
||||
# else:
|
||||
# result = space_state.intersect_ray(a, b)
|
||||
# if result.has("collider"):
|
||||
# var body = result.collider
|
||||
# var normal = result.normal
|
||||
# var position = result.position
|
||||
# var decal = blood_decal.instance()
|
||||
# decal.add_to_group("blood")
|
||||
# body.add_child(decal)
|
||||
# decal.global_transform.origin = position
|
||||
# var scale = 0.5 + rnd.randf() * 2.0
|
||||
# var rot = PI * 2.0 * rnd.randf()
|
||||
# decal.global_transform.basis = Basis(normal).scaled(Vector3(scale, 1.0, scale)).rotated(normal, rot)
|
||||
return ERR_BUSY
|
||||
|
||||
func update(delta):
|
||||
return ERR_BUSY
|
||||
|
||||
|
||||
@@ -35,12 +35,12 @@ func update_physics(delta):
|
||||
if animtree:
|
||||
root_motion_track = animtree.root_motion_track
|
||||
else:
|
||||
return
|
||||
if characters.handle_cmdq(root):
|
||||
return
|
||||
return FAILED
|
||||
var skel = root.get_meta("skeleton")
|
||||
if !skel:
|
||||
return
|
||||
return FAILED
|
||||
if characters.handle_cmdq(root):
|
||||
return ERR_BUSY
|
||||
if root.has_meta("cmdqueue"):
|
||||
var cmds = root.get_meta("cmdqueue")
|
||||
var cmd = cmds.pop_front()
|
||||
@@ -256,3 +256,7 @@ func update_physics(delta):
|
||||
root.set_meta("cmdqueue", cmds)
|
||||
else:
|
||||
root.remove_meta("cmdqueue")
|
||||
return ERR_BUSY
|
||||
|
||||
func update(delta):
|
||||
return ERR_BUSY
|
||||
|
||||
@@ -23,15 +23,68 @@ var material_female = preload("res://scenes/clothes/nun-clothes.material")
|
||||
var material_male = preload("res://scenes/clothes/clothes-male.material")
|
||||
|
||||
var state = 0
|
||||
var health = 100.0
|
||||
var stamina = 100.0
|
||||
var rnd: RandomNumberGenerator
|
||||
const attack_distance = 2.0
|
||||
const guard_distance = 2.0
|
||||
const engage_distance = 10.0
|
||||
const flee_distance = 5.0
|
||||
|
||||
var blackboard = {
|
||||
"stamina": 100.0,
|
||||
"health": 100.0,
|
||||
"melee_weapon_equipped": false,
|
||||
"attack_cooldown": 0.0,
|
||||
"guard_cooldown": 0.0,
|
||||
"flee_cooldown": 0.0,
|
||||
"guard": false,
|
||||
"melee_damage": false,
|
||||
"dot": 0.0
|
||||
}
|
||||
|
||||
func look_at(ch):
|
||||
var current = root.global_transform
|
||||
var at = ch.global_transform.origin
|
||||
at.y = current.origin.y
|
||||
root.global_transform = current.looking_at(at, Vector3.UP)
|
||||
|
||||
func combat_event(ev, data):
|
||||
var cam = get_character().get_viewport().get_camera()
|
||||
var player
|
||||
if cam:
|
||||
player = cam.get_meta("player")
|
||||
assert(player)
|
||||
match ev:
|
||||
"about_to_attack":
|
||||
var who = data[0]
|
||||
if who != root:
|
||||
var where = who.global_transform.origin
|
||||
var curpos = root.global_transform.origin
|
||||
var dst = where.distance_squared_to(curpos)
|
||||
if dst < guard_distance * guard_distance:
|
||||
if who == player:
|
||||
blackboard.guard = true
|
||||
"damage":
|
||||
var who = data[0]
|
||||
var weapon = data[1]
|
||||
if who != root:
|
||||
var where = who.global_transform.origin
|
||||
var curpos = root.global_transform.origin
|
||||
var dst = where.distance_squared_to(curpos)
|
||||
if dst < attack_distance * attack_distance:
|
||||
if who == player:
|
||||
blackboard.melee_damage = true
|
||||
|
||||
var initialized = false
|
||||
func init():
|
||||
assert(!initialized)
|
||||
name = "bandit_ai"
|
||||
root = get_character()
|
||||
assert(root.has_meta("skeleton"))
|
||||
root.add_to_group("students")
|
||||
root.add_to_group("student")
|
||||
rnd = RandomNumberGenerator.new()
|
||||
rnd.randomize()
|
||||
root.add_to_group("bandits")
|
||||
root.add_to_group("bandit")
|
||||
combat.connect("event", self, "combat_event")
|
||||
|
||||
var character_data = root.get_meta("character_data")
|
||||
if character_data.sex == "female":
|
||||
@@ -47,8 +100,395 @@ func init():
|
||||
h += garments_head_male
|
||||
characters.call_deferred("setup_garments", root, g, h, material_male)
|
||||
state = 0
|
||||
for e in conf_behaviors.keys():
|
||||
if !run_behaviors.has(e):
|
||||
run_behaviors[e] = conf_behaviors[e].new()
|
||||
initialized = true
|
||||
var cooldown = 0.0
|
||||
|
||||
class base_bhv:
|
||||
var active = false
|
||||
var finished = false
|
||||
func run(delta: float, bb: Dictionary):
|
||||
pass
|
||||
func stop():
|
||||
pass
|
||||
func activate():
|
||||
pass
|
||||
|
||||
class walkto extends base_bhv:
|
||||
signal arrived(where)
|
||||
var state = 0
|
||||
var where: Vector3
|
||||
var speed: = 0.0
|
||||
var gap: = 0.0
|
||||
var root
|
||||
var timeout: = 0.0
|
||||
var pdist = INF
|
||||
var cost: = 0.0
|
||||
func look_at(root):
|
||||
var current = root.global_transform
|
||||
var at = where
|
||||
at.y = current.origin.y
|
||||
root.global_transform = current.looking_at(at, Vector3.UP)
|
||||
root.set_meta("orientation", Transform(root.global_transform.basis, Vector3()))
|
||||
func run(delta: float, bb: Dictionary):
|
||||
assert(active)
|
||||
assert(root)
|
||||
var gpos = root.global_transform.origin
|
||||
var dst = gpos.distance_squared_to(where)
|
||||
match state:
|
||||
0:
|
||||
look_at(root)
|
||||
characters.animation_node_travel(root, "locomotion")
|
||||
characters.set_walk_speed(root, speed, 0)
|
||||
state = 1
|
||||
1:
|
||||
bb.stamina -= cost * delta
|
||||
timeout -= delta
|
||||
state = 2
|
||||
2:
|
||||
if dst < gap * gap:
|
||||
emit_signal("arrived", gpos)
|
||||
state = 10
|
||||
elif timeout < 0.0:
|
||||
root.global_transform.origin = where
|
||||
emit_signal("arrived", gpos)
|
||||
state = 20
|
||||
elif dst > pdist && dst > gap * gap:
|
||||
root.global_transform.origin = where
|
||||
emit_signal("arrived", gpos)
|
||||
state = 30
|
||||
printerr("missed the target: ", sqrt(dst), gap)
|
||||
elif dst < 3.0 * gap * gap && timeout > 0.0:
|
||||
characters.set_walk_speed(root, 0.5 * speed, 0)
|
||||
10:
|
||||
finished = true
|
||||
20:
|
||||
finished = true
|
||||
30:
|
||||
finished = true
|
||||
200:
|
||||
timeout -= delta
|
||||
if timeout < 0.0:
|
||||
root.global_transform.origin = where
|
||||
characters.set_walk_speed(root, 0, 0)
|
||||
finished = true
|
||||
state = 300
|
||||
300:
|
||||
printerr("should not be here: ", sqrt(dst), gap)
|
||||
breakpoint
|
||||
# print("walkto state: ", state)
|
||||
|
||||
pdist = dst
|
||||
func start(root: Node, where: Vector3, speed: float, gap: float, cost: float, timeout: float):
|
||||
assert(root)
|
||||
assert(!active)
|
||||
state = 0
|
||||
self.root = root
|
||||
self.where = where
|
||||
self.gap = gap
|
||||
self.timeout = timeout
|
||||
self.speed = speed
|
||||
self.cost = cost
|
||||
active = true
|
||||
func stop():
|
||||
assert(active)
|
||||
assert(root)
|
||||
characters.set_walk_speed(root, 0, 0)
|
||||
active = false
|
||||
finished = false
|
||||
state = 0
|
||||
# print("walkto stopped")
|
||||
|
||||
class attack extends base_bhv:
|
||||
var root
|
||||
var anim
|
||||
var event
|
||||
var state = 0
|
||||
func start(root: Node, anim: String, event: String):
|
||||
self.root = root
|
||||
self.anim = anim
|
||||
self.event = event
|
||||
active = true
|
||||
func look_at(root, bb):
|
||||
var current = root.global_transform
|
||||
var at = bb.enemy_pos
|
||||
at.y = current.origin.y
|
||||
root.global_transform = current.looking_at(at, Vector3.UP)
|
||||
root.set_meta("orientation", Transform(root.global_transform.basis, Vector3()))
|
||||
func run(delta: float, bb: Dictionary):
|
||||
assert(active)
|
||||
assert(root)
|
||||
# print("attack state: ", state, " ", active, " ", finished)
|
||||
if finished:
|
||||
return
|
||||
# print("attack running")
|
||||
bb.attack_cooldown -= delta
|
||||
if bb.attack_cooldown > 0.0:
|
||||
return
|
||||
match state:
|
||||
0:
|
||||
combat.emit_signal("event", event, [root])
|
||||
look_at(root, bb)
|
||||
state = 1
|
||||
1:
|
||||
bb.stamina -= 0.5 * delta
|
||||
bb.stamina -= 3500 * delta
|
||||
characters.animation_node_travel(root, anim)
|
||||
# print("attack: ", anim)
|
||||
state = 2
|
||||
2:
|
||||
bb.stamina -= 5 * delta
|
||||
bb.attack_cooldown = 1.8
|
||||
finished = true
|
||||
# print("attack ", anim, " ", event, " done")
|
||||
func stop():
|
||||
assert(active)
|
||||
assert(root)
|
||||
active = false
|
||||
finished = false
|
||||
state = 0
|
||||
class take_weapon extends base_bhv:
|
||||
var weapon
|
||||
var root
|
||||
func start(root: Node, weapon):
|
||||
self.root = root
|
||||
self.weapon = weapon
|
||||
active = true
|
||||
func activate():
|
||||
pass
|
||||
func run(delta: float, bb: Dictionary):
|
||||
assert(active)
|
||||
assert(root)
|
||||
if finished:
|
||||
return
|
||||
if bb.melee_weapon_equipped:
|
||||
return
|
||||
var skel = root.get_meta("skeleton")
|
||||
var wslot = skel.get_node("wrist_r/weapon_right")
|
||||
wslot.set_meta("owner", root)
|
||||
inventory.equip(wslot, weapon)
|
||||
bb.melee_weapon_equipped = true
|
||||
finished = true
|
||||
func stop():
|
||||
# can't re-run this one
|
||||
assert(active)
|
||||
assert(root)
|
||||
finished = false
|
||||
active = false
|
||||
finished = false
|
||||
|
||||
class guard extends base_bhv:
|
||||
var root
|
||||
var anim1
|
||||
var anim2
|
||||
var state = 0
|
||||
func start(root: Node, anim1, anim2: String):
|
||||
self.root = root
|
||||
self.anim1 = anim1
|
||||
self.anim2 = anim2
|
||||
active = true
|
||||
func run(delta: float, bb: Dictionary):
|
||||
assert(active)
|
||||
assert(root)
|
||||
# print("guard state: ", state, " ", finished)
|
||||
if finished:
|
||||
return
|
||||
match state:
|
||||
0:
|
||||
# guard
|
||||
var anim
|
||||
if bb.dot < 0:
|
||||
anim = anim1
|
||||
else:
|
||||
anim = anim2
|
||||
characters.animation_node_travel(root, anim)
|
||||
# print("guard playing animation ", anim)
|
||||
state = 1
|
||||
1:
|
||||
state = 2
|
||||
2:
|
||||
bb.guard_cooldown = 1.5
|
||||
finished = true
|
||||
class get_damage extends base_bhv:
|
||||
var root
|
||||
var anim1
|
||||
var anim2
|
||||
var state = 0
|
||||
var cost = 0.0
|
||||
func start(root: Node, anim1, anim2: String, cost: float):
|
||||
self.root = root
|
||||
self.anim1 = anim1
|
||||
self.anim2 = anim2
|
||||
self.cost = cost
|
||||
active = true
|
||||
func run(delta: float, bb: Dictionary):
|
||||
assert(active)
|
||||
assert(root)
|
||||
if finished:
|
||||
return
|
||||
match state:
|
||||
0:
|
||||
# guard
|
||||
var anim
|
||||
if bb.dot < 0:
|
||||
anim = anim1
|
||||
else:
|
||||
anim = anim2
|
||||
characters.animation_node_travel(root, anim)
|
||||
if bb.stamina > 50.0:
|
||||
bb.health -= cost
|
||||
else:
|
||||
bb.health -= 5.0 * cost
|
||||
bb.stamina = 5.0
|
||||
# print("guard playing animation ", anim)
|
||||
state = 1
|
||||
1:
|
||||
state = 2
|
||||
2:
|
||||
bb.guard_cooldown = 1.5
|
||||
finished = true
|
||||
func stop():
|
||||
assert(active)
|
||||
assert(root)
|
||||
active = false
|
||||
finished = false
|
||||
state = 0
|
||||
# print("guard stopped")
|
||||
|
||||
class rest extends base_bhv:
|
||||
var root
|
||||
func start(root: Node):
|
||||
self.root = root
|
||||
active = true
|
||||
func run(delta: float, bb: Dictionary):
|
||||
assert(active)
|
||||
assert(root)
|
||||
if finished:
|
||||
return
|
||||
if bb.stamina < 100.0:
|
||||
# print("rest: stamina: ", bb.stamina)
|
||||
bb.stamina += 15500.0 * delta
|
||||
else:
|
||||
finished = true
|
||||
func stop():
|
||||
assert(active)
|
||||
assert(root)
|
||||
active = false
|
||||
finished = false
|
||||
|
||||
#var walk_to: walkto
|
||||
#var flee_to: walkto
|
||||
#var melee_attack: attack
|
||||
#var take_melee_weapon: take_weapon
|
||||
#var guard_melee: guard
|
||||
#var do_rest: rest
|
||||
|
||||
var conf_behaviors: = {
|
||||
"take_melee_weapon": take_weapon,
|
||||
"approach": walkto,
|
||||
"flee": walkto,
|
||||
"melee_attack": attack,
|
||||
"guard": guard,
|
||||
"rest": rest,
|
||||
"get_melee_damage": get_damage
|
||||
}
|
||||
|
||||
var pdst = INF
|
||||
static func calc_utility(utility: String, bb: Dictionary):
|
||||
match utility:
|
||||
"take_melee_weapon":
|
||||
if bb.health <= 0.0:
|
||||
return 0.0
|
||||
if bb.melee_weapon_equipped:
|
||||
return 0.0
|
||||
else:
|
||||
if bb.enemy_distance < engage_distance * engage_distance:
|
||||
return 110.0
|
||||
"approach":
|
||||
if bb.health <= 0.0:
|
||||
return 0.0
|
||||
if bb.enemy_distance < 1.6 * 1.6:
|
||||
return 0.0
|
||||
if bb.stamina > 50.0 && bb.enemy_distance < engage_distance * engage_distance:
|
||||
return 10.0 + (bb.enemy_distance - 10.0) / 6.0
|
||||
"melee_attack":
|
||||
if bb.health <= 0.0:
|
||||
return 0.0
|
||||
if bb.melee_weapon_equipped:
|
||||
if bb.attack_cooldown <= 0.0:
|
||||
var d = attack_distance * attack_distance
|
||||
if bb.stamina > 20.0 && bb.enemy_distance <= d:
|
||||
return 50.0
|
||||
"flee":
|
||||
if bb.health <= 0.0:
|
||||
return 0.0
|
||||
if bb.flee_cooldown > 0.0:
|
||||
return 0.0
|
||||
if bb.stamina <= 50.0 && bb.stamina > 10.0 && bb.enemy_distance < flee_distance * flee_distance:
|
||||
return 100.0 + clamp((100.0 - bb.stamina), 0, 90.0) * 2.0
|
||||
if bb.stamina <= 10.0 && bb.enemy_distance <= flee_distance * flee_distance * 0.5:
|
||||
return 250.0
|
||||
if bb.stamina <= 50.0 && bb.enemy_distance < engage_distance * engage_distance:
|
||||
if bb.randf < 0.3:
|
||||
return 100.0
|
||||
if bb.enemy_distance < 1.4 * 1.4:
|
||||
return 150.0
|
||||
if bb.health < 50 && bb.health > 15:
|
||||
return 160
|
||||
"guard":
|
||||
if bb.health <= 0.0:
|
||||
return 0.0
|
||||
if bb.guard_cooldown > 0.0:
|
||||
return 0.0
|
||||
elif bb.guard:
|
||||
bb.guard = false
|
||||
return 300.0
|
||||
# elif bb.enemy_distance < guard_distance * guard_distance * 0.3 && bb.stamina > 10.0:
|
||||
# return 80
|
||||
# elif bb.enemy_distance < attack_distance * attack_distance * 0.3:
|
||||
# return 10.0
|
||||
"rest":
|
||||
if bb.stamina >= 100.0:
|
||||
return 0.0
|
||||
if bb.stamina <= 10.0 && bb.enemy_distance >= flee_distance * flee_distance:
|
||||
return 100.0 + bb.enemy_distance / 10.0
|
||||
if bb.health < 10:
|
||||
return 2000
|
||||
"get_melee_damage":
|
||||
if bb.health <= 0.0:
|
||||
return 0.0
|
||||
if bb.melee_damage:
|
||||
bb.melee_damage = false
|
||||
print("DAMAGE2 ", bb.health)
|
||||
return 1000
|
||||
_:
|
||||
assert(false)
|
||||
return 0.0
|
||||
var last_behavior
|
||||
func select_behavior():
|
||||
var best_behavior
|
||||
var best_utility
|
||||
best_behavior = "rest"
|
||||
best_utility = 0.0
|
||||
for e in conf_behaviors.keys():
|
||||
var utility = calc_utility(e, blackboard)
|
||||
if e == last_behavior:
|
||||
utility *= 2.0
|
||||
if best_utility < utility:
|
||||
best_utility = utility
|
||||
best_behavior = e
|
||||
last_behavior = best_behavior
|
||||
return best_behavior
|
||||
|
||||
var last_bhv
|
||||
var last_running = []
|
||||
var current_running = []
|
||||
var run_behaviors = {}
|
||||
func update_physics(delta):
|
||||
assert(initialized)
|
||||
assert(root)
|
||||
var cam = root.get_viewport().get_camera()
|
||||
if !cam:
|
||||
return
|
||||
@@ -57,82 +497,94 @@ func update_physics(delta):
|
||||
var space: PhysicsDirectSpaceState = root.get_world().get_direct_space_state()
|
||||
var o = root.global_transform.origin
|
||||
var p = cam.get_meta("player").global_transform
|
||||
var pdst = o.distance_squared_to(p.origin)
|
||||
var adest = o + (p.origin - o).normalized() * 3.0
|
||||
var fdest = o + (o - p.origin).normalized() * 3.0
|
||||
var cmdq = []
|
||||
if root.has_meta("cmdqueue"):
|
||||
cmdq = root.get_meta("cmdqueue")
|
||||
pdst = o.distance_squared_to(p.origin)
|
||||
blackboard.enemy_distance = pdst
|
||||
blackboard.randf = rnd.randf()
|
||||
blackboard.enemy_pos = p.origin
|
||||
blackboard.space = space
|
||||
# var adest = o + (p.origin - o).normalized() * min(2.0, sqrt(pdst))
|
||||
var adest = p.origin
|
||||
var away = (o - p.origin).normalized()
|
||||
var attack_xform = Transform(root.global_transform.basis, o + away * 1.5)
|
||||
|
||||
var fdest = o + away * 4.0
|
||||
var enemy_dir: Vector3 = Transform(p.basis, Vector3()).xform(Vector3(0, 0, -1))
|
||||
var root_dir: Vector3 = Transform(root.global_transform.basis, Vector3()).xform(Vector3(0, 0, -1))
|
||||
var dot = root_dir.dot(enemy_dir)
|
||||
blackboard.dot = dot
|
||||
|
||||
var prev_state = state
|
||||
match state:
|
||||
0:
|
||||
if stamina < 100.0:
|
||||
stamina += delta
|
||||
if stamina > 50.0 && pdst < 100.0 && pdst > 8.0:
|
||||
var skel = root.get_meta("skeleton")
|
||||
var wslot = skel.get_node("wrist_r/weapon_right")
|
||||
wslot.set_meta("owner", root)
|
||||
inventory.equip(wslot, "s_dagger")
|
||||
# walk to enemy
|
||||
state = 10
|
||||
elif stamina > 50.0 && pdst <= 8.0:
|
||||
# melee attack enemy
|
||||
state = 20
|
||||
elif stamina <= 50.0 && stamina > 10.0 && pdst < 50.0:
|
||||
# flee away
|
||||
state = 30
|
||||
elif stamina <= 10.0 && pdst <= 16.0:
|
||||
# still flee away
|
||||
state = 30
|
||||
elif stamina <= 10.0 && pdst > 16.0:
|
||||
# rest
|
||||
state = 40
|
||||
10:
|
||||
# walk to enemy (player)
|
||||
stamina -= 4 * delta
|
||||
var dest = adest
|
||||
cmdq.push_back(["walkto", dest, 1.5, 2])
|
||||
state = 11
|
||||
11:
|
||||
# wait for start walking
|
||||
if root.has_meta("cmdq_walk"):
|
||||
characters.set_walk_speed(root, 0.5, 0)
|
||||
state = 12
|
||||
12:
|
||||
# finished walking
|
||||
stamina -= 4 * delta
|
||||
if !root.has_meta("cmdq_walk"):
|
||||
state = 0
|
||||
20:
|
||||
# attack
|
||||
stamina -= 3500 * delta
|
||||
characters.animation_node_travel(root, "attack-melee1")
|
||||
cooldown = 0.8
|
||||
state = 21
|
||||
21:
|
||||
cooldown -= delta
|
||||
stamina -= 5 * delta
|
||||
if cooldown <= 0.0:
|
||||
state = 0
|
||||
30:
|
||||
# walk away from enemy (player)
|
||||
stamina -= 15 * delta
|
||||
var dest = fdest
|
||||
cmdq.push_back(["walkto", dest, 1.5, 2])
|
||||
state = 31
|
||||
31:
|
||||
# wait for start fleeing
|
||||
if root.has_meta("cmdq_walk"):
|
||||
characters.set_walk_speed(root, 0.65, 0)
|
||||
state = 32
|
||||
32:
|
||||
# finished fleeing
|
||||
stamina -= 15 * delta
|
||||
if !root.has_meta("cmdq_walk"):
|
||||
state = 0
|
||||
40:
|
||||
stamina += 15500.0 * delta
|
||||
if stamina > 90.0:
|
||||
state = 0
|
||||
stamina = clamp(stamina, 0, 100.0)
|
||||
root.set_meta("cmdqueue", cmdq)
|
||||
last_running = current_running.duplicate()
|
||||
current_running = []
|
||||
var bhv = select_behavior()
|
||||
if last_bhv != bhv:
|
||||
# print("behavior: ", bhv)
|
||||
last_bhv = bhv
|
||||
if !run_behaviors[bhv].active:
|
||||
match bhv:
|
||||
"take_melee_weapon":
|
||||
run_behaviors[bhv].start(root, "s_dagger")
|
||||
"approach":
|
||||
var dest = adest
|
||||
if pdst > 25.0:
|
||||
run_behaviors[bhv].start(root, dest, 0.5, 3.0, 4.0, 6.0)
|
||||
else:
|
||||
run_behaviors[bhv].start(root, dest, 0.2, 1.5, 2.0, 6.0)
|
||||
"melee_attack":
|
||||
run_behaviors[bhv].start(root, "attack-melee1", "about_to_attack")
|
||||
"flee":
|
||||
# walk away from enemy (player)
|
||||
var dest = fdest
|
||||
run_behaviors[bhv].start(root, dest, 0.3, 1.5, 20.0, 6.0)
|
||||
"rest":
|
||||
run_behaviors[bhv].start(root)
|
||||
"guard":
|
||||
run_behaviors[bhv].start(root, "guard-melee1", "guard-front-melee1")
|
||||
"get_melee_damage":
|
||||
run_behaviors[bhv].start(root, "guard-melee1", "guard-front-melee1", 10.0)
|
||||
_:
|
||||
assert(false)
|
||||
# print("adding behavior: ", bhv)
|
||||
current_running.push_back(run_behaviors[bhv])
|
||||
for e in current_running:
|
||||
if !e in last_running:
|
||||
if !e.active:
|
||||
e.activate()
|
||||
e.run(delta, blackboard)
|
||||
#FIXME: mess :(
|
||||
if e == run_behaviors["flee"]:
|
||||
blackboard.flee_cooldown = 2.0 + rnd.randf() * 3.0
|
||||
if e.finished && e.active:
|
||||
# print("in current run but finished")
|
||||
e.stop()
|
||||
for e in last_running:
|
||||
if !e in current_running:
|
||||
if e.active:
|
||||
# print("not in current run but was in last")
|
||||
e.stop()
|
||||
1:
|
||||
state = 2
|
||||
2:
|
||||
state = 3
|
||||
3:
|
||||
state = 0
|
||||
if blackboard.stamina < 100.0:
|
||||
blackboard.stamina += delta
|
||||
if blackboard.attack_cooldown > 0.0:
|
||||
blackboard.attack_cooldown -= delta
|
||||
if blackboard.guard_cooldown > 0.0:
|
||||
blackboard.guard_cooldown -= delta
|
||||
if blackboard.flee_cooldown > 0.0:
|
||||
blackboard.flee_cooldown -= delta
|
||||
blackboard.stamina = clamp(blackboard.stamina, 0, 100.0)
|
||||
blackboard.health = clamp(blackboard.health, 0, 100.0)
|
||||
return ERR_BUSY
|
||||
func update(delta):
|
||||
return ERR_BUSY
|
||||
|
||||
##
|
||||
# if prev_state != state:
|
||||
# print("new state: ", state)
|
||||
# print("running ", current_running.size(), " behaviors")
|
||||
|
||||
@@ -37,3 +37,8 @@ func action(data):
|
||||
# if data.action == "hips_action":
|
||||
# print(data)
|
||||
# marker_hips_action(data)
|
||||
|
||||
func update(delta):
|
||||
return ERR_BUSY
|
||||
func update_physics(delta):
|
||||
return ERR_BUSY
|
||||
|
||||
@@ -151,6 +151,7 @@ func update_physics(delta):
|
||||
state = 0
|
||||
root.set_meta("cmdqueue", cmdq)
|
||||
oldx = p.origin
|
||||
return ERR_BUSY
|
||||
# print("state =", state)
|
||||
# var px = p.origin
|
||||
# px.y = root.global_transform.origin.y
|
||||
@@ -225,3 +226,5 @@ func update_physics(delta):
|
||||
## cmdq.push_back(["equip", "wrist_r/weapon_right", "s_dagger"])
|
||||
## other.set_meta("cmdqueue", cmdq)
|
||||
## group_manager.submit_player_npc_event_arot(root, "sacrificed-a", root, "sacrificed", root)
|
||||
func update(delta):
|
||||
return ERR_BUSY
|
||||
|
||||
@@ -42,3 +42,8 @@ func init():
|
||||
g += garments_male_main
|
||||
h += garments_head_male
|
||||
characters.call_deferred("setup_garments", root, g, h, material_male)
|
||||
func update(delta):
|
||||
return ERR_BUSY
|
||||
func update_physics(delta):
|
||||
return ERR_BUSY
|
||||
|
||||
|
||||
@@ -81,3 +81,8 @@ func setup_garments():
|
||||
# cmdq.push_back(["equip", "wrist_r/weapon_right", "s_dagger"])
|
||||
# other.set_meta("cmdqueue", cmdq)
|
||||
# group_manager.submit_player_npc_event_arot(root, "sacrificed-a", root, "sacrificed", root)
|
||||
func update_physics(delta):
|
||||
return ERR_BUSY
|
||||
func update(delta):
|
||||
return ERR_BUSY
|
||||
|
||||
|
||||
@@ -15,11 +15,21 @@ func init():
|
||||
assert(root.has_meta("skeleton"))
|
||||
|
||||
var attack = false
|
||||
var jump = false
|
||||
var equipped = false
|
||||
var vjump = Vector3()
|
||||
|
||||
func update(delta):
|
||||
if Input.is_action_pressed("attack"):
|
||||
attack = true
|
||||
if !controls.is_gui:
|
||||
if !attack:
|
||||
if Input.is_action_just_pressed("attack"):
|
||||
attack = true
|
||||
if !jump:
|
||||
if Input.is_action_just_pressed("jump"):
|
||||
jump = true
|
||||
vjump = Vector3.UP * 10.0
|
||||
return ERR_BUSY
|
||||
|
||||
|
||||
func update_physics(delta):
|
||||
var orientation: Transform
|
||||
@@ -76,6 +86,11 @@ func update_physics(delta):
|
||||
cmdq = root.get_meta("cmdqueue")
|
||||
cmdq.push_back(["climb", "1"])
|
||||
root.set_meta("cmdqueue", cmdq)
|
||||
if jump:
|
||||
root.move_and_slide(vjump, Vector3(0.0, 1.0, 0.0), true, 4, 0.785, false)
|
||||
vjump *= (1.0 - delta)
|
||||
if vjump.length_squared() <= 0.0:
|
||||
jump = false
|
||||
|
||||
if attack:
|
||||
if !equipped:
|
||||
@@ -84,6 +99,7 @@ func update_physics(delta):
|
||||
wslot.set_meta("owner", root)
|
||||
inventory.equip(wslot, "s_dagger")
|
||||
equipped = true
|
||||
combat.emit_signal("event", "about_to_attack", [root])
|
||||
animtree["parameters/state/playback"].travel("attack-melee1")
|
||||
attack = false
|
||||
else:
|
||||
@@ -121,4 +137,5 @@ func update_physics(delta):
|
||||
vehicle.engine_force = 500 * xmotion.y
|
||||
var accel = vehicle.angular_velocity * 350.0 * delta
|
||||
vehicle.steering = -xmotion.x * 0.7
|
||||
return ERR_BUSY
|
||||
|
||||
|
||||
Reference in New Issue
Block a user