Item Durability

  • Papaya Pete
  • Topic Author
  • Offline
  • Gold Boarder
  • Gold Boarder
More
6 years 9 months ago #2240 by Papaya Pete
Item Durability was created by Papaya Pete
I'm going to be working on a new snippet that adds item durability, which to begin with will just be used by armor and weapons. As I'm looking through the code, to see what changes/additions I need to make, I'm realizing that object files are going to be changed, seeing as it'll be saving two new values.

I guess my only (minor) worry is having to do a complete object wipe. Has anyone else tried something like this, adding new values to an object to be saved? Curious to see if anyone else has ever been forced to do a full wipe after adding something.

Please Log in or Create an account to join the conversation.

More
6 years 9 months ago #2241 by DirtyDevil
Replied by DirtyDevil on topic Item Durability
Item durability was added to NewDawn mud that I worked on many years ago, it also had a fumble then meant that you could break a weapon when fighting my missing a hit. I have a version of the whole mud but am struggling to get it to compile to check what features were in the version I have. I have also sent an email to mono.org which is where the mud was once hosted in 1996

I have found an old webpage that still kicking about on the internet
community.fortunecity.ws/rivendell/dunge...newbie/newdawnh.html

I will wait for the reply from mono.org (a telnet bbs still running in a world of WWW)to see if they have the code lying around. If not I will upload what I have

Please Log in or Create an account to join the conversation.

  • Papaya Pete
  • Topic Author
  • Offline
  • Gold Boarder
  • Gold Boarder
More
6 years 9 months ago #2242 by Papaya Pete
Replied by Papaya Pete on topic Item Durability
Well I was looking over the code a little bit today, just to get an idea on what files to work on and such... and so far, it looks like I'll have to tinker with act.wizard.c to show durability (current and max) when statting an item... then there's making the additions to oedit.c so that you can set it in the first place. Structs.h under object data, fight.c is where damage to items (and removal upon breaking) would take place. act.item.c, to make sure that it isn't broken when you try to wield/wear an item (if it's broken, "Hey, this is broken, you can't use it!). Let's see... genobj.c is where item saving and loading takes place, need to do some work there as well. And in utils.h. That's what I've seen so far: it looks like it's going to be a lot of work but not impossible.

NewDawn, huh? I know of another mud that did item durabilities too... Eternal Visions, actually. Thing is, while the place is still up, hardly anyone ever goes on there, and last I heard the coder there is pretty strict about letting anyone look at the code. I'm not even sure if it would help much to take a look, seeing as EV used a circlemud base that's been highly modified.

Please Log in or Create an account to join the conversation.

More
6 years 9 months ago #2274 by Kewlb
Replied by Kewlb on topic Item Durability
I implemented item durability in my fallout game.

Since I was going to have to add some values to the obj file I went ahead and did one for material type and one for durability. The material affected the decay rate & ease of damage of an item. As a person fought they might take damage to certain body parts in which turn that armor might degrade. I had energy weapons degrade armor the most. I also made it so its overall effectiveness (statistics assigned to that object type) would slide up/down based on its condition. I then coded in the ability to repair items with like items.

If you get stuck or need pointers just let me know.

Please Log in or Create an account to join the conversation.

  • Papaya Pete
  • Topic Author
  • Offline
  • Gold Boarder
  • Gold Boarder
More
6 years 9 months ago #2279 by Papaya Pete
Replied by Papaya Pete on topic Item Durability
Ah after some work and looking it over with a friend, who helped me to see I was forgetting to make sure things were loading properly, I have the basics done. In oedit, one can set an item's max durability and current durability, with a 0 max meaning that the item is indestructible. With how I've coded it in thus far, it means going in by hand and making the small additions to each of the objects in the world files (basically adding " 0 0" after the four "vals" are stored) or just wiping and starting over.

I've been trying to write instructions out as I go along, so I don't feel so overwhelmed I just never get around to it. Hoping to get the actual wear and tear implemented sometime this week.

Please Log in or Create an account to join the conversation.

More
6 years 9 months ago #2302 by Kewlb
Replied by Kewlb on topic Item Durability
another method is to write your "save to disk" function for your objects first, compile, boot your game, oedit save each zone writing these new values, shut the game down. Now write in the code to read the new values.. no need to manually make modifications.

Please Log in or Create an account to join the conversation.

  • Vatiken
  • Vatiken's Avatar
  • Offline
  • Administrator
  • Administrator
  • tbaMUD Programmer
More
6 years 9 months ago #2308 by Vatiken
Replied by Vatiken on topic Item Durability
Both those ideas are awful, being complete wastes of time and prone to errors. I know this for a fact because they were ideas I had also come up with and utilized a long long long time ago when I first started coding.

If you go into db.c and go into the parse_object() function you will see that the problem of adding to the world files has occured in the past and has been properly dealt with in the stock tba code.

ADDING NEW DATA
In the following snippet t[3] & t[4] were added after the fact for OBJ_LEVEL() and OBJ_TIMER(). It checks for 5 arguments but has conditions for if it only finds 3 or 4. If this occurs, it just sets them both to 0. Using this method you won't have any issues with old world files mixing with new ones, and most importantly, no manual editing.
  if (!get_line(obj_f, line)) {
    log("SYSERR: Expecting third numeric line of %s, but file ended!", buf2);
    exit(1);
  }
  if ((retval = sscanf(line, "%d %d %d %d %d", t, t + 1, t + 2, t + 3, t + 4)) != 5) {
    if (retval == 3) {
      t[3] = 0;
      t[4] = 0;
    } else if (retval == 4)
      t[4] = 0;
    else {
      log("SYSERR: Format error in third numeric line (expecting 5 args, got %d), %s", retval, buf2);
      exit(1);
    }
  }

  GET_OBJ_WEIGHT(obj_proto + i) = t[0];
  GET_OBJ_COST(obj_proto + i) = t[1];
  GET_OBJ_RENT(obj_proto + i) = t[2];
  GET_OBJ_LEVEL(obj_proto + i) = t[3];
  GET_OBJ_TIMER(obj_proto + i) = t[4];

SAVING MODIFIED FILES
The following snippet shows how when converting a older file, the code automatically puts the newly converted object file into the MUD's save list so you can save all the files at once from within the game.
  } else if (((retval == 4) || (retval == 3)) && (bitwarning == FALSE)) {

    if (retval == 3)
      t[3] = 0;
    else if (retval == 4)
      t[3] = asciiflag_conv_aff(f3);

    log("Converting object #%d to 128bits..", nr);
    GET_OBJ_EXTRA(obj_proto + i)[0] = asciiflag_conv(f1);
    ...
    GET_OBJ_PERM(obj_proto + i)[3] = 0;

    if(bitsavetodisk) {
      add_to_save_list(zone_table[real_zone_by_thing(nr)].number, 1);
      converting = TRUE;
    }

    log("   done.");
  } else if (retval == 13) {

tbaMUD developer/programmer

Please Log in or Create an account to join the conversation.

  • Papaya Pete
  • Topic Author
  • Offline
  • Gold Boarder
  • Gold Boarder
More
6 years 9 months ago #2309 by Papaya Pete
Replied by Papaya Pete on topic Item Durability
Hmmm I see what you mean, that looks like a very easy way to do some converting!

Well, I've been doing a little more testing... and I've run across another problem. So far, I've gotten those new values added in and saved. They seem to load properly and everything, and I've even got some code in to do damage to weapons as they're used in combat. However, if a character saves and quits with a broken weapon (0 condition) and logs back in... the weapon is once again back to it's original starting point when first loaded (in this case, 100 out of 100).

On another note... the game crashes when walking into another room at seemingly random times. Looking through the crash log, I can't seem to find any error messages... I'll keep hunting. I have the feeling this item condition thing is a bit more than I can handle!

Please Log in or Create an account to join the conversation.

  • Papaya Pete
  • Topic Author
  • Offline
  • Gold Boarder
  • Gold Boarder
More
6 years 9 months ago #2320 by Papaya Pete
Replied by Papaya Pete on topic Item Durability
Ah found out what the problem was.

The conditions of objects that were on the players were not being saved properly. Or, they were, but I didn't add in the code to consider durability. So made the necessary additions to objsave_save_obj_record function in objsave.c, and it looks like it's working the way it should be. Also, the crashes have stopped.

So I've gotten the wear and tear for weapons part down in the hit() function in fight.c. Hmmm. So the next step is randomly determining which location is struck, check to see if something is worn there, and then roll some dice to see if it's damage from the blow. The only thing that I don't know how to do is check the victim's location for gear...

Let's see if I can figure that out. Though pointers are always appreciated. :)

Please Log in or Create an account to join the conversation.

  • Vatiken
  • Vatiken's Avatar
  • Offline
  • Administrator
  • Administrator
  • tbaMUD Programmer
More
6 years 9 months ago #2321 by Vatiken
Replied by Vatiken on topic Item Durability
You most likely have a condition while loading objects that sets any object with 0 current durability back to the max. An easy way to help diagnose this would be to create an object with 0 current durability and manually load it into the game. If it stays at 0, then the issue is most likely in the parse_object() function.

tbaMUD developer/programmer
The following user(s) said Thank You: Papaya Pete

Please Log in or Create an account to join the conversation.

  • Papaya Pete
  • Topic Author
  • Offline
  • Gold Boarder
  • Gold Boarder
More
6 years 9 months ago #2322 by Papaya Pete
Replied by Papaya Pete on topic Item Durability
Yeah I wasn't even saving any of the condition info into the player's plrobj file, that was the source of the problem. Got it fixed now, and also took a look at what you posted earlier....

If you go into db.c and go into the parse_object() function you will see that the problem of adding to the world files has occured in the past and has been properly dealt with in the stock tba code.


Taking a look at it, I finally understood what was going on after getting a night of sleep. I stored the condition data on the second line instead of the third, so I made those same retval checks on the second line of data that were done on the third (taking into account there aren't the same number of values). Threw in the stock zones and everything, and it all loads perfectly fine! Thank you very much for pointing that out. :)

Now to figure out how to see what a victim is wearing.

Please Log in or Create an account to join the conversation.

  • Papaya Pete
  • Topic Author
  • Offline
  • Gold Boarder
  • Gold Boarder
More
6 years 9 months ago #2324 by Papaya Pete
Replied by Papaya Pete on topic Item Durability
Ok, I figured out how to do a hit-location check and see if the victim of the blow has armor on a specified location. If it does, then damage is applied to that item's durability. The only thing I have to add in is a check to see whether or not the item is unbreakable, in which case it won't deal any damage.

The next step is displaying the item's condition in the short desc, when you see it in a room, in your inventory, equipment, and so on. Example: a sword (excellent)

After that, it's setting up shops to be able to repair items with damaged conditions. That should be it.

That crash out of the blue still happens. I was in combat and the mud crashed in the middle of it, without any error message to syslog. I'll have to figure out how to use the gdb in order to find out what's going on.

Anyways, hope you guys don't feel like I'm just filling up space here, I just want to give little updates to let people know how far along I am. :)

Please Log in or Create an account to join the conversation.

More
6 years 9 months ago #2332 by thomas
Replied by thomas on topic Item Durability
I, for one, don't feel you're just "filling up space".

And there's a guide to gdb here: www.tbamud.com/forum/4-development/6-debugging-tutorial-for-gdb

Please Log in or Create an account to join the conversation.

  • Papaya Pete
  • Topic Author
  • Offline
  • Gold Boarder
  • Gold Boarder
More
6 years 9 months ago #2340 by Papaya Pete
Replied by Papaya Pete on topic Item Durability
Ah that came in handy! I followed the tutorial and managed to get some info on this crash.

Seems the crash occurs when damage is supposed to occur to a worn item, but the problem is there is no item worn on that location! Here is what gdb came up with.
(gdb) bt
#0  0x00482052 in hit (ch=0x80f107b0, victim=0x80adf088, type=-1)
    at fight.c:1137
#1  0x00482e0d in perform_violence () at fight.c:1230
#2  0x004fa2aa in heartbeat (heart_pulse=180) at comm.c:991
#3  0x004fdd15 in game_loop (local_mother_desc=3) at comm.c:938
#4  0x004fee86 in init_game (local_port=4000) at comm.c:533
#5  main (argc=2, argv=0x28ac50) at comm.c:353
(gdb) list
1142                          send_to_char(victim, "\trWith that final blow, %s that you were wearing fall apart!\tn\n", GET_OBJ_SHORT(headarm));
1143                          send_to_room(IN_ROOM(victim), "\tr%s is less protected as %s falls apart after that last blow!\tn\n", GET_NAME(victim), GET_OBJ_SHORT(headarm));
1144                          obj_to_char(unequip_char(victim, WEAR_HEAD), victim);
1145                      }
1146                  }
1147              break;
1148            default:
1149            break;
1150        }
1151
(gdb) info local
wielded = <optimized out>
bodyarm = 0x0
neckarm1 = 0x0
neckarm2 = 0x0
headarm = 0x0
shield = 0x0
legarmor = 0x0
feetarm = 0x0
handarm = 0x0
armarmor = 0x0
aboutarm = 0x0
waistarm = 0x0
rwristarm = 0x0
lwristarm = 0x0
w_type = 303
victim_ac = <optimized out>
calc_thaco = 0
dam = 12
diceroll = 5
wpnprof = <optimized out>
location = <optimized out>
(gdb) up
#1  0x00482e0d in perform_violence () at fight.c:1230
1230            hit(ch, FIGHTING(ch), TYPE_UNDEFINED);
(gdb) list
1225          /* have to implement a better way for number of attacks for mobs */
1226          num_of_attacks += ((int) GET_LEVEL(ch) / 5) - 1;
1227        }
1228
1229        for (loop_attacks = 1; loop_attacks < num_of_attacks && ch && FIGHTING(ch); loop_attacks++)
1230            hit(ch, FIGHTING(ch), TYPE_UNDEFINED);
1231
1232        if (GROUP(ch)) {
1233          while ((tch = (struct char_data *) simple_list(GROUP(ch)->members)) != NULL) {
1234            if (tch == ch)
(gdb) info local
ch = 0x80f107b0
tch = <optimized out>
wielded = <optimized out>
num_of_attacks = 4
loop_attacks = <optimized out>
(gdb) up
#2  0x004fa2aa in heartbeat (heart_pulse=180) at comm.c:991
991         perform_violence();
(gdb) list
986
987       if (!(heart_pulse % PULSE_MOBILE))
988         mobile_activity();
989
990       if (!(heart_pulse % PULSE_VIOLENCE))
991         perform_violence();
992
993       if (!(heart_pulse % (SECS_PER_MUD_HOUR * PASSES_PER_SEC))) {  /* Tick ! */
994         next_tick = SECS_PER_MUD_HOUR;  /* Reset tick coundown */
995         weather_and_time(1);

Here's an example also of the variables I defined, and a little bit of the location code to boot.
struct obj_data *wielded = GET_EQ(ch, WEAR_WIELD);
  struct obj_data *bodyarm = GET_EQ(victim, WEAR_BODY);
  struct obj_data *neckarm1 = GET_EQ(victim, WEAR_NECK_1);
  struct obj_data *neckarm2 = GET_EQ(victim, WEAR_NECK_2);
  struct obj_data *headarm = GET_EQ(victim, WEAR_HEAD);
  struct obj_data *shield = GET_EQ(victim, WEAR_SHIELD);
  struct obj_data *legarmor = GET_EQ(victim, WEAR_LEGS);
  struct obj_data *feetarm = GET_EQ(victim, WEAR_FEET);
  struct obj_data *handarm = GET_EQ(victim, WEAR_HANDS);
  struct obj_data *armarmor = GET_EQ(victim, WEAR_ARMS);
  struct obj_data *aboutarm = GET_EQ(victim, WEAR_ABOUT);
  struct obj_data *waistarm = GET_EQ(victim, WEAR_WAIST);
  struct obj_data *rwristarm = GET_EQ(victim, WEAR_WRIST_R);
  struct obj_data *lwristarm = GET_EQ(victim, WEAR_WRIST_L);
switch (location) {
        case 1:  // Feet Location
        case 2:
          if ((feetarm) && (GET_OBJ_MAX_DURAB(feetarm) != 0))
              diceroll = rand_number(1, 100);
              if (diceroll <= 10) {
                  send_to_char(ch, "\tRWith that blow, %s has been damaged!\tn\n", GET_OBJ_SHORT(feetarm));
                  GET_OBJ_DURABILITY(feetarm) -= rand_number(1, 6);
                  if (GET_OBJ_DURABILITY(feetarm) < 0)
                      GET_OBJ_DURABILITY(feetarm) = 0;
                  if (GET_OBJ_DURABILITY(feetarm) == 0) {
                      send_to_char(victim, "\trWith that final blow, %s that you were wearing fall apart!\tn\n", GET_OBJ_SHORT(feetarm));
                      send_to_room(IN_ROOM(victim), "\tr%s is less protected as %s falls apart after that last blow!\tn\n", GET_NAME(victim), GET_OBJ_SHORT(feetarm));
                      obj_to_char(unequip_char(victim, WEAR_FEET), victim);
                  }
              }
          break;
        case 3:  // Leg location
        case 4:
        case 5:
          if ((legarmor) && (GET_OBJ_MAX_DURAB(legarmor) != 0))
              diceroll = rand_number(1, 100);
              if (diceroll <= 10) {
                  send_to_char(ch, "\tRWith that blow, %s has been damaged!\tn\n", GET_OBJ_SHORT(legarmor));
                  GET_OBJ_DURABILITY(legarmor) -= rand_number(1, 6);
                  if (GET_OBJ_DURABILITY(legarmor) < 0)
                      GET_OBJ_DURABILITY(legarmor) = 0;
                  if (GET_OBJ_DURABILITY(legarmor) == 0) {
                      send_to_char(victim, "\trWith that final blow, %s that you were wearing fall apart!\tn\n", GET_OBJ_SHORT(legarmor));
                      send_to_room(IN_ROOM(victim), "\tr%s is less protected as %s falls apart after that last blow!\tn\n", GET_NAME(victim), GET_OBJ_SHORT(legarmor));
                      obj_to_char(unequip_char(victim, WEAR_LEGS), victim);
                  }
              }
          break;

Thanks for showing me that link, I'll finish trying to find out what the problem is. I think the issue is when I check to see whether something is located on a wear slot; it shouldn't even be reaching the send_to_char reporting to the player that the non-existing item is damaged.

Very educational!

Please Log in or Create an account to join the conversation.

  • Papaya Pete
  • Topic Author
  • Offline
  • Gold Boarder
  • Gold Boarder
More
6 years 9 months ago #2355 by Papaya Pete
Replied by Papaya Pete on topic Item Durability
So after a night of rest I'm coming back to this problem. I did some testing, and tried putting in more checking... but for some reason, the logic just isn't working. The strange thing is that I've used the same logic before and it worked fine! The only difference: before, it was on the attacker. Here's the snippet for when a weapon is damaged.
/* Figuring out amount of wear and tear on equipment involved
       First, starting with weapons, if any */
    if (wielded && GET_OBJ_TYPE(wielded) == ITEM_WEAPON && (GET_OBJ_MAX_DURAB(wielded) != 0)) {
        diceroll = rand_number(1, 100);
        if (diceroll <= 100) { // Base 10% chance per hit of wearing weapon down
            act("\tRYour weapon, $p, has been slightly damaged!\tn\n", FALSE, ch, wielded, 0, TO_CHAR);
            GET_OBJ_DURABILITY(wielded) -= rand_number(1, 6);
            if (GET_OBJ_DURABILITY(wielded) < 0)
                GET_OBJ_DURABILITY(wielded) = 0;
            if (GET_OBJ_DURABILITY(wielded) == 0) {
                send_to_char(ch, "\trYou're shocked as %s breaks after that last blow!\tn", GET_OBJ_SHORT(wielded));
                send_to_room(IN_ROOM(ch), "\tr%s is shocked as %s breaks after that last blow!\tn", GET_NAME(ch), GET_OBJ_SHORT(wielded));
                obj_to_char(unequip_char(ch, WEAR_WIELD), ch); }
        }
    }

Now here is one case from the armor wear and tear. I know I've posted one before, but figured this would be for easier to refer to. Not to mention I've changed the if statement to practically match what happens in the weapon checking.
    switch (location) {
        case 1:  // Feet Location
        case 2:
          if ((feetarm) && GET_OBJ_TYPE(feetarm) == ITEM_ARMOR && (GET_OBJ_MAX_DURAB(feetarm) != 0))
              diceroll = rand_number(1, 100);
              if (diceroll <= 10) {
                  send_to_char(ch, "\tRWith that blow, %s has been damaged!\tn\n", GET_OBJ_SHORT(feetarm));
                  GET_OBJ_DURABILITY(feetarm) -= rand_number(1, 6);
                  if (GET_OBJ_DURABILITY(feetarm) < 0)
                      GET_OBJ_DURABILITY(feetarm) = 0;
                  if (GET_OBJ_DURABILITY(feetarm) == 0) {
                      send_to_char(victim, "\trWith that final blow, %s that you were wearing fall apart!\tn\n", GET_OBJ_SHORT(feetarm));
                      send_to_room(IN_ROOM(victim), "\tr%s is less protected as %s falls apart after that last blow!\tn\n", GET_NAME(victim), GET_OBJ_SHORT(feetarm));
                      obj_to_char(unequip_char(victim, WEAR_FEET), victim);
                  }
              }
          break;

I'm sure I'm just missing something simple, but for some reason when your target is not wearing something it still goes right through that if statement as if there was something there.

Please Log in or Create an account to join the conversation.

More
6 years 9 months ago #2360 by thomas
Replied by thomas on topic Item Durability
Where is "feetarm" populated?

Please Log in or Create an account to join the conversation.

  • Papaya Pete
  • Topic Author
  • Offline
  • Gold Boarder
  • Gold Boarder
More
6 years 9 months ago #2363 by Papaya Pete
Replied by Papaya Pete on topic Item Durability
Right at the beginning of the hit function, same place where "wielded" is populated.
struct obj_data *wielded = GET_EQ(ch, WEAR_WIELD);
  struct obj_data *feetarm = GET_EQ(victim, WEAR_FEET);

Please Log in or Create an account to join the conversation.

More
6 years 9 months ago #2368 by thomas
Replied by thomas on topic Item Durability
Are there any possiblity that the item is removed twice? I see the loop is around the hit function, so I'd guess not, but doublecheck :)

Please Log in or Create an account to join the conversation.

  • Vatiken
  • Vatiken's Avatar
  • Offline
  • Administrator
  • Administrator
  • tbaMUD Programmer
More
6 years 9 months ago #2373 by Vatiken
Replied by Vatiken on topic Item Durability
struct obj_data *targ;

/* Item Durability */
if ((targ = GET_EQ(ch, rand_number(0, NUM_WEARS)) != NULL) {
  if (rand_number(1, 10) == 10 && GET_OBJ_TYPE(targ) == ITEM_ARMOR && GET_OBJ_MAX_DURAB(targ)) {
    send_to_char(ch, "\tRWith that blow, %s has been damaged!\tn\n", GET_OBJ_SHORT(targ));
    GET_OBJ_DURABILITY(targ) = MAX(GET_OBJ_DURABILITY(targ) -rand_number(1, 6), 0);
    if (!GET_OBJ_DURABILITY(targ)) {
      send_to_char(victim, "\trWith that final blow, %s that you were wearing fall apart!\tn\n",GET_OBJ_SHORT(targ));
      send_to_room(IN_ROOM(victim), "\tr%s is less protected as %s falls apart after that last blow!\tn\n", GET_NAME(victim), GET_OBJ_SHORT(targ));
      obj_to_char(unequip_char(victim, targ->worn_on), victim);
    }  
  }
}
The first step would be to clean up your code as much as possible. The above snippet should work in replace of the entire switch() as well as some of the other code. The problem with large switches that include the same lines of code over and over again is that: A) more time needed to program, B) more chance of human error and C) more difficult to accurately debug.

tbaMUD developer/programmer
The following user(s) said Thank You: Papaya Pete

Please Log in or Create an account to join the conversation.

  • Papaya Pete
  • Topic Author
  • Offline
  • Gold Boarder
  • Gold Boarder
More
6 years 9 months ago - 6 years 9 months ago #2382 by Papaya Pete
Replied by Papaya Pete on topic Item Durability
Yeah, that did it! Thank you so much. :)

So much simpler too... the switch was pretty huge, and was a pain if I wanted to change something about the code. There was something up with it too, because, before work, I tried just checking one location very simply and there was no crash.

So next week, it's onto trying to get the condition to show when you see it lying in the room or in your inventory/equipment list.

Having a much better idea on how to use gdb now, I might be able to see if I can squash some bug that causes the mud to crash on shutdown. My suspicion is leaning towards one of the snippets I've done in the past... will need to update that.

Edit: which I just did in around a half hour. Yeah... it's an ugly series of if-thens, but better than trying to do a switch and had little choice due to the messages being different. Oh well. It works!

So last step (besides copying all these changes into a txt file) is getting shops to repair damaged items. Should be fun.
Last edit: 6 years 9 months ago by Papaya Pete. Reason: Finished item condition descs.

Please Log in or Create an account to join the conversation.

Time to create page: 0.366 seconds