Daemon666 / CSB Checkpoints Public

KZ-style checkpoints: /cp saves origin, angles and velocity, /tp restores, /gocheck cycles saved points.

v1.0.0 139 téléchargements GPL-3.0 Dernière mise à jour Aug 23, 2026
csb_checkpoints.sma v1.0.0 163 lignes · 4.4 KB Brut
1 /*
2 * CSB Checkpoints
3 * Copyright (C) 2026 counter-strike-boost.com
4 *
5 * A lightweight KZ-style checkpoint system. /cp saves the player's origin,
6 * angles and velocity, /tp teleports back to the last saved point with
7 * set_pev + EngFunc_SetOrigin, and /gocheck cycles through every point saved on
8 * the current map. A cvar can force saving only while on the ground, and a HUD
9 * counter shows how many points are stored.
10 *
11 * Inspired by KZ / climb checkpoint plugins. Independent GPL re-implementation.
12 *
13 * This program is free software: you can redistribute it and/or modify it under
14 * the terms of the GNU General Public License as published by the Free Software
15 * Foundation, either version 3 of the License, or (at your option) any later
16 * version. It is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 * FOR A PARTICULAR PURPOSE. See <https://www.gnu.org/licenses/> for details.
19 */
20
21 #include <amxmodx>
22 #include <fakemeta>
23
24 new const PLUGIN[] = "CSB Checkpoints"
25 new const VERSION[] = "1.0.0"
26 new const AUTHOR[] = "counter-strike-boost.com"
27
28 #define MAX_CP 8
29 #define FL_ONGROUND (1<<9)
30
31 new g_pEnabled, g_pGroundOnly
32
33 new Float:g_cpOrigin[33][MAX_CP][3]
34 new Float:g_cpAngles[33][MAX_CP][3]
35 new Float:g_cpVel[33][MAX_CP][3]
36 new g_cpCount[33]
37 new g_cpCycle[33]
38
39 public plugin_init()
40 {
41 register_plugin(PLUGIN, VERSION, AUTHOR)
42
43 g_pEnabled = register_cvar("csb_cp_enabled", "1")
44 g_pGroundOnly = register_cvar("csb_cp_groundonly", "1")
45
46 register_clcmd("say /cp", "cmdSave")
47 register_clcmd("say_team /cp", "cmdSave")
48 register_clcmd("say /tp", "cmdRestore")
49 register_clcmd("say_team /tp", "cmdRestore")
50 register_clcmd("say /gocheck", "cmdCycle")
51 register_clcmd("say_team /gocheck", "cmdCycle")
52 register_clcmd("say /clearcp", "cmdClear")
53 }
54
55 public client_putinserver(id)
56 {
57 g_cpCount[id] = 0
58 g_cpCycle[id] = 0
59 }
60
61 public cmdSave(id)
62 {
63 if (!get_pcvar_num(g_pEnabled) || !is_user_alive(id))
64 return PLUGIN_HANDLED
65
66 if (get_pcvar_num(g_pGroundOnly) && !(pev(id, pev_flags) & FL_ONGROUND))
67 {
68 client_print(id, print_chat, "[CSB] You must be on the ground to save a checkpoint.")
69 return PLUGIN_HANDLED
70 }
71
72 if (g_cpCount[id] >= MAX_CP)
73 {
74 /* drop the oldest by shifting down */
75 for (new i = 1; i < MAX_CP; i++)
76 {
77 copyVec(g_cpOrigin[id][i - 1], g_cpOrigin[id][i])
78 copyVec(g_cpAngles[id][i - 1], g_cpAngles[id][i])
79 copyVec(g_cpVel[id][i - 1], g_cpVel[id][i])
80 }
81
82 g_cpCount[id] = MAX_CP - 1
83 }
84
85 new slot = g_cpCount[id]
86
87 pev(id, pev_origin, g_cpOrigin[id][slot])
88 pev(id, pev_v_angle, g_cpAngles[id][slot])
89 pev(id, pev_velocity, g_cpVel[id][slot])
90
91 g_cpCount[id]++
92 g_cpCycle[id] = g_cpCount[id] - 1
93
94 showCount(id, "Checkpoint saved")
95 return PLUGIN_HANDLED
96 }
97
98 public cmdRestore(id)
99 {
100 if (!get_pcvar_num(g_pEnabled) || !is_user_alive(id))
101 return PLUGIN_HANDLED
102
103 if (g_cpCount[id] <= 0)
104 {
105 client_print(id, print_chat, "[CSB] No checkpoint saved yet. Use /cp first.")
106 return PLUGIN_HANDLED
107 }
108
109 teleport(id, g_cpCount[id] - 1)
110 showCount(id, "Teleported to last checkpoint")
111 return PLUGIN_HANDLED
112 }
113
114 public cmdCycle(id)
115 {
116 if (!get_pcvar_num(g_pEnabled) || !is_user_alive(id))
117 return PLUGIN_HANDLED
118
119 if (g_cpCount[id] <= 0)
120 {
121 client_print(id, print_chat, "[CSB] No checkpoints saved.")
122 return PLUGIN_HANDLED
123 }
124
125 g_cpCycle[id] = (g_cpCycle[id] + 1) % g_cpCount[id]
126 teleport(id, g_cpCycle[id])
127
128 client_print(id, print_chat, "[CSB] Checkpoint %d / %d.", g_cpCycle[id] + 1, g_cpCount[id])
129 return PLUGIN_HANDLED
130 }
131
132 public cmdClear(id)
133 {
134 g_cpCount[id] = 0
135 g_cpCycle[id] = 0
136 client_print(id, print_chat, "[CSB] Checkpoints cleared.")
137 return PLUGIN_HANDLED
138 }
139
140 teleport(id, slot)
141 {
142 if (slot < 0 || slot >= g_cpCount[id])
143 return
144
145 engfunc(EngFunc_SetOrigin, id, g_cpOrigin[id][slot])
146 set_pev(id, pev_angles, g_cpAngles[id][slot])
147 set_pev(id, pev_v_angle, g_cpAngles[id][slot])
148 set_pev(id, pev_fixangle, 1)
149 set_pev(id, pev_velocity, g_cpVel[id][slot])
150 }
151
152 copyVec(Float:dest[3], const Float:src[3])
153 {
154 dest[0] = src[0]
155 dest[1] = src[1]
156 dest[2] = src[2]
157 }
158
159 showCount(id, const what[])
160 {
161 client_print(id, print_chat, "[CSB] %s (%d stored).", what, g_cpCount[id])
162 }
163