X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Fmonsters%2Fsv_monsters.qc;h=b4861b917dd39e068cb816fc3253f89f9b7acf4a;hb=0076d3f631e54b908b7506883c75c6d28f6b9505;hp=469dd7b9cd7d3ec41d609dc48def8cacb2825928;hpb=decae9170e9c82c24a2f9a4fa524c866c8e3d36e;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/monsters/sv_monsters.qc b/qcsrc/common/monsters/sv_monsters.qc index 469dd7b9c..b4861b917 100644 --- a/qcsrc/common/monsters/sv_monsters.qc +++ b/qcsrc/common/monsters/sv_monsters.qc @@ -1,6 +1,5 @@ #include "sv_monsters.qh" -#include #include #include "../constants.qh" #include "../teams.qh" @@ -18,7 +17,7 @@ #include "../vehicles/all.qh" #include #include -#include "../triggers/triggers.qh" +#include "../mapobjects/triggers.qh" #include #include #include @@ -35,7 +34,8 @@ void monster_dropitem(entity this, entity attacker) return; vector org = CENTER_OR_VIEWOFS(this); - entity e = new(droppedweapon); // use weapon handling to remove it on touch + entity e = spawn(); + Item_SetLoot(e, true); e.spawnfunc_checked = true; e.monster_loot = this.monster_loot; @@ -48,8 +48,6 @@ void monster_dropitem(entity this, entity attacker) e.noalign = true; StartItem(e, e.monster_loot); e.gravity = 1; - set_movetype(e, MOVETYPE_TOSS); - e.reset = SUB_Remove; setorigin(e, org); e.velocity = randomvec() * 175 + '0 0 325'; e.item_spawnshieldtime = time + 0.7; @@ -83,6 +81,7 @@ bool Monster_ValidTarget(entity this, entity targ) || (IS_VEHICLE(targ) && !((Monsters_from(this.monsterid)).spawnflags & MON_FLAG_RANGED)) // melee vs vehicle is useless || (time < game_starttime) // monsters do nothing before match has started || (targ.takedamage == DAMAGE_NO) + || (game_stopped) || (targ.items & IT_INVISIBILITY) || (IS_SPEC(targ) || IS_OBSERVER(targ)) // don't attack spectators || (!IS_VEHICLE(targ) && (IS_DEAD(targ) || IS_DEAD(this) || targ.health <= 0 || this.health <= 0)) @@ -125,7 +124,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)) { @@ -173,6 +172,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); @@ -245,7 +246,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))); @@ -274,7 +275,7 @@ void Monster_Sounds_Precache(entity this) void Monster_Sounds_Clear(entity this) { -#define _MSOUND(m) if(this.monstersound_##m) { strunzone(this.monstersound_##m); this.monstersound_##m = string_null; } +#define _MSOUND(m) strfree(this.monstersound_##m); ALLMONSTERSOUNDS #undef _MSOUND } @@ -299,7 +300,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))) @@ -309,9 +310,7 @@ bool Monster_Sounds_Load(entity this, string f, int first) field = Monster_Sound_SampleField(argv(0)); if(GetMonsterSoundSampleField_notFound) continue; - if (this.(field)) - strunzone(this.(field)); - this.(field) = strzone(strcat(argv(1), " ", argv(2))); + strcpy(this.(field), strcat(argv(1), " ", argv(2))); } fclose(fh); return true; @@ -335,7 +334,11 @@ void Monster_Sound(entity this, .string samplefield, float sound_delay, bool del if(delaytoo) if(time < this.msound_delay) return; // too early - GlobalSound_string(this, this.(samplefield), chan, VOL_BASE, VOICETYPE_PLAYERSOUND); + string sample = this.(samplefield); + if (sample != "") sample = GlobalSound_sample(sample, random()); + float myscale = ((this.scale) ? this.scale : 1); // safety net + // TODO: change volume depending on size too? + sound7(this, chan, sample, VOL_BASE, ATTEN_NORM, 100 / myscale, 0); this.msound_delay = time + sound_delay; } @@ -361,7 +364,7 @@ bool Monster_Attack_Melee(entity this, entity targ, float damg, vector anim, flo traceline(this.origin + this.view_ofs, this.origin + v_forward * er, 0, this); if(trace_ent.takedamage) - Damage(trace_ent, this, this, damg * MONSTER_SKILLMOD(this), deathtype, trace_ent.origin, normalize(trace_ent.origin - this.origin)); + Damage(trace_ent, this, this, damg * MONSTER_SKILLMOD(this), deathtype, DMG_NOWEP, trace_ent.origin, normalize(trace_ent.origin - this.origin)); return true; } @@ -565,7 +568,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) @@ -656,12 +659,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)); @@ -677,6 +681,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)); @@ -697,52 +702,11 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed) 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) @@ -753,7 +717,7 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed) { this.last_trace = time + 0.4; - Damage (this, NULL, NULL, 2, DEATH_DROWN.m_id, this.origin, '0 0 0'); + Damage (this, NULL, NULL, 2, DEATH_DROWN.m_id, DMG_NOWEP, this.origin, '0 0 0'); this.angles = '90 90 0'; if(random() < 0.5) { @@ -806,27 +770,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; @@ -891,9 +834,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) @@ -964,7 +904,7 @@ void Monster_Reset(entity this) this.moveto = this.origin; } -void Monster_Dead_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) +void Monster_Dead_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force) { this.health -= damage; @@ -1004,7 +944,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) { @@ -1043,7 +983,7 @@ void Monster_Dead(entity this, entity attacker, float gibbed) } } -void Monster_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) +void Monster_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force) { if((this.spawnflags & MONSTERFLAG_INVINCIBLE) && deathtype != DEATH_KILL.m_id && !ITEM_DAMAGE_NEEDKILL(deathtype)) return; @@ -1205,6 +1145,64 @@ void Monster_Anim(entity this) */ } +void Monster_Frozen_Think(entity this) +{ + if(STAT(FROZEN, this) == 2) + { + STAT(REVIVE_PROGRESS, this) = bound(0, STAT(REVIVE_PROGRESS, this) + this.ticrate * this.revive_speed, 1); + this.health = max(1, STAT(REVIVE_PROGRESS, this) * this.max_health); + this.iceblock.alpha = bound(0.2, 1 - STAT(REVIVE_PROGRESS, this), 1); + + if(!(this.spawnflags & MONSTERFLAG_INVINCIBLE) && this.sprite) + WaypointSprite_UpdateHealth(this.sprite, this.health); + + if(STAT(REVIVE_PROGRESS, this) >= 1) + Unfreeze(this); + } + else if(STAT(FROZEN, this) == 3) + { + STAT(REVIVE_PROGRESS, this) = bound(0, STAT(REVIVE_PROGRESS, this) - this.ticrate * this.revive_speed, 1); + this.health = max(0, autocvar_g_nades_ice_health + (this.max_health-autocvar_g_nades_ice_health) * STAT(REVIVE_PROGRESS, this) ); + + 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, DMG_NOWEP, this.origin, '0 0 0'); + } + + else if ( STAT(REVIVE_PROGRESS, this) <= 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); @@ -1212,14 +1210,27 @@ void Monster_Think(entity this) if(this.monster_lifetime && time >= this.monster_lifetime) { - Damage(this, this, this, this.health + this.max_health, DEATH_KILL.m_id, this.origin, this.origin); + Damage(this, this, this, this.health + this.max_health, DEATH_KILL.m_id, DMG_NOWEP, this.origin, this.origin); 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); @@ -1261,7 +1272,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); @@ -1355,7 +1370,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;