From 30f8e7eb6bce8eff2d72c2506bc4cee365ddfce1 Mon Sep 17 00:00:00 2001 From: Martin Neal Date: Mon, 2 Nov 2026 12:24:13 +1300 Subject: [PATCH 1/4] Implements Rotors, RotorCount, Rotor#Anim, Rotor#FLH, and Rotor#TiltedAnims --- code/aircraft.cpp | 181 +++++++++++++++++++++++++++++++++------ code/aircraft.h | 2 +- code/airctype.cpp | 214 ++++++++++++++++++++++++++++++++++++++++++++-- code/airctype.h | 40 ++++++++- 4 files changed, 402 insertions(+), 35 deletions(-) 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..bbff2bbbe 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,89 @@ 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 const* tiltedKeys[ROTOR_COUNT] = { + "Rotor1TiltedAnims", + "Rotor2TiltedAnims", + "Rotor3TiltedAnims", + "Rotor4TiltedAnims" + }; + + 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'; + + ArtINI.Get_String( + Graphic_Name(), + tiltedKeys[rotor], + "", + tiltednames, + sizeof(tiltednames) + ); + + int direction = 0; + 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 +405,7 @@ void AircraftTypeClass::Compute_CRC(CRCEngine & crc) const BASECLASS::Compute_CRC(crc); crc(IsRotorEquipped); - crc(IsRotorCustom); + crc(RotorCount); crc(IsLandable); crc(HeapID); } @@ -307,6 +422,7 @@ void AircraftTypeClass::Post_Load(void) Fetch_Voxel_Image(); Fetch_Normal_Image(); + Load_Rotor_Assets(); } @@ -321,7 +437,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 +472,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); }; From 04f4056b1d9a25e89ab52da71a89723e0a12fccc Mon Sep 17 00:00:00 2001 From: Martin Neal Date: Mon, 2 Nov 2026 12:25:45 +1300 Subject: [PATCH 2/4] Adds first pass at documentation --- manual/changes/draw-rotors-on-aircraft.md | 64 +++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 manual/changes/draw-rotors-on-aircraft.md diff --git a/manual/changes/draw-rotors-on-aircraft.md b/manual/changes/draw-rotors-on-aircraft.md new file mode 100644 index 000000000..631c84eca --- /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 + +credit: [Orac] +--- + +When `Rotors` is set to yes in an aircraft's art.ini entry, the game will now draw a rotor effect over the unit, following the Red Alert convention for this. + +As in Red Alert, a rotor is a 12 frame shape. The game cycles through the first 4 frames while flying, and through the second 8 frames while landed. The rotor is drawn at `Translucency=25` when landed, and `Translucency=50` when flying. + +The `RotorCount` key has been added. When ommitted, the game assumes 1 rotor, but it supports up to 4. + +By default, the game will look for the files `LROTOR.SHP` and `RROTOR.SHP` and use them if present. If the aircraft has more than one rotor, `LROTOR.SHP` will be assigned to rotors 1 and 3, `RROTOR.SHP` will be assigned to rotors 2 and 4. + +To load custom rotor shapes, the keys `Rotor1Anim`, `Rotor2Anim`, `Rotor3Anim`, and `Rotor4Anim` have been added. These accept shape files set up as above, with 4 flying frames followed by 8 landed frames. Note that not all `Rotor#Anim` keys need to be specified, if an aircraft has only `Rotor1Anim` with a `RotorCount` greater than 1, `Rotor1Anim` will be used for all rotors. If an aircraft has more than one rotor and both `Rotor1Anim` and `Rotor2Anim`, `Rotor1Anim` will be used for rotors 1 and 3, `Rotor2Anim` will be used for rotors 2 and 4. This behaviour can be overriden by specifying more rotor anims. + +Rotor positions can be set by FLH (Forward, Lateral, Height) value, using `Rotor1FLH`, `Rotor2FLH`, `Rotor3FLH`, and `Rotor4FLH`. + +While moving, many helicopters tilt forward. To visually support this, `Rotor1TiltedAnims`, `Rotor2TiltedAnims`, `Rotor3TiltedAnims` and `Rotor4TiltedAnims` have been added. Each of these expects a list of 8 rotor shapes in clockwise order starting at North (facing towards the top right corner of the screen). The game will select the rotor anim closest to the unit's direction of travel and display this instead of the flat rotor anim while moving in a direction. Each of these tilted rotor shapes follows the same rules as the normal rotors and uses the same FLH. From 786a3cc33ca84b5384fcbc2c95112e91221d4bae Mon Sep 17 00:00:00 2001 From: Martin Neal Date: Tue, 3 Nov 2026 09:23:19 +1300 Subject: [PATCH 3/4] Minor refactor --- code/airctype.cpp | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/code/airctype.cpp b/code/airctype.cpp index bbff2bbbe..1281f90ed 100644 --- a/code/airctype.cpp +++ b/code/airctype.cpp @@ -329,13 +329,6 @@ bool AircraftTypeClass::Read_INI(CCINIClass const& ini) const int ROTOR_DIRECTION_COUNT = 8; // Number of directions expected in list const int ROTOR_FILENAME_LENGTH = 15; - char const* tiltedKeys[ROTOR_COUNT] = { - "Rotor1TiltedAnims", - "Rotor2TiltedAnims", - "Rotor3TiltedAnims", - "Rotor4TiltedAnims" - }; - char(*tiltedFiles[ROTOR_COUNT])[ROTOR_FILENAME_LENGTH + 1] = { Rotor1TiltedFiles, Rotor2TiltedFiles, @@ -343,7 +336,8 @@ bool AircraftTypeClass::Read_INI(CCINIClass const& ini) Rotor4TiltedFiles }; - char tiltednames[ROTOR_DIRECTION_COUNT * ROTOR_FILENAME_LENGTH + (ROTOR_DIRECTION_COUNT - 1) + 1 + char tiltednames[ + ROTOR_DIRECTION_COUNT * ROTOR_FILENAME_LENGTH + (ROTOR_DIRECTION_COUNT - 1) + 1 ]; for (int rotor = 0; rotor < ROTOR_COUNT; ++rotor) { @@ -352,15 +346,26 @@ bool AircraftTypeClass::Read_INI(CCINIClass const& ini) } tiltednames[0] = '\0'; - ArtINI.Get_String( - Graphic_Name(), - tiltedKeys[rotor], - "", - tiltednames, - sizeof(tiltednames) - ); - 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) { From 81b9baf3ab9b0e60d777489f326f31fa20e92121 Mon Sep 17 00:00:00 2001 From: Martin Neal Date: Tue, 3 Nov 2026 09:49:06 +1300 Subject: [PATCH 4/4] Added documentation --- manual/changes/draw-rotors-on-aircraft.md | 20 +- manual/content/keys/customrotor.md | 11 - manual/content/keys/rotor1anim.md | 9 + manual/content/keys/rotor1flh.md | 9 + manual/content/keys/rotor1tiltedanims.md | 9 + manual/content/keys/rotor2anim.md | 9 + manual/content/keys/rotor2flh.md | 9 + manual/content/keys/rotor2tiltedanims.md | 9 + manual/content/keys/rotor3anim.md | 9 + manual/content/keys/rotor3flh.md | 9 + manual/content/keys/rotor3tiltedanims.md | 9 + manual/content/keys/rotor4anim.md | 9 + manual/content/keys/rotor4flh.md | 9 + manual/content/keys/rotor4tiltedanims.md | 9 + manual/content/keys/rotorcount.md | 9 + manual/content/keys/rotors.md | 6 +- manual/content/systems/aircraft-rotors.md | 56 ++++ manual/data/ini-keys.yaml | 340 +++++++++++++++++----- manual/data/tombstones.yaml | 6 + 19 files changed, 463 insertions(+), 93 deletions(-) delete mode 100644 manual/content/keys/customrotor.md create mode 100644 manual/content/keys/rotor1anim.md create mode 100644 manual/content/keys/rotor1flh.md create mode 100644 manual/content/keys/rotor1tiltedanims.md create mode 100644 manual/content/keys/rotor2anim.md create mode 100644 manual/content/keys/rotor2flh.md create mode 100644 manual/content/keys/rotor2tiltedanims.md create mode 100644 manual/content/keys/rotor3anim.md create mode 100644 manual/content/keys/rotor3flh.md create mode 100644 manual/content/keys/rotor3tiltedanims.md create mode 100644 manual/content/keys/rotor4anim.md create mode 100644 manual/content/keys/rotor4flh.md create mode 100644 manual/content/keys/rotor4tiltedanims.md create mode 100644 manual/content/keys/rotorcount.md create mode 100644 manual/content/systems/aircraft-rotors.md diff --git a/manual/changes/draw-rotors-on-aircraft.md b/manual/changes/draw-rotors-on-aircraft.md index 631c84eca..cc39aecc6 100644 --- a/manual/changes/draw-rotors-on-aircraft.md +++ b/manual/changes/draw-rotors-on-aircraft.md @@ -45,20 +45,20 @@ targets: - type: key id: Rotor4FLH effect: added +- type: key + id: CustomRotor + effect: removed +- type: system + id: aircraft-rotors + effect: added credit: [Orac] --- -When `Rotors` is set to yes in an aircraft's art.ini entry, the game will now draw a rotor effect over the unit, following the Red Alert convention for this. - -As in Red Alert, a rotor is a 12 frame shape. The game cycles through the first 4 frames while flying, and through the second 8 frames while landed. The rotor is drawn at `Translucency=25` when landed, and `Translucency=50` when flying. - -The `RotorCount` key has been added. When ommitted, the game assumes 1 rotor, but it supports up to 4. - -By default, the game will look for the files `LROTOR.SHP` and `RROTOR.SHP` and use them if present. If the aircraft has more than one rotor, `LROTOR.SHP` will be assigned to rotors 1 and 3, `RROTOR.SHP` will be assigned to rotors 2 and 4. +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. -To load custom rotor shapes, the keys `Rotor1Anim`, `Rotor2Anim`, `Rotor3Anim`, and `Rotor4Anim` have been added. These accept shape files set up as above, with 4 flying frames followed by 8 landed frames. Note that not all `Rotor#Anim` keys need to be specified, if an aircraft has only `Rotor1Anim` with a `RotorCount` greater than 1, `Rotor1Anim` will be used for all rotors. If an aircraft has more than one rotor and both `Rotor1Anim` and `Rotor2Anim`, `Rotor1Anim` will be used for rotors 1 and 3, `Rotor2Anim` will be used for rotors 2 and 4. This behaviour can be overriden by specifying more rotor anims. +`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 positions can be set by FLH (Forward, Lateral, Height) value, using `Rotor1FLH`, `Rotor2FLH`, `Rotor3FLH`, and `Rotor4FLH`. +`Rotor#TiltedAnims` selects facing-specific shapes while the aircraft moves. -While moving, many helicopters tilt forward. To visually support this, `Rotor1TiltedAnims`, `Rotor2TiltedAnims`, `Rotor3TiltedAnims` and `Rotor4TiltedAnims` have been added. Each of these expects a list of 8 rotor shapes in clockwise order starting at North (facing towards the top right corner of the screen). The game will select the rotor anim closest to the unit's direction of travel and display this instead of the flat rotor anim while moving in a direction. Each of these tilted rotor shapes follows the same rules as the normal rotors and uses the same FLH. +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.