├── .gitattributes ├── pawn.json ├── .gitignore ├── test.pwn ├── .vscode └── tasks.json ├── README.md └── actor_robbery.inc /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pwn linguist-language=Pawn 2 | *.inc linguist-language=Pawn 3 | -------------------------------------------------------------------------------- /pawn.json: -------------------------------------------------------------------------------- 1 | { 2 | "user": "Patrick", 3 | "repo": "actor_robbery", 4 | "entry": "test.pwn", 5 | "output": "test.amx", 6 | "dependencies": [ 7 | "sampctl/samp-stdlib" 8 | ] 9 | } -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /test.pwn: -------------------------------------------------------------------------------- 1 | #include 2 | #include "actor_robbery.inc" 3 | 4 | main() { 5 | new actor= Robbery_CreateActor(5, 192.168, 1.1, 1.10, 90, 1, 5000, 15000); 6 | actor = Robbery_CreateActor(5, 192.168, 1.1, 1.10, 90, 1, 5000, 15000); 7 | actor = Robbery_CreateActor(5, 192.168, 1.1, 1.10, 90, 1, 5000, 15000); 8 | actor = Robbery_CreateActor(5, 192.168, 1.1, 1.10, 90, 1, 5000, 15000); 9 | actor = Robbery_CreateActor(5, 192.168, 1.1, 1.10, 90, 1, 5000, 15000); 10 | actor = Robbery_CreateActor(5, 192.168, 1.1, 1.10, 90, 1, 5000, 15000); 11 | actor = Robbery_CreateActor(5, 192.168, 1.1, 1.10, 90, 1, 5000, 15000); 12 | actor = Robbery_CreateActor(5, 192.168, 1.1, 1.10, 90, 1, 5000, 15000); 13 | 14 | printf("total actors: %i", actor); 15 | new 16 | Float:x, 17 | Float:y, 18 | Float:z, 19 | Float:ang, 20 | skinid, 21 | vwid, 22 | _min, 23 | _max; 24 | Robbery_GetActorData(actor, skinid, x, y, z, ang, vwid, _min, _max); 25 | 26 | printf("actor, skinid, x, y, z, ang, min, max", actor, skinid, x, y, z, ang, vwid, _min, _max); 27 | } 28 | 29 | public OnPlayerKeyStateChange(playerid, newkeys, oldkeys) { 30 | return 1; 31 | } 32 | 33 | public OnPlayerRequestRobbery(playerid, actorid) { 34 | new exampleName[24]; 35 | GetPlayerName(playerid, exampleName, 24); 36 | 37 | if(!strcmp(exampleName, "COP")) 38 | { 39 | SendClientMessage(playerid, -1, "COP no ROB."); 40 | return 0; // Must return 0 for the robbery to not commence. 41 | } 42 | return 1; 43 | } 44 | -------------------------------------------------------------------------------- /.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 | # actor_robbery 2 | 3 | [![sampctl](https://img.shields.io/badge/sampctl-actor_robbery-2f2f2f.svg?style=for-the-badge)](https://github.com/Patrick/actor_robbery) 4 | 5 | 33 | 34 | ## Table of Contents 35 | 36 | * [Introduction](#introduction) 37 | * [Installation](#Installation) 38 | * [Testing](#testing) 39 | * [Usage](#usage) 40 | 41 | ## Introduction 42 | 43 | Inspired by GTA V store robbery. **actor_robbery.inc** imitates it! You basically aim at the actor and the actor will play 3 animation sequence, the actor will either give you the money or you will leave empty handed. 44 | 45 | ## Installation 46 | 47 | Simply install to your project: 48 | 49 | ```bash 50 | sampctl package install Patrick/actor_robbery 51 | ``` 52 | 53 | Include in your code and begin using the library: 54 | 55 | ```pawn 56 | #include 57 | ``` 58 | 59 | ## Testing 60 | 61 | 65 | 66 | To test, simply run the package: 67 | 68 | ```bash 69 | sampctl package run 70 | ``` 71 | 72 | ## Usage 73 | 74 | **Functions** 75 | ``` 76 | Function: 77 | CreateActorRobbery 78 | 79 | Info: 80 | Creates the robbery actor according to the position set. 81 | 82 | Param: 83 | * skinid -> Skin ID of the robbery actor 84 | * Float:x -> Coordinate X of the robbery actor 85 | * Float:y -> Coordinate X of the robbery actor 86 | * Float:z -> Coordinate X of the robbery actor 87 | * Float:ang -> Facing angle of the robbery actor 88 | * actor_vwid -> virtualid of the robbery actor 89 | * r_moneymin -> Minimum money to be robbed from the robbery actor 90 | * r_moneymax -> Maximum money to be robbed from the robbery actor 91 | 92 | Function: 93 | GetActorRobberyData 94 | 95 | Info: 96 | Retrieves the actor data 97 | 98 | Param: 99 | * actorid -> ID of robbery actor you want to retrieve data from. 100 | * &skinid -> Skin ID of the robbery actor 101 | * &Float:x -> Coordinate X of the robbery actor 102 | * &Float:y -> Coordinate X of the robbery actor 103 | * &Float:z -> Coordinate X of the robbery actor 104 | * &Float:ang -> Facing angle of the robbery actor 105 | * &actor_vwid -> virtualid of the robbery actor 106 | * &r_moneymin -> Minimum money to be robbed from the robbery actor 107 | * &r_moneymax -> Maximum money to be robbed from the robbery actor 108 | 109 | Function: 110 | GetActorFreeID 111 | 112 | Info: 113 | Retrieves the unused ID of an actor. 114 | 115 | Param: 116 | None 117 | ``` 118 | 119 | **Callbacks** 120 | ``` 121 | //OnPlayerRequestRobbery is called when the player aims at an actor. You can disallow a player from robbing by returning 0. 122 | forward OnPlayerRequestRobbery(playerid, actorid); 123 | 124 | //OnPlayerStartRobbery is called when the player aims at an actor after OnPlayerRequestRobbery allows the player to rob. 125 | forward OnPlayerStartRobbery(playerid, actorid, robbed_recently); 126 | 127 | //OnPlayerFinishRobbery is called when the 3 animation sequence has been played. 128 | forward OnPlayerFinishRobbery(playerid, actorid, robbedmoney, type); 129 | ``` 130 | **Animation Sequence** 131 | 132 | 1. SHP_Rob_HandsUp 133 | 2. SHP_Rob_GiveCash 134 | 3. DUCK_cower 135 | -------------------------------------------------------------------------------- /actor_robbery.inc: -------------------------------------------------------------------------------- 1 | /* 2 | [DECLARATIONS] 3 | */ 4 | 5 | #if !defined _samp_included 6 | #error Please include a_samp before actor_robbery. 7 | #endif 8 | 9 | #if !defined KEY_AIM 10 | #define KEY_AIM 128 11 | #endif 12 | 13 | #if !defined PreloadAnimLib 14 | #define PreloadAnimLib(%1,%2) ApplyAnimation(%1,%2,"null",0.0,0,0,0,0,0) 15 | #endif 16 | 17 | #define MAX_ROBBERY_ACTORS (50) 18 | 19 | #define TYPE_SUCCESS (0) 20 | #define TYPE_FAILED (1) 21 | #define TYPE_UNFINISHED (2) 22 | 23 | #define MIN_MONEY_ROB 500 24 | #define MAX_MONEY_ROB 10000 25 | #define ROBBERY_WAIT_TIME (5) 26 | 27 | 28 | 29 | enum E_ACTOR_ROBBERY_DATA 30 | { 31 | actor_skin, 32 | Float:actor_x, 33 | Float:actor_y, 34 | Float:actor_z, 35 | Float:actor_ang, 36 | actor_vw, 37 | money_min, 38 | money_max, 39 | 40 | bool:actor_created, 41 | actor_robbedRecently 42 | } 43 | static 44 | robbery_data[MAX_ROBBERY_ACTORS][E_ACTOR_ROBBERY_DATA], 45 | i_actor = 0; 46 | 47 | forward RunActorAnimationSequence(playerid, actorid, animation_pattern); 48 | forward OnPlayerStartRobbery(playerid, actorid, bool:robbed_recently); 49 | forward OnPlayerFinishRobbery(playerid, actorid, robbedmoney, type); 50 | forward OnPlayerRequestRobbery(playerid, actorid); 51 | 52 | 53 | /* 54 | Function: 55 | CreateActorRobbery 56 | 57 | Info: 58 | Creates the robbery actor according to the position set. 59 | 60 | Param: 61 | * skinid -> Skin ID of the robbery actor 62 | * Float:x -> Coordinate X of the robbery actor 63 | * Float:y -> Coordinate X of the robbery actor 64 | * Float:z -> Coordinate X of the robbery actor 65 | * Float:ang -> Facing angle of the robbery actor 66 | * actor_vwid -> virtualid of the robbery actor 67 | * r_moneymin -> Minimum money to be robbed from the robbery actor 68 | * r_moneymax -> Maximum money to be robbed from the robbery actor 69 | 70 | */ 71 | 72 | 73 | 74 | #pragma deprecated GetActorRobberyData 75 | stock GetActorRobberyData(actorid, &skinid, &Float:x, &Float:y, &Float:z, &Float:ang, &actor_vwid, &r_moneymin, &r_moneymax) { 76 | #pragma unused actorid, skinid, x, y, z, ang, actor_vwid, r_moneymin, r_moneymax 77 | } 78 | 79 | #pragma deprecated Please use new function name Robbery_CreateActor. 80 | stock CreateActorRobbery(skinid, Float:x, Float:y, Float:z, Float:ang, actor_vwid = 0, r_moneymin = MIN_MONEY_ROB, r_moneymax = MAX_MONEY_ROB) { 81 | #pragma unused skinid, x, y, z, ang, actor_vwid, r_moneymin, r_moneymax 82 | return -1; 83 | } 84 | 85 | stock Robbery_CreateActor(skinid, Float:x, Float:y, Float:z, Float:ang, actor_vwid = 0, r_moneymin = MIN_MONEY_ROB, r_moneymax = MAX_MONEY_ROB) { 86 | new actorid = GetActorFreeID(); 87 | 88 | if(actorid == -1) { 89 | print("ERROR: Robbery_CreateActor - MAX_ROBBERY_ACTOR reached, increase the limit size."); 90 | return -1; 91 | } 92 | 93 | CreateActor(skinid, x, y, z, ang); 94 | SetActorVirtualWorld(actorid, actor_vwid); 95 | 96 | robbery_data[actorid][actor_created] = true; 97 | robbery_data[actorid][actor_skin] = skinid; 98 | robbery_data[actorid][actor_x] = x; 99 | robbery_data[actorid][actor_y] = y; 100 | robbery_data[actorid][actor_z] = z; 101 | robbery_data[actorid][actor_ang] = ang; 102 | robbery_data[actorid][actor_vw] = actor_vwid; 103 | robbery_data[actorid][money_min] = r_moneymin; 104 | robbery_data[actorid][money_max] = r_moneymax; 105 | 106 | return (i_actor ++); 107 | } 108 | 109 | /* 110 | Function: 111 | Robbery_GetActorData 112 | 113 | Info: 114 | Retrieves the actor data 115 | 116 | Param: 117 | * actorid -> ID of robbery actor you want to retrieve data from. 118 | * &skinid -> Skin ID of the robbery actor 119 | * &Float:x -> Coordinate X of the robbery actor 120 | * &Float:y -> Coordinate X of the robbery actor 121 | * &Float:z -> Coordinate X of the robbery actor 122 | * &Float:ang -> Facing angle of the robbery actor 123 | * &actor_vwid -> virtualid of the robbery actor 124 | * &r_moneymin -> Minimum money to be robbed from the robbery actor 125 | * &r_moneymax -> Maximum money to be robbed from the robbery actor 126 | */ 127 | 128 | stock Robbery_GetActorData(actorid, &skinid, &Float:x, &Float:y, &Float:z, &Float:ang, &actor_vwid, &r_moneymin, &r_moneymax) { 129 | if(actorid == INVALID_ACTOR_ID) { 130 | print("ERROR: GetActorRobberyData - Invalid actorid input."); 131 | return 1; 132 | } 133 | 134 | skinid = robbery_data[actorid][actor_skin]; 135 | x = robbery_data[actorid][actor_x]; 136 | y = robbery_data[actorid][actor_y]; 137 | z = robbery_data[actorid][actor_z] ; 138 | ang = robbery_data[actorid][actor_ang] ; 139 | actor_vwid = robbery_data[actorid][actor_vw]; 140 | r_moneymin = robbery_data[actorid][money_min]; 141 | r_moneymax = robbery_data[actorid][money_max]; 142 | return 1; 143 | } 144 | 145 | /* 146 | Function: 147 | GetActorFreeID 148 | 149 | Info: 150 | Retrieves the unused ID of an actor. 151 | 152 | Param: 153 | None 154 | 155 | */ 156 | 157 | static stock GetActorFreeID() 158 | { 159 | for(new i = 0; i < MAX_ROBBERY_ACTORS; i++) { 160 | if(!robbery_data[i][actor_created]) { 161 | return i; 162 | } 163 | } 164 | return -1; 165 | } 166 | 167 | /* 168 | Robbery IMPL 169 | */ 170 | 171 | public RunActorAnimationSequence(playerid, actorid, animation_pattern) { 172 | switch(animation_pattern) { 173 | case 0: { 174 | ClearActorAnimations(actorid); 175 | ApplyActorAnimation(actorid, "SHOP", "SHP_Rob_HandsUp", 4.1, 0, 1, 1, 1, 0); 176 | 177 | SetTimerEx("RunActorAnimationSequence", 1000 * ROBBERY_WAIT_TIME, false, "iii", playerid, actorid, 1); 178 | 179 | new Float:x, Float:y, Float:z; 180 | GetPlayerPos(playerid, x, y, z); 181 | 182 | for(new i = 0, j = GetPlayerPoolSize(); i <= j; i++) { 183 | if(!IsPlayerConnected(i)) { 184 | continue; 185 | } 186 | PlayerPlaySound(i, 3401, x, y, z); 187 | } 188 | } 189 | case 1: { 190 | if(!IsPlayerInRangeOfPoint(playerid, 10.0, robbery_data[actorid][actor_x], robbery_data[actorid][actor_y], robbery_data[actorid][actor_z])) { 191 | CallLocalFunction("OnPlayerFinishRobbery", "iiii", playerid, actorid, 0, TYPE_UNFINISHED); 192 | } 193 | else { 194 | ClearActorAnimations(actorid); 195 | ApplyActorAnimation(actorid, "SHOP", "SHP_Rob_GiveCash", 4.1, 0, 1, 1, 1, 0); 196 | 197 | SetTimerEx("RunActorAnimationSequence", 1000 * ROBBERY_WAIT_TIME, false, "iii", playerid, actorid, 2); 198 | } 199 | } 200 | case 2: { 201 | ClearActorAnimations(actorid); 202 | ApplyActorAnimation(actorid, "PED", "DUCK_cower", 4.1, 1, 1, 1, 1, 1); 203 | 204 | SetTimerEx("RunActorAnimationSequence", 1000 * 60 * ROBBERY_WAIT_TIME, false, "iii", playerid, actorid, 3); 205 | 206 | new robberyChance = random(100); 207 | if(robberyChance > 40) { 208 | CallLocalFunction("OnPlayerFinishRobbery", "iiii", playerid, actorid, (random(robbery_data[actorid][money_max] - robbery_data[actorid][money_min]) + robbery_data[actorid][money_min]), TYPE_SUCCESS); 209 | } 210 | else { 211 | CallLocalFunction("OnPlayerFinishRobbery", "iiii", playerid, actorid, 0, TYPE_FAILED); 212 | } 213 | } 214 | case 3: { 215 | ClearActorAnimations(actorid); 216 | PlayerPlaySound(playerid, 0, 0.0, 0.0, 0.0); 217 | } 218 | } 219 | return 1; 220 | } 221 | 222 | public OnPlayerConnect(playerid) 223 | { 224 | EnablePlayerCameraTarget(playerid, 1); 225 | 226 | PreloadAnimLib(playerid, "PED"); 227 | PreloadAnimLib(playerid, "SHOP"); 228 | 229 | #if defined actorrob_OnPlayerConnect 230 | return actorrob_OnPlayerConnect(playerid); 231 | #else 232 | return 1; 233 | #endif 234 | } 235 | 236 | public OnPlayerKeyStateChange(playerid, newkeys, oldkeys) 237 | { 238 | if((newkeys & KEY_AIM) == KEY_AIM && GetPlayerState(playerid) == PLAYER_STATE_ONFOOT) 239 | { 240 | switch(GetPlayerWeapon(playerid)) 241 | { 242 | case 22 .. 33: 243 | { 244 | new actorid = GetPlayerCameraTargetActor(playerid); 245 | 246 | if(actorid == INVALID_ACTOR_ID) { 247 | return 1; 248 | } 249 | 250 | if(!robbery_data[actorid][actor_created]) { 251 | // this fixes the issue with normal create actors. 252 | // there was a bug that you aim at an actor and rob it even though it wasn't created by actor_robbery. 253 | return 1; 254 | } 255 | 256 | if(!OnPlayerRequestRobbery(playerid, actorid)) 257 | { 258 | return 1; 259 | } 260 | 261 | if(gettime() - robbery_data[actorid][actor_robbedRecently] < 60 * ROBBERY_WAIT_TIME) { 262 | return CallLocalFunction("OnPlayerStartRobbery", "iii", playerid, actorid, true); 263 | } 264 | 265 | robbery_data[actorid][actor_robbedRecently] = gettime(); 266 | RunActorAnimationSequence(playerid, actorid, 0); 267 | CallLocalFunction("OnPlayerStartRobbery", "iii", playerid, actorid, false); 268 | } 269 | } 270 | } 271 | #if defined actorrob_OnPlayerKeyStateChange 272 | return actorrob_OnPlayerKeyStateChange(playerid, newkeys, oldkeys); 273 | #else 274 | return 1; 275 | #endif 276 | } 277 | 278 | /* OnPlayerRequestRobbery 279 | Usage: return 0 to disallow the robbery. 280 | See test.pwn for example. 281 | */ 282 | 283 | public OnPlayerRequestRobbery(playerid, actorid) 284 | { 285 | #if defined actorrob_OnPlayerRequestRobbery 286 | return actorrob_OnPlayerRequestRobbery(playerid, actorid); 287 | #else 288 | return 1; // Default version always wants to returns >1 to allow robbery 289 | #endif 290 | } 291 | 292 | //OnPlayerKeyStateChange hook directives 293 | 294 | #if defined _ALS_OnPlayerKeyStateChange 295 | #undef OnPlayerKeyStateChange 296 | #else 297 | #define _ALS_OnPlayerKeyStateChange 298 | #endif 299 | 300 | #define OnPlayerKeyStateChange actorrob_OnPlayerKeyStateChange 301 | 302 | #if defined actorrob_OnPlayerKeyStateChange 303 | forward actorrob_OnPlayerKeyStateChange(playerid, newkeys, oldkeys); 304 | #endif 305 | 306 | //OnPlayerConnect directives 307 | 308 | #if defined _ALS_OnPlayerConnect 309 | #undef OnPlayerConnect 310 | #else 311 | #define _ALS_OnPlayerConnect 312 | #endif 313 | #define OnPlayerConnect actorrob_OnPlayerConnect 314 | #if defined actorrob_OnPlayerConnect 315 | forward actorrob_OnPlayerConnect(playerid); 316 | #endif 317 | 318 | //OnPlayerRequestRobbery directives 319 | 320 | #if defined _ALS_OnPlayerRequestRobbery 321 | #undef OnPlayerRequestRobbery 322 | #else 323 | #define _ALS_OnPlayerRequestRobbery 324 | #endif 325 | #define OnPlayerRequestRobbery actorrob_OnPlayerRequestRobbery 326 | #if defined actorrob_OnPlayerRequestRobbery 327 | forward actorrob_OnPlayerRequestRobbery(playerid); 328 | #endif 329 | --------------------------------------------------------------------------------