

places <- []

portal_place <- null
spell_place <- null


function reset_places()
{
  places=[]
  portal_place=null
  spell_place=null
}


class MagicPlace
{
  </persistent=1/> sensor=null
  </persistent=1/> optional=true
  </persistent=1/> activated=false


  function destroy()
  {
    if (sensor) { sensor.destroy(); sensor=null }
  }


  function beforeErosion() {}
  function  afterErosion() {}
  function beforeObjects() {}

  // function onLoaded() { print("onLoaded() called!!!\n"); }
}


//ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ//


class MagicCircle extends MagicPlace
{
  </persistent=1/> cx=0
  </persistent=1/> cz=0
  </persistent=1/> rad=0

  </persistent=1/> action=null


  constructor(x, z, r, a)
  {
    cx=x; cz=z; rad=r
    action=a
  }


  function canFit()
  {
    return test_circle_mark(cx, cz, rad, MARK_PLACEMENT|MARK_WATER, 0)
  }


  function intersects(p)
  {
    if (!p) return false;

    if (p instanceof MagicCircle)
    {
      local dx=wrap(p.cx-cx)
      local dz=wrap(p.cz-cz)
      return dx*dx+dz*dz < p.rad*p.rad+2*p.rad*rad+rad*rad
    }
    else
      return p.intersects(this);
  }


  function beforeErosion()
  {
    mark_circle(cx, cz, rad, MARK_PLACE, 0);
    flatten_circle(cx, cz, rad*1.5, get_average_circle_height(cx, cz, rad), 0.8, 2)
  }


  function afterErosion()
  {
    local y=get_average_circle_height(cx, cz, rad)
    flatten_circle(cx, cz, rad*1.5, y, 0.5, 2)
  }


  function beforeObjects()
  {
    local y=get_land_height(cx, cz)

    if (frnd()<0.3)
    {
      create_stone_circle(cx, cz, rad)
      if (frnd()<0.5) create_stone_circle(cx, cz, rad*0.8)
    }
    else
    {
      create_menhir_circle(cx, cz, rad)
    }

    if (!sensor && !in_main_menu)
    {
      sensor=Sensor(vec4f(cx, y, cz, 1), rad)
      sensor.setOnEvent(onActivate.bindenv(this))
    }
  }


  function onActivate()
  {
    activated=true
    sensor.destroy(); sensor=null
    if (action) action()
  }
}


//ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ//


class TreeCircle extends MagicCircle
{
  </persistent=1/> objects=null

  function beforeObjects()
  {
    objects=create_circle_of_trees(cx, cz, rad)

    sensor=TimeTrigger(0,
      onActivate.bindenv(this),
      checkCondition.bindenv(this))
  }


  function checkCondition()
  {
    foreach (o in objects)
    {
      if (!o) continue;
      if (!o.hasFoliage()) return false;
    }
    return true;
  }
}


function create_circle_of_trees(cx, cz, rad)
{
  local objs=[]

  local cpos=vec4f(cx, 0, cz, 1)
  local num=(rad*(0.4+srnd()*0.05)).tointeger()
  if (num<3) num=3
  local ofs=frnd()
  for (local i=0; i<num; ++i)
  {
    local p=cpos+make_dir_xz((i+srnd()*0.1)/num+ofs)*(rad*(0.75+srnd()*0.04));
    local o=TreeObject(getx(p), getz(p),
      get_pal_color(cur_world_pal, "leaves"), get_pal_color(cur_world_pal, "trunk"))
    o.setFoliage(false)
    objs.append(o)
  }

  return objs;
}


//ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ//


class StoneCupCircle extends MagicCircle
{
  </persistent=1/> objects=null

  function beforeObjects()
  {
    objects=create_stone_cup_circle(cx, cz, rad)

    sensor=TimeTrigger(0,
      onActivate.bindenv(this),
      checkCondition.bindenv(this))
  }


  function onActivate()
  {
    foreach (o in objects) o.setActive(false)
    base.onActivate()
  }


  function checkCondition()
  {
    foreach (o in objects)
    {
      if (!o) continue;
      if (!o.isBurning()) return false;
    }
    return true;
  }
}


function create_stone_cup_circle(cx, cz, rad)
{
  local objs=[]

  local cpos=vec4f(cx, 0, cz, 1)
  local num=(rad*(0.4+srnd()*0.05)).tointeger()
  if (num<3) num=3
  local ofs=frnd()
  for (local i=0; i<num; ++i)
  {
    local p=cpos+make_dir_xz((i+srnd()*0.1)/num+ofs)*(rad*(0.75+srnd()*0.04));
    local o=StoneCup1Object(getx(p), getz(p))
    objs.append(o)
  }

  return objs;
}


//ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ//


monster_spawn_enabled<-true


function spawn_birds()
{
  if (!monster_spawn_enabled) return;
  local cpos=vec4f(cx, get_land_height(cx, cz)-5, cz, 1)
  for (local n=30; n; --n)
  {
    local dir=make_dir_xz(frnd())
    BirdMonster(cpos+dir*(rad*1.2), dir)
  }
}


function spawn_wyverns()
{
  if (!monster_spawn_enabled) return;
  local cpos=vec4f(cx, get_land_height(cx, cz)-10, cz, 1)
  for (local n=3; n; --n)
  {
    local dir=make_dir_xz(frnd())
    WyvernMonster(cpos+dir*(rad*1.5))
  }
}


function spawn_caterpillars()
{
  if (!monster_spawn_enabled) return;
  local cpos=vec4f(cx, get_land_height(cx, cz)-10, cz, 1)
  for (local n=3; n; --n)
  {
    local dir=make_dir_xz(frnd())
    LandMonster(cpos+dir*(rad*1.5), dir)
  }
}


function spawn_mana()
{
  local cpos=vec4f(cx, get_land_height(cx, cz)-10, cz, 1)
  for (local n=30; n; --n)
  {
    local dir=make_dir_xz(frnd())
    ManaBall(cpos+dir*(rad*1.2), rndf(0.1, 0.2), vec4f(0, rndf(15, 30), 0, 0))
  }
}


function spawn_spell()
{
  local list=[ID_MeteorSpell, ID_WaterSourceSpell, ID_FaultSpell]
  if (DEMO) list.extend([ID_HillSpell, ID_PitSpell])
  else list.extend([ID_HealingSpell, ID_LightningSpell, ID_ThunderstormSpell,
    ID_GuardTowerSpell, ID_VolcanoSpell])

  local filtered=[]
  foreach (s in list) if (!player_has_spell(s)) filtered.append(s)

  if (filtered.len()==0) filtered=list

  SpellObject(cx, cz, filtered[irnd()%filtered.len()])
}


function spawn_portal()
{
  WorldPortal(vec4f(cx, get_land_height(cx, cz), cz, 1))
  action=null
}


function create_stone_circle(cx, cz, rad)
{
  local cpos=vec4f(cx, 0, cz, 1)
  local num=(rad*(1.5+srnd()*0.1)).tointeger()
  local ofs=frnd()
  for (local i=0; i<num; ++i)
  {
    local p=cpos+make_dir_xz((i+srnd()*0.2)/num+ofs)*(rad*(1+srnd()*0.04))
    Stone1StaticObject(getx(p), getz(p))
  }
}


function create_menhir_circle(cx, cz, rad)
{
  local cpos=vec4f(cx, 0, cz, 1)
  local num=(rad*(0.5+srnd()*0.1)).tointeger()
  if (num<3) num=3
  local ofs=frnd()
  for (local i=0; i<num; ++i)
  {
    local p=cpos+make_dir_xz((i+srnd()*0.1)/num+ofs)*(rad*(1+srnd()*0.04));
    (frnd()<0.5?Menhir1StaticObject:Menhir2StaticObject)(getx(p), getz(p))
  }
}


function new_magic_place()
{
  local cls=MagicCircle
  local rad=rndf(5, 20)

  local action=null, opt=(frnd()<0.5)
  local r=frnd()
  if (r<0.05) { action=spawn_spell; opt=true }
  else if (r<0.10) { action=spawn_mana; opt=true }
  else if (r<0.40) action=spawn_wyverns
  else if (r<0.70) action=spawn_caterpillars
  else action=spawn_birds

  // action=spawn_caterpillars //==

  if (!spell_place) { action=spawn_spell; opt=true }

  if (action==spawn_spell)
  {
    r=frnd()
    if (r<0.3)
    {
      cls=StoneCupCircle
      rad=rndf(10, 15)
    }
    else if (r<0.6)
    {
      cls=TreeCircle
      rad=rndf(20, 30)
    }
  }

  local p=cls(hmrnd(), hmrnd(), rad, action)
  p.optional=opt
  if (action==spawn_spell) spell_place=p.weakref()
  return p;
}


function check_portal()
{
  if (!portal_place || !portal_place.action) return;

  if (!cur_world || !cur_world.activated)
  {
    foreach (p in places)
      if (!p.optional && !p.activated) return;

    if (are_any_monsters_alive()) return;
  }

  portal_place.action=spawn_portal
  portal_place.action()
}


function check_conditions()
{
  check_portal()
}


function create_magic_places()
{
  local iter=1000

  local p=null
  for (;;)
  {
    if (--iter<0) break; //== fatal error?

    p=MagicCircle(hmrnd(), hmrnd(), rndf(10, 15), check_portal)
    if (!p.canFit()) { p.destroy(); continue; }

    places.append(p)
    portal_place=p.weakref()
    break;
  }

  for (local num=irnd()%5+5; num>0; )
  {
    if (--iter<0) break; //== fatal error?

    local np=new_magic_place()

    local ok=true
    if (!np.canFit()) ok=false
    if (ok) foreach (p in places)
      if (np.intersects(p)) { ok=false; break; }

    if (!ok) { np.destroy(); continue; }

    places.append(np)
    --num
  }
}
