params.gno
3.84 Kb · 112 lines
1package game
2
3import "chain"
4
5// param is one tunable number of the game, with the bounds an admin has to
6// stay within.
7type param struct {
8 key string
9 value int64
10 min int64
11 max int64
12 doc string
13}
14
15// paramLeaderboardSize is the one param the realm itself consumes. Every
16// other param is only stored here and applied by the game server.
17const paramLeaderboardSize = "leaderboard_size"
18
19// defaultParams returns the registry with its default values. The order is
20// the display order, in StateJSON as well as in Render.
21func defaultParams() []*param {
22 return []*param{
23 {"plane_speed", 70, 20, 300, "cruise speed, m/s"},
24 {"boost_speed", 130, 20, 600, "speed while boosting, m/s"},
25 {"boost_capacity_ms", 4000, 0, 60000, "how long a full boost tank lasts, 0 disables boost"},
26 {"boost_recharge_ms", 10000, 100, 600000, "time to refill an empty tank while not boosting"},
27 {"turn_rate", 80, 20, 360, "pitch and turn responsiveness, deg/s"},
28 {"plane_health", 100, 1, 1000, "hit points"},
29 {"fire_cooldown_ms", 160, 50, 5000, "minimum time between shots"},
30 {"bullet_speed", 400, 100, 2000, "m/s"},
31 {"bullet_ttl_ms", 1500, 100, 10000, "bullet lifetime"},
32 {"bullet_damage", 20, 1, 1000, "hit points removed per bullet"},
33 {"respawn_ms", 3000, 0, 60000, "delay before a destroyed plane respawns"},
34 {"balloon_respawn_ms", 6000, 0, 600000, "delay before a popped balloon comes back"},
35 {paramLeaderboardSize, 10, 1, 100, "entries a leaderboard keeps, on-chain and on the server"},
36 {"max_players", 64, 1, 1000, "server capacity"},
37 {"bot_max", 2, 0, 16, "bots flying with a lone pilot, 0 for no bots"},
38 {"bot_off_players", 5, 1, 64, "from this many pilots there are no bots"},
39 {"bot_aim_error", 8, 0, 45, "how far a bot's shot can stray from its aim, degrees"},
40 {"bot_fire_interval_ms", 900, 100, 10000, "minimum time between a bot's shots"},
41 }
42}
43
44// findParam returns the param registered under key, or nil. The registry is
45// a dozen entries, a linear scan is cheaper than any index.
46func findParam(key string) *param {
47 for _, p := range params {
48 if p.key == key {
49 return p
50 }
51 }
52 return nil
53}
54
55// SetParam changes a game parameter. Admin only.
56//
57// The key must exist and the value must be within the bounds of that key,
58// see Render("params"). Lowering leaderboard_size truncates the kill
59// leaderboard right away. Raising it does not bring back the lines that were
60// dropped: the list fills up again as kills come in.
61func SetParam(cur realm, key string, value int64) {
62 assertAdmin(0, cur)
63 p := findParam(key)
64 if p == nil {
65 panic(errUnknownParam)
66 }
67 if value < p.min || value > p.max {
68 panic("gnofly: " + key + " must be between " + itoa(p.min) + " and " + itoa(p.max))
69 }
70 p.value = value
71 if key == paramLeaderboardSize {
72 trimRankings()
73 }
74 bump()
75 chain.Emit("ParamSet", "key", key, "value", itoa(value))
76}
77
78// SetParamBounds changes the range SetParam accepts for a key. Owner only.
79//
80// The bounds are the guard rail between the owner and the admins: admins tune
81// values within them, the owner decides how far tuning may go. The current
82// value has to fit the new bounds, so that the registry never holds a value
83// SetParam would refuse.
84func SetParamBounds(cur realm, key string, min, max int64) {
85 assertOwner(0, cur)
86 p := findParam(key)
87 if p == nil {
88 panic(errUnknownParam)
89 }
90 if min < 0 || min > max {
91 panic(errInvalidBounds)
92 }
93 // An empty leaderboard has no last line to compare a new total with.
94 if key == paramLeaderboardSize && min < 1 {
95 panic(errLeaderboardMin)
96 }
97 if p.value < min || p.value > max {
98 panic(errValueOutOfBounds)
99 }
100 p.min, p.max = min, max
101 bump()
102 chain.Emit("ParamBoundsSet", "key", key, "min", itoa(min), "max", itoa(max))
103}
104
105// Param returns the value of a game parameter. It panics on an unknown key.
106func Param(key string) int64 {
107 p := findParam(key)
108 if p == nil {
109 panic(errUnknownParam)
110 }
111 return p.value
112}