X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Fmonsters%2Fsv_monsters.qc;h=80cd21b481b41474dcf860d2d42178c95428f228;hb=6ea97246f03651c514be506bf57cbc0c2351e935;hp=fcab35af5334e5e282dc9013e0e12d0ca28d3586;hpb=75cc3b0a65b02ee61f525e6c6d788ab591868e42;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/monsters/sv_monsters.qc b/qcsrc/common/monsters/sv_monsters.qc index fcab35af53..80cd21b481 100644 --- a/qcsrc/common/monsters/sv_monsters.qc +++ b/qcsrc/common/monsters/sv_monsters.qc @@ -25,8 +25,8 @@ void monsters_setstatus(entity this) { - this.stat_monsters_total = monsters_total; - this.stat_monsters_killed = monsters_killed; + STAT(MONSTERS_TOTAL, this) = monsters_total; + STAT(MONSTERS_KILLED, this) = monsters_killed; } void monster_dropitem(entity this, entity attacker) @@ -46,7 +46,7 @@ void monster_dropitem(entity this, entity attacker) if(e && e.monster_loot) { e.noalign = true; - e.monster_loot(e); + StartItem(e, e.monster_loot); e.gravity = 1; set_movetype(e, MOVETYPE_TOSS); e.reset = SUB_Remove; @@ -99,9 +99,10 @@ bool Monster_ValidTarget(entity this, entity targ) return false; } - traceline(this.origin + this.view_ofs, targ.origin, MOVE_NOMONSTERS, this); + vector targ_origin = ((targ.absmin + targ.absmax) * 0.5); + traceline(this.origin + this.view_ofs, targ_origin, MOVE_NOMONSTERS, this); - if(trace_fraction < 1) + if(trace_fraction < 1 && trace_ent != targ) return false; // solid if(autocvar_g_monsters_target_infront || (this.spawnflags & MONSTERFLAG_INFRONT)) @@ -124,7 +125,7 @@ entity Monster_FindTarget(entity this) vector my_center = CENTER_OR_VIEWOFS(this); // find the closest acceptable target to pass to - FOREACH_ENTITY_RADIUS(this.origin, this.target_range, it.monster_attack, + IL_EACH(g_monster_targets, it.monster_attack && vdist(it.origin - this.origin, <, this.target_range), { if(Monster_ValidTarget(this, it)) { @@ -172,6 +173,8 @@ void monster_changeteam(entity this, int newteam) if(!teamplay) { return; } this.team = newteam; + if(!this.monster_attack) + IL_PUSH(g_monster_targets, this); this.monster_attack = true; // new team, activate attacking monster_setupcolors(this); @@ -244,7 +247,7 @@ void Monster_Sound_Precache(string f) { if(tokenize_console(s) != 3) { - LOG_TRACE("Invalid sound info line: ", s); + //LOG_DEBUG("Invalid sound info line: ", s); // probably a comment, no need to spam warnings continue; } PrecacheGlobalSound(strcat(argv(1), " ", argv(2))); @@ -298,7 +301,7 @@ bool Monster_Sounds_Load(entity this, string f, int first) float fh = fopen(f, FILE_READ); if(fh < 0) { - LOG_TRACE("Monster sound file not found: ", f); + //LOG_DEBUG("Monster sound file not found: ", f); // no biggie, monster has no sounds, let's not spam it return false; } while((s = fgets(fh))) @@ -564,7 +567,7 @@ vector Monster_Move_Target(entity this, entity targ) || ((trace_fraction < 1) && (trace_ent != this.enemy))) { this.enemy = NULL; - this.pass_distance = 0; + //this.pass_distance = 0; } if(this.enemy) @@ -655,12 +658,13 @@ vector Monster_Move_Target(entity this, entity targ) void Monster_CalculateVelocity(entity this, vector to, vector from, float turnrate, float movespeed) { - float current_distance = vlen((('1 0 0' * to.x) + ('0 1 0' * to.y)) - (('1 0 0' * from.x) + ('0 1 0' * from.y))); // for the sake of this check, exclude Z axis - float initial_height = 0; //min(50, (targ_distance * tanh(20))); - float current_height = (initial_height * min(1, (this.pass_distance) ? (current_distance / this.pass_distance) : current_distance)); + //float current_distance = vlen((('1 0 0' * to.x) + ('0 1 0' * to.y)) - (('1 0 0' * from.x) + ('0 1 0' * from.y))); // for the sake of this check, exclude Z axis + //float initial_height = 0; //min(50, (targ_distance * tanh(20))); + //float current_height = (initial_height * min(1, (this.pass_distance) ? (current_distance / this.pass_distance) : current_distance)); //print("current_height = ", ftos(current_height), ", initial_height = ", ftos(initial_height), ".\n"); - vector targpos; + vector targpos = to; +#if 0 if(current_height) // make sure we can actually do this arcing path { targpos = (to + ('0 0 1' * current_height)); @@ -676,6 +680,7 @@ void Monster_CalculateVelocity(entity this, vector to, vector from, float turnra } } else { targpos = to; } +#endif //this.angles = normalize(('0 1 0' * to_y) - ('0 1 0' * from_y)); @@ -693,54 +698,14 @@ void Monster_CalculateVelocity(entity this, vector to, vector from, float turnra void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed) { // update goal entity if lost - if(this.target2 && this.goalentity.targetname != this.target2) { this.goalentity = find(NULL, targetname, this.target2); } + if(this.target2 && this.target2 != "" && this.goalentity.targetname != this.target2) + this.goalentity = find(NULL, targetname, this.target2); - if(STAT(FROZEN, this) == 2) + if(STAT(FROZEN, this)) { - this.revive_progress = bound(0, this.revive_progress + this.ticrate * this.revive_speed, 1); - this.health = max(1, this.revive_progress * this.max_health); - this.iceblock.alpha = bound(0.2, 1 - this.revive_progress, 1); - - if(!(this.spawnflags & MONSTERFLAG_INVINCIBLE) && this.sprite) - WaypointSprite_UpdateHealth(this.sprite, this.health); - movelib_brake_simple(this, stpspeed); setanim(this, this.anim_idle, true, false, false); - - this.enemy = NULL; - this.nextthink = time + this.ticrate; - - if(this.revive_progress >= 1) - Unfreeze(this); - - return; - } - else if(STAT(FROZEN, this) == 3) - { - this.revive_progress = bound(0, this.revive_progress - this.ticrate * this.revive_speed, 1); - this.health = max(0, autocvar_g_nades_ice_health + (this.max_health-autocvar_g_nades_ice_health) * this.revive_progress ); - - if(!(this.spawnflags & MONSTERFLAG_INVINCIBLE) && this.sprite) - WaypointSprite_UpdateHealth(this.sprite, this.health); - - movelib_brake_simple(this, stpspeed); - setanim(this, this.anim_idle, true, false, false); - - this.enemy = NULL; - this.nextthink = time + this.ticrate; - - if(this.health < 1) - { - Unfreeze(this); - this.health = 0; - if(this.event_damage) - this.event_damage(this, this, this.frozen_by, 1, DEATH_NADE_ICE_FREEZE.m_id, this.origin, '0 0 0'); - } - - else if ( this.revive_progress <= 0 ) - Unfreeze(this); - - return; + return; // no physics while frozen! } if(this.flags & FL_SWIM) @@ -804,27 +769,6 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed) if(DIFF_TEAM(this.monster_follow, this)) this.monster_follow = NULL; - if(time >= this.last_enemycheck) - { - if(!this.enemy) - { - this.enemy = Monster_FindTarget(this); - if(this.enemy) - { - WarpZone_RefSys_Copy(this.enemy, this); - WarpZone_RefSys_AddInverse(this.enemy, this); // wz1^-1 ... wzn^-1 receiver - this.moveto = WarpZone_RefSys_TransformOrigin(this.enemy, this, (0.5 * (this.enemy.absmin + this.enemy.absmax))); - this.monster_moveto = '0 0 0'; - this.monster_face = '0 0 0'; - - this.pass_distance = vlen((('1 0 0' * this.enemy.origin_x) + ('0 1 0' * this.enemy.origin_y)) - (('1 0 0' * this.origin_x) + ('0 1 0' * this.origin_y))); - Monster_Sound(this, monstersound_sight, 0, false, CH_VOICE); - } - } - - this.last_enemycheck = time + 1; // check for enemies every second - } - if(this.state == MONSTER_ATTACK_RANGED && IS_ONGROUND(this)) { this.state = 0; @@ -866,9 +810,9 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed) else { entity e = this.goalentity; //find(NULL, targetname, this.target2); - if(e.target2) + if(e.target2 && e.target2 != "") this.target2 = e.target2; - else if(e.target) // compatibility + else if(e.target && e.target != "") // compatibility this.target2 = e.target; movelib_brake_simple(this, stpspeed); @@ -889,9 +833,6 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed) turny = bound(turny * -1, shortangle_f(real_angle.y, this.angles.y), turny); this.angles_y += turny; } - - .entity weaponentity = weaponentities[0]; // TODO? - Monster_Attack_Check(this, this.enemy, weaponentity); } void Monster_Remove(entity this) @@ -1002,7 +943,7 @@ void Monster_Dead(entity this, entity attacker, float gibbed) if(IS_PLAYER(attacker)) if(autocvar_g_monsters_score_spawned || !((this.spawnflags & MONSTERFLAG_SPAWNED) || (this.spawnflags & MONSTERFLAG_RESPAWNED))) - PlayerScore_Add(attacker, SP_SCORE, +autocvar_g_monsters_score_kill); + GameRules_scoring_add(attacker, SCORE, +autocvar_g_monsters_score_kill); if(gibbed) { @@ -1010,6 +951,9 @@ void Monster_Dead(entity this, entity attacker, float gibbed) totalspawned -= 1; } + if(!gibbed && this.mdl_dead && this.mdl_dead != "") + _setmodel(this, this.mdl_dead); + this.event_damage = ((gibbed) ? func_null : Monster_Dead_Damage); this.solid = SOLID_CORPSE; this.takedamage = DAMAGE_AIM; @@ -1073,8 +1017,8 @@ void Monster_Damage(entity this, entity inflictor, entity attacker, float damage this.dmg_time = time; - if(sound_allowed(MSG_BROADCAST, attacker) && deathtype != DEATH_DROWN.m_id && deathtype != DEATH_FIRE.m_id) - spamsound (this, CH_PAIN, SND(BODYIMPACT1), VOL_BASE, ATTEN_NORM); // FIXME: PLACEHOLDER + if(deathtype != DEATH_DROWN.m_id && deathtype != DEATH_FIRE.m_id && sound_allowed(MSG_BROADCAST, attacker)) + spamsound (this, CH_PAIN, SND_BODYIMPACT1, VOL_BASE, ATTEN_NORM); // FIXME: PLACEHOLDER this.velocity += force * this.damageforcescale; @@ -1200,6 +1144,64 @@ void Monster_Anim(entity this) */ } +void Monster_Frozen_Think(entity this) +{ + if(STAT(FROZEN, this) == 2) + { + this.revive_progress = bound(0, this.revive_progress + this.ticrate * this.revive_speed, 1); + this.health = max(1, this.revive_progress * this.max_health); + this.iceblock.alpha = bound(0.2, 1 - this.revive_progress, 1); + + if(!(this.spawnflags & MONSTERFLAG_INVINCIBLE) && this.sprite) + WaypointSprite_UpdateHealth(this.sprite, this.health); + + if(this.revive_progress >= 1) + Unfreeze(this); + } + else if(STAT(FROZEN, this) == 3) + { + this.revive_progress = bound(0, this.revive_progress - this.ticrate * this.revive_speed, 1); + this.health = max(0, autocvar_g_nades_ice_health + (this.max_health-autocvar_g_nades_ice_health) * this.revive_progress ); + + if(!(this.spawnflags & MONSTERFLAG_INVINCIBLE) && this.sprite) + WaypointSprite_UpdateHealth(this.sprite, this.health); + + if(this.health < 1) + { + Unfreeze(this); + this.health = 0; + if(this.event_damage) + this.event_damage(this, this, this.frozen_by, 1, DEATH_NADE_ICE_FREEZE.m_id, this.origin, '0 0 0'); + } + + else if ( this.revive_progress <= 0 ) + Unfreeze(this); + } + // otherwise, no revival! + + this.enemy = NULL; // TODO: save enemy, and attack when revived? +} + +void Monster_Enemy_Check(entity this) +{ + if(!this.enemy) + { + this.enemy = Monster_FindTarget(this); + if(this.enemy) + { + WarpZone_RefSys_Copy(this.enemy, this); + WarpZone_RefSys_AddInverse(this.enemy, this); // wz1^-1 ... wzn^-1 receiver + // update move target immediately? + this.moveto = WarpZone_RefSys_TransformOrigin(this.enemy, this, (0.5 * (this.enemy.absmin + this.enemy.absmax))); + this.monster_moveto = '0 0 0'; + this.monster_face = '0 0 0'; + + //this.pass_distance = vlen((('1 0 0' * this.enemy.origin_x) + ('0 1 0' * this.enemy.origin_y)) - (('1 0 0' * this.origin_x) + ('0 1 0' * this.origin_y))); + Monster_Sound(this, monstersound_sight, 0, false, CH_VOICE); + } + } +} + void Monster_Think(entity this) { setthink(this, Monster_Think); @@ -1211,10 +1213,23 @@ void Monster_Think(entity this) return; } + if(STAT(FROZEN, this)) + Monster_Frozen_Think(this); + else if(time >= this.last_enemycheck) + { + Monster_Enemy_Check(this); + this.last_enemycheck = time + 1; // check for enemies every second + } + Monster mon = Monsters_from(this.monsterid); if(mon.mr_think(mon, this)) + { Monster_Move(this, this.speed2, this.speed, this.stopspeed); + .entity weaponentity = weaponentities[0]; // TODO? + Monster_Attack_Check(this, this.enemy, weaponentity); + } + Monster_Anim(this); CSQCMODEL_AUTOUPDATE(this); @@ -1256,7 +1271,11 @@ bool Monster_Spawn_Setup(entity this) Monster_Sounds_Update(this); if(teamplay) + { + if(!this.monster_attack) + IL_PUSH(g_monster_targets, this); this.monster_attack = true; // we can have monster enemies in team games + } Monster_Sound(this, monstersound_spawn, 0, false, CH_VOICE); @@ -1290,7 +1309,13 @@ bool Monster_Spawn(entity this, bool check_appear, int mon_id) if(!autocvar_g_monsters) { Monster_Remove(this); return false; } if(!(this.spawnflags & MONSTERFLAG_RESPAWNED)) + { IL_PUSH(g_monsters, this); + if(this.mdl && this.mdl != "") + precache_model(this.mdl); + if(this.mdl_dead && this.mdl_dead != "") + precache_model(this.mdl_dead); + } if(check_appear && Monster_Appear_Check(this, mon_id)) { return true; } // return true so the monster isn't removed @@ -1309,7 +1334,11 @@ bool Monster_Spawn(entity this, bool check_appear, int mon_id) if(!(this.spawnflags & MONSTERFLAG_RESPAWNED)) // don't count re-spawning monsters either monsters_total += 1; - setmodel(this, mon.m_model); + if(this.mdl && this.mdl != "") + _setmodel(this, this.mdl); + else + setmodel(this, mon.m_model); + this.flags = FL_MONSTER; this.classname = "monster"; this.takedamage = DAMAGE_AIM; @@ -1340,7 +1369,7 @@ bool Monster_Spawn(entity this, bool check_appear, int mon_id) this.candrop = true; this.view_ofs = '0 0 0.7' * (this.maxs_z * 0.5); this.oldtarget2 = this.target2; - this.pass_distance = 0; + //this.pass_distance = 0; this.deadflag = DEAD_NO; this.spawn_time = time; this.gravity = 1; @@ -1374,7 +1403,7 @@ bool Monster_Spawn(entity this, bool check_appear, int mon_id) this.scale *= 1.3; } - setsize(this, mon.mins * this.scale, mon.maxs * this.scale); + setsize(this, mon.m_mins * this.scale, mon.m_maxs * this.scale); this.ticrate = bound(sys_frametime, ((!this.ticrate) ? autocvar_g_monsters_think_delay : this.ticrate), 60);