e7299b17e9
Stack installed: - netfox v1.35.3 (core + extras + noray + internals) - godot-jolt v0.16.0-stable Architecture: - Server: ENet transport (works headless, no netfox deps) - Client/Editor: netfox rollback (RollbackSynchronizer, TickInterpolator) New/modified: - docs/migration-netfox-plan.md — migration architecture - scripts/network/network_manager.gd — netfox-aware ENet fallback - scripts/network/player.gd — clean base player - client/characters/player_netfox.gd — rollback player w/ WeaponManager - client/characters/input/player_net_input.gd — BaseNetInput subclass - client/characters/character/fps_character_controller.gd — netfox input feed - client/weapons/ — weapon data, registry, TacticalWeaponHitscan, WeaponManager - client/scripts/round_replicator.gd — client-side round state bridge - server/scripts/round_manager.gd — improved state machine - server/scripts/plugin_api/plugin_manager.gd — refined plugin system - config: enemy_tag, ally_tag for meatball targeting Removed: old C++ SimulationServer GDExtension (replaced by netfox rollback)
176 lines
4.2 KiB
GDScript
176 lines
4.2 KiB
GDScript
## WeaponRegistry — central registry of all weapon definitions.
|
|
##
|
|
## All weapon data is defined here as static constants. Systems that need
|
|
## weapon stats (WeaponManager, BuyMenu, RoundManager) reference this.
|
|
##
|
|
## To add a new weapon: create a WeaponData resource in client/weapons/data/
|
|
## and register it in the ALL array below.
|
|
|
|
extends Node
|
|
class_name WeaponRegistry
|
|
|
|
# Define all weapons as convenient static getters
|
|
static var KNIFE: WeaponData:
|
|
get: return _knife
|
|
static var GLOCK: WeaponData:
|
|
get: return _glock
|
|
static var USP: WeaponData:
|
|
get: return _usp
|
|
static var AK47: WeaponData:
|
|
get: return _ak47
|
|
static var M4A1: WeaponData:
|
|
get: return _m4a1
|
|
static var AWP: WeaponData:
|
|
get: return _awp
|
|
|
|
# Weapon ID constants
|
|
const ID_KNIFE: int = 0
|
|
const ID_GLOCK: int = 1
|
|
const ID_USP: int = 2
|
|
const ID_AK47: int = 3
|
|
const ID_M4A1: int = 4
|
|
const ID_AWP: int = 5
|
|
|
|
## Array of all weapons for iteration
|
|
static var ALL: Array[WeaponData] = []
|
|
|
|
## Map of weapon_id → WeaponData for fast lookup
|
|
static var BY_ID: Dictionary = {}
|
|
|
|
## Static initializer
|
|
static func _static_init() -> void:
|
|
ALL = [_knife, _glock, _usp, _ak47, _m4a1, _awp]
|
|
for w in ALL:
|
|
BY_ID[w.weapon_id] = w
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Weapon definitions
|
|
# ---------------------------------------------------------------------------
|
|
|
|
static var _knife: WeaponData = _make_weapon_data({
|
|
weapon_id = ID_KNIFE,
|
|
weapon_name = "Knife",
|
|
slot = 0,
|
|
damage = 34,
|
|
fire_mode = WeaponData.FireMode.MELEE,
|
|
fire_rate = 0.0,
|
|
magazine_size = 0,
|
|
reserve_size = 0,
|
|
move_speed_multiplier = 1.0,
|
|
price = 0,
|
|
kill_reward = 1500,
|
|
armor_penetration = 0.0,
|
|
max_distance = 3.0,
|
|
})
|
|
|
|
static var _glock: WeaponData = _make_weapon_data({
|
|
weapon_id = ID_GLOCK,
|
|
weapon_name = "Glock-18",
|
|
slot = 1,
|
|
damage = 25,
|
|
fire_rate = 6.0,
|
|
magazine_size = 20,
|
|
reserve_size = 120,
|
|
recoil_per_shot = 0.4,
|
|
move_speed_multiplier = 0.86,
|
|
price = 200,
|
|
kill_reward = 300,
|
|
armor_penetration = 0.35,
|
|
team = 0, # Terrorist default
|
|
})
|
|
|
|
static var _usp: WeaponData = _make_weapon_data({
|
|
weapon_id = ID_USP,
|
|
weapon_name = "USP-S",
|
|
slot = 1,
|
|
damage = 28,
|
|
fire_rate = 5.0,
|
|
magazine_size = 12,
|
|
reserve_size = 24,
|
|
recoil_per_shot = 0.3,
|
|
move_speed_multiplier = 0.86,
|
|
price = 200,
|
|
kill_reward = 300,
|
|
armor_penetration = 0.50,
|
|
team = 1, # CT default
|
|
})
|
|
|
|
static var _ak47: WeaponData = _make_weapon_data({
|
|
weapon_id = ID_AK47,
|
|
weapon_name = "AK-47",
|
|
slot = 3,
|
|
damage = 36,
|
|
fire_mode = WeaponData.FireMode.AUTO,
|
|
fire_rate = 10.0,
|
|
magazine_size = 30,
|
|
reserve_size = 90,
|
|
recoil_per_shot = 0.8,
|
|
recoil_recovery = 6.0,
|
|
spread_walking = 3.0,
|
|
spread_sprinting = 8.0,
|
|
move_speed_multiplier = 0.78,
|
|
price = 2700,
|
|
kill_reward = 300,
|
|
armor_penetration = 0.77,
|
|
team = 0,
|
|
})
|
|
|
|
static var _m4a1: WeaponData = _make_weapon_data({
|
|
weapon_id = ID_M4A1,
|
|
weapon_name = "M4A1-S",
|
|
slot = 3,
|
|
damage = 33,
|
|
fire_mode = WeaponData.FireMode.AUTO,
|
|
fire_rate = 10.0,
|
|
magazine_size = 25,
|
|
reserve_size = 75,
|
|
recoil_per_shot = 0.7,
|
|
recoil_recovery = 7.0,
|
|
spread_walking = 2.5,
|
|
spread_sprinting = 7.0,
|
|
move_speed_multiplier = 0.78,
|
|
price = 2900,
|
|
kill_reward = 300,
|
|
armor_penetration = 0.77,
|
|
team = 1,
|
|
})
|
|
|
|
static var _awp: WeaponData = _make_weapon_data({
|
|
weapon_id = ID_AWP,
|
|
weapon_name = "AWP",
|
|
slot = 4,
|
|
damage = 115,
|
|
fire_rate = 1.5,
|
|
magazine_size = 10,
|
|
reserve_size = 30,
|
|
recoil_per_shot = 4.0,
|
|
recoil_recovery = 1.0,
|
|
spread_idle = 0.0,
|
|
spread_walking = 10.0,
|
|
spread_sprinting = 20.0,
|
|
move_speed_multiplier = 0.57,
|
|
price = 4750,
|
|
kill_reward = 100,
|
|
armor_penetration = 0.87,
|
|
max_distance = 2000.0,
|
|
headshot_multiplier = 5.0, # AWP one-shots through armor
|
|
})
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Factory
|
|
# ---------------------------------------------------------------------------
|
|
|
|
static func _make_weapon_data(dict: Dictionary) -> WeaponData:
|
|
var w := WeaponData.new()
|
|
for key in dict:
|
|
w.set(key, dict[key])
|
|
return w
|
|
|
|
## Look up a weapon by its ID.
|
|
static func get_by_id(id: int) -> WeaponData:
|
|
return BY_ID.get(id, _knife)
|
|
|
|
## Get the default weapon for a team (0=T, 1=CT).
|
|
static func get_default_weapon(team_id: int) -> WeaponData:
|
|
return _glock if team_id == 0 else _usp
|