Git Repos / fte_dogmode / qc / func / breakable.qc
Last update to this file was on 2025-08-13 at 05:20.
Show breakable.qc
//==============================================================================
// func_breakable -- AD breakable code modified by Qmaster, iw, and dumptruck_ds
//==============================================================================
//======================================================================
// constants
//======================================================================
#ifdef SSQC
//----------------------------------------------------------------------
// base_breakable spawnflags -- CEV
//----------------------------------------------------------------------
typedef enumflags
{
SPAWNFLAG_BASE_BREAKABLE_NO_MONSTERS = 1, // used in base_entities.qc
SPAWNFLAG_BASE_BREAKABLE_EXPLODE = 2, // explosion effect and sound
// SPAWNFLAG_NOT_ON_EASY = 256, // see base_entities.qc -- CEV
// SPAWNFLAG_NOT_ON_NORMAL = 512,
// SPAWNFLAG_NOT_ON_HARD_OR_NIGHTMARE = 1024,
// SPAWNFLAG_NOT_IN_DEATHMATCH = 2048,
// SPAWNFLAG_NOT_IN_COOP = 4096,
// SPAWNFLAG_NOT_IN_SP = 8192,
// SPAWNFLAG_NOT_ON_SKILL2 = 32768, // see base_entities.qc -- CEV
// SPAWNFLAG_NOT_ON_SKILL3 = 65536, // see base_entities.qc -- CEV
// SPAWNFLAG_CENTERPRINTALL = 131072 // see base_entities.qc -- CEV
} base_breakable_spawnflags;
#endif
#ifdef SSQC
const float BASE_BREAKABLE_DEFAULTDEBRIS = 5;
const float BASE_BREAKABLE_MAXDEBRIS = 8;
#endif
//======================================================================
// forward declarations
//======================================================================
// base_breakable
#ifdef SSQC
void() sub_dislodge_resting_entities;
void(vector dir) base_breakable_die;
void(vector dir) base_breakable_destroy;
void() base_breakable_use;
void(string key, string value) base_breakable_init_field;
void(entity e) base_breakable_init;
strip void() base_breakable;
#endif
// func_breakable
#ifdef SSQC
void(entity e) func_breakable_init;
void() func_breakable;
#endif
//------------------------------------------------------------------------------
//----------------------------------------------------------------------
// base breakable class; used by func_breakable (below), func_fall2
//----------------------------------------------------------------------
// class base_breakable: base_func
// {
#ifdef SSQC
//--------------------------------------------------------------
// SUB_DislodgeRestingEntities
// This clears the FL_ONGROUND flag from any entities that are on
// top of self. The engine does not update the FL_ONGROUND flag
// automatically in some cases, with the result that certain types
// of entities can be left floating in mid-air if the entity they
// are resting on is removed from under them. This function is
// intended to be called in the case where self is going to be
// removed, to ensure that other entities are not left floating. -- iw
//--------------------------------------------------------------
void() sub_dislodge_resting_entities =
{
local entity e = nextent (world);
while (e && e != world)
{
if (e.groundentity == self && e.flags & FL_ONGROUND)
{
e.flags &= ~FL_ONGROUND;
// TODO CEV auto-set NETFLAGS from here
// to keep CSQC updated on origin as entity
// e falls to the ground
}
e = nextent (e);
}
};
//==============================================================
// Below this is from Rubicon2 -- dumptruck_ds
//==============================================================
//--------------------------------------------------------------
// dumptruck_ds -- set the spawnflag for cosmetic explosion
// effect; use "dmg" value to hurt the player
//--------------------------------------------------------------
void(vector dir) base_breakable_die =
{
var vector org, vel;
var entity d;
var float item_index;
self.deadflag |= DF_DEAD | DF_GIBBED;
if (self.noise1 != __NULL__ && self.noise1 != "")
{
// thanks to Qmaster!!! He helped me sort out
// noise1 playing from 0 0 0 with this temp
// entity - dumptruck_ds
var entity s = spawn ();
s.origin = ((self.absmin + self.absmax) * 0.5);
setsize (s, '0 0 0', '0 0 0');
s.solid = SOLID_NOT;
s.think = sub_remove;
s.nextthink = time + 60;
sound (s, CHAN_AUTO, self.noise1, VOL_HIGH, ATTN_NORM);
}
// this is to ensure that any debris from another
// func_breakable which is resting on top of this
// func_breakable is not left floating in mid-air
// after this entity is removed -- iw
sub_dislodge_resting_entities ();
self.origin = ((self.absmin + self.absmax) * 0.5);
setorigin (self, self.origin);
if (self.switchshadstyle)
lightstyle (self.switchshadstyle, "m");
// increase the distance debris will fly -- CEV
self.health *= 2;
// a more complicated base_monster_destroy_items () that
// randomizes origin a bit & sets debris frames -- CEV
for (float i = 0; i < BASE_ENTITY_ITEMLEN; i++)
{
item_index = self.item[i];
if (item_index == 0 || item_index == __NULL__)
continue;
org_x = (self.maxs_x - self.mins_x) * random() +
self.mins_x;
org_y = (self.maxs_y - self.mins_y) * random() +
self.mins_y;
org_z = (self.maxs_z - self.mins_z) * random() +
self.mins_z;
vel = velocity_for_damage (dir, self.health);
d = spawn_base_item_throwable (item_index,
org, vel, SPAWNFLAG_ITEM_THROWN);
// randomly choose size -- this won't persist once
// a player picks up a piece of debris but that's
// fine -- CEV
if (item_index >= ITEM_SEQ_BREAKABLE_START &&
item_index <= ITEM_SEQ_BREAKABLE_END)
{
if (random() > 0.333)
// larger
d.frame = 1;
else
// smaller
d.frame = 2;
}
}
if (self.spawnflags & SPAWNFLAG_BASE_BREAKABLE_EXPLODE)
{
self.takedamage = DAMAGE_NO;
t_radiusdamage2 (self, self, self.dmg, world);
write_explosion (self.origin);
spawn_base_explosion (self.origin);
}
base_entity_remove (self);
};
//--------------------------------------------------------------
void(vector dir) base_breakable_destroy =
{
activator = damage_attacker;
sub_usetargets ();
base_breakable_die (dir);
};
//--------------------------------------------------------------
void() base_breakable_use =
{
if (self.targetname == __NULL__ || self.targetname == "")
return;
activator = other;
sub_usetargets ();
base_breakable_die ('0 0 0');
};
//--------------------------------------------------------------
void(string key, string value) base_breakable_init_field =
{
switch (key)
{
case "drop_item":
base_entity_init_drop_item (stof(value));
break;
}
};
//--------------------------------------------------------------
// need to precache destruction sounds here; debris models
// will be precached in items/throwables.qc -- CEV
//--------------------------------------------------------------
void(entity e) base_breakable_init =
{
base_func_init (e);
if (e.noise != __NULL__ && e.noise1 != "")
{
precache_sound (e.noise1);
}
else
{
// adding new default sounds for "simple" breakables
// in 1.2.0 -- dumptruck_ds
switch (e.style)
{
// here's generic metal breaking
case 0: case 11: case 12: case 17:
case 18: case 19: case 24: case 31:
precache_sound ("break/metal2.wav");
e.noise1 = "break/metal2.wav";
break;
// wood sounds -- CEV
case 3: case 4: case 5:
precache_sound ("break/wood1.wav");
precache_sound ("break/wood2.wav");
// wood only randomized
if (random() > 0.6)
e.noise1 = "break/wood1.wav";
else
e.noise1 = "break/wood2.wav";
break;
// glass sounds -- more of a shattering sound
case 6: case 7: case 8: case 9: case 10:
precache_sound ("break/metal1.wav");
e.noise1 = "break/metal1.wav";
break;
// bricks -- CEV
case 1: case 2: case 13: case 14: case 15:
case 16: case 20: case 21: case 22: case 23:
precache_sound ("break/stones1.wav");
precache_sound ("break/bricks1.wav");
if (random() > 0.6)
e.noise1 = "break/bricks1.wav";
else
e.noise1 = "break/stones1.wav";
break;
// stones -- CEV
case 25: case 26: case 27: case 28:
case 29: case 30:
precache_sound ("break/stones1.wav");
precache_sound ("break/bricks1.wav");
if (random() > 0.6)
e.noise1 = "break/stones1.wav";
else
e.noise1 = "break/bricks1.wav";
break;
}
}
};
//--------------------------------------------------------------
strip void() base_breakable =
{
base_breakable_init (self);
};
#endif
// };
/*QUAKED func_breakable (0 .5 .8) ? NO_MONSTERS X X X X X X X NOT_ON_EASY NOT_ON_NORMAL NOT_ON_HARD_OR_NIGHTMARE NOT_IN_DEATHMATCH NOT_IN_COOP NOT_IN_SINGLEPLAYER X NOT_ON_HARD_ONLY NOT_ON_NIGHTMARE_ONLY
"Breakable - See manual for full details
Defaults to built-in .mdl file with 32 styles, cnt is number of pieces of debris to spawn (built-in only)
If noise1 is not set it will default to various sounds in sounds/break folder
Use spawnflag 2 for an explosion, dmg is amount of damage inflicted"
spawnflags(flags)
1 : "No Monster Damage" : 0 : "Only the player can break"
2 : "Explosion" : 0 : "Produces explosion effect and sound"
style(choices) : "Built-in debris style" : 0
0 : "Green Metal (default)"
1 : "Red Metal"
2 : "Concrete"
3 : "Pine wood"
4 : "Brown wood"
5 : "Red wood"
6 : "Stained Glass Yellow Flames"
7 : "Stained Glass Red Rays"
8 : "Stained Glass Yellow Dragon"
9 : "Stained Glass Blue Dragon"
10 : "Stained Glass Red Dragon"
11 : "Light Copper"
12 : "Dark Copper"
13 : "Tan Bricks Large"
14 : "Brown Bricks Large"
15 : "Green Bricks Large"
16 : "Generic Light Brown"
17 : "Red Brown Computer"
18 : "Grey Black Computer"
19 : "Blue Green Metal"
20 : "Blue Green Runic Wall"
21 : "Brown Metal"
22 : "Dark Brown Metal"
23 : "Medium Brown Metal"
24 : "Blue Metal"
25 : "Green Stonework"
26 : "Blue Stonework"
27 : "Brown Bricks"
28 : "Tan Blue Bricks"
29 : "Red Bricks"
30 : "Blue Bricks"
31 : "Metal Rivets"
noise1(string) : "Break noise (overrides default sounds)"
cnt(integer) : "Number of pieces of debris to spawn" : 4
health(integer) : "Health of breakable" : 20
dmg(integer) : "Amount of Explosive Damage" : 20
*/
//----------------------------------------------------------------------
// class func_breakable: base_breakable
// {
#ifdef SSQC
//--------------------------------------------------------------
void(entity e) func_breakable_init =
{
var float iaidx = 0;
e.classname = "func_breakable";
e.classtype = CT_FUNC_BREAKABLE;
base_breakable_init (e);
e.solid = SOLID_BSP;
e.movetype = MOVETYPE_PUSH;
setmodel (e, e.model);
if (!e.health)
e.health = 20;
// restrict cnt to a sane range w/a default -- CEV
if (!e.cnt)
e.cnt = BASE_BREAKABLE_DEFAULTDEBRIS;
else
e.cnt = bound (1, e.cnt, BASE_BREAKABLE_MAXDEBRIS);
// set up debris item index array -- CEV
for (float i = 0; i < e.cnt; i++)
{
iaidx = BASE_ENTITY_ITEMLEN - (i + 1);
// skip if this item index is occupied -- CEV
if (e.item[iaidx])
continue;
// .style maps directly to item_info starting at
// the ITEM_SEQ_BREAKABLE_START offset (that is,
// item_info is in the same order as listed in the
// QUAKEED comments on func_breakable -- CEV
e.item[iaidx] = ITEM_SEQ_BREAKABLE_START + e.style;
}
if (e.targetname != "" && e.targetname != __NULL__)
{
e.use = base_breakable_use;
}
else
{
e.takedamage = DAMAGE_YES;
e.th_destroy = base_breakable_destroy;
}
if (e.switchshadstyle)
lightstyle (e.switchshadstyle, "a");
};
//--------------------------------------------------------------
void() func_breakable =
{
BASE_FUNC_PREINIT (base_breakable_init_field)
func_breakable_init (self);
};
#endif
// };
Return to the top of this page or return to the overview of this repo.
Log breakable.qc
Date | Commit Message | Author | + | - |
---|---|---|---|---|
2025-08-13 | Another big commit. Item changes, field rework, etc. | cev | +160 | -334 |
2025-03-30 | Big commit. Entity networking, etc. | cev | +25 | -12 |
2024-06-15 | Major update, committing as-is, will have bugs | cev | +16 | -2 |
2024-04-12 | Moveable gibs, heads, some bugfixes | cev | +24 | -23 |
2024-03-24 | 2nd pass refactor, rework QC class structure | cev | +214 | -193 |
2024-02-27 | Bullet projectile, pmove changes, misc | cev | +3 | -3 |
2024-02-18 | Client/player, projectiles, entrypoints refactor | cev | +9 | -7 |
2024-01-31 | Class based monster refactor & start projectiles | cev | +8 | -4 |
2024-01-13 | Refactored items into classes, fix teleporttrain | cev | +1 | -1 |
2024-01-09 | Continue OO / Class-based refactor | cev | +374 | -431 |
2023-12-09 | Start OO / class-based refactor, work on items | cev | -3 | |
2023-11-27 | Code reorg, minor movement changes, misc | cev | +581 |
Return to the top of this page or return to the overview of this repo.