grendel-1.0.0a7/backup/
grendel-1.0.0a7/bin/
grendel-1.0.0a7/boards/
grendel-1.0.0a7/clans/
grendel-1.0.0a7/documentation/todo/
grendel-1.0.0a7/help/
grendel-1.0.0a7/logs/
grendel-1.0.0a7/players/
grendel-1.0.0a7/progs/
grendel-1.0.0a7/races/
grendel-1.0.0a7/src/contrib/
grendel-1.0.0a7/src/modules/speller/
grendel-1.0.0a7/src/modules/status/
grendel-1.0.0a7/src/tests/
grendel-1.0.0a7/src/tests/dunit/
{
  Summary:
  	Timer class
    
  ## $Id: timers.pas,v 1.12 2004/04/01 13:04:32 druid Exp $
}

unit timers;

interface


uses
{$IFDEF WIN32}
	Windows,
{$ENDIF}
	SysUtils,
	Classes,
	skills,
	dtypes,
	chars;


type
	TIMER_FUNC = procedure;
	SPEC_FUNC = procedure(ch, victim : GCharacter; sn : GSkill);

	GTimer = class
	private
		_name : string;
		_counter : integer;
		timer_func : TIMER_FUNC;
		timeout : integer;
		looping : boolean;

	published
		constructor Create(const name_ : string; func_ : TIMER_FUNC; timeout_ : integer; looping_ : boolean);
		
		property name : string read _name;
		property counter : integer read _counter write _counter;
	end;

	GSpecTimer = class (GTimer)
	private
		spec_func : SPEC_FUNC;
		ch, victim : GCharacter;
		timer_type : integer;
		sn : GSkill;

	published
		constructor Create(const name_ : string; timer_type_ : integer; func_ : SPEC_FUNC; timeout_ : integer; ch_, victim_ : GCharacter; sn_ : GSkill);
	end;

	GTimerThread = class (TThread)
	private
		last_update : TDateTime;

	protected
		procedure Execute; override;
	
	published
		constructor Create();
		
		property lastUpdate : TDateTime read last_update;
	end;


var
	timer_list : GDLinkedList;


procedure registerTimer(const name : string; func : TIMER_FUNC; timeout : integer; looping : boolean); overload;
procedure registerTimer(const name : string; timer_type : integer; func : SPEC_FUNC; timeout : integer; ch, victim : GCharacter; sn : GSkill); overload;

procedure unregisterTimer(const name_ : string); overload;
procedure unregisterTimer(ch : GCharacter; timer_type : integer); overload;

function hasTimer(ch : GCharacter; timer_type : integer) : GTimer; overload;
function hasTimer(ch : GCharacter; const timer_name : string) : GTimer; overload;

procedure initTimers();
procedure cleanupTimers();


implementation


uses
{$IFDEF WIN32}
	Winsock2,
{$ENDIF}
	constants,
	console,
	mudsystem,
	util,
	commands,
	update,
	area,
	debug,
	conns,
	player,
	server,
	Channels;


// GTimer
constructor GTimer.Create(const name_ : string; func_ : TIMER_FUNC; timeout_ : integer; looping_ : boolean);
begin
  inherited Create;

  Self._name := name_;
  Self._counter := timeout_;
  Self.timer_func := func_;
  Self.timeout := timeout_;
  Self.looping := looping_;
end;

// GSpecTimer
constructor GSpecTimer.Create(const name_ : string; timer_type_ : integer; func_ : SPEC_FUNC; timeout_ : integer; ch_, victim_ : GCharacter; sn_ : GSkill);
begin
  inherited Create(name_, nil, timeout_, false);

  Self.spec_func := func_;
  Self.timer_type := timer_type_;
  Self.ch := ch_;
  Self.victim := victim_;
  Self.sn := sn_;
end;


// GTimerThread
constructor GTimerThread.Create();
begin
  inherited Create(false);

  last_update := Now();
end;

{ TODO remove nodes }
procedure GTimerThread.Execute();
var
   node, node_next : GListNode;
   timer : GTimer;
   spec : GSpecTimer;
begin
  while (not Terminated) do
    begin
    last_update := Now();

    node := timer_list.head;

    while (node <> nil) do
      begin
      timer := GTimer(node.element);
      node_next := node.next;

      try
        dec(timer._counter);

        if (timer._counter = 0) then
          begin
          if (timer is GSpecTimer) then
            begin
            spec := GSpecTimer(timer);

            if (assigned(spec.spec_func)) then
              spec.spec_func(spec.ch, spec.victim, spec.sn);
            end
          else
            if (assigned(timer.timer_func)) then
              timer.timer_func;

          if (not timer.looping) then
            begin
            timer_list.remove(node);
            timer.Free();
            end
          else
            timer._counter := timer.timeout;
          end;
      except
        on E : Exception do	
        	begin
        	reportException(E, 'GTimerThread.Execute');
            timer_list.remove(node);
            timer.Free();
        	end;
      end;

      node := node_next;
      end;

    Sleep(250);
    end;
end;

procedure registerTimer(const name : string; func : TIMER_FUNC; timeout : integer; looping : boolean);
var
   timer : GTimer;
begin
  timer := GTimer.Create(name, func, timeout, looping);

  timer_list.insertLast(timer);
end;

procedure registerTimer(const name : string; timer_type : integer; func : SPEC_FUNC; timeout : integer; ch, victim : GCharacter; sn : GSkill);
var
   timer : GSpecTimer;
begin
  timer := GSpecTimer.Create(name, timer_type, func, timeout, ch, victim, sn);

  timer_list.insertLast(timer);
end;

{ TODO remove nodes }
procedure unregisterTimer(const name_ : string);
var
   timer : GTimer;
   node : GListNode;
begin
  node := timer_list.head;

  while (node <> nil) do
    begin
    timer := GTimer(node.element);

    if (timer.name = name_) then
      begin
      timer_list.remove(node);
      timer.Free();
      break;
      end;

    node := node.next;
    end;
end;

{ TODO remove nodes }
procedure unregisterTimer(ch : GCharacter; timer_type : integer);
var
   timer : GTimer;
   spec : GSpecTimer;
   node : GListNode;
begin
  node := timer_list.head;

  while (node <> nil) do
    begin
    timer := GTimer(node.element);

    if (timer is GSpecTimer) then
      begin
      spec := GSpecTimer(timer);

      if (spec.ch = ch) and (spec.timer_type = timer_type) then
        begin
        timer_list.remove(node);
        timer.Free();
        break;
        end;
      end;

    node := node.next;
    end;
end;

function hasTimer(ch : GCharacter; timer_type : integer) : GTimer;
var
  timer : GTimer;
  spec : GSpecTimer;
  iterator : GIterator;
begin
  Result := nil;

  iterator := timer_list.iterator();

  while (iterator.hasNext()) do
    begin
    timer := GTimer(iterator.next());

    if (timer is GSpecTimer) then
      begin
      spec := GSpecTimer(timer);

      if (spec.ch = ch) and (spec.timer_type = timer_type) and (spec.counter > 0) then
        begin
        Result := timer;
        break;
        end;
      end;
    end;
    
  iterator.Free();
end;

function hasTimer(ch : GCharacter; const timer_name : string) : GTimer;
var
  timer : GTimer;
  spec : GSpecTimer;
  iterator : GIterator;
begin
  Result := nil;

  iterator := timer_list.iterator();

  while (iterator.hasNext()) do
    begin
    timer := GTimer(iterator.next());

    if (timer is GSpecTimer) then
      begin
      spec := GSpecTimer(timer);

      if (spec.ch = ch) and (spec.name = timer_name) and (spec.counter > 0) then
        begin
        Result := timer;
        break;
        end;
      end;
    end;
    
  iterator.Free();
end;

// main timers
procedure update_auction;
begin
  if (auction_good.pulse > 0) then
    dec(auction_good.pulse)
  else
  if (auction_good.item <> nil) then
    begin
    auction_good.update;
    auction_good.pulse := CPULSE_AUCTION;
    end;

  if (auction_evil.pulse > 0) then
    dec(auction_evil.pulse)
  else
  if (auction_evil.item <> nil) then
    begin
    auction_evil.update;
    auction_evil.pulse := CPULSE_AUCTION;
    end;
end;

procedure update_main();
var
  iterator : GIterator;
  conn : GPlayerConnection;
begin
  iterator := connection_list.iterator();

  while (iterator.hasNext()) do
    begin
    conn := GPlayerConnection(iterator.next());

		conn.pulse();
    end;
    
  iterator.Free();
end;

procedure update_gamehour();
var
  iterator : GIterator;
  area : GArea;
  ch : GCharacter;
begin
{$IFDEF WIN32}
  status := GetHeapStatus;
{$ENDIF}

  update_affects;
  update_tracks;

  { update age of areas and reset if hit timer }
  iterator := area_list.iterator();
  
  while (iterator.hasNext()) do
    begin
    area := GArea(iterator.next());

    area.update();
    end;
  
  iterator.Free();

  iterator := char_list.iterator();
  
  while (iterator.hasNext()) do
    begin
    ch := GCharacter(iterator.next());

    if (not ch.IS_NPC) and (IS_SET(GPlayer(ch).flags, PLR_LINKLESS)) then
      begin
      inc(GPlayer(ch).ld_timer);

      if (GPlayer(ch).ld_timer > IDLE_LINKDEAD) then
        begin
        GPlayer(ch).quit;
        continue;
        end;
      end;
    end;
  
  iterator.Free();
end;

procedure update_sec();
begin
	calculateonline();
	
	if (bg_info.count > 0) then
		begin
		dec(bg_info.count);

		case bg_info.count of
			60,30,10,5,2 : battlegroundMessage();
			0 : startBattleground();
		end;
		end;

	regenerate_chars();
end;

procedure initTimers();
begin
  timer_list := GDLinkedList.Create();

  registerTimer('main', update_main, 1, true);
  registerTimer('auction', update_auction, 1, true);
  registerTimer('gamehour', update_gamehour, CPULSE_GAMEHOUR, true);
  registerTimer('second', update_sec, CPULSE_PER_SEC, true);
end;

procedure cleanupTimers();
begin
  timer_list.clear();
  timer_list.Free();
end;

end.