// ai_monsters.qc: basic monster functions /* ALL MONSTERS SHOULD BE 1 0 0 IN COLOR */ // name =[framenum, nexttime, nextthink] {code} // expands to: // name() // { // self.frame=framenum; // self.nextthink = time + nexttime; // self.think = nextthink // // }; float() enemy_is_high = { return !self.enemy || fabs(self.enemy.origin_z - self.origin_z) >= AI_MONSTER_HIGH; }; /* ================ monster_use Using a monster makes it angry at the current activator ================ */ void() monster_use = { if(self.enemy) { return; } if(self.health <= 0) { return; } if(activator.items & IT_INVISIBILITY) { return; } if(activator.flags & FL_NOTARGET) { return; } if(activator.classname != "player") { return; } // delay reaction so if the monster is teleported, its sound is still // heard self.enemy = activator; self.nextthink = time + 0.1; self.think = found_target; }; /* ================ monster_death_use When a mosnter dies, it fires all of its targets with the current enemy as activator. ================ */ void() monster_death_use = { entity ent, otemp, stemp; // fall to ground if(self.flags & FL_FLY) { self.flags = self.flags - FL_FLY; } if(self.flags & FL_SWIM) { self.flags = self.flags - FL_SWIM; } if(!self.target) { return; } activator = self.enemy; sub_use_targets(); }; //============================================================================ void() walkmonster_start_go = { string stemp; entity etemp; self.origin_z = self.origin_z + 1; // raise off floor a bit drop_to_floor(); if(!walk_move(0, 0)) { print_dbg("walkmonster in wall at: ", vtos(self.origin), "\n"); } self.takedamage = DAMAGE_AIM; self.ideal_yaw = self.angles * '0 1 0'; if(!self.yaw_speed) { self.yaw_speed = 20; } self.view_ofs = '0 0 25'; self.use = monster_use; self.flags = self.flags | FL_MONSTER; if(self.target) { self.goalentity = self.movetarget = find(world, targetname, self.target); self.ideal_yaw = vec_yaw(self.goalentity.origin - self.origin); if(!self.movetarget) { print_dbg("Monster can't find target at ", vtos(self.origin), "\n"); } // this used to be an error_obj if(self.movetarget.classname == "path_corner") { self.th_walk(); } else { self.pausetime = 99999999; } self.th_stand(); } else { self.pausetime = 99999999; self.th_stand(); } // spread think times so they don't all happen at same time self.nextthink = time + 0.1 + random() * 0.5; }; void() walkmonster_start = { // delay drop to floor to make sure all doors have been spawned // spread think times so they don't all happen at same time self.nextthink = time + 0.1 + random() * 0.5; self.think = walkmonster_start_go; total_monsters = total_monsters + 1; }; void() flymonster_start_go = { self.takedamage = DAMAGE_AIM; self.ideal_yaw = self.angles * '0 1 0'; if(!self.yaw_speed) { self.yaw_speed = 10; } self.view_ofs = '0 0 25'; self.use = monster_use; self.flags = self.flags | FL_FLY; self.flags = self.flags | FL_MONSTER; if(!walk_move(0, 0)) { print_dbg("flymonster in wall at: ", vtos(self.origin), "\n"); } if(self.target) { self.goalentity = self.movetarget = find(world, targetname, self.target); if(!self.movetarget) { print_dbg("Monster can't find target at ", vtos(self.origin), "\n"); } // this used to be an error_obj if(self.movetarget.classname == "path_corner") { self.th_walk(); } else { self.pausetime = 99999999; } self.th_stand(); } else { self.pausetime = 99999999; self.th_stand(); } self.nextthink = time + 0.1 + random() * 0.5; }; void() flymonster_start = { // spread think times so they don't all happen at same time self.flags |= FL_FLY; self.nextthink = time + 0.1 + random() * 0.5; self.think = flymonster_start_go; total_monsters = total_monsters + 1; }; void() swimmonster_start_go = { if(deathmatch) { remove(self); return; } self.takedamage = DAMAGE_AIM; self.ideal_yaw = self.angles * '0 1 0'; if(!self.yaw_speed) { self.yaw_speed = 10; } self.view_ofs = '0 0 10'; self.use = monster_use; self.flags = self.flags | FL_SWIM; self.flags = self.flags | FL_MONSTER; if(self.target) { self.goalentity = self.movetarget = find(world, targetname, self.target); if(!self.movetarget) { print_dbg("Monster can't find target at ", vtos(self.origin), "\n"); } // this used to be an error_obj self.ideal_yaw = vec_yaw(self.goalentity.origin - self.origin); self.th_walk(); } else { self.pausetime = 99999999; self.th_stand(); } // spread think times so they don't all happen at same time self.nextthink = time + 0.1 + random() * 0.5; }; void() swimmonster_start = { // spread think times so they don't all happen at same time self.flags |= FL_SWIM; self.nextthink = time + 0.1 + random() * 0.5; self.think = swimmonster_start_go; total_monsters = total_monsters + 1; };