Announcement

Collapse
No announcement yet.

On the Topic of the Spikes...

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • On the Topic of the Spikes...

    So, about a day ago, I made a post mentioning that I am not posting my mod until I have fixed a problem with my modified spikes.

    For explanations sake, here is how it is currently working in English:

    The spikes, when shot, are now a movetype toss, and is a trigger solid (so the player can get damaged by it). Once it touches a solid object (the spikes delete on touch by player), it sticks there, and becomes a movetype none. The think is sub remove, and it thinks after 60 seconds on spawn.

    My problem is that the nails can't stick and move with moving map objects, like secret doors and the like. Right now, they just kinda float in mid air. My first attempt did not work at all, and caused the Spikes to do a weird boomerang effect.

    Here are the constraints for the think function I need:
    1. Needs to still delete after 60 seconds.
    2. Needs to still interact with players.
    3. Needs to follow moving map objects when stuck to them.

    That is essentially what I need to get this working. My only fear is that it will still cause massive lag if enough nails are following an object, even with DP7 protocol. We can always try and see though.

    Here is all relating nail code. I would like to note that the nails were the first thing I did, and it's a lot messier than it needed to be. Being naive is fun!

    Code:
    void(vector org, vector dir) launch_spike =
    {
    	newmis = spawn ();
    	newmis.owner = self;
    	newmis.solid = SOLID_TRIGGER;
    
    	newmis.angles = vectoangles(dir);
    	newmis.weaponmodel = self.weaponmodel;
    	newmis.touch = spike_touch;
    	newmis.classname = "spike";
    	newmis.think = SUB_Remove;
    	if (!deathmatch)
    	{
    		newmis.movetype = MOVETYPE_FLYMISSILE;
    		newmis.nextthink = time + 6;
    	}
    	else
    	{
    		newmis.movetype = MOVETYPE_TOSS;
    		newmis.nextthink = time + 60;
    	}
    	setmodel (newmis, "progs/spike.mdl");
    	setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);		
    	setorigin (newmis, org);
    
    	newmis.velocity = dir * 1000;
    };
    
    void() spike_touch =
    {
    if (!deathmatch)
    {
    local float rand;
    	if (other == self.owner)
    		return;
    
    	if (other.solid == SOLID_TRIGGER)
    		return;	// trigger field, do nothing
    
    	if (pointcontents(self.origin) == CONTENT_SKY)
    	{
    		remove(self);
    		return;
    	}
    	
    // hit something that bleeds
    	if (other.takedamage)
    	{
    		spawn_touchblood (9);
    		T_Damage (other, self, self.owner, 9);
    	}
    	else
    	{
    		WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
    		
    		if (self.classname == "wizspike")
    			WriteByte (MSG_BROADCAST, TE_WIZSPIKE);
    		else if (self.classname == "knightspike")
    			WriteByte (MSG_BROADCAST, TE_KNIGHTSPIKE);
    		else
    			WriteByte (MSG_BROADCAST, TE_SPIKE);
    		WriteCoord (MSG_BROADCAST, self.origin_x);
    		WriteCoord (MSG_BROADCAST, self.origin_y);
    		WriteCoord (MSG_BROADCAST, self.origin_z);
    	}
    
    	remove(self);
    
    }
    else
    {
    local float rand;
    	if (other == self.owner && self.velocity)
    		return;
    
    	if (other.solid == SOLID_TRIGGER)
    		return;	// trigger field, do nothing
    
    	if (pointcontents(self.origin) == CONTENT_SKY)
    	{
    		remove(self);
    		return;
    	}
    	if (other.classname == self.classname) {
    		remove(self);
    		return;
    	}
    	
    // hit something that bleeds
    	if (other.takedamage)
    	{
    		spawn_touchblood (9);
    		T_Damage (other, self, self.owner, 9);
    		remove(self);
    	}
    	else
    	{
    		self.classname = "stuck_spike";
    		self.movetype = MOVETYPE_NONE;
    		//setsize (self, VEC_ORIGIN, ' 0 0 4');
    		self.velocity = '0 0 0';
    		self.angles = vectoangles(trace_plane_normal);
    		self.angles_x = self.angles_x+(crandom()*30);
    		self.angles_y = self.angles_y+(crandom()*30);
    		self.angles_z = self.angles_z+(crandom()*30);
    
    		WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
    		
    		if (self.classname == "wizspike")
    			WriteByte (MSG_BROADCAST, TE_WIZSPIKE);
    		else if (self.classname == "knightspike")
    			WriteByte (MSG_BROADCAST, TE_KNIGHTSPIKE);
    		else
    			WriteByte (MSG_BROADCAST, TE_SPIKE);
    		WriteCoord (MSG_BROADCAST, self.origin_x);
    		WriteCoord (MSG_BROADCAST, self.origin_y);
    		WriteCoord (MSG_BROADCAST, self.origin_z);
    		
    		
    	}
    
    }
    };
    If anyone has a solution to my problem, I will be in your debt, and thanks in advance!

    Note: if this was easier than I thought, I'm going to jump off a cliff.

  • #2
    please don't shoot me!

    if you want an entity to follow another entity, the easiest way is to just use movetype_follow. obviously this requires that the engine supports this.
    failing that, you can just do something like:
    Code:
    void()spike_touch=
    {
    if (other.takedamage)
    {
    T_Damage(...);
    }
    if (other.solid != SOLID_BSP || pointcontents(self.origin) == CONTENT_SKY)
    remove(self);
    else
    {
    self.enemy = other;
    self.solid = SOLID_NOT;
    self.movetype = MOVETYPE_NONE;
    self.dietime = time + 60;
    if (other)
    {
    self.nextthink = time;
    self.think = (void()){if(self.origin != self.enemy.origin+offset)setorigin(self, self.enemy.origin+offset); if (time > self.dietime)remove(self);self.nextthink = time;};
    }
    else
    {
    self.think = SUB_Remove;
    self.nextthink = self.dietime;
    }
    }
    };
    obviously that assumes nothing will rotate. it is possible to deal with that with a few dotproducts and stuff, but its muuuch easier to just use movetype_follow, which I didn't document here so maybe not. go read some extension specs.
    Some Game Thing

    Comment


    • #3
      I do want this fully compatible, so I want to take the hard route. Nice solution though!

      Comment


      • #4
        this is the code that you need to use if you wish to attach an mdl entity to either an mdl or a solid_bsp entity, and have it actually rotate relative to the entity that it is attached to.
        call calc_attachment to figure out the relative position.
        call do_attachment periodically to keep the attached entity tracking its attachee.

        note that vectoangles2 is an extension, one which will safely degrade in vanilla, but in doing so, the roll angle of the nail will be discarded. This is not an issue at all if the entity that its attached to yaws (eg: doors or monsters), but will be a problem if the attachee changes its pitch or roll (like players or weird trapdoors and other special rotations, although players are limited in their pitch/roll, so it shouldn't be too obvious).
        while I've not actually tested this stuff for typos, it should work otherwise work perfectly with vanilla other than for the aforementioned roll issue. note that you will need fteqcc to compile thanks to me using lazy syntax, feel free to pad it out to avoid fteqcc if you so desire.

        note that mdl models have an inverted pitch - a bug in vanilla quake. makevectors uses player/bsp pitch, while vectoangles uses inverted/mdl pitch. this is what the angles_x*-1 stuff is about.

        anyway, the code:
        Code:
        //global scope
        .vector relorg;
        .vector relfwd;
        .vector relup;
        vectoangles(vector forward, vector up) vectoangles2 = #51; //if not supported by the engine, the 'up' vector will be treated as '0 0 1'.
        
        //to figure out the various values to express our position relative to our attachee
        void(entity targ) calc_attachment =
        {
          makevectors([self.angles_x*-1,self_angles_y,self_angles_z]);
          vector nailforward = v_forward;
          vector nailup = v_up;
          if (targ.solid == SOLID_BSP)
            makevectors(targ.angles);
          else
            makevectors([targ.angles_x*-1,targ_angles_y,targ_angles_z]);
          //dotproducts
          self.relorg_x = (self.origin-targ.origin)*v_forward;
          self.relorg_y = (self.origin-targ.origin)*v_right;
          self.relorg_z = (self.origin-targ.origin)*v_up;
          self.relfwd_x = nailforward*v_forward;
          self.relfwd_y = nailforward*v_right;
          self.relfwd_z = nailforward*v_up;
          self.relup_x = nailup*v_forward;
          self.relup_y = nailup*v_right;
          self.relup_z = nailup*v_up;
          self.enemy = targ;
        };
        void() do_attachment =
        {
          entity targ = self.enemy;
          if (targ.solid == SOLID_BSP)
            makevectors(targ.angles);
          else
            makevectors([targ.angles_x*-1,targ_angles_y,targ_angles_z]);
          setorigin(self, targ.origin + self.relorg_x * v_forward + self.relorg_y * v_right + self.relorg_z * v_up); //relink it properly
          vector fwddir = self.relfwd_x * v_forward + self.relfwd_y * v_right + self.relfwd_z * v_up;
          vector updir = self.relup_x * v_forward + self.relup_y * v_right + self.relup_z * v_up;
          self.angles = vectoangles2(fwddir, updir);
        };
        figure out how to plug that into your own code yourself.
        Some Game Thing

        Comment

        Working...
        X