diff --git a/R3F_LOG_ENABLE.h b/R3F_LOG_ENABLE.h new file mode 100644 index 0000000..5027628 --- /dev/null +++ b/R3F_LOG_ENABLE.h @@ -0,0 +1,9 @@ +/* + * Add a double-slash ( // ) at the begining of the #include line to disable the logistics system. + * To enable the logistics system, write #define R3F_LOG_enable withouth the double-slash. + * + * Ajoutez deux barres obliques ( // ) au début de la ligne #include pour désactiver le système logistique. + * Pour activer le système logistique, écrivez #define R3F_LOG_enable sans les deux barres obliques. + */ + +#define R3F_LOG_enable \ No newline at end of file diff --git a/USER_FUNCT/auto_load_in_vehicle.sqf b/USER_FUNCT/auto_load_in_vehicle.sqf new file mode 100644 index 0000000..68529c2 --- /dev/null +++ b/USER_FUNCT/auto_load_in_vehicle.sqf @@ -0,0 +1,33 @@ +/** + * Load automatically and instantly a list of sereval objects and/or class names into a vehicle/cargo. + * + * @param 0 the vehicle or cargo to be loaded + * @param 1 the array of objects and/or class name to load in, which can be a mix of these elements : + * object's name set in the editor or object's script variable + * class name as a string, if so an object of this class name will be spawned, then loaded + * an array ["class_name", quantity] to spawn then load several objects of the same type + * + * @usage The following command loads my_object1 and my_object2 into my_vehicle + * @usage nul = [my_vehicle, [my_object1, my_object2] ] execVM "R3F_LOG\USER_FUNCT\auto_load_in_vehicle.sqf"; + * + * @usage The following command spawns and loads one "Box_IND_Ammo_F" and one "Box_IND_Grenades_F" into my_vehicle + * @usage nul = [my_vehicle, ["Box_IND_Ammo_F", "Box_IND_Grenades_F"] ] execVM "R3F_LOG\USER_FUNCT\auto_load_in_vehicle.sqf"; + * + * @usage The following command spawns and loads two "Box_IND_Ammo_F" and one "Box_IND_Grenades_F" into my_vehicle + * @usage nul = [my_vehicle, [ ["Box_IND_Ammo_F", 2], "Box_IND_Grenades_F" ] ] execVM "R3F_LOG\USER_FUNCT\auto_load_in_vehicle.sqf"; + * + * @usage The following command loads my_object1, two "Box_IND_Ammo_F" and one "Box_IND_Grenades_F" into my_vehicle + * @usage nul = [my_vehicle, [ my_object1, ["Box_IND_Ammo_F", 2], "Box_IND_Grenades_F" ] ] execVM "R3F_LOG\USER_FUNCT\auto_load_in_vehicle.sqf"; + * + * @usage You can replace "my_vehicle" by "this" if you put the line in the initialization line in the mission editor. + */ + +if (isServer) then +{ + waitUntil {!isNil "R3F_LOG_active"}; + + if (R3F_LOG_active) then + { + _this call R3F_LOG_FNCT_transporteur_charger_auto; + }; +}; \ No newline at end of file diff --git a/USER_FUNCT/do_not_lose_it.sqf b/USER_FUNCT/do_not_lose_it.sqf new file mode 100644 index 0000000..a57d322 --- /dev/null +++ b/USER_FUNCT/do_not_lose_it.sqf @@ -0,0 +1,76 @@ +/** + * Execute this script to prevent the object to be lost during the mission. + * Useful for mandatory objects like a flag pole with addAction. + * It must be executed from the initialisation line or at any other time on the server and all clients. + * + * The script does : + * It makes the object indestructible (from any kind of damage). + * It denies the ability to send/sell back the object to any creation factory (if applicable). + * If the object is loaded in a vehicle/cargo which has been destroyed, it will be unloaded/teleported to a given position. + * If the object was lifted to a crashed helicopter, it will be detached/teleported to a given position. + * If the object was towed to a destroyed vehicle, it will be untowed/teleported to a given position. + * + * @param 0 the object to protect and to not lose + * @param 1 (optional) choose where to restore the object if destroyed in transport cargo (default : "spawn_pos") + * set to "spawn_pos" to teleport the object on its initial spawn position + * set to "exact_spawn_pos" to teleport the object on its exact initial spawn position and direction (no collision check) + * set to "cargo_pos" to unload the object around the destroyed cargo + * set to any marker name to teleport the object to the marker position + * + * @usage nul = [my_object] execVM "R3F_LOG\USER_FUNCT\do_not_lose_it.sqf"; + * @usage nul = [my_object, "spawn_pos"] execVM "R3F_LOG\USER_FUNCT\do_not_lose_it.sqf"; + * @usage nul = [my_object, "cargo_pos"] execVM "R3F_LOG\USER_FUNCT\do_not_lose_it.sqf"; + * @usage nul = [my_object, ""] execVM "R3F_LOG\USER_FUNCT\do_not_lose_it.sqf"; + * + * @usage You can replace "my_object" by "this" if you put the line in the initialization line in the mission editor. + */ + +private ["_objet", "_pos_respawn"]; + +_objet = _this select 0; +_pos_respawn = if (count _this > 1) then {_this select 1} else {"spawn_pos"}; + +if (!isNull _objet) then +{ + waitUntil {!isNil "R3F_LOG_active"}; + + if (R3F_LOG_active) then + { + _objet addEventHandler ["HandleDamage", {0}]; + + if (isServer) then + { + // Attendre le mutex + waitUntil + { + if (R3F_LOG_mutex_local_verrou) then + { + false + } + else + { + R3F_LOG_mutex_local_verrou = true; + true + } + }; + + R3F_LOG_liste_objets_a_proteger pushBack _objet; + + R3F_LOG_mutex_local_verrou = false; + + if (_pos_respawn == "spawn_pos" || _pos_respawn == "exact_spawn_pos") then + { + _objet setVariable ["R3F_LOG_pos_respawn", getPosASL _objet, false]; + + if (_pos_respawn == "exact_spawn_pos") then + { + _objet setVariable ["R3F_LOG_dir_respawn", getDir _objet, false]; + }; + } + else + { + _objet setVariable ["R3F_LOG_pos_respawn", _pos_respawn, false]; + }; + }; + }; +}; \ No newline at end of file diff --git a/USER_FUNCT/dump_creation_factory_categories.sqf b/USER_FUNCT/dump_creation_factory_categories.sqf new file mode 100644 index 0000000..0c8de74 --- /dev/null +++ b/USER_FUNCT/dump_creation_factory_categories.sqf @@ -0,0 +1,68 @@ +/** + * Dump to the RPT file the list of all existing categories that can be allowed/denied to a creation factory. + * This is a helper function to define your own white/black list for a creation factory. + * See USER_FUNCT\init_creation_factory.sqf and the PDF documentation for more information. + * Note : the RPT file is located here : C:\Users\\AppData\Local\Arma 3\. See https://community.bistudio.com/wiki/RPT + * + * @param 0 (optional) true to also dump the display name and number of entries as a comment, false to hide (default : true) + * @param 1 (optional) true to dump the empty categories (i.e. categories with no entry in CfgVehicles) (default : false) + * + * @usage execute the following line in the BIS' debug console or the init line of the player + * @usage nul = [] execVM "R3F_LOG\USER_FUNCT\dump_creation_factory_categories.sqf"; + * + * @usage to not dump the comments after the class names, set the optional param 0 to false + * @usage nul = [false] execVM "R3F_LOG\USER_FUNCT\dump_creation_factory_categories.sqf"; + * + * @usage to dump all categories, including empty ones, set param 1 to true + * @usage nul = [true, true] execVM "R3F_LOG\USER_FUNCT\dump_creation_factory_categories.sqf"; + */ + +waitUntil {!isNil "R3F_LOG_active"}; + +private ["_comment", "_montrer_categories_vides", "_retour_liste_cfgVehicles_par_categories", "_cfgVehicles_categories", "_cfgVehicles_par_categories", "_nb_categories", "_idx_categorie", "_align_comma", "_x"]; + +_comment = if (count _this > 0) then {_this select 0} else {true}; +_montrer_categories_vides = if (count _this > 1) then {_this select 1} else {false}; + +_retour_liste_cfgVehicles_par_categories = [objNull, _montrer_categories_vides] call R3F_LOG_FNCT_recuperer_liste_cfgVehicles_par_categories; + +_cfgVehicles_categories = _retour_liste_cfgVehicles_par_categories select 0; +_cfgVehicles_par_categories = _retour_liste_cfgVehicles_par_categories select 1; + +diag_log text "R3F_LOG_CFG_CF_your_own_categories_list ="; +diag_log text "["; + +_nb_categories = count _cfgVehicles_categories; +for [{_idx_categorie = 0}, {_idx_categorie < _nb_categories}, {_idx_categorie = _idx_categorie+1}] do +{ + if (_comment) then + { + // Formatage du tableau sans virgule pour le dernier élément + alignement des commentaires + _align_comma = if (_idx_categorie != _nb_categories-1) then {","} else {" "}; + for "_x" from 1 to (32 - count toArray (_cfgVehicles_categories select _idx_categorie)) do {_align_comma = _align_comma + " ";}; + + // Dump des infos de la catégorie + diag_log text format + [ + " ""%1""%2 // %3 (%4 entries)", + _cfgVehicles_categories select _idx_categorie, + _align_comma, + getText (configFile >> "CfgVehicleClasses" >> (_cfgVehicles_categories select _idx_categorie) >> "displayName"), + count (_cfgVehicles_par_categories select _idx_categorie) + ]; + } + else + { + _align_comma = if (_idx_categorie != _nb_categories-1) then {","} else {""}; + + // Dump des infos de la catégorie + diag_log text format + [ + " ""%1""%2", + _cfgVehicles_categories select _idx_categorie, + _align_comma + ]; + }; +}; + +diag_log text "];"; \ No newline at end of file diff --git a/USER_FUNCT/init_creation_factory.sqf b/USER_FUNCT/init_creation_factory.sqf new file mode 100644 index 0000000..3b85793 --- /dev/null +++ b/USER_FUNCT/init_creation_factory.sqf @@ -0,0 +1,32 @@ +/** + * Initialize a vehicle or an object to be a creation factory (object spawning system) + * + * @param 0 the creation factory, can be a mobile vehicle or any object + * @param 1 (optional) creation credits limitation, -1 for unlimited credits (default : -1) + * @param 2 (optional) side to allow accessing to the factory (default : all sides allowed) + * @param 3 (optional) list of class names of allowed categories (white list) + * if param not set, all the categories are allowed, except those in the black list defined in config_creation_factory.sqf + * if string "FULL", use the white list R3F_LOG_CFG_CF_whitelist_full_categories (config_creation_factory.sqf) + * if string "MEDIUM", use the white list R3F_LOG_CFG_CF_whitelist_medium_categories (config_creation_factory.sqf) + * if string "LIGHT", use the white list R3F_LOG_CFG_CF_whitelist_light_categories (config_creation_factory.sqf) + * if array of CfgVehicleClasses entries (class names, e.g. : ["Furniture", "Fortifications"]), use this array as white list + * + * @usage nul = [my_factory] execVM "R3F_LOG\USER_FUNCT\init_creation_factory.sqf"; // Unlimited credits, all sides allowed, all categories except black list in config_creation_factory.sqf + * @usage nul = [my_factory, 10000] execVM "R3F_LOG\USER_FUNCT\init_creation_factory.sqf"; // 10000 credits, all sides allowed, all categories except black list in config_creation_factory.sqf + * @usage nul = [my_factory, -1, independent] execVM "R3F_LOG\USER_FUNCT\init_creation_factory.sqf"; // Unlimited credits, allow to GUER side, all categories except black list + * @usage nul = [my_factory, -1, nil, "MEDIUM"] execVM "R3F_LOG\USER_FUNCT\init_creation_factory.sqf"; // All sides allowed, use white list MEDIUM in config_creation_factory.sqf + * @usage nul = [my_factory, -1, nil, ["Car", "Armored"]] execVM "R3F_LOG\USER_FUNCT\init_creation_factory.sqf"; // Allow only categories "Car" and "Armored" + * @usage You can replace "my_factory" by "this" if you put the line in the initialization line in the mission editor. + * + * @note the categories are the same as in the mission editor. Class names can be found in the BIS' config viewer in the config file CfgVehicleClasses. + */ + +if (!isDedicated) then +{ + waitUntil {!isNil "R3F_LOG_active"}; + + if (R3F_LOG_active) then + { + _this call R3F_LOG_FNCT_usine_init; + }; +}; \ No newline at end of file diff --git a/USER_FUNCT/watch_objects_to_not_lose.sqf b/USER_FUNCT/watch_objects_to_not_lose.sqf new file mode 100644 index 0000000..2faddff --- /dev/null +++ b/USER_FUNCT/watch_objects_to_not_lose.sqf @@ -0,0 +1,7 @@ +/** + * THIS SCRIPT HAS BEEN REMOVED. PLEASE USE "R3F_LOG\USER_FUNCT\do_not_lose_it.sqf". + */ + +sleep 1; +systemChat "ERROR : The logistics script ""USER_FUNCT\watch_objects_to_not_lose.sqf"" has been removed. Please use ""USER_FUNCT\do_not_lose_it.sqf""."; +diag_log "ERROR : The logistics script ""USER_FUNCT\watch_objects_to_not_lose.sqf"" has been removed. Please use ""USER_FUNCT\do_not_lose_it.sqf""."; \ No newline at end of file diff --git a/config_creation_factory.sqf b/config_creation_factory.sqf new file mode 100644 index 0000000..5ea6384 --- /dev/null +++ b/config_creation_factory.sqf @@ -0,0 +1,248 @@ +/** + * CREATION FACTORY CONFIGURATION FILE + * + * English and French comments + * Commentaires anglais et français + * + * (EN) + * This file contains the predefined lists of available categories in the creation factory. + * The objects/vehicles categories are the same as in the mission editor. + * It corresponds to the tree CfgVehicleClasses in the config file. + * To add a category in one of the lists, you must write its class name. Use the BIS' "Config viewer". + * + * To understand the white or black list system, read also the needed parameters in USER_FUNCT\init_creation_factory.sqf + * There are three white list "FULL", "MEDIUM" and "LIGHT", and a black list. + * The black list is used if no white list is mentioned when calling USER_FUNCT\init_creation_factory.sqf. + * + * (FR) + * Ce fichier contient la liste des catégories disponibles dans l'usine de création. + * Les catégories d'objets/véhicules sont les mêmes que dans l'éditeur de mission. + * Cela correspond à l'arborescence CfgVehicleClasses dans le config file. + * Pour ajouter une catégorie dans une des listes, vous devez écrire son nom de classe. Utilisez le "Config viewer" de BIS. + * + * Pour comprendre le système de white/black list, consultez les paramètres requis par USER_FUNCT\init_creation_factory.sqf + * Il y a trois white list "FULL", "MEDIUM" and "LIGHT", et une black list. + * La black list est utilisée si aucune white list n'est mentionnée lors de l'appel de USER_FUNCT\init_creation_factory.sqf. + */ + +/** + * SELL BACK REIMBURSEMENT RATE + * + * Rate of reimbursement from the buying price granted to the factory when the object is send back to it. + * Value of 0 means no credits back, 0.5 means half buying price, 1 means full buying price, and so on. + * Set to -1 to disable the possibility to give back objects to the creation factory. + * Note : the reimbursement amount take also into account of the damage level of the object. + * + * Taux de remboursement par rapport au prix d'achat accordé à l'usine lors de la restitution d'un objet. + * Une valeur de 0 signifie pas de crédits en retour, 0.5 donne 50% du prix d'achat, 1 correspond à 100% du prix d'achat. + * Mettre à -1 pour désactiver la possibilité de redonner les objets à l'usine de création. + * Note : le montant du remboursement prend aussi en compte l'état (dommage) de l'objet. + */ +R3F_LOG_CFG_CF_sell_back_bargain_rate = 0.75; + +/** + * LIGHT WHITE LIST + * Categories of objects/vehicles available in a "LIGHT" factory (see USER_FUNCT\init_creation_factory.sqf). + */ +R3F_LOG_CFG_CF_whitelist_light_categories = +[ + "Objects", // Objects (1 entries) + "Armory", // Armory (0 entries) + "Targets", // Targets (0 entries) + "Cargo", // Objects (Construction) (43 entries) + "Flag", // Objects (Flags) (35 entries) + "Lamps", // Objects (Lamps) (0 entries) + "Communication", // Objects (Communications) (0 entries) + "Furniture", // Objects (Furniture) (22 entries) + "Misc", // Objects (0 entries) + "Signs", // Objects (Signs) (50 entries) + "Small_items", // Objects (Small) (88 entries) + "Training", // Training (80 entries) + "Shelters", // Objects (Shelters) (0 entries) + "Fortifications", // Objects (Fortifications) (47 entries) + "Tents", // Objects (Camping) (46 entries) + "Market", // Objects (Market) (11 entries) + "Structures", // Structures (0 entries) + "Structures_Military", // Structures (Military) (12 entries) + "Structures_Walls", // Structures (Walls) (0 entries) + "Structures_Fences" // Structures (Fences) (1 entries) +]; + +/** + * MEDIUM WHITE LIST + * Categories of objects/vehicles available in a "MEDIUM" factory (see USER_FUNCT\init_creation_factory.sqf). + * It includes all the categories of the "LIGHT" list, and the listed categories below. + */ +R3F_LOG_CFG_CF_whitelist_medium_categories = R3F_LOG_CFG_CF_whitelist_light_categories + +[ + "Ammo", // Ammo (49 entries) + "Static", // Static (28 entries) + "Container", // Objects (Containers) (39 entries) + "Objects_Airport", // Objects (Airport) (20 entries) + + // All in Arma + "StaticW", // Static (woodland) (4 entries) + "Static_ChDKZ", // Static (Insurgency) (0 entries) + "Static_USMC", // Static (USMC) (0 entries) + "Static_RU", // Static (RU) (0 entries) + "Static_CDF" // Static (CDF) (0 entries) +]; + +/** + * FULL WHITE LIST + * Categories of objects/vehicles available in a "FULL" factory (see USER_FUNCT\init_creation_factory.sqf). + * It includes all the categories of the "MEDIUM" list, and the listed categories below. + */ +R3F_LOG_CFG_CF_whitelist_full_categories = R3F_LOG_CFG_CF_whitelist_medium_categories + +[ + "Car", // Cars (42 entries) + "Armored", // Armored (16 entries) + "Air", // Air (19 entries) + "Support", // Supports (21 entries) + "Ship", // Ships (13 entries) + "Autonomous", // Autonomous (15 entries) + "Submarine", // Submarines (3 entries) + "Wreck", // Wrecks (24 entries) + "Wreck_sub", // Wrecks (Submerged) (5 entries) + "Military", // Objects (Military) (9 entries) + "Structures_Commercial", // Structures (Commercial) (1 entries) + "Structures_Infrastructure", // Structures (Infrastructure) (1 entries) + "Structures_Town", // Structures (Town) (4 entries) + "Structures_Cultural", // Structures (Cultural) (0 entries) + "Structures_Industrial", // Structures (Industrial) (0 entries) + "Structures_Transport", // Structures (Transport) (0 entries) + "Structures_Village", // Structures (Village) (0 entries) + "Structures_Slums", // Structures (Slums) (0 entries) + "Structures_Airport", // Structures (Airport) (0 entries) + + // All in Arma + "Wrecks", // Wrecks (19 entries) + "Military_US_EP1", // Military (US) (12 entries) + "Military_TKA_EP1", // Military (TKA) (12 entries) + "Military_GUE_EP1", // Military (Guerillas) (12 entries) + "SupportWoodland_ACR", // Support (woodland) (4 entries) + "WarfareBuildingsClassname", // Warfare Buildings (79 entries) + "ArmouredD", // Armored (desert) (1 entries) + "ArmouredW", // Armored (woodland) (7 entries) + "CarD", // Cars (desert) (4 entries) + "CarW", // Cars (woodland) (10 entries) + "Military_With_side", // Military (36 entries) + "WarfareClassName", // Warfare (16 entries) + "Armored_CDF", // Armored (CDF) (0 entries) + "Armored_ChDKZ", // Armored (Insurgency) (0 entries) + "Armored_USMC", // Armored (USMC) (0 entries) + "Armored_RU", // Armored (RU) (0 entries) + "Car_USMC", // Cars (USMC) (0 entries) + "Car_RU", // Cars (RU) (0 entries) + "Car_ChDKZ", // Cars (Insurgency) (0 entries) + "Car_CDF", // Cars (CDF) (0 entries) + "Air_ChDKZ", // Air (Insurgency) (0 entries) + "Air_USMC", // Air (USMC) (0 entries) + "Air_RU", // Air (RU) (0 entries) + "Air_CDF", // Air (CDF) (0 entries) + "Ship_CDF", // Ship (CDF) (0 entries) + "Ship_ChDKZ", // Ship (Insurgency) (0 entries) + "Ship_USMC", // Ship (USMC) (0 entries) + "Ship_RU", // Ship (RU) (0 entries) + "support_ChDKZ", // Support (Insurgency) (0 entries) + "support_USMC", // Support (USMC) (0 entries) + "support_RU", // Support (RU) (0 entries) + "support_CDF", // Support (CDF) (0 entries) + "Structures_E", // Structures EP1 (0 entries) + "Ruins" // Ruins (0 entries) +]; + +/** + * BLACK LIST + * Categories of objects/vehicles to deny if no white list is set to the factory (see USER_FUNCT\init_creation_factory.sqf). + */ +R3F_LOG_CFG_CF_blacklist_categories = +[ + "Submerged", // Objects (Sea) (2 entries) + "Camera", // Cameras (0 entries) + "Sounds", // Sounds (9 entries) + "Mines", // Mines (15 entries) + "Backpacks", // Backpacks (157 entries) + "Uniforms", // Uniforms (0 entries) + "Anomalies", // Anomalies (0 entries) + "Test", // TEST (0 entries) + "Locations", // Locations (0 entries) + "Modules", // Modules (128 entries) + "Emitters", // Emitters (0 entries) + "WeaponsPrimary", // Weapons (Primary) (30 entries) + "WeaponsSecondary", // Weapons (Launchers) (10 entries) + "WeaponsHandguns", // Weapons (Sidearms) (6 entries) + "WeaponAccessories", // Weapon Accessories (26 entries) + "Magazines", // Magazines (0 entries) + "Items", // Items (18 entries) + "ItemsHeadgear", // Items (Headgear) (110 entries) + "ItemsVests", // Items (Vests) (39 entries) + "ItemsUniforms", // Items (Uniforms) (53 entries) + "Intel", // Intel (3 entries) + "Virtual", // Virtual Entities (0 entries) + "Garbage", // Objects (Garbage) (15 entries) + "Helpers", // Objects (Helpers) (34 entries) + "Dead_bodies", // Objects (Dead bodies) (12 entries) + "SystemLocations", // Locations (11 entries) + "SystemSides", // Sides (3 entries) + "SystemMisc", // Misc (3 entries) + "Objects_VR", // Objects (Virtual Reality) (1 entries) + "Objects_Sports", // Objects (Sports) (24 entries) + "Structures_VR", // Structures (Virtual Reality) (10 entries) + "Structures_Sports", // Structures (Sports) (11 entries) + "Explosives", // Explosives (0 entries) + "Respawn", // Respawn (5 entries) + + // All in Arma + "IEDs", // IEDs (4 entries) + "LocationLogics", // Locations (14 entries) + "Test_EP1" // Test EP1 (0 entries) +]; + +/** + * CREATION COST FACTOR + * + * Multiplication factor to fix the CfgVehicles' "cost" property values of vehicles/objects. + * It permits to have a better homogeneity between values. + * For example a SDV (Submarine) has a cost (divided by 100) of 100 and a Hunter (Car) of 5000. + * By fixing the values with factors, the SDV (Submarine) costs 100x4000 = 400.000 and the Hunter (Car) 5000x12 = 60.000. + * The format of the array is ["categorie class name", multiplication factor]. + * All non-listed categories have a factor of 1x. + * + * Facteur de multiplication pour corriger la propriété "cost" des objets/véhicules dans le CfgVehicles. + * Par exemple, un sous-marins SDV (Submarine) a un coût (divisé par 100) de 100 et un Hunter (Car) du 5000. + * En appliquant un facteur de correction, le SDV (Submarine) vaut 100x4000 = 400 000 et le Hunter (Car) 5000x12 = 60 000. + * Le format du tableau est ["nom de classe de la catégorie", facteur de multiplication] + * Les catégories non listées ont un facteur de 1x. + */ +R3F_LOG_CFG_CF_creation_cost_factor = +[ + ["Car", 12], + ["Armored", 15], + ["Air", 15], + ["Support", 100], + ["Ammo", 5000], + ["Ship", 8], + ["Static", 3], + ["Autonomous", 10], + ["Submarine", 1500], + ["Wreck", 100], + ["Wreck_sub", 100], + ["Cargo", 10], + ["Container", 5], + ["Objects_Airport", 50], + + // All in Arma + ["StaticW", 3], + ["Military_US_EP1", 8000], + ["Military_TKA_EP1", 8000], + ["Military_GUE_EP1", 8000], + ["SupportWoodland_ACR", 70], + ["WarfareBuildingsClassname", 100], + ["ArmouredD", 5], + ["ArmouredW", 20], + ["CarD", 60], + ["CarW", 60], + ["Military_With_side", 1000], + ["WarfareClassName", 50] +]; \ No newline at end of file diff --git a/desc_include.h b/desc_include.h new file mode 100644 index 0000000..bd22e41 --- /dev/null +++ b/desc_include.h @@ -0,0 +1,6 @@ +#include "R3F_LOG_ENABLE.h" + +#ifdef R3F_LOG_enable +#include "transporteur\dlg_contenu_vehicule.h" +#include "usine_creation\dlg_liste_objets.h" +#endif \ No newline at end of file diff --git a/en_strings_lang.sqf b/en_strings_lang.sqf new file mode 100644 index 0000000..dde5f45 --- /dev/null +++ b/en_strings_lang.sqf @@ -0,0 +1,93 @@ +/* + * TRANSLATION FILE (ENGLIGH) + * + * Alternative to stringtable.csv which is simpler to install for the mission maker. + * The token ""%1"" represents a dynamic value generated by the scripts, like a vehicle name. + * + * Alternative au stringtable.csv qui est plus simple à installer pour le créateur de mission. + * Le mot-clé ""%1"" représente une valeur dynamique fournie par les scripts, comme par exemple un nom de véhicule. + */ + +STR_R3F_LOG_action_heliporter = "Lift the object"; +STR_R3F_LOG_action_heliporter_fait = "Object ""%1"" attached."; +STR_R3F_LOG_action_heliport_larguer = "Drop the object"; +STR_R3F_LOG_action_heliport_larguer_fait = "Object ""%1"" dropped."; +STR_R3F_LOG_action_heliport_attente = "Hooking... (%1)"; +STR_R3F_LOG_action_heliport_echec_attente = "Lift aborted ! Stay hover during the hooking."; + +STR_R3F_LOG_action_deplacer_objet = "Take ""%1"""; +STR_R3F_LOG_action_relacher_objet = "Release ""%1"""; +STR_R3F_LOG_action_aligner_pente = "Adjust to the slope"; +STR_R3F_LOG_action_aligner_sol = "Adjust to the ground"; +STR_R3F_LOG_action_aligner_horizon = "Adjust horizontally"; +STR_R3F_LOG_action_tourner = "Turn left/right (X / C keys)"; +STR_R3F_LOG_action_rapprocher = "Closer/further (F / R keys)"; +STR_R3F_LOG_ne_pas_monter_dans_vehicule = "You can't get in a vehicle while you're carrying this object !"; + +STR_R3F_LOG_action_charger_deplace = "Load in the vehicle"; +STR_R3F_LOG_action_selectionner_objet_charge = "Load ""%1"" in..."; +STR_R3F_LOG_action_charger_selection = "... load in ""%1"""; +STR_R3F_LOG_action_selectionner_objet_fait = "Now select the destination for ""%1""..."; +STR_R3F_LOG_action_charger_en_cours = "Loading in progress..."; +STR_R3F_LOG_action_charger_fait = "The object ""%1"" has been loaded in ""%2""."; +STR_R3F_LOG_action_charger_pas_assez_de_place = "There is not enough space for this object in this vehicle !"; + +STR_R3F_LOG_action_remorquer_direct = "Tow ""%1"""; +STR_R3F_LOG_action_remorquer_deplace = "Tow the object"; +STR_R3F_LOG_action_detacher = "Untow the object"; +STR_R3F_LOG_action_detacher_fait = "Object untowed."; +STR_R3F_LOG_action_detacher_impossible_pour_ce_vehicule = "Only the pilot can detach this object."; + +STR_R3F_LOG_action_contenu_vehicule = "View the vehicle's content"; +STR_R3F_LOG_action_decharger_en_cours = "Unloading in progress..."; +STR_R3F_LOG_action_decharger_fait = "The object ""%1"" has been unloaded from the vehicle."; +STR_R3F_LOG_action_decharger_deja_fait = "The object has already been unloaded !"; +STR_R3F_LOG_action_decharger_deplacable_exceptionnel = "Once released, this object will no more be movable manually.
Do you confirm the action ?"; + +STR_R3F_LOG_action_ouvrir_usine = "Open the creation factory"; +STR_R3F_LOG_action_creer_en_cours = "Creation in progress..."; +STR_R3F_LOG_action_creer_fait = "The object ""%1"" has been created."; +STR_R3F_LOG_action_creer_pas_assez_credits = "The factory has not enough credits to create this object."; +STR_R3F_LOG_action_revendre_usine_direct = "Send back ""%1"" to the factory"; +STR_R3F_LOG_action_revendre_usine_deplace = "Send back to the factory"; +STR_R3F_LOG_action_revendre_usine_selection = "... send back to the factory"; +STR_R3F_LOG_action_revendre_en_cours = "Sending back to the factory..."; +STR_R3F_LOG_action_revendre_fait = "The object ""%1"" has been sent back to the factory."; +STR_R3F_LOG_action_revendre_decharger_avant = "You can't sent it back while its cargo content is not empty !"; + +STR_R3F_LOG_mutex_action_en_cours = "The current operation isn't finished !"; +STR_R3F_LOG_joueur_dans_objet = "There is a player in the object ""%1"" !"; +STR_R3F_LOG_objet_en_cours_transport = "The object ""%1"" is already in transit !"; +STR_R3F_LOG_objet_remorque_en_cours = "Impossible because the object ""%1"" is towing another object !"; +STR_R3F_LOG_trop_loin = "Impossible because the object ""%1"" is too far !"; + +STR_R3F_LOG_dlg_CV_titre = "Vehicle's content"; +STR_R3F_LOG_dlg_CV_capacite_vehicule = "Loading : %1/%2"; +STR_R3F_LOG_dlg_CV_btn_decharger = "UNLOAD"; +STR_R3F_LOG_dlg_CV_btn_fermer = "CANCEL"; + +STR_R3F_LOG_dlg_LO_titre = "Creation factory"; +STR_R3F_LOG_dlg_LO_credits_restants = "Remaining credits : %1"; +STR_R3F_LOG_dlg_LO_btn_creer = "CREATE"; +STR_R3F_LOG_dlg_LO_btn_fermer = "CANCEL"; + +STR_R3F_LOG_nom_fonctionnalite_proprietes = "Properties"; +STR_R3F_LOG_nom_fonctionnalite_side = "Side"; +STR_R3F_LOG_nom_fonctionnalite_places = "Seating"; +STR_R3F_LOG_nom_fonctionnalite_passif = "It can be :"; +STR_R3F_LOG_nom_fonctionnalite_passif_deplace = "Moved by player"; +STR_R3F_LOG_nom_fonctionnalite_passif_heliporte = "Lifted"; +STR_R3F_LOG_nom_fonctionnalite_passif_remorque = "Towed"; +STR_R3F_LOG_nom_fonctionnalite_passif_transporte = "Transported"; +STR_R3F_LOG_nom_fonctionnalite_passif_transporte_capacite = "load cost %1"; +STR_R3F_LOG_nom_fonctionnalite_actif = "It can :"; +STR_R3F_LOG_nom_fonctionnalite_actif_heliporte = "Lift"; +STR_R3F_LOG_nom_fonctionnalite_actif_remorque = "Tow"; +STR_R3F_LOG_nom_fonctionnalite_actif_transporte = "Transport"; +STR_R3F_LOG_nom_fonctionnalite_actif_transporte_capacite = "max load %1"; + +STR_R3F_LOG_deverrouillage_en_cours = "Unlocking... (%1)"; +STR_R3F_LOG_deverrouillage_echec_attente = "Unlock canceled ! Hold the aiming of the object during the countdown."; +STR_R3F_LOG_deverrouillage_succes_attente = "Object unlocked."; +STR_R3F_LOG_action_deverrouiller = "Unlock ""%1"""; +STR_R3F_LOG_action_deverrouiller_impossible = "Object locked"; \ No newline at end of file diff --git a/fonctions_generales/determiner_fonctionnalites_logistique.sqf b/fonctions_generales/determiner_fonctionnalites_logistique.sqf new file mode 100644 index 0000000..b4c1daa --- /dev/null +++ b/fonctions_generales/determiner_fonctionnalites_logistique.sqf @@ -0,0 +1,112 @@ +/** + * Détermine les fonctionnalités logistique disponibles pour une classe donnée + * + * @param 0 le nom de classe pour lequel déterminer les fonctionnalités logistique + * + * @return 0 true si can_be_depl_heli_remorq_transp + * @return 1 true si can_be_moved_by_player + * @return 2 true si can_be_lifted + * @return 3 true si can_be_towed + * @return 4 true si can_be_transported_cargo + * @return 5 true si can_lift + * @return 6 true si can_tow + * @return 7 true si can_transport_cargo + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +private ["_classe", "_tab_classe_heritage", "_config", "_idx"]; +private ["_can_be_depl_heli_remorq_transp", "_can_lift", "_can_tow", "_can_transport_cargo", "_can_transport_cargo_cout"]; +private ["_can_be_moved_by_player", "_can_be_lifted", "_can_be_towed", "_can_be_transported_cargo", "_can_be_transported_cargo_cout"]; + +_classe = _this select 0; + +// Calcul de l'arborescence d'héritage +_tab_classe_heritage = []; +for [ + {_config = configFile >> "CfgVehicles" >> _classe}, + {isClass _config}, + {_config = inheritsFrom _config} +] do +{ + _tab_classe_heritage pushBack (toLower configName _config); +}; + +// Calcul des fonctionnalités + +_can_be_depl_heli_remorq_transp = false; +{ + if (_x in R3F_LOG_objets_depl_heli_remorq_transp) exitWith {_can_be_depl_heli_remorq_transp = true;}; +} forEach _tab_classe_heritage; + +_can_be_moved_by_player = false; +_can_be_lifted = false; +_can_be_towed = false; +_can_be_transported_cargo = false; +_can_be_transported_cargo_cout = 0; + +if (_can_be_depl_heli_remorq_transp) then +{ + { + if (_x in R3F_LOG_CFG_can_be_moved_by_player) exitWith {_can_be_moved_by_player = true;}; + } forEach _tab_classe_heritage; + + { + if (_x in R3F_LOG_CFG_can_be_lifted) exitWith {_can_be_lifted = true;}; + } forEach _tab_classe_heritage; + + { + if (_x in R3F_LOG_CFG_can_be_towed) exitWith {_can_be_towed = true;}; + } forEach _tab_classe_heritage; + + { + _idx = R3F_LOG_classes_objets_transportables find _x; + if (_idx != -1) exitWith + { + _can_be_transported_cargo = true; + _can_be_transported_cargo_cout = R3F_LOG_CFG_can_be_transported_cargo select _idx select 1; + }; + } forEach _tab_classe_heritage; +}; + +_can_lift = false; +{ + if (_x in R3F_LOG_CFG_can_lift) exitWith {_can_lift = true;}; +} forEach _tab_classe_heritage; + +_can_tow = false; +{ + if (_x in R3F_LOG_CFG_can_tow) exitWith {_can_tow = true;}; +} forEach _tab_classe_heritage; + +_can_transport_cargo = false; +_can_transport_cargo_cout = 0; +{ + _idx = R3F_LOG_classes_transporteurs find _x; + if (_idx != -1) exitWith + { + _can_transport_cargo = true; + _can_transport_cargo_cout = R3F_LOG_CFG_can_transport_cargo select _idx select 1; + }; +} forEach _tab_classe_heritage; + +// Cargo de capacité nulle +if (_can_transport_cargo_cout <= 0) then {_can_transport_cargo = false;}; + +// Retour des fonctionnalités +[ + _can_be_depl_heli_remorq_transp, + _can_be_moved_by_player, + _can_lift, + _can_be_lifted, + _can_tow, + _can_be_towed, + _can_transport_cargo, + _can_transport_cargo_cout, + _can_be_transported_cargo, + _can_be_transported_cargo_cout +] \ No newline at end of file diff --git a/fonctions_generales/formater_fonctionnalites_logistique.sqf b/fonctions_generales/formater_fonctionnalites_logistique.sqf new file mode 100644 index 0000000..50a62ae --- /dev/null +++ b/fonctions_generales/formater_fonctionnalites_logistique.sqf @@ -0,0 +1,63 @@ +/** + * Affiche dans la zone "hint" les fonctionnalités logistique disponibles pour une classe donnée + * + * @param 0 le nom de classe pour lequel consulter les fonctionnalités logistique + * @return structuredText des fonctionnalités logistique + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +private ["_classe", "_fonctionnalites", "_side", "_places", "_infos", "_j", "_tab_inheritance_tree"]; + +_classe = _this select 0; + +if !(isClass (configFile >> "CfgVehicles" >> _classe)) exitWith {}; + +_fonctionnalites = [_classe] call R3F_LOG_FNCT_determiner_fonctionnalites_logistique; + +_side = switch (getNumber (configFile >> "CfgVehicles" >> _classe >> "side")) do +{ + case 0: {"EAST"}; + case 1: {"WEST"}; + case 2: {"GUER"}; + case 3: {"CIV"}; + default {"NONE"}; +}; + +_places = 0; +if (!isNil "R3F_LOG_VIS_objet" && {!isNull R3F_LOG_VIS_objet && {typeOf R3F_LOG_VIS_objet == _classe}}) then +{ + { + _places = _places + (R3F_LOG_VIS_objet emptyPositions _x); + } forEach ["Commander", "Driver", "Gunner", "Cargo"]; +}; + +_infos = ""; +_infos = _infos + format ["%1 : %2
", STR_R3F_LOG_nom_fonctionnalite_side, _side]; +if (_places != 0) then {_infos = _infos + format ["%1 : %2
", STR_R3F_LOG_nom_fonctionnalite_places, _places]} else {_infos = _infos + "
";}; +_infos = _infos + "
"; +_infos = _infos + format ["%1
", STR_R3F_LOG_nom_fonctionnalite_passif]; +_infos = _infos + format ["- %1
", STR_R3F_LOG_nom_fonctionnalite_passif_deplace, if (_fonctionnalites select R3F_LOG_IDX_can_be_moved_by_player) then {"#00eeff"} else {"#777777"}]; +_infos = _infos + format ["- %1
", STR_R3F_LOG_nom_fonctionnalite_passif_heliporte, if (_fonctionnalites select R3F_LOG_IDX_can_be_lifted) then {"#00ee00"} else {"#777777"}]; +_infos = _infos + format ["- %1
", STR_R3F_LOG_nom_fonctionnalite_passif_remorque, if (_fonctionnalites select R3F_LOG_IDX_can_be_towed) then {"#00ee00"} else {"#777777"}]; +_infos = _infos + format ["- %1%3
", + STR_R3F_LOG_nom_fonctionnalite_passif_transporte, + if (_fonctionnalites select R3F_LOG_IDX_can_be_transported_cargo) then {"#f5f500"} else {"#777777"}, + if (_fonctionnalites select R3F_LOG_IDX_can_be_transported_cargo) then {format [" (" + STR_R3F_LOG_nom_fonctionnalite_passif_transporte_capacite + ")", _fonctionnalites select R3F_LOG_IDX_can_be_transported_cargo_cout]} else {""} +]; +_infos = _infos + "
"; +_infos = _infos + format ["%1
", STR_R3F_LOG_nom_fonctionnalite_actif]; +_infos = _infos + format ["- %1
", STR_R3F_LOG_nom_fonctionnalite_actif_heliporte, if (_fonctionnalites select R3F_LOG_IDX_can_lift) then {"#00ee00"} else {"#777777"}]; +_infos = _infos + format ["- %1
", STR_R3F_LOG_nom_fonctionnalite_actif_remorque, if (_fonctionnalites select R3F_LOG_IDX_can_tow) then {"#00ee00"} else {"#777777"}]; +_infos = _infos + format ["- %1%3
", + STR_R3F_LOG_nom_fonctionnalite_actif_transporte, + if (_fonctionnalites select R3F_LOG_IDX_can_transport_cargo) then {"#f5f500"} else {"#777777"}, + if (_fonctionnalites select R3F_LOG_IDX_can_transport_cargo) then {format [" (" + STR_R3F_LOG_nom_fonctionnalite_actif_transporte_capacite + ")", _fonctionnalites select R3F_LOG_IDX_can_transport_cargo_cout]} else {""} +]; +_infos = _infos + "
"; + +parseText _infos \ No newline at end of file diff --git a/fonctions_generales/formater_nombre_entier_milliers.sqf b/fonctions_generales/formater_nombre_entier_milliers.sqf new file mode 100644 index 0000000..c69b48d --- /dev/null +++ b/fonctions_generales/formater_nombre_entier_milliers.sqf @@ -0,0 +1,46 @@ +/** + * Formate un nombre entier avec des séparateurs de milliers + * + * @param 0 le nombre à formater + * @return chaîne de caractère représentant le nombre formaté + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +private ["_nombre", "_centaines", "_str_signe", "_str_nombre", "_str_centaines"]; + +_nombre = _this select 0; + +_str_signe = if (_nombre < 0) then {"-"} else {""}; +_nombre = floor abs _nombre; + +_str_nombre = ""; +while {_nombre >= 1000} do +{ + _centaines = _nombre - (1000 * floor (0.001 * _nombre)); + _nombre = floor (0.001 * _nombre); + + if (_centaines < 100) then + { + if (_centaines < 10) then + { + _str_centaines = "00" + str _centaines; + } + else + { + _str_centaines = "0" + str _centaines; + }; + } + else + { + _str_centaines = str _centaines; + }; + + _str_nombre = "." + _str_centaines + _str_nombre; +}; + +_str_signe + str _nombre + _str_nombre \ No newline at end of file diff --git a/fonctions_generales/lib_geometrie_3D.sqf b/fonctions_generales/lib_geometrie_3D.sqf new file mode 100644 index 0000000..558e315 --- /dev/null +++ b/fonctions_generales/lib_geometrie_3D.sqf @@ -0,0 +1,1097 @@ +/** + * Bibliothèque de fonctions de calculs dans un espace 3D (calculs d'intersection, rotations, etc.). + * + * Fournit une série de fonctions de calculs d'intersection (bounding sphere, bounding box, rayon-bbox) + * Fournit des fonctions de génération de matrices 3x3 de rotations yaw, pitch, roll + * Fournit des fonctions de multiplications vec3 x mat3x3 et mat3x3 x mat3x3 + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Liste des fonctions : + * --------------------- + * // Calculs d'intersection rayon/bounding box/sphere/mesh + * R3F_LOG_FNCT_3D_ray_intersect_bbox + * R3F_LOG_FNCT_3D_ray_intersect_bbox_obj + * R3F_LOG_FNCT_3D_cam_intersect_bbox_obj + * + * R3F_LOG_FNCT_3D_pos_est_dans_bbox + * R3F_LOG_FNCT_3D_distance_min_pos_bbox + * + * R3F_LOG_FNCT_3D_bounding_sphere_intersect_bounding_sphere + * R3F_LOG_FNCT_3D_intersect_bounding_sphere_objs + * R3F_LOG_FNCT_3D_bounding_sphere_intersect_bounding_box + * R3F_LOG_FNCT_3D_bbox_intersect_bbox + * R3F_LOG_FNCT_3D_bbox_intersect_bbox_objs + * R3F_LOG_FNCT_3D_mesh_collision_objs + * + * // Recherche de position + * R3F_LOG_FNCT_3D_tirer_position_degagee_ciel + * R3F_LOG_FNCT_3D_tirer_position_degagee_sol + * + * // Utilitaires + * R3F_LOG_FNCT_3D_cursorTarget_distance_bbox + * R3F_LOG_FNCT_3D_cursorTarget_virtuel + * R3F_LOG_FNCT_3D_get_huit_coins_bounding_box_model + * R3F_LOG_FNCT_3D_get_huit_coins_bounding_box_world + * R3F_LOG_FNCT_3D_get_objets_genants_rayon + * R3F_LOG_FNCT_3D_get_bounding_box_depuis_classname + * R3F_LOG_FNCT_3D_get_hauteur_terrain_min_max_objet + * + * // Transformation 3D + * R3F_LOG_FNCT_3D_mult_mat3x3 + * R3F_LOG_FNCT_3D_mult_vec_mat3x3 + * R3F_LOG_FNCT_3D_mat_rot_roll + * R3F_LOG_FNCT_3D_mat_rot_pitch + * R3F_LOG_FNCT_3D_mat_rot_yaw + * + * // Visualisation + * R3F_LOG_FNCT_3D_tracer_bbox + * R3F_LOG_FNCT_3D_tracer_bbox_obj + */ + +/** + * Calcule l'intersection d'un rayon avec une bounding box + * @param 0 position du rayon (dans le repère de la bbox) + * @param 1 direction du rayon (dans le repère de la bbox) + * @param 2 position min de la bounding box + * @param 3 position max de la bounding box + * @return la distance entre la position du rayon et la bounding box; 1E39 (infini) si pas d'intersection + * @note le rayon doit être défini dans le repère de la bbox (worldToModel) + */ +R3F_LOG_FNCT_3D_ray_intersect_bbox = +{ + private ["_ray_pos", "_ray_dir", "_bbox_min", "_bbox_max", "_inv_ray_x", "_inv_ray_y", "_inv_ray_z"]; + private ["_tmin", "_tmax", "_tymin", "_tymax", "_tzmin", "_tzmax"]; + + _ray_pos = _this select 0; + _ray_dir = _this select 1; + _bbox_min = _this select 2; + _bbox_max = _this select 3; + + // Optimisation (1 div + 2 mul au lieu de 2 div) et gestion de la division par zéro + _inv_ray_x = if (_ray_dir select 0 != 0) then {1 / (_ray_dir select 0)} else {1E39}; + _inv_ray_y = if (_ray_dir select 1 != 0) then {1 / (_ray_dir select 1)} else {1E39}; + _inv_ray_z = if (_ray_dir select 2 != 0) then {1 / (_ray_dir select 2)} else {1E39}; + + /* Pour chaque axe, on calcule la distance d'intersection du rayon avec les deux plans de la bounding box */ + + if (_inv_ray_x < 0) then + { + _tmax = ((_bbox_min select 0) - (_ray_pos select 0)) * _inv_ray_x; + _tmin = ((_bbox_max select 0) - (_ray_pos select 0)) * _inv_ray_x; + } + else + { + _tmin = ((_bbox_min select 0) - (_ray_pos select 0)) * _inv_ray_x; + _tmax = ((_bbox_max select 0) - (_ray_pos select 0)) * _inv_ray_x; + }; + + if (_inv_ray_y < 0) then + { + _tymax = ((_bbox_min select 1) - (_ray_pos select 1)) * _inv_ray_y; + _tymin = ((_bbox_max select 1) - (_ray_pos select 1)) * _inv_ray_y; + } + else + { + _tymin = ((_bbox_min select 1) - (_ray_pos select 1)) * _inv_ray_y; + _tymax = ((_bbox_max select 1) - (_ray_pos select 1)) * _inv_ray_y; + }; + + if ((_tmin > _tymax) || (_tymin > _tmax)) exitWith {1E39}; + + _tmin = _tmin max _tymin; + _tmax = _tmax min _tymax; + + if (_inv_ray_z < 0) then + { + _tzmax = ((_bbox_min select 2) - (_ray_pos select 2)) * _inv_ray_z; + _tzmin = ((_bbox_max select 2) - (_ray_pos select 2)) * _inv_ray_z; + } + else + { + _tzmin = ((_bbox_min select 2) - (_ray_pos select 2)) * _inv_ray_z; + _tzmax = ((_bbox_max select 2) - (_ray_pos select 2)) * _inv_ray_z; + }; + + if ((_tmin > _tzmax) || (_tzmin > _tmax)) exitWith {1E39}; + + _tmin = _tmin max _tzmin; + _tmax = _tmax min _tzmax; + + if (_tmax < 0) exitWith {1E39}; + + _tmin +}; + +/** + * Calcule l'intersection d'un rayon avec un objet + * @param 0 position du rayon (dans le repère worldATL) + * @param 1 direction du rayon (dans le repère world) + * @param 2 l'objet pour lequel calculer l'intersection de bounding box + * @return la distance entre la position du rayon et la bounding box; 1E39 (infini) si pas d'intersection + */ +R3F_LOG_FNCT_3D_ray_intersect_bbox_obj = +{ + private ["_ray_pos", "_ray_dir", "_objet"]; + + _ray_pos = _this select 0; + _ray_dir = _this select 1; + _objet = _this select 2; + + [ + _objet worldToModel _ray_pos, + // (_objet worldToModel _ray_dir) vectorDiff (_objet worldToModel [0,0,0]), Manque de précision numérique, d'où l'expression ci-dessous + (_objet worldToModel ASLtoATL (_ray_dir vectorAdd getPosASL _objet)) vectorDiff (_objet worldToModel ASLtoATL (getPosASL _objet)), + boundingBoxReal _objet select 0, + boundingBoxReal _objet select 1 + ] call R3F_LOG_FNCT_3D_ray_intersect_bbox +}; + +/** + * Calcule l'intersection du centre de la caméra avec la bounding box d'un objet + * @param 0 l'objet pour lequel on souhaite calculer l'intersection de bounding box + * @return la distance entre la caméra du joueur et la bounding box; 1E39 (infini) si pas d'intersection + */ +R3F_LOG_FNCT_3D_cam_intersect_bbox_obj = +{ + private ["_objet", "_pos_cam", "_pos_devant", "_dir_cam"]; + + _objet = _this select 0; + + if (isNull _objet) exitWith {1E39}; + + _pos_cam = positionCameraToWorld [0, 0, 0]; + _pos_devant = positionCameraToWorld [0, 0, 1]; + _dir_cam = (ATLtoASL _pos_devant) vectorDiff (ATLtoASL _pos_cam); + + [_pos_cam, _dir_cam, _objet] call R3F_LOG_FNCT_3D_ray_intersect_bbox_obj +}; + +/** + * Indique si une position se trouve à l'intérieur d'une bounding box + * @param 0 position à tester (dans le repère de la bbox) + * @param 1 position min de la bounding box + * @param 2 position max de la bounding box + * @return true si la position se trouve à l'intérieur de la bounding box, false sinon + * @note la position doit être défini dans le repère de la bbox (worldToModel) + */ +R3F_LOG_FNCT_3D_pos_est_dans_bbox = +{ + private ["_pos", "_bbox_min", "_bbox_max"]; + + _pos = _this select 0; + _bbox_min = _this select 1; + _bbox_max = _this select 2; + + (_bbox_min select 0 <= _pos select 0) && (_pos select 0 <= _bbox_max select 0) && + (_bbox_min select 1 <= _pos select 1) && (_pos select 1 <= _bbox_max select 1) && + (_bbox_min select 2 <= _pos select 2) && (_pos select 2 <= _bbox_max select 2) +}; + +/** + * Calcule la distance minimale entre une position et une bounding box + * @param 0 la position pour laquelle calculer la distance avec la bbox (dans le repère de la bbox) + * @param 1 position min de la bounding box + * @param 2 position max de la bounding box + * @return distance du segment le plus court reliant la position à la bounding box + */ +R3F_LOG_FNCT_3D_distance_min_pos_bbox = +{ + private ["_pos", "_bbox_min", "_bbox_max", "_pos_intersect_min_bbox"]; + + _pos = _this select 0; + _bbox_min = _this select 1; + _bbox_max = _this select 2; + + _pos_intersect_min_bbox = + [ + (_bbox_min select 0) max (_pos select 0) min (_bbox_max select 0), + (_bbox_min select 1) max (_pos select 1) min (_bbox_max select 1), + (_bbox_min select 2) max (_pos select 2) min (_bbox_max select 2) + ]; + + _pos_intersect_min_bbox distance _pos +}; + +/** + * Indique s'il y a intersection entre deux bounding sphere + * @param 0 position centrale de la première bounding sphere + * @param 1 rayon de la première bounding sphere + * @param 2 position centrale de la deuxième bounding sphere + * @param 3 rayon de la deuxième bounding sphere + * @return true s'il y a intersection entre les deux bounding sphere, false sinon + * @note les deux bounding sphere doivent être définies dans le même repère (worldASL ou model) + * @note pour effecteur un test entre un point et une sphere, définir un rayon de 0 + */ +R3F_LOG_FNCT_3D_bounding_sphere_intersect_bounding_sphere = +{ + private ["_pos1", "_rayon1", "_pos2", "_rayon2"]; + + _pos1 = _this select 0; + _rayon1 = _this select 1; + _pos2 = _this select 2; + _rayon2 = _this select 3; + + (_pos1 distance _pos2) <= (_rayon1 + _rayon2) +}; + +/** + * Détermine s'il y a intersection entre les bounding spheres de deux objets + * @param 0 le premier objet pour lequel calculer l'intersection de bounding sphere + * @param 1 le deuxième objet pour lequel calculer l'intersection de bounding sphere + * @return true s'il y a intersection entre les bounding sphere des deux objets, false sinon + */ +R3F_LOG_FNCT_3D_intersect_bounding_sphere_objs = +{ + private ["_objet1", "_objet2"]; + + _objet1 = _this select 0; + _objet2 = _this select 1; + + // Valeurs selon le formule de R3F_LOG_FNCT_3D_bounding_sphere_intersect_bounding_sphere + //_pos1 = [0,0,0]; + //_rayon1 = (vectorMagnitude (boundingBoxReal _objet1 select 0)) max (vectorMagnitude (boundingBoxReal _objet1 select 1)); + //_pos2 = _objet1 worldToModel (_objet2 modelToWorld [0,0,0]); + //_rayon2 = (vectorMagnitude (boundingBoxReal _objet2 select 0)) max (vectorMagnitude (boundingBoxReal _objet2 select 1)); + // Retour : (_pos1 distance _pos2) <= (_rayon1 + _rayon2) + + // Ce qui donne + vectorMagnitude (_objet1 worldToModel (_objet2 modelToWorld [0,0,0])) <= ( + ((vectorMagnitude (boundingBoxReal _objet1 select 0)) max (vectorMagnitude (boundingBoxReal _objet1 select 1))) + + + ((vectorMagnitude (boundingBoxReal _objet2 select 0)) max (vectorMagnitude (boundingBoxReal _objet2 select 1))) + ) +}; + +/** + * Détermine s'il y a intersection entre entre une bounding box et une bounding sphere + * @param 0 la position centrale de la bounding sphere (dans le repère de la bbox) + * @param 1 rayon de la bounding sphere + * @param 2 position min de la bounding box + * @param 3 position max de la bounding box + * @return true s'il y a intersection entre la bounding box et la bounding sphere, false sinon + */ +R3F_LOG_FNCT_3D_bounding_sphere_intersect_bounding_box = +{ + private ["_pos_bsphere", "_rayon_bsphere", "_bbox_min", "_bbox_max", "_pos_intersect_min_bbox"]; + + // Utilisation "inline" de la fonction R3F_LOG_FNCT_3D_distance_min_pos_bbox + _pos_bsphere = _this select 0; + _rayon_bsphere = _this select 1; + _bbox_min = _this select 2; + _bbox_max = _this select 3; + + _pos_intersect_min_bbox = + [ + (_bbox_min select 0) max (_pos_bsphere select 0) min (_bbox_max select 0), + (_bbox_min select 1) max (_pos_bsphere select 1) min (_bbox_max select 1), + (_bbox_min select 2) max (_pos_bsphere select 2) min (_bbox_max select 2) + ]; + + (_pos_intersect_min_bbox distance _pos_bsphere) <= _rayon_bsphere +}; + +/** + * Détermine s'il y a intersection entre les bounding box de deux objets + * @param 0 le premier objet pour lequel calculer l'intersection + * @param 1 position min de la bounding box du premier objet + * @param 2 position max de la bounding box du premier objet + * @param 3 le deuxième objet pour lequel calculer l'intersection + * @param 4 position min de la bounding box du deuxième objet + * @param 5 position max de la bounding box du deuxième objet + * @return true s'il y a intersection entre les bounding box des deux objets, false sinon + * @note les objets peuvent être d'un type ne correspondant pas aux bounding box + * @note cela permet par exemple d'utiliser une logique de jeu, pour un calcul à priori + */ +R3F_LOG_FNCT_3D_bbox_intersect_bbox = +{ + private ["_objet1", "_objet2", "_bbox1_min", "_bbox1_max", "_bbox2_min", "_bbox2_max", "_intersect", "_coins", "_rayons"]; + + _objet1 = _this select 0; + _bbox1_min = _this select 1; + _bbox1_max = _this select 2; + _objet2 = _this select 3; + _bbox2_min = _this select 4; + _bbox2_max = _this select 5; + + // Quitter dès maintenant s'il est impossible d'avoir une intersection + if !( + [ + _objet2 worldToModel (_objet1 modelToWorld [0,0,0]), + (vectorMagnitude _bbox1_min) max (vectorMagnitude _bbox1_max), + _bbox2_min, + _bbox2_max + ] call R3F_LOG_FNCT_3D_bounding_sphere_intersect_bounding_box + && + [ + _objet1 worldToModel (_objet2 modelToWorld [0,0,0]), + (vectorMagnitude _bbox2_min) max (vectorMagnitude _bbox2_max), + _bbox1_min, + _bbox1_max + ] call R3F_LOG_FNCT_3D_bounding_sphere_intersect_bounding_box + ) exitWith {false}; + + _intersect = false; + _coins = []; + + // Composition des coordonnées des 8 coins de la bounding box de l'objet1, dans l'espace du modèle _objet2 + _coins set [0, _objet2 worldToModel (_objet1 modelToWorld [_bbox1_min select 0, _bbox1_min select 1, _bbox1_min select 2])]; + _coins set [1, _objet2 worldToModel (_objet1 modelToWorld [_bbox1_min select 0, _bbox1_min select 1, _bbox1_max select 2])]; + _coins set [2, _objet2 worldToModel (_objet1 modelToWorld [_bbox1_min select 0, _bbox1_max select 1, _bbox1_min select 2])]; + _coins set [3, _objet2 worldToModel (_objet1 modelToWorld [_bbox1_min select 0, _bbox1_max select 1, _bbox1_max select 2])]; + _coins set [4, _objet2 worldToModel (_objet1 modelToWorld [_bbox1_max select 0, _bbox1_min select 1, _bbox1_min select 2])]; + _coins set [5, _objet2 worldToModel (_objet1 modelToWorld [_bbox1_max select 0, _bbox1_min select 1, _bbox1_max select 2])]; + _coins set [6, _objet2 worldToModel (_objet1 modelToWorld [_bbox1_max select 0, _bbox1_max select 1, _bbox1_min select 2])]; + _coins set [7, _objet2 worldToModel (_objet1 modelToWorld [_bbox1_max select 0, _bbox1_max select 1, _bbox1_max select 2])]; + + // Test de présence de chacun des coins de la bounding box de l'objet1, dans la bounding box de l'objet2 + { + // Utilisation "inline" de la fonction R3F_LOG_FNCT_3D_pos_est_dans_bbox + if ( + (_bbox2_min select 0 <= _x select 0) && (_x select 0 <= _bbox2_max select 0) && + (_bbox2_min select 1 <= _x select 1) && (_x select 1 <= _bbox2_max select 1) && + (_bbox2_min select 2 <= _x select 2) && (_x select 2 <= _bbox2_max select 2) + ) exitWith {_intersect = true;}; + } forEach _coins; + + if (_intersect) exitWith {true}; + + // Composition des coordonnées des 8 coins de la bounding box de l'objet2, dans l'espace du modèle _objet1 + _coins set [0, _objet1 worldToModel (_objet2 modelToWorld [_bbox2_min select 0, _bbox2_min select 1, _bbox2_min select 2])]; + _coins set [1, _objet1 worldToModel (_objet2 modelToWorld [_bbox2_min select 0, _bbox2_min select 1, _bbox2_max select 2])]; + _coins set [2, _objet1 worldToModel (_objet2 modelToWorld [_bbox2_min select 0, _bbox2_max select 1, _bbox2_min select 2])]; + _coins set [3, _objet1 worldToModel (_objet2 modelToWorld [_bbox2_min select 0, _bbox2_max select 1, _bbox2_max select 2])]; + _coins set [4, _objet1 worldToModel (_objet2 modelToWorld [_bbox2_max select 0, _bbox2_min select 1, _bbox2_min select 2])]; + _coins set [5, _objet1 worldToModel (_objet2 modelToWorld [_bbox2_max select 0, _bbox2_min select 1, _bbox2_max select 2])]; + _coins set [6, _objet1 worldToModel (_objet2 modelToWorld [_bbox2_max select 0, _bbox2_max select 1, _bbox2_min select 2])]; + _coins set [7, _objet1 worldToModel (_objet2 modelToWorld [_bbox2_max select 0, _bbox2_max select 1, _bbox2_max select 2])]; + + // Test de présence de chacun des coins de la bounding box de l'objet2, dans la bounding box de l'objet1 + { + // Utilisation "inline" de la fonction R3F_LOG_FNCT_3D_pos_est_dans_bbox + if ( + (_bbox1_min select 0 <= _x select 0) && (_x select 0 <= _bbox1_max select 0) && + (_bbox1_min select 1 <= _x select 1) && (_x select 1 <= _bbox1_max select 1) && + (_bbox1_min select 2 <= _x select 2) && (_x select 2 <= _bbox1_max select 2) + ) exitWith {_intersect = true;}; + } forEach _coins; + + if (_intersect) exitWith {true}; + + // Composition des 12 rayons [pos, dir, longueur] correspondant aux segments de la bounding box de l'objet2, dans l'espace du modèle _objet1 + _rayons = []; + _rayons set [ 0, [_coins select 1, _coins select 0, vectorMagnitude ((_coins select 1) vectorDiff (_coins select 0))]]; + _rayons set [ 1, [_coins select 2, _coins select 0, vectorMagnitude ((_coins select 2) vectorDiff (_coins select 0))]]; + _rayons set [ 2, [_coins select 1, _coins select 3, vectorMagnitude ((_coins select 1) vectorDiff (_coins select 3))]]; + _rayons set [ 3, [_coins select 2, _coins select 3, vectorMagnitude ((_coins select 2) vectorDiff (_coins select 3))]]; + _rayons set [ 4, [_coins select 5, _coins select 4, vectorMagnitude ((_coins select 5) vectorDiff (_coins select 4))]]; + _rayons set [ 5, [_coins select 6, _coins select 4, vectorMagnitude ((_coins select 6) vectorDiff (_coins select 4))]]; + _rayons set [ 6, [_coins select 5, _coins select 7, vectorMagnitude ((_coins select 5) vectorDiff (_coins select 7))]]; + _rayons set [ 7, [_coins select 6, _coins select 7, vectorMagnitude ((_coins select 6) vectorDiff (_coins select 7))]]; + _rayons set [ 8, [_coins select 0, _coins select 4, vectorMagnitude ((_coins select 0) vectorDiff (_coins select 4))]]; + _rayons set [ 9, [_coins select 1, _coins select 5, vectorMagnitude ((_coins select 1) vectorDiff (_coins select 5))]]; + _rayons set [10, [_coins select 2, _coins select 6, vectorMagnitude ((_coins select 2) vectorDiff (_coins select 6))]]; + _rayons set [11, [_coins select 3, _coins select 7, vectorMagnitude ((_coins select 3) vectorDiff (_coins select 7))]]; + + // Test d'intersection de chaque rayon avec la bounding box de l'objet1 + { + // Si la dimension de la bbox, dans l'axe concerné, est nulle, on fait un calcul basé sur la position (rayon de longueur nulle) + if (_x select 2 == 0) then + { + if ([_x select 0, _bbox1_min, _bbox1_max] call R3F_LOG_FNCT_3D_pos_est_dans_bbox) exitWith {_intersect = true;}; + } + else + { + if ([ + _x select 0, + ((_x select 1) vectorDiff (_x select 0)) vectorMultiply (1 / (_x select 2)), // Direction rayon + _bbox1_min, + _bbox1_max + ] call R3F_LOG_FNCT_3D_ray_intersect_bbox <= (_x select 2)) exitWith {_intersect = true;}; + }; + } forEach _rayons; + + _intersect +}; + +/** + * Détermine s'il y a intersection entre les bounding box de deux objets + * @param 0 le premier objet pour lequel calculer l'intersection + * @param 1 le deuxième objet pour lequel calculer l'intersection + * @return true s'il y a intersection entre les bounding box des deux objets, false sinon + */ +R3F_LOG_FNCT_3D_bbox_intersect_bbox_objs = +{ + private ["_objet1", "_objet2"]; + + _objet1 = _this select 0; + _objet2 = _this select 1; + + [ + _objet1, + boundingBoxReal _objet1 select 0, + boundingBoxReal _objet1 select 1, + _objet2, + boundingBoxReal _objet2 select 0, + boundingBoxReal _objet2 select 1 + ] call R3F_LOG_FNCT_3D_bbox_intersect_bbox +}; + +/** + * Détermine s'il y a une collision physique réelle (mesh) entre deux objets + * @param 0 le premier objet pour lequel calculer l'intersection + * @param 1 le deuxième objet pour lequel calculer l'intersection + * @param 2 (optionnel) true pour tester directement la collision de mesh sans tester les bbox, false pour d'abord tester les bbox (défaut : false) + * @return true s'il y a une collision physique réelle (mesh) entre deux objets, false sinon + * @note le calcul est basé sur les collisions PhysX, des objets non PhysX ne genère pas de collision + * + * @note WARNING WORK IN PROGRESS FUNCTION, NOT FOR USE !!! TODO FINALIZE IT + */ +R3F_LOG_FNCT_3D_mesh_collision_objs = +{ + private ["_objet1", "_objet2", "_objet_test1", "_objet_test2", "_force_test_mesh", "_pos_test", "_num_frame_start", "_collision"]; + + _objet1 = _this select 0; + _objet2 = _this select 1; + _force_test_mesh = if (count _this > 2) then {_this select 2} else {false}; + + // Quitter dès maintenant s'il est impossible d'avoir une intersection (sauf test forcé) + if (!_force_test_mesh && {!( + [ + _objet1, + boundingBoxReal _objet1 select 0, + boundingBoxReal _objet1 select 1, + _objet2, + boundingBoxReal _objet2 select 0, + boundingBoxReal _objet2 select 1 + ] call R3F_LOG_FNCT_3D_bbox_intersect_bbox + )}) exitWith {false}; + + systemChat format ["PROBABLE INTERSECT MESH : %1 @ %2", _objet2, time];//TODO REMOVE + + _pos_test = ATLtoASL (player modelToWorld [0,16,20]);// TODO remplacer par R3F_LOG_FNCT_3D_tirer_position_degagee_ciel + + _objet_test1 = (typeOf _objet1) createVehicleLocal ([] call R3F_LOG_FNCT_3D_tirer_position_degagee_ciel); + _objet_test1 setVectorDirAndUp [vectorDir _objet1, vectorUp _objet1]; + _objet_test1 allowDamage false; + _objet_test1 addEventHandler ["EpeContactStart", {if (!isNull (_this select 1)) then {(_this select 0) setVariable ["R3F_LOG_3D_collision", true, false];};}]; + _objet_test1 setVariable ["R3F_LOG_3D_collision", false, false]; + + _objet_test2 = (typeOf _objet2) createVehicleLocal ([] call R3F_LOG_FNCT_3D_tirer_position_degagee_ciel); + _objet_test2 setVectorDirAndUp [vectorDir _objet2, vectorUp _objet2]; + _objet_test2 allowDamage false; + _objet_test2 addEventHandler ["EpeContactStart", {if (!isNull (_this select 1)) then {(_this select 0) setVariable ["R3F_LOG_3D_collision", true, false];};}]; + _objet_test2 setVariable ["R3F_LOG_3D_collision", false, false]; + + _objet_test1 setVelocity [0,0,0]; + _objet_test1 setVectorDirAndUp [vectorDir _objet1, vectorUp _objet1]; + _objet_test1 setPosASL _pos_test; + _objet_test2 setVelocity [0,0,0]; + _objet_test2 setVectorDirAndUp [vectorDir _objet2, vectorUp _objet2]; + _objet_test2 setPosASL (_pos_test vectorAdd ((_objet1 worldToModel (_objet2 modelToWorld [0,0,0])) vectorDiff (_objet1 modelToWorld [0,0,0]))); + + _num_frame_start = diag_frameno; + waitUntil + { + _collision = (_objet_test1 getVariable "R3F_LOG_3D_collision") || (_objet_test2 getVariable "R3F_LOG_3D_collision"); + _collision || (diag_frameno - _num_frame_start > 10) + }; + + if (_collision) then {systemChat format ["RESULTAT COLLISION: %1 @ %2", _objet2, time];};//TODO REMOVE + + sleep 0.02;// TODO REMOVE + + deleteVehicle _objet_test1; + deleteVehicle _objet_test2; + + _collision +}; + +/** + * Retourne une position dégagée dans le ciel + * @param 0 (optionnel) offset 3D du cube dans lequel chercher une position (défaut [0,0,0]) + * @return position dégagée (sphère de 50m de rayon) dans le ciel + */ +R3F_LOG_FNCT_3D_tirer_position_degagee_ciel = +{ + private ["_offset", "_nb_tirages", "_position_degagee"]; + + _offset = if (count _this > 0) then {_this select 0} else {[0,0,0]}; + + // Trouver une position dégagée (sphère de 50m de rayon) dans le ciel + for [ + { + _position_degagee = [random 3000, random 3000, 10000 + (random 20000)] vectorAdd _offset; + _nb_tirages = 1; + }, + { + !isNull (nearestObject _position_degagee) && _nb_tirages < 25 + }, + { + _position_degagee = [random 3000, random 3000, 10000 + (random 20000)] vectorAdd _offset; + _nb_tirages = _nb_tirages+1; + } + ] do {}; + + _position_degagee +}; + +/** + * Retourne une position suffisamment dégagée au sol pour créer un objet + * @param 0 le rayon de la zone dégagée à trouver au sein de la zone de recherche + * @param 1 la position centrale autour de laquelle chercher + * @param 2 le rayon maximal autour de la position centrale dans lequel chercher la position dégagée + * @param 3 (optionnel) nombre limite de tentatives de sélection d'une position dégagée avant abandon (défaut : 30) + * @param 4 (optionnel) true pour autoriser de retourner une position sur l'eau, false sinon (défaut : false) + * @return position dégagée du rayon indiqué, au sein de la zone de recherche, ou un tableau vide en cas d'échec + * @note cette fonction pallie au manque de fiabilité des commandes findEmptyPosition et isFlatEmpty concernant les collisions + */ +R3F_LOG_FNCT_3D_tirer_position_degagee_sol = +{ + private ["_rayon_degage", "_pos_centre", "_rayon_max", "_nb_tirages_max", "_eau_autorise", "_rayon_max_carre"]; + private ["_nb_tirages", "_objets_genants", "_position_degagee", "_rayon_curr", "_angle_curr", "_intersect"]; + + _rayon_degage = 1 max (_this select 0); + _pos_centre = _this select 1; + _rayon_max = _rayon_degage max (_this select 2); + _nb_tirages_max = if (count _this > 3) then {_this select 3} else {30}; + _eau_autorise = if (count _this > 4) then {_this select 4} else {false}; + + _rayon_max_carre = _rayon_max * _rayon_max; + + for [ + { + _position_degagee = [_pos_centre select 0, _pos_centre select 1, 0]; + _nb_tirages = 0; + }, + { + if (!_eau_autorise && surfaceIsWater _position_degagee) then {_nb_tirages < _nb_tirages_max} + else + { + _intersect = false; + + // Pour chaque objets à proximité de la zone à tester + { + // Test de collision de la bbox de l'objet avec la bounding sphere de la zone à tester + if ( + [ + _x worldToModel _position_degagee, + _rayon_degage, + boundingBoxReal _x select 0, + boundingBoxReal _x select 1 + ] call R3F_LOG_FNCT_3D_bounding_sphere_intersect_bounding_box + ) exitWith {_intersect = true;}; + } forEach ([_position_degagee, _rayon_degage+15] call R3F_LOG_FNCT_3D_get_objets_genants_rayon); + + _intersect && _nb_tirages < _nb_tirages_max + } + }, + { + // Tirage d'un angle aléatoire, et d'une rayon aléatoirement (distribution surfacique uniforme) + _angle_curr = random 360; + _rayon_curr = sqrt random _rayon_max_carre; + + _position_degagee = + [ + (_pos_centre select 0) + _rayon_curr * sin _angle_curr, + (_pos_centre select 1) + _rayon_curr * cos _angle_curr, + 0 + ]; + + _nb_tirages = _nb_tirages+1; + } + ] do {}; + + // Echec, position introuvée + if (_nb_tirages >= _nb_tirages_max) then {_position_degagee = [];}; + + _position_degagee +}; + +/** + * Calcule la distance entre le joueur et la bbox de l'objet pointé + * @return tableau avec en premier élément l'objet pointé (ou objNull), et en deuxième élément la distance entre le joueur et la bbox de l'objet pointé + */ +R3F_LOG_FNCT_3D_cursorTarget_distance_bbox = +{ + private ["_objet", "_joueur"]; + + _objet = cursorTarget; + _joueur = player; + + if (!isNull _objet && !isNull _joueur && alive _joueur && cameraOn == _joueur) then + { + [ + _objet, + [ + _objet worldToModel (_joueur modelToWorld (_joueur selectionPosition "head")), + boundingBoxReal _objet select 0, + boundingBoxReal _objet select 1 + ] call R3F_LOG_FNCT_3D_distance_min_pos_bbox + ] + } + else + { + [objNull, 1E39] + }; +}; + +/** + * Retourne l'objet pointé par le joueur à une distance max de la bounding box de l'objet pointé + * @param 0 (optionnel) liste d'objets à ignorer (défaut []) + * @param 1 (optionnel) distance maximale entre l'unité et la bounding box des objets (défaut : 10) + * @return l'objet pointé par le joueur ou objNull + */ +R3F_LOG_FNCT_3D_cursorTarget_virtuel = +{ + private ["_liste_ingores", "_distance_max", "_joueur", "_objet_pointe", "_cursorTarget_distance"]; + + if (isNull player) exitWith {objNull}; + + _liste_ingores = if (!isNil "_this" && {typeName _this == "ARRAY" && {count _this > 0}}) then {_this select 0} else {[]}; + _distance_max = if (!isNil "_this" && {typeName _this == "ARRAY" && {count _this > 1}}) then {_this select 1} else {10}; + _joueur = player; + + _objet_pointe = objNull; + + _cursorTarget_distance = call R3F_LOG_FNCT_3D_cursorTarget_distance_bbox; + + if (!isNull (_cursorTarget_distance select 0) && + {!((_cursorTarget_distance select 0) in _liste_ingores) && (_cursorTarget_distance select 1) <= _distance_max} + ) then + { + _objet_pointe = cursorTarget; + } + else + { + private ["_vec_dir_unite_world", "_pos_unite_world", "_liste_objets"]; + + _vec_dir_unite_world = (ATLtoASL positionCameraToWorld [0, 0, 1]) vectorDiff (ATLtoASL positionCameraToWorld [0,0,0]); + _pos_unite_world = _joueur modelToWorld (_joueur selectionPosition "head"); + + _liste_objets = lineIntersectsObjs [ + (ATLtoASL _pos_unite_world), + (ATLtoASL _pos_unite_world) vectorAdd (_vec_dir_unite_world vectorMultiply _distance_max), + objNull, + player, + true, + 16 + 32 + ]; + + { + if (!(_x in _liste_ingores) && + [ + _x worldToModel _pos_unite_world, + boundingBoxReal _x select 0, + boundingBoxReal _x select 1 + ] call R3F_LOG_FNCT_3D_distance_min_pos_bbox <= _distance_max + ) exitWith {_objet_pointe = _x;}; + } forEach _liste_objets; + }; + + _objet_pointe +}; + +/** + * Retourne la position des huit coins d'une bounding box dans le repère du modèle + * @param 0 position min de la bounding box + * @param 1 position max de la bounding box + * @return tableau contenant la position des huit coins d'une bounding box dans le repère du modèle + */ +R3F_LOG_FNCT_3D_get_huit_coins_bounding_box_model = +{ + private ["_bbox_min", "_bbox_max"]; + + _bbox_min = _this select 0; + _bbox_max = _this select 1; + + [ + [_bbox_min select 0, _bbox_min select 1, _bbox_min select 2], + [_bbox_min select 0, _bbox_min select 1, _bbox_max select 2], + [_bbox_min select 0, _bbox_max select 1, _bbox_min select 2], + [_bbox_min select 0, _bbox_max select 1, _bbox_max select 2], + [_bbox_max select 0, _bbox_min select 1, _bbox_min select 2], + [_bbox_max select 0, _bbox_min select 1, _bbox_max select 2], + [_bbox_max select 0, _bbox_max select 1, _bbox_min select 2], + [_bbox_max select 0, _bbox_max select 1, _bbox_max select 2] + ] +}; + +/** + * Retourne la position des huit coins d'une bounding box dans le repère world + * @param 0 l'objet pour lequel calculer les huit coins de la bbox dans le repère world + * @return tableau contenant la position des huit coins d'une bounding box dans le repère world + */ +R3F_LOG_FNCT_3D_get_huit_coins_bounding_box_world = +{ + private ["_objet", "_bbox_min", "_bbox_max"]; + + _objet = _this select 0; + + _bbox_min = boundingBoxReal _objet select 0; + _bbox_max = boundingBoxReal _objet select 1; + + [ + _objet modelToWorld [_bbox_min select 0, _bbox_min select 1, _bbox_min select 2], + _objet modelToWorld [_bbox_min select 0, _bbox_min select 1, _bbox_max select 2], + _objet modelToWorld [_bbox_min select 0, _bbox_max select 1, _bbox_min select 2], + _objet modelToWorld [_bbox_min select 0, _bbox_max select 1, _bbox_max select 2], + _objet modelToWorld [_bbox_max select 0, _bbox_min select 1, _bbox_min select 2], + _objet modelToWorld [_bbox_max select 0, _bbox_min select 1, _bbox_max select 2], + _objet modelToWorld [_bbox_max select 0, _bbox_max select 1, _bbox_min select 2], + _objet modelToWorld [_bbox_max select 0, _bbox_max select 1, _bbox_max select 2] + ] +}; + +/** + * Retourne la liste des objets présents dans un périmètre et pouvant avoir une collision physique, y compris les éléments de décors propres à la carte + * @param 0 la position centrale de la zone de recherche + * @param 1 le rayon de recherche + * @return la liste des objets présents dans un périmètre et pouvant avoir une collision physique + * @note la liste des objets retournées contient également les éléments de terrain tels que les rochers et les arbres, murs, bâtiments, ... + */ +R3F_LOG_FNCT_3D_get_objets_genants_rayon = +{ + private ["_pos_centre", "_rayon", "_obj_proches", "_elements_terrain", "_bbox_dim", "_volume", "_e"]; + + _pos_centre = _this select 0; + _rayon = _this select 1; + + // Récupération des objets et véhicules proches avec bounding suffisamment grande + _obj_proches = []; + { + _bbox_dim = (boundingBoxReal _x select 1) vectorDiff (boundingBoxReal _x select 0); + _volume = (_bbox_dim select 0) * (_bbox_dim select 1) * (_bbox_dim select 2); + + // Filtre : volume suffisamment important + if (_volume > 0.08) then + { + // Filtre : insectes et vie ambiante + if !(typeOf _x in ["Snake_random_F", "ButterFly_random", "HouseFly", "HoneyBee", "Mosquito"]) then + { + _obj_proches pushBack _x; + }; + }; + } forEach (nearestObjects [_pos_centre, ["All"], _rayon]); + + // Récupération de TOUS les éléments à proximité (y compris les rochers, végétations, insectes, particules en suspension, ...) + // On ignore les éléments non gênants tels que les traces de pas, insectes, particules en suspension, ... + _elements_terrain = []; + { + _e = _x; + + // Filtre : objet immobile + if (vectorMagnitude velocity _e == 0) then + { + _bbox_dim = (boundingBoxReal _e select 1) vectorDiff (boundingBoxReal _e select 0); + _volume = (_bbox_dim select 0) * (_bbox_dim select 1) * (_bbox_dim select 2); + + // Filtre : volume suffisamment important + if (_volume > 0.08) then + { + // Filtre : insectes et vie ambiante + if !(typeOf _x in ["Snake_random_F", "ButterFly_random", "HouseFly", "HoneyBee", "Mosquito"]) then + { + // Filtre : ignorer les segments de routes + if ({_x == _e} count (getPos _e nearRoads 1) == 0) then + { + _elements_terrain pushBack _e; + }; + }; + }; + }; + } forEach nearestObjects [_pos_centre, [], _rayon]; + + _elements_terrain - _obj_proches + _obj_proches +}; + +/** + * Retourne la bounding box d'un objet depuis son nom de classe + * @param 0 le nom de classe de l'objet + * @return la bounding box d'un objet correspondant au nom de classe + */ +R3F_LOG_FNCT_3D_get_bounding_box_depuis_classname = +{ + private ["_classe", "_objet_tmp", "_bbox"]; + + _classe = _this select 0; + + // Création du véhicule local temporaire dans le ciel pour connaître la bounding box de l'objet + _objet_tmp = _classe createVehicleLocal ([] call R3F_LOG_FNCT_3D_tirer_position_degagee_ciel); + sleep 0.01; + _bbox = boundingBoxReal _objet_tmp; + deleteVehicle _objet_tmp; + + _bbox +}; + +/** + * Calcule les hauteurs de terrain ASL minimale et maximale des quatre coins inférieurs d'un objet + * @param 0 l'objet pour lequel calculer les hauteur de terrains min et max + * @return tableau contenant respectivement las hauteurs de terrain ASL minimal et maximal + */ +R3F_LOG_FNCT_3D_get_hauteur_terrain_min_max_objet = +{ + private ["_objet", "_x1", "_x2", "_y1", "_y2", "_z", "_hauteur_min", "_hauteur_max", "_hauteur"]; + + _objet = _this select 0; + + _x1 = boundingBoxReal _objet select 0 select 0; + _x2 = boundingBoxReal _objet select 1 select 0; + _y1 = boundingBoxReal _objet select 0 select 1; + _y2 = boundingBoxReal _objet select 1 select 1; + + _z = boundingBoxReal _objet select 0 select 2; + + _hauteur_min = 1E39; + _hauteur_max = -1E39; + + // Pour chaque coin de l'objet + { + _hauteur = getTerrainHeightASL (_objet modelToWorld _x); + + if (_hauteur < _hauteur_min) then {_hauteur_min = _hauteur}; + if (_hauteur > _hauteur_max) then {_hauteur_max = _hauteur}; + } forEach [[_x1, _y1, _z], [_x1, _y2, _z], [_x2, _y1, _z], [_x2, _y2, _z]]; + + [_hauteur_min, _hauteur_max] +}; + +/** + * Multiplie deux matrices 3x3 + * @param 0 la première matrice 3x3 à multiplier + * @param 1 la deuxième matrice 3x3 à multiplier + * @return la matrice 3x3 résultant de la multiplication + */ +R3F_LOG_FNCT_3D_mult_mat3x3 = +{ + private ["_a", "_b"]; + + _a = _this select 0; + _b = _this select 1; + + [ + [ + (_a select 0 select 0) * (_b select 0 select 0) + (_a select 0 select 1) * (_b select 1 select 0) + (_a select 0 select 2) * (_b select 2 select 0), + (_a select 0 select 0) * (_b select 0 select 1) + (_a select 0 select 1) * (_b select 1 select 1) + (_a select 0 select 2) * (_b select 2 select 1), + (_a select 0 select 0) * (_b select 0 select 2) + (_a select 0 select 1) * (_b select 1 select 2) + (_a select 0 select 2) * (_b select 2 select 2) + ], + [ + (_a select 1 select 0) * (_b select 0 select 0) + (_a select 1 select 1) * (_b select 1 select 0) + (_a select 1 select 2) * (_b select 2 select 0), + (_a select 1 select 0) * (_b select 0 select 1) + (_a select 1 select 1) * (_b select 1 select 1) + (_a select 1 select 2) * (_b select 2 select 1), + (_a select 1 select 0) * (_b select 0 select 2) + (_a select 1 select 1) * (_b select 1 select 2) + (_a select 1 select 2) * (_b select 2 select 2) + ], + [ + (_a select 2 select 0) * (_b select 0 select 0) + (_a select 2 select 1) * (_b select 1 select 0) + (_a select 2 select 2) * (_b select 2 select 0), + (_a select 2 select 0) * (_b select 0 select 1) + (_a select 2 select 1) * (_b select 1 select 1) + (_a select 2 select 2) * (_b select 2 select 1), + (_a select 2 select 0) * (_b select 0 select 2) + (_a select 2 select 1) * (_b select 1 select 2) + (_a select 2 select 2) * (_b select 2 select 2) + ] + ] +}; + +/** + * Multiplie un vecteur 3D avec une matrice 3x3 + * @param 0 le vecteur 3D à multiplier + * @param 1 le matrice 3x3 avec laquelle multiplier le vecteur + * @return le vecteur 3D résultant de la multiplication + */ +R3F_LOG_FNCT_3D_mult_vec_mat3x3 = +{ + private ["_vec", "_mat"]; + + _vec = _this select 0; + _mat = _this select 1; + + [ + (_vec select 0) * (_mat select 0 select 0) + (_vec select 1) * (_mat select 1 select 0) + (_vec select 2) * (_mat select 2 select 0), + (_vec select 0) * (_mat select 0 select 1) + (_vec select 1) * (_mat select 1 select 1) + (_vec select 2) * (_mat select 2 select 1), + (_vec select 0) * (_mat select 0 select 2) + (_vec select 1) * (_mat select 1 select 2) + (_vec select 2) * (_mat select 2 select 2) + ] +}; + +/** + * Retourne la matrice 3x3 de rotation en roulis (roll) pour un angle donné + * @param l'angle de rotation en degrés + * @return la matrice 3x3 de rotation en roulis (roll) pour un angle donné + */ +R3F_LOG_FNCT_3D_mat_rot_roll = +{ + [ + [cos _this, 0, sin _this], + [0, 1, 0], + [-sin _this, 0, cos _this] + ] +}; + +/** + * Retourne la matrice 3x3 de rotation en tangage (pitch) pour un angle donné + * @param l'angle de rotation en degrés + * @return la matrice 3x3 de rotation en tangage (pitch) pour un angle donné + */ +R3F_LOG_FNCT_3D_mat_rot_pitch = +{ + [ + [1, 0, 0], + [0, cos _this, -sin _this], + [0, sin _this, cos _this] + ] +}; + +/** + * Retourne la matrice 3x3 de rotation en lacet (yaw) pour un angle donné + * @param l'angle de rotation en degrés + * @return la matrice 3x3 de rotation en lacet (yaw) pour un angle donné + */ +R3F_LOG_FNCT_3D_mat_rot_yaw = +{ + [ + [cos _this, -sin _this, 0], + [sin _this, cos _this, 0], + [0, 0, 1] + ] +}; + +/** + * Trace dans le jeu une bounding box donnée pour un objet passé en paramètre + * @param 0 l'objet pour lequel tracer la bounding box + * @param 1 position min de la bounding box de l'objet + * @param 2 position max de la bounding box de l'objet + * @note les objets peuvent être d'un type ne correspondant pas aux bounding box + * @note cela permet par exemple d'utiliser une logique de jeu, pour un calcul à priori + */ +R3F_LOG_FNCT_3D_tracer_bbox = +{ + private ["_objet", "_bbox_min", "_bbox_max", "_coins", "_couleur"]; + + _objet = _this select 0; + _bbox_min = _this select 1; + _bbox_max = _this select 2; + + if !(isNull _objet) then + { + // Composition des coordonnées des 8 coins, dans l'espace world + _coins = [_objet] call R3F_LOG_FNCT_3D_get_huit_coins_bounding_box_world; + + // Faire clignoter en rouge/vert le tracé + _couleur = if (floor (2*diag_tickTime) % 2 == 0) then {[0.95,0,0,1]} else {[0,1,0,1]}; + + // Tracer les segments de la bounding box + drawLine3D [_coins select 1, _coins select 0, _couleur]; + drawLine3D [_coins select 2, _coins select 0, _couleur]; + drawLine3D [_coins select 1, _coins select 3, _couleur]; + drawLine3D [_coins select 2, _coins select 3, _couleur]; + + drawLine3D [_coins select 5, _coins select 4, _couleur]; + drawLine3D [_coins select 6, _coins select 4, _couleur]; + drawLine3D [_coins select 5, _coins select 7, _couleur]; + drawLine3D [_coins select 6, _coins select 7, _couleur]; + + drawLine3D [_coins select 0, _coins select 4, _couleur]; + drawLine3D [_coins select 1, _coins select 5, _couleur]; + drawLine3D [_coins select 2, _coins select 6, _couleur]; + drawLine3D [_coins select 3, _coins select 7, _couleur]; + }; +}; + +/** + * Trace dans le jeu la bounding box de l'objet passé en paramètre + * @param 0 l'objet pour lequel tracer la bounding box + */ +R3F_LOG_FNCT_3D_tracer_bbox_obj = +{ + private ["_objet"]; + + _objet = _this select 0; + + if !(isNull _objet) then + { + [_objet, boundingBoxReal _objet select 0, boundingBoxReal _objet select 1] call R3F_LOG_FNCT_3D_tracer_bbox; + }; +}; + +// Quelques contrôles et visualisations in-game durant le développement +//#define R3F_LOG_3D_dev_mode // TODO commenter cette ligne lors du release +#ifdef R3F_LOG_3D_dev_mode +if (isNil "R3F_LOG_joueur_deplace_objet") then {R3F_LOG_joueur_deplace_objet = objNull}; +addMissionEventHandler ["Draw3D", +{ + if !(isNull player) then + { + private ["_objet"]; + + _objet = cursorTarget; + + if (!isNull R3F_LOG_joueur_deplace_objet) then + { + //[R3F_LOG_joueur_deplace_objet] call R3F_LOG_FNCT_3D_tracer_bbox_obj; + + { + if ([ + R3F_LOG_joueur_deplace_objet, + boundingBoxReal R3F_LOG_joueur_deplace_objet select 0, + boundingBoxReal R3F_LOG_joueur_deplace_objet select 1, + _x, + boundingBoxReal _x select 0, + boundingBoxReal _x select 1 + ] call R3F_LOG_FNCT_3D_bbox_intersect_bbox) then + { + //systemChat format ["COLLISION BBOX %1 @ %2", typeOf _x, time]; + [_x] call R3F_LOG_FNCT_3D_tracer_bbox_obj; + }; + } forEach (nearestObjects [R3F_LOG_joueur_deplace_objet, ["All"], 15] - [player, R3F_LOG_joueur_deplace_objet]); + } + else + { + if (false && !isNull _objet) then + { + hintSilent format ["%1 | %2 | %3", typeOf _objet, [_objet] call R3F_LOG_FNCT_3D_cam_intersect_bbox_obj, + [_objet worldToModel (positionCameraToWorld [0, 0, 0]), boundingBoxReal _objet select 0, boundingBoxReal _objet select 1] call R3F_LOG_FNCT_3D_pos_est_dans_bbox]; + + [_objet] call R3F_LOG_FNCT_3D_tracer_bbox_obj; + } + else + { + _cursorTarget_distance = call R3F_LOG_FNCT_3D_cursorTarget_distance_bbox; + hintSilent format ["%1 | %2", typeOf (_cursorTarget_distance select 0), _cursorTarget_distance select 1]; + + if !(isNull (_cursorTarget_distance select 0)) then + { + [_cursorTarget_distance select 0] call R3F_LOG_FNCT_3D_tracer_bbox_obj; + }; + }; + }; + + //{ + // // Calcul de la bbox élargie par rapport au gabarit max d'une unité + // _bbox_min_elargie = (boundingBoxReal _x select 0) vectorDiff [1, 1, 2]; + // _bbox_max_elargie = (boundingBoxReal _x select 1) vectorAdd [1, 1, 2]; + // + // if ([_x worldToModel (player modelToWorld [0,0,0]), _bbox_min_elargie, _bbox_max_elargie] call R3F_LOG_FNCT_3D_pos_est_dans_bbox) then + // { + // //systemChat format ["JOUEUR PROCHE %1 @ %2", typeOf _x, time]; + // }; + //} forEach (nearestObjects [player, ["All"], 15] - [player]); + + drawIcon3D ["\A3\ui_f\data\map\vehicleicons\iconManMedic_ca.paa", [1,0,0,1], positionCameraToWorld [0, 0, 1], 0.2, 0.2, 0, "", 1, 0, "TahomaB"]; + + //if !(isNil "R3F_LOG_liste_objets_en_deplacement") then + //{ + // { + // [_x] call R3F_LOG_FNCT_3D_tracer_bbox_obj; + // } forEach R3F_LOG_liste_objets_en_deplacement; + //}; + + //{ + // [_x] call R3F_LOG_FNCT_3D_tracer_bbox_obj; + //} forEach [[[R3F_LOG_joueur_deplace_objet]] call R3F_LOG_FNCT_3D_cursorTarget_virtuel]; + + //{ + // [_x] call R3F_LOG_FNCT_3D_tracer_bbox_obj; + //} forEach ([player, 100] call R3F_LOG_FNCT_3D_get_objets_genants_rayon); + }; +}]; +#endif \ No newline at end of file diff --git a/fonctions_generales/lib_visualisation_objet.sqf b/fonctions_generales/lib_visualisation_objet.sqf new file mode 100644 index 0000000..daeabb8 --- /dev/null +++ b/fonctions_generales/lib_visualisation_objet.sqf @@ -0,0 +1,108 @@ +/** + * Bibliothèque de fonctions permettant la visualisation 3D d'objets + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Démarre le mode de visualisation 3D + */ +R3F_LOG_VIS_FNCT_demarrer_visualisation = +{ + // Création d'une caméra + R3F_LOG_VIS_cam = "camera" camCreate ([[5000, 5000, 0]] call R3F_LOG_FNCT_3D_tirer_position_degagee_ciel); + R3F_LOG_VIS_cam cameraEffect ["Internal", "BACK"]; + R3F_LOG_VIS_cam camSetFocus [-1, -1]; + showCinemaBorder false; + R3F_LOG_VIS_cam camCommit 0; + camUseNVG (sunOrMoon == 0); + + R3F_LOG_VIS_objet = objNull; + + // Fil d'exécution réalisant une rotation continue de la caméra autour de l'objet à visualiser + 0 spawn + { + // Tant qu'on ne quitte pas la visualisation + while {!isNull R3F_LOG_VIS_cam} do + { + private ["_objet", "_distance_cam", "_azimut_cam"]; + + // Attente d'un objet à visualiser + waitUntil {!isNull R3F_LOG_VIS_objet}; + + _objet = R3F_LOG_VIS_objet; + + _distance_cam = 2.25 * ( + [boundingBoxReal _objet select 0 select 0, boundingBoxReal _objet select 0 select 2] + distance + [boundingBoxReal _objet select 1 select 0, boundingBoxReal _objet select 1 select 2] + ); + _azimut_cam = 0; + + R3F_LOG_VIS_cam camSetTarget _objet; + R3F_LOG_VIS_cam camSetPos (_objet modelToWorld [_distance_cam * sin _azimut_cam, _distance_cam * cos _azimut_cam, _distance_cam * 0.33]); + R3F_LOG_VIS_cam camCommit 0; + + // Rotation autour de l'objet + while {R3F_LOG_VIS_objet == _objet} do + { + _azimut_cam = _azimut_cam + 3.25; + + R3F_LOG_VIS_cam camSetPos (_objet modelToWorld [_distance_cam * sin _azimut_cam, _distance_cam * cos _azimut_cam, _distance_cam * 0.33]); + R3F_LOG_VIS_cam camCommit 0.05; + + sleep 0.05; + }; + }; + }; +}; + +/** + * Termine le mode de visualisation 3D + */ +R3F_LOG_VIS_FNCT_terminer_visualisation = +{ + if (!isNull R3F_LOG_VIS_objet) then {detach R3F_LOG_VIS_objet; deleteVehicle R3F_LOG_VIS_objet;}; + R3F_LOG_VIS_objet = objNull; + + R3F_LOG_VIS_cam cameraEffect ["Terminate", "BACK"]; + camDestroy R3F_LOG_VIS_cam; + R3F_LOG_VIS_cam = objNull; +}; + +/** + * Visualiser un type d'objet en 3D + * + * @param 0 le nom de classe de l'objet à visualiser + */ +R3F_LOG_VIS_FNCT_voir_objet = +{ + private ["_classe_a_visualiser", "_objet", "_position_attache"]; + + if (isNil "R3F_LOG_VIS_cam") then + { + call R3F_LOG_VIS_FNCT_demarrer_visualisation; + }; + + _classe_a_visualiser = _this select 0; + + // Ignorer les objets non instanciables + if (_classe_a_visualiser != "" && {isClass (configFile >> "CfgVehicles" >> _classe_a_visualiser) && {getNumber (configFile >> "CfgVehicles" >> _classe_a_visualiser >> "scope") > 0}}) then + { + // Ignorer si l'objet à visualiser est le même que précédemment + if (isNull R3F_LOG_VIS_objet || {_classe_a_visualiser != typeOf R3F_LOG_VIS_objet}) then + { + // Créer et placer l'objet dans le ciel + _position_attache = [[5000, 5000, 0]] call R3F_LOG_FNCT_3D_tirer_position_degagee_ciel; + _objet = _classe_a_visualiser createVehicleLocal _position_attache; + _objet attachTo [R3F_LOG_PUBVAR_point_attache, _position_attache]; + + if (!isNull R3F_LOG_VIS_objet) then {detach R3F_LOG_VIS_objet; deleteVehicle R3F_LOG_VIS_objet;}; + R3F_LOG_VIS_objet = _objet; + }; + }; +}; \ No newline at end of file diff --git a/fonctions_generales/unite_marche_dessus.sqf b/fonctions_generales/unite_marche_dessus.sqf new file mode 100644 index 0000000..658f543 --- /dev/null +++ b/fonctions_generales/unite_marche_dessus.sqf @@ -0,0 +1,41 @@ +/** + * Vérifie si une unité marche sur un objet ou est collée contre celui-ci + * + * @param 0 l'unité + * @param 1 l'objet pour lequel vérifier si l'unité marche dessus + * + * @return vrai si une unité marche sur un objet ou est collée contre celui-ci + * + * @note les bounding box, trop approximatives, ne sont pas utilisées + * @note le calcul se fait à l'aide de quelques dizaines de "lineIntersectsWith" + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +private ["_unite", "_objet", "_contact", "_rayon", "_angle", "_pos_debut_segment", "_pos_fin_segment"]; + +_unite = _this select 0; +_objet = _this select 1; + +_contact = false; + +// On scanne autour de l'unité avec des segments répartis sur 3 cercles +for "_rayon" from 0.3 to 0.9 step 0.3 do +{ + for "_angle" from 0 to 359 step 360 / (40 * _rayon) do + { + _pos_debut_segment = _unite modelToWorld [_rayon*sin _angle, _rayon*cos _angle, 1]; + _pos_fin_segment = [_pos_debut_segment select 0, _pos_debut_segment select 1, -1]; + + if (_objet in lineIntersectsWith [ATLtoASL _pos_debut_segment, ATLtoASL _pos_fin_segment, _unite, objNull, false]) then + { + _contact = true; + }; + }; +}; + +_contact \ No newline at end of file diff --git a/heliporteur/heliporter.sqf b/heliporteur/heliporter.sqf new file mode 100644 index 0000000..6f7f601 --- /dev/null +++ b/heliporteur/heliporter.sqf @@ -0,0 +1,219 @@ +/** + * Héliporte un objet avec un héliporteur + * + * @param 0 l'héliporteur + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +if (R3F_LOG_mutex_local_verrou) then +{ + hintC STR_R3F_LOG_mutex_action_en_cours; +} +else +{ + R3F_LOG_mutex_local_verrou = true; + + private ["_heliporteur", "_objet"]; + + _heliporteur = _this select 0; + + // Recherche de l'objet à héliporter + _objet = objNull; + { + if ( + (_x getVariable ["R3F_LOG_fonctionnalites", R3F_LOG_CST_zero_log] select R3F_LOG_IDX_can_be_lifted) && + _x != _heliporteur && !(_x getVariable "R3F_LOG_disabled") && + ((getPosASL _heliporteur select 2) - (getPosASL _x select 2) > 2 && (getPosASL _heliporteur select 2) - (getPosASL _x select 2) < 15) + ) exitWith {_objet = _x;}; + } forEach (nearestObjects [_heliporteur, ["All"], 20]); + + if (!isNull _objet) then + { + if !(_objet getVariable "R3F_LOG_disabled") then + { + if (isNull (_objet getVariable "R3F_LOG_est_transporte_par") && (isNull (_objet getVariable "R3F_LOG_est_deplace_par") || (!alive (_objet getVariable "R3F_LOG_est_deplace_par")) || (!isPlayer (_objet getVariable "R3F_LOG_est_deplace_par")))) then + { + // Finalement on autorise l'héliport d'un véhicule avec du personnel à bord + //if (count crew _objet == 0 || getNumber (configFile >> "CfgVehicles" >> (typeOf _objet) >> "isUav") == 1) then + //{ + // Ne pas héliporter quelque chose qui remorque autre chose + if (isNull (_objet getVariable ["R3F_LOG_remorque", objNull])) then + { + private ["_duree", "_ctrl_titre", "_ctrl_fond", "_ctrl_jauge", "_time_debut", "_attente_valide", "_pas_de_hook"]; + + _duree = 10; + + #define _JAUGE_Y 0.7 + #define _JAUGE_W 0.4 + #define _JAUGE_H 0.025 + + disableSerialization; + + // Création du titre du compte-à-rebours dans le display du jeu + _ctrl_titre = (findDisplay 46) ctrlCreate ["RscText", -1]; + _ctrl_titre ctrlSetPosition [0.5 - 0.5*_JAUGE_W, _JAUGE_Y - 1.5*_JAUGE_H, _JAUGE_W, 1.5*_JAUGE_H]; + _ctrl_titre ctrlSetFontHeight 1.5*_JAUGE_H; + _ctrl_titre ctrlSetText format [STR_R3F_LOG_action_heliport_attente, _duree]; + _ctrl_titre ctrlCommit 0; + + // Création de l'arrière-plan de la jauge dans le display du jeu + _ctrl_fond = (findDisplay 46) ctrlCreate ["RscText", -1]; + _ctrl_fond ctrlSetBackgroundColor [0, 0, 0, 0.4]; + _ctrl_fond ctrlSetPosition [0.5 - 0.5*_JAUGE_W, _JAUGE_Y, _JAUGE_W, _JAUGE_H]; + _ctrl_fond ctrlCommit 0; + + // Création d'une jauge à 0% dans le display du jeu + _ctrl_jauge = (findDisplay 46) ctrlCreate ["RscText", -1]; + _ctrl_jauge ctrlSetBackgroundColor [0, 0.6, 0, 1]; + _ctrl_jauge ctrlSetPosition [0.5 - 0.5*_JAUGE_W, _JAUGE_Y, 0, _JAUGE_H]; + _ctrl_jauge ctrlCommit 0; + + // La jauge passe progressivement de 0% à 100% + _ctrl_jauge ctrlSetPosition [0.5 - 0.5*_JAUGE_W, _JAUGE_Y, _JAUGE_W, _JAUGE_H]; + _ctrl_jauge ctrlCommit _duree; + + _time_debut = time; + _attente_valide = true; + + while {_attente_valide && time - _time_debut < _duree} do + { + _ctrl_titre ctrlSetText format [STR_R3F_LOG_action_heliport_attente, ceil (_duree - (time - _time_debut))]; + + // A partir des versions > 1.32, on interdit le lift si le hook de BIS est utilisé + if (productVersion select 2 > 132) then + { + // Call compile car la commande getSlingLoad n'existe pas en 1.32 + _pas_de_hook = _heliporteur call compile format ["isNull getSlingLoad _this"]; + } + else + { + _pas_de_hook = true; + }; + + // Pour valider l'héliportage, il faut rester en stationnaire au dessus de l'objet pendant le compte-à-rebours + if !( + alive player && vehicle player == _heliporteur && !(_heliporteur getVariable "R3F_LOG_disabled") && _pas_de_hook && + isNull (_heliporteur getVariable "R3F_LOG_heliporte") && (vectorMagnitude velocity _heliporteur < 6) && (_heliporteur distance _objet < 15) && + !(_objet getVariable "R3F_LOG_disabled") && isNull (_objet getVariable "R3F_LOG_est_transporte_par") && + (isNull (_objet getVariable "R3F_LOG_est_deplace_par") || (!alive (_objet getVariable "R3F_LOG_est_deplace_par")) || (!isPlayer (_objet getVariable "R3F_LOG_est_deplace_par"))) && + ((getPosASL _heliporteur select 2) - (getPosASL _objet select 2) > 2 && (getPosASL _heliporteur select 2) - (getPosASL _objet select 2) < 15) + ) then + { + _attente_valide = false; + }; + + sleep 0.1; + }; + + // On effecture l'héliportage + if (_attente_valide) then + { + ctrlDelete _ctrl_titre; + ctrlDelete _ctrl_fond; + ctrlDelete _ctrl_jauge; + + _heliporteur setVariable ["R3F_LOG_heliporte", _objet, true]; + _objet setVariable ["R3F_LOG_est_transporte_par", _heliporteur, true]; + + // Attacher sous l'héliporteur au ras du sol + _objet attachTo [_heliporteur, [ + 0, + 0, + (boundingBoxReal _heliporteur select 0 select 2) - (boundingBoxReal _objet select 0 select 2) - (getPos _heliporteur select 2) + 0.5 + ]]; + + // Ré-aligner dans le sens de la longueur si besoin + if (((boundingBoxReal _objet select 1 select 0) - (boundingBoxReal _objet select 0 select 0)) > + ((boundingBoxReal _objet select 1 select 1) - (boundingBoxReal _objet select 0 select 1))) then + { + [_objet, "setDir", 90] call R3F_LOG_FNCT_exec_commande_MP; + }; + + systemChat format [STR_R3F_LOG_action_heliporter_fait, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + + // Boucle de contrôle pendant l'héliportage + [_heliporteur, _objet] spawn + { + private ["_heliporteur", "_objet", "_a_ete_souleve"]; + + _heliporteur = _this select 0; + _objet = _this select 1; + + _a_ete_souleve = false; + + while {_heliporteur getVariable "R3F_LOG_heliporte" == _objet} do + { + // Mémoriser si l'objet a déjà été soulevé (cables tendus) + if (!_a_ete_souleve && getPos _objet select 2 > 3) then + { + _a_ete_souleve = true; + }; + + // Si l'hélico se fait détruire ou si l'objet héliporté entre en contact avec le sol, on largue l'objet + if (!alive _heliporteur || (_a_ete_souleve && getPos _objet select 2 < 0)) exitWith + { + _heliporteur setVariable ["R3F_LOG_heliporte", objNull, true]; + _objet setVariable ["R3F_LOG_est_transporte_par", objNull, true]; + + // Détacher l'objet et lui appliquer la vitesse de l'héliporteur (inertie) + [_objet, "detachSetVelocity", velocity _heliporteur] call R3F_LOG_FNCT_exec_commande_MP; + + systemChat format [STR_R3F_LOG_action_heliport_larguer_fait, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + + sleep 0.1; + }; + }; + } + else + { + systemChat STR_R3F_LOG_action_heliport_echec_attente; + + // La jauge s'arrête + _ctrl_jauge ctrlSetPosition ctrlPosition _ctrl_jauge; + + // La jauge clignote rouge + _ctrl_jauge ctrlSetBackgroundColor [1, 0, 0, 1]; + _ctrl_jauge ctrlCommit 0; sleep 0.175; + _ctrl_jauge ctrlSetBackgroundColor [1, 0, 0, 0]; + _ctrl_jauge ctrlCommit 0; sleep 0.175; + _ctrl_jauge ctrlSetBackgroundColor [1, 0, 0, 1]; + _ctrl_jauge ctrlCommit 0; sleep 0.175; + _ctrl_jauge ctrlSetBackgroundColor [1, 0, 0, 0]; + _ctrl_jauge ctrlCommit 0; sleep 0.175; + _ctrl_jauge ctrlSetBackgroundColor [1, 0, 0, 1]; + _ctrl_jauge ctrlCommit 0; sleep 0.175; + _ctrl_jauge ctrlSetBackgroundColor [1, 0, 0, 0]; + _ctrl_jauge ctrlCommit 0; sleep 0.175; + _ctrl_jauge ctrlSetBackgroundColor [1, 0, 0, 1]; + _ctrl_jauge ctrlCommit 0; sleep 0.175; + + ctrlDelete _ctrl_titre; + ctrlDelete _ctrl_fond; + ctrlDelete _ctrl_jauge; + }; + } + else + { + systemChat format [STR_R3F_LOG_objet_remorque_en_cours, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + //} + //else + //{ + // systemChat format [STR_R3F_LOG_joueur_dans_objet, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + //}; + } + else + { + systemChat format [STR_R3F_LOG_objet_en_cours_transport, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + }; + }; + + R3F_LOG_mutex_local_verrou = false; +}; \ No newline at end of file diff --git a/heliporteur/heliporteur_init.sqf b/heliporteur/heliporteur_init.sqf new file mode 100644 index 0000000..3177236 --- /dev/null +++ b/heliporteur/heliporteur_init.sqf @@ -0,0 +1,19 @@ +/** + * Initialise un véhicule héliporteur + * + * @param 0 l'héliporteur + */ + +private ["_heliporteur"]; + +_heliporteur = _this select 0; + +// Définition locale de la variable si elle n'est pas définie sur le réseau +if (isNil {_heliporteur getVariable "R3F_LOG_heliporte"}) then +{ + _heliporteur setVariable ["R3F_LOG_heliporte", objNull, false]; +}; + +_heliporteur addAction [("" + STR_R3F_LOG_action_heliporter + ""), {_this call R3F_LOG_FNCT_heliporteur_heliporter}, nil, 6, true, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_action_heliporter_valide"]; + +_heliporteur addAction [("" + STR_R3F_LOG_action_heliport_larguer + ""), {_this call R3F_LOG_FNCT_heliporteur_larguer}, nil, 6, true, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_action_heliport_larguer_valide"]; \ No newline at end of file diff --git a/heliporteur/larguer.sqf b/heliporteur/larguer.sqf new file mode 100644 index 0000000..fcd9968 --- /dev/null +++ b/heliporteur/larguer.sqf @@ -0,0 +1,35 @@ +/** + * Larguer un objet en train d'être héliporté + * + * @param 0 l'héliporteur + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +if (R3F_LOG_mutex_local_verrou) then +{ + hintC STR_R3F_LOG_mutex_action_en_cours; +} +else +{ + R3F_LOG_mutex_local_verrou = true; + + private ["_heliporteur", "_objet"]; + + _heliporteur = _this select 0; + _objet = _heliporteur getVariable "R3F_LOG_heliporte"; + + _heliporteur setVariable ["R3F_LOG_heliporte", objNull, true]; + _objet setVariable ["R3F_LOG_est_transporte_par", objNull, true]; + + // Détacher l'objet et lui appliquer la vitesse de l'héliporteur (inertie) + [_objet, "detachSetVelocity", velocity _heliporteur] call R3F_LOG_FNCT_exec_commande_MP; + + systemChat format [STR_R3F_LOG_action_heliport_larguer_fait, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + + R3F_LOG_mutex_local_verrou = false; +}; \ No newline at end of file diff --git a/init.sqf b/init.sqf new file mode 100644 index 0000000..1b958aa --- /dev/null +++ b/init.sqf @@ -0,0 +1,343 @@ +/** + * Script principal qui initialise le système de logistique + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "R3F_LOG_ENABLE.h" + +#ifdef R3F_LOG_enable + /* DEBUT import config */ + + // Initialise les listes vides avant que le config.sqf les concatène + R3F_LOG_CFG_can_tow = []; + R3F_LOG_CFG_can_be_towed = []; + R3F_LOG_CFG_can_lift = []; + R3F_LOG_CFG_can_be_lifted = []; + R3F_LOG_CFG_can_transport_cargo = []; + R3F_LOG_CFG_can_be_transported_cargo = []; + R3F_LOG_CFG_can_be_moved_by_player = []; + + // Initialise les listes vides de config_creation_factory.sqf + R3F_LOG_CFG_CF_whitelist_full_categories = []; + R3F_LOG_CFG_CF_whitelist_medium_categories = []; + R3F_LOG_CFG_CF_whitelist_light_categories = []; + R3F_LOG_CFG_CF_blacklist_categories = []; + + #include "config.sqf" + #include "config_creation_factory.sqf" + + // Chargement du fichier de langage + call compile preprocessFile format ["R3F_LOG\%1_strings_lang.sqf", R3F_LOG_CFG_language]; + + /* + * On inverse l'ordre de toutes les listes de noms de classes pour donner + * la priorité aux classes spécifiques sur les classes génériques + */ + reverse R3F_LOG_CFG_can_tow; + reverse R3F_LOG_CFG_can_be_towed; + reverse R3F_LOG_CFG_can_lift; + reverse R3F_LOG_CFG_can_be_lifted; + reverse R3F_LOG_CFG_can_transport_cargo; + reverse R3F_LOG_CFG_can_be_transported_cargo; + reverse R3F_LOG_CFG_can_be_moved_by_player; + + // On passe tous les noms de classes en minuscules + {R3F_LOG_CFG_can_tow set [_forEachIndex, toLower _x];} forEach R3F_LOG_CFG_can_tow; + {R3F_LOG_CFG_can_be_towed set [_forEachIndex, toLower _x];} forEach R3F_LOG_CFG_can_be_towed; + {R3F_LOG_CFG_can_lift set [_forEachIndex, toLower _x];} forEach R3F_LOG_CFG_can_lift; + {R3F_LOG_CFG_can_be_lifted set [_forEachIndex, toLower _x];} forEach R3F_LOG_CFG_can_be_lifted; + {R3F_LOG_CFG_can_transport_cargo select _forEachIndex set [0, toLower (_x select 0)];} forEach R3F_LOG_CFG_can_transport_cargo; + {R3F_LOG_CFG_can_be_transported_cargo select _forEachIndex set [0, toLower (_x select 0)];} forEach R3F_LOG_CFG_can_be_transported_cargo; + {R3F_LOG_CFG_can_be_moved_by_player set [_forEachIndex, toLower _x];} forEach R3F_LOG_CFG_can_be_moved_by_player; + + // On construit la liste des classes des transporteurs dans les quantités associées (pour les nearestObjects, count isKindOf, ...) + R3F_LOG_classes_transporteurs = []; + { + R3F_LOG_classes_transporteurs pushBack (_x select 0); + } forEach R3F_LOG_CFG_can_transport_cargo; + + // On construit la liste des classes des transportables dans les quantités associées (pour les nearestObjects, count isKindOf, ...) + R3F_LOG_classes_objets_transportables = []; + { + R3F_LOG_classes_objets_transportables pushBack (_x select 0); + } forEach R3F_LOG_CFG_can_be_transported_cargo; + + // Union des tableaux de types d'objets servant dans un isKindOf + R3F_LOG_objets_depl_heli_remorq_transp = []; + { + if !(_x in R3F_LOG_objets_depl_heli_remorq_transp) then + { + R3F_LOG_objets_depl_heli_remorq_transp pushBack _x; + }; + } forEach (R3F_LOG_CFG_can_be_moved_by_player + R3F_LOG_CFG_can_be_lifted + R3F_LOG_CFG_can_be_towed + R3F_LOG_classes_objets_transportables); + + // Gestion compatibilité fichier de config 3.0 => 3.1 (définition de valeurs par défaut) + if (isNil "R3F_LOG_CFG_lock_objects_mode") then {R3F_LOG_CFG_lock_objects_mode = "side";}; + if (isNil "R3F_LOG_CFG_unlock_objects_timer") then {R3F_LOG_CFG_unlock_objects_timer = 30;}; + if (isNil "R3F_LOG_CFG_CF_sell_back_bargain_rate") then {R3F_LOG_CFG_CF_sell_back_bargain_rate = 0.75;}; + if (isNil "R3F_LOG_CFG_CF_creation_cost_factor") then {R3F_LOG_CFG_CF_creation_cost_factor = [];}; + + /* FIN import config */ + + if (isServer) then + { + // On crée le point d'attache qui servira aux attachTo pour les objets à charger virtuellement dans les véhicules + R3F_LOG_PUBVAR_point_attache = "Land_HelipadEmpty_F" createVehicle [0,0,0]; + R3F_LOG_PUBVAR_point_attache setPosASL [0,0,0]; + R3F_LOG_PUBVAR_point_attache setVectorDirAndUp [[0,1,0], [0,0,1]]; + + // Partage du point d'attache avec tous les joueurs + publicVariable "R3F_LOG_PUBVAR_point_attache"; + + /** Liste des objets à ne pas perdre dans un vehicule/cargo détruit */ + R3F_LOG_liste_objets_a_proteger = []; + + /* Protège les objets présents dans R3F_LOG_liste_objets_a_proteger */ + execVM "R3F_LOG\surveiller_objets_a_proteger.sqf"; + }; + + /** + * Suite à une PVEH, exécute une commande en fonction de la localité de l'argument + * @param 0 l'argument sur lequel exécuter la commande + * @param 1 la commande à exécuter (chaîne de caractères) + * @param 2 les éventuels paramètres de la commande (optionnel) + * @note il faut passer par la fonction R3F_LOG_FNCT_exec_commande_MP + */ + R3F_LOG_FNCT_PVEH_commande_MP = + { + private ["_argument", "_commande", "_parametre"]; + _argument = _this select 1 select 0; + _commande = _this select 1 select 1; + _parametre = if (count (_this select 1) == 3) then {_this select 1 select 2} else {0}; + + // Commandes à argument global et effet local + switch (_commande) do + { + // Aucune pour l'instant + // ex : case "switchMove": {_argument switchMove _parametre;}; + }; + + // Commandes à argument local et effet global + if (local _argument) then + { + switch (_commande) do + { + case "setDir": {_argument setDir _parametre;}; + case "setVelocity": {_argument setVelocity _parametre;}; + case "detachSetVelocity": {detach _argument; _argument setVelocity _parametre;}; + }; + }; + + // Commandes à faire uniquement sur le serveur + if (isServer) then + { + if (_commande == "setOwnerTo") then + { + _argument setOwner (owner _parametre); + }; + }; + }; + "R3F_LOG_PV_commande_MP" addPublicVariableEventHandler R3F_LOG_FNCT_PVEH_commande_MP; + + /** + * Ordonne l'exécution d'une commande quelque soit la localité de l'argument ou de l'effet + * @param 0 l'argument sur lequel exécuter la commande + * @param 1 la commande à exécuter (chaîne de caractères) + * @param 2 les éventuels paramètres de la commande (optionnel) + * @usage [_objet, "setDir", 160] call R3F_LOG_FNCT_exec_commande_MP + */ + R3F_LOG_FNCT_exec_commande_MP = + { + R3F_LOG_PV_commande_MP = _this; + publicVariable "R3F_LOG_PV_commande_MP"; + ["R3F_LOG_PV_commande_MP", R3F_LOG_PV_commande_MP] spawn R3F_LOG_FNCT_PVEH_commande_MP; + }; + + /** Pseudo-mutex permettant de n'exécuter qu'un script de manipulation d'objet à la fois (true : vérouillé) */ + R3F_LOG_mutex_local_verrou = false; + + call compile preprocessFile "R3F_LOG\fonctions_generales\lib_geometrie_3D.sqf"; + + // Indices du tableau des fonctionnalités retourné par R3F_LOG_FNCT_determiner_fonctionnalites_logistique + R3F_LOG_IDX_can_be_depl_heli_remorq_transp = 0; + R3F_LOG_IDX_can_be_moved_by_player = 1; + R3F_LOG_IDX_can_lift = 2; + R3F_LOG_IDX_can_be_lifted = 3; + R3F_LOG_IDX_can_tow = 4; + R3F_LOG_IDX_can_be_towed = 5; + R3F_LOG_IDX_can_transport_cargo = 6; + R3F_LOG_IDX_can_transport_cargo_cout = 7; + R3F_LOG_IDX_can_be_transported_cargo = 8; + R3F_LOG_IDX_can_be_transported_cargo_cout = 9; + R3F_LOG_CST_zero_log = [false, false, false, false, false, false, false, 0, false, 0]; + + R3F_LOG_FNCT_determiner_fonctionnalites_logistique = compile preprocessFile "R3F_LOG\fonctions_generales\determiner_fonctionnalites_logistique.sqf"; + + R3F_LOG_FNCT_calculer_chargement_vehicule = compile preprocessFile "R3F_LOG\transporteur\calculer_chargement_vehicule.sqf"; + R3F_LOG_FNCT_transporteur_charger_auto = compile preprocessFile "R3F_LOG\transporteur\charger_auto.sqf"; + + // Un serveur dédié n'en a pas besoin + if !(isDedicated) then + { + // Le client attend que le serveur ai créé et publié la référence de l'objet servant de point d'attache + waitUntil {!isNil "R3F_LOG_PUBVAR_point_attache"}; + + /** Indique quel objet le joueur est en train de déplacer, objNull si aucun */ + R3F_LOG_joueur_deplace_objet = objNull; + + /** Objet actuellement sélectionner pour être chargé/remorqué */ + R3F_LOG_objet_selectionne = objNull; + + /** Tableau contenant toutes les usines créées */ + R3F_LOG_CF_liste_usines = []; + + call compile preprocessFile "R3F_LOG\fonctions_generales\lib_visualisation_objet.sqf"; + + R3F_LOG_FNCT_objet_relacher = compile preprocessFile "R3F_LOG\objet_deplacable\relacher.sqf"; + R3F_LOG_FNCT_objet_deplacer = compile preprocessFile "R3F_LOG\objet_deplacable\deplacer.sqf"; + + R3F_LOG_FNCT_heliporteur_heliporter = compile preprocessFile "R3F_LOG\heliporteur\heliporter.sqf"; + R3F_LOG_FNCT_heliporteur_larguer = compile preprocessFile "R3F_LOG\heliporteur\larguer.sqf"; + R3F_LOG_FNCT_heliporteur_init = compile preprocessFile "R3F_LOG\heliporteur\heliporteur_init.sqf"; + + R3F_LOG_FNCT_remorqueur_detacher = compile preprocessFile "R3F_LOG\remorqueur\detacher.sqf"; + R3F_LOG_FNCT_remorqueur_remorquer_deplace = compile preprocessFile "R3F_LOG\remorqueur\remorquer_deplace.sqf"; + R3F_LOG_FNCT_remorqueur_remorquer_direct = compile preprocessFile "R3F_LOG\remorqueur\remorquer_direct.sqf"; + R3F_LOG_FNCT_remorqueur_init = compile preprocessFile "R3F_LOG\remorqueur\remorqueur_init.sqf"; + + R3F_LOG_FNCT_transporteur_charger_deplace = compile preprocessFile "R3F_LOG\transporteur\charger_deplace.sqf"; + R3F_LOG_FNCT_transporteur_charger_selection = compile preprocessFile "R3F_LOG\transporteur\charger_selection.sqf"; + R3F_LOG_FNCT_transporteur_decharger = compile preprocessFile "R3F_LOG\transporteur\decharger.sqf"; + R3F_LOG_FNCT_transporteur_selectionner_objet = compile preprocessFile "R3F_LOG\transporteur\selectionner_objet.sqf"; + R3F_LOG_FNCT_transporteur_voir_contenu_vehicule = compile preprocessFile "R3F_LOG\transporteur\voir_contenu_vehicule.sqf"; + R3F_LOG_FNCT_transporteur_init = compile preprocessFile "R3F_LOG\transporteur\transporteur_init.sqf"; + + R3F_LOG_FNCT_usine_remplir_liste_objets = compile preprocessFile "R3F_LOG\usine_creation\remplir_liste_objets.sqf"; + R3F_LOG_FNCT_usine_creer_objet = compile preprocessFile "R3F_LOG\usine_creation\creer_objet.sqf"; + R3F_LOG_FNCT_usine_ouvrir_usine = compile preprocessFile "R3F_LOG\usine_creation\ouvrir_usine.sqf"; + R3F_LOG_FNCT_usine_init = compile preprocessFile "R3F_LOG\usine_creation\usine_init.sqf"; + R3F_LOG_FNCT_usine_revendre_deplace = compile preprocessFile "R3F_LOG\usine_creation\revendre_deplace.sqf"; + R3F_LOG_FNCT_usine_revendre_selection = compile preprocessFile "R3F_LOG\usine_creation\revendre_selection.sqf"; + R3F_LOG_FNCT_usine_revendre_direct = compile preprocessFile "R3F_LOG\usine_creation\revendre_direct.sqf"; + R3F_LOG_FNCT_recuperer_liste_cfgVehicles_par_categories = compile preprocessFile "R3F_LOG\usine_creation\recuperer_liste_cfgVehicles_par_categories.sqf"; + R3F_LOG_FNCT_determiner_cout_creation = compile preprocessFile "R3F_LOG\usine_creation\determiner_cout_creation.sqf"; + + R3F_LOG_FNCT_objet_init = compile preprocessFile "R3F_LOG\objet_commun\objet_init.sqf"; + R3F_LOG_FNCT_objet_est_verrouille = compile preprocessFile "R3F_LOG\objet_commun\objet_est_verrouille.sqf"; + R3F_LOG_FNCT_deverrouiller_objet = compile preprocessFile "R3F_LOG\objet_commun\deverrouiller_objet.sqf"; + R3F_LOG_FNCT_definir_proprietaire_verrou = compile preprocessFile "R3F_LOG\objet_commun\definir_proprietaire_verrou.sqf"; + + R3F_LOG_FNCT_formater_fonctionnalites_logistique = compile preprocessFile "R3F_LOG\fonctions_generales\formater_fonctionnalites_logistique.sqf"; + R3F_LOG_FNCT_formater_nombre_entier_milliers = compile preprocessFile "R3F_LOG\fonctions_generales\formater_nombre_entier_milliers.sqf"; + + // Liste des variables activant ou non les actions de menu + R3F_LOG_action_charger_deplace_valide = false; + R3F_LOG_action_charger_selection_valide = false; + R3F_LOG_action_contenu_vehicule_valide = false; + + R3F_LOG_action_remorquer_deplace_valide = false; + + R3F_LOG_action_heliporter_valide = false; + R3F_LOG_action_heliport_larguer_valide = false; + + R3F_LOG_action_deplacer_objet_valide = false; + R3F_LOG_action_remorquer_direct_valide = false; + R3F_LOG_action_detacher_valide = false; + R3F_LOG_action_selectionner_objet_charge_valide = false; + + R3F_LOG_action_ouvrir_usine_valide = false; + R3F_LOG_action_revendre_usine_direct_valide = false; + R3F_LOG_action_revendre_usine_deplace_valide = false; + R3F_LOG_action_revendre_usine_selection_valide = false; + + R3F_LOG_action_deverrouiller_valide = false; + + /** Sur ordre (publicVariable), révéler la présence d'un objet au joueur (accélérer le retour des addActions) */ + R3F_LOG_FNCT_PUBVAR_reveler_au_joueur = + { + private ["_objet"]; + _objet = _this select 1; + + if (alive player) then + { + player reveal _objet; + }; + }; + "R3F_LOG_PUBVAR_reveler_au_joueur" addPublicVariableEventHandler R3F_LOG_FNCT_PUBVAR_reveler_au_joueur; + + /** Event handler GetIn : ne pas monter dans un véhicule qui est en cours de transport */ + R3F_LOG_FNCT_EH_GetIn = + { + if (local (_this select 2)) then + { + _this spawn + { + sleep 0.1; + if ((!(isNull (_this select 0 getVariable "R3F_LOG_est_deplace_par")) && (alive (_this select 0 getVariable "R3F_LOG_est_deplace_par")) && (isPlayer (_this select 0 getVariable "R3F_LOG_est_deplace_par"))) || !(isNull (_this select 0 getVariable "R3F_LOG_est_transporte_par"))) then + { + (_this select 2) action ["GetOut", _this select 0]; + (_this select 2) action ["Eject", _this select 0]; + if (player == _this select 2) then {hintC format [STR_R3F_LOG_objet_en_cours_transport, getText (configFile >> "CfgVehicles" >> (typeOf (_this select 0)) >> "displayName")];}; + }; + }; + }; + }; + + // Actions à faire quand le joueur est apparu + 0 spawn + { + waitUntil {!isNull player}; + + // Ajout d'un event handler "WeaponDisassembled" pour gérer le cas où une arme est démontée alors qu'elle est en cours de transport + player addEventHandler ["WeaponDisassembled", + { + private ["_objet"]; + + // Récupération de l'arme démontée avec cursorTarget au lieu de _this (http://feedback.arma3.com/view.php?id=18090) + _objet = cursorTarget; + + if (!isNull _objet && {!isNull (_objet getVariable ["R3F_LOG_est_deplace_par", objNull])}) then + { + _objet setVariable ["R3F_LOG_est_deplace_par", objNull, true]; + }; + }]; + }; + + /** Variable publique passer à true pour informer le script surveiller_nouveaux_objets.sqf de la création d'un objet */ + R3F_LOG_PUBVAR_nouvel_objet_a_initialiser = false; + + /* Vérification permanente des conditions donnant accès aux addAction */ + execVM "R3F_LOG\surveiller_conditions_actions_menu.sqf"; + + /* Auto-détection permanente des objets sur le jeu */ + execVM "R3F_LOG\surveiller_nouveaux_objets.sqf"; + + /* + * Système assurant la protection contre les blessures lors du déplacement d'objets + * On choisit de ne pas faire tourner le système sur un serveur dédié par économie de ressources. + * Seuls les joueurs et les IA commandées par les joueurs (locales) seront protégés. + * Les IA n'étant pas commandées par un joueur ne seront pas protégées, ce qui est un moindre mal. + */ + execVM "R3F_LOG\systeme_protection_blessures.sqf"; + }; + + R3F_LOG_active = true; +#else + // Pour les actions du PC d'arti + R3F_LOG_joueur_deplace_objet = objNull; + R3F_LOG_active = false; +#endif \ No newline at end of file diff --git a/objet_commun/definir_proprietaire_verrou.sqf b/objet_commun/definir_proprietaire_verrou.sqf new file mode 100644 index 0000000..d5bcb18 --- /dev/null +++ b/objet_commun/definir_proprietaire_verrou.sqf @@ -0,0 +1,29 @@ +/** + * Défini le propriétaire (side/faction/player) du verrou d'un objet + * + * @param 0 l'objet pour lequel définir le propriétaire du verrou + * @param 1 l'unité pour laquelle définir le verrou + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +private ["_objet", "_unite"]; + +_objet = _this select 0; +_unite = _this select 1; + +// Si le verrou de l'objet ne correspond pas à l'unité, on redéfini sa valeur pour lui correspondre +if (isNil {_objet getVariable "R3F_LOG_proprietaire_verrou"} || {[_objet, _unite] call R3F_LOG_FNCT_objet_est_verrouille}) then +{ + switch (R3F_LOG_CFG_lock_objects_mode) do + { + case "side": {_objet setVariable ["R3F_LOG_proprietaire_verrou", side group _unite, true];}; + case "faction": {_objet setVariable ["R3F_LOG_proprietaire_verrou", faction _unite, true];}; + case "player": {_objet setVariable ["R3F_LOG_proprietaire_verrou", name _unite, true];}; + case "unit": {_objet setVariable ["R3F_LOG_proprietaire_verrou", _unite, true];}; + }; +}; \ No newline at end of file diff --git a/objet_commun/deverrouiller_objet.sqf b/objet_commun/deverrouiller_objet.sqf new file mode 100644 index 0000000..ed5731c --- /dev/null +++ b/objet_commun/deverrouiller_objet.sqf @@ -0,0 +1,90 @@ +/** + * Gestion du déverrouillage d'un objet et du compte-à-rebours + * + * @param 0 l'objet à déverrouiller + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +if (R3F_LOG_mutex_local_verrou) then +{ + hintC STR_R3F_LOG_mutex_action_en_cours; +} +else +{ + R3F_LOG_mutex_local_verrou = true; + + private ["_objet", "_duree", "_ctrl_titre", "_ctrl_fond", "_ctrl_jauge", "_time_debut", "_attente_valide", "_cursorTarget_distance"]; + + _objet = _this select 0; + _duree = R3F_LOG_CFG_unlock_objects_timer; + + #define _JAUGE_Y 0.7 + #define _JAUGE_W 0.4 + #define _JAUGE_H 0.025 + + disableSerialization; + + // Création du titre du compte-à-rebours dans le display du jeu + _ctrl_titre = (findDisplay 46) ctrlCreate ["RscText", -1]; + _ctrl_titre ctrlSetPosition [0.5 - 0.5*_JAUGE_W, _JAUGE_Y - 1.5*_JAUGE_H, _JAUGE_W, 1.5*_JAUGE_H]; + _ctrl_titre ctrlSetFontHeight 1.5*_JAUGE_H; + _ctrl_titre ctrlSetText format [STR_R3F_LOG_deverrouillage_en_cours, _duree]; + _ctrl_titre ctrlCommit 0; + + // Création de l'arrière-plan de la jauge dans le display du jeu + _ctrl_fond = (findDisplay 46) ctrlCreate ["RscText", -1]; + _ctrl_fond ctrlSetBackgroundColor [0, 0, 0, 0.4]; + _ctrl_fond ctrlSetPosition [0.5 - 0.5*_JAUGE_W, _JAUGE_Y, _JAUGE_W, _JAUGE_H]; + _ctrl_fond ctrlCommit 0; + + // Création d'une jauge à 0% dans le display du jeu + _ctrl_jauge = (findDisplay 46) ctrlCreate ["RscText", -1]; + _ctrl_jauge ctrlSetBackgroundColor [0, 0.6, 0, 1]; + _ctrl_jauge ctrlSetPosition [0.5 - 0.5*_JAUGE_W, _JAUGE_Y, 0, _JAUGE_H]; + _ctrl_jauge ctrlCommit 0; + + // La jauge passe progressivement de 0% à 100% + _ctrl_jauge ctrlSetPosition [0.5 - 0.5*_JAUGE_W, _JAUGE_Y, _JAUGE_W, _JAUGE_H]; + _ctrl_jauge ctrlCommit _duree; + + _time_debut = time; + _attente_valide = true; + + while {_attente_valide && time - _time_debut < _duree} do + { + _ctrl_titre ctrlSetText format [STR_R3F_LOG_deverrouillage_en_cours, ceil (_duree - (time - _time_debut))]; + + _cursorTarget_distance = call R3F_LOG_FNCT_3D_cursorTarget_distance_bbox; + + // Pour valider le déverrouillage, il faut maintenir la visée l'objet pendant le compte-à-rebours + if (!alive player || _cursorTarget_distance select 0 != _objet || _cursorTarget_distance select 1 > 5) then + { + _attente_valide = false; + }; + + sleep 0.1; + }; + + ctrlDelete _ctrl_titre; + ctrlDelete _ctrl_fond; + ctrlDelete _ctrl_jauge; + + if (_attente_valide) then + { + // Mise à jour du propriétaire du verrou + [_objet, player] call R3F_LOG_FNCT_definir_proprietaire_verrou; + + systemChat STR_R3F_LOG_deverrouillage_succes_attente; + } + else + { + hintC STR_R3F_LOG_deverrouillage_echec_attente; + }; + + R3F_LOG_mutex_local_verrou = false; +}; \ No newline at end of file diff --git a/objet_commun/objet_est_verrouille.sqf b/objet_commun/objet_est_verrouille.sqf new file mode 100644 index 0000000..29bf1bb --- /dev/null +++ b/objet_commun/objet_est_verrouille.sqf @@ -0,0 +1,30 @@ +/** + * Détermine si un objet est verrouillé ou non pour un joueur donné + * + * @param 0 l'objet pour lequel savoir s'il est verrouillé + * @param 1 l'unité pour laquelle savoir si l'objet est verrouillé + * + * @return true si l'objet est verrouillé, false sinon + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +private ["_objet", "_unite", "_objet_verrouille"]; + +_objet = _this select 0; +_unite = _this select 1; + +_objet_verrouille = switch (R3F_LOG_CFG_lock_objects_mode) do +{ + case "side": {_objet getVariable ["R3F_LOG_proprietaire_verrou", side group _unite] != side group _unite}; + case "faction": {_objet getVariable ["R3F_LOG_proprietaire_verrou", faction _unite] != faction _unite}; + case "player": {_objet getVariable ["R3F_LOG_proprietaire_verrou", name _unite] != name _unite}; + case "unit": {_objet getVariable ["R3F_LOG_proprietaire_verrou", _unite] != _unite}; + default {false}; +}; + +_objet_verrouille \ No newline at end of file diff --git a/objet_commun/objet_init.sqf b/objet_commun/objet_init.sqf new file mode 100644 index 0000000..a45fafe --- /dev/null +++ b/objet_commun/objet_init.sqf @@ -0,0 +1,119 @@ +/** + * Initialise un objet déplaçable/héliportable/remorquable/transportable + * + * @param 0 l'objet + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +private ["_objet", "_config", "_nom", "_fonctionnalites"]; + +_objet = _this select 0; + +_config = configFile >> "CfgVehicles" >> (typeOf _objet); +_nom = getText (_config >> "displayName"); + +// Définition locale de la variable si elle n'est pas définie sur le réseau +if (isNil {_objet getVariable "R3F_LOG_est_transporte_par"}) then +{ + _objet setVariable ["R3F_LOG_est_transporte_par", objNull, false]; +}; + +// Définition locale de la variable si elle n'est pas définie sur le réseau +if (isNil {_objet getVariable "R3F_LOG_est_deplace_par"}) then +{ + _objet setVariable ["R3F_LOG_est_deplace_par", objNull, false]; +}; + +// Définition locale de la variable si elle n'est pas définie sur le réseau +if (isNil {_objet getVariable "R3F_LOG_proprietaire_verrou"}) then +{ + // En mode de lock side : uniquement si l'objet appartient initialement à une side militaire + if (R3F_LOG_CFG_lock_objects_mode == "side") then + { + switch (getNumber (_config >> "side")) do + { + case 0: {_objet setVariable ["R3F_LOG_proprietaire_verrou", east, false];}; + case 1: {_objet setVariable ["R3F_LOG_proprietaire_verrou", west, false];}; + case 2: {_objet setVariable ["R3F_LOG_proprietaire_verrou", independent, false];}; + }; + } + else + { + // En mode de lock faction : uniquement si l'objet appartient initialement à une side militaire + if (R3F_LOG_CFG_lock_objects_mode == "faction") then + { + switch (getNumber (_config >> "side")) do + { + case 0; case 1; case 2: + {_objet setVariable ["R3F_LOG_proprietaire_verrou", getText (_config >> "faction"), false];}; + }; + }; + }; +}; + +// Si on peut embarquer dans l'objet +if (isNumber (_config >> "preciseGetInOut")) then +{ + // Ne pas monter dans un véhicule qui est en cours de transport + _objet addEventHandler ["GetIn", R3F_LOG_FNCT_EH_GetIn]; +}; + +// Indices du tableau des fonctionnalités retourné par R3F_LOG_FNCT_determiner_fonctionnalites_logistique +#define __can_be_depl_heli_remorq_transp 0 +#define __can_be_moved_by_player 1 +#define __can_lift 2 +#define __can_be_lifted 3 +#define __can_tow 4 +#define __can_be_towed 5 +#define __can_transport_cargo 6 +#define __can_transport_cargo_cout 7 +#define __can_be_transported_cargo 8 +#define __can_be_transported_cargo_cout 9 + +_fonctionnalites = _objet getVariable "R3F_LOG_fonctionnalites"; + +if (R3F_LOG_CFG_unlock_objects_timer != -1) then +{ + _objet addAction [("" + format [STR_R3F_LOG_action_deverrouiller, _nom] + ""), {_this call R3F_LOG_FNCT_deverrouiller_objet}, false, 11, false, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_action_deverrouiller_valide"]; +} +else +{ + _objet addAction [("" + STR_R3F_LOG_action_deverrouiller_impossible + ""), {hintC STR_R3F_LOG_action_deverrouiller_impossible;}, false, 11, false, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_action_deverrouiller_valide"]; +}; + +if (_fonctionnalites select __can_be_moved_by_player) then +{ + _objet addAction [("" + format [STR_R3F_LOG_action_deplacer_objet, _nom] + ""), {_this call R3F_LOG_FNCT_objet_deplacer}, false, 5, false, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_action_deplacer_objet_valide"]; +}; + +if (_fonctionnalites select __can_be_towed) then +{ + if (_fonctionnalites select __can_be_moved_by_player) then + { + _objet addAction [("" + STR_R3F_LOG_action_remorquer_deplace + ""), {_this call R3F_LOG_FNCT_remorqueur_remorquer_deplace}, nil, 6, true, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_joueur_deplace_objet == _target && R3F_LOG_action_remorquer_deplace_valide"]; + }; + + _objet addAction [("" + format [STR_R3F_LOG_action_remorquer_direct, _nom] + ""), {_this call R3F_LOG_FNCT_remorqueur_remorquer_direct}, nil, 5, false, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_action_remorquer_direct_valide"]; + + _objet addAction [("" + STR_R3F_LOG_action_detacher + ""), {_this call R3F_LOG_FNCT_remorqueur_detacher}, nil, 6, true, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_action_detacher_valide"]; +}; + +if (_fonctionnalites select __can_be_transported_cargo) then +{ + if (_fonctionnalites select __can_be_moved_by_player) then + { + _objet addAction [("" + STR_R3F_LOG_action_charger_deplace + ""), {_this call R3F_LOG_FNCT_transporteur_charger_deplace}, nil, 8, true, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_joueur_deplace_objet == _target && R3F_LOG_action_charger_deplace_valide"]; + }; + + _objet addAction [("" + format [STR_R3F_LOG_action_selectionner_objet_charge, _nom] + ""), {_this call R3F_LOG_FNCT_transporteur_selectionner_objet}, nil, 5, false, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_action_selectionner_objet_charge_valide"]; +}; + +if (_fonctionnalites select __can_be_moved_by_player) then +{ + _objet addAction [("" + STR_R3F_LOG_action_revendre_usine_deplace + ""), {_this call R3F_LOG_FNCT_usine_revendre_deplace}, nil, 7, false, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_action_revendre_usine_deplace_valide"]; +}; \ No newline at end of file diff --git a/objet_deplacable/deplacer.sqf b/objet_deplacable/deplacer.sqf new file mode 100644 index 0000000..362b400 --- /dev/null +++ b/objet_deplacable/deplacer.sqf @@ -0,0 +1,498 @@ +/** + * Fait déplacer un objet par le joueur. Il garde l'objet tant qu'il ne le relâche pas ou ne meurt pas. + * L'objet est relaché quand la variable R3F_LOG_joueur_deplace_objet passe à objNull ce qui terminera le script + * + * @param 0 l'objet à déplacer + * @param 3 true si l'objet est chargé dans un véhicule + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +if (R3F_LOG_mutex_local_verrou) then +{ + hintC STR_R3F_LOG_mutex_action_en_cours; +} +else +{ + R3F_LOG_mutex_local_verrou = true; + + R3F_LOG_objet_selectionne = objNull; + + private ["_objet", "_decharger", "_joueur", "_dir_joueur", "_arme_courante", "_muzzle_courant", "_mode_muzzle_courant", "_restaurer_arme"]; + private ["_vec_dir_rel", "_vec_dir_up", "_dernier_vec_dir_up", "_avant_dernier_vec_dir_up", "_normale_surface"]; + private ["_pos_rel_objet_initial", "_pos_rel_objet", "_dernier_pos_rel_objet", "_avant_dernier_pos_rel_objet"]; + private ["_elev_cam_initial", "_elev_cam", "_offset_hauteur_cam", "_offset_bounding_center", "_offset_hauteur_terrain"]; + private ["_offset_hauteur", "_dernier_offset_hauteur", "_avant_dernier_offset_hauteur"]; + private ["_hauteur_terrain_min_max_objet", "_offset_hauteur_terrain_min", "_offset_hauteur_terrain_max"]; + private ["_action_relacher", "_action_aligner_pente", "_action_aligner_sol", "_action_aligner_horizon", "_action_tourner", "_action_rapprocher"]; + private ["_idx_eh_fired", "_idx_eh_keyDown", "_idx_eh_keyUp", "_time_derniere_rotation", "_time_derniere_translation"]; + + _objet = _this select 0; + _decharger = if (count _this >= 4) then {_this select 3} else {false}; + _joueur = player; + _dir_joueur = getDir _joueur; + + if (isNull (_objet getVariable ["R3F_LOG_est_transporte_par", objNull]) && (isNull (_objet getVariable ["R3F_LOG_est_deplace_par", objNull]) || (!alive (_objet getVariable ["R3F_LOG_est_deplace_par", objNull])) || (!isPlayer (_objet getVariable ["R3F_LOG_est_deplace_par", objNull])))) then + { + if (isNull (_objet getVariable ["R3F_LOG_remorque", objNull])) then + { + if (count crew _objet == 0 || getNumber (configFile >> "CfgVehicles" >> (typeOf _objet) >> "isUav") == 1) then + { + [_objet, _joueur] call R3F_LOG_FNCT_definir_proprietaire_verrou; + + _objet setVariable ["R3F_LOG_est_deplace_par", _joueur, true]; + + _joueur forceWalk true; + + R3F_LOG_joueur_deplace_objet = _objet; + + if (_decharger) then + { + // Orienter l'objet en fonction de son profil + if (((boundingBoxReal _objet select 1 select 1) - (boundingBoxReal _objet select 0 select 1)) != 0 && // Div par 0 + { + ((boundingBoxReal _objet select 1 select 0) - (boundingBoxReal _objet select 0 select 0)) > 3.2 && + ((boundingBoxReal _objet select 1 select 0) - (boundingBoxReal _objet select 0 select 0)) / + ((boundingBoxReal _objet select 1 select 1) - (boundingBoxReal _objet select 0 select 1)) > 1.25 + } + ) then + {R3F_LOG_deplace_dir_rel_objet = 90;} else {R3F_LOG_deplace_dir_rel_objet = 0;}; + + // Calcul de la position relative, de sorte à éloigner l'objet suffisamment pour garder un bon champ de vision + _pos_rel_objet_initial = [ + (boundingCenter _objet select 0) * cos R3F_LOG_deplace_dir_rel_objet - (boundingCenter _objet select 1) * sin R3F_LOG_deplace_dir_rel_objet, + ((-(boundingBoxReal _objet select 0 select 0) * sin R3F_LOG_deplace_dir_rel_objet) max (-(boundingBoxReal _objet select 1 select 0) * sin R3F_LOG_deplace_dir_rel_objet)) + + ((-(boundingBoxReal _objet select 0 select 1) * cos R3F_LOG_deplace_dir_rel_objet) max (-(boundingBoxReal _objet select 1 select 1) * cos R3F_LOG_deplace_dir_rel_objet)) + + 2 + 0.3 * ( + ((boundingBoxReal _objet select 1 select 1)-(boundingBoxReal _objet select 0 select 1)) * abs sin R3F_LOG_deplace_dir_rel_objet + + ((boundingBoxReal _objet select 1 select 0)-(boundingBoxReal _objet select 0 select 0)) * abs cos R3F_LOG_deplace_dir_rel_objet + ), + -(boundingBoxReal _objet select 0 select 2) + ]; + + _elev_cam_initial = acos ((ATLtoASL positionCameraToWorld [0, 0, 1] select 2) - (ATLtoASL positionCameraToWorld [0, 0, 0] select 2)); + + _pos_rel_objet_initial set [2, 0.1 + (_joueur selectionPosition "head" select 2) + (_pos_rel_objet_initial select 1) * tan (89 min (-89 max (90-_elev_cam_initial)))]; + } + else + { + R3F_LOG_deplace_dir_rel_objet = (getDir _objet) - _dir_joueur; + + _pos_rel_objet_initial = _joueur worldToModel (_objet modelToWorld [0,0,0]); + + // Calcul de la position relative de l'objet, basée sur la position initiale, et sécurisée pour ne pas que l'objet rentre dans le joueur lors de la rotation + // L'ajout de ce calcul a également rendu inutile le test avec la fonction R3F_LOG_FNCT_unite_marche_dessus lors de la prise de l'objet + _pos_rel_objet_initial = [ + _pos_rel_objet_initial select 0, + (_pos_rel_objet_initial select 1) max + ( + ((-(boundingBoxReal _objet select 0 select 0) * sin R3F_LOG_deplace_dir_rel_objet) max (-(boundingBoxReal _objet select 1 select 0) * sin R3F_LOG_deplace_dir_rel_objet)) + + ((-(boundingBoxReal _objet select 0 select 1) * cos R3F_LOG_deplace_dir_rel_objet) max (-(boundingBoxReal _objet select 1 select 1) * cos R3F_LOG_deplace_dir_rel_objet)) + + 1.2 + ), + _pos_rel_objet_initial select 2 + ]; + + _elev_cam_initial = acos ((ATLtoASL positionCameraToWorld [0, 0, 1] select 2) - (ATLtoASL positionCameraToWorld [0, 0, 0] select 2)); + }; + R3F_LOG_deplace_distance_rel_objet = _pos_rel_objet_initial select 1; + + // Détermination du mode d'alignement initial en fonction du type d'objet, de ses dimensions, ... + R3F_LOG_deplace_mode_alignement = switch (true) do + { + case !(_objet isKindOf "Static"): {"sol"}; + // Objet statique allongé + case ( + ((boundingBoxReal _objet select 1 select 1) - (boundingBoxReal _objet select 0 select 1)) != 0 && // Div par 0 + { + ((boundingBoxReal _objet select 1 select 0) - (boundingBoxReal _objet select 0 select 0)) / + ((boundingBoxReal _objet select 1 select 1) - (boundingBoxReal _objet select 0 select 1)) > 1.75 + } + ): {"pente"}; + // Objet statique carré ou peu allongé + default {"horizon"}; + }; + + // On demande à ce que l'objet soit local au joueur pour réduire les latences (setDir, attachTo périodique) + if (!local _objet) then + { + private ["_time_demande_setOwner"]; + _time_demande_setOwner = time; + [_objet, "setOwnerTo", _joueur] call R3F_LOG_FNCT_exec_commande_MP; + waitUntil {local _objet || time > _time_demande_setOwner + 1.5}; + }; + + // On prévient tout le monde qu'un nouveau objet va être déplace pour ingorer les éventuelles blessures + R3F_LOG_PV_nouvel_objet_en_deplacement = _objet; + publicVariable "R3F_LOG_PV_nouvel_objet_en_deplacement"; + ["R3F_LOG_PV_nouvel_objet_en_deplacement", R3F_LOG_PV_nouvel_objet_en_deplacement] call R3F_LOG_FNCT_PVEH_nouvel_objet_en_deplacement; + + // Mémorisation de l'arme courante et de son mode de tir + _arme_courante = currentWeapon _joueur; + _muzzle_courant = currentMuzzle _joueur; + _mode_muzzle_courant = currentWeaponMode _joueur; + + // Sous l'eau on n'a pas le choix de l'arme + if (!surfaceIsWater getPos _joueur) then + { + // Prise du PA si le joueur en a un + if (handgunWeapon _joueur != "") then + { + _restaurer_arme = false; + for [{_idx_muzzle = 0}, {currentWeapon _joueur != handgunWeapon _joueur}, {_idx_muzzle = _idx_muzzle+1}] do + { + _joueur action ["SWITCHWEAPON", _joueur, _joueur, _idx_muzzle]; + }; + } + // Sinon pas d'arme dans les mains + else + { + _restaurer_arme = true; + _joueur action ["SWITCHWEAPON", _joueur, _joueur, 99999]; + }; + } else {_restaurer_arme = false;}; + + sleep 0.5; + + // Vérification qu'on ai bien obtenu la main (conflit d'accès simultanés) + if (_objet getVariable "R3F_LOG_est_deplace_par" == _joueur && isNull (_objet getVariable ["R3F_LOG_est_transporte_par", objNull])) then + { + R3F_LOG_deplace_force_setVector = false; // Mettre à true pour forcer la ré-otientation de l'objet, en forçant les filtres anti-flood + R3F_LOG_deplace_force_attachTo = false; // Mettre à true pour forcer le repositionnement de l'objet, en forçant les filtres anti-flood + + // Ajout des actions de gestion de l'orientation + _action_relacher = _joueur addAction [("" + format [STR_R3F_LOG_action_relacher_objet, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")] + ""), {_this call R3F_LOG_FNCT_objet_relacher}, nil, 10, true, true]; + _action_aligner_pente = _joueur addAction [("" + STR_R3F_LOG_action_aligner_pente + ""), {R3F_LOG_deplace_mode_alignement = "pente"; R3F_LOG_deplace_force_setVector = true;}, nil, 6, false, true, "", "R3F_LOG_deplace_mode_alignement != ""pente"""]; + _action_aligner_sol = _joueur addAction [("" + STR_R3F_LOG_action_aligner_sol + ""), {R3F_LOG_deplace_mode_alignement = "sol"; R3F_LOG_deplace_force_setVector = true;}, nil, 6, false, true, "", "R3F_LOG_deplace_mode_alignement != ""sol"""]; + _action_aligner_horizon = _joueur addAction [("" + STR_R3F_LOG_action_aligner_horizon + ""), {R3F_LOG_deplace_mode_alignement = "horizon"; R3F_LOG_deplace_force_setVector = true;}, nil, 6, false, true, "", "R3F_LOG_deplace_mode_alignement != ""horizon"""]; + _action_tourner = _joueur addAction [("" + STR_R3F_LOG_action_tourner + ""), {R3F_LOG_deplace_dir_rel_objet = R3F_LOG_deplace_dir_rel_objet + 12; R3F_LOG_deplace_force_setVector = true;}, nil, 6, false, false]; + _action_rapprocher = _joueur addAction [("" + STR_R3F_LOG_action_rapprocher + ""), {R3F_LOG_deplace_distance_rel_objet = R3F_LOG_deplace_distance_rel_objet - 0.4; R3F_LOG_deplace_force_attachTo = true;}, nil, 6, false, false]; + + // Relâcher l'objet dès que le joueur tire. Le detach sert à rendre l'objet solide pour ne pas tirer au travers. + _idx_eh_fired = _joueur addEventHandler ["Fired", {if (!surfaceIsWater getPos player) then {detach R3F_LOG_joueur_deplace_objet; R3F_LOG_joueur_deplace_objet = objNull;};}]; + + // Gestion des évènements KeyDown et KeyUp pour faire tourner l'objet avec les touches X/C + R3F_LOG_joueur_deplace_key_rotation = ""; + R3F_LOG_joueur_deplace_key_translation = ""; + _time_derniere_rotation = 0; + _time_derniere_translation = 0; + _idx_eh_keyDown = (findDisplay 46) displayAddEventHandler ["KeyDown", + { + switch (_this select 1) do + { + case 45: {R3F_LOG_joueur_deplace_key_rotation = "X"; true}; + case 46: {R3F_LOG_joueur_deplace_key_rotation = "C"; true}; + case 33: {R3F_LOG_joueur_deplace_key_translation = "F"; true}; + case 19: {R3F_LOG_joueur_deplace_key_translation = "R"; true}; + default {false}; + } + }]; + _idx_eh_keyUp = (findDisplay 46) displayAddEventHandler ["KeyUp", + { + switch (_this select 1) do + { + case 45: {R3F_LOG_joueur_deplace_key_rotation = ""; true}; + case 46: {R3F_LOG_joueur_deplace_key_rotation = ""; true}; + case 33: {R3F_LOG_joueur_deplace_key_translation = ""; true}; + case 19: {R3F_LOG_joueur_deplace_key_translation = ""; true}; + default {false}; + } + }]; + + // Initialisation de l'historique anti-flood + _offset_hauteur = _pos_rel_objet_initial select 2; + _dernier_offset_hauteur = _offset_hauteur + 100; + _avant_dernier_offset_hauteur = _dernier_offset_hauteur + 100; + _dernier_pos_rel_objet = _pos_rel_objet_initial; + _avant_dernier_pos_rel_objet = _dernier_pos_rel_objet; + _vec_dir_rel = [sin R3F_LOG_deplace_dir_rel_objet, cos R3F_LOG_deplace_dir_rel_objet, 0]; + _vec_dir_up = [_vec_dir_rel, [0, 0, 1]]; + _dernier_vec_dir_up = [[0,0,0] vectorDiff (_vec_dir_up select 0), _vec_dir_up select 1]; + _avant_dernier_vec_dir_up = [_dernier_vec_dir_up select 0, [0,0,0] vectorDiff (_dernier_vec_dir_up select 1)]; + + _objet attachTo [_joueur, _pos_rel_objet_initial]; + + // Si échec transfert local, mode dégradé : on conserve la direction de l'objet par rapport au joueur + if (!local _objet) then {[_objet, "setDir", R3F_LOG_deplace_dir_rel_objet] call R3F_LOG_FNCT_exec_commande_MP;}; + + R3F_LOG_mutex_local_verrou = false; + + // Boucle de gestion des évènements et du positionnement pendant le déplacement + while {!isNull R3F_LOG_joueur_deplace_objet && _objet getVariable "R3F_LOG_est_deplace_par" == _joueur && alive _joueur} do + { + // Gestion de l'orientation de l'objet en fonction du terrain + if (local _objet) then + { + // En fonction de la touche appuyée (X/C), on fait pivoter l'objet + if (R3F_LOG_joueur_deplace_key_rotation == "X" || R3F_LOG_joueur_deplace_key_rotation == "C") then + { + // Un cycle sur deux maxi (flood) on modifie de l'angle + if (time - _time_derniere_rotation > 0.045) then + { + if (R3F_LOG_joueur_deplace_key_rotation == "X") then {R3F_LOG_deplace_dir_rel_objet = R3F_LOG_deplace_dir_rel_objet + 4;}; + if (R3F_LOG_joueur_deplace_key_rotation == "C") then {R3F_LOG_deplace_dir_rel_objet = R3F_LOG_deplace_dir_rel_objet - 4;}; + + R3F_LOG_deplace_force_setVector = true; + _time_derniere_rotation = time; + }; + } else {_time_derniere_rotation = 0;}; + + _vec_dir_rel = [sin R3F_LOG_deplace_dir_rel_objet, cos R3F_LOG_deplace_dir_rel_objet, 0]; + + // Conversion de la normale du sol dans le repère du joueur car l'objet est attachTo + _normale_surface = surfaceNormal getPos _objet; + _normale_surface = (player worldToModel ASLtoATL (_normale_surface vectorAdd getPosASL player)) vectorDiff (player worldToModel ASLtoATL (getPosASL player)); + + // Redéfinir l'orientation en fonction du terrain et du mode d'alignement + _vec_dir_up = switch (R3F_LOG_deplace_mode_alignement) do + { + case "sol": {[[-cos R3F_LOG_deplace_dir_rel_objet, sin R3F_LOG_deplace_dir_rel_objet, 0] vectorCrossProduct _normale_surface, _normale_surface]}; + case "pente": {[_vec_dir_rel, _normale_surface]}; + default {[_vec_dir_rel, [0, 0, 1]]}; + }; + + // On ré-oriente l'objet, lorsque nécessaire (pas de flood) + if (R3F_LOG_deplace_force_setVector || + ( + // Vecteur dir suffisamment différent du dernier + (_vec_dir_up select 0) vectorCos (_dernier_vec_dir_up select 0) < 0.999 && + // et différent de l'avant dernier (pas d'oscillations sans fin) + vectorMagnitude ((_vec_dir_up select 0) vectorDiff (_avant_dernier_vec_dir_up select 0)) > 1E-9 + ) || + ( + // Vecteur up suffisamment différent du dernier + (_vec_dir_up select 1) vectorCos (_dernier_vec_dir_up select 1) < 0.999 && + // et différent de l'avant dernier (pas d'oscillations sans fin) + vectorMagnitude ((_vec_dir_up select 1) vectorDiff (_avant_dernier_vec_dir_up select 1)) > 1E-9 + ) + ) then + { + _objet setVectorDirAndUp _vec_dir_up; + + _avant_dernier_vec_dir_up = _dernier_vec_dir_up; + _dernier_vec_dir_up = _vec_dir_up; + + R3F_LOG_deplace_force_setVector = false; + }; + }; + + sleep 0.015; + + // En fonction de la touche appuyée (F/R), on fait avancer ou reculer l'objet + if (R3F_LOG_joueur_deplace_key_translation == "F" || R3F_LOG_joueur_deplace_key_translation == "R") then + { + // Un cycle sur deux maxi (flood) on modifie de l'angle + if (time - _time_derniere_translation > 0.045) then + { + if (R3F_LOG_joueur_deplace_key_translation == "F") then + { + R3F_LOG_deplace_distance_rel_objet = R3F_LOG_deplace_distance_rel_objet - 0.075; + } + else + { + R3F_LOG_deplace_distance_rel_objet = R3F_LOG_deplace_distance_rel_objet + 0.075; + }; + + // Borne min-max de la distance + R3F_LOG_deplace_distance_rel_objet = R3F_LOG_deplace_distance_rel_objet min ( + ( + vectorMagnitude [ + (-(boundingBoxReal _objet select 0 select 0)) max (boundingBoxReal _objet select 1 select 0), + (-(boundingBoxReal _objet select 0 select 1)) max (boundingBoxReal _objet select 1 select 1), + 0 + ] + 2 + ) max (_pos_rel_objet_initial select 1) + ) max ( + ( + ((-(boundingBoxReal _objet select 0 select 0) * sin R3F_LOG_deplace_dir_rel_objet) max (-(boundingBoxReal _objet select 1 select 0) * sin R3F_LOG_deplace_dir_rel_objet)) + + ((-(boundingBoxReal _objet select 0 select 1) * cos R3F_LOG_deplace_dir_rel_objet) max (-(boundingBoxReal _objet select 1 select 1) * cos R3F_LOG_deplace_dir_rel_objet)) + + 1.2 + ) + ); + + R3F_LOG_deplace_force_attachTo = true; + _time_derniere_translation = time; + }; + } else {_time_derniere_translation = 0;}; + + // Calcul de la position relative de l'objet, basée sur la position initiale, et sécurisée pour ne pas que l'objet rentre dans le joueur lors de la rotation + // L'ajout de ce calcul a également rendu inutile le test avec la fonction R3F_LOG_FNCT_unite_marche_dessus lors de la prise de l'objet + _pos_rel_objet = [ + _pos_rel_objet_initial select 0, + R3F_LOG_deplace_distance_rel_objet max + ( + ((-(boundingBoxReal _objet select 0 select 0) * sin R3F_LOG_deplace_dir_rel_objet) max (-(boundingBoxReal _objet select 1 select 0) * sin R3F_LOG_deplace_dir_rel_objet)) + + ((-(boundingBoxReal _objet select 0 select 1) * cos R3F_LOG_deplace_dir_rel_objet) max (-(boundingBoxReal _objet select 1 select 1) * cos R3F_LOG_deplace_dir_rel_objet)) + + 1.2 + ), + _pos_rel_objet_initial select 2 + ]; + + _elev_cam = acos ((ATLtoASL positionCameraToWorld [0, 0, 1] select 2) - (ATLtoASL positionCameraToWorld [0, 0, 0] select 2)); + _offset_hauteur_cam = (vectorMagnitude [_pos_rel_objet select 0, _pos_rel_objet select 1, 0]) * tan (89 min (-89 max (_elev_cam_initial - _elev_cam))); + _offset_bounding_center = ((_objet modelToWorld boundingCenter _objet) select 2) - ((_objet modelToWorld [0,0,0]) select 2); + + // Calcul de la hauteur de l'objet en fonction de l'élévation de la caméra et du terrain + if (_objet isKindOf "Static") then + { + // En mode horizontal, la plage d'offset terrain est calculée de sorte à conserver au moins un des quatre coins inférieurs en contact avec le sol + if (R3F_LOG_deplace_mode_alignement == "horizon") then + { + _hauteur_terrain_min_max_objet = [_objet] call R3F_LOG_FNCT_3D_get_hauteur_terrain_min_max_objet; + _offset_hauteur_terrain_min = (_hauteur_terrain_min_max_objet select 0) - (getPosASL _joueur select 2) + _offset_bounding_center; + _offset_hauteur_terrain_max = (_hauteur_terrain_min_max_objet select 1) - (getPosASL _joueur select 2) + _offset_bounding_center; + + // On autorise un léger enterrement jusqu'à 40% de la hauteur de l'objet + _offset_hauteur_terrain_min = _offset_hauteur_terrain_min min (_offset_hauteur_terrain_max - 0.4 * ((boundingBoxReal _objet select 1 select 2) - (boundingBoxReal _objet select 0 select 2)) / (_dernier_vec_dir_up select 1 select 2)); + } + // Dans les autres modes d'alignement, on autorise un léger enterrement jusqu'à 40% de la hauteur de l'objet + else + { + _offset_hauteur_terrain_max = getTerrainHeightASL (getPos _objet) - (getPosASL _joueur select 2) + _offset_bounding_center; + _offset_hauteur_terrain_min = _offset_hauteur_terrain_max - 0.4 * ((boundingBoxReal _objet select 1 select 2) - (boundingBoxReal _objet select 0 select 2)) / (_dernier_vec_dir_up select 1 select 2); + }; + + if (R3F_LOG_CFG_no_gravity_objects_can_be_set_in_height_over_ground) then + { + _offset_hauteur = _offset_hauteur_terrain_min max ((-1.4 + _offset_bounding_center) max ((2.75 + _offset_bounding_center) min ((_pos_rel_objet select 2) + _offset_hauteur_cam))); + } + else + { + _offset_hauteur = _offset_hauteur_terrain_min max (_offset_hauteur_terrain_max min ((_pos_rel_objet select 2) + _offset_hauteur_cam)) + (getPosATL _joueur select 2); + }; + } + else + { + _offset_hauteur_terrain = getTerrainHeightASL (getPos _objet) - (getPosASL _joueur select 2) + _offset_bounding_center; + _offset_hauteur = _offset_hauteur_terrain max ((-1.4 + _offset_bounding_center) max ((2.75 + _offset_bounding_center) min ((_pos_rel_objet select 2) + _offset_hauteur_cam))); + }; + + // On repositionne l'objet par rapport au joueur, lorsque nécessaire (pas de flood) + if (R3F_LOG_deplace_force_attachTo || + ( + // Positionnement en hauteur suffisamment différent + abs (_offset_hauteur - _dernier_offset_hauteur) > 0.025 && + // et différent de l'avant dernier (pas d'oscillations sans fin) + abs (_offset_hauteur - _avant_dernier_offset_hauteur) > 1E-9 + ) || + ( + // Position relative suffisamment différente + vectorMagnitude (_pos_rel_objet vectorDiff _dernier_pos_rel_objet) > 0.025 && + // et différente de l'avant dernier (pas d'oscillations sans fin) + vectorMagnitude (_pos_rel_objet vectorDiff _avant_dernier_pos_rel_objet) > 1E-9 + ) + ) then + { + _objet attachTo [_joueur, [ + _pos_rel_objet select 0, + _pos_rel_objet select 1, + _offset_hauteur + ]]; + + _avant_dernier_offset_hauteur = _dernier_offset_hauteur; + _dernier_offset_hauteur = _offset_hauteur; + + _avant_dernier_pos_rel_objet = _dernier_pos_rel_objet; + _dernier_pos_rel_objet = _pos_rel_objet; + + R3F_LOG_deplace_force_attachTo = false; + }; + + // On interdit de monter dans un véhicule tant que l'objet est porté + if (vehicle _joueur != _joueur) then + { + systemChat STR_R3F_LOG_ne_pas_monter_dans_vehicule; + _joueur action ["GetOut", vehicle _joueur]; + _joueur action ["Eject", vehicle _joueur]; + sleep 1; + }; + + // Le joueur change d'arme, on stoppe le déplacement et on ne reprendra pas l'arme initiale + if (currentWeapon _joueur != "" && currentWeapon _joueur != handgunWeapon _joueur && !surfaceIsWater getPos _joueur) then + { + R3F_LOG_joueur_deplace_objet = objNull; + _restaurer_arme = false; + }; + + sleep 0.015; + }; + + // Si l'objet est relaché (et donc pas chargé dans un véhicule) + if (isNull (_objet getVariable ["R3F_LOG_est_transporte_par", objNull])) then + { + // L'objet n'est plus porté, on le repose. Le léger setVelocity vers le haut sert à defreezer les objets qui pourraient flotter. + // TODO gestion collision, en particulier si le joueur meurt + [_objet, "detachSetVelocity", [0, 0, 0.1]] call R3F_LOG_FNCT_exec_commande_MP; + }; + + _joueur removeEventHandler ["Fired", _idx_eh_fired]; + (findDisplay 46) displayRemoveEventHandler ["KeyDown", _idx_eh_keyDown]; + (findDisplay 46) displayRemoveEventHandler ["KeyUp", _idx_eh_keyUp]; + + _joueur removeAction _action_relacher; + _joueur removeAction _action_aligner_pente; + _joueur removeAction _action_aligner_sol; + _joueur removeAction _action_aligner_horizon; + _joueur removeAction _action_tourner; + _joueur removeAction _action_rapprocher; + + _objet setVariable ["R3F_LOG_est_deplace_par", objNull, true]; + } + // Echec d'obtention de l'objet + else + { + _objet setVariable ["R3F_LOG_est_deplace_par", objNull, true]; + R3F_LOG_mutex_local_verrou = false; + }; + + _joueur forceWalk false; + R3F_LOG_joueur_deplace_objet = objNull; + + // Reprise de l'arme et restauration de son mode de tir, si nécessaire + if (alive _joueur && !surfaceIsWater getPos _joueur && _restaurer_arme) then + { + for [{_idx_muzzle = 0}, + {currentWeapon _joueur != _arme_courante || + currentMuzzle _joueur != _muzzle_courant || + currentWeaponMode _joueur != _mode_muzzle_courant}, + {_idx_muzzle = _idx_muzzle+1}] do + { + _joueur action ["SWITCHWEAPON", _joueur, _joueur, _idx_muzzle]; + }; + }; + + sleep 5; // Délai de 5 secondes pour attendre la chute/stabilisation + if (!isNull _objet) then + { + if (isNull (_objet getVariable ["R3F_LOG_est_deplace_par", objNull]) || + {(!alive (_objet getVariable "R3F_LOG_est_deplace_par")) || (!isPlayer (_objet getVariable "R3F_LOG_est_deplace_par"))} + ) then + { + R3F_LOG_PV_fin_deplacement_objet = _objet; + publicVariable "R3F_LOG_PV_fin_deplacement_objet"; + ["R3F_LOG_PV_fin_deplacement_objet", R3F_LOG_PV_fin_deplacement_objet] call R3F_LOG_FNCT_PVEH_fin_deplacement_objet; + }; + }; + } + else + { + hintC format [STR_R3F_LOG_joueur_dans_objet, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + R3F_LOG_mutex_local_verrou = false; + }; + } + else + { + hintC format [STR_R3F_LOG_objet_remorque_en_cours, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + R3F_LOG_mutex_local_verrou = false; + }; + } + else + { + hintC format [STR_R3F_LOG_objet_en_cours_transport, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + R3F_LOG_mutex_local_verrou = false; + }; +}; \ No newline at end of file diff --git a/objet_deplacable/relacher.sqf b/objet_deplacable/relacher.sqf new file mode 100644 index 0000000..27b3337 --- /dev/null +++ b/objet_deplacable/relacher.sqf @@ -0,0 +1,17 @@ +/** + * Passe la variable R3F_LOG_joueur_deplace_objet à objNull pour informer le script "deplacer" d'arrêter de déplacer l'objet + */ + +if (R3F_LOG_mutex_local_verrou) then +{ + hintC STR_R3F_LOG_mutex_action_en_cours; +} +else +{ + R3F_LOG_mutex_local_verrou = true; + + R3F_LOG_joueur_deplace_objet = objNull; + sleep 0.25; + + R3F_LOG_mutex_local_verrou = false; +}; \ No newline at end of file diff --git a/remorqueur/detacher.sqf b/remorqueur/detacher.sqf new file mode 100644 index 0000000..bf763ea --- /dev/null +++ b/remorqueur/detacher.sqf @@ -0,0 +1,72 @@ +/** + * Détacher un objet d'un véhicule + * + * @param 0 l'objet à détacher + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +if (R3F_LOG_mutex_local_verrou) then +{ + hintC STR_R3F_LOG_mutex_action_en_cours; +} +else +{ + R3F_LOG_mutex_local_verrou = true; + + private ["_remorqueur", "_objet"]; + + _objet = _this select 0; + _remorqueur = _objet getVariable "R3F_LOG_est_transporte_par"; + + // Ne pas permettre de décrocher un objet s'il est en fait héliporté + if (_remorqueur getVariable "R3F_LOG_fonctionnalites" select R3F_LOG_IDX_can_tow) then + { + [_objet, player] call R3F_LOG_FNCT_definir_proprietaire_verrou; + + _remorqueur setVariable ["R3F_LOG_remorque", objNull, true]; + _objet setVariable ["R3F_LOG_est_transporte_par", objNull, true]; + + // Le léger setVelocity vers le haut sert à defreezer les objets qui pourraient flotter. + [_objet, "detachSetVelocity", [0, 0, 0.1]] call R3F_LOG_FNCT_exec_commande_MP; + + player playMove format ["AinvPknlMstpSlay%1Dnon_medic", switch (currentWeapon player) do + { + case "": {"Wnon"}; + case primaryWeapon player: {"Wrfl"}; + case secondaryWeapon player: {"Wlnr"}; + case handgunWeapon player: {"Wpst"}; + default {"Wrfl"}; + }]; + sleep 7; + + if (alive player) then + { + if (_objet getVariable "R3F_LOG_fonctionnalites" select R3F_LOG_IDX_can_be_moved_by_player) then + { + // Si personne n'a touché à l'objet pendant le sleep 7 + if (isNull (_remorqueur getVariable "R3F_LOG_remorque") && + (isNull (_objet getVariable "R3F_LOG_est_transporte_par")) && + (isNull (_objet getVariable "R3F_LOG_est_deplace_par")) + ) then + { + [_objet, player, 0, true] spawn R3F_LOG_FNCT_objet_deplacer; + }; + } + else + { + systemChat STR_R3F_LOG_action_detacher_fait; + }; + }; + } + else + { + hintC STR_R3F_LOG_action_detacher_impossible_pour_ce_vehicule; + }; + + R3F_LOG_mutex_local_verrou = false; +}; \ No newline at end of file diff --git a/remorqueur/remorquer_deplace.sqf b/remorqueur/remorquer_deplace.sqf new file mode 100644 index 0000000..85f8b75 --- /dev/null +++ b/remorqueur/remorquer_deplace.sqf @@ -0,0 +1,102 @@ +/** + * Remorque l'objet déplacé par le joueur avec un remorqueur + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +if (R3F_LOG_mutex_local_verrou) then +{ + hintC STR_R3F_LOG_mutex_action_en_cours; +} +else +{ + R3F_LOG_mutex_local_verrou = true; + + private ["_objet", "_remorqueur", "_offset_attach_y"]; + + _objet = R3F_LOG_joueur_deplace_objet; + _remorqueur = [_objet, 5] call R3F_LOG_FNCT_3D_cursorTarget_virtuel; + + if (!isNull _remorqueur && { + _remorqueur getVariable ["R3F_LOG_fonctionnalites", R3F_LOG_CST_zero_log] select R3F_LOG_IDX_can_tow && + alive _remorqueur && isNull (_remorqueur getVariable "R3F_LOG_remorque") && (vectorMagnitude velocity _remorqueur < 6) && !(_remorqueur getVariable "R3F_LOG_disabled") + }) then + { + [_remorqueur, player] call R3F_LOG_FNCT_definir_proprietaire_verrou; + + _remorqueur setVariable ["R3F_LOG_remorque", _objet, true]; + _objet setVariable ["R3F_LOG_est_transporte_par", _remorqueur, true]; + + // On place le joueur sur le côté du véhicule en fonction qu'il se trouve à sa gauche ou droite + if ((_remorqueur worldToModel (player modelToWorld [0,0,0])) select 0 > 0) then + { + player attachTo [_remorqueur, [ + (boundingBoxReal _remorqueur select 1 select 0) + 0.5, + (boundingBoxReal _remorqueur select 0 select 1), + (boundingBoxReal _remorqueur select 0 select 2) - (boundingBoxReal player select 0 select 2) + ]]; + + player setDir 270; + } + else + { + player attachTo [_remorqueur, [ + (boundingBoxReal _remorqueur select 0 select 0) - 0.5, + (boundingBoxReal _remorqueur select 0 select 1), + (boundingBoxReal _remorqueur select 0 select 2) - (boundingBoxReal player select 0 select 2) + ]]; + + player setDir 90; + }; + + // Faire relacher l'objet au joueur + R3F_LOG_joueur_deplace_objet = objNull; + + player playMove format ["AinvPknlMstpSlay%1Dnon_medic", switch (currentWeapon player) do + { + case "": {"Wnon"}; + case primaryWeapon player: {"Wrfl"}; + case secondaryWeapon player: {"Wlnr"}; + case handgunWeapon player: {"Wpst"}; + default {"Wrfl"}; + }]; + sleep 2; + + // Quelques corrections visuelles pour des classes spécifiques + if (typeOf _remorqueur == "B_Truck_01_mover_F") then {_offset_attach_y = 1.0;} + else {_offset_attach_y = 0.2;}; + + // Attacher à l'arrière du véhicule au ras du sol + _objet attachTo [_remorqueur, [ + (boundingCenter _objet select 0), + (boundingBoxReal _remorqueur select 0 select 1) + (boundingBoxReal _objet select 0 select 1) + _offset_attach_y, + (boundingBoxReal _remorqueur select 0 select 2) - (boundingBoxReal _objet select 0 select 2) + ]]; + + detach player; + + // Si l'objet est une arme statique, on corrige l'orientation en fonction de la direction du canon + if (_objet isKindOf "StaticWeapon") then + { + private ["_azimut_canon"]; + + _azimut_canon = ((_objet weaponDirection (weapons _objet select 0)) select 0) atan2 ((_objet weaponDirection (weapons _objet select 0)) select 1); + + // Seul le D30 a le canon pointant vers le véhicule + if !(_objet isKindOf "D30_Base") then // All in Arma + { + _azimut_canon = _azimut_canon + 180; + }; + + [_objet, "setDir", (getDir _objet)-_azimut_canon] call R3F_LOG_FNCT_exec_commande_MP; + }; + + sleep 7; + }; + + R3F_LOG_mutex_local_verrou = false; +}; \ No newline at end of file diff --git a/remorqueur/remorquer_direct.sqf b/remorqueur/remorquer_direct.sqf new file mode 100644 index 0000000..80f934c --- /dev/null +++ b/remorqueur/remorquer_direct.sqf @@ -0,0 +1,140 @@ +/** + * Remorque l'objet pointé au véhicule remorqueur valide le plus proche + * + * @param 0 l'objet à remorquer + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +if (R3F_LOG_mutex_local_verrou) then +{ + hintC STR_R3F_LOG_mutex_action_en_cours; +} +else +{ + R3F_LOG_mutex_local_verrou = true; + + private ["_objet", "_remorqueur", "_offset_attach_y"]; + + _objet = _this select 0; + + // Recherche du remorqueur valide le plus proche + _remorqueur = objNull; + { + if ( + _x != _objet && (_x getVariable ["R3F_LOG_fonctionnalites", R3F_LOG_CST_zero_log] select R3F_LOG_IDX_can_tow) && + alive _x && isNull (_x getVariable "R3F_LOG_est_transporte_par") && + isNull (_x getVariable "R3F_LOG_remorque") && (vectorMagnitude velocity _x < 6) && + !([_x, player] call R3F_LOG_FNCT_objet_est_verrouille) && !(_x getVariable "R3F_LOG_disabled") && + { + private ["_delta_pos"]; + + _delta_pos = + ( + _objet modelToWorld + [ + boundingCenter _objet select 0, + boundingBoxReal _objet select 1 select 1, + boundingBoxReal _objet select 0 select 2 + ] + ) vectorDiff ( + _x modelToWorld + [ + boundingCenter _x select 0, + boundingBoxReal _x select 0 select 1, + boundingBoxReal _x select 0 select 2 + ] + ); + + // L'arrière du remorqueur est proche de l'avant de l'objet pointé + abs (_delta_pos select 0) < 3 && abs (_delta_pos select 1) < 5 + } + ) exitWith {_remorqueur = _x;}; + } forEach (nearestObjects [_objet, ["All"], 30]); + + if (!isNull _remorqueur) then + { + if (isNull (_objet getVariable "R3F_LOG_est_transporte_par") && (isNull (_objet getVariable "R3F_LOG_est_deplace_par") || (!alive (_objet getVariable "R3F_LOG_est_deplace_par")) || (!isPlayer (_objet getVariable "R3F_LOG_est_deplace_par")))) then + { + [_remorqueur, player] call R3F_LOG_FNCT_definir_proprietaire_verrou; + + _remorqueur setVariable ["R3F_LOG_remorque", _objet, true]; + _objet setVariable ["R3F_LOG_est_transporte_par", _remorqueur, true]; + + // On place le joueur sur le côté du véhicule en fonction qu'il se trouve à sa gauche ou droite + if ((_remorqueur worldToModel (player modelToWorld [0,0,0])) select 0 > 0) then + { + player attachTo [_remorqueur, [ + (boundingBoxReal _remorqueur select 1 select 0) + 0.5, + (boundingBoxReal _remorqueur select 0 select 1), + (boundingBoxReal _remorqueur select 0 select 2) - (boundingBoxReal player select 0 select 2) + ]]; + + player setDir 270; + } + else + { + player attachTo [_remorqueur, [ + (boundingBoxReal _remorqueur select 0 select 0) - 0.5, + (boundingBoxReal _remorqueur select 0 select 1), + (boundingBoxReal _remorqueur select 0 select 2) - (boundingBoxReal player select 0 select 2) + ]]; + + player setDir 90; + }; + + player playMove format ["AinvPknlMstpSlay%1Dnon_medic", switch (currentWeapon player) do + { + case "": {"Wnon"}; + case primaryWeapon player: {"Wrfl"}; + case secondaryWeapon player: {"Wlnr"}; + case handgunWeapon player: {"Wpst"}; + default {"Wrfl"}; + }]; + sleep 2; + + // Quelques corrections visuelles pour des classes spécifiques + if (typeOf _remorqueur == "B_Truck_01_mover_F") then {_offset_attach_y = 1.0;} + else {_offset_attach_y = 0.2;}; + + // Attacher à l'arrière du véhicule au ras du sol + _objet attachTo [_remorqueur, [ + (boundingCenter _objet select 0), + (boundingBoxReal _remorqueur select 0 select 1) + (boundingBoxReal _objet select 0 select 1) + _offset_attach_y, + (boundingBoxReal _remorqueur select 0 select 2) - (boundingBoxReal _objet select 0 select 2) + ]]; + + R3F_LOG_objet_selectionne = objNull; + + detach player; + + // Si l'objet est une arme statique, on corrige l'orientation en fonction de la direction du canon + if (_objet isKindOf "StaticWeapon") then + { + private ["_azimut_canon"]; + + _azimut_canon = ((_objet weaponDirection (weapons _objet select 0)) select 0) atan2 ((_objet weaponDirection (weapons _objet select 0)) select 1); + + // Seul le D30 a le canon pointant vers le véhicule + if !(_objet isKindOf "D30_Base") then // All in Arma + { + _azimut_canon = _azimut_canon + 180; + }; + + [_objet, "setDir", (getDir _objet)-_azimut_canon] call R3F_LOG_FNCT_exec_commande_MP; + }; + + sleep 7; + } + else + { + hintC format [STR_R3F_LOG_objet_en_cours_transport, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + }; + + R3F_LOG_mutex_local_verrou = false; +}; \ No newline at end of file diff --git a/remorqueur/remorqueur_init.sqf b/remorqueur/remorqueur_init.sqf new file mode 100644 index 0000000..377c350 --- /dev/null +++ b/remorqueur/remorqueur_init.sqf @@ -0,0 +1,17 @@ +/** + * Initialise un véhicule remorqueur + * + * @param 0 le remorqueur + */ + +private ["_remorqueur"]; + +_remorqueur = _this select 0; + +// Définition locale de la variable si elle n'est pas définie sur le réseau +if (isNil {_remorqueur getVariable "R3F_LOG_remorque"}) then +{ + _remorqueur setVariable ["R3F_LOG_remorque", objNull, false]; +}; + +_remorqueur addAction [("" + STR_R3F_LOG_action_remorquer_deplace + ""), {_this call R3F_LOG_FNCT_remorqueur_remorquer_deplace}, nil, 7, true, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_joueur_deplace_objet != _target && R3F_LOG_action_remorquer_deplace_valide"]; \ No newline at end of file diff --git a/surveiller_conditions_actions_menu.sqf b/surveiller_conditions_actions_menu.sqf new file mode 100644 index 0000000..b6bc8b2 --- /dev/null +++ b/surveiller_conditions_actions_menu.sqf @@ -0,0 +1,297 @@ +/* +* Evalue régulièrement les conditions à vérifier pour autoriser les actions logistiques + * Permet de diminuer la fréquence des vérifications des conditions normalement faites + * dans les addAction (~60Hz) et donc de limiter la consommation CPU. + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +private ["_joueur", "_vehicule_joueur", "_cursorTarget_distance", "_objet_pointe", "_objet_pas_en_cours_de_deplacement", "_fonctionnalites", "_pas_de_hook"]; +private ["_objet_deverrouille", "_objet_pointe_autre_que_deplace", "_objet_pointe_autre_que_deplace_deverrouille", "_isUav", "_usine_autorisee_client"]; + +// Indices du tableau des fonctionnalités retourné par R3F_LOG_FNCT_determiner_fonctionnalites_logistique +#define __can_be_depl_heli_remorq_transp 0 +#define __can_be_moved_by_player 1 +#define __can_lift 2 +#define __can_be_lifted 3 +#define __can_tow 4 +#define __can_be_towed 5 +#define __can_transport_cargo 6 +#define __can_transport_cargo_cout 7 +#define __can_be_transported_cargo 8 +#define __can_be_transported_cargo_cout 9 + +sleep 2; + +while {true} do +{ +_joueur = player; +_vehicule_joueur = vehicle _joueur; + +_cursorTarget_distance = call R3F_LOG_FNCT_3D_cursorTarget_distance_bbox; +_objet_pointe = _cursorTarget_distance select 0; + + +_isNOTlocked = locked _objet_pointe < 2; + + +if (call compile R3F_LOG_CFG_string_condition_allow_logistics_on_this_client && +!R3F_LOG_mutex_local_verrou && _vehicule_joueur == _joueur && !isNull _objet_pointe && _cursorTarget_distance select 1 < 3.75 +) then +{ +R3F_LOG_objet_addAction = _objet_pointe; + +_fonctionnalites = _objet_pointe getVariable ["R3F_LOG_fonctionnalites", R3F_LOG_CST_zero_log]; + +_objet_pas_en_cours_de_deplacement = (isNull (_objet_pointe getVariable ["R3F_LOG_est_deplace_par", objNull]) || +{(!alive (_objet_pointe getVariable "R3F_LOG_est_deplace_par")) || (!isPlayer (_objet_pointe getVariable "R3F_LOG_est_deplace_par"))}); + +_isUav = (getNumber (configFile >> "CfgVehicles" >> (typeOf _objet_pointe) >> "isUav") == 1); + +_usine_autorisee_client = call compile R3F_LOG_CFG_string_condition_allow_creation_factory_on_this_client; + +// L'objet est-il déverrouillé +_objet_deverrouille = !([_objet_pointe, _joueur] call R3F_LOG_FNCT_objet_est_verrouille); + +// Trouver l'objet pointé qui se trouve derrière l'objet en cours de déplacement +_objet_pointe_autre_que_deplace = [R3F_LOG_joueur_deplace_objet, 3.75] call R3F_LOG_FNCT_3D_cursorTarget_virtuel; + +if (!isNull _objet_pointe_autre_que_deplace) then +{ +// L'objet (pointé qui se trouve derrière l'objet en cours de déplacement) est-il déverrouillé +_objet_pointe_autre_que_deplace_deverrouille = !([_objet_pointe_autre_que_deplace, _joueur] call R3F_LOG_FNCT_objet_est_verrouille); +}; + +// Si l'objet est un objet déplaçable +if (_fonctionnalites select __can_be_moved_by_player) then +{ +// Condition action deplacer_objet +R3F_LOG_action_deplacer_objet_valide = (count crew _objet_pointe == 0 || _isUav) && (isNull R3F_LOG_joueur_deplace_objet) && +_objet_pas_en_cours_de_deplacement && isNull (_objet_pointe getVariable "R3F_LOG_est_transporte_par") && _isNOTlocked && +_objet_deverrouille && !(_objet_pointe getVariable "R3F_LOG_disabled"); + +// Condition action revendre_usine_deplace +R3F_LOG_action_revendre_usine_deplace_valide = _usine_autorisee_client && R3F_LOG_CFG_CF_sell_back_bargain_rate != -1 && _isNOTlocked && +_objet_pointe getVariable ["R3F_LOG_CF_depuis_usine", false] && (count crew _objet_pointe == 0 || _isUav) && +(R3F_LOG_joueur_deplace_objet == _objet_pointe) && !(_objet_pointe getVariable "R3F_LOG_disabled") && !isNull _objet_pointe_autre_que_deplace && +{ +!(_objet_pointe_autre_que_deplace getVariable ["R3F_LOG_CF_disabled", true]) && +_objet_pointe_autre_que_deplace getVariable ["R3F_LOG_CF_side_addAction", side group _joueur] == side group _joueur && +(abs ((getPosASL _objet_pointe_autre_que_deplace select 2) - (getPosASL player select 2)) < 2.5) && _isNOTlocked && +alive _objet_pointe_autre_que_deplace && (vectorMagnitude velocity _objet_pointe_autre_que_deplace < 6) +}; +}; + + + +// Si l'objet est un objet remorquable +if (_fonctionnalites select __can_be_towed) then +{ +// Et qu'il est déplaçable +if (_fonctionnalites select __can_be_moved_by_player) then +{ +// Condition action remorquer_deplace +R3F_LOG_action_remorquer_deplace_valide = !(_objet_pointe getVariable "R3F_LOG_disabled") && (count crew _objet_pointe == 0 || _isUav) && _isNOTlocked && +(R3F_LOG_joueur_deplace_objet == _objet_pointe) && !isNull _objet_pointe_autre_que_deplace && +{ +(_objet_pointe_autre_que_deplace getVariable ["R3F_LOG_fonctionnalites", R3F_LOG_CST_zero_log] select __can_tow) && alive _objet_pointe_autre_que_deplace && _isNOTlocked && +isNull (_objet_pointe_autre_que_deplace getVariable "R3F_LOG_est_transporte_par") && isNull (_objet_pointe_autre_que_deplace getVariable "R3F_LOG_remorque") && +(vectorMagnitude velocity _objet_pointe_autre_que_deplace < 6) && +_objet_pointe_autre_que_deplace_deverrouille && !(_objet_pointe_autre_que_deplace getVariable "R3F_LOG_disabled") +}; +}; + +// Condition action selectionner_objet_remorque +R3F_LOG_action_remorquer_direct_valide = (count crew _objet_pointe == 0 || _isUav) && isNull R3F_LOG_joueur_deplace_objet && _isNOTlocked && +isNull (_objet_pointe getVariable "R3F_LOG_est_transporte_par") && isNull (_objet_pointe getVariable ["R3F_LOG_remorque", objNull]) && +_objet_pas_en_cours_de_deplacement && _objet_deverrouille && !(_objet_pointe getVariable "R3F_LOG_disabled") && +{ +{ +_x != _objet_pointe && (_x getVariable ["R3F_LOG_fonctionnalites", R3F_LOG_CST_zero_log] select __can_tow) && +alive _x && isNull (_x getVariable "R3F_LOG_est_transporte_par") && +isNull (_x getVariable "R3F_LOG_remorque") && (vectorMagnitude velocity _x < 6) && locked _x < 2 && +!([_x, _joueur] call R3F_LOG_FNCT_objet_est_verrouille) && !(_x getVariable "R3F_LOG_disabled") && +{ +private ["_delta_pos"]; + +_delta_pos = +( +_objet_pointe modelToWorld +[ +boundingCenter _objet_pointe select 0, +boundingBoxReal _objet_pointe select 1 select 1, +boundingBoxReal _objet_pointe select 0 select 2 +] +) vectorDiff ( +_x modelToWorld +[ +boundingCenter _x select 0, +boundingBoxReal _x select 0 select 1, +boundingBoxReal _x select 0 select 2 +] +); + +// L'arrière du remorqueur est proche de l'avant de l'objet pointé +abs (_delta_pos select 0) < 3 && abs (_delta_pos select 1) < 5 +} +} count (nearestObjects [_objet_pointe, ["All"], 30]) != 0 +}; + +// Condition action detacher +R3F_LOG_action_detacher_valide = (isNull R3F_LOG_joueur_deplace_objet) && _isNOTlocked && +!isNull (_objet_pointe getVariable "R3F_LOG_est_transporte_par") && _objet_deverrouille && !(_objet_pointe getVariable "R3F_LOG_disabled"); +}; + +// Si l'objet est un objet transportable +if (_fonctionnalites select __can_be_transported_cargo) then +{ +// Et qu'il est déplaçable +if (_fonctionnalites select __can_be_moved_by_player) then +{ +// Condition action charger_deplace +R3F_LOG_action_charger_deplace_valide = (count crew _objet_pointe == 0 || _isUav) && (R3F_LOG_joueur_deplace_objet == _objet_pointe) && +!(_objet_pointe getVariable "R3F_LOG_disabled") && !isNull _objet_pointe_autre_que_deplace && _isNOTlocked && +{ +(_objet_pointe_autre_que_deplace getVariable ["R3F_LOG_fonctionnalites", R3F_LOG_CST_zero_log] select __can_transport_cargo) && +(abs ((getPosASL _objet_pointe_autre_que_deplace select 2) - (getPosASL player select 2)) < 2.5) && _isNOTlocked && +alive _objet_pointe_autre_que_deplace && (vectorMagnitude velocity _objet_pointe_autre_que_deplace < 6) && +_objet_pointe_autre_que_deplace_deverrouille && !(_objet_pointe_autre_que_deplace getVariable "R3F_LOG_disabled") +}; +}; + +// Condition action selectionner_objet_charge +R3F_LOG_action_selectionner_objet_charge_valide = (count crew _objet_pointe == 0 || _isUav) && isNull R3F_LOG_joueur_deplace_objet && +isNull (_objet_pointe getVariable "R3F_LOG_est_transporte_par") && _isNOTlocked && +_objet_pas_en_cours_de_deplacement && _objet_deverrouille && !(_objet_pointe getVariable "R3F_LOG_disabled"); +}; + +// Si l'objet est un véhicule remorqueur +if (_fonctionnalites select __can_tow) then +{ +// Condition action remorquer_deplace +R3F_LOG_action_remorquer_deplace_valide = (alive _objet_pointe) && (!isNull R3F_LOG_joueur_deplace_objet) && +!(R3F_LOG_joueur_deplace_objet getVariable "R3F_LOG_disabled") && (R3F_LOG_joueur_deplace_objet != _objet_pointe) && +(R3F_LOG_joueur_deplace_objet getVariable ["R3F_LOG_fonctionnalites", R3F_LOG_CST_zero_log] select __can_be_towed) && +isNull (_objet_pointe getVariable "R3F_LOG_est_transporte_par") && _isNOTlocked && +isNull (_objet_pointe getVariable "R3F_LOG_remorque") && (vectorMagnitude velocity _objet_pointe < 6) && +_objet_deverrouille && !(_objet_pointe getVariable "R3F_LOG_disabled"); +}; + +// Si l'objet est un véhicule transporteur +if (_fonctionnalites select __can_transport_cargo) then +{ +// Condition action charger_deplace +R3F_LOG_action_charger_deplace_valide = alive _objet_pointe && (!isNull R3F_LOG_joueur_deplace_objet) && +!(R3F_LOG_joueur_deplace_objet getVariable "R3F_LOG_disabled") && (R3F_LOG_joueur_deplace_objet != _objet_pointe) && _isNOTlocked && +(R3F_LOG_joueur_deplace_objet getVariable ["R3F_LOG_fonctionnalites", R3F_LOG_CST_zero_log] select __can_be_transported_cargo) && +(vectorMagnitude velocity _objet_pointe < 6) && _objet_deverrouille && !(_objet_pointe getVariable "R3F_LOG_disabled"); + +// Condition action charger_selection +R3F_LOG_action_charger_selection_valide = alive _objet_pointe && (isNull R3F_LOG_joueur_deplace_objet) && +(!isNull R3F_LOG_objet_selectionne) && (R3F_LOG_objet_selectionne != _objet_pointe) && +!(R3F_LOG_objet_selectionne getVariable "R3F_LOG_disabled") && _isNOTlocked && +(R3F_LOG_objet_selectionne getVariable ["R3F_LOG_fonctionnalites", R3F_LOG_CST_zero_log] select __can_be_transported_cargo) && +(vectorMagnitude velocity _objet_pointe < 6) && _objet_deverrouille && !(_objet_pointe getVariable "R3F_LOG_disabled"); + +// Condition action contenu_vehicule +R3F_LOG_action_contenu_vehicule_valide = alive _objet_pointe && (isNull R3F_LOG_joueur_deplace_objet) && _isNOTlocked && +(vectorMagnitude velocity _objet_pointe < 6) && _objet_deverrouille && !(_objet_pointe getVariable "R3F_LOG_disabled"); +}; + +// Condition action ouvrir_usine +R3F_LOG_action_ouvrir_usine_valide = _usine_autorisee_client && isNull R3F_LOG_joueur_deplace_objet && +!(_objet_pointe getVariable "R3F_LOG_CF_disabled") && alive _objet_pointe && +_objet_pointe getVariable ["R3F_LOG_CF_side_addAction", side group _joueur] == side group _joueur; + +// Condition action revendre_usine_deplace +R3F_LOG_action_revendre_usine_deplace_valide = _usine_autorisee_client && R3F_LOG_CFG_CF_sell_back_bargain_rate != -1 && alive _objet_pointe && +(!isNull R3F_LOG_joueur_deplace_objet) && R3F_LOG_joueur_deplace_objet getVariable ["R3F_LOG_CF_depuis_usine", false] && +!(R3F_LOG_joueur_deplace_objet getVariable "R3F_LOG_disabled") && (R3F_LOG_joueur_deplace_objet != _objet_pointe) && +(vectorMagnitude velocity _objet_pointe < 6) && !(_objet_pointe getVariable "R3F_LOG_CF_disabled") && +_objet_pointe getVariable ["R3F_LOG_CF_side_addAction", side group _joueur] == side group _joueur; + +// Condition action revendre_usine_selection +R3F_LOG_action_revendre_usine_selection_valide = _usine_autorisee_client && R3F_LOG_CFG_CF_sell_back_bargain_rate != -1 && alive _objet_pointe && +(isNull R3F_LOG_joueur_deplace_objet) && R3F_LOG_objet_selectionne getVariable ["R3F_LOG_CF_depuis_usine", false] && +(!isNull R3F_LOG_objet_selectionne) && (R3F_LOG_objet_selectionne != _objet_pointe) && !(R3F_LOG_objet_selectionne getVariable "R3F_LOG_disabled") && +(vectorMagnitude velocity _objet_pointe < 6) && !(_objet_pointe getVariable "R3F_LOG_CF_disabled") && +_objet_pointe getVariable ["R3F_LOG_CF_side_addAction", side group _joueur] == side group _joueur; + +// Condition action revendre_usine_direct +R3F_LOG_action_revendre_usine_direct_valide = _usine_autorisee_client && R3F_LOG_CFG_CF_sell_back_bargain_rate != -1 && +_objet_pointe getVariable ["R3F_LOG_CF_depuis_usine", false] && (count crew _objet_pointe == 0 || _isUav) && _isNOTlocked && +isNull R3F_LOG_joueur_deplace_objet && isNull (_objet_pointe getVariable ["R3F_LOG_est_transporte_par", objNull]) && +_objet_pas_en_cours_de_deplacement && +{ +_objet_pointe distance _x < 20 && !(_x getVariable "R3F_LOG_CF_disabled") && _isNOTlocked && +_x getVariable ["R3F_LOG_CF_side_addAction", side group _joueur] == side group _joueur +} count R3F_LOG_CF_liste_usines != 0; + +// Condition déverrouiller objet +R3F_LOG_action_deverrouiller_valide = _objet_pas_en_cours_de_deplacement && !_objet_deverrouille && !(_objet_pointe getVariable "R3F_LOG_disabled"); +} +else +{ +R3F_LOG_action_deplacer_objet_valide = false; +R3F_LOG_action_remorquer_direct_valide = false; +R3F_LOG_action_detacher_valide = false; +R3F_LOG_action_selectionner_objet_charge_valide = false; +R3F_LOG_action_remorquer_deplace_valide = false; +R3F_LOG_action_charger_deplace_valide = false; +R3F_LOG_action_charger_selection_valide = false; +R3F_LOG_action_contenu_vehicule_valide = false; +R3F_LOG_action_ouvrir_usine_valide = false; +R3F_LOG_action_selectionner_objet_revendre_usine_valide = false; +R3F_LOG_action_revendre_usine_direct_valide = false; +R3F_LOG_action_revendre_usine_deplace_valide = false; +R3F_LOG_action_revendre_usine_selection_valide = false; +R3F_LOG_action_deverrouiller_valide = false; +}; + +// Si le joueur est pilote dans un héliporteur +if (call compile R3F_LOG_CFG_string_condition_allow_logistics_on_this_client && _isNOTlocked && +!R3F_LOG_mutex_local_verrou && _vehicule_joueur != _joueur && driver _vehicule_joueur == _joueur && {_vehicule_joueur getVariable ["R3F_LOG_fonctionnalites", R3F_LOG_CST_zero_log] select __can_lift} +) then +{ +R3F_LOG_objet_addAction = _vehicule_joueur; + +// Note : pas de restriction liée à R3F_LOG_proprietaire_verrou pour l'héliportage + +// A partir des versions > 1.32, on interdit le lift si le hook de BIS est utilisé +if (productVersion select 2 > 132) then +{ +// Call compile car la commande getSlingLoad n'existe pas en 1.32 +_pas_de_hook = _vehicule_joueur call compile format ["isNull getSlingLoad _this"]; +} +else +{ +_pas_de_hook = true; +}; + +// Condition action heliporter +R3F_LOG_action_heliporter_valide = !(_vehicule_joueur getVariable "R3F_LOG_disabled") && _pas_de_hook && _isNOTlocked && +isNull (_vehicule_joueur getVariable "R3F_LOG_heliporte") && (vectorMagnitude velocity _vehicule_joueur < 6) && +{ +{ +(_x getVariable ["R3F_LOG_fonctionnalites", R3F_LOG_CST_zero_log] select __can_be_lifted) && +_x != _vehicule_joueur && !(_x getVariable "R3F_LOG_disabled") && locked _x < 2 && +((getPosASL _vehicule_joueur select 2) - (getPosASL _x select 2) > 2 && (getPosASL _vehicule_joueur select 2) - (getPosASL _x select 2) < 15) +} count (nearestObjects [_vehicule_joueur, ["All"], 15]) != 0 +}; + +// Condition action heliport_larguer +R3F_LOG_action_heliport_larguer_valide = !isNull (_vehicule_joueur getVariable "R3F_LOG_heliporte") && !(_vehicule_joueur getVariable "R3F_LOG_disabled") && _isNOTlocked && +(vectorMagnitude velocity _vehicule_joueur < 25) && ((getPosASL _vehicule_joueur select 2) - (0 max getTerrainHeightASL getPos _vehicule_joueur) < 40); +} +else +{ +R3F_LOG_action_heliporter_valide = false; +R3F_LOG_action_heliport_larguer_valide = false; +}; + +sleep 0.4; +}; \ No newline at end of file diff --git a/surveiller_nouveaux_objets.sqf b/surveiller_nouveaux_objets.sqf new file mode 100644 index 0000000..db9b519 --- /dev/null +++ b/surveiller_nouveaux_objets.sqf @@ -0,0 +1,187 @@ +/** + * Recherche périodiquement les nouveaux objets pour leur ajouter les fonctionnalités de logistique si besoin + * Script à faire tourner dans un fil d'exécution dédié + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +sleep 4; + +private +[ + "_compteur_cyclique", "_liste_nouveaux_objets", "_liste_vehicules_connus", "_liste_statiques", "_liste_nouveaux_statiques", + "_liste_statiques_connus", "_liste_statiques_cycle_precedent", "_count_liste_objets", "_i", "_objet", "_fonctionnalites", + "_liste_purge", "_seuil_nb_statiques_avant_purge", "_seuil_nb_vehicules_avant_purge" +]; + +// Contiendra la liste des objets déjà parcourus récupérés avec la commande "vehicles" +_liste_vehicules_connus = []; +// Contiendra la liste des objets dérivant de "Static" (caisse de mun, drapeau, ...) déjà parcourus récupérés avec la commande "nearestObjects" +_liste_statiques_connus = []; +// Contiendra la liste des objets "Static" récupérés lors du tour de boucle précécent (optimisation des opérations sur les tableaux) +_liste_statiques_cycle_precedent = []; + +// Indices du tableau des fonctionnalités retourné par R3F_LOG_FNCT_determiner_fonctionnalites_logistique +#define __can_be_depl_heli_remorq_transp 0 +#define __can_be_moved_by_player 1 +#define __can_lift 2 +#define __can_be_lifted 3 +#define __can_tow 4 +#define __can_be_towed 5 +#define __can_transport_cargo 6 +#define __can_transport_cargo_cout 7 +#define __can_be_transported_cargo 8 +#define __can_be_transported_cargo_cout 9 + +// Période de recherche des objets dérivant de "Static" +#define __tempo 3 +// Utiliser la commande vehicles une fois tout les X cycles de période __tempo +#define __nb_cycles_commande_vehicles 4 + +_compteur_cyclique = 0; +_seuil_nb_statiques_avant_purge = 150; +_seuil_nb_vehicules_avant_purge = 150; + +while {true} do +{ + if (!isNull player) then + { + // Tout les __nb_cycles_commande_vehicles ou sur ordre, on récupère les nouveaux véhicules du jeu + if (_compteur_cyclique == 0 || R3F_LOG_PUBVAR_nouvel_objet_a_initialiser) then + { + R3F_LOG_PUBVAR_nouvel_objet_a_initialiser = false; // Acquittement local + + // Purge de _liste_vehicules_connus quand nécessaire + if (count _liste_vehicules_connus > _seuil_nb_vehicules_avant_purge) then + { + _liste_purge = []; + { + if (!isNull _x) then + { + _liste_purge pushBack _x; + }; + } forEach _liste_vehicules_connus; + + _liste_vehicules_connus = _liste_purge; + _seuil_nb_vehicules_avant_purge = count _liste_vehicules_connus + 75; + }; + + // Purge de _liste_statiques_connus quand nécessaire + if (count _liste_statiques_connus > _seuil_nb_statiques_avant_purge) then + { + _liste_purge = []; + { + if (!isNull _x && + { + !isNil {_x getVariable "R3F_LOG_fonctionnalites"} || + (_x getVariable ["R3F_LOG_CF_depuis_usine", false]) + } + ) then + { + _liste_purge pushBack _x; + }; + } forEach _liste_statiques_connus; + + _liste_statiques_connus = _liste_purge; + _seuil_nb_statiques_avant_purge = count _liste_statiques_connus + 150; + }; + + // Récupération des nouveaux véhicules + _liste_nouveaux_objets = vehicles - _liste_vehicules_connus; + _liste_vehicules_connus = _liste_vehicules_connus + _liste_nouveaux_objets; + } + else + { + _liste_nouveaux_objets = []; + }; + _compteur_cyclique = (_compteur_cyclique + 1) mod __nb_cycles_commande_vehicles; + + // En plus des nouveaux véhicules, on récupère les statiques (caisse de mun, drapeau, ...) proches du joueur non connus + // Optimisation "_liste_statiques_cycle_precedent" : et qui n'étaient pas proches du joueur au cycle précédent + _liste_statiques = nearestObjects [player, ["Static"], 25]; + if (count _liste_statiques != 0) then + { + _liste_nouveaux_statiques = _liste_statiques - _liste_statiques_cycle_precedent - _liste_statiques_connus; + _liste_statiques_connus = _liste_statiques_connus + _liste_nouveaux_statiques; + _liste_statiques_cycle_precedent = _liste_statiques; + } + else + { + _liste_nouveaux_statiques = []; + _liste_statiques_cycle_precedent = []; + }; + + _liste_nouveaux_objets = _liste_nouveaux_objets + _liste_nouveaux_statiques; + _count_liste_objets = count _liste_nouveaux_objets; + + if (_count_liste_objets > 0) then + { + // On parcoure tous les nouveaux objets en __tempo secondes + for [{_i = 0}, {_i < _count_liste_objets}, {_i = _i + 1}] do + { + _objet = _liste_nouveaux_objets select _i; + _fonctionnalites = [typeOf _objet] call R3F_LOG_FNCT_determiner_fonctionnalites_logistique; + + // Si au moins une fonctionnalité + if ( + _fonctionnalites select __can_be_depl_heli_remorq_transp || + _fonctionnalites select __can_lift || + _fonctionnalites select __can_tow || + _fonctionnalites select __can_transport_cargo + ) then + { + _objet setVariable ["R3F_LOG_fonctionnalites", _fonctionnalites, false]; + + if (isNil {_objet getVariable "R3F_LOG_disabled"}) then + { + _objet setVariable ["R3F_LOG_disabled", R3F_LOG_CFG_disabled_by_default, false]; + }; + + // Si l'objet est un objet déplaçable/héliportable/remorquable/transportable + if (_fonctionnalites select __can_be_depl_heli_remorq_transp) then + { + [_objet] call R3F_LOG_FNCT_objet_init; + }; + + // Si l'objet est un véhicule héliporteur + if (_fonctionnalites select __can_lift) then + { + [_objet] call R3F_LOG_FNCT_heliporteur_init; + }; + + // Si l'objet est un véhicule remorqueur + if (_fonctionnalites select __can_tow) then + { + [_objet] call R3F_LOG_FNCT_remorqueur_init; + }; + + // Si l'objet est un véhicule transporteur + if (_fonctionnalites select __can_transport_cargo) then + { + [_objet] call R3F_LOG_FNCT_transporteur_init; + }; + }; + + // Si l'objet a été créé depuis une usine, on ajoute la possibilité de revendre à l'usine, quelque soit ses fonctionnalités logistiques + if (_objet getVariable ["R3F_LOG_CF_depuis_usine", false]) then + { + _objet addAction [("" + format [STR_R3F_LOG_action_revendre_usine_direct, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")] + ""), {_this call R3F_LOG_FNCT_usine_revendre_direct}, nil, 5, false, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_action_revendre_usine_direct_valide"]; + }; + + sleep (0.07 max (__tempo / _count_liste_objets)); + }; + } + else + { + sleep __tempo; + }; + } + else + { + sleep 2; + }; +}; \ No newline at end of file diff --git a/surveiller_objets_a_proteger.sqf b/surveiller_objets_a_proteger.sqf new file mode 100644 index 0000000..96d940b --- /dev/null +++ b/surveiller_objets_a_proteger.sqf @@ -0,0 +1,93 @@ +/** +* Vérifie périodiquement que les objets à protéger et ne pas perdre aient besoin d'être déchargés/téléportés. +* Script à faire tourner dans un fil d'exécution dédié sur le serveur. +* +* Copyright (C) 2014 Team ~R3F~ +* +* This program is free software under the terms of the GNU General Public License version 3. +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +while {true} do +{ + // Pour chaque objet à protéger + { + private ["_objet", "_bbox_dim", "_pos_respawn", "_pos_degagee", "_rayon"]; + + _objet = _x; + + if (!isNull _objet) then + { + // Si l'objet est transporté/héliporté/remorqué + if !(isNull (_objet getVariable ["R3F_LOG_est_transporte_par", objNull])) then + { + // Mais que le transporteur est détruit/héliporté/remorqué + if !(alive (_objet getVariable "R3F_LOG_est_transporte_par")) then + { + // Récupération de la position de respawn en accord avec le paramètre passé dans "do_not_lose_it" + if (typeName (_objet getVariable "R3F_LOG_pos_respawn") == "ARRAY") then + { + _pos_respawn = _objet getVariable "R3F_LOG_pos_respawn"; + } + else + { + if (_objet getVariable "R3F_LOG_pos_respawn" == "cargo_pos") then + { + _pos_respawn = getPos (_objet getVariable "R3F_LOG_est_transporte_par"); + } + else + { + _pos_respawn = getMarkerPos (_objet getVariable "R3F_LOG_pos_respawn"); + }; + }; + + _bbox_dim = (vectorMagnitude (boundingBoxReal _objet select 0)) max (vectorMagnitude (boundingBoxReal _objet select 1)); + + // Si mode de respawn != "exact_spawn_pos" + if (isNil {_objet getVariable "R3F_LOG_dir_respawn"}) then + { + // Recherche d'une position dégagée (on augmente progressivement le rayon jusqu'à trouver une position) + for [{_rayon = 5 max (2*_bbox_dim); _pos_degagee = [];}, {count _pos_degagee == 0 && _rayon <= 100 + (8*_bbox_dim)}, {_rayon = _rayon + 20 + (5*_bbox_dim)}] do + { + _pos_degagee = [ + _bbox_dim, + _pos_respawn, + _rayon, + 100 min (5 + _rayon^1.2) + ] call R3F_LOG_FNCT_3D_tirer_position_degagee_sol; + }; + + // En cas d'échec de la recherche de position dégagée + if (count _pos_degagee == 0) then {_pos_degagee = _pos_respawn;}; + + // On ramène l'objet sur la position + detach _objet; + _objet setPos _pos_degagee; + } + else + { + // On ramène l'objet sur la position + detach _objet; + _objet setPosASL _pos_respawn; + _objet setDir (_objet getVariable "R3F_LOG_dir_respawn"); + }; + + // On retire l'objet du contenu du véhicule (s'il est dedans) + _objets_charges = (_objet getVariable "R3F_LOG_est_transporte_par") getVariable ["R3F_LOG_objets_charges", []]; + if (_objet in _objets_charges) then + { + _objets_charges = _objets_charges - [_objet]; + (_objet getVariable "R3F_LOG_est_transporte_par") setVariable ["R3F_LOG_objets_charges", _objets_charges, true]; + }; + + _objet setVariable ["R3F_LOG_est_transporte_par", objNull, true]; + + sleep 4; + }; + }; + }; + } forEach R3F_LOG_liste_objets_a_proteger; + + sleep 90; +}; \ No newline at end of file diff --git a/systeme_protection_blessures.sqf b/systeme_protection_blessures.sqf new file mode 100644 index 0000000..9ccd6f7 --- /dev/null +++ b/systeme_protection_blessures.sqf @@ -0,0 +1,171 @@ +/** + * Système assurant la protection contre les blessures des unités locales lors du déplacement manuels d'objets + * Les objets en cours de transport/heliport/remorquage ne sont pas concernés. + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** Contient la liste de tous les objets en cours de déplacements manuels */ +R3F_LOG_liste_objets_en_deplacement = []; + +/** + * Fonction PVEH ajoutant les nouveaux objets en cours de déplacement dans la liste + * @param 1 le nouvel objet en cours de déplacement + */ +R3F_LOG_FNCT_PVEH_nouvel_objet_en_deplacement = +{ + private ["_objet"]; + + _objet = _this select 1; + + R3F_LOG_liste_objets_en_deplacement = R3F_LOG_liste_objets_en_deplacement - [_objet]; + R3F_LOG_liste_objets_en_deplacement pushBack _objet; + + _objet allowDamage false; +}; +"R3F_LOG_PV_nouvel_objet_en_deplacement" addPublicVariableEventHandler R3F_LOG_FNCT_PVEH_nouvel_objet_en_deplacement; + +/** + * Fonction PVEH retirant de la liste les objets dont le déplacement est terminé + * @param 1 l'objet dont le déplacement est terminé + */ +R3F_LOG_FNCT_PVEH_fin_deplacement_objet = +{ + private ["_objet"]; + + _objet = _this select 1; + + R3F_LOG_liste_objets_en_deplacement = R3F_LOG_liste_objets_en_deplacement - [_this select 1]; + + // Limitation : si l'objet a été "allowDamage false" par ailleurs, il ne le sera plus. Voir http://feedback.arma3.com/view.php?id=19211 + _objet allowDamage true; +}; +"R3F_LOG_PV_fin_deplacement_objet" addPublicVariableEventHandler R3F_LOG_FNCT_PVEH_fin_deplacement_objet; + +/** + * Fonction traitant les event handler HandleDamage des unités locales, + * si la blessure provient d'un objet en déplacement, la blessure est ignorée + * @param voir https://community.bistudio.com/wiki/Arma_3:_Event_Handlers#HandleDamage + * @return niveau de blessure inchangé si due au déplacement d'un objet, sinon rien pour laisser A3 gérer la blessure + * @note implémentation de la commande getHit manquante ( http://feedback.arma3.com/view.php?id=18261 ) + */ +R3F_LOG_FNCT_EH_HandleDamage = +{ + private ["_unite", "_selection", "_blessure", "_source"]; + + _unite = _this select 0; + _selection = _this select 1; + _blessure = _this select 2; + _source = _this select 3; + + if ( + // Filtre sur les blessures de type choc/collision + _this select 4 == "" && {(isNull _source || _source == _unite || _source in R3F_LOG_liste_objets_en_deplacement) + && { + // Si l'unité est potentiellement en collision avec un objet en cours de déplacement + { + !isNull _x && + { + // Calcul de collision possible unité-objet + [ + _x worldToModel (_unite modelToWorld [0,0,0]), // position de l'unité dans le repère de l'objet en déplacement + (boundingBoxReal _x select 0) vectorDiff [12, 12, 12], // bbox min élargie (zone de sûreté) + (boundingBoxReal _x select 1) vectorAdd [12, 12, 12] // bbox max élargie (zone de sûreté) + ] call R3F_LOG_FNCT_3D_pos_est_dans_bbox + } + } count R3F_LOG_liste_objets_en_deplacement != 0 + } + }) then + { + // Retourner la valeur de blessure précédente de l'unité + if (_selection == "") then + { + damage _unite + } + else + { + _unite getHit _selection + }; + }; +}; + +sleep 5; + +while {true} do +{ + private ["_idx_objet"]; + + // Vérifier que les unités locales à la machine sont gérées, et ne plus gérées celles qui ne sont plus locales + // Par chaque unité + { + // Unité non gérée + if (isNil {_x getVariable "R3F_LOG_idx_EH_HandleDamage"}) then + { + // Et qui est locale + if (local _x) then + { + // Event handler de à chaque blessure, vérifiant si elle est due à un objet en déplacement + _x setVariable ["R3F_LOG_idx_EH_HandleDamage", _x addEventHandler ["HandleDamage", {_this call R3F_LOG_FNCT_EH_HandleDamage}]]; + }; + } + // Unité déjà gérée + else + { + // Mais qui n'est plus locale + if (!local _x) then + { + // Suppresion des event handler de gestion des blessures + _x removeEventHandler ["HandleDamage", _x getVariable "R3F_LOG_idx_EH_HandleDamage"]; + _x setVariable ["R3F_LOG_idx_EH_HandleDamage", nil]; + }; + }; + } forEach call {// Calcul du paramètre du forEach + /* + * Sur un serveur non-dédié, on ne protège que le joueur et son groupe (économie de ressources) + * Les IA non commandées par des joueurs ne seront donc pas protégées, ce qui est un moindre mal. + */ + if (isServer && !isDedicated) then {if (!isNull player) then {units group player} else {[]}} + /* + * Chez un joueur (ou un serveur dédié), on protège toutes les unités locales. + * Dans la pratique un serveur dédié n'appelle pas ce script, par choix, pour économiser les ressources. + */ + else {allUnits} + }; + + // Vérifier l'intégrité de la liste des objets en cours de déplacements, et la nettoyer si besoin + for [{_idx_objet = 0}, {_idx_objet < count R3F_LOG_liste_objets_en_deplacement}, {;}] do + { + private ["_objet"]; + + _objet = R3F_LOG_liste_objets_en_deplacement select _idx_objet; + + if (isNull _objet) then + { + R3F_LOG_liste_objets_en_deplacement = R3F_LOG_liste_objets_en_deplacement - [objNull]; + + // On recommence la validation de la liste + _idx_objet = 0; + } + else + { + // Si l'objet n'est plus déplacé par une unité valide + if !(isNull (_objet getVariable ["R3F_LOG_est_deplace_par", objNull]) || + {alive (_objet getVariable "R3F_LOG_est_deplace_par") && isPlayer (_objet getVariable "R3F_LOG_est_deplace_par")} + ) then + { + ["R3F_LOG_PV_fin_deplacement_objet", _objet] call R3F_LOG_FNCT_PVEH_fin_deplacement_objet; + + // On recommence la validation de la liste + _idx_objet = 0; + } + // Si l'objet est toujours en déplacement, on poursuit le parcours de la liste + else {_idx_objet = _idx_objet+1;}; + }; + }; + + sleep 90; +}; \ No newline at end of file diff --git a/transporteur/calculer_chargement_vehicule.sqf b/transporteur/calculer_chargement_vehicule.sqf new file mode 100644 index 0000000..2ccefdd --- /dev/null +++ b/transporteur/calculer_chargement_vehicule.sqf @@ -0,0 +1,45 @@ +/** + * Retourne le chargement actuel et la capacité maximale d'un véhicule + * + * @param 0 le transporteur pour lequel calculer le chargement + * + * @return tableau content le chargement actuel et la capacité d'un véhicule + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +private ["_transporteur", "_objets_charges", "_chargement_actuel", "_chargement_maxi"]; + +_transporteur = _this select 0; + +_objets_charges = _transporteur getVariable ["R3F_LOG_objets_charges", []]; + +// Calcul du chargement actuel +_chargement_actuel = 0; +{ + if (isNil {_x getVariable "R3F_LOG_fonctionnalites"}) then + { + _chargement_actuel = _chargement_actuel + (([typeOf _x] call R3F_LOG_FNCT_determiner_fonctionnalites_logistique) select R3F_LOG_IDX_can_be_transported_cargo_cout); + } + else + { + _chargement_actuel = _chargement_actuel + (_x getVariable "R3F_LOG_fonctionnalites" select R3F_LOG_IDX_can_be_transported_cargo_cout); + }; + +} forEach _objets_charges; + +// Recherche de la capacité maximale du transporteur +if (isNil {_transporteur getVariable "R3F_LOG_fonctionnalites"}) then +{ + _chargement_maxi = ([typeOf _transporteur] call R3F_LOG_FNCT_determiner_fonctionnalites_logistique) select R3F_LOG_IDX_can_transport_cargo_cout; +} +else +{ + _chargement_maxi = _transporteur getVariable "R3F_LOG_fonctionnalites" select R3F_LOG_IDX_can_transport_cargo_cout; +}; + +[_chargement_actuel, _chargement_maxi] \ No newline at end of file diff --git a/transporteur/charger_auto.sqf b/transporteur/charger_auto.sqf new file mode 100644 index 0000000..bee9dd2 --- /dev/null +++ b/transporteur/charger_auto.sqf @@ -0,0 +1,181 @@ +/** + * Charger automatiquement un ou plusieurs objets/noms de classe dans un transporteur + * + * @param 0 le transporteur + * @param 1 tableau d'objets et/ou noms de classe, pouvant être un mélange des formats suivants : + * objet + * nom de classe, dans ce cas, l'objet sera créé avant d'être chargé + * tableau ["nom de classe", quantité] à créer avant d'être chargé + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +// Attendre le mutex +waitUntil +{ + if (R3F_LOG_mutex_local_verrou) then + { + false + } + else + { + R3F_LOG_mutex_local_verrou = true; + true + } +}; + +private ["_transporteur", "_liste_a_charger", "_chargement", "_chargement_actuel", "_chargement_maxi", "_objets_charges", "_cout_chargement_objet"]; +private ["_objet_ou_classe", "_quantite", "_objet", "_classe", "_bbox", "_bbox_dim", "_pos_degagee", "_fonctionnalites", "_i"]; + +_transporteur = _this select 0; +_liste_a_charger = _this select 1; + +_chargement = [_transporteur] call R3F_LOG_FNCT_calculer_chargement_vehicule; +_chargement_actuel = _chargement select 0; +_chargement_maxi = _chargement select 1; +_objets_charges = _transporteur getVariable ["R3F_LOG_objets_charges", []]; + +// Pour chaque élément de la liste à charger +{ + if (typeName _x == "ARRAY" && {count _x > 0}) then + { + _objet_ou_classe = _x select 0; + + if (typeName _objet_ou_classe == "STRING" && count _x > 1) then + { + _quantite = _x select 1; + } + else + { + _quantite = 1; + }; + } + else + { + _objet_ou_classe = _x; + _quantite = 1; + }; + + if (typeName _objet_ou_classe == "STRING") then + { + _classe = _objet_ou_classe; + _bbox = [_classe] call R3F_LOG_FNCT_3D_get_bounding_box_depuis_classname; + _bbox_dim = (vectorMagnitude (_bbox select 0)) max (vectorMagnitude (_bbox select 1)); + + // Recherche d'une position dégagée. Les véhicules doivent être créé au niveau du sol sinon ils ne peuvent être utilisés. + if (_classe isKindOf "AllVehicles") then + { + _pos_degagee = [_bbox_dim, getPos _transporteur, 200, 50] call R3F_LOG_FNCT_3D_tirer_position_degagee_sol; + } + else + { + _pos_degagee = [] call R3F_LOG_FNCT_3D_tirer_position_degagee_ciel; + }; + + if (count _pos_degagee == 0) then {_pos_degagee = getPosATL _transporteur;}; + } + else + { + _classe = typeOf _objet_ou_classe; + }; + + _fonctionnalites = [_classe] call R3F_LOG_FNCT_determiner_fonctionnalites_logistique; + _cout_chargement_objet = _fonctionnalites select R3F_LOG_IDX_can_be_transported_cargo_cout; + + // S'assurer que le type d'objet à charger est transportable + if !(_fonctionnalites select R3F_LOG_IDX_can_be_transported_cargo) then + { + diag_log format ["[Auto-load ""%1"" in ""%2""] : %3", + getText (configFile >> "CfgVehicles" >> _classe >> "displayName"), + getText (configFile >> "CfgVehicles" >> (typeOf _transporteur) >> "displayName"), + "The object is not a transporable class."]; + + systemChat format ["[Auto-load ""%1"" in ""%2""] : %3", + getText (configFile >> "CfgVehicles" >> _classe >> "displayName"), + getText (configFile >> "CfgVehicles" >> (typeOf _transporteur) >> "displayName"), + "The object is not a transporable class."]; + } + else + { + for [{_i = 0}, {_i < _quantite}, {_i = _i+1}] do + { + // Si l'objet à charger est donné en tant que nom de classe, on le crée + if (typeName _objet_ou_classe == "STRING") then + { + // Recherche d'une position dégagée. Les véhicules doivent être créé au niveau du sol sinon ils ne peuvent être utilisés. + if (_classe isKindOf "AllVehicles") then + { + _objet = _classe createVehicle _pos_degagee; + _objet setVectorDirAndUp [[-cos getDir _transporteur, sin getDir _transporteur, 0] vectorCrossProduct surfaceNormal _pos_degagee, surfaceNormal _pos_degagee]; + _objet setVelocity [0, 0, 0]; + } + else + { + _objet = _classe createVehicle _pos_degagee; + }; + } + else + { + _objet = _objet_ou_classe; + }; + + if (!isNull _objet) then + { + // Vérifier qu'il n'est pas déjà transporté + if (isNull (_objet getVariable ["R3F_LOG_est_transporte_par", objNull]) && + (isNull (_objet getVariable ["R3F_LOG_est_deplace_par", objNull]) || (!alive (_objet getVariable ["R3F_LOG_est_deplace_par", objNull])) || (!isPlayer (_objet getVariable ["R3F_LOG_est_deplace_par", objNull]))) + ) then + { + if (isNull (_objet getVariable ["R3F_LOG_remorque", objNull])) then + { + // Si l'objet loge dans le véhicule + if (_chargement_actuel + _cout_chargement_objet <= _chargement_maxi) then + { + _chargement_actuel = _chargement_actuel + _cout_chargement_objet; + _objets_charges pushBack _objet; + + _objet setVariable ["R3F_LOG_est_transporte_par", _transporteur, true]; + _objet attachTo [R3F_LOG_PUBVAR_point_attache, [] call R3F_LOG_FNCT_3D_tirer_position_degagee_ciel]; + } + else + { + diag_log format ["[Auto-load ""%1"" in ""%2""] : %3", + getText (configFile >> "CfgVehicles" >> _classe >> "displayName"), + getText (configFile >> "CfgVehicles" >> (typeOf _transporteur) >> "displayName"), + STR_R3F_LOG_action_charger_pas_assez_de_place]; + + systemChat format ["[Auto-load ""%1"" in ""%2""] : %3", + getText (configFile >> "CfgVehicles" >> _classe >> "displayName"), + getText (configFile >> "CfgVehicles" >> (typeOf _transporteur) >> "displayName"), + STR_R3F_LOG_action_charger_pas_assez_de_place]; + + if (typeName _objet_ou_classe == "STRING") then + { + deleteVehicle _objet; + }; + }; + } + else + { + diag_log format [STR_R3F_LOG_objet_remorque_en_cours, getText (configFile >> "CfgVehicles" >> _classe >> "displayName")]; + systemChat format [STR_R3F_LOG_objet_remorque_en_cours, getText (configFile >> "CfgVehicles" >> _classe >> "displayName")]; + }; + } + else + { + diag_log format [STR_R3F_LOG_objet_en_cours_transport, getText (configFile >> "CfgVehicles" >> _classe >> "displayName")]; + systemChat format [STR_R3F_LOG_objet_en_cours_transport, getText (configFile >> "CfgVehicles" >> _classe >> "displayName")]; + }; + }; + }; + }; +} forEach _liste_a_charger; + +// On mémorise sur le réseau le nouveau contenu du véhicule +_transporteur setVariable ["R3F_LOG_objets_charges", _objets_charges, true]; + +R3F_LOG_mutex_local_verrou = false; \ No newline at end of file diff --git a/transporteur/charger_deplace.sqf b/transporteur/charger_deplace.sqf new file mode 100644 index 0000000..bd8fa7e --- /dev/null +++ b/transporteur/charger_deplace.sqf @@ -0,0 +1,71 @@ +/** + * Charger l'objet déplacé par le joueur dans un transporteur + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +if (R3F_LOG_mutex_local_verrou) then +{ + hintC STR_R3F_LOG_mutex_action_en_cours; +} +else +{ + R3F_LOG_mutex_local_verrou = true; + + private ["_objet", "_transporteur"]; + + _objet = R3F_LOG_joueur_deplace_objet; + _transporteur = [_objet, 5] call R3F_LOG_FNCT_3D_cursorTarget_virtuel; + + if (!isNull _transporteur && { + _transporteur getVariable ["R3F_LOG_fonctionnalites", R3F_LOG_CST_zero_log] select R3F_LOG_IDX_can_transport_cargo && + alive _transporteur && (vectorMagnitude velocity _transporteur < 6) && !(_transporteur getVariable "R3F_LOG_disabled") && + (abs ((getPosASL _transporteur select 2) - (getPosASL player select 2)) < 2.5) + }) then + { + if (isNull (_objet getVariable ["R3F_LOG_remorque", objNull])) then + { + private ["_objets_charges", "_chargement", "_cout_chargement_objet"]; + + _chargement = [_transporteur] call R3F_LOG_FNCT_calculer_chargement_vehicule; + _cout_chargement_objet = _objet getVariable "R3F_LOG_fonctionnalites" select R3F_LOG_IDX_can_be_transported_cargo_cout; + + // Si l'objet loge dans le véhicule + if ((_chargement select 0) + _cout_chargement_objet <= (_chargement select 1)) then + { + [_transporteur, player] call R3F_LOG_FNCT_definir_proprietaire_verrou; + + // On mémorise sur le réseau le nouveau contenu du véhicule + _objets_charges = _transporteur getVariable ["R3F_LOG_objets_charges", []]; + _objets_charges = _objets_charges + [_objet]; + _transporteur setVariable ["R3F_LOG_objets_charges", _objets_charges, true]; + + _objet setVariable ["R3F_LOG_est_transporte_par", _transporteur, true]; + + // Faire relacher l'objet au joueur + R3F_LOG_joueur_deplace_objet = objNull; + waitUntil {_objet getVariable "R3F_LOG_est_deplace_par" != player}; + + _objet attachTo [R3F_LOG_PUBVAR_point_attache, [] call R3F_LOG_FNCT_3D_tirer_position_degagee_ciel]; + + systemChat format [STR_R3F_LOG_action_charger_fait, + getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName"), + getText (configFile >> "CfgVehicles" >> (typeOf _transporteur) >> "displayName")]; + } + else + { + hintC STR_R3F_LOG_action_charger_pas_assez_de_place; + }; + } + else + { + hintC format [STR_R3F_LOG_objet_remorque_en_cours, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + }; + + R3F_LOG_mutex_local_verrou = false; +}; \ No newline at end of file diff --git a/transporteur/charger_selection.sqf b/transporteur/charger_selection.sqf new file mode 100644 index 0000000..8d289f1 --- /dev/null +++ b/transporteur/charger_selection.sqf @@ -0,0 +1,101 @@ +/** + * Charger l'objet sélectionné (R3F_LOG_objet_selectionne) dans un transporteur + * + * @param 0 le transporteur + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +if (R3F_LOG_mutex_local_verrou) then +{ + hintC STR_R3F_LOG_mutex_action_en_cours; +} +else +{ + R3F_LOG_mutex_local_verrou = true; + + private ["_objet", "_transporteur"]; + + _objet = R3F_LOG_objet_selectionne; + _transporteur = _this select 0; + + if (!(isNull _objet) && !(_objet getVariable "R3F_LOG_disabled")) then + { + if (isNull (_objet getVariable "R3F_LOG_est_transporte_par") && (isNull (_objet getVariable "R3F_LOG_est_deplace_par") || (!alive (_objet getVariable "R3F_LOG_est_deplace_par")) || (!isPlayer (_objet getVariable "R3F_LOG_est_deplace_par")))) then + { + if (isNull (_objet getVariable ["R3F_LOG_remorque", objNull])) then + { + if (count crew _objet == 0 || getNumber (configFile >> "CfgVehicles" >> (typeOf _objet) >> "isUav") == 1) then + { + private ["_objets_charges", "_chargement", "_cout_chargement_objet"]; + + _chargement = [_transporteur] call R3F_LOG_FNCT_calculer_chargement_vehicule; + _cout_chargement_objet = _objet getVariable "R3F_LOG_fonctionnalites" select R3F_LOG_IDX_can_be_transported_cargo_cout; + + // Si l'objet loge dans le véhicule + if ((_chargement select 0) + _cout_chargement_objet <= (_chargement select 1)) then + { + if (_objet distance _transporteur <= 30) then + { + [_transporteur, player] call R3F_LOG_FNCT_definir_proprietaire_verrou; + + // On mémorise sur le réseau le nouveau contenu du véhicule + _objets_charges = _transporteur getVariable ["R3F_LOG_objets_charges", []]; + _objets_charges = _objets_charges + [_objet]; + _transporteur setVariable ["R3F_LOG_objets_charges", _objets_charges, true]; + + _objet setVariable ["R3F_LOG_est_transporte_par", _transporteur, true]; + + systemChat STR_R3F_LOG_action_charger_en_cours; + + sleep 2; + + // Gestion conflit d'accès + if (_objet getVariable "R3F_LOG_est_transporte_par" == _transporteur && _objet in (_transporteur getVariable "R3F_LOG_objets_charges")) then + { + _objet attachTo [R3F_LOG_PUBVAR_point_attache, [] call R3F_LOG_FNCT_3D_tirer_position_degagee_ciel]; + + systemChat format [STR_R3F_LOG_action_charger_fait, + getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName"), + getText (configFile >> "CfgVehicles" >> (typeOf _transporteur) >> "displayName")]; + } + else + { + _objet setVariable ["R3F_LOG_est_transporte_par", objNull, true]; + hintC format ["ERROR : " + STR_R3F_LOG_objet_en_cours_transport, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + } + else + { + hintC format [STR_R3F_LOG_trop_loin, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + } + else + { + hintC STR_R3F_LOG_action_charger_pas_assez_de_place; + }; + } + else + { + hintC format [STR_R3F_LOG_joueur_dans_objet, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + } + else + { + hintC format [STR_R3F_LOG_objet_remorque_en_cours, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + } + else + { + hintC format [STR_R3F_LOG_objet_en_cours_transport, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + }; + + R3F_LOG_objet_selectionne = objNull; + + R3F_LOG_mutex_local_verrou = false; +}; \ No newline at end of file diff --git a/transporteur/decharger.sqf b/transporteur/decharger.sqf new file mode 100644 index 0000000..017df4a --- /dev/null +++ b/transporteur/decharger.sqf @@ -0,0 +1,142 @@ +/** + * Décharger un objet d'un transporteur - appelé deuis l'interface listant le contenu du transporteur + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +if (R3F_LOG_mutex_local_verrou) then +{ + hintC STR_R3F_LOG_mutex_action_en_cours; +} +else +{ + R3F_LOG_mutex_local_verrou = true; + + #include "dlg_constantes.h" + private ["_transporteur", "_objets_charges", "_type_objet_a_decharger", "_objet_a_decharger", "_action_confirmee", "_est_deplacable"]; + + _transporteur = uiNamespace getVariable "R3F_LOG_dlg_CV_transporteur"; + _objets_charges = _transporteur getVariable ["R3F_LOG_objets_charges", []]; + + if (lbCurSel R3F_LOG_IDC_dlg_CV_liste_contenu == -1) exitWith {R3F_LOG_mutex_local_verrou = false;}; + + _type_objet_a_decharger = lbData [R3F_LOG_IDC_dlg_CV_liste_contenu, lbCurSel R3F_LOG_IDC_dlg_CV_liste_contenu]; + + _est_deplacable = ([_type_objet_a_decharger] call R3F_LOG_FNCT_determiner_fonctionnalites_logistique) select R3F_LOG_IDX_can_be_moved_by_player; + + if (!(_type_objet_a_decharger isKindOf "AllVehicles") && !_est_deplacable) then + { + _action_confirmee = [STR_R3F_LOG_action_decharger_deplacable_exceptionnel, "Warning", true, true] call BIS_fnc_GUImessage; + } + else + { + _action_confirmee = true; + }; + + if (_action_confirmee) then + { + closeDialog 0; + + // Recherche d'un objet du type demandé + _objet_a_decharger = objNull; + { + if (typeOf _x == _type_objet_a_decharger) exitWith + { + _objet_a_decharger = _x; + }; + } forEach _objets_charges; + + if !(isNull _objet_a_decharger) then + { + [_objet_a_decharger, player] call R3F_LOG_FNCT_definir_proprietaire_verrou; + + // On mémorise sur le réseau le nouveau contenu du transporteur (càd avec cet objet en moins) + _objets_charges = _transporteur getVariable ["R3F_LOG_objets_charges", []]; + _objets_charges = _objets_charges - [_objet_a_decharger]; + _transporteur setVariable ["R3F_LOG_objets_charges", _objets_charges, true]; + + _objet_a_decharger setVariable ["R3F_LOG_est_transporte_par", objNull, true]; + + // Prise en compte de l'objet dans l'environnement du joueur (accélérer le retour des addActions) + _objet_a_decharger spawn + { + sleep 4; + R3F_LOG_PUBVAR_reveler_au_joueur = _this; + publicVariable "R3F_LOG_PUBVAR_reveler_au_joueur"; + ["R3F_LOG_PUBVAR_reveler_au_joueur", R3F_LOG_PUBVAR_reveler_au_joueur] spawn R3F_LOG_FNCT_PUBVAR_reveler_au_joueur; + }; + + if (!(_objet_a_decharger isKindOf "AllVehicles") || _est_deplacable) then + { + R3F_LOG_mutex_local_verrou = false; + [_objet_a_decharger, player, 0, true] spawn R3F_LOG_FNCT_objet_deplacer; + } + else + { + private ["_bbox_dim", "_pos_degagee", "_rayon"]; + + systemChat STR_R3F_LOG_action_decharger_en_cours; + + _bbox_dim = (vectorMagnitude (boundingBoxReal _objet_a_decharger select 0)) max (vectorMagnitude (boundingBoxReal _objet_a_decharger select 1)); + + sleep 1; + + // Recherche d'une position dégagée (on augmente progressivement le rayon jusqu'à trouver une position) + for [{_rayon = 5 max (2*_bbox_dim); _pos_degagee = [];}, {count _pos_degagee == 0 && _rayon <= 30 + (8*_bbox_dim)}, {_rayon = _rayon + 10 + (2*_bbox_dim)}] do + { + _pos_degagee = [ + _bbox_dim, + _transporteur modelToWorld [0, if (_transporteur isKindOf "AllVehicles") then {(boundingBoxReal _transporteur select 0 select 1) - 2 - 0.3*_rayon} else {0}, 0], + _rayon, + 100 min (5 + _rayon^1.2) + ] call R3F_LOG_FNCT_3D_tirer_position_degagee_sol; + }; + + if (count _pos_degagee > 0) then + { + detach _objet_a_decharger; + _objet_a_decharger setPos _pos_degagee; + _objet_a_decharger setVectorDirAndUp [[-cos getDir _transporteur, sin getDir _transporteur, 0] vectorCrossProduct surfaceNormal _pos_degagee, surfaceNormal _pos_degagee]; + _objet_a_decharger setVelocity [0, 0, 0]; + + sleep 0.4; // Car la nouvelle position n'est pas prise en compte instantannément + + // Si l'objet a été créé assez loin, on indique sa position relative + if (_objet_a_decharger distance _transporteur > 40) then + { + systemChat format [STR_R3F_LOG_action_decharger_fait + " (%2)", + getText (configFile >> "CfgVehicles" >> (typeOf _objet_a_decharger) >> "displayName"), + format ["%1m %2deg", round (_objet_a_decharger distance _transporteur), round ([_transporteur, _objet_a_decharger] call BIS_fnc_dirTo)] + ]; + } + else + { + systemChat format [STR_R3F_LOG_action_decharger_fait, getText (configFile >> "CfgVehicles" >> (typeOf _objet_a_decharger) >> "displayName")]; + }; + R3F_LOG_mutex_local_verrou = false; + } + // Si échec recherche position dégagée, on décharge l'objet comme un déplaçable + else + { + systemChat "WARNING : no free position found."; + + R3F_LOG_mutex_local_verrou = false; + [_objet_a_decharger, player, 0, true] spawn R3F_LOG_FNCT_objet_deplacer; + }; + }; + } + else + { + hintC STR_R3F_LOG_action_decharger_deja_fait; + R3F_LOG_mutex_local_verrou = false; + }; + } + else + { + R3F_LOG_mutex_local_verrou = false; + }; +}; \ No newline at end of file diff --git a/transporteur/dlg_constantes.h b/transporteur/dlg_constantes.h new file mode 100644 index 0000000..6e84898 --- /dev/null +++ b/transporteur/dlg_constantes.h @@ -0,0 +1,94 @@ +/** + * Constantes pour rendre les définitions des boîtes de dialogue plus lisible et maintenable + */ + +#define R3F_LOG_ID_transporteur_START 65430 + +#define R3F_LOG_IDD_dlg_contenu_vehicule (R3F_LOG_ID_transporteur_START + 1) + +#define R3F_LOG_IDC_dlg_CV_capacite_vehicule (R3F_LOG_ID_transporteur_START + 2) +#define R3F_LOG_IDC_dlg_CV_liste_contenu (R3F_LOG_ID_transporteur_START + 3) +#define R3F_LOG_IDC_dlg_CV_btn_decharger (R3F_LOG_ID_transporteur_START + 4) + +#define R3F_LOG_IDC_dlg_CV_titre (R3F_LOG_ID_transporteur_START + 10) +#define R3F_LOG_IDC_dlg_CV_credits (R3F_LOG_ID_transporteur_START + 11) +#define R3F_LOG_IDC_dlg_CV_btn_fermer (R3F_LOG_ID_transporteur_START + 12) + +#define R3F_LOG_IDC_dlg_CV_jauge_chargement (R3F_LOG_ID_transporteur_START + 13) + +// Control types +#define CT_STATIC 0 +#define CT_BUTTON 1 +#define CT_EDIT 2 +#define CT_SLIDER 3 +#define CT_COMBO 4 +#define CT_LISTBOX 5 +#define CT_TOOLBOX 6 +#define CT_CHECKBOXES 7 +#define CT_PROGRESS 8 +#define CT_HTML 9 +#define CT_STATIC_SKEW 10 +#define CT_ACTIVETEXT 11 +#define CT_TREE 12 +#define CT_STRUCTURED_TEXT 13 +#define CT_CONTEXT_MENU 14 +#define CT_CONTROLS_GROUP 15 +#define CT_SHORTCUT_BUTTON 16 // Arma 2 - textured button + +#define CT_XKEYDESC 40 +#define CT_XBUTTON 41 +#define CT_XLISTBOX 42 +#define CT_XSLIDER 43 +#define CT_XCOMBO 44 +#define CT_ANIMATED_TEXTURE 45 +#define CT_OBJECT 80 +#define CT_OBJECT_ZOOM 81 +#define CT_OBJECT_CONTAINER 82 +#define CT_OBJECT_CONT_ANIM 83 +#define CT_LINEBREAK 98 +#define CT_USER 99 +#define CT_MAP 100 +#define CT_MAP_MAIN 101 +#define CT_List_N_Box 102 // Arma 2 - N columns list box + +// Static styles +#define ST_POS 0x0F +#define ST_HPOS 0x03 +#define ST_VPOS 0x0C +#define ST_LEFT 0x00 +#define ST_RIGHT 0x01 +#define ST_CENTER 0x02 +#define ST_DOWN 0x04 +#define ST_UP 0x08 +#define ST_VCENTER 0x0c + +#define ST_TYPE 0xF0 +#define ST_SINGLE 0 +#define ST_MULTI 16 +#define ST_TITLE_BAR 32 +#define ST_PICTURE 48 +#define ST_FRAME 64 +#define ST_BACKGROUND 80 +#define ST_GROUP_BOX 96 +#define ST_GROUP_BOX2 112 +#define ST_HUD_BACKGROUND 128 +#define ST_TILE_PICTURE 144 +#define ST_WITH_RECT 160 +#define ST_LINE 176 + +#define ST_SHADOW 0x100 +#define ST_NO_RECT 0x200 +#define ST_KEEP_ASPECT_RATIO 0x800 + +#define ST_TITLE ST_TITLE_BAR + ST_CENTER + +// Slider styles +#define SL_DIR 0x400 +#define SL_VERT 0 +#define SL_HORZ 0x400 + +#define SL_TEXTURES 0x10 + +// Listbox styles +#define LB_TEXTURES 0x10 +#define LB_MULTI 0x20 \ No newline at end of file diff --git a/transporteur/dlg_contenu_vehicule.h b/transporteur/dlg_contenu_vehicule.h new file mode 100644 index 0000000..9dbd413 --- /dev/null +++ b/transporteur/dlg_contenu_vehicule.h @@ -0,0 +1,265 @@ +/** + * Interface d'affichage du contenu du véhicule + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dlg_constantes.h" + +#define R3F_LOG_dlg_CV_jauge_chargement_h 0.027 + +class R3F_LOG_dlg_contenu_vehicule +{ + idd = R3F_LOG_IDD_dlg_contenu_vehicule; + name = "R3F_LOG_dlg_contenu_vehicule"; + movingEnable = false; + + controlsBackground[] = + { + R3F_LOG_dlg_CV_titre_fond, + R3F_LOG_dlg_CV_fond_noir + }; + objects[] = {}; + controls[] = + { + R3F_LOG_dlg_CV_titre, + R3F_LOG_dlg_CV_capacite_vehicule, + R3F_LOG_dlg_CV_jauge_chargement, + R3F_LOG_dlg_CV_liste_contenu, + + R3F_LOG_dlg_CV_credits, + R3F_LOG_dlg_CV_btn_decharger, + R3F_LOG_dlg_CV_btn_fermer + }; + + // Définition des classes de base + class R3F_LOG_dlg_CV_texte + { + idc = -1; + type = CT_STATIC; + style = ST_LEFT; + x = 0.0; w = 0.3; + y = 0.0; h = 0.03; + sizeEx = 0.023; + colorBackground[] = {0,0,0,0}; + colorText[] = {1,1,1,1}; + font = "PuristaMedium"; + text = ""; + }; + + class R3F_LOG_dlg_CV_btn + { + idc = -1; + type = 16; + style = 0; + + text = "btn"; + action = ""; + + x = 0; w = 0.17; + y = 0; h = 0.045; + + font = "PuristaLight"; + size = 0.038; + sizeEx = 0.038; + + animTextureNormal = "#(argb,8,8,3)color(1,1,1,1)"; + animTextureDisabled = "#(argb,8,8,3)color(1,1,1,1)"; + animTextureOver = "#(argb,8,8,3)color(1,1,1,0.5)"; + animTextureFocused = "#(argb,8,8,3)color(1,1,1,1)"; + animTexturePressed = "#(argb,8,8,3)color(1,1,1,1)"; + animTextureDefault = "#(argb,8,8,3)color(1,1,1,1)"; + textureNoShortcut = "#(argb,8,8,3)color(0,0,0,0)"; + colorBackground[] = {0,0,0,0.8}; + colorBackground2[] = {1,1,1,0.5}; + colorBackgroundFocused[] = {1,1,1,0.5}; + color[] = {1,1,1,1}; + color2[] = {1,1,1,1}; + colorText[] = {1,1,1,1}; + colorFocused[] = {1,1,1,1}; + colorDisabled[] = {1,1,1,0.25}; + period = 0.6; + periodFocus = 0.6; + periodOver = 0.6; + shadow = 0; + + class HitZone + { + left = 0.000; + top = 0.000; + right = 0.000; + bottom = 0.000; + }; + + class ShortcutPos + { + left = 0.000; + top = 0.000; + w = 0.023; + h = 0.050; + }; + + class TextPos + { + left = 0.010; + top = 0.000; + right = 0.000; + bottom = 0.000; + }; + + soundEnter[] = {"\A3\ui_f\data\sound\RscButtonMenu\soundEnter",0.09,1}; + soundPush[] = {"\A3\ui_f\data\sound\RscButtonMenu\soundPush",0.09,1}; + soundClick[] = {"\A3\ui_f\data\sound\RscButtonMenu\soundClick",0.09,1}; + soundEscape[] = {"\A3\ui_f\data\sound\RscButtonMenu\soundEscape",0.09,1}; + + class Attributes + { + font = "PuristaLight"; + color = "#E5E5E5"; + align = "left"; + shadow = "false"; + }; + + class AttributesImage + { + font = "PuristaLight"; + color = "#E5E5E5"; + align = "left"; + }; + }; + + class R3F_LOG_dlg_CV_liste + { + type = CT_LISTBOX; + style = ST_MULTI; + idc = -1; + text = ""; + w = 0.275; + h = 0.04; + wholeHeight = 0.45; + rowHeight = 0.06; + font = "PuristaSemibold"; + sizeEx = 0.035; + soundSelect[] = {"",0.1,1}; + soundExpand[] = {"",0.1,1}; + soundCollapse[] = {"",0.1,1}; + maxHistoryDelay = 1; + autoScrollSpeed = -1; + autoScrollDelay = 5; + autoScrollRewind = 0; + + shadow = 0; + colorShadow[] = {0,0,0,0.5}; + color[] = {1,1,1,1}; + colorText[] = {1,1,1,1.0}; + colorDisabled[] = {1,1,1,0.25}; + colorScrollbar[] = {1,0,0,0}; + colorSelect[] = {0,0,0,1}; + colorSelect2[] = {0,0,0,1}; + colorSelectBackground[] = {0.95,0.95,0.95,1}; + colorSelectBackground2[] = {1,1,1,0.5}; + colorBackground[] = {0,0,0,0}; + period = 1.2; + + class ListScrollBar + { + color[] = {1,1,1,0.6}; + colorActive[] = {1,1,1,1}; + colorDisabled[] = {1,1,1,0.3}; + thumb = "\A3\ui_f\data\gui\cfg\scrollbar\thumb_ca.paa"; + arrowFull = "\A3\ui_f\data\gui\cfg\scrollbar\arrowFull_ca.paa"; + arrowEmpty = "\A3\ui_f\data\gui\cfg\scrollbar\arrowEmpty_ca.paa"; + border = "\A3\ui_f\data\gui\cfg\scrollbar\border_ca.paa"; + }; + }; + // FIN Définition des classes de base + + + class R3F_LOG_dlg_CV_titre_fond : R3F_LOG_dlg_CV_texte + { + x = 0.26; w = 0.45; + y = 0.145 - R3F_LOG_dlg_CV_jauge_chargement_h-0.005; h = 0.07; + colorBackground[] = {"(profilenamespace getvariable ['GUI_BCG_RGB_R',0.69])","(profilenamespace getvariable ['GUI_BCG_RGB_G',0.75])","(profilenamespace getvariable ['GUI_BCG_RGB_B',0.5])","(profilenamespace getvariable ['GUI_BCG_RGB_A',0.8])"}; + }; + + class R3F_LOG_dlg_CV_titre : R3F_LOG_dlg_CV_texte + { + idc = R3F_LOG_IDC_dlg_CV_titre; + x = 0.26; w = 0.45; + y = 0.145 - R3F_LOG_dlg_CV_jauge_chargement_h-0.005; h = 0.04; + sizeEx = 0.05; + text = ""; + }; + + class R3F_LOG_dlg_CV_capacite_vehicule : R3F_LOG_dlg_CV_texte + { + idc = R3F_LOG_IDC_dlg_CV_capacite_vehicule; + x = 0.255; w = 0.4; + y = 0.185 - R3F_LOG_dlg_CV_jauge_chargement_h-0.005; h = 0.03; + sizeEx = 0.03; + text = ""; + }; + + class R3F_LOG_dlg_CV_fond_noir : R3F_LOG_dlg_CV_texte + { + x = 0.26; w = 0.45; + y = 0.220 - R3F_LOG_dlg_CV_jauge_chargement_h-0.005; h = R3F_LOG_dlg_CV_jauge_chargement_h + 0.010 + 0.54 - 0.005; + colorBackground[] = {0,0,0,0.5}; + }; + + class R3F_LOG_dlg_CV_jauge_chargement + { + idc = R3F_LOG_IDC_dlg_CV_jauge_chargement; + type = CT_PROGRESS; + style = ST_LEFT; + x = 0.26 + 0.0035; w = 0.45 - 0.007; + y = 0.220 - R3F_LOG_dlg_CV_jauge_chargement_h-0.005 + 0.0035; h = R3F_LOG_dlg_CV_jauge_chargement_h; + shadow = 2; + colorBar[] = {0.9,0.9,0.9,0.9}; + colorExtBar[] = {1,1,1,1}; + colorFrame[] = {1,1,1,1}; + texture = ""; + textureExt = ""; + }; + + class R3F_LOG_dlg_CV_liste_contenu : R3F_LOG_dlg_CV_liste + { + idc = R3F_LOG_IDC_dlg_CV_liste_contenu; + x = 0.26; w = 0.45; + y = 0.22 + 0.005; h = 0.54 - 0.005; + onLBDblClick = "0 spawn R3F_LOG_FNCT_transporteur_decharger;"; + onLBSelChanged = "uiNamespace setVariable [""R3F_LOG_dlg_CV_lbCurSel_data"", (_this select 0) lbData (_this select 1)];"; + }; + + class R3F_LOG_dlg_CV_credits : R3F_LOG_dlg_CV_texte + { + idc = R3F_LOG_IDC_dlg_CV_credits; + x = 0.255; w = 0.19; + y = 0.813; h = 0.02; + colorText[] = {0.5,0.5,0.5,0.75}; + font = "PuristaLight"; + sizeEx = 0.02; + text = ""; + }; + + class R3F_LOG_dlg_CV_btn_decharger : R3F_LOG_dlg_CV_btn + { + idc = R3F_LOG_IDC_dlg_CV_btn_decharger; + x = 0.365; y = 0.765; + sizeEx = 0.02; + text = ""; + action = "0 spawn R3F_LOG_FNCT_transporteur_decharger;"; + }; + + class R3F_LOG_dlg_CV_btn_fermer : R3F_LOG_dlg_CV_btn + { + idc = R3F_LOG_IDC_dlg_CV_btn_fermer; + x = 0.54; y = 0.765; + text = ""; + action = "closeDialog 0;"; + }; +}; \ No newline at end of file diff --git a/transporteur/selectionner_objet.sqf b/transporteur/selectionner_objet.sqf new file mode 100644 index 0000000..78257c2 --- /dev/null +++ b/transporteur/selectionner_objet.sqf @@ -0,0 +1,42 @@ +/** + * Sélectionne un objet à charger dans un transporteur + * + * @param 0 l'objet à sélectionner + */ + +if (R3F_LOG_mutex_local_verrou) then +{ + hintC STR_R3F_LOG_mutex_action_en_cours; +} +else +{ + R3F_LOG_mutex_local_verrou = true; + + R3F_LOG_objet_selectionne = _this select 0; + systemChat format [STR_R3F_LOG_action_selectionner_objet_fait, getText (configFile >> "CfgVehicles" >> (typeOf R3F_LOG_objet_selectionne) >> "displayName")]; + + [R3F_LOG_objet_selectionne, player] call R3F_LOG_FNCT_definir_proprietaire_verrou; + + // Déselectionner l'objet si le joueur n'en fait rien + [] spawn + { + while {!isNull R3F_LOG_objet_selectionne} do + { + if (!alive player) then + { + R3F_LOG_objet_selectionne = objNull; + } + else + { + if (vehicle player != player || (player distance R3F_LOG_objet_selectionne > 40) || !isNull R3F_LOG_joueur_deplace_objet) then + { + R3F_LOG_objet_selectionne = objNull; + }; + }; + + sleep 0.2; + }; + }; + + R3F_LOG_mutex_local_verrou = false; +}; \ No newline at end of file diff --git a/transporteur/transporteur_init.sqf b/transporteur/transporteur_init.sqf new file mode 100644 index 0000000..cebde74 --- /dev/null +++ b/transporteur/transporteur_init.sqf @@ -0,0 +1,21 @@ +/** + * Initialise un véhicule transporteur + * + * @param 0 le transporteur + */ + +private ["_transporteur"]; + +_transporteur = _this select 0; + +// Définition locale de la variable si elle n'est pas définie sur le réseau +if (isNil {_transporteur getVariable "R3F_LOG_objets_charges"}) then +{ + _transporteur setVariable ["R3F_LOG_objets_charges", [], false]; +}; + +_transporteur addAction [("" + STR_R3F_LOG_action_charger_deplace + ""), {_this call R3F_LOG_FNCT_transporteur_charger_deplace}, nil, 8, true, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_joueur_deplace_objet != _target && R3F_LOG_action_charger_deplace_valide"]; + +_transporteur addAction [("" + format [STR_R3F_LOG_action_charger_selection, getText (configFile >> "CfgVehicles" >> (typeOf _transporteur) >> "displayName")] + ""), {_this call R3F_LOG_FNCT_transporteur_charger_selection}, nil, 7, true, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_action_charger_selection_valide"]; + +_transporteur addAction [("" + STR_R3F_LOG_action_contenu_vehicule + ""), {_this call R3F_LOG_FNCT_transporteur_voir_contenu_vehicule}, nil, 4, false, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_action_contenu_vehicule_valide"]; \ No newline at end of file diff --git a/transporteur/voir_contenu_vehicule.sqf b/transporteur/voir_contenu_vehicule.sqf new file mode 100644 index 0000000..08fcf86 --- /dev/null +++ b/transporteur/voir_contenu_vehicule.sqf @@ -0,0 +1,155 @@ +/** + * Ouvre la boîte de dialogue du contenu du véhicule et la prérempli en fonction de véhicule + * + * @param 0 le véhicule dont il faut afficher le contenu + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dlg_constantes.h" + +disableSerialization; // A cause des displayCtrl + +private ["_transporteur", "_chargement", "_chargement_precedent", "_contenu"]; +private ["_tab_objets", "_tab_quantite", "_i", "_dlg_contenu_vehicule", "_ctrl_liste"]; + +R3F_LOG_objet_selectionne = objNull; + +_transporteur = _this select 0; +uiNamespace setVariable ["R3F_LOG_dlg_CV_transporteur", _transporteur]; + +[_transporteur, player] call R3F_LOG_FNCT_definir_proprietaire_verrou; + +createDialog "R3F_LOG_dlg_contenu_vehicule"; +waitUntil (uiNamespace getVariable "R3F_LOG_dlg_contenu_vehicule"); +_dlg_contenu_vehicule = findDisplay R3F_LOG_IDD_dlg_contenu_vehicule; + +/**** DEBUT des traductions des labels ****/ +(_dlg_contenu_vehicule displayCtrl R3F_LOG_IDC_dlg_CV_titre) ctrlSetText STR_R3F_LOG_dlg_CV_titre; +(_dlg_contenu_vehicule displayCtrl R3F_LOG_IDC_dlg_CV_credits) ctrlSetText "[R3F] Logistics"; +(_dlg_contenu_vehicule displayCtrl R3F_LOG_IDC_dlg_CV_btn_decharger) ctrlSetText STR_R3F_LOG_dlg_CV_btn_decharger; +(_dlg_contenu_vehicule displayCtrl R3F_LOG_IDC_dlg_CV_btn_fermer) ctrlSetText STR_R3F_LOG_dlg_CV_btn_fermer; +/**** FIN des traductions des labels ****/ + +_ctrl_liste = _dlg_contenu_vehicule displayCtrl R3F_LOG_IDC_dlg_CV_liste_contenu; + +_chargement_precedent = []; + +while {!isNull _dlg_contenu_vehicule} do +{ + _chargement = [_transporteur] call R3F_LOG_FNCT_calculer_chargement_vehicule; + + // Si le contenu a changé, on rafraichit l'interface + if !([_chargement, _chargement_precedent] call BIS_fnc_areEqual) then + { + _chargement_precedent = +_chargement; + + _contenu = _transporteur getVariable ["R3F_LOG_objets_charges", []]; + + /** Liste des noms de classe des objets contenu dans le véhicule, sans doublon */ + _tab_objets = []; + /** Quantité associé (par l'index) aux noms de classe dans _tab_objets */ + _tab_quantite = []; + /** Coût de chargement associé (par l'index) aux noms de classe dans _tab_objets */ + _tab_cout_chargement = []; + + // Préparation de la liste du contenu et des quantités associées aux objets + for [{_i = 0}, {_i < count _contenu}, {_i = _i + 1}] do + { + private ["_objet"]; + _objet = _contenu select _i; + + if !((typeOf _objet) in _tab_objets) then + { + _tab_objets pushBack (typeOf _objet); + _tab_quantite pushBack 1; + if (!isNil {_objet getVariable "R3F_LOG_fonctionnalites"}) then + { + _tab_cout_chargement pushBack (_objet getVariable "R3F_LOG_fonctionnalites" select R3F_LOG_IDX_can_be_transported_cargo_cout); + } + else + { + _tab_cout_chargement pushBack (([typeOf _objet] call R3F_LOG_FNCT_determiner_fonctionnalites_logistique) select R3F_LOG_IDX_can_be_transported_cargo_cout); + }; + } + else + { + private ["_idx_objet"]; + _idx_objet = _tab_objets find (typeOf _objet); + _tab_quantite set [_idx_objet, ((_tab_quantite select _idx_objet) + 1)]; + }; + }; + + lbClear _ctrl_liste; + (_dlg_contenu_vehicule displayCtrl R3F_LOG_IDC_dlg_CV_capacite_vehicule) ctrlSetText (format [STR_R3F_LOG_dlg_CV_capacite_vehicule+" pl.", _chargement select 0, _chargement select 1]); + if (_chargement select 1 != 0) then {(_dlg_contenu_vehicule displayCtrl R3F_LOG_IDC_dlg_CV_jauge_chargement) progressSetPosition ((_chargement select 0) / (_chargement select 1));}; + (_dlg_contenu_vehicule displayCtrl R3F_LOG_IDC_dlg_CV_jauge_chargement) ctrlShow ((_chargement select 0) != 0); + + if (count _tab_objets == 0) then + { + (_dlg_contenu_vehicule displayCtrl R3F_LOG_IDC_dlg_CV_btn_decharger) ctrlEnable false; + } + else + { + // Insertion de chaque type d'objets dans la liste + for [{_i = 0}, {_i < count _tab_objets}, {_i = _i + 1}] do + { + private ["_classe", "_quantite", "_icone", "_tab_icone", "_index"]; + + _classe = _tab_objets select _i; + _quantite = _tab_quantite select _i; + _cout_chargement = _tab_cout_chargement select _i; + _icone = getText (configFile >> "CfgVehicles" >> _classe >> "icon"); + + // Icône par défaut + if (_icone == "") then + { + _icone = "\A3\ui_f\data\map\VehicleIcons\iconObject_ca.paa"; + }; + + // Si le chemin commence par A3\ ou a3\, on rajoute un \ au début + _tab_icone = toArray toLower _icone; + if (count _tab_icone >= 3 && + { + _tab_icone select 0 == (toArray "a" select 0) && + _tab_icone select 1 == (toArray "3" select 0) && + _tab_icone select 2 == (toArray "\" select 0) + }) then + { + _icone = "\" + _icone; + }; + + // Si icône par défaut, on rajoute le chemin de base par défaut + _tab_icone = toArray _icone; + if (_tab_icone select 0 != (toArray "\" select 0)) then + { + _icone = format ["\A3\ui_f\data\map\VehicleIcons\%1_ca.paa", _icone]; + }; + + // Si pas d'extension de fichier, on rajoute ".paa" + _tab_icone = toArray _icone; + if (count _tab_icone >= 4 && {_tab_icone select (count _tab_icone - 4) != (toArray "." select 0)}) then + { + _icone = _icone + ".paa"; + }; + + _index = _ctrl_liste lbAdd (getText (configFile >> "CfgVehicles" >> _classe >> "displayName") + format [" (%1x %2pl.)", _quantite, _cout_chargement]); + _ctrl_liste lbSetPicture [_index, _icone]; + _ctrl_liste lbSetData [_index, _classe]; + + if (uiNamespace getVariable ["R3F_LOG_dlg_CV_lbCurSel_data", ""] == _classe) then + { + _ctrl_liste lbSetCurSel _index; + }; + }; + + (_dlg_contenu_vehicule displayCtrl R3F_LOG_IDC_dlg_CV_btn_decharger) ctrlEnable true; + }; + }; + + sleep 0.15; +}; \ No newline at end of file diff --git a/usine_creation/creer_objet.sqf b/usine_creation/creer_objet.sqf new file mode 100644 index 0000000..9ac4a83 --- /dev/null +++ b/usine_creation/creer_objet.sqf @@ -0,0 +1,171 @@ +/** + * Créer un objet - appelé deuis l'interface de l'usine de création + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +if (R3F_LOG_mutex_local_verrou) then +{ + hintC STR_R3F_LOG_mutex_action_en_cours; +} +else +{ + R3F_LOG_mutex_local_verrou = true; + + disableSerialization; // A cause des displayCtrl + + #include "dlg_constantes.h" + private ["_usine", "_classe", "_cout", "_objet", "_pos_degagee", "_action_confirmee", "_est_deplacable"]; + + _usine = uiNamespace getVariable "R3F_LOG_dlg_LO_usine"; + + if (lbCurSel R3F_LOG_IDC_dlg_LO_liste_objets == -1) exitWith {R3F_LOG_mutex_local_verrou = false;}; + _classe = lbData [R3F_LOG_IDC_dlg_LO_liste_objets, lbCurSel R3F_LOG_IDC_dlg_LO_liste_objets]; + + if (_classe != "") then + { + _cout = [_classe] call R3F_LOG_FNCT_determiner_cout_creation; + _est_deplacable = ([_classe] call R3F_LOG_FNCT_determiner_fonctionnalites_logistique) select R3F_LOG_IDX_can_be_moved_by_player; + + // L'usine a-t-elle assez de crédits ? + if (_usine getVariable "R3F_LOG_CF_credits" == -1 || _usine getVariable "R3F_LOG_CF_credits" >= _cout) then + { + // Recherche d'une position dégagée. Les véhicules doivent être créé au niveau du sol sinon ils ne peuvent être utilisés. + if (_classe isKindOf "AllVehicles") then + { + private ["_rayon", "_bbox", "_bbox_dim"]; + + systemChat STR_R3F_LOG_action_creer_en_cours; + sleep 0.5; + + _bbox = [_classe] call R3F_LOG_FNCT_3D_get_bounding_box_depuis_classname; + _bbox_dim = (vectorMagnitude (_bbox select 0)) max (vectorMagnitude (_bbox select 1)); + + // Recherche d'une position dégagée (on augmente progressivement le rayon jusqu'à trouver une position) + for [{_rayon = 5 max (2*_bbox_dim); _pos_degagee = [];}, {count _pos_degagee == 0 && _rayon <= 30 + (8*_bbox_dim)}, {_rayon = _rayon + 10 + (2*_bbox_dim)}] do + { + _pos_degagee = [ + _bbox_dim, + _usine modelToWorld [0, if (_usine isKindOf "AllVehicles") then {(boundingBoxReal _usine select 0 select 1) - 2 - 0.3*_rayon} else {0}, 0], + _rayon, + 100 min (5 + _rayon^1.2) + ] call R3F_LOG_FNCT_3D_tirer_position_degagee_sol; + }; + } + else + { + _pos_degagee = [] call R3F_LOG_FNCT_3D_tirer_position_degagee_ciel; + }; + + if (count _pos_degagee > 0) then + { + // Si l'objet n'est ni un véhicule, ni déplaçable manuellement, on demande confirmation de création + if (!(_classe isKindOf "AllVehicles") && !_est_deplacable) then + { + _action_confirmee = [STR_R3F_LOG_action_decharger_deplacable_exceptionnel, "Warning", true, true] call BIS_fnc_GUImessage; + } + else + { + _action_confirmee = true; + }; + + if (_action_confirmee) then + { + // Déduction des crédits (si limité) + if (_usine getVariable "R3F_LOG_CF_credits" != -1) then + { + _usine setVariable ["R3F_LOG_CF_credits", 0 max ((_usine getVariable "R3F_LOG_CF_credits") - _cout), true]; + }; + + _objet = _classe createVehicle _pos_degagee; + _objet setPos _pos_degagee; + _objet setVectorDirAndUp [[-cos getDir _usine, sin getDir _usine, 0] vectorCrossProduct surfaceNormal _pos_degagee, surfaceNormal _pos_degagee]; + _objet setVelocity [0, 0, 0]; + + if !(isNull _objet) then + { + // Désactivation du bouton fermer car la création est engagée + (findDisplay R3F_LOG_IDD_dlg_liste_objets displayCtrl R3F_LOG_IDC_dlg_LO_btn_fermer) ctrlEnable false; + + // Mémoriser que cet objet a été créé depuis une usine + _objet setVariable ["R3F_LOG_CF_depuis_usine", true, true]; + + [_objet, player] call R3F_LOG_FNCT_definir_proprietaire_verrou; + + sleep 0.5; + + // Informer tout le monde qu'il y a un nouvel objet + R3F_LOG_PUBVAR_nouvel_objet_a_initialiser = true; + publicVariable "R3F_LOG_PUBVAR_nouvel_objet_a_initialiser"; + + // Prise en compte de l'objet dans l'environnement du joueur (accélérer le retour des addActions) + _objet spawn + { + sleep 4; + R3F_LOG_PUBVAR_reveler_au_joueur = _this; + publicVariable "R3F_LOG_PUBVAR_reveler_au_joueur"; + ["R3F_LOG_PUBVAR_reveler_au_joueur", R3F_LOG_PUBVAR_reveler_au_joueur] spawn R3F_LOG_FNCT_PUBVAR_reveler_au_joueur; + }; + + // Si l'objet créé est un drone, on y place des IA en équipage + if (getNumber (configFile >> "CfgVehicles" >> (typeOf _objet) >> "isUav") == 1) then + { + createVehicleCrew _objet; + sleep 0.5; + }; + + if (!(_objet isKindOf "AllVehicles") || _est_deplacable) then + { + R3F_LOG_mutex_local_verrou = false; + [_objet, player, 0, true] spawn R3F_LOG_FNCT_objet_deplacer; + } + else + { + sleep 0.4; // Car la prise en compte n'est pas instantannée + + // Si l'objet a été créé assez loin, on indique sa position relative + if (_objet distance _usine > 40) then + { + systemChat format [STR_R3F_LOG_action_creer_fait + " (%2)", + getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName"), + format ["%1m %2deg", round (_objet distance _usine), round ([_usine, _objet] call BIS_fnc_dirTo)] + ]; + } + else + { + systemChat format [STR_R3F_LOG_action_creer_fait, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + R3F_LOG_mutex_local_verrou = false; + }; + + closeDialog 0; + } + else + { + hintC format ["ERROR : ""%1"" is not an instanciable objet.", _classe]; + R3F_LOG_mutex_local_verrou = false; + }; + } + else + { + R3F_LOG_mutex_local_verrou = false; + }; + } + else + { + hintC format ["ERROR : no empty position found around. Creation canceled. Move out objects around the factory and try again."]; + R3F_LOG_mutex_local_verrou = false; + }; + } + else + { + hintC STR_R3F_LOG_action_creer_pas_assez_credits; + R3F_LOG_mutex_local_verrou = false; + }; + } + else {R3F_LOG_mutex_local_verrou = false;}; +}; \ No newline at end of file diff --git a/usine_creation/determiner_cout_creation.sqf b/usine_creation/determiner_cout_creation.sqf new file mode 100644 index 0000000..fae4183 --- /dev/null +++ b/usine_creation/determiner_cout_creation.sqf @@ -0,0 +1,30 @@ +/** + * Retourne le coût de création d'un objet + * + * @param 0 la classe d'objet pour lequel déterminer le coût de création + * + * @return le coût de création de l'objet + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +private ["_classe", "_categorie_toLower", "_idx_facteur_cout", "_facteur_cout", "_cout_creation"]; + +_classe = _this select 0; + +_categorie_toLower = toLower getText (configFile >> "CfgVehicles" >> _classe >> "vehicleClass"); + +// Recherche de l'éventuel facteur de coût de création +_facteur_cout = 1; +{ + if (_categorie_toLower == toLower (_x select 0)) exitWith {_facteur_cout = _x select 1;}; +} forEach R3F_LOG_CFG_CF_creation_cost_factor; + +// Formule de calcul de coût +_cout_creation = _facteur_cout * (1 max ceil (0.01 * getNumber (configFile >> "CfgVehicles" >> _classe >> "cost"))); + +_cout_creation \ No newline at end of file diff --git a/usine_creation/dlg_constantes.h b/usine_creation/dlg_constantes.h new file mode 100644 index 0000000..070ec12 --- /dev/null +++ b/usine_creation/dlg_constantes.h @@ -0,0 +1,93 @@ +/** + * Constantes pour rendre les définitions des boîtes de dialogue plus lisible et maintenable + */ + +#define R3F_LOG_ID_usine_creation_START 65860 + +#define R3F_LOG_IDD_dlg_liste_objets (R3F_LOG_ID_usine_creation_START + 1) + +#define R3F_LOG_IDC_dlg_LO_titre (R3F_LOG_ID_usine_creation_START + 2) +#define R3F_LOG_IDC_dlg_LO_credits_restants (R3F_LOG_ID_usine_creation_START + 3) +#define R3F_LOG_IDC_dlg_LO_liste_categories (R3F_LOG_ID_usine_creation_START + 4) +#define R3F_LOG_IDC_dlg_LO_liste_objets (R3F_LOG_ID_usine_creation_START + 5) +#define R3F_LOG_IDC_dlg_LO_btn_creer (R3F_LOG_ID_usine_creation_START + 6) +#define R3F_LOG_IDC_dlg_LO_btn_fermer (R3F_LOG_ID_usine_creation_START + 7) +#define R3F_LOG_IDC_dlg_LO_infos_titre (R3F_LOG_ID_usine_creation_START + 8) +#define R3F_LOG_IDC_dlg_LO_infos (R3F_LOG_ID_usine_creation_START + 9) + +// Control types +#define CT_STATIC 0 +#define CT_BUTTON 1 +#define CT_EDIT 2 +#define CT_SLIDER 3 +#define CT_COMBO 4 +#define CT_LISTBOX 5 +#define CT_TOOLBOX 6 +#define CT_CHECKBOXES 7 +#define CT_PROGRESS 8 +#define CT_HTML 9 +#define CT_STATIC_SKEW 10 +#define CT_ACTIVETEXT 11 +#define CT_TREE 12 +#define CT_STRUCTURED_TEXT 13 +#define CT_CONTEXT_MENU 14 +#define CT_CONTROLS_GROUP 15 +#define CT_SHORTCUT_BUTTON 16 // Arma 2 - textured button + +#define CT_XKEYDESC 40 +#define CT_XBUTTON 41 +#define CT_XLISTBOX 42 +#define CT_XSLIDER 43 +#define CT_XCOMBO 44 +#define CT_ANIMATED_TEXTURE 45 +#define CT_OBJECT 80 +#define CT_OBJECT_ZOOM 81 +#define CT_OBJECT_CONTAINER 82 +#define CT_OBJECT_CONT_ANIM 83 +#define CT_LINEBREAK 98 +#define CT_USER 99 +#define CT_MAP 100 +#define CT_MAP_MAIN 101 +#define CT_List_N_Box 102 // Arma 2 - N columns list box + +// Static styles +#define ST_POS 0x0F +#define ST_HPOS 0x03 +#define ST_VPOS 0x0C +#define ST_LEFT 0x00 +#define ST_RIGHT 0x01 +#define ST_CENTER 0x02 +#define ST_DOWN 0x04 +#define ST_UP 0x08 +#define ST_VCENTER 0x0c + +#define ST_TYPE 0xF0 +#define ST_SINGLE 0 +#define ST_MULTI 16 +#define ST_TITLE_BAR 32 +#define ST_PICTURE 48 +#define ST_FRAME 64 +#define ST_BACKGROUND 80 +#define ST_GROUP_BOX 96 +#define ST_GROUP_BOX2 112 +#define ST_HUD_BACKGROUND 128 +#define ST_TILE_PICTURE 144 +#define ST_WITH_RECT 160 +#define ST_LINE 176 + +#define ST_SHADOW 0x100 +#define ST_NO_RECT 0x200 +#define ST_KEEP_ASPECT_RATIO 0x800 + +#define ST_TITLE ST_TITLE_BAR + ST_CENTER + +// Slider styles +#define SL_DIR 0x400 +#define SL_VERT 0 +#define SL_HORZ 0x400 + +#define SL_TEXTURES 0x10 + +// Listbox styles +#define LB_TEXTURES 0x10 +#define LB_MULTI 0x20 \ No newline at end of file diff --git a/usine_creation/dlg_liste_objets.h b/usine_creation/dlg_liste_objets.h new file mode 100644 index 0000000..783c42b --- /dev/null +++ b/usine_creation/dlg_liste_objets.h @@ -0,0 +1,274 @@ +/** + * Interface d'affichage du contenu du véhicule + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dlg_constantes.h" + +class R3F_LOG_dlg_liste_objets +{ + idd = R3F_LOG_IDD_dlg_liste_objets; + name = "R3F_LOG_dlg_liste_objets"; + movingEnable = false; + + onUnload = "call compile preprocessFile ""R3F_LOG\usine_creation\memoriser_dlg_liste_objets.sqf"";"; + + controlsBackground[] = {R3F_LOG_dlg_LO_titre_fond}; + objects[] = {}; + controls[] = + { + R3F_LOG_dlg_LO_titre, + R3F_LOG_dlg_LO_credits_restants, + R3F_LOG_dlg_LO_liste_categories, + R3F_LOG_dlg_LO_liste_objets, + R3F_LOG_dlg_LO_btn_creer, + R3F_LOG_dlg_LO_btn_fermer, + R3F_LOG_dlg_LO_infos_titre_fond, + R3F_LOG_dlg_LO_infos_titre, + R3F_LOG_dlg_LO_infos + }; + + // Définition des classes de base + class R3F_LOG_dlg_LO_texte + { + idc = -1; + type = CT_STATIC; + style = ST_LEFT; + x = 0.0; w = 0.3; + y = 0.0; h = 0.03; + sizeEx = 0.023; + colorBackground[] = {0,0,0,0}; + colorText[] = {1,1,1,1}; + font = "PuristaMedium"; + text = ""; + }; + + class R3F_LOG_dlg_LO_btn + { + idc = -1; + type = CT_SHORTCUT_BUTTON; + style = ST_CENTER; + + text = "btn"; + action = ""; + + x = 0; w = 0.195; + y = 0; h = 0.045; + + font = "PuristaLight"; + size = 0.038; + sizeEx = 0.038; + + animTextureNormal = "#(argb,8,8,3)color(1,1,1,1)"; + animTextureDisabled = "#(argb,8,8,3)color(1,1,1,1)"; + animTextureOver = "#(argb,8,8,3)color(1,1,1,0.5)"; + animTextureFocused = "#(argb,8,8,3)color(1,1,1,1)"; + animTexturePressed = "#(argb,8,8,3)color(1,1,1,1)"; + animTextureDefault = "#(argb,8,8,3)color(1,1,1,1)"; + textureNoShortcut = "#(argb,8,8,3)color(0,0,0,0)"; + colorBackground[] = {0,0,0,0.8}; + colorBackground2[] = {1,1,1,0.5}; + colorBackgroundFocused[] = {1,1,1,0.5}; + color[] = {1,1,1,1}; + color2[] = {1,1,1,1}; + colorText[] = {1,1,1,1}; + colorFocused[] = {1,1,1,1}; + colorDisabled[] = {1,1,1,0.25}; + period = 0.6; + periodFocus = 0.6; + periodOver = 0.6; + shadow = 0; + + class HitZone + { + left = 0.000; + top = 0.000; + right = 0.000; + bottom = 0.000; + }; + + class ShortcutPos + { + left = 0.000; + top = 0.000; + w = 0.023; + h = 0.050; + }; + + class TextPos + { + left = 0.010; + top = 0.000; + right = 0.000; + bottom = 0.000; + }; + + soundEnter[] = {"\A3\ui_f\data\sound\RscButtonMenu\soundEnter",0.09,1}; + soundPush[] = {"\A3\ui_f\data\sound\RscButtonMenu\soundPush",0.09,1}; + soundClick[] = {"\A3\ui_f\data\sound\RscButtonMenu\soundClick",0.09,1}; + soundEscape[] = {"\A3\ui_f\data\sound\RscButtonMenu\soundEscape",0.09,1}; + + class Attributes + { + font = "PuristaLight"; + color = "#E5E5E5"; + align = "left"; + shadow = "false"; + }; + + class AttributesImage + { + font = "PuristaLight"; + color = "#E5E5E5"; + align = "left"; + }; + }; + + class R3F_LOG_dlg_LO_liste + { + type = CT_LISTBOX; + style = ST_MULTI; + idc = -1; + text = ""; + w = 0.275; + h = 0.04; + wholeHeight = 0.45; + rowHeight = 0.035; + font = "PuristaSemibold"; + sizeEx = 0.03; + soundSelect[] = {"",0.1,1}; + soundExpand[] = {"",0.1,1}; + soundCollapse[] = {"",0.1,1}; + arrowFull = "\A3\ui_f\data\gui\cfg\scrollbar\arrowFull_ca.paa"; + arrowEmpty = "\A3\ui_f\data\gui\cfg\scrollbar\arrowEmpty_ca.paa"; + maxHistoryDelay = 1; + autoScrollSpeed = 0; + autoScrollDelay = 0; + autoScrollRewind = 0; + + shadow = 0; + colorShadow[] = {0,0,0,0.5}; + colorText[] = {1,1,1,1.0}; + colorDisabled[] = {1,1,1,0.25}; + colorScrollbar[] = {1,0,0,0}; + colorSelect[] = {0,0,0,1}; + colorSelect2[] = {0,0,0,1}; + colorSelectBackground[] = {0.95,0.95,0.95,1}; + colorSelectBackground2[] = {1,1,1,0.75}; + colorBackground[] = {0,0,0,0.75}; + period = 1.2; + + class ComboScrollBar + { + color[] = {1,1,1,1}; + colorActive[] = {1,1,1,1}; + colorDisabled[] = {1,1,1,0.3}; + thumb = "\A3\ui_f\data\gui\cfg\scrollbar\thumb_ca.paa"; + arrowFull = "\A3\ui_f\data\gui\cfg\scrollbar\arrowFull_ca.paa"; + arrowEmpty = "\A3\ui_f\data\gui\cfg\scrollbar\arrowEmpty_ca.paa"; + border = "\A3\ui_f\data\gui\cfg\scrollbar\border_ca.paa"; + }; + + class ListScrollBar + { + color[] = {1,1,1,1}; + colorActive[] = {1,1,1,1}; + colorDisabled[] = {1,1,1,0.3}; + thumb = "\A3\ui_f\data\gui\cfg\scrollbar\thumb_ca.paa"; + arrowFull = "\A3\ui_f\data\gui\cfg\scrollbar\arrowFull_ca.paa"; + arrowEmpty = "\A3\ui_f\data\gui\cfg\scrollbar\arrowEmpty_ca.paa"; + border = "\A3\ui_f\data\gui\cfg\scrollbar\border_ca.paa"; + }; + }; + // FIN Définition des classes de base + + class R3F_LOG_dlg_LO_titre_fond : R3F_LOG_dlg_LO_texte + { + x = safeZoneX + 0.005; w = 0.40; + y = safeZoneY + 0.005; h = 0.07; + colorBackground[] = {"(profilenamespace getvariable ['GUI_BCG_RGB_R',0.69])","(profilenamespace getvariable ['GUI_BCG_RGB_G',0.75])","(profilenamespace getvariable ['GUI_BCG_RGB_B',0.5])","(profilenamespace getvariable ['GUI_BCG_RGB_A',0.8])"}; + }; + + class R3F_LOG_dlg_LO_titre : R3F_LOG_dlg_LO_texte + { + idc = R3F_LOG_IDC_dlg_LO_titre; + x = safeZoneX + 0.005; w = 0.40; + y = safeZoneY + 0.005; h = 0.04; + sizeEx = 0.05; + text = ""; + }; + + class R3F_LOG_dlg_LO_credits_restants : R3F_LOG_dlg_LO_texte + { + idc = R3F_LOG_IDC_dlg_LO_credits_restants; + x = safeZoneX + 0.005; w = 0.40; + y = safeZoneY + 0.045; h = 0.03; + sizeEx = 0.03; + text = ""; + }; + + class R3F_LOG_dlg_LO_liste_categories : R3F_LOG_dlg_LO_liste + { + idc = R3F_LOG_IDC_dlg_LO_liste_categories; + type = CT_COMBO; + x = safeZoneX + 0.005; w = 0.40; + y = safeZoneY + 0.080; h = 0.045; + onLBSelChanged = "call R3F_LOG_FNCT_usine_remplir_liste_objets;"; + }; + + class R3F_LOG_dlg_LO_liste_objets : R3F_LOG_dlg_LO_liste + { + idc = R3F_LOG_IDC_dlg_LO_liste_objets; + x = safeZoneX + 0.005; w = 0.40; + y = safeZoneY + 0.130; h = safeZoneH - 0.185; + onLBDblClick = "0 spawn R3F_LOG_FNCT_usine_creer_objet;"; + onLBSelChanged = "[(_this select 0) lbData (_this select 1)] call R3F_LOG_VIS_FNCT_voir_objet;"; + }; + + class R3F_LOG_dlg_LO_btn_creer : R3F_LOG_dlg_LO_btn + { + idc = R3F_LOG_IDC_dlg_LO_btn_creer; + x = safeZoneX + 0.005; y = safeZoneH + safeZoneY - 0.050; + text = ""; + action = "0 spawn R3F_LOG_FNCT_usine_creer_objet;"; + }; + + class R3F_LOG_dlg_LO_btn_fermer : R3F_LOG_dlg_LO_btn + { + idc = R3F_LOG_IDC_dlg_LO_btn_fermer; + x = safeZoneX + 0.005 + 0.205; y = safeZoneH + safeZoneY - 0.050; + text = ""; + action = "closeDialog 0;"; + }; + + class R3F_LOG_dlg_LO_infos_titre_fond : R3F_LOG_dlg_LO_texte + { + x = safeZoneX + safeZoneW - 0.005 - 0.35; w = 0.35; + y = safeZoneY + 0.005; h = 0.055; + colorBackground[] = {"(profilenamespace getvariable ['GUI_BCG_RGB_R',0.69])","(profilenamespace getvariable ['GUI_BCG_RGB_G',0.75])","(profilenamespace getvariable ['GUI_BCG_RGB_B',0.5])","(profilenamespace getvariable ['GUI_BCG_RGB_A',0.8])"}; + }; + + class R3F_LOG_dlg_LO_infos_titre : R3F_LOG_dlg_LO_texte + { + idc = R3F_LOG_IDC_dlg_LO_infos_titre; + x = safeZoneX + safeZoneW - 0.005 - 0.35; w = 0.35; + y = safeZoneY + 0.005; h = 0.045; + sizeEx = 0.05; + text = ""; + }; + + class R3F_LOG_dlg_LO_infos : R3F_LOG_dlg_LO_texte + { + idc = R3F_LOG_IDC_dlg_LO_infos; + type = CT_STRUCTURED_TEXT; + x = safeZoneX + safeZoneW - 0.005 - 0.35; w = 0.35; + y = safeZoneY + 0.065; h = 0.44; + size = 0.033; + colorBackground[] = {0,0,0,0.75}; + }; +}; \ No newline at end of file diff --git a/usine_creation/memoriser_dlg_liste_objets.sqf b/usine_creation/memoriser_dlg_liste_objets.sqf new file mode 100644 index 0000000..1831031 --- /dev/null +++ b/usine_creation/memoriser_dlg_liste_objets.sqf @@ -0,0 +1,21 @@ +/** + * Enregistre les valeurs des champs avant fermeture de la boîte de dialogue de l'usine de création. + * ouvrir_usine.sqf s'en servira pour la préremplir à l'ouverture + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +disableSerialization; // A cause des displayCtrl + +private ["_dlg_liste_objets"]; + +#include "dlg_constantes.h" + +_dlg_liste_objets = findDisplay R3F_LOG_IDD_dlg_liste_objets; + +(uiNamespace getVariable "R3F_LOG_dlg_LO_usine") setVariable ["R3F_LOG_CF_mem_idx_categorie", lbCurSel (_dlg_liste_objets displayCtrl R3F_LOG_IDC_dlg_LO_liste_categories)]; +(uiNamespace getVariable "R3F_LOG_dlg_LO_usine") setVariable ["R3F_LOG_CF_mem_idx_objet", lbCurSel (_dlg_liste_objets displayCtrl R3F_LOG_IDC_dlg_LO_liste_objets)]; \ No newline at end of file diff --git a/usine_creation/ouvrir_usine.sqf b/usine_creation/ouvrir_usine.sqf new file mode 100644 index 0000000..05ede73 --- /dev/null +++ b/usine_creation/ouvrir_usine.sqf @@ -0,0 +1,95 @@ +/** + * Ouvre la boîte de dialogue du contenu de l'usine + * + * @param 0 l'usine qu'il faut ouvrir + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dlg_constantes.h" + +disableSerialization; // A cause des displayCtrl + +private ["_usine", "_credits_usine", "_dlg_liste_objets", "_ctrl_liste_categories", "_sel_categorie"]; + +R3F_LOG_objet_selectionne = objNull; + +_usine = _this select 0; +uiNamespace setVariable ["R3F_LOG_dlg_LO_usine", _usine]; + +call R3F_LOG_VIS_FNCT_demarrer_visualisation; + +// Pré-calculer une fois pour toutes les usines la liste des objets du CfgVehicles classés par catégorie +if (isNil {_usine getVariable "R3F_LOG_CF_cfgVehicles_par_categories"}) then +{ + private ["_retour_liste_cfgVehicles_par_categories"]; + + _retour_liste_cfgVehicles_par_categories = [_usine] call R3F_LOG_FNCT_recuperer_liste_cfgVehicles_par_categories; + + _usine setVariable ["R3F_LOG_CF_cfgVehicles_categories", + (_retour_liste_cfgVehicles_par_categories select 0)]; + _usine setVariable ["R3F_LOG_CF_cfgVehicles_par_categories", + (_retour_liste_cfgVehicles_par_categories select 1)]; +}; + +createDialog "R3F_LOG_dlg_liste_objets"; +_dlg_liste_objets = findDisplay R3F_LOG_IDD_dlg_liste_objets; + +/**** DEBUT des traductions des labels ****/ +(_dlg_liste_objets displayCtrl R3F_LOG_IDC_dlg_LO_titre) ctrlSetText STR_R3F_LOG_dlg_LO_titre; +(_dlg_liste_objets displayCtrl R3F_LOG_IDC_dlg_LO_btn_creer) ctrlSetText STR_R3F_LOG_dlg_LO_btn_creer; +(_dlg_liste_objets displayCtrl R3F_LOG_IDC_dlg_LO_btn_fermer) ctrlSetText STR_R3F_LOG_dlg_LO_btn_fermer; +(_dlg_liste_objets displayCtrl R3F_LOG_IDC_dlg_LO_infos_titre) ctrlSetText STR_R3F_LOG_nom_fonctionnalite_proprietes; +/**** FIN des traductions des labels ****/ + +_ctrl_liste_categories = _dlg_liste_objets displayCtrl R3F_LOG_IDC_dlg_LO_liste_categories; +_sel_categorie = 0 max (_usine getVariable "R3F_LOG_CF_mem_idx_categorie"); + +// Insertion de chaque catégories disponibles dans la liste +{ + private ["_categorie", "_config", "_nom"]; + + _categorie = _x; + _config = configFile >> "CfgVehicleClasses" >> _categorie; + _nom = getText (_config >> "displayName"); + + _index = _ctrl_liste_categories lbAdd format ["%1", _nom]; + _ctrl_liste_categories lbSetData [_index, _categorie]; +} forEach (_usine getVariable "R3F_LOG_CF_cfgVehicles_categories"); + +_ctrl_liste_categories lbSetCurSel _sel_categorie; + +while {!isNull _dlg_liste_objets} do +{ + _credits_usine = _usine getVariable "R3F_LOG_CF_credits"; + + // Activer le bouton de création que s'il y a assez de crédits + (_dlg_liste_objets displayCtrl R3F_LOG_IDC_dlg_LO_btn_creer) ctrlEnable (_credits_usine != 0); + + if (_credits_usine == -1) then + { + (_dlg_liste_objets displayCtrl R3F_LOG_IDC_dlg_LO_credits_restants) ctrlSetText (format [STR_R3F_LOG_dlg_LO_credits_restants, "unlimited"]); + } + else + { + (_dlg_liste_objets displayCtrl R3F_LOG_IDC_dlg_LO_credits_restants) ctrlSetText (format [STR_R3F_LOG_dlg_LO_credits_restants, _credits_usine]); + }; + + // Afficher les infos de l'objet + if (lbCurSel R3F_LOG_IDC_dlg_LO_liste_objets != -1) then + { + (_dlg_liste_objets displayCtrl R3F_LOG_IDC_dlg_LO_infos) ctrlSetStructuredText ([lbData [R3F_LOG_IDC_dlg_LO_liste_objets, lbCurSel R3F_LOG_IDC_dlg_LO_liste_objets]] call R3F_LOG_FNCT_formater_fonctionnalites_logistique); + }; + + // Fermer la boîte de dialogue si l'usine n'est plus accessible + if (!alive _usine || (_usine getVariable "R3F_LOG_CF_disabled")) then + { + closeDialog 0; + }; + + sleep 0.15; +}; + +call R3F_LOG_VIS_FNCT_terminer_visualisation; \ No newline at end of file diff --git a/usine_creation/recuperer_liste_cfgVehicles_par_categories.sqf b/usine_creation/recuperer_liste_cfgVehicles_par_categories.sqf new file mode 100644 index 0000000..c7ef1ea --- /dev/null +++ b/usine_creation/recuperer_liste_cfgVehicles_par_categories.sqf @@ -0,0 +1,78 @@ +/** + * Récupère les liste des catégories (CfgVehicleClasses) et pour chacune d'elles les véhicules associés (CfgVehicles) + * + * @param 0 (optionnel) l'éventuelle usine pour laquelle récupérer les catégories autorisées (en fonction de la white ou black list) + * @param 1 (optionnel) true pour conserver les catégories vides (càd sans entrée dans le CfgVehicles) (défaut : false) + * + * @return tableau au format [tableau des catégories, tableau 2D des véhicules associés à chaque catégorie] + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +private ["_usine", "_montrer_categories_vides", "_nb_config", "_idx_categorie", "_idx_config", "_config"]; +private ["_cfgVehicles_categories", "_cfgVehicles_categories_toLower", "_cfgVehicles_par_categories", "_clean_cfgVehicles_categories", "_clean_cfgVehicles_par_categories"]; + +_usine = if (count _this > 0) then {_this select 0} else {objNull}; +_montrer_categories_vides = if (count _this > 1) then {_this select 1} else {false}; + +_cfgVehicles_categories = []; +_cfgVehicles_categories_toLower = []; +_cfgVehicles_par_categories = []; + +// Récupération de la liste des catégories de véhicules +_nb_config = count (configFile >> "CfgVehicleClasses"); +for [{_idx_config = 0}, {_idx_config < _nb_config}, {_idx_config = _idx_config+1}] do +{ + _config = (configFile >> "CfgVehicleClasses") select _idx_config; + if (isClass _config) then + { + // Si la catégorie est autorisé (en fonction de la white ou black list) + if (isNull _usine || {(_usine getVariable "R3F_LOG_CF_blackwhitelist_mode" == "white") isEqualTo (toLower configName _config in (_usine getVariable "R3F_LOG_CF_blackwhitelist_categories"))}) then + { + _cfgVehicles_categories pushBack (configName _config); + _cfgVehicles_categories_toLower pushBack (toLower configName _config); + _cfgVehicles_par_categories pushBack []; + }; + }; +}; + +// Création de la liste des véhicules, classés par catégorie +_nb_config = count (configFile >> "CfgVehicles"); +for [{_idx_config = 0}, {_idx_config < _nb_config}, {_idx_config = _idx_config+1}] do +{ + _config = (configFile >> "CfgVehicles") select _idx_config; + if (isClass _config) then + { + // Objet instanciable + if (getNumber (_config >> "scope") == 2 && !(configName _config isKindOf "Man")) then + { + // Si l'objet correspond à une side valide + if (isNull _usine || {getNumber (_config >> "side") in (_usine getVariable "R3F_LOG_CF_num_sides")}) then + { + _idx_categorie = _cfgVehicles_categories_toLower find (toLower getText (_config >> "vehicleClass")); + + if (_idx_categorie != -1) then + { + (_cfgVehicles_par_categories select _idx_categorie) pushBack (configName _config); + }; + }; + }; + }; +}; + +// Suppression des catégories ne possédant aucun objet +_clean_cfgVehicles_categories = []; +_clean_cfgVehicles_par_categories = []; +{ + if (_montrer_categories_vides || count (_cfgVehicles_par_categories select _forEachIndex) > 0) then + { + _clean_cfgVehicles_categories pushBack _x; + _clean_cfgVehicles_par_categories pushBack (_cfgVehicles_par_categories select _forEachIndex); + }; +} forEach _cfgVehicles_categories; + +[_clean_cfgVehicles_categories, _clean_cfgVehicles_par_categories] \ No newline at end of file diff --git a/usine_creation/remplir_liste_objets.sqf b/usine_creation/remplir_liste_objets.sqf new file mode 100644 index 0000000..d8f7740 --- /dev/null +++ b/usine_creation/remplir_liste_objets.sqf @@ -0,0 +1,86 @@ +/** + * Enregistre les valeurs des champs avant fermeture de la boîte de dialogue de l'usine de création. + * ouvrir_usine.sqf s'en servira pour la préremplir à l'ouverture + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +disableSerialization; // A cause des displayCtrl + +private ["_usine", "_dlg_liste_objets", "_ctrl_liste_objets", "_sel_categorie", "_sel_objet"]; + +#include "dlg_constantes.h" + +_usine = uiNamespace getVariable "R3F_LOG_dlg_LO_usine"; + +_dlg_liste_objets = findDisplay R3F_LOG_IDD_dlg_liste_objets; + +_ctrl_liste_objets = _dlg_liste_objets displayCtrl R3F_LOG_IDC_dlg_LO_liste_objets; + +_sel_categorie = lbCurSel (_dlg_liste_objets displayCtrl R3F_LOG_IDC_dlg_LO_liste_categories); +_sel_objet = 0 max (_usine getVariable "R3F_LOG_CF_mem_idx_objet"); +_usine setVariable ["R3F_LOG_CF_mem_idx_objet", 0]; + +lbClear _ctrl_liste_objets; + +if (count (_usine getVariable "R3F_LOG_CF_cfgVehicles_par_categories") > 0) then +{ + // Insertion de chaque type d'objets disponibles dans la liste + { + private ["_classe", "_config", "_nom", "_icone", "_cout", "_tab_icone", "_index"]; + + _classe = _x; + _config = configFile >> "CfgVehicles" >> _classe; + _nom = getText (_config >> "displayName"); + _icone = getText (_config >> "icon"); + _cout = [_classe] call R3F_LOG_FNCT_determiner_cout_creation; + + // Icône par défaut + if (_icone == "") then + { + _icone = "\A3\ui_f\data\map\VehicleIcons\iconObject_ca.paa"; + }; + + // Si le chemin commence par A3\ ou a3\, on rajoute un \ au début + _tab_icone = toArray toLower _icone; + if (count _tab_icone >= 3 && + { + _tab_icone select 0 == (toArray "a" select 0) && + _tab_icone select 1 == (toArray "3" select 0) && + _tab_icone select 2 == (toArray "\" select 0) + }) then + { + _icone = "\" + _icone; + }; + + // Si icône par défaut, on rajoute le chemin de base par défaut + _tab_icone = toArray _icone; + if (_tab_icone select 0 != (toArray "\" select 0)) then + { + _icone = format ["\A3\ui_f\data\map\VehicleIcons\%1_ca.paa", _icone]; + }; + + // Si pas d'extension de fichier, on rajoute ".paa" + _tab_icone = toArray _icone; + if (count _tab_icone >= 4 && {_tab_icone select (count _tab_icone - 4) != (toArray "." select 0)}) then + { + _icone = _icone + ".paa"; + }; + + _index = _ctrl_liste_objets lbAdd format ["%1 (%2 cred.)", _nom, [_cout] call R3F_LOG_FNCT_formater_nombre_entier_milliers]; + _ctrl_liste_objets lbSetPicture [_index, _icone]; + _ctrl_liste_objets lbSetData [_index, _classe]; + } forEach (_usine getVariable "R3F_LOG_CF_cfgVehicles_par_categories" select _sel_categorie); + + // Ajout d'une ligne vide car l'affichage des listes de BIS est bugué (dernier élément masqué)..... + _ctrl_liste_objets lbSetData [_ctrl_liste_objets lbAdd "", ""]; + + // Sélectionner l'objet mémoriser en le plaçant visuellement au centre de la liste + _ctrl_liste_objets lbSetCurSel (lbSize _ctrl_liste_objets - 1); + _ctrl_liste_objets lbSetCurSel (_sel_objet - 8 max 0); + _ctrl_liste_objets lbSetCurSel _sel_objet; +}; \ No newline at end of file diff --git a/usine_creation/revendre_deplace.sqf b/usine_creation/revendre_deplace.sqf new file mode 100644 index 0000000..6191ecf --- /dev/null +++ b/usine_creation/revendre_deplace.sqf @@ -0,0 +1,79 @@ +/** + * Revendre l'objet déplacé par le joueur à une usine + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +if (R3F_LOG_mutex_local_verrou) then +{ + hintC STR_R3F_LOG_mutex_action_en_cours; +} +else +{ + R3F_LOG_mutex_local_verrou = true; + + private ["_objet", "_usine"]; + + _objet = R3F_LOG_joueur_deplace_objet; + _usine = [_objet, 5] call R3F_LOG_FNCT_3D_cursorTarget_virtuel; + + if (!isNull _usine && { + !(_usine getVariable ["R3F_LOG_CF_disabled", true]) && alive _usine && (vectorMagnitude velocity _usine < 6) && + (abs ((getPosASL _usine select 2) - (getPosASL player select 2)) < 2.5) + }) then + { + if (isNull (_objet getVariable ["R3F_LOG_remorque", objNull])) then + { + if (count (_objet getVariable ["R3F_LOG_objets_charges", []]) == 0) then + { + _objet setVariable ["R3F_LOG_est_transporte_par", _usine, true]; + + // Faire relacher l'objet au joueur + R3F_LOG_joueur_deplace_objet = objNull; + waitUntil {_objet getVariable "R3F_LOG_est_deplace_par" != player}; + + // Suppression de l'équipage IA dans le cas d'un drone + if (getNumber (configFile >> "CfgVehicles" >> (typeOf _objet) >> "isUav") == 1) then + { + {if (!isPlayer _x) then {_objet deleteVehicleCrew _x;};} forEach crew _objet; + }; + + deleteVehicle _objet; + + // Si l'usine n'a pas de crédits illimité et que le taux d'occasion n'est pas nul + if (_usine getVariable "R3F_LOG_CF_credits" != -1 && R3F_LOG_CFG_CF_sell_back_bargain_rate > 0) then + { + private ["_cout_neuf", "_valeur_occasion"]; + + _cout_neuf = [typeOf _objet] call R3F_LOG_FNCT_determiner_cout_creation; + _valeur_occasion = ceil (R3F_LOG_CFG_CF_sell_back_bargain_rate * (1 - damage _objet) * _cout_neuf); + + // Ajout de la valeur d'occasion de l'objet dans les crédits de l'usine + _usine setVariable ["R3F_LOG_CF_credits", (_usine getVariable "R3F_LOG_CF_credits") + _valeur_occasion, true]; + + systemChat format [STR_R3F_LOG_action_revendre_fait + " (+%2 credits)", + getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName"), [_valeur_occasion] call R3F_LOG_FNCT_formater_nombre_entier_milliers]; + } + else + { + systemChat format [STR_R3F_LOG_action_revendre_fait, + getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + } + else + { + hintC STR_R3F_LOG_action_revendre_decharger_avant; + }; + } + else + { + hintC format [STR_R3F_LOG_objet_remorque_en_cours, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + }; + + R3F_LOG_mutex_local_verrou = false; +}; \ No newline at end of file diff --git a/usine_creation/revendre_direct.sqf b/usine_creation/revendre_direct.sqf new file mode 100644 index 0000000..bbd22b1 --- /dev/null +++ b/usine_creation/revendre_direct.sqf @@ -0,0 +1,122 @@ +/** + * Revendre l'objet sélectionné (R3F_LOG_objet_selectionne) à une usine + * + * @param 0 l'usine + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +if (R3F_LOG_mutex_local_verrou) then +{ + hintC STR_R3F_LOG_mutex_action_en_cours; +} +else +{ + R3F_LOG_mutex_local_verrou = true; + + private ["_objet", "_usine", "_distance_usine"]; + + _objet = _this select 0; + + // Recherche de l'usine la plus proche + _usine = objNull; + _distance_usine = 1E39; + { + if ( + _objet distance _x < 22 && !(_x getVariable "R3F_LOG_CF_disabled") && + _x getVariable ["R3F_LOG_CF_side_addAction", side group player] == side group player && + _objet distance _x < _distance_usine + ) then + { + _usine = _x; + _distance_usine = _objet distance _x; + }; + } forEach R3F_LOG_CF_liste_usines; + + if (!isNull _usine && !isNull _objet) then + { + if (isNull (_objet getVariable ["R3F_LOG_est_transporte_par", objNull]) && (isNull (_objet getVariable ["R3F_LOG_est_deplace_par", objNull]) || (!alive (_objet getVariable ["R3F_LOG_est_deplace_par", objNull])) || (!isPlayer (_objet getVariable ["R3F_LOG_est_deplace_par", objNull])))) then + { + if (isNull (_objet getVariable ["R3F_LOG_remorque", objNull])) then + { + if (count crew _objet == 0 || getNumber (configFile >> "CfgVehicles" >> (typeOf _objet) >> "isUav") == 1) then + { + if (_objet distance _usine <= 30) then + { + if (count (_objet getVariable ["R3F_LOG_objets_charges", []]) == 0) then + { + _objet setVariable ["R3F_LOG_est_transporte_par", _usine, true]; + + systemChat STR_R3F_LOG_action_revendre_en_cours; + + sleep 2; + + // Gestion conflit d'accès + if (_objet getVariable "R3F_LOG_est_transporte_par" == _usine && !(_objet in (_usine getVariable "R3F_LOG_objets_charges"))) then + { + // Suppression de l'équipage IA dans le cas d'un drone + if (getNumber (configFile >> "CfgVehicles" >> (typeOf _objet) >> "isUav") == 1) then + { + {if (!isPlayer _x) then {_objet deleteVehicleCrew _x;};} forEach crew _objet; + }; + + deleteVehicle _objet; + + // Si l'usine n'a pas de crédits illimité et que le taux d'occasion n'est pas nul + if (_usine getVariable "R3F_LOG_CF_credits" != -1 && R3F_LOG_CFG_CF_sell_back_bargain_rate > 0) then + { + private ["_cout_neuf", "_valeur_occasion"]; + + _cout_neuf = [typeOf _objet] call R3F_LOG_FNCT_determiner_cout_creation; + _valeur_occasion = ceil (R3F_LOG_CFG_CF_sell_back_bargain_rate * (1 - damage _objet) * _cout_neuf); + + // Ajout de la valeur d'occasion de l'objet dans les crédits de l'usine + _usine setVariable ["R3F_LOG_CF_credits", (_usine getVariable "R3F_LOG_CF_credits") + _valeur_occasion, true]; + + systemChat format [STR_R3F_LOG_action_revendre_fait + " (+%2 credits)", + getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName"), [_valeur_occasion] call R3F_LOG_FNCT_formater_nombre_entier_milliers]; + } + else + { + systemChat format [STR_R3F_LOG_action_revendre_fait, + getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + } + else + { + _objet setVariable ["R3F_LOG_est_transporte_par", objNull, true]; + hintC format ["ERROR : " + STR_R3F_LOG_objet_en_cours_transport, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + } + else + { + hintC STR_R3F_LOG_action_revendre_decharger_avant; + }; + } + else + { + hintC format [STR_R3F_LOG_trop_loin, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + } + else + { + hintC format [STR_R3F_LOG_joueur_dans_objet, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + } + else + { + hintC format [STR_R3F_LOG_objet_remorque_en_cours, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + } + else + { + hintC format [STR_R3F_LOG_objet_en_cours_transport, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + }; + + R3F_LOG_mutex_local_verrou = false; +}; \ No newline at end of file diff --git a/usine_creation/revendre_selection.sqf b/usine_creation/revendre_selection.sqf new file mode 100644 index 0000000..b1e6022 --- /dev/null +++ b/usine_creation/revendre_selection.sqf @@ -0,0 +1,110 @@ +/** + * Revendre l'objet sélectionné (R3F_LOG_objet_selectionne) à une usine + * + * @param 0 l'usine + * + * Copyright (C) 2014 Team ~R3F~ + * + * This program is free software under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +if (R3F_LOG_mutex_local_verrou) then +{ + hintC STR_R3F_LOG_mutex_action_en_cours; +} +else +{ + R3F_LOG_mutex_local_verrou = true; + + private ["_objet", "_usine"]; + + _objet = R3F_LOG_objet_selectionne; + _usine = _this select 0; + + if (!(isNull _objet) && !(_objet getVariable "R3F_LOG_disabled")) then + { + if (isNull (_objet getVariable "R3F_LOG_est_transporte_par") && (isNull (_objet getVariable "R3F_LOG_est_deplace_par") || (!alive (_objet getVariable "R3F_LOG_est_deplace_par")) || (!isPlayer (_objet getVariable "R3F_LOG_est_deplace_par")))) then + { + if (isNull (_objet getVariable ["R3F_LOG_remorque", objNull])) then + { + if (count crew _objet == 0 || getNumber (configFile >> "CfgVehicles" >> (typeOf _objet) >> "isUav") == 1) then + { + if (_objet distance _usine <= 30) then + { + if (count (_objet getVariable ["R3F_LOG_objets_charges", []]) == 0) then + { + _objet setVariable ["R3F_LOG_est_transporte_par", _usine, true]; + + systemChat STR_R3F_LOG_action_revendre_en_cours; + + sleep 2; + + // Gestion conflit d'accès + if (_objet getVariable "R3F_LOG_est_transporte_par" == _usine && !(_objet in (_usine getVariable "R3F_LOG_objets_charges"))) then + { + // Suppression de l'équipage IA dans le cas d'un drone + if (getNumber (configFile >> "CfgVehicles" >> (typeOf _objet) >> "isUav") == 1) then + { + {if (!isPlayer _x) then {_objet deleteVehicleCrew _x;};} forEach crew _objet; + }; + + deleteVehicle _objet; + + // Si l'usine n'a pas de crédits illimité et que le taux d'occasion n'est pas nul + if (_usine getVariable "R3F_LOG_CF_credits" != -1 && R3F_LOG_CFG_CF_sell_back_bargain_rate > 0) then + { + private ["_cout_neuf", "_valeur_occasion"]; + + _cout_neuf = [typeOf _objet] call R3F_LOG_FNCT_determiner_cout_creation; + _valeur_occasion = ceil (R3F_LOG_CFG_CF_sell_back_bargain_rate * (1 - damage _objet) * _cout_neuf); + + // Ajout de la valeur d'occasion de l'objet dans les crédits de l'usine + _usine setVariable ["R3F_LOG_CF_credits", (_usine getVariable "R3F_LOG_CF_credits") + _valeur_occasion, true]; + + systemChat format [STR_R3F_LOG_action_revendre_fait + " (+%2 credits)", + getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName"), [_valeur_occasion] call R3F_LOG_FNCT_formater_nombre_entier_milliers]; + } + else + { + systemChat format [STR_R3F_LOG_action_revendre_fait, + getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + } + else + { + _objet setVariable ["R3F_LOG_est_transporte_par", objNull, true]; + hintC format ["ERROR : " + STR_R3F_LOG_objet_en_cours_transport, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + } + else + { + hintC STR_R3F_LOG_action_revendre_decharger_avant; + }; + } + else + { + hintC format [STR_R3F_LOG_trop_loin, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + } + else + { + hintC format [STR_R3F_LOG_joueur_dans_objet, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + } + else + { + hintC format [STR_R3F_LOG_objet_remorque_en_cours, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + } + else + { + hintC format [STR_R3F_LOG_objet_en_cours_transport, getText (configFile >> "CfgVehicles" >> (typeOf _objet) >> "displayName")]; + }; + }; + + R3F_LOG_objet_selectionne = objNull; + + R3F_LOG_mutex_local_verrou = false; +}; \ No newline at end of file diff --git a/usine_creation/usine_init.sqf b/usine_creation/usine_init.sqf new file mode 100644 index 0000000..95628d6 --- /dev/null +++ b/usine_creation/usine_init.sqf @@ -0,0 +1,127 @@ +/** + * Initialise et configure une usine de création + * + * @param 0 l'usine + * @param 1 (optionnel) son crédit de création, -1 pour un crédit infinie (défaut : -1) + * @param 2 (optionnel) side pour laquelle autoriser l'accès (défaut : accès pour toutes les sides) + * @param 3 (optionnel) liste des noms de classes des catégories autorisés (white list) + * si non renseigné, toutes les catégories non présentes l'éventuelle black list saisie dans config_creation_factory.sqf + * si chaîne de caractères "FULL", utilisation de la liste R3F_LOG_CFG_CF_whitelist_full_categories (config_creation_factory.sqf) + * si chaîne de caractères "MEDIUM", utilisation de la liste R3F_LOG_CFG_CF_whitelist_medium_categories (config_creation_factory.sqf) + * si chaîne de caractères "LIGHT", utilisation de la liste R3F_LOG_CFG_CF_whitelist_light_categories (config_creation_factory.sqf) + * si tableau de noms de classes du CfgVehicleClasses (ex : ["Furniture", "Fortifications"]), utilisation de la liste fournie + */ + +private ["_usine", "_credits_usine", "_num_side", "_param3", "_blackwhitelist_categories_toLower"]; + +_usine = _this select 0; + +// Récupération du paramètre optionnel de crédits +if (count _this > 1 && {!isNil {_this select 1}}) then +{ + if (typeName (_this select 1) != "SCALAR") then + { + systemChat "ERROR : credits parameter passed to ""init creation factory"" is not a number."; + diag_log text "ERROR : credits parameter passed to ""init creation factory"" is not a number."; + _this set [1, -1]; + }; + + _credits_usine = _this select 1; +} +else {_credits_usine = -1}; + +// Si une side est spécifiée, on l'autorise, ainsi que les sides civil et neutre +if (count _this > 2 && {!isNil {_this select 2}}) then +{ + if (typeName (_this select 2) != "SIDE") then + { + systemChat "ERROR : side parameter passed to ""init creation factory"" is not a side."; + diag_log text "ERROR : side parameter passed to ""init creation factory"" is not a side."; + _this set [2, civilian]; + }; + + _num_side = switch (_this select 2) do + { + case east: {0}; + case west: {1}; + case independent: {2}; + case civilian: {3}; + default {4}; + }; + + _usine setVariable ["R3F_LOG_CF_num_sides", [_num_side, 3, 4], false]; + _usine setVariable ["R3F_LOG_CF_side_addAction", _this select 2, false]; +} +// Par défaut, toutes les sides sont autorisées +else +{ + _usine setVariable ["R3F_LOG_CF_num_sides", [0, 1, 2, 3, 4], false]; + // R3F_LOG_CF_side_addAction reste nil +}; + +/** Crédits de création, -1 pour un crédit infinie */ +if (isNil {_usine getVariable "R3F_LOG_CF_credits"}) then +{ + _usine setVariable ["R3F_LOG_CF_credits", _credits_usine, false]; +}; + +if (isNil {_usine getVariable "R3F_LOG_CF_disabled"}) then +{ + _usine setVariable ["R3F_LOG_CF_disabled", false, false]; +}; + +// Gestion de la configuration black/white liste des catégories accessibles +if (isNil {_usine getVariable "R3F_LOG_CF_blackwhitelist_categories"}) then +{ + if (count _this > 3 && {!isNil {_this select 3}}) then + { + _param3 = _this select 3; + + _usine setVariable ["R3F_LOG_CF_blackwhitelist_mode", "white", false]; + + // Param 3 parmi "FULL" ou "LIGHT" : utilisation de la white list correspondante dans le config_creation_factory.sqf + if (typeName _param3 == "STRING") then + { + _usine setVariable ["R3F_LOG_CF_blackwhitelist_categories", switch (_param3) do { + case "LIGHT": {R3F_LOG_CFG_CF_whitelist_light_categories}; + case "MEDIUM": {R3F_LOG_CFG_CF_whitelist_medium_categories}; + case "FULL": {R3F_LOG_CFG_CF_whitelist_full_categories}; + default {R3F_LOG_CFG_CF_whitelist_full_categories}; + }]; + } + else + { + // White list personnalisée en param 3 + if (typeName _param3 == "ARRAY") then + { + _usine setVariable ["R3F_LOG_CF_blackwhitelist_categories", _param3, false]; + }; + }; + } + else + { + // Par défaut, autoriser tout sauf la black list du config_creation_factory.sqf + _usine setVariable ["R3F_LOG_CF_blackwhitelist_mode", "black", false]; + _usine setVariable ["R3F_LOG_CF_blackwhitelist_categories", R3F_LOG_CFG_CF_blacklist_categories, false]; + }; + + // Conversion des catégories en lettres minuscules + _blackwhitelist_categories_toLower = []; + { + _blackwhitelist_categories_toLower pushBack toLower _x; + } forEach (_usine getVariable "R3F_LOG_CF_blackwhitelist_categories"); + _usine setVariable ["R3F_LOG_CF_blackwhitelist_categories", _blackwhitelist_categories_toLower, false]; +}; + +// Initialisation des variables mémorisant les valeurs saisies dans l'interface entre deux ouvertures +_usine setVariable ["R3F_LOG_CF_mem_idx_categorie", 0]; +_usine setVariable ["R3F_LOG_CF_mem_idx_objet", 0]; + +/** Tableau contenant toutes les usines créées */ +R3F_LOG_CF_liste_usines pushBack _usine; + +_usine addAction [("" + STR_R3F_LOG_action_ouvrir_usine + ""), {_this call R3F_LOG_FNCT_usine_ouvrir_usine}, nil, 5, false, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_action_ouvrir_usine_valide"]; + +_usine addAction [("" + STR_R3F_LOG_action_revendre_usine_deplace + ""), {_this call R3F_LOG_FNCT_usine_revendre_deplace}, nil, 7, false, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_action_revendre_usine_deplace_valide"]; + +_usine addAction [("" + STR_R3F_LOG_action_revendre_usine_selection + ""), {_this call R3F_LOG_FNCT_usine_revendre_selection}, nil, 6, false, true, "", "!R3F_LOG_mutex_local_verrou && R3F_LOG_objet_addAction == _target && R3F_LOG_action_revendre_usine_selection_valide"]; \ No newline at end of file