/* * Irresistible Gaming (c) 2018 * Developed by Lorenc Pekaj * Module: cnr\features\robbery\safes.pwn * Purpose: safe robbery system (within stores) */ /* ** Includes ** */ #include < YSI\y_hooks > /* ** Definitions ** */ #define MAX_ROBBERIES ( 500 ) #define MAX_ROBBERY_WAIT ( 300 ) #define MAX_DRILL_STRENGTH ( 200 ) #define ROBBERY_MONEYCASE_BONUS ( 1.4 ) #define STATE_NONE ( 0 ) #define STATE_ROBBED ( 1 ) #define STATE_PICKED ( 2 ) /* ** Variables ** */ enum E_ROBBERY_SYSTEM { E_NAME[ 32 ], E_ROB_VALUE, E_WORLD, E_ROB_TIME, bool: E_ROBBED, E_STATE, E_SAFE, E_SAFE_DOOR, E_SAFE_MONEY, E_SAFE_LOOT, E_ROBTIMER, bool: E_OPEN, E_C4, bool: E_C4_SLOT, E_DRILL, E_DRILL_PLACER, E_DRILL_EFFECT, Float: E_DOOR_X, Float: E_DOOR_Y, Float: E_DOOR_Z, Float: E_DOOR_ROT, Text3D: E_LABEL, Float: E_MULTIPLIER, E_BUSINESS_ID }; enum { ROBBERY_TYPE_DRILL, ROBBERY_TYPE_C4, ROBBERY_TYPE_LABOR }; new g_robberyData [ MAX_ROBBERIES ] [ E_ROBBERY_SYSTEM ], p_drillStrength [ MAX_PLAYERS ], Iterator:RobberyCount ; /* ** Forwards ** */ stock Float: distanceFromSafe( iPlayer, iRobbery, &Float: fDistance = Float: 0x7F800000 ) { static Float: fX, Float: fY, Float: fZ; if ( ! Iter_Contains( RobberyCount, iRobbery ) ) return fDistance; if ( g_robberyData[ iRobbery ] [ E_WORLD ] != -1 && g_robberyData[ iRobbery ] [ E_WORLD ] != GetPlayerVirtualWorld( iPlayer ) ) return fDistance; if ( GetDynamicObjectPos( g_robberyData[ iRobbery ] [ E_SAFE ], fX, fY, fZ ) ) fDistance = GetPlayerDistanceFromPoint( iPlayer, fX, fY, fZ ); return fDistance; } /* ** Hooks ** */ hook OnServerUpdate( ) { // Replenish Robberies foreach ( new robberyid : RobberyCount ) if ( g_iTime > g_robberyData[ robberyid ] [ E_ROB_TIME ] && g_robberyData[ robberyid ] [ E_ROBBED ] ) { setSafeReplenished( robberyid ); } return 1; } /* ** Functions ** */ stock CreateRobberyCheckpoint( szName[ 32 ], iRobValue, Float: fX, Float: fY, Float: fZ, Float: rotation, worldid ) { new Float: offsetX, Float: offsetY; new rID = Iter_Free( RobberyCount ); if ( rID != ITER_NONE ) { Iter_Add( RobberyCount, rID ); //fX += 0.1 * floatsin( rotation, degrees ); //fY += 0.1 * floatcos( rotation, degrees ); g_robberyData[ rID ] [ E_SAFE ] = CreateDynamicObject( 19618, fX, fY, fZ, 0, 0, rotation, worldid ); offsetX = 0.48 * floatsin( -( rotation + 119 ), degrees ); offsetY = 0.48 * floatcos( -( rotation + 119 ), degrees ); // SAFE DOOR g_robberyData[ rID ] [ E_DOOR_X ] = fX + offsetX; g_robberyData[ rID ] [ E_DOOR_Y ] = fY + offsetY; g_robberyData[ rID ] [ E_DOOR_Z ] = fZ; g_robberyData[ rID ] [ E_DOOR_ROT ] = rotation; g_robberyData[ rID ] [ E_SAFE_DOOR ] = CreateDynamicObject( 19619, fX + offsetX, fY + offsetY, fZ, 0, 0, rotation, worldid ); // SetDynamicObjectMaterial( g_robberyData[ rID ] [ E_SAFE ], 5, 1829, "kbmiscfrn2", "man_mny1", 0 ); // SetDynamicObjectMaterial( g_robberyData[ rID ] [ E_SAFE_DOOR ], 2, 0, "none", "none", -1 ); g_robberyData[ rID ] [ E_LABEL ] = CreateDynamic3DTextLabel( sprintf( "%s\n"COL_WHITE"Left ALT To Crack Safe", szName ), COLOR_GREY, fX, fY, fZ, 15.0, .testlos = 0, .worldid = worldid ); format( g_robberyData[ rID ] [ E_NAME ], 32, "%s", szName ); g_robberyData[ rID ] [ E_WORLD ] = worldid; g_robberyData[ rID ] [ E_ROB_VALUE ] = iRobValue; g_robberyData[ rID ] [ E_ROBBED ] = false; g_robberyData[ rID ] [ E_STATE ] = STATE_NONE; g_robberyData[ rID ] [ E_ROBTIMER ] = 0xFFFF; g_robberyData[ rID ] [ E_DRILL_PLACER ] = INVALID_PLAYER_ID; g_robberyData[ rID ] [ E_DRILL_EFFECT ] = INVALID_OBJECT_ID; g_robberyData[ rID ] [ E_MULTIPLIER ] = 1.0; g_robberyData[ rID ] [ E_BUSINESS_ID ] = -1; return rID; } else { static surplus; printf("Too many robberies created. Increase MAX_BUSINESSES to %d", ++surplus + MAX_BUSINESSES ); } return ITER_NONE; // if there's multiple, we will return none } stock CreateMultipleRobberies( szName[ 32 ], iRobValue, Float: fX, Float: fY, Float: fZ, Float: rotation, ... ) { for( new i = 6; i < numargs( ); i++ ) { new worldid = getarg( i ); CreateRobberyCheckpoint( szName, iRobValue, fX, fY, fZ, rotation, worldid ); if ( worldid == -1 ) break; } } stock getClosestRobberySafe( playerid, &Float: dis = 99999.99 ) { new Float: dis2, object = INVALID_OBJECT_ID, Float: X, Float: Y, Float: Z, world = GetPlayerVirtualWorld( playerid ) ; foreach(new i : RobberyCount) { if ( world != 0 && g_robberyData[ i ] [ E_WORLD ] != -1 && g_robberyData[ i ] [ E_WORLD ] != world ) continue; GetDynamicObjectPos( g_robberyData[ i ] [ E_SAFE ], X, Y, Z ); dis2 = GetPlayerDistanceFromPoint( playerid, X, Y, Z ); if ( dis2 < dis && dis2 != -1.00 ) { dis = dis2; object = i; } } return object; } stock GetXYInFrontOfSafe( robberyid, &Float: X, &Float: Y, &Float: Z, Float: distance = 1.1 ) // old 1.25 { static Float: iFloat; GetDynamicObjectPos( g_robberyData[ robberyid ] [ E_SAFE ], X, Y, Z ); GetDynamicObjectRot( g_robberyData[ robberyid ] [ E_SAFE ], iFloat, iFloat, iFloat ); X += distance * -floatsin( -iFloat, degrees ); Y += distance * -floatcos( -iFloat, degrees ); } stock AttachToRobberySafe( robberyid, playerid, type ) { if ( !IsPlayerConnected( playerid ) ) return 0xFFFF; // Not connected if (!Iter_Contains(RobberyCount, robberyid)) return 0xAA; // Invalid Robbery if ( ( g_robberyData[ robberyid ] [ E_C4_SLOT ] == true && type == ROBBERY_TYPE_DRILL ) || ( g_robberyData[ robberyid ] [ E_DRILL_PLACER ] != INVALID_PLAYER_ID && type == ROBBERY_TYPE_C4 ) ) return 0x1B; // Is occupied? if ( g_robberyData[ robberyid ] [ E_ROBBED ] || g_robberyData[ robberyid ] [ E_OPEN ] || g_robberyData[ robberyid ] [ E_ROBTIMER ] != 0xFFFF ) return 0x2C; // It's been robbed/opened! if ( p_Class[ playerid ] == CLASS_POLICE ) return 0xBB; // Not civilian if ( IsPlayerAttachedObjectSlotUsed( playerid, 0 ) || g_robberyData[ robberyid ] [ E_STATE ] ) return 0xBC; // Currently picking/being robbed/being picked //if ( g_robberyData[ robberyid ] [ E_BUSINESS_ID ] != -1 && ! g_businessData[ g_robberyData[ robberyid ] [ E_BUSINESS_ID ] ] [ E_BANK ] ) // return 0xBF; // has $0 in bank as biz if ( g_robberyData[ robberyid ] [ E_BUSINESS_ID ] != -1 && ! JobEquals( playerid, JOB_BURGLAR ) ) return 0xCB; // must be burglar to rob safe if ( IsBusinessAssociate( playerid, g_robberyData[ robberyid ] [ E_BUSINESS_ID ] ) ) return 0xCA; // is biz associate static Float: fX, Float: fY, Float: fZ, Float: offsetX, Float: offsetY, Float: rotation ; GetDynamicObjectPos( g_robberyData[ robberyid ] [ E_SAFE ], fX, fY, fZ ); GetDynamicObjectRot( g_robberyData[ robberyid ] [ E_SAFE ], rotation, rotation, rotation ); if ( g_Debugging ) { printf("[DEBUG] [ROBBERY] [%d] AttachToRobberySafe( %d, %d, %d ) { open : %d, robbed : %d, c4: %d, drill : %d, dplacer : %d, deffect : %d, replenish : %d, raw ts : %d, current ts : %d, name : %s, state : %d }", robberyid, robberyid, playerid, type, g_robberyData[ robberyid ] [ E_OPEN ], g_robberyData[ robberyid ] [ E_ROBBED ], g_robberyData[ robberyid ] [ E_C4 ], g_robberyData[ robberyid ] [ E_DRILL ], g_robberyData[ robberyid ] [ E_DRILL_PLACER ], g_robberyData[ robberyid ] [ E_DRILL_EFFECT ], g_robberyData[ robberyid ] [ E_ROB_TIME ] - g_iTime, g_robberyData[ robberyid ] [ E_ROB_TIME ], g_iTime, g_robberyData[ robberyid ] [ E_NAME ], g_robberyData[ robberyid ] [ E_STATE ] ); } // start the drill/c4 switch( type ) { case ROBBERY_TYPE_DRILL: { if ( p_drillStrength[ playerid ] <= 0 ) return 0xA1; if ( g_robberyData[ robberyid ] [ E_DRILL_PLACER ] != INVALID_PLAYER_ID || IsValidDynamicObject( g_robberyData[ robberyid ] [ E_DRILL ] ) ) return 0x2B; // Valid drill/driller already on? // DRILL offsetX = 0.8 * floatsin( -( rotation + 200 ), degrees ); offsetY = 0.8 * floatcos( -( rotation + 200 ), degrees ); g_robberyData[ robberyid ] [ E_DRILL_PLACER ] = playerid; g_robberyData[ robberyid ] [ E_DRILL ] = CreateDynamicObject( 341, fX + offsetX, fY + offsetY, fZ, 0, 24.0, rotation + 90, g_robberyData[ robberyid ] [ E_WORLD ] ); offsetX = -1.4 * floatsin( -( rotation + 170 ), degrees ); offsetY = -1.4 * floatcos( -( rotation + 170 ), degrees ); g_robberyData[ robberyid ] [ E_DRILL_EFFECT ] = CreateDynamicObject( 18718, fX + offsetX, fY + offsetY, fZ, 90, 0, rotation, g_robberyData[ robberyid ] [ E_WORLD ] ); g_robberyData[ robberyid ] [ E_ROBTIMER ] = SetTimerEx( "onSafeBust", 7500, false, "dddd", playerid, robberyid, type, 0 ); p_drillStrength[ playerid ] -= 10; Streamer_Update( playerid ); return 1; } case ROBBERY_TYPE_C4: { if ( g_robberyData[ robberyid ] [ E_C4_SLOT ] == false ) { // slot 1 = orignally 185 degrees offsetX = 0.35 * floatsin( -( rotation + 180 ), degrees ); offsetY = 0.35 * floatcos( -( rotation + 180 ), degrees ); //case 0: g_robberyData[ robberyid ] [ E_C4 ] [ 0 ] = CreateDynamicObject( 363, fX + offsetX, fY + offsetY, fZ + 0.18534, 0, 0, rotation, g_robberyData[ robberyid ] [ E_WORLD ] ); //case 1: g_robberyData[ robberyid ] [ E_C4 ] [ 1 ] = CreateDynamicObject( 363, fX + offsetX, fY + offsetY, fZ + 0.44483, 0, 90, rotation, g_robberyData[ robberyid ] [ E_WORLD ] ); //case 2: g_robberyData[ robberyid ] [ E_C4 ] [ 2 ] = CreateDynamicObject( 363, fX + offsetX, fY + offsetY, fZ - 0.06090, 0, 90, rotation, g_robberyData[ robberyid ] [ E_WORLD ] ); g_robberyData[ robberyid ] [ E_C4 ] = CreateDynamicObject( 363, fX + offsetX, fY + offsetY, fZ + 0.18534, 0, 0, rotation, g_robberyData[ robberyid ] [ E_WORLD ] ); g_robberyData[ robberyid ] [ E_C4_SLOT ] = true; g_robberyData[ robberyid ] [ E_ROBTIMER ] = SetTimerEx( "onSafeBust", 960, false, "dddd", playerid, robberyid, type, 0 ); return 1; } } } return -1; } stock RemoveRobberyAttachments( robberyid ) { if (!Iter_Contains(RobberyCount, robberyid)) return; // Invalid Robbery DestroyDynamicObject( g_robberyData[ robberyid ] [ E_DRILL ] ); DestroyDynamicObject( g_robberyData[ robberyid ] [ E_DRILL_EFFECT ] ); DestroyDynamicObject( g_robberyData[ robberyid ] [ E_C4 ] ); g_robberyData[ robberyid ] [ E_C4_SLOT ] = false; g_robberyData[ robberyid ] [ E_C4 ] = INVALID_OBJECT_ID; g_robberyData[ robberyid ] [ E_DRILL ] = INVALID_OBJECT_ID; g_robberyData[ robberyid ] [ E_DRILL_PLACER ] = INVALID_PLAYER_ID; g_robberyData[ robberyid ] [ E_DRILL_EFFECT ] = INVALID_OBJECT_ID; if ( g_Debugging ) { printf("[DEBUG] [ROBBERY] [%d] RemoveRobberyAttachments { open : %d, robbed : %d, c4: %d, drill : %d, dplacer : %d, deffect : %d, replenish : %d, raw ts : %d, current ts : %d, name : %s, state : %d }", robberyid, g_robberyData[ robberyid ] [ E_OPEN ], g_robberyData[ robberyid ] [ E_ROBBED ], g_robberyData[ robberyid ] [ E_C4 ], g_robberyData[ robberyid ] [ E_DRILL ], g_robberyData[ robberyid ] [ E_DRILL_PLACER ], g_robberyData[ robberyid ] [ E_DRILL_EFFECT ], g_robberyData[ robberyid ] [ E_ROB_TIME ] - g_iTime, g_robberyData[ robberyid ] [ E_ROB_TIME ], g_iTime, g_robberyData[ robberyid ] [ E_NAME ], g_robberyData[ robberyid ] [ E_STATE ] ); } } stock createRobberyLootInstance( playerid, robberyid, type ) { if (!Iter_Contains(RobberyCount, robberyid)) return; // Invalid Robbery static Float: fX, Float: fY, Float: fZ, Float: fRotation; GetDynamicObjectPos( g_robberyData[ robberyid ] [ E_SAFE ], fX, fY, fZ ); GetDynamicObjectRot( g_robberyData[ robberyid ] [ E_SAFE ], fRotation, fRotation, fRotation ); new businessid = g_robberyData[ robberyid ] [ E_BUSINESS_ID ]; new bool: business_robbery = businessid != -1; new Float: random_chance = fRandomEx( 0.0, 101.0 ); new Float: probability = 90.0; if ( business_robbery ) { switch ( g_businessData[ businessid ] [ E_SECURITY_LEVEL ] ) { case 0: probability = 25.0; case 1: probability = 50.0; case 2: probability = 75.0; case 3: probability = 101.0; // must be over 100.0% } } // printf ( "[BIZ]Probability %0.3f - dice %0.3f", probability, random_chance ); if ( business_robbery ? random_chance > probability : ( p_Robberies[ playerid ] <= 20 ? 100.0 : random_chance ) > 5.0 ) { new Float: iRobAmount = float( g_robberyData[ robberyid ] [ E_ROB_VALUE ] ); new Float: iLoot = fRandomEx( iRobAmount / 2.0, iRobAmount ); // Apply multiplier iLoot *= g_robberyData[ robberyid ] [ E_MULTIPLIER ]; g_robberyData[ robberyid ] [ E_MULTIPLIER ] = 1.0; // check if this is a business safe if ( business_robbery ) { new Float: final_bank = float( g_businessData[ businessid ] [ E_BANK ] ); switch ( g_businessData[ businessid ] [ E_SECURITY_LEVEL ] ) { case 0: iLoot = floatround( final_bank * 0.75 ); case 1: iLoot = floatround( final_bank * 0.5 ); case 2: iLoot = floatround( final_bank * 0.25 ); case 3: iLoot = 0; // floatround( final_bank * 0.1 ); } // update business data g_businessData[ businessid ] [ E_BANK ] -= floatround( iLoot ); UpdateBusinessData( businessid ); // tax 10 percent for me iLoot *= 0.9; // add loot anyway under 3k if ( iLoot < 3000 ) iLoot = RandomEx( 1500, 3000 ); } // Loose 50% because of impact // if ( type == ROBBERY_TYPE_C4 ) iLoot *= 0.50; // money offset fX += 0.07 * floatsin( -fRotation, degrees ); fY += 0.07 * floatcos( -fRotation, degrees ); DestroyDynamicObject( g_robberyData[ robberyid ] [ E_SAFE_MONEY ] ); g_robberyData[ robberyid ] [ E_SAFE_MONEY ] = CreateDynamicObject( 2005, fX, fY, fZ - 0.1, 0, 0, g_robberyData[ robberyid ] [ E_DOOR_ROT ], g_robberyData[ robberyid ] [ E_WORLD ] ); SetDynamicObjectMaterial( g_robberyData[ robberyid ] [ E_SAFE_MONEY ], 0, 2005, "cr_safe_cash", "man_mny2", 0xFF98FB98 ); g_robberyData[ robberyid ] [ E_SAFE_LOOT ] = floatround( iLoot ); if ( IsPlayerConnected( playerid ) ) Streamer_Update( playerid ); } else { if ( IsPlayerConnected( playerid ) && p_Class[ playerid ] != CLASS_POLICE ) { new szLocation[ MAX_ZONE_NAME ], id = p_LastEnteredEntrance[ playerid ], business_id = g_robberyData[ robberyid ] [ E_BUSINESS_ID ] ; if ( id != -1 ) // Sometimes the player isn't even inside a home. GetZoneFromCoordinates( szLocation, g_entranceData[ id ] [ E_EX ], g_entranceData[ id ] [ E_EY ], g_entranceData[ id ] [ E_EZ ] ); else if ( business_id != -1 ) GetZoneFromCoordinates( szLocation, g_businessData[ business_id ] [ E_X ], g_businessData[ business_id ] [ E_Y ], g_businessData[ business_id ] [ E_Z ] ); if ( GetPlayerInterior( playerid ) != 0 ) SendClientMessageToCops( -1, ""COL_BLUE"[ROBBERY]"COL_WHITE" %s has failed robbing %s"COL_WHITE" near %s.", ReturnPlayerName( playerid ), g_robberyData[ robberyid ] [ E_NAME ], szLocation ); else SendClientMessageToCops( -1, ""COL_BLUE"[ROBBERY]"COL_WHITE" %s has failed robbing %s"COL_WHITE".", ReturnPlayerName( playerid ), g_robberyData[ robberyid ] [ E_NAME ] ); SendClientMessage( playerid, -1, ""COL_GREY"[SERVER]"COL_WHITE" No loot, and the alarm went off. Cops have been alerted." ); GivePlayerWantedLevel( playerid, 6 ); CreateCrimeReport( playerid ); } g_robberyData[ robberyid ] [ E_ROB_TIME ] = g_iTime + MAX_ROBBERY_WAIT; g_robberyData[ robberyid ] [ E_ROBBED ] = true; } if ( g_Debugging ) { printf("[DEBUG] [ROBBERY] [%d] createRobberyLootInstance( %d, %d, %d ) { open : %d, robbed : %d, c4: %d, drill : %d, dplacer : %d, deffect : %d, replenish : %d, raw ts : %d, current ts : %d, name : %s, state : %d }", robberyid, playerid, robberyid, type, g_robberyData[ robberyid ] [ E_OPEN ], g_robberyData[ robberyid ] [ E_ROBBED ], g_robberyData[ robberyid ] [ E_C4 ], g_robberyData[ robberyid ] [ E_DRILL ], g_robberyData[ robberyid ] [ E_DRILL_PLACER ], g_robberyData[ robberyid ] [ E_DRILL_EFFECT ], g_robberyData[ robberyid ] [ E_ROB_TIME ] - g_iTime, g_robberyData[ robberyid ] [ E_ROB_TIME ], g_iTime, g_robberyData[ robberyid ] [ E_NAME ], g_robberyData[ robberyid ] [ E_STATE ] ); } } function onSafeBust( playerid, robberyid, type, index ) { new bConnected = IsPlayerConnected( playerid ); switch( type ) { case ROBBERY_TYPE_C4: { if ( index < 3 ) { if ( bConnected ) { PlayerPlaySound( playerid, 1056, g_robberyData[ robberyid ] [ E_DOOR_X ], g_robberyData[ robberyid ] [ E_DOOR_Y ], g_robberyData[ robberyid ] [ E_DOOR_Z ] ); GameTextForPlayer( playerid, "~r~Fall back!~n~c4 in detonation!", 4000, 3 ); } g_robberyData[ robberyid ] [ E_ROBTIMER ] = SetTimerEx( "onSafeBust", 960, false, "dddd", playerid, robberyid, type, index + 1 ); } else { if ( bConnected ) { GameTextForPlayer( playerid, "~g~We're in!", 4000, 3 ); PlayerPlaySound( playerid, 1057, g_robberyData[ robberyid ] [ E_DOOR_X ], g_robberyData[ robberyid ] [ E_DOOR_Y ], g_robberyData[ robberyid ] [ E_DOOR_Z ] ); } g_robberyData[ robberyid ] [ E_STATE ] = STATE_NONE; g_robberyData[ robberyid ] [ E_ROBTIMER ] = 0xFFFF; RemoveRobberyAttachments( robberyid ); ControlRobberySafe( robberyid, true ); createRobberyLootInstance( playerid, robberyid, type ); CreateExplosionEx( g_robberyData[ robberyid ] [ E_DOOR_X ], g_robberyData[ robberyid ] [ E_DOOR_Y ], g_robberyData[ robberyid ] [ E_DOOR_Z ], 12, 0.0, g_robberyData[ robberyid ] [ E_WORLD ], -1 ); } } case ROBBERY_TYPE_DRILL, ROBBERY_TYPE_LABOR: { g_robberyData[ robberyid ] [ E_STATE ] = STATE_NONE; g_robberyData[ robberyid ] [ E_ROBTIMER ] = 0xFFFF; RemoveRobberyAttachments( robberyid ); ControlRobberySafe( robberyid, true ); createRobberyLootInstance( playerid, robberyid, type ); if ( type == ROBBERY_TYPE_LABOR ) SetTimerEx( "handlePlayerRobbery", 1350, false, "ddd", playerid, KEY_WALK, KEY_SPRINT ); } } if ( g_Debugging ) { printf("[DEBUG] [ROBBERY] [%d] onSafeBust( %d, %d, %d, %d ) { open : %d, robbed : %d, c4: %d, drill : %d, dplacer : %d, deffect : %d, replenish : %d, raw ts : %d, current ts : %d, name : %s, state : %d }", robberyid, playerid, robberyid, type, index, g_robberyData[ robberyid ] [ E_OPEN ], g_robberyData[ robberyid ] [ E_ROBBED ], g_robberyData[ robberyid ] [ E_C4 ], g_robberyData[ robberyid ] [ E_DRILL ], g_robberyData[ robberyid ] [ E_DRILL_PLACER ], g_robberyData[ robberyid ] [ E_DRILL_EFFECT ], g_robberyData[ robberyid ] [ E_ROB_TIME ] - g_iTime, g_robberyData[ robberyid ] [ E_ROB_TIME ], g_iTime, g_robberyData[ robberyid ] [ E_NAME ], g_robberyData[ robberyid ] [ E_STATE ] ); } } stock ControlRobberySafe( rID, bool: open ) { static Float: Z; if (Iter_Contains(RobberyCount, rID)) { GetDynamicObjectPos( g_robberyData[ rID ] [ E_SAFE_DOOR ], Z, Z, Z ); if ( g_robberyData[ rID ] [ E_OPEN ] == true && open == true ) { printf("[GM:WARNING] Safe %d was stopped from opening twice.", rID ); return; } if ( open ) { // Must close it SetDynamicObjectPos( g_robberyData[ rID ] [ E_SAFE_DOOR ], g_robberyData[ rID ] [ E_DOOR_X ], g_robberyData[ rID ] [ E_DOOR_Y ], Z ); SetDynamicObjectRot( g_robberyData[ rID ] [ E_SAFE_DOOR ], 0.0, 0.0, g_robberyData[ rID ] [ E_DOOR_ROT ] ); SetTimerEx( "Physics_OpenSafe", 450, false, "dd", rID, 0 ); } else { SetDynamicObjectPos( g_robberyData[ rID ] [ E_SAFE_DOOR ], g_robberyData[ rID ] [ E_DOOR_X ], g_robberyData[ rID ] [ E_DOOR_Y ], Z ); SetDynamicObjectRot( g_robberyData[ rID ] [ E_SAFE_DOOR ], 0.0, 0.0, g_robberyData[ rID ] [ E_DOOR_ROT ] ); g_robberyData[ rID ] [ E_OPEN ] = false; } if ( g_Debugging ) { new robberyid = rID; printf("[DEBUG] [ROBBERY] [%d] ControlRobberySafe( %d, %d ) { open : %d, robbed : %d, c4: %d, drill : %d, dplacer : %d, deffect : %d, replenish : %d, raw ts : %d, current ts : %d, name : %s, state : %d }", robberyid, rID, open, g_robberyData[ robberyid ] [ E_OPEN ], g_robberyData[ robberyid ] [ E_ROBBED ], g_robberyData[ robberyid ] [ E_C4 ], g_robberyData[ robberyid ] [ E_DRILL ], g_robberyData[ robberyid ] [ E_DRILL_PLACER ], g_robberyData[ robberyid ] [ E_DRILL_EFFECT ], g_robberyData[ robberyid ] [ E_ROB_TIME ] - g_iTime, g_robberyData[ robberyid ] [ E_ROB_TIME ], g_iTime, g_robberyData[ robberyid ] [ E_NAME ], g_robberyData[ robberyid ] [ E_STATE ] ); } } } function Physics_OpenSafe( handle, time_elapsed ) { // two seconds elapsed if ( time_elapsed >= 2000 ) { g_robberyData[ handle ] [ E_OPEN ] = true; return 1; } new Float: angle = 50.0 * floatlog( ( time_elapsed + 167.5 ) / 3.0, 2.72 ) - 200.0; // natural log (use https://www.geogebra.org/graphing) SetDynamicObjectRot( g_robberyData[ handle ] [ E_SAFE_DOOR ], 0.0, 0.0, g_robberyData[ handle ] [ E_DOOR_ROT ] - angle ); return SetTimerEx( "Physics_OpenSafe", 15, false, "dd", handle, time_elapsed + 15 ); } stock setSafeReplenished( rID ) { static Float: Z; if (Iter_Contains(RobberyCount, rID)) { DestroyDynamicObject( g_robberyData[ rID ] [ E_SAFE_MONEY ] ); g_robberyData[ rID ] [ E_ROBBED ] = false; g_robberyData[ rID ] [ E_ROBTIMER ] = 0xFFFF; g_robberyData[ rID ] [ E_DRILL_PLACER ] = INVALID_PLAYER_ID; g_robberyData[ rID ] [ E_DRILL_EFFECT ] = INVALID_OBJECT_ID; g_robberyData[ rID ] [ E_ROB_TIME ] = -1; g_robberyData[ rID ] [ E_ROBBED ] = false; g_robberyData[ rID ] [ E_STATE ] = STATE_NONE; g_robberyData[ rID ] [ E_OPEN ] = false; g_robberyData[ rID ] [ E_SAFE_MONEY ] = 0xFFFF; g_robberyData[ rID ] [ E_SAFE_LOOT ] = 0; StopDynamicObject( g_robberyData[ rID ] [ E_SAFE_DOOR ] ); GetDynamicObjectPos( g_robberyData[ rID ] [ E_SAFE_DOOR ], Z, Z, Z ); SetDynamicObjectPos( g_robberyData[ rID ] [ E_SAFE_DOOR ], g_robberyData[ rID ] [ E_DOOR_X ], g_robberyData[ rID ] [ E_DOOR_Y ], Z ); SetDynamicObjectRot( g_robberyData[ rID ] [ E_SAFE_DOOR ], 0.0, 0.0, g_robberyData[ rID ] [ E_DOOR_ROT ] ); if ( g_Debugging ) { new robberyid = rID; printf("[DEBUG] [ROBBERY] [%d] setSafeReplenished( %d ) { open : %d, robbed : %d, c4: %d, drill : %d, dplacer : %d, deffect : %d, replenish : %d, raw ts : %d, current ts : %d, name : %s, state : %d }", robberyid, rID, g_robberyData[ robberyid ] [ E_OPEN ], g_robberyData[ robberyid ] [ E_ROBBED ], g_robberyData[ robberyid ] [ E_C4 ], g_robberyData[ robberyid ] [ E_DRILL ], g_robberyData[ robberyid ] [ E_DRILL_PLACER ], g_robberyData[ robberyid ] [ E_DRILL_EFFECT ], g_robberyData[ robberyid ] [ E_ROB_TIME ] - g_iTime, g_robberyData[ robberyid ] [ E_ROB_TIME ], g_iTime, g_robberyData[ robberyid ] [ E_NAME ], g_robberyData[ robberyid ] [ E_STATE ] ); //SendClientMessageToAdmins( -1, ""COL_ORANGE"[DEBUG]"COL_GREY" Robbery "COL_GREY"%s(%d)"COL_GREY" has been replenished!", g_robberyData[ rID ] [ E_NAME ], rID ); } return 1; } printf( "[WARNING] Invalid safe %d is being set for replenishment.", rID ); return 0; } stock haltRobbery( rID ) { KillTimer( g_robberyData[ rID ] [ E_ROBTIMER ] ); g_robberyData[ rID ] [ E_ROBTIMER ] = 0xFFFF; RemoveRobberyAttachments( rID ); if ( g_Debugging ) { printf("[DEBUG] [ROBBERY] [%d] haltRobbery( %d ) { open : %d, robbed : %d, c4: %d, drill : %d, dplacer : %d, deffect : %d, replenish : %d, raw ts : %d, current ts : %d, name : %s, state : %d }", robberyid, rID, g_robberyData[ robberyid ] [ E_OPEN ], g_robberyData[ robberyid ] [ E_ROBBED ], g_robberyData[ robberyid ] [ E_C4 ], g_robberyData[ robberyid ] [ E_DRILL ], g_robberyData[ robberyid ] [ E_DRILL_PLACER ], g_robberyData[ robberyid ] [ E_DRILL_EFFECT ], g_robberyData[ robberyid ] [ E_ROB_TIME ] - g_iTime, g_robberyData[ robberyid ] [ E_ROB_TIME ], g_iTime, g_robberyData[ robberyid ] [ E_NAME ], g_robberyData[ robberyid ] [ E_STATE ] ); } } stock truncateDrills( playerid ) { foreach(new i : RobberyCount) { if ( g_robberyData[ i ] [ E_DRILL_PLACER ] == playerid ) haltRobbery( i ); } }