WeaponTypes - Page 2

WeaponTypes

Resources to get you going on your new project, or to help you over some emergent problems during your development cycle.

Moderator: Moderators

User avatar
FLOZi
MC: Legacy & Spring 1944 Developer
Posts: 6240
Joined: 29 Apr 2005, 01:14

Post by FLOZi »

KDR_11k wrote:Your long explaination about tolerance has confused me a lot but I think I can figure out what you want: wait-for-turn in an AimWeaponX function would terminate when the turn is closer than <tolerance> to the final rotation. You can just write your scripts to act like that without needing the engine to enforce another hacky special rule.

OTA had it. Spring had it.

FOR A DAMN REASON.
imbaczek
Posts: 3629
Joined: 22 Aug 2006, 16:19

Post by imbaczek »

what units was tolerance in?
User avatar
FLOZi
MC: Legacy & Spring 1944 Developer
Posts: 6240
Joined: 29 Apr 2005, 01:14

Post by FLOZi »

imbaczek wrote:what units was tolerance in?
64k angle iirc
User avatar
KDR_11k
Game Developer
Posts: 8293
Joined: 25 Jun 2006, 08:44

Post by KDR_11k »

Ah, okay, I found the code that uses tolerance (confusingly named weapon.maxAngleDif in the code, default is 3000 by the way). Aim calls happen either every 15 frames or when the target has moved more than <tolerance> away from the previous aim, whichever happens first. Argh's explanation sounded like it did something else. Tolerance won't ever make the unit miss though, the weapon does not check where it was aimed but where it should go. Try emit-sfxing a shot in FireWeapon, it'll often go into a direction the real shot doesn't (unless the weapon is turretless).

However, pitchtolerance does not exist.
User avatar
FLOZi
MC: Legacy & Spring 1944 Developer
Posts: 6240
Joined: 29 Apr 2005, 01:14

Post by FLOZi »

So it is still in then? Excellent.

Suppose I should have checked myself, I already knew about it being called maxAngleDif :oops:
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Well, even if it's in, it is not working right. Try giving a unit a Tolerance of 45K, and see if it opens fire before AimWeapon returns TRUE to the COBHandler. It won't, and that's not what should happen.
User avatar
FLOZi
MC: Legacy & Spring 1944 Developer
Posts: 6240
Joined: 29 Apr 2005, 01:14

Post by FLOZi »

What? How else would AimWeapon work?

Can a mod please split all this discussion out, we've majorly derailed. :P
User avatar
KDR_11k
Game Developer
Posts: 8293
Joined: 25 Jun 2006, 08:44

Post by KDR_11k »

I'd say unsticky this thread and put the information in the wiki.

Either way, why should it EVER allow shooting before AimWeapon returns true? Do you want it to arbitrarily define aiming as done? Oh, hey, let's just make the missile launch while the silo is still unfolding, yeah, that's gonna be great! Weapon disabled because it's only available in an upgrade? Hey, what do we care?
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

The way it used to work was that you could have AimWeapon return TRUE because piecenum == heading / pitch - tolerance. Duh. We did not return TRUE until Tolerance was satisfied, basically, instead of returning TRUE when an arbitrary angle (3000) was satisfied. Because sometimes 3000 is too much or too little.

With the laser thing, fine, let's just make a new class called LaserBoltProjectile and a weapon called LaserBolt, that are identical to LaserCannon except for the rendering method, since you seem to think that changing a few tags on a few dozen weapons (even in OTA games, we're talking maybe 60-70, tops, and a lot of it can be automated with find-and-replace) is too onerous :roll:
User avatar
KDR_11k
Game Developer
Posts: 8293
Joined: 25 Jun 2006, 08:44

Post by KDR_11k »

I can make it use case behaviour, no need for a new class for the beam caps but it should not trigger without the modder invoking it since beamcaps work well for the default graphics. There is no reason to make the default behaviour only work well for non-default cases, if you want no beamcap you can very well just tell it that you don't want it.
The way it used to work was that you could have AimWeapon return TRUE because piecenum == heading / pitch - tolerance.

Code: Select all

AimWeapon1(h,p) {
 while(heading > h + TOLERANCE) {
  heading = heading - TURNRATE;
  turn turret to y-axis heading now;
  sleep 30;
 }
 while(heading < h - TOLERANCE) {
  heading = heading + TURNRATE;
  turn turret to y-axis heading now;
  sleep 30;
 }
 return true;
}
Simplified because I can't be arsed to write the whole case logic here. But you'll probably still have the code because
We did not return TRUE until Tolerance was satisfied, basically, instead of returning TRUE when an arbitrary angle (3000) was satisfied. Because sometimes 3000 is too much or too little.
Spring never decides to return true for you, only a "return true" statement will. Tolerance in Spring defines how much the target can move before that true becomes invalid. Spring cannot know how you'd measure the angle your turret is pointed at and as such cannot prematurely return true, it can only execute your function and obey the return true statement.

If you want your behaviour then please define an algorithm that will do what you want. After that we can determine if it's a good idea.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

I can make it use case behaviour, no need for a new class for the beam caps but it should not trigger without the modder invoking it since beamcaps work well for the default graphics.
No, because that will involve 1-3 IF statements, slowing down that code. It'd be faster, better code if LaserBolt was a separate weapon type.

And I didn't just remove the caps, I removed the second copy of the texture, which was being drawn 4 times, that made the center "color" in order to emulate OTA stuff for backwards-compatibility, because with ColorMap, you don't need to have them anyhow. What I gave you was a completely new animal- using 8 fewer polygons, 1 fewer textures, and a lot less code-per-frame. Just build a new case in WeaponDefHandler, looking for "beamBolt" in the TDF section, it'll keep everybody happier. What I proposed was a completely new projectile type, and I'd rather have it perform like I wrote it (er, aside from that mistake with deleteme, oops) than make LaserCannonProjectile even longer and slower.

We need to quit doing that to Spring's weapons- it's better to have 50 different classes than 1 that does everything, because each of the 50, while they will be limited in certain ways, will run sooooo much faster than 1 will that the overall cost savings will win every time. Even if an IF returns immediately because the value returned is FALSE, that's an extra step we don't want in something as performance-crucial as weapons code. Look at the horrible performance of missiles in general, due to both the really horrible smoketrail code and the messy, option-filled series of IF-trees that are a part of it. It's exactly what we don't want. It'd be better to have different missile types (dancing, wobbling, gravity-arced, non-guided, etc.) than to have what we actually have, which is one projectile that can do all of those things- and must waste many cycles every time such a projectile is created on irrelevant code.

When I get the chance to sit down with it, I also have some other weapons I'd like to add as entirely new classes, such as a weapon that can behave like poison gas / fire / radiation / whatever (it's very easy, just needs a new type of explosion behavior)... and we should finally get rid of the default explosion code entirely, and simply point towards default CustomExplosionGenerators that perform the same functions (easy to do, and would remove more IFs from Spring's code).


Spring never decides to return true for you, only a "return true" statement will.
No, but Spring supplies the variable values for (heading, pitch), the two vars populated every time AimWeapon is called. Try your example code out, using some simple NanoBlobs aiming code or a OTA tank, I suspect you will start to see why I'm getting all grumpy about this issue ;)

As for a fix... the algorithm needs to be on the COBHandler side. Pseudocode:

Unit.cpp (I think that's where this function call occurs): CALL COBHandler AimWeapon

COBHandler: CALL AimWeapon, GET value of Tolerance and pitchTolerance (again, those should both work).

AimWeapon: IF COB contains wait-for-turn AND heading OR pitch (I think COBhandler just looks for the first two var assignments within that function, you cannot define heading, pitch inversely, or as third / fourth variables, IIRC from testing), then:

Return TRUE IF piecenum (normalized vector) / target (normalized vector) <= Tolerance AND <= pitchTolerance. That's all that needs to happen. A little nasty, but I doubt if it includes a lot more logic than is already in that code.
User avatar
KDR_11k
Game Developer
Posts: 8293
Joined: 25 Jun 2006, 08:44

Post by KDR_11k »

Personally I think we should unify the weapons and leave only an instahitweapon and a projectileweapon type behind, the current fragmentation is already a maintenance nightmare and limits flexibility, leading to issues like lightning not damaging shields or missiles not obeying accuracy. If you want to be the weapon maintainer of 50+ classes be my guest but I doubt you're going to become the primary dev for these things.

What would your algorithm do if I have e.g. two pieces I want to turn by heading / 2 each? I do that quite often with my bipeds.

Of course you can't assign heading and pitch in a different order, function parameters are identified by their order.

And how would I disable that "tolerant" behaviour (other than moving the commands into a separate function and calling that)? Zeroing tolerance would force a constant reaim. In a worst case scenario the difference between the weapon and target angle could be 2*tolerance (weapon stops aiming at one end of the cone, target moves to the other end). Why don't you just increase your turret's turnrate if you want it to finish aiming faster?

Special case hacks are the worst you can do to the codebase. The special case behaviour for show in FireWeapon is bad enough already. The COB interpreter shouldn't have any different behaviour based on the function an instruction is in. Besides, you oppose an if in a weapon function but you have no trouble adding a complicated check to the COB interpreter?


I'd rather see poison and other delayed effects implemented by letting the custom explo gens spawn damaging explosions and projectiles. Oh, wait, I forgot, versatile code is a performance nightmare, right?
User avatar
FLOZi
MC: Legacy & Spring 1944 Developer
Posts: 6240
Joined: 29 Apr 2005, 01:14

Post by FLOZi »

Pretty sure that COB has never ever done that with regards to tolerance.

Once again can a mod please split this discussion from the sticky?
tombom
Posts: 1933
Joined: 18 Dec 2005, 20:21

Post by tombom »

A single if statement to check a single value is not a major performance hog. Writing sensible code is far better than the very limited performance gains you might get by making a new class for every single change (which would also be a nightmare of duplicate code most likely).
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Zeroing tolerance would force a constant reaim.
Which is how it used to work. So the default value, in the source, was 500, IIRC.

And FLOZi, show me another way to do that, I'm open to another approach, but the only other way I can think of to do this is to check the AimFromWeapon(piecenum) and IF piecenum (normalized vector) / piecenum centroid to target (vector) <= tolerance THEN return TRUE.

Any other ideas?
Personally I think we should unify the weapons and leave only an instahitweapon and a projectileweapon type behind, the current fragmentation is already a maintenance nightmare and limits flexibility, leading to issues like lightning not damaging shields or missiles not obeying accuracy. If you want to be the weapon maintainer of 50+ classes be my guest but I doubt you're going to become the primary dev for these things.
You're right, I am not likely to become the primary dev for these things.

A, because my C++ skills overall are only so-so at best. I know it, I'm ok with that.

B, because I haven't even bothered trying to compile since the whole move to MingW, etc., because I only ever got it to compile in MS C++ 2005, and I haven't felt like wasting several days of my life, AGAIN, just to be able to compile something that I do not have commit access to. I have a game to build, and that's a higher priority, frankly. I just thought that the BeamBolt was a good idea, and since you've been messing with this area of the code, I thought that you might get it implemented.

C, because there are very few areas of Spring that I am sufficiently interested in and understand well enough to poke my nose in. I wouldn't touch the pathfinder code, even though I know it has problems- I know I'm not qualified to mess with it, and I don't want to screw it up in some subtle way trying, either.

Weapons, however, are (for the most part) rather simple code. Moreover, they directly affect game design itself, which is my primary interest. So, any changes to them, that I am aware of naturally attracts my interest...



Now, as to your specific proposal:

If you actually build your omni-weapon, and get the Spring devs to let you commit that, and make it mandatory, and I will immediately take a very, very keen interest in building a separate trunk of Spring, which will not include that ;)

I can tell you, with absolute 100% certainty, that your idea is a bad one.

If you wanna build something like that as an OPTIONAL THING, for people who don't mind terrifically-slow code for every weapon particle... be my guest. There's no harm in watching you prove me right ;)

"Hard to maintain" to me sounds like, "I am too lazy to write a proper #Include for all functions that should be common to all properly-separated code segments, and document why that code is #include for commonality and true ease of maintenance".

If you want to fix the whole collideFriendly mess, the best way to do that is to write up a new bit of code, ProjectileCollisions.cpp... put the relevant code for validating avoid / collide Friendly / Feature into that, and then have every single weapon class #include that code and call that function, not to build a ridiculous bloat of IF trees :|
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

A single if statement to check a single value is not a major performance hog.
But it gets called any time any weapon particle is created. With rapid-fire weapons, and lots of Units all firing, that may mean 10, 20, 30 all being updated, and running that if statement. Is that if in the middle of a function that runs every sync cycle, or is it just called once? An if is not an if... frequency is the issue. I learned that when writing the suspension simulation code for vehicles in PURE, which at this point only 3 people have seen besides me- frequency is the bane we want to avoid in sync code, and whatever can be unsynced and run through the stack between sync cycles should do so.

If you have 50 weapons, all using 50 different pieces of code, you're right, the performance advantages are fairly small. However, most Spring games aren't going to even use all 50 weapon classes (assuming there were 50, which there aren't), and some classes run much faster than others, but are called less often, etc.

Then the advantages of smaller, faster, tighter classes become more and more obvious.



Look, people... before I read one more stupid, condescending, Argh-is-an-idiot post in this thread, I want you to go build yourselves a Missile weapon that burst-fires 50 missiles, with smoke trails and heightMod=1.0 and with a burst delay of 0.1.

Go do that, equip a Unit with it, turn on shadow rendering, and watch Spring become a slideshow when that weapon fires.

This is what one, "I am trying to be a single weapon that does many things" weapon does, people (that, and the horrible drawing code for the smoketrails)...

Then do that with a plasma weapon, which uses some of the shortest weapons code in Spring.

Then come back to this conversation.
Last edited by Argh on 17 Sep 2007, 22:52, edited 1 time in total.
tombom
Posts: 1933
Joined: 18 Dec 2005, 20:21

Post by tombom »

Argh wrote:"Hard to maintain" to me sounds like, "I am too lazy to write a proper #Include for all functions that should be common to all properly-separated code segments, and document why that code is #include for commonality and true ease of maintenance".

If you want to fix the whole collideFriendly mess, the best way to do that is to write up a new bit of code, ProjectileCollisions.cpp... put the relevant code for validating avoid / collide Friendly / Feature into that, and then have every single weapon class #include that code and call that function, not to build a ridiculous bloat of IF trees :|
This is a bad idea ~_~

semi_: because usually you are going to compile every .cpp file
semi_: and if one of them is included to another
semi_: then that means you have multiple definitions of symbols
semi_: usually build systems are made so that each .cpp is compiled
semi_: and each .h is not
semi_: so that is why you use .h files for code you want to include
semi_: you can work around it, but it has no benefit, only downside
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Semi is correct, I wasn't implying that we shouldn't use .h files. Sorry for not communicating very well. The point I'm trying to make is that we need more stuff that is called as includes for common functions, like:

Code: Select all

#include "StdAfx.h"
#include "Game/GameHelper.h"
#include "LaserCannon.h"
#include "Map/Ground.h"
#include "Sim/MoveTypes/AirMoveType.h"
#include "Sim/Projectiles/WeaponProjectiles/LaserProjectile.h"
#include "Sim/Units/Unit.h"
#include "Sound.h"
#include "WeaponDefHandler.h"
#include "mmgr.h"
And less of:

Code: Select all

void CLaserCannon::Update(void)
{
	if(targetType!=Target_None){
		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
		if(!onlyForward){
			wantedDir=targetPos-weaponPos;
			wantedDir.Normalize();
		}
		predict=(targetPos-weaponPos).Length()/projectileSpeed;
	}
	CWeapon::Update();
}

bool CLaserCannon::TryTarget(const float3& pos,bool userTarget,CUnit* unit)
{
	if(!CWeapon::TryTarget(pos,userTarget,unit))
		return false;

	if(unit){
		if(unit->isUnderWater && !weaponDef->waterweapon)
			return false;
	} else {
		if(pos.y<0 && !weaponDef->waterweapon)
			return false;
	}

	float3 dir=pos-weaponMuzzlePos;
	float length=dir.Length();
	if(length==0)
		return true;

	dir/=length;

	if(!onlyForward){		//skip ground col testing for aircrafts
		float g=ground->LineGroundCol(weaponMuzzlePos,pos);
		if(g>0 && g<length*0.9f)
			return false;
	}
	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
		return false;

	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
		return false;
	return true;
Which, in all practicality, should be the same #include whatever.h for every single LOS weapon in Spring :P
User avatar
Pxtl
Posts: 6112
Joined: 23 Oct 2004, 01:43

Post by Pxtl »

Umm, I realize that it's unpopular, but doesn't C++ have this fancy-schmancy concept called "inheritence?" - provide an intermediate class for direct-fire weapons. Alternately, you could forward the execution to a static method in a utility class, rather than using includes. But I'm just an OOP dork who hates old-fashioned C code.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

C++ <> LUA. You don't really have inheritance. But you can use sub-functions and includes to achieve exactly the same thing.

Here, for all of you people who are coders, but too lazy to go look at why ol' Argh is on his milk-crate and grumpy about these issues... here is the current guided missile function, in a small font:

#include "StdAfx.h"
#include "Game/Camera.h"
#include "Game/GameHelper.h"
#include "LogOutput.h"
#include "Map/Ground.h"
#include "Matrix44f.h"
#include "MissileProjectile.h"
#include "myMath.h"
#include "Sim/Projectiles/ProjectileHandler.h"
#include "Rendering/GL/myGL.h"
#include "Rendering/GL/VertexArray.h"
#include "Rendering/UnitModels/3DModelParser.h"
#include "Rendering/UnitModels/UnitDrawer.h"
#include "Sim/Misc/GeometricObjects.h"
#include "Sim/Projectiles/Unsynced/SmokeTrailProjectile.h"
#include "Sim/Units/Unit.h"
#include "Sim/Weapons/WeaponDefHandler.h"
#include "Sync/SyncTracer.h"
#include "mmgr.h"

static const float Smoke_Time=60;

CR_BIND_DERIVED(CMissileProjectile, CWeaponProjectile, (float3(0,0,0),float3(0,0,0),NULL,0,0,0,NULL,NULL,float3(0,0,0)));

CR_REG_METADATA(CMissileProjectile,(
CR_MEMBER(dir),
CR_MEMBER(maxSpeed),
CR_MEMBER(curSpeed),
CR_MEMBER(ttl),
CR_MEMBER(areaOfEffect),
CR_MEMBER(age),
CR_MEMBER(oldSmoke),
CR_MEMBER(oldDir),
CR_MEMBER(target),
CR_MEMBER(decoyTarget),
CR_MEMBER(drawTrail),
CR_MEMBER(numParts),
CR_MEMBER(targPos),
CR_MEMBER(isWobbling),
CR_MEMBER(wobbleDir),
CR_MEMBER(wobbleTime),
CR_MEMBER(wobbleDif),
CR_MEMBER(danceMove),
CR_MEMBER(danceCenter),
CR_MEMBER(danceTime),
CR_MEMBER(isDancing),
CR_MEMBER(extraHeight),
CR_MEMBER(extraHeightDecay),
CR_MEMBER(extraHeightTime),
CR_RESERVED(16)
));

CMissileProjectile::CMissileProjectile(const float3& pos, const float3& speed, CUnit* owner, float areaOfEffect, float maxSpeed, int ttl, CUnit* target, const WeaponDef *weaponDef, float3 targetPos)
: CWeaponProjectile(pos, speed, owner, target, targetPos, weaponDef, 0, true),
ttl(ttl),
maxSpeed(maxSpeed),
target(target),
dir(speed),
oldSmoke(pos),
age(0),
drawTrail(true),
numParts(0),
areaOfEffect(areaOfEffect),
decoyTarget(0),
targPos(targetPos),
wobbleTime(1),
wobbleDir(0, 0, 0),
wobbleDif(0, 0, 0),
danceMove(0, 0, 0),
danceCenter(0, 0, 0),
danceTime(1),
isDancing(weaponDef? (weaponDef->dance > 0): false),
isWobbling(weaponDef? (weaponDef->wobble > 0): false),
extraHeightTime(0)
{
curSpeed=speed.Length();
dir.Normalize();
oldDir=dir;
if(target)
AddDeathDependence(target);

SetRadius(0.0f);
if((weaponDef)&&(!weaponDef->visuals.modelName.empty())){
S3DOModel* model = modelParser->Load3DO(string("objects3d/")+weaponDef->visuals.modelName,1,colorTeam);
if(model){
SetRadius(model->radius);
}
}

drawRadius=radius+maxSpeed*8;
ENTER_MIXED;
float3 camDir=(pos-camera->pos).Normalize();
if(camera->pos.distance(pos)*0.2f+(1-fabs(camDir.dot(dir)))*3000 < 200)
drawTrail=false;
ENTER_SYNCED;
castShadow=true;
#ifdef TRACE_SYNC
tracefile << "New missile: ";
tracefile << pos.x << " " << pos.y << " " << pos.z << " " << speed.x << " " << speed.y << " " << speed.z << "\n";
#endif
if(target)
target->IncomingMissile(this);

if((weaponDef)&&(weaponDef->trajectoryHeight>0)){
float dist=pos.distance(targPos);
extraHeight=dist*weaponDef->trajectoryHeight;
if(dist<maxSpeed)
dist=maxSpeed;
extraHeightTime=(int)(dist/*+pos.distance(targPos+UpVector*dist))*0.5f*//maxSpeed);
extraHeightDecay=extraHeight/extraHeightTime;
}
}

CMissileProjectile::~CMissileProjectile(void)
{
}

void CMissileProjectile::DependentDied(CObject* o)
{
if(o==target)
target=0;
if(o==decoyTarget)
decoyTarget=0;
CWeaponProjectile::DependentDied(o);
}

void CMissileProjectile::Collision()
{
float h=ground->GetHeight2(pos.x,pos.z);
if (weaponDef->waterweapon && h < pos.y) return; //let waterweapons travel in water
if(h>pos.y && fabs(speed.y)>0.001f)
pos-=speed*std::min((float)1,float((h-pos.y)/fabs(speed.y)));
if (weaponDef->visuals.smokeTrail)
SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldDir,owner,false,true,7,Smoke_Time,0.6f,drawTrail);
//helper->Explosion(pos,damages,areaOfEffect,owner);
CWeaponProjectile::Collision();
oldSmoke=pos;
}

void CMissileProjectile::Collision(CUnit *unit)
{
if (weaponDef->visuals.smokeTrail)
SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldDir,owner,false,true,7,Smoke_Time,0.6f,drawTrail);
// unit->DoDamage(damages,owner);
//helper->Explosion(pos,damages,areaOfEffect,owner);

CWeaponProjectile::Collision(unit);
oldSmoke=pos;
}

void CMissileProjectile::Update(void)
{
ttl--;
if(ttl>0){
if(curSpeed<maxSpeed)
curSpeed+=weaponDef->weaponacceleration;

float3 targSpeed(0,0,0);
if(weaponDef->tracks && (decoyTarget || target)){
if(decoyTarget){
targPos=decoyTarget->pos;
targSpeed=decoyTarget->speed;
} else {
targSpeed=target->speed;
if((target->physicalState==CSolidObject::Flying && (target->midPos-pos).SqLength()<150*150) || !owner)
targPos=target->midPos;
else
targPos=helper->GetUnitErrorPos(target,owner->allyteam);
}
}

if (isWobbling) {
--wobbleTime;
if (wobbleTime == 0) {
float3 newWob = gs->randVector();
wobbleDif = (newWob - wobbleDir) * (1.0f / 16);
wobbleTime = 16;
}
wobbleDir += wobbleDif;
dir += wobbleDir * weaponDef->wobble * (owner? (1 - owner->limExperience * 0.5f): 1);
dir.Normalize();
}

if (isDancing) {
--danceTime;
if (danceTime <= 0) {
danceMove = gs->randVector() * weaponDef->dance - danceCenter;
danceCenter += danceMove;
danceTime = 8;
}
pos += danceMove;
}

float3 orgTargPos(targPos);
float dist=targPos.distance(pos);
if(dist==0)
dist=0.1f;
if(extraHeightTime){
extraHeight-=extraHeightDecay;
--extraHeightTime;
targPos.y+=extraHeight;
dir.y-=extraHeightDecay/dist;
//geometricObjects->AddLine(pos,targPos,3,1,1);
}
float3 dif(targPos + targSpeed*(dist/maxSpeed)*0.7f - pos);
dif.Normalize();
float3 dif2=dif-dir;
float tracking=weaponDef->turnrate;
if(dif2.Length()<tracking){
dir=dif;
} else {
dif2-=dir*(dif2.dot(dir));
dif2.Normalize();
dir+=dif2*tracking;
dir.Normalize();
}

speed=dir*curSpeed;

targPos=orgTargPos;
} else {
speed*=0.995f;
speed.y+=gs->gravity;
dir=speed;
dir.Normalize();
}
pos+=speed;

age++;
numParts++;
if(weaponDef->visuals.smokeTrail && !(age&7)){
CSmokeTrailProjectile* tp=SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldDir,owner,age==8,false,7,Smoke_Time,0.6f,drawTrail);
oldSmoke=pos;
oldDir=dir;
numParts=0;
useAirLos=tp->useAirLos;
if(!drawTrail){
ENTER_MIXED;
float3 camDir=(pos-camera->pos).Normalize();
if(camera->pos.distance(pos)*0.2f+(1-fabs(camDir.dot(dir)))*3000 > 300)
drawTrail=true;
ENTER_SYNCED;
}
}

//CWeaponProjectile::Update();
}

void CMissileProjectile::Draw(void)
{
float3 interPos=pos+speed*gu->timeOffset;
inArray=true;
float age2=(age&7)+gu->timeOffset;

float color=0.6f;
unsigned char col[4];

if (weaponDef->visuals.smokeTrail)
if(drawTrail){ //draw the trail as a single quad
float3 dif(interPos-camera->pos);
dif.Normalize();
float3 dir1(dif.cross(dir));
dir1.Normalize();
float3 dif2(oldSmoke-camera->pos);
dif2.Normalize();
float3 dir2(dif2.cross(oldDir));
dir2.Normalize();


float a1=(1-float(0)/(Smoke_Time))*255;
a1*=0.7f+fabs(dif.dot(dir));
float alpha=min((float)255,max(float(0),a1));
col[0]=(unsigned char) (color*alpha);
col[1]=(unsigned char) (color*alpha);
col[2]=(unsigned char) (color*alpha);
col[3]=(unsigned char) alpha;

unsigned char col2[4];
float a2=(1-float(age2)/(Smoke_Time))*255;
if(age<8)
a2=0;
a2*=0.7f+fabs(dif2.dot(oldDir));
alpha=min((float)255,max((float)0,a2));
col2[0]=(unsigned char) (color*alpha);
col2[1]=(unsigned char) (color*alpha);
col2[2]=(unsigned char) (color*alpha);
col2[3]=(unsigned char) alpha;

float size=(1);
float size2=(1+(age2*(1/Smoke_Time))*7);

float txs=weaponDef->visuals.texture2->xend - (weaponDef->visuals.texture2->xend-weaponDef->visuals.texture2->xstart)*(age2/8.0f);//(1-age2/8.0f);
va->AddVertexTC(interPos-dir1*size, txs, weaponDef->visuals.texture2->ystart, col);
va->AddVertexTC(interPos+dir1*size, txs, weaponDef->visuals.texture2->yend, col);
va->AddVertexTC(oldSmoke+dir2*size2, weaponDef->visuals.texture2->xend, weaponDef->visuals.texture2->yend, col2);
va->AddVertexTC(oldSmoke-dir2*size2, weaponDef->visuals.texture2->xend, weaponDef->visuals.texture2->ystart, col2);
} else { //draw the trail as particles
float dist=pos.distance(oldSmoke);
float3 dirpos1=pos-dir*dist*0.33f;
float3 dirpos2=oldSmoke+oldDir*dist*0.33f;

for(int a=0;a<numParts;++a){
//float a1=1-float(a)/Smoke_Time;
float alpha=255;
col[0]=(unsigned char) (color*alpha);
col[1]=(unsigned char) (color*alpha);
col[2]=(unsigned char) (color*alpha);
col[3]=(unsigned char)alpha;//min(255,max(0,a1*255));
float size=(1+(a*(1/Smoke_Time))*7);

float3 pos1=CalcBeizer(float(a)/(numParts),pos,dirpos1,dirpos2,oldSmoke);
va->AddVertexTC(pos1+( camera->up+camera->right)*size, ph->smoketex[0].xstart, ph->smoketex[0].ystart, col);
va->AddVertexTC(pos1+( camera->up-camera->right)*size, ph->smoketex[0].xend, ph->smoketex[0].ystart, col);
va->AddVertexTC(pos1+(-camera->up-camera->right)*size, ph->smoketex[0].xend, ph->smoketex[0].ystart, col);
va->AddVertexTC(pos1+(-camera->up+camera->right)*size, ph->smoketex[0].xstart, ph->smoketex[0].ystart, col);
}

}
//rita flaren
col[0]=255;
col[1]=210;
col[2]=180;
col[3]=1;
float fsize = radius*0.4f;
va->AddVertexTC(interPos-camera->right*fsize-camera->up*fsize,weaponDef->visuals.texture1->xstart,weaponDef->visuals.texture1->ystart,col);
va->AddVertexTC(interPos+camera->right*fsize-camera->up*fsize,weaponDef->visuals.texture1->xend,weaponDef->visuals.texture1->ystart,col);
va->AddVertexTC(interPos+camera->right*fsize+camera->up*fsize,weaponDef->visuals.texture1->xend,weaponDef->visuals.texture1->yend,col);
va->AddVertexTC(interPos-camera->right*fsize+camera->up*fsize,weaponDef->visuals.texture1->xstart,weaponDef->visuals.texture1->yend,col);

/* col[0]=200;
col[1]=200;
col[2]=200;
col[3]=255;
float3 r=dir.cross(UpVector);
r.Normalize();
float3 u=dir.cross(r);
va->AddVertexTC(interPos+r*1.0f,1.0f/16,1.0f/16,col);
va->AddVertexTC(interPos-r*1.0f,1.0f/16,1.0f/16,col);
va->AddVertexTC(interPos+dir*9,1.0f/16,1.0f/16,col);
va->AddVertexTC(interPos+dir*9,1.0f/16,1.0f/16,col);

va->AddVertexTC(interPos+u*1.0f,1.0f/16,1.0f/16,col);
va->AddVertexTC(interPos-u*1.0f,1.0f/16,1.0f/16,col);
va->AddVertexTC(interPos+dir*9,1.0f/16,1.0f/16,col);
va->AddVertexTC(interPos+dir*9,1.0f/16,1.0f/16,col);*/
}

void CMissileProjectile::DrawUnitPart(void)
{
float3 interPos=pos+speed*gu->timeOffset;
glPushMatrix();
float3 rightdir;
if(dir.y!=1)
rightdir=dir.cross(UpVector);
else
rightdir=float3(1,0,0);
rightdir.Normalize();
float3 updir=rightdir.cross(dir);

CMatrix44f transMatrix;
transMatrix[0]=-rightdir.x;
transMatrix[1]=-rightdir.y;
transMatrix[2]=-rightdir.z;
transMatrix[4]=updir.x;
transMatrix[5]=updir.y;
transMatrix[6]=updir.z;
transMatrix[8]=dir.x;
transMatrix[9]=dir.y;
transMatrix[10]=dir.z;
transMatrix[12]=interPos.x+dir.x*radius*0.9f;
transMatrix[13]=interPos.y+dir.y*radius*0.9f;
transMatrix[14]=interPos.z+dir.z*radius*0.9f;
glMultMatrixf(&transMatrix[0]);

glCallList(modelDispList);
glPopMatrix();
}

int CMissileProjectile::ShieldRepulse(CPlasmaRepulser* shield,float3 shieldPos, float shieldForce, float shieldMaxSpeed)
{
float3 sdir=pos-shieldPos;
sdir.Normalize();
if(ttl > 0){
float3 dif2=sdir-dir;
float tracking=max(shieldForce*0.05f,weaponDef->turnrate*2); //steer away twice as fast as we can steer toward target
if(dif2.Length()<tracking){
dir=sdir;
} else {
dif2-=dir*(dif2.dot(dir));
dif2.Normalize();
dir+=dif2*tracking;
dir.Normalize();
}
return 2;
}
return 0;
}

void CMissileProjectile::DrawS3O(void)
{
unitDrawer->SetS3OTeamColour(colorTeam);
DrawUnitPart();
}


Do we really want to add every other possible weapon to this horrible bloat? Does anybody really doubt that therein lies a nightmare? Does anybody really think this will get easier to maintain, when it gets larger and larger?

Or should we figure out what properties should be common to all weapons, which properties should be common to a large sub-set of all weapons, make these properties into one, relatively-short include, and be in a better position to maintain and add new classes?
Post Reply

Return to “Game Development Tutorials & Resources”