05-27-2005, 07:36 AM
the Langolier,May 26 2005, 07:40 PM Wrote:Rarity App
I wrote this a little while ago based on Jarulf's guide. Any item it won't calculate can't drop from monsters. It has slightly different results than Jarulf's version, probably due to a slightly different monster distribution we each used.
I also included results for racks (because on some items like Awesome plates it influenced the overall odds significantly) assuming an average appearance of 1 rack per type per game. Since there are 14 levels a rack can appear on it becomes 1/14 chance for a rack per game per level.
If you have any questions about the statistics used by the calculator I will be happy to go into detail.
[right][snapback]78654[/snapback][/right]
OK, Below is my total monster count and it seems I used 185 monster on a level (normal monsters), except on level 1, 2 and 15 were I use 180 (more bosses though typically, it is for multplayer by the way) and level 16 were I use 187. I also include the code for bosses and such (soon I have pasted the whole program here :) ).
Code:
procedure domonsters(dlvl:word; var xprob:real);
var
tprob : real;
mslot : word;
begin
tprob:=0;
for mslot:=0 to mlast do begin
if (mprob[mslot,dlvl]>0) and (not (mslot in [38..41,117])) then begin
tprob:=tprob+onemprob(dlvl,mslot)*mprob[mslot,dlvl]/mprob[totmprobpos,dlvl];
end;
end;
case dlvl of
1 : xprob:=xprob*pot(1-tprob,170);
2 : xprob:=xprob*pot(1-tprob,180);
15 : xprob:=xprob*pot(1-tprob,180);
16 : xprob:=xprob*pot(1-tprob,187);
else
xprob:=xprob*pot(1-tprob,185);
end;
end; { domonsters }
procedure dobosses(dlvl:word; var xprob:real);
var
bslot : word;
blustslot : word;
begin
if dgame then
blustslot:=92
else
blustslot:=93;
for bslot:=(lastspboss+1) to blast do begin
if (dlvl=bdata^[bslot,12]) and (mprob[bdata^[bslot,0],dlvl]>0) then begin
if bslot=blustslot then { Bloodlust }
xprob:=xprob*(1-onebprob(dlvl,bslot))
else
xprob:=xprob*(1-onebprob(dlvl,bslot)*mprob[bdata^[bslot,0],dlvl]/100)
end;
end;
end; { dobosses }
I also include the following to make it more complete:
Code:
procedure dolazroom(var xprob:real);
begin
xprob:=xprob*pot(1-onemprob(15,103),2); { Hell Spawn }
xprob:=xprob*pot(1-onemprob(15,108),4); { Advocate }
xprob:=xprob*(1-onebprob(15,4)); { Lazarus }
xprob:=xprob*(1-onebprob(15,5)); { Red Vex }
xprob:=xprob*(1-onebprob(15,6)); { Black Jade }
end; { dolazroom }
procedure docompletedungeon(var xprob:real; var hdlvl:word);
var
dlvl,tdlvl : word;
tprob,hprob : real;
begin
hprob:=1;
tdlvl:=0;
for dlvl:=1 to lastlevel do begin
tprob:=xprob;
domonsters(dlvl,xprob);
dobosses(dlvl,xprob);
doother(dlvl,xprob);
case dlvl of
2 : xprob:=xprob*(1-onebprob(2,9)); { Butcher }
3 : xprob:=xprob*(1-onebprob(3,1)); { Skeleton King }
15 : dolazroom(xprob);
16 : begin
xprob:=xprob*(1-onemprob(16,110)); { Diablo }
xprob:=xprob*(1-onemprob(16,93)); { Black Knight }
end;
19 : if islot in [154,155] then
xprob:=xprob*(1-onebprob(19,10)); { Hork Demon }
{ ej helt korrekt }
24 : if islot in [124,143,145,150] then
xprob:=xprob*(1-onebprob(24,12)); { Na Krul }
end;
if (xprob/tprob)<hprob then begin
hprob:=xprob/tprob;
tdlvl:=dlvl;
end;
end;
hdlvl:=tdlvl;
end; { docompletedungeon }
procedure docompletemonsters(var xprob:real; var hdlvl:word);
var
dlvl,tdlvl : word;
tprob,hprob : real;
begin
hprob:=1;
tdlvl:=0;
for dlvl:=1 to lastlevel do begin
tprob:=xprob;
domonsters(dlvl,xprob);
case dlvl of
15 : begin
xprob:=xprob*pot(1-onemprob(15,103),2); { Hell Spawn }
xprob:=xprob*pot(1-onemprob(15,108),4); { Advocate }
end;
16 : xprob:=xprob*(1-onemprob(16,93)); { Black Knight }
end;
if (xprob/tprob)<hprob then begin
hprob:=xprob/tprob;
tdlvl:=dlvl;
end;
end;
hdlvl:=tdlvl;
end; { docompletemonsters }
procedure docompletebosses(var xprob:real; var hdlvl:word);
var
dlvl,tdlvl : word;
tprob,hprob : real;
begin
hprob:=1;
tdlvl:=0;
for dlvl:=1 to lastlevel do begin
tprob:=xprob;
dobosses(dlvl,xprob);
case dlvl of
2 : xprob:=xprob*(1-onebprob(2,9)); { Butcher }
3 : xprob:=xprob*(1-onebprob(3,1)); { Skeleton King }
15 : begin
xprob:=xprob*(1-onebprob(15,4)); { Lazarus }
xprob:=xprob*(1-onebprob(15,5)); { Red Vex }
xprob:=xprob*(1-onebprob(15,6)); { Black Jade }
end;
16 : xprob:=xprob*(1-onemprob(16,110)); { Diablo }
end;
if (xprob/tprob)<hprob then begin
hprob:=xprob/tprob;
tdlvl:=dlvl;
end;
end;
hdlvl:=tdlvl;
end; { docompletebosses }
procedure dolazrun(var xprob:real; var hdlvl:word);
var
dlvl,tdlvl : word;
tprob,hprob : real;
begin
hprob:=1;
tdlvl:=0;
for dlvl:=13 to 15 do begin
tprob:=xprob;
dobosses(dlvl,xprob);
case dlvl of
15 : dolazroom(xprob);
end;
if (xprob/tprob)<hprob then begin
hprob:=xprob/tprob;
tdlvl:=dlvl;
end;
end;
hdlvl:=tdlvl;
end; { dolazrun }
procedure docustom(var xprob:real; var hdlvl:word);
var
dlvl : word;
begin
xprob:=xprob*(1-onebprob(15,4)); { Lazarus }
xprob:=xprob*(1-onebprob(15,5)); { Red Vex }
xprob:=xprob*(1-onebprob(15,6)); { Black Jade }
end; { docustom }
The above is different routines for me to be able to calculate different "runs", like a typical Laz run, or full dungeon (game) or just some other specific case.
Below is the main function doing the calls. The "fixfile" is a file with list of specific magic items to do the calculations for, it lists prefix, suffix and base items. The mprob file is just a data file holding the same data for monster probability found in my guide for each level. I believe it is the output of the program that calculated those values which I then inserted into my Guide.
Code:
procedure domagicprob;
var
xprob : real;
many : boolean;
i,j : word;
fslot : word;
istart,iend : word;
hdlvl : word;
ok : boolean;
begin
readmprob(getpath+'mprob.txt');
readfixdata(getpath+'fixfile.txt');
writeheader;
{$IFDEF allrun}
for pslot:=0 to plast do begin
for sslot:=0 to slast do begin
islot:=255;
ok:=true;
{$ELSE}
if flast>0 then begin
for fslot:=1 to flast do begin
pslot:=fdata[fslot].pslot;
sslot:=fdata[fslot].sslot;
islot:=fdata[fslot].islot;
if not dgame then begin
case islot of
83..87 : islot:=islot+4;
88..255 : islot:=islot+5;
end;
end;
if (pslot>plast) or (sslot>slast) or (islot>ilast) then
ok:=false
else
ok:=true;
{$ENDIF}
qlvlp:=pdata^[pslot,16];
qlvls:=sdata^[sslot,16];
write(target,qlvlp:4);
writename(target,pname^[pslot],1,1);
write(target,qlvls:3);
writename(target,sname^[sslot],1,1);
if dgame then
case islot of
152..153 : islot:=151;
155 : islot:=154;
end
else
case islot of
157..158 : islot:=156;
160 : islot:=159;
end;
if islot=255 then begin
istart:=startbitem;
iend:=ilast; end
else begin
istart:=islot;
iend:=istart;
end;
many:=false;
for islot:=istart to iend do begin
if prefixpossible(islot,pslot) and suffixpossible(islot,sslot) and ok then begin
if many then
write(target,'':61);
qlvli:=idata^[islot,24];
write(target,qlvli:2);
writename(target,iname1^[islot],1,1);
writeln(pname^[pslot]:25,sname^[sslot]:25,iname1^[islot]:25);
many:=true;
for run:=0 to lastrun do begin
if runs[run]=1 then begin
for diff:=0 to 2 do begin
xprob:=1;
case run of
0 : docustom(xprob,hdlvl);
1 : docompletedungeon(xprob,hdlvl);
2 : docompletemonsters(xprob,hdlvl);
3 : docompletebosses(xprob,hdlvl);
4 : dolazrun(xprob,hdlvl);
end;
writexprob(target,xprob,10);
if hdlvl<>0 then
writedlvl(target,hdlvl,3)
else
write(target,' -');
end;
write(target,' ');
end;
end;
writeln(target);
end;
end;
end;
end;
end; { domagicprob }
Below are some utility functions called in various places in code posted so far:
Code:
procedure readmprob(filename:string);
var
mprobfile : text;
mprobdata : real;
dlvl,mslot : word;
begin
assign(mprobfile,filename);
reset(mprobfile);
for dlvl:=1 to lastlevel do begin
mprob[totmprobpos,dlvl]:=0;
for mslot:=0 to (totmprobpos-1) do begin
read(mprobfile,mprobdata);
mprob[mslot,dlvl]:=round(mprobdata);
mprob[totmprobpos,dlvl]:=mprob[totmprobpos,dlvl]+mprob[mslot,dlvl];
end;
readln(mprobfile);
end;
close(mprobfile);
end; { readmprob }
function prefixpossible(islot,pslot:word):boolean;
var
ok : boolean;
begin
ok:=false;
case idata^[islot,12] of
12,13 : ok:=pdata^[pslot,20] and 1<>0; { jewlery }
3 : ok:=pdata^[pslot,20] and 16<>0; { bow }
10 : ok:=pdata^[pslot,21] and 1<>0; { staff }
1,2,4 : ok:=pdata^[pslot,21] and 16<>0; { weapon }
5 : ok:=pdata^[pslot,22] and 1<>0; { shield }
6,7,8,9 : ok:=pdata^[pslot,22] and 16<>0; { armor }
end;
prefixpossible:=ok;
end; { prefixpossible }
function suffixpossible(islot,sslot:word):boolean;
var
ok : boolean;
begin
ok:=false;
case idata^[islot,12] of
12,13 : ok:=sdata^[sslot,20] and 1<>0; { jewlery }
3 : ok:=sdata^[sslot,20] and 16<>0; { bow }
10 : ok:=sdata^[sslot,21] and 1<>0; { staff }
1,2,4 : ok:=sdata^[sslot,21] and 16<>0; { weapon }
5 : ok:=sdata^[sslot,22] and 1<>0; { shield }
6,7,8,9 : ok:=sdata^[sslot,22] and 16<>0; { armor }
end;
suffixpossible:=ok;
end; { suffixpossible }
function pcursed(pslot:word):boolean;
begin
pcursed:=pdata^[pslot,32]=0;
end; { pcursed }
function scursed(sslot:word):boolean;
begin
scursed:=sdata^[sslot,32]=0;
end; { scursed }
function ipossiblemonster(lvl:word):word;
var
i : word;
possible : word;
begin
possible:=0;
for i:=startbitem to ilast do begin
if lvl>=idata^[i,24] then
possible:=possible+idata^[i,0];
end;
ipossiblemonster:=possible;
end; { ipossiblemonster }
function ipossibleboss(lvl:word):word;
var
i : word;
possible : word;
begin
possible:=0;
for i:=startbitem to ilast do begin
if (lvl>=idata^[i,24]) and (idata^[i,0]>0) and (idata^[i,56] in [0,23..26]) then
inc(possible);
end;
ipossibleboss:=possible;
end; { ipossibleboss }
function ipossibleother(lvl:word):word;
var
i : word;
possible : word;
begin
possible:=0;
for i:=startbitem to ilast do begin
if (lvl>=idata^[i,24]) and (idata^[i,0]>0) then
inc(possible);
end;
ipossibleother:=possible;
end; { ipossibleother }
function jpossible(lvl,islot:word):word;
var
i : word;
possible : word;
begin
possible:=0;
for i:=151 to 160 do begin
if ((idata^[islot,56])=(idata^[i,56])) and (lvl>=idata^[i,24]) then
inc(possible);
end;
jpossible:=possible;
end; { jpossible }
function ppossible(lvl,islot:word;curseok:boolean):real;
var
i : word;
possible : real;
begin
possible:=0;
for i:=0 to plast do begin
if (lvl>=pdata^[i,16]) and ((lvl div 2)<=pdata^[i,16]) and prefixpossible(islot,i) then begin
if pdata^[i,32]=1 then
possible:=possible+1
else
if curseok then
possible:=possible+1/3;
end;
end;
ppossible:=possible;
end; { ppossible }
function spossible(lvl,islot:word;curseok:boolean):real;
var
i : word;
possible : real;
begin
possible:=0;
for i:=0 to slast do begin
if (lvl>=sdata^[i,16]) and ((lvl div 2)<=sdata^[i,16]) and suffixpossible(islot,i) then begin
if sdata^[i,32]=1 then
possible:=possible+1
else
if curseok then
possible:=possible+1/3;
end;
end;
spossible:=possible;
end; { spossible }
function irange(islot:word):word;
begin
case islot of
48..76 : irange:=idata^[islot,44]-idata^[islot,40]+1; { AC }
else
irange:=1;
end;
end; { irange }
function prange(pslot:word):word;
begin
case pslot of
0..23 : prange:=pdata^[pslot,12]-pdata^[pslot,8]+1; { range }
24 : prange:=26*(pdata^[pslot,12]-pdata^[pslot,8]+1); { king's serie }
25 : prange:=21*(pdata^[pslot,12]-pdata^[pslot,8]+1); { king's serie }
26 : prange:=16*(pdata^[pslot,12]-pdata^[pslot,8]+1); { king's serie }
27 : prange:=15*(pdata^[pslot,12]-pdata^[pslot,8]+1); { king's serie }
28 : prange:=15*(pdata^[pslot,12]-pdata^[pslot,8]+1); { king's serie }
29 : prange:=15*(pdata^[pslot,12]-pdata^[pslot,8]+1); { king's serie }
30 : prange:=15*(pdata^[pslot,12]-pdata^[pslot,8]+1); { king's serie }
31 : prange:=15*(pdata^[pslot,12]-pdata^[pslot,8]+1); { king's serie }
32 : prange:=15*(pdata^[pslot,12]-pdata^[pslot,8]+1); { king's serie }
33 : prange:=25*(pdata^[pslot,12]-pdata^[pslot,8]+1); { king's serie }
34 : prange:=25*(pdata^[pslot,12]-pdata^[pslot,8]+1); { king's serie }
35..80 : prange:=pdata^[pslot,12]-pdata^[pslot,8]+1; { range }
81..82 : prange:=1; { F/L damage }
84 : prange:=pdata^[pslot,12]-pdata^[pslot,8]+1; { range }
85 : prange:=15*(pdata^[pslot,12]-pdata^[pslot,8]+1); { Doppel kolla }
else
prange:=1;
end;
end; { prange }
function srange(sslot:word):word;
begin
case sslot of
0..67 : srange:=sdata^[sslot,12]-sdata^[sslot,8]+1; { range }
68..73 : srange:=1; { F/L damage }
74..75 : srange:=sdata^[sslot,12]-sdata^[sslot,8]+1; { range }
76 : srange:=1; { thorns }
77..97 : srange:=sdata^[sslot,12]-sdata^[sslot,8]+1; { range }
else
srange:=1;
end;
end; { srange }
I believ now that I have posted about everything as far as the calculations goes. I still have not been home so I can upload the actual file to my website.
There are three types of people in the world. Those who can count and those who can't.