*Fixes the gaussian PRNG

*Fixes a minor mistake in num2hex
*Fixes a bad call to num2hex which was causing data_core records to all have an ID of "000000". Fixes #583
*Rebalances dna modification to match the PRNG fixes.
*Fixes cloning computer not copying b_type to data disks

DNA modifier features:
*Probability indicators for emitter settings
*Info on last pulse operation
*Cannot operate on dead subjects
*UE/UI/SE spaced out more

Modified   code/__HELPERS/maths.dm
Modified   code/__HELPERS/type2type.dm
Modified   code/__HELPERS/unsorted.dm
Modified   code/datums/datacore.dm
Modified   code/game/dna.dm
Modified   code/game/machinery/computer/cloning.dm
Modified   code/game/machinery/computer/security.dm
This commit is contained in:
carnie
2013-05-23 12:05:04 +01:00
parent ae69fb4351
commit 52e2efdb7f
7 changed files with 59 additions and 43 deletions

View File

@@ -114,6 +114,9 @@ var/const/Sqrt2 = 1.41421356
//since this method produces two random numbers, one is saved for subsequent calls //since this method produces two random numbers, one is saved for subsequent calls
//(making the cost negligble for every second call) //(making the cost negligble for every second call)
//This will return +/- decimals, situated about mean with standard deviation stddev //This will return +/- decimals, situated about mean with standard deviation stddev
//68% chance that the number is within 1stddev
//95% chance that the number is within 2stddev
//98% chance that the number is within 3stddev...etc
var/gaussian_next var/gaussian_next
#define ACCURACY 10000 #define ACCURACY 10000
/proc/gaussian(mean, stddev) /proc/gaussian(mean, stddev)
@@ -126,9 +129,9 @@ var/gaussian_next
R1 = rand(-ACCURACY,ACCURACY)/ACCURACY R1 = rand(-ACCURACY,ACCURACY)/ACCURACY
R2 = rand(-ACCURACY,ACCURACY)/ACCURACY R2 = rand(-ACCURACY,ACCURACY)/ACCURACY
working = R1*R1 + R2*R2 working = R1*R1 + R2*R2
while(working >= 1) while(working >= 1 || working==0)
working = sqrt(-2 * log(working) / working)
R1 *= working R1 *= working
R2 *= working gaussian_next = R2 * working
gaussian_next = R2
return (mean + stddev * R1) return (mean + stddev * R1)
#undef ACCURACY #undef ACCURACY

View File

@@ -38,6 +38,7 @@
//if len < 0 then the returned string will be as long as it needs to be to contain the data //if len < 0 then the returned string will be as long as it needs to be to contain the data
//Only supports positive numbers //Only supports positive numbers
//if an invalid number is provided, it assumes num==0 //if an invalid number is provided, it assumes num==0
//Note, unlike previous versions, this one works from low to high <-- that way
/proc/num2hex(num, len=2) /proc/num2hex(num, len=2)
if(!isnum(num)) if(!isnum(num))
num = 0 num = 0
@@ -45,7 +46,7 @@
. = "" . = ""
var/i=0 var/i=0
while(1) while(1)
if(len<0) if(len<=0)
if(!num) break if(!num) break
else else
if(i>=len) break if(i>=len) break

View File

@@ -20,15 +20,9 @@
var/r = hex2num(textr) var/r = hex2num(textr)
var/g = hex2num(textg) var/g = hex2num(textg)
var/b = hex2num(textb) var/b = hex2num(textb)
textr = num2hex(255 - r) textr = num2hex(255 - r, 2)
textg = num2hex(255 - g) textg = num2hex(255 - g, 2)
textb = num2hex(255 - b) textb = num2hex(255 - b, 2)
if (length(textr) < 2)
textr = text("0[]", textr)
if (length(textg) < 2)
textr = text("0[]", textg)
if (length(textb) < 2)
textr = text("0[]", textb)
return text("#[][][]", textr, textg, textb) return text("#[][][]", textr, textg, textb)
return return

View File

@@ -30,7 +30,7 @@
else else
assignment = "Unassigned" assignment = "Unassigned"
var/id = add_zero(num2hex(rand(1, 1.6777215E7)), 6) //this was the best they could come up with? A large random number? *sigh* var/id = num2hex(rand(1, 1.6777215E7),6) //this was the best they could come up with? A large random number? *sigh*
//General Record //General Record
var/datum/data/record/G = new() var/datum/data/record/G = new()

View File

@@ -4,12 +4,10 @@
#define NUMBER_OF_BUFFERS 3 #define NUMBER_OF_BUFFERS 3
#define RADIATION_STRENGTH_MAX 15 #define RADIATION_STRENGTH_MAX 15
#define RADIATION_STRENGTH_MULTIPLIER 5 //larger has a more range #define RADIATION_STRENGTH_MULTIPLIER 1 //larger has a more range
#define RADIATION_STRENGTH_BIAS 0 //skews the randomisation based on radstrength*num
#define RADIATION_DURATION_MAX 30 #define RADIATION_DURATION_MAX 30
#define RADIATION_ACCURACY_MULTIPLIER 12 //larger is less accurate #define RADIATION_ACCURACY_MULTIPLIER 4 //larger is less accurate
#define RADIATION_ACCURACY_BIAS 0 //skews the randomisation based on radduration*num
#define RADIATION_IRRADIATION_MULTIPLIER 0.3 //multiplier for how much radiation a test subject recieves #define RADIATION_IRRADIATION_MULTIPLIER 0.3 //multiplier for how much radiation a test subject recieves
@@ -140,26 +138,21 @@
/proc/getblock(input, blocknumber, blocksize=DNA_BLOCK_SIZE) /proc/getblock(input, blocknumber, blocksize=DNA_BLOCK_SIZE)
return copytext(input, blocksize*(blocknumber-1)+1, (blocksize*blocknumber)+1) return copytext(input, blocksize*(blocknumber-1)+1, (blocksize*blocknumber)+1)
/*
/proc/getblockbuffer(input,blocknumber,blocksize)
var/result[blocksize]
var/start = (blocksize*blocknumber)-blocksize
for(var/i=1, i<=blocksize, i++)
result[i] = copytext(input, start+i, start+i+1)
return result
*/
/proc/setblock(istring, blocknumber, replacement, blocksize=DNA_BLOCK_SIZE) /proc/setblock(istring, blocknumber, replacement, blocksize=DNA_BLOCK_SIZE)
if(!istring || !blocknumber || !replacement || !blocksize) return 0 if(!istring || !blocknumber || !replacement || !blocksize) return 0
return getleftblocks(istring, blocknumber, blocksize) + replacement + getrightblocks(istring, blocknumber, blocksize) return getleftblocks(istring, blocknumber, blocksize) + replacement + getrightblocks(istring, blocknumber, blocksize)
/proc/scramble(input,rs,rd) /proc/scramble(input,rs,rd)
var/length = length(input) var/length = length(input)
var/num = hex2num(input) var/ran = gaussian(0, rs*RADIATION_STRENGTH_MULTIPLIER)
num = round(num + gaussian(rs*RADIATION_STRENGTH_BIAS, rs*RADIATION_STRENGTH_MULTIPLIER), 1) if(ran == 0) ran = pick(-1,1) //hacky, statistically should almost never happen. 0-change makes people mad though
return num2hex(Wrap(num, 0, 16**length), length) else if(ran < 0) ran = round(ran) //negative, so floor it
else ran = -round(-ran) //positive, so ceiling it
return num2hex(Wrap(hex2num(input)+ran, 0, 16**length), length)
/proc/randomize_radiation_accuracy(position_we_were_supposed_to_hit, radduration, number_of_blocks) /proc/randomize_radiation_accuracy(position_we_were_supposed_to_hit, radduration, number_of_blocks)
return Wrap(round(position_we_were_supposed_to_hit + gaussian(radduration*RADIATION_ACCURACY_BIAS, RADIATION_ACCURACY_MULTIPLIER/radduration), 1), 1, number_of_blocks+1) return Wrap(round(position_we_were_supposed_to_hit + gaussian(0, RADIATION_ACCURACY_MULTIPLIER/radduration), 1), 1, number_of_blocks+1)
/proc/randmutb(mob/living/carbon/M) /proc/randmutb(mob/living/carbon/M)
if(!check_dna_integrity(M)) return if(!check_dna_integrity(M)) return
@@ -710,7 +703,7 @@
return return
/obj/machinery/computer/scan_consolenew/attackby(obj/item/W as obj, mob/user as mob) /obj/machinery/computer/scan_consolenew/attackby(obj/item/W as obj, mob/user as mob)
if((istype(W, /obj/item/weapon/disk/data)) && (!diskette)) if(istype(W, /obj/item/weapon/disk/data) && !diskette)
user.drop_item() user.drop_item()
W.loc = src W.loc = src
diskette = W diskette = W
@@ -728,9 +721,9 @@
return return
ShowInterface(user) ShowInterface(user)
/obj/machinery/computer/scan_consolenew/proc/ShowInterface(mob/user) /obj/machinery/computer/scan_consolenew/proc/ShowInterface(mob/user, last_change)
if(!user) return if(!user) return
var/datum/browser/popup = new(user, "scannernew", "DNA Modifier Console", 880, 450) // Set up the popup browser window var/datum/browser/popup = new(user, "scannernew", "DNA Modifier Console", 880, 470) // Set up the popup browser window
popup.add_stylesheet("scannernew", 'html/browser/scannernew.css') popup.add_stylesheet("scannernew", 'html/browser/scannernew.css')
var/mob/living/carbon/viable_occupant var/mob/living/carbon/viable_occupant
@@ -744,12 +737,13 @@
switch(viable_occupant.stat) switch(viable_occupant.stat)
if(CONSCIOUS) occupant_status = "<span class='good'>Conscious</span>" if(CONSCIOUS) occupant_status = "<span class='good'>Conscious</span>"
if(UNCONSCIOUS) occupant_status = "<span class='average'>Unconscious</span>" if(UNCONSCIOUS) occupant_status = "<span class='average'>Unconscious</span>"
else occupant_status = "<span class='bad'>DEAD</span>" else occupant_status = "<span class='bad'>DEAD - Cannot Operate</span>"
occupant_status = "[viable_occupant.name] => [occupant_status]<br />" occupant_status = "[viable_occupant.name] => [occupant_status]<br />"
occupant_status += "<div class='line'><div class='statusLabel'>Health:</div><div class='progressBar'><div style='width: [viable_occupant.health]%;' class='progressFill good'></div></div><div class='statusValue'>[viable_occupant.health]%</div></div>" occupant_status += "<div class='line'><div class='statusLabel'>Health:</div><div class='progressBar'><div style='width: [viable_occupant.health]%;' class='progressFill good'></div></div><div class='statusValue'>[viable_occupant.health]%</div></div>"
occupant_status += "<div class='line'><div class='statusLabel'>Radiation Level:</div><div class='progressBar'><div style='width: [viable_occupant.radiation]%;' class='progressFill bad'></div></div><div class='statusValue'>[viable_occupant.radiation]%</div></div>" occupant_status += "<div class='line'><div class='statusLabel'>Radiation Level:</div><div class='progressBar'><div style='width: [viable_occupant.radiation]%;' class='progressFill bad'></div></div><div class='statusValue'>[viable_occupant.radiation]%</div></div>"
var/rejuvenators = viable_occupant.reagents.get_reagent_amount("inaprovaline") var/rejuvenators = viable_occupant.reagents.get_reagent_amount("inaprovaline")
occupant_status += "<div class='line'><div class='statusLabel'>Rejuvenators:</div><div class='progressBar'><div style='width: [round((rejuvenators / REJUVENATORS_MAX) * 100)]%;' class='progressFill highlight'></div></div><div class='statusValue'>[rejuvenators] units</div></div>" occupant_status += "<div class='line'><div class='statusLabel'>Rejuvenators:</div><div class='progressBar'><div style='width: [round((rejuvenators / REJUVENATORS_MAX) * 100)]%;' class='progressFill highlight'></div></div><div class='statusValue'>[rejuvenators] units</div></div>"
occupant_status += "<div class='line'><div class='statusLabel'>Last Operation:</div> [last_change]</div>"
else else
viable_occupant = null viable_occupant = null
occupant_status = "<span class='bad'>Invalid DNA structure</span>" occupant_status = "<span class='bad'>Invalid DNA structure</span>"
@@ -763,7 +757,18 @@
else else
occupant_status = "<span class='bad'>Error: Undefined</span>" occupant_status = "<span class='bad'>Error: Undefined</span>"
scanner_status = "<span class='bad'>Error: No scanner detected</span>" scanner_status = "<span class='bad'>Error: No scanner detected</span>"
var/status = "<div class='statusDisplay'>Scanner Status: [scanner_status]<br>Subject Status: [occupant_status]<br>Emitter Array Output Level: [radstrength]<br>Emitter Array Pulse Duration: [radduration]</div>"
var/status = "<div class='statusDisplay'>Scanner Status: [scanner_status]<br>Subject Status: [occupant_status]<br>"
var/stddev = radstrength*RADIATION_STRENGTH_MULTIPLIER
status += "Emitter Array Output Level: [radstrength] <i>Mutation: (-[stddev]<->+[stddev])=68% (-[2*stddev]<->+[2*stddev])=95%</i><br>"
stddev = RADIATION_ACCURACY_MULTIPLIER/radduration
var/chance_to_hit
switch(stddev) //hardcoded values from a z-table for a normal distribution
if(0 to 0.25) chance_to_hit = ">95%"
if(0.25 to 0.5) chance_to_hit = "68-95%"
if(0.5 to 0.75) chance_to_hit = "55-68%"
else chance_to_hit = "<38%"
status += "Emitter Array Pulse Duration: [radduration] <i>Accuracy: ([chance_to_hit])</i></div>"
var/buttons = "<a href='?src=\ref[src];'>Scan</a> " var/buttons = "<a href='?src=\ref[src];'>Scan</a> "
if(connected) buttons += "<a href='?src=\ref[src];task=togglelock;'>Toggle Bolts</a> " if(connected) buttons += "<a href='?src=\ref[src];task=togglelock;'>Toggle Bolts</a> "
@@ -846,15 +851,16 @@
temp_html += status temp_html += status
temp_html += buttons temp_html += buttons
var/max_line_len = 10*DNA_BLOCK_SIZE
temp_html += "<div class='line'><div class='statusLabel'>Unique Enzymes :</div><div class='statusValue'><span class='highlight'>" temp_html += "<div class='line'><div class='statusLabel'>Unique Enzymes :</div><div class='statusValue'><span class='highlight'>"
if(viable_occupant) if(viable_occupant)
temp_html += "[viable_occupant.dna.unique_enzymes]" temp_html += "[viable_occupant.dna.unique_enzymes]"
else else
temp_html += " - " temp_html += " - "
temp_html += "</span></div></div>" temp_html += "</span></div></div><br>"
temp_html += "<div class='line'><div class='statusLabel'>Unique Identifier:</div><div class='statusValue'><span class='highlight'>" temp_html += "<div class='line'><div class='statusLabel'>Unique Identifier:</div><div class='statusValue'><span class='highlight'>"
var/max_line_len = DNA_BLOCK_SIZE * 10
if(viable_occupant) if(viable_occupant)
var/len = length(viable_occupant.dna.uni_identity) var/len = length(viable_occupant.dna.uni_identity)
for(var/i=1, i<=len, i++) for(var/i=1, i<=len, i++)
@@ -865,7 +871,7 @@
temp_html += " " temp_html += " "
else else
temp_html += " - " temp_html += " - "
temp_html += "</span></div></div>" temp_html += "</span></div></div><br>"
temp_html += "<div class='line'><div class='statusLabel'>Structural Enzymes:</div><div class='statusValue'><span class='highlight'>" temp_html += "<div class='line'><div class='statusLabel'>Structural Enzymes:</div><div class='statusValue'><span class='highlight'>"
if(viable_occupant) if(viable_occupant)
@@ -905,6 +911,7 @@
//Basic Tasks/////////////////////////////////////////// //Basic Tasks///////////////////////////////////////////
var/num = round(text2num(href_list["num"])) var/num = round(text2num(href_list["num"]))
var/last_change
switch(href_list["task"]) switch(href_list["task"])
if("togglelock") if("togglelock")
if(connected) connected.locked = !connected.locked if(connected) connected.locked = !connected.locked
@@ -1010,7 +1017,7 @@
diskette.loc = get_turf(src) diskette.loc = get_turf(src)
diskette = null diskette = null
if("pulseui","pulsese") if("pulseui","pulsese")
if(num && viable_occupant && connected) if(num && viable_occupant && connected && viable_occupant.stat != DEAD)
radduration = Wrap(radduration, 1, RADIATION_DURATION_MAX+1) radduration = Wrap(radduration, 1, RADIATION_DURATION_MAX+1)
radstrength = Wrap(radstrength, 1, RADIATION_STRENGTH_MAX+1) radstrength = Wrap(radstrength, 1, RADIATION_STRENGTH_MAX+1)
@@ -1031,8 +1038,14 @@
num = Wrap(num, 1, len+1) num = Wrap(num, 1, len+1)
num = randomize_radiation_accuracy(num, radduration, len) num = randomize_radiation_accuracy(num, radduration, len)
var/block = round((num-1)/DNA_BLOCK_SIZE)+1
var/subblock = num - block*DNA_BLOCK_SIZE
last_change = "UI #[block]-[subblock]; "
var/hex = copytext(viable_occupant.dna.uni_identity, num, num+1) var/hex = copytext(viable_occupant.dna.uni_identity, num, num+1)
last_change += "[hex]"
hex = scramble(hex, radstrength, radduration) hex = scramble(hex, radstrength, radduration)
last_change += "->[hex]"
viable_occupant.dna.uni_identity = copytext(viable_occupant.dna.uni_identity, 1, num) + hex + copytext(viable_occupant.dna.uni_identity, num+1, 0) viable_occupant.dna.uni_identity = copytext(viable_occupant.dna.uni_identity, 1, num) + hex + copytext(viable_occupant.dna.uni_identity, num+1, 0)
updateappearance(viable_occupant) updateappearance(viable_occupant)
@@ -1041,8 +1054,14 @@
num = Wrap(num, 1, len+1) num = Wrap(num, 1, len+1)
num = randomize_radiation_accuracy(num, radduration, len) num = randomize_radiation_accuracy(num, radduration, len)
var/block = round((num-1)/DNA_BLOCK_SIZE)+1
var/subblock = num - block*DNA_BLOCK_SIZE
last_change = "SE #[block]-[subblock]; "
var/hex = copytext(viable_occupant.dna.struc_enzymes, num, num+1) var/hex = copytext(viable_occupant.dna.struc_enzymes, num, num+1)
last_change += "[hex]"
hex = scramble(hex, radstrength, radduration) hex = scramble(hex, radstrength, radduration)
last_change += "->[hex]"
viable_occupant.dna.struc_enzymes = copytext(viable_occupant.dna.struc_enzymes, 1, num) + hex + copytext(viable_occupant.dna.struc_enzymes, num+1, 0) viable_occupant.dna.struc_enzymes = copytext(viable_occupant.dna.struc_enzymes, 1, num) + hex + copytext(viable_occupant.dna.struc_enzymes, num+1, 0)
domutcheck(viable_occupant, connected) domutcheck(viable_occupant, connected)
@@ -1052,7 +1071,7 @@
if(connected) if(connected)
connected.locked = locked_state connected.locked = locked_state
ShowInterface(usr) ShowInterface(usr,last_change)
/////////////////////////// DNA MACHINES /////////////////////////// DNA MACHINES
@@ -1063,11 +1082,9 @@
#undef RADIATION_STRENGTH_MAX #undef RADIATION_STRENGTH_MAX
#undef RADIATION_STRENGTH_MULTIPLIER #undef RADIATION_STRENGTH_MULTIPLIER
#undef RADIATION_STRENGTH_BIAS
#undef RADIATION_DURATION_MAX #undef RADIATION_DURATION_MAX
#undef RADIATION_ACCURACY_MULTIPLIER #undef RADIATION_ACCURACY_MULTIPLIER
#undef RADIATION_ACCURACY_BIAS
#undef RADIATION_IRRADIATION_MULTIPLIER #undef RADIATION_IRRADIATION_MULTIPLIER

View File

@@ -351,6 +351,7 @@
R.fields["UE"] = subject.dna.unique_enzymes R.fields["UE"] = subject.dna.unique_enzymes
R.fields["UI"] = subject.dna.uni_identity R.fields["UI"] = subject.dna.uni_identity
R.fields["SE"] = subject.dna.struc_enzymes R.fields["SE"] = subject.dna.struc_enzymes
R.fields["b_type"] = subject.dna.b_type
//Add an implant if needed //Add an implant if needed
var/obj/item/weapon/implant/health/imp = locate(/obj/item/weapon/implant/health, subject) var/obj/item/weapon/implant/health/imp = locate(/obj/item/weapon/implant/health, subject)

View File

@@ -389,7 +389,7 @@ What a mess.*/
if ("New Record (General)") if ("New Record (General)")
var/datum/data/record/G = new /datum/data/record() var/datum/data/record/G = new /datum/data/record()
G.fields["name"] = "New Record" G.fields["name"] = "New Record"
G.fields["id"] = text("[]", add_zero(num2hex(rand(1, 1.6777215E7)), 6)) G.fields["id"] = "[num2hex(rand(1, 1.6777215E7), 6)]"
G.fields["rank"] = "Unassigned" G.fields["rank"] = "Unassigned"
G.fields["sex"] = "Male" G.fields["sex"] = "Male"
G.fields["age"] = "Unknown" G.fields["age"] = "Unknown"