func (m *Mob) PowerPoints() int {
	return m.VarInt("power_points", 1)
}
PowerPoints Returns the players power points.
package world
import (
	"math"
	"math/rand"
	"sync"
	"time"
	"github.com/spkaeros/rscgo/pkg/game/entity"
	"github.com/spkaeros/rscgo/pkg/log"
	"github.com/spkaeros/rscgo/pkg/isaac"
	rscRand "github.com/spkaeros/rscgo/pkg/rand"
	"github.com/spkaeros/rscgo/pkg/tasks"
)
type MobState = int
const (
	StateIdle MobState = 0
	StateChatting = 1 << iota
	StateFighting
	StateBanking
	StateMenu
	StateTrading
	StateDueling
	MSBatching
	StateSleeping
	StateChangingLooks
	StateShopping
	MSItemAction
	StateAction
	StateFightingDuel   = StateDueling | StateFighting
	StateChatChoosing   = StateMenu | StateChatting
	StateItemChoosing   = StateMenu | MSItemAction
	StateObjectChoosing = StateMenu | MSBatching
	StatePanelActive = StateBanking | StateShopping | StateChangingLooks | StateSleeping | StateTrading | StateDueling
	StateBusy      = StatePanelActive | StateChatting | MSItemAction | MSBatching | StateAction
	StateWaitEvent = StateMenu | StateChatting | MSItemAction | MSBatching
)
const (
	SyncInit = 0
	SyncSprite = 1 << iota
	SyncMoved
	SyncRemoved
	SyncAppearance
	SyncNeedsPosition = SyncRemoved | SyncMoved | SyncSprite
)
var mask = ^3
type mobSet []entity.MobileEntity
type MobList struct {
	mobSet
	sync.RWMutex
}
func NewMobList() *MobList {
	return &MobList{mobSet: make(mobSet, 0, 255)}
}
func (l *MobList) Add(m entity.MobileEntity) int {
	l.Lock()
	defer l.Unlock()
	l.mobSet = append(l.mobSet, m)
	return len(l.mobSet)
}
func (l *MobList) Range(action func(entity.MobileEntity) bool) int {
	l.RLock()
	defer l.RUnlock()
	for i, v := range l.mobSet {
		if action(v) {
			return i
		}
	}
	return -1
}
func (l *MobList) Size() int {
	l.RLock()
	defer l.RUnlock()
	return len(l.mobSet)
}
func (l *MobList) Contains(mob entity.MobileEntity) bool {
	l.RLock()
	defer l.RUnlock()
	for _, v := range l.mobSet {
		if v == mob {
			return true
		}
	}
	return false
}
func (l *MobList) Remove(m entity.MobileEntity) bool {
	l.Lock()
	defer l.Unlock()
	for i, v := range l.mobSet {
		if v == m {
			if i >= len(l.mobSet) {
				l.mobSet = l.mobSet[:i]
			} else {
				l.mobSet = append(l.mobSet[:i], l.mobSet[i+1:]...)
			}
			return true
		}
	}
	return false
}
func (l *MobList) RangePlayers(action func(*Player) bool) int {
	return l.Range(func(m entity.MobileEntity) bool {
		if p := AsPlayer(m); p != nil {
			return action(p)
		}
		return false
	})
}
func (l *MobList) RangeNpcs(action func(*NPC) bool) int {
	return l.Range(func(m entity.MobileEntity) bool {
		if n := AsNpc(m); n != nil {
			return action(n)
		}
		return false
	})
}
func (l *MobList) Get(idx int) entity.MobileEntity {
	l.RLock()
	defer l.RUnlock()
	for _, v := range l.mobSet {
		if v.ServerIndex() == idx{
			return v
		}
	}
	return nil
}
type Mob struct {
	SyncMask       int
	skills		   entity.SkillTable
	path		   *Pathway
	Prayers		   [15]bool
	entity.Entity
	*entity.AttributeList
	sync.RWMutex
}
func (m *Mob) ExperienceReward() float64 {
	meleeTotal := (m.Skills().Maximum(entity.StatStrength) + m.Skills().Maximum(entity.StatAttack) + m.Skills().Maximum(entity.StatDefense)) * 2.0
	total := float64(m.Skills().Maximum(entity.StatHits) + meleeTotal)
	return math.Floor(total/7.0) * 2.0 + 20.0
}
func (m *Mob) TargetMob() entity.MobileEntity {
	return m.VarMob("targetMob")
}
func (m *Mob) TargetNpc() *NPC {
	return AsNpc(m.TargetMob())
}
func (m *Mob) TargetPlayer() *Player {
	return AsPlayer(m.TargetMob())
}
func (p *Player) IsPlayer() bool {
	return true
}
func (p *Player) Type() entity.Type {
	return entity.TypePlayer
}
func (p *Player) IsNpc() bool {
	return false
}
func (n *NPC) Type() entity.Type {
	return entity.TypeNpc
}
func (n *NPC) IsPlayer() bool {
	return false
}
func (n *NPC) IsNpc() bool {
	return true
}
func (m *Mob) Skulls() map[uint64]time.Time {
	return nil
}
func (m *Mob) Busy() bool {
	return m.State()&StateBusy != 0
}
func (m *Mob) BusyInput() bool {
	filtered := m.State()&StateWaitEvent
	return filtered&StateMenu != 0 
}
func (m *Mob) IsFighting() bool {
	return m.HasState(StateFighting)
}
func (m *Mob) FightTarget() entity.MobileEntity {
	return m.VarMob("fightTarget")
}
func (m *Mob) SetFightTarget(m2 entity.MobileEntity) {
	m.SetVar("fightTarget", m2)
}
func (m *Mob) FightRound() int {
	return m.VarInt("fightRound", 0)
}
func (m *Mob) SetFightRound(i int) {
	m.SetVar("fightRound", i)
}
func (m *Mob) LastRetreat() time.Time {
	return m.VarTime("lastRetreat")
}
func (m *Mob) LastFight() time.Time {
	return m.VarTime("lastFight")
}
func (m *Mob) UpdateLastRetreat() {
	m.SetVar("lastRetreat", time.Now())
}
func (m *Mob) UpdateLastFight() {
	m.SetVar("lastFight", time.Now())
}
func (m *Mob) Direction() int {
	return m.VarInt("direction", North)
}
func (m *Mob) SetDirection(direction int) {
	m.SetVar("direction", direction)
	m.SetSpriteUpdated()
}
func (m *Mob) SetSpriteUpdated() {
	m.Lock()
	defer m.Unlock()
	m.SyncMask |= SyncSprite
}
func (m *Mob) SetRegionRemoved() {
	m.Lock()
	defer m.Unlock()
	m.SyncMask |= SyncRemoved
}
func (m *Mob) SetRegionMoved() {
	m.Lock()
	defer m.Unlock()
	m.SyncMask |= SyncMoved
}
func (m *Mob) SetAppearanceChanged() {
	m.Lock()
	defer m.Unlock()
	m.SyncMask |= SyncAppearance
}
func (m *Mob) ResetRegionMoved() {
	m.Lock()
	defer m.Unlock()
	m.SyncMask &= ^SyncMoved
}
func (m *Mob) ResetRegionRemoved() {
	m.Lock()
	defer m.Unlock()
	m.SyncMask &= ^SyncRemoved
}
func (m *Mob) ResetAppearanceChanged() {
	m.Lock()
	defer m.Unlock()
	m.SyncMask &= ^SyncAppearance
}
func (m *Mob) ResetSpriteUpdated() {
	m.Lock()
	defer m.Unlock()
	m.SyncMask &= ^SyncSprite
}
func (m *Mob) SetPath(path *Pathway) {
	m.path = path
}
func (m *Mob) WalkTo(end entity.Location) bool {
	path := NewPathfinder(m.Clone(), end.Clone()).MakePath()
	m.SetPath(path)
	return path != nil
}
func StartCombat(attacker, defender entity.MobileEntity) {
	if targetp := AsPlayer(defender); targetp != nil {
		targetp.PlaySound("underattack")
		if attacker := AsPlayer(attacker); attacker != nil && !attacker.IsDueling() && !targetp.SkulledOn(attacker.UsernameHash()) {
			attacker.SkullOn(targetp)
		}
	}
	attacker.SessionCache().UnsetVar("targetPlayer")
	defender.SessionCache().SetVar("fightTarget", attacker)
	attacker.SessionCache().SetVar("fightTarget", defender)
	attacker.AddState(StateFighting)
	defender.AddState(StateFighting)
	attacker.SetDirection(RightFighting)
	defender.SetDirection(LeftFighting)
	attacker.SetLocation(defender.Clone(), true)
	defender.SetRegionRemoved()
	attacker.SetRegionRemoved()
	tasks.Schedule(2, func() bool {
		if (defender.IsPlayer() && !AsPlayer(defender).Connected()) || !defender.HasState(StateFighting) ||
			(attacker.IsPlayer() && !AsPlayer(attacker).Connected()) || !attacker.HasState(StateFighting) || attacker.LongestDelta(defender) > 0  {
			attacker.ResetFighting()
			defender.ResetFighting()
			return true
		}
		defer func() {
			attacker.SessionCache().Inc("fightRound", 1)
			attacker, defender = defender, attacker
		}()
		if defender.IsPlayer() && attacker.IsNpc() && defender.PrayerActivated(12) {
			return false
		}
		nextHit := int(math.Min(float64(defender.Skills().Current(entity.StatHits)), float64(attacker.MeleeDamage(defender))))
		if defender.DamageFrom(attacker, nextHit, 0) {
			return true
		}
		return false
	})
}
func (m *Mob) Path() *Pathway {
	return m.path
}
func (m *Mob) ResetPath() {
	m.UnsetVar("pathLength")
	m.path = nil
}
func (m *Mob) FinishedPath() bool {
	path := m.Path()
	if path == nil {
		return m.VarInt("pathLength", 0) <= 0
	}
	return path.CurrentWaypoint >= path.countWaypoints() || !path.nextTileFrom(m.Clone()).IsValid()
}
func UpdateRegions(m entity.MobileEntity, x, y int) {
	next := Region(x, y)
	if cur := Region(m.X(), m.Y()); next != cur {
		if p, ok := m.(*Player); ok && p != nil {
			if cur.Players.Contains(p) {
				cur.Players.Remove(p)
			}
			if !next.Players.Contains(p) {
				next.Players.Add(p)
			}
		} else if n, ok := m.(*NPC); ok && n != nil {
			if cur.NPCs.Contains(n) {
				cur.NPCs.Remove(n)
			}
			if !next.NPCs.Contains(n) {
				next.NPCs.Add(n)
			}
		}
	}
}
func (p *Player) SetLocation(l entity.Location, teleport bool) {
	UpdateRegions(p, l.X(), l.Y())
	p.Mob.SetCoords(l.X(), l.Y(), teleport)
}
func (n *NPC) SetLocation(l entity.Location, teleport bool) {
	UpdateRegions(n, l.X(), l.Y())
	n.Mob.SetCoords(l.X(), l.Y(), teleport)
}
func (m *Mob) SetCoords(x, y int, teleport bool) {
	if !teleport {
		m.SetDirection(m.DirectionToward(NewLocation(x, y)))
		m.SetRegionMoved()
	} else {
		m.SetRegionRemoved()
	}
	m.SetX(x)
	m.SetY(y)
}
func (p *Player) Teleport(x, y int) {
	UpdateRegions(p, x, y)
	p.SetCoords(x, y, true)
}
func (n *NPC) Teleport(x, y int) {
	UpdateRegions(n, x, y)
	n.SetCoords(x, y, true)
}
func (m *Mob) SessionCache() *entity.AttributeList {
	return m.AttributeList
}
func (m *Mob) State() int {
	return m.VarInt("state", StateIdle)
}
func (m *Mob) HasState(state ...int) bool {
	return m.HasMasks("state", state...)
}
func (m *Mob) AddState(state int) {
	if state == StateIdle {
		m.SetVar("state", StateIdle)
		return
	}
	if m.HasState(state) {
		log.Warn("Attempted to add a Mobstate that we already have:", state)
		return
	}
	m.StoreMask("state", state)
}
func (m *Mob) RemoveState(state int) {
	if state == StateIdle {
		return
	}
	if !m.HasState(state) {
		log.Warn("Attempted to remove a Mobstate that we did not add:", state)
		return
	}
	m.RemoveMask("state", state)
}
func (m *Mob) ResetFighting() {
	if m.IsFighting() {
		m.UnsetVar("fightTarget")
		m.UnsetVar("fightRound")
		m.SetDirection(NorthWest)
		m.RemoveState(StateFighting)
		if m.HasState(StateDueling) {
			m.RemoveState(StateDueling)
		}
		m.UpdateLastFight()
	}
	target := m.VarMob("fightTarget")
	if target != nil && target.IsFighting() {
		target.SessionCache().UnsetVar("fightTarget")
		target.SessionCache().UnsetVar("fightRound")
		target.SetDirection(NorthWest)
		target.RemoveState(StateFighting)
		if target.HasState(StateDueling) {
			target.RemoveState(StateDueling)
		}
		target.UpdateLastFight()
	}
}
func (m *Mob) FightMode() int {
	return m.VarInt("fight_mode", 0)
}
func (m *Mob) SetFightMode(i int) {
	m.SetVar("fight_mode", i)
}
func (m *Mob) ArmourPoints() int {
	return m.VarInt("armour_points", 1)
}
func (m *Mob) SetArmourPoints(i int) {
	m.SetVar("armour_points", i)
}
func (m *Mob) IncArmourPoints(i int) {
	m.IncPoints("armour", i)
}