diff --git a/TO_MERGE/agm/Optics/agm_optics_pip.p3d b/TO_MERGE/agm/Optics/agm_optics_pip.p3d new file mode 100644 index 0000000000..d331ce4acd Binary files /dev/null and b/TO_MERGE/agm/Optics/agm_optics_pip.p3d differ diff --git a/TO_MERGE/agm/Optics/clientInit.sqf b/TO_MERGE/agm/Optics/clientInit.sqf new file mode 100644 index 0000000000..7dca46fdc4 --- /dev/null +++ b/TO_MERGE/agm/Optics/clientInit.sqf @@ -0,0 +1,25 @@ +// TMR: Optics initialization and functions +// (C) 2013 Ryan Schultz. See LICENSE. + +// Request a resource layer from the game engine. +AGM_Optics_scopeRSC = ["AGM_Optics_Scope"] call BIS_fnc_rscLayer; + +// Set global variables +AGM_Optics_inScope = false; // Is the scope up? +AGM_Optics_currentOptic = ""; // What optic is attached right now? + +0 = 0 spawn { + waituntil {!isNull (findDisplay 46)}; + + [] call AGM_Optics_fnc_initScope; + + // PiP technique by BadBenson + AGM_Optics_Camera = "camera" camCreate (positioncameratoworld [0,0,0]); + AGM_Optics_Camera camSetFov 0.7; + AGM_Optics_Camera camSetTarget player; + AGM_Optics_Camera camCommit 1; + "agm_optics_rendertarget0" setPiPEffect [2, 1.0, 1.0, 1.0, 0.0, [0.0, 1.0, 0.0, 0.25], [1.0, 0.0, 1.0, 1.0], [0.199, 0.587, 0.114, 0.0]]; + AGM_Optics_Camera cameraEffect ["INTERNAL", "BACK","agm_optics_rendertarget0"]; + + waitUntil {[] call AGM_Optics_fnc_mainLoop; False}; +}; diff --git a/TO_MERGE/agm/Optics/config.cpp b/TO_MERGE/agm/Optics/config.cpp new file mode 100644 index 0000000000..429c57cbe2 --- /dev/null +++ b/TO_MERGE/agm/Optics/config.cpp @@ -0,0 +1,454 @@ +class CfgPatches { + class AGM_Optics { + units[] = {}; + weapons[] = {}; + requiredVersion = 0.60; + requiredAddons[] = {AGM_Core}; + version = 0.1; + author[] = {"Taosenai"}; + authorUrl = "http://www.ryanschultz.org/tmr/"; + }; +}; + +class CfgFunctions { + class AGM_Optics { + class AGM_Optics { + file = "AGM_Optics\functions"; + class firedEH; + class hideScope; + class initScope; + class mainLoop; + }; + }; +}; + +class Extended_PostInit_EventHandlers { + class AGM_Optics { + clientInit = "call compile preProcessFileLineNumbers '\AGM_Optics\clientInit.sqf'"; + }; +}; + +class Extended_FiredBIS_EventHandlers { + class CAManBase { + class AGM_Optics { + clientFiredBIS = "_this call AGM_Optics_fnc_firedEH;"; + }; + }; +}; + +class CfgOpticsEffect { + class AGM_OpticsRadBlur1 { + type = "radialblur"; + params[] = {0.015, 0, 0.14, 0.2}; + priority = 950; + }; +}; + + +class CfgWeapons { + class ItemCore; + class InventoryItem_Base_F; + class InventoryMuzzleItem_Base_F; + class InventoryOpticsItem_Base_F; + + class optic_Hamr : ItemCore { + displayName = "HAMR 4x"; + descriptionShort = "High Accuracy Multi-Range Optic<br />Magnification: 4x<br />Reticle: CM-RW 6.5mm"; + scope = 2; + weaponInfoType = "AGM_RscWeapon"; + + AGM_Optics_enhanced = 1; + AGM_Optics_reticle = "\AGM_Optics\data\hamr\hamr-reticle65_ca.paa"; + AGM_Optics_reticleIllum = "\AGM_Optics\data\hamr\hamr-reticle65Illum_ca.paa"; + AGM_Optics_body = "\AGM_Optics\data\hamr\hamr-body_ca.paa"; + AGM_Optics_bodyNight = "\AGM_Optics\data\hamr\hamr-bodyNight_ca.paa"; + + model = "\A3\weapons_f\acc\acco_hamr_F"; + + class ItemInfo : InventoryOpticsItem_Base_F { + mass = 4; + optics = 1; + optictype = 1; + rmbhint = "HAMR"; + modeloptics = "\AGM_Optics\agm_optics_pip.p3d"; + + class OpticsModes { + class Hamr2Collimator { + AGM_Optics_enhanced = 0; + opticsID = 1; + useModelOptics = 0; + opticsppeffects[] = {}; + opticsFlare = 0; + opticsDisablePeripherialVision = 0; + opticsZoomMin = 0.375; + opticsZoomMax = 1; + opticsZoomInit = 0.75; + memoryPointCamera = "eye"; + visionMode[] = {}; + distanceZoomMin = 300; + distanceZoomMax = 300; + }; + + class Hamr2Scope { + cameradir = ""; + distanceZoomMin = 300; + distanceZoomMax = 300; + memorypointcamera = "opticView"; + opticsdisableperipherialvision = 0; + opticsdisplayname = "IHAMR"; + opticsflare = 1; + opticsid = 2; + opticsppeffects[] = {"OpticsCHAbera2", "OpticsBlur1", "AGM_OpticsRadBlur1"}; + opticszoominit = 0.0872664626; + opticszoommax = 0.0872664626; + opticszoommin = 0.0872664626; + discretefov[] = {0.0872664626}; + discreteinitindex = 0; + usemodeloptics = 1; + modeloptics = "\AGM_Optics\agm_optics_pip.p3d"; + visionmode[] = {"Normal", "NVG"}; + }; + }; + }; + }; + + class optic_Arco : ItemCore { + descriptionshort = "Advanced Rifle Combat Optic<br />Magnification: 4x<br />Reticle: SpecterDR 6.5mm"; + displayname = "ARCO 4x"; + picture = "\A3\weapons_F\Data\UI\gear_acco_Arco_CA.paa"; + scope = 2; + weaponInfoType = "AGM_RscWeapon"; + + model = "\A3\weapons_f\acc\acco_Arco_F"; + + AGM_Optics_enhanced = 1; + AGM_Optics_reticle = "\AGM_Optics\data\arco\arco-reticle65_ca.paa"; + AGM_Optics_reticleIllum = "\AGM_Optics\data\arco\arco-reticle65Illum_ca.paa"; + AGM_Optics_body = "\AGM_Optics\data\arco\arco-body_ca.paa"; + AGM_Optics_bodyNight = "\AGM_Optics\data\arco\arco-bodyNight_ca.paa"; + + class ItemInfo: InventoryOpticsItem_Base_F { + mass = 4; + optics = 1; + optictype = 1; + rmbhint = "ARCO"; + + class OpticsModes { + class ARCO2collimator { + AGM_Optics_enhanced = 0; + cameradir = ""; + distancezoommax = 300; + distancezoommin = 300; + memorypointcamera = "eye"; + opticsdisableperipherialvision = 0; + opticsdisplayname = "CQB"; + opticsflare = 0; + opticsid = 1; + opticsppeffects[] = {}; + opticszoominit = 0.75; + opticszoommax = 1.1; + opticszoommin = 0.375; + usemodeloptics = 0; + visionmode[] = {}; + }; + class ARCO2scope: ARCO2collimator { + cameradir = ""; + distanceZoomMin = 300; + distanceZoomMax = 300; + memorypointcamera = "opticView"; + opticsdisableperipherialvision = 0; + opticsdisplayname = "ARCO"; + opticsflare = 1; + opticsid = 2; + opticsppeffects[] = {"OpticsCHAbera2", "OpticsBlur1", "AGM_OpticsRadBlur1"}; + opticszoominit = 0.0872664626; // 0.0872664626 rad = 5 degrees + opticszoommax = 0.0872664626; // SpecterDR 4x is 6 degrees + opticszoommin = 0.0872664626; // Scope graphic in game covers 1 degree + discretefov[] = {0.0872664626}; + discreteinitindex = 0; + usemodeloptics = 1; + modeloptics = "\AGM_Optics\data\AGM_Optics_reticle90.p3d"; + visionmode[] = {"Normal"}; + }; + }; + }; + }; + + class optic_MRCO : ItemCore { + displayName = "MRCO 1x/4x"; + descriptionShort = "Medium Range Combat Optic<br />Magnification: 1x/4x<br />Reticle: Pitbull Gen II 5.56mm"; + scope = 2; + weaponInfoType = "AGM_RscWeapon"; + + AGM_Optics_enhanced = 1; + AGM_Optics_reticle = "\AGM_Optics\data\mrco\mrco-reticle556_ca.paa"; + AGM_Optics_reticleIllum = "\AGM_Optics\data\mrco\mrco-reticle556Illum_ca.paa"; + AGM_Optics_body = "\AGM_Optics\data\mrco\mrco-body_ca.paa"; + AGM_Optics_bodyNight = "\AGM_Optics\data\mrco\mrco-bodyNight_ca.paa"; + + class ItemInfo : InventoryOpticsItem_Base_F { + opticType = 1; + mass = 4; + optics = 1; + modelOptics = "\A3\Weapons_f_beta\acc\reticle_MRCO_F"; + + class OpticsModes { + class MRCOcq { + AGM_Optics_enhanced = 0; + opticsID = 1; + useModelOptics = 0; + opticsPPEffects[] = {}; + opticsFlare = 0; + opticsDisablePeripherialVision = 0; + opticsZoomMin = 0.375; + opticsZoomMax = 1; + opticsZoomInit = 0.75; + memoryPointCamera = "eye"; + visionMode[] = {}; + distanceZoomMin = 100; + distanceZoomMax = 100; + }; + + class MRCOscope { + cameradir = ""; + distanceZoomMin = 300; + distanceZoomMax = 300; + memorypointcamera = "eye"; + opticsdisableperipherialvision = 0; + opticsdisplayname = "MRCO"; + opticsflare = 1; + opticsid = 2; + opticsppeffects[] = {"OpticsCHAbera2", "OpticsBlur2", "AGM_OpticsRadBlur1"}; + opticszoominit = 0.0872664626; + opticszoommax = 0.0872664626; + opticszoommin = 0.0872664626; + discretefov[] = {0.0872664626}; + discreteinitindex = 0; + usemodeloptics = 1; + modeloptics = "\AGM_Optics\data\AGM_Optics_reticle90.p3d"; + visionmode[] = {"Normal"}; + }; + }; + }; + }; + + class optic_Nightstalker : ItemCore { + class ItemInfo: InventoryOpticsItem_Base_F { + class OpticsModes { + class NCTALKEP {}; + class Iron : NCTALKEP { + opticsppeffects[] = {}; // Fix Arma 3 bug + }; + }; + }; + }; + + class optic_SOS: ItemCore { + class ItemInfo: InventoryOpticsItem_Base_F { + modelOptics = "\AGM_Optics\agm_optics_pip.p3d"; + class OpticsModes { + class Snip { + visionMode[] = {"Normal","TI","NVG"}; + thermalMode[] = {5,6}; + opticsPPEffects[] = {"OpticsCHAbera1","radblur"}; + modelOptics[] = {"\AGM_Optics\agm_optics_pip.p3d","\AGM_Optics\agm_optics_pip.p3d"}; + }; + }; + + }; + }; + + class optic_DMS : ItemCore { + class ItemInfo: InventoryOpticsItem_Base_F { + class OpticsModes { + class Snip {}; + class Iron : Snip { + opticsppeffects[] = {}; // Fix Arma 3 bug + }; + }; + }; + }; + + class optic_LRPS : ItemCore { + descriptionshort = "Nightforce NXS Riflescope<br />Magnification: 5.5-22x"; + displayname = "NXS 5.5-22x"; + weaponinfotype = "AGM_RscWeapon"; + + AGM_Optics_enhanced = 1; + AGM_Optics_reticle = "\AGM_Optics\data\sos\sos-reticleMLR_ca.paa"; + AGM_Optics_reticleIllum = "\AGM_Optics\data\sos\sos-reticleMLRIllum_ca.paa"; + AGM_Optics_body = "\AGM_Optics\data\sos\sos-body_ca.paa"; + AGM_Optics_bodyNight = "\AGM_Optics\data\sos\sos-bodyNight_ca.paa"; + + class ItemInfo: InventoryOpticsItem_Base_F { + modeloptics = "\AGM_Optics\data\AGM_Optics_reticle90.p3d"; + weaponinfotype = "RscWeaponRangeZeroingFOV"; + opticType = 2; // Sniper optics + + class OpticsModes { + // Based on Nightforce NXS 5.5-22 scope + class Snip { + cameradir = ""; + discretedistance[] = {100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300}; + discretedistanceinitindex = 0; + discreteinitindex = 0; + distancezoommax = 2300; + distancezoommin = 100; + memorypointcamera = "opticView"; + modeloptics = "\AGM_Optics\data\AGM_Optics_reticle90.p3d"; + opticsdisableperipherialvision = 1; + opticsdisplayname = "SOS"; + opticsflare = 1; + opticsid = 1; + opticsppeffects[] = {"OpticsCHAbera1", "OpticsBlur1", "AGM_OpticsRadBlur1"}; + // How to determine opticszoom + // First do the basic math based on the listed FOV of the scope to + // get a baseline FOV + // 0.1 meter at 100 meters = 1 mrad + // + // 5.5x FOV -- 5.3 m at 100 m = 53 mrad + // = 0.053 rad = 3.037 deg FOV + + // 22x FOV -- 1.4 m at 100m = 14 mrad + // = 0.014 rad = 0.802 deg + + // The FOV you give the engine is based on a rather larger scope outline, so we + // have to do this extra work ourselves. + + // At 1680x1050 + // The width of a TMR optic viewfield is 864px + // The engine viewport width (which is what the below FOV is based on) is 980 + // (864/980) = (FOV to give engine / true FOV of optic) + // 864/980 * 0.053 = 0.04673 + // 864/980 * 0.014 = 0.01234 + + // Measured experimentally, these values seem quite right. + // Certainly they're close enough after you account for pixel density, etc. + + opticszoominit = 0.01234; + opticszoommax = 0.04673; + opticszoommin = 0.01234; + discretefov[] = {}; + usemodeloptics = 1; + visionmode[] = {"Normal"}; + }; + }; + }; + }; + + class optic_Yorris : ItemCore { + descriptionshort = "Burris FastFire II Red Dot Sight<br />Magnification: 1x"; + displayname = "FastFire II"; + }; + + class optic_MRD : ItemCore { + descriptionshort = "Eotech MRDS Red Dot Sight<br />Magnification: 1x"; + displayname = "MRDS"; + }; + + class optic_Holosight : ItemCore { + descriptionshort = "Eotech XPS3 Holographic Sight<br />Magnification: 1x"; + displayname = "XPS3 Holo"; + }; +}; + +class RscOpticsText; +class RscOpticsValue; +class RscInGameUI { + class RscUnitInfo; + class RscWeaponZeroing; + class AGM_RscWeapon : RscWeaponZeroing { + idd = -1; + controls[] = {"CA_Zeroing", "CA_FOVMode"}; + + onLoad ="with uiNameSpace do { AGM_OpticsIGUI = _this select 0 }"; + + class CA_FOVMode : RscOpticsValue { + idc = 154; + style = 2; + colorText[] = {0, 0, 0, 0}; + x = 0; + y = 0; + w = 0; + h = 0; + }; + }; +}; + +class RscTitles { + class AGM_Optics_Scope { + idd = -1; + onLoad = "with uiNameSpace do { AGM_Optics_Scope = _this select 0 };"; + onUnload = ""; + movingEnable = 1; + duration = 10000; + controls[] = {"Reticle", "ReticleNight", "BodyNight", "Body"}; + + class Reticle { + colorBackground[] = {0,0,0, 0}; + colorText[] = {1,1,1, 1}; + fade = 0; + font = "PuristaMedium"; + h = SafeZoneH; + idc = 1; + lineSpacing = 1.0; + movingEnable = 1; + size = 0; + sizeEx = 1; + style = 48; + text = ""; + type = 0; + w = SafeZoneWAbs / ((getResolution select 0) / (getResolution select 1)); + x = (SafeZoneXAbs + SafeZoneWAbs/2 - (SafeZoneWAbs / ((getResolution select 0) / (getResolution select 1)))/2); + y = SafeZoneY; + }; + + class ReticleNight : Reticle { + idc = 2; + text = ""; + }; + + class Body : Reticle { + idc = 6; + text = ""; + x = (SafeZoneXAbs + SafeZoneWAbs/2 - (SafeZoneWAbs / ((getResolution select 0) / (getResolution select 1)))); + y = SafeZoneY - (SafeZoneH/2); + w = SafeZoneWAbs / ((getResolution select 0) / (getResolution select 1)) * 2; + h = SafeZoneH * 2; + }; + + class BodyNight : Body { + idc = 5; + text = ""; + }; + }; +}; + +class PreloadTextures { + class CfgWeapons { + class optic_hamr { + AGM_Optics_body= "*"; + AGM_Optics_bodyNight = "*"; + AGM_Optics_reticle = "*"; + AGM_Optics_reticleIllum = "*"; + }; + class optic_arco { + AGM_Optics_body= "*"; + AGM_Optics_bodyNight = "*"; + AGM_Optics_reticle = "*"; + AGM_Optics_reticleIllum = "*"; + }; + class optic_mrco { + AGM_Optics_body= "*"; + AGM_Optics_bodyNight = "*"; + AGM_Optics_reticle = "*"; + AGM_Optics_reticleIllum = "*"; + }; + class optic_LRPS { + AGM_Optics_body= "*"; + AGM_Optics_bodyNight = "*"; + AGM_Optics_reticle = "*"; + AGM_Optics_reticleIllum = "*"; + }; + }; +}; diff --git a/TO_MERGE/agm/Optics/data/arco/arco-bodyNight_ca.paa b/TO_MERGE/agm/Optics/data/arco/arco-bodyNight_ca.paa new file mode 100644 index 0000000000..9b186b56f4 Binary files /dev/null and b/TO_MERGE/agm/Optics/data/arco/arco-bodyNight_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/arco/arco-body_ca.paa b/TO_MERGE/agm/Optics/data/arco/arco-body_ca.paa new file mode 100644 index 0000000000..193b14a92c Binary files /dev/null and b/TO_MERGE/agm/Optics/data/arco/arco-body_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/arco/arco-reticle65Illum_ca.paa b/TO_MERGE/agm/Optics/data/arco/arco-reticle65Illum_ca.paa new file mode 100644 index 0000000000..d193051e81 Binary files /dev/null and b/TO_MERGE/agm/Optics/data/arco/arco-reticle65Illum_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/arco/arco-reticle65_ca.paa b/TO_MERGE/agm/Optics/data/arco/arco-reticle65_ca.paa new file mode 100644 index 0000000000..671417fd4b Binary files /dev/null and b/TO_MERGE/agm/Optics/data/arco/arco-reticle65_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/black.rvmat b/TO_MERGE/agm/Optics/data/black.rvmat new file mode 100644 index 0000000000..431d76689f --- /dev/null +++ b/TO_MERGE/agm/Optics/data/black.rvmat @@ -0,0 +1,8 @@ +ambient[]={0,0,0,0.89999998}; +diffuse[]={0,0,0,0.89999998}; +forcedDiffuse[]={0,0,0,1}; +emmisive[]={0,0,0,1}; +specular[]={0,0,0,0}; +specularPower=1; +PixelShaderID="Normal"; +VertexShaderID="Basic"; diff --git a/TO_MERGE/agm/Optics/data/em.rvmat b/TO_MERGE/agm/Optics/data/em.rvmat new file mode 100644 index 0000000000..a491df4b9a --- /dev/null +++ b/TO_MERGE/agm/Optics/data/em.rvmat @@ -0,0 +1,20 @@ +ambient[]={1,1,1,1}; +diffuse[]={1,1,1,1}; +forcedDiffuse[]={0,0,0,0}; +emmisive[]={1,1,1,1}; +specular[]={1,0.99956858,1,1}; +specularPower=1; +PixelShaderID="Normal"; +VertexShaderID="Basic"; +class Stage1 +{ + texture="#(argb,8,8,3)color(0.5,0.5,0.5,0.5,DT)"; + uvSource="tex"; + class uvTransform + { + aside[]={1,0,0}; + up[]={0,1,0}; + dir[]={0,0,0}; + pos[]={0,0,0}; + }; +}; diff --git a/TO_MERGE/agm/Optics/data/hamr/hamr-bodyNight_ca.paa b/TO_MERGE/agm/Optics/data/hamr/hamr-bodyNight_ca.paa new file mode 100644 index 0000000000..422b13f7f1 Binary files /dev/null and b/TO_MERGE/agm/Optics/data/hamr/hamr-bodyNight_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/hamr/hamr-body_ca.paa b/TO_MERGE/agm/Optics/data/hamr/hamr-body_ca.paa new file mode 100644 index 0000000000..6b55916c5f Binary files /dev/null and b/TO_MERGE/agm/Optics/data/hamr/hamr-body_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/hamr/hamr-reticle65Illum_ca.paa b/TO_MERGE/agm/Optics/data/hamr/hamr-reticle65Illum_ca.paa new file mode 100644 index 0000000000..7af73234fc Binary files /dev/null and b/TO_MERGE/agm/Optics/data/hamr/hamr-reticle65Illum_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/hamr/hamr-reticle65_ca.paa b/TO_MERGE/agm/Optics/data/hamr/hamr-reticle65_ca.paa new file mode 100644 index 0000000000..2cbf329c89 Binary files /dev/null and b/TO_MERGE/agm/Optics/data/hamr/hamr-reticle65_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/mrco/mrco-bodyNight_ca.paa b/TO_MERGE/agm/Optics/data/mrco/mrco-bodyNight_ca.paa new file mode 100644 index 0000000000..381fdd3e97 Binary files /dev/null and b/TO_MERGE/agm/Optics/data/mrco/mrco-bodyNight_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/mrco/mrco-body_ca.paa b/TO_MERGE/agm/Optics/data/mrco/mrco-body_ca.paa new file mode 100644 index 0000000000..bfcaa9828f Binary files /dev/null and b/TO_MERGE/agm/Optics/data/mrco/mrco-body_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/mrco/mrco-reticle556Illum_ca.paa b/TO_MERGE/agm/Optics/data/mrco/mrco-reticle556Illum_ca.paa new file mode 100644 index 0000000000..5bf836d593 Binary files /dev/null and b/TO_MERGE/agm/Optics/data/mrco/mrco-reticle556Illum_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/mrco/mrco-reticle556_ca.paa b/TO_MERGE/agm/Optics/data/mrco/mrco-reticle556_ca.paa new file mode 100644 index 0000000000..e7b8599f83 Binary files /dev/null and b/TO_MERGE/agm/Optics/data/mrco/mrco-reticle556_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/scopeblack-100_ca.paa b/TO_MERGE/agm/Optics/data/scopeblack-100_ca.paa new file mode 100644 index 0000000000..d0232dc0cc Binary files /dev/null and b/TO_MERGE/agm/Optics/data/scopeblack-100_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/scopeblack-70_ca.paa b/TO_MERGE/agm/Optics/data/scopeblack-70_ca.paa new file mode 100644 index 0000000000..62b06d7f84 Binary files /dev/null and b/TO_MERGE/agm/Optics/data/scopeblack-70_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/scopeblack-80_ca.paa b/TO_MERGE/agm/Optics/data/scopeblack-80_ca.paa new file mode 100644 index 0000000000..f74e3e41f1 Binary files /dev/null and b/TO_MERGE/agm/Optics/data/scopeblack-80_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/scopeblack-90_ca.paa b/TO_MERGE/agm/Optics/data/scopeblack-90_ca.paa new file mode 100644 index 0000000000..2240dcc5fe Binary files /dev/null and b/TO_MERGE/agm/Optics/data/scopeblack-90_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/sos/sos-bodyNight_ca.paa b/TO_MERGE/agm/Optics/data/sos/sos-bodyNight_ca.paa new file mode 100644 index 0000000000..22f008b17a Binary files /dev/null and b/TO_MERGE/agm/Optics/data/sos/sos-bodyNight_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/sos/sos-body_ca.paa b/TO_MERGE/agm/Optics/data/sos/sos-body_ca.paa new file mode 100644 index 0000000000..37c6d47d63 Binary files /dev/null and b/TO_MERGE/agm/Optics/data/sos/sos-body_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/sos/sos-reticleMLRIllum_ca.paa b/TO_MERGE/agm/Optics/data/sos/sos-reticleMLRIllum_ca.paa new file mode 100644 index 0000000000..65d0afb2e2 Binary files /dev/null and b/TO_MERGE/agm/Optics/data/sos/sos-reticleMLRIllum_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/sos/sos-reticleMLR_ca.paa b/TO_MERGE/agm/Optics/data/sos/sos-reticleMLR_ca.paa new file mode 100644 index 0000000000..48bc7f4e00 Binary files /dev/null and b/TO_MERGE/agm/Optics/data/sos/sos-reticleMLR_ca.paa differ diff --git a/TO_MERGE/agm/Optics/data/tmr_optics_reticle100.p3d b/TO_MERGE/agm/Optics/data/tmr_optics_reticle100.p3d new file mode 100644 index 0000000000..365c9d5555 Binary files /dev/null and b/TO_MERGE/agm/Optics/data/tmr_optics_reticle100.p3d differ diff --git a/TO_MERGE/agm/Optics/data/tmr_optics_reticle70.p3d b/TO_MERGE/agm/Optics/data/tmr_optics_reticle70.p3d new file mode 100644 index 0000000000..cbb0181a17 Binary files /dev/null and b/TO_MERGE/agm/Optics/data/tmr_optics_reticle70.p3d differ diff --git a/TO_MERGE/agm/Optics/data/tmr_optics_reticle80.p3d b/TO_MERGE/agm/Optics/data/tmr_optics_reticle80.p3d new file mode 100644 index 0000000000..cbb0181a17 Binary files /dev/null and b/TO_MERGE/agm/Optics/data/tmr_optics_reticle80.p3d differ diff --git a/TO_MERGE/agm/Optics/data/tmr_optics_reticle90.p3d b/TO_MERGE/agm/Optics/data/tmr_optics_reticle90.p3d new file mode 100644 index 0000000000..c2f1ae5ceb Binary files /dev/null and b/TO_MERGE/agm/Optics/data/tmr_optics_reticle90.p3d differ diff --git a/TO_MERGE/agm/Optics/data/tmr_reticle_clear.p3d b/TO_MERGE/agm/Optics/data/tmr_reticle_clear.p3d new file mode 100644 index 0000000000..89a29d7d8c Binary files /dev/null and b/TO_MERGE/agm/Optics/data/tmr_reticle_clear.p3d differ diff --git a/TO_MERGE/agm/Optics/functions/fn_firedEH.sqf b/TO_MERGE/agm/Optics/functions/fn_firedEH.sqf new file mode 100644 index 0000000000..1030fceefd --- /dev/null +++ b/TO_MERGE/agm/Optics/functions/fn_firedEH.sqf @@ -0,0 +1,149 @@ +/* + * Original Author: Taosenai + * Adapted By: KoffeinFlummi + * + * Animates the scope when firing. + * + * Arguments: + * 0: Unit + * 1: Weapon + * 2: Muzzle + * 3: Mode + * 4: Ammo + * 5: Magazine + * 6: Projectile + * + * Return Value: + * None + */ + +if (_this select 0 != AGM_player) exitwith {}; // Sanity check + +0 = _this spawn { + disableSerialization; + + _weaponType = _this select 1; + _config = configFile >> "CfgWeapons" >> _weaponType; + _scope = uiNameSpace getVariable "AGM_Optics_Scope"; + + // @todo + _recoilMulti = getNumber (_config >> "tmr_smallarms_recoil_shakeMultiplier"); // Will be 0 if undefined + + if (_recoilMulti == 0) then { + _recoilMulti = 1; + }; + if (_recoilMulti > 2.6) then { + _recoilMulti = 2.6; // Don't get too high + }; + + // Reduce the reticle movement as the player drops into lower, supported stances. + _detectStance = (player selectionPosition "Neck" select 2); + if (_detectStance < 1.3) then { + _recoilMulti = _recoilMulti - 0.10; + }; + if (_detectStance < 0.7) then { + _recoilMulti = _recoilMulti - 0.20; + }; + + // Reduce reticle movement if the player is rested (tmr_autorest). + if (player getVariable ["tmr_autorest_rested", false]) then { + _recoilMulti = _recoilMulti - 0.20; + }; + + // Reduce reticle movement if the player is deployed (tmr_autorest). + if (player getVariable ["tmr_autorest_deployed", false]) then { + _recoilMulti = _recoilMulti - 0.30; + }; + _recoilMulti = 1; + // @endtodo + + + // Constants which determine how the scope recoils + _recoilScope = 0.03 * _recoilMulti + random 0.0015; + _recoilRing = 0.03 * _recoilMulti + random 0.0015; + + _randomScopeShiftX = 0.005 * _recoilMulti - random 0.011; + + _randomReticleShiftX = 0.0036 * _recoilMulti + random 0.0045; // Always tend up and right; + _randomReticleShiftY = -0.0046 * _recoilMulti - random 0.0055; + + ///////// + // Center everything + + // getResolution select 4 should return the aspect ratio, but it's totally wrong + // for triple head displays. We'll compute it manually. + _aspectRatio = (getResolution select 0) / (getResolution select 1); + + _reticleX = (SafeZoneXAbs + SafeZoneWAbs/2 - (SafeZoneWAbs / _aspectRatio)/2); + _reticleY = SafeZoneY; + _reticleW = SafeZoneWAbs / _aspectRatio; + _reticleH = SafeZoneH; + + // Reticle + (_scope displayCtrl 1) ctrlSetPosition [_reticleX, _reticleY, _reticleW, _reticleH]; + // Reticle night (illum) + (_scope displayCtrl 2) ctrlSetPosition [_reticleX, _reticleY, _reticleW, _reticleH]; + + _bodyX = (SafeZoneXAbs + SafeZoneWAbs/2 - (SafeZoneWAbs / _aspectRatio)); + _bodyY = SafeZoneY - (SafeZoneH/2); + _bodyW = SafeZoneWAbs / _aspectRatio * 2; + _bodyH = SafeZoneH * 2; + + // Body night + (_scope displayCtrl 5) ctrlSetPosition [_bodyX, _bodyY, _bodyW, _bodyH]; + // Body + (_scope displayCtrl 6) ctrlSetPosition [_bodyX, _bodyY, _bodyW, _bodyH]; + + _centerDelay = 0.01; + (_scope displayCtrl 1) ctrlCommit _centerDelay; + (_scope displayCtrl 2) ctrlCommit _centerDelay; + (_scope displayCtrl 5) ctrlCommit _centerDelay; + (_scope displayCtrl 6) ctrlCommit _centerDelay; + + ///////// + // Create and commit recoil effect + + // Move reticle + + (_scope displayCtrl 1) ctrlSetPosition [_reticleX - (_recoilScope/2) + _randomReticleShiftX, _reticleY - (_recoilScope/2) + _randomReticleShiftY, _reticleW + _recoilScope, _reticleH + _recoilScope]; + (_scope displayCtrl 2) ctrlSetPosition [_reticleX - (_recoilScope/2) + _randomReticleShiftX, _reticleY - (_recoilScope/2) + _randomReticleShiftY, _reticleW + _recoilScope, _reticleH + _recoilScope]; + + // Move body + + (_scope displayCtrl 5) ctrlSetPosition [_bodyX - (_recoilScope/2) + _randomScopeShiftX, _bodyY - (_recoilScope/2), _bodyW + _recoilScope, _bodyH + _recoilScope]; + (_scope displayCtrl 6) ctrlSetPosition [_bodyX - (_recoilScope/2) + _randomScopeShiftX, _bodyY - (_recoilScope/2), _bodyW + _recoilScope, _bodyH + _recoilScope]; + + _recoilDelay = 0.036; + _fa = false; + _cwm = currentWeaponMode player; + if (_cwm == "FullAuto" || _cwm == "manual" || _cwm == "Burst") then { + _recoilDelay = getNumber (_config >> _cwm >> "reloadTime")/2.2; + _fa = true; + }; + (_scope displayCtrl 1) ctrlCommit _recoilDelay; + (_scope displayCtrl 2) ctrlCommit _recoilDelay; + (_scope displayCtrl 5) ctrlCommit _recoilDelay; + (_scope displayCtrl 6) ctrlCommit _recoilDelay; + + ////////////// + + waituntil {sleep 0.01; ctrlCommitted (_scope displayCtrl 6)}; + + ////////////// + + ////// + // Bring them all back + (_scope displayCtrl 1) ctrlSetPosition [_reticleX, _reticleY, _reticleW, _reticleH]; + (_scope displayCtrl 2) ctrlSetPosition [_reticleX, _reticleY, _reticleW, _reticleH]; + (_scope displayCtrl 5) ctrlSetPosition [_bodyX, _bodyY, _bodyW, _bodyH]; + (_scope displayCtrl 6) ctrlSetPosition [_bodyX, _bodyY, _bodyW, _bodyH]; + + _recenterDelay = 0.09; + if (_fa) then { + _recenterDelay = getNumber (_config >> _cwm >> "reloadTime")/2.2; + }; + (_scope displayCtrl 1) ctrlCommit _recenterDelay; + (_scope displayCtrl 2) ctrlCommit _recenterDelay; + (_scope displayCtrl 5) ctrlCommit _recenterDelay; + (_scope displayCtrl 6) ctrlCommit _recenterDelay; +}; diff --git a/TO_MERGE/agm/Optics/functions/fn_hideScope.sqf b/TO_MERGE/agm/Optics/functions/fn_hideScope.sqf new file mode 100644 index 0000000000..8b048f1bd7 --- /dev/null +++ b/TO_MERGE/agm/Optics/functions/fn_hideScope.sqf @@ -0,0 +1,19 @@ +/* + * Original Author: Taosenai + * Adapted By: KoffeinFlummi + * + * Hides the scope. + * + */ + +private ["_scope"]; + +((uiNameSpace getVariable "AGM_Optics_Scope") displayCtrl 1) ctrlSetTextColor [1,1,1,0]; +((uiNameSpace getVariable "AGM_Optics_Scope") displayCtrl 2) ctrlSetTextColor [1,1,1,0]; +((uiNameSpace getVariable "AGM_Optics_Scope") displayCtrl 5) ctrlSetTextColor [1,1,1,0]; +((uiNameSpace getVariable "AGM_Optics_Scope") displayCtrl 6) ctrlSetTextColor [1,1,1,0]; + +((uiNameSpace getVariable "AGM_Optics_Scope") displayCtrl 1) ctrlCommit 0; +((uiNameSpace getVariable "AGM_Optics_Scope") displayCtrl 2) ctrlCommit 0; +((uiNameSpace getVariable "AGM_Optics_Scope") displayCtrl 5) ctrlCommit 0; +((uiNameSpace getVariable "AGM_Optics_Scope") displayCtrl 6) ctrlCommit 0; diff --git a/TO_MERGE/agm/Optics/functions/fn_initScope.sqf b/TO_MERGE/agm/Optics/functions/fn_initScope.sqf new file mode 100644 index 0000000000..f2e078ebbe --- /dev/null +++ b/TO_MERGE/agm/Optics/functions/fn_initScope.sqf @@ -0,0 +1,25 @@ +/* + * Original Author: Taosenai + * Adapted By: KoffeinFlummi + * + * Initializes the scope resources. + * + */ + +private ["_display"]; + +// Make sure we only cutRsc when the resource isn't already available +if (isNil {uiNameSpace getVariable "AGM_Optics_Scope"} or {isNull (uiNameSpace getVariable "AGM_Optics_Scope")}) exitWith { + AGM_Optics_scopeRSC cutRsc ["AGM_Optics_Scope","PLAIN",0]; + ((uiNameSpace getVariable "AGM_Optics_Scope") displayCtrl 1) ctrlSetTextColor [1,1,1,0]; + ((uiNameSpace getVariable "AGM_Optics_Scope") displayCtrl 2) ctrlSetTextColor [1,1,1,0]; + ((uiNameSpace getVariable "AGM_Optics_Scope") displayCtrl 5) ctrlSetTextColor [1,1,1,0]; + ((uiNameSpace getVariable "AGM_Optics_Scope") displayCtrl 6) ctrlSetTextColor [1,1,1,0]; + + ((uiNameSpace getVariable "AGM_Optics_Scope") displayCtrl 1) ctrlCommit 0; + ((uiNameSpace getVariable "AGM_Optics_Scope") displayCtrl 2) ctrlCommit 0; + ((uiNameSpace getVariable "AGM_Optics_Scope") displayCtrl 5) ctrlCommit 0; + ((uiNameSpace getVariable "AGM_Optics_Scope") displayCtrl 6) ctrlCommit 0; + True +}; +False diff --git a/TO_MERGE/agm/Optics/functions/fn_mainLoop.sqf b/TO_MERGE/agm/Optics/functions/fn_mainLoop.sqf new file mode 100644 index 0000000000..e73b56db37 --- /dev/null +++ b/TO_MERGE/agm/Optics/functions/fn_mainLoop.sqf @@ -0,0 +1,94 @@ +/* + * Original Author: Taosenai + * Adapted By: KoffeinFlummi + * + * Monitors the RscInGameUI and displays the overlays when needed. + * + * Arguments: + * None + * + * Return Value: + * None + */ + +if !(cameraOn == AGM_player && {alive AGM_player} && {!visibleMap} && {ctrlShown ((uinamespace getVariable "AGM_OpticsIGUI") displayCtrl 154)}) exitWith { + // Failed the state check, hide the scope if it's up + if (AGM_Optics_inScope) then { + // Hide the scope + AGM_Optics_inScope = false; + AGM_Optics_inScope_FOV = ([] call cba_fnc_getFOV) select 0; + + [] call AGM_Optics_fnc_hideScope; + }; +}; + +AGM_Optics_Camera setposATL (positioncameratoworld [0,0,0.4]); +AGM_Optics_Camera camPrepareTarget (positioncameratoworld [0,0,50]); +AGM_Optics_Camera camCommitPrepared 0; + +if (cameraView == "Gunner") then { + AGM_Optics_Camera camsetFOV 0.7; + AGM_Optics_Camera camcommit 0; +} else { + AGM_Optics_Camera camsetFOV 0.01; + AGM_Optics_Camera camcommit 0; +}; + +private ["_optic", "_scope"]; + +disableSerialization; + +// Get the name of the attached optic +_optic = (primaryWeaponItems AGM_player) select 2; +_scope = uiNameSpace getVariable "AGM_Optics_Scope"; + +// Init the scope (if needed) +[] call AGM_Optics_fnc_initScope; + +// Check if the optic has changed since we last drew it +_doUpdateAllLayers = false; +if (AGM_Optics_currentOptic != _optic) then { + AGM_Optics_currentOptic = _optic; + _doUpdateAllLayers = true; +}; + +// Check if Splendid Camera, unit switch, etc. has blanked out our displays for no good reason (grrr) +if (ctrlText (_scope displayCtrl 1) == "") then { + _doUpdateAllLayers = true; +}; + +// Draw the correct layers (don't show them) +if (_doUpdateAllLayers) then { + (_scope displayCtrl 1) ctrlSetText getText (configFile >> "CfgWeapons" >> _optic >> "AGM_Optics_reticle"); + (_scope displayCtrl 2) ctrlSetText getText (configFile >> "CfgWeapons" >> _optic >> "AGM_Optics_reticleIllum"); + (_scope displayCtrl 5) ctrlSetText getText (configFile >> "CfgWeapons" >> _optic >> "AGM_Optics_bodyNight"); + (_scope displayCtrl 6) ctrlSetText getText (configFile >> "CfgWeapons" >> _optic >> "AGM_Optics_body"); +}; + +// Stop processing if already in the scope view and FOV hasn't changed +if (AGM_Optics_inScope) exitwith {}; + +// Mark that we're in enhanced scope view +AGM_Optics_inScope = true; + +// Calculate lighting +_lighting = sunOrMoon; // 1 is day, 0 is night + +_nightOpacity = 1; +_dayOpacity = (0 max moonIntensity * (1 - (0 max overcast)))/5; + +if (_lighting == 1) then { + _nightOpacity = 0; + _dayOpacity = 1; +}; + +// Apply lighting and make layers visible +(_scope displayCtrl 1) ctrlSetTextColor [1,1,1,1]; +(_scope displayCtrl 2) ctrlSetTextColor [1,1,1,_nightOpacity]; +(_scope displayCtrl 5) ctrlSetTextColor [1,1,1,_nightOpacity]; +(_scope displayCtrl 6) ctrlSetTextColor [1,1,1,_dayOpacity]; + +(_scope displayCtrl 1) ctrlCommit 0; +(_scope displayCtrl 2) ctrlCommit 0; +(_scope displayCtrl 5) ctrlCommit 0; +(_scope displayCtrl 6) ctrlCommit 0; diff --git a/addons/common/functions/fnc_progressBar.sqf b/addons/common/functions/fnc_progressBar.sqf index 15fbab1e24..69b91237e6 100644 --- a/addons/common/functions/fnc_progressBar.sqf +++ b/addons/common/functions/fnc_progressBar.sqf @@ -1,24 +1,24 @@ /* -* Author: commy2, Glowbal, PabstMirror -* -* Draw progress bar and execute given function if succesful. -* Finish/Failure/Conditional are all passed [_args, _elapsedTime, _totalTime, _errorCode] -* -* Argument: -* 0: NUMBER - Total Time (in game "time" seconds) -* 1: ARRAY - Arguments, passed to condition, fail and finish -* 2: CODE or STRING - On Finish: Code called or STRING raised as event. -* 3: CODE or STRING - On Failure: Code called or STRING raised as event. -* 4: STRING - (Optional) Localized Title -* 5: CODE - (Optional) Code to check each frame -* 6: ARRAY - (Optional) Exceptions for checking EGVAR(common,canInteractWith) -* -* Return value: -* Nothing -* -* Example: -* [5, [], {Hint "Finished!"}, {hint "Failure!"}, "My Title"] call ace_common_fnc_progressBar -*/ + * Author: commy2, Glowbal, PabstMirror + * + * Draw progress bar and execute given function if succesful. + * Finish/Failure/Conditional are all passed [_args, _elapsedTime, _totalTime, _errorCode] + * + * Argument: + * 0: NUMBER - Total Time (in game "time" seconds) + * 1: ARRAY - Arguments, passed to condition, fail and finish + * 2: CODE or STRING - On Finish: Code called or STRING raised as event. + * 3: CODE or STRING - On Failure: Code called or STRING raised as event. + * 4: STRING - (Optional) Localized Title + * 5: CODE - (Optional) Code to check each frame + * 6: ARRAY - (Optional) Exceptions for checking EFUNC(common,canInteractWith) + * + * Return value: + * Nothing + * + * Example: + * [5, [], {Hint "Finished!"}, {hint "Failure!"}, "My Title"] call ace_common_fnc_progressBar + */ #include "script_component.hpp" @@ -36,65 +36,69 @@ createDialog QGVAR(ProgressBar_Dialog); (uiNamespace getVariable QGVAR(ctrlProgressBarTitle)) ctrlSetText _localizedTitle; if (GVAR(SettingProgressBarLocation) == 1) then { - private "_ctrlPos"; - _ctrlPos = [1 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2), 29 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2), 38 * (((safezoneW / safezoneH) min 1.2) / 40), 0.8 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)]; - (uiNamespace getVariable QGVAR(ctrlProgressBar)) ctrlSetPosition _ctrlPos; - (uiNamespace getVariable QGVAR(ctrlProgressBarTitle)) ctrlSetPosition _ctrlPos; - (uiNamespace getVariable QGVAR(ctrlProgressBar)) ctrlCommit 0; - (uiNamespace getVariable QGVAR(ctrlProgressBarTitle)) ctrlCommit 0; + private "_ctrlPos"; + _ctrlPos = [1 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2), 29 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2), 38 * (((safezoneW / safezoneH) min 1.2) / 40), 0.8 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)]; + (uiNamespace getVariable QGVAR(ctrlProgressBar)) ctrlSetPosition _ctrlPos; + (uiNamespace getVariable QGVAR(ctrlProgressBarTitle)) ctrlSetPosition _ctrlPos; + (uiNamespace getVariable QGVAR(ctrlProgressBar)) ctrlCommit 0; + (uiNamespace getVariable QGVAR(ctrlProgressBarTitle)) ctrlCommit 0; }; _perFrameFunction = { - PARAMS_2(_parameters,_pfhID); - EXPLODE_8_PVT(_parameters,_args,_onFinish,_onFail,_condition,_player,_startTime,_totalTime,_exceptions); - private ["_elapsedTime", "_errorCode"]; + PARAMS_2(_parameters,_pfhID); + EXPLODE_8_PVT(_parameters,_args,_onFinish,_onFail,_condition,_player,_startTime,_totalTime,_exceptions); + private ["_elapsedTime", "_errorCode"]; - _elapsedTime = time - _startTime; - _errorCode = -1; + _elapsedTime = time - _startTime; + _errorCode = -1; - if (isNull (uiNamespace getVariable [QGVAR(ctrlProgressBar), controlNull])) then { - _errorCode = 1; - } else { - if (ACE_player != _player) then { - _errorCode = 2; + if (isNull (uiNamespace getVariable [QGVAR(ctrlProgressBar), controlNull])) then { + _errorCode = 1; } else { - if (!([_args, _elapsedTime, _totalTime, _errorCode] call _condition)) then { - _errorCode = 3; - } else { - if (!([_player, objNull, _exceptions] call EGVAR(common,canInteractWith))) then { - _errorCode = 4; + if (ACE_player != _player) then { + _errorCode = 2; } else { - if (_elapsedTime >= _totalTime) then { - _errorCode = 0; - }; + if (!([_args, _elapsedTime, _totalTime, _errorCode] call _condition)) then { + _errorCode = 3; + } else { + if (!([_player, objNull, _exceptions] call EFUNC(common,canInteractWith))) then { + _errorCode = 4; + } else { + if (_elapsedTime >= _totalTime) then { + _errorCode = 0; + }; + }; + }; }; - }; }; - }; - if (_errorCode != -1) then { - //Error or Success, close dialog and remove PFEH - closeDialog 0; - [_pfhID] call CBA_fnc_removePerFrameHandler; + if (_errorCode != -1) then { + //Error or Success, close dialog and remove PFEH - if (_errorCode == 0) then { - if ((typeName _onFinish) == (typeName "")) then { - [_onFinish, [_args, _elapsedTime, _totalTime, _errorCode]] call FUNC(localEvent); - } else { - [_args, _elapsedTime, _totalTime, _errorCode] call _onFinish; - }; + //Only close dialog if it's the progressBar: + if (!isNull (uiNamespace getVariable [QGVAR(ctrlProgressBar), controlNull])) then { + closeDialog 0; + }; + [_pfhID] call CBA_fnc_removePerFrameHandler; + + if (_errorCode == 0) then { + if ((typeName _onFinish) == (typeName "")) then { + [_onFinish, [_args, _elapsedTime, _totalTime, _errorCode]] call FUNC(localEvent); + } else { + [_args, _elapsedTime, _totalTime, _errorCode] call _onFinish; + }; + } else { + if ((typeName _onFail) == (typeName "")) then { + [_onFail, [_args, _elapsedTime, _totalTime, _errorCode]] call FUNC(localEvent); + } else { + [_args, _elapsedTime, _totalTime, _errorCode] call _onFail; + }; + }; } else { - if ((typeName _onFail) == (typeName "")) then { - [_onFail, [_args, _elapsedTime, _totalTime, _errorCode]] call FUNC(localEvent); - } else { - [_args, _elapsedTime, _totalTime, _errorCode] call _onFail; - }; + //Update Progress Bar (ratio of elepased:total) + (uiNamespace getVariable QGVAR(ctrlProgressBar)) progressSetPosition (_elapsedTime / _totalTime); }; - } else { - //Update Progress Bar (ratio of elepased:total) - (uiNamespace getVariable QGVAR(ctrlProgressBar)) progressSetPosition (_elapsedTime / _totalTime); - }; }; [_perFrameFunction, 0, [_args, _onFinish, _onFail, _condition, _player, time, _totalTime, _exceptions]] call CBA_fnc_addPerFrameHandler; diff --git a/tools/ace_build_tool/pabstFrankensteinBuilder.py b/tools/ace_build_tool/pabstFrankensteinBuilder.py new file mode 100644 index 0000000000..eb35f1c7e5 --- /dev/null +++ b/tools/ace_build_tool/pabstFrankensteinBuilder.py @@ -0,0 +1,776 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +# make.py +# An Arma 3 addon build system + +############################################################################### + +# The MIT License (MIT) + +# Copyright (c) 2013-2014 Ryan Schultz + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +############################################################################### + +__version__ = "0.3dev" + +import sys + +if sys.version_info[0] == 2: + print("Python 3 is required.") + sys.exit(1) + +import os +import os.path +import shutil +import platform +import glob +import subprocess +import hashlib +import configparser +import json +import traceback + +if sys.platform == "win32": + import winreg + +############################################################################### +# http://akiscode.com/articles/sha-1directoryhash.shtml +# Copyright (c) 2009 Stephen Akiki +# MIT License (Means you can do whatever you want with this) +# See http://www.opensource.org/licenses/mit-license.php +# Error Codes: +# -1 -> Directory does not exist +# -2 -> General error (see stack traceback) +def get_directory_hash(directory): + directory_hash = hashlib.sha1() + if not os.path.exists (directory): + return -1 + + try: + for root, dirs, files in os.walk(directory): + for names in files: + path = os.path.join(root, names) + try: + f = open(path, 'rb') + except: + # You can't open the file for some reason + f.close() + continue + + while 1: + # Read file in as little chunks + buf = f.read(4096) + if not buf: break + new = hashlib.sha1(buf) + directory_hash.update(new.digest()) + f.close() + + except: + # Print the stack traceback + traceback.print_exc() + return -2 + + return directory_hash.hexdigest() + +# Copyright (c) André Burgaud +# http://www.burgaud.com/bring-colors-to-the-windows-console-with-python/ +if sys.platform == "win32": + from ctypes import windll, Structure, c_short, c_ushort, byref + + SHORT = c_short + WORD = c_ushort + + class COORD(Structure): + """struct in wincon.h.""" + _fields_ = [ + ("X", SHORT), + ("Y", SHORT)] + + class SMALL_RECT(Structure): + """struct in wincon.h.""" + _fields_ = [ + ("Left", SHORT), + ("Top", SHORT), + ("Right", SHORT), + ("Bottom", SHORT)] + + class CONSOLE_SCREEN_BUFFER_INFO(Structure): + """struct in wincon.h.""" + _fields_ = [ + ("dwSize", COORD), + ("dwCursorPosition", COORD), + ("wAttributes", WORD), + ("srWindow", SMALL_RECT), + ("dwMaximumWindowSize", COORD)] + + # winbase.h + STD_INPUT_HANDLE = -10 + STD_OUTPUT_HANDLE = -11 + STD_ERROR_HANDLE = -12 + + # wincon.h + FOREGROUND_BLACK = 0x0000 + FOREGROUND_BLUE = 0x0001 + FOREGROUND_GREEN = 0x0002 + FOREGROUND_CYAN = 0x0003 + FOREGROUND_RED = 0x0004 + FOREGROUND_MAGENTA = 0x0005 + FOREGROUND_YELLOW = 0x0006 + FOREGROUND_GREY = 0x0007 + FOREGROUND_INTENSITY = 0x0008 # foreground color is intensified. + + BACKGROUND_BLACK = 0x0000 + BACKGROUND_BLUE = 0x0010 + BACKGROUND_GREEN = 0x0020 + BACKGROUND_CYAN = 0x0030 + BACKGROUND_RED = 0x0040 + BACKGROUND_MAGENTA = 0x0050 + BACKGROUND_YELLOW = 0x0060 + BACKGROUND_GREY = 0x0070 + BACKGROUND_INTENSITY = 0x0080 # background color is intensified. + + stdout_handle = windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE) + SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute + GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo + + def get_text_attr(): + """Returns the character attributes (colors) of the console screen + buffer.""" + csbi = CONSOLE_SCREEN_BUFFER_INFO() + GetConsoleScreenBufferInfo(stdout_handle, byref(csbi)) + return csbi.wAttributes + + def set_text_attr(color): + """Sets the character attributes (colors) of the console screen + buffer. Color is a combination of foreground and background color, + foreground and background intensity.""" + SetConsoleTextAttribute(stdout_handle, color) +############################################################################### + +def find_bi_tools(work_drive): + """Find BI tools.""" + + reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER) + try: + k = winreg.OpenKey(reg, r"Software\bohemia interactive\arma 3 tools") + arma3tools_path = winreg.QueryValueEx(k, "path")[0] + winreg.CloseKey(k) + except: + raise Exception("BadTools","Arma 3 Tools are not installed correctly or the P: drive needs to be created.") + + addonbuilder_path = os.path.join(arma3tools_path, "AddonBuilder", "AddonBuilder.exe") + dssignfile_path = os.path.join(arma3tools_path, "DSSignFile", "DSSignFile.exe") + dscreatekey_path = os.path.join(arma3tools_path, "DSSignFile", "DSCreateKey.exe") + + if os.path.isfile(addonbuilder_path) and os.path.isfile(dssignfile_path) and os.path.isfile(dscreatekey_path): + return [addonbuilder_path, dssignfile_path, dscreatekey_path] + else: + raise Exception("BadTools","Arma 3 Tools are not installed correctly or the P: drive needs to be created.") + +def find_depbo_tools(): + """Use registry entries to find DePBO-based tools.""" + + reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER) + try: + k = winreg.OpenKey(reg, r"Software\Mikero\pboProject") + try: + pboproject_path = winreg.QueryValueEx(k, "exe")[0] + winreg.CloseKey(k) + print("Found pboproject.") + except: + print_error("ERROR: Could not find pboProject.") + + k = winreg.OpenKey(reg, r"Software\Mikero\rapify") + try: + rapify_path = winreg.QueryValueEx(k, "exe")[0] + winreg.CloseKey(k) + print("Found rapify.") + except: + print_error("Could not find rapify.") + + k = winreg.OpenKey(reg, r"Software\Mikero\MakePbo") + try: + makepbo_path = winreg.QueryValueEx(k, "exe")[0] + winreg.CloseKey(k) + print("Found makepbo.") + except: + print_error("Could not find makepbo.") + except: + raise Exception("BadDePBO", "DePBO tools not installed correctly") + + #Strip any quotations from the path due to a MikeRo tool bug which leaves a trailing space in some of its registry paths. + return [pboproject_path.strip('"'),rapify_path.strip('"'),makepbo_path.strip('"')] + +def color(color): + """Set the color. Works on Win32 and normal terminals.""" + if sys.platform == "win32": + if color == "green": + set_text_attr(FOREGROUND_GREEN | get_text_attr() & 0x0070 | FOREGROUND_INTENSITY) + elif color == "red": + set_text_attr(FOREGROUND_RED | get_text_attr() & 0x0070 | FOREGROUND_INTENSITY) + elif color == "blue": + set_text_attr(FOREGROUND_BLUE | get_text_attr() & 0x0070 | FOREGROUND_INTENSITY) + elif color == "reset": + set_text_attr(FOREGROUND_GREY | get_text_attr() & 0x0070) + elif color == "grey": + set_text_attr(FOREGROUND_GREY | get_text_attr() & 0x0070) + else : + if color == "green": + sys.stdout.write('\033[92m') + elif color == "red": + sys.stdout.write('\033[91m') + elif color == "blue": + sys.stdout.write('\033[94m') + elif color == "reset": + sys.stdout.write('\033[0m') + +def print_error(msg): + color("red") + print ("ERROR: " + msg) + color("reset") + +def print_green(msg): + color("green") + print(msg) + color("reset") + +def print_blue(msg): + color("blue") + print(msg) + color("reset") + +def print_yellow(msg): + color("yellow") + print(msg) + color("reset") + +############################################################################### + +def main(argv): + """Build an Arma addon suite in a directory from rules in a make.cfg file.""" + print_blue(("\nmake.py for Arma, v" + __version__)) + + if sys.platform != "win32": + print_error("Non-Windows platform (Cygwin?). Please re-run from cmd.") + sys.exit(1) + + reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER) + try: + k = winreg.OpenKey(reg, r"Software\bohemia interactive\arma 3 tools") + arma3tools_path = winreg.QueryValueEx(k, "path")[0] + winreg.CloseKey(k) + except: + raise Exception("BadTools","Arma 3 Tools are not installed correctly or the P: drive needs to be created.") + + # Default behaviors + test = False # Copy to Arma 3 directory? + arg_modules = False # Only build modules on command line? + make_release = False # Make zip file from the release? + release_version = 0 # Version of release + use_pboproject = True # Default to pboProject build tool + make_target = "DEFAULT" # Which section in make.cfg to use for the build + new_key = False # Make a new key and use it to sign? + quiet = False # Suppress output from build tool? + + # Parse arguments + if "help" in argv or "-h" in argv or "--help" in argv: + print (""" +make.py [help] [test] [force] [key <name>] [target <name>] [release <version>] + [module name] [module name] [...] + +test -- Copy result to Arma 3. +release <version> -- Make archive with <version>. +force -- Ignore cache and build all. +target <name> -- Use rules in make.cfg under heading [<name>] rather than + default [Make] +key <name> -- Use key in working directory with <name> to sign. If it does not + exist, create key. +quiet -- Suppress command line output from build tool. + +If module names are specified, only those modules will be built. + +Examples: + make.py force test + Build all modules (ignoring cache) and copy the mod folder to the Arma 3 + directory. + make.py mymodule_gun + Only build the module named 'mymodule_gun'. + make.py force key MyNewKey release 1.0 + Build all modules (ignoring cache), sign them with NewKey, and pack them + into a zip file for release with version 1.0. + + +If a file called $NOBIN$ is found in the module directory, that module will not be binarized. + +See the make.cfg file for additional build options. +""") + sys.exit(0) + + if "force" in argv: + argv.remove("force") + force_build = True + else: + force_build = False + + if "test" in argv: + test = True + argv.remove("test") + + if "release" in argv: + make_release = True + release_version = argv[argv.index("release") + 1] + argv.remove(release_version) + argv.remove("release") + + if "target" in argv: + make_target = argv[argv.index("target") + 1] + argv.remove("target") + argv.remove(make_target) + force_build = True + + if "key" in argv: + new_key = True + key_name = argv[argv.index("key") + 1] + argv.remove("key") + argv.remove(key_name) + + if "quiet" in argv: + quiet = True + argv.remove("quiet") + + # Get the directory the make script is in. + make_root = os.path.dirname(os.path.realpath(__file__)) + make_root_parent = os.path.abspath(os.path.join(os.getcwd(), os.pardir)) + os.chdir(make_root) + + cfg = configparser.ConfigParser(); + try: + cfg.read(os.path.join(make_root, "make.cfg")) + + # Project name (with @ symbol) + project = cfg.get(make_target, "project", fallback="@"+os.path.basename(os.getcwd())) + + # Private key path + key = cfg.get(make_target, "key", fallback=None) + + # Project prefix (folder path) + prefix = cfg.get(make_target, "prefix", fallback="") + + # Should we autodetect modules on a complete build? + module_autodetect = cfg.getboolean(make_target, "module_autodetect", fallback=True) + + # Manual list of modules to build for a complete build + modules = cfg.get(make_target, "modules", fallback=None) + # Parse it out + if modules: + modules = [x.strip() for x in modules.split(',')] + else: + modules = [] + + # List of directories to ignore when detecting + ignore = [x.strip() for x in cfg.get(make_target, "ignore", fallback="release").split(',')] + + # BI Tools work drive on Windows + work_drive = cfg.get(make_target, "work_drive", fallback="P:\\") + + # Which build tool should we use? + build_tool = "pboproject" + + # Release/build directory, relative to script dir + release_dir = cfg.get(make_target, "release_dir", fallback="release") + + # Project PBO file prefix (files are renamed to prefix_name.pbo) + pbo_name_prefix = cfg.get(make_target, "pbo_name_prefix", fallback=None) + + # Project module Root + module_root_parent = os.path.abspath(os.path.join(os.path.join(work_drive, prefix), os.pardir)) + module_root = cfg.get(make_target, "module_root", fallback=os.path.join(make_root_parent, "addons")) + print_green ("module_root: " + module_root) + if (os.path.isdir(module_root)): + os.chdir(module_root) + else: + print_error ("Directory " + module_root + " does not exist.") + sys.exit() + + except: + raise + print_error("Could not parse make.cfg.") + sys.exit(1) + + + + # See if we have been given specific modules to build from command line. + if len(argv) > 1 and not make_release: + arg_modules = True + modules = argv[1:] + + # Find the tools we need. + try: + tools = find_bi_tools(work_drive) + addonbuilder = tools[0] + dssignfile = tools[1] + dscreatekey = tools[2] + + except: + print_error("Arma 3 Tools are not installed correctly or the P: drive has not been created.") + sys.exit(1) + + if build_tool == "pboproject": + try: + depbo_tools = find_depbo_tools() + pboproject = depbo_tools[0] + rapifyTool = depbo_tools[1] + makepboTool = depbo_tools[2] + except: + raise + print_error("Could not find dePBO tools. Download the needed tools from: https://dev.withsix.com/projects/mikero-pbodll/files") + sys.exit(1) + + # Try to open and deserialize build cache file. + try: + cache = {} + with open(os.path.join(make_root, "make.cache"), 'r') as f: + cache_raw = f.read() + + cache = json.loads(cache_raw) + + except: + print ("No cache found.") + cache = {} + + # Get list of subdirs in make root. + dirs = next(os.walk(module_root))[1] + + # Autodetect what directories to build. + if module_autodetect and not arg_modules: + modules = [] + for path in dirs: + # Any dir that has a config.cpp in its root is an addon to build. + config_path = os.path.join(path, 'config.cpp') + if os.path.isfile(config_path) and not path in ignore: + modules.append(path) + + # Make the key specified from command line if necessary. + if new_key: + if not os.path.isfile(os.path.join(module_root, key_name + ".biprivatekey")): + print_green("\nRequested key does not exist.") + ret = subprocess.call([dscreatekey, key_name]) # Created in make_root + if ret == 0: + print_blue("Created: " + os.path.join(module_root, key_name + ".biprivatekey")) + else: + print_error("Failed to create key!") + + try: + print_blue("Copying public key to release directory.") + + try: + os.makedirs(os.path.join(module_root, release_dir, "Keys")) + except: + pass + + shutil.copyfile(os.path.join(module_root, key_name + ".bikey"), os.path.join(module_root, release_dir, "Keys", key_name + ".bikey")) + + except: + raise + print_error("Could not copy key to release directory.") + + else: + print_green("\nNOTE: Using key " + os.path.join(module_root, key_name + ".biprivatekey")) + + key = os.path.join(module_root, key_name + ".biprivatekey") + + + # For each module, prep files and then build. + for module in modules: + print_green("\nMaking " + module + "-"*max(1, (60-len(module)))) + + # Cache check + if module in cache: + old_sha = cache[module] + else: + old_sha = "" + + # Hash the module + new_sha = get_directory_hash(os.path.join(module_root, module)) + + # Check if it needs rebuilt + # print ("Hash:", new_sha) + if old_sha == new_sha: + if not force_build: + print("Module has not changed.") + # Skip everything else + continue + + # Only do this if the project isn't stored directly on the work drive. + # Split the path at the drive name and see if they are on the same drive (usually P:) + if os.path.splitdrive(module_root)[0] != os.path.splitdrive(work_drive)[0]: + try: + # Remove old work drive version (ignore errors) + shutil.rmtree(os.path.join(work_drive, prefix, module), True) + + # Copy module to the work drive + shutil.copytree(module, os.path.join(work_drive, prefix, module)) + + except: + raise + print_error("ERROR: Could not copy module to work drive. Does the module exist?") + input("Press Enter to continue...") + print("Resuming build...") + continue + else: + print("WARNING: Module is stored on work drive (" + work_drive + ").") + + try: + # Remove the old pbo, key, and log + old = os.path.join(module_root, release_dir, project, "Addons", module) + "*" + files = glob.glob(old) + for f in files: + os.remove(f) + + if pbo_name_prefix: + old = os.path.join(module_root, release_dir, project, "Addons", pbo_name_prefix+module) + "*" + files = glob.glob(old) + for f in files: + os.remove(f) + except: + raise + print_error("ERROR: Could not copy module to work drive. Does the module exist?") + input("Press Enter to continue...") + print("Resuming build...") + continue + + # Build the module into a pbo + print_blue("Building: " + os.path.join(work_drive, prefix, module)) + print_blue("Destination: " + os.path.join(module_root, release_dir, project, "Addons")) + + # Make destination folder (if needed) + try: + os.makedirs(os.path.join(module_root, release_dir, project, "Addons")) + except: + pass + + # Run build tool + build_successful = False + if build_tool == "pboproject": + try: + #PABST: Convert config (run the macro'd config.cpp through CfgConvert twice to produce a de-macro'd cpp that pboProject can read without fucking up: + os.chdir("P:\\CfgConvert") + shutil.copyfile(os.path.join(work_drive, prefix, module, "config.cpp"), os.path.join(work_drive, prefix, module, "config.backup")) + print_green("\Pabst (double converting):" + "cfgConvertGUI.exe " + os.path.join(work_drive, prefix, module, "config.cpp")) + ret = subprocess.call(["cfgConvertGUI.exe", os.path.join(work_drive, prefix, module, "config.cpp")]) + ret = subprocess.call(["cfgConvertGUI.exe", os.path.join(work_drive, prefix, module, "config.bin")]) + + # Call pboProject + os.chdir("P:\\") + + if os.path.isfile(os.path.join(work_drive, prefix, module, "$NOBIN$")): + print_green("$NOBIN$ Found. Proceeding with non-binarizing!") + cmd = [makepboTool, "-P","-A","-L","-N","-G", os.path.join(work_drive, prefix, module),os.path.join(module_root, release_dir, project,"Addons")] + + else: + cmd = [pboproject, "-P", os.path.join(work_drive, prefix, module), "+Engine=Arma3", "-S","+Noisy", "+X", "+Clean", "+Mod="+os.path.join(module_root, release_dir, project), "-Key"] + + color("grey") + if quiet: + devnull = open(os.devnull, 'w') + ret = subprocess.call(cmd, stdout=devnull) + devnull.close() + else: + ret = subprocess.call(cmd) + color("reset") + + if ret == 0: + print_green("pboProject return code == " + str(ret)) + # Prettyprefix rename the PBO if requested. + if pbo_name_prefix: + try: + os.rename(os.path.join(module_root, release_dir, project, "Addons", module+".pbo"), os.path.join(module_root, release_dir, project, "Addons", pbo_name_prefix+module+".pbo")) + except: + raise + print_error("Could not rename built PBO with prefix.") + # Sign result + if key: + print("Signing with " + key + ".") + if pbo_name_prefix: + ret = subprocess.call([dssignfile, key, os.path.join(module_root, release_dir, project, "Addons", pbo_name_prefix + module + ".pbo")]) + else: + ret = subprocess.call([dssignfile, key, os.path.join(module_root, release_dir, project, "Addons", module + ".pbo")]) + + if ret == 0: + build_successful = True + else: + build_successful = True + + if not build_successful: + print_error("pboProject return code == " + str(ret)) + print_error("Module not successfully built/signed.") + #input("Press Enter to continue...") + print ("Resuming build...") + continue + + #PABST: cleanup config BS (you could comment this out to see the "de-macroed" cpp + print_green("\Pabst (restoring): " + os.path.join(work_drive, prefix, module, "config.cpp")) + os.remove(os.path.join(work_drive, prefix, module, "config.cpp")) + os.remove(os.path.join(work_drive, prefix, module, "config.bin")) + os.rename(os.path.join(work_drive, prefix, module, "config.backup"), os.path.join(work_drive, prefix, module, "config.cpp")) + + # Back to the root + os.chdir(module_root) + + except: + raise + print_error("Could not run Addon Builder.") + input("Press Enter to continue...") + print ("Resuming build...") + continue + + elif build_tool== "addonbuilder": + # Detect $NOBIN$ and do not binarize if found. + if os.path.isfile(os.path.join(work_drive, prefix, module, "$NOBIN$")): + do_binarize = False + print("$NOBIN$ file found in module, packing only.") + else: + do_binarize = True + try: + # Call AddonBuilder + os.chdir("P:\\") + + cmd = [addonbuilder, os.path.join(work_drive, prefix, module), os.path.join(make_root, release_dir, project, "Addons"), "-clear", "-project="+work_drive] + if not do_binarize: + cmd.append("-packonly") + + if quiet: + previousDirectory = os.getcwd() + os.chdir(arma3tools_path) + devnull = open(os.devnull, 'w') + ret = subprocess.call(cmd, stdout=devnull) + devnull.close() + os.chdir(previousDirectory) + else: + previousDirectory = os.getcwd() + os.chdir(arma3tools_path) + print_error("Current directory - " + os.getcwd()) + ret = subprocess.call(cmd) + os.chdir(previousDirectory) + print_error("Current directory - " + os.getcwd()) + color("reset") + print_green("completed") + # Prettyprefix rename the PBO if requested. + if pbo_name_prefix: + try: + os.rename(os.path.join(make_root, release_dir, project, "Addons", module+".pbo"), os.path.join(make_root, release_dir, project, "Addons", pbo_name_prefix+module+".pbo")) + except: + raise + print_error("Could not rename built PBO with prefix.") + + if ret == 0: + # Sign result + if key: + print("Signing with " + key + ".") + if pbo_name_prefix: + ret = subprocess.call([dssignfile, key, os.path.join(make_root, release_dir, project, "Addons", pbo_name_prefix + module + ".pbo")]) + else: + ret = subprocess.call([dssignfile, key, os.path.join(make_root, release_dir, project, "Addons", module + ".pbo")]) + + if ret == 0: + build_successful = True + else: + build_successful = True + + if not build_successful: + print_error("Module not successfully built.") + + # Back to the root + os.chdir(make_root) + + except: + raise + print_error("Could not run Addon Builder.") + input("Press Enter to continue...") + print ("Resuming build...") + continue + + else: + print_error("Unknown build_tool " + build_tool + "!") + + # Update the hash for a successfully built module + if build_successful: + cache[module] = new_sha + + # Done building all modules! + + # Write out the cache state + cache_out = json.dumps(cache) + with open(os.path.join(make_root, "make.cache"), 'w') as f: + f.write(cache_out) + + # Delete the pboproject temp files if building a release. + if make_release and build_tool == "pboproject": + try: + shutil.rmtree(os.path.join(module_root, release_dir, project, "temp"), True) + except: + print_error("ERROR: Could not delete pboProject temp files.") + + print_green("\nDone.") + + # Make release + if make_release: + print_blue("\nMaking release: " + project + "-" + release_version + ".zip") + + try: + # Delete all log files + for root, dirs, files in os.walk(os.path.join(module_root, release_dir, project, "Addons")): + for currentFile in files: + if currentFile.lower().endswith("log"): + os.remove(os.path.join(root, currentFile)) + + # Create a zip with the contents of release/ in it + shutil.make_archive(project + "-" + release_version, "zip", os.path.join(module_root, release_dir)) + except: + raise + print_error("Could not make release.") + + # Copy to Arma 3 folder for testing + if test: + print_blue("\nCopying to Arma 3.") + + if sys.platform == "win32": + reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) + try: + k = winreg.OpenKey(reg, r"SOFTWARE\Wow6432Node\Bohemia Interactive\Arma 3") + a3_path = winreg.EnumValue(k, 1)[1] + winreg.CloseKey(k) + except: + print_error("Could not find Arma 3's directory in the registry.") + else: + a3_path = cygwin_a3path + + if os.path.exists(a3_path): + try: + shutil.rmtree(os.path.join(a3_path, project), True) + shutil.copytree(os.path.join(module_root, release_dir, project), os.path.join(a3_path, project)) + except: + print_error("Could not copy files. Is Arma 3 running?") + +if __name__ == "__main__": + main(sys.argv) +input("Press Enter to continue...") \ No newline at end of file