Item & Monster Specs

Any developer realated stuff
Maven
Posts: 138
Joined: Sat Apr 16, 2011 9:39 pm

Post by Maven »

ZeroZero, I'm looking at how the character creation does attributes, and it doesn't look like a simple random function. Did you have a disassembled event for character creation?

Did you find a new place to host the disassemblies? I noticed Desmet Irkm had one that I couldn't find here. It has been decades since I've done much 6502 assembly code, but it should be easier than trying to guess a function to fit the results I'm seeing.
Maven
Posts: 138
Joined: Sat Apr 16, 2011 9:39 pm

Post by Maven »

So here's what I got from the nm1b.asm:

Code: Select all

b6fb:00fd:1   20 2a 08 mk_attr  jsr $082a             ; create RND
b6fe:0100:1   a6 71             ldx $71               ; get back offset
b700:0102:1   a5 5a             lda $5a               ; get RND lo byte
b702:0104:1   29 07             and #$07              ; only bits 0, 1, 2
b704:0106:1   18                clc 
b705:0107:1   7d 53 a2          adc $a253,x           ; add the base value to RND
b708:010a:1   c9 13             cmp #$13              ; is 19?
b70a:010c:1   90 02             bcc val_ok            ; if smaller, ok
b70c:010e:1   a9 12             lda #$12              ; else set maximum of 18
b70e:0110:1   99 49 a2 val_ok   sta $a249,y           ; store into attrib packing buffer
b71
What is this $a253 table? I'm guessing the lower limits on attributes for each race. Where can I find the actual numbers?

This would seem to give a pretty even distribution on attributes with a hugely lopsided tendency to give 18's. That's not what I'm seeing. Hmmm. Maybe I'll have to download a C64 Emulator and see what actual attributes it tends to give on character create.
User avatar
ZeroZero
Posts: 286
Joined: Tue Mar 10, 2009 9:10 pm
Location: Germany

Post by ZeroZero »

I updated the roster file format in the sticky:

Code: Select all

--------------------------------------------------------------
3) in guild event used table for attrib creation
--------------------------------------------------------------
Basic values per RACE for attributes
Five values per race, indexed by race value

a253  0A 06 08 08 05 08 09 09 
a25b  06 06 0C 06 07 0A 03 04 
a263  06 0C 05 0A 09 08 09 07 
a26b  06 0B 03 08 0B 04 09 0A 
a273  07 03 04 
As you can see, for a HUMAN e.g. the minimum attrib values are:
ST 10, IQ 6, DX 8, CN 8, LK 5
and maximums (bits 0-2 of RND)
ST 17, IQ 13, DX 15, CN 15, LK 12

These can be increased in review board.
Maven
Posts: 138
Joined: Sat Apr 16, 2011 9:39 pm

Post by Maven »

Thanks, ZeroZero. That's exactly what I was looking for.

But that would give us a pretty even distribution across the ranges, with double the possibility of 18 for Dwarf Strength and Hobbit Dex.

That's not what I'm seeing on my MSDOS game. I'm getting a lot more numbers toward the top of the range, and very few on the bottom of the range.

Hmmmm. More testing needed...
User avatar
ZeroZero
Posts: 286
Joined: Tue Mar 10, 2009 9:10 pm
Location: Germany

Post by ZeroZero »

Well you have the full disasembled source code.

But I have a hint for you, why the distribution is not like you expect ;-):

The random number generator does NOT work using whole integers,
but the lower 3 bits of any number rolled....

Does a bell ring?

(And again: I ONLY had a look into the C64 version, there are dramatic
differences in every single aspect of the game in other versions, even in
character value creation, e.g. in initial HP and SP. I could also imagine,
that on the DOS version a different base value table is used or the
RND uses the whole integer value.)
Maven
Posts: 138
Joined: Sat Apr 16, 2011 9:39 pm

Post by Maven »

Trying to guess more information about item effects, I made a list of all the items with effects, sorted by the byte in the item table. I can't figure out what the high order bit might mean.

Code: Select all

01 Troll Ring      HP Regen
01 Troll Staff     HP Regen
02 Mage Staff      Regen Magic
04 Conjurstaff     Spells use half magic
05 Bardsword       Unlimited Songs
05 Lak's Lyre      Unlimited Songs
06 Luckshield      
07 Speedboots      
08 Theif Dagger    
09 Crystal Sword   Needed for the fight with the Crystal Golem
0a Eye             Brings the Mad God to life
0b Silvr Square    Needed on Mangar's Level
0c Silvr Circle    Needed on Mangar's Level
0d Silvr Triang    Needed on Mangar's Level
0e Onyx Key        Needed to enter Mangar's Domain
0f Master Key      Used to get past gates in town

90 Lightwand       Light - Range 2 - Does not detect secret doors
90 Dayblade        Light - Range 2 - Does not detect secret doors
91 Heal Harp       Heal 2-8 damage
12 Powerstaff      Burns one group for 4-16 Damage
93 Galt's Flute    Summons Wolf
94 Pipes of Pan    Casts Light of some type
95 Ogrewand        Summons Ogre
96 Broom           Levitation
96 Ali's Carpet    Levitation
97 Pureblade       Flesh Anew
98 Travelhelm      Teleport
19 Dag Stone       Light - Range 3 - Does not detect secret doors
1a Sorcerstaff     Disrupt Illusion
1a Truthdrum       Disrupt Illusion
1b Ring of Power   Burns one group for 10-40 Damage
9c Lorehelm        Casts Sorceror Sight
9c Arc's Eye       Sorceror Sight
9d Kiels Compass   Casts Scry Site
9e Magic Mouth     Area Enchant spell (Detects stairs)
9f Arcshield       Fries one group for 6-24 Damage

a0 Arc's Hammer    Casts light of some type
a2 Ybarrashield    Ybarra's Mystical Coat of Armor
a3 Staff of Lor    Restoration
a4 Exorwand        Disposess
a5 Sword of Pak    Summons Lesser Demon
a5 Spiritdrum      Summons Lesser Demon
a5 Spirithelm      Summons Lessor Demon
a6 WizWand         Summons Demon
a7 Deathring       Animate Dead
28 Spectre Snare   Spell Bind
2b Fire Horn       Burns one group for 16-64 Damage
2c Dragonwand      Steams one group for 20-80 Damage
2d Frost Horn      Freezes one group for 24-96 Damage
2d Dragonshield    Freezes one group for 24-96 Damage
2f Flame Horn      Fries one group for 40-160 Damage

b0 Torch           
b1 Lamp            
b2 Dragon Fgn      
b3 Giant Fgn       
b4 Ogre Fgn        
b5 Mongo Fgn       
b7 Old Man Fgn     
39 Thor Fgn        
ba Mage Fgn        
bb Lich Fgn        
bc Samurai Fgn     
bd Titan Fgn       
be Golem Fgn       
Looks like the Thor Fgn is an anomaly. Which might be a good thing. He isn't in the monster table. I summoned a Thor, and I was glad he was on my side! He has LO armor class and lots of hit points, and does lots of damage. Which is sorta irrelevant because he critical hits very round.
Caracas
Posts: 89
Joined: Thu Jan 20, 2011 9:16 am
Location: Belgium

Post by Caracas »

I had been looking at that as well.
First I thought that if the high order bit was set, the item didn't have to be equiped in order to use it.
quick tests showed that this is not the case.
It might be that it has no meaning at all. Maybe it is something left over from other versions.
drifting
Posts: 153
Joined: Wed Dec 07, 2011 10:21 pm

Post by drifting »

I believe B0 and above is single-use item.
The check for single use items is:

Code: Select all

if ((effect & 0x7f) >= 0x30)
  single_use = true;
The Thor figurine is an example of an item effect below 0xB0 that is a single use item.
I can't figure out what the high order bit might mean.
The high bit is not used in the DOS version. The effect is AND'd with 0x7f immediately after access which strips the high bit.

Item values

Code: Select all

seg019:41A8 itemPriceList   db 0, 28h, 78h, 41h, 19h, 11h, 39h, 12h; 0
seg019:41A8                                         ; DATA XREF: garth_getItemValue
seg019:41A8                 db 31h, 11h, 21h, 0Ah, 39h, 79h, 1Ah, 3Ah; 8
seg019:41A8                 db 21h, 29h, 41h, 21h, 69h, 69h, 69h, 1Ah; 16
seg019:41A8                 db 22h, 2Ah, 4Ah, 2Ah, 32h, 3Ah, 62h, 0Bh; 24
seg019:41A8                 db 12h, 1Ah, 22h, 1Ah, 1Ah, 13h, 1Ah, 0Bh; 32
seg019:41A8                 db 3Ah, 0Ah, 6Ah, 32h, 3Ah, 22h, 0Bh, 2Ah; 40
seg019:41A8                 db 32h, 2Ah, 2Ah, 1Ah, 22h, 2Ah, 22h, 32h; 48
seg019:41A8                 db 32h, 0Bh, 42h, 62h, 42h, 22h, 42h, 62h; 56
seg019:41A8                 db 82h, 0Bh, 13h, 13h, 2Bh, 33h, 5Ah, 7Ah; 64
seg019:41A8                 db 23h, 43h, 1Bh, 3Bh, 0Ch, 63h, 62h, 0Bh; 72
seg019:41A8                 db 42h, 5Ah, 1Ah, 32h, 43h, 23h, 4Bh, 63h; 80
seg019:41A8                 db 23h, 7Bh, 23h, 1Bh, 43h, 73h, 33h, 13h; 88
seg019:41A8                 db 14h, 14h, 1Ch, 1Ch, 24h, 34h, 0Ch, 14h; 96
seg019:41A8                 db 0Ch, 0Ch, 1Ch, 2Ch, 42h, 0Bh, 44h, 0Dh; 104
seg019:41A8                 db 0Dh, 2Ah, 3Ch, 0Ch, 34h, 0Bh, 62h, 2Ch; 112
seg019:41A8                 db 62h, 64h, 0Bh, 0Bh, 0Bh, 13h, 7Ah, 15h; 120
This is the table used to get item values for Garth. The data is packed in scientific notation. The low three bits are the exponent. The high five bits are the multiplier. Note that this array starts at one instead of zero. So the Torch's value is 0x28.

To convert to a real value:

Code: Select all

static uint32_t getValue(uint8_t v)
{
  uint8_t i;
  uint32_t rval = 1;
  
  i = v & 7;
  while (i--) rval *= 10;
  
  return (rval * (v >> 3));
}
Determining items drop at what level
This is based entirely on where you are. The "monster level for random encounters" for the current level you are on is used to determine what can drop. There are two arrays that are use to determine which item to drop (and also what type of monster to fight. The algorithm is the same.)

Code: Select all

seg019:1F8E monsterRandomMask db 15,15,31,31,31,31,31,31; 0
seg019:1F9E monsterLevelOffset db 0,8,8,16,32,48,64,81 ; 0

The code to get the random item is like this:
newItemNumber = (random() & monsterRandomMask[monsterLevel]) + monsterLevelOffset[monsterLevel]
if (newItemNumber == 0)
  newItemNumber = 1
For example, the first level of the Castle has a monster level of 3. So the monsterRandomMask would be 31 and the monsterLevelOffset is 16. So that level would drop items with an index between 16 and 47.
drifting
Posts: 153
Joined: Wed Dec 07, 2011 10:21 pm

Post by drifting »

Determining Character Attack Priority

Code: Select all

charPriority = char.battlesWon >> 9;

if (char.dexterity > 14) 
  charPriority += (char.dexterity - 14) << 3;

charPriority += random() & 0x1f;

switch (char.class) {
  case magician:
  case conjurer:
  case sorcerer:
  case wizard:
    charPriority += (char.level >> 3);
    break;
  case bard:
  case rogue:
    charPriority += (char.level >> 2);
    break;
  case monk:
    charPriority += char.level;
    break;
  default:
    charPriority += (char.level >> 1);
    break;
}

if (charPriority == 0)
  charPriority = 1;
if (charPriority > 0xff)
  charPriority = 0xff;
  • char.battlesWon is at 0x58 of the character file. It is incremented every time a battle is won.
Determining Monster Attack Priority

Code: Select all

This is the table used to determine monster priority

seg019:1B42 monPriorityList     db 0,0,0,1,1,1,1,0,0,2,2,2,2,1,3,2,3,4,3,3,4,2,2,2,2,4; 0
seg019:1B42                                         ; DATA XREF: bat_getMonMeleeSuccess+54r
seg019:1B42                                         ; bat_getMonMeleeSuccess+A9r ...
seg019:1B42                 db 24h,3,4,5,84h,4,5,5,4,4,4,4,4,6,26h,7,6,8,7,7,7,8,7; 26
seg019:1B42                 db 7,8,88h,6,6,6,6,0Ah,9,9,0Ah,6Ah,0Ah,0Bh,0Bh,0Dh,6Bh; 49
seg019:1B42                 db 0Bh,8,8,8,8,0Bh,0Ch,2Bh,0Ch,0ABh,0Ch,4Dh,8Eh,0Ch,0Ah; 66
seg019:1B42                 db 0Ah,0Ah,0Ah,0EEh,0Fh,0Fh,0Eh,90h,11h,0D0h,30h,10h,12h; 81
seg019:1B42                 db 53h,74h,13h,13h,14h,14h,10h,17h,16h,10h,10h,10h,13h; 94
seg019:1B42                 db 56h,18h,36h,59h,0BBh,12h,15h,15h,15h,18h,1Ah,0F8h,1Ch; 107
seg019:1B42                 db 1Ch,1Eh,9Dh,75h,0B7h,15h,0DFh,0FFh; 120

It is used to determine individual monster priority like this:

monPriorityBase = (monPriorityList[monType] & 0x1f) << 2;

individualPriority = monPriorityBase + (random() & 0x1f);

if (individualPriority > 0xff)
  individualPriority = 0xff;
The monPriorityList is also used for:
  • Determining the monster's to-hit range.
  • Determining the monster's damage dice and special attack
  • Determining whether the monster group will advance.
Last edited by drifting on Wed Jan 04, 2012 10:25 pm, edited 1 time in total.
Maven
Posts: 138
Joined: Sat Apr 16, 2011 9:39 pm

Post by Maven »

Well, look at that! I have been wondering about those things since... forever. Thank you for posting these things and clearing up these mysteries.

So now I can go check and make sure I got the item costs correct. And I can build a better (more accurate) table of what drops where. I'm assuming the town has a monster level of 0, and at night it gets bumped up to 1? Yes, I see that matches what I have experienced.

That bit about monster attack priority is most interesting. So no wonder my Monk always seems to hit first. But the Dex has a HUGE impact, and the number of battles won is also a factor, but only after 512 battles. Wow. That has implications.

This is great stuff!
Caracas
Posts: 89
Joined: Thu Jan 20, 2011 9:16 am
Location: Belgium

Post by Caracas »

That is awesome stuff! where did you get that?

So for calculating the prices, I assume you have to do the following:

Code: Select all

28h 00101000 5*10^0=5
78h 01111000 15*10^0=15
41h 01000001 8*10^1=80
19h 00011001 3*10^1=30
11h 00010001 2*10^1=20
39h 00111001 7*10^1=70
12h 00010010 2*10^2=200
...
Interesting to know that the maximum price of an item can be 310 million gold :)
Caracas
Posts: 89
Joined: Thu Jan 20, 2011 9:16 am
Location: Belgium

Post by Caracas »

A question about monks:
on the first page of this thread, Maven gave an overview of the items and the damage that weapons do. Is there any data on the damage that monks do with no weapons equiped (i.e. dice rols) and how this increases when they level up?
I understand how their DEX increases their chance to hit, but I would like to know what damage levels they do.
drifting
Posts: 153
Joined: Wed Dec 07, 2011 10:21 pm

Post by drifting »

Caracas wrote:A question about monks:
on the first page of this thread, Maven gave an overview of the items and the damage that weapons do. Is there any data on the damage that monks do with no weapons equiped (i.e. dice rols) and how this increases when they level up?
I understand how their DEX increases their chance to hit, but I would like to know what damage levels they do.

Code: Select all

seg019:2512 monkDamageList  db 0,1,2,3,4,23h,23h,24h,24h,25h,25h,25h,25h,26h,26h,26h; 0
seg019:2512                                         ; DATA XREF: bat_getCharMeleeSuccess+165r
seg019:2512                 db 44h,44h,44h,44h,45h,45h,45h,45h,63h,63h,63h,64h,64h; 16
seg019:2512                 db 64h,65h,66h,0,0      ; 29

damageDice = monkDamageList[char.level >> 1];
For damageDice, the low 5 bits are the number of dice to roll. The high three bits are an index into this array:

Code: Select all

seg019:250A meleeDiceMask   db 3,7,15,31,63,127,255,1; 0

So to translate into XdY, you do:
X = (damageDice & 0x1f) + 1;
Y = meleeDiceMask[damageDice >> 5] + 1;
So, for example, a level 29 monk:
damageDice = 0x26;
X = 7
Y = 8
So the damage would be 7d8 per attack
drifting
Posts: 153
Joined: Wed Dec 07, 2011 10:21 pm

Post by drifting »

Found something interesting while looking in to the monster to-hit code. The Word of Fear and Curse spells actually increase the monster's ability to hit. It's easy to verify.

Take a wizard into the city alone and enter a battle. Cast MIMI until the AC is L0. All of the monsters in the city should miss every time with an AC of L0. Now start casting CURS each round. After a few rounds the monsters will start hitting you.

This is on the DOS version. Does this happen on any of the other versions?
Maven
Posts: 138
Joined: Sat Apr 16, 2011 9:39 pm

Post by Maven »

More interesting stuff...

I did the test on the FEAR spell. I ran around until I found 8 Kobolds, and made sure my AC was LO. Then I started casting FEAR spells and watching how much I got hit. I needed 4 FEAR spells before they started hitting sometimes, and 18 FEAR spells before they were hitting every time. Maybe I'm off one or two, though, because that doesn't seem right.

You're right. It definitely HELPS the enemy to cast FEAR.


The information about attack priority was fascinating to me. I had noticed that my Monk was always the first one in my party to attack, and even faster than some of the high level monsters, as he got up there in levels. I wondered if it was because he was a Monk or a Hobbit, or both. Now I know! It also means there's an upper cap to the attack priority on enemies, and even Mangar and Demon Lords and Old Men can be beaten. The upper cap is 155. So all I have to do is get my attack priority up to 156, and I'll beat them every time. The formula shows that the way to do that is to win more than 63488 battles, and even a level 1 Wizard will beat them every time.

So I created a new party and fired up my keystroke recorder program. Since I want to win lots of battles, it seemed optimal to fight small groups at a time. I started on the Samurai Statue, and as soon as I got the Wind Giant spell, I moved up to Stone Giants and Golems. It was fascinating to watch as my Monk slowly started to attacker faster than my Storm Giant. Eventually, I upgraded to a Demon Lord to watch as my Monk started even beating him. I'm at the point now where even my Bard beats the Storm Giant sometimes, but my magic users are still way behind.

One thing I noticed doing this test is the drops. There seem to be a couple of screwy things with the drops when only fighting one monster at a time. When fighting statues, the game seems to pick two items and drop them over and over. Halbards and Plate Armor, for example. If I restart the game, it picks two other items and drops them over and over. Scale Armor and War Axes, or Torches and Maces. Even stranger--at night, when I don't usually get drops of items whose Index is less than 8, I can get Torches, Halbards, and War Axes.

When I started fighting the Stone Golems in the first level of the Castle, it would pick 4 items. Leather Glvs, Mthr Scale, Mthr Gloves, Fin's Flute, for example. The item indices were always 8 apart. If I wanted another item to drop, I could leave the game and restart, and it would pick 4 other items.

Oh, and it seems the same party member always gets the drops. Until his inventory is full.
Post Reply