import random
import math

# base definitions

class ref(dict):
    def add(self, **d):
        try:
            base = self.base
        except:
            base = {}
        obj = {} # ugly code but it works
        obj.update(base)
        obj.update(d)
        self[obj['name']] = obj
    def set_base(self, **base):
        self.base = base

weapons = ref()
weapons.set_base(name = 'base weapon', damage = 1, hits = 1, damage_type = 'kinetic', min_range = 1, max_range = 1, precision = 1, precision_bonus = 0)

actors = ref()
actors.set_base(name = 'base actor', size = 25)

def chance_to_hit(weapon, target, distance):
    return 1 - (1 - 1.*target['size']/(target['size'] + 5 * max(weapon['min_range'], distance)**2))**weapon['precision']

def average_damage(weapon, target, distance):
    if distance > weapon['max_range']:
        return 0
    accuracy = chance_to_hit(weapon, target, distance)
    return accuracy * weapon['damage'] * weapon['hits']

# object definitions

weapons.add(
    name = 'rifle',
    damage = 25,
    damage_type = 'kinetic/bullet',
    min_range = 8,
    max_range = 30,
    precision = 8,
    precision_bonus = 12,
    )

weapons.add(
    name = 'SMG',
    damage = 10,
    hits = 3,
    damage_type = 'kinetic/bullet',
    min_range = 5,
    max_range = 20,
    precision = 5,
    precision_bonus = 4,
    )

weapons.add(
    name = 'pistol',
    damage = 15,
    damage_type = 'kinetic/bullet',
    min_range = 4,
    max_range = 15,
    precision = 6,
    precision_bonus = 2,
    )

weapons.add(
    name = 'shotgun',
    damage = 0.75,
    hits = 40,
    damage_type = 'kinetic/bullet',
    min_range = 2,
    max_range = 9,
    precision = 1,
    precision_bonus = 0,
    )

weapons.add(
    name = 'pike',
    damage = 25,
    damage_type = 'kinetic/edged',
    min_range = 2,
    max_range = 2,
    precision = 3,
    precision_bonus = 0,
    )

weapons.add(
    name = 'sword',
    damage = 30,
    damage_type = 'kinetic/edged',
    min_range = 1,
    max_range = 1,
    precision = 3,
    precision_bonus = 0,
    )

actors.add(
    name = 'human',
    size = 25)

actors.add(
    name = 'mecha',
    size = 100)

actors.add(
    name = 'mouse',
    size = 5)

# example use:
# average_damage(weapons['rifle'], actors['human'], 5)
