Illerai:Sandbox/combat pseudocode

From Illerai
Jump to navigation Jump to search
/** 
unimplemented:
	prayers
	amulet of avarice
	warden p2
	nmz
	Castle wars bracelet
	melee:
		verac's
		bulwark (pummel)
	ranged:
		Slayer helmet (i) and Black mask (i) for max hit
		karil's
		ice arrows
		chinchompas
		bolts/zcb
		venator bow
		strangeness from old specs/ogre bow
	npcs:
		maiden
		guardians
		verzik
		kraken (ranged)
	magic:
		ahrim's
		thammaron's sceptre
		spell max hits
	special attacks
	league relics?
*/

// Please note that all divisions in this code are integer divisions that
// truncate towards zero. Python's // operator does the wrong thing for 
// negative numbers.

randominc(n):
	return int(random.random() * (n+1))

npc_defence_roll:
	effective_defence_level = monster.getBoostedLevel(DEFENCE)
	effective_defence_level += 9

	defence_roll = effective_defence_level * (monster.getDefensiveBonus(style.type) + 64)

	if monster.invocation_level is not None:
		defence_roll = defence_roll * (250 + monster.invocation_level) / 250

	return defence_roll


melee_player_attack_roll:
	style = player.getCombatStyle()

	effective_attack_level = int(player.getBoostedLevel(ATTACK) * player.getPrayerBoost(ATTACK))
	if style.stance == "Accurate":
		effective_attack_level += 3
	elif style.stance == "Controlled":
		effective_attack_level += 1
	effective_attack_level += 8

	if player.wearingFullVoidMelee():
		effective_attack_level = effective_attack_level * 11/10

	attack_roll = effective_attack_level * (player.getBonus(style.type) + 64)

	if player.wearing(["Salve amulet (e)", "Salve amulet(ei)"]) and monster.hasAttribute("undead"):
		attack_roll = attack_roll * 6/5
	elif player.wearing(["Salve amulet", "Salve amulet(i)"]) and monster.hasAttribute("undead"):
		attack_roll = attack_roll * 7/6
	elif player.wearingBlackMask() and isSlayerTask:
		attack_roll = attack_roll * 7/6

	if player.wearing(["Viggora's chainmace", "Ursine chainmace"]) and isInWilderness:
		attack_roll = attack_roll * 3/2
	if player.wearing(["Arclight"]) and monster.hasAttribute("demonic"):
		attack_roll = attack_roll * 17/10
	if player.wearing(["Dragon hunter lance"]) and monster.hasAttribute("draconic"):
		attack_roll = attack_roll * 6/5
	if player.wearing(["Keris partisan of breaching"]) and monster.hasAttribute("kalphite"):
		attack_roll = attack_roll * 133/100
	if player.wearing(["Blisterwood flail", "Blisterwood sickle"]) and monster.hasAttribute("vampyre"): // TODO: make sure this actually works
		attack_roll = attack_roll * 21/20
	if player.wearing(["Tzhaar-ket-em", "Tzhaar-ket-om", "Tzhaar-ket-om (t)", "Toktz-xil-ak", "Toktz-xil-ek"]) and player.wearing("Obsidian platebody") and player.wearing("Obsidian platelegs") and player.wearing("Obsidian helmet"):
		attack_roll = attack_roll * 11/10

	if style.type == CRUSH:
		inq_pieces = player.countWorn(["Inquisitor's great helm", "Inquisitor's hauberk", "Inquisitor's plateskirt"])
		if inq_pieces == 3:
			inq_pieces = 5
		attack_roll = attack_roll * (200 + inq_pieces) / 200

	return attack_roll


melee_max_hit:
	style = player.getCombatStyle()

	effective_strength_level = int(player.getBoostedLevel(STRENGTH) * player.getPrayerBoost(STRENGTH))
	if style.stance == "Aggressive":
		effective_strength_level += 3
	elif style.stance == "Controlled":
		effective_strength_level += 1
	effective_strength_level += 8

	if player.wearingFullVoidMelee():
		effective_strength_level = effective_strength_level * 11/10

	max_hit = (effective_strength_level * (player.getBonus(STRENGTH_BONUS) + 64) + 320) / 640
	base_damage = max_hit

	if player.wearing(["Salve amulet (e)", "Salve amulet(ei)"]) and monster.hasAttribute("undead"):
		max_hit = max_hit * 6/5
	elif player.wearing(["Salve amulet", "Salve amulet(i)"]) and monster.hasAttribute("undead"):
		max_hit = max_hit * 7/6
	elif player.wearingBlackMask() and isSlayerTask:
		max_hit = max_hit * 7/6

	if player.wearing(["Arclight"]) and monster.hasAttribute("demonic"):
		max_hit = max_hit * 17/10
	if player.wearing(["Tzhaar-ket-em", "Tzhaar-ket-om", "Tzhaar-ket-om (t)", "Toktz-xil-ak", "Toktz-xil-ek"]) and player.wearing("Obsidian platebody") and player.wearing("Obsidian platelegs") and player.wearing("Obsidian helmet"):
		max_hit += base_damage / 10 // TODO: confirm that this is the appropriate place
	if player.wearing(["Tzhaar-ket-em", "Tzhaar-ket-om", "Tzhaar-ket-om (t)", "Toktz-xil-ak", "Toktz-xil-ek"]) and player.wearing("Berserker necklace"):
		max_hit = max_hit * 6/5
	if player.wearing(["Dragon hunter lance"]) and monster.hasAttribute("draconic"):
		max_hit = max_hit * 6/5
	if player.wearing(["Barronite mace"]) and monster.hasAttribute("golem"):
		max_hit = max_hit * 23/20
	if player.wearing(["Viggora's chainmace", "Ursine chainmace"]) and isInWilderness:
		max_hit = max_hit * 3/2
	if player.wearing(["Silverlight", "Darklight", "Silverlight (dyed)"]) and monster.hasAttribute("demonic"):
		max_hit = max_hit * 8/5 // There is no accuracy boost
	if player.wearing(["Blisterwood flail"]) and monster.hasAttribute("vampyre"):
		max_hit = max_hit * 5/4
	if player.wearing(["Blisterwood sickle"]) and monster.hasAttribute("vampyre"):
		max_hit = max_hit * 23/20
	if player.wearing(["Ivandis flail"]) and monster.hasAttribute("vampyre"):
		max_hit = max_hit * 6/5
	if player.wearing(["Leaf-bladed battleaxe"]) and monster.hasAttribute("leafy"):
		max_hit = max_hit * 47/40
	if player.wearing(["Colossal blade"]):
		max_hit = max_hit + min(monster.size * 2, 10)
	if style.type == CRUSH:
		inq_pieces = player.countWorn(["Inquisitor's great helm", "Inquisitor's hauberk", "Inquisitor's plateskirt"])
		if inq_pieces == 3:
			inq_pieces = 5
		max_hit = max_hit * (200 + inq_pieces) / 200

	// TODO: many more...
	return max_hit

ranged_player_attack_roll:
	style = player.getCombatStyle()

	effective_ranged_level = int(player.getBoostedLevel(RANGED) * player.getPrayerBoost(RANGED))
	if style.stance == "Accurate":
		effective_ranged_level += 3
	effective_ranged_level += 8

	if player.wearingFullVoidRanged():
		effective_ranged_level = effective_ranged_level * 11/10

	attack_roll = effective_ranged_level * (player.getBonus(RANGED) + 64)

	if player.wearing(["Salve amulet(ei)"]) and monster.hasAttribute("undead"):
		attack_roll = attack_roll * 6/5
	elif player.wearing(["Salve amulet(i)"]) and monster.hasAttribute("undead"):
		attack_roll = attack_roll * 7/6
	elif player.wearingImbuedBlackMask() and isSlayerTask:
		attack_roll = attack_roll * 23/20

	if player.wearing(["Twisted bow"]):
		cap = 250
		if monster.hasAttribute("raids"):
			cap = 350
		tbow_magic = max(monster.getBaseLevel(MAGIC), monster.getBonus(MAGIC_BONUS))
		m = min(tbow_magic, cap) * 3/10
		tbow_mod = min(140, 140 + (m*10-10)/100 - (m-100)^2/100)
		attack_roll = attack_roll * tbow_mod / 100
	if player.wearing(["Craw's bow"]) and isInWilderness:
		attack_roll = attack_roll * 3/2
	if player.wearing(["Dragon hunter crossbow"]):
		// TODO: https://twitter.com/JagexAsh/status/1647928422843273220 for max_hit seems to be additive now
		attack_roll = attack_roll * 13/10
	if player.wearingAnyCrystalBow():
		// TODO: crystal buff actually applies before slayer helm. need to test salve.
		crystal_pieces = (player.isWearing("Crystal helm") ? 1 : 0) + (player.isWearing("Crystal legs") ? 2 : 0) + (player.isWearing("Crystal body") ? 3 : 0)
		attack_roll = attack_roll * (20 + crystal_pieces) / 20
	
	return attack_roll

ranged_max_hit:
	style = player.getCombatStyle()

	effective_ranged_level = int(player.getBoostedLevel(RANGED) * player.getPrayerBoost(RANGED))
	if style.stance == "Accurate":
		effective_ranged_level += 3
	effective_ranged_level += 8

	if player.wearingFullEliteVoidRanged():
		effective_ranged_level = effective_ranged_level * 9/8
	elif player.wearingFullVoidRanged():
		effective_ranged_level = effective_ranged_level * 11/10

	max_hit = (effective_ranged_level * (player.getBonus(RANGED_STRENGTH) + 64) + 320) / 640
	
	if player.wearing(["Twisted bow"]):
		cap = 250
		if monster.hasAttribute("raids"):
			cap = 350
		tbow_magic = max(monster.getBaseLevel(MAGIC), monster.getBonus(MAGIC_BONUS))
		m = min(tbow_magic, cap) * 3/10
		tbow_mod = min(250, 250 + (m*10-14)/100 - (m-140)^2/100) // the min() is redundant :-)
		max_hit = max_hit * tbow_mod / 100
	if player.wearing(["Craw's bow"]):
		max_hit = max_hit * 3/2
	if player.wearing(["Dragon hunter crossbow"]):
		// TODO: https://twitter.com/JagexAsh/status/1647928422843273220 for max_hit seems to be additive now
		// Is it 25% or 30%? Wiki says 25%
		max_hit = max_hit * 5 / 4
	if player.wearingAnyCrystalBow():
		crystal_pieces = (player.isWearing("Crystal helm") ? 1 : 0) + (player.isWearing("Crystal legs") ? 2 : 0) + (player.isWearing("Crystal body") ? 3 : 0)
		max_hit = max_hit * (40 + crystal_pieces) / 40
		
	return max_hit

// For a few things that don't respect prayers, stances, etc
old_ranged_max_hit(slot):
	effective_ranged_level = player.getBoostedLevel(RANGED)

	max_hit = (effective_ranged_level * (player.getBonusAtSlot(slot, RANGED_STRENGTH) + 64) + 320) / 640
	
	return max_hit
	

magic_player_attack_roll:
	style = player.getCombatStyle()

	effective_magic_level = int(player.getBoostedLevel(MAGIC) * player.getPrayerBoost(MAGIC))
	if style.stance == "Accurate":
		effective_magic_level += 2
	effective_magic_level += 9

	if player.wearingFullVoidMagic():
		effective_magic_level = effective_magic_level * 29/20

	magic_bonus = player.getBonus(MAGIC)
	
	if player.wearing(["Tumeken's shadow"]):
		if monster.hasAttribute("toa"):
			magic_bonus = magic_bonus * 4
		else:
			magic_bonus = magic_bonus * 3
	
	attack_roll = effective_magic_level * (magic_bonus + 64)

	if player.wearing(["Salve amulet(ei)"]) and monster.hasAttribute("undead"):
		attack_roll = attack_roll * 6/5
	elif player.wearing(["Salve amulet(i)"]) and monster.hasAttribute("undead"):
		attack_roll = attack_roll * 23/20
	elif player.wearingImbuedBlackMask() and isSlayerTask:
		attack_roll = attack_roll * 23/20
		
	if player.wearing(["Thammaron's sceptre", "Accursed sceptre"]) and isInWilderness:
		attack_roll = attack_roll * 3/2
	if player.wearing(["Mystic smoke staff"]) and player.spell().spellbook == "Standard":
		attack_roll = attack_roll * 11/10
	
	return attack_roll


magic_max_hit:
	max_hit = None
	magic_level = player.getBoostedLevel(MAGIC)
	
	if player.spell().max_hit:
		max_hit = player.spell().max_hit
	elif player.spell().name == "Magic Dart":
		if player.wearing(["Slayer's staff (e)"]) and isSlayerTask:
			max_hit = 13 + magic_level / 6
		else:
			max_hit = 10 + magic_level / 10
	elif player.wearing(["Starter staff"]):
		max_hit = 8
	elif player.wearing(["Trident of the seas", "Trident of the seas (e)"]):
		max_hit = magic_level / 3 - 5
	elif player.wearing(["Thammaron's sceptre"]):
		max_hit = magic_level / 3 - 8
	elif player.wearing(["Accursed sceptre"]):
		max_hit = magic_level / 3 - 6
	elif player.wearing(["Trident of the swamp", "Trident of the swamp (e)"]):
		max_hit = magic_level / 3 - 2
	elif player.wearing(["Sanguinesti staff", "Holy sanguinesti staff"]):
		max_hit = magic_level / 3 - 1
	elif player.wearing(["Dawnbringer"]):
		max_hit = magic_level / 6 - 1
	elif player.wearing(["Tumeken's shadow"]):
		max_hit = magic_level / 3 + 1
	elif player.wearing(["Warped sceptre"]):
		max_hit = (8 * magic_level + 96) / 37
	elif player.wearing(["Crystal staff (basic)", "Corrupted staff (basic)"]):
		max_hit = 23
	elif player.wearing(["Crystal staff (attuned)", "Corrupted staff (attuned)"]):
		max_hit = 31
	elif player.wearing(["Crystal staff (perfected)", "Corrupted staff (perfected)"]):
		max_hit = 39
	elif player.wearing(["Swamp lizard"]):
		max_hit = (magic_level * (56 + 64) + 320) / 640
	elif player.wearing(["Orange salamander"]):
		max_hit = (magic_level * (59 + 64) + 320) / 640
	elif player.wearing(["Red salamander"]):
		max_hit = (magic_level * (77 + 64) + 320) / 640
	elif player.wearing(["Black salamander"]):
		max_hit = (magic_level * (92 + 64) + 320) / 640

	if player.wearing(["Chaos gauntlets"]) and player.spell().is_bolt:
		max_hit = max_hit + 3
	if charge and player.spell().is_god_spell:
		max_hit = max_hit + 10

	magic_damage_bonus = player.getBonus(MAGIC_DAMAGE) * 10
	if player.wearing(["Tumeken's shadow"]):
		// Supposedly this caps at 100, but nothing goes that high yet
		if monster.hasAttribute("toa"):
			magic_damage_bonus = magic_damage_bonus * 4
		else:
			magic_damage_bonus = magic_damage_bonus * 3
			
	if player.wearingFullEliteVoidMagic():
		// This comes after shadow's tripling
		magic_damage_bonus = magic_damage_bonus + 25
	if player.wearing(["Mystic smoke staff"]) and player.spell().spellbook == "Standard":
		magic_damage_bonus = magic_damage_bonus + 100
		
	blackMaskBonus = false
	if player.wearing(["Salve amulet(ei)"]) and monster.hasAttribute("undead"):
		magic_damage_bonus = magic_damage_bonus + 200
	elif player.wearing(["Salve amulet(i)"]) and monster.hasAttribute("undead"):
		magic_damage_bonus = magic_damage_bonus + 150
	elif player.wearingImbuedBlackMask() and isSlayerTask:
		blackMaskBonus = true
		
	max_hit = max_hit * (1000 + magic_damage_bonus) / 1000
	
	if blackMaskBonus:
		max_hit = max_hit * 23/20
		
	// accursed sceptre passive effect comes after black mask
	
	return max_hit

style = player.getCombatStyle()
if style == MELEE:
    max_attack_roll = melee_player_attack_roll()
    max_hit = max(0, melee_max_hit())
elif style == RANGED:
    max_attack_roll = ranged_player_attack_roll()
    max_hit = max(0, ranged_max_hit())
elif style == MAGIC:
    max_attack_roll = magic_player_attack_roll()
    max_hit = max(0, magic_max_hit())
    
// TODO: Get the right defence roll depending on melee/ranged vs magic and monsters that use defence for magic (ice demon, verzik, etc)
max_defence_roll = npc_defence_roll()
    
if player.wearing(["Brimstone ring"]) and style == MAGIC:
	if random(4) == 0:
		max_defence_roll = max_defence_roll * 9/10

if player.wearing(["Scythe of vitur"]):
	num_of_hits = min(monster.size, 3)
	for _ in range(num_of_hits):
		if randominc(max_attack_roll) > randominc(max_defence_roll):
			hit_opponent(randominc(max_hit))
			max_hit /= 2
else:
	attack_roll = randominc(max_attack_roll)
	defence_roll = randominc(max_defence_roll)
	
	if attack_roll <= defence_roll and player.wearing(["Osmumten's fang"]):
		attack_roll = randominc(max_attack_roll)
		if monster.hasAttribute("toa"):
			defence_roll = randominc(max_defence_roll)
	
	if attack_roll > defence_roll:
		if player.wearing(["Osmumten's fang"]):
			fifteen = max_hit * 15/100
			hit = fifteen + randominc(max_hit - fifteen*2)
		else:
			hit = randominc(max_hit)
		if player.wearing(["Gadderhammer"]) and monster.hasAttribute("shade"):
			if random(20) == 0:
				hit = hit * 2
			else:
				hit = hit * 5/4
		if player.wearingAnyKeris() and monster.hasAttribute("kalphite"):
			if random(51) == 0:
				hit = hit * 3
		if player.wearing(["Holy water"]) and monster.hasAttribute("demonic"):
			hit = hit * 8 / 5
			// if monster defence level isn't drained, drain it by level/20
		if player.wearingFullDharok() and style == MELEE:
			hit = hit * (10000 + (player.base_hp - player.current_hp) * player.current_hp) / 10000
		if player.wearing(['Tome of fire']) and player.spell().element == "Fire":
			hit = hit * 3 / 2
			
			
	
		if monster.name == "Skogre" or monster.name == "Zogre":
			if player.wearing(["Comp ogre bow"]) and player.UsingBrutalArrows():
				hit = hit * 1 // do nothing
			elif player.spell().name == "Crumble Undead":
				hit = hit / 2
			else:
				hit = hit / 4
		if monster.name == "Zulrah" and hit > 50:
			hit = 45 + randominc(5)
		if monster.name == "Ice demon":
			if player.spell().element == "Fire":
				hit = hit * 3/2
			else:
				// TODO: is there anything that isn't /3?
				hit = hit / 3
		if monster.name == "Corporeal Beast":
			if ((style.category == "Spears" or style.category == "Halberds" or player.wearing("Osmumten's fang")) and style.type == STAB) or style == MAGIC:
				hit = hit * 1 // do nothing
			else:
				hit = hit / 2
		if monster.name == "Slagilith" and !player.wieldingPickaxe():
			hit = hit / 3
		
		if monster.kerisCorrupted:
			hit = hit * 5/4
		
		hit_opponent(hit)
		// TODO: other stuff that only happens on success
	else:
		hit_opponent(0)

hit_opponent(hit):
	if monster.hasAttribute("penance"):
		// Damage is even increased for missed attacks
		hit = hit + player.BarbarianAssault.AttackerLevel // (1-5)

	// Apply damage and do other stuff