Skip to content

Commit 8ff28b5

Browse files
committed
Fix W3DModelDraw transitionstate issue
Fix Model Anim scaling issue Fix ScatterTarget range check issue Add StickyBomb Crate collide
1 parent f41010b commit 8ff28b5

File tree

13 files changed

+351
-9
lines changed

13 files changed

+351
-9
lines changed

GeneralsMD/Code/GameEngine/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ set(GAMEENGINE_SRC
425425
Include/GameLogic/Module/SabotageSupplyCenterCrateCollide.h
426426
Include/GameLogic/Module/SabotageSupplyDropzoneCrateCollide.h
427427
Include/GameLogic/Module/SalvageCrateCollide.h
428+
Include/GameLogic/Module/StickyBombCrateCollide.h
428429
Include/GameLogic/Module/ScatterShotUpdate.h
429430
Include/GameLogic/Module/ShroudCrateCollide.h
430431
Include/GameLogic/Module/SlavedUpdate.h
@@ -912,6 +913,7 @@ set(GAMEENGINE_SRC
912913
Source/GameLogic/Object/Collide/CrateCollide/SabotageSupplyCenterCrateCollide.cpp
913914
Source/GameLogic/Object/Collide/CrateCollide/SabotageSupplyDropzoneCrateCollide.cpp
914915
Source/GameLogic/Object/Collide/CrateCollide/SalvageCrateCollide.cpp
916+
Source/GameLogic/Object/Collide/CrateCollide/StickyBombCrateCollide.cpp
915917
Source/GameLogic/Object/Collide/CrateCollide/ShroudCrateCollide.cpp
916918
Source/GameLogic/Object/Collide/CrateCollide/UnitCrateCollide.cpp
917919
Source/GameLogic/Object/Collide/CrateCollide/VeterancyCrateCollide.cpp

GeneralsMD/Code/GameEngine/Include/Common/DrawModule.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ class ObjectDrawInterface
199199
Note that you must call this AFTER setting the condition codes.
200200
*/
201201
virtual void setAnimationLoopDuration(UnsignedInt numFrames) = 0;
202+
virtual bool isIgnoreAnimLoopDuration() const = 0;
202203

203204
/**
204205
similar to the above, but assumes that the current state is a "ONCE",

GeneralsMD/Code/GameEngine/Include/GameLogic/Module/CrateCollide.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@ class CrateCollideModuleData : public CollideModuleData
4848
KindOfMaskType m_kindof; ///< the kind(s) of units that can be collided with
4949
KindOfMaskType m_kindofnot; ///< the kind(s) of units that CANNOT be collided with
5050
Bool m_isForbidOwnerPlayer; ///< This crate cannot be picked up by the player of the dead thing that made it.
51+
Bool m_isAllowNeutralPlayer; ///< This crate can be picked up by the neutral player
5152
Bool m_isBuildingPickup; ///< This crate can be picked up by a Building (bypassing AI requirement)
5253
Bool m_isHumanOnlyPickup; ///< Can this crate only be picked up by a human player? (Mission thing)
54+
Bool m_isAllowPickAboveTerrain; ///< Can this crate only be picked when on the ground´?
5355
ScienceType m_pickupScience; ///< Can only be picked up by a unit whose player has this science
5456
FXList *m_executeFX; ///< FXList to play when activated
5557

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
** Command & Conquer Generals Zero Hour(tm)
3+
** Copyright 2025 Electronic Arts Inc.
4+
**
5+
** This program is free software: you can redistribute it and/or modify
6+
** it under the terms of the GNU General Public License as published by
7+
** the Free Software Foundation, either version 3 of the License, or
8+
** (at your option) any later version.
9+
**
10+
** This program is distributed in the hope that it will be useful,
11+
** but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
** GNU General Public License for more details.
14+
**
15+
** You should have received a copy of the GNU General Public License
16+
** along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
////////////////////////////////////////////////////////////////////////////////
20+
// //
21+
// (c) 2001-2003 Electronic Arts Inc. //
22+
// //
23+
////////////////////////////////////////////////////////////////////////////////
24+
25+
///////////////////////////////////////////////////////////////////////////////////////////////////
26+
//
27+
// FILE: StickyBombCrateCollide.h
28+
// Author: Kris Morness, June 2003
29+
// Desc: A crate (actually a saboteur - mobile crate) that resets ALL command center general powers
30+
//
31+
///////////////////////////////////////////////////////////////////////////////////////////////////
32+
33+
#pragma once
34+
35+
#ifndef STICKY_BOMB_CRATE_COLLIDE_H_
36+
#define STICKY_BOMB_CRATE_COLLIDE_H_
37+
38+
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
39+
#include "Common/Module.h"
40+
#include "GameLogic/Module/CrateCollide.h"
41+
42+
// FORWARD REFERENCES /////////////////////////////////////////////////////////////////////////////
43+
class Thing;
44+
45+
//-------------------------------------------------------------------------------------------------
46+
class StickyBombCrateCollideModuleData : public CrateCollideModuleData
47+
{
48+
public:
49+
50+
Bool m_needsTarget; ///< Need valid AI target (e.g. ordered to enter a building/unit, or projectile target)
51+
Bool m_allowMultiCollide; ///< if we are a crate, allow spawning multiple sticky bombs, or just single use
52+
Bool m_showInfiltrationEvent; ///< show an infiltration map event for the target player
53+
AsciiString m_stickyBombObjectName; ///< the object to create
54+
55+
StickyBombCrateCollideModuleData()
56+
{
57+
m_needsTarget = FALSE;
58+
m_allowMultiCollide = FALSE;
59+
m_showInfiltrationEvent = FALSE;
60+
m_stickyBombObjectName = AsciiString::TheEmptyString;
61+
}
62+
63+
static void buildFieldParse(MultiIniFieldParse& p)
64+
{
65+
CrateCollideModuleData::buildFieldParse(p);
66+
67+
static const FieldParse dataFieldParse[] =
68+
{
69+
{ "NeedsTarget", INI::parseBool, NULL, offsetof(StickyBombCrateCollideModuleData, m_needsTarget) },
70+
{ "AllowMultiCollide", INI::parseBool, NULL, offsetof(StickyBombCrateCollideModuleData, m_allowMultiCollide) },
71+
{ "ShowInfiltrationEvent", INI::parseBool, NULL, offsetof(StickyBombCrateCollideModuleData, m_showInfiltrationEvent) },
72+
{ "StickyBombObject", INI::parseAsciiString, NULL, offsetof(StickyBombCrateCollideModuleData, m_stickyBombObjectName) },
73+
{ 0, 0, 0, 0 }
74+
};
75+
p.add( dataFieldParse );
76+
}
77+
78+
};
79+
80+
//-------------------------------------------------------------------------------------------------
81+
class StickyBombCrateCollide : public CrateCollide
82+
{
83+
84+
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( StickyBombCrateCollide, "StickyBombCrateCollide" )
85+
MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA( StickyBombCrateCollide, StickyBombCrateCollideModuleData );
86+
87+
public:
88+
89+
StickyBombCrateCollide( Thing *thing, const ModuleData* moduleData );
90+
// virtual destructor prototype provided by memory pool declaration
91+
92+
protected:
93+
94+
/// This allows specific vetoes to certain types of crates and their data
95+
virtual Bool isValidToExecute( const Object *other ) const;
96+
97+
/// This is the game logic execution function that all real CrateCollides will implement
98+
virtual Bool executeCrateBehavior( Object *other );
99+
100+
/// This would allow entering buildings? Lets disable it for now
101+
// virtual Bool isSabotageBuildingCrateCollide() const { return TRUE; }
102+
103+
private:
104+
Bool m_hasCollided;
105+
106+
};
107+
108+
#endif

GeneralsMD/Code/GameEngine/Include/GameLogic/Module/StickyBombUpdate.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class StickyBombUpdateModuleData : public UpdateModuleData
5050

5151
AsciiString m_animBaseTemplate;
5252
AsciiString m_animTimedTemplate;
53+
Bool m_showTimer;
5354

5455
StickyBombUpdateModuleData()
5556
{
@@ -58,6 +59,7 @@ class StickyBombUpdateModuleData : public UpdateModuleData
5859
m_geometryBasedDamageFX = NULL;
5960
m_animBaseTemplate = AsciiString::TheEmptyString;
6061
m_animTimedTemplate = AsciiString::TheEmptyString;
62+
m_showTimer = TRUE;
6163
}
6264

6365
static void buildFieldParse(MultiIniFieldParse& p)
@@ -71,6 +73,7 @@ class StickyBombUpdateModuleData : public UpdateModuleData
7173
{ "GeometryBasedDamageFX", INI::parseFXList, NULL, offsetof( StickyBombUpdateModuleData, m_geometryBasedDamageFX ) },
7274
{ "Animation2DBase", INI::parseAsciiString, NULL, offsetof( StickyBombUpdateModuleData, m_animBaseTemplate) },
7375
{ "Animation2DTimed", INI::parseAsciiString, NULL, offsetof( StickyBombUpdateModuleData, m_animTimedTemplate) },
76+
{ "ShowTimer", INI::parseBool, NULL, offsetof( StickyBombUpdateModuleData, m_showTimer) },
7477
{ 0, 0, 0, 0 }
7578
};
7679
p.add(dataFieldParse);
@@ -95,7 +98,7 @@ class StickyBombUpdate : public UpdateModule
9598

9699
void initStickyBomb( Object *object, const Object *bomber, const Coord3D *specificPos = NULL );
97100
void detonate();
98-
Bool isTimedBomb() const { return m_dieFrame > 0; }
101+
Bool isTimedBomb() const { return (m_dieFrame > 0) && getStickyBombUpdateModuleData()->m_showTimer; }
99102
UnsignedInt getDetonationFrame() const { return m_dieFrame; }
100103
Object* getTargetObject() const;
101104
void setTargetObject( Object *obj );

GeneralsMD/Code/GameEngine/Source/Common/System/MemoryInit.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ static PoolSizeRec sizes[] =
294294
{ "RailedTransportContain", 16, 16 },
295295
{ "RailroadBehavior", 16, 16 },
296296
{ "SalvageCrateCollide", 32, 32 },
297+
{ "StickyBombCrateCollide", 32, 32 },
297298
{ "ShroudCrateCollide", 32, 32 },
298299
{ "SlavedUpdate", 64, 32 },
299300
{ "SlowDeathBehavior", 1400, 256 },

GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@
253253
#include "GameLogic/Module/SabotageSupplyCenterCrateCollide.h"
254254
#include "GameLogic/Module/SabotageSupplyDropzoneCrateCollide.h"
255255
#include "GameLogic/Module/SalvageCrateCollide.h"
256+
#include "GameLogic/Module/StickyBombCrateCollide.h"
256257
#include "GameLogic/Module/ShroudCrateCollide.h"
257258
#include "GameLogic/Module/UnitCrateCollide.h"
258259
#include "GameLogic/Module/VeterancyCrateCollide.h"
@@ -545,6 +546,7 @@ void ModuleFactory::init( void )
545546
addModule( SabotageSupplyCenterCrateCollide );
546547
addModule( SabotageSupplyDropzoneCrateCollide );
547548
addModule( SalvageCrateCollide );
549+
addModule( StickyBombCrateCollide );
548550

549551
// body modules
550552
addModule( InactiveBody );

GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ void Drawable::setAnimationLoopDuration(UnsignedInt numFrames)
726726
for (DrawModule** dm = getDrawModules(); *dm; ++dm)
727727
{
728728
ObjectDrawInterface* di = (*dm)->getObjectDrawInterface();
729-
if (di)
729+
if (di && !di->isIgnoreAnimLoopDuration())
730730
di->setAnimationLoopDuration(numFrames);
731731
}
732732
}

GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Collide/CrateCollide/CrateCollide.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@
4848
CrateCollideModuleData::CrateCollideModuleData()
4949
{
5050
m_isForbidOwnerPlayer = FALSE;
51+
m_isAllowNeutralPlayer = FALSE;
5152
m_executeAnimationDisplayTimeInSeconds = 0.0f;
5253
m_executeAnimationZRisePerSecond = 0.0f;
5354
m_executeAnimationFades = TRUE;
5455
m_isBuildingPickup = FALSE;
5556
m_isHumanOnlyPickup = FALSE;
57+
m_isAllowPickAboveTerrain = FALSE;
5658
m_executeFX = NULL;
5759
m_pickupScience = SCIENCE_INVALID;
5860

@@ -75,8 +77,10 @@ void CrateCollideModuleData::buildFieldParse(MultiIniFieldParse& p)
7577
{ "RequiredKindOf", KindOfMaskType::parseFromINI, NULL, offsetof( CrateCollideModuleData, m_kindof ) },
7678
{ "ForbiddenKindOf", KindOfMaskType::parseFromINI, NULL, offsetof( CrateCollideModuleData, m_kindofnot ) },
7779
{ "ForbidOwnerPlayer", INI::parseBool, NULL, offsetof( CrateCollideModuleData, m_isForbidOwnerPlayer ) },
80+
{ "AllowNeutralPlayer", INI::parseBool, NULL, offsetof( CrateCollideModuleData, m_isAllowNeutralPlayer ) },
7881
{ "BuildingPickup", INI::parseBool, NULL, offsetof( CrateCollideModuleData, m_isBuildingPickup ) },
7982
{ "HumanOnly", INI::parseBool, NULL, offsetof( CrateCollideModuleData, m_isHumanOnlyPickup ) },
83+
{ "AllowPickAboveTerrain", INI::parseBool, NULL, offsetof( CrateCollideModuleData, m_isAllowPickAboveTerrain ) },
8084
{ "PickupScience", INI::parseScience, NULL, offsetof( CrateCollideModuleData, m_pickupScience ) },
8185
{ "ExecuteFX", INI::parseFXList, NULL, offsetof( CrateCollideModuleData, m_executeFX ) },
8286
{ "ExecuteAnimation", INI::parseAsciiString, NULL, offsetof( CrateCollideModuleData, m_executionAnimationTemplate ) },
@@ -149,11 +153,12 @@ Bool CrateCollide::isValidToExecute( const Object *other ) const
149153
if( other == NULL )
150154
return FALSE;
151155

156+
const CrateCollideModuleData* md = getCrateCollideModuleData();
157+
152158
//Nothing Neutral can pick up any type of crate
153-
if( other->isNeutralControlled() )
159+
if(other->isNeutralControlled() && !md->m_isAllowNeutralPlayer)
154160
return FALSE;
155161

156-
const CrateCollideModuleData* md = getCrateCollideModuleData();
157162
Bool validBuildingAttempt = md->m_isBuildingPickup && other->isKindOf( KINDOF_STRUCTURE );
158163

159164
// Must be a "Unit" type thing. Real Game Object, not just Object
@@ -168,7 +173,7 @@ Bool CrateCollide::isValidToExecute( const Object *other ) const
168173
return FALSE;
169174

170175
// crates cannot be claimed while in the air, except by buildings
171-
if( getObject()->isAboveTerrain() && !validBuildingAttempt )
176+
if( getObject()->isAboveTerrain() && !(validBuildingAttempt || md->m_isAllowPickAboveTerrain))
172177
return FALSE;
173178

174179
if( md->m_isForbidOwnerPlayer && (getObject()->getControllingPlayer() == other->getControllingPlayer()) )

0 commit comments

Comments
 (0)