├── .gitattributes
├── readme-images
└── example.png
├── pawn.json
├── .travis.yml
├── test.pwn
├── .gitignore
├── LICENSE
├── .vscode
└── tasks.json
├── README.md
└── markerplus.inc
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pwn linguist-language=Pawn
2 | *.inc linguist-language=Pawn
3 |
--------------------------------------------------------------------------------
/readme-images/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Ramon-Sd/marker-plus/HEAD/readme-images/example.png
--------------------------------------------------------------------------------
/pawn.json:
--------------------------------------------------------------------------------
1 | {
2 | "user": "Ramon-Sd",
3 | "repo": "marker-plus",
4 | "tag": "1.0.0",
5 | "entry": "test.pwn",
6 | "output": "gamemodes/test.amx",
7 | "dependencies": [
8 | "pawn-lang/samp-stdlib",
9 | "samp-incognito/samp-streamer-plugin"
10 | ],
11 | "runtime": {
12 | "mode": "y_testing"
13 | }
14 | }
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: cpp
2 | sudo: enabled
3 | install:
4 | - curl https://raw.githubusercontent.com/Southclaws/sampctl/master/install-deb.sh | sh
5 | - sudo dpkg --add-architecture i386
6 | - sudo apt update && sudo apt install -y g++-multilib
7 | script:
8 | - sampctl package ensure
9 | - sampctl package build
10 | - sampctl package run
11 |
--------------------------------------------------------------------------------
/test.pwn:
--------------------------------------------------------------------------------
1 | #include "markerplus.inc"
2 |
3 | main()
4 | {
5 | return 0;
6 | }
7 |
8 | static myMarker;
9 |
10 | public OnGameModeInit() {
11 |
12 | myMarker = CreateMarker(ICON_FACTORY, true, 0.0, 0.0, 0.0);
13 | return 1;
14 | }
15 |
16 | public OnGameModeExit() {
17 |
18 | DestroyMarker(myMarker);
19 | return 1;
20 | }
21 |
22 | public OnPlayerEnterMarker(playerid, markerid) {
23 |
24 | return 1;
25 | }
26 |
27 | public OnPlayerLeaveMarker(playerid, markerid) {
28 |
29 | return 1;
30 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #
2 | # Package only files
3 | #
4 |
5 | # Compiled Bytecode, precompiled output and assembly
6 | *.amx
7 | *.lst
8 | *.asm
9 |
10 | # Vendor directory for dependencies
11 | dependencies/
12 |
13 | # Dependency versions lockfile
14 | pawn.lock
15 |
16 |
17 | #
18 | # Server/gamemode related files
19 | #
20 |
21 | # compiled settings file
22 | # keep `samp.json` file on version control
23 | # but make sure the `rcon_password` field is set externally
24 | # you can use the environment variable `SAMP_RCON_PASSWORD` to do this.
25 | server.cfg
26 |
27 | # Plugins directory
28 | plugins/
29 |
30 | # binaries
31 | *.exe
32 | *.dll
33 | *.so
34 | announce
35 | samp03svr
36 | samp-npc
37 |
38 | # logs
39 | logs/
40 | server_log.txt
41 | crashinfo.txt
42 |
43 | # Ban list
44 | samp.ban
45 |
46 | #
47 | # Common files
48 | #
49 |
50 | *.sublime-workspace
51 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Ramon
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "build only",
6 | "type": "shell",
7 | "command": "sampctl package build",
8 | "group": {
9 | "kind": "build",
10 | "isDefault": true
11 | },
12 | "isBackground": false,
13 | "presentation": {
14 | "reveal": "silent",
15 | "panel": "dedicated"
16 | },
17 | "problemMatcher": "$sampctl"
18 | },
19 | {
20 | "label": "build watcher",
21 | "type": "shell",
22 | "command": "sampctl package build --watch",
23 | "group": "build",
24 | "isBackground": true,
25 | "presentation": {
26 | "reveal": "silent",
27 | "panel": "dedicated"
28 | },
29 | "problemMatcher": "$sampctl"
30 | },
31 | {
32 | "label": "run tests",
33 | "type": "shell",
34 | "command": "sampctl package run",
35 | "group": {
36 | "kind": "test",
37 | "isDefault": true
38 | },
39 | "isBackground": true,
40 | "presentation": {
41 | "reveal": "silent",
42 | "panel": "dedicated"
43 | },
44 | "problemMatcher": "$sampctl"
45 | },
46 | {
47 | "label": "run tests watcher",
48 | "type": "shell",
49 | "command": "sampctl package run --watch",
50 | "group": "test",
51 | "isBackground": true,
52 | "presentation": {
53 | "reveal": "silent",
54 | "panel": "dedicated"
55 | },
56 | "problemMatcher": "$sampctl"
57 | }
58 | ]
59 | }
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/Ramon-Sd/marker-plus)
2 |
3 |
4 |
5 | > Enables the creation of custom markers for SA-MP.
6 |
7 |
8 |
9 | 1. [Installation](#-Installation)
10 |
11 | 2. [Documentation](#-Documentation)
12 |
13 |
14 |
15 | ## 🚀 Installation
16 |
17 | You can install the "Marker Plus" library in two ways:
18 |
19 | - Using sampctl: You can install the library using the sampctl package manager. Simply run the following command in the terminal:
20 | ```bash
21 | sampctl package install Ramon-Sd/marker-plus
22 | ```
23 |
24 | - Using Git: You can clone the library's Git repository and manually add it to your project. Run the following command in the terminal:
25 | ```bash
26 | git clone https://github.com/Ramon-Sd/marker-plus.git
27 | ```
28 |
29 | Then, include the "markerplus.inc" include file in your code:
30 |
31 | ```pawn
32 | #include "markerplus.inc"
33 | ```
34 |
35 | ## ☕ Documentation
36 |
37 | ### **Functions**
38 |
39 |
40 | - **CreateMarker**: Creates a custom marker. This function returns a unique marker ID.
41 | - Parameters:
42 | - `icon` (icon): The marker icon. It can be one of the icons defined in the `enum`.
43 | - `calledActive` (active): Indicates whether the marker is active or not.
44 | - `x`, `y`, `z` (coordinates): The coordinates of the marker in the SA-MP world.
45 | - `worldID` (optional): The ID of the world where the marker is located. The default is -1 (main world).
46 | - `interiorID` (optional): The ID of the interior where the marker is located. The default is -1 (no interior).
47 | - `drawDistance` (optional): The marker's draw distance. The default is 0.0 (always draw).
48 | - Return:
49 | - Returns the ID of the created marker, or a warning message if the marker limit is reached.
50 |
51 | - **DestroyMarker**: Destroys an existing marker in SA-MP.
52 | - Parameters:
53 | - `markerid` (marker ID): The ID of the marker to be destroyed.
54 |
55 | ### **Callbacks**
56 |
57 |
58 | - **OnPlayerEnterMarker**: Called when a player enters the area of a marker.
59 | - Parameters:
60 | - `playerid` (player ID): The ID of the player who entered the marker area.
61 | - `markerid` (marker ID): The ID of the marker whose area was accessed.
62 |
63 | - **OnPlayerLeaveMarker**: Called when a player leaves the area of a marker.
64 | - Parameters:
65 | - `playerid` (player ID): The ID of the player who left the marker area.
66 | - `markerid` (marker ID): The ID of the marker whose area was left.
67 |
68 | ### **Example**
69 |
70 |
71 | ```pawn
72 | #include "markerplus.inc"
73 |
74 | main()
75 | {
76 | return 0;
77 | }
78 |
79 | static myMarker;
80 |
81 | public OnGameModeInit() {
82 |
83 | myMarker = CreateMarker(ICON_FACTORY, true, 0.0, 0.0, 0.0);
84 | return 1;
85 | }
86 |
87 | public OnGameModeExit() {
88 |
89 | DestroyMarker(myMarker);
90 | return 1;
91 | }
92 |
93 | public OnPlayerEnterMarker(playerid, markerid) {
94 |
95 | return 1;
96 | }
97 |
98 | public OnPlayerLeaveMarker(playerid, markerid) {
99 |
100 | return 1;
101 | }
102 | ```
103 |
104 |
105 |
106 | This project is licensed. See the [LICENSE](LICENSE.md) file for more details.
107 |
--------------------------------------------------------------------------------
/markerplus.inc:
--------------------------------------------------------------------------------
1 | #if !defined _samp_included
2 | #include "a_samp.inc"
3 | #endif
4 |
5 | #if !defined _streamer_included
6 | #include "streamer.inc"
7 | #endif
8 |
9 | #if defined _INC_markerplus
10 | #endinput
11 | #endif
12 | #define _INC_markerplus
13 |
14 |
15 | #if !defined MAX_MARKERS
16 | #define MAX_MARKERS (401)
17 | #endif
18 |
19 | #define INVALID_MARKER_ID (-1)
20 |
21 |
22 | enum {
23 | ICON_INVALID,
24 | ICON_FACTORY,
25 | ICON_CONSTRUCTION,
26 | ICON_BANK,
27 | ICON_HOUSE,
28 | ICON_PRAIA,
29 | ICON_ROAD,
30 | ICON_CITY,
31 | ICON_HOUSE_2,
32 | ICON_AMBULANCE,
33 | ICON_FIRE_TRUCK,
34 | ICON_POLICE_CAR,
35 | ICON_SHIP,
36 | ICON_BUS
37 | }
38 |
39 | static const ICON_LETTER[][5] = {
40 | "NULL", "F", "A", "G", "H", "J", "K", "C", "B", "h", "f", "p", "o", "v"
41 | };
42 |
43 | static const ICON_FONT[][15] = {
44 | "NULL", "Webdings", "Webdings", "Webdings", "Webdings", "Webdings",
45 | "Webdings", "Webdings", "Webdings", "Webdings", "Webdings", "Webdings",
46 | "Webdings", "Webdings"
47 | };
48 |
49 |
50 | enum MarkerData {
51 |
52 | STREAMER_TAG_AREA:markerCalledArea,
53 | markerIcon,
54 | bool:markerCalledActive,
55 | Float:markerPosition[3],
56 | markerWorldID,
57 | markerInteriorID,
58 | Float:markerDrawDistance
59 | }
60 |
61 | enum PlayerMarkerData {
62 |
63 | markerObject[MAX_MARKERS],
64 | markerObjectIcon[MAX_MARKERS],
65 | bool:markerVisible[MAX_MARKERS]
66 | }
67 |
68 | static markerData[MAX_MARKERS][MarkerData];
69 | static playerMarkerData[MAX_PLAYERS][PlayerMarkerData];
70 |
71 |
72 | static IsValidMarker(markerid) {
73 | return !(
74 |
75 | markerData[markerid][markerPosition][0] == 0.0 &&
76 | markerData[markerid][markerPosition][1] == 0.0 &&
77 | markerData[markerid][markerPosition][2] == 0.0
78 | );
79 | }
80 |
81 | static GetFreeMarkerID() {
82 |
83 | for (new i = 0; i < MAX_MARKERS; i++) {
84 |
85 | if (!IsValidMarker(i))
86 | return i;
87 | }
88 | return INVALID_MARKER_ID;
89 | }
90 |
91 | static GetIconLetter(icon) {
92 |
93 | return ICON_LETTER[icon];
94 | }
95 |
96 | static GetIconFont(icon) {
97 |
98 | return ICON_FONT[icon];
99 | }
100 |
101 | static Player_CreateMarkers(playerID) {
102 |
103 | for (new i = 0; i < MAX_MARKERS; i++) {
104 |
105 | if (!IsValidMarker(i))
106 | continue;
107 |
108 | playerMarkerData[playerID][markerObject][i] = CreatePlayerObject(
109 | playerID,
110 | 19197,
111 | markerData[i][markerPosition][0], markerData[i][markerPosition][1], markerData[i][markerPosition][2],
112 | 0.0, 0.0, 0.0,
113 | markerData[i][markerDrawDistance]
114 | );
115 |
116 | SetPlayerObjectMaterial(
117 | playerID,
118 | playerMarkerData[playerID][markerObject][i],
119 | 0, 18646,
120 | "matcolours", "lightblue", 0x00000000
121 | );
122 |
123 | playerMarkerData[playerID][markerObjectIcon][i] = CreatePlayerObject(
124 | playerID,
125 | 11737,
126 | markerData[i][markerPosition][0], markerData[i][markerPosition][1], (markerData[i][markerPosition][2] + 1.5),
127 | 90.0, 0.0, 0.0,
128 | markerData[i][markerDrawDistance]
129 | );
130 |
131 | SetPlayerObjectMaterialText(
132 | playerID,
133 | playerMarkerData[playerID][markerObjectIcon][i],
134 | GetIconLetter(markerData[i][markerIcon]), 0, OBJECT_MATERIAL_SIZE_256x256,
135 | GetIconFont(markerData[i][markerIcon]), 150, 1, 0xFFF8F8FF, 0x00000000, 1
136 | );
137 | playerMarkerData[playerID][markerVisible][i] = true;
138 | }
139 | }
140 |
141 | static Player_DestroyMarkers(playerID) {
142 |
143 | for (new i = 0; i < MAX_MARKERS; i++) {
144 |
145 | if (playerMarkerData[playerID][markerObjectIcon][i] >= 0) {
146 | DestroyPlayerObject(playerID, playerMarkerData[playerID][markerObjectIcon][i]);
147 | playerMarkerData[playerID][markerObjectIcon][i] = INVALID_OBJECT_ID;
148 | DestroyPlayerObject(playerID, playerMarkerData[playerID][markerObject][i]);
149 | playerMarkerData[playerID][markerObject][i] = INVALID_OBJECT_ID;
150 | playerMarkerData[playerID][markerVisible][i] = false;
151 | }
152 | }
153 | }
154 |
155 | static Player_SetIconFace(playerID) {
156 |
157 | for (new i = 0; i < MAX_MARKERS; i++) {
158 |
159 | if (!IsValidMarker(i))
160 | continue;
161 |
162 | if (!playerMarkerData[playerID][markerVisible][i])
163 | continue;
164 |
165 | new Float:playerPosition[3];
166 | GetPlayerPos(playerID, playerPosition[0], playerPosition[1], playerPosition[2]);
167 |
168 | new Float:objectPosition[3];
169 | GetPlayerObjectPos(
170 | playerID,
171 | playerMarkerData[playerID][markerObjectIcon][i],
172 | objectPosition[0],
173 | objectPosition[1],
174 | objectPosition[2]
175 | );
176 |
177 | playerPosition[2] = atan2(playerPosition[1] - objectPosition[1], playerPosition[0] - objectPosition[0]) - 90.0;
178 |
179 | SetPlayerObjectRot(
180 | playerID,
181 | playerMarkerData[playerID][markerObjectIcon][i],
182 | 90.0, 0.0, playerPosition[2] + 180
183 | );
184 | }
185 | }
186 |
187 |
188 | forward OnPlayerEnterMarker(playerid, markerid);
189 | forward OnPlayerLeaveMarker(playerid, markerid);
190 |
191 |
192 | stock CreateMarker(icon, calledActive, Float:x, Float:y, Float:z, worldID = -1, interiorID = -1, Float:drawDistance = 0.0) {
193 |
194 | new markerid = GetFreeMarkerID();
195 | if (markerid == INVALID_MARKER_ID) {
196 | return printf("(!) Marker.INC -> Warning : Reached limit. (MAX_MARKERS: %d)", MAX_MARKERS);
197 | }
198 |
199 | markerData[markerid][markerCalledArea] = CreateDynamicCylinder(x, y, (z - 0.1), (z + 10.0), 1.0, worldID, interiorID, -1);
200 |
201 | markerData[markerid][markerIcon] = icon;
202 | markerData[markerid][markerCalledArea] = calledActive;
203 | markerData[markerid][markerPosition][0] = x;
204 | markerData[markerid][markerPosition][1] = y;
205 | markerData[markerid][markerPosition][2] = z;
206 | markerData[markerid][markerWorldID] = worldID;
207 | markerData[markerid][markerInteriorID] = interiorID;
208 | markerData[markerid][markerDrawDistance] = drawDistance;
209 |
210 | return markerid;
211 | }
212 |
213 | stock DestroyMarker(markerid) {
214 |
215 | new markerDataVoid[MarkerData];
216 | markerData[markerid] = markerDataVoid;
217 |
218 | for (new i = GetPlayerPoolSize(); i >= 0; i--) {
219 |
220 | if (!IsPlayerConnected(i))
221 | continue;
222 |
223 | if (playerMarkerData[i][markerObjectIcon][markerid] >= 0) {
224 | DestroyPlayerObject(i, playerMarkerData[i][markerObjectIcon][markerid]);
225 | playerMarkerData[i][markerObjectIcon][markerid] = INVALID_OBJECT_ID;
226 | }
227 | }
228 | }
229 |
230 |
231 | public OnPlayerEnterDynamicArea(playerid, STREAMER_TAG_AREA:areaid) {
232 |
233 | for (new i = 0; i < MAX_MARKERS; i++) {
234 |
235 | if (!IsValidMarker(i))
236 | continue;
237 |
238 | if (!markerData[i][markerCalledArea])
239 | continue;
240 |
241 | if (areaid == markerData[i][markerCalledArea]) {
242 |
243 | CallRemoteFunction("OnPlayerEnterMarker", "ii", playerid, i);
244 | }
245 | }
246 |
247 | #if defined MPHook_OnPlayerEnterDynamicArea
248 | return MPHook_OnPlayerEnterDynamicArea(playerid, STREAMER_TAG_AREA:areaid);
249 | #else
250 | return 1;
251 | #endif
252 | }
253 | #if defined _ALS_OnPlayerEnterDynamicArea
254 | #undef OnPlayerEnterDynamicArea
255 | #else
256 | #define _ALS_OnPlayerEnterDynamicArea
257 | #endif
258 |
259 | #define OnPlayerEnterDynamicArea MPHook_OnPlayerEnterDynamicArea
260 | #if defined MPHook_OnPlayerEnterDynamicArea
261 | forward MPHook_OnPlayerEnterDynamicArea(playerid, STREAMER_TAG_AREA:areaid);
262 | #endif
263 |
264 | public OnPlayerLeaveDynamicArea(playerid, STREAMER_TAG_AREA:areaid) {
265 |
266 | for (new i = 0; i < MAX_MARKERS; i++) {
267 |
268 | if (!IsValidMarker(i))
269 | continue;
270 |
271 | if (!markerData[i][markerCalledActive])
272 | continue;
273 |
274 | if (areaid == markerData[i][markerCalledArea]) {
275 |
276 | CallRemoteFunction("OnPlayerLeaveMarker", "ii", playerid, i);
277 | }
278 | }
279 |
280 | #if defined MPHook_OnPlayerLeaveDynamicArea
281 | return MPHook_OnPlayerLeaveDynamicArea(playerid, STREAMER_TAG_AREA:areaid);
282 | #else
283 | return 1;
284 | #endif
285 | }
286 | #if defined _ALS_OnPlayerLeaveDynamicArea
287 | #undef OnPlayerLeaveDynamicArea
288 | #else
289 | #define _ALS_OnPlayerLeaveDynamicArea
290 | #endif
291 |
292 | #define OnPlayerLeaveDynamicArea MPHook_OnPlayerLeaveDynamicArea
293 | #if defined MPHook_OnPlayerLeaveDynamicArea
294 | forward MPHook_OnPlayerLeaveDynamicArea(playerid, STREAMER_TAG_AREA:areaid);
295 | #endif
296 |
297 | public OnPlayerUpdate(playerid) {
298 |
299 | if (!IsPlayerConnected(playerid))
300 | return 0;
301 |
302 | for (new i = 0; i < MAX_MARKERS; i++) {
303 |
304 | if (!IsValidMarker(i))
305 | continue;
306 |
307 | new Float:playerPosition[3];
308 | GetPlayerPos(playerid, playerPosition[0], playerPosition[1], playerPosition[2]);
309 |
310 | if (
311 | playerPosition[0] > markerData[i][markerPosition][0] - 5.0 && playerPosition[1] > markerData[i][markerPosition][1] - 5.0 &&
312 | playerPosition[0] < markerData[i][markerPosition][0] + 5.0 && playerPosition[1] < markerData[i][markerPosition][1] + 5.0
313 | ) {
314 |
315 | if (playerMarkerData[playerid][markerVisible][i]) {
316 | SetPlayerObjectMaterialText(
317 | playerid,
318 | playerMarkerData[playerid][markerObjectIcon][i],
319 | GetIconLetter(markerData[i][markerIcon]), 0, OBJECT_MATERIAL_SIZE_256x256,
320 | GetIconFont(markerData[i][markerIcon]), 150, 1, 0x00000000, 0x00000000, 1
321 | );
322 |
323 | SetPlayerObjectPos(
324 | playerid,
325 | playerMarkerData[playerid][markerObjectIcon][i],
326 | markerData[i][markerPosition][0],
327 | markerData[i][markerPosition][1],
328 | ((markerData[i][markerPosition][2] + 1.5) * 2)
329 | );
330 |
331 | playerMarkerData[playerid][markerVisible][i] = false;
332 | }
333 | }
334 | else {
335 |
336 | if (!playerMarkerData[playerid][markerVisible][i]) {
337 |
338 | SetPlayerObjectMaterialText(
339 | playerid,
340 | playerMarkerData[playerid][markerObjectIcon][i],
341 | GetIconLetter(markerData[i][markerIcon]), 0, OBJECT_MATERIAL_SIZE_256x256,
342 | GetIconFont(markerData[i][markerIcon]), 150, 1, 0xFFF8F8FF, 0x00000000, 1
343 | );
344 |
345 | SetPlayerObjectPos(
346 | playerid,
347 | playerMarkerData[playerid][markerObjectIcon][i],
348 | markerData[i][markerPosition][0],
349 | markerData[i][markerPosition][1],
350 | (markerData[i][markerPosition][2] + 1.5)
351 | );
352 |
353 | playerMarkerData[playerid][markerVisible][i] = true;
354 | }
355 | }
356 | Player_SetIconFace(playerid);
357 | }
358 |
359 | #if defined MPHook_OnPlayerUpdate
360 | return MPHook_OnPlayerUpdate(playerid);
361 | #else
362 | return 1;
363 | #endif
364 | }
365 | #if defined _ALS_OnPlayerUpdate
366 | #undef OnPlayerUpdate
367 | #else
368 | #define _ALS_OnPlayerUpdate
369 | #endif
370 |
371 | #define OnPlayerUpdate MPHook_OnPlayerUpdate
372 | #if defined MPHook_OnPlayerUpdate
373 | forward MPHook_OnPlayerUpdate(playerid);
374 | #endif
375 |
376 | public OnPlayerConnect(playerid) {
377 |
378 | Player_CreateMarkers(playerid);
379 |
380 | #if defined MPHook_OnPlayerConnect
381 | return MPHook_OnPlayerConnect(playerid);
382 | #else
383 | return 1;
384 | #endif
385 | }
386 | #if defined _ALS_OnPlayerConnect
387 | #undef OnPlayerConnect
388 | #else
389 | #define _ALS_OnPlayerConnect
390 | #endif
391 |
392 | #define OnPlayerConnect MPHook_OnPlayerConnect
393 | #if defined MPHook_OnPlayerConnect
394 | forward MPHook_OnPlayerConnect(playerid);
395 | #endif
396 |
397 | public OnPlayerDisconnect(playerid, reason) {
398 |
399 | Player_DestroyMarkers(playerid);
400 |
401 | #if defined MPHook_OnPlayerDisconnect
402 | return MPHook_OnPlayerDisconnect(playerid, reason);
403 | #else
404 | return 1;
405 | #endif
406 | }
407 | #if defined _ALS_OnPlayerDisconnect
408 | #undef OnPlayerDisconnect
409 | #else
410 | #define _ALS_OnPlayerDisconnect
411 | #endif
412 |
413 | #define OnPlayerDisconnect MPHook_OnPlayerDisconnect
414 | #if defined MPHook_OnPlayerDisconnect
415 | forward MPHook_OnPlayerDisconnect(playerid, reason);
416 | #endif
417 |
--------------------------------------------------------------------------------