2025-07-18 05:17 CEST

View Issue Details Jump to Notes ]
IDProjectCategoryView StatusLast Update
0000553Spring engineGeneralpublic2007-09-11 12:45
ReporterKDR_11k 
Assigned Totvo 
PrioritynormalSeverityfeatureReproducibilityN/A
StatusresolvedResolutionfixed 
Product Version 
Target VersionFixed in Version 
Summary0000553: [patch] AimFromWeapon, fixedLauncher and other tweaks
Description- Weapons now use AimFromWeapon to determine the part to aim from, this prevents waggling and failing to aim at close ranges. Internally this means weaponMuzzlePos holds the position where projectiles get spawned, not weaponPos.
- Melee weapon now reports a proper angle to AimWeapon.
- Added fixedLauncher tag (bool) for missiles and starburst missiles, this makes the projectile spawn with the orientation of the shooting piece instead of their normal orientation. The weapon will not properly check if allies are in the way so make sure you align the launchers in a way that won't hammer right into your own forces and perhaps use collideFriendly=0. FixedLauncher conflicts with trajectoryHeight and IMO combining them is pointless anyway so don't use both on a weapon.
- Made starburst missiles obey startvelocity and weaponacceleration, if your mod set them to something silly because they didn't do anything before you'll have to adjust.
- Added projectiles tag (int), each time a weapon fires this many projectiles are spawned (on the same frame). Make sure you put them on different trajectories somehow (sprayangle or different firepoints) because otherwise they'll all be clumped in one shot. Can be set to 0 as well for script trigger weapons and can be combined with burst.
- Added COB call to "ShotX" that happens shortly before weaponX uses QueryWeaponX, use this for switching firepoints in bursts or when using multiple projectiles.
- Missiles and starburst missiles now obey smoketrail, set it to 0 to disable the smoke. To get a missile without smoketrail you have to define the weapon as a missile with WeaponType=MissileLauncher in the tdf.
- StartBuilding now supplies the pitch as the second parameter to help with custom build FX.
Additional InformationSince I lack experience with Spring coding it would be helpful if a more experienced dev looked through the changes to see if there are any mistakes or style errors.

The patch was taken against revision 3842.
TagsNo tags attached.
Checked infolog.txt for Errors
Attached Files
  • patch file icon weaponChanges.patch (47,800 bytes) 2007-06-24 21:59 -
    Index: Sim/Projectiles/LightingProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/LightingProjectile.cpp	(revision 3842)
    +++ Sim/Projectiles/LightingProjectile.cpp	(working copy)
    @@ -58,7 +58,7 @@
     	}
     
     	if(weapon){
    -		pos=weapon->weaponPos;
    +		pos=weapon->weaponMuzzlePos;
     	}
     	for(int a=1;a<10;++a)
     		displacements[a]+=(gs->randFloat()-0.5f)*0.3f;
    Index: Sim/Projectiles/MissileProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/MissileProjectile.cpp	(revision 3842)
    +++ Sim/Projectiles/MissileProjectile.cpp	(working copy)
    @@ -120,7 +120,7 @@
     	float h=ground->GetHeight2(pos.x,pos.z);
     	if(h>pos.y && fabs(speed.y)>0.001f)
     		pos-=speed*std::min((float)1,float((h-pos.y)/fabs(speed.y)));
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldDir,owner,false,true,7,Smoke_Time,0.6f,drawTrail);
    +	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;
    @@ -128,7 +128,7 @@
     
     void CMissileProjectile::Collision(CUnit *unit)
     {
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldDir,owner,false,true,7,Smoke_Time,0.6f,drawTrail);
    +	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);
     
    @@ -206,7 +206,7 @@
     
     	age++;
     	numParts++;
    -	if(!(age&7)){
    +	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;
    @@ -233,6 +233,7 @@
     	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();
    Index: Sim/Projectiles/StarburstProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/StarburstProjectile.cpp	(revision 3842)
    +++ Sim/Projectiles/StarburstProjectile.cpp	(working copy)
    @@ -110,7 +110,7 @@
     	float h=ground->GetHeight2(pos.x,pos.z);
     	if(h>pos.y)
     		pos+=speed*(h-pos.y)/speed.y;
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
    +	if (weaponDef->visuals.smokeTrail) SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
     	oldSmokeDir=dir;
     //	helper->Explosion(pos,damages,areaOfEffect,owner);
     	CWeaponProjectile::Collision();
    @@ -119,7 +119,7 @@
     
     void CStarburstProjectile::Collision(CUnit *unit)
     {
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
    +	if (weaponDef->visuals.smokeTrail) SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
     	oldSmokeDir=dir;
     //	unit->DoDamage(damages,owner);
     //	helper->Explosion(pos,damages,areaOfEffect,owner);
    @@ -145,8 +145,7 @@
     	}
     	if(uptime>0){
     		if(curSpeed<maxSpeed)
    -			curSpeed+=0.1f;
    -		dir=UpVector;
    +			curSpeed+=weaponDef->weaponacceleration;
     		speed=dir*curSpeed;
     	} else if(doturn && ttl>0){
     		float3 dif(targetPos-pos);
    @@ -164,7 +163,7 @@
     		speed=dir*curSpeed;
     	} else if(ttl>0){
     		if(curSpeed<maxSpeed)
    -			curSpeed+=0.1f;
    +			curSpeed+=weaponDef->weaponacceleration;
     		float3 dif(targetPos-pos);
     		dif.Normalize();
     		if(dif.dot(dir)>maxGoodDif){
    @@ -197,7 +196,7 @@
     
     	age++;
     	numParts++;
    -	if(!(age&7)){
    +	if(weaponDef->visuals.smokeTrail && !(age&7)){
     		if(curCallback)
     			curCallback->drawCallbacker=0;
     		curCallback=SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,age==8,false,7,Smoke_Time,0.7f,drawTrail,this);
    @@ -226,6 +225,7 @@
     	unsigned char col[4];
     	unsigned char col2[4];
     
    +	if (weaponDef->visuals.smokeTrail)
     	if(drawTrail){		//draw the trail as a single quad
     
     		float3 dif(interPos-camera->pos);
    Index: Sim/Projectiles/StarburstProjectile.h
    ===================================================================
    --- Sim/Projectiles/StarburstProjectile.h	(revision 3842)
    +++ Sim/Projectiles/StarburstProjectile.h	(working copy)
    @@ -27,6 +27,7 @@
     	float3 dir;
     	float maxSpeed;
     	float curSpeed;
    +	float acceleration;
     	int ttl;
     	int uptime;
     	float areaOfEffect;
    Index: Sim/Units/COB/CobFile.cpp
    ===================================================================
    --- Sim/Units/COB/CobFile.cpp	(revision 3842)
    +++ Sim/Units/COB/CobFile.cpp	(working copy)
    @@ -166,7 +166,7 @@
     	}
     
     	//Map common function names to indicies
    -	scriptIndex.resize(COBFN_Last + COB_MaxWeapons * 5);
    +	scriptIndex.resize(COBFN_Last + COB_MaxWeapons * 6);
     	scriptIndex[COBFN_Create] = getFunctionId("Create");
     	scriptIndex[COBFN_StartMoving] = getFunctionId("StartMoving");
     	scriptIndex[COBFN_StopMoving] = getFunctionId("StopMoving");
    @@ -197,6 +197,7 @@
     		scriptIndex[COBFN_AimFromPrimary + i] = getFunctionId("AimFrom" + weapon);
     		scriptIndex[COBFN_FirePrimary + i] = getFunctionId("Fire" + weapon);
     		scriptIndex[COBFN_EndBurst + i] = getFunctionId("EndBurst" + weap);
    +		scriptIndex[COBFN_Shot + i] = getFunctionId("Shot" + weap);
     
     		// If new-naming functions are not found, we need to support the old naming scheme
     		if (i > 2)
    Index: Sim/Units/COB/CobFile.h
    ===================================================================
    --- Sim/Units/COB/CobFile.h	(revision 3842)
    +++ Sim/Units/COB/CobFile.h	(working copy)
    @@ -46,6 +46,7 @@
     const int COBFN_AimFromPrimary = COBFN_AimPrimary + COB_MaxWeapons;
     const int COBFN_FirePrimary = COBFN_AimFromPrimary + COB_MaxWeapons;
     const int COBFN_EndBurst = COBFN_FirePrimary + COB_MaxWeapons;
    +const int COBFN_Shot = COBFN_EndBurst + COB_MaxWeapons;
     
     class CCobFile
     {
    Index: Sim/Units/COB/CobInstance.cpp
    ===================================================================
    --- Sim/Units/COB/CobInstance.cpp	(revision 3842)
    +++ Sim/Units/COB/CobInstance.cpp	(working copy)
    @@ -650,15 +650,15 @@
     				dir.Normalize();
     
     				float3 targetPos = unit->weapons[type-2048]->targetPos;
    -				float3 weaponPos = unit->weapons[type-2048]->weaponPos;
    +				float3 weaponMuzzlePos = unit->weapons[type-2048]->weaponMuzzlePos;
     
     				unit->weapons[type-2048]->targetPos = pos+dir;
    -				unit->weapons[type-2048]->weaponPos = pos;
    +				unit->weapons[type-2048]->weaponMuzzlePos = pos;
     
     				unit->weapons[type-2048]->Fire();
     
     				unit->weapons[type-2048]->targetPos = targetPos;
    -				unit->weapons[type-2048]->weaponPos = weaponPos;
    +				unit->weapons[type-2048]->weaponMuzzlePos = weaponMuzzlePos;
     
     			}
     			else if (type & 4096) {
    Index: Sim/Units/UnitTypes/Builder.cpp
    ===================================================================
    --- Sim/Units/UnitTypes/Builder.cpp	(revision 3842)
    +++ Sim/Units/UnitTypes/Builder.cpp	(working copy)
    @@ -583,9 +583,12 @@
     {
     	float3 wantedDir=(pos-this->pos).Normalize();
     	short int h=GetHeadingFromVector(wantedDir.x,wantedDir.z);
    +	short int p=(short int) (asin(wantedDir.dot(updir))*(32768/PI));
    +	short int pitch=(short int) (asin(frontdir.dot(float3(0,1,0)))*(32768/PI));
     
     	std::vector<int> args;
     	args.push_back(short(h-heading));
    +	args.push_back(short(p-pitch));
     	cob->Call("StartBuilding", args);
     
     	int soundIdx = unitDef->sounds.build.getRandomIdx();
    Index: Sim/Weapons/BeamLaser.cpp
    ===================================================================
    --- Sim/Weapons/BeamLaser.cpp	(revision 3842)
    +++ Sim/Weapons/BeamLaser.cpp	(working copy)
    @@ -42,6 +42,7 @@
     {
     	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();
    @@ -84,7 +85,7 @@
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
    @@ -92,14 +93,14 @@
     	dir/=length;
     
     	if(!onlyForward){		//skip ground col testing for aircrafts
    -		float g=ground->LineGroundCol(weaponPos,pos);
    +		float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     		if(g>0 && g<length*0.9f)
     			return false;
     	}
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -125,7 +126,7 @@
     		if(salvoLeft==salvoSize-1){
     			if(fireSoundId)
     				sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    -			dir=targetPos-weaponPos;
    +			dir=targetPos-weaponMuzzlePos;
     			dir.Normalize();
     			oldDir=dir;
     		} else {
    @@ -147,7 +148,7 @@
     #endif
     	float maxLength=range*rangeMod;
     	float curLength=0;
    -	float3 curPos=weaponPos;
    +	float3 curPos=weaponMuzzlePos;
     	float3 hitPos;
     
     	bool tryAgain=true;
    @@ -192,7 +193,7 @@
     		// Dynamic Damage
     		DamageArray dynDamages;
     		if (weaponDef->dynDamageExp > 0)
    -			dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponPos, curPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
    +			dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponMuzzlePos, curPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
     		helper->Explosion(hitPos, weaponDef->dynDamageExp>0?dynDamages*(intensity*damageMul):weaponDef->damages*(intensity*damageMul), areaOfEffect, weaponDef->edgeEffectiveness, weaponDef->explosionSpeed,owner, true, 1.0f, false, weaponDef->explosionGenerator, hit, dir, weaponDef->id);
     	}
     
    Index: Sim/Weapons/Cannon.cpp
    ===================================================================
    --- Sim/Weapons/Cannon.cpp	(revision 3842)
    +++ Sim/Weapons/Cannon.cpp	(working copy)
    @@ -59,6 +59,8 @@
     	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;
     		float3 diff = targetPos-weaponPos;
     		wantedDir = GetWantedDir(diff);
     		float speed2D = wantedDir.Length2D() * projectileSpeed;
    @@ -94,7 +96,7 @@
     	{
     		return true;
     	}
    -	float3 dif(pos-weaponPos);
    +	float3 dif(pos-weaponMuzzlePos);
     
     	float3 dir(GetWantedDir(dif));
     
    @@ -109,7 +111,7 @@
     	}
     	flatdir/=flatlength;
     
    -	float gc=ground->TrajectoryGroundCol(weaponPos, flatdir, flatlength-10,
    +	float gc=ground->TrajectoryGroundCol(weaponMuzzlePos, flatdir, flatlength-10,
     			dir.y , gs->gravity / (projectileSpeed * projectileSpeed) * 0.5f);
     	if(gc>0) {
     		return false;
    @@ -119,7 +121,7 @@
     	if(gc>0 && gc<length*0.40f)
     		return false;
     */
    -	if(avoidFriendly && helper->TestTrajectoryCone(weaponPos, flatdir,
    +	if(avoidFriendly && helper->TestTrajectoryCone(weaponMuzzlePos, flatdir,
     		flatlength-30, dir.y, gs->gravity /
     		(projectileSpeed * projectileSpeed) * 0.5f,
     		(accuracy+sprayangle) * 0.6f * (1-owner->limExperience * 0.9f) * 0.9f,
    @@ -142,7 +144,7 @@
     
     void CCannon::Fire(void)
     {
    -	float3 diff = targetPos-weaponPos;
    +	float3 diff = targetPos-weaponMuzzlePos;
     	float3 dir=GetWantedDir(diff);
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.9f);
     	dir.Normalize();
    @@ -159,7 +161,7 @@
     	} else {
     		ttl=predict*2;
     	}
    -	SAFE_NEW CExplosiveProjectile(weaponPos,dir*projectileSpeed,owner,weaponDef, ttl,areaOfEffect);
    +	SAFE_NEW CExplosiveProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,weaponDef, ttl,areaOfEffect);
     	//CWeaponProjectile::CreateWeaponProjectile(weaponPos,owner->speed,owner, NULL, float3(0,0,0), weaponDef);
     
     //	SAFE_NEW CSmokeProjectile(weaponPos,dir*0.01f,90,0.1f,0.02f,owner,0.6f);
    @@ -168,8 +170,8 @@
     //	p->maxheat=p->heat;
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    -	if(weaponPos.y<30)
    - 		water->AddExplosion(weaponPos,damages[0]*0.1f,sqrt(damages[0])+80);
    +	if(weaponMuzzlePos.y<30)
    + 		water->AddExplosion(weaponMuzzlePos,damages[0]*0.1f,sqrt(damages[0])+80);
     }
     
     void CCannon::SlowUpdate(void)
    Index: Sim/Weapons/DGunWeapon.cpp
    ===================================================================
    --- Sim/Weapons/DGunWeapon.cpp	(revision 3842)
    +++ Sim/Weapons/DGunWeapon.cpp	(working copy)
    @@ -23,7 +23,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -42,13 +43,13 @@
     	if(onlyForward){
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
     	dir.Normalize();
     
    -	SAFE_NEW CFireBallProjectile(weaponPos,dir*projectileSpeed,owner,0,targetPos,weaponDef);
    +	SAFE_NEW CFireBallProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,0,targetPos,weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume*0.2f);
     }
    Index: Sim/Weapons/EmgCannon.cpp
    ===================================================================
    --- Sim/Weapons/EmgCannon.cpp	(revision 3842)
    +++ Sim/Weapons/EmgCannon.cpp	(working copy)
    @@ -27,7 +27,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -49,21 +50,21 @@
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.5f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.5f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -83,15 +84,16 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType)){		//the taairmovetype cant align itself properly, change back when that is fixed
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
     	dir.Normalize();
     
    -	SAFE_NEW CEmgProjectile(weaponPos,dir*projectileSpeed,owner,weaponDef->visuals.color,weaponDef->intensity,(int)(range/projectileSpeed), weaponDef);
    +	SAFE_NEW CEmgProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,weaponDef->visuals.color,weaponDef->intensity,(int)(range/projectileSpeed), weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
     
     
    +
    Index: Sim/Weapons/FlameThrower.cpp
    ===================================================================
    --- Sim/Weapons/FlameThrower.cpp	(revision 3842)
    +++ Sim/Weapons/FlameThrower.cpp	(working copy)
    @@ -26,12 +26,12 @@
     
     void CFlameThrower::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
     	float3 spread=(gs->randVector()*sprayangle+salvoError)*0.2f;
     	spread-=dir*0.001f;
     
    -	SAFE_NEW CFlameProjectile(weaponPos,dir*projectileSpeed,spread,owner,weaponDef,(int)(range/projectileSpeed*weaponDef->duration));
    +	SAFE_NEW CFlameProjectile(weaponMuzzlePos,dir*projectileSpeed,spread,owner,weaponDef,(int)(range/projectileSpeed*weaponDef->duration));
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    @@ -49,21 +49,21 @@
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner)){
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner)){
     		return false;
     	}
     	return true;
    @@ -73,6 +73,7 @@
     {
     	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;
     		wantedDir=targetPos-weaponPos;
     		wantedDir.Normalize();
     	}
    Index: Sim/Weapons/LaserCannon.cpp
    ===================================================================
    --- Sim/Weapons/LaserCannon.cpp	(revision 3842)
    +++ Sim/Weapons/LaserCannon.cpp	(working copy)
    @@ -29,7 +29,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -51,7 +52,7 @@
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
    @@ -59,14 +60,14 @@
     	dir/=length;
     
     	if(!onlyForward){		//skip ground col testing for aircrafts
    -		float g=ground->LineGroundCol(weaponPos,pos);
    +		float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     		if(g>0 && g<length*0.9f)
     			return false;
     	}
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -83,7 +84,7 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType)){		//the taairmovetype cant align itself properly, change back when that is fixed
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.7f);
    @@ -95,10 +96,11 @@
     		fpsSub=6;
     #endif
     
    -	SAFE_NEW CLaserProjectile(weaponPos, dir*projectileSpeed, owner, weaponDef->duration*weaponDef->maxvelocity, weaponDef->visuals.color, weaponDef->visuals.color2, weaponDef->intensity, weaponDef, (int)((weaponDef->range-fpsSub*4)/weaponDef->projectilespeed)-fpsSub);
    +	SAFE_NEW CLaserProjectile(weaponMuzzlePos, dir*projectileSpeed, owner, weaponDef->duration*weaponDef->maxvelocity, weaponDef->visuals.color, weaponDef->visuals.color2, weaponDef->intensity, weaponDef, (int)((weaponDef->range-fpsSub*4)/weaponDef->projectilespeed)-fpsSub);
     
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
     
     
    +
    Index: Sim/Weapons/LightingCannon.cpp
    ===================================================================
    --- Sim/Weapons/LightingCannon.cpp	(revision 3842)
    +++ Sim/Weapons/LightingCannon.cpp	(working copy)
    @@ -29,6 +29,7 @@
     {
     	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();
    @@ -50,21 +51,21 @@
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -76,14 +77,14 @@
     
     void CLightingCannon::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
     	CUnit* u=0;
    -	float r=helper->TraceRay(weaponPos,dir,range,0,owner,u);
    +	float r=helper->TraceRay(weaponMuzzlePos,dir,range,0,owner,u);
     
     	float3 newDir;
     	CPlasmaRepulser* shieldHit;
    -	float shieldLength=interceptHandler.AddShieldInterceptableBeam(this,weaponPos,dir,range,newDir,shieldHit);
    +	float shieldLength=interceptHandler.AddShieldInterceptableBeam(this,weaponMuzzlePos,dir,range,newDir,shieldHit);
     	if(shieldLength<r){
     		r=shieldLength;
     		}
    @@ -94,11 +95,11 @@
     	// Dynamic Damage
     	DamageArray dynDamages;
     	if (weaponDef->dynDamageExp > 0)
    -		dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponPos, targetPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
    +		dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponMuzzlePos, targetPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
     
    -	helper->Explosion(weaponPos+dir*r,weaponDef->dynDamageExp>0?dynDamages:weaponDef->damages,areaOfEffect,weaponDef->edgeEffectiveness,weaponDef->explosionSpeed,owner,false,0.5f,true,weaponDef->explosionGenerator, u,dir, weaponDef->id);
    +	helper->Explosion(weaponMuzzlePos+dir*r,weaponDef->dynDamageExp>0?dynDamages:weaponDef->damages,areaOfEffect,weaponDef->edgeEffectiveness,weaponDef->explosionSpeed,owner,false,0.5f,true,weaponDef->explosionGenerator, u,dir, weaponDef->id);
     
    -	SAFE_NEW CLightingProjectile(weaponPos,weaponPos+dir*(r+10),owner,color,weaponDef,10,this);
    +	SAFE_NEW CLightingProjectile(weaponMuzzlePos,weaponMuzzlePos+dir*(r+10),owner,color,weaponDef,10,this);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     
    Index: Sim/Weapons/MeleeWeapon.cpp
    ===================================================================
    --- Sim/Weapons/MeleeWeapon.cpp	(revision 3842)
    +++ Sim/Weapons/MeleeWeapon.cpp	(working copy)
    @@ -27,8 +27,16 @@
     
     void CMeleeWeapon::Update()
     {
    +	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();
    -
     }
     
     void CMeleeWeapon::Fire(void)
    Index: Sim/Weapons/MissileLauncher.cpp
    ===================================================================
    --- Sim/Weapons/MissileLauncher.cpp	(revision 3842)
    +++ Sim/Weapons/MissileLauncher.cpp	(working copy)
    @@ -25,7 +25,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			float dist=wantedDir.Length();
     			predict=dist/projectileSpeed;
    @@ -45,12 +46,15 @@
     	if(onlyForward){
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     		if(weaponDef->trajectoryHeight>0){
     			dir.y+=weaponDef->trajectoryHeight;
     			dir.Normalize();
     		}
    +		if (weaponDef->fixedLauncher) {
    +			dir=weaponDir;
    +		}
     	}
     
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
    @@ -60,7 +64,7 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType))
     		startSpeed+=owner->speed;
     
    -	SAFE_NEW CMissileProjectile(weaponPos,startSpeed,owner,areaOfEffect,projectileSpeed,(int)(range/projectileSpeed+25),targetUnit, weaponDef,targetPos);
    +	SAFE_NEW CMissileProjectile(weaponMuzzlePos,startSpeed,owner,areaOfEffect,projectileSpeed,(int)(range/projectileSpeed+25),targetUnit, weaponDef,targetPos);
     	//CWeaponProjectile::CreateWeaponProjectile(weaponPos,startSpeed,owner,targetUnit, float3(0,0,0), weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    @@ -79,7 +83,7 @@
     		if(pos.y<0)
     			return false;
     	}
    -	float3 dir=pos-weaponPos;
    +	float3 dir = pos-weaponMuzzlePos;
     	if(weaponDef->trajectoryHeight>0){	//do a different test depending on if the missile has a high trajectory or not
     		float3 flatdir(dir.x,0,dir.z);
     		dir.Normalize();
    @@ -91,11 +95,11 @@
     		float linear=dir.y+weaponDef->trajectoryHeight;
     		float quadratic=-weaponDef->trajectoryHeight/flatlength;
     
    -		float gc=ground->TrajectoryGroundCol(weaponPos,flatdir,flatlength-30,linear,quadratic);
    +		float gc=ground->TrajectoryGroundCol(weaponMuzzlePos,flatdir,flatlength-30,linear,quadratic);
     		if(gc>0)
     			return false;
     
    -		if(avoidFriendly && helper->TestTrajectoryCone(weaponPos,flatdir,flatlength-30,linear,quadratic,0,8,owner->allyteam,owner)){
    +		if(avoidFriendly && helper->TestTrajectoryCone(weaponMuzzlePos,flatdir,flatlength-30,linear,quadratic,0,8,owner->allyteam,owner)){
     			return false;
     		}
     	} else {
    @@ -106,7 +110,7 @@
     		dir/=length;
     
     		if(!onlyForward){		//skip ground col testing for aircrafts
    -			float g=ground->LineGroundCol(weaponPos,pos);
    +			float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     			if(g>0 && g<length*0.9f)
     				return false;
     		} else {
    @@ -115,7 +119,7 @@
     			if(owner->frontdir.dot(goaldir) < maxAngleDif)
     				return false;
     		}
    -		if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
    +		if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
     			return false;
     	}
     	return true;
    Index: Sim/Weapons/Rifle.cpp
    ===================================================================
    --- Sim/Weapons/Rifle.cpp	(revision 3842)
    +++ Sim/Weapons/Rifle.cpp	(working copy)
    @@ -37,6 +37,7 @@
     {
     	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;
     		wantedDir=targetPos-weaponPos;
     		wantedDir.Normalize();
     	}
    @@ -56,18 +57,18 @@
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.9f),owner->allyteam,owner)){
    +	if(helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.9f),owner->allyteam,owner)){
     		return false;
     	}
     	return true;
    @@ -75,7 +76,7 @@
     
     void CRifle::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.9f);
     	dir.Normalize();
    @@ -84,13 +85,13 @@
     	tracefile << owner->pos.x << " " << dir.x << " " << targetPos.x << " " << targetPos.y << " " << targetPos.z << "\n";
     #endif
     	CUnit* hit;
    -	float length=helper->TraceRay(weaponPos,dir,range,damages[0],owner,hit);
    +	float length=helper->TraceRay(weaponMuzzlePos,dir,range,damages[0],owner,hit);
     	if(hit){
     		hit->DoDamage(damages,owner,ZeroVector, weaponDef->id);
    -		SAFE_NEW CHeatCloudProjectile(weaponPos+dir*length,hit->speed*0.9f,30,1,owner);
    +		SAFE_NEW CHeatCloudProjectile(weaponMuzzlePos+dir*length,hit->speed*0.9f,30,1,owner);
     	}
    -	SAFE_NEW CTracerProjectile(weaponPos,dir*projectileSpeed,length,owner);
    -	SAFE_NEW CSmokeProjectile(weaponPos,float3(0,0.0f,0),70,0.1f,0.02f,owner,0.6f);
    +	SAFE_NEW CTracerProjectile(weaponMuzzlePos,dir*projectileSpeed,length,owner);
    +	SAFE_NEW CSmokeProjectile(weaponMuzzlePos,float3(0,0.0f,0),70,0.1f,0.02f,owner,0.6f);
     	if(fireSoundId)
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    Index: Sim/Weapons/StarburstLauncher.cpp
    ===================================================================
    --- Sim/Weapons/StarburstLauncher.cpp	(revision 3842)
    +++ Sim/Weapons/StarburstLauncher.cpp	(working copy)
    @@ -30,6 +30,7 @@
     {
     	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;
     		wantedDir=(targetPos-weaponPos).Normalize();		//the aiming upward is apperently implicid so aim toward target
     	}
     	CWeapon::Update();
    @@ -37,7 +38,11 @@
     
     void CStarburstLauncher::Fire(void)
     {
    -	CStarburstProjectile* p=SAFE_NEW CStarburstProjectile(weaponPos+float3(0,2,0),float3(0,0.01f,0),owner,targetPos,areaOfEffect,projectileSpeed,tracking,(int)uptime,targetUnit, weaponDef,interceptTarget);
    +	float3 speed(0,weaponDef->startvelocity,0);
    +	if(weaponDef->fixedLauncher) {
    +		speed=weaponDir * weaponDef->startvelocity;
    +	}
    +	CStarburstProjectile* p=SAFE_NEW CStarburstProjectile(weaponMuzzlePos+float3(0,2,0),speed,owner,targetPos,areaOfEffect,projectileSpeed,tracking,(int)uptime,targetUnit, weaponDef,interceptTarget);
     
     	if(weaponDef->targetable)
     		interceptHandler.AddInterceptTarget(p,targetPos);
    @@ -59,8 +64,12 @@
     			return false;
     	}
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,UpVector,100,0,owner->allyteam,owner))
    -		return false;
    +	if(!weaponDef->fixedLauncher)
    +		if(avoidFriendly && helper->TestCone(weaponMuzzlePos,UpVector,100,0,owner->allyteam,owner))
    +			return false;
    +	else
    +		if(avoidFriendly && helper->TestCone(weaponMuzzlePos,weaponDir,100,0,owner->allyteam,owner))
    +			return false;
     
     	return true;
     }
    Index: Sim/Weapons/TorpedoLauncher.cpp
    ===================================================================
    --- Sim/Weapons/TorpedoLauncher.cpp	(revision 3842)
    +++ Sim/Weapons/TorpedoLauncher.cpp	(working copy)
    @@ -30,7 +30,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -//		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +//		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			float dist=wantedDir.Length();
     			predict=dist/projectileSpeed;
    @@ -46,7 +47,7 @@
     //	if(onlyForward){
     //		dir=owner->frontdir;
     //	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     		if(weaponDef->trajectoryHeight>0){
     			dir.y+=weaponDef->trajectoryHeight;
    @@ -57,7 +58,7 @@
     
     //	if(onlyForward)
     //		startSpeed+=owner->speed*0.5f;
    -	SAFE_NEW CTorpedoProjectile(weaponPos,startSpeed,owner,areaOfEffect,projectileSpeed,tracking,(int)(range/projectileSpeed+15),targetUnit, weaponDef);
    +	SAFE_NEW CTorpedoProjectile(weaponMuzzlePos,startSpeed,owner,areaOfEffect,projectileSpeed,tracking,(int)(range/projectileSpeed+15),targetUnit, weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    @@ -76,14 +77,14 @@
     	if(ground->GetHeight2(pos.x,pos.z)>0)
     		return 0;
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)+0.05f,owner->allyteam,owner))	//+0.05f since torpedoes has an unfortunate tendency to hit own ships due to movement
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)+0.05f,owner->allyteam,owner))	//+0.05f since torpedoes has an unfortunate tendency to hit own ships due to movement
     		return false;
     	return true;
     }
    Index: Sim/Weapons/Weapon.cpp
    ===================================================================
    --- Sim/Weapons/Weapon.cpp	(revision 3842)
    +++ Sim/Weapons/Weapon.cpp	(working copy)
    @@ -56,9 +56,11 @@
     	CR_MEMBER(subClassReady),
     	CR_MEMBER(onlyForward),
     	CR_MEMBER(weaponPos),
    +	CR_MEMBER(weaponMuzzlePos),
     	CR_MEMBER(lastRequest),
     	CR_MEMBER(damages),
     	CR_MEMBER(relWeaponPos),
    +	CR_MEMBER(relWeaponMuzzlePos),
     	CR_MEMBER(muzzleFlareSize),
     	CR_MEMBER(lastTargetRetry),
     	CR_MEMBER(areaOfEffect),
    @@ -127,8 +129,10 @@
     	subClassReady(true),
     	onlyForward(false),
     	weaponPos(0,0,0),
    +	weaponMuzzlePos(0,0,0),
     	lastRequest(0),
     	relWeaponPos(0,1,0),
    +	relWeaponMuzzlePos(0,1,0),
     	muzzleFlareSize(1),
     	lastTargetRetry(-100),
     	areaOfEffect(1),
    @@ -167,12 +171,11 @@
     	if(hasCloseTarget){
     		std::vector<int> args;
     		args.push_back(0);
    -		if(useWeaponPosForAim){
    -			owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    -		} else {
    -			owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
    -		}
    +		owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     		relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
    +
    +		owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    +		relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
     	}
     
     	if(targetType==Target_Unit){
    @@ -249,16 +252,18 @@
     	&& subClassReady
     	&& reloadStatus<=gs->frameNum
     	&& (!weaponDef->stockpile || numStockpiled)
    -	&& (weaponDef->waterweapon || weaponPos.y>0)
    +	&& (weaponDef->waterweapon || weaponMuzzlePos.y>0)
     	&& (owner->unitDef->maxFuel==0 || owner->currentFuel > 0)
     	){
     		if ((weaponDef->stockpile || (gs->Team(owner->team)->metal>=metalFireCost && gs->Team(owner->team)->energy>=energyFireCost))) {
     			std::vector<int> args;
     			args.push_back(0);
     			owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    -			relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
    -			weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +			owner->localmodel->GetEmitDirPos(args[0], relWeaponMuzzlePos, weaponDir);
    +			weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
     			useWeaponPosForAim=reloadTime/16+8;
    +			weaponDir = owner->frontdir * weaponDir.z + owner->updir * weaponDir.y + owner->rightdir * weaponDir.x;
    +			weaponDir.Normalize();
     
     			if(TryTarget(targetPos,haveUserTarget,targetUnit)){
     				if(weaponDef->stockpile){
    @@ -294,35 +299,52 @@
     			}
     		}
     	}
    -	if(salvoLeft && nextSalvo<=gs->frameNum){
    +	if(salvoLeft && nextSalvo<=gs->frameNum ){
     		salvoLeft--;
     		nextSalvo=gs->frameNum+salvoDelay;
     		owner->lastFireWeapon=gs->frameNum;
    +		
    +		int projectiles = weaponDef->projectilespershot;
    +		
    +		while(projectiles > 0) {
    +			--projectiles;
    +			
    +			// add to the commandShotCount if this is the last salvo,
    +			// and it is being directed towards the current target
    +			// (helps when deciding if a queued ground attack order has been completed)
    +			if ((salvoLeft == 0) && (owner->commandShotCount >= 0) &&
    +			    ((targetType == Target_Pos) && (targetPos == owner->userAttackPos)) ||
    +					((targetType == Target_Unit) && (targetUnit == owner->userTarget))) {
    +				owner->commandShotCount++;
    +			}
    +	
    +			std::vector<int> args;
    +			args.push_back(0);
    +	
    +			owner->cob->Call(COBFN_Shot+weaponNum,0);
    +	
    +			owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
    +			relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     
    -		// add to the commandShotCount if this is the last salvo,
    -		// and it is being directed towards the current target
    -		// (helps when deciding if a queued ground attack order has been completed)
    -		if ((salvoLeft == 0) && (owner->commandShotCount >= 0) &&
    -		    ((targetType == Target_Pos) && (targetPos == owner->userAttackPos)) ||
    -				((targetType == Target_Unit) && (targetUnit == owner->userTarget))) {
    -			owner->commandShotCount++;
    -		}
    +			owner->cob->Call(/*COBFN_AimFromPrimary+weaponNum*/COBFN_QueryPrimary+weaponNum/**/,args);
    +			owner->localmodel->GetEmitDirPos(args[0], relWeaponMuzzlePos, weaponDir);
     
    -		std::vector<int> args;
    -		args.push_back(0);
    -		owner->cob->Call(/*COBFN_AimFromPrimary+weaponNum/*/COBFN_QueryPrimary+weaponNum/**/,args);
    -		relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
    -		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +			weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
     
    -//		logOutput.Print("RelPosFire %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
    -
    -		if (owner->unitDef->decloakOnFire && (owner->scriptCloak <= 2)) {
    -			owner->isCloaked = false;
    -			owner->curCloakTimeout = gs->frameNum + owner->cloakTimeout;
    +			weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +			weaponDir = owner->frontdir * weaponDir.z + owner->updir * weaponDir.y + owner->rightdir * weaponDir.x;
    +			weaponDir.Normalize();
    +	
    +	//		logOutput.Print("RelPosFire %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
    +	
    +			if (owner->unitDef->decloakOnFire && (owner->scriptCloak <= 2)) {
    +				owner->isCloaked = false;
    +				owner->curCloakTimeout = gs->frameNum + owner->cloakTimeout;
    +			}
    +	
    +			Fire();
     		}
     
    -		Fire();
    -
     		//Rock the unit in the direction of the fireing
     		float3 rockDir = wantedDir;
     		rockDir.y = 0;
    @@ -353,9 +375,9 @@
     
     	if(!weaponDef->waterweapon && pos.y<1)
     		pos.y=1;
    -	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -	if(weaponPos.y<ground->GetHeight2(weaponPos.x,weaponPos.z))
    -		weaponPos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +	if(weaponMuzzlePos.y<ground->GetHeight2(weaponMuzzlePos.x,weaponMuzzlePos.z))
    +		weaponMuzzlePos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
     
     	if(!TryTarget(pos,userTarget,0))
     		return false;
    @@ -378,8 +400,10 @@
     
     	weaponPos= owner->pos + owner->frontdir * relWeaponPos.z
     		+ owner->updir * relWeaponPos.y + owner->rightdir * relWeaponPos.x;
    -	if(weaponPos.y < ground->GetHeight2(weaponPos.x, weaponPos.z))
    -		weaponPos = owner->pos + UpVector * 10;
    +	weaponMuzzlePos= owner->pos + owner->frontdir * relWeaponMuzzlePos.z
    +		+ owner->updir * relWeaponMuzzlePos.y + owner->rightdir * relWeaponMuzzlePos.x;
    +	if(weaponMuzzlePos.y < ground->GetHeight2(weaponMuzzlePos.x, weaponMuzzlePos.z))
    +		weaponMuzzlePos = owner->pos + UpVector * 10;
     	//hope that we are underground because we are a popup weapon and will come above ground later
     
     	if(!unit){
    @@ -427,18 +451,17 @@
     #endif
     	std::vector<int> args;
     	args.push_back(0);
    -	if(useWeaponPosForAim){
    -		owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    -		if(useWeaponPosForAim>1)
    -			useWeaponPosForAim--;
    -	} else {
    -		owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
    -	}
    +	owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     	relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -	if(weaponPos.y<ground->GetHeight2(weaponPos.x,weaponPos.z))
    -		weaponPos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
     
    +	owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    +	relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +
    +	if(weaponMuzzlePos.y<ground->GetHeight2(weaponMuzzlePos.x,weaponMuzzlePos.z))
    +		weaponMuzzlePos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
    +
     	predictSpeedMod=1+(gs->randFloat()-0.5f)*2*(1-owner->limExperience);
     
     	if((targetPos-weaponPos).SqLength() < relWeaponPos.SqLength()*16)
    @@ -542,7 +565,7 @@
     	if(weaponDef->stockpile && !numStockpiled)
     		return false;
     
    -	float3 dif=pos-weaponPos;
    +	float3 dif=pos-weaponMuzzlePos;
     
     	float r=GetRange2D(owner->pos.y-pos.y);
     	if(dif.SqLength2D()>=r*r)
    @@ -586,11 +609,13 @@
     	owner->frontdir = GetVectorFromHeading(owner->heading);
     	owner->rightdir = owner->frontdir.cross(owner->updir);
     	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;
     	bool val = TryTarget(tempTargetPos,userTarget,unit);
     	owner->frontdir = tempfrontdir;
     	owner->rightdir = temprightdir;
     	owner->heading = tempHeadding;
     	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;
     	return val;
     }
     
    @@ -616,11 +641,13 @@
     	owner->frontdir = GetVectorFromHeading(owner->heading);
     	owner->rightdir = owner->frontdir.cross(owner->updir);
     	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;
     	bool val = TryTarget(pos, userTarget, 0);
     	owner->frontdir = tempfrontdir;
     	owner->rightdir = temprightdir;
     	owner->heading = tempHeadding;
     	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;
     	return val;
     }
     
    @@ -631,6 +658,10 @@
     	owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     	relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +
    +	owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    +	relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
     //	logOutput.Print("RelPos %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
     
     	if (range > owner->maxRange) {
    Index: Sim/Weapons/Weapon.h
    ===================================================================
    --- Sim/Weapons/Weapon.h	(revision 3842)
    +++ Sim/Weapons/Weapon.h	(working copy)
    @@ -60,6 +60,11 @@
     
     	float3 relWeaponPos;				//weaponpos relative to the unit
     	float3 weaponPos;						//absolute weapon pos
    +
    +	float3 relWeaponMuzzlePos;			//position of the firepoint
    +	float3 weaponMuzzlePos;
    +	float3 weaponDir;
    +
     	float muzzleFlareSize;			//size of muzzle flare if drawn
     	int useWeaponPosForAim;			//sometimes weapon pos is better to use than aimpos
     	bool hasCloseTarget;					//might need to update weapon pos more often when enemy is near
    Index: Sim/Weapons/WeaponDefHandler.cpp
    ===================================================================
    --- Sim/Weapons/WeaponDefHandler.cpp	(revision 3842)
    +++ Sim/Weapons/WeaponDefHandler.cpp	(working copy)
    @@ -109,6 +109,7 @@
     
     	sunparser->GetDef(weaponDefs[id].waterweapon, "0", weaponname + "\\waterweapon");
     	sunparser->GetDef(weaponDefs[id].tracks, "0", weaponname + "\\tracks");
    +	sunparser->GetDef(weaponDefs[id].fixedLauncher, "0", weaponname + "\\FixedLauncher");
     	sunparser->GetDef(weaponDefs[id].noExplode, "0", weaponname + "\\NoExplode");
     	sunparser->GetDef(weaponDefs[id].maxvelocity, "0", weaponname + "\\weaponvelocity");
     	sunparser->GetDef(weaponDefs[id].isShield, "0", weaponname + "\\IsShield");
    @@ -243,6 +244,7 @@
     	weaponDefs[id].reload = atof(sunparser->SGetValueDef("1", weaponname + "\\reloadtime").c_str());
     	weaponDefs[id].salvodelay = atof(sunparser->SGetValueDef("0.1", weaponname + "\\burstrate").c_str());
     	sunparser->GetDef(weaponDefs[id].salvosize, "1", weaponname + "\\burst");
    +	sunparser->GetDef(weaponDefs[id].projectilespershot, "1", weaponname + "\\projectiles");
     	weaponDefs[id].maxAngle = atof(sunparser->SGetValueDef("3000", weaponname + "\\tolerance").c_str()) * 180.0f / 0x7fff;
     	weaponDefs[id].restTime = 0.0f;
     	sunparser->GetDef(weaponDefs[id].metalcost, "0", weaponname + "\\metalpershot");
    Index: Sim/Weapons/WeaponDefHandler.h
    ===================================================================
    --- Sim/Weapons/WeaponDefHandler.h	(revision 3842)
    +++ Sim/Weapons/WeaponDefHandler.h	(working copy)
    @@ -72,11 +72,14 @@
     	float energycost;
     	float supplycost;
     
    +	int projectilespershot;
    +
     	int id;
     	int tdfId;	//the id= tag in the tdf
     
     	bool turret;
     	bool onlyForward;
    +	bool fixedLauncher;
     	bool waterweapon;
     	bool tracks;
     	bool dropped;
    
    patch file icon weaponChanges.patch (47,800 bytes) 2007-06-24 21:59 +
  • patch file icon weaponChangesFix1.patch (57,391 bytes) 2007-07-12 18:12 -
    Index: Projectiles/LightingProjectile.cpp
    ===================================================================
    --- Projectiles/LightingProjectile.cpp	(revision 3912)
    +++ Projectiles/LightingProjectile.cpp	(working copy)
    @@ -58,7 +58,7 @@
     	}
     
     	if(weapon){
    -		pos=weapon->weaponPos;
    +		pos=weapon->weaponMuzzlePos;
     	}
     	for(int a=1;a<10;++a)
     		displacements[a]+=(gs->randFloat()-0.5f)*0.3f;
    Index: Projectiles/MissileProjectile.cpp
    ===================================================================
    --- Projectiles/MissileProjectile.cpp	(revision 3912)
    +++ Projectiles/MissileProjectile.cpp	(working copy)
    @@ -120,7 +120,8 @@
     	float h=ground->GetHeight2(pos.x,pos.z);
     	if(h>pos.y && fabs(speed.y)>0.001f)
     		pos-=speed*std::min((float)1,float((h-pos.y)/fabs(speed.y)));
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldDir,owner,false,true,7,Smoke_Time,0.6f,drawTrail);
    +	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;
    @@ -128,7 +129,8 @@
     
     void CMissileProjectile::Collision(CUnit *unit)
     {
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldDir,owner,false,true,7,Smoke_Time,0.6f,drawTrail);
    +	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);
     
    @@ -206,7 +208,7 @@
     
     	age++;
     	numParts++;
    -	if(!(age&7)){
    +	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;
    @@ -233,66 +235,67 @@
     	float color=0.6f;
     	unsigned char col[4];
     
    -	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;
    +	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;//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);
    +			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;
    Index: Projectiles/StarburstProjectile.cpp
    ===================================================================
    --- Projectiles/StarburstProjectile.cpp	(revision 3912)
    +++ Projectiles/StarburstProjectile.cpp	(working copy)
    @@ -110,7 +110,8 @@
     	float h=ground->GetHeight2(pos.x,pos.z);
     	if(h>pos.y)
     		pos+=speed*(h-pos.y)/speed.y;
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
    +	if (weaponDef->visuals.smokeTrail)
    +		SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
     	oldSmokeDir=dir;
     //	helper->Explosion(pos,damages,areaOfEffect,owner);
     	CWeaponProjectile::Collision();
    @@ -119,7 +120,8 @@
     
     void CStarburstProjectile::Collision(CUnit *unit)
     {
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
    +	if (weaponDef->visuals.smokeTrail)
    +		SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
     	oldSmokeDir=dir;
     //	unit->DoDamage(damages,owner);
     //	helper->Explosion(pos,damages,areaOfEffect,owner);
    @@ -145,8 +147,7 @@
     	}
     	if(uptime>0){
     		if(curSpeed<maxSpeed)
    -			curSpeed+=0.1f;
    -		dir=UpVector;
    +			curSpeed+=weaponDef->weaponacceleration;
     		speed=dir*curSpeed;
     	} else if(doturn && ttl>0){
     		float3 dif(targetPos-pos);
    @@ -164,7 +165,7 @@
     		speed=dir*curSpeed;
     	} else if(ttl>0){
     		if(curSpeed<maxSpeed)
    -			curSpeed+=0.1f;
    +			curSpeed+=weaponDef->weaponacceleration;
     		float3 dif(targetPos-pos);
     		dif.Normalize();
     		if(dif.dot(dir)>maxGoodDif){
    @@ -197,7 +198,7 @@
     
     	age++;
     	numParts++;
    -	if(!(age&7)){
    +	if(weaponDef->visuals.smokeTrail && !(age&7)){
     		if(curCallback)
     			curCallback->drawCallbacker=0;
     		curCallback=SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,age==8,false,7,Smoke_Time,0.7f,drawTrail,this);
    @@ -226,65 +227,66 @@
     	unsigned char col[4];
     	unsigned char col2[4];
     
    -	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(oldSmokeDir));
    -		dir2.Normalize();
    -
    -
    -		float a1=(1-float(0)/(Smoke_Time))*255;
    -		a1*=0.7f+fabs(dif.dot(dir));
    -		int alpha=min(255,(int)max(0.f,a1));
    -		col[0]=(unsigned char) (color*alpha);
    -		col[1]=(unsigned char) (color*alpha);
    -		col[2]=(unsigned char) (color*alpha);
    -		col[3]=(unsigned char)alpha;
    -
    -		float a2=(1-float(age2)/(Smoke_Time))*255;
    -		a2*=0.7f+fabs(dif2.dot(oldSmokeDir));
    -		if(age<8)
    -			a2=0;
    -		alpha=min(255,(int)max(0.f,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+oldSmokeDir*dist*0.33f;
    -
    -		for(int a=0;a<numParts;++a){
    -			//float a1=1-float(a)/Smoke_Time;
    -			col[0]=(unsigned char) (color*255);
    -			col[1]=(unsigned char) (color*255);
    -			col[2]=(unsigned char) (color*255);
    -			col[3]=255;//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);
    +	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(oldSmokeDir));
    +			dir2.Normalize();
    +	
    +	
    +			float a1=(1-float(0)/(Smoke_Time))*255;
    +			a1*=0.7f+fabs(dif.dot(dir));
    +			int alpha=min(255,(int)max(0.f,a1));
    +			col[0]=(unsigned char) (color*alpha);
    +			col[1]=(unsigned char) (color*alpha);
    +			col[2]=(unsigned char) (color*alpha);
    +			col[3]=(unsigned char)alpha;
    +	
    +			float a2=(1-float(age2)/(Smoke_Time))*255;
    +			a2*=0.7f+fabs(dif2.dot(oldSmokeDir));
    +			if(age<8)
    +				a2=0;
    +			alpha=min(255,(int)max(0.f,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+oldSmokeDir*dist*0.33f;
    +	
    +			for(int a=0;a<numParts;++a){
    +				//float a1=1-float(a)/Smoke_Time;
    +				col[0]=(unsigned char) (color*255);
    +				col[1]=(unsigned char) (color*255);
    +				col[2]=(unsigned char) (color*255);
    +				col[3]=255;//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);
    +			}
    +	
     		}
    -
    -	}
     	DrawCallback();
     	if(curCallback==0)
     		DrawCallback();
    Index: Projectiles/StarburstProjectile.h
    ===================================================================
    --- Projectiles/StarburstProjectile.h	(revision 3912)
    +++ Projectiles/StarburstProjectile.h	(working copy)
    @@ -27,6 +27,7 @@
     	float3 dir;
     	float maxSpeed;
     	float curSpeed;
    +	float acceleration;
     	int ttl;
     	int uptime;
     	float areaOfEffect;
    Index: Units/COB/CobFile.cpp
    ===================================================================
    --- Units/COB/CobFile.cpp	(revision 3912)
    +++ Units/COB/CobFile.cpp	(working copy)
    @@ -166,7 +166,7 @@
     	}
     
     	//Map common function names to indicies
    -	scriptIndex.resize(COBFN_Last + COB_MaxWeapons * 5);
    +	scriptIndex.resize(COBFN_Last + COB_MaxWeapons * 6);
     	scriptIndex[COBFN_Create] = getFunctionId("Create");
     	scriptIndex[COBFN_StartMoving] = getFunctionId("StartMoving");
     	scriptIndex[COBFN_StopMoving] = getFunctionId("StopMoving");
    @@ -197,6 +197,7 @@
     		scriptIndex[COBFN_AimFromPrimary + i] = getFunctionId("AimFrom" + weapon);
     		scriptIndex[COBFN_FirePrimary + i] = getFunctionId("Fire" + weapon);
     		scriptIndex[COBFN_EndBurst + i] = getFunctionId("EndBurst" + weap);
    +		scriptIndex[COBFN_Shot + i] = getFunctionId("Shot" + weap);
     
     		// If new-naming functions are not found, we need to support the old naming scheme
     		if (i > 2)
    Index: Units/COB/CobFile.h
    ===================================================================
    --- Units/COB/CobFile.h	(revision 3912)
    +++ Units/COB/CobFile.h	(working copy)
    @@ -46,6 +46,7 @@
     const int COBFN_AimFromPrimary = COBFN_AimPrimary + COB_MaxWeapons;
     const int COBFN_FirePrimary = COBFN_AimFromPrimary + COB_MaxWeapons;
     const int COBFN_EndBurst = COBFN_FirePrimary + COB_MaxWeapons;
    +const int COBFN_Shot = COBFN_EndBurst + COB_MaxWeapons;
     
     class CCobFile
     {
    Index: Units/COB/CobInstance.cpp
    ===================================================================
    --- Units/COB/CobInstance.cpp	(revision 3912)
    +++ Units/COB/CobInstance.cpp	(working copy)
    @@ -655,15 +655,15 @@
     				dir.Normalize();
     
     				float3 targetPos = unit->weapons[type-2048]->targetPos;
    -				float3 weaponPos = unit->weapons[type-2048]->weaponPos;
    +				float3 weaponMuzzlePos = unit->weapons[type-2048]->weaponMuzzlePos;
     
     				unit->weapons[type-2048]->targetPos = pos+dir;
    -				unit->weapons[type-2048]->weaponPos = pos;
    +				unit->weapons[type-2048]->weaponMuzzlePos = pos;
     
     				unit->weapons[type-2048]->Fire();
     
     				unit->weapons[type-2048]->targetPos = targetPos;
    -				unit->weapons[type-2048]->weaponPos = weaponPos;
    +				unit->weapons[type-2048]->weaponMuzzlePos = weaponMuzzlePos;
     
     			}
     			else if (type & 4096) {
    Index: Units/UnitTypes/Builder.cpp
    ===================================================================
    --- Units/UnitTypes/Builder.cpp	(revision 3912)
    +++ Units/UnitTypes/Builder.cpp	(working copy)
    @@ -581,9 +581,12 @@
     {
     	float3 wantedDir=(pos-this->pos).Normalize();
     	short int h=GetHeadingFromVector(wantedDir.x,wantedDir.z);
    +	short int p=(short int) (asin(wantedDir.dot(updir))*(32768/PI));
    +	short int pitch=(short int) (asin(frontdir.dot(updir))*(32768/PI));
     
     	std::vector<int> args;
     	args.push_back(short(h-heading));
    +	args.push_back(short(p-pitch));
     	cob->Call("StartBuilding", args);
     
     	int soundIdx = unitDef->sounds.build.getRandomIdx();
    Index: Weapons/BeamLaser.cpp
    ===================================================================
    --- Weapons/BeamLaser.cpp	(revision 3912)
    +++ Weapons/BeamLaser.cpp	(working copy)
    @@ -42,6 +42,7 @@
     {
     	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();
    @@ -84,7 +85,7 @@
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     
     	float length=dir.Length();
     	if(length==0)
    @@ -93,14 +94,14 @@
     	dir/=length;
     
     	if(!onlyForward){		//skip ground col testing for aircrafts
    -		float g=ground->LineGroundCol(weaponPos,pos);
    +		float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     		if(g>0 && g<length*0.9f)
     			return false;
     	}
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -126,7 +127,7 @@
     		if(salvoLeft==salvoSize-1){
     			if(fireSoundId)
     				sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    -			dir=targetPos-weaponPos;
    +			dir=targetPos-weaponMuzzlePos;
     			dir.Normalize();
     			oldDir=dir;
     		} else {
    @@ -150,7 +151,7 @@
     
     	float maxLength=range*rangeMod;
     	float curLength=0;
    -	float3 curPos=weaponPos;
    +	float3 curPos=weaponMuzzlePos;
     	float3 hitPos;
     
     	bool tryAgain=true;
    @@ -218,7 +219,7 @@
     		// Dynamic Damage
     		DamageArray dynDamages;
     		if (weaponDef->dynDamageExp > 0)
    -			dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponPos, curPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
    +			dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponMuzzlePos, curPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
     		helper->Explosion(hitPos, weaponDef->dynDamageExp>0?dynDamages*(intensity*damageMul):weaponDef->damages*(intensity*damageMul), areaOfEffect, weaponDef->edgeEffectiveness, weaponDef->explosionSpeed,owner, true, 1.0f, false, weaponDef->explosionGenerator, hit, dir, weaponDef->id);
     	}
     
    Index: Weapons/Cannon.cpp
    ===================================================================
    --- Weapons/Cannon.cpp	(revision 3912)
    +++ Weapons/Cannon.cpp	(working copy)
    @@ -59,6 +59,8 @@
     	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;
     		float3 diff = targetPos-weaponPos;
     		wantedDir = GetWantedDir(diff);
     		float speed2D = wantedDir.Length2D() * projectileSpeed;
    @@ -94,7 +96,7 @@
     	{
     		return true;
     	}
    -	float3 dif(pos-weaponPos);
    +	float3 dif(pos-weaponMuzzlePos);
     
     	float3 dir(GetWantedDir(dif));
     
    @@ -109,7 +111,7 @@
     	}
     	flatdir/=flatlength;
     
    -	float gc=ground->TrajectoryGroundCol(weaponPos, flatdir, flatlength-10,
    +	float gc=ground->TrajectoryGroundCol(weaponMuzzlePos, flatdir, flatlength-10,
     			dir.y , gs->gravity / (projectileSpeed * projectileSpeed) * 0.5f);
     	if(gc>0) {
     		return false;
    @@ -119,7 +121,7 @@
     	if(gc>0 && gc<length*0.40f)
     		return false;
     */
    -	if(avoidFriendly && helper->TestTrajectoryCone(weaponPos, flatdir,
    +	if(avoidFriendly && helper->TestTrajectoryCone(weaponMuzzlePos, flatdir,
     		flatlength-30, dir.y, gs->gravity /
     		(projectileSpeed * projectileSpeed) * 0.5f,
     		(accuracy+sprayangle) * 0.6f * (1-owner->limExperience * 0.9f) * 0.9f,
    @@ -142,7 +144,7 @@
     
     void CCannon::Fire(void)
     {
    -	float3 diff = targetPos-weaponPos;
    +	float3 diff = targetPos-weaponMuzzlePos;
     	float3 dir=GetWantedDir(diff);
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.9f);
     	dir.Normalize();
    @@ -159,7 +161,7 @@
     	} else {
     		ttl=predict*2;
     	}
    -	SAFE_NEW CExplosiveProjectile(weaponPos,dir*projectileSpeed,owner,weaponDef, ttl,areaOfEffect);
    +	SAFE_NEW CExplosiveProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,weaponDef, ttl,areaOfEffect);
     	//CWeaponProjectile::CreateWeaponProjectile(weaponPos,owner->speed,owner, NULL, float3(0,0,0), weaponDef);
     
     //	SAFE_NEW CSmokeProjectile(weaponPos,dir*0.01f,90,0.1f,0.02f,owner,0.6f);
    @@ -168,8 +170,8 @@
     //	p->maxheat=p->heat;
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    -	if(weaponPos.y<30)
    - 		water->AddExplosion(weaponPos,damages[0]*0.1f,sqrt(damages[0])+80);
    +	if(weaponMuzzlePos.y<30)
    + 		water->AddExplosion(weaponMuzzlePos,damages[0]*0.1f,sqrt(damages[0])+80);
     }
     
     void CCannon::SlowUpdate(void)
    Index: Weapons/DGunWeapon.cpp
    ===================================================================
    --- Weapons/DGunWeapon.cpp	(revision 3912)
    +++ Weapons/DGunWeapon.cpp	(working copy)
    @@ -23,7 +23,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -42,13 +43,13 @@
     	if(onlyForward){
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
     	dir.Normalize();
     
    -	SAFE_NEW CFireBallProjectile(weaponPos,dir*projectileSpeed,owner,0,targetPos,weaponDef);
    +	SAFE_NEW CFireBallProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,0,targetPos,weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume*0.2f);
     }
    Index: Weapons/EmgCannon.cpp
    ===================================================================
    --- Weapons/EmgCannon.cpp	(revision 3912)
    +++ Weapons/EmgCannon.cpp	(working copy)
    @@ -27,7 +27,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -49,21 +50,21 @@
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.5f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.5f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -83,15 +84,16 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType)){		//the taairmovetype cant align itself properly, change back when that is fixed
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
     	dir.Normalize();
     
    -	SAFE_NEW CEmgProjectile(weaponPos,dir*projectileSpeed,owner,weaponDef->visuals.color,weaponDef->intensity,(int)(range/projectileSpeed), weaponDef);
    +	SAFE_NEW CEmgProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,weaponDef->visuals.color,weaponDef->intensity,(int)(range/projectileSpeed), weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
     
     
    +
    Index: Weapons/FlameThrower.cpp
    ===================================================================
    --- Weapons/FlameThrower.cpp	(revision 3912)
    +++ Weapons/FlameThrower.cpp	(working copy)
    @@ -26,12 +26,12 @@
     
     void CFlameThrower::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
     	float3 spread=(gs->randVector()*sprayangle+salvoError)*0.2f;
     	spread-=dir*0.001f;
     
    -	SAFE_NEW CFlameProjectile(weaponPos,dir*projectileSpeed,spread,owner,weaponDef,(int)(range/projectileSpeed*weaponDef->duration));
    +	SAFE_NEW CFlameProjectile(weaponMuzzlePos,dir*projectileSpeed,spread,owner,weaponDef,(int)(range/projectileSpeed*weaponDef->duration));
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    @@ -49,21 +49,21 @@
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner)){
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner)){
     		return false;
     	}
     	return true;
    @@ -73,6 +73,7 @@
     {
     	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;
     		wantedDir=targetPos-weaponPos;
     		wantedDir.Normalize();
     	}
    Index: Weapons/LaserCannon.cpp
    ===================================================================
    --- Weapons/LaserCannon.cpp	(revision 3912)
    +++ Weapons/LaserCannon.cpp	(working copy)
    @@ -29,7 +29,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -51,7 +52,7 @@
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
    @@ -59,14 +60,14 @@
     	dir/=length;
     
     	if(!onlyForward){		//skip ground col testing for aircrafts
    -		float g=ground->LineGroundCol(weaponPos,pos);
    +		float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     		if(g>0 && g<length*0.9f)
     			return false;
     	}
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -83,7 +84,7 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType)){		//the taairmovetype cant align itself properly, change back when that is fixed
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.7f);
    @@ -95,10 +96,11 @@
     		fpsSub=6;
     #endif
     
    -	SAFE_NEW CLaserProjectile(weaponPos, dir*projectileSpeed, owner, weaponDef->duration*weaponDef->maxvelocity, weaponDef->visuals.color, weaponDef->visuals.color2, weaponDef->intensity, weaponDef, (int)((weaponDef->range-fpsSub*4)/weaponDef->projectilespeed)-fpsSub);
    +	SAFE_NEW CLaserProjectile(weaponMuzzlePos, dir*projectileSpeed, owner, weaponDef->duration*weaponDef->maxvelocity, weaponDef->visuals.color, weaponDef->visuals.color2, weaponDef->intensity, weaponDef, (int)((weaponDef->range-fpsSub*4)/weaponDef->projectilespeed)-fpsSub);
     
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
     
     
    +
    Index: Weapons/LightingCannon.cpp
    ===================================================================
    --- Weapons/LightingCannon.cpp	(revision 3912)
    +++ Weapons/LightingCannon.cpp	(working copy)
    @@ -29,6 +29,7 @@
     {
     	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();
    @@ -50,21 +51,21 @@
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -76,14 +77,14 @@
     
     void CLightingCannon::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
     	CUnit* u=0;
    -	float r=helper->TraceRay(weaponPos,dir,range,0,owner,u);
    +	float r=helper->TraceRay(weaponMuzzlePos,dir,range,0,owner,u);
     
     	float3 newDir;
     	CPlasmaRepulser* shieldHit;
    -	float shieldLength=interceptHandler.AddShieldInterceptableBeam(this,weaponPos,dir,range,newDir,shieldHit);
    +	float shieldLength=interceptHandler.AddShieldInterceptableBeam(this,weaponMuzzlePos,dir,range,newDir,shieldHit);
     	if(shieldLength<r){
     		r=shieldLength;
     		}
    @@ -94,11 +95,11 @@
     	// Dynamic Damage
     	DamageArray dynDamages;
     	if (weaponDef->dynDamageExp > 0)
    -		dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponPos, targetPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
    +		dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponMuzzlePos, targetPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
     
    -	helper->Explosion(weaponPos+dir*r,weaponDef->dynDamageExp>0?dynDamages:weaponDef->damages,areaOfEffect,weaponDef->edgeEffectiveness,weaponDef->explosionSpeed,owner,false,0.5f,true,weaponDef->explosionGenerator, u,dir, weaponDef->id);
    +	helper->Explosion(weaponMuzzlePos+dir*r,weaponDef->dynDamageExp>0?dynDamages:weaponDef->damages,areaOfEffect,weaponDef->edgeEffectiveness,weaponDef->explosionSpeed,owner,false,0.5f,true,weaponDef->explosionGenerator, u,dir, weaponDef->id);
     
    -	SAFE_NEW CLightingProjectile(weaponPos,weaponPos+dir*(r+10),owner,color,weaponDef,10,this);
    +	SAFE_NEW CLightingProjectile(weaponMuzzlePos,weaponMuzzlePos+dir*(r+10),owner,color,weaponDef,10,this);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     
    Index: Weapons/MeleeWeapon.cpp
    ===================================================================
    --- Weapons/MeleeWeapon.cpp	(revision 3912)
    +++ Weapons/MeleeWeapon.cpp	(working copy)
    @@ -27,8 +27,16 @@
     
     void CMeleeWeapon::Update()
     {
    +	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();
    -
     }
     
     void CMeleeWeapon::Fire(void)
    Index: Weapons/MissileLauncher.cpp
    ===================================================================
    --- Weapons/MissileLauncher.cpp	(revision 3912)
    +++ Weapons/MissileLauncher.cpp	(working copy)
    @@ -25,7 +25,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			float dist=wantedDir.Length();
     			predict=dist/projectileSpeed;
    @@ -45,12 +46,15 @@
     	if(onlyForward){
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     		if(weaponDef->trajectoryHeight>0){
     			dir.y+=weaponDef->trajectoryHeight;
     			dir.Normalize();
     		}
    +		if (weaponDef->fixedLauncher) {
    +			dir=weaponDir;
    +		}
     	}
     
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
    @@ -60,7 +64,7 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType))
     		startSpeed+=owner->speed;
     
    -	SAFE_NEW CMissileProjectile(weaponPos,startSpeed,owner,areaOfEffect,projectileSpeed,(int)(range/projectileSpeed+25),targetUnit, weaponDef,targetPos);
    +	SAFE_NEW CMissileProjectile(weaponMuzzlePos,startSpeed,owner,areaOfEffect,projectileSpeed,(int)(range/projectileSpeed+25),targetUnit, weaponDef,targetPos);
     	//CWeaponProjectile::CreateWeaponProjectile(weaponPos,startSpeed,owner,targetUnit, float3(0,0,0), weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    @@ -79,7 +83,7 @@
     		if(pos.y<0)
     			return false;
     	}
    -	float3 dir=pos-weaponPos;
    +	float3 dir = pos-weaponMuzzlePos;
     	if(weaponDef->trajectoryHeight>0){	//do a different test depending on if the missile has a high trajectory or not
     		float3 flatdir(dir.x,0,dir.z);
     		dir.Normalize();
    @@ -91,11 +95,11 @@
     		float linear=dir.y+weaponDef->trajectoryHeight;
     		float quadratic=-weaponDef->trajectoryHeight/flatlength;
     
    -		float gc=ground->TrajectoryGroundCol(weaponPos,flatdir,flatlength-30,linear,quadratic);
    +		float gc=ground->TrajectoryGroundCol(weaponMuzzlePos,flatdir,flatlength-30,linear,quadratic);
     		if(gc>0)
     			return false;
     
    -		if(avoidFriendly && helper->TestTrajectoryCone(weaponPos,flatdir,flatlength-30,linear,quadratic,0,8,owner->allyteam,owner)){
    +		if(avoidFriendly && helper->TestTrajectoryCone(weaponMuzzlePos,flatdir,flatlength-30,linear,quadratic,0,8,owner->allyteam,owner)){
     			return false;
     		}
     	} else {
    @@ -106,7 +110,7 @@
     		dir/=length;
     
     		if(!onlyForward){		//skip ground col testing for aircrafts
    -			float g=ground->LineGroundCol(weaponPos,pos);
    +			float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     			if(g>0 && g<length*0.9f)
     				return false;
     		} else {
    @@ -115,7 +119,7 @@
     			if(owner->frontdir.dot(goaldir) < maxAngleDif)
     				return false;
     		}
    -		if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
    +		if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
     			return false;
     	}
     	return true;
    Index: Weapons/Rifle.cpp
    ===================================================================
    --- Weapons/Rifle.cpp	(revision 3912)
    +++ Weapons/Rifle.cpp	(working copy)
    @@ -37,6 +37,7 @@
     {
     	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;
     		wantedDir=targetPos-weaponPos;
     		wantedDir.Normalize();
     	}
    @@ -56,18 +57,18 @@
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.9f),owner->allyteam,owner)){
    +	if(helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.9f),owner->allyteam,owner)){
     		return false;
     	}
     	return true;
    @@ -75,7 +76,7 @@
     
     void CRifle::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.9f);
     	dir.Normalize();
    @@ -84,13 +85,13 @@
     	tracefile << owner->pos.x << " " << dir.x << " " << targetPos.x << " " << targetPos.y << " " << targetPos.z << "\n";
     #endif
     	CUnit* hit;
    -	float length=helper->TraceRay(weaponPos,dir,range,damages[0],owner,hit);
    +	float length=helper->TraceRay(weaponMuzzlePos,dir,range,damages[0],owner,hit);
     	if(hit){
     		hit->DoDamage(damages,owner,ZeroVector, weaponDef->id);
    -		SAFE_NEW CHeatCloudProjectile(weaponPos+dir*length,hit->speed*0.9f,30,1,owner);
    +		SAFE_NEW CHeatCloudProjectile(weaponMuzzlePos+dir*length,hit->speed*0.9f,30,1,owner);
     	}
    -	SAFE_NEW CTracerProjectile(weaponPos,dir*projectileSpeed,length,owner);
    -	SAFE_NEW CSmokeProjectile(weaponPos,float3(0,0.0f,0),70,0.1f,0.02f,owner,0.6f);
    +	SAFE_NEW CTracerProjectile(weaponMuzzlePos,dir*projectileSpeed,length,owner);
    +	SAFE_NEW CSmokeProjectile(weaponMuzzlePos,float3(0,0.0f,0),70,0.1f,0.02f,owner,0.6f);
     	if(fireSoundId)
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    Index: Weapons/StarburstLauncher.cpp
    ===================================================================
    --- Weapons/StarburstLauncher.cpp	(revision 3912)
    +++ Weapons/StarburstLauncher.cpp	(working copy)
    @@ -30,6 +30,7 @@
     {
     	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;
     		wantedDir=(targetPos-weaponPos).Normalize();		//the aiming upward is apperently implicid so aim toward target
     	}
     	CWeapon::Update();
    @@ -37,7 +38,11 @@
     
     void CStarburstLauncher::Fire(void)
     {
    -	CStarburstProjectile* p=SAFE_NEW CStarburstProjectile(weaponPos+float3(0,2,0),float3(0,0.01f,0),owner,targetPos,areaOfEffect,projectileSpeed,tracking,(int)uptime,targetUnit, weaponDef,interceptTarget);
    +	float3 speed(0,weaponDef->startvelocity,0);
    +	if(weaponDef->fixedLauncher) {
    +		speed=weaponDir * weaponDef->startvelocity;
    +	}
    +	CStarburstProjectile* p=SAFE_NEW CStarburstProjectile(weaponMuzzlePos+float3(0,2,0),speed,owner,targetPos,areaOfEffect,projectileSpeed,tracking,(int)uptime,targetUnit, weaponDef,interceptTarget);
     
     	if(weaponDef->targetable)
     		interceptHandler.AddInterceptTarget(p,targetPos);
    @@ -59,8 +64,12 @@
     			return false;
     	}
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,UpVector,100,0,owner->allyteam,owner))
    -		return false;
    +	if(!weaponDef->fixedLauncher)
    +		if(avoidFriendly && helper->TestCone(weaponMuzzlePos,UpVector,100,0,owner->allyteam,owner))
    +			return false;
    +	else
    +		if(avoidFriendly && helper->TestCone(weaponMuzzlePos,weaponDir,100,0,owner->allyteam,owner))
    +			return false;
     
     	return true;
     }
    Index: Weapons/TorpedoLauncher.cpp
    ===================================================================
    --- Weapons/TorpedoLauncher.cpp	(revision 3912)
    +++ Weapons/TorpedoLauncher.cpp	(working copy)
    @@ -30,7 +30,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -//		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +//		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			float dist=wantedDir.Length();
     			predict=dist/projectileSpeed;
    @@ -46,7 +47,7 @@
     //	if(onlyForward){
     //		dir=owner->frontdir;
     //	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     		if(weaponDef->trajectoryHeight>0){
     			dir.y+=weaponDef->trajectoryHeight;
    @@ -57,7 +58,7 @@
     
     //	if(onlyForward)
     //		startSpeed+=owner->speed*0.5f;
    -	SAFE_NEW CTorpedoProjectile(weaponPos,startSpeed,owner,areaOfEffect,projectileSpeed,tracking,(int)(range/projectileSpeed+15),targetUnit, weaponDef);
    +	SAFE_NEW CTorpedoProjectile(weaponMuzzlePos,startSpeed,owner,areaOfEffect,projectileSpeed,tracking,(int)(range/projectileSpeed+15),targetUnit, weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    @@ -76,14 +77,14 @@
     	if(ground->GetHeight2(pos.x,pos.z)>0)
     		return 0;
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)+0.05f,owner->allyteam,owner))	//+0.05f since torpedoes has an unfortunate tendency to hit own ships due to movement
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)+0.05f,owner->allyteam,owner))	//+0.05f since torpedoes has an unfortunate tendency to hit own ships due to movement
     		return false;
     	return true;
     }
    Index: Weapons/Weapon.cpp
    ===================================================================
    --- Weapons/Weapon.cpp	(revision 3912)
    +++ Weapons/Weapon.cpp	(working copy)
    @@ -56,9 +56,11 @@
     	CR_MEMBER(subClassReady),
     	CR_MEMBER(onlyForward),
     	CR_MEMBER(weaponPos),
    +	CR_MEMBER(weaponMuzzlePos),
     	CR_MEMBER(lastRequest),
     	CR_MEMBER(damages),
     	CR_MEMBER(relWeaponPos),
    +	CR_MEMBER(relWeaponMuzzlePos),
     	CR_MEMBER(muzzleFlareSize),
     	CR_MEMBER(lastTargetRetry),
     	CR_MEMBER(areaOfEffect),
    @@ -130,8 +132,10 @@
     	subClassReady(true),
     	onlyForward(false),
     	weaponPos(0,0,0),
    +	weaponMuzzlePos(0,0,0),
     	lastRequest(0),
     	relWeaponPos(0,1,0),
    +	relWeaponMuzzlePos(0,1,0),
     	muzzleFlareSize(1),
     	lastTargetRetry(-100),
     	areaOfEffect(1),
    @@ -173,12 +177,11 @@
     	if(hasCloseTarget){
     		std::vector<int> args;
     		args.push_back(0);
    -		if(useWeaponPosForAim){
    -			owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    -		} else {
    -			owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
    -		}
    +		owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     		relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
    +
    +		owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    +		relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
     	}
     
     	if(targetType==Target_Unit){
    @@ -255,16 +258,18 @@
     	&& subClassReady
     	&& reloadStatus<=gs->frameNum
     	&& (!weaponDef->stockpile || numStockpiled)
    -	&& (weaponDef->waterweapon || weaponPos.y>0)
    +	&& (weaponDef->waterweapon || weaponMuzzlePos.y>0)
     	&& (owner->unitDef->maxFuel==0 || owner->currentFuel > 0)
     	){
     		if ((weaponDef->stockpile || (gs->Team(owner->team)->metal>=metalFireCost && gs->Team(owner->team)->energy>=energyFireCost))) {
     			std::vector<int> args;
     			args.push_back(0);
     			owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    -			relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
    -			weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +			owner->localmodel->GetEmitDirPos(args[0], relWeaponMuzzlePos, weaponDir);
    +			weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
     			useWeaponPosForAim=reloadTime/16+8;
    +			weaponDir = owner->frontdir * weaponDir.z + owner->updir * weaponDir.y + owner->rightdir * weaponDir.x;
    +			weaponDir.Normalize();
     
     			if(TryTarget(targetPos,haveUserTarget,targetUnit)){
     				if(weaponDef->stockpile){
    @@ -300,35 +305,52 @@
     			}
     		}
     	}
    -	if(salvoLeft && nextSalvo<=gs->frameNum){
    +	if(salvoLeft && nextSalvo<=gs->frameNum ){
     		salvoLeft--;
     		nextSalvo=gs->frameNum+salvoDelay;
     		owner->lastFireWeapon=gs->frameNum;
    +		
    +		int projectiles = weaponDef->projectilespershot;
    +		
    +		while(projectiles > 0) {
    +			--projectiles;
    +			
    +			// add to the commandShotCount if this is the last salvo,
    +			// and it is being directed towards the current target
    +			// (helps when deciding if a queued ground attack order has been completed)
    +			if ((salvoLeft == 0) && (owner->commandShotCount >= 0) &&
    +			    ((targetType == Target_Pos) && (targetPos == owner->userAttackPos)) ||
    +					((targetType == Target_Unit) && (targetUnit == owner->userTarget))) {
    +				owner->commandShotCount++;
    +			}
    +	
    +			std::vector<int> args;
    +			args.push_back(0);
    +	
    +			owner->cob->Call(COBFN_Shot+weaponNum,0);
    +	
    +			owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
    +			relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     
    -		// add to the commandShotCount if this is the last salvo,
    -		// and it is being directed towards the current target
    -		// (helps when deciding if a queued ground attack order has been completed)
    -		if ((salvoLeft == 0) && (owner->commandShotCount >= 0) &&
    -		    ((targetType == Target_Pos) && (targetPos == owner->userAttackPos)) ||
    -				((targetType == Target_Unit) && (targetUnit == owner->userTarget))) {
    -			owner->commandShotCount++;
    -		}
    +			owner->cob->Call(/*COBFN_AimFromPrimary+weaponNum*/COBFN_QueryPrimary+weaponNum/**/,args);
    +			owner->localmodel->GetEmitDirPos(args[0], relWeaponMuzzlePos, weaponDir);
     
    -		std::vector<int> args;
    -		args.push_back(0);
    -		owner->cob->Call(/*COBFN_AimFromPrimary+weaponNum/*/COBFN_QueryPrimary+weaponNum/**/,args);
    -		relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
    -		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +			weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
     
    -//		logOutput.Print("RelPosFire %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
    -
    -		if (owner->unitDef->decloakOnFire && (owner->scriptCloak <= 2)) {
    -			owner->isCloaked = false;
    -			owner->curCloakTimeout = gs->frameNum + owner->cloakTimeout;
    +			weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +			weaponDir = owner->frontdir * weaponDir.z + owner->updir * weaponDir.y + owner->rightdir * weaponDir.x;
    +			weaponDir.Normalize();
    +	
    +	//		logOutput.Print("RelPosFire %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
    +	
    +			if (owner->unitDef->decloakOnFire && (owner->scriptCloak <= 2)) {
    +				owner->isCloaked = false;
    +				owner->curCloakTimeout = gs->frameNum + owner->cloakTimeout;
    +			}
    +	
    +			Fire();
     		}
     
    -		Fire();
    -
     		//Rock the unit in the direction of the fireing
     		float3 rockDir = wantedDir;
     		rockDir.y = 0;
    @@ -359,9 +381,9 @@
     
     	if(!weaponDef->waterweapon && pos.y<1)
     		pos.y=1;
    -	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -	if(weaponPos.y<ground->GetHeight2(weaponPos.x,weaponPos.z))
    -		weaponPos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +	if(weaponMuzzlePos.y<ground->GetHeight2(weaponMuzzlePos.x,weaponMuzzlePos.z))
    +		weaponMuzzlePos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
     
     	if(!TryTarget(pos,userTarget,0))
     		return false;
    @@ -384,8 +406,10 @@
     
     	weaponPos= owner->pos + owner->frontdir * relWeaponPos.z
     		+ owner->updir * relWeaponPos.y + owner->rightdir * relWeaponPos.x;
    -	if(weaponPos.y < ground->GetHeight2(weaponPos.x, weaponPos.z))
    -		weaponPos = owner->pos + UpVector * 10;
    +	weaponMuzzlePos= owner->pos + owner->frontdir * relWeaponMuzzlePos.z
    +		+ owner->updir * relWeaponMuzzlePos.y + owner->rightdir * relWeaponMuzzlePos.x;
    +	if(weaponMuzzlePos.y < ground->GetHeight2(weaponMuzzlePos.x, weaponMuzzlePos.z))
    +		weaponMuzzlePos = owner->pos + UpVector * 10;
     	//hope that we are underground because we are a popup weapon and will come above ground later
     
     	if(!unit){
    @@ -433,18 +457,17 @@
     #endif
     	std::vector<int> args;
     	args.push_back(0);
    -	if(useWeaponPosForAim){
    -		owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    -		if(useWeaponPosForAim>1)
    -			useWeaponPosForAim--;
    -	} else {
    -		owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
    -	}
    +	owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     	relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -	if(weaponPos.y<ground->GetHeight2(weaponPos.x,weaponPos.z))
    -		weaponPos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
     
    +	owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    +	relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +
    +	if(weaponMuzzlePos.y<ground->GetHeight2(weaponMuzzlePos.x,weaponMuzzlePos.z))
    +		weaponMuzzlePos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
    +
     	predictSpeedMod=1+(gs->randFloat()-0.5f)*2*(1-owner->limExperience);
     
     	if((targetPos-weaponPos).SqLength() < relWeaponPos.SqLength()*16)
    @@ -548,7 +571,7 @@
     	if(weaponDef->stockpile && !numStockpiled)
     		return false;
     
    -	float3 dif=pos-weaponPos;
    +	float3 dif=pos-weaponMuzzlePos;
     
     	if (targetBorder != 0 && unit) {
     		float3 diff(dif);
    @@ -616,11 +639,13 @@
     	owner->frontdir = GetVectorFromHeading(owner->heading);
     	owner->rightdir = owner->frontdir.cross(owner->updir);
     	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;
     	bool val = TryTarget(tempTargetPos,userTarget,unit);
     	owner->frontdir = tempfrontdir;
     	owner->rightdir = temprightdir;
     	owner->heading = tempHeadding;
     	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;
     	return val;
     }
     
    @@ -646,11 +671,13 @@
     	owner->frontdir = GetVectorFromHeading(owner->heading);
     	owner->rightdir = owner->frontdir.cross(owner->updir);
     	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;
     	bool val = TryTarget(pos, userTarget, 0);
     	owner->frontdir = tempfrontdir;
     	owner->rightdir = temprightdir;
     	owner->heading = tempHeadding;
     	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;
     	return val;
     }
     
    @@ -661,6 +688,10 @@
     	owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     	relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +
    +	owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    +	relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
     //	logOutput.Print("RelPos %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
     
     	if (range > owner->maxRange) {
    Index: Weapons/Weapon.h
    ===================================================================
    --- Weapons/Weapon.h	(revision 3912)
    +++ Weapons/Weapon.h	(working copy)
    @@ -60,6 +60,11 @@
     
     	float3 relWeaponPos;				//weaponpos relative to the unit
     	float3 weaponPos;						//absolute weapon pos
    +
    +	float3 relWeaponMuzzlePos;			//position of the firepoint
    +	float3 weaponMuzzlePos;
    +	float3 weaponDir;
    +
     	float muzzleFlareSize;			//size of muzzle flare if drawn
     	int useWeaponPosForAim;			//sometimes weapon pos is better to use than aimpos
     	bool hasCloseTarget;					//might need to update weapon pos more often when enemy is near
    Index: Weapons/WeaponDefHandler.cpp
    ===================================================================
    --- Weapons/WeaponDefHandler.cpp	(revision 3912)
    +++ Weapons/WeaponDefHandler.cpp	(working copy)
    @@ -111,6 +111,7 @@
     
     	sunparser->GetDef(weaponDefs[id].waterweapon, "0", weaponname + "\\waterweapon");
     	sunparser->GetDef(weaponDefs[id].tracks, "0", weaponname + "\\tracks");
    +	sunparser->GetDef(weaponDefs[id].fixedLauncher, "0", weaponname + "\\FixedLauncher");
     	sunparser->GetDef(weaponDefs[id].noExplode, "0", weaponname + "\\NoExplode");
     	sunparser->GetDef(weaponDefs[id].maxvelocity, "0", weaponname + "\\weaponvelocity");
     	sunparser->GetDef(weaponDefs[id].isShield, "0", weaponname + "\\IsShield");
    @@ -256,6 +257,7 @@
     	weaponDefs[id].reload = atof(sunparser->SGetValueDef("1", weaponname + "\\reloadtime").c_str());
     	weaponDefs[id].salvodelay = atof(sunparser->SGetValueDef("0.1", weaponname + "\\burstrate").c_str());
     	sunparser->GetDef(weaponDefs[id].salvosize, "1", weaponname + "\\burst");
    +	sunparser->GetDef(weaponDefs[id].projectilespershot, "1", weaponname + "\\projectiles");
     	weaponDefs[id].maxAngle = atof(sunparser->SGetValueDef("3000", weaponname + "\\tolerance").c_str()) * 180.0f / 0x7fff;
     	weaponDefs[id].restTime = 0.0f;
     	sunparser->GetDef(weaponDefs[id].metalcost, "0", weaponname + "\\metalpershot");
    Index: Weapons/WeaponDefHandler.h
    ===================================================================
    --- Weapons/WeaponDefHandler.h	(revision 3912)
    +++ Weapons/WeaponDefHandler.h	(working copy)
    @@ -72,11 +72,14 @@
     	float energycost;
     	float supplycost;
     
    +	int projectilespershot;
    +
     	int id;
     	int tdfId;	//the id= tag in the tdf
     
     	bool turret;
     	bool onlyForward;
    +	bool fixedLauncher;
     	bool waterweapon;
     	bool tracks;
     	bool dropped;
    
    patch file icon weaponChangesFix1.patch (57,391 bytes) 2007-07-12 18:12 +
  • patch file icon evenMoreWeaponChanges.patch (78,478 bytes) 2007-07-20 17:12 -
    Index: Sim/Projectiles/EmgProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/EmgProjectile.cpp	(revision 4026)
    +++ Sim/Projectiles/EmgProjectile.cpp	(working copy)
    @@ -4,6 +4,7 @@
     #include "Rendering/GL/VertexArray.h"
     #include "Sync/SyncTracer.h"
     #include "ProjectileHandler.h"
    +#include "Map/Ground.h"
     #include "Sim/Weapons/WeaponDefHandler.h"
     #include "mmgr.h"
     
    @@ -52,10 +53,14 @@
     void CEmgProjectile::Collision(CUnit* unit)
     {
     //	unit->DoDamage(damages,owner);
    -
     	CWeaponProjectile::Collision(unit);
     }
     
    +void CEmgProjectile::Collision() {
    +	if (!(weaponDef->waterweapon && ground->GetHeight2(pos.x, pos.z) < pos.y))
    +		CWeaponProjectile::Collision();
    +}
    +
     void CEmgProjectile::Draw(void)
     {
     	inArray=true;
    Index: Sim/Projectiles/EmgProjectile.h
    ===================================================================
    --- Sim/Projectiles/EmgProjectile.h	(revision 4026)
    +++ Sim/Projectiles/EmgProjectile.h	(working copy)
    @@ -14,6 +14,7 @@
     	void Update(void);
     	void Draw(void);
     	void Collision(CUnit* unit);
    +	void Collision();
     	int ShieldRepulse(CPlasmaRepulser* shield,float3 shieldPos, float shieldForce, float shieldMaxSpeed);
     
     	int ttl;
    Index: Sim/Projectiles/ExplosiveProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/ExplosiveProjectile.cpp	(revision 4026)
    +++ Sim/Projectiles/ExplosiveProjectile.cpp	(working copy)
    @@ -18,18 +18,20 @@
     
     CR_REG_METADATA(CExplosiveProjectile, (
     	CR_MEMBER(ttl),
    -	CR_MEMBER(areaOfEffect)
    +	CR_MEMBER(areaOfEffect),
    +	CR_MEMBER(gravity)
     	));
     
     //////////////////////////////////////////////////////////////////////
     // Construction/Destruction
     //////////////////////////////////////////////////////////////////////
     
    -CExplosiveProjectile::CExplosiveProjectile(const float3& pos,const float3& speed,CUnit* owner, WeaponDef *weaponDef, int ttl,float areaOfEffect)
    +CExplosiveProjectile::CExplosiveProjectile(const float3& pos,const float3& speed,CUnit* owner, WeaponDef *weaponDef, int ttl,float areaOfEffect, float gravity)
     : CWeaponProjectile(pos,speed,owner, 0,ZeroVector,weaponDef,0, true),
     	ttl(ttl),
     	areaOfEffect(areaOfEffect),
    -	curTime(0)
    +	curTime(0),
    +	gravity(gravity)
     {
     	useAirLos=true;
     
    @@ -53,7 +55,7 @@
     void CExplosiveProjectile::Update()
     {
     	pos+=speed;
    -	speed.y+=gs->gravity;
    +	speed.y+=gravity;
     
     	if(!--ttl)
     		Collision();
    @@ -75,6 +77,9 @@
     			float3 n=ground->GetNormal(pos.x,pos.z);
     			pos-=speed*max(0.0f,min(1.0f,float((h-pos.y)*n.y/n.dot(speed)+0.1f)));
     		}
    +		else if (weaponDef->waterweapon) {
    +			return; //let waterweapons go underwater
    +		}
     	}
     //	helper->Explosion(pos,damages,areaOfEffect,owner);
     	CWeaponProjectile::Collision();
    Index: Sim/Projectiles/ExplosiveProjectile.h
    ===================================================================
    --- Sim/Projectiles/ExplosiveProjectile.h	(revision 4026)
    +++ Sim/Projectiles/ExplosiveProjectile.h	(working copy)
    @@ -12,7 +12,7 @@
     {
     	CR_DECLARE(CExplosiveProjectile);
     public:
    -	CExplosiveProjectile(const float3& pos,const float3& speed,CUnit* owner, WeaponDef *weaponDef, int ttl=100000,float areaOfEffect=8);
    +	CExplosiveProjectile(const float3& pos,const float3& speed,CUnit* owner, WeaponDef *weaponDef, int ttl=100000,float areaOfEffect=8,float gravity=0);
     	virtual ~CExplosiveProjectile();
     	virtual void Update();
     	void Draw(void);
    @@ -24,6 +24,7 @@
     	float areaOfEffect;
     	float invttl;
     	float curTime;
    +	float gravity;
     };
     
     #endif // __EXPLOSIVE_PROJECTILE_H__
    Index: Sim/Projectiles/FireBallProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/FireBallProjectile.cpp	(revision 4026)
    +++ Sim/Projectiles/FireBallProjectile.cpp	(working copy)
    @@ -3,6 +3,7 @@
     #include "Rendering/GL/VertexArray.h"
     #include "Game/Camera.h"
     #include "Sim/Weapons/WeaponDefHandler.h"
    +#include "Map/Ground.h"
     #include "creg/STL_Deque.h"
     #include "ProjectileHandler.h"
     #include "mmgr.h"
    @@ -125,6 +126,7 @@
     
     void CFireBallProjectile::Collision()
     {
    +	if(weaponDef->waterweapon && ground->GetHeight2(pos.x, pos.z)<pos.y) return; //make waterweapons not explode in water
     	CWeaponProjectile::Collision();
     	deleteMe = false;
     }
    Index: Sim/Projectiles/FlameProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/FlameProjectile.cpp	(revision 4026)
    +++ Sim/Projectiles/FlameProjectile.cpp	(working copy)
    @@ -44,6 +44,7 @@
     
     void CFlameProjectile::Collision(void)
     {
    +	if(ground->GetHeight2(pos.x, pos.z) < pos.y && weaponDef->waterweapon) return; //prevent waterweapons from colliding with water
     	float3 norm=ground->GetNormal(pos.x,pos.z);
     	float ns=speed.dot(norm);
     	speed-=norm*ns*1;
    Index: Sim/Projectiles/LaserProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/LaserProjectile.cpp	(revision 4026)
    +++ Sim/Projectiles/LaserProjectile.cpp	(working copy)
    @@ -7,6 +7,7 @@
     #include "ProjectileHandler.h"
     #include "SimpleParticleSystem.h"
     #include "mmgr.h"
    +#include "Map/Ground.h"
     
     CR_BIND_DERIVED(CLaserProjectile, CWeaponProjectile, (float3(0,0,0),float3(0,0,0),NULL,0,float3(0,0,0),float3(0,0,0),0,NULL,0));
     
    @@ -104,6 +105,8 @@
     
     void CLaserProjectile::Collision()
     {
    +	if(weaponDef->waterweapon && ground->GetHeight2(pos.x,pos.z) < pos.y) 
    +		return; //prevent impact on water if waterweapon is set
     	float3 oldPos=pos;
     	CWeaponProjectile::Collision();
     
    Index: Sim/Projectiles/LightingProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/LightingProjectile.cpp	(revision 4026)
    +++ Sim/Projectiles/LightingProjectile.cpp	(working copy)
    @@ -59,7 +59,7 @@
     	}
     
     	if(weapon){
    -		pos=weapon->weaponPos;
    +		pos=weapon->weaponMuzzlePos;
     	}
     	for(int a=1;a<10;++a)
     		displacements[a]+=(gs->randFloat()-0.5f)*0.3f;
    Index: Sim/Projectiles/MissileProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/MissileProjectile.cpp	(revision 4026)
    +++ Sim/Projectiles/MissileProjectile.cpp	(working copy)
    @@ -119,9 +119,11 @@
     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)));
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldDir,owner,false,true,7,Smoke_Time,0.6f,drawTrail);
    +	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;
    @@ -129,7 +131,8 @@
     
     void CMissileProjectile::Collision(CUnit *unit)
     {
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldDir,owner,false,true,7,Smoke_Time,0.6f,drawTrail);
    +	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);
     
    @@ -207,7 +210,7 @@
     
     	age++;
     	numParts++;
    -	if(!(age&7)){
    +	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;
    @@ -234,66 +237,67 @@
     	float color=0.6f;
     	unsigned char col[4];
     
    -	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;
    +	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;//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);
    +			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;
    Index: Sim/Projectiles/StarburstProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/StarburstProjectile.cpp	(revision 4026)
    +++ Sim/Projectiles/StarburstProjectile.cpp	(working copy)
    @@ -65,7 +65,12 @@
     	areaOfEffect(areaOfEffect)
     {
     	this->uptime=uptime;
    -	ttl=(int)min(3000.f,uptime+(weaponDef?weaponDef->range:0)/maxSpeed+100);
    +	if (weaponDef->flighttime == 0) {
    +		ttl=(int)min(3000.f,uptime+(weaponDef?weaponDef->range:0)/maxSpeed+100);
    +	}
    +	else {
    +		ttl=weaponDef->flighttime;
    +	}
     
     	maxGoodDif=cos(tracking*0.6f);
     	curSpeed=speed.Length();
    @@ -109,9 +114,11 @@
     void CStarburstProjectile::Collision()
     {
     	float h=ground->GetHeight2(pos.x,pos.z);
    +	if(weaponDef->waterweapon && h < pos.y) return; //prevent impact on water if waterweapon is set
     	if(h>pos.y)
     		pos+=speed*(h-pos.y)/speed.y;
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
    +	if (weaponDef->visuals.smokeTrail)
    +		SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
     	oldSmokeDir=dir;
     //	helper->Explosion(pos,damages,areaOfEffect,owner);
     	CWeaponProjectile::Collision();
    @@ -120,7 +127,8 @@
     
     void CStarburstProjectile::Collision(CUnit *unit)
     {
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
    +	if (weaponDef->visuals.smokeTrail)
    +		SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
     	oldSmokeDir=dir;
     //	unit->DoDamage(damages,owner);
     //	helper->Explosion(pos,damages,areaOfEffect,owner);
    @@ -146,8 +154,7 @@
     	}
     	if(uptime>0){
     		if(curSpeed<maxSpeed)
    -			curSpeed+=0.1f;
    -		dir=UpVector;
    +			curSpeed+=weaponDef->weaponacceleration;
     		speed=dir*curSpeed;
     	} else if(doturn && ttl>0){
     		float3 dif(targetPos-pos);
    @@ -159,13 +166,18 @@
     			dif=dif-dir;
     			dif-=dir*(dif.dot(dir));
     			dif.Normalize();
    -			dir+=dif*0.06f;
    +			if (weaponDef->turnrate != 0) {
    +				dir+=dif*weaponDef->turnrate;
    +			}
    +			else {
    +				dir+=dif*0.06;
    +			}
     			dir.Normalize();
     		}
     		speed=dir*curSpeed;
     	} else if(ttl>0){
     		if(curSpeed<maxSpeed)
    -			curSpeed+=0.1f;
    +			curSpeed+=weaponDef->weaponacceleration;
     		float3 dif(targetPos-pos);
     		dif.Normalize();
     		if(dif.dot(dir)>maxGoodDif){
    @@ -198,7 +210,7 @@
     
     	age++;
     	numParts++;
    -	if(!(age&7)){
    +	if(weaponDef->visuals.smokeTrail && !(age&7)){
     		if(curCallback)
     			curCallback->drawCallbacker=0;
     		curCallback=SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,age==8,false,7,Smoke_Time,0.7f,drawTrail,this);
    @@ -227,65 +239,66 @@
     	unsigned char col[4];
     	unsigned char col2[4];
     
    -	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(oldSmokeDir));
    -		dir2.Normalize();
    -
    -
    -		float a1=(1-float(0)/(Smoke_Time))*255;
    -		a1*=0.7f+fabs(dif.dot(dir));
    -		int alpha=min(255,(int)max(0.f,a1));
    -		col[0]=(unsigned char) (color*alpha);
    -		col[1]=(unsigned char) (color*alpha);
    -		col[2]=(unsigned char) (color*alpha);
    -		col[3]=(unsigned char)alpha;
    -
    -		float a2=(1-float(age2)/(Smoke_Time))*255;
    -		a2*=0.7f+fabs(dif2.dot(oldSmokeDir));
    -		if(age<8)
    -			a2=0;
    -		alpha=min(255,(int)max(0.f,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+oldSmokeDir*dist*0.33f;
    -
    -		for(int a=0;a<numParts;++a){
    -			//float a1=1-float(a)/Smoke_Time;
    -			col[0]=(unsigned char) (color*255);
    -			col[1]=(unsigned char) (color*255);
    -			col[2]=(unsigned char) (color*255);
    -			col[3]=255;//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);
    +	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(oldSmokeDir));
    +			dir2.Normalize();
    +	
    +	
    +			float a1=(1-float(0)/(Smoke_Time))*255;
    +			a1*=0.7f+fabs(dif.dot(dir));
    +			int alpha=min(255,(int)max(0.f,a1));
    +			col[0]=(unsigned char) (color*alpha);
    +			col[1]=(unsigned char) (color*alpha);
    +			col[2]=(unsigned char) (color*alpha);
    +			col[3]=(unsigned char)alpha;
    +	
    +			float a2=(1-float(age2)/(Smoke_Time))*255;
    +			a2*=0.7f+fabs(dif2.dot(oldSmokeDir));
    +			if(age<8)
    +				a2=0;
    +			alpha=min(255,(int)max(0.f,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+oldSmokeDir*dist*0.33f;
    +	
    +			for(int a=0;a<numParts;++a){
    +				//float a1=1-float(a)/Smoke_Time;
    +				col[0]=(unsigned char) (color*255);
    +				col[1]=(unsigned char) (color*255);
    +				col[2]=(unsigned char) (color*255);
    +				col[3]=255;//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);
    +			}
    +	
     		}
    -
    -	}
     	DrawCallback();
     	if(curCallback==0)
     		DrawCallback();
    Index: Sim/Projectiles/StarburstProjectile.h
    ===================================================================
    --- Sim/Projectiles/StarburstProjectile.h	(revision 4026)
    +++ Sim/Projectiles/StarburstProjectile.h	(working copy)
    @@ -27,6 +27,7 @@
     	float3 dir;
     	float maxSpeed;
     	float curSpeed;
    +	float acceleration;
     	int ttl;
     	int uptime;
     	float areaOfEffect;
    Index: Sim/Projectiles/TorpedoProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/TorpedoProjectile.cpp	(revision 4026)
    +++ Sim/Projectiles/TorpedoProjectile.cpp	(working copy)
    @@ -10,6 +10,7 @@
     #include "BubbleProjectile.h"
     #include "ProjectileHandler.h"
     #include "mmgr.h"
    +#include "Sim/Weapons/WeaponDefHandler.h"
     
     CR_BIND_DERIVED(CTorpedoProjectile, CTorpedoProjectile, (float3(0,0,0),float3(0,0,0),NULL,0,0,0,0,NULL,NULL));
     
    @@ -82,14 +83,14 @@
     
     void CTorpedoProjectile::Update(void)
     {
    -	if(pos.y>-3){		//tracking etc only work when we have gotten underwater
    +	if(!(weaponDef->submissile) && pos.y>-3){		//tracking etc only work when we have gotten underwater
     		speed.y+=gs->gravity;
     		if(dir.y>0)
     			dir.y=0;
     		dir=speed;
     		dir.Normalize();
     	} else {
    -		if(pos.y-speed.y>-3){		//level out torpedo a bit when hitting water
    +		if(!(weaponDef->submissile) && pos.y-speed.y>-3){		//level out torpedo a bit when hitting water
     			dir.y*=0.5f;
     			dir.Normalize();
     		}
    @@ -103,7 +104,7 @@
     					targPos=target->midPos;
     				else
     					targPos=helper->GetUnitErrorPos(target,owner->allyteam);
    -				if(targPos.y>0)
    +				if(!(weaponDef->submissile) && targPos.y>0)
     					targPos.y=0;
     
     				float dist=targPos.distance(pos);
    Index: Sim/Units/COB/CobFile.cpp
    ===================================================================
    --- Sim/Units/COB/CobFile.cpp	(revision 4026)
    +++ Sim/Units/COB/CobFile.cpp	(working copy)
    @@ -166,7 +166,7 @@
     	}
     
     	//Map common function names to indicies
    -	scriptIndex.resize(COBFN_Last + COB_MaxWeapons * 5);
    +	scriptIndex.resize(COBFN_Last + COB_MaxWeapons * 6);
     	scriptIndex[COBFN_Create] = getFunctionId("Create");
     	scriptIndex[COBFN_StartMoving] = getFunctionId("StartMoving");
     	scriptIndex[COBFN_StopMoving] = getFunctionId("StopMoving");
    @@ -197,6 +197,7 @@
     		scriptIndex[COBFN_AimFromPrimary + i] = getFunctionId("AimFrom" + weapon);
     		scriptIndex[COBFN_FirePrimary + i] = getFunctionId("Fire" + weapon);
     		scriptIndex[COBFN_EndBurst + i] = getFunctionId("EndBurst" + weap);
    +		scriptIndex[COBFN_Shot + i] = getFunctionId("Shot" + weap);
     
     		// If new-naming functions are not found, we need to support the old naming scheme
     		if (i > 2)
    Index: Sim/Units/COB/CobFile.h
    ===================================================================
    --- Sim/Units/COB/CobFile.h	(revision 4026)
    +++ Sim/Units/COB/CobFile.h	(working copy)
    @@ -46,6 +46,7 @@
     const int COBFN_AimFromPrimary = COBFN_AimPrimary + COB_MaxWeapons;
     const int COBFN_FirePrimary = COBFN_AimFromPrimary + COB_MaxWeapons;
     const int COBFN_EndBurst = COBFN_FirePrimary + COB_MaxWeapons;
    +const int COBFN_Shot = COBFN_EndBurst + COB_MaxWeapons;
     
     class CCobFile
     {
    Index: Sim/Units/COB/CobInstance.cpp
    ===================================================================
    --- Sim/Units/COB/CobInstance.cpp	(revision 4026)
    +++ Sim/Units/COB/CobInstance.cpp	(working copy)
    @@ -655,15 +655,15 @@
     				dir.Normalize();
     
     				float3 targetPos = unit->weapons[type-2048]->targetPos;
    -				float3 weaponPos = unit->weapons[type-2048]->weaponPos;
    +				float3 weaponMuzzlePos = unit->weapons[type-2048]->weaponMuzzlePos;
     
     				unit->weapons[type-2048]->targetPos = pos+dir;
    -				unit->weapons[type-2048]->weaponPos = pos;
    +				unit->weapons[type-2048]->weaponMuzzlePos = pos;
     
     				unit->weapons[type-2048]->Fire();
     
     				unit->weapons[type-2048]->targetPos = targetPos;
    -				unit->weapons[type-2048]->weaponPos = weaponPos;
    +				unit->weapons[type-2048]->weaponMuzzlePos = weaponMuzzlePos;
     
     			}
     			else if (type & 4096) {
    Index: Sim/Units/UnitLoader.cpp
    ===================================================================
    --- Sim/Units/UnitLoader.cpp	(revision 4026)
    +++ Sim/Units/UnitLoader.cpp	(working copy)
    @@ -351,7 +351,7 @@
     	} else if(weapondef->type=="MissileLauncher"){
     		weapon=SAFE_NEW CMissileLauncher(owner);
     	} else if(weapondef->type=="TorpedoLauncher"){
    -		if(owner->unitDef->canfly){
    +		if(owner->unitDef->canfly && !weapondef->submissile){
     			weapon=SAFE_NEW CBombDropper(owner,true);
     			if(weapondef->tracks)
     				((CBombDropper*)weapon)->tracking=weapondef->turnrate;
    Index: Sim/Units/UnitTypes/Builder.cpp
    ===================================================================
    --- Sim/Units/UnitTypes/Builder.cpp	(revision 4026)
    +++ Sim/Units/UnitTypes/Builder.cpp	(working copy)
    @@ -582,9 +582,12 @@
     {
     	float3 wantedDir=(pos-this->pos).Normalize();
     	short int h=GetHeadingFromVector(wantedDir.x,wantedDir.z);
    +	short int p=(short int) (asin(wantedDir.dot(updir))*(32768/PI));
    +	short int pitch=(short int) (asin(frontdir.dot(updir))*(32768/PI));
     
     	std::vector<int> args;
     	args.push_back(short(h-heading));
    +	args.push_back(short(p-pitch));
     	cob->Call("StartBuilding", args);
     
     	int soundIdx = unitDef->sounds.build.getRandomIdx();
    Index: Sim/Weapons/BeamLaser.cpp
    ===================================================================
    --- Sim/Weapons/BeamLaser.cpp	(revision 4026)
    +++ Sim/Weapons/BeamLaser.cpp	(working copy)
    @@ -43,6 +43,7 @@
     {
     	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();
    @@ -77,15 +78,17 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater)
    -			return false;
    -	} else {
    -		if(pos.y<0)
    -			return false;
    +	if(!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater)
    +				return false;
    +		} else {
    +			if(pos.y<0)
    +				return false;
    +		}
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     
     	float length=dir.Length();
     	if(length==0)
    @@ -94,14 +97,14 @@
     	dir/=length;
     
     	if(!onlyForward){		//skip ground col testing for aircrafts
    -		float g=ground->LineGroundCol(weaponPos,pos);
    +		float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     		if(g>0 && g<length*0.9f)
     			return false;
     	}
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -127,7 +130,7 @@
     		if(salvoLeft==salvoSize-1){
     			if(fireSoundId)
     				sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    -			dir=targetPos-weaponPos;
    +			dir=targetPos-weaponMuzzlePos;
     			dir.Normalize();
     			oldDir=dir;
     		} else {
    @@ -151,7 +154,7 @@
     
     	float maxLength=range*rangeMod;
     	float curLength=0;
    -	float3 curPos=weaponPos;
    +	float3 curPos=weaponMuzzlePos;
     	float3 hitPos;
     
     	bool tryAgain=true;
    @@ -219,7 +222,7 @@
     		// Dynamic Damage
     		DamageArray dynDamages;
     		if (weaponDef->dynDamageExp > 0)
    -			dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponPos, curPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
    +			dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponMuzzlePos, curPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
     		helper->Explosion(hitPos, weaponDef->dynDamageExp>0?dynDamages*(intensity*damageMul):weaponDef->damages*(intensity*damageMul), areaOfEffect, weaponDef->edgeEffectiveness, weaponDef->explosionSpeed,owner, true, 1.0f, false, weaponDef->explosionGenerator, hit, dir, weaponDef->id);
     	}
     
    Index: Sim/Weapons/bombdropper.cpp
    ===================================================================
    --- Sim/Weapons/bombdropper.cpp	(revision 4026)
    +++ Sim/Weapons/bombdropper.cpp	(working copy)
    @@ -56,14 +56,14 @@
     		if(weaponPos.y>targetPos.y){
     			float d=targetPos.y-weaponPos.y;
     			float s=-owner->speed.y;
    -			float sq=(s-2*d)/-gs->gravity;
    +			float sq=(s-2*d)/-(weaponDef->myGravity==0 ? gs->gravity : -(weaponDef->myGravity));
     			if(sq>0)
    -				predict=s/gs->gravity+sqrt(sq);
    +				predict=s/(weaponDef->myGravity==0 ? gs->gravity : -(weaponDef->myGravity))+sqrt(sq);
     			else
     				predict=0;
     			float3 hitpos=owner->pos+owner->speed*predict;
     			float speedf=owner->speed.Length();
    -			if(hitpos.distance2D(targetPos)<(salvoSize-1)*speedf*salvoDelay*0.5f+bombMoveRange){
    +			if(hitpos.distance2D(targetPos)<max(1,(salvoSize-1))*speedf*salvoDelay*0.5f+bombMoveRange){
     				subClassReady=true;
     			}
     		}
    @@ -99,14 +99,16 @@
     		float3 dif=targetPos-weaponPos;		//fudge a bit better lateral aim to compensate for imprecise aircraft steering
     		dif.y=0;
     		float3 dir=owner->speed;
    -		dir.y=0;
     		dir.Normalize();
    +		dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.9f); //add a random spray
    +		dir.y=min(0.0,dir.y);
    +		dir.Normalize();
     		dif-=dir*dif.dot(dir);
     		dif/=max(0.01f,predict);
     		float size=dif.Length();
     		if(size>1.0f)
     			dif/=size*1.0f;
    -		SAFE_NEW CExplosiveProjectile(weaponPos,owner->speed+dif,owner, weaponDef, 1000,areaOfEffect);
    +		SAFE_NEW CExplosiveProjectile(weaponPos,owner->speed+dif,owner, weaponDef, 1000,areaOfEffect,weaponDef->myGravity==0 ? gs->gravity : -(weaponDef->myGravity));
     	}
     	//CWeaponProjectile::CreateWeaponProjectile(owner->pos,owner->speed,owner, NULL, float3(0,0,0), damages, weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
    Index: Sim/Weapons/Cannon.cpp
    ===================================================================
    --- Sim/Weapons/Cannon.cpp	(revision 4026)
    +++ Sim/Weapons/Cannon.cpp	(working copy)
    @@ -26,6 +26,7 @@
     	CR_MEMBER(minPredict),
     	CR_MEMBER(highTrajectory),
     	CR_MEMBER(selfExplode),
    +	CR_MEMBER(gravity),
     	CR_RESERVED(16)
     	));
     
    @@ -41,11 +42,12 @@
     
     void CCannon::Init(void)
     {
    +	gravity = weaponDef->myGravity==0 ? gs->gravity : -(weaponDef->myGravity);
     	if(highTrajectory){
    -		maxPredict=projectileSpeed*2/-gs->gravity;
    -		minPredict=projectileSpeed*1.41f/-gs->gravity;
    +		maxPredict=projectileSpeed*2/-gravity;
    +		minPredict=projectileSpeed*1.41f/-gravity;
     	} else {
    -		maxPredict=projectileSpeed*1.41f/-gs->gravity;
    +		maxPredict=projectileSpeed*1.41f/-gravity;
     	}
     	CWeapon::Init();
     }
    @@ -60,6 +62,8 @@
     	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;
     		float3 diff = targetPos-weaponPos;
     		wantedDir = GetWantedDir(diff);
     		float speed2D = wantedDir.Length2D() * projectileSpeed;
    @@ -78,24 +82,26 @@
     		return false;
     	}
     
    -	if(unit)
    -	{
    -		if(unit->isUnderWater)
    +	if(!weaponDef->waterweapon) {
    +		if(unit)
     		{
    -			return false;
    +			if(unit->isUnderWater)
    +			{
    +				return false;
    +			}
    +		} else {
    +			if(pos.y<0)
    +			{
    +				return false;
    +			}
     		}
    -	} else {
    -		if(pos.y<0)
    -		{
    -			return false;
    -		}
     	}
     
     	if (projectileSpeed == 0)
     	{
     		return true;
     	}
    -	float3 dif(pos-weaponPos);
    +	float3 dif(pos-weaponMuzzlePos);
     
     	float3 dir(GetWantedDir(dif));
     
    @@ -110,8 +116,8 @@
     	}
     	flatdir/=flatlength;
     
    -	float gc=ground->TrajectoryGroundCol(weaponPos, flatdir, flatlength-10,
    -			dir.y , gs->gravity / (projectileSpeed * projectileSpeed) * 0.5f);
    +	float gc=ground->TrajectoryGroundCol(weaponMuzzlePos, flatdir, flatlength-10,
    +			dir.y , gravity / (projectileSpeed * projectileSpeed) * 0.5f);
     	if(gc>0) {
     		return false;
     	}
    @@ -120,8 +126,8 @@
     	if(gc>0 && gc<length*0.40f)
     		return false;
     */
    -	if(avoidFriendly && helper->TestTrajectoryCone(weaponPos, flatdir,
    -		flatlength-30, dir.y, gs->gravity /
    +	if(avoidFriendly && helper->TestTrajectoryCone(weaponMuzzlePos, flatdir,
    +		flatlength-30, dir.y, gravity /
     		(projectileSpeed * projectileSpeed) * 0.5f,
     		(accuracy+sprayangle) * 0.6f * (1-owner->limExperience * 0.9f) * 0.9f,
     		3, owner->allyteam, owner))
    @@ -143,7 +149,7 @@
     
     void CCannon::Fire(void)
     {
    -	float3 diff = targetPos-weaponPos;
    +	float3 diff = targetPos-weaponMuzzlePos;
     	float3 dir=GetWantedDir(diff);
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.9f);
     	dir.Normalize();
    @@ -153,14 +159,14 @@
     #endif
     	int ttl = 0;
     	float sqSpeed2D = dir.SqLength2D() * projectileSpeed * projectileSpeed;
    -	int predict = (int)ceil((sqSpeed2D == 0) ? (-2 * projectileSpeed * dir.y / gs->gravity)
    +	int predict = (int)ceil((sqSpeed2D == 0) ? (-2 * projectileSpeed * dir.y / gravity)
     			: sqrt(diff.SqLength2D() / sqSpeed2D));
     	if(selfExplode) {
     		ttl=(int)(predict+gs->randFloat()*2.5f-0.5f);
     	} else {
     		ttl=predict*2;
     	}
    -	SAFE_NEW CExplosiveProjectile(weaponPos,dir*projectileSpeed,owner,weaponDef, ttl,areaOfEffect);
    +	SAFE_NEW CExplosiveProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,weaponDef, ttl,areaOfEffect,gravity);
     	//CWeaponProjectile::CreateWeaponProjectile(weaponPos,owner->speed,owner, NULL, float3(0,0,0), weaponDef);
     
     //	SAFE_NEW CSmokeProjectile(weaponPos,dir*0.01f,90,0.1f,0.02f,owner,0.6f);
    @@ -169,8 +175,8 @@
     //	p->maxheat=p->heat;
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    -	if(weaponPos.y<30)
    - 		water->AddExplosion(weaponPos,damages[0]*0.1f,sqrt(damages[0])+80);
    +//	if(weaponMuzzlePos.y<30)
    +//		water->AddExplosion(weaponMuzzlePos,damages[0]*0.1f,sqrt(damages[0])+80);
     }
     
     void CCannon::SlowUpdate(void)
    @@ -178,10 +184,10 @@
     	if(owner->useHighTrajectory!=highTrajectory){
     		highTrajectory=owner->useHighTrajectory;
     		if(highTrajectory){
    -			maxPredict=projectileSpeed*2/-gs->gravity;
    -			minPredict=projectileSpeed*1.41f/-gs->gravity;
    +			maxPredict=projectileSpeed*2/-gravity;
    +			minPredict=projectileSpeed*1.41f/-gravity;
     		} else {
    -			maxPredict=projectileSpeed*1.41f/-gs->gravity;
    +			maxPredict=projectileSpeed*1.41f/-gravity;
     		}
     	}
     	CWeapon::SlowUpdate();
    @@ -201,7 +207,7 @@
     {
     	float Dsq = diff.SqLength();
     	float DFsq = diff.SqLength2D();
    -	float g = gs->gravity;
    +	float g = gravity;
     	float v = projectileSpeed;
     	float dy = diff.y;
     	float dxz = sqrt(DFsq);
    @@ -237,7 +243,7 @@
     
     float CCannon::GetRange2D(float yDiff) const
     {
    -	float root1 = 1 + 2*gs->gravity*yDiff/(projectileSpeed*projectileSpeed);
    +	float root1 = 1 + 2*gravity*yDiff/(projectileSpeed*projectileSpeed);
     	if(root1 < 0){
     		return 0;
     	} else {
    Index: Sim/Weapons/Cannon.h
    ===================================================================
    --- Sim/Weapons/Cannon.h	(revision 4026)
    +++ Sim/Weapons/Cannon.h	(working copy)
    @@ -22,6 +22,7 @@
     
     	float maxPredict;
     	float minPredict;
    +	float gravity;
     	bool highTrajectory;
     	bool selfExplode;
     	void SlowUpdate(void);
    Index: Sim/Weapons/DGunWeapon.cpp
    ===================================================================
    --- Sim/Weapons/DGunWeapon.cpp	(revision 4026)
    +++ Sim/Weapons/DGunWeapon.cpp	(working copy)
    @@ -27,7 +27,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -46,13 +47,13 @@
     	if(onlyForward){
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
     	dir.Normalize();
     
    -	SAFE_NEW CFireBallProjectile(weaponPos,dir*projectileSpeed,owner,0,targetPos,weaponDef);
    +	SAFE_NEW CFireBallProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,0,targetPos,weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume*0.2f);
     }
    Index: Sim/Weapons/EmgCannon.cpp
    ===================================================================
    --- Sim/Weapons/EmgCannon.cpp	(revision 4026)
    +++ Sim/Weapons/EmgCannon.cpp	(working copy)
    @@ -31,7 +31,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -45,29 +46,31 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater)
    -			return false;
    -	} else {
    -		if(pos.y<0)
    -			return false;
    +	if (!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater)
    +				return false;
    +		} else {
    +			if(pos.y<0)
    +				return false;
    +		}
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.5f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.5f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -87,15 +90,16 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType)){		//the taairmovetype cant align itself properly, change back when that is fixed
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
     	dir.Normalize();
     
    -	SAFE_NEW CEmgProjectile(weaponPos,dir*projectileSpeed,owner,weaponDef->visuals.color,weaponDef->intensity,(int)(range/projectileSpeed), weaponDef);
    +	SAFE_NEW CEmgProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,weaponDef->visuals.color,weaponDef->intensity,(int)(range/projectileSpeed), weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
     
     
    +
    Index: Sim/Weapons/FlameThrower.cpp
    ===================================================================
    --- Sim/Weapons/FlameThrower.cpp	(revision 4026)
    +++ Sim/Weapons/FlameThrower.cpp	(working copy)
    @@ -27,12 +27,12 @@
     
     void CFlameThrower::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
     	float3 spread=(gs->randVector()*sprayangle+salvoError)*0.2f;
     	spread-=dir*0.001f;
     
    -	SAFE_NEW CFlameProjectile(weaponPos,dir*projectileSpeed,spread,owner,weaponDef,(int)(range/projectileSpeed*weaponDef->duration));
    +	SAFE_NEW CFlameProjectile(weaponMuzzlePos,dir*projectileSpeed,spread,owner,weaponDef,(int)(range/projectileSpeed*weaponDef->duration));
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    @@ -42,29 +42,31 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater)
    -			return false;
    -	} else {
    -		if(pos.y<0)
    -			return false;
    +	if (!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater)
    +				return false;
    +		} else {
    +			if(pos.y<0)
    +				return false;
    +		}
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner)){
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner)){
     		return false;
     	}
     	return true;
    @@ -74,6 +76,7 @@
     {
     	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;
     		wantedDir=targetPos-weaponPos;
     		wantedDir.Normalize();
     	}
    Index: Sim/Weapons/LaserCannon.cpp
    ===================================================================
    --- Sim/Weapons/LaserCannon.cpp	(revision 4026)
    +++ Sim/Weapons/LaserCannon.cpp	(working copy)
    @@ -30,7 +30,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -45,14 +46,14 @@
     		return false;
     
     	if(unit){
    -		if(unit->isUnderWater)
    +		if(unit->isUnderWater && !weaponDef->waterweapon)
     			return false;
     	} else {
    -		if(pos.y<0)
    +		if(pos.y<0 && !weaponDef->waterweapon)
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
    @@ -60,14 +61,14 @@
     	dir/=length;
     
     	if(!onlyForward){		//skip ground col testing for aircrafts
    -		float g=ground->LineGroundCol(weaponPos,pos);
    +		float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     		if(g>0 && g<length*0.9f)
     			return false;
     	}
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -84,7 +85,7 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType)){		//the taairmovetype cant align itself properly, change back when that is fixed
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.7f);
    @@ -96,10 +97,11 @@
     		fpsSub=6;
     #endif
     
    -	SAFE_NEW CLaserProjectile(weaponPos, dir*projectileSpeed, owner, weaponDef->duration*weaponDef->maxvelocity, weaponDef->visuals.color, weaponDef->visuals.color2, weaponDef->intensity, weaponDef, (int)((weaponDef->range-fpsSub*4)/weaponDef->projectilespeed)-fpsSub);
    +	SAFE_NEW CLaserProjectile(weaponMuzzlePos, dir*projectileSpeed, owner, weaponDef->duration*weaponDef->maxvelocity, weaponDef->visuals.color, weaponDef->visuals.color2, weaponDef->intensity, weaponDef, (int)((weaponDef->range-fpsSub*4)/weaponDef->projectilespeed)-fpsSub);
     
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
     
     
    +
    Index: Sim/Weapons/LightingCannon.cpp
    ===================================================================
    --- Sim/Weapons/LightingCannon.cpp	(revision 4026)
    +++ Sim/Weapons/LightingCannon.cpp	(working copy)
    @@ -9,6 +9,7 @@
     #include "WeaponDefHandler.h"
     #include "Sim/Misc/InterceptHandler.h"
     #include "mmgr.h"
    +#include "PlasmaRepulser.h"
     
     CR_BIND_DERIVED(CLightingCannon, CWeapon, (NULL));
     
    @@ -30,6 +31,7 @@
     {
     	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();
    @@ -43,29 +45,31 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater)
    -			return false;
    -	} else {
    -		if(pos.y<0)
    -			return false;
    +	if(!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater)
    +				return false;
    +		} else {
    +			if(pos.y<0)
    +				return false;
    +		}
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -77,17 +81,22 @@
     
     void CLightingCannon::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
    +	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
    +	dir.Normalize();
     	CUnit* u=0;
    -	float r=helper->TraceRay(weaponPos,dir,range,0,owner,u);
    +	float r=helper->TraceRay(weaponMuzzlePos,dir,range,0,owner,u);
     
     	float3 newDir;
     	CPlasmaRepulser* shieldHit;
    -	float shieldLength=interceptHandler.AddShieldInterceptableBeam(this,weaponPos,dir,range,newDir,shieldHit);
    +	float shieldLength=interceptHandler.AddShieldInterceptableBeam(this,weaponMuzzlePos,dir,range,newDir,shieldHit);
     	if(shieldLength<r){
     		r=shieldLength;
    +		if(shieldHit) {
    +			shieldHit->BeamIntercepted(this);
     		}
    +	}
     
     //	if(u)
     //		u->DoDamage(damages,owner,ZeroVector);
    @@ -95,11 +104,11 @@
     	// Dynamic Damage
     	DamageArray dynDamages;
     	if (weaponDef->dynDamageExp > 0)
    -		dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponPos, targetPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
    +		dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponMuzzlePos, targetPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
     
    -	helper->Explosion(weaponPos+dir*r,weaponDef->dynDamageExp>0?dynDamages:weaponDef->damages,areaOfEffect,weaponDef->edgeEffectiveness,weaponDef->explosionSpeed,owner,false,0.5f,true,weaponDef->explosionGenerator, u,dir, weaponDef->id);
    +	helper->Explosion(weaponMuzzlePos+dir*r,weaponDef->dynDamageExp>0?dynDamages:weaponDef->damages,areaOfEffect,weaponDef->edgeEffectiveness,weaponDef->explosionSpeed,owner,false,0.5f,true,weaponDef->explosionGenerator, u,dir, weaponDef->id);
     
    -	SAFE_NEW CLightingProjectile(weaponPos,weaponPos+dir*(r+10),owner,color,weaponDef,10,this);
    +	SAFE_NEW CLightingProjectile(weaponMuzzlePos,weaponMuzzlePos+dir*(r+10),owner,color,weaponDef,10,this);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     
    @@ -110,7 +119,8 @@
     void CLightingCannon::SlowUpdate(void)
     {
     	CWeapon::SlowUpdate();
    -	if(targetType==Target_Unit){
    -		predict=(gs->randFloat()-0.5f)*20*range/weaponPos.distance(targetUnit->midPos)*(1.2f-owner->limExperience);		//make the weapon somewhat less effecient against aircrafts hopefully
    -	}
    +	//We don't do hardcoded inaccuracies, use targetMoveError if you want inaccuracy!
    +//	if(targetType==Target_Unit){
    +//		predict=(gs->randFloat()-0.5f)*20*range/weaponPos.distance(targetUnit->midPos)*(1.2f-owner->limExperience);		//make the weapon somewhat less effecient against aircrafts hopefully
    +//	}
     }
    Index: Sim/Weapons/MeleeWeapon.cpp
    ===================================================================
    --- Sim/Weapons/MeleeWeapon.cpp	(revision 4026)
    +++ Sim/Weapons/MeleeWeapon.cpp	(working copy)
    @@ -31,8 +31,16 @@
     
     void CMeleeWeapon::Update()
     {
    +	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();
    -
     }
     
     void CMeleeWeapon::Fire(void)
    Index: Sim/Weapons/MissileLauncher.cpp
    ===================================================================
    --- Sim/Weapons/MissileLauncher.cpp	(revision 4026)
    +++ Sim/Weapons/MissileLauncher.cpp	(working copy)
    @@ -29,7 +29,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			float dist=wantedDir.Length();
     			predict=dist/projectileSpeed;
    @@ -49,12 +50,15 @@
     	if(onlyForward){
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     		if(weaponDef->trajectoryHeight>0){
     			dir.y+=weaponDef->trajectoryHeight;
     			dir.Normalize();
     		}
    +		if (weaponDef->fixedLauncher) {
    +			dir=weaponDir;
    +		}
     	}
     
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
    @@ -64,7 +68,7 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType))
     		startSpeed+=owner->speed;
     
    -	SAFE_NEW CMissileProjectile(weaponPos,startSpeed,owner,areaOfEffect,projectileSpeed,(int)(range/projectileSpeed+25),targetUnit, weaponDef,targetPos);
    +	SAFE_NEW CMissileProjectile(weaponMuzzlePos,startSpeed,owner,areaOfEffect,projectileSpeed,weaponDef->flighttime==0 ? (int)(range/projectileSpeed+25) : weaponDef->flighttime,targetUnit, weaponDef,targetPos);
     	//CWeaponProjectile::CreateWeaponProjectile(weaponPos,startSpeed,owner,targetUnit, float3(0,0,0), weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    @@ -75,15 +79,17 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater){
    -			return false;
    +	if (!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater){
    +				return false;
    +			}
    +		} else {
    +			if(pos.y<0)
    +				return false;
     		}
    -	} else {
    -		if(pos.y<0)
    -			return false;
     	}
    -	float3 dir=pos-weaponPos;
    +	float3 dir = pos-weaponMuzzlePos;
     	if(weaponDef->trajectoryHeight>0){	//do a different test depending on if the missile has a high trajectory or not
     		float3 flatdir(dir.x,0,dir.z);
     		dir.Normalize();
    @@ -95,11 +101,11 @@
     		float linear=dir.y+weaponDef->trajectoryHeight;
     		float quadratic=-weaponDef->trajectoryHeight/flatlength;
     
    -		float gc=ground->TrajectoryGroundCol(weaponPos,flatdir,flatlength-30,linear,quadratic);
    +		float gc=ground->TrajectoryGroundCol(weaponMuzzlePos,flatdir,flatlength-30,linear,quadratic);
     		if(gc>0)
     			return false;
     
    -		if(avoidFriendly && helper->TestTrajectoryCone(weaponPos,flatdir,flatlength-30,linear,quadratic,0,8,owner->allyteam,owner)){
    +		if(avoidFriendly && helper->TestTrajectoryCone(weaponMuzzlePos,flatdir,flatlength-30,linear,quadratic,0,8,owner->allyteam,owner)){
     			return false;
     		}
     	} else {
    @@ -110,7 +116,7 @@
     		dir/=length;
     
     		if(!onlyForward){		//skip ground col testing for aircrafts
    -			float g=ground->LineGroundCol(weaponPos,pos);
    +			float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     			if(g>0 && g<length*0.9f)
     				return false;
     		} else {
    @@ -119,7 +125,7 @@
     			if(owner->frontdir.dot(goaldir) < maxAngleDif)
     				return false;
     		}
    -		if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
    +		if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
     			return false;
     	}
     	return true;
    Index: Sim/Weapons/PlasmaRepulser.cpp
    ===================================================================
    --- Sim/Weapons/PlasmaRepulser.cpp	(revision 4026)
    +++ Sim/Weapons/PlasmaRepulser.cpp	(working copy)
    @@ -70,6 +70,8 @@
     
     	if(weaponDef->shieldPower==0)
     		curPower=99999999999.0f;
    +	else
    +		curPower=weaponDef->shieldStartingPower;
     
     	CWeapon::Init();
     }
    Index: Sim/Weapons/Rifle.cpp
    ===================================================================
    --- Sim/Weapons/Rifle.cpp	(revision 4026)
    +++ Sim/Weapons/Rifle.cpp	(working copy)
    @@ -41,6 +41,7 @@
     {
     	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;
     		wantedDir=targetPos-weaponPos;
     		wantedDir.Normalize();
     	}
    @@ -60,18 +61,18 @@
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.9f),owner->allyteam,owner)){
    +	if(helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.9f),owner->allyteam,owner)){
     		return false;
     	}
     	return true;
    @@ -79,7 +80,7 @@
     
     void CRifle::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.9f);
     	dir.Normalize();
    @@ -88,13 +89,13 @@
     	tracefile << owner->pos.x << " " << dir.x << " " << targetPos.x << " " << targetPos.y << " " << targetPos.z << "\n";
     #endif
     	CUnit* hit;
    -	float length=helper->TraceRay(weaponPos,dir,range,damages[0],owner,hit);
    +	float length=helper->TraceRay(weaponMuzzlePos,dir,range,damages[0],owner,hit);
     	if(hit){
     		hit->DoDamage(damages,owner,ZeroVector, weaponDef->id);
    -		SAFE_NEW CHeatCloudProjectile(weaponPos+dir*length,hit->speed*0.9f,30,1,owner);
    +		SAFE_NEW CHeatCloudProjectile(weaponMuzzlePos+dir*length,hit->speed*0.9f,30,1,owner);
     	}
    -	SAFE_NEW CTracerProjectile(weaponPos,dir*projectileSpeed,length,owner);
    -	SAFE_NEW CSmokeProjectile(weaponPos,float3(0,0.0f,0),70,0.1f,0.02f,owner,0.6f);
    +	SAFE_NEW CTracerProjectile(weaponMuzzlePos,dir*projectileSpeed,length,owner);
    +	SAFE_NEW CSmokeProjectile(weaponMuzzlePos,float3(0,0.0f,0),70,0.1f,0.02f,owner,0.6f);
     	if(fireSoundId)
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    Index: Sim/Weapons/StarburstLauncher.cpp
    ===================================================================
    --- Sim/Weapons/StarburstLauncher.cpp	(revision 4026)
    +++ Sim/Weapons/StarburstLauncher.cpp	(working copy)
    @@ -32,6 +32,7 @@
     {
     	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;
     		wantedDir=(targetPos-weaponPos).Normalize();		//the aiming upward is apperently implicid so aim toward target
     	}
     	CWeapon::Update();
    @@ -39,7 +40,11 @@
     
     void CStarburstLauncher::Fire(void)
     {
    -	CStarburstProjectile* p=SAFE_NEW CStarburstProjectile(weaponPos+float3(0,2,0),float3(0,0.01f,0),owner,targetPos,areaOfEffect,projectileSpeed,tracking,(int)uptime,targetUnit, weaponDef,interceptTarget);
    +	float3 speed(0,weaponDef->startvelocity,0);
    +	if(weaponDef->fixedLauncher) {
    +		speed=weaponDir * weaponDef->startvelocity;
    +	}
    +	CStarburstProjectile* p=SAFE_NEW CStarburstProjectile(weaponMuzzlePos+float3(0,2,0),speed,owner,targetPos,areaOfEffect,projectileSpeed,tracking,(int)uptime,targetUnit, weaponDef,interceptTarget);
     
     	if(weaponDef->targetable)
     		interceptHandler.AddInterceptTarget(p,targetPos);
    @@ -54,15 +59,19 @@
     		return false;
     
     	if(unit){
    -		if(unit->isUnderWater)
    +		if(unit->isUnderWater && !weaponDef->waterweapon)
     			return false;
     	} else {
    -		if(pos.y<0)
    +		if(pos.y<0 && !weaponDef->waterweapon)
     			return false;
     	}
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,UpVector,100,0,owner->allyteam,owner))
    -		return false;
    +	if(!weaponDef->fixedLauncher)
    +		if(avoidFriendly && helper->TestCone(weaponMuzzlePos,UpVector,100,0,owner->allyteam,owner))
    +			return false;
    +	else
    +		if(avoidFriendly && helper->TestCone(weaponMuzzlePos,weaponDir,100,0,owner->allyteam,owner))
    +			return false;
     
     	return true;
     }
    Index: Sim/Weapons/TorpedoLauncher.cpp
    ===================================================================
    --- Sim/Weapons/TorpedoLauncher.cpp	(revision 4026)
    +++ Sim/Weapons/TorpedoLauncher.cpp	(working copy)
    @@ -32,7 +32,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -//		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +//		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			float dist=wantedDir.Length();
     			predict=dist/projectileSpeed;
    @@ -48,18 +49,24 @@
     //	if(onlyForward){
     //		dir=owner->frontdir;
     //	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     		if(weaponDef->trajectoryHeight>0){
     			dir.y+=weaponDef->trajectoryHeight;
     			dir.Normalize();
     		}
     //	}
    -	float3 startSpeed=dir*weaponDef->startvelocity;
    +	float3 startSpeed;
    +	if (!weaponDef->fixedLauncher) {
    +		startSpeed=dir*weaponDef->startvelocity;
    +	}
    +	else {
    +		startSpeed=weaponDir*weaponDef->startvelocity;
    +	}
     
     //	if(onlyForward)
     //		startSpeed+=owner->speed*0.5f;
    -	SAFE_NEW CTorpedoProjectile(weaponPos,startSpeed,owner,areaOfEffect,projectileSpeed,tracking,(int)(range/projectileSpeed+15),targetUnit, weaponDef);
    +	SAFE_NEW CTorpedoProjectile(weaponMuzzlePos,startSpeed,owner,areaOfEffect,projectileSpeed,tracking,weaponDef->flighttime==0 ? (int)(range/projectileSpeed+25) : weaponDef->flighttime,targetUnit, weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    @@ -70,22 +77,22 @@
     		return false;
     
     	if(unit){
    -		if(unit->unitDef->canhover)
    +		if(!(weaponDef->submissile) && unit->unitDef->canhover)
     			return false;
    -		if(unit->unitDef->canfly && unit->pos.y>0)
    +		if(!(weaponDef->submissile) && unit->unitDef->canfly && unit->pos.y>0)
     			return false;
     	}
    -	if(ground->GetHeight2(pos.x,pos.z)>0)
    +	if(!(weaponDef->submissile) && ground->GetHeight2(pos.x,pos.z)>0)
     		return 0;
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)+0.05f,owner->allyteam,owner))	//+0.05f since torpedoes has an unfortunate tendency to hit own ships due to movement
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)+0.05f,owner->allyteam,owner))	//+0.05f since torpedoes has an unfortunate tendency to hit own ships due to movement
     		return false;
     	return true;
     }
    Index: Sim/Weapons/Weapon.cpp
    ===================================================================
    --- Sim/Weapons/Weapon.cpp	(revision 4026)
    +++ Sim/Weapons/Weapon.cpp	(working copy)
    @@ -56,9 +56,11 @@
     	CR_MEMBER(subClassReady),
     	CR_MEMBER(onlyForward),
     	CR_MEMBER(weaponPos),
    +	CR_MEMBER(weaponMuzzlePos),
     	CR_MEMBER(lastRequest),
     	CR_MEMBER(damages),
     	CR_MEMBER(relWeaponPos),
    +	CR_MEMBER(relWeaponMuzzlePos),
     	CR_MEMBER(muzzleFlareSize),
     	CR_MEMBER(lastTargetRetry),
     	CR_MEMBER(areaOfEffect),
    @@ -131,8 +133,10 @@
     	subClassReady(true),
     	onlyForward(false),
     	weaponPos(0,0,0),
    +	weaponMuzzlePos(0,0,0),
     	lastRequest(0),
     	relWeaponPos(0,1,0),
    +	relWeaponMuzzlePos(0,1,0),
     	muzzleFlareSize(1),
     	lastTargetRetry(-100),
     	areaOfEffect(1),
    @@ -174,11 +178,14 @@
     	if(hasCloseTarget){
     		std::vector<int> args;
     		args.push_back(0);
    -		if(useWeaponPosForAim){
    +		if(useWeaponPosForAim){ //if we couldn't get a line of fire from the muzzle try if we can get it from the aim piece
     			owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
     		} else {
     			owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     		}
    +		relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
    +
    +		owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     		relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     	}
     
    @@ -256,16 +263,18 @@
     	&& subClassReady
     	&& reloadStatus<=gs->frameNum
     	&& (!weaponDef->stockpile || numStockpiled)
    -	&& (weaponDef->waterweapon || weaponPos.y>0)
    +	&& (weaponDef->fireSubmersed || weaponMuzzlePos.y>0)
     	&& (owner->unitDef->maxFuel==0 || owner->currentFuel > 0)
     	){
     		if ((weaponDef->stockpile || (gs->Team(owner->team)->metal>=metalFireCost && gs->Team(owner->team)->energy>=energyFireCost))) {
     			std::vector<int> args;
     			args.push_back(0);
     			owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    -			relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
    -			weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +			owner->localmodel->GetEmitDirPos(args[0], relWeaponMuzzlePos, weaponDir);
    +			weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
     			useWeaponPosForAim=reloadTime/16+8;
    +			weaponDir = owner->frontdir * weaponDir.z + owner->updir * weaponDir.y + owner->rightdir * weaponDir.x;
    +			weaponDir.Normalize();
     
     			if(TryTarget(targetPos,haveUserTarget,targetUnit)){
     				if(weaponDef->stockpile){
    @@ -301,35 +310,52 @@
     			}
     		}
     	}
    -	if(salvoLeft && nextSalvo<=gs->frameNum){
    +	if(salvoLeft && nextSalvo<=gs->frameNum ){
     		salvoLeft--;
     		nextSalvo=gs->frameNum+salvoDelay;
     		owner->lastFireWeapon=gs->frameNum;
    +		
    +		int projectiles = weaponDef->projectilespershot;
    +		
    +		while(projectiles > 0) {
    +			--projectiles;
    +			
    +			// add to the commandShotCount if this is the last salvo,
    +			// and it is being directed towards the current target
    +			// (helps when deciding if a queued ground attack order has been completed)
    +			if ((salvoLeft == 0) && (owner->commandShotCount >= 0) &&
    +			    ((targetType == Target_Pos) && (targetPos == owner->userAttackPos)) ||
    +					((targetType == Target_Unit) && (targetUnit == owner->userTarget))) {
    +				owner->commandShotCount++;
    +			}
    +	
    +			std::vector<int> args;
    +			args.push_back(0);
    +	
    +			owner->cob->Call(COBFN_Shot+weaponNum,0);
    +	
    +			owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
    +			relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     
    -		// add to the commandShotCount if this is the last salvo,
    -		// and it is being directed towards the current target
    -		// (helps when deciding if a queued ground attack order has been completed)
    -		if ((salvoLeft == 0) && (owner->commandShotCount >= 0) &&
    -		    ((targetType == Target_Pos) && (targetPos == owner->userAttackPos)) ||
    -				((targetType == Target_Unit) && (targetUnit == owner->userTarget))) {
    -			owner->commandShotCount++;
    -		}
    +			owner->cob->Call(/*COBFN_AimFromPrimary+weaponNum*/COBFN_QueryPrimary+weaponNum/**/,args);
    +			owner->localmodel->GetEmitDirPos(args[0], relWeaponMuzzlePos, weaponDir);
     
    -		std::vector<int> args;
    -		args.push_back(0);
    -		owner->cob->Call(/*COBFN_AimFromPrimary+weaponNum/*/COBFN_QueryPrimary+weaponNum/**/,args);
    -		relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
    -		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +			weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
     
    -//		logOutput.Print("RelPosFire %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
    -
    -		if (owner->unitDef->decloakOnFire && (owner->scriptCloak <= 2)) {
    -			owner->isCloaked = false;
    -			owner->curCloakTimeout = gs->frameNum + owner->cloakTimeout;
    +			weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +			weaponDir = owner->frontdir * weaponDir.z + owner->updir * weaponDir.y + owner->rightdir * weaponDir.x;
    +			weaponDir.Normalize();
    +	
    +	//		logOutput.Print("RelPosFire %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
    +	
    +			if (owner->unitDef->decloakOnFire && (owner->scriptCloak <= 2)) {
    +				owner->isCloaked = false;
    +				owner->curCloakTimeout = gs->frameNum + owner->cloakTimeout;
    +			}
    +	
    +			Fire();
     		}
     
    -		Fire();
    -
     		//Rock the unit in the direction of the fireing
     		float3 rockDir = wantedDir;
     		rockDir.y = 0;
    @@ -360,9 +386,9 @@
     
     	if(!weaponDef->waterweapon && pos.y<1)
     		pos.y=1;
    -	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -	if(weaponPos.y<ground->GetHeight2(weaponPos.x,weaponPos.z))
    -		weaponPos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +	if(weaponMuzzlePos.y<ground->GetHeight2(weaponMuzzlePos.x,weaponMuzzlePos.z))
    +		weaponMuzzlePos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
     
     	if(!TryTarget(pos,userTarget,0))
     		return false;
    @@ -385,8 +411,10 @@
     
     	weaponPos= owner->pos + owner->frontdir * relWeaponPos.z
     		+ owner->updir * relWeaponPos.y + owner->rightdir * relWeaponPos.x;
    -	if(weaponPos.y < ground->GetHeight2(weaponPos.x, weaponPos.z))
    -		weaponPos = owner->pos + UpVector * 10;
    +	weaponMuzzlePos= owner->pos + owner->frontdir * relWeaponMuzzlePos.z
    +		+ owner->updir * relWeaponMuzzlePos.y + owner->rightdir * relWeaponMuzzlePos.x;
    +	if(weaponMuzzlePos.y < ground->GetHeight2(weaponMuzzlePos.x, weaponMuzzlePos.z))
    +		weaponMuzzlePos = owner->pos + UpVector * 10;
     	//hope that we are underground because we are a popup weapon and will come above ground later
     
     	if(!unit){
    @@ -434,18 +462,23 @@
     #endif
     	std::vector<int> args;
     	args.push_back(0);
    -	if(useWeaponPosForAim){
    +	if(useWeaponPosForAim){ //If we can't get a line of fire from the muzzle try the aim piece instead since the weapon may just be turned in a wrong way
     		owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
     		if(useWeaponPosForAim>1)
     			useWeaponPosForAim--;
     	} else {
     		owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     	}
    +	relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +
    +	owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     	relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -	if(weaponPos.y<ground->GetHeight2(weaponPos.x,weaponPos.z))
    -		weaponPos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
     
    +	if(weaponMuzzlePos.y<ground->GetHeight2(weaponMuzzlePos.x,weaponMuzzlePos.z))
    +		weaponMuzzlePos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
    +
     	predictSpeedMod=1+(gs->randFloat()-0.5f)*2*(1-owner->limExperience);
     
     	if((targetPos-weaponPos).SqLength() < relWeaponPos.SqLength()*16)
    @@ -549,7 +582,7 @@
     	if(weaponDef->stockpile && !numStockpiled)
     		return false;
     
    -	float3 dif=pos-weaponPos;
    +	float3 dif=pos-weaponMuzzlePos;
     	float heightDiff;
     
     	if (targetBorder != 0 && unit) {
    @@ -621,11 +654,13 @@
     	owner->frontdir = GetVectorFromHeading(owner->heading);
     	owner->rightdir = owner->frontdir.cross(owner->updir);
     	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;
     	bool val = TryTarget(tempTargetPos,userTarget,unit);
     	owner->frontdir = tempfrontdir;
     	owner->rightdir = temprightdir;
     	owner->heading = tempHeadding;
     	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;
     	return val;
     }
     
    @@ -651,11 +686,13 @@
     	owner->frontdir = GetVectorFromHeading(owner->heading);
     	owner->rightdir = owner->frontdir.cross(owner->updir);
     	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;
     	bool val = TryTarget(pos, userTarget, 0);
     	owner->frontdir = tempfrontdir;
     	owner->rightdir = temprightdir;
     	owner->heading = tempHeadding;
     	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;
     	return val;
     }
     
    @@ -666,6 +703,10 @@
     	owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     	relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +
    +	owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    +	relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
     //	logOutput.Print("RelPos %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
     
     	if (range > owner->maxRange) {
    Index: Sim/Weapons/Weapon.h
    ===================================================================
    --- Sim/Weapons/Weapon.h	(revision 4026)
    +++ Sim/Weapons/Weapon.h	(working copy)
    @@ -60,6 +60,11 @@
     
     	float3 relWeaponPos;				//weaponpos relative to the unit
     	float3 weaponPos;						//absolute weapon pos
    +
    +	float3 relWeaponMuzzlePos;			//position of the firepoint
    +	float3 weaponMuzzlePos;
    +	float3 weaponDir;
    +
     	float muzzleFlareSize;			//size of muzzle flare if drawn
     	int useWeaponPosForAim;			//sometimes weapon pos is better to use than aimpos
     	bool hasCloseTarget;					//might need to update weapon pos more often when enemy is near
    Index: Sim/Weapons/WeaponDefHandler.cpp
    ===================================================================
    --- Sim/Weapons/WeaponDefHandler.cpp	(revision 4026)
    +++ Sim/Weapons/WeaponDefHandler.cpp	(working copy)
    @@ -67,6 +67,7 @@
     	bool ballistic;
     	//bool twophase;
     	bool beamweapon;
    +	bool manualBombSettings; //Allow the user to manually specify the burst and burstrate for his AircraftBomb
     	//bool guided;
     	//bool vlaunch;
     	int rendertype;
    @@ -94,6 +95,7 @@
     	sunparser->GetDef(weaponDefs[id].minIntensity, "0", weaponname + "\\MinIntensity");
     
     	sunparser->GetDef(weaponDefs[id].dropped, "0", weaponname + "\\dropped");
    +	sunparser->GetDef(manualBombSettings, "0", weaponname + "\\manualbombsettings");
     	sunparser->GetDef(lineofsight, "0", weaponname + "\\lineofsight");
     	sunparser->GetDef(ballistic, "0", weaponname + "\\ballistic");
     	sunparser->GetDef(weaponDefs[id].twophase, "0", weaponname + "\\twophase");
    @@ -110,7 +112,10 @@
     	sunparser->GetDef(weaponDefs[id].noSelfDamage, "0", weaponname + "\\NoSelfDamage");
     
     	sunparser->GetDef(weaponDefs[id].waterweapon, "0", weaponname + "\\waterweapon");
    +	sunparser->GetDef(weaponDefs[id].fireSubmersed, weaponDefs[id].waterweapon ? "1":"0", weaponname + "\\firesubmersed");
    +	sunparser->GetDef(weaponDefs[id].submissile, "0", weaponname + "\\submissile");
     	sunparser->GetDef(weaponDefs[id].tracks, "0", weaponname + "\\tracks");
    +	sunparser->GetDef(weaponDefs[id].fixedLauncher, "0", weaponname + "\\FixedLauncher");
     	sunparser->GetDef(weaponDefs[id].noExplode, "0", weaponname + "\\NoExplode");
     	sunparser->GetDef(weaponDefs[id].maxvelocity, "0", weaponname + "\\weaponvelocity");
     	sunparser->GetDef(weaponDefs[id].isShield, "0", weaponname + "\\IsShield");
    @@ -256,6 +261,7 @@
     	weaponDefs[id].reload = atof(sunparser->SGetValueDef("1", weaponname + "\\reloadtime").c_str());
     	weaponDefs[id].salvodelay = atof(sunparser->SGetValueDef("0.1", weaponname + "\\burstrate").c_str());
     	sunparser->GetDef(weaponDefs[id].salvosize, "1", weaponname + "\\burst");
    +	sunparser->GetDef(weaponDefs[id].projectilespershot, "1", weaponname + "\\projectiles");
     	weaponDefs[id].maxAngle = atof(sunparser->SGetValueDef("3000", weaponname + "\\tolerance").c_str()) * 180.0f / 0x7fff;
     	weaponDefs[id].restTime = 0.0f;
     	sunparser->GetDef(weaponDefs[id].metalcost, "0", weaponname + "\\metalpershot");
    @@ -263,6 +269,7 @@
     	sunparser->GetDef(weaponDefs[id].selfExplode, "0", weaponname + "\\burnblow");
     	sunparser->GetDef(weaponDefs[id].sweepFire, "0", weaponname + "\\sweepfire");
     	sunparser->GetDef(weaponDefs[id].canAttackGround, "1", weaponname + "\\canattackground");
    +	weaponDefs[id].myGravity = atof(sunparser->SGetValueDef("0", weaponname + "\\myGravity").c_str());
     
     	weaponDefs[id].fireStarter=atof(sunparser->SGetValueDef("0", weaponname + "\\firestarter").c_str())*0.01f;
     	weaponDefs[id].paralyzer=!!atoi(sunparser->SGetValueDef("0", weaponname + "\\paralyzer").c_str());
    @@ -292,6 +299,7 @@
     	sunparser->GetDef(weaponDefs[id].shieldPower, "0", weaponname + "\\shieldpower");
     	sunparser->GetDef(weaponDefs[id].shieldPowerRegen, "0", weaponname + "\\shieldpowerregen");
     	sunparser->GetDef(weaponDefs[id].shieldPowerRegenEnergy, "0", weaponname + "\\shieldpowerregenenergy");
    +	sunparser->GetDef(weaponDefs[id].shieldStartingPower, "0", weaponname + "\\shieldstartingpower");
     	sunparser->GetDef(weaponDefs[id].shieldInterceptType, "0", weaponname + "\\shieldintercepttype");
     	weaponDefs[id].shieldGoodColor=sunparser->GetFloat3(float3(0.5f,0.5f,1),weaponname + "\\shieldgoodcolor");
     	weaponDefs[id].shieldBadColor=sunparser->GetFloat3(float3(1,0.5f,0.5f),weaponname + "\\shieldbadcolor");
    @@ -345,10 +353,11 @@
     		weaponDefs[id].visuals.color = tempCol;
     
     	weaponDefs[id].uptime = atof(sunparser->SGetValueDef("0", weaponname + "\\weapontimer").c_str());
    +	weaponDefs[id].flighttime = atof(sunparser->SGetValueDef("0", weaponname + "\\flighttime").c_str()) * 32;
     
     	weaponDefs[id].turnrate = atof(sunparser->SGetValueDef("0", weaponname + "\\turnrate").c_str()) * PI / 0x7fff /30.0f;
     
    -	if(weaponDefs[id].type=="AircraftBomb"){
    +	if(weaponDefs[id].type=="AircraftBomb" && !manualBombSettings){
     		if(weaponDefs[id].reload<0.5f){
     			weaponDefs[id].salvodelay=min(0.2f,weaponDefs[id].reload);
     			weaponDefs[id].salvosize=(int)(1/weaponDefs[id].salvodelay)+1;
    Index: Sim/Weapons/WeaponDefHandler.h
    ===================================================================
    --- Sim/Weapons/WeaponDefHandler.h	(revision 4026)
    +++ Sim/Weapons/WeaponDefHandler.h	(working copy)
    @@ -67,17 +67,23 @@
     	float restTime;
     
     	float uptime;
    +	int flighttime;
     
     	float metalcost;
     	float energycost;
     	float supplycost;
     
    +	int projectilespershot;
    +
     	int id;
     	int tdfId;	//the id= tag in the tdf
     
     	bool turret;
     	bool onlyForward;
    +	bool fixedLauncher;
     	bool waterweapon;
    +	bool fireSubmersed;
    +	bool submissile; //Lets a torpedo travel above water like it does below water
     	bool tracks;
     	bool dropped;
     	bool paralyzer;			//weapon will only paralyze not do real damage
    @@ -102,6 +108,7 @@
     
     	bool selfExplode;
     	bool gravityAffected;
    +	float myGravity;
     	bool twophase;
     	bool guided;
     	bool vlaunch;
    @@ -165,6 +172,7 @@
     	float shieldPower;			//how much damage the shield can reflect (0=infinite)
     	float shieldPowerRegen;	//how fast the power regenerates per second
     	float shieldPowerRegenEnergy;	//how much energy is needed to regenerate power per second
    +	float shieldStartingPower;	//how much power the shield has when first created
     	float3 shieldGoodColor;			//color when shield at full power
     	float3 shieldBadColor;			//color when shield is empty
     	float shieldAlpha;					//shield alpha value
    
    patch file icon evenMoreWeaponChanges.patch (78,478 bytes) 2007-07-20 17:12 +
  • patch file icon kdr11k_weapon_changes_r4220.patch (79,395 bytes) 2007-08-18 14:16 -
    Index: Sim/Projectiles/EmgProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/EmgProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/EmgProjectile.cpp	(working copy)
    @@ -4,6 +4,7 @@
     #include "Rendering/GL/VertexArray.h"
     #include "Sync/SyncTracer.h"
     #include "ProjectileHandler.h"
    +#include "Map/Ground.h"
     #include "Sim/Weapons/WeaponDefHandler.h"
     #include "mmgr.h"
     
    @@ -52,10 +53,14 @@
     void CEmgProjectile::Collision(CUnit* unit)
     {
     //	unit->DoDamage(damages,owner);
    -
     	CWeaponProjectile::Collision(unit);
     }
     
    +void CEmgProjectile::Collision() {
    +	if (!(weaponDef->waterweapon && ground->GetHeight2(pos.x, pos.z) < pos.y))
    +		CWeaponProjectile::Collision();
    +}
    +
     void CEmgProjectile::Draw(void)
     {
     	inArray=true;
    Index: Sim/Projectiles/EmgProjectile.h
    ===================================================================
    --- Sim/Projectiles/EmgProjectile.h	(revision 4220)
    +++ Sim/Projectiles/EmgProjectile.h	(working copy)
    @@ -14,6 +14,7 @@
     	void Update(void);
     	void Draw(void);
     	void Collision(CUnit* unit);
    +	void Collision();
     	int ShieldRepulse(CPlasmaRepulser* shield,float3 shieldPos, float shieldForce, float shieldMaxSpeed);
     
     	int ttl;
    Index: Sim/Projectiles/ExplosiveProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/ExplosiveProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/ExplosiveProjectile.cpp	(working copy)
    @@ -18,18 +18,20 @@
     
     CR_REG_METADATA(CExplosiveProjectile, (
     	CR_MEMBER(ttl),
    -	CR_MEMBER(areaOfEffect)
    +	CR_MEMBER(areaOfEffect),
    +	CR_MEMBER(gravity)
     	));
     
     //////////////////////////////////////////////////////////////////////
     // Construction/Destruction
     //////////////////////////////////////////////////////////////////////
     
    -CExplosiveProjectile::CExplosiveProjectile(const float3& pos,const float3& speed,CUnit* owner, WeaponDef *weaponDef, int ttl,float areaOfEffect)
    +CExplosiveProjectile::CExplosiveProjectile(const float3& pos,const float3& speed,CUnit* owner, WeaponDef *weaponDef, int ttl,float areaOfEffect, float gravity)
     : CWeaponProjectile(pos,speed,owner, 0,ZeroVector,weaponDef,0, true),
     	ttl(ttl),
     	areaOfEffect(areaOfEffect),
    -	curTime(0)
    +	curTime(0),
    +	gravity(gravity)
     {
     	useAirLos=true;
     
    @@ -53,7 +55,7 @@
     void CExplosiveProjectile::Update()
     {
     	pos+=speed;
    -	speed.y+=gs->gravity;
    +	speed.y+=gravity;
     
     	if(!--ttl)
     		Collision();
    @@ -75,6 +77,9 @@
     			float3 n=ground->GetNormal(pos.x,pos.z);
     			pos-=speed*max(0.0f,min(1.0f,float((h-pos.y)*n.y/n.dot(speed)+0.1f)));
     		}
    +		else if (weaponDef->waterweapon) {
    +			return; //let waterweapons go underwater
    +		}
     	}
     //	helper->Explosion(pos,damages,areaOfEffect,owner);
     	CWeaponProjectile::Collision();
    Index: Sim/Projectiles/ExplosiveProjectile.h
    ===================================================================
    --- Sim/Projectiles/ExplosiveProjectile.h	(revision 4220)
    +++ Sim/Projectiles/ExplosiveProjectile.h	(working copy)
    @@ -12,7 +12,7 @@
     {
     	CR_DECLARE(CExplosiveProjectile);
     public:
    -	CExplosiveProjectile(const float3& pos,const float3& speed,CUnit* owner, WeaponDef *weaponDef, int ttl=100000,float areaOfEffect=8);
    +	CExplosiveProjectile(const float3& pos,const float3& speed,CUnit* owner, WeaponDef *weaponDef, int ttl=100000,float areaOfEffect=8,float gravity=0);
     	virtual ~CExplosiveProjectile();
     	virtual void Update();
     	void Draw(void);
    @@ -24,6 +24,7 @@
     	float areaOfEffect;
     	float invttl;
     	float curTime;
    +	float gravity;
     };
     
     #endif // __EXPLOSIVE_PROJECTILE_H__
    Index: Sim/Projectiles/FireBallProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/FireBallProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/FireBallProjectile.cpp	(working copy)
    @@ -3,6 +3,7 @@
     #include "Rendering/GL/VertexArray.h"
     #include "Game/Camera.h"
     #include "Sim/Weapons/WeaponDefHandler.h"
    +#include "Map/Ground.h"
     #include "creg/STL_Deque.h"
     #include "ProjectileHandler.h"
     #include "mmgr.h"
    @@ -125,8 +126,10 @@
     
     void CFireBallProjectile::Collision()
     {
    +	if(weaponDef->waterweapon && ground->GetHeight2(pos.x, pos.z)<pos.y) return; //make waterweapons not explode in water
     	CWeaponProjectile::Collision();
     	deleteMe = false;
     }
     
     
    +
    Index: Sim/Projectiles/FlameProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/FlameProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/FlameProjectile.cpp	(working copy)
    @@ -44,6 +44,7 @@
     
     void CFlameProjectile::Collision(void)
     {
    +	if(ground->GetHeight2(pos.x, pos.z) < pos.y && weaponDef->waterweapon) return; //prevent waterweapons from colliding with water
     	float3 norm=ground->GetNormal(pos.x,pos.z);
     	float ns=speed.dot(norm);
     	speed-=norm*ns*1;
    Index: Sim/Projectiles/LaserProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/LaserProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/LaserProjectile.cpp	(working copy)
    @@ -7,6 +7,7 @@
     #include "ProjectileHandler.h"
     #include "SimpleParticleSystem.h"
     #include "mmgr.h"
    +#include "Map/Ground.h"
     
     CR_BIND_DERIVED(CLaserProjectile, CWeaponProjectile, (float3(0,0,0),float3(0,0,0),NULL,0,float3(0,0,0),float3(0,0,0),0,NULL,0));
     
    @@ -104,6 +105,8 @@
     
     void CLaserProjectile::Collision()
     {
    +	if(weaponDef->waterweapon && ground->GetHeight2(pos.x,pos.z) < pos.y) 
    +		return; //prevent impact on water if waterweapon is set
     	float3 oldPos=pos;
     	CWeaponProjectile::Collision();
     
    Index: Sim/Projectiles/LightingProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/LightingProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/LightingProjectile.cpp	(working copy)
    @@ -59,7 +59,7 @@
     	}
     
     	if(weapon){
    -		pos=weapon->weaponPos;
    +		pos=weapon->weaponMuzzlePos;
     	}
     	for(int a=1;a<10;++a)
     		displacements[a]+=(gs->randFloat()-0.5f)*0.3f;
    Index: Sim/Projectiles/MissileProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/MissileProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/MissileProjectile.cpp	(working copy)
    @@ -119,9 +119,11 @@
     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)));
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldDir,owner,false,true,7,Smoke_Time,0.6f,drawTrail);
    +	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;
    @@ -129,7 +131,8 @@
     
     void CMissileProjectile::Collision(CUnit *unit)
     {
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldDir,owner,false,true,7,Smoke_Time,0.6f,drawTrail);
    +	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);
     
    @@ -207,7 +210,7 @@
     
     	age++;
     	numParts++;
    -	if(!(age&7)){
    +	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;
    @@ -234,66 +237,67 @@
     	float color=0.6f;
     	unsigned char col[4];
     
    -	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;
    +	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;//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);
    +			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;
    Index: Sim/Projectiles/StarburstProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/StarburstProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/StarburstProjectile.cpp	(working copy)
    @@ -67,7 +67,12 @@
     	distanceToTravel(maxdistance)
     {
     	this->uptime=uptime;
    -	ttl=(int)min(3000.f,uptime+(weaponDef?weaponDef->range:0)/maxSpeed+100);
    +	if (weaponDef->flighttime == 0) {
    +		ttl=(int)min(3000.f,uptime+(weaponDef?weaponDef->range:0)/maxSpeed+100);
    +	}
    +	else {
    +		ttl=weaponDef->flighttime;
    +	}
     
     	maxGoodDif=cos(tracking*0.6f);
     	curSpeed=speed.Length();
    @@ -111,9 +116,11 @@
     void CStarburstProjectile::Collision()
     {
     	float h=ground->GetHeight2(pos.x,pos.z);
    +	if(weaponDef->waterweapon && h < pos.y) return; //prevent impact on water if waterweapon is set
     	if(h>pos.y)
     		pos+=speed*(h-pos.y)/speed.y;
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
    +	if (weaponDef->visuals.smokeTrail)
    +		SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
     	oldSmokeDir=dir;
     //	helper->Explosion(pos,damages,areaOfEffect,owner);
     	CWeaponProjectile::Collision();
    @@ -122,7 +129,8 @@
     
     void CStarburstProjectile::Collision(CUnit *unit)
     {
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
    +	if (weaponDef->visuals.smokeTrail)
    +		SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
     	oldSmokeDir=dir;
     //	unit->DoDamage(damages,owner);
     //	helper->Explosion(pos,damages,areaOfEffect,owner);
    @@ -148,8 +156,7 @@
     	}
     	if(uptime>0){
     		if(curSpeed<maxSpeed)
    -			curSpeed+=0.1f;
    -		dir=UpVector;
    +			curSpeed+=weaponDef->weaponacceleration;
     		speed=dir*curSpeed;
     	} else if(doturn && ttl>0 && distanceToTravel>0) {
     		float3 dif(targetPos-pos);
    @@ -161,14 +168,20 @@
     			dif=dif-dir;
     			dif-=dir*(dif.dot(dir));
     			dif.Normalize();
    -			dir+=dif*0.06f;
    +			if (weaponDef->turnrate != 0) {
    +				dir+=dif*weaponDef->turnrate;
    +			}
    +			else {
    +				dir+=dif*0.06;
    +			}
     			dir.Normalize();
     		}
     		speed=dir*curSpeed;
    -		distanceToTravel-=speed.Length2D();
    +		if (distanceToTravel != MAX_WORLD_SIZE)
    +			distanceToTravel-=speed.Length2D();
     	} else if(ttl>0 && distanceToTravel>0) {
     		if(curSpeed<maxSpeed)
    -			curSpeed+=0.1f;
    +			curSpeed+=weaponDef->weaponacceleration;
     		float3 dif(targetPos-pos);
     		dif.Normalize();
     		if(dif.dot(dir)>maxGoodDif){
    @@ -181,7 +194,8 @@
     			dir.Normalize();
     		}
     		speed=dir*curSpeed;
    -		distanceToTravel-=speed.Length2D();
    +		if (distanceToTravel != MAX_WORLD_SIZE)
    +			distanceToTravel-=speed.Length2D();
     	} else {
     		dir.y+=gs->gravity;
     		dir.Normalize();
    @@ -202,7 +216,7 @@
     
     	age++;
     	numParts++;
    -	if(!(age&7)){
    +	if(weaponDef->visuals.smokeTrail && !(age&7)){
     		if(curCallback)
     			curCallback->drawCallbacker=0;
     		curCallback=SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,age==8,false,7,Smoke_Time,0.7f,drawTrail,this);
    @@ -231,65 +245,66 @@
     	unsigned char col[4];
     	unsigned char col2[4];
     
    -	if(drawTrail){		//draw the trail as a single quad
    +	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(oldSmokeDir));
    -		dir2.Normalize();
    +			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(oldSmokeDir));
    +			dir2.Normalize();
     
     
    -		float a1=(1-float(0)/(Smoke_Time))*255;
    -		a1*=0.7f+fabs(dif.dot(dir));
    -		int alpha=min(255,(int)max(0.f,a1));
    -		col[0]=(unsigned char) (color*alpha);
    -		col[1]=(unsigned char) (color*alpha);
    -		col[2]=(unsigned char) (color*alpha);
    -		col[3]=(unsigned char)alpha;
    +			float a1=(1-float(0)/(Smoke_Time))*255;
    +			a1*=0.7f+fabs(dif.dot(dir));
    +			int alpha=min(255,(int)max(0.f,a1));
    +			col[0]=(unsigned char) (color*alpha);
    +			col[1]=(unsigned char) (color*alpha);
    +			col[2]=(unsigned char) (color*alpha);
    +			col[3]=(unsigned char)alpha;
     
    -		float a2=(1-float(age2)/(Smoke_Time))*255;
    -		a2*=0.7f+fabs(dif2.dot(oldSmokeDir));
    -		if(age<8)
    -			a2=0;
    -		alpha=min(255,(int)max(0.f,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 a2=(1-float(age2)/(Smoke_Time))*255;
    +			a2*=0.7f+fabs(dif2.dot(oldSmokeDir));
    +			if(age<8)
    +				a2=0;
    +			alpha=min(255,(int)max(0.f,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 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+oldSmokeDir*dist*0.33f;
    +			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+oldSmokeDir*dist*0.33f;
     
    -		for(int a=0;a<numParts;++a){
    -			//float a1=1-float(a)/Smoke_Time;
    -			col[0]=(unsigned char) (color*255);
    -			col[1]=(unsigned char) (color*255);
    -			col[2]=(unsigned char) (color*255);
    -			col[3]=255;//min(255,max(0,a1*255));
    -			float size=(1+(a)*(1/Smoke_Time)*7);
    +			for(int a=0;a<numParts;++a){
    +				//float a1=1-float(a)/Smoke_Time;
    +				col[0]=(unsigned char) (color*255);
    +				col[1]=(unsigned char) (color*255);
    +				col[2]=(unsigned char) (color*255);
    +				col[3]=255;//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);
    +				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);
    +			}
    +
     		}
    -
    -	}
     	DrawCallback();
     	if(curCallback==0)
     		DrawCallback();
    Index: Sim/Projectiles/StarburstProjectile.h
    ===================================================================
    --- Sim/Projectiles/StarburstProjectile.h	(revision 4220)
    +++ Sim/Projectiles/StarburstProjectile.h	(working copy)
    @@ -30,6 +30,7 @@
     	float3 dir;
     	float maxSpeed;
     	float curSpeed;
    +	float acceleration;
     	int ttl;
     	int uptime;
     	float areaOfEffect;
    Index: Sim/Projectiles/TorpedoProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/TorpedoProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/TorpedoProjectile.cpp	(working copy)
    @@ -10,6 +10,7 @@
     #include "BubbleProjectile.h"
     #include "ProjectileHandler.h"
     #include "mmgr.h"
    +#include "Sim/Weapons/WeaponDefHandler.h"
     
     CR_BIND_DERIVED(CTorpedoProjectile, CTorpedoProjectile, (float3(0,0,0),float3(0,0,0),NULL,0,0,0,0,NULL,NULL));
     
    @@ -82,14 +83,14 @@
     
     void CTorpedoProjectile::Update(void)
     {
    -	if(pos.y>-3){		//tracking etc only work when we have gotten underwater
    +	if(!(weaponDef->submissile) && pos.y>-3){		//tracking etc only work when we have gotten underwater
     		speed.y+=gs->gravity;
     		if(dir.y>0)
     			dir.y=0;
     		dir=speed;
     		dir.Normalize();
     	} else {
    -		if(pos.y-speed.y>-3){		//level out torpedo a bit when hitting water
    +		if(!(weaponDef->submissile) && pos.y-speed.y>-3){		//level out torpedo a bit when hitting water
     			dir.y*=0.5f;
     			dir.Normalize();
     		}
    @@ -103,7 +104,7 @@
     					targPos=target->midPos;
     				else
     					targPos=helper->GetUnitErrorPos(target,owner->allyteam);
    -				if(targPos.y>0)
    +				if(!(weaponDef->submissile) && targPos.y>0)
     					targPos.y=0;
     
     				float dist=targPos.distance(pos);
    Index: Sim/Units/COB/CobFile.cpp
    ===================================================================
    --- Sim/Units/COB/CobFile.cpp	(revision 4220)
    +++ Sim/Units/COB/CobFile.cpp	(working copy)
    @@ -166,7 +166,7 @@
     	}
     
     	//Map common function names to indicies
    -	scriptIndex.resize(COBFN_Last + COB_MaxWeapons * 5);
    +	scriptIndex.resize(COBFN_Last + COB_MaxWeapons * 6);
     	scriptIndex[COBFN_Create] = getFunctionId("Create");
     	scriptIndex[COBFN_StartMoving] = getFunctionId("StartMoving");
     	scriptIndex[COBFN_StopMoving] = getFunctionId("StopMoving");
    @@ -197,6 +197,7 @@
     		scriptIndex[COBFN_AimFromPrimary + i] = getFunctionId("AimFrom" + weapon);
     		scriptIndex[COBFN_FirePrimary + i] = getFunctionId("Fire" + weapon);
     		scriptIndex[COBFN_EndBurst + i] = getFunctionId("EndBurst" + weap);
    +		scriptIndex[COBFN_Shot + i] = getFunctionId("Shot" + weap);
     
     		// If new-naming functions are not found, we need to support the old naming scheme
     		if (i > 2)
    Index: Sim/Units/COB/CobFile.h
    ===================================================================
    --- Sim/Units/COB/CobFile.h	(revision 4220)
    +++ Sim/Units/COB/CobFile.h	(working copy)
    @@ -46,6 +46,7 @@
     const int COBFN_AimFromPrimary = COBFN_AimPrimary + COB_MaxWeapons;
     const int COBFN_FirePrimary = COBFN_AimFromPrimary + COB_MaxWeapons;
     const int COBFN_EndBurst = COBFN_FirePrimary + COB_MaxWeapons;
    +const int COBFN_Shot = COBFN_EndBurst + COB_MaxWeapons;
     
     class CCobFile
     {
    Index: Sim/Units/COB/CobInstance.cpp
    ===================================================================
    --- Sim/Units/COB/CobInstance.cpp	(revision 4220)
    +++ Sim/Units/COB/CobInstance.cpp	(working copy)
    @@ -665,15 +665,15 @@
     				dir.Normalize();
     
     				float3 targetPos = unit->weapons[index]->targetPos;
    -				float3 weaponPos = unit->weapons[index]->weaponPos;
    +				float3 weaponMuzzlePos = unit->weapons[index]->weaponMuzzlePos;
     
     				unit->weapons[index]->targetPos = pos+dir;
    -				unit->weapons[index]->weaponPos = pos;
    +				unit->weapons[index]->weaponMuzzlePos = pos;
     
     				unit->weapons[index]->Fire();
     
     				unit->weapons[index]->targetPos = targetPos;
    -				unit->weapons[index]->weaponPos = weaponPos;
    +				unit->weapons[index]->weaponMuzzlePos = weaponMuzzlePos;
     			}
     			else if (type & 4096) {
     				unsigned index = type - 4096;
    Index: Sim/Units/UnitLoader.cpp
    ===================================================================
    --- Sim/Units/UnitLoader.cpp	(revision 4220)
    +++ Sim/Units/UnitLoader.cpp	(working copy)
    @@ -348,7 +348,7 @@
     	} else if(weapondef->type=="MissileLauncher"){
     		weapon=SAFE_NEW CMissileLauncher(owner);
     	} else if(weapondef->type=="TorpedoLauncher"){
    -		if(owner->unitDef->canfly){
    +		if(owner->unitDef->canfly && !weapondef->submissile){
     			weapon=SAFE_NEW CBombDropper(owner,true);
     			if(weapondef->tracks)
     				((CBombDropper*)weapon)->tracking=weapondef->turnrate;
    @@ -493,3 +493,4 @@
     }
     
     
    +
    Index: Sim/Units/UnitTypes/Builder.cpp
    ===================================================================
    --- Sim/Units/UnitTypes/Builder.cpp	(revision 4220)
    +++ Sim/Units/UnitTypes/Builder.cpp	(working copy)
    @@ -582,9 +582,12 @@
     {
     	float3 wantedDir=(pos-this->pos).Normalize();
     	short int h=GetHeadingFromVector(wantedDir.x,wantedDir.z);
    +	short int p=(short int) (asin(wantedDir.dot(updir))*(32768/PI));
    +	short int pitch=(short int) (asin(frontdir.dot(updir))*(32768/PI));
     
     	std::vector<int> args;
     	args.push_back(short(h-heading));
    +	args.push_back(short(p-pitch));
     	cob->Call("StartBuilding", args);
     
     	int soundIdx = unitDef->sounds.build.getRandomIdx();
    Index: Sim/Weapons/BeamLaser.cpp
    ===================================================================
    --- Sim/Weapons/BeamLaser.cpp	(revision 4220)
    +++ Sim/Weapons/BeamLaser.cpp	(working copy)
    @@ -43,6 +43,7 @@
     {
     	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();
    @@ -77,15 +78,17 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater)
    -			return false;
    -	} else {
    -		if(pos.y<0)
    -			return false;
    +	if(!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater)
    +				return false;
    +		} else {
    +			if(pos.y<0)
    +				return false;
    +		}
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     
     	float length=dir.Length();
     	if(length==0)
    @@ -94,14 +97,14 @@
     	dir/=length;
     
     	if(!onlyForward){		//skip ground col testing for aircrafts
    -		float g=ground->LineGroundCol(weaponPos,pos);
    +		float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     		if(g>0 && g<length*0.9f)
     			return false;
     	}
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -127,7 +130,7 @@
     		if(salvoLeft==salvoSize-1){
     			if(fireSoundId)
     				sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    -			dir=targetPos-weaponPos;
    +			dir=targetPos-weaponMuzzlePos;
     			dir.Normalize();
     			oldDir=dir;
     		} else {
    @@ -151,7 +154,7 @@
     
     	float maxLength=range*rangeMod;
     	float curLength=0;
    -	float3 curPos=weaponPos;
    +	float3 curPos=weaponMuzzlePos;
     	float3 hitPos;
     
     	bool tryAgain=true;
    @@ -220,7 +223,7 @@
     		// Dynamic Damage
     		DamageArray dynDamages;
     		if (weaponDef->dynDamageExp > 0)
    -			dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponPos, curPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
    +			dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponMuzzlePos, curPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
     		helper->Explosion(hitPos, weaponDef->dynDamageExp>0?dynDamages*(intensity*damageMul):weaponDef->damages*(intensity*damageMul), areaOfEffect, weaponDef->edgeEffectiveness, weaponDef->explosionSpeed,owner, true, 1.0f, false, weaponDef->explosionGenerator, hit, dir, weaponDef->id);
     	}
     
    Index: Sim/Weapons/bombdropper.cpp
    ===================================================================
    --- Sim/Weapons/bombdropper.cpp	(revision 4220)
    +++ Sim/Weapons/bombdropper.cpp	(working copy)
    @@ -56,14 +56,14 @@
     		if(weaponPos.y>targetPos.y){
     			float d=targetPos.y-weaponPos.y;
     			float s=-owner->speed.y;
    -			float sq=(s-2*d)/-gs->gravity;
    +			float sq=(s-2*d)/-(weaponDef->myGravity==0 ? gs->gravity : -(weaponDef->myGravity));
     			if(sq>0)
    -				predict=s/gs->gravity+sqrt(sq);
    +				predict=s/(weaponDef->myGravity==0 ? gs->gravity : -(weaponDef->myGravity))+sqrt(sq);
     			else
     				predict=0;
     			float3 hitpos=owner->pos+owner->speed*predict;
     			float speedf=owner->speed.Length();
    -			if(hitpos.distance2D(targetPos)<(salvoSize-1)*speedf*salvoDelay*0.5f+bombMoveRange){
    +			if(hitpos.distance2D(targetPos)<max(1,(salvoSize-1))*speedf*salvoDelay*0.5f+bombMoveRange){
     				subClassReady=true;
     			}
     		}
    @@ -108,7 +108,7 @@
     		float size=dif.Length();
     		if(size>1.0f)
     			dif/=size*1.0f;
    -		SAFE_NEW CExplosiveProjectile(weaponPos,owner->speed+dif,owner, weaponDef, 1000,areaOfEffect);
    +		SAFE_NEW CExplosiveProjectile(weaponPos,owner->speed+dif,owner, weaponDef, 1000,areaOfEffect,weaponDef->myGravity==0 ? gs->gravity : -(weaponDef->myGravity));
     	}
     	//CWeaponProjectile::CreateWeaponProjectile(owner->pos,owner->speed,owner, NULL, float3(0,0,0), damages, weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
    Index: Sim/Weapons/Cannon.cpp
    ===================================================================
    --- Sim/Weapons/Cannon.cpp	(revision 4220)
    +++ Sim/Weapons/Cannon.cpp	(working copy)
    @@ -29,6 +29,7 @@
     	CR_MEMBER(rangeFactor),
     	CR_MEMBER(lastDiff),
     	CR_MEMBER(lastDir),
    +	CR_MEMBER(gravity),
     	CR_RESERVED(16)
     	));
     
    @@ -47,11 +48,12 @@
     
     void CCannon::Init(void)
     {
    +	gravity = weaponDef->myGravity==0 ? gs->gravity : -(weaponDef->myGravity);
     	if(highTrajectory){
    -		maxPredict=projectileSpeed*2/-gs->gravity;
    -		minPredict=projectileSpeed*1.41f/-gs->gravity;
    +		maxPredict=projectileSpeed*2/-gravity;
    +		minPredict=projectileSpeed*1.41f/-gravity;
     	} else {
    -		maxPredict=projectileSpeed*1.41f/-gs->gravity;
    +		maxPredict=projectileSpeed*1.41f/-gravity;
     	}
     	CWeapon::Init();
     
    @@ -79,6 +81,8 @@
     	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;
     		float3 diff = targetPos-weaponPos;
     		wantedDir = GetWantedDir(diff);
     		float speed2D = wantedDir.Length2D() * projectileSpeed;
    @@ -97,24 +101,26 @@
     		return false;
     	}
     
    -	if(unit)
    -	{
    -		if(unit->isUnderWater)
    +	if(!weaponDef->waterweapon) {
    +		if(unit)
     		{
    -			return false;
    +			if(unit->isUnderWater)
    +			{
    +				return false;
    +			}
    +		} else {
    +			if(pos.y<0)
    +			{
    +				return false;
    +			}
     		}
    -	} else {
    -		if(pos.y<0)
    -		{
    -			return false;
    -		}
     	}
     
     	if (projectileSpeed == 0)
     	{
     		return true;
     	}
    -	float3 dif(pos-weaponPos);
    +	float3 dif(pos-weaponMuzzlePos);
     
     	float3 dir(GetWantedDir(dif));
     
    @@ -129,8 +135,8 @@
     	}
     	flatdir/=flatlength;
     
    -	float gc=ground->TrajectoryGroundCol(weaponPos, flatdir, flatlength-10,
    -			dir.y , gs->gravity / (projectileSpeed * projectileSpeed) * 0.5f);
    +	float gc=ground->TrajectoryGroundCol(weaponMuzzlePos, flatdir, flatlength-10,
    +			dir.y , gravity / (projectileSpeed * projectileSpeed) * 0.5f);
     	if(gc>0) {
     		return false;
     	}
    @@ -139,8 +145,8 @@
     	if(gc>0 && gc<length*0.40f)
     		return false;
     */
    -	if(avoidFriendly && helper->TestTrajectoryCone(weaponPos, flatdir,
    -		flatlength-30, dir.y, gs->gravity /
    +	if(avoidFriendly && helper->TestTrajectoryCone(weaponMuzzlePos, flatdir,
    +		flatlength-30, dir.y, gravity /
     		(projectileSpeed * projectileSpeed) * 0.5f,
     		(accuracy+sprayangle) * 0.6f * (1-owner->limExperience * 0.9f) * 0.9f,
     		3, owner->allyteam, owner))
    @@ -162,7 +168,7 @@
     
     void CCannon::Fire(void)
     {
    -	float3 diff = targetPos-weaponPos;
    +	float3 diff = targetPos-weaponMuzzlePos;
     	float3 dir=GetWantedDir(diff);
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.9f);
     	dir.Normalize();
    @@ -172,14 +178,14 @@
     #endif
     	int ttl = 0;
     	float sqSpeed2D = dir.SqLength2D() * projectileSpeed * projectileSpeed;
    -	int predict = (int)ceil((sqSpeed2D == 0) ? (-2 * projectileSpeed * dir.y / gs->gravity)
    +	int predict = (int)ceil((sqSpeed2D == 0) ? (-2 * projectileSpeed * dir.y / gravity)
     			: sqrt(diff.SqLength2D() / sqSpeed2D));
     	if(selfExplode) {
     		ttl=(int)(predict+gs->randFloat()*2.5f-0.5f);
     	} else {
     		ttl=predict*2;
     	}
    -	SAFE_NEW CExplosiveProjectile(weaponPos,dir*projectileSpeed,owner,weaponDef, ttl,areaOfEffect);
    +	SAFE_NEW CExplosiveProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,weaponDef, ttl,areaOfEffect,gravity);
     	//CWeaponProjectile::CreateWeaponProjectile(weaponPos,owner->speed,owner, NULL, float3(0,0,0), weaponDef);
     
     //	SAFE_NEW CSmokeProjectile(weaponPos,dir*0.01f,90,0.1f,0.02f,owner,0.6f);
    @@ -188,8 +194,8 @@
     //	p->maxheat=p->heat;
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    -	if(weaponPos.y<30)
    - 		water->AddExplosion(weaponPos,damages[0]*0.1f,sqrt(damages[0])+80);
    +//	if(weaponMuzzlePos.y<30)
    +//		water->AddExplosion(weaponMuzzlePos,damages[0]*0.1f,sqrt(damages[0])+80);
     }
     
     void CCannon::SlowUpdate(void)
    @@ -197,10 +203,10 @@
     	if(owner->useHighTrajectory!=highTrajectory){
     		highTrajectory=owner->useHighTrajectory;
     		if(highTrajectory){
    -			maxPredict=projectileSpeed*2/-gs->gravity;
    -			minPredict=projectileSpeed*1.41f/-gs->gravity;
    +			maxPredict=projectileSpeed*2/-gravity;
    +			minPredict=projectileSpeed*1.41f/-gravity;
     		} else {
    -			maxPredict=projectileSpeed*1.41f/-gs->gravity;
    +			maxPredict=projectileSpeed*1.41f/-gravity;
     		}
     	}
     	CWeapon::SlowUpdate();
    @@ -229,7 +235,7 @@
     
     	float Dsq = diff.SqLength();
     	float DFsq = diff.SqLength2D();
    -	float g = gs->gravity;
    +	float g = gravity;
     	float v = projectileSpeed;
     	float dy = diff.y;
     	float dxz = sqrt(DFsq);
    @@ -279,10 +285,10 @@
     		// f(0) == 1, f(smoothHeight) == heightBoostFactor
     		yDiff *= 1.f + (heightBoostFactor-1.f) * (-yDiff)/smoothHeight;
     
    -	float root1 = speed2dSq + 2*gs->gravity*yDiff;
    +	float root1 = speed2dSq + 2*gravity*yDiff;
     	if(root1 < 0.f){
     		return 0.f;
     	} else {
    -		return rangeFactor*(speed2dSq + speed2d*sqrt(root1))/(-gs->gravity);
    +		return rangeFactor*(speed2dSq + speed2d*sqrt(root1))/(-gravity);
     	}
     }
    Index: Sim/Weapons/Cannon.h
    ===================================================================
    --- Sim/Weapons/Cannon.h	(revision 4220)
    +++ Sim/Weapons/Cannon.h	(working copy)
    @@ -36,6 +36,8 @@
     	bool highTrajectory;
     	/// burnblow tag. defines flakker-like behaviour
     	bool selfExplode;
    +	/// projectile gravity
    +	float gravity;
     
     	void SlowUpdate(void);
     	/// tells where to point the gun to hit the point at pos+diff
    Index: Sim/Weapons/DGunWeapon.cpp
    ===================================================================
    --- Sim/Weapons/DGunWeapon.cpp	(revision 4220)
    +++ Sim/Weapons/DGunWeapon.cpp	(working copy)
    @@ -27,7 +27,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -46,13 +47,13 @@
     	if(onlyForward){
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
     	dir.Normalize();
     
    -	SAFE_NEW CFireBallProjectile(weaponPos,dir*projectileSpeed,owner,0,targetPos,weaponDef);
    +	SAFE_NEW CFireBallProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,0,targetPos,weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume*0.2f);
     }
    Index: Sim/Weapons/EmgCannon.cpp
    ===================================================================
    --- Sim/Weapons/EmgCannon.cpp	(revision 4220)
    +++ Sim/Weapons/EmgCannon.cpp	(working copy)
    @@ -31,7 +31,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -45,29 +46,31 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater)
    -			return false;
    -	} else {
    -		if(pos.y<0)
    -			return false;
    +	if (!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater)
    +				return false;
    +		} else {
    +			if(pos.y<0)
    +				return false;
    +		}
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.5f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.5f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -87,15 +90,17 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType)){		//the taairmovetype cant align itself properly, change back when that is fixed
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
     	dir.Normalize();
     
    -	SAFE_NEW CEmgProjectile(weaponPos,dir*projectileSpeed,owner,weaponDef->visuals.color,weaponDef->intensity,(int)(range/projectileSpeed), weaponDef);
    +	SAFE_NEW CEmgProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,weaponDef->visuals.color,weaponDef->intensity,(int)(range/projectileSpeed), weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
     
     
    +
    +
    Index: Sim/Weapons/FlameThrower.cpp
    ===================================================================
    --- Sim/Weapons/FlameThrower.cpp	(revision 4220)
    +++ Sim/Weapons/FlameThrower.cpp	(working copy)
    @@ -27,12 +27,12 @@
     
     void CFlameThrower::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
     	float3 spread=(gs->randVector()*sprayangle+salvoError)*0.2f;
     	spread-=dir*0.001f;
     
    -	SAFE_NEW CFlameProjectile(weaponPos,dir*projectileSpeed,spread,owner,weaponDef,(int)(range/projectileSpeed*weaponDef->duration));
    +	SAFE_NEW CFlameProjectile(weaponMuzzlePos,dir*projectileSpeed,spread,owner,weaponDef,(int)(range/projectileSpeed*weaponDef->duration));
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    @@ -42,29 +42,31 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater)
    -			return false;
    -	} else {
    -		if(pos.y<0)
    -			return false;
    +	if (!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater)
    +				return false;
    +		} else {
    +			if(pos.y<0)
    +				return false;
    +		}
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner)){
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner)){
     		return false;
     	}
     	return true;
    @@ -74,6 +76,7 @@
     {
     	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;
     		wantedDir=targetPos-weaponPos;
     		wantedDir.Normalize();
     	}
    Index: Sim/Weapons/LaserCannon.cpp
    ===================================================================
    --- Sim/Weapons/LaserCannon.cpp	(revision 4220)
    +++ Sim/Weapons/LaserCannon.cpp	(working copy)
    @@ -30,7 +30,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -45,14 +46,14 @@
     		return false;
     
     	if(unit){
    -		if(unit->isUnderWater)
    +		if(unit->isUnderWater && !weaponDef->waterweapon)
     			return false;
     	} else {
    -		if(pos.y<0)
    +		if(pos.y<0 && !weaponDef->waterweapon)
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
    @@ -60,14 +61,14 @@
     	dir/=length;
     
     	if(!onlyForward){		//skip ground col testing for aircrafts
    -		float g=ground->LineGroundCol(weaponPos,pos);
    +		float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     		if(g>0 && g<length*0.9f)
     			return false;
     	}
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -84,7 +85,7 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType)){		//the taairmovetype cant align itself properly, change back when that is fixed
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.7f);
    @@ -96,10 +97,12 @@
     		fpsSub=6;
     #endif
     
    -	SAFE_NEW CLaserProjectile(weaponPos, dir*projectileSpeed, owner, weaponDef->duration*weaponDef->maxvelocity, weaponDef->visuals.color, weaponDef->visuals.color2, weaponDef->intensity, weaponDef, (int)((weaponDef->range-fpsSub*4)/weaponDef->projectilespeed)-fpsSub);
    +	SAFE_NEW CLaserProjectile(weaponMuzzlePos, dir*projectileSpeed, owner, weaponDef->duration*weaponDef->maxvelocity, weaponDef->visuals.color, weaponDef->visuals.color2, weaponDef->intensity, weaponDef, (int)((weaponDef->range-fpsSub*4)/weaponDef->projectilespeed)-fpsSub);
     
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
     
     
    +
    +
    Index: Sim/Weapons/LightingCannon.cpp
    ===================================================================
    --- Sim/Weapons/LightingCannon.cpp	(revision 4220)
    +++ Sim/Weapons/LightingCannon.cpp	(working copy)
    @@ -31,6 +31,7 @@
     {
     	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();
    @@ -44,29 +45,31 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater)
    -			return false;
    -	} else {
    -		if(pos.y<0)
    -			return false;
    +	if(!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater)
    +				return false;
    +		} else {
    +			if(pos.y<0)
    +				return false;
    +		}
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -78,16 +81,16 @@
     
     void CLightingCannon::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
     	dir.Normalize();
     	CUnit* u=0;
    -	float r=helper->TraceRay(weaponPos,dir,range,0,owner,u);
    +	float r=helper->TraceRay(weaponMuzzlePos,dir,range,0,owner,u);
     
     	float3 newDir;
     	CPlasmaRepulser* shieldHit;
    -	float shieldLength=interceptHandler.AddShieldInterceptableBeam(this,weaponPos,dir,range,newDir,shieldHit);
    +	float shieldLength=interceptHandler.AddShieldInterceptableBeam(this,weaponMuzzlePos,dir,range,newDir,shieldHit);
     	if(shieldLength<r){
     		r=shieldLength;
     		if(shieldHit) {
    @@ -101,11 +104,11 @@
     	// Dynamic Damage
     	DamageArray dynDamages;
     	if (weaponDef->dynDamageExp > 0)
    -		dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponPos, targetPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
    +		dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponMuzzlePos, targetPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
     
    -	helper->Explosion(weaponPos+dir*r,weaponDef->dynDamageExp>0?dynDamages:weaponDef->damages,areaOfEffect,weaponDef->edgeEffectiveness,weaponDef->explosionSpeed,owner,false,0.5f,true,weaponDef->explosionGenerator, u,dir, weaponDef->id);
    +	helper->Explosion(weaponMuzzlePos+dir*r,weaponDef->dynDamageExp>0?dynDamages:weaponDef->damages,areaOfEffect,weaponDef->edgeEffectiveness,weaponDef->explosionSpeed,owner,false,0.5f,true,weaponDef->explosionGenerator, u,dir, weaponDef->id);
     
    -	SAFE_NEW CLightingProjectile(weaponPos,weaponPos+dir*(r+10),owner,color,weaponDef,10,this);
    +	SAFE_NEW CLightingProjectile(weaponMuzzlePos,weaponMuzzlePos+dir*(r+10),owner,color,weaponDef,10,this);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     
    Index: Sim/Weapons/MeleeWeapon.cpp
    ===================================================================
    --- Sim/Weapons/MeleeWeapon.cpp	(revision 4220)
    +++ Sim/Weapons/MeleeWeapon.cpp	(working copy)
    @@ -33,21 +33,23 @@
     {
     	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();
    -
     }
     
     void CMeleeWeapon::Fire(void)
     {
     	if(targetType==Target_Unit){
    -		float3 impulseDir = targetUnit->pos-weaponPos;
    +		float3 impulseDir = targetUnit->pos-weaponMuzzlePos;
     		impulseDir.Normalize();
    -		targetUnit->DoDamage(damages,owner,impulseDir,weaponDef->id);
    +		// the heavier the unit, the more impulse it does
    +		targetUnit->DoDamage(damages,owner,impulseDir*owner->mass,weaponDef->id);
     		if(fireSoundId)
     			sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     	}
    Index: Sim/Weapons/MissileLauncher.cpp
    ===================================================================
    --- Sim/Weapons/MissileLauncher.cpp	(revision 4220)
    +++ Sim/Weapons/MissileLauncher.cpp	(working copy)
    @@ -29,7 +29,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			float dist=wantedDir.Length();
     			predict=dist/projectileSpeed;
    @@ -49,12 +50,15 @@
     	if(onlyForward){
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     		if(weaponDef->trajectoryHeight>0){
     			dir.y+=weaponDef->trajectoryHeight;
     			dir.Normalize();
     		}
    +		if (weaponDef->fixedLauncher) {
    +			dir=weaponDir;
    +		}
     	}
     
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
    @@ -64,7 +68,7 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType))
     		startSpeed+=owner->speed;
     
    -	SAFE_NEW CMissileProjectile(weaponPos,startSpeed,owner,areaOfEffect,projectileSpeed,(int)(range/projectileSpeed+25),targetUnit, weaponDef,targetPos);
    +	SAFE_NEW CMissileProjectile(weaponMuzzlePos,startSpeed,owner,areaOfEffect,projectileSpeed,weaponDef->flighttime==0 ? (int)(range/projectileSpeed+25) : weaponDef->flighttime,targetUnit, weaponDef,targetPos);
     	//CWeaponProjectile::CreateWeaponProjectile(weaponPos,startSpeed,owner,targetUnit, float3(0,0,0), weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    @@ -75,15 +79,17 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater){
    -			return false;
    +	if (!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater){
    +				return false;
    +			}
    +		} else {
    +			if(pos.y<0)
    +				return false;
     		}
    -	} else {
    -		if(pos.y<0)
    -			return false;
     	}
    -	float3 dir=pos-weaponPos;
    +	float3 dir = pos-weaponMuzzlePos;
     	if(weaponDef->trajectoryHeight>0){	//do a different test depending on if the missile has a high trajectory or not
     		float3 flatdir(dir.x,0,dir.z);
     		dir.Normalize();
    @@ -95,11 +101,11 @@
     		float linear=dir.y+weaponDef->trajectoryHeight;
     		float quadratic=-weaponDef->trajectoryHeight/flatlength;
     
    -		float gc=ground->TrajectoryGroundCol(weaponPos,flatdir,flatlength-30,linear,quadratic);
    +		float gc=ground->TrajectoryGroundCol(weaponMuzzlePos,flatdir,flatlength-30,linear,quadratic);
     		if(gc>0)
     			return false;
     
    -		if(avoidFriendly && helper->TestTrajectoryCone(weaponPos,flatdir,flatlength-30,linear,quadratic,0,8,owner->allyteam,owner)){
    +		if(avoidFriendly && helper->TestTrajectoryCone(weaponMuzzlePos,flatdir,flatlength-30,linear,quadratic,0,8,owner->allyteam,owner)){
     			return false;
     		}
     	} else {
    @@ -110,7 +116,7 @@
     		dir/=length;
     
     		if(!onlyForward){		//skip ground col testing for aircrafts
    -			float g=ground->LineGroundCol(weaponPos,pos);
    +			float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     			if(g>0 && g<length*0.9f)
     				return false;
     		} else {
    @@ -119,7 +125,7 @@
     			if(owner->frontdir.dot(goaldir) < maxAngleDif)
     				return false;
     		}
    -		if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
    +		if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
     			return false;
     	}
     	return true;
    Index: Sim/Weapons/PlasmaRepulser.cpp
    ===================================================================
    --- Sim/Weapons/PlasmaRepulser.cpp	(revision 4220)
    +++ Sim/Weapons/PlasmaRepulser.cpp	(working copy)
    @@ -70,6 +70,8 @@
     
     	if(weaponDef->shieldPower==0)
     		curPower=99999999999.0f;
    +	else
    +		curPower=weaponDef->shieldStartingPower;
     
     	CWeapon::Init();
     }
    Index: Sim/Weapons/Rifle.cpp
    ===================================================================
    --- Sim/Weapons/Rifle.cpp	(revision 4220)
    +++ Sim/Weapons/Rifle.cpp	(working copy)
    @@ -41,6 +41,7 @@
     {
     	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;
     		wantedDir=targetPos-weaponPos;
     		wantedDir.Normalize();
     	}
    @@ -60,18 +61,18 @@
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.9f),owner->allyteam,owner)){
    +	if(helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.9f),owner->allyteam,owner)){
     		return false;
     	}
     	return true;
    @@ -79,7 +80,7 @@
     
     void CRifle::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.9f);
     	dir.Normalize();
    @@ -88,13 +89,13 @@
     	tracefile << owner->pos.x << " " << dir.x << " " << targetPos.x << " " << targetPos.y << " " << targetPos.z << "\n";
     #endif
     	CUnit* hit;
    -	float length=helper->TraceRay(weaponPos,dir,range,damages[0],owner,hit,collisionFlags);
    +	float length=helper->TraceRay(weaponMuzzlePos,dir,range,damages[0],owner,hit,collisionFlags);
     	if(hit){
     		hit->DoDamage(damages,owner,ZeroVector, weaponDef->id);
    -		SAFE_NEW CHeatCloudProjectile(weaponPos+dir*length,hit->speed*0.9f,30,1,owner);
    +		SAFE_NEW CHeatCloudProjectile(weaponMuzzlePos+dir*length,hit->speed*0.9f,30,1,owner);
     	}
    -	SAFE_NEW CTracerProjectile(weaponPos,dir*projectileSpeed,length,owner);
    -	SAFE_NEW CSmokeProjectile(weaponPos,float3(0,0.0f,0),70,0.1f,0.02f,owner,0.6f);
    +	SAFE_NEW CTracerProjectile(weaponMuzzlePos,dir*projectileSpeed,length,owner);
    +	SAFE_NEW CSmokeProjectile(weaponMuzzlePos,float3(0,0.0f,0),70,0.1f,0.02f,owner,0.6f);
     	if(fireSoundId)
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    Index: Sim/Weapons/StarburstLauncher.cpp
    ===================================================================
    --- Sim/Weapons/StarburstLauncher.cpp	(revision 4220)
    +++ Sim/Weapons/StarburstLauncher.cpp	(working copy)
    @@ -32,6 +32,7 @@
     {
     	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;
     		wantedDir=(targetPos-weaponPos).Normalize();		//the aiming upward is apperently implicid so aim toward target
     	}
     	CWeapon::Update();
    @@ -39,7 +40,15 @@
     
     void CStarburstLauncher::Fire(void)
     {
    -	CStarburstProjectile* p=SAFE_NEW CStarburstProjectile(weaponPos+float3(0,2,0),float3(0,0.01f,0),owner,targetPos,areaOfEffect,projectileSpeed,tracking,(int)uptime,targetUnit, weaponDef,interceptTarget,range);
    +	float3 speed(0,weaponDef->startvelocity,0);
    +	float maxrange;
    +	if (weaponDef->fixedLauncher) {
    +		speed = weaponDir * weaponDef->startvelocity;
    +		maxrange = (float)MAX_WORLD_SIZE;
    +	} else {
    +		maxrange = (float)range;
    +	}
    +	CStarburstProjectile* p=SAFE_NEW CStarburstProjectile(weaponMuzzlePos+float3(0,2,0),speed,owner,targetPos,areaOfEffect,projectileSpeed,tracking,(int)uptime,targetUnit, weaponDef,interceptTarget, maxrange);
     
     	if(weaponDef->targetable)
     		interceptHandler.AddInterceptTarget(p,targetPos);
    @@ -54,14 +63,15 @@
     		return false;
     
     	if(unit){
    -		if(unit->isUnderWater)
    +		if(unit->isUnderWater && !weaponDef->waterweapon)
     			return false;
     	} else {
    -		if(pos.y<0)
    +		if(pos.y<0 && !weaponDef->waterweapon)
     			return false;
     	}
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,UpVector,100,0,owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,
    +			(weaponDef->fixedLauncher ? weaponDir : UpVector), 100, 0, owner->allyteam, owner))
     		return false;
     
     	return true;
    Index: Sim/Weapons/TorpedoLauncher.cpp
    ===================================================================
    --- Sim/Weapons/TorpedoLauncher.cpp	(revision 4220)
    +++ Sim/Weapons/TorpedoLauncher.cpp	(working copy)
    @@ -32,7 +32,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -//		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +//		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			float dist=wantedDir.Length();
     			predict=dist/projectileSpeed;
    @@ -48,18 +49,24 @@
     //	if(onlyForward){
     //		dir=owner->frontdir;
     //	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     		if(weaponDef->trajectoryHeight>0){
     			dir.y+=weaponDef->trajectoryHeight;
     			dir.Normalize();
     		}
     //	}
    -	float3 startSpeed=dir*weaponDef->startvelocity;
    +	float3 startSpeed;
    +	if (!weaponDef->fixedLauncher) {
    +		startSpeed=dir*weaponDef->startvelocity;
    +	}
    +	else {
    +		startSpeed=weaponDir*weaponDef->startvelocity;
    +	}
     
     //	if(onlyForward)
     //		startSpeed+=owner->speed*0.5f;
    -	SAFE_NEW CTorpedoProjectile(weaponPos,startSpeed,owner,areaOfEffect,projectileSpeed,tracking,(int)(range/projectileSpeed+15),targetUnit, weaponDef);
    +	SAFE_NEW CTorpedoProjectile(weaponMuzzlePos,startSpeed,owner,areaOfEffect,projectileSpeed,tracking,weaponDef->flighttime==0 ? (int)(range/projectileSpeed+25) : weaponDef->flighttime,targetUnit, weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    @@ -70,22 +77,22 @@
     		return false;
     
     	if(unit){
    -		if(unit->unitDef->canhover)
    +		if(!(weaponDef->submissile) && unit->unitDef->canhover)
     			return false;
    -		if(unit->unitDef->canfly && unit->pos.y>0)
    +		if(!(weaponDef->submissile) && unit->unitDef->canfly && unit->pos.y>0)
     			return false;
     	}
    -	if(ground->GetHeight2(pos.x,pos.z)>0)
    +	if(!(weaponDef->submissile) && ground->GetHeight2(pos.x,pos.z)>0)
     		return 0;
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)+0.05f,owner->allyteam,owner))	//+0.05f since torpedoes has an unfortunate tendency to hit own ships due to movement
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)+0.05f,owner->allyteam,owner))	//+0.05f since torpedoes has an unfortunate tendency to hit own ships due to movement
     		return false;
     	return true;
     }
    Index: Sim/Weapons/Weapon.cpp
    ===================================================================
    --- Sim/Weapons/Weapon.cpp	(revision 4220)
    +++ Sim/Weapons/Weapon.cpp	(working copy)
    @@ -57,9 +57,11 @@
     	CR_MEMBER(subClassReady),
     	CR_MEMBER(onlyForward),
     	CR_MEMBER(weaponPos),
    +	CR_MEMBER(weaponMuzzlePos),
     	CR_MEMBER(lastRequest),
     	CR_MEMBER(damages),
     	CR_MEMBER(relWeaponPos),
    +	CR_MEMBER(relWeaponMuzzlePos),
     	CR_MEMBER(muzzleFlareSize),
     	CR_MEMBER(lastTargetRetry),
     	CR_MEMBER(areaOfEffect),
    @@ -133,8 +135,10 @@
     	subClassReady(true),
     	onlyForward(false),
     	weaponPos(0,0,0),
    +	weaponMuzzlePos(0,0,0),
     	lastRequest(0),
     	relWeaponPos(0,1,0),
    +	relWeaponMuzzlePos(0,1,0),
     	muzzleFlareSize(1),
     	lastTargetRetry(-100),
     	areaOfEffect(1),
    @@ -177,11 +181,14 @@
     	if(hasCloseTarget){
     		std::vector<int> args;
     		args.push_back(0);
    -		if(useWeaponPosForAim){
    +		if(useWeaponPosForAim){ //if we couldn't get a line of fire from the muzzle try if we can get it from the aim piece
     			owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
     		} else {
     			owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     		}
    +		relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
    +
    +		owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     		relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     	}
     
    @@ -259,16 +266,18 @@
     	&& subClassReady
     	&& reloadStatus<=gs->frameNum
     	&& (!weaponDef->stockpile || numStockpiled)
    -	&& (weaponDef->waterweapon || weaponPos.y>0)
    +	&& (weaponDef->fireSubmersed || weaponMuzzlePos.y>0)
     	&& (owner->unitDef->maxFuel==0 || owner->currentFuel > 0)
     	){
     		if ((weaponDef->stockpile || (gs->Team(owner->team)->metal>=metalFireCost && gs->Team(owner->team)->energy>=energyFireCost))) {
     			std::vector<int> args;
     			args.push_back(0);
     			owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    -			relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
    -			weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +			owner->localmodel->GetEmitDirPos(args[0], relWeaponMuzzlePos, weaponDir);
    +			weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
     			useWeaponPosForAim=reloadTime/16+8;
    +			weaponDir = owner->frontdir * weaponDir.z + owner->updir * weaponDir.y + owner->rightdir * weaponDir.x;
    +			weaponDir.Normalize();
     
     			if(TryTarget(targetPos,haveUserTarget,targetUnit)){
     				if(weaponDef->stockpile){
    @@ -304,35 +313,52 @@
     			}
     		}
     	}
    -	if(salvoLeft && nextSalvo<=gs->frameNum){
    +	if(salvoLeft && nextSalvo<=gs->frameNum ){
     		salvoLeft--;
     		nextSalvo=gs->frameNum+salvoDelay;
     		owner->lastFireWeapon=gs->frameNum;
    +		
    +		int projectiles = weaponDef->projectilespershot;
    +		
    +		while(projectiles > 0) {
    +			--projectiles;
    +			
    +			// add to the commandShotCount if this is the last salvo,
    +			// and it is being directed towards the current target
    +			// (helps when deciding if a queued ground attack order has been completed)
    +			if ((salvoLeft == 0) && (owner->commandShotCount >= 0) &&
    +			    ((targetType == Target_Pos) && (targetPos == owner->userAttackPos)) ||
    +					((targetType == Target_Unit) && (targetUnit == owner->userTarget))) {
    +				owner->commandShotCount++;
    +			}
    +	
    +			std::vector<int> args;
    +			args.push_back(0);
    +	
    +			owner->cob->Call(COBFN_Shot+weaponNum,0);
    +	
    +			owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
    +			relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     
    -		// add to the commandShotCount if this is the last salvo,
    -		// and it is being directed towards the current target
    -		// (helps when deciding if a queued ground attack order has been completed)
    -		if ((salvoLeft == 0) && (owner->commandShotCount >= 0) &&
    -		    ((targetType == Target_Pos) && (targetPos == owner->userAttackPos)) ||
    -				((targetType == Target_Unit) && (targetUnit == owner->userTarget))) {
    -			owner->commandShotCount++;
    -		}
    +			owner->cob->Call(/*COBFN_AimFromPrimary+weaponNum*/COBFN_QueryPrimary+weaponNum/**/,args);
    +			owner->localmodel->GetEmitDirPos(args[0], relWeaponMuzzlePos, weaponDir);
     
    -		std::vector<int> args;
    -		args.push_back(0);
    -		owner->cob->Call(/*COBFN_AimFromPrimary+weaponNum/*/COBFN_QueryPrimary+weaponNum/**/,args);
    -		relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
    -		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +			weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
     
    -//		logOutput.Print("RelPosFire %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
    -
    -		if (owner->unitDef->decloakOnFire && (owner->scriptCloak <= 2)) {
    -			owner->isCloaked = false;
    -			owner->curCloakTimeout = gs->frameNum + owner->cloakTimeout;
    +			weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +			weaponDir = owner->frontdir * weaponDir.z + owner->updir * weaponDir.y + owner->rightdir * weaponDir.x;
    +			weaponDir.Normalize();
    +	
    +	//		logOutput.Print("RelPosFire %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
    +	
    +			if (owner->unitDef->decloakOnFire && (owner->scriptCloak <= 2)) {
    +				owner->isCloaked = false;
    +				owner->curCloakTimeout = gs->frameNum + owner->cloakTimeout;
    +			}
    +	
    +			Fire();
     		}
     
    -		Fire();
    -
     		//Rock the unit in the direction of the fireing
     		float3 rockDir = wantedDir;
     		rockDir.y = 0;
    @@ -363,9 +389,9 @@
     
     	if(!weaponDef->waterweapon && pos.y<1)
     		pos.y=1;
    -	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -	if(weaponPos.y<ground->GetHeight2(weaponPos.x,weaponPos.z))
    -		weaponPos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +	if(weaponMuzzlePos.y<ground->GetHeight2(weaponMuzzlePos.x,weaponMuzzlePos.z))
    +		weaponMuzzlePos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
     
     	if(!TryTarget(pos,userTarget,0))
     		return false;
    @@ -388,8 +414,10 @@
     
     	weaponPos= owner->pos + owner->frontdir * relWeaponPos.z
     		+ owner->updir * relWeaponPos.y + owner->rightdir * relWeaponPos.x;
    -	if(weaponPos.y < ground->GetHeight2(weaponPos.x, weaponPos.z))
    -		weaponPos = owner->pos + UpVector * 10;
    +	weaponMuzzlePos= owner->pos + owner->frontdir * relWeaponMuzzlePos.z
    +		+ owner->updir * relWeaponMuzzlePos.y + owner->rightdir * relWeaponMuzzlePos.x;
    +	if(weaponMuzzlePos.y < ground->GetHeight2(weaponMuzzlePos.x, weaponMuzzlePos.z))
    +		weaponMuzzlePos = owner->pos + UpVector * 10;
     	//hope that we are underground because we are a popup weapon and will come above ground later
     
     	if(!unit){
    @@ -437,18 +465,23 @@
     #endif
     	std::vector<int> args;
     	args.push_back(0);
    -	if(useWeaponPosForAim){
    +	if(useWeaponPosForAim){ //If we can't get a line of fire from the muzzle try the aim piece instead since the weapon may just be turned in a wrong way
     		owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
     		if(useWeaponPosForAim>1)
     			useWeaponPosForAim--;
     	} else {
     		owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     	}
    +	relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +
    +	owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     	relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -	if(weaponPos.y<ground->GetHeight2(weaponPos.x,weaponPos.z))
    -		weaponPos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
     
    +	if(weaponMuzzlePos.y<ground->GetHeight2(weaponMuzzlePos.x,weaponMuzzlePos.z))
    +		weaponMuzzlePos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
    +
     	predictSpeedMod=1+(gs->randFloat()-0.5f)*2*(1-owner->limExperience);
     
     	if((targetPos-weaponPos).SqLength() < relWeaponPos.SqLength()*16)
    @@ -552,7 +585,7 @@
     	if(weaponDef->stockpile && !numStockpiled)
     		return false;
     
    -	float3 dif=pos-weaponPos;
    +	float3 dif=pos-weaponMuzzlePos;
     	float heightDiff; // negative when target below owner
     
     	if (targetBorder != 0 && unit) {
    @@ -624,11 +657,13 @@
     	owner->frontdir = GetVectorFromHeading(owner->heading);
     	owner->rightdir = owner->frontdir.cross(owner->updir);
     	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;
     	bool val = TryTarget(tempTargetPos,userTarget,unit);
     	owner->frontdir = tempfrontdir;
     	owner->rightdir = temprightdir;
     	owner->heading = tempHeadding;
     	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;
     	return val;
     }
     
    @@ -654,11 +689,13 @@
     	owner->frontdir = GetVectorFromHeading(owner->heading);
     	owner->rightdir = owner->frontdir.cross(owner->updir);
     	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;
     	bool val = TryTarget(pos, userTarget, 0);
     	owner->frontdir = tempfrontdir;
     	owner->rightdir = temprightdir;
     	owner->heading = tempHeadding;
     	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;
     	return val;
     }
     
    @@ -669,6 +706,10 @@
     	owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     	relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +
    +	owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    +	relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
     //	logOutput.Print("RelPos %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
     
     	if (range > owner->maxRange) {
    Index: Sim/Weapons/Weapon.h
    ===================================================================
    --- Sim/Weapons/Weapon.h	(revision 4220)
    +++ Sim/Weapons/Weapon.h	(working copy)
    @@ -60,6 +60,11 @@
     
     	float3 relWeaponPos;				//weaponpos relative to the unit
     	float3 weaponPos;						//absolute weapon pos
    +
    +	float3 relWeaponMuzzlePos;			//position of the firepoint
    +	float3 weaponMuzzlePos;
    +	float3 weaponDir;
    +
     	float muzzleFlareSize;			//size of muzzle flare if drawn
     	int useWeaponPosForAim;			//sometimes weapon pos is better to use than aimpos
     	bool hasCloseTarget;					//might need to update weapon pos more often when enemy is near
    Index: Sim/Weapons/WeaponDefHandler.cpp
    ===================================================================
    --- Sim/Weapons/WeaponDefHandler.cpp	(revision 4220)
    +++ Sim/Weapons/WeaponDefHandler.cpp	(working copy)
    @@ -67,6 +67,7 @@
     	bool ballistic;
     	//bool twophase;
     	bool beamweapon;
    +	bool manualBombSettings; //Allow the user to manually specify the burst and burstrate for his AircraftBomb
     	//bool guided;
     	//bool vlaunch;
     	int rendertype;
    @@ -94,6 +95,7 @@
     	sunparser->GetDef(weaponDefs[id].minIntensity, "0", weaponname + "\\MinIntensity");
     
     	sunparser->GetDef(weaponDefs[id].dropped, "0", weaponname + "\\dropped");
    +	sunparser->GetDef(manualBombSettings, "0", weaponname + "\\manualbombsettings");
     	sunparser->GetDef(lineofsight, "0", weaponname + "\\lineofsight");
     	sunparser->GetDef(ballistic, "0", weaponname + "\\ballistic");
     	sunparser->GetDef(weaponDefs[id].twophase, "0", weaponname + "\\twophase");
    @@ -110,7 +112,10 @@
     	sunparser->GetDef(weaponDefs[id].noSelfDamage, "0", weaponname + "\\NoSelfDamage");
     
     	sunparser->GetDef(weaponDefs[id].waterweapon, "0", weaponname + "\\waterweapon");
    +	sunparser->GetDef(weaponDefs[id].fireSubmersed, weaponDefs[id].waterweapon ? "1":"0", weaponname + "\\firesubmersed");
    +	sunparser->GetDef(weaponDefs[id].submissile, "0", weaponname + "\\submissile");
     	sunparser->GetDef(weaponDefs[id].tracks, "0", weaponname + "\\tracks");
    +	sunparser->GetDef(weaponDefs[id].fixedLauncher, "0", weaponname + "\\FixedLauncher");
     	sunparser->GetDef(weaponDefs[id].noExplode, "0", weaponname + "\\NoExplode");
     	sunparser->GetDef(weaponDefs[id].maxvelocity, "0", weaponname + "\\weaponvelocity");
     	sunparser->GetDef(weaponDefs[id].isShield, "0", weaponname + "\\IsShield");
    @@ -256,6 +261,7 @@
     	weaponDefs[id].reload = atof(sunparser->SGetValueDef("1", weaponname + "\\reloadtime").c_str());
     	weaponDefs[id].salvodelay = atof(sunparser->SGetValueDef("0.1", weaponname + "\\burstrate").c_str());
     	sunparser->GetDef(weaponDefs[id].salvosize, "1", weaponname + "\\burst");
    +	sunparser->GetDef(weaponDefs[id].projectilespershot, "1", weaponname + "\\projectiles");
     	weaponDefs[id].maxAngle = atof(sunparser->SGetValueDef("3000", weaponname + "\\tolerance").c_str()) * 180.0f / 0x7fff;
     	weaponDefs[id].restTime = 0.0f;
     	sunparser->GetDef(weaponDefs[id].metalcost, "0", weaponname + "\\metalpershot");
    @@ -263,6 +269,7 @@
     	sunparser->GetDef(weaponDefs[id].selfExplode, "0", weaponname + "\\burnblow");
     	sunparser->GetDef(weaponDefs[id].sweepFire, "0", weaponname + "\\sweepfire");
     	sunparser->GetDef(weaponDefs[id].canAttackGround, "1", weaponname + "\\canattackground");
    +	weaponDefs[id].myGravity = atof(sunparser->SGetValueDef("0", weaponname + "\\myGravity").c_str());
     
     	weaponDefs[id].fireStarter=atof(sunparser->SGetValueDef("0", weaponname + "\\firestarter").c_str())*0.01f;
     	weaponDefs[id].paralyzer=!!atoi(sunparser->SGetValueDef("0", weaponname + "\\paralyzer").c_str());
    @@ -292,6 +299,7 @@
     	sunparser->GetDef(weaponDefs[id].shieldPower, "0", weaponname + "\\shieldpower");
     	sunparser->GetDef(weaponDefs[id].shieldPowerRegen, "0", weaponname + "\\shieldpowerregen");
     	sunparser->GetDef(weaponDefs[id].shieldPowerRegenEnergy, "0", weaponname + "\\shieldpowerregenenergy");
    +	sunparser->GetDef(weaponDefs[id].shieldStartingPower, "0", weaponname + "\\shieldstartingpower");
     	sunparser->GetDef(weaponDefs[id].shieldInterceptType, "0", weaponname + "\\shieldintercepttype");
     	weaponDefs[id].shieldGoodColor=sunparser->GetFloat3(float3(0.5f,0.5f,1),weaponname + "\\shieldgoodcolor");
     	weaponDefs[id].shieldBadColor=sunparser->GetFloat3(float3(1,0.5f,0.5f),weaponname + "\\shieldbadcolor");
    @@ -353,10 +361,11 @@
     		weaponDefs[id].visuals.color = tempCol;
     
     	weaponDefs[id].uptime = atof(sunparser->SGetValueDef("0", weaponname + "\\weapontimer").c_str());
    +	weaponDefs[id].flighttime = atof(sunparser->SGetValueDef("0", weaponname + "\\flighttime").c_str()) * 32;
     
     	weaponDefs[id].turnrate = atof(sunparser->SGetValueDef("0", weaponname + "\\turnrate").c_str()) * PI / 0x7fff /30.0f;
     
    -	if(weaponDefs[id].type=="AircraftBomb"){
    +	if(weaponDefs[id].type=="AircraftBomb" && !manualBombSettings){
     		if(weaponDefs[id].reload<0.5f){
     			weaponDefs[id].salvodelay=min(0.2f,weaponDefs[id].reload);
     			weaponDefs[id].salvosize=(int)(1/weaponDefs[id].salvodelay)+1;
    Index: Sim/Weapons/WeaponDefHandler.h
    ===================================================================
    --- Sim/Weapons/WeaponDefHandler.h	(revision 4220)
    +++ Sim/Weapons/WeaponDefHandler.h	(working copy)
    @@ -67,17 +67,23 @@
     	float restTime;
     
     	float uptime;
    +	int flighttime;
     
     	float metalcost;
     	float energycost;
     	float supplycost;
     
    +	int projectilespershot;
    +
     	int id;
     	int tdfId;	//the id= tag in the tdf
     
     	bool turret;
     	bool onlyForward;
    +	bool fixedLauncher;
     	bool waterweapon;
    +	bool fireSubmersed;
    +	bool submissile; //Lets a torpedo travel above water like it does below water
     	bool tracks;
     	bool dropped;
     	bool paralyzer;			//weapon will only paralyze not do real damage
    @@ -102,6 +108,7 @@
     
     	bool selfExplode;
     	bool gravityAffected;
    +	float myGravity;
     	bool twophase;
     	bool guided;
     	bool vlaunch;
    @@ -165,6 +172,7 @@
     	float shieldPower;			//how much damage the shield can reflect (0=infinite)
     	float shieldPowerRegen;	//how fast the power regenerates per second
     	float shieldPowerRegenEnergy;	//how much energy is needed to regenerate power per second
    +	float shieldStartingPower;	//how much power the shield has when first created
     	float3 shieldGoodColor;			//color when shield at full power
     	float3 shieldBadColor;			//color when shield is empty
     	float shieldAlpha;					//shield alpha value
    Index: System/GlobalStuff.h
    ===================================================================
    --- System/GlobalStuff.h	(revision 4220)
    +++ System/GlobalStuff.h	(working copy)
    @@ -20,7 +20,7 @@
      *
      * Defines the maximum world size as 1000000
      */
    -#define MAX_WORLD_SIZE 1000000;
    +#define MAX_WORLD_SIZE 1000000
     
     /**
      * @brief square size
    @@ -260,42 +260,42 @@
     
     	/**
     	 * @brief disable helper AIs
    -	 * 
    +	 *
     	 * Whether helper AIs are allow, including GroupAI and LuaUI control widgets
     	 */
     	bool noHelperAIs;
     
     	/**
     	 * @brief definition editing enabled
    -	 * 
    +	 *
     	 * Whether definition editing is enabled
     	 */
     	bool editDefsEnabled;
     
     	/**
     	 * @brief LuaRules control
    -	 * 
    +	 *
     	 * Whether or not LuaRules is enabled
     	 */
     	bool useLuaRules;
     
     	/**
     	 * @brief LuaGaia control
    -	 * 
    +	 *
     	 * Whether or not LuaGaia is enabled
     	 */
     	bool useLuaGaia;
     
     	/**
     	 * @brief gaia team
    -	 * 
    +	 *
     	 * gaia's team id
     	 */
     	int gaiaTeamID;
     
     	/**
     	 * @brief gaia team
    -	 * 
    +	 *
     	 * gaia's team id
     	 */
     	int gaiaAllyTeamID;
    
    patch file icon kdr11k_weapon_changes_r4220.patch (79,395 bytes) 2007-08-18 14:16 +
  • patch file icon kdr11k_weapon_changes_r4220_v2.patch (80,018 bytes) 2007-08-18 17:05 -
    Index: Sim/Projectiles/EmgProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/EmgProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/EmgProjectile.cpp	(working copy)
    @@ -4,6 +4,7 @@
     #include "Rendering/GL/VertexArray.h"
     #include "Sync/SyncTracer.h"
     #include "ProjectileHandler.h"
    +#include "Map/Ground.h"
     #include "Sim/Weapons/WeaponDefHandler.h"
     #include "mmgr.h"
     
    @@ -52,10 +53,14 @@
     void CEmgProjectile::Collision(CUnit* unit)
     {
     //	unit->DoDamage(damages,owner);
    -
     	CWeaponProjectile::Collision(unit);
     }
     
    +void CEmgProjectile::Collision() {
    +	if (!(weaponDef->waterweapon && ground->GetHeight2(pos.x, pos.z) < pos.y))
    +		CWeaponProjectile::Collision();
    +}
    +
     void CEmgProjectile::Draw(void)
     {
     	inArray=true;
    Index: Sim/Projectiles/EmgProjectile.h
    ===================================================================
    --- Sim/Projectiles/EmgProjectile.h	(revision 4220)
    +++ Sim/Projectiles/EmgProjectile.h	(working copy)
    @@ -14,6 +14,7 @@
     	void Update(void);
     	void Draw(void);
     	void Collision(CUnit* unit);
    +	void Collision();
     	int ShieldRepulse(CPlasmaRepulser* shield,float3 shieldPos, float shieldForce, float shieldMaxSpeed);
     
     	int ttl;
    Index: Sim/Projectiles/ExplosiveProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/ExplosiveProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/ExplosiveProjectile.cpp	(working copy)
    @@ -18,18 +18,20 @@
     
     CR_REG_METADATA(CExplosiveProjectile, (
     	CR_MEMBER(ttl),
    -	CR_MEMBER(areaOfEffect)
    +	CR_MEMBER(areaOfEffect),
    +	CR_MEMBER(gravity)
     	));
     
     //////////////////////////////////////////////////////////////////////
     // Construction/Destruction
     //////////////////////////////////////////////////////////////////////
     
    -CExplosiveProjectile::CExplosiveProjectile(const float3& pos,const float3& speed,CUnit* owner, WeaponDef *weaponDef, int ttl,float areaOfEffect)
    +CExplosiveProjectile::CExplosiveProjectile(const float3& pos,const float3& speed,CUnit* owner, WeaponDef *weaponDef, int ttl,float areaOfEffect, float gravity)
     : CWeaponProjectile(pos,speed,owner, 0,ZeroVector,weaponDef,0, true),
     	ttl(ttl),
     	areaOfEffect(areaOfEffect),
    -	curTime(0)
    +	curTime(0),
    +	gravity(gravity)
     {
     	useAirLos=true;
     
    @@ -53,7 +55,7 @@
     void CExplosiveProjectile::Update()
     {
     	pos+=speed;
    -	speed.y+=gs->gravity;
    +	speed.y+=gravity;
     
     	if(!--ttl)
     		Collision();
    @@ -75,6 +77,9 @@
     			float3 n=ground->GetNormal(pos.x,pos.z);
     			pos-=speed*max(0.0f,min(1.0f,float((h-pos.y)*n.y/n.dot(speed)+0.1f)));
     		}
    +		else if (weaponDef->waterweapon) {
    +			return; //let waterweapons go underwater
    +		}
     	}
     //	helper->Explosion(pos,damages,areaOfEffect,owner);
     	CWeaponProjectile::Collision();
    Index: Sim/Projectiles/ExplosiveProjectile.h
    ===================================================================
    --- Sim/Projectiles/ExplosiveProjectile.h	(revision 4220)
    +++ Sim/Projectiles/ExplosiveProjectile.h	(working copy)
    @@ -12,7 +12,7 @@
     {
     	CR_DECLARE(CExplosiveProjectile);
     public:
    -	CExplosiveProjectile(const float3& pos,const float3& speed,CUnit* owner, WeaponDef *weaponDef, int ttl=100000,float areaOfEffect=8);
    +	CExplosiveProjectile(const float3& pos,const float3& speed,CUnit* owner, WeaponDef *weaponDef, int ttl=100000,float areaOfEffect=8,float gravity=0);
     	virtual ~CExplosiveProjectile();
     	virtual void Update();
     	void Draw(void);
    @@ -24,6 +24,7 @@
     	float areaOfEffect;
     	float invttl;
     	float curTime;
    +	float gravity;
     };
     
     #endif // __EXPLOSIVE_PROJECTILE_H__
    Index: Sim/Projectiles/FireBallProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/FireBallProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/FireBallProjectile.cpp	(working copy)
    @@ -3,6 +3,7 @@
     #include "Rendering/GL/VertexArray.h"
     #include "Game/Camera.h"
     #include "Sim/Weapons/WeaponDefHandler.h"
    +#include "Map/Ground.h"
     #include "creg/STL_Deque.h"
     #include "ProjectileHandler.h"
     #include "mmgr.h"
    @@ -125,8 +126,10 @@
     
     void CFireBallProjectile::Collision()
     {
    +	if(weaponDef->waterweapon && ground->GetHeight2(pos.x, pos.z)<pos.y) return; //make waterweapons not explode in water
     	CWeaponProjectile::Collision();
     	deleteMe = false;
     }
     
     
    +
    Index: Sim/Projectiles/FlameProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/FlameProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/FlameProjectile.cpp	(working copy)
    @@ -44,6 +44,7 @@
     
     void CFlameProjectile::Collision(void)
     {
    +	if(ground->GetHeight2(pos.x, pos.z) < pos.y && weaponDef->waterweapon) return; //prevent waterweapons from colliding with water
     	float3 norm=ground->GetNormal(pos.x,pos.z);
     	float ns=speed.dot(norm);
     	speed-=norm*ns*1;
    Index: Sim/Projectiles/LaserProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/LaserProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/LaserProjectile.cpp	(working copy)
    @@ -7,6 +7,7 @@
     #include "ProjectileHandler.h"
     #include "SimpleParticleSystem.h"
     #include "mmgr.h"
    +#include "Map/Ground.h"
     
     CR_BIND_DERIVED(CLaserProjectile, CWeaponProjectile, (float3(0,0,0),float3(0,0,0),NULL,0,float3(0,0,0),float3(0,0,0),0,NULL,0));
     
    @@ -104,6 +105,8 @@
     
     void CLaserProjectile::Collision()
     {
    +	if(weaponDef->waterweapon && ground->GetHeight2(pos.x,pos.z) < pos.y) 
    +		return; //prevent impact on water if waterweapon is set
     	float3 oldPos=pos;
     	CWeaponProjectile::Collision();
     
    Index: Sim/Projectiles/LightingProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/LightingProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/LightingProjectile.cpp	(working copy)
    @@ -59,7 +59,7 @@
     	}
     
     	if(weapon){
    -		pos=weapon->weaponPos;
    +		pos=weapon->weaponMuzzlePos;
     	}
     	for(int a=1;a<10;++a)
     		displacements[a]+=(gs->randFloat()-0.5f)*0.3f;
    Index: Sim/Projectiles/MissileProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/MissileProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/MissileProjectile.cpp	(working copy)
    @@ -119,9 +119,11 @@
     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)));
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldDir,owner,false,true,7,Smoke_Time,0.6f,drawTrail);
    +	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;
    @@ -129,7 +131,8 @@
     
     void CMissileProjectile::Collision(CUnit *unit)
     {
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldDir,owner,false,true,7,Smoke_Time,0.6f,drawTrail);
    +	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);
     
    @@ -207,7 +210,7 @@
     
     	age++;
     	numParts++;
    -	if(!(age&7)){
    +	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;
    @@ -234,66 +237,67 @@
     	float color=0.6f;
     	unsigned char col[4];
     
    -	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;
    +	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;//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);
    +			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;
    Index: Sim/Projectiles/StarburstProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/StarburstProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/StarburstProjectile.cpp	(working copy)
    @@ -15,6 +15,8 @@
     #include "ProjectileHandler.h"
     #include "mmgr.h"
     
    +#include "LogOutput.h"
    +
     static const float Smoke_Time=70;
     
     CR_BIND_DERIVED(CStarburstProjectile, CWeaponProjectile, (float3(0,0,0),float3(0,0,0),NULL,float3(0,0,0),0,0,0,0,NULL,NULL,NULL,0));
    @@ -67,7 +69,12 @@
     	distanceToTravel(maxdistance)
     {
     	this->uptime=uptime;
    -	ttl=(int)min(3000.f,uptime+(weaponDef?weaponDef->range:0)/maxSpeed+100);
    +	if (weaponDef->flighttime == 0) {
    +		ttl=(int)min(3000.f,uptime+(weaponDef?weaponDef->range:0)/maxSpeed+100);
    +	}
    +	else {
    +		ttl=weaponDef->flighttime;
    +	}
     
     	maxGoodDif=cos(tracking*0.6f);
     	curSpeed=speed.Length();
    @@ -111,9 +118,11 @@
     void CStarburstProjectile::Collision()
     {
     	float h=ground->GetHeight2(pos.x,pos.z);
    +	if(weaponDef->waterweapon && h < pos.y) return; //prevent impact on water if waterweapon is set
     	if(h>pos.y)
     		pos+=speed*(h-pos.y)/speed.y;
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
    +	if (weaponDef->visuals.smokeTrail)
    +		SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
     	oldSmokeDir=dir;
     //	helper->Explosion(pos,damages,areaOfEffect,owner);
     	CWeaponProjectile::Collision();
    @@ -122,7 +131,8 @@
     
     void CStarburstProjectile::Collision(CUnit *unit)
     {
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
    +	if (weaponDef->visuals.smokeTrail)
    +		SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
     	oldSmokeDir=dir;
     //	unit->DoDamage(damages,owner);
     //	helper->Explosion(pos,damages,areaOfEffect,owner);
    @@ -148,8 +158,7 @@
     	}
     	if(uptime>0){
     		if(curSpeed<maxSpeed)
    -			curSpeed+=0.1f;
    -		dir=UpVector;
    +			curSpeed+=weaponDef->weaponacceleration;
     		speed=dir*curSpeed;
     	} else if(doturn && ttl>0 && distanceToTravel>0) {
     		float3 dif(targetPos-pos);
    @@ -161,14 +170,20 @@
     			dif=dif-dir;
     			dif-=dir*(dif.dot(dir));
     			dif.Normalize();
    -			dir+=dif*0.06f;
    +			if (weaponDef->turnrate != 0) {
    +				dir+=dif*weaponDef->turnrate;
    +			}
    +			else {
    +				dir+=dif*0.06;
    +			}
     			dir.Normalize();
     		}
     		speed=dir*curSpeed;
    -		distanceToTravel-=speed.Length2D();
    +		if (distanceToTravel != MAX_WORLD_SIZE)
    +			distanceToTravel-=speed.Length2D();
     	} else if(ttl>0 && distanceToTravel>0) {
     		if(curSpeed<maxSpeed)
    -			curSpeed+=0.1f;
    +			curSpeed+=weaponDef->weaponacceleration;
     		float3 dif(targetPos-pos);
     		dif.Normalize();
     		if(dif.dot(dir)>maxGoodDif){
    @@ -181,7 +196,8 @@
     			dir.Normalize();
     		}
     		speed=dir*curSpeed;
    -		distanceToTravel-=speed.Length2D();
    +		if (distanceToTravel != MAX_WORLD_SIZE)
    +			distanceToTravel-=speed.Length2D();
     	} else {
     		dir.y+=gs->gravity;
     		dir.Normalize();
    @@ -202,7 +218,7 @@
     
     	age++;
     	numParts++;
    -	if(!(age&7)){
    +	if(weaponDef->visuals.smokeTrail && !(age&7)){
     		if(curCallback)
     			curCallback->drawCallbacker=0;
     		curCallback=SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,age==8,false,7,Smoke_Time,0.7f,drawTrail,this);
    @@ -231,65 +247,66 @@
     	unsigned char col[4];
     	unsigned char col2[4];
     
    -	if(drawTrail){		//draw the trail as a single quad
    +	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(oldSmokeDir));
    -		dir2.Normalize();
    +			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(oldSmokeDir));
    +			dir2.Normalize();
     
     
    -		float a1=(1-float(0)/(Smoke_Time))*255;
    -		a1*=0.7f+fabs(dif.dot(dir));
    -		int alpha=min(255,(int)max(0.f,a1));
    -		col[0]=(unsigned char) (color*alpha);
    -		col[1]=(unsigned char) (color*alpha);
    -		col[2]=(unsigned char) (color*alpha);
    -		col[3]=(unsigned char)alpha;
    +			float a1=(1-float(0)/(Smoke_Time))*255;
    +			a1*=0.7f+fabs(dif.dot(dir));
    +			int alpha=min(255,(int)max(0.f,a1));
    +			col[0]=(unsigned char) (color*alpha);
    +			col[1]=(unsigned char) (color*alpha);
    +			col[2]=(unsigned char) (color*alpha);
    +			col[3]=(unsigned char)alpha;
     
    -		float a2=(1-float(age2)/(Smoke_Time))*255;
    -		a2*=0.7f+fabs(dif2.dot(oldSmokeDir));
    -		if(age<8)
    -			a2=0;
    -		alpha=min(255,(int)max(0.f,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 a2=(1-float(age2)/(Smoke_Time))*255;
    +			a2*=0.7f+fabs(dif2.dot(oldSmokeDir));
    +			if(age<8)
    +				a2=0;
    +			alpha=min(255,(int)max(0.f,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 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+oldSmokeDir*dist*0.33f;
    +			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+oldSmokeDir*dist*0.33f;
     
    -		for(int a=0;a<numParts;++a){
    -			//float a1=1-float(a)/Smoke_Time;
    -			col[0]=(unsigned char) (color*255);
    -			col[1]=(unsigned char) (color*255);
    -			col[2]=(unsigned char) (color*255);
    -			col[3]=255;//min(255,max(0,a1*255));
    -			float size=(1+(a)*(1/Smoke_Time)*7);
    +			for(int a=0;a<numParts;++a){
    +				//float a1=1-float(a)/Smoke_Time;
    +				col[0]=(unsigned char) (color*255);
    +				col[1]=(unsigned char) (color*255);
    +				col[2]=(unsigned char) (color*255);
    +				col[3]=255;//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);
    +				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);
    +			}
    +
     		}
    -
    -	}
     	DrawCallback();
     	if(curCallback==0)
     		DrawCallback();
    Index: Sim/Projectiles/StarburstProjectile.h
    ===================================================================
    --- Sim/Projectiles/StarburstProjectile.h	(revision 4220)
    +++ Sim/Projectiles/StarburstProjectile.h	(working copy)
    @@ -30,6 +30,7 @@
     	float3 dir;
     	float maxSpeed;
     	float curSpeed;
    +	float acceleration;
     	int ttl;
     	int uptime;
     	float areaOfEffect;
    Index: Sim/Projectiles/TorpedoProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/TorpedoProjectile.cpp	(revision 4220)
    +++ Sim/Projectiles/TorpedoProjectile.cpp	(working copy)
    @@ -10,6 +10,7 @@
     #include "BubbleProjectile.h"
     #include "ProjectileHandler.h"
     #include "mmgr.h"
    +#include "Sim/Weapons/WeaponDefHandler.h"
     
     CR_BIND_DERIVED(CTorpedoProjectile, CTorpedoProjectile, (float3(0,0,0),float3(0,0,0),NULL,0,0,0,0,NULL,NULL));
     
    @@ -82,14 +83,14 @@
     
     void CTorpedoProjectile::Update(void)
     {
    -	if(pos.y>-3){		//tracking etc only work when we have gotten underwater
    +	if(!(weaponDef->submissile) && pos.y>-3){		//tracking etc only work when we have gotten underwater
     		speed.y+=gs->gravity;
     		if(dir.y>0)
     			dir.y=0;
     		dir=speed;
     		dir.Normalize();
     	} else {
    -		if(pos.y-speed.y>-3){		//level out torpedo a bit when hitting water
    +		if(!(weaponDef->submissile) && pos.y-speed.y>-3){		//level out torpedo a bit when hitting water
     			dir.y*=0.5f;
     			dir.Normalize();
     		}
    @@ -103,7 +104,7 @@
     					targPos=target->midPos;
     				else
     					targPos=helper->GetUnitErrorPos(target,owner->allyteam);
    -				if(targPos.y>0)
    +				if(!(weaponDef->submissile) && targPos.y>0)
     					targPos.y=0;
     
     				float dist=targPos.distance(pos);
    Index: Sim/Units/COB/CobFile.cpp
    ===================================================================
    --- Sim/Units/COB/CobFile.cpp	(revision 4220)
    +++ Sim/Units/COB/CobFile.cpp	(working copy)
    @@ -166,7 +166,7 @@
     	}
     
     	//Map common function names to indicies
    -	scriptIndex.resize(COBFN_Last + COB_MaxWeapons * 5);
    +	scriptIndex.resize(COBFN_Last + COB_MaxWeapons * 6);
     	scriptIndex[COBFN_Create] = getFunctionId("Create");
     	scriptIndex[COBFN_StartMoving] = getFunctionId("StartMoving");
     	scriptIndex[COBFN_StopMoving] = getFunctionId("StopMoving");
    @@ -197,6 +197,7 @@
     		scriptIndex[COBFN_AimFromPrimary + i] = getFunctionId("AimFrom" + weapon);
     		scriptIndex[COBFN_FirePrimary + i] = getFunctionId("Fire" + weapon);
     		scriptIndex[COBFN_EndBurst + i] = getFunctionId("EndBurst" + weap);
    +		scriptIndex[COBFN_Shot + i] = getFunctionId("Shot" + weap);
     
     		// If new-naming functions are not found, we need to support the old naming scheme
     		if (i > 2)
    Index: Sim/Units/COB/CobFile.h
    ===================================================================
    --- Sim/Units/COB/CobFile.h	(revision 4220)
    +++ Sim/Units/COB/CobFile.h	(working copy)
    @@ -46,6 +46,7 @@
     const int COBFN_AimFromPrimary = COBFN_AimPrimary + COB_MaxWeapons;
     const int COBFN_FirePrimary = COBFN_AimFromPrimary + COB_MaxWeapons;
     const int COBFN_EndBurst = COBFN_FirePrimary + COB_MaxWeapons;
    +const int COBFN_Shot = COBFN_EndBurst + COB_MaxWeapons;
     
     class CCobFile
     {
    Index: Sim/Units/COB/CobInstance.cpp
    ===================================================================
    --- Sim/Units/COB/CobInstance.cpp	(revision 4220)
    +++ Sim/Units/COB/CobInstance.cpp	(working copy)
    @@ -665,15 +665,15 @@
     				dir.Normalize();
     
     				float3 targetPos = unit->weapons[index]->targetPos;
    -				float3 weaponPos = unit->weapons[index]->weaponPos;
    +				float3 weaponMuzzlePos = unit->weapons[index]->weaponMuzzlePos;
     
     				unit->weapons[index]->targetPos = pos+dir;
    -				unit->weapons[index]->weaponPos = pos;
    +				unit->weapons[index]->weaponMuzzlePos = pos;
     
     				unit->weapons[index]->Fire();
     
     				unit->weapons[index]->targetPos = targetPos;
    -				unit->weapons[index]->weaponPos = weaponPos;
    +				unit->weapons[index]->weaponMuzzlePos = weaponMuzzlePos;
     			}
     			else if (type & 4096) {
     				unsigned index = type - 4096;
    Index: Sim/Units/UnitLoader.cpp
    ===================================================================
    --- Sim/Units/UnitLoader.cpp	(revision 4220)
    +++ Sim/Units/UnitLoader.cpp	(working copy)
    @@ -348,7 +348,7 @@
     	} else if(weapondef->type=="MissileLauncher"){
     		weapon=SAFE_NEW CMissileLauncher(owner);
     	} else if(weapondef->type=="TorpedoLauncher"){
    -		if(owner->unitDef->canfly){
    +		if(owner->unitDef->canfly && !weapondef->submissile){
     			weapon=SAFE_NEW CBombDropper(owner,true);
     			if(weapondef->tracks)
     				((CBombDropper*)weapon)->tracking=weapondef->turnrate;
    @@ -377,7 +377,7 @@
     			((CStarburstLauncher*)weapon)->tracking=weapondef->turnrate;
     		else
     			((CStarburstLauncher*)weapon)->tracking=0;
    -		((CStarburstLauncher*)weapon)->uptime=weapondef->uptime*30;
    +		((CStarburstLauncher*)weapon)->uptime=weapondef->uptime*GAME_SPEED;
     	}else {
     		logOutput << "Unknown weapon type " << weapondef->type.c_str() << "\n";
     		return 0;
    @@ -493,3 +493,4 @@
     }
     
     
    +
    Index: Sim/Units/UnitTypes/Builder.cpp
    ===================================================================
    --- Sim/Units/UnitTypes/Builder.cpp	(revision 4220)
    +++ Sim/Units/UnitTypes/Builder.cpp	(working copy)
    @@ -582,9 +582,12 @@
     {
     	float3 wantedDir=(pos-this->pos).Normalize();
     	short int h=GetHeadingFromVector(wantedDir.x,wantedDir.z);
    +	short int p=(short int) (asin(wantedDir.dot(updir))*(32768/PI));
    +	short int pitch=(short int) (asin(frontdir.dot(updir))*(32768/PI));
     
     	std::vector<int> args;
     	args.push_back(short(h-heading));
    +	args.push_back(short(p-pitch));
     	cob->Call("StartBuilding", args);
     
     	int soundIdx = unitDef->sounds.build.getRandomIdx();
    Index: Sim/Weapons/BeamLaser.cpp
    ===================================================================
    --- Sim/Weapons/BeamLaser.cpp	(revision 4220)
    +++ Sim/Weapons/BeamLaser.cpp	(working copy)
    @@ -43,6 +43,7 @@
     {
     	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();
    @@ -77,15 +78,17 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater)
    -			return false;
    -	} else {
    -		if(pos.y<0)
    -			return false;
    +	if(!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater)
    +				return false;
    +		} else {
    +			if(pos.y<0)
    +				return false;
    +		}
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     
     	float length=dir.Length();
     	if(length==0)
    @@ -94,14 +97,14 @@
     	dir/=length;
     
     	if(!onlyForward){		//skip ground col testing for aircrafts
    -		float g=ground->LineGroundCol(weaponPos,pos);
    +		float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     		if(g>0 && g<length*0.9f)
     			return false;
     	}
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -127,7 +130,7 @@
     		if(salvoLeft==salvoSize-1){
     			if(fireSoundId)
     				sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    -			dir=targetPos-weaponPos;
    +			dir=targetPos-weaponMuzzlePos;
     			dir.Normalize();
     			oldDir=dir;
     		} else {
    @@ -151,7 +154,7 @@
     
     	float maxLength=range*rangeMod;
     	float curLength=0;
    -	float3 curPos=weaponPos;
    +	float3 curPos=weaponMuzzlePos;
     	float3 hitPos;
     
     	bool tryAgain=true;
    @@ -220,7 +223,7 @@
     		// Dynamic Damage
     		DamageArray dynDamages;
     		if (weaponDef->dynDamageExp > 0)
    -			dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponPos, curPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
    +			dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponMuzzlePos, curPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
     		helper->Explosion(hitPos, weaponDef->dynDamageExp>0?dynDamages*(intensity*damageMul):weaponDef->damages*(intensity*damageMul), areaOfEffect, weaponDef->edgeEffectiveness, weaponDef->explosionSpeed,owner, true, 1.0f, false, weaponDef->explosionGenerator, hit, dir, weaponDef->id);
     	}
     
    Index: Sim/Weapons/bombdropper.cpp
    ===================================================================
    --- Sim/Weapons/bombdropper.cpp	(revision 4220)
    +++ Sim/Weapons/bombdropper.cpp	(working copy)
    @@ -56,14 +56,14 @@
     		if(weaponPos.y>targetPos.y){
     			float d=targetPos.y-weaponPos.y;
     			float s=-owner->speed.y;
    -			float sq=(s-2*d)/-gs->gravity;
    +			float sq=(s-2*d)/-(weaponDef->myGravity==0 ? gs->gravity : -(weaponDef->myGravity));
     			if(sq>0)
    -				predict=s/gs->gravity+sqrt(sq);
    +				predict=s/(weaponDef->myGravity==0 ? gs->gravity : -(weaponDef->myGravity))+sqrt(sq);
     			else
     				predict=0;
     			float3 hitpos=owner->pos+owner->speed*predict;
     			float speedf=owner->speed.Length();
    -			if(hitpos.distance2D(targetPos)<(salvoSize-1)*speedf*salvoDelay*0.5f+bombMoveRange){
    +			if(hitpos.distance2D(targetPos)<max(1,(salvoSize-1))*speedf*salvoDelay*0.5f+bombMoveRange){
     				subClassReady=true;
     			}
     		}
    @@ -108,7 +108,7 @@
     		float size=dif.Length();
     		if(size>1.0f)
     			dif/=size*1.0f;
    -		SAFE_NEW CExplosiveProjectile(weaponPos,owner->speed+dif,owner, weaponDef, 1000,areaOfEffect);
    +		SAFE_NEW CExplosiveProjectile(weaponPos,owner->speed+dif,owner, weaponDef, 1000,areaOfEffect,weaponDef->myGravity==0 ? gs->gravity : -(weaponDef->myGravity));
     	}
     	//CWeaponProjectile::CreateWeaponProjectile(owner->pos,owner->speed,owner, NULL, float3(0,0,0), damages, weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
    Index: Sim/Weapons/Cannon.cpp
    ===================================================================
    --- Sim/Weapons/Cannon.cpp	(revision 4220)
    +++ Sim/Weapons/Cannon.cpp	(working copy)
    @@ -29,6 +29,7 @@
     	CR_MEMBER(rangeFactor),
     	CR_MEMBER(lastDiff),
     	CR_MEMBER(lastDir),
    +	CR_MEMBER(gravity),
     	CR_RESERVED(16)
     	));
     
    @@ -47,11 +48,12 @@
     
     void CCannon::Init(void)
     {
    +	gravity = weaponDef->myGravity==0 ? gs->gravity : -(weaponDef->myGravity);
     	if(highTrajectory){
    -		maxPredict=projectileSpeed*2/-gs->gravity;
    -		minPredict=projectileSpeed*1.41f/-gs->gravity;
    +		maxPredict=projectileSpeed*2/-gravity;
    +		minPredict=projectileSpeed*1.41f/-gravity;
     	} else {
    -		maxPredict=projectileSpeed*1.41f/-gs->gravity;
    +		maxPredict=projectileSpeed*1.41f/-gravity;
     	}
     	CWeapon::Init();
     
    @@ -79,6 +81,8 @@
     	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;
     		float3 diff = targetPos-weaponPos;
     		wantedDir = GetWantedDir(diff);
     		float speed2D = wantedDir.Length2D() * projectileSpeed;
    @@ -97,24 +101,26 @@
     		return false;
     	}
     
    -	if(unit)
    -	{
    -		if(unit->isUnderWater)
    +	if(!weaponDef->waterweapon) {
    +		if(unit)
     		{
    -			return false;
    +			if(unit->isUnderWater)
    +			{
    +				return false;
    +			}
    +		} else {
    +			if(pos.y<0)
    +			{
    +				return false;
    +			}
     		}
    -	} else {
    -		if(pos.y<0)
    -		{
    -			return false;
    -		}
     	}
     
     	if (projectileSpeed == 0)
     	{
     		return true;
     	}
    -	float3 dif(pos-weaponPos);
    +	float3 dif(pos-weaponMuzzlePos);
     
     	float3 dir(GetWantedDir(dif));
     
    @@ -129,8 +135,8 @@
     	}
     	flatdir/=flatlength;
     
    -	float gc=ground->TrajectoryGroundCol(weaponPos, flatdir, flatlength-10,
    -			dir.y , gs->gravity / (projectileSpeed * projectileSpeed) * 0.5f);
    +	float gc=ground->TrajectoryGroundCol(weaponMuzzlePos, flatdir, flatlength-10,
    +			dir.y , gravity / (projectileSpeed * projectileSpeed) * 0.5f);
     	if(gc>0) {
     		return false;
     	}
    @@ -139,8 +145,8 @@
     	if(gc>0 && gc<length*0.40f)
     		return false;
     */
    -	if(avoidFriendly && helper->TestTrajectoryCone(weaponPos, flatdir,
    -		flatlength-30, dir.y, gs->gravity /
    +	if(avoidFriendly && helper->TestTrajectoryCone(weaponMuzzlePos, flatdir,
    +		flatlength-30, dir.y, gravity /
     		(projectileSpeed * projectileSpeed) * 0.5f,
     		(accuracy+sprayangle) * 0.6f * (1-owner->limExperience * 0.9f) * 0.9f,
     		3, owner->allyteam, owner))
    @@ -162,7 +168,7 @@
     
     void CCannon::Fire(void)
     {
    -	float3 diff = targetPos-weaponPos;
    +	float3 diff = targetPos-weaponMuzzlePos;
     	float3 dir=GetWantedDir(diff);
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.9f);
     	dir.Normalize();
    @@ -172,14 +178,14 @@
     #endif
     	int ttl = 0;
     	float sqSpeed2D = dir.SqLength2D() * projectileSpeed * projectileSpeed;
    -	int predict = (int)ceil((sqSpeed2D == 0) ? (-2 * projectileSpeed * dir.y / gs->gravity)
    +	int predict = (int)ceil((sqSpeed2D == 0) ? (-2 * projectileSpeed * dir.y / gravity)
     			: sqrt(diff.SqLength2D() / sqSpeed2D));
     	if(selfExplode) {
     		ttl=(int)(predict+gs->randFloat()*2.5f-0.5f);
     	} else {
     		ttl=predict*2;
     	}
    -	SAFE_NEW CExplosiveProjectile(weaponPos,dir*projectileSpeed,owner,weaponDef, ttl,areaOfEffect);
    +	SAFE_NEW CExplosiveProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,weaponDef, ttl,areaOfEffect,gravity);
     	//CWeaponProjectile::CreateWeaponProjectile(weaponPos,owner->speed,owner, NULL, float3(0,0,0), weaponDef);
     
     //	SAFE_NEW CSmokeProjectile(weaponPos,dir*0.01f,90,0.1f,0.02f,owner,0.6f);
    @@ -188,8 +194,8 @@
     //	p->maxheat=p->heat;
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    -	if(weaponPos.y<30)
    - 		water->AddExplosion(weaponPos,damages[0]*0.1f,sqrt(damages[0])+80);
    +//	if(weaponMuzzlePos.y<30)
    +//		water->AddExplosion(weaponMuzzlePos,damages[0]*0.1f,sqrt(damages[0])+80);
     }
     
     void CCannon::SlowUpdate(void)
    @@ -197,10 +203,10 @@
     	if(owner->useHighTrajectory!=highTrajectory){
     		highTrajectory=owner->useHighTrajectory;
     		if(highTrajectory){
    -			maxPredict=projectileSpeed*2/-gs->gravity;
    -			minPredict=projectileSpeed*1.41f/-gs->gravity;
    +			maxPredict=projectileSpeed*2/-gravity;
    +			minPredict=projectileSpeed*1.41f/-gravity;
     		} else {
    -			maxPredict=projectileSpeed*1.41f/-gs->gravity;
    +			maxPredict=projectileSpeed*1.41f/-gravity;
     		}
     	}
     	CWeapon::SlowUpdate();
    @@ -229,7 +235,7 @@
     
     	float Dsq = diff.SqLength();
     	float DFsq = diff.SqLength2D();
    -	float g = gs->gravity;
    +	float g = gravity;
     	float v = projectileSpeed;
     	float dy = diff.y;
     	float dxz = sqrt(DFsq);
    @@ -279,10 +285,10 @@
     		// f(0) == 1, f(smoothHeight) == heightBoostFactor
     		yDiff *= 1.f + (heightBoostFactor-1.f) * (-yDiff)/smoothHeight;
     
    -	float root1 = speed2dSq + 2*gs->gravity*yDiff;
    +	float root1 = speed2dSq + 2*gravity*yDiff;
     	if(root1 < 0.f){
     		return 0.f;
     	} else {
    -		return rangeFactor*(speed2dSq + speed2d*sqrt(root1))/(-gs->gravity);
    +		return rangeFactor*(speed2dSq + speed2d*sqrt(root1))/(-gravity);
     	}
     }
    Index: Sim/Weapons/Cannon.h
    ===================================================================
    --- Sim/Weapons/Cannon.h	(revision 4220)
    +++ Sim/Weapons/Cannon.h	(working copy)
    @@ -36,6 +36,8 @@
     	bool highTrajectory;
     	/// burnblow tag. defines flakker-like behaviour
     	bool selfExplode;
    +	/// projectile gravity
    +	float gravity;
     
     	void SlowUpdate(void);
     	/// tells where to point the gun to hit the point at pos+diff
    Index: Sim/Weapons/DGunWeapon.cpp
    ===================================================================
    --- Sim/Weapons/DGunWeapon.cpp	(revision 4220)
    +++ Sim/Weapons/DGunWeapon.cpp	(working copy)
    @@ -27,7 +27,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -46,13 +47,13 @@
     	if(onlyForward){
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
     	dir.Normalize();
     
    -	SAFE_NEW CFireBallProjectile(weaponPos,dir*projectileSpeed,owner,0,targetPos,weaponDef);
    +	SAFE_NEW CFireBallProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,0,targetPos,weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume*0.2f);
     }
    Index: Sim/Weapons/EmgCannon.cpp
    ===================================================================
    --- Sim/Weapons/EmgCannon.cpp	(revision 4220)
    +++ Sim/Weapons/EmgCannon.cpp	(working copy)
    @@ -31,7 +31,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -45,29 +46,31 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater)
    -			return false;
    -	} else {
    -		if(pos.y<0)
    -			return false;
    +	if (!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater)
    +				return false;
    +		} else {
    +			if(pos.y<0)
    +				return false;
    +		}
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.5f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.5f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -87,15 +90,17 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType)){		//the taairmovetype cant align itself properly, change back when that is fixed
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
     	dir.Normalize();
     
    -	SAFE_NEW CEmgProjectile(weaponPos,dir*projectileSpeed,owner,weaponDef->visuals.color,weaponDef->intensity,(int)(range/projectileSpeed), weaponDef);
    +	SAFE_NEW CEmgProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,weaponDef->visuals.color,weaponDef->intensity,(int)(range/projectileSpeed), weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
     
     
    +
    +
    Index: Sim/Weapons/FlameThrower.cpp
    ===================================================================
    --- Sim/Weapons/FlameThrower.cpp	(revision 4220)
    +++ Sim/Weapons/FlameThrower.cpp	(working copy)
    @@ -27,12 +27,12 @@
     
     void CFlameThrower::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
     	float3 spread=(gs->randVector()*sprayangle+salvoError)*0.2f;
     	spread-=dir*0.001f;
     
    -	SAFE_NEW CFlameProjectile(weaponPos,dir*projectileSpeed,spread,owner,weaponDef,(int)(range/projectileSpeed*weaponDef->duration));
    +	SAFE_NEW CFlameProjectile(weaponMuzzlePos,dir*projectileSpeed,spread,owner,weaponDef,(int)(range/projectileSpeed*weaponDef->duration));
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    @@ -42,29 +42,31 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater)
    -			return false;
    -	} else {
    -		if(pos.y<0)
    -			return false;
    +	if (!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater)
    +				return false;
    +		} else {
    +			if(pos.y<0)
    +				return false;
    +		}
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner)){
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner)){
     		return false;
     	}
     	return true;
    @@ -74,6 +76,7 @@
     {
     	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;
     		wantedDir=targetPos-weaponPos;
     		wantedDir.Normalize();
     	}
    Index: Sim/Weapons/LaserCannon.cpp
    ===================================================================
    --- Sim/Weapons/LaserCannon.cpp	(revision 4220)
    +++ Sim/Weapons/LaserCannon.cpp	(working copy)
    @@ -30,7 +30,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -45,14 +46,14 @@
     		return false;
     
     	if(unit){
    -		if(unit->isUnderWater)
    +		if(unit->isUnderWater && !weaponDef->waterweapon)
     			return false;
     	} else {
    -		if(pos.y<0)
    +		if(pos.y<0 && !weaponDef->waterweapon)
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
    @@ -60,14 +61,14 @@
     	dir/=length;
     
     	if(!onlyForward){		//skip ground col testing for aircrafts
    -		float g=ground->LineGroundCol(weaponPos,pos);
    +		float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     		if(g>0 && g<length*0.9f)
     			return false;
     	}
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -84,7 +85,7 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType)){		//the taairmovetype cant align itself properly, change back when that is fixed
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.7f);
    @@ -96,10 +97,12 @@
     		fpsSub=6;
     #endif
     
    -	SAFE_NEW CLaserProjectile(weaponPos, dir*projectileSpeed, owner, weaponDef->duration*weaponDef->maxvelocity, weaponDef->visuals.color, weaponDef->visuals.color2, weaponDef->intensity, weaponDef, (int)((weaponDef->range-fpsSub*4)/weaponDef->projectilespeed)-fpsSub);
    +	SAFE_NEW CLaserProjectile(weaponMuzzlePos, dir*projectileSpeed, owner, weaponDef->duration*weaponDef->maxvelocity, weaponDef->visuals.color, weaponDef->visuals.color2, weaponDef->intensity, weaponDef, (int)((weaponDef->range-fpsSub*4)/weaponDef->projectilespeed)-fpsSub);
     
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
     
     
    +
    +
    Index: Sim/Weapons/LightingCannon.cpp
    ===================================================================
    --- Sim/Weapons/LightingCannon.cpp	(revision 4220)
    +++ Sim/Weapons/LightingCannon.cpp	(working copy)
    @@ -31,6 +31,7 @@
     {
     	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();
    @@ -44,29 +45,31 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater)
    -			return false;
    -	} else {
    -		if(pos.y<0)
    -			return false;
    +	if(!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater)
    +				return false;
    +		} else {
    +			if(pos.y<0)
    +				return false;
    +		}
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -78,16 +81,16 @@
     
     void CLightingCannon::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
     	dir.Normalize();
     	CUnit* u=0;
    -	float r=helper->TraceRay(weaponPos,dir,range,0,owner,u);
    +	float r=helper->TraceRay(weaponMuzzlePos,dir,range,0,owner,u);
     
     	float3 newDir;
     	CPlasmaRepulser* shieldHit;
    -	float shieldLength=interceptHandler.AddShieldInterceptableBeam(this,weaponPos,dir,range,newDir,shieldHit);
    +	float shieldLength=interceptHandler.AddShieldInterceptableBeam(this,weaponMuzzlePos,dir,range,newDir,shieldHit);
     	if(shieldLength<r){
     		r=shieldLength;
     		if(shieldHit) {
    @@ -101,11 +104,11 @@
     	// Dynamic Damage
     	DamageArray dynDamages;
     	if (weaponDef->dynDamageExp > 0)
    -		dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponPos, targetPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
    +		dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponMuzzlePos, targetPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
     
    -	helper->Explosion(weaponPos+dir*r,weaponDef->dynDamageExp>0?dynDamages:weaponDef->damages,areaOfEffect,weaponDef->edgeEffectiveness,weaponDef->explosionSpeed,owner,false,0.5f,true,weaponDef->explosionGenerator, u,dir, weaponDef->id);
    +	helper->Explosion(weaponMuzzlePos+dir*r,weaponDef->dynDamageExp>0?dynDamages:weaponDef->damages,areaOfEffect,weaponDef->edgeEffectiveness,weaponDef->explosionSpeed,owner,false,0.5f,true,weaponDef->explosionGenerator, u,dir, weaponDef->id);
     
    -	SAFE_NEW CLightingProjectile(weaponPos,weaponPos+dir*(r+10),owner,color,weaponDef,10,this);
    +	SAFE_NEW CLightingProjectile(weaponMuzzlePos,weaponMuzzlePos+dir*(r+10),owner,color,weaponDef,10,this);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     
    Index: Sim/Weapons/MeleeWeapon.cpp
    ===================================================================
    --- Sim/Weapons/MeleeWeapon.cpp	(revision 4220)
    +++ Sim/Weapons/MeleeWeapon.cpp	(working copy)
    @@ -33,21 +33,23 @@
     {
     	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();
    -
     }
     
     void CMeleeWeapon::Fire(void)
     {
     	if(targetType==Target_Unit){
    -		float3 impulseDir = targetUnit->pos-weaponPos;
    +		float3 impulseDir = targetUnit->pos-weaponMuzzlePos;
     		impulseDir.Normalize();
    -		targetUnit->DoDamage(damages,owner,impulseDir,weaponDef->id);
    +		// the heavier the unit, the more impulse it does
    +		targetUnit->DoDamage(damages,owner,impulseDir*owner->mass,weaponDef->id);
     		if(fireSoundId)
     			sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     	}
    Index: Sim/Weapons/MissileLauncher.cpp
    ===================================================================
    --- Sim/Weapons/MissileLauncher.cpp	(revision 4220)
    +++ Sim/Weapons/MissileLauncher.cpp	(working copy)
    @@ -29,7 +29,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			float dist=wantedDir.Length();
     			predict=dist/projectileSpeed;
    @@ -48,8 +49,10 @@
     	float3 dir;
     	if(onlyForward){
     		dir=owner->frontdir;
    +	} else if (weaponDef->fixedLauncher) {
    +		dir=weaponDir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     		if(weaponDef->trajectoryHeight>0){
     			dir.y+=weaponDef->trajectoryHeight;
    @@ -64,7 +67,7 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType))
     		startSpeed+=owner->speed;
     
    -	SAFE_NEW CMissileProjectile(weaponPos,startSpeed,owner,areaOfEffect,projectileSpeed,(int)(range/projectileSpeed+25),targetUnit, weaponDef,targetPos);
    +	SAFE_NEW CMissileProjectile(weaponMuzzlePos,startSpeed,owner,areaOfEffect,projectileSpeed,weaponDef->flighttime==0 ? (int)(range/projectileSpeed+25) : weaponDef->flighttime,targetUnit, weaponDef,targetPos);
     	//CWeaponProjectile::CreateWeaponProjectile(weaponPos,startSpeed,owner,targetUnit, float3(0,0,0), weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    @@ -75,15 +78,17 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater){
    -			return false;
    +	if (!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater){
    +				return false;
    +			}
    +		} else {
    +			if(pos.y<0)
    +				return false;
     		}
    -	} else {
    -		if(pos.y<0)
    -			return false;
     	}
    -	float3 dir=pos-weaponPos;
    +	float3 dir = pos-weaponMuzzlePos;
     	if(weaponDef->trajectoryHeight>0){	//do a different test depending on if the missile has a high trajectory or not
     		float3 flatdir(dir.x,0,dir.z);
     		dir.Normalize();
    @@ -95,11 +100,11 @@
     		float linear=dir.y+weaponDef->trajectoryHeight;
     		float quadratic=-weaponDef->trajectoryHeight/flatlength;
     
    -		float gc=ground->TrajectoryGroundCol(weaponPos,flatdir,flatlength-30,linear,quadratic);
    +		float gc=ground->TrajectoryGroundCol(weaponMuzzlePos,flatdir,flatlength-30,linear,quadratic);
     		if(gc>0)
     			return false;
     
    -		if(avoidFriendly && helper->TestTrajectoryCone(weaponPos,flatdir,flatlength-30,linear,quadratic,0,8,owner->allyteam,owner)){
    +		if(avoidFriendly && helper->TestTrajectoryCone(weaponMuzzlePos,flatdir,flatlength-30,linear,quadratic,0,8,owner->allyteam,owner)){
     			return false;
     		}
     	} else {
    @@ -110,7 +115,7 @@
     		dir/=length;
     
     		if(!onlyForward){		//skip ground col testing for aircrafts
    -			float g=ground->LineGroundCol(weaponPos,pos);
    +			float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     			if(g>0 && g<length*0.9f)
     				return false;
     		} else {
    @@ -119,7 +124,7 @@
     			if(owner->frontdir.dot(goaldir) < maxAngleDif)
     				return false;
     		}
    -		if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
    +		if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
     			return false;
     	}
     	return true;
    Index: Sim/Weapons/PlasmaRepulser.cpp
    ===================================================================
    --- Sim/Weapons/PlasmaRepulser.cpp	(revision 4220)
    +++ Sim/Weapons/PlasmaRepulser.cpp	(working copy)
    @@ -70,6 +70,8 @@
     
     	if(weaponDef->shieldPower==0)
     		curPower=99999999999.0f;
    +	else
    +		curPower=weaponDef->shieldStartingPower;
     
     	CWeapon::Init();
     }
    Index: Sim/Weapons/Rifle.cpp
    ===================================================================
    --- Sim/Weapons/Rifle.cpp	(revision 4220)
    +++ Sim/Weapons/Rifle.cpp	(working copy)
    @@ -41,6 +41,7 @@
     {
     	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;
     		wantedDir=targetPos-weaponPos;
     		wantedDir.Normalize();
     	}
    @@ -60,18 +61,18 @@
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.9f),owner->allyteam,owner)){
    +	if(helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.9f),owner->allyteam,owner)){
     		return false;
     	}
     	return true;
    @@ -79,7 +80,7 @@
     
     void CRifle::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.9f);
     	dir.Normalize();
    @@ -88,13 +89,13 @@
     	tracefile << owner->pos.x << " " << dir.x << " " << targetPos.x << " " << targetPos.y << " " << targetPos.z << "\n";
     #endif
     	CUnit* hit;
    -	float length=helper->TraceRay(weaponPos,dir,range,damages[0],owner,hit,collisionFlags);
    +	float length=helper->TraceRay(weaponMuzzlePos,dir,range,damages[0],owner,hit,collisionFlags);
     	if(hit){
     		hit->DoDamage(damages,owner,ZeroVector, weaponDef->id);
    -		SAFE_NEW CHeatCloudProjectile(weaponPos+dir*length,hit->speed*0.9f,30,1,owner);
    +		SAFE_NEW CHeatCloudProjectile(weaponMuzzlePos+dir*length,hit->speed*0.9f,30,1,owner);
     	}
    -	SAFE_NEW CTracerProjectile(weaponPos,dir*projectileSpeed,length,owner);
    -	SAFE_NEW CSmokeProjectile(weaponPos,float3(0,0.0f,0),70,0.1f,0.02f,owner,0.6f);
    +	SAFE_NEW CTracerProjectile(weaponMuzzlePos,dir*projectileSpeed,length,owner);
    +	SAFE_NEW CSmokeProjectile(weaponMuzzlePos,float3(0,0.0f,0),70,0.1f,0.02f,owner,0.6f);
     	if(fireSoundId)
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    Index: Sim/Weapons/StarburstLauncher.cpp
    ===================================================================
    --- Sim/Weapons/StarburstLauncher.cpp	(revision 4220)
    +++ Sim/Weapons/StarburstLauncher.cpp	(working copy)
    @@ -32,6 +32,7 @@
     {
     	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;
     		wantedDir=(targetPos-weaponPos).Normalize();		//the aiming upward is apperently implicid so aim toward target
     	}
     	CWeapon::Update();
    @@ -39,7 +40,17 @@
     
     void CStarburstLauncher::Fire(void)
     {
    -	CStarburstProjectile* p=SAFE_NEW CStarburstProjectile(weaponPos+float3(0,2,0),float3(0,0.01f,0),owner,targetPos,areaOfEffect,projectileSpeed,tracking,(int)uptime,targetUnit, weaponDef,interceptTarget,range);
    +	float3 speed(0,weaponDef->startvelocity,0);
    +	float maxrange;
    +	if (weaponDef->fixedLauncher) {
    +		speed = weaponDir * weaponDef->startvelocity;
    +		maxrange = (float)MAX_WORLD_SIZE;
    +	} else if (weaponDef->flighttime > 0) {
    +		maxrange = (float)MAX_WORLD_SIZE;
    +	} else {
    +		maxrange = (float)range;
    +	}
    +	CStarburstProjectile* p=SAFE_NEW CStarburstProjectile(weaponMuzzlePos+float3(0,2,0),speed,owner,targetPos,areaOfEffect,projectileSpeed,tracking,(int)uptime,targetUnit, weaponDef,interceptTarget, maxrange);
     
     	if(weaponDef->targetable)
     		interceptHandler.AddInterceptTarget(p,targetPos);
    @@ -54,14 +65,15 @@
     		return false;
     
     	if(unit){
    -		if(unit->isUnderWater)
    +		if(unit->isUnderWater && !weaponDef->waterweapon)
     			return false;
     	} else {
    -		if(pos.y<0)
    +		if(pos.y<0 && !weaponDef->waterweapon)
     			return false;
     	}
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,UpVector,100,0,owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,
    +			(weaponDef->fixedLauncher ? weaponDir : UpVector), 100, 0, owner->allyteam, owner))
     		return false;
     
     	return true;
    Index: Sim/Weapons/TorpedoLauncher.cpp
    ===================================================================
    --- Sim/Weapons/TorpedoLauncher.cpp	(revision 4220)
    +++ Sim/Weapons/TorpedoLauncher.cpp	(working copy)
    @@ -32,7 +32,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -//		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +//		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			float dist=wantedDir.Length();
     			predict=dist/projectileSpeed;
    @@ -48,18 +49,24 @@
     //	if(onlyForward){
     //		dir=owner->frontdir;
     //	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     		if(weaponDef->trajectoryHeight>0){
     			dir.y+=weaponDef->trajectoryHeight;
     			dir.Normalize();
     		}
     //	}
    -	float3 startSpeed=dir*weaponDef->startvelocity;
    +	float3 startSpeed;
    +	if (!weaponDef->fixedLauncher) {
    +		startSpeed=dir*weaponDef->startvelocity;
    +	}
    +	else {
    +		startSpeed=weaponDir*weaponDef->startvelocity;
    +	}
     
     //	if(onlyForward)
     //		startSpeed+=owner->speed*0.5f;
    -	SAFE_NEW CTorpedoProjectile(weaponPos,startSpeed,owner,areaOfEffect,projectileSpeed,tracking,(int)(range/projectileSpeed+15),targetUnit, weaponDef);
    +	SAFE_NEW CTorpedoProjectile(weaponMuzzlePos,startSpeed,owner,areaOfEffect,projectileSpeed,tracking,weaponDef->flighttime==0 ? (int)(range/projectileSpeed+25) : weaponDef->flighttime,targetUnit, weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    @@ -70,22 +77,22 @@
     		return false;
     
     	if(unit){
    -		if(unit->unitDef->canhover)
    +		if(!(weaponDef->submissile) && unit->unitDef->canhover)
     			return false;
    -		if(unit->unitDef->canfly && unit->pos.y>0)
    +		if(!(weaponDef->submissile) && unit->unitDef->canfly && unit->pos.y>0)
     			return false;
     	}
    -	if(ground->GetHeight2(pos.x,pos.z)>0)
    +	if(!(weaponDef->submissile) && ground->GetHeight2(pos.x,pos.z)>0)
     		return 0;
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)+0.05f,owner->allyteam,owner))	//+0.05f since torpedoes has an unfortunate tendency to hit own ships due to movement
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)+0.05f,owner->allyteam,owner))	//+0.05f since torpedoes has an unfortunate tendency to hit own ships due to movement
     		return false;
     	return true;
     }
    Index: Sim/Weapons/Weapon.cpp
    ===================================================================
    --- Sim/Weapons/Weapon.cpp	(revision 4220)
    +++ Sim/Weapons/Weapon.cpp	(working copy)
    @@ -57,9 +57,11 @@
     	CR_MEMBER(subClassReady),
     	CR_MEMBER(onlyForward),
     	CR_MEMBER(weaponPos),
    +	CR_MEMBER(weaponMuzzlePos),
     	CR_MEMBER(lastRequest),
     	CR_MEMBER(damages),
     	CR_MEMBER(relWeaponPos),
    +	CR_MEMBER(relWeaponMuzzlePos),
     	CR_MEMBER(muzzleFlareSize),
     	CR_MEMBER(lastTargetRetry),
     	CR_MEMBER(areaOfEffect),
    @@ -133,8 +135,10 @@
     	subClassReady(true),
     	onlyForward(false),
     	weaponPos(0,0,0),
    +	weaponMuzzlePos(0,0,0),
     	lastRequest(0),
     	relWeaponPos(0,1,0),
    +	relWeaponMuzzlePos(0,1,0),
     	muzzleFlareSize(1),
     	lastTargetRetry(-100),
     	areaOfEffect(1),
    @@ -177,11 +181,14 @@
     	if(hasCloseTarget){
     		std::vector<int> args;
     		args.push_back(0);
    -		if(useWeaponPosForAim){
    +		if(useWeaponPosForAim){ //if we couldn't get a line of fire from the muzzle try if we can get it from the aim piece
     			owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
     		} else {
     			owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     		}
    +		relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
    +
    +		owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     		relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     	}
     
    @@ -259,16 +266,18 @@
     	&& subClassReady
     	&& reloadStatus<=gs->frameNum
     	&& (!weaponDef->stockpile || numStockpiled)
    -	&& (weaponDef->waterweapon || weaponPos.y>0)
    +	&& (weaponDef->fireSubmersed || weaponMuzzlePos.y>0)
     	&& (owner->unitDef->maxFuel==0 || owner->currentFuel > 0)
     	){
     		if ((weaponDef->stockpile || (gs->Team(owner->team)->metal>=metalFireCost && gs->Team(owner->team)->energy>=energyFireCost))) {
     			std::vector<int> args;
     			args.push_back(0);
     			owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    -			relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
    -			weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +			owner->localmodel->GetEmitDirPos(args[0], relWeaponMuzzlePos, weaponDir);
    +			weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
     			useWeaponPosForAim=reloadTime/16+8;
    +			weaponDir = owner->frontdir * weaponDir.z + owner->updir * weaponDir.y + owner->rightdir * weaponDir.x;
    +			weaponDir.Normalize();
     
     			if(TryTarget(targetPos,haveUserTarget,targetUnit)){
     				if(weaponDef->stockpile){
    @@ -304,35 +313,52 @@
     			}
     		}
     	}
    -	if(salvoLeft && nextSalvo<=gs->frameNum){
    +	if(salvoLeft && nextSalvo<=gs->frameNum ){
     		salvoLeft--;
     		nextSalvo=gs->frameNum+salvoDelay;
     		owner->lastFireWeapon=gs->frameNum;
    +		
    +		int projectiles = weaponDef->projectilespershot;
    +		
    +		while(projectiles > 0) {
    +			--projectiles;
    +			
    +			// add to the commandShotCount if this is the last salvo,
    +			// and it is being directed towards the current target
    +			// (helps when deciding if a queued ground attack order has been completed)
    +			if ((salvoLeft == 0) && (owner->commandShotCount >= 0) &&
    +			    ((targetType == Target_Pos) && (targetPos == owner->userAttackPos)) ||
    +					((targetType == Target_Unit) && (targetUnit == owner->userTarget))) {
    +				owner->commandShotCount++;
    +			}
    +	
    +			std::vector<int> args;
    +			args.push_back(0);
    +	
    +			owner->cob->Call(COBFN_Shot+weaponNum,0);
    +	
    +			owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
    +			relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     
    -		// add to the commandShotCount if this is the last salvo,
    -		// and it is being directed towards the current target
    -		// (helps when deciding if a queued ground attack order has been completed)
    -		if ((salvoLeft == 0) && (owner->commandShotCount >= 0) &&
    -		    ((targetType == Target_Pos) && (targetPos == owner->userAttackPos)) ||
    -				((targetType == Target_Unit) && (targetUnit == owner->userTarget))) {
    -			owner->commandShotCount++;
    -		}
    +			owner->cob->Call(/*COBFN_AimFromPrimary+weaponNum*/COBFN_QueryPrimary+weaponNum/**/,args);
    +			owner->localmodel->GetEmitDirPos(args[0], relWeaponMuzzlePos, weaponDir);
     
    -		std::vector<int> args;
    -		args.push_back(0);
    -		owner->cob->Call(/*COBFN_AimFromPrimary+weaponNum/*/COBFN_QueryPrimary+weaponNum/**/,args);
    -		relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
    -		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +			weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
     
    -//		logOutput.Print("RelPosFire %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
    -
    -		if (owner->unitDef->decloakOnFire && (owner->scriptCloak <= 2)) {
    -			owner->isCloaked = false;
    -			owner->curCloakTimeout = gs->frameNum + owner->cloakTimeout;
    +			weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +			weaponDir = owner->frontdir * weaponDir.z + owner->updir * weaponDir.y + owner->rightdir * weaponDir.x;
    +			weaponDir.Normalize();
    +	
    +	//		logOutput.Print("RelPosFire %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
    +	
    +			if (owner->unitDef->decloakOnFire && (owner->scriptCloak <= 2)) {
    +				owner->isCloaked = false;
    +				owner->curCloakTimeout = gs->frameNum + owner->cloakTimeout;
    +			}
    +	
    +			Fire();
     		}
     
    -		Fire();
    -
     		//Rock the unit in the direction of the fireing
     		float3 rockDir = wantedDir;
     		rockDir.y = 0;
    @@ -363,9 +389,9 @@
     
     	if(!weaponDef->waterweapon && pos.y<1)
     		pos.y=1;
    -	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -	if(weaponPos.y<ground->GetHeight2(weaponPos.x,weaponPos.z))
    -		weaponPos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +	if(weaponMuzzlePos.y<ground->GetHeight2(weaponMuzzlePos.x,weaponMuzzlePos.z))
    +		weaponMuzzlePos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
     
     	if(!TryTarget(pos,userTarget,0))
     		return false;
    @@ -388,8 +414,10 @@
     
     	weaponPos= owner->pos + owner->frontdir * relWeaponPos.z
     		+ owner->updir * relWeaponPos.y + owner->rightdir * relWeaponPos.x;
    -	if(weaponPos.y < ground->GetHeight2(weaponPos.x, weaponPos.z))
    -		weaponPos = owner->pos + UpVector * 10;
    +	weaponMuzzlePos= owner->pos + owner->frontdir * relWeaponMuzzlePos.z
    +		+ owner->updir * relWeaponMuzzlePos.y + owner->rightdir * relWeaponMuzzlePos.x;
    +	if(weaponMuzzlePos.y < ground->GetHeight2(weaponMuzzlePos.x, weaponMuzzlePos.z))
    +		weaponMuzzlePos = owner->pos + UpVector * 10;
     	//hope that we are underground because we are a popup weapon and will come above ground later
     
     	if(!unit){
    @@ -437,18 +465,23 @@
     #endif
     	std::vector<int> args;
     	args.push_back(0);
    -	if(useWeaponPosForAim){
    +	if(useWeaponPosForAim){ //If we can't get a line of fire from the muzzle try the aim piece instead since the weapon may just be turned in a wrong way
     		owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
     		if(useWeaponPosForAim>1)
     			useWeaponPosForAim--;
     	} else {
     		owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     	}
    +	relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +
    +	owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     	relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -	if(weaponPos.y<ground->GetHeight2(weaponPos.x,weaponPos.z))
    -		weaponPos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
     
    +	if(weaponMuzzlePos.y<ground->GetHeight2(weaponMuzzlePos.x,weaponMuzzlePos.z))
    +		weaponMuzzlePos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
    +
     	predictSpeedMod=1+(gs->randFloat()-0.5f)*2*(1-owner->limExperience);
     
     	if((targetPos-weaponPos).SqLength() < relWeaponPos.SqLength()*16)
    @@ -552,7 +585,7 @@
     	if(weaponDef->stockpile && !numStockpiled)
     		return false;
     
    -	float3 dif=pos-weaponPos;
    +	float3 dif=pos-weaponMuzzlePos;
     	float heightDiff; // negative when target below owner
     
     	if (targetBorder != 0 && unit) {
    @@ -624,11 +657,13 @@
     	owner->frontdir = GetVectorFromHeading(owner->heading);
     	owner->rightdir = owner->frontdir.cross(owner->updir);
     	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;
     	bool val = TryTarget(tempTargetPos,userTarget,unit);
     	owner->frontdir = tempfrontdir;
     	owner->rightdir = temprightdir;
     	owner->heading = tempHeadding;
     	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;
     	return val;
     }
     
    @@ -654,11 +689,13 @@
     	owner->frontdir = GetVectorFromHeading(owner->heading);
     	owner->rightdir = owner->frontdir.cross(owner->updir);
     	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;
     	bool val = TryTarget(pos, userTarget, 0);
     	owner->frontdir = tempfrontdir;
     	owner->rightdir = temprightdir;
     	owner->heading = tempHeadding;
     	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;
     	return val;
     }
     
    @@ -669,6 +706,10 @@
     	owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     	relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +
    +	owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    +	relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
     //	logOutput.Print("RelPos %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
     
     	if (range > owner->maxRange) {
    Index: Sim/Weapons/Weapon.h
    ===================================================================
    --- Sim/Weapons/Weapon.h	(revision 4220)
    +++ Sim/Weapons/Weapon.h	(working copy)
    @@ -60,6 +60,11 @@
     
     	float3 relWeaponPos;				//weaponpos relative to the unit
     	float3 weaponPos;						//absolute weapon pos
    +
    +	float3 relWeaponMuzzlePos;			//position of the firepoint
    +	float3 weaponMuzzlePos;
    +	float3 weaponDir;
    +
     	float muzzleFlareSize;			//size of muzzle flare if drawn
     	int useWeaponPosForAim;			//sometimes weapon pos is better to use than aimpos
     	bool hasCloseTarget;					//might need to update weapon pos more often when enemy is near
    Index: Sim/Weapons/WeaponDefHandler.cpp
    ===================================================================
    --- Sim/Weapons/WeaponDefHandler.cpp	(revision 4220)
    +++ Sim/Weapons/WeaponDefHandler.cpp	(working copy)
    @@ -67,6 +67,7 @@
     	bool ballistic;
     	//bool twophase;
     	bool beamweapon;
    +	bool manualBombSettings; //Allow the user to manually specify the burst and burstrate for his AircraftBomb
     	//bool guided;
     	//bool vlaunch;
     	int rendertype;
    @@ -94,6 +95,7 @@
     	sunparser->GetDef(weaponDefs[id].minIntensity, "0", weaponname + "\\MinIntensity");
     
     	sunparser->GetDef(weaponDefs[id].dropped, "0", weaponname + "\\dropped");
    +	sunparser->GetDef(manualBombSettings, "0", weaponname + "\\manualbombsettings");
     	sunparser->GetDef(lineofsight, "0", weaponname + "\\lineofsight");
     	sunparser->GetDef(ballistic, "0", weaponname + "\\ballistic");
     	sunparser->GetDef(weaponDefs[id].twophase, "0", weaponname + "\\twophase");
    @@ -110,7 +112,10 @@
     	sunparser->GetDef(weaponDefs[id].noSelfDamage, "0", weaponname + "\\NoSelfDamage");
     
     	sunparser->GetDef(weaponDefs[id].waterweapon, "0", weaponname + "\\waterweapon");
    +	sunparser->GetDef(weaponDefs[id].fireSubmersed, weaponDefs[id].waterweapon ? "1":"0", weaponname + "\\firesubmersed");
    +	sunparser->GetDef(weaponDefs[id].submissile, "0", weaponname + "\\submissile");
     	sunparser->GetDef(weaponDefs[id].tracks, "0", weaponname + "\\tracks");
    +	sunparser->GetDef(weaponDefs[id].fixedLauncher, "0", weaponname + "\\FixedLauncher");
     	sunparser->GetDef(weaponDefs[id].noExplode, "0", weaponname + "\\NoExplode");
     	sunparser->GetDef(weaponDefs[id].maxvelocity, "0", weaponname + "\\weaponvelocity");
     	sunparser->GetDef(weaponDefs[id].isShield, "0", weaponname + "\\IsShield");
    @@ -256,6 +261,7 @@
     	weaponDefs[id].reload = atof(sunparser->SGetValueDef("1", weaponname + "\\reloadtime").c_str());
     	weaponDefs[id].salvodelay = atof(sunparser->SGetValueDef("0.1", weaponname + "\\burstrate").c_str());
     	sunparser->GetDef(weaponDefs[id].salvosize, "1", weaponname + "\\burst");
    +	sunparser->GetDef(weaponDefs[id].projectilespershot, "1", weaponname + "\\projectiles");
     	weaponDefs[id].maxAngle = atof(sunparser->SGetValueDef("3000", weaponname + "\\tolerance").c_str()) * 180.0f / 0x7fff;
     	weaponDefs[id].restTime = 0.0f;
     	sunparser->GetDef(weaponDefs[id].metalcost, "0", weaponname + "\\metalpershot");
    @@ -263,6 +269,7 @@
     	sunparser->GetDef(weaponDefs[id].selfExplode, "0", weaponname + "\\burnblow");
     	sunparser->GetDef(weaponDefs[id].sweepFire, "0", weaponname + "\\sweepfire");
     	sunparser->GetDef(weaponDefs[id].canAttackGround, "1", weaponname + "\\canattackground");
    +	weaponDefs[id].myGravity = atof(sunparser->SGetValueDef("0", weaponname + "\\myGravity").c_str());
     
     	weaponDefs[id].fireStarter=atof(sunparser->SGetValueDef("0", weaponname + "\\firestarter").c_str())*0.01f;
     	weaponDefs[id].paralyzer=!!atoi(sunparser->SGetValueDef("0", weaponname + "\\paralyzer").c_str());
    @@ -292,6 +299,7 @@
     	sunparser->GetDef(weaponDefs[id].shieldPower, "0", weaponname + "\\shieldpower");
     	sunparser->GetDef(weaponDefs[id].shieldPowerRegen, "0", weaponname + "\\shieldpowerregen");
     	sunparser->GetDef(weaponDefs[id].shieldPowerRegenEnergy, "0", weaponname + "\\shieldpowerregenenergy");
    +	sunparser->GetDef(weaponDefs[id].shieldStartingPower, "0", weaponname + "\\shieldstartingpower");
     	sunparser->GetDef(weaponDefs[id].shieldInterceptType, "0", weaponname + "\\shieldintercepttype");
     	weaponDefs[id].shieldGoodColor=sunparser->GetFloat3(float3(0.5f,0.5f,1),weaponname + "\\shieldgoodcolor");
     	weaponDefs[id].shieldBadColor=sunparser->GetFloat3(float3(1,0.5f,0.5f),weaponname + "\\shieldbadcolor");
    @@ -353,10 +361,11 @@
     		weaponDefs[id].visuals.color = tempCol;
     
     	weaponDefs[id].uptime = atof(sunparser->SGetValueDef("0", weaponname + "\\weapontimer").c_str());
    +	weaponDefs[id].flighttime = atof(sunparser->SGetValueDef("0", weaponname + "\\flighttime").c_str()) * 32;
     
     	weaponDefs[id].turnrate = atof(sunparser->SGetValueDef("0", weaponname + "\\turnrate").c_str()) * PI / 0x7fff /30.0f;
     
    -	if(weaponDefs[id].type=="AircraftBomb"){
    +	if(weaponDefs[id].type=="AircraftBomb" && !manualBombSettings){
     		if(weaponDefs[id].reload<0.5f){
     			weaponDefs[id].salvodelay=min(0.2f,weaponDefs[id].reload);
     			weaponDefs[id].salvosize=(int)(1/weaponDefs[id].salvodelay)+1;
    Index: Sim/Weapons/WeaponDefHandler.h
    ===================================================================
    --- Sim/Weapons/WeaponDefHandler.h	(revision 4220)
    +++ Sim/Weapons/WeaponDefHandler.h	(working copy)
    @@ -67,17 +67,23 @@
     	float restTime;
     
     	float uptime;
    +	int flighttime;
     
     	float metalcost;
     	float energycost;
     	float supplycost;
     
    +	int projectilespershot;
    +
     	int id;
     	int tdfId;	//the id= tag in the tdf
     
     	bool turret;
     	bool onlyForward;
    +	bool fixedLauncher;
     	bool waterweapon;
    +	bool fireSubmersed;
    +	bool submissile; //Lets a torpedo travel above water like it does below water
     	bool tracks;
     	bool dropped;
     	bool paralyzer;			//weapon will only paralyze not do real damage
    @@ -102,6 +108,7 @@
     
     	bool selfExplode;
     	bool gravityAffected;
    +	float myGravity;
     	bool twophase;
     	bool guided;
     	bool vlaunch;
    @@ -165,6 +172,7 @@
     	float shieldPower;			//how much damage the shield can reflect (0=infinite)
     	float shieldPowerRegen;	//how fast the power regenerates per second
     	float shieldPowerRegenEnergy;	//how much energy is needed to regenerate power per second
    +	float shieldStartingPower;	//how much power the shield has when first created
     	float3 shieldGoodColor;			//color when shield at full power
     	float3 shieldBadColor;			//color when shield is empty
     	float shieldAlpha;					//shield alpha value
    Index: System/GlobalStuff.h
    ===================================================================
    --- System/GlobalStuff.h	(revision 4220)
    +++ System/GlobalStuff.h	(working copy)
    @@ -20,7 +20,7 @@
      *
      * Defines the maximum world size as 1000000
      */
    -#define MAX_WORLD_SIZE 1000000;
    +#define MAX_WORLD_SIZE 1000000
     
     /**
      * @brief square size
    @@ -260,42 +260,42 @@
     
     	/**
     	 * @brief disable helper AIs
    -	 * 
    +	 *
     	 * Whether helper AIs are allow, including GroupAI and LuaUI control widgets
     	 */
     	bool noHelperAIs;
     
     	/**
     	 * @brief definition editing enabled
    -	 * 
    +	 *
     	 * Whether definition editing is enabled
     	 */
     	bool editDefsEnabled;
     
     	/**
     	 * @brief LuaRules control
    -	 * 
    +	 *
     	 * Whether or not LuaRules is enabled
     	 */
     	bool useLuaRules;
     
     	/**
     	 * @brief LuaGaia control
    -	 * 
    +	 *
     	 * Whether or not LuaGaia is enabled
     	 */
     	bool useLuaGaia;
     
     	/**
     	 * @brief gaia team
    -	 * 
    +	 *
     	 * gaia's team id
     	 */
     	int gaiaTeamID;
     
     	/**
     	 * @brief gaia team
    -	 * 
    +	 *
     	 * gaia's team id
     	 */
     	int gaiaAllyTeamID;
    
    patch file icon kdr11k_weapon_changes_r4220_v2.patch (80,018 bytes) 2007-08-18 17:05 +
  • patch file icon kdr11k_weapon_changes_r4223_v3.patch (80,656 bytes) 2007-08-18 22:41 -
    Index: rts/Sim/Projectiles/EmgProjectile.cpp
    ===================================================================
    --- rts/Sim/Projectiles/EmgProjectile.cpp	(revision 4223)
    +++ rts/Sim/Projectiles/EmgProjectile.cpp	(working copy)
    @@ -4,6 +4,7 @@
     #include "Rendering/GL/VertexArray.h"
     #include "Sync/SyncTracer.h"
     #include "ProjectileHandler.h"
    +#include "Map/Ground.h"
     #include "Sim/Weapons/WeaponDefHandler.h"
     #include "mmgr.h"
     
    @@ -52,10 +53,14 @@
     void CEmgProjectile::Collision(CUnit* unit)
     {
     //	unit->DoDamage(damages,owner);
    -
     	CWeaponProjectile::Collision(unit);
     }
     
    +void CEmgProjectile::Collision() {
    +	if (!(weaponDef->waterweapon && ground->GetHeight2(pos.x, pos.z) < pos.y))
    +		CWeaponProjectile::Collision();
    +}
    +
     void CEmgProjectile::Draw(void)
     {
     	inArray=true;
    Index: rts/Sim/Projectiles/EmgProjectile.h
    ===================================================================
    --- rts/Sim/Projectiles/EmgProjectile.h	(revision 4223)
    +++ rts/Sim/Projectiles/EmgProjectile.h	(working copy)
    @@ -14,6 +14,7 @@
     	void Update(void);
     	void Draw(void);
     	void Collision(CUnit* unit);
    +	void Collision();
     	int ShieldRepulse(CPlasmaRepulser* shield,float3 shieldPos, float shieldForce, float shieldMaxSpeed);
     
     	int ttl;
    Index: rts/Sim/Projectiles/ExplosiveProjectile.cpp
    ===================================================================
    --- rts/Sim/Projectiles/ExplosiveProjectile.cpp	(revision 4223)
    +++ rts/Sim/Projectiles/ExplosiveProjectile.cpp	(working copy)
    @@ -18,18 +18,21 @@
     
     CR_REG_METADATA(CExplosiveProjectile, (
     	CR_MEMBER(ttl),
    -	CR_MEMBER(areaOfEffect)
    +	CR_MEMBER(areaOfEffect),
    +	CR_MEMBER(gravity)
     	));
     
     //////////////////////////////////////////////////////////////////////
     // Construction/Destruction
     //////////////////////////////////////////////////////////////////////
     
    -CExplosiveProjectile::CExplosiveProjectile(const float3& pos, const float3& speed, CUnit* owner, const WeaponDef* weaponDef, int ttl, float areaOfEffect)
    +CExplosiveProjectile::CExplosiveProjectile(const float3& pos, const float3& speed,
    +		CUnit* owner, const WeaponDef *weaponDef, int ttl, float areaOfEffect, float gravity)
     : CWeaponProjectile(pos, speed, owner, 0, ZeroVector, weaponDef, 0, true),
     	ttl(ttl),
     	areaOfEffect(areaOfEffect),
    -	curTime(0)
    +	curTime(0),
    +	gravity(gravity)
     {
     	useAirLos=true;
     
    @@ -53,7 +56,7 @@
     void CExplosiveProjectile::Update()
     {
     	pos+=speed;
    -	speed.y+=gs->gravity;
    +	speed.y+=gravity;
     
     	if(!--ttl)
     		Collision();
    @@ -75,6 +78,9 @@
     			float3 n=ground->GetNormal(pos.x,pos.z);
     			pos-=speed*max(0.0f,min(1.0f,float((h-pos.y)*n.y/n.dot(speed)+0.1f)));
     		}
    +		else if (weaponDef->waterweapon) {
    +			return; //let waterweapons go underwater
    +		}
     	}
     //	helper->Explosion(pos,damages,areaOfEffect,owner);
     	CWeaponProjectile::Collision();
    Index: rts/Sim/Projectiles/ExplosiveProjectile.h
    ===================================================================
    --- rts/Sim/Projectiles/ExplosiveProjectile.h	(revision 4223)
    +++ rts/Sim/Projectiles/ExplosiveProjectile.h	(working copy)
    @@ -12,7 +12,8 @@
     {
     	CR_DECLARE(CExplosiveProjectile);
     public:
    -	CExplosiveProjectile(const float3& pos, const float3& speed, CUnit* owner, const WeaponDef* weaponDef, int ttl=100000, float areaOfEffect=8);
    +	CExplosiveProjectile(const float3& pos, const float3& speed, CUnit* owner,
    +		const WeaponDef *weaponDef, int ttl=100000, float areaOfEffect=8, float gravity=0);
     	virtual ~CExplosiveProjectile();
     	virtual void Update();
     	void Draw(void);
    @@ -24,6 +25,7 @@
     	float areaOfEffect;
     	float invttl;
     	float curTime;
    +	float gravity;
     };
     
     #endif // __EXPLOSIVE_PROJECTILE_H__
    Index: rts/Sim/Projectiles/FireBallProjectile.cpp
    ===================================================================
    --- rts/Sim/Projectiles/FireBallProjectile.cpp	(revision 4223)
    +++ rts/Sim/Projectiles/FireBallProjectile.cpp	(working copy)
    @@ -3,6 +3,7 @@
     #include "Rendering/GL/VertexArray.h"
     #include "Game/Camera.h"
     #include "Sim/Weapons/WeaponDefHandler.h"
    +#include "Map/Ground.h"
     #include "creg/STL_Deque.h"
     #include "ProjectileHandler.h"
     #include "mmgr.h"
    @@ -125,8 +126,10 @@
     
     void CFireBallProjectile::Collision()
     {
    +	if(weaponDef->waterweapon && ground->GetHeight2(pos.x, pos.z)<pos.y) return; //make waterweapons not explode in water
     	CWeaponProjectile::Collision();
     	deleteMe = false;
     }
     
     
    +
    Index: rts/Sim/Projectiles/FlameProjectile.cpp
    ===================================================================
    --- rts/Sim/Projectiles/FlameProjectile.cpp	(revision 4223)
    +++ rts/Sim/Projectiles/FlameProjectile.cpp	(working copy)
    @@ -44,6 +44,7 @@
     
     void CFlameProjectile::Collision(void)
     {
    +	if(ground->GetHeight2(pos.x, pos.z) < pos.y && weaponDef->waterweapon) return; //prevent waterweapons from colliding with water
     	float3 norm=ground->GetNormal(pos.x,pos.z);
     	float ns=speed.dot(norm);
     	speed-=norm*ns*1;
    Index: rts/Sim/Projectiles/LaserProjectile.cpp
    ===================================================================
    --- rts/Sim/Projectiles/LaserProjectile.cpp	(revision 4223)
    +++ rts/Sim/Projectiles/LaserProjectile.cpp	(working copy)
    @@ -7,6 +7,7 @@
     #include "ProjectileHandler.h"
     #include "SimpleParticleSystem.h"
     #include "mmgr.h"
    +#include "Map/Ground.h"
     
     CR_BIND_DERIVED(CLaserProjectile, CWeaponProjectile, (float3(0,0,0),float3(0,0,0),NULL,0,float3(0,0,0),float3(0,0,0),0,NULL,0));
     
    @@ -104,6 +105,8 @@
     
     void CLaserProjectile::Collision()
     {
    +	if(weaponDef->waterweapon && ground->GetHeight2(pos.x,pos.z) < pos.y) 
    +		return; //prevent impact on water if waterweapon is set
     	float3 oldPos=pos;
     	CWeaponProjectile::Collision();
     
    Index: rts/Sim/Projectiles/LightingProjectile.cpp
    ===================================================================
    --- rts/Sim/Projectiles/LightingProjectile.cpp	(revision 4223)
    +++ rts/Sim/Projectiles/LightingProjectile.cpp	(working copy)
    @@ -59,7 +59,7 @@
     	}
     
     	if(weapon){
    -		pos=weapon->weaponPos;
    +		pos=weapon->weaponMuzzlePos;
     	}
     	for(int a=1;a<10;++a)
     		displacements[a]+=(gs->randFloat()-0.5f)*0.3f;
    Index: rts/Sim/Projectiles/MissileProjectile.cpp
    ===================================================================
    --- rts/Sim/Projectiles/MissileProjectile.cpp	(revision 4223)
    +++ rts/Sim/Projectiles/MissileProjectile.cpp	(working copy)
    @@ -119,9 +119,11 @@
     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)));
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldDir,owner,false,true,7,Smoke_Time,0.6f,drawTrail);
    +	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;
    @@ -129,7 +131,8 @@
     
     void CMissileProjectile::Collision(CUnit *unit)
     {
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldDir,owner,false,true,7,Smoke_Time,0.6f,drawTrail);
    +	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);
     
    @@ -207,7 +210,7 @@
     
     	age++;
     	numParts++;
    -	if(!(age&7)){
    +	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;
    @@ -234,66 +237,67 @@
     	float color=0.6f;
     	unsigned char col[4];
     
    -	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;
    +	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;//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);
    +			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;
    Index: rts/Sim/Projectiles/StarburstProjectile.cpp
    ===================================================================
    --- rts/Sim/Projectiles/StarburstProjectile.cpp	(revision 4223)
    +++ rts/Sim/Projectiles/StarburstProjectile.cpp	(working copy)
    @@ -15,6 +15,8 @@
     #include "ProjectileHandler.h"
     #include "mmgr.h"
     
    +#include "LogOutput.h"
    +
     static const float Smoke_Time=70;
     
     CR_BIND_DERIVED(CStarburstProjectile, CWeaponProjectile, (float3(0,0,0),float3(0,0,0),NULL,float3(0,0,0),0,0,0,0,NULL,NULL,NULL,0));
    @@ -67,7 +69,12 @@
     	distanceToTravel(maxdistance)
     {
     	this->uptime=uptime;
    -	ttl=(int)min(3000.f,uptime+(weaponDef?weaponDef->range:0)/maxSpeed+100);
    +	if (weaponDef->flighttime == 0) {
    +		ttl=(int)min(3000.f,uptime+(weaponDef?weaponDef->range:0)/maxSpeed+100);
    +	}
    +	else {
    +		ttl=weaponDef->flighttime;
    +	}
     
     	maxGoodDif=cos(tracking*0.6f);
     	curSpeed=speed.Length();
    @@ -111,9 +118,11 @@
     void CStarburstProjectile::Collision()
     {
     	float h=ground->GetHeight2(pos.x,pos.z);
    +	if(weaponDef->waterweapon && h < pos.y) return; //prevent impact on water if waterweapon is set
     	if(h>pos.y)
     		pos+=speed*(h-pos.y)/speed.y;
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
    +	if (weaponDef->visuals.smokeTrail)
    +		SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
     	oldSmokeDir=dir;
     //	helper->Explosion(pos,damages,areaOfEffect,owner);
     	CWeaponProjectile::Collision();
    @@ -122,7 +131,8 @@
     
     void CStarburstProjectile::Collision(CUnit *unit)
     {
    -	SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
    +	if (weaponDef->visuals.smokeTrail)
    +		SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,false,true,7,Smoke_Time,0.7f,drawTrail);
     	oldSmokeDir=dir;
     //	unit->DoDamage(damages,owner);
     //	helper->Explosion(pos,damages,areaOfEffect,owner);
    @@ -148,8 +158,7 @@
     	}
     	if(uptime>0){
     		if(curSpeed<maxSpeed)
    -			curSpeed+=0.1f;
    -		dir=UpVector;
    +			curSpeed+=weaponDef->weaponacceleration;
     		speed=dir*curSpeed;
     	} else if(doturn && ttl>0 && distanceToTravel>0) {
     		float3 dif(targetPos-pos);
    @@ -161,14 +170,20 @@
     			dif=dif-dir;
     			dif-=dir*(dif.dot(dir));
     			dif.Normalize();
    -			dir+=dif*0.06f;
    +			if (weaponDef->turnrate != 0) {
    +				dir+=dif*weaponDef->turnrate;
    +			}
    +			else {
    +				dir+=dif*0.06;
    +			}
     			dir.Normalize();
     		}
     		speed=dir*curSpeed;
    -		distanceToTravel-=speed.Length2D();
    +		if (distanceToTravel != MAX_WORLD_SIZE)
    +			distanceToTravel-=speed.Length2D();
     	} else if(ttl>0 && distanceToTravel>0) {
     		if(curSpeed<maxSpeed)
    -			curSpeed+=0.1f;
    +			curSpeed+=weaponDef->weaponacceleration;
     		float3 dif(targetPos-pos);
     		dif.Normalize();
     		if(dif.dot(dir)>maxGoodDif){
    @@ -181,7 +196,8 @@
     			dir.Normalize();
     		}
     		speed=dir*curSpeed;
    -		distanceToTravel-=speed.Length2D();
    +		if (distanceToTravel != MAX_WORLD_SIZE)
    +			distanceToTravel-=speed.Length2D();
     	} else {
     		dir.y+=gs->gravity;
     		dir.Normalize();
    @@ -202,7 +218,7 @@
     
     	age++;
     	numParts++;
    -	if(!(age&7)){
    +	if(weaponDef->visuals.smokeTrail && !(age&7)){
     		if(curCallback)
     			curCallback->drawCallbacker=0;
     		curCallback=SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,age==8,false,7,Smoke_Time,0.7f,drawTrail,this);
    @@ -231,65 +247,66 @@
     	unsigned char col[4];
     	unsigned char col2[4];
     
    -	if(drawTrail){		//draw the trail as a single quad
    +	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(oldSmokeDir));
    -		dir2.Normalize();
    +			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(oldSmokeDir));
    +			dir2.Normalize();
     
     
    -		float a1=(1-float(0)/(Smoke_Time))*255;
    -		a1*=0.7f+fabs(dif.dot(dir));
    -		int alpha=min(255,(int)max(0.f,a1));
    -		col[0]=(unsigned char) (color*alpha);
    -		col[1]=(unsigned char) (color*alpha);
    -		col[2]=(unsigned char) (color*alpha);
    -		col[3]=(unsigned char)alpha;
    +			float a1=(1-float(0)/(Smoke_Time))*255;
    +			a1*=0.7f+fabs(dif.dot(dir));
    +			int alpha=min(255,(int)max(0.f,a1));
    +			col[0]=(unsigned char) (color*alpha);
    +			col[1]=(unsigned char) (color*alpha);
    +			col[2]=(unsigned char) (color*alpha);
    +			col[3]=(unsigned char)alpha;
     
    -		float a2=(1-float(age2)/(Smoke_Time))*255;
    -		a2*=0.7f+fabs(dif2.dot(oldSmokeDir));
    -		if(age<8)
    -			a2=0;
    -		alpha=min(255,(int)max(0.f,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 a2=(1-float(age2)/(Smoke_Time))*255;
    +			a2*=0.7f+fabs(dif2.dot(oldSmokeDir));
    +			if(age<8)
    +				a2=0;
    +			alpha=min(255,(int)max(0.f,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 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+oldSmokeDir*dist*0.33f;
    +			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+oldSmokeDir*dist*0.33f;
     
    -		for(int a=0;a<numParts;++a){
    -			//float a1=1-float(a)/Smoke_Time;
    -			col[0]=(unsigned char) (color*255);
    -			col[1]=(unsigned char) (color*255);
    -			col[2]=(unsigned char) (color*255);
    -			col[3]=255;//min(255,max(0,a1*255));
    -			float size=(1+(a)*(1/Smoke_Time)*7);
    +			for(int a=0;a<numParts;++a){
    +				//float a1=1-float(a)/Smoke_Time;
    +				col[0]=(unsigned char) (color*255);
    +				col[1]=(unsigned char) (color*255);
    +				col[2]=(unsigned char) (color*255);
    +				col[3]=255;//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);
    +				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);
    +			}
    +
     		}
    -
    -	}
     	DrawCallback();
     	if(curCallback==0)
     		DrawCallback();
    Index: rts/Sim/Projectiles/StarburstProjectile.h
    ===================================================================
    --- rts/Sim/Projectiles/StarburstProjectile.h	(revision 4223)
    +++ rts/Sim/Projectiles/StarburstProjectile.h	(working copy)
    @@ -30,6 +30,7 @@
     	float3 dir;
     	float maxSpeed;
     	float curSpeed;
    +	float acceleration;
     	int ttl;
     	int uptime;
     	float areaOfEffect;
    Index: rts/Sim/Projectiles/TorpedoProjectile.cpp
    ===================================================================
    --- rts/Sim/Projectiles/TorpedoProjectile.cpp	(revision 4223)
    +++ rts/Sim/Projectiles/TorpedoProjectile.cpp	(working copy)
    @@ -10,6 +10,7 @@
     #include "BubbleProjectile.h"
     #include "ProjectileHandler.h"
     #include "mmgr.h"
    +#include "Sim/Weapons/WeaponDefHandler.h"
     
     CR_BIND_DERIVED(CTorpedoProjectile, CTorpedoProjectile, (float3(0,0,0),float3(0,0,0),NULL,0,0,0,0,NULL,NULL));
     
    @@ -82,14 +83,14 @@
     
     void CTorpedoProjectile::Update(void)
     {
    -	if(pos.y>-3){		//tracking etc only work when we have gotten underwater
    +	if(!(weaponDef->submissile) && pos.y>-3){		//tracking etc only work when we have gotten underwater
     		speed.y+=gs->gravity;
     		if(dir.y>0)
     			dir.y=0;
     		dir=speed;
     		dir.Normalize();
     	} else {
    -		if(pos.y-speed.y>-3){		//level out torpedo a bit when hitting water
    +		if(!(weaponDef->submissile) && pos.y-speed.y>-3){		//level out torpedo a bit when hitting water
     			dir.y*=0.5f;
     			dir.Normalize();
     		}
    @@ -103,7 +104,7 @@
     					targPos=target->midPos;
     				else
     					targPos=helper->GetUnitErrorPos(target,owner->allyteam);
    -				if(targPos.y>0)
    +				if(!(weaponDef->submissile) && targPos.y>0)
     					targPos.y=0;
     
     				float dist=targPos.distance(pos);
    Index: rts/Sim/Units/COB/CobFile.cpp
    ===================================================================
    --- rts/Sim/Units/COB/CobFile.cpp	(revision 4223)
    +++ rts/Sim/Units/COB/CobFile.cpp	(working copy)
    @@ -166,7 +166,7 @@
     	}
     
     	//Map common function names to indicies
    -	scriptIndex.resize(COBFN_Last + COB_MaxWeapons * 5);
    +	scriptIndex.resize(COBFN_Last + COB_MaxWeapons * 6);
     	scriptIndex[COBFN_Create] = getFunctionId("Create");
     	scriptIndex[COBFN_StartMoving] = getFunctionId("StartMoving");
     	scriptIndex[COBFN_StopMoving] = getFunctionId("StopMoving");
    @@ -197,6 +197,7 @@
     		scriptIndex[COBFN_AimFromPrimary + i] = getFunctionId("AimFrom" + weapon);
     		scriptIndex[COBFN_FirePrimary + i] = getFunctionId("Fire" + weapon);
     		scriptIndex[COBFN_EndBurst + i] = getFunctionId("EndBurst" + weap);
    +		scriptIndex[COBFN_Shot + i] = getFunctionId("Shot" + weap);
     
     		// If new-naming functions are not found, we need to support the old naming scheme
     		if (i > 2)
    Index: rts/Sim/Units/COB/CobFile.h
    ===================================================================
    --- rts/Sim/Units/COB/CobFile.h	(revision 4223)
    +++ rts/Sim/Units/COB/CobFile.h	(working copy)
    @@ -46,6 +46,7 @@
     const int COBFN_AimFromPrimary = COBFN_AimPrimary + COB_MaxWeapons;
     const int COBFN_FirePrimary = COBFN_AimFromPrimary + COB_MaxWeapons;
     const int COBFN_EndBurst = COBFN_FirePrimary + COB_MaxWeapons;
    +const int COBFN_Shot = COBFN_EndBurst + COB_MaxWeapons;
     
     class CCobFile
     {
    Index: rts/Sim/Units/COB/CobInstance.cpp
    ===================================================================
    --- rts/Sim/Units/COB/CobInstance.cpp	(revision 4223)
    +++ rts/Sim/Units/COB/CobInstance.cpp	(working copy)
    @@ -665,15 +665,15 @@
     				dir.Normalize();
     
     				float3 targetPos = unit->weapons[index]->targetPos;
    -				float3 weaponPos = unit->weapons[index]->weaponPos;
    +				float3 weaponMuzzlePos = unit->weapons[index]->weaponMuzzlePos;
     
     				unit->weapons[index]->targetPos = pos+dir;
    -				unit->weapons[index]->weaponPos = pos;
    +				unit->weapons[index]->weaponMuzzlePos = pos;
     
     				unit->weapons[index]->Fire();
     
     				unit->weapons[index]->targetPos = targetPos;
    -				unit->weapons[index]->weaponPos = weaponPos;
    +				unit->weapons[index]->weaponMuzzlePos = weaponMuzzlePos;
     			}
     			else if (type & 4096) {
     				unsigned index = type - 4096;
    Index: rts/Sim/Units/UnitLoader.cpp
    ===================================================================
    --- rts/Sim/Units/UnitLoader.cpp	(revision 4223)
    +++ rts/Sim/Units/UnitLoader.cpp	(working copy)
    @@ -348,7 +348,7 @@
     	} else if(weapondef->type=="MissileLauncher"){
     		weapon=SAFE_NEW CMissileLauncher(owner);
     	} else if(weapondef->type=="TorpedoLauncher"){
    -		if(owner->unitDef->canfly){
    +		if(owner->unitDef->canfly && !weapondef->submissile){
     			weapon=SAFE_NEW CBombDropper(owner,true);
     			if(weapondef->tracks)
     				((CBombDropper*)weapon)->tracking=weapondef->turnrate;
    @@ -377,7 +377,7 @@
     			((CStarburstLauncher*)weapon)->tracking=weapondef->turnrate;
     		else
     			((CStarburstLauncher*)weapon)->tracking=0;
    -		((CStarburstLauncher*)weapon)->uptime=weapondef->uptime*30;
    +		((CStarburstLauncher*)weapon)->uptime=weapondef->uptime*GAME_SPEED;
     	}else {
     		logOutput << "Unknown weapon type " << weapondef->type.c_str() << "\n";
     		return 0;
    @@ -461,3 +461,4 @@
     }
     
     
    +
    Index: rts/Sim/Units/UnitTypes/Builder.cpp
    ===================================================================
    --- rts/Sim/Units/UnitTypes/Builder.cpp	(revision 4223)
    +++ rts/Sim/Units/UnitTypes/Builder.cpp	(working copy)
    @@ -582,9 +582,12 @@
     {
     	float3 wantedDir=(pos-this->pos).Normalize();
     	short int h=GetHeadingFromVector(wantedDir.x,wantedDir.z);
    +	short int p=(short int) (asin(wantedDir.dot(updir))*(32768/PI));
    +	short int pitch=(short int) (asin(frontdir.dot(updir))*(32768/PI));
     
     	std::vector<int> args;
     	args.push_back(short(h-heading));
    +	args.push_back(short(p-pitch));
     	cob->Call("StartBuilding", args);
     
     	int soundIdx = unitDef->sounds.build.getRandomIdx();
    Index: rts/Sim/Weapons/BeamLaser.cpp
    ===================================================================
    --- rts/Sim/Weapons/BeamLaser.cpp	(revision 4223)
    +++ rts/Sim/Weapons/BeamLaser.cpp	(working copy)
    @@ -43,6 +43,7 @@
     {
     	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();
    @@ -77,15 +78,17 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater)
    -			return false;
    -	} else {
    -		if(pos.y<0)
    -			return false;
    +	if(!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater)
    +				return false;
    +		} else {
    +			if(pos.y<0)
    +				return false;
    +		}
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     
     	float length=dir.Length();
     	if(length==0)
    @@ -94,14 +97,14 @@
     	dir/=length;
     
     	if(!onlyForward){		//skip ground col testing for aircrafts
    -		float g=ground->LineGroundCol(weaponPos,pos);
    +		float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     		if(g>0 && g<length*0.9f)
     			return false;
     	}
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -127,7 +130,7 @@
     		if(salvoLeft==salvoSize-1){
     			if(fireSoundId)
     				sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    -			dir=targetPos-weaponPos;
    +			dir=targetPos-weaponMuzzlePos;
     			dir.Normalize();
     			oldDir=dir;
     		} else {
    @@ -151,7 +154,7 @@
     
     	float maxLength=range*rangeMod;
     	float curLength=0;
    -	float3 curPos=weaponPos;
    +	float3 curPos=weaponMuzzlePos;
     	float3 hitPos;
     
     	bool tryAgain=true;
    @@ -220,7 +223,7 @@
     		// Dynamic Damage
     		DamageArray dynDamages;
     		if (weaponDef->dynDamageExp > 0)
    -			dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponPos, curPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
    +			dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponMuzzlePos, curPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
     		helper->Explosion(hitPos, weaponDef->dynDamageExp>0?dynDamages*(intensity*damageMul):weaponDef->damages*(intensity*damageMul), areaOfEffect, weaponDef->edgeEffectiveness, weaponDef->explosionSpeed,owner, true, 1.0f, false, weaponDef->explosionGenerator, hit, dir, weaponDef->id);
     	}
     
    Index: rts/Sim/Weapons/bombdropper.cpp
    ===================================================================
    --- rts/Sim/Weapons/bombdropper.cpp	(revision 4223)
    +++ rts/Sim/Weapons/bombdropper.cpp	(working copy)
    @@ -56,14 +56,14 @@
     		if(weaponPos.y>targetPos.y){
     			float d=targetPos.y-weaponPos.y;
     			float s=-owner->speed.y;
    -			float sq=(s-2*d)/-gs->gravity;
    +			float sq=(s-2*d)/-(weaponDef->myGravity==0 ? gs->gravity : -(weaponDef->myGravity));
     			if(sq>0)
    -				predict=s/gs->gravity+sqrt(sq);
    +				predict=s/(weaponDef->myGravity==0 ? gs->gravity : -(weaponDef->myGravity))+sqrt(sq);
     			else
     				predict=0;
     			float3 hitpos=owner->pos+owner->speed*predict;
     			float speedf=owner->speed.Length();
    -			if(hitpos.distance2D(targetPos)<(salvoSize-1)*speedf*salvoDelay*0.5f+bombMoveRange){
    +			if(hitpos.distance2D(targetPos)<max(1,(salvoSize-1))*speedf*salvoDelay*0.5f+bombMoveRange){
     				subClassReady=true;
     			}
     		}
    @@ -108,7 +108,7 @@
     		float size=dif.Length();
     		if(size>1.0f)
     			dif/=size*1.0f;
    -		SAFE_NEW CExplosiveProjectile(weaponPos,owner->speed+dif,owner, weaponDef, 1000,areaOfEffect);
    +		SAFE_NEW CExplosiveProjectile(weaponPos,owner->speed+dif,owner, weaponDef, 1000,areaOfEffect,weaponDef->myGravity==0 ? gs->gravity : -(weaponDef->myGravity));
     	}
     	//CWeaponProjectile::CreateWeaponProjectile(owner->pos,owner->speed,owner, NULL, float3(0,0,0), damages, weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
    Index: rts/Sim/Weapons/Cannon.cpp
    ===================================================================
    --- rts/Sim/Weapons/Cannon.cpp	(revision 4223)
    +++ rts/Sim/Weapons/Cannon.cpp	(working copy)
    @@ -29,6 +29,7 @@
     	CR_MEMBER(rangeFactor),
     	CR_MEMBER(lastDiff),
     	CR_MEMBER(lastDir),
    +	CR_MEMBER(gravity),
     	CR_RESERVED(16)
     	));
     
    @@ -47,11 +48,12 @@
     
     void CCannon::Init(void)
     {
    +	gravity = weaponDef->myGravity==0 ? gs->gravity : -(weaponDef->myGravity);
     	if(highTrajectory){
    -		maxPredict=projectileSpeed*2/-gs->gravity;
    -		minPredict=projectileSpeed*1.41f/-gs->gravity;
    +		maxPredict=projectileSpeed*2/-gravity;
    +		minPredict=projectileSpeed*1.41f/-gravity;
     	} else {
    -		maxPredict=projectileSpeed*1.41f/-gs->gravity;
    +		maxPredict=projectileSpeed*1.41f/-gravity;
     	}
     	CWeapon::Init();
     
    @@ -79,6 +81,8 @@
     	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;
     		float3 diff = targetPos-weaponPos;
     		wantedDir = GetWantedDir(diff);
     		float speed2D = wantedDir.Length2D() * projectileSpeed;
    @@ -97,24 +101,26 @@
     		return false;
     	}
     
    -	if(unit)
    -	{
    -		if(unit->isUnderWater)
    +	if(!weaponDef->waterweapon) {
    +		if(unit)
     		{
    -			return false;
    +			if(unit->isUnderWater)
    +			{
    +				return false;
    +			}
    +		} else {
    +			if(pos.y<0)
    +			{
    +				return false;
    +			}
     		}
    -	} else {
    -		if(pos.y<0)
    -		{
    -			return false;
    -		}
     	}
     
     	if (projectileSpeed == 0)
     	{
     		return true;
     	}
    -	float3 dif(pos-weaponPos);
    +	float3 dif(pos-weaponMuzzlePos);
     
     	float3 dir(GetWantedDir(dif));
     
    @@ -129,8 +135,8 @@
     	}
     	flatdir/=flatlength;
     
    -	float gc=ground->TrajectoryGroundCol(weaponPos, flatdir, flatlength-10,
    -			dir.y , gs->gravity / (projectileSpeed * projectileSpeed) * 0.5f);
    +	float gc=ground->TrajectoryGroundCol(weaponMuzzlePos, flatdir, flatlength-10,
    +			dir.y , gravity / (projectileSpeed * projectileSpeed) * 0.5f);
     	if(gc>0) {
     		return false;
     	}
    @@ -139,8 +145,8 @@
     	if(gc>0 && gc<length*0.40f)
     		return false;
     */
    -	if(avoidFriendly && helper->TestTrajectoryCone(weaponPos, flatdir,
    -		flatlength-30, dir.y, gs->gravity /
    +	if(avoidFriendly && helper->TestTrajectoryCone(weaponMuzzlePos, flatdir,
    +		flatlength-30, dir.y, gravity /
     		(projectileSpeed * projectileSpeed) * 0.5f,
     		(accuracy+sprayangle) * 0.6f * (1-owner->limExperience * 0.9f) * 0.9f,
     		3, owner->allyteam, owner))
    @@ -162,7 +168,7 @@
     
     void CCannon::Fire(void)
     {
    -	float3 diff = targetPos-weaponPos;
    +	float3 diff = targetPos-weaponMuzzlePos;
     	float3 dir=GetWantedDir(diff);
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.9f);
     	dir.Normalize();
    @@ -172,14 +178,14 @@
     #endif
     	int ttl = 0;
     	float sqSpeed2D = dir.SqLength2D() * projectileSpeed * projectileSpeed;
    -	int predict = (int)ceil((sqSpeed2D == 0) ? (-2 * projectileSpeed * dir.y / gs->gravity)
    +	int predict = (int)ceil((sqSpeed2D == 0) ? (-2 * projectileSpeed * dir.y / gravity)
     			: sqrt(diff.SqLength2D() / sqSpeed2D));
     	if(selfExplode) {
     		ttl=(int)(predict+gs->randFloat()*2.5f-0.5f);
     	} else {
     		ttl=predict*2;
     	}
    -	SAFE_NEW CExplosiveProjectile(weaponPos,dir*projectileSpeed,owner,weaponDef, ttl,areaOfEffect);
    +	SAFE_NEW CExplosiveProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,weaponDef, ttl,areaOfEffect,gravity);
     	//CWeaponProjectile::CreateWeaponProjectile(weaponPos,owner->speed,owner, NULL, float3(0,0,0), weaponDef);
     
     //	SAFE_NEW CSmokeProjectile(weaponPos,dir*0.01f,90,0.1f,0.02f,owner,0.6f);
    @@ -188,8 +194,8 @@
     //	p->maxheat=p->heat;
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    -	if (weaponPos.y < 30)
    -		water->AddExplosion(weaponPos, weaponDef->damages[0] * 0.1f, sqrt(weaponDef->damages[0]) + 80);
    +//	if(weaponMuzzlePos.y < 30)
    +//		water->AddExplosion(weaponMuzzlePos, weaponDef->damages[0] * 0.1f, sqrt(weaponDef->damages[0]) + 80);
     }
     
     void CCannon::SlowUpdate(void)
    @@ -197,10 +203,10 @@
     	if(owner->useHighTrajectory!=highTrajectory){
     		highTrajectory=owner->useHighTrajectory;
     		if(highTrajectory){
    -			maxPredict=projectileSpeed*2/-gs->gravity;
    -			minPredict=projectileSpeed*1.41f/-gs->gravity;
    +			maxPredict=projectileSpeed*2/-gravity;
    +			minPredict=projectileSpeed*1.41f/-gravity;
     		} else {
    -			maxPredict=projectileSpeed*1.41f/-gs->gravity;
    +			maxPredict=projectileSpeed*1.41f/-gravity;
     		}
     	}
     	CWeapon::SlowUpdate();
    @@ -229,7 +235,7 @@
     
     	float Dsq = diff.SqLength();
     	float DFsq = diff.SqLength2D();
    -	float g = gs->gravity;
    +	float g = gravity;
     	float v = projectileSpeed;
     	float dy = diff.y;
     	float dxz = sqrt(DFsq);
    @@ -279,10 +285,10 @@
     		// f(0) == 1, f(smoothHeight) == heightBoostFactor
     		yDiff *= 1.f + (heightBoostFactor-1.f) * (-yDiff)/smoothHeight;
     
    -	float root1 = speed2dSq + 2*gs->gravity*yDiff;
    +	float root1 = speed2dSq + 2*gravity*yDiff;
     	if(root1 < 0.f){
     		return 0.f;
     	} else {
    -		return rangeFactor*(speed2dSq + speed2d*sqrt(root1))/(-gs->gravity);
    +		return rangeFactor*(speed2dSq + speed2d*sqrt(root1))/(-gravity);
     	}
     }
    Index: rts/Sim/Weapons/Cannon.h
    ===================================================================
    --- rts/Sim/Weapons/Cannon.h	(revision 4223)
    +++ rts/Sim/Weapons/Cannon.h	(working copy)
    @@ -36,6 +36,8 @@
     	bool highTrajectory;
     	/// burnblow tag. defines flakker-like behaviour
     	bool selfExplode;
    +	/// projectile gravity
    +	float gravity;
     
     	void SlowUpdate(void);
     	/// tells where to point the gun to hit the point at pos+diff
    Index: rts/Sim/Weapons/DGunWeapon.cpp
    ===================================================================
    --- rts/Sim/Weapons/DGunWeapon.cpp	(revision 4223)
    +++ rts/Sim/Weapons/DGunWeapon.cpp	(working copy)
    @@ -27,7 +27,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -46,13 +47,13 @@
     	if(onlyForward){
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
     	dir.Normalize();
     
    -	SAFE_NEW CFireBallProjectile(weaponPos,dir*projectileSpeed,owner,0,targetPos,weaponDef);
    +	SAFE_NEW CFireBallProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,0,targetPos,weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume*0.2f);
     }
    Index: rts/Sim/Weapons/EmgCannon.cpp
    ===================================================================
    --- rts/Sim/Weapons/EmgCannon.cpp	(revision 4223)
    +++ rts/Sim/Weapons/EmgCannon.cpp	(working copy)
    @@ -31,7 +31,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -45,29 +46,31 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater)
    -			return false;
    -	} else {
    -		if(pos.y<0)
    -			return false;
    +	if (!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater)
    +				return false;
    +		} else {
    +			if(pos.y<0)
    +				return false;
    +		}
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.5f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.5f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -87,15 +90,17 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType)){		//the taairmovetype cant align itself properly, change back when that is fixed
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
     	dir.Normalize();
     
    -	SAFE_NEW CEmgProjectile(weaponPos,dir*projectileSpeed,owner,weaponDef->visuals.color,weaponDef->intensity,(int)(range/projectileSpeed), weaponDef);
    +	SAFE_NEW CEmgProjectile(weaponMuzzlePos,dir*projectileSpeed,owner,weaponDef->visuals.color,weaponDef->intensity,(int)(range/projectileSpeed), weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
     
     
    +
    +
    Index: rts/Sim/Weapons/FlameThrower.cpp
    ===================================================================
    --- rts/Sim/Weapons/FlameThrower.cpp	(revision 4223)
    +++ rts/Sim/Weapons/FlameThrower.cpp	(working copy)
    @@ -27,12 +27,12 @@
     
     void CFlameThrower::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
     	float3 spread=(gs->randVector()*sprayangle+salvoError)*0.2f;
     	spread-=dir*0.001f;
     
    -	SAFE_NEW CFlameProjectile(weaponPos,dir*projectileSpeed,spread,owner,weaponDef,(int)(range/projectileSpeed*weaponDef->duration));
    +	SAFE_NEW CFlameProjectile(weaponMuzzlePos,dir*projectileSpeed,spread,owner,weaponDef,(int)(range/projectileSpeed*weaponDef->duration));
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    @@ -42,29 +42,31 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater)
    -			return false;
    -	} else {
    -		if(pos.y<0)
    -			return false;
    +	if (!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater)
    +				return false;
    +		} else {
    +			if(pos.y<0)
    +				return false;
    +		}
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner)){
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner)){
     		return false;
     	}
     	return true;
    @@ -74,6 +76,7 @@
     {
     	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;
     		wantedDir=targetPos-weaponPos;
     		wantedDir.Normalize();
     	}
    Index: rts/Sim/Weapons/LaserCannon.cpp
    ===================================================================
    --- rts/Sim/Weapons/LaserCannon.cpp	(revision 4223)
    +++ rts/Sim/Weapons/LaserCannon.cpp	(working copy)
    @@ -30,7 +30,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			wantedDir.Normalize();
     		}
    @@ -45,14 +46,14 @@
     		return false;
     
     	if(unit){
    -		if(unit->isUnderWater)
    +		if(unit->isUnderWater && !weaponDef->waterweapon)
     			return false;
     	} else {
    -		if(pos.y<0)
    +		if(pos.y<0 && !weaponDef->waterweapon)
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
    @@ -60,14 +61,14 @@
     	dir/=length;
     
     	if(!onlyForward){		//skip ground col testing for aircrafts
    -		float g=ground->LineGroundCol(weaponPos,pos);
    +		float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     		if(g>0 && g<length*0.9f)
     			return false;
     	}
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.7f),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -84,7 +85,7 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType)){		//the taairmovetype cant align itself properly, change back when that is fixed
     		dir=owner->frontdir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     	}
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.7f);
    @@ -96,10 +97,12 @@
     		fpsSub=6;
     #endif
     
    -	SAFE_NEW CLaserProjectile(weaponPos, dir*projectileSpeed, owner, weaponDef->duration*weaponDef->maxvelocity, weaponDef->visuals.color, weaponDef->visuals.color2, weaponDef->intensity, weaponDef, (int)((weaponDef->range-fpsSub*4)/weaponDef->projectilespeed)-fpsSub);
    +	SAFE_NEW CLaserProjectile(weaponMuzzlePos, dir*projectileSpeed, owner, weaponDef->duration*weaponDef->maxvelocity, weaponDef->visuals.color, weaponDef->visuals.color2, weaponDef->intensity, weaponDef, (int)((weaponDef->range-fpsSub*4)/weaponDef->projectilespeed)-fpsSub);
     
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
     
     
    +
    +
    Index: rts/Sim/Weapons/LightingCannon.cpp
    ===================================================================
    --- rts/Sim/Weapons/LightingCannon.cpp	(revision 4223)
    +++ rts/Sim/Weapons/LightingCannon.cpp	(working copy)
    @@ -31,6 +31,7 @@
     {
     	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();
    @@ -44,29 +45,31 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater)
    -			return false;
    -	} else {
    -		if(pos.y<0)
    -			return false;
    +	if(!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater)
    +				return false;
    +		} else {
    +			if(pos.y<0)
    +				return false;
    +		}
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(avoidFeature && helper->LineFeatureCol(weaponPos,dir,length))
    +	if(avoidFeature && helper->LineFeatureCol(weaponMuzzlePos,dir,length))
     		return false;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
     		return false;
     	return true;
     }
    @@ -78,16 +81,16 @@
     
     void CLightingCannon::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.5f);
     	dir.Normalize();
     	CUnit* u=0;
    -	float r=helper->TraceRay(weaponPos,dir,range,0,owner,u);
    +	float r=helper->TraceRay(weaponMuzzlePos,dir,range,0,owner,u);
     
     	float3 newDir;
     	CPlasmaRepulser* shieldHit;
    -	float shieldLength=interceptHandler.AddShieldInterceptableBeam(this,weaponPos,dir,range,newDir,shieldHit);
    +	float shieldLength=interceptHandler.AddShieldInterceptableBeam(this,weaponMuzzlePos,dir,range,newDir,shieldHit);
     	if(shieldLength<r){
     		r=shieldLength;
     		if(shieldHit) {
    @@ -101,11 +104,11 @@
     	// Dynamic Damage
     	DamageArray dynDamages;
     	if (weaponDef->dynDamageExp > 0)
    -		dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponPos, targetPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
    +		dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponMuzzlePos, targetPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted);
     
    -	helper->Explosion(weaponPos+dir*r,weaponDef->dynDamageExp>0?dynDamages:weaponDef->damages,areaOfEffect,weaponDef->edgeEffectiveness,weaponDef->explosionSpeed,owner,false,0.5f,true,weaponDef->explosionGenerator, u,dir, weaponDef->id);
    +	helper->Explosion(weaponMuzzlePos+dir*r,weaponDef->dynDamageExp>0?dynDamages:weaponDef->damages,areaOfEffect,weaponDef->edgeEffectiveness,weaponDef->explosionSpeed,owner,false,0.5f,true,weaponDef->explosionGenerator, u,dir, weaponDef->id);
     
    -	SAFE_NEW CLightingProjectile(weaponPos,weaponPos+dir*(r+10),owner,color,weaponDef,10,this);
    +	SAFE_NEW CLightingProjectile(weaponMuzzlePos,weaponMuzzlePos+dir*(r+10),owner,color,weaponDef,10,this);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     
    Index: rts/Sim/Weapons/MeleeWeapon.cpp
    ===================================================================
    --- rts/Sim/Weapons/MeleeWeapon.cpp	(revision 4223)
    +++ rts/Sim/Weapons/MeleeWeapon.cpp	(working copy)
    @@ -33,21 +33,23 @@
     {
     	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();
    -
     }
     
     void CMeleeWeapon::Fire(void)
     {
     	if(targetType==Target_Unit){
    -		float3 impulseDir = targetUnit->pos-weaponPos;
    +		float3 impulseDir = targetUnit->pos-weaponMuzzlePos;
     		impulseDir.Normalize();
    -		targetUnit->DoDamage(weaponDef->damages,owner,impulseDir,weaponDef->id);
    +		// the heavier the unit, the more impulse it does
    +		targetUnit->DoDamage(weaponDef->damages, owner, impulseDir * owner->mass, weaponDef->id);
     		if(fireSoundId)
     			sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     	}
    Index: rts/Sim/Weapons/MissileLauncher.cpp
    ===================================================================
    --- rts/Sim/Weapons/MissileLauncher.cpp	(revision 4223)
    +++ rts/Sim/Weapons/MissileLauncher.cpp	(working copy)
    @@ -29,7 +29,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			float dist=wantedDir.Length();
     			predict=dist/projectileSpeed;
    @@ -48,8 +49,10 @@
     	float3 dir;
     	if(onlyForward){
     		dir=owner->frontdir;
    +	} else if (weaponDef->fixedLauncher) {
    +		dir=weaponDir;
     	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     		if(weaponDef->trajectoryHeight>0){
     			dir.y+=weaponDef->trajectoryHeight;
    @@ -64,7 +67,7 @@
     	if(onlyForward && dynamic_cast<CAirMoveType*>(owner->moveType))
     		startSpeed+=owner->speed;
     
    -	SAFE_NEW CMissileProjectile(weaponPos,startSpeed,owner,areaOfEffect,projectileSpeed,(int)(range/projectileSpeed+25),targetUnit, weaponDef,targetPos);
    +	SAFE_NEW CMissileProjectile(weaponMuzzlePos,startSpeed,owner,areaOfEffect,projectileSpeed,weaponDef->flighttime==0 ? (int)(range/projectileSpeed+25) : weaponDef->flighttime,targetUnit, weaponDef,targetPos);
     	//CWeaponProjectile::CreateWeaponProjectile(weaponPos,startSpeed,owner,targetUnit, float3(0,0,0), weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
    @@ -75,15 +78,17 @@
     	if(!CWeapon::TryTarget(pos,userTarget,unit))
     		return false;
     
    -	if(unit){
    -		if(unit->isUnderWater){
    -			return false;
    +	if (!weaponDef->waterweapon) {
    +		if(unit){
    +			if(unit->isUnderWater){
    +				return false;
    +			}
    +		} else {
    +			if(pos.y<0)
    +				return false;
     		}
    -	} else {
    -		if(pos.y<0)
    -			return false;
     	}
    -	float3 dir=pos-weaponPos;
    +	float3 dir = pos-weaponMuzzlePos;
     	if(weaponDef->trajectoryHeight>0){	//do a different test depending on if the missile has a high trajectory or not
     		float3 flatdir(dir.x,0,dir.z);
     		dir.Normalize();
    @@ -95,11 +100,11 @@
     		float linear=dir.y+weaponDef->trajectoryHeight;
     		float quadratic=-weaponDef->trajectoryHeight/flatlength;
     
    -		float gc=ground->TrajectoryGroundCol(weaponPos,flatdir,flatlength-30,linear,quadratic);
    +		float gc=ground->TrajectoryGroundCol(weaponMuzzlePos,flatdir,flatlength-30,linear,quadratic);
     		if(gc>0)
     			return false;
     
    -		if(avoidFriendly && helper->TestTrajectoryCone(weaponPos,flatdir,flatlength-30,linear,quadratic,0,8,owner->allyteam,owner)){
    +		if(avoidFriendly && helper->TestTrajectoryCone(weaponMuzzlePos,flatdir,flatlength-30,linear,quadratic,0,8,owner->allyteam,owner)){
     			return false;
     		}
     	} else {
    @@ -110,7 +115,7 @@
     		dir/=length;
     
     		if(!onlyForward){		//skip ground col testing for aircrafts
    -			float g=ground->LineGroundCol(weaponPos,pos);
    +			float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     			if(g>0 && g<length*0.9f)
     				return false;
     		} else {
    @@ -119,7 +124,7 @@
     			if(owner->frontdir.dot(goaldir) < maxAngleDif)
     				return false;
     		}
    -		if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
    +		if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle),owner->allyteam,owner))
     			return false;
     	}
     	return true;
    Index: rts/Sim/Weapons/PlasmaRepulser.cpp
    ===================================================================
    --- rts/Sim/Weapons/PlasmaRepulser.cpp	(revision 4223)
    +++ rts/Sim/Weapons/PlasmaRepulser.cpp	(working copy)
    @@ -70,6 +70,8 @@
     
     	if(weaponDef->shieldPower==0)
     		curPower=99999999999.0f;
    +	else
    +		curPower=weaponDef->shieldStartingPower;
     
     	CWeapon::Init();
     }
    Index: rts/Sim/Weapons/Rifle.cpp
    ===================================================================
    --- rts/Sim/Weapons/Rifle.cpp	(revision 4223)
    +++ rts/Sim/Weapons/Rifle.cpp	(working copy)
    @@ -41,6 +41,7 @@
     {
     	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;
     		wantedDir=targetPos-weaponPos;
     		wantedDir.Normalize();
     	}
    @@ -60,18 +61,18 @@
     			return false;
     	}
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	float g=ground->LineGroundCol(weaponPos,pos);
    +	float g=ground->LineGroundCol(weaponMuzzlePos,pos);
     	if(g>0 && g<length*0.9f)
     		return false;
     
    -	if(helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.9f),owner->allyteam,owner)){
    +	if(helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)*(1-owner->limExperience*0.9f),owner->allyteam,owner)){
     		return false;
     	}
     	return true;
    @@ -79,7 +80,7 @@
     
     void CRifle::Fire(void)
     {
    -	float3 dir=targetPos-weaponPos;
    +	float3 dir=targetPos-weaponMuzzlePos;
     	dir.Normalize();
     	dir+=(gs->randVector()*sprayangle+salvoError)*(1-owner->limExperience*0.9f);
     	dir.Normalize();
    @@ -88,13 +89,13 @@
     	tracefile << owner->pos.x << " " << dir.x << " " << targetPos.x << " " << targetPos.y << " " << targetPos.z << "\n";
     #endif
     	CUnit* hit;
    -	float length = helper->TraceRay(weaponPos, dir, range, weaponDef->damages[0], owner, hit, collisionFlags);
    -	if (hit) {
    +	float length=helper->TraceRay(weaponMuzzlePos, dir, range, weaponDef->damages[0], owner, hit, collisionFlags);
    +	if(hit) {
     		hit->DoDamage(weaponDef->damages, owner, ZeroVector, weaponDef->id);
    -		SAFE_NEW CHeatCloudProjectile(weaponPos + dir * length, hit->speed * 0.9f, 30, 1, owner);
    +		SAFE_NEW CHeatCloudProjectile(weaponMuzzlePos + dir * length, hit->speed*0.9f, 30, 1, owner);
     	}
    -	SAFE_NEW CTracerProjectile(weaponPos,dir*projectileSpeed,length,owner);
    -	SAFE_NEW CSmokeProjectile(weaponPos,float3(0,0.0f,0),70,0.1f,0.02f,owner,0.6f);
    +	SAFE_NEW CTracerProjectile(weaponMuzzlePos,dir*projectileSpeed,length,owner);
    +	SAFE_NEW CSmokeProjectile(weaponMuzzlePos,float3(0,0.0f,0),70,0.1f,0.02f,owner,0.6f);
     	if(fireSoundId)
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    Index: rts/Sim/Weapons/StarburstLauncher.cpp
    ===================================================================
    --- rts/Sim/Weapons/StarburstLauncher.cpp	(revision 4223)
    +++ rts/Sim/Weapons/StarburstLauncher.cpp	(working copy)
    @@ -32,6 +32,7 @@
     {
     	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;
     		wantedDir=(targetPos-weaponPos).Normalize();		//the aiming upward is apperently implicid so aim toward target
     	}
     	CWeapon::Update();
    @@ -39,7 +40,17 @@
     
     void CStarburstLauncher::Fire(void)
     {
    -	CStarburstProjectile* p=SAFE_NEW CStarburstProjectile(weaponPos+float3(0,2,0),float3(0,0.01f,0),owner,targetPos,areaOfEffect,projectileSpeed,tracking,(int)uptime,targetUnit, weaponDef,interceptTarget,range);
    +	float3 speed(0,weaponDef->startvelocity,0);
    +	float maxrange;
    +	if (weaponDef->fixedLauncher) {
    +		speed = weaponDir * weaponDef->startvelocity;
    +		maxrange = (float)MAX_WORLD_SIZE;
    +	} else if (weaponDef->flighttime > 0) {
    +		maxrange = (float)MAX_WORLD_SIZE;
    +	} else {
    +		maxrange = (float)range;
    +	}
    +	CStarburstProjectile* p=SAFE_NEW CStarburstProjectile(weaponMuzzlePos+float3(0,2,0),speed,owner,targetPos,areaOfEffect,projectileSpeed,tracking,(int)uptime,targetUnit, weaponDef,interceptTarget, maxrange);
     
     	if(weaponDef->targetable)
     		interceptHandler.AddInterceptTarget(p,targetPos);
    @@ -54,14 +65,15 @@
     		return false;
     
     	if(unit){
    -		if(unit->isUnderWater)
    +		if(unit->isUnderWater && !weaponDef->waterweapon)
     			return false;
     	} else {
    -		if(pos.y<0)
    +		if(pos.y<0 && !weaponDef->waterweapon)
     			return false;
     	}
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,UpVector,100,0,owner->allyteam,owner))
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,
    +			(weaponDef->fixedLauncher ? weaponDir : UpVector), 100, 0, owner->allyteam, owner))
     		return false;
     
     	return true;
    Index: rts/Sim/Weapons/TorpedoLauncher.cpp
    ===================================================================
    --- rts/Sim/Weapons/TorpedoLauncher.cpp	(revision 4223)
    +++ rts/Sim/Weapons/TorpedoLauncher.cpp	(working copy)
    @@ -32,7 +32,8 @@
     {
     	if(targetType!=Target_None){
     		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -//		if(!onlyForward){		
    +		weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +//		if(!onlyForward){
     			wantedDir=targetPos-weaponPos;
     			float dist=wantedDir.Length();
     			predict=dist/projectileSpeed;
    @@ -48,18 +49,24 @@
     //	if(onlyForward){
     //		dir=owner->frontdir;
     //	} else {
    -		dir=targetPos-weaponPos;
    +		dir=targetPos-weaponMuzzlePos;
     		dir.Normalize();
     		if(weaponDef->trajectoryHeight>0){
     			dir.y+=weaponDef->trajectoryHeight;
     			dir.Normalize();
     		}
     //	}
    -	float3 startSpeed=dir*weaponDef->startvelocity;
    +	float3 startSpeed;
    +	if (!weaponDef->fixedLauncher) {
    +		startSpeed=dir*weaponDef->startvelocity;
    +	}
    +	else {
    +		startSpeed=weaponDir*weaponDef->startvelocity;
    +	}
     
     //	if(onlyForward)
     //		startSpeed+=owner->speed*0.5f;
    -	SAFE_NEW CTorpedoProjectile(weaponPos,startSpeed,owner,areaOfEffect,projectileSpeed,tracking,(int)(range/projectileSpeed+15),targetUnit, weaponDef);
    +	SAFE_NEW CTorpedoProjectile(weaponMuzzlePos,startSpeed,owner,areaOfEffect,projectileSpeed,tracking,weaponDef->flighttime==0 ? (int)(range/projectileSpeed+25) : weaponDef->flighttime,targetUnit, weaponDef);
     	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
     		sound->PlaySample(fireSoundId,owner,fireSoundVolume);
     }
    @@ -70,22 +77,22 @@
     		return false;
     
     	if(unit){
    -		if(unit->unitDef->canhover)
    +		if(!(weaponDef->submissile) && unit->unitDef->canhover)
     			return false;
    -		if(unit->unitDef->canfly && unit->pos.y>0)
    +		if(!(weaponDef->submissile) && unit->unitDef->canfly && unit->pos.y>0)
     			return false;
     	}
    -	if(ground->GetHeight2(pos.x,pos.z)>0)
    +	if(!(weaponDef->submissile) && ground->GetHeight2(pos.x,pos.z)>0)
     		return 0;
     
    -	float3 dir=pos-weaponPos;
    +	float3 dir=pos-weaponMuzzlePos;
     	float length=dir.Length();
     	if(length==0)
     		return true;
     
     	dir/=length;
     
    -	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle)+0.05f,owner->allyteam,owner))	//+0.05f since torpedoes has an unfortunate tendency to hit own ships due to movement
    +	if(avoidFriendly && helper->TestCone(weaponMuzzlePos,dir,length,(accuracy+sprayangle)+0.05f,owner->allyteam,owner))	//+0.05f since torpedoes has an unfortunate tendency to hit own ships due to movement
     		return false;
     	return true;
     }
    Index: rts/Sim/Weapons/Weapon.cpp
    ===================================================================
    --- rts/Sim/Weapons/Weapon.cpp	(revision 4223)
    +++ rts/Sim/Weapons/Weapon.cpp	(working copy)
    @@ -57,8 +57,10 @@
     	CR_MEMBER(subClassReady),
     	CR_MEMBER(onlyForward),
     	CR_MEMBER(weaponPos),
    +	CR_MEMBER(weaponMuzzlePos),
     	CR_MEMBER(lastRequest),
     	CR_MEMBER(relWeaponPos),
    +	CR_MEMBER(relWeaponMuzzlePos),
     	CR_MEMBER(muzzleFlareSize),
     	CR_MEMBER(lastTargetRetry),
     	CR_MEMBER(areaOfEffect),
    @@ -132,8 +134,10 @@
     	subClassReady(true),
     	onlyForward(false),
     	weaponPos(0,0,0),
    +	weaponMuzzlePos(0,0,0),
     	lastRequest(0),
     	relWeaponPos(0,1,0),
    +	relWeaponMuzzlePos(0,1,0),
     	muzzleFlareSize(1),
     	lastTargetRetry(-100),
     	areaOfEffect(1),
    @@ -176,11 +180,14 @@
     	if(hasCloseTarget){
     		std::vector<int> args;
     		args.push_back(0);
    -		if(useWeaponPosForAim){
    +		if(useWeaponPosForAim){ //if we couldn't get a line of fire from the muzzle try if we can get it from the aim piece
     			owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
     		} else {
     			owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     		}
    +		relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
    +
    +		owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     		relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     	}
     
    @@ -258,16 +265,18 @@
     	&& subClassReady
     	&& reloadStatus<=gs->frameNum
     	&& (!weaponDef->stockpile || numStockpiled)
    -	&& (weaponDef->waterweapon || weaponPos.y>0)
    +	&& (weaponDef->fireSubmersed || weaponMuzzlePos.y>0)
     	&& (owner->unitDef->maxFuel==0 || owner->currentFuel > 0)
     	){
     		if ((weaponDef->stockpile || (gs->Team(owner->team)->metal>=metalFireCost && gs->Team(owner->team)->energy>=energyFireCost))) {
     			std::vector<int> args;
     			args.push_back(0);
     			owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    -			relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
    -			weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +			owner->localmodel->GetEmitDirPos(args[0], relWeaponMuzzlePos, weaponDir);
    +			weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
     			useWeaponPosForAim=reloadTime/16+8;
    +			weaponDir = owner->frontdir * weaponDir.z + owner->updir * weaponDir.y + owner->rightdir * weaponDir.x;
    +			weaponDir.Normalize();
     
     			if(TryTarget(targetPos,haveUserTarget,targetUnit)){
     				if(weaponDef->stockpile){
    @@ -303,35 +312,52 @@
     			}
     		}
     	}
    -	if(salvoLeft && nextSalvo<=gs->frameNum){
    +	if(salvoLeft && nextSalvo<=gs->frameNum ){
     		salvoLeft--;
     		nextSalvo=gs->frameNum+salvoDelay;
     		owner->lastFireWeapon=gs->frameNum;
    +		
    +		int projectiles = weaponDef->projectilespershot;
    +		
    +		while(projectiles > 0) {
    +			--projectiles;
    +			
    +			// add to the commandShotCount if this is the last salvo,
    +			// and it is being directed towards the current target
    +			// (helps when deciding if a queued ground attack order has been completed)
    +			if ((salvoLeft == 0) && (owner->commandShotCount >= 0) &&
    +			    ((targetType == Target_Pos) && (targetPos == owner->userAttackPos)) ||
    +					((targetType == Target_Unit) && (targetUnit == owner->userTarget))) {
    +				owner->commandShotCount++;
    +			}
    +	
    +			std::vector<int> args;
    +			args.push_back(0);
    +	
    +			owner->cob->Call(COBFN_Shot+weaponNum,0);
    +	
    +			owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
    +			relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     
    -		// add to the commandShotCount if this is the last salvo,
    -		// and it is being directed towards the current target
    -		// (helps when deciding if a queued ground attack order has been completed)
    -		if ((salvoLeft == 0) && (owner->commandShotCount >= 0) &&
    -		    ((targetType == Target_Pos) && (targetPos == owner->userAttackPos)) ||
    -				((targetType == Target_Unit) && (targetUnit == owner->userTarget))) {
    -			owner->commandShotCount++;
    -		}
    +			owner->cob->Call(/*COBFN_AimFromPrimary+weaponNum*/COBFN_QueryPrimary+weaponNum/**/,args);
    +			owner->localmodel->GetEmitDirPos(args[0], relWeaponMuzzlePos, weaponDir);
     
    -		std::vector<int> args;
    -		args.push_back(0);
    -		owner->cob->Call(/*COBFN_AimFromPrimary+weaponNum/*/COBFN_QueryPrimary+weaponNum/**/,args);
    -		relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
    -		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +			weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
     
    -//		logOutput.Print("RelPosFire %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
    -
    -		if (owner->unitDef->decloakOnFire && (owner->scriptCloak <= 2)) {
    -			owner->isCloaked = false;
    -			owner->curCloakTimeout = gs->frameNum + owner->cloakTimeout;
    +			weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +			weaponDir = owner->frontdir * weaponDir.z + owner->updir * weaponDir.y + owner->rightdir * weaponDir.x;
    +			weaponDir.Normalize();
    +	
    +	//		logOutput.Print("RelPosFire %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
    +	
    +			if (owner->unitDef->decloakOnFire && (owner->scriptCloak <= 2)) {
    +				owner->isCloaked = false;
    +				owner->curCloakTimeout = gs->frameNum + owner->cloakTimeout;
    +			}
    +	
    +			Fire();
     		}
     
    -		Fire();
    -
     		//Rock the unit in the direction of the fireing
     		float3 rockDir = wantedDir;
     		rockDir.y = 0;
    @@ -362,9 +388,9 @@
     
     	if(!weaponDef->waterweapon && pos.y<1)
     		pos.y=1;
    -	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -	if(weaponPos.y<ground->GetHeight2(weaponPos.x,weaponPos.z))
    -		weaponPos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +	if(weaponMuzzlePos.y<ground->GetHeight2(weaponMuzzlePos.x,weaponMuzzlePos.z))
    +		weaponMuzzlePos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
     
     	if(!TryTarget(pos,userTarget,0))
     		return false;
    @@ -387,8 +413,10 @@
     
     	weaponPos= owner->pos + owner->frontdir * relWeaponPos.z
     		+ owner->updir * relWeaponPos.y + owner->rightdir * relWeaponPos.x;
    -	if(weaponPos.y < ground->GetHeight2(weaponPos.x, weaponPos.z))
    -		weaponPos = owner->pos + UpVector * 10;
    +	weaponMuzzlePos= owner->pos + owner->frontdir * relWeaponMuzzlePos.z
    +		+ owner->updir * relWeaponMuzzlePos.y + owner->rightdir * relWeaponMuzzlePos.x;
    +	if(weaponMuzzlePos.y < ground->GetHeight2(weaponMuzzlePos.x, weaponMuzzlePos.z))
    +		weaponMuzzlePos = owner->pos + UpVector * 10;
     	//hope that we are underground because we are a popup weapon and will come above ground later
     
     	if(!unit){
    @@ -441,18 +469,23 @@
     #endif
     	std::vector<int> args;
     	args.push_back(0);
    -	if(useWeaponPosForAim){
    +	if(useWeaponPosForAim){ //If we can't get a line of fire from the muzzle try the aim piece instead since the weapon may just be turned in a wrong way
     		owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
     		if(useWeaponPosForAim>1)
     			useWeaponPosForAim--;
     	} else {
     		owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     	}
    +	relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
    +
    +	owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     	relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    -	if(weaponPos.y<ground->GetHeight2(weaponPos.x,weaponPos.z))
    -		weaponPos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
     
    +	if(weaponMuzzlePos.y<ground->GetHeight2(weaponMuzzlePos.x,weaponMuzzlePos.z))
    +		weaponMuzzlePos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later
    +
     	predictSpeedMod=1+(gs->randFloat()-0.5f)*2*(1-owner->limExperience);
     
     	if((targetPos-weaponPos).SqLength() < relWeaponPos.SqLength()*16)
    @@ -556,7 +589,7 @@
     	if(weaponDef->stockpile && !numStockpiled)
     		return false;
     
    -	float3 dif=pos-weaponPos;
    +	float3 dif=pos-weaponMuzzlePos;
     	float heightDiff; // negative when target below owner
     
     	if (targetBorder != 0 && unit) {
    @@ -628,11 +661,13 @@
     	owner->frontdir = GetVectorFromHeading(owner->heading);
     	owner->rightdir = owner->frontdir.cross(owner->updir);
     	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;
     	bool val = TryTarget(tempTargetPos,userTarget,unit);
     	owner->frontdir = tempfrontdir;
     	owner->rightdir = temprightdir;
     	owner->heading = tempHeadding;
     	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;
     	return val;
     }
     
    @@ -658,11 +693,13 @@
     	owner->frontdir = GetVectorFromHeading(owner->heading);
     	owner->rightdir = owner->frontdir.cross(owner->updir);
     	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;
     	bool val = TryTarget(pos, userTarget, 0);
     	owner->frontdir = tempfrontdir;
     	owner->rightdir = temprightdir;
     	owner->heading = tempHeadding;
     	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;
     	return val;
     }
     
    @@ -673,6 +710,10 @@
     	owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
     	relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
     	weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    +
    +	owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
    +	relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
    +	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
     //	logOutput.Print("RelPos %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
     
     	if (range > owner->maxRange) {
    Index: rts/Sim/Weapons/Weapon.h
    ===================================================================
    --- rts/Sim/Weapons/Weapon.h	(revision 4223)
    +++ rts/Sim/Weapons/Weapon.h	(working copy)
    @@ -60,6 +60,11 @@
     
     	float3 relWeaponPos;				//weaponpos relative to the unit
     	float3 weaponPos;						//absolute weapon pos
    +
    +	float3 relWeaponMuzzlePos;			//position of the firepoint
    +	float3 weaponMuzzlePos;
    +	float3 weaponDir;
    +
     	float muzzleFlareSize;			//size of muzzle flare if drawn
     	int useWeaponPosForAim;			//sometimes weapon pos is better to use than aimpos
     	bool hasCloseTarget;					//might need to update weapon pos more often when enemy is near
    Index: rts/Sim/Weapons/WeaponDefHandler.cpp
    ===================================================================
    --- rts/Sim/Weapons/WeaponDefHandler.cpp	(revision 4223)
    +++ rts/Sim/Weapons/WeaponDefHandler.cpp	(working copy)
    @@ -67,6 +67,7 @@
     	bool ballistic;
     	//bool twophase;
     	bool beamweapon;
    +	bool manualBombSettings; //Allow the user to manually specify the burst and burstrate for his AircraftBomb
     	//bool guided;
     	//bool vlaunch;
     	int rendertype;
    @@ -94,6 +95,7 @@
     	sunparser->GetDef(weaponDefs[id].minIntensity, "0", weaponname + "\\MinIntensity");
     
     	sunparser->GetDef(weaponDefs[id].dropped, "0", weaponname + "\\dropped");
    +	sunparser->GetDef(manualBombSettings, "0", weaponname + "\\manualbombsettings");
     	sunparser->GetDef(lineofsight, "0", weaponname + "\\lineofsight");
     	sunparser->GetDef(ballistic, "0", weaponname + "\\ballistic");
     	sunparser->GetDef(weaponDefs[id].twophase, "0", weaponname + "\\twophase");
    @@ -110,7 +112,10 @@
     	sunparser->GetDef(weaponDefs[id].noSelfDamage, "0", weaponname + "\\NoSelfDamage");
     
     	sunparser->GetDef(weaponDefs[id].waterweapon, "0", weaponname + "\\waterweapon");
    +	sunparser->GetDef(weaponDefs[id].fireSubmersed, weaponDefs[id].waterweapon ? "1":"0", weaponname + "\\firesubmersed");
    +	sunparser->GetDef(weaponDefs[id].submissile, "0", weaponname + "\\submissile");
     	sunparser->GetDef(weaponDefs[id].tracks, "0", weaponname + "\\tracks");
    +	sunparser->GetDef(weaponDefs[id].fixedLauncher, "0", weaponname + "\\FixedLauncher");
     	sunparser->GetDef(weaponDefs[id].noExplode, "0", weaponname + "\\NoExplode");
     	sunparser->GetDef(weaponDefs[id].maxvelocity, "0", weaponname + "\\weaponvelocity");
     	sunparser->GetDef(weaponDefs[id].isShield, "0", weaponname + "\\IsShield");
    @@ -256,6 +261,7 @@
     	weaponDefs[id].reload = atof(sunparser->SGetValueDef("1", weaponname + "\\reloadtime").c_str());
     	weaponDefs[id].salvodelay = atof(sunparser->SGetValueDef("0.1", weaponname + "\\burstrate").c_str());
     	sunparser->GetDef(weaponDefs[id].salvosize, "1", weaponname + "\\burst");
    +	sunparser->GetDef(weaponDefs[id].projectilespershot, "1", weaponname + "\\projectiles");
     	weaponDefs[id].maxAngle = atof(sunparser->SGetValueDef("3000", weaponname + "\\tolerance").c_str()) * 180.0f / 0x7fff;
     	weaponDefs[id].restTime = 0.0f;
     	sunparser->GetDef(weaponDefs[id].metalcost, "0", weaponname + "\\metalpershot");
    @@ -263,6 +269,7 @@
     	sunparser->GetDef(weaponDefs[id].selfExplode, "0", weaponname + "\\burnblow");
     	sunparser->GetDef(weaponDefs[id].sweepFire, "0", weaponname + "\\sweepfire");
     	sunparser->GetDef(weaponDefs[id].canAttackGround, "1", weaponname + "\\canattackground");
    +	weaponDefs[id].myGravity = atof(sunparser->SGetValueDef("0", weaponname + "\\myGravity").c_str());
     
     	weaponDefs[id].fireStarter=atof(sunparser->SGetValueDef("0", weaponname + "\\firestarter").c_str())*0.01f;
     	weaponDefs[id].paralyzer=!!atoi(sunparser->SGetValueDef("0", weaponname + "\\paralyzer").c_str());
    @@ -292,6 +299,7 @@
     	sunparser->GetDef(weaponDefs[id].shieldPower, "0", weaponname + "\\shieldpower");
     	sunparser->GetDef(weaponDefs[id].shieldPowerRegen, "0", weaponname + "\\shieldpowerregen");
     	sunparser->GetDef(weaponDefs[id].shieldPowerRegenEnergy, "0", weaponname + "\\shieldpowerregenenergy");
    +	sunparser->GetDef(weaponDefs[id].shieldStartingPower, "0", weaponname + "\\shieldstartingpower");
     	sunparser->GetDef(weaponDefs[id].shieldInterceptType, "0", weaponname + "\\shieldintercepttype");
     	weaponDefs[id].shieldGoodColor=sunparser->GetFloat3(float3(0.5f,0.5f,1),weaponname + "\\shieldgoodcolor");
     	weaponDefs[id].shieldBadColor=sunparser->GetFloat3(float3(1,0.5f,0.5f),weaponname + "\\shieldbadcolor");
    @@ -353,10 +361,11 @@
     		weaponDefs[id].visuals.color = tempCol;
     
     	weaponDefs[id].uptime = atof(sunparser->SGetValueDef("0", weaponname + "\\weapontimer").c_str());
    +	weaponDefs[id].flighttime = atof(sunparser->SGetValueDef("0", weaponname + "\\flighttime").c_str()) * 32;
     
     	weaponDefs[id].turnrate = atof(sunparser->SGetValueDef("0", weaponname + "\\turnrate").c_str()) * PI / 0x7fff /30.0f;
     
    -	if(weaponDefs[id].type=="AircraftBomb"){
    +	if(weaponDefs[id].type=="AircraftBomb" && !manualBombSettings){
     		if(weaponDefs[id].reload<0.5f){
     			weaponDefs[id].salvodelay=min(0.2f,weaponDefs[id].reload);
     			weaponDefs[id].salvosize=(int)(1/weaponDefs[id].salvodelay)+1;
    Index: rts/Sim/Weapons/WeaponDefHandler.h
    ===================================================================
    --- rts/Sim/Weapons/WeaponDefHandler.h	(revision 4223)
    +++ rts/Sim/Weapons/WeaponDefHandler.h	(working copy)
    @@ -68,17 +68,23 @@
     	float restTime;
     
     	float uptime;
    +	int flighttime;
     
     	float metalcost;
     	float energycost;
     	float supplycost;
     
    +	int projectilespershot;
    +
     	int id;
     	int tdfId;	//the id= tag in the tdf
     
     	bool turret;
     	bool onlyForward;
    +	bool fixedLauncher;
     	bool waterweapon;
    +	bool fireSubmersed;
    +	bool submissile; //Lets a torpedo travel above water like it does below water
     	bool tracks;
     	bool dropped;
     	bool paralyzer;			//weapon will only paralyze not do real damage
    @@ -103,6 +109,7 @@
     
     	bool selfExplode;
     	bool gravityAffected;
    +	float myGravity;
     	bool twophase;
     	bool guided;
     	bool vlaunch;
    @@ -166,6 +173,7 @@
     	float shieldPower;			//how much damage the shield can reflect (0=infinite)
     	float shieldPowerRegen;	//how fast the power regenerates per second
     	float shieldPowerRegenEnergy;	//how much energy is needed to regenerate power per second
    +	float shieldStartingPower;	//how much power the shield has when first created
     	float3 shieldGoodColor;			//color when shield at full power
     	float3 shieldBadColor;			//color when shield is empty
     	float shieldAlpha;					//shield alpha value
    Index: rts/System/GlobalStuff.h
    ===================================================================
    --- rts/System/GlobalStuff.h	(revision 4223)
    +++ rts/System/GlobalStuff.h	(working copy)
    @@ -20,7 +20,7 @@
      *
      * Defines the maximum world size as 1000000
      */
    -#define MAX_WORLD_SIZE 1000000;
    +#define MAX_WORLD_SIZE 1000000
     
     /**
      * @brief square size
    @@ -260,42 +260,42 @@
     
     	/**
     	 * @brief disable helper AIs
    -	 * 
    +	 *
     	 * Whether helper AIs are allow, including GroupAI and LuaUI control widgets
     	 */
     	bool noHelperAIs;
     
     	/**
     	 * @brief definition editing enabled
    -	 * 
    +	 *
     	 * Whether definition editing is enabled
     	 */
     	bool editDefsEnabled;
     
     	/**
     	 * @brief LuaRules control
    -	 * 
    +	 *
     	 * Whether or not LuaRules is enabled
     	 */
     	bool useLuaRules;
     
     	/**
     	 * @brief LuaGaia control
    -	 * 
    +	 *
     	 * Whether or not LuaGaia is enabled
     	 */
     	bool useLuaGaia;
     
     	/**
     	 * @brief gaia team
    -	 * 
    +	 *
     	 * gaia's team id
     	 */
     	int gaiaTeamID;
     
     	/**
     	 * @brief gaia team
    -	 * 
    +	 *
     	 * gaia's team id
     	 */
     	int gaiaAllyTeamID;
    
    patch file icon kdr11k_weapon_changes_r4223_v3.patch (80,656 bytes) 2007-08-18 22:41 +

-Relationships
+Relationships

-Notes

~0000995

tvo (reporter)

Index: rts/Sim/Units/UnitTypes/Builder.cpp
===================================================================
--- rts/Sim/Units/UnitTypes/Builder.cpp (revision 3886)
+++ rts/Sim/Units/UnitTypes/Builder.cpp (working copy)
@@ -583,9 +583,12 @@
 {
        float3 wantedDir=(pos-this->pos).Normalize();
        short int h=GetHeadingFromVector(wantedDir.x,wantedDir.z);
+ short int p=(short int) (asin(wantedDir.dot(updir))*(32768/PI));
+ short int pitch=(short int) (asin(frontdir.dot(float3(0,1,0)))*(32768/PI));

        std::vector<int> args;
        args.push_back(short(h-heading));
+ args.push_back(short(p-pitch));
        cob->Call("StartBuilding", args);

        int soundIdx = unitDef->sounds.build.getRandomIdx();

Why is p calculated with updir and pitch with float3(0,1,0)? Any (mathematical) reasons for that or a bug?



In at least MissileProjectile.cpp, after applying your patch, code like this results. Spaces are marked with underscores, other indentation are tabs.

____if (weaponDef->visuals.smokeTrail)
    if(drawTrail){ //draw the trail as a single quad
    } else { //draw the trail as particles
    }

Now how does this look with 4 character tabs:

    if (weaponDef->visuals.smokeTrail)
    if(drawTrail){ //draw the trail as a single quad
    } else { //draw the trail as particles
    }

Please don't do this, it makes the code really hard to read, especially since the pieces I left out in the inner if are very big chunks of code. Indent the big chunk properly so it is clear it is a nested if block, and so it doesn't look totally borked on anything but 8 character tabs.



The same, applies to the lines like:

    if (weaponDef->visuals.smokeTrail) SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldDir,owner,false,true,7,Smoke_Time,0.6f,drawTrail);

(all on one line)

These lines are really too long, put the SAFE_NEW ... part on the next line.



For the rest it looks about right, though I should look somewhat better at the bigger changes.

Could you fix/comment the above points?

~0000997

KDR_11k (reporter)

I'm not sure what happened with the indentations but I suppose it's the fault of my editor, context. If you press enter at the wrong point it creates the indents with spaces instead of tabs.

Not sure about the updir/0,1,0 issue either, I think I copied the pitch calculation from the weapon code.

~0000998

tvo (reporter)

But do you see my point?

You added an extra top-level if condition just by indenting it less/differently from the if below it, instead of actually indenting the if below it one level more.

I wouldn't really care if it was a 5 line if condition without else, but this is one huge if with an else block, so writing an if before it makes it unclear what the 'real' indentation depth of the inner block is, and it makes it unclear to which if the else belongs.

~0000999

KDR_11k (reporter)

Oh, THAT. I probably forgot to indent the block... I do use size 4 tabs, maybe I didn't indent it because I wasn't sure I was disabling the right block of code and wanted to do that after I'm sure it works. I'll add a file with the mentioned things fixed

~0001014

KDR_11k (reporter)

BTW, please don't commit it right now, I'm making some further additions and I don't think I could make a separate patch with those easily.

~0001018

imbaczek (reporter)

please commit the part responsible for turning Melee type weapons towards their targets, currently they turn to the west no matter where the target is.

~0001022

KDR_11k (reporter)

Last edited: 2007-07-19 22:37

I really have no idea how I make patches of a part of the changes.

I could upload my current patch state but I've made some weapons able to fire and travel underwater if waterweapon=1 is set but it doesn't apply to all weapons and I'm not sure if I can leave it at such an incomplete change.

~0001024

KDR_11k (reporter)

Okay, I've done my additions. The new changelog looks like this:

- Weapons now use AimFromWeapon to determine the part to aim from, this prevents waggling and failing to aim at close ranges. Internally this means weaponMuzzlePos holds the position where projectiles get spawned, not weaponPos. To simulate the old behaviour make AimFromWeapon return the same piece as QueryWeapon does.
- Melee weapon now reports a proper angle to AimWeapon.
- Added fixedLauncher tag (bool) for missiles, starburst missiles and torpedoes, this makes the projectile spawn with the orientation of the shooting piece instead of their normal orientation. The weapon will not properly check if allies are in the way so make sure you align the launchers in a way that won't hammer right into your own forces and perhaps use collideFriendly=0. FixedLauncher conflicts with trajectoryHeight and IMO combining them is pointless anyway so don't use both on a weapon.
- Made starburst missiles obey startvelocity and weaponacceleration, if your mod set them to something silly because they didn't do anything before you'll have to adjust.
- Added projectiles tag (int), each time a weapon fires this many projectiles are spawned (on the same frame). Make sure you put them on different trajectories somehow (sprayangle or different firepoints) because otherwise they'll all be clumped in one shot. Can be set to 0 as well for script trigger weapons and can be combined with burst.
- Added COB call to "ShotX" that happens shortly before weaponX uses QueryWeaponX, use this for switching firepoints in bursts or when using multiple projectiles.
- Missiles and starburst missiles now obey smoketrail, set it to 0 to disable the smoke. To get a missile without smoketrail you have to define the weapon as a missile with WeaponType=MissileLauncher in the tdf.
- StartBuilding now supplies the pitch as the second parameter to help with custom build FX.
- Missiles, starburst missiles and torpedoes now use flighttime if present instead of the hardcoded formula (which is still used if flighttime is not present)
- Added SubMissile tag (bool) for TorpedoLaunchers, if set to 1 the torpedo will travel like a missile outside of water. It will not emit a smoketrail, though. When fired from a plane it will behave the same way but the plane will probably be considered a fighter, not a bomber.
- All weapons (save for the Rifle which noone uses anyway) can now attack underwater targets if they have waterweapon=1 set.
- Added fireSubmersed tag (bool), defaults to the value of waterweapon. If set the weapon can fire underwater, if not then not. Use it for weapons that cannot fire underwater but can hit underwater targets. Works even for torpedoes.
- Starburst missiles now obey turnrate for the turn at the peak of their flight (if supplied, otherwise the old value is used).
- Bombs can use manually defined burst and burstrate values instead of autogenerated ones by using the new manualBombSettings tag (bool). Keep in mind that (roughly) burst*burstrate defines the area in which the bomber is willing to drop the bomb so if you make it too small the bomber might miss the drop area and not drop any bomb.
- Added myGravity tag (float) for ballistic weapons (Cannon and Bomb), it overrides the map gravity if used. Regular map gravity is around 0.2.
- Bombs now obey Accuracy and SprayAngle.
- Fixed lightning weapons having a hardcoded inaccuracy, made it obey accuracy and sprayangle tag instead.
- Fixed Lightning weapons not doing damage to shields.
- Added ShieldStartingPower tag (float) for shields, if set the shield starts with this much power instead of 0.

I occassionally got a crash the moment I hit enter when the "waiting for connections, press Enter to start" message was visible but I have no idea how to translate the stacktrace in a custom build so I couldn't track it down. It didn't happen consistently and only very rarely. No idea if that was my patch or something in the SVN version.

I think the patch was taken against rev 4014 or so.

~0001029

imbaczek (reporter)

kdr: you need to
$ scons configure debug=yes optimize=yes
if you're building with mingw/gcc. start the debugger
$ gdb spring
(gdb) run
and when it crashes
(gdb) bt
this is true both in linux and windows.

note that optimize=yes might give strange backtraces, but optimize=no might not cause any crashes.

~0001078

imbaczek (reporter)

Committed fixes to bombs and lighting cannon. Too afraid to commit the rest ;) I'd like someone else to take a look or two.

Oh, committed the melee fix sometime earlier.

~0001111

KDR_11k (reporter)

I noticed that the SVN version now has a changed range limiter system for starbursts, this should be disabled if fixedLauncher or Flighttime are used for the weapon since then the range measurement is either off (it doesn't check for range use during the "ascent" which isn't vertical with fixedLauncher) or limiting (for a guided missile you wouldn't want the range limit to override the mod-defined flighttime so the missile can keep tracking the target even if it moves quickly)

~0001121

tvo (reporter)

imbaczek: can you make a patch of the remaining patch so I can take a look?

~0001122

imbaczek (reporter)

will do.

~0001125

imbaczek (reporter)

uploaded a patch that compiles.

starburst missiles are broken but don't have the time to fix them now. will try later, for now don't commit them.

~0001126

imbaczek (reporter)

don't remember what I changed, but from my limited testing nothing's broken. kdr, if you have some test mod using those features, please test if everything works as advertised.

~0001127

imbaczek (reporter)

conflicts against r4223 resolved.

~0001189

imbaczek (reporter)

Tobi, have you taken a look at the patch? I'm tempted to commit it by the end of the week, so it gets some testing by mod devs. Been running with it for 3 weeks now and didn't notice any wrong behaviour, so it doesn't break anything that I test with (mostly BA, but a little bit of Gundam, too, and the recent bug-exposing CvC.)

~0001192

tvo (reporter)

No, didn't really get around to it yet. Skimmed through it once, but that doesn't really count :-)

It is OK if you commit it especially if you have given it so much testing already. I will look at it later then and fix anything I may see then.

~0001193

imbaczek (reporter)

ok, committed in r4264. may the search for bugs commence.

~0001242

tvo (reporter)

Ok, looked through it in a bit more detail and didn't really see anything obviously wrong so I think this can be closed ?

If not, just reopen :)
+Notes

-Issue History
Date Modified Username Field Change
2007-06-24 21:59 KDR_11k New Issue
2007-06-24 21:59 KDR_11k File Added: weaponChanges.patch
2007-06-25 10:13 tvo Summary AimFromWeapon, fixedLauncher and other tweaks => [patch] AimFromWeapon, fixedLauncher and other tweaks
2007-07-10 23:17 tvo Note Added: 0000995
2007-07-12 08:29 KDR_11k Note Added: 0000997
2007-07-12 15:25 tvo Note Added: 0000998
2007-07-12 18:11 KDR_11k Note Added: 0000999
2007-07-12 18:12 KDR_11k File Added: weaponChangesFix1.patch
2007-07-18 20:32 KDR_11k Note Added: 0001014
2007-07-19 19:23 imbaczek Note Added: 0001018
2007-07-19 22:36 KDR_11k Note Added: 0001022
2007-07-19 22:37 KDR_11k Note Edited: 0001022
2007-07-20 17:12 KDR_11k File Added: evenMoreWeaponChanges.patch
2007-07-20 17:16 KDR_11k Note Added: 0001024
2007-07-23 10:58 imbaczek Note Added: 0001029
2007-08-11 10:38 imbaczek Note Added: 0001078
2007-08-17 09:56 KDR_11k Note Added: 0001111
2007-08-18 11:45 tvo Note Added: 0001121
2007-08-18 12:17 imbaczek Note Added: 0001122
2007-08-18 14:16 imbaczek File Added: kdr11k_weapon_changes_r4220.patch
2007-08-18 14:17 imbaczek Note Added: 0001125
2007-08-18 17:05 imbaczek File Added: kdr11k_weapon_changes_r4220_v2.patch
2007-08-18 17:07 imbaczek Note Added: 0001126
2007-08-18 22:41 imbaczek File Added: kdr11k_weapon_changes_r4223_v3.patch
2007-08-18 22:41 imbaczek Note Added: 0001127
2007-08-29 20:12 imbaczek Note Added: 0001189
2007-08-30 20:15 tvo Note Added: 0001192
2007-08-30 23:16 imbaczek Note Added: 0001193
2007-09-11 12:45 tvo Status new => resolved
2007-09-11 12:45 tvo Resolution open => fixed
2007-09-11 12:45 tvo Assigned To => tvo
2007-09-11 12:45 tvo Note Added: 0001242
+Issue History