/* =========================================================================== Copyright (C) 2015 the OpenMoHAA team This file is part of OpenMoHAA source code. OpenMoHAA source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. OpenMoHAA source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenMoHAA source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ // gibs.cpp: Gibs - nuff said #include "gibs.h" #include "decals.h" #include "level.h" #include "g_phys.h" Event EV_ThrowGib ( "throwgib", EV_DEFAULT, "eif", "ent velocity scale", "Throw a gib.", EV_NORMAL ); CLASS_DECLARATION(Mover, Gib, "gib") { {&EV_ThrowGib, &Gib::Throw }, {&EV_Touch, &Gib::Splat }, {&EV_Stop, &Gib::Stop }, {&EV_Damage, &Gib::Damage}, {NULL, NULL } }; Gib::Gib( str name, qboolean blood_trail, str bloodtrailname, str bloodspurtname, str bloodsplatname, float bloodsplatsize, float pitch ) { setSize(Vector("0 0 0"), Vector("0 0 0")); if (name.length()) { setModel(name.c_str()); } setMoveType(MOVETYPE_GIB); setSolidType(SOLID_BBOX); takedamage = DAMAGE_YES; sprayed = false; fadesplat = true; scale = 2.0f; next_bleed_time = 0; final_pitch = pitch; if (blood_trail) { // Make a blood emitter and bind it to the head blood = new Mover; if (bloodtrailname.length()) { blood->setModel(bloodtrailname.c_str()); } blood->setMoveType(MOVETYPE_BOUNCE); blood->setSolidType(SOLID_NOT); blood->bind(this); // Save the blood spurt name if (bloodspurtname.length()) { blood_spurt_name = bloodspurtname; } // Save the blood splat name if (bloodsplatname.length()) { blood_splat_name = bloodsplatname; } blood_splat_size = bloodsplatsize; } else { blood = NULL; } Sound("snd_decap", CHAN_BODY, 1, 300); } Gib::~Gib() { if (blood) { blood->PostEvent(EV_Remove, 0); } blood = NULL; } Gib::Gib() { if (LoadingSavegame) { return; } setSize(Vector("0 0 0"), Vector("0 0 0")); setModel("gib1.def"); setMoveType(MOVETYPE_GIB); setSolidType(SOLID_BBOX); sprayed = 0; fadesplat = true; scale = 2.0f; } void Gib::Stop(Event *ev) { //setSolidType( SOLID_NOT ); if (blood) { blood->PostEvent(EV_Remove, 0); } blood = NULL; } void Gib::Splat(Event *ev) { if (g_gametype->integer != GT_SINGLE_PLAYER) { return; } if (sprayed > 3) { //setSolidType(SOLID_NOT); return; } sprayed++; scale -= 0.2f; // Stop spinning / force to final pitch avelocity = vec_zero; if (final_pitch != NO_FINAL_PITCH) { angles[PITCH] = final_pitch; setAngles(angles); } SprayBlood(origin); Sound("snd_gibhit"); } void Gib::Damage(Event *ev) { Vector direction; Entity *blood; Vector dir; if (next_bleed_time > level.time) { return; } direction = ev->GetVector(5); // Spawn a blood spurt if (blood_spurt_name.length() > 0) { blood = new Animate; blood->setModel(blood_spurt_name.c_str()); dir[0] = -direction[0]; dir[1] = -direction[1]; dir[2] = -direction[2]; blood->angles = dir.toAngles(); blood->setAngles(blood->angles); blood->setOrigin(centroid); blood->origin.copyTo(blood->edict->s.origin2); blood->setSolidType(SOLID_NOT); blood->PostEvent(EV_Remove, 1); next_bleed_time = level.time + 0.5; } } void Gib::SprayBlood(Vector start) { Vector norm; trace_t trace; Vector trace_end; trace_end = velocity; trace_end.normalize(); trace_end *= 1000; trace_end += start; trace = G_Trace(start, vec_zero, vec_zero, trace_end, this, MASK_SOLID, false, "Gib::SprayBlood"); if (HitSky(&level.impact_trace) || (!level.impact_trace.ent) || (level.impact_trace.ent->solid != SOLID_BSP)) { return; } // Do a bloodsplat if (blood_splat_name.length()) { Decal *decal = new Decal; decal->setShader(blood_splat_name); decal->setOrigin(Vector(trace.endpos) + (Vector(level.impact_trace.plane.normal) * 0.2f)); decal->setDirection(level.impact_trace.plane.normal); decal->setOrientation("random"); decal->setRadius(blood_splat_size + G_Random(blood_splat_size)); } } void Gib::ClipGibVelocity(void) { if (velocity[0] < -400) { velocity[0] = -400; } else if (velocity[0] > 400) { velocity[0] = 400; } if (velocity[1] < -400) { velocity[1] = -400; } else if (velocity[1] > 400) { velocity[1] = 400; } if (velocity[2] < 200) { velocity[2] = 200; // always some upwards } else if (velocity[2] > 600) { velocity[2] = 600; } } void Gib::SetVelocity(float damage) { velocity[0] = 100.0 * crandom(); velocity[1] = 100.0 * crandom(); velocity[2] = 200.0 + 100.0 * random(); avelocity = Vector(G_Random(600), G_Random(600), G_Random(600)); if ((damage < -150) && (G_Random() > 0.95f)) { velocity *= 2.0f; } else if (damage < -100) { velocity *= 1.5f; } ClipGibVelocity(); } void Gib::Throw(Event *ev) { Entity *ent; ent = ev->GetEntity(1); setOrigin(ent->centroid); origin.copyTo(edict->s.origin2); SetVelocity(ev->GetInteger(2)); edict->s.scale = ev->GetFloat(3); PostEvent(EV_FadeOut, 10 + G_Random(5)); } void CreateGibs(Entity *ent, float damage, float scale, int num, const char *modelname) {}