Random Monsters

 

I stripped this from my private source and pasted this tutorial together because I couldn't find a copy of the original tute. Also, the way this is currently implemented is that the person who spawns the monster gets awarded the frags the monster gets for you. You can change it around to fit your own mod. And, it currently spawns the monster near your position. It should be pretty easy to change that to make it spawn random monsters at deathmatch spawn points. It will work just fine in either case because the basic stuff is all here. If I left anything out or you have problems, please let me know.

Maj.Bitch


Add this to your g_local.h file

// NEW - (Maj.Bitch) for ent->mtype variable

// TYPE OF MONSTER ---- DEFAULT HEALTH
#define M_NOMONSTER  0   //     0
#define M_SOLDIERLT  1   //    20
#define M_SOLDIER    2   //    30
#define M_SOLDIERSS  3   //    40
#define M_FLIPPER    4   //    50 - Shark
#define M_FLYER      5   //    50 - Flyer
#define M_INFANTRY   6   //   100
#define M_INSANE     7   //   100 - Crazy Marine
#define M_GUNNER     8   //   175
#define M_CHICK      9   //   175
#define M_PARASITE  10   //   175
#define M_FLOATER   11   //   200
#define M_HOVER     12   //   240 - Icarus
#define M_BERSERK   13   //   240
#define M_MEDIC     14   //   300 - unused
#define M_MUTANT    15   //   300
#define M_BRAIN     16   //   300
#define M_GLADIATOR 17   //   400
#define M_TANK      18   //   750
#define M_SUPERTANK 19   //  1500
#define M_BOSS2     20   //  2000
#define M_JORG      21   //  3000
#define M_MAKRON    22   //  3000

===============================================
===============================================
Add this variable to edict_t struct

   int mtype;

===============================================
===============================================

Put this line at the very top of ClientObituary()

  // Was this a monster that did the killing?
  if (Monster_Obits(self, attacker)) return;


===============================================
===============================================

Paste all this stuff at the bottom of g_monster.c


//======================================================
//======== GENERIC MONSTER SPAWNING ROUTINES ===========
//======================================================

//======================================================
// Frag award and Obits for Victims of Monster attacks!
// Attacker=Monster
// Attacker->activator=Monster's Owner
//======================================================
qboolean Monster_Obits(edict_t *victim, edict_t *attacker) {
char *message1="";
char *message2="";

  // No Monster obits in single-player mode.
  if (!deathmatch->value) return false;

  // No message if killed by your own Monster!
  if (victim==attacker->activator) return false;

  message1="was killed by";

  // What type of monster was this?
  switch (attacker->mtype) {
    case M_BERSERK:
      message2="'s Berserker";
      break;
    case M_BOSS2:
      message2="'s Boss";
      break;
    case M_SOLDIERSS:
      message2="'s SoldierSS";
      break;
    case M_JORG:
      message2="'s Jorg";
      break;
    case M_BRAIN:
      message2="'s Brain";
      break;
    case M_CHICK:
      message2="'s Chick";
      break;
    case M_FLIPPER:
      message2="'s Shark";
      break;
    case M_FLOATER:
      message2="'s Floater";
      break;
    case M_FLYER:
      message2="'s Flyer";
      break;
    case M_INSANE:
      message2="'s Insane";
      break;
    case M_GLADIATOR:
      message2="'s Gladiator";
      break;
    case M_HOVER:
      message2="'s Icarus";
      break;
    case M_INFANTRY:
      message2="'s Infantry";
      break;
    case M_SOLDIERLT:
      message2="'s SoldierLT";
      break;
    case M_SOLDIER:
      message2="'s Soldier";
      break;
    case M_MEDIC:
      message2="'s Medic";
      break;
    case M_MUTANT:
      message2="'s Mutant";
      break;
    case M_PARASITE:
      message2="'s Parasite";
      break;
    case M_TANK:
      message2="'s Tank";
      break;
    case M_MAKRON:
      message2="'s Makron";
      break;
    case M_GUNNER:
      message2="'s Gunner";
      break;
    case M_SUPERTANK:
      message2="'s Supertank";
      break;
    default:
      return false; }

  // Print the obituary message..
  if (victim->client && attacker->activator->client) {
    gi.bprintf(PRINT_MEDIUM,"%s %s %s %s!\n",
                                 victim->client->pers.netname,
                                 message1,
                                 attacker->activator->client->pers.netname,
                                 message2);
    // Give Monster's activator/owner this frag!! - CHANGE THIS TO FIT YOUR MOD
    attacker->activator->client->resp.score++; }

  return true;
}

//======================================================
// Timer entity initiates the Monsters monster-Detonation.
//======================================================
void Kill_Monster(edict_t *timer) {

  // Is Monster still alive?
  if (timer->activator!=NULL)
    // Maximally damage this monster (5000 dmg units ought to do it!!)
    T_Damage(timer->activator, timer, timer, zvec, timer->activator->s.origin, NULL, 5000, 1, 0, MOD_SPLASH);

  G_FreeEdict(timer);
}

//=========================================================
// Spawn a Monster of type 'mtype' at 'torigin' and timer
// will monster-destruct monster in number of 'secs'.
//=========================================================
qboolean G_Spawn_Monster(edict_t *ent, vec3_t torigin, int mtype, float secs) {
edict_t *monster;
edict_t *timer;
int temp;

  if (secs<=0) {
    gi.cprintf(ent, PRINT_HIGH,"G_Spawn_Monster called with 0 secs??\n");
    return false; }

  if (mtype!=M_FLIPPER)
    if (gi.pointcontents(torigin) & CONTENTS_SOLID) {
      gi.cprintf(ent,PRINT_HIGH,"Monster materialized in solid matter!\n");
      return false; }

  // Create basic entity stuff...
  monster = G_Spawn();
  gi.linkentity(monster);

  // Force skill to NIGHTMARE MODE - hehe!!
  gi.cvar_forceset("skill", va("%f","3"));

  temp=deathmatch->value;
  deathmatch->value=0;  // Temporarily disable this!

  // Create this monster type
  switch (mtype) {
    case M_BERSERK:   SP_monster_berserk(monster);
                      monster->classname = "XBerserk";break;
    case M_BOSS2:     SP_monster_boss2(monster);
                      monster->classname = "XBoss2";break;
    case M_SOLDIERSS: SP_monster_soldier_ss(monster);
                      monster->classname = "XSoldierSS";break;
    case M_JORG:      SP_monster_jorg(monster);
                      monster->classname = "XJorg";break;
    case M_BRAIN:     SP_monster_brain(monster);
                      monster->classname = "XBrain";break;
    case M_CHICK:     SP_monster_chick(monster);
                      monster->classname = "XChick";break;
    case M_FLIPPER:   SP_monster_flipper(monster);
                      monster->classname = "XShark";break;
    case M_FLOATER:   SP_monster_floater(monster);
                      monster->classname = "XFloater";break;
    case M_FLYER:     SP_monster_flyer(monster);
                      monster->classname = "XFlyer";break;
    case M_INSANE:    SP_misc_insane(monster);
                      monster->classname = "XInsane";break;
    case M_GLADIATOR: SP_monster_gladiator(monster);
                      monster->classname = "XGladiator";break;
    case M_HOVER:     SP_monster_hover(monster);
                      monster->classname = "XIcarus";break;
    case M_INFANTRY:  SP_monster_infantry(monster);
                      monster->classname = "XInfantry";break;
    case M_SOLDIERLT: SP_monster_soldier_light(monster);
                      monster->classname = "XSoldierLT";break;
    case M_SOLDIER:   SP_monster_soldier(monster);
                      monster->classname = "XSoldier";break;
    case M_MEDIC:     SP_monster_medic(monster);
                      monster->classname = "XMedic";break;
    case M_MUTANT:    SP_monster_mutant(monster);
                      monster->classname = "XMutant";break;
    case M_PARASITE:  SP_monster_parasite(monster);
                      monster->classname = "XParasite";break;
    case M_TANK:      SP_monster_tank(monster);
                      monster->classname = "XTank";break;
    case M_MAKRON:    SP_monster_makron(monster);
                      monster->classname = "XMakron";break;
    case M_GUNNER:    SP_monster_gunner(monster);
                      monster->classname = "XGunner";break;
    case M_SUPERTANK: SP_monster_supertank(monster);
                      monster->classname = "XSuperTank"; }

  deathmatch->value=temp;   // Restore to previous value!

  monster->owner=world;   // Creator can be killed too.
  monster->activator=ent; // Link to creator for frags..
  monster->mtype=mtype;   // Type of monster this is (for obits)..
  VectorCopy(torigin, monster->s.origin);

  // Set ai for Brutal Mode and to start pursuit ASAP!!
  monster->monsterinfo.aiflags |= (AI_BRUTAL&AI_PURSUE_NEXT));

  // Play a powerup sound..
  gi.sound(monster, CHAN_VOICE, gi.soundindex("misc/power1.wav"), 1.0, ATTN_IDLE, OFF);

  // - DELETE THE TIMER IF YOU DON'T WANT THEM TO SELF-DESTRUCT AUTOMATICALLY

  // -------------------------------------
  // Timer destroys monster after # secs.
  // -------------------------------------

  timer=G_Spawn();
  timer->owner=ent;
  timer->activator=monster;  // Link to Monster
  timer->takedamage=DAMAGE_NO;
  timer->movetype=MOVETYPE_NONE;
  timer->solid = SOLID_NOT;
  VectorClear(timer->s.origin);
  VectorClear(timer->mins);
  VectorClear(timer->maxs);
  timer->think=Kill_Monster;
  timer->nextthink=level.time + secs;
  gi.linkentity(timer);

  // Link back to Owner
  ent->goalentity=timer;

  return true; // Spawn successful
}

// SET A COMMAND TO ACTIVATE THIS BY SERVER COMMAND
// AND CHANGE THIS AROUND TO FIT YOUR MOD...

//====================================================
// Spawn a monster from command line..
//====================================================
void Cmd_Monsters_f(edict_t *ent, int mtype) {
vec3_t forward, torigin;

  // Not available to dead or respawning players!
  if (!ent || !ent->inuse || !ent->client) return;

  // Already spawned? Then detonate
  if (ent->goalentity) {
    Kill_Monster(ent->goalentity);
    ent->goalentity=NULL;
    gi.centerprintf(ent, "MONSTER DESTROYED!\n");
    return; }

  // See if we can project origin forward 50 units...
  AngleVectors(ent->s.angles, forward, NULL, NULL);
  VectorMA(ent->s.origin, 50, forward, torigin);

  if (G_Spawn_Monster(ent, torigin, mtype, 180))
    gi.centerprintf(ent, "MOVE AWAY NOW!\n");
}