Author Topic: Error with 357 revolver  (Read 2608 times)

Offline huntersan9

  • Acquaintance
  • *
  • Posts: 3
    • View Profile
Error with 357 revolver
« on: August 02, 2008, 11:39:40 pm »
I'm just starting a western type mud, and I just got a chance to look at the firearms code.  Initially, I've been reading code to find out where everything is, but I *THINK* I found a bug or at least a logic error.

I don't *THINK* I adjusted any of the code in the files mentioned, but it is possible.

Log:
Code: [Select]
> clone /domains/campus/weap/357pistol.c
You clone a .357 magnum revolver ( /domains/campus/weap/357pistol.c ).
> wield revolver
You wield a .357 magnum revolver.
> clone /domains/campus/obj/357round.c
You clone a .357 pistol round ( /domains/campus/obj/357round.c ).
> load round into revolver
You load your a .357 magnum revolver.
> call revolver->GetCaliber()
OBJ(revolver /domains/campus/weap/357pistol#856) -> GetCaliber() = 357.000000
> shoot dummy with revolver
You shoot at Dummy!

The bullet smashes into Dummy's torso!

you do 51 points of damage
Dummy says in English, "I receive damage from pirch. Damage type is PIERCE, raw
    damage is 51, body part(s) affected: torso."
Dummy says in English, "Actual damage done: 51."
> clone /domains/campus/obj/357round.c
You clone a .357 pistol round ( /domains/campus/obj/357round.c ).
> load round into revolver
That is not the right caliber.
> call revolver->GetCaliber()
OBJ(revolver /domains/campus/weap/357pistol#856) -> GetCaliber() = 35.700001
>


Looking at the /lib/firearms.c code, I noticed the following:
lines 379-393
Code: [Select]
mixed eventLoad(object ob){
    mixed can = CanLoad(this_player());
    if(!can || !intp(can)) return 0;
    if(!ob || !objectp(ob) || (objectp(ob) && living(ob))){
        write("Load "+GetKeyName()+" with what?");
        return 1;
    }
    if(GetFirearmType() == "revolver" && ob && objectp(ob) &&
      ob->GetFirearmType() == "revolver" && (base_name(ob) == LIB_ROUND ||
        inherits(LIB_ROUND,ob)) && ob->GetCaliber() == GetCaliber() &&
      rounds != MaxAmmo){
        rounds++;
    }
    return 1;
}

which calls on GetCalliber():
line 376:
Code: [Select]
int GetCaliber(){ return Caliber; }
After I shoot, the calliber changes.  Inspecting eventFire():
lines 266-270
Code: [Select]
266        if(Caliber){
267            if(to_float(Caliber) < 1.00) Caliber = to_float(Caliber) * 100.00;
268            if(Caliber > 99) Caliber = to_float(Caliber) * 0.10;
269            dam = (to_int(Caliber) / 6);
270        }

266: Caliber is equal to 357, which is true.
267: Caliber, even as float, is > 1, still 357.  Next.
268: Caliber is greater than 99, but is made a float and multiplied by 0.10!  which sets Caliber to 35.700001!  Which returns the 35.7 as the caliber. 

I haven't been able to study down into the mechanics as to what this is calculating, but I wanted to see if I'm the only one experiencing this.

Thanks,

huntersan9

Offline Kaylus

  • Acquaintance
  • *
  • Posts: 9
    • View Profile
Re: Error with 357 revolver
« Reply #1 on: August 03, 2008, 07:25:45 pm »
266: Caliber is equal to 357, which is true.
267: Caliber, even as float, is > 1, still 357.  Next.
268: Caliber is greater than 99, but is made a float and multiplied by 0.10!  which sets Caliber to 35.700001!  Which returns the 35.7 as the caliber. 

I haven't been able to study down into the mechanics as to what this is calculating, but I wanted to see if I'm the only one experiencing this.

Hunter,

The section in eventfire is calculating the damage done to an individual. A lower caliber weapon is going to be causing less damage. Basically it's purposefully creating a lower number so that you don't end up having massive amounts of damage, but then again that code is totally wasted if you don't use a standard.

I would recommend setting the caliber to '.357', that way the code doesn't accidently allow a 357 to best a 50-cal weapon. That's the proper way to calculate them anyways, for example.

One weapon with caliber 50.
One weapon with caliber 357.

The 50 cal will be set to 5
The 357 will be set to 35.7

Now if you use .50 and .357 they come out to

50 and 35.7

Which is more appropriate given the context. That code though isn't really ideal for what you are working on, need to hook that puppy in with the limbs system and link it to a weapons skill if it isn't already! Heh.

In summary: It does that on purpose to generate the damage passed on to another function, but it uses floats so you can specify the caliber how it's supposed to be. (.357 and .55and .22)

Offline huntersan9

  • Acquaintance
  • *
  • Posts: 3
    • View Profile
Re: Error with 357 revolver
« Reply #2 on: August 04, 2008, 10:00:21 pm »
Thanks for the quick reply!   ;D

However, I'm not quite worring about the damage at this point, but this specifically:

When the gun is cloned in, it reports it's Caliber as 357.
You fire the gun, and the line I mentioned changes the value that GetCaliber reads to 35.700001
You unload the shells
When you try to load the rounds for a 357, you get an error because the gun is now reporting the caliber as 35.700001 and the round is reporting it's caliber as 357.  Load fails.

I'm sorry if I wasn't clear, about the problem before.  I'll be looking into the code more tomorrow, but for now I'm still wondering how to fix it.


Offline Kaylus

  • Acquaintance
  • *
  • Posts: 9
    • View Profile
Re: Error with 357 revolver
« Reply #3 on: August 05, 2008, 03:01:29 pm »
Hunter,

Gotcha, because that is what you are telling it to do. I'm taking it "Caliber" is the name of the float variable within the weapon and all of the code is within the same file. If that is the case then your logic problem is right there:

Code: [Select]
266        if(Caliber){
267            if(to_float(Caliber) < 1.00) Caliber = to_float(Caliber) * 100.00;
268            if(Caliber > 99) Caliber = to_float(Caliber) * 0.10;
269            dam = (to_int(Caliber) / 6);
270        }

You are changing Caliber to Caliber * .10 -- when what you need to do is either evaluate it within the expression or just create a new variable.

Code: [Select]
If(Caliber) {
  if(to_float(Caliber) < 1.00) dam = (to_int(to_float(Caliber) * 100.00) / 6);
  if(Caliber > 99) dam = (to_int(to_float(Caliber) * 0.10) / 6);
  else dam = (to_int(Caliber) / 6);
}

Or something similar, that should fix you up -- note, that I don't have the lib you are using and haven't tested this code -- it was just written in a post at the spur of a moment, so anything like a missed parentheses or colon is not my responsibility.. :D

Kevin

Offline cratylus

  • Your favorite and best
  • Administrator
  • ***
  • Posts: 1024
  • Cratylus@Dead Souls <ds> np
    • View Profile
    • About Cratylus
Re: Error with 357 revolver
« Reply #4 on: August 10, 2008, 12:01:38 pm »
Yer both right...what I was attempting to do was handle the
weirdness of .357 and .38 being roughly the same caliber
while at the same time calculating integer damage. That
was the point of the multiplication by 0.10, but sadly I
goofed and rather than apply that calculation to a temporary
variable, I changed the pistol's Caliber permanently. Ewps!

The following code should behave more sanely. Note especially
the debug statements. If you enable debugging for yourself
(see: help debug ), you'll get a report of what the pistol
is calculating at a given point. Debug statements are a very
handy tool for when your code is doing something you
don't understand.

Note that this code isn't perfect, it's just a quick rewrite to
better illustrate the mechanics of what's going on.

/lib/firearm.c
Code: [Select]
#include "include/firearm.h"
#include <lib.h>
#include <damage_types.h>
#include <dirs.h>
inherit LIB_STORAGE;
inherit LIB_LOAD;

private int MaxAmmo, Millimeter, AmmoSize;
private string FirearmType, AmmoType;
private string AmmoFile, firearm_name;
private float Caliber;
private string *namen;
private string *ammonamen;
private int loaded, rounds;
private int shells, magnum;
private int mag,cloned;
private int autohit;
private int dam, last_shot;

static void create(){
    string *s_save, *a_save;

    ::create();

    s_save = storage::GetSave();
    a_save = s_save;

    AddSave( a_save );
    AddSave( ({ "loaded", "rounds", "shells" , "mag" , "cloned" }) );
    MaxAmmo=6;
    AmmoFile="/domains/default/obj/round";
    FirearmType="revolver";
    AmmoType="round";
    loaded=1;
    rounds=0;
}

void init(){
    object ob;
    object *inv;
    ::init();
    //add_action("startLoad","load");
    //add_action("startUnload","unload");
    this_object()->CalculateAmmoSize();
    namen=this_object()->GetId();
    if(FirearmType=="revolver"
      && !present("cylinder",this_object())){
        new("/lib/cylinder")->eventMove(this_object());
    }
    if(FirearmType=="revolver" && !cloned){
        cloned=1;
        ob=present("cylinder", this_object());
        inv=all_inventory(ob);
        filter(inv, (: this_object()->InitRevolver($1->GetId()) :) );
    }
    if(FirearmType=="auto" && !present("clip",this_object()) ){
        mag=0;
        loaded=0;
        rounds=0;
    }
}

string SetFirearmName(string str){
    if(str) firearm_name = str;
    return firearm_name;
}

string GetFirearmName(){
    if(firearm_name) return firearm_name;
    return GetKeyName();
}

int InitRevolver(string *arr){
    if(member_array("round",arr) != -1){
        rounds++;
        return 1;
    }
    if(member_array("shell",arr) != -1){
        shells++;
        return 1;
    }
}
mixed CanGetFrom(object who, object item){
    return "It doesn't work that way. Try unloading it.";
}

mixed CanPutInto(object who, object what){
    return "It doesn't work that way. Try loading the "+GetFirearmName()+" with something.";
}

int CanReceive(object ob){
    string *idarray;
    if(FirearmType=="revolver"){
        if(rounds == MaxAmmo){
            write("It is already fully loaded.");
            return 1;
        }
    }
    if(FirearmType != "auto" && ob->GetKeyName() != "revolver cylinder"){
        write("This "+GetFirearmName()+" only receives bullets.");
        return 0;
    }
    idarray=ob->GetId();
    if(FirearmType=="auto" && member_array("magazine",idarray) == -1){
        write("This "+GetFirearmName()+" only receives ammunition clips.");
        return 0;
    }
    if(FirearmType=="auto" && ob->GetMillimeter() != this_object()->GetMillimeter() ){
        write("That is not the correct ammunition clip size.");
        return 0;
    }
    if(FirearmType=="auto" && ob->GetCaliber() != this_object()->GetCaliber() ){
        write("That is not the correct ammunition clip caliber.");
        return 0;
    }
    if(FirearmType=="auto" && ob->GetAmmoType() != this_object()->GetAmmoType() ){
        write("That is not the correct ammunition clip type.");
        return 0;
    }
    if(FirearmType=="auto" && mag){
        write("The "+GetFirearmName()+" is already loaded.");
        return 0;
    }
    if(FirearmType=="auto"){
        mag=1;
        rounds=sizeof(all_inventory(ob));
    }
    return 1;
}
int CanRelease(object ob){
    if(ob->GetKeyName()=="revolver cylinder"){
        return 0;

    }
    return 1;
}

mixed eventShoot(object ob, mixed target){
    object cible;
    object shell;
    object *obs;
    if(objectp(target)){
        cible = target;
    }
    else {
        obs = filter(get_livings(environment(this_player())),
          (: answers_to($(target), $1) :));
        if(!sizeof(obs)) cible = present(target,environment(this_player()));
        else cible = obs[0];
    }
    if(cible) target = cible->GetName();

    else {
        write("It seems there's a problem targeting "+target+".");
        return 1;
    }

    if(!rounds || rounds == 0){
        write("Your weapon is not loaded.\n");
        say(environment(this_object())->GetName()+" tries to shoot "+capitalize(target)+" with an unloaded weapon.\n");
        return 1;
    }
    write("You shoot at "+capitalize(target)+"!\n");
    say(environment(this_object())->GetName()+" shoots at "+capitalize(target)+"!\n");
    if(cible) tell_object(cible, environment(this_object())->GetName()+
          " shoots at you!\n");
    this_object()->eventFire(target);
    if(FirearmType=="auto"){
        shell = new(LIB_SHELL);
        if(!shell) return 1;
        shell->SetFirearmType(GetFirearmType());
        shell->SetCaliber(GetCaliber());
        shell->eventMove(environment(environment(this_object())));
    }
    return 1;
}

int eventFire(mixed str){
    object ob;
    object *obs;
    int tempclass, i, dex;
    int TorsoNum, NumLimbs;
    mixed dexmap;
    string tempshort,templong;
    string *limbarr;
    int limbhit;
    string limbname;
    string s1,s2;
    rounds--;
    if(this_object()->GetFirearmType() == "auto"){
        if(first_inventory(present("magazine",this_object())) ){
            first_inventory(present("magazine",this_object()))->eventDestruct();
            present("magazine",this_object())->MinusAmmo(1);
        }
        else rounds=0;
    }
    if(this_object()->GetFirearmType() == "revolver"){
        shells++;
        ob=present("cylinder",this_object());
        if(present("round",ob)) present("round",ob)->eventDestruct();
        new("/lib/shell")->eventMove(ob);
    }
    if(rounds <= 0) loaded=0;
    ob = 0;
    if(objectp(str)) ob = str;
    else obs = filter(get_livings(environment(this_player())),
          (: answers_to($(str), $1) :));
    if(!ob && !sizeof(obs)) ob = present(str,environment(this_player()));
    else if(!ob) ob = obs[0];
    if(creatorp(ob)){
        write(ob->GetName()+" catches your bullet in "+possessive(ob)+" teeth.\n");
        say(ob->GetName()+" catches the bullet in "+possessive(ob)+" teeth.\n");
        autohit=0;
        return 1;
    }
    if(ob && !living(ob) && base_name(ob) != LIB_CORPSE){
        tell_room(environment(environment(this_object())),
          "The bullet smashes into "+lower_case(ob->GetShort())+"!\n");
        if(!sscanf(ob->GetLong(),"%sIt has been damaged by gun%s",s1,s2)){
            tempclass=ob->GetClass();
            if(tempclass) ob->SetClass(tempclass/2);
            tempshort=ob->GetShort();
            tempshort = "a damaged "+remove_article(tempshort);
            ob->SetShort(tempshort);
            templong=ob->GetLong();
            if(sscanf(templong,"%s\n\n%s",s1,s2) >=1){
                templong=s1+" It has been damaged by gunfire.\n\n";
            }
            else
                templong += " It has been damaged by gunfire.";
            ob->SetLong(templong);
            return 1;
        }
        tempclass=ob->GetClass();
        if(tempclass) ob->SetClass(tempclass/2);
        return 1;
    }
    i = random(100);
    if(!creatorp(environment())){
        dex = environment(this_object())->GetStatLevel("coordination");
        dex += (environment(this_object())->GetStatLevel("luck") / 3);
        if(environment(this_object())->GetSkillLevel("firearms") < 10){
            int now = time();
            if(last_shot == now) dex -= 100;
            else if((now - last_shot) < 2)  dex -= 50;
        }
    }
    else dex = 200;
    last_shot = time();
    if((ob && living(ob)) && (i < dex || autohit==1)){
        NumLimbs=sizeof(ob->GetLimbs());
        TorsoNum=member_array(ob->GetTorso(),ob->GetLimbs());
        i=random(100);
        if(i < 50) limbhit=TorsoNum;
        else limbhit=random(NumLimbs);
        limbarr=ob->GetLimbs();
        limbname=limbarr[limbhit];
        tell_room(environment(environment(this_object())),"The bullet smashes into "+
          capitalize(str)+"'s "+limbname+"!\n",ob);
        tell_object(ob,"The bullet smashes into your "+limbname+"!\n");
        ob->AddLead("gunshot_wounds", 1);
        ob->SetAttack(this_agent());
        if(!present("firearms_wound",ob)){
            new(LIB_WOUND)->eventMove(ob);
        }
        if(Caliber){
            float tmp;
            int extradam = this_object()->GetMagnum();
            debug("extradam: "+extradam);
            if(to_float(Caliber) < 1.00) Caliber = to_float(Caliber) * 100.00;
            debug("Caliber: "+Caliber);
            if(Caliber > 99) tmp = to_float(Caliber) * 0.10;
            else tc(Caliber +" is not larger than 99");
            debug("tmp: "+tmp);
            dam = to_int(tmp);
            debug("pre magnum dam: "+dam);
            if(extradam) dam += (random(extradam/2) + extradam/2);
            debug("post magnum dam: "+dam);
        }
        if(Millimeter){
            dam = Millimeter;
            dam *= random(10);
        }
        if(!dam) dam = 7;
        debug("pre modifiers dam: "+dam);

        dam += random(environment(this_object())->GetStatLevel("coordination"));
        debug("post coordination check dam: "+dam);
        dam += environment(this_object())->GetSkillLevel("projectile attack");
        debug("post skill level check dam: "+dam);
        dam -= random(ob->GetStatLevel("luck"));
        debug("post luck check on target dam: "+dam);
        dam -= random(ob->GetSkillLevel("projectile defense"));
        debug("post skill level check on target dam: "+dam);

        if(creatorp(this_player())) write("you do "+dam+" points of damage");

        ob->eventReceiveDamage(environment(this_object()),(PIERCE), dam, 0, limbname);
        if(!ob->GetInCombat()){
            ob->eventForce("attack "+environment(this_object())->GetKeyName());
        }
        autohit=0;
        return 1;
    }
    write("Your shot misses its mark.\n");
    say(environment(this_object())->GetName()+"'s shot misses its mark.\n");
    this_object()->missed_shot();
    return 1;
}

int missed_shot(){
    object ob,maghere,magstuff;
    string str;
    int i;
    object *inv;
    string *arr;
    if(environment(environment(this_object()))->GetClimate() != "indoors"){
        return 1;
    }
    inv=all_inventory(environment(environment(this_object())));
    i=random(sizeof(inv));
    if(living(inv[i])){
        tell_room(environment(environment(this_object())), inv[i]->GetName()+" is struck "+
          "by the stray bullet!",inv[i]);
        tell_object(inv[i],"You are struck by a stray bullet from "+environment(this_object())->GetName()+
          "'s gun.\n");
    }
    if(!living(inv[i])){
        arr=explode(inv[i]->GetKeyName(),"");
        if(arr[sizeof(arr)-1] =="s"){
            tell_room(environment(environment(this_object())),capitalize(inv[i]->GetShort())+" are struck by the stray bullet.");
        }
        else
            tell_room(environment(environment(this_object())),capitalize(inv[i]->GetShort())+" is struck by the stray bullet.");
    }
    autohit=1;
    rounds++;
    this_object()->eventFire(inv[i]->GetKeyName());
    if(this_object()->GetFirearmType() == "revolver"){
        shells--;
        present("shell",present("cylinder",this_object()))->eventDestruct();
        ob=new("/lib/round");
        ob->SetCaliber(this_object()->GetCaliber());
        ob->SetMillimeter(this_object()->GetMillimeter());
        ob->SetFirearmType(this_object()->GetFirearmType());
        ob->SetAmmoType(this_object()->GetAmmoType());
        ob->eventMove(present("cylinder",this_object()));
    }
    else
    {
        str = "";
        maghere=present("magazine",this_object());
        if(maghere) magstuff = first_inventory(maghere);
        if(maghere && magstuff) str=base_name(magstuff);
        if(str && str !="" ) new(str)->eventMove(maghere);
    }
    return 1;
}
int CalculateAmmoSize(){
    float i;
    i=this_object()->GetCaliber();
    if(i > 0){
        if(stringp(i)) sscanf(i,"%d",i);
        if(intp(i)) to_float(i);
        while(i > 1.0){
            i = i*(0.1);
        }
        i = i*(25.4);
        AmmoSize=to_int(i);
        dam=AmmoSize*(AmmoSize);
        dam *= 3;
        return 1;
    }
    AmmoSize=this_object()->GetMillimeter();
    return 1;
}
int ShowRounds(){ environment(this_object())->eventPrint("Firearm has: "+rounds+" rounds.\n");
    environment(this_object())->eventPrint("Firearm has: "+shells+" shells.\n");
    return 1;
}
int SetAmmo(int i){ rounds=i; return 1; }
int GetAmmo(){ return rounds; }
int GetMag(){ return mag; }
int SetMag(int i){ mag=i; return 1; }
int SetLoaded(int i){ loaded=i; return 1; }
int GetLive(){ return loaded; }
int SetAmmoFile(string str){ AmmoFile=str; return 1; }
int SetAmmoType(string str){ AmmoType=str; return 1; }
int SetFirearmType(string str){ FirearmType=str; return 1; }
int SetMaxAmmo(int x){ MaxAmmo=x; return 1; }
int SetCaliber(int x){ Caliber=x; return 1; }
int SetMillimeter(int x){ Millimeter=x; return 1; }
string GetAmmoType(){ return AmmoType; }
string GetFirearmType(){ return FirearmType; }
int GetMaxAmmo(){ return MaxAmmo; }
int GetCaliber(){ return Caliber; }
int GetMillimeter(){ return Millimeter; }

mixed eventLoad(object ob){
    mixed can = CanLoad(this_player());
    if(!can || !intp(can)) return 0;
    if(!ob || !objectp(ob) || (objectp(ob) && living(ob))){
        write("Load "+GetKeyName()+" with what?");
        return 1;
    }
    if(GetFirearmType() == "revolver" && ob && objectp(ob) &&
      ob->GetFirearmType() == "revolver" && (base_name(ob) == LIB_ROUND ||
        inherits(LIB_ROUND,ob)) && ob->GetCaliber() == GetCaliber() &&
      rounds != MaxAmmo){
        rounds++;
    }
    return 1;
}

mixed eventUnload(mixed what){
    string n1,s1,s2;
    int n2;
    mixed can = CanUnload(this_player());
    if(!can || !intp(can)) return 0;

    if(FirearmType=="auto" && !mag){
        write("It's already unloaded.");
        return 1;
    }
    if(mag==1 && environment(this_object()) == this_player()){
        this_object()->doMagUnload();
        return 1;
    }
    if(FirearmType=="revolver" &&
      environment(this_object()) == this_player()){
        if(rounds == 0 && shells == 0){
            write("Your "+GetFirearmName()+" is already empty.");
            return 1;
        }
        if(intp(what) && what < 7 && what > 0) true();
        else what = "all";
        write("You unload your "+GetFirearmName()+".");
        this_object()->doRevolverUnload("all",what);
        return 1;
    }
}

int doMagUnload(){
    if(!present("clip",this_object())){
        write("The "+GetFirearmName()+" is already empty.");
        return 0;
    }
    write("You unload an ammo clip from your "+GetFirearmName()+".");
    say(this_player()->GetName()+" unloads an ammo clip from "+possessive(this_player())+" "+GetFirearmName()+".");
    present("clip",this_object())->eventMove(environment(this_object()));
    mag=0;
    loaded=0;
    rounds=0;
    return 1;
}

int doRevolverUnload(string what, string num){
    int i,n1,n2;
    if(sscanf(num,"%d",n1)){
    }
    if(what=="all"){
        n1=shells;
        n2=rounds;
    }
    if(what=="shells" || what=="all"){
        i=shells-n1;
        while(shells > i){
            present("shell",present("revolver cylinder",this_object()))->eventMove(environment(this_object()));
            shells--;
        }
    }
    if(what=="rounds" || what=="all"){
        if(what != "all") n2=n1;
        i=rounds-n2;
        while(rounds > i){
            present("round",present("revolver cylinder",this_object()))->eventMove(environment(this_object()));
            rounds--;
        }
    }
    if(n2 > 0){
        string things = "rounds";
        if(n2 == 1) things = "round";
        write("You unload "+cardinal(n2)+" "+things+" from your "+GetFirearmName()+".");
    }
    if(n1 > 0){
        string things = "shells";
        if(n1 == 1) things = "shell";
        write("You unload "+cardinal(n1)+" "+things+" from your "+GetFirearmName()+".");
    }
    say(environment(this_object())->GetName()+" unloads some cartridges from "+
      possessive(environment(this_object()))+" revolver.");
    return 1;
}

int GetMaxLoaded(){
    if(rounds + shells >= MaxAmmo) return 1;
    return 0;
}

int GetMagnum(){
    return magnum;
}

int SetMagnum(int i){
    if(i > 0) magnum = i;
    else magnum = 0;
    return magnum;
}

It isn't much excuse, but it's worth mentioning that my firearms
code is one of the very earliest pieces of lib coding I ever did,
so you'll likely see some clumsy stuff in there. Definitely unpretty
and could probably use a complete overhaul...but hey, it mostly
works for now :)

-Crat