diff --git a/code/aircraft.cpp b/code/aircraft.cpp index 9d9a69d80..41116f21d 100644 --- a/code/aircraft.cpp +++ b/code/aircraft.cpp @@ -93,9 +93,11 @@ #include "aircraft.h" +#include "_convert.h" #include "_map.h" #include "_rtti.h" #include "_rules.h" +#include "_surface.h" #include "_tactica.h" #include "airctype.h" #include "anim.h" @@ -107,7 +109,9 @@ #include "ccrand.h" #include "cell.h" #include "dbgprint.h" +#include "draw.h" #include "findmake.h" +#include "globals.h" #include "house.h" #include "houstype.h" #include "incdec.h" @@ -115,6 +119,7 @@ #include "infatype.h" #include "inline.h" #include "ion.h" +#include "lightcon.h" #include "map.h" #include "mono.h" #include "partsys.h" @@ -122,7 +127,9 @@ #include "rules.h" #include "savestream.h" #include "scenario.h" +#include "scheme.h" #include "session.h" +#include "shapeset.h" #include "stimer.h" #include "sun.h" #include "swizzle.h" @@ -435,6 +442,11 @@ void AircraftClass::Draw_It(Point2D const & xpoint, Rect const & cliprect) const key = -1; matrix = Locomotion->Draw_Matrix(&key); Draw_Voxel(Class->Voxel, 0, key, &Class->VoxelIndex, cliprect, point, Get_Isometric_View_Matrix() * matrix, newbrightness, SHAPE_NORMAL); + + // Draw rotor blades, if equipped (and not crashing). + if (Class->IsRotorEquipped && Strength > 0) { + Draw_Rotors(point, cliprect, matrix); + } } /* @@ -459,47 +471,164 @@ void AircraftClass::Draw_It(Point2D const & xpoint, Rect const & cliprect) const * HISTORY: * * 07/26/1996 JLB : Created. * *=============================================================================================*/ -void AircraftClass::Draw_Rotors(Point2D const & xy, Rect const & cliprect) const +void AircraftClass::Draw_Rotors(Point2D const& xy, Rect const& cliprect, Matrix3D const& matrix) const { - ShapeFlags_Type flags = ShapeFlags_Type(SHAPE_CENTER|SHAPE_WIN_REL); + /* + ** Don't draw rotors if the aircraft is hidden from the viewing player. + */ + VisualType visual = Visual_Character(); + + if (visual == VISUAL_HIDDEN) { + return; + } + + ShapeFlags_Type flags = ShapeFlags_Type(SHAPE_CENTER | SHAPE_WIN_REL); int shapenum; /* - ** The rotor shape number depends on whether the helicopter is idling - ** or not. A landed helicopter uses slow moving "idling" blades. + ** The rotor shape number depends on whether the helicopter is idling + ** or not. A landed helicopter uses idling blades. */ if (HeightAGL == 0) { - shapenum = (Fetch_Stage()%8)+4; - flags = flags; - } else { - shapenum = Fetch_Stage()%4; - flags = ShapeFlags_Type(flags|SHAPE_PREDATOR); + shapenum = (Fetch_Stage() % 8) + 4; + + // cloaked, idling + if (visual == VISUAL_SHADOWY) { + flags = ShapeFlags_Type(flags | SHAPE_TRANSLUCENT50); + } + // uncloaked, idling + else { + flags = ShapeFlags_Type(flags | SHAPE_TRANSLUCENT25); + } } + else { + shapenum = Fetch_Stage() % 4; - #if 0 - if (*this == AIRCRAFT_TRANSPORT) { - int _stretch[FACING_COUNT] = {8, 9, 10, 9, 8, 9, 10, 9}; + // cloaked + if (visual == VISUAL_SHADOWY) { + flags = ShapeFlags_Type(flags | SHAPE_TRANSLUCENT75); + } + // uncloaked + else { + flags = ShapeFlags_Type(flags | SHAPE_TRANSLUCENT50); + } + } - /* - ** Dual rotors offset along flight axis. - */ - short xx = x; - short yy = y-LEPTON_TO_PIXEL(Height); - FacingType face = Dir_Facing(SecondaryFacing); - Move_Point(xx, yy, SecondaryFacing.Current(), _stretch[face]); - Draw_Shape(AircraftTypeClass::RRotorData, shapenum, xx, yy-2, window, flags, NULL, DisplayClass::UnitShadow); + char const* rotorFiles[4] = { + Class->Rotor1File, + Class->Rotor2File, + Class->Rotor3File, + Class->Rotor4File + }; + + void const* const* rotorData[4] = { + &Class->Rotor1Data, + &Class->Rotor2Data, + &Class->Rotor3Data, + &Class->Rotor4Data + }; - Move_Point(xx, yy, SecondaryFacing.Current()+DIR_S, _stretch[face]*2); - Draw_Shape(AircraftTypeClass::LRotorData, shapenum, xx, yy-2, window, flags, NULL, DisplayClass::UnitShadow); + void const* const* tiltedData[4] = { + Class->Rotor1TiltedData, + Class->Rotor2TiltedData, + Class->Rotor3TiltedData, + Class->Rotor4TiltedData + }; - } else { + TPoint3D const* rotorFLH[4] = { + &Class->Rotor1FLH, + &Class->Rotor2FLH, + &Class->Rotor3FLH, + &Class->Rotor4FLH + }; + + /* + ** Count the rotor artwork sets. + */ + int artworkCount = 0; + + for (int i = 0; i < 4; ++i) { + if (rotorFiles[i][0] == '\0') { + break; + } + + artworkCount++; + } + + /* + ** Draw each rotor at its configured FLH. + */ + for (int rotor = 0; rotor < Class->RotorCount && rotor < 4; ++rotor) { + ShapeSet const* rotordata = NULL; + + if (artworkCount > 0) { + /* + ** Resolve the repeating custom artwork pattern. + */ + int artIndex = rotor % artworkCount; + + if (Locomotion->Is_Moving_Now()) { + int direction = SecondaryFacing.Current().As_Dir8(); + + rotordata = static_cast( + tiltedData[artIndex][direction] + ); + } + + /* + ** Fall back to the ordinary custom rotor if stationary + ** or if the directional rotor could not be loaded. + */ + if (rotordata == NULL) { + rotordata = static_cast( + *rotorData[artIndex] + ); + } + } /* - ** Single rotor centered about shape. + ** Fall back to the built-in rotor if no custom artwork is + ** configured or the selected custom artwork could not be loaded. */ - Draw_Shape(AircraftTypeClass::RRotorData, shapenum, x, ((y-LEPTON_TO_PIXEL(Height))-2), window, flags, NULL, DisplayClass::UnitShadow); + if (rotordata == NULL) { + rotordata = static_cast( + (rotor % 2 == 0) + ? AircraftTypeClass::LRotorData + : AircraftTypeClass::RRotorData + ); + } + + if (rotordata == NULL) { + continue; + } + + Vector3 localOffset( + rotorFLH[rotor]->X / 8.0f, + rotorFLH[rotor]->Y / 8.0f, + rotorFLH[rotor]->Z / 8.0f + ); + + Matrix3D rotorMatrix = Get_Isometric_View_Matrix() * matrix; + Vector3 projectedOffset = rotorMatrix.Rotate_Vector(localOffset); + + Point2D rotorPoint = xy; + rotorPoint.X += (int)(projectedOffset.X + 0.5f); + rotorPoint.Y -= (int)(projectedOffset.Y + 0.5f); + + Draw_Shape( + *LogicalSurface, + *ColorSchemes[House->Scheme]->Converter, + rotordata, + shapenum, + rotorPoint, + cliprect, + flags, + NULL, + 0, + ZGRAD_90DEG, + NORMAL_LIGHT + ); } - #endif } diff --git a/code/aircraft.h b/code/aircraft.h index 591ddd970..ed0049aed 100644 --- a/code/aircraft.h +++ b/code/aircraft.h @@ -130,7 +130,7 @@ class AircraftClass : public FootClass, public IFlyControl ** object interacts with the map and thus indirectly controls rendering. */ virtual void Look(bool incremental=false, bool=false) override; - void Draw_Rotors(Point2D const & xy, Rect const & cliprect) const; + void Draw_Rotors(Point2D const & xy, Rect const & cliprect, Matrix3D const& matrix) const; virtual int Exit_Object(TechnoClass *) override; virtual void Draw_It(Point2D const & point, Rect const & cliprect) const override; diff --git a/code/airctype.cpp b/code/airctype.cpp index 1dbe12e3c..1281f90ed 100644 --- a/code/airctype.cpp +++ b/code/airctype.cpp @@ -52,6 +52,7 @@ #include "_mixfile.h" #include "_rules.h" #include "aircraft.h" +#include "animtype.h" #include "findmake.h" #include "globals.h" #include "incdec.h" @@ -80,21 +81,60 @@ void const * AircraftTypeClass::RRotorData = NULL; * HISTORY: * * 07/26/1994 JLB : Created. * *=============================================================================================*/ -AircraftTypeClass::AircraftTypeClass(char const * ininame) : +AircraftTypeClass::AircraftTypeClass(char const* ininame) : BASECLASS(ininame, SPEED_WINGED), IsLandable(false), IsRotorEquipped(false), - IsRotorCustom(false), + RotorCount(1), + Rotor1Data(NULL), + Rotor2Data(NULL), + Rotor3Data(NULL), + Rotor4Data(NULL), + Rotor1TiltedData(NULL), + Rotor2TiltedData(NULL), + Rotor3TiltedData(NULL), + Rotor4TiltedData(NULL), IsCarryall(false), HeapID(AIRCRAFT_NONE) { Create_ID(); + Rotor1FLH = Point3D(0, 0, 0); + Rotor2FLH = Point3D(0, 0, 0); + Rotor3FLH = Point3D(0, 0, 0); + Rotor4FLH = Point3D(0, 0, 0); + AircraftTypes.Add(this); HeapID = AircraftType(AircraftTypes.ID(this)); IsMoveToShroud = false; Rotation = 32; + + Rotor1File[0] = '\0'; + Rotor2File[0] = '\0'; + Rotor3File[0] = '\0'; + Rotor4File[0] = '\0'; + + char(*tiltedFiles[4])[15 + 1] = { + Rotor1TiltedFiles, + Rotor2TiltedFiles, + Rotor3TiltedFiles, + Rotor4TiltedFiles + }; + + void const** tiltedData[4] = { + Rotor1TiltedData, + Rotor2TiltedData, + Rotor3TiltedData, + Rotor4TiltedData + }; + + for (int rotor = 0; rotor < 4; ++rotor) { + for (int direction = 0; direction < 8; ++direction) { + tiltedFiles[rotor][direction][0] = '\0'; + tiltedData[rotor][direction] = NULL; + } + } } @@ -264,14 +304,94 @@ Point3D AircraftTypeClass::Lepton_Dimensions(void) const * HISTORY: * * 07/19/1996 JLB : Created. * *=============================================================================================*/ -bool AircraftTypeClass::Read_INI(CCINIClass const & ini) +bool AircraftTypeClass::Read_INI(CCINIClass const& ini) { if (BASECLASS::Read_INI(ini)) { IsLandable = ini.Get_Bool(Name(), "Landable", IsLandable); IsCarryall = ini.Get_Bool(Name(), "Carryall", IsCarryall); IsRotorEquipped = ArtINI.Get_Bool(Graphic_Name(), "Rotors", IsRotorEquipped); - IsRotorCustom = ArtINI.Get_Bool(Graphic_Name(), "CustomRotor", IsRotorCustom); + RotorCount = ArtINI.Get_Int(Graphic_Name(), "RotorCount", RotorCount); + Rotor1FLH = ArtINI.Get_Point(Graphic_Name(), "Rotor1FLH", Rotor1FLH); + Rotor2FLH = ArtINI.Get_Point(Graphic_Name(), "Rotor2FLH", Rotor2FLH); + Rotor3FLH = ArtINI.Get_Point(Graphic_Name(), "Rotor3FLH", Rotor3FLH); + Rotor4FLH = ArtINI.Get_Point(Graphic_Name(), "Rotor4FLH", Rotor4FLH); + ArtINI.Get_String(Graphic_Name(), "Rotor1Anim", "", Rotor1File, sizeof(Rotor1File)); + ArtINI.Get_String(Graphic_Name(), "Rotor2Anim", "", Rotor2File, sizeof(Rotor2File)); + ArtINI.Get_String(Graphic_Name(), "Rotor3Anim", "", Rotor3File, sizeof(Rotor3File)); + ArtINI.Get_String(Graphic_Name(), "Rotor4Anim", "", Rotor4File, sizeof(Rotor4File)); + + /* + ** Read the directional rotor filenames for each rotor. + */ + { + const int ROTOR_COUNT = 4; // Max number of rotors + const int ROTOR_DIRECTION_COUNT = 8; // Number of directions expected in list + const int ROTOR_FILENAME_LENGTH = 15; + + char(*tiltedFiles[ROTOR_COUNT])[ROTOR_FILENAME_LENGTH + 1] = { + Rotor1TiltedFiles, + Rotor2TiltedFiles, + Rotor3TiltedFiles, + Rotor4TiltedFiles + }; + + char tiltednames[ + ROTOR_DIRECTION_COUNT * ROTOR_FILENAME_LENGTH + (ROTOR_DIRECTION_COUNT - 1) + 1 + ]; + + for (int rotor = 0; rotor < ROTOR_COUNT; ++rotor) { + for (int direction = 0; direction < ROTOR_DIRECTION_COUNT; ++direction) { + tiltedFiles[rotor][direction][0] = '\0'; + } + tiltednames[0] = '\0'; + + int direction = 0; + switch (rotor) { + case 0: + ArtINI.Get_String( + Graphic_Name(), "Rotor1TiltedAnims", "", tiltednames, sizeof(tiltednames)); + break; + case 1: + ArtINI.Get_String( + Graphic_Name(), "Rotor2TiltedAnims", "", tiltednames, sizeof(tiltednames)); + break; + case 2: + ArtINI.Get_String( + Graphic_Name(), "Rotor3TiltedAnims", "", tiltednames, sizeof(tiltednames)); + break; + case 3: + ArtINI.Get_String( + Graphic_Name(), "Rotor4TiltedAnims", "", tiltednames, sizeof(tiltednames)); + break; + } + + char* filename = tiltednames; + + while (*filename != '\0' && direction < ROTOR_DIRECTION_COUNT) { + char* comma = strchr(filename, ','); + + if (comma != NULL) { + *comma = '\0'; + } + + size_t length = strlen(filename); + + if (length > 0 && length <= ROTOR_FILENAME_LENGTH) { + strcpy(tiltedFiles[rotor][direction], filename); + } + + direction++; + + if (comma == NULL) { + break; + } + + filename = comma + 1; + } + } + } + Load_Rotor_Assets(); return(true); } return(false); @@ -290,7 +410,7 @@ void AircraftTypeClass::Compute_CRC(CRCEngine & crc) const BASECLASS::Compute_CRC(crc); crc(IsRotorEquipped); - crc(IsRotorCustom); + crc(RotorCount); crc(IsLandable); crc(HeapID); } @@ -307,6 +427,7 @@ void AircraftTypeClass::Post_Load(void) Fetch_Voxel_Image(); Fetch_Normal_Image(); + Load_Rotor_Assets(); } @@ -321,7 +442,19 @@ void AircraftTypeClass::Serialize(SaveStreamClass & stream) stream.Serialize(HeapID); stream.Serialize(IsCarryall); stream.Serialize(IsRotorEquipped); - stream.Serialize(IsRotorCustom); + stream.Serialize(RotorCount); + stream.Serialize(Rotor1FLH); + stream.Serialize(Rotor2FLH); + stream.Serialize(Rotor3FLH); + stream.Serialize(Rotor4FLH); + stream.Serialize(Rotor1File); + stream.Serialize(Rotor2File); + stream.Serialize(Rotor3File); + stream.Serialize(Rotor4File); + stream.Serialize(Rotor1TiltedFiles); + stream.Serialize(Rotor2TiltedFiles); + stream.Serialize(Rotor3TiltedFiles); + stream.Serialize(Rotor4TiltedFiles); stream.Serialize(IsLandable); } @@ -344,3 +477,77 @@ AircraftTypeClass * AircraftTypeClass::Find_Or_Make(char const * name) { return(TFind_Or_Make(name, AircraftTypes)); } + + +/// +/// Gets the SHP data for each of the rotor filenames specified by the Rotor#Anim and +/// Rotor#TiltedAnims keys. These files aren't initialized through anims so need to be +/// loaded specially. Because they aren't anims, they also need to be restored on game load, +/// so this function is used both when reading the INI and when reloading a savegame. +/// +void AircraftTypeClass::Load_Rotor_Assets(void) +{ + /* + ** Load the ordinary custom rotor SHPs. + */ + char const* rotorFiles[] = { + Rotor1File, + Rotor2File, + Rotor3File, + Rotor4File + }; + + void const** rotorData[] = { + &Rotor1Data, + &Rotor2Data, + &Rotor3Data, + &Rotor4Data + }; + + for (int i = 0; i < 4; ++i) { + *rotorData[i] = NULL; + + if (rotorFiles[i][0] != '\0') { + char fullname[MAX_PATH]; + _makepath(fullname, NULL, NULL, rotorFiles[i], ".SHP"); + *rotorData[i] = MFCD::Retrieve(fullname); + } + } + + /* + ** Load the directional rotor SHPs from the stored filenames. + */ + char(*tiltedFiles[4])[15 + 1] = { + Rotor1TiltedFiles, + Rotor2TiltedFiles, + Rotor3TiltedFiles, + Rotor4TiltedFiles + }; + + void const** tiltedData[4] = { + Rotor1TiltedData, + Rotor2TiltedData, + Rotor3TiltedData, + Rotor4TiltedData + }; + + for (int rotor = 0; rotor < 4; ++rotor) { + for (int direction = 0; direction < 8; ++direction) { + tiltedData[rotor][direction] = NULL; + + if (tiltedFiles[rotor][direction][0] != '\0') { + char fullname[MAX_PATH]; + + _makepath( + fullname, + NULL, + NULL, + tiltedFiles[rotor][direction], + ".SHP" + ); + + tiltedData[rotor][direction] = MFCD::Retrieve(fullname); + } + } + } +} diff --git a/code/airctype.h b/code/airctype.h index 913c8e1a8..a54a37d9e 100644 --- a/code/airctype.h +++ b/code/airctype.h @@ -45,9 +45,42 @@ class AircraftTypeClass : public TechnoTypeClass bool IsRotorEquipped; // Is a rotor attached? /* - ** Is there a custom rotor animation stage set for each facing of the aircraft? + ** How many rotors does the aircraft have? */ - bool IsRotorCustom; // Custom rotor sets for each facing? + int RotorCount; + + /* + ** This is the shape to display for the rotor anim if the aircraft is not tilted. + */ + char Rotor1File[15 + 1]; + char Rotor2File[15 + 1]; + char Rotor3File[15 + 1]; + char Rotor4File[15 + 1]; + void const* Rotor1Data; + void const* Rotor2Data; + void const* Rotor3Data; + void const* Rotor4Data; + + /* + ** This is the rotor shape to display for each facing, starting with the north facing + ** and rotating clockwise around the 8 facings, similar to muzzle flash anim behavior. + */ + char Rotor1TiltedFiles[8][15 + 1]; + char Rotor2TiltedFiles[8][15 + 1]; + char Rotor3TiltedFiles[8][15 + 1]; + char Rotor4TiltedFiles[8][15 + 1]; + void const* Rotor1TiltedData[8]; + void const* Rotor2TiltedData[8]; + void const* Rotor3TiltedData[8]; + void const* Rotor4TiltedData[8]; + + /* + ** This is the FLH for each rotor. + */ + TPoint3D Rotor1FLH; + TPoint3D Rotor2FLH; + TPoint3D Rotor3FLH; + TPoint3D Rotor4FLH; /* ** Can this aircraft land? If it can land it is presumed to be controllable by the player. @@ -79,4 +112,7 @@ class AircraftTypeClass : public TechnoTypeClass static void const * LRotorData; static void const * RRotorData; + + private: + void Load_Rotor_Assets(void); }; diff --git a/manual/changes/draw-rotors-on-aircraft.md b/manual/changes/draw-rotors-on-aircraft.md new file mode 100644 index 000000000..cc39aecc6 --- /dev/null +++ b/manual/changes/draw-rotors-on-aircraft.md @@ -0,0 +1,64 @@ +--- +title: Draw rotors on aircraft +category: feature +release: 0.2.0 +targets: +- type: key + id: Rotors + effect: changed +- type: key + id: RotorCount + effect: added +- type: key + id: Rotor1Anim + effect: added +- type: key + id: Rotor2Anim + effect: added +- type: key + id: Rotor3Anim + effect: added +- type: key + id: Rotor4Anim + effect: added +- type: key + id: Rotor1TiltedAnims + effect: added +- type: key + id: Rotor2TiltedAnims + effect: added +- type: key + id: Rotor3TiltedAnims + effect: added +- type: key + id: Rotor4TiltedAnims + effect: added +- type: key + id: Rotor1FLH + effect: added +- type: key + id: Rotor2FLH + effect: added +- type: key + id: Rotor3FLH + effect: added +- type: key + id: Rotor4FLH + effect: added +- type: key + id: CustomRotor + effect: removed +- type: system + id: aircraft-rotors + effect: added + +credit: [Orac] +--- + +Set `Rotors=yes` in an aircraft's `art.ini` image section to draw separate rotor shapes. Each shape uses 12 frames: 0–3 while airborne and 4–11 while landed. + +`RotorCount` sets how many rotors are drawn, up to four. `Rotor#Anim` and `Rotor#FLH` select custom shapes and their positions; without a loaded custom shape, the engine uses `LROTOR.SHP` and `RROTOR.SHP` when available. + +`Rotor#TiltedAnims` selects facing-specific shapes while the aircraft moves. + +The unused `CustomRotor` assignment is no longer read. diff --git a/manual/content/keys/customrotor.md b/manual/content/keys/customrotor.md deleted file mode 100644 index 25af77c6d..000000000 --- a/manual/content/keys/customrotor.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -key: CustomRotor -summary: Parsed rotor flag that the engine never uses. -no_effect: true -see_also: ["Rotors"] -when_omitted: - kind: value - value: "no" ---- - -OpenTS draws no separate rotor blades over an aircraft, so it never selects rotor artwork for each facing. [`Rotors`](/keys/rotors/) is unused for the same reason. diff --git a/manual/content/keys/rotor1anim.md b/manual/content/keys/rotor1anim.md new file mode 100644 index 000000000..e7ed6ff01 --- /dev/null +++ b/manual/content/keys/rotor1anim.md @@ -0,0 +1,9 @@ +--- +key: Rotor1Anim +summary: First custom shape in the repeating rotor-art sequence. +when_omitted: + kind: value + value: "" +--- + +`Rotor1Anim` names the first custom SHP file in the aircraft's repeating rotor-art sequence. [Aircraft rotors](/systems/aircraft-rotors/#custom-artwork) explains how the engine selects custom and built-in shapes. diff --git a/manual/content/keys/rotor1flh.md b/manual/content/keys/rotor1flh.md new file mode 100644 index 000000000..e1e78256a --- /dev/null +++ b/manual/content/keys/rotor1flh.md @@ -0,0 +1,9 @@ +--- +key: Rotor1FLH +summary: Forward, lateral, and height offset for rotor 1. +when_omitted: + kind: value + value: "0,0,0" +--- + +`Rotor1FLH` moves rotor 1 from the aircraft's center along its local forward, lateral, and height axes. [Aircraft rotors](/systems/aircraft-rotors/#custom-artwork) explains how the offset affects drawing. diff --git a/manual/content/keys/rotor1tiltedanims.md b/manual/content/keys/rotor1tiltedanims.md new file mode 100644 index 000000000..e0af1f9a1 --- /dev/null +++ b/manual/content/keys/rotor1tiltedanims.md @@ -0,0 +1,9 @@ +--- +key: Rotor1TiltedAnims +summary: Facing-specific SHP names for rotor 1 while the aircraft moves. +when_omitted: + kind: value + value: "" +--- + +`Rotor1TiltedAnims` lists up to eight direction-specific SHP base names for rotor 1, in facing order from north clockwise. [Aircraft rotors](/systems/aircraft-rotors/#directional-artwork) explains when these shapes are used. diff --git a/manual/content/keys/rotor2anim.md b/manual/content/keys/rotor2anim.md new file mode 100644 index 000000000..d89f70498 --- /dev/null +++ b/manual/content/keys/rotor2anim.md @@ -0,0 +1,9 @@ +--- +key: Rotor2Anim +summary: Second custom shape in the repeating rotor-art sequence. +when_omitted: + kind: value + value: "" +--- + +`Rotor2Anim` names the second custom SHP file in the aircraft's repeating rotor-art sequence. [Aircraft rotors](/systems/aircraft-rotors/#custom-artwork) explains how the engine selects custom and built-in shapes. diff --git a/manual/content/keys/rotor2flh.md b/manual/content/keys/rotor2flh.md new file mode 100644 index 000000000..8b72d2a4f --- /dev/null +++ b/manual/content/keys/rotor2flh.md @@ -0,0 +1,9 @@ +--- +key: Rotor2FLH +summary: Forward, lateral, and height offset for rotor 2. +when_omitted: + kind: value + value: "0,0,0" +--- + +`Rotor2FLH` moves rotor 2 from the aircraft's center along its local forward, lateral, and height axes. [Aircraft rotors](/systems/aircraft-rotors/#custom-artwork) explains how the offset affects drawing. diff --git a/manual/content/keys/rotor2tiltedanims.md b/manual/content/keys/rotor2tiltedanims.md new file mode 100644 index 000000000..d8baf47df --- /dev/null +++ b/manual/content/keys/rotor2tiltedanims.md @@ -0,0 +1,9 @@ +--- +key: Rotor2TiltedAnims +summary: Facing-specific SHP names for rotor 2 while the aircraft moves. +when_omitted: + kind: value + value: "" +--- + +`Rotor2TiltedAnims` lists up to eight direction-specific SHP base names for rotor 2, in facing order from north clockwise. [Aircraft rotors](/systems/aircraft-rotors/#directional-artwork) explains when these shapes are used. diff --git a/manual/content/keys/rotor3anim.md b/manual/content/keys/rotor3anim.md new file mode 100644 index 000000000..c2a3d51c2 --- /dev/null +++ b/manual/content/keys/rotor3anim.md @@ -0,0 +1,9 @@ +--- +key: Rotor3Anim +summary: Third custom shape in the repeating rotor-art sequence. +when_omitted: + kind: value + value: "" +--- + +`Rotor3Anim` names the third custom SHP file in the aircraft's repeating rotor-art sequence. [Aircraft rotors](/systems/aircraft-rotors/#custom-artwork) explains how the engine selects custom and built-in shapes. diff --git a/manual/content/keys/rotor3flh.md b/manual/content/keys/rotor3flh.md new file mode 100644 index 000000000..522a6c050 --- /dev/null +++ b/manual/content/keys/rotor3flh.md @@ -0,0 +1,9 @@ +--- +key: Rotor3FLH +summary: Forward, lateral, and height offset for rotor 3. +when_omitted: + kind: value + value: "0,0,0" +--- + +`Rotor3FLH` moves rotor 3 from the aircraft's center along its local forward, lateral, and height axes. [Aircraft rotors](/systems/aircraft-rotors/#custom-artwork) explains how the offset affects drawing. diff --git a/manual/content/keys/rotor3tiltedanims.md b/manual/content/keys/rotor3tiltedanims.md new file mode 100644 index 000000000..088728442 --- /dev/null +++ b/manual/content/keys/rotor3tiltedanims.md @@ -0,0 +1,9 @@ +--- +key: Rotor3TiltedAnims +summary: Facing-specific SHP names for rotor 3 while the aircraft moves. +when_omitted: + kind: value + value: "" +--- + +`Rotor3TiltedAnims` lists up to eight direction-specific SHP base names for rotor 3, in facing order from north clockwise. [Aircraft rotors](/systems/aircraft-rotors/#directional-artwork) explains when these shapes are used. diff --git a/manual/content/keys/rotor4anim.md b/manual/content/keys/rotor4anim.md new file mode 100644 index 000000000..e690ab935 --- /dev/null +++ b/manual/content/keys/rotor4anim.md @@ -0,0 +1,9 @@ +--- +key: Rotor4Anim +summary: Fourth custom shape in the repeating rotor-art sequence. +when_omitted: + kind: value + value: "" +--- + +`Rotor4Anim` names the fourth custom SHP file in the aircraft's repeating rotor-art sequence. [Aircraft rotors](/systems/aircraft-rotors/#custom-artwork) explains how the engine selects custom and built-in shapes. diff --git a/manual/content/keys/rotor4flh.md b/manual/content/keys/rotor4flh.md new file mode 100644 index 000000000..acdcc6bb4 --- /dev/null +++ b/manual/content/keys/rotor4flh.md @@ -0,0 +1,9 @@ +--- +key: Rotor4FLH +summary: Forward, lateral, and height offset for rotor 4. +when_omitted: + kind: value + value: "0,0,0" +--- + +`Rotor4FLH` moves rotor 4 from the aircraft's center along its local forward, lateral, and height axes. [Aircraft rotors](/systems/aircraft-rotors/#custom-artwork) explains how the offset affects drawing. diff --git a/manual/content/keys/rotor4tiltedanims.md b/manual/content/keys/rotor4tiltedanims.md new file mode 100644 index 000000000..61ae30b30 --- /dev/null +++ b/manual/content/keys/rotor4tiltedanims.md @@ -0,0 +1,9 @@ +--- +key: Rotor4TiltedAnims +summary: Facing-specific SHP names for rotor 4 while the aircraft moves. +when_omitted: + kind: value + value: "" +--- + +`Rotor4TiltedAnims` lists up to eight direction-specific SHP base names for rotor 4, in facing order from north clockwise. [Aircraft rotors](/systems/aircraft-rotors/#directional-artwork) explains when these shapes are used. diff --git a/manual/content/keys/rotorcount.md b/manual/content/keys/rotorcount.md new file mode 100644 index 000000000..047d3f5c8 --- /dev/null +++ b/manual/content/keys/rotorcount.md @@ -0,0 +1,9 @@ +--- +key: RotorCount +summary: Number of rotors drawn for the aircraft. +when_omitted: + kind: value + value: "1" +--- + +`RotorCount` sets how many rotors OpenTS draws when [`Rotors=yes`](/keys/rotors/) is enabled. [Aircraft rotors](/systems/aircraft-rotors/#rotor-count-and-frame-selection) explains the limit and frame selection. diff --git a/manual/content/keys/rotors.md b/manual/content/keys/rotors.md index fa4ece3c9..a5111a28b 100644 --- a/manual/content/keys/rotors.md +++ b/manual/content/keys/rotors.md @@ -1,11 +1,9 @@ --- key: Rotors -summary: Parsed rotor flag that the engine never uses. -no_effect: true -see_also: ["CustomRotor"] +summary: Controls whether OpenTS draws rotor effects on an aircraft. when_omitted: kind: value value: "no" --- -OpenTS draws no separate rotor blades over an aircraft at any setting. A helicopter shows only the frames its own artwork supplies, so spinning blades must be part of that artwork. +Set `Rotors=yes` in the aircraft's `art.ini` image section to draw separate rotor artwork. [Aircraft rotors](/systems/aircraft-rotors/) explains how the engine selects and positions the shapes. diff --git a/manual/content/systems/aircraft-rotors.md b/manual/content/systems/aircraft-rotors.md new file mode 100644 index 000000000..a62bf2157 --- /dev/null +++ b/manual/content/systems/aircraft-rotors.md @@ -0,0 +1,56 @@ +--- +title: Aircraft rotors +summary: How rotor count, artwork, direction, placement, and visibility affect aircraft drawing. +category: rendering-presentation +keys: + - Rotors + - RotorCount + - Rotor1Anim + - Rotor2Anim + - Rotor3Anim + - Rotor4Anim + - Rotor1FLH + - Rotor2FLH + - Rotor3FLH + - Rotor4FLH + - Rotor1TiltedAnims + - Rotor2TiltedAnims + - Rotor3TiltedAnims + - Rotor4TiltedAnims +--- + +OpenTS draws separate rotor shapes only when an aircraft's `art.ini` image section sets [`Rotors=yes`](/keys/rotors/). The aircraft must have positive strength and be visible to the current player; a hidden aircraft's rotors are not drawn. + +Rotor shapes are 25% translucent when the aircraft is landed and 50% when it is airborne. A cloaked aircraft uses 50% and 75% translucency, respectively. + +## Rotor count and frame selection + +[`RotorCount`](/keys/rotorcount/) sets how many rotors the engine draws, up to four. A value of zero or less draws none. Each rotor uses a 12-frame SHP: frames 0–3 while airborne and frames 4–11 while landed. + +If custom artwork is unavailable, rotor 1 and rotor 3 use `LROTOR.SHP`, while rotor 2 and rotor 4 use `RROTOR.SHP`. A rotor is not drawn if neither its custom SHP nor its built-in SHP loads. + +## Custom artwork + +[`Rotor1Anim`](/keys/rotor1anim/), [`Rotor2Anim`](/keys/rotor2anim/), [`Rotor3Anim`](/keys/rotor3anim/), and [`Rotor4Anim`](/keys/rotor4anim/) name custom SHP files by their base names; the engine adds `.SHP`. Keep each name to 15 characters. Each custom SHP must have the same 12-frame layout as the built-in rotor shapes. + +The engine counts consecutive `Rotor#Anim` names starting at `Rotor1Anim` and stops at the first missing name. It repeats that sequence for additional rotors: one custom name serves every rotor, two names alternate, and longer sequences repeat in order. A gap causes later `Rotor#Anim` settings to be ignored. If a custom SHP cannot be loaded, the engine uses that rotor's built-in SHP instead. + +[`Rotor1FLH`](/keys/rotor1flh/), [`Rotor2FLH`](/keys/rotor2flh/), [`Rotor3FLH`](/keys/rotor3flh/), and [`Rotor4FLH`](/keys/rotor4flh/) move their rotors along the aircraft's local forward, lateral, and height axes. Flat and direction-specific artwork use the same offset. + +```ini title="art.ini" +[MYHELI] +Rotors=yes +RotorCount=2 +Rotor1Anim=MYROTOR +Rotor1FLH=32,0,48 +Rotor2FLH=-32,0,48 +Rotor1TiltedAnims=MYROT_N,MYROT_NE,MYROT_E,MYROT_SE,MYROT_S,MYROT_SW,MYROT_W,MYROT_NW +``` + +In this example, both rotors use `MYROTOR`; `Rotor1TiltedAnims` supplies the eight directional versions for both. + +## Directional artwork + +Each of [`Rotor1TiltedAnims`](/keys/rotor1tiltedanims/), [`Rotor2TiltedAnims`](/keys/rotor2tiltedanims/), [`Rotor3TiltedAnims`](/keys/rotor3tiltedanims/), and [`Rotor4TiltedAnims`](/keys/rotor4tiltedanims/) must supply eight comma-separated SHP base names, ordered from north (facing towards the top right corner of the screen) clockwise. Each filename in the list may contain at most 15 characters; an empty position leaves that facing without a directional shape. + +While the aircraft is moving, the engine selects the directional shape for its current facing. If that shape is missing, it uses the corresponding flat custom shape, then the built-in shape. Directional shapes are considered only for the consecutive custom-art sequence described above; setting a `Rotor#TiltedAnims` key without a matching `Rotor#Anim` does not enable custom rotor artwork. diff --git a/manual/data/ini-keys.yaml b/manual/data/ini-keys.yaml index 9e64aa358..fd263623f 100644 --- a/manual/data/ini-keys.yaml +++ b/manual/data/ini-keys.yaml @@ -2980,7 +2980,7 @@ BehavesLike: source: code/ptype.cpp guard: null level: ParticleTypeClass - - applies_to: &id023 + - applies_to: &id022 - ParticleSystemType file: rules.ini section: @@ -4281,7 +4281,7 @@ C4Warhead: CD: key: CD scopes: - - applies_to: &id021 + - applies_to: &id020 - Campaign file: battle.ini section: @@ -4470,7 +4470,7 @@ CarryOverMoney: Carryall: key: Carryall scopes: - - applies_to: &id019 + - applies_to: &id024 - AircraftType file: rules.ini section: @@ -5168,7 +5168,7 @@ Color: source: code/houstype.cpp guard: null level: HouseTypeClass - - applies_to: &id020 + - applies_to: &id019 - Tiberium file: rules.ini section: @@ -6132,23 +6132,6 @@ CursorScale: source: code/options.cpp guard: null level: OptionsClass -CustomRotor: - key: CustomRotor - scopes: - - applies_to: *id019 - file: art.ini - section: - kind: image - fallback: object-type - value_type: boolean - status: generated - _provenance: - default_candidate: 'no' - declared_in: AircraftTypeClass - member: IsRotorCustom - source: code/airctype.cpp - guard: null - level: AircraftTypeClass Cyborg: key: Cyborg scopes: @@ -6449,7 +6432,7 @@ DeathFrames: Debris: key: Debris scopes: - - applies_to: *id020 + - applies_to: *id019 file: rules.ini section: kind: identifier @@ -7011,7 +6994,7 @@ Description: source: code/suprtype.cpp guard: null level: SuperWeaponTypeClass - - applies_to: *id021 + - applies_to: *id020 file: battle.ini section: kind: identifier @@ -8675,7 +8658,7 @@ FinalDamageState: FinalMovie: key: FinalMovie scopes: - - applies_to: *id021 + - applies_to: *id020 file: battle.ini section: kind: identifier @@ -8729,7 +8712,7 @@ FireAngle: scopes: - applies_to: *id003 file: art.ini - section: &id022 + section: &id021 kind: image fallback: object-type value_type: angle @@ -8748,7 +8731,7 @@ FireAngle: value_type: integer applies_to: *id003 - file: art.ini - section: *id022 + section: *id021 value_type: angle applies_to: *id003 precedence: read more than once -- the art.ini value is applied last and overrides the others @@ -10035,7 +10018,7 @@ Group: Growth: key: Growth scopes: - - applies_to: *id020 + - applies_to: *id019 file: rules.ini section: kind: identifier @@ -10052,7 +10035,7 @@ Growth: GrowthPercentage: key: GrowthPercentage scopes: - - applies_to: *id020 + - applies_to: *id019 file: rules.ini section: kind: identifier @@ -10579,7 +10562,7 @@ High: HighRadarBrightness: key: HighRadarBrightness scopes: - - applies_to: &id024 + - applies_to: &id023 - Theater file: rules.ini section: @@ -10597,7 +10580,7 @@ HighRadarBrightness: HoldsWhat: key: HoldsWhat scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -11276,7 +11259,7 @@ Image: source: code/objtype.cpp guard: null level: ObjectTypeClass - - applies_to: *id020 + - applies_to: *id019 file: rules.ini section: kind: identifier @@ -11309,7 +11292,7 @@ Image: ImageLetter: key: ImageLetter scopes: - - applies_to: *id024 + - applies_to: *id023 file: rules.ini section: kind: identifier @@ -12310,7 +12293,7 @@ IsAnimatedTiberium: IsArctic: key: IsArctic scopes: - - applies_to: *id024 + - applies_to: *id023 file: rules.ini section: kind: identifier @@ -12457,7 +12440,7 @@ IsFlammable: IsIceGrowthEnabled: key: IsIceGrowthEnabled scopes: - - applies_to: *id024 + - applies_to: *id023 file: rules.ini section: kind: identifier @@ -12926,7 +12909,7 @@ IsWebImmune: IsoRoot: key: IsoRoot scopes: - - applies_to: *id024 + - applies_to: *id023 file: rules.ini section: kind: identifier @@ -12994,7 +12977,7 @@ Land: Landable: key: Landable scopes: - - applies_to: *id019 + - applies_to: *id024 file: rules.ini section: kind: identifier @@ -13061,7 +13044,7 @@ LargeVisceroid: Laser: key: Laser scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -13078,7 +13061,7 @@ Laser: LaserColor: key: LaserColor scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -13315,7 +13298,7 @@ Level: Lifetime: key: Lifetime scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -13400,7 +13383,7 @@ LightRedTint: LightSize: key: LightSize scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -13695,7 +13678,7 @@ Lose: LowRadarBrightness: key: LowRadarBrightness scopes: - - applies_to: *id024 + - applies_to: *id023 file: rules.ini section: kind: identifier @@ -13748,7 +13731,7 @@ MMRampBase: MMSuffix: key: MMSuffix scopes: - - applies_to: *id024 + - applies_to: *id023 file: rules.ini section: kind: identifier @@ -14776,7 +14759,7 @@ MovementLineThick: MovementPerturbationCoefficient: key: MovementPerturbationCoefficient scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -15980,7 +15963,7 @@ OnTransOnly: OneFrameLight: key: OneFrameLight scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -16225,7 +16208,7 @@ Particle: ParticleCap: key: ParticleCap scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -16242,7 +16225,7 @@ ParticleCap: ParticlesPerCoord: key: ParticlesPerCoord scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -16804,7 +16787,7 @@ PoseDir: PositionPerturbationCoefficient: key: PositionPerturbationCoefficient scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -16853,7 +16836,7 @@ Power: source: code/builtype.cpp guard: null level: BuildingTypeClass - - applies_to: *id020 + - applies_to: *id019 file: rules.ini section: kind: identifier @@ -18822,7 +18805,7 @@ RequiredAddOn: RequiredAddon: key: RequiredAddon scopes: - - applies_to: *id021 + - applies_to: *id020 file: battle.ini section: kind: identifier @@ -19014,7 +18997,7 @@ RollAngle: Root: key: Root scopes: - - applies_to: *id024 + - applies_to: *id023 file: rules.ini section: kind: identifier @@ -19061,10 +19044,231 @@ Rotates: source: code/bullettype.cpp guard: null level: BulletTypeClass +Rotor1Anim: + key: Rotor1Anim + scopes: + - applies_to: *id024 + file: art.ini + section: + kind: image + fallback: object-type + value_type: string + status: generated + _provenance: + default_candidate: null + declared_in: AircraftTypeClass + member: Rotor1File + source: code/airctype.cpp + guard: null + level: AircraftTypeClass +Rotor1FLH: + key: Rotor1FLH + scopes: + - applies_to: *id024 + file: art.ini + section: + kind: image + fallback: object-type + value_type: point (x,y,z) + status: generated + _provenance: + default_candidate: null + declared_in: AircraftTypeClass + member: Rotor1FLH + source: code/airctype.cpp + guard: null + level: AircraftTypeClass +Rotor1TiltedAnims: + key: Rotor1TiltedAnims + scopes: + - applies_to: *id024 + file: art.ini + section: + kind: image + fallback: object-type + value_type: string + status: generated + _provenance: + default_candidate: null + declared_in: AircraftTypeClass + member: tiltednames + source: code/airctype.cpp + guard: null + level: AircraftTypeClass +Rotor2Anim: + key: Rotor2Anim + scopes: + - applies_to: *id024 + file: art.ini + section: + kind: image + fallback: object-type + value_type: string + status: generated + _provenance: + default_candidate: null + declared_in: AircraftTypeClass + member: Rotor2File + source: code/airctype.cpp + guard: null + level: AircraftTypeClass +Rotor2FLH: + key: Rotor2FLH + scopes: + - applies_to: *id024 + file: art.ini + section: + kind: image + fallback: object-type + value_type: point (x,y,z) + status: generated + _provenance: + default_candidate: null + declared_in: AircraftTypeClass + member: Rotor2FLH + source: code/airctype.cpp + guard: null + level: AircraftTypeClass +Rotor2TiltedAnims: + key: Rotor2TiltedAnims + scopes: + - applies_to: *id024 + file: art.ini + section: + kind: image + fallback: object-type + value_type: string + status: generated + _provenance: + default_candidate: null + declared_in: AircraftTypeClass + member: tiltednames + source: code/airctype.cpp + guard: null + level: AircraftTypeClass +Rotor3Anim: + key: Rotor3Anim + scopes: + - applies_to: *id024 + file: art.ini + section: + kind: image + fallback: object-type + value_type: string + status: generated + _provenance: + default_candidate: null + declared_in: AircraftTypeClass + member: Rotor3File + source: code/airctype.cpp + guard: null + level: AircraftTypeClass +Rotor3FLH: + key: Rotor3FLH + scopes: + - applies_to: *id024 + file: art.ini + section: + kind: image + fallback: object-type + value_type: point (x,y,z) + status: generated + _provenance: + default_candidate: null + declared_in: AircraftTypeClass + member: Rotor3FLH + source: code/airctype.cpp + guard: null + level: AircraftTypeClass +Rotor3TiltedAnims: + key: Rotor3TiltedAnims + scopes: + - applies_to: *id024 + file: art.ini + section: + kind: image + fallback: object-type + value_type: string + status: generated + _provenance: + default_candidate: null + declared_in: AircraftTypeClass + member: tiltednames + source: code/airctype.cpp + guard: null + level: AircraftTypeClass +Rotor4Anim: + key: Rotor4Anim + scopes: + - applies_to: *id024 + file: art.ini + section: + kind: image + fallback: object-type + value_type: string + status: generated + _provenance: + default_candidate: null + declared_in: AircraftTypeClass + member: Rotor4File + source: code/airctype.cpp + guard: null + level: AircraftTypeClass +Rotor4FLH: + key: Rotor4FLH + scopes: + - applies_to: *id024 + file: art.ini + section: + kind: image + fallback: object-type + value_type: point (x,y,z) + status: generated + _provenance: + default_candidate: null + declared_in: AircraftTypeClass + member: Rotor4FLH + source: code/airctype.cpp + guard: null + level: AircraftTypeClass +Rotor4TiltedAnims: + key: Rotor4TiltedAnims + scopes: + - applies_to: *id024 + file: art.ini + section: + kind: image + fallback: object-type + value_type: string + status: generated + _provenance: + default_candidate: null + declared_in: AircraftTypeClass + member: tiltednames + source: code/airctype.cpp + guard: null + level: AircraftTypeClass +RotorCount: + key: RotorCount + scopes: + - applies_to: *id024 + file: art.ini + section: + kind: image + fallback: object-type + value_type: integer + status: generated + _provenance: + default_candidate: '1' + declared_in: AircraftTypeClass + member: RotorCount + source: code/airctype.cpp + guard: null + level: AircraftTypeClass Rotors: key: Rotors scopes: - - applies_to: *id019 + - applies_to: *id024 file: art.ini section: kind: image @@ -19308,7 +19512,7 @@ ScatterSound: Scenario: key: Scenario scopes: - - applies_to: *id021 + - applies_to: *id020 file: battle.ini section: kind: identifier @@ -20607,7 +20811,7 @@ SlopeSetPieces2: Slowdown: key: Slowdown scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -20868,7 +21072,7 @@ Soylent: SparkSpawnFrames: key: SparkSpawnFrames scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -20933,7 +21137,7 @@ SpawnCount: SpawnCutoff: key: SpawnCutoff scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -20950,7 +21154,7 @@ SpawnCutoff: SpawnDirection: key: SpawnDirection scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -20967,7 +21171,7 @@ SpawnDirection: SpawnFrames: key: SpawnFrames scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -20984,7 +21188,7 @@ SpawnFrames: SpawnRadius: key: SpawnRadius scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -21001,7 +21205,7 @@ SpawnRadius: SpawnSparkPercentage: key: SpawnSparkPercentage scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -21018,7 +21222,7 @@ SpawnSparkPercentage: SpawnTranslucencyCutoff: key: SpawnTranslucencyCutoff scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -21049,7 +21253,7 @@ Spawns: source: code/animtype.cpp guard: null level: AnimTypeClass - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -21656,7 +21860,7 @@ SpeedType: SpiralDeltaPerCoord: key: SpiralDeltaPerCoord scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -21673,7 +21877,7 @@ SpiralDeltaPerCoord: SpiralRadius: key: SpiralRadius scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier @@ -21847,7 +22051,7 @@ Spread: source: code/warhead.cpp guard: null level: WarheadTypeClass - - applies_to: *id020 + - applies_to: *id019 file: rules.ini section: kind: identifier @@ -21864,7 +22068,7 @@ Spread: SpreadPercentage: key: SpreadPercentage scopes: - - applies_to: *id020 + - applies_to: *id019 file: rules.ini section: kind: identifier @@ -22343,7 +22547,7 @@ Suffix: source: code/houstype.cpp guard: null level: HouseTypeClass - - applies_to: *id024 + - applies_to: *id023 file: rules.ini section: kind: identifier @@ -25396,7 +25600,7 @@ VSync: Value: key: Value scopes: - - applies_to: *id020 + - applies_to: *id019 file: rules.ini section: kind: identifier @@ -25662,7 +25866,7 @@ Velocity: VelocityPerturbationCoefficient: key: VelocityPerturbationCoefficient scopes: - - applies_to: *id023 + - applies_to: *id022 file: rules.ini section: kind: identifier diff --git a/manual/data/tombstones.yaml b/manual/data/tombstones.yaml index c5d88d146..c60b2c4ff 100644 --- a/manual/data/tombstones.yaml +++ b/manual/data/tombstones.yaml @@ -251,3 +251,9 @@ - "-MESSAGES" - Disable network protection summary: Let in-game chat from outside the match through. Removed when a line began to be accepted only from a seat of the match. +- type: key + id: CustomRotor + route: /keys/customrotor/ + search_aliases: + - CustomRotor + summary: Was read as a rotor flag but had no effect. Removed when OpenTS added aircraft rotor drawing.