Problem while buying missiles

Find any bugs in Vega Strike? See if someone has already found it, or report them here!
Post Reply
echoes91
Trader
Trader
Posts: 23
Joined: Mon Mar 07, 2011 8:50 pm

Problem while buying missiles

Post by echoes91 »

(feel free to skip the story and read the last line :) )

Hello, i noticed a curious thing since i bought my Derivative. I usually load, for example, 3 FoF missiles in 3 slots and 6 dumbs in 1 slot (one day i'd like to know why those numbers but it's a different topic). Now, when i dock after some killing to buy new missiles, i noticed that i can buy new dumbs choosing the old slot and the game just refill it to 6 missiles. But, when I try to buy new FoF and choose the (now empty) old slots, they're pink instead of yellow in the list and i simply can't do it (the dumb's slot remains yellow so they're replaceble). Instead of it, I'm able to buy, for example, 3 Image Rec missiles and replace the old kind. This way makes the slots yellow again. After the next bounty, the story repeats with inverted parts: can't buy new ImageRec (pink slots) but can buy a different kind like FoF and replace.

It looks like that an empty missile slot can't be refilled with the same kind of missile but any different missile can replace them.

P.S. By the way, SVN last revision
Last edited by echoes91 on Thu Jul 21, 2011 10:05 pm, edited 1 time in total.
travists
Expert Mercenary
Expert Mercenary
Posts: 893
Joined: Thu Jul 08, 2010 11:43 pm
Location: Sol III North American Continent

Re: Problem while buying missiles

Post by travists »

I can second that problem (on SVN) plowshare loaded with IRs, one per. As the IRs are larger missiles (why I don't know) I thought it was because of that.
echoes91
Trader
Trader
Posts: 23
Joined: Mon Mar 07, 2011 8:50 pm

Re: Problem while buying missiles

Post by echoes91 »

That's a different issue related to ammo's volume and ship's mount volume, both written inside unit.cvs and quite hard to find for a "normal" player I think... anyway it could make sense, every ship's got some room for missiles which aren't all the same. The line i wrote in Bold instead doesn't make sense at all!
philo
Explorer
Explorer
Posts: 15
Joined: Thu Aug 18, 2011 1:57 pm

Re: Problem while buying missiles

Post by philo »

I can confirm this issue (latest SVN - but I faintly seem to remember that it was like that in 0.5.0 already).

There is no explanation for it other than being a bug.
It only happens with IR and FoF missiles, never with heetseakers or dumbfires. Whenever I want to reload, say a Lancelot with four single FoF, then because of the bug I need to first buy and reload with any other kind of missile acceptable to the slot, after which I'm finally able to buy and equip the FoF over those dummy missiles.
___________________
Main system: Core 2 Duo E8400 2 x 3.00GHz; Geforce 8500 GT (512 Mb); 4 GB DDR2; Onboard sound.
maze
Hunter
Hunter
Posts: 94
Joined: Tue Oct 30, 2012 10:39 pm

Re: Problem while buying missiles

Post by maze »

I found the cause for this bug. It's located in src/cmd/unit_generic.cpp

I) ROOT CAUSE:

Below you can read the relevant code extract, broken down into separate sections for explanatory reasons.
In the code below, up->mount is the weapon (of any sort) that is evaluated for eligibility and mount[jmod] is a mount of the player's ship.
I've broken the code into 4 phpbb blocks purely for ease of explanation, but the 4 extracts below are directly following each other in the source.
Basically this code extract will be crossed through if the type of the examined ship's mount fits the type of mount for the upgrade being evaluated for eligibility.
If at any point the boolean cancompletefully is allocated to false, the weapon ends up not being eligible for this mount of the player's ship.
We'll use the example of a Dostoevsky ship trying to mount a torpedo.

I.A) Installing a new weapon on an empty mount, or a mount with a different weapon previously installed.

Code: Select all

                         if (up->mounts[i].type->weapon_name != mounts[jmod].type->weapon_name || mounts[jmod].status
                              == Mount::DESTROYED || mounts[jmod].status == Mount::UNCHOSEN) {
                              //If missile, can upgrade directly, if other type of ammo, needs actual gun to be present.
                              if (isammo && !ismissiletype) {
                                  cancompletefully = false;
                              } else {
                                  ++numave;                                 //ok now we can compute percentage of used parts
                                  Mount upmount( up->mounts[i] );
                                  if (templ) {
                                      if (templ->GetNumMounts() > jmod) {
                                          if (templ->mounts[jmod].volume != -1)
                                              if (upmount.ammo*upmount.type->volume > templ->mounts[jmod].volume)
                                                  upmount.ammo = (int) ( (templ->mounts[jmod].volume+1)/upmount.type->volume );
                                      }
                                  }
                                  //compute here
                                  percentage += mounts[jmod].Percentage( &upmount );
                                  //if we wish to modify the mounts
                                  if (touchme)
                                      //switch this mount with the upgrador mount
                                      mounts[jmod].ReplaceMounts( this, &upmount );
                              }
                          } else {
Note in the above there is never any sort of comparison between the volume of the upgrade and the volume accepted by the ship's mount. Only the type of mount has to fit (this is handled by code above my extract in the source file unit_generic.cpp).

I.B) Adding ammo to an already mounted gun or missile rack, including when said mount has 0 ammo remaining.

Code: Select all

                              if (isammo && up->mounts[i].type->weapon_name == mounts[jmod].type->weapon_name) {
                                  //if is ammo and is same weapon type
                                  int tmpammo = mounts[jmod].ammo;
                                  if (mounts[jmod].ammo != -1 && up->mounts[i].ammo != -1) {
                                      tmpammo += up->mounts[i].ammo;
                                      if (templ) {
                                          if (templ->GetNumMounts() > jmod) {
                                              if (templ->mounts[jmod].volume != -1) {
                                                  if (templ->mounts[jmod].volume < mounts[jmod].type->volume*tmpammo) {
                                                      tmpammo =
                                                          (int) floor( .125
                                                                      +( (0
                                                                          +templ->mounts[jmod].volume)
                                                                        /mounts[jmod].type->volume ) );
                                                  }
                                              }
                                          }
                                      }

Code: Select all

                                      if (tmpammo*mounts[jmod].type->volume > mounts[jmod].volume)
                                          tmpammo = (int) floor( .125+( (0+mounts[jmod].volume)/mounts[jmod].type->volume ) );
In the above the available volume of the ship's mount has been evaluated against the volume required to add one to its ammo count.
But in the case of a Dosto and a torpedo, the volume of the ship's mount is 32, while the volume necessary per torpedo is 100.
I don't know where the 0.125 comes from, but in the Dosto/Torpedo example it's not enough to bring tmpammo to a value of one...

Code: Select all

                                      if (tmpammo > mounts[jmod].ammo) { 
                                          cancompletefully = true;
                                          if (touchme)
                                              mounts[jmod].ammo = tmpammo;
                                      } else {
                                          cancompletefully = false;
                                      }
                                  }
                              } else {
                                  cancompletefully = false;
                              }   
                          }
II) SUGGESTED FIXES:
II.A) Treat a mount with zero ammo remaining same as an empty mount
This is author's preferred approach at this stage, being that it is probably the safest in order to achieve consistency.
I've also proposed this fix on SF in the bug tracking system.

svn diff

Code: Select all

Index: src/cmd/unit_generic.cpp
===================================================================
--- src/cmd/unit_generic.cpp    (revision 13449)
+++ src/cmd/unit_generic.cpp    (working copy)
@@ -6366,7 +6366,7 @@
                     //only look at this mount if it can fit in the rack
                     if ( (unsigned int) (up->mounts[i].type->size) == (up->mounts[i].type->size&mounts[jmod].size) ) {
                         if (up->mounts[i].type->weapon_name != mounts[jmod].type->weapon_name || mounts[jmod].status
-                            == Mount::DESTROYED || mounts[jmod].status == Mount::UNCHOSEN) {
+                            == Mount::DESTROYED || mounts[jmod].status == Mount::UNCHOSEN || mounts[jmod].ammo == 0) {
                             //If missile, can upgrade directly, if other type of ammo, needs actual gun to be present.
                             if (isammo && !ismissiletype) {
                                 cancompletefully = false;
II.B) Override of volume ratio calculation so that a stock of 1 ammo is always authorized
I haven't done any sort of testing on that one, but it's a possibility after all. I can only tell you that for me it compiles. I'd consider it less reliable so long as the same kind of volume check that there is in I.B is not added in I.A.

svn diff

Code: Select all

Index: src/cmd/unit_generic.cpp
===================================================================
--- src/cmd/unit_generic.cpp    (revision 13449)
+++ src/cmd/unit_generic.cpp    (working copy)
@@ -6397,17 +6397,17 @@
                                         if (templ->GetNumMounts() > jmod) {
                                             if (templ->mounts[jmod].volume != -1) {
                                                 if (templ->mounts[jmod].volume < mounts[jmod].type->volume*tmpammo) {
-                                                    tmpammo =
+                                                    tmpammo = std::min( 1, 
                                                         (int) floor( .125
                                                                     +( (0
                                                                         +templ->mounts[jmod].volume)
-                                                                      /mounts[jmod].type->volume ) );
+                                                                      /mounts[jmod].type->volume ) ) );
                                                 }
                                             }
                                         }
                                     }
                                     if (tmpammo*mounts[jmod].type->volume > mounts[jmod].volume)
-                                        tmpammo = (int) floor( .125+( (0+mounts[jmod].volume)/mounts[jmod].type->volume ) );
+                                        tmpammo = std::min( 1, (int) floor( .125+( (0+mounts[jmod].volume)/mounts[jmod].type->volume ) ) );
                                     if (tmpammo > mounts[jmod].ammo) {
                                         cancompletefully = true;
                                         if (touchme)
III) DISCUSSION:

Both fixes I suggest are on the generous side. After all, we could consider that if a mount's volume is insuffcient, even if it is of the right type, then it should not be possible to install the weapon there... But in the particular case of a Dostoevsky, we can be sure it was the content dev's intent to allow the ship to carry a torpedo, if only a single one... Personally as a player I would kind of feel spoiled if this was changed somehow.

In some cases this might be exceedingly generous though. Once, when I was pretty deep in Rlaan space, couldn't find any torpedo so I bought a miniature grav-thumper to the insects (btw, is it intended that an ammo gun can fit to a missile mount?). The weapon initially came with 8 ammo. But I seem to remember that, when buying ammo to refill, I could never bring the ammo count above 1. Selling and rebuying the weapon at any given upgrade center was expensive, but it did bring the ammo count back to 8... I suspect the reason for this was that there isn't any sort of volume check in the code extract I.A above. Had there been, I suspect my ammo count would have been one also when buying the weapon brand new.

Maybe a fair compromise would be to add some volume check within I.A (like the one there is in I.B, but in both I.A and I.B add an override so that a raw capacity of zero coming out of the volume calculation is transformed into a capacity of 1.
klauss
Elite
Elite
Posts: 7243
Joined: Mon Apr 18, 2005 2:40 pm
Location: LS87, Buenos Aires, República Argentina

Re: Problem while buying missiles

Post by klauss »

I think I've seen a bug report about this. Please add these comments (or a link to this post) to that bug tracker so I can take a look at it when I have the time (otherwise I might miss it)
Oíd mortales, el grito sagrado...
Call me "Menes, lord of Cats"
Wing Commander Universe
maze
Hunter
Hunter
Posts: 94
Joined: Tue Oct 30, 2012 10:39 pm

Re: Problem while buying missiles

Post by maze »

I did a comment in the bug tracker already (with one of my two patches and link to here). Just for the sake of completeness, it's issue 3552768
klauss
Elite
Elite
Posts: 7243
Joined: Mon Apr 18, 2005 2:40 pm
Location: LS87, Buenos Aires, República Argentina

Re: Problem while buying missiles

Post by klauss »

Cool - yes, I've noticed something similar with "cancompletefully" in PGG. There, at least, the fix was to clean up units.csv (it contained a few numbers that shouldn't have been there), rather than a change in the code. I'm hoping this one's the same.
Oíd mortales, el grito sagrado...
Call me "Menes, lord of Cats"
Wing Commander Universe
maze
Hunter
Hunter
Posts: 94
Joined: Tue Oct 30, 2012 10:39 pm

Re: Problem while buying missiles

Post by maze »

The code's not completely consistent though, and I'm nearly sure this affects not only buying missiles but also ammo guns.
With my current understanding, I'd say that if only units.csv is changed, then there'll always remain some inconsistency between buying an ammo gun brand new and refilling ammo to an existing gun. Depending in what way it plays out, it may or may not make any sense in-game.

Namely, when buying a new ammo gun, the ammo you get is defined only by teh characteristics of a mount object which is totally unrelated to your ship's stats.
But when you refill ammo, the max you can climb to is limited by a feature of your ship's mount (its volume to be precise), not the gun itself. So, if the max capacity associated to your ship is larger than the initial ammo number coming with that gun, in-game reality remains consistent. It it's smaller, then it makes no sense, because you can't refill ammo to a number that you had in the past and you had no issue with.

If the only target is to fix the Dosto/Torpedo bug, then increasing the Dosto's missile mount volume to about 88 or higher should do the job. It would also have some other in-game effects, all making the ship more powerful, of course. Then I guess you could fix all instances of such issues by changing only units.csv, and increasing the volume of all bugged ship mounts to what it needs to be to prevent this issue from occuring in its nonsensical incarnation. But it's not robust as long as the code's inconsistency remains: for instance, somebody could do the same mistake in the future when adding or editing a ship, or possibly when adding or editing a new weapon (for the latter I'm not sure, the former is certain).

That's kind of the short version of my huge post above, might not be useless after all.
maze
Hunter
Hunter
Posts: 94
Joined: Tue Oct 30, 2012 10:39 pm

Re: Problem while buying missiles

Post by maze »

I've been thinking about it a little bit more and it might be that my proposed batch in section II.A from my long section above is problematic. In any case there's probably a better way to fix the issue. I'll come back soon with another proposal, I just need to find where in the code a ship's mount gets attributed a volume.

(I post this also in the bug tracker)
maze
Hunter
Hunter
Posts: 94
Joined: Tue Oct 30, 2012 10:39 pm

Re: Problem while buying missiles

Post by maze »

I have to finish this before I dive relentlessly into my disappearing bases issue.

Okay so please find below my (hopefully final) fix to ammo weapon purchase/ammo refill code. I also added the patch as an attached file. I have also submitted it in the Review Board.

This patch has two effects:
1) Fix bug #3552768 in the tracker when you're trying to refill your torpedo in a Dostoevsky. Issue is that the volume of a Dosto missile mount is 32, but the volume taken by a single torpedo is 100. In this configuration, the program lets you install a torpedo because the mount type fits, but it does not let you refill (nor sell) an empty torpedo tube. After applying the patch, you will be able to refill one torpedo. This could be theoretically fixed by modifying only units.csv, however as i wrote above it wouldn't be a robust fix because adding further content migh then cause a regression. Besides (for example), while the Dosto is intended to be able to carry a single torpedo, you might not necessarily want it to be able to carry huge numbers smaller missiles... Therefore I made my change in a way which is kind of nice to players: if you mount type is compatible with the weapon, you can always embark at least one ammo, even if your mount's volume is smaller than the volume taken by a single ammo.
2) When buying a new ammo weapon, you don't get the full ammo count which is defined in units.csv if your mount's volume is not enough to store this amount (but you always get one ammo, as I wrote above). This is necessary for consistency, otherwise you end up in a situation where you can't refill to the ammo count that came initially with the weapon, and I don't think this could be fixed by a change of units.csv alone.

So here's a comparative in relevant situations:
  • Before applying the patch
    • Dosto buying Advtorpedo: initial ammo count 1
    • Dosto refilling Advtorpedo: max ammo count 0
    • Dosto buying Miniature Grav Thumper: initial ammo count 8
    • Dosto refilling Miniature Grav Thumper: max ammo count 1
  • After applying the patch
    • Dosto buying Advtorpedo: initial ammo count 1
    • Dosto refilling Advtorpedo: max ammo count 1
    • Dosto buying Miniature Grav Thumper: initial ammo count 1
    • Dosto refilling Miniature Grav Thumper: max ammo count 1
svn diff

Code: Select all

Index: src/cmd/unit_generic.cpp
===================================================================
--- src/cmd/unit_generic.cpp    (revision 13459)
+++ src/cmd/unit_generic.cpp    (working copy)
@@ -6388,9 +6388,19 @@
                                 if (templ) {
                                     if (templ->GetNumMounts() > jmod) {
                                         if (templ->mounts[jmod].volume != -1)
-                                            if (upmount.ammo*upmount.type->volume > templ->mounts[jmod].volume)
+                                            if (upmount.ammo*upmount.type->volume > templ->mounts[jmod].volume) {
                                                 upmount.ammo = (int) ( (templ->mounts[jmod].volume+1)/upmount.type->volume );
+                                                upmount.ammo = std::max(upmount.ammo, 1);
+                                            }
                                     }
+                                } else {
+                                    if (GetNumMounts() > jmod) {
+                                        if (mounts[jmod].volume != -1)
+                                            if (upmount.ammo*upmount.type->volume > mounts[jmod].volume) {
+                                                upmount.ammo = (int) ( (mounts[jmod].volume+1)/upmount.type->volume );
+                                                upmount.ammo = std::max(upmount.ammo, 1);
+                                            }
+                                    }
                                 }
                                 //compute here
                                 percentage += mounts[jmod].Percentage( &upmount );
@@ -6410,16 +6420,16 @@
                                             if (templ->mounts[jmod].volume != -1) {
                                                 if (templ->mounts[jmod].volume < mounts[jmod].type->volume*tmpammo) {
                                                     tmpammo =
-                                                        (int) floor( .125
-                                                                    +( (0
-                                                                        +templ->mounts[jmod].volume)
-                                                                      /mounts[jmod].type->volume ) );
+                                                        (int) (
+                                                                    +(templ->mounts[jmod].volume + 1)
+                                                                      /mounts[jmod].type->volume) ;
                                                 }
                                             }
                                         }
                                     }
                                     if (tmpammo*mounts[jmod].type->volume > mounts[jmod].volume)
-                                        tmpammo = (int) floor( .125+( (0+mounts[jmod].volume)/mounts[jmod].type->volume ) );
+                                        tmpammo = (int) ( (mounts[jmod].volume + 1)/mounts[jmod].type->volume);
+                                    tmpammo = std::max(tmpammo, 1);
                                     if (tmpammo > mounts[jmod].ammo) {
                                         cancompletefully = true;
                                         if (touchme)
You do not have the required permissions to view the files attached to this post.
maze
Hunter
Hunter
Posts: 94
Joined: Tue Oct 30, 2012 10:39 pm

Re: Problem while buying missiles

Post by maze »

Ok, so this is probably and finally figured out. Out of the Review Board process comes a new safer patch, which simplifies things by rounding up in a way which is a little nicer to players, in addition to not being buggy anymore, as you will see for yourself in the examples below. Also, the initial patch had potential issues with windows specifically.

The development team still has some testing to do before this can applied to the source tree, but things are in a good way.

In the meanwhile I post here the third and last (and hopefully final) patch version, so that you can apply it to your source tree should you wish to anticipate.

svn diff

Code: Select all

Index: src/cmd/unit_generic.cpp
===================================================================
--- src/cmd/unit_generic.cpp    (revision 13459)
+++ src/cmd/unit_generic.cpp    (working copy)
@@ -6389,8 +6389,16 @@
                                     if (templ->GetNumMounts() > jmod) {
                                         if (templ->mounts[jmod].volume != -1)
                                             if (upmount.ammo*upmount.type->volume > templ->mounts[jmod].volume)
-                                                upmount.ammo = (int) ( (templ->mounts[jmod].volume+1)/upmount.type->volume );
+                                                upmount.ammo = (int) ( (upmount.type->volume
+                                                            + templ->mounts[jmod].volume - 1)/upmount.type->volume );
                                     }
+                                } else {
+                                    if (GetNumMounts() > jmod) {
+                                        if (mounts[jmod].volume != -1)
+                                            if (upmount.ammo*upmount.type->volume > mounts[jmod].volume)
+                                                upmount.ammo = (int) ( (upmount.type->volume
+                                                            + mounts[jmod].volume - 1)/upmount.type->volume );
+                                    }
                                 }
                                 //compute here
                                 percentage += mounts[jmod].Percentage( &upmount );
@@ -6410,16 +6418,16 @@
                                             if (templ->mounts[jmod].volume != -1) {
                                                 if (templ->mounts[jmod].volume < mounts[jmod].type->volume*tmpammo) {
                                                     tmpammo =
-                                                        (int) floor( .125
-                                                                    +( (0
-                                                                        +templ->mounts[jmod].volume)
-                                                                      /mounts[jmod].type->volume ) );
+                                                        (int) ( (mounts[jmod].type->volume
+                                                                    + templ->mounts[jmod].volume - 1)
+                                                                      /mounts[jmod].type->volume) ;
                                                 }
                                             }
                                         }
                                     }
                                     if (tmpammo*mounts[jmod].type->volume > mounts[jmod].volume)
-                                        tmpammo = (int) floor( .125+( (0+mounts[jmod].volume)/mounts[jmod].type->volume ) );
+                                        tmpammo = (int) ( (mounts[jmod].type->volume
+                                                    + mounts[jmod].volume - 1)/mounts[jmod].type->volume);
                                     if (tmpammo > mounts[jmod].ammo) {
                                         cancompletefully = true;
                                         if (touchme)
Here's some effects of the above patch v3 examplified:
  • Before applying the patch
    • Dosto buying Advtorpedo: initial ammo count 1
    • Dosto refilling Advtorpedo: max ammo count 0
    • Dosto buying Miniature Grav Thumper: initial ammo count 8
    • Dosto refilling Miniature Grav Thumper: max ammo count 1
    • Dosto buying Friend or Foe: initial ammo count 2
    • Dosto refilling Friend or Foe: max ammo count 2
  • After applying the patch
    • Dosto buying Advtorpedo: initial ammo count 1
    • Dosto refilling Advtorpedo: max ammo count 1
    • Dosto buying Miniature Grav Thumper: initial ammo count 2
    • Dosto refilling Miniature Grav Thumper: max ammo count 2
    • Dosto buying Friend or Foe: initial ammo count 3
    • Dosto refilling Friend or Foe: max ammo count 3
You do not have the required permissions to view the files attached to this post.
TBeholder
Elite Venturer
Elite Venturer
Posts: 753
Joined: Sat Apr 15, 2006 2:40 am
Location: chthonic safety

Re: Problem while buying missiles

Post by TBeholder »

Ah, so the mount volume for custom specs was reset? No wonder...
0/1 thing is kind of correct - pylon type launchers are supposed to work like this: volume as such should not matter, only comatible mount size, so such mount is given volume=0 and it receives 1 of any compatible ammo - no more, no less.
It's just that missiles aren't removed properly, so instead of "installing new weapon" the same type is treated as "refill", and oops - there's no free volume at all.

Edit: posted in a patch that makes missile mounts UNCHOSEN upon spending all ammo. Now these mounts fall under IsEmpty() - cannot be selected, show as empty and are treated just as if there was nothing installed.
"Two Eyes Good, Eleven Eyes Better." -Michele Carter
Post Reply