Files
net-gunner/scripts/trap.gd

182 lines
4.7 KiB
GDScript

class_name Trap extends Area3D
enum Type{
BOMB,
MINE,
GAS,
FORCE_PANEL,
SWITCH,
PITFALL
}
const range_shapes : Dictionary = {
Trap.Type.BOMB : Vector3(5,1,5),
Trap.Type.GAS : Vector3(1,1,1),
Trap.Type.PITFALL : Vector3(1,1,1),
Trap.Type.FORCE_PANEL : Vector3(1,1,1),
Trap.Type.SWITCH : Vector3(3,1,3),
Trap.Type.MINE : Vector3(5,1,5),
}
const trap_icons : Dictionary = {
Trap.Type.BOMB : preload("res://visuals/images/icons/t-bomb.png"),
Trap.Type.GAS : preload("res://visuals/images/icons/t-gas.png"),
Trap.Type.PITFALL : preload("res://visuals/images/icons/t-pitfall.png"),
Trap.Type.FORCE_PANEL : preload("res://visuals/images/icons/t-force_panel.png"),
Trap.Type.SWITCH : preload("res://visuals/images/icons/t-switch.png"),
Trap.Type.MINE : preload("res://visuals/images/icons/t-mine.png"),
}
const bomb_explosion_template = preload("res://templates/explosion.tscn")
const mine_explosion_template = preload("res://templates/explosion.tscn")
const switch_explosion_template = preload("res://templates/explosion.tscn")
const gas_emitter_template = preload("res://templates/gas_emitter.tscn")
@onready var range_area : Area3D = %RangeArea
@onready var range_shape : BoxShape3D = %RangeShape.shape
@onready var model : MeshInstance3D = %Model
@onready var icon : Sprite3D = %Icon
@onready var force_strip : Sprite3D = %ForceStrip
@onready var material : StandardMaterial3D = model.get_surface_override_material(0)
@onready var reveal_timer : Timer = %RevealTimer
@onready var activation_timer : Timer = %ActivationTimer
var type : Type
var square : Vector3i
var trap_owner : int
var direction : Vector3
var disarming : bool
var disarm_id : int
var delayed_trigger_tween : Tween = null
var damage : int = 10
var just_revealed : bool = false
signal disarmed(type : Trap.Type)
signal activated(type : Trap.Type)
func setup(type : Type, direction : Vector3, trap_owner : int) -> void:
self.type = type
self.trap_owner = trap_owner
if type == Type.FORCE_PANEL:
var r : float = atan2(direction.z, direction.x)
var cardinal : float = roundi(r * 2 / PI) * PI / 2
self.direction = Vector3(cos(cardinal), 0, sin(cardinal))
func disarm() -> void:
disarmed.emit(type)
queue_free()
func reveal() -> void:
if model.visible:
return
model.visible = true
reveal_timer.start(5)
just_revealed = true
func is_just_revealed() -> bool:
return just_revealed
func is_revealed() -> bool:
return model.visible
func _on_reveal_timeout() -> void:
if Game.level.is_square_detected(square) or disarming:
reveal_timer.start(5)
else:
model.visible = false
func _ready() -> void:
var owns_trap = trap_owner == Multiplayer.id
icon.texture = trap_icons[type]
model.visible = owns_trap
icon.visible = owns_trap
range_shape.size = range_shapes[type]
material.albedo_color = Color.YELLOW if owns_trap else Color.RED
match(type):
Type.BOMB:
damage = 15
Type.MINE:
damage = 10
Type.SWITCH:
damage = 5
Type.GAS:
activation_timer.start()
Type.FORCE_PANEL:
var r : float = atan2(direction.z, -direction.x) + PI/2
force_strip.rotate_y(r)
force_strip.visible = true
func _process(delta: float) -> void:
just_revealed = false
func blast(body : Player) -> void:
body.hurt(damage)
func activate() -> void:
var explode : bool = false
match(type):
Type.FORCE_PANEL:
for body in get_overlapping_bodies():
body.fling(direction, 5.0)
Type.MINE:
var exp = mine_explosion_template.instantiate()
Game.level.add_vfx(exp, square)
explode = true
Type.SWITCH:
var exp = switch_explosion_template.instantiate()
Game.level.add_vfx(exp, square)
explode = true
Type.BOMB:
var exp = bomb_explosion_template.instantiate()
Game.level.add_vfx(exp, square)
explode = true
Type.GAS:
var emitter = gas_emitter_template.instantiate()
emitter.trap_owner = trap_owner
emitter.square = square
emitter.damage = 4
Game.level.add_vfx(emitter, square)
if explode:
trigger_adjacent_bombs()
blast_players()
Game.level.remove_trap_square(square)
activated.emit(type)
queue_free()
func trigger_adjacent_bombs() -> void:
for trap : Trap in range_area.get_overlapping_areas():
if trap.type == Type.BOMB:
trap.delay_trigger()
func blast_players() -> void:
for body in range_area.get_overlapping_bodies():
blast(body)
func delay_trigger() -> void:
if delayed_trigger_tween != null:
return
delayed_trigger_tween = create_tween()
delayed_trigger_tween.tween_interval(.25)
delayed_trigger_tween.tween_callback(activate)
func _on_body_entered(body: Node3D) -> void:
if type == Type.GAS:
return
if body.id == trap_owner:
return
if !disarming or body.id != disarm_id:
if !body.detecting:
activate()
func _on_activation_timer_timeout() -> void:
activate()