// $Id: timers.pas,v 1.12 2001/05/11 14:24:24 druid Exp $ unit timers; interface uses Windows, SysUtils, Classes, skills, dtypes, chars; type TIMER_FUNC = procedure; SPEC_FUNC = procedure(ch, victim : GCharacter; sn : GSkill); GTimer = class name : string; timer_func : TIMER_FUNC; counter, timeout : integer; looping : boolean; constructor Create(name_ : string; func_ : TIMER_FUNC; timeout_ : integer; looping_ : boolean); end; GSpecTimer = class (GTimer) spec_func : SPEC_FUNC; ch, victim : GCharacter; timer_type : integer; sn : GSkill; constructor Create(timer_type_ : integer; func_ : SPEC_FUNC; timeout_ : integer; ch_, victim_ : GCharacter; sn_ : GSkill); end; GTimerThread = class (TThread) last_update : TDateTime; procedure Execute; override; constructor Create; end; var timer_list : GDLinkedList; procedure registerTimer(name_ : string; func_ : TIMER_FUNC; timeout_ : integer; looping_ : boolean); overload; procedure registerTimer(timer_type_ : integer; func_ : SPEC_FUNC; timeout_ : integer; ch_, victim_ : GCharacter; sn_ : GSkill); overload; procedure unregisterTimer(name_ : string); overload; procedure unregisterTimer(ch : GCharacter; timer_type : integer); overload; function hasTimer(ch : GCharacter; timer_type : integer) : GTimer; implementation uses Winsock2, constants, mudsystem, util, mudthread, update, debug, area, conns, Channels; // GTimer constructor GTimer.Create(name_ : string; func_ : TIMER_FUNC; timeout_ : integer; looping_ : boolean); begin inherited Create; name := name_; timer_func := func_; timeout := timeout_; counter := timeout_; looping := looping_; end; // GSpecTimer constructor GSpecTimer.Create(timer_type_ : integer; func_ : SPEC_FUNC; timeout_ : integer; ch_, victim_ : GCharacter; sn_ : GSkill); begin inherited Create(timer_names[timer_type_], nil, timeout_, false); spec_func := func_; timer_type := timer_type_; ch := ch_; victim := victim_; sn := sn_; end; // GTimerThread constructor GTimerThread.Create; begin inherited Create(false); end; 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 := 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 : EExternal do begin bugreport('GTimerThread.Execute', 'timers.pas', 'Timer "' + timer.name + '" failed to execute correctly', 'Timer "' + timer.name + '" failed to execute correctly'); outputError(E); end else bugreport('GTimerThread.Execute', 'timers.pas', 'Timer "' + timer.name + '" failed to execute correctly', 'Timer "' + timer.name + '" failed to execute correctly'); { if (timer is GSpecTimer) then begin timer_list.remove(node); timer.Free; end else timer.counter := timer.timeout; } end; node := node_next; end; Sleep(250); end; end; procedure registerTimer(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(timer_type_ : integer; func_ : SPEC_FUNC; timeout_ : integer; ch_, victim_ : GCharacter; sn_ : GSkill); overload; var timer : GSpecTimer; begin timer := GSpecTimer.Create(timer_type_, func_, timeout_, ch_, victim_, sn_); timer_list.insertLast(timer); end; procedure unregisterTimer(name_ : string); var timer : GTimer; node : GListNode; begin node := timer_list.head; while (node <> nil) do begin timer := node.element; if (timer.name = name_) then begin timer_list.remove(node); timer.Free; break; end; node := node.next; end; end; 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 := 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; node : GListNode; begin Result := nil; node := timer_list.head; while (node <> nil) do begin timer := node.element; if (timer is GSpecTimer) then begin spec := GSpecTimer(timer); if (spec.ch = ch) and (spec.timer_type = timer_type) then begin Result := timer; break; end; end; node := node.next; end; 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 node, node_next : GListNode; conn : GConnection; begin node := connection_list.head; while (node <> nil) do begin node_next := node.next; conn := node.element; inc(conn.idle); if (((conn.state = CON_NAME) and (conn.idle > IDLE_NAME)) or ((conn.state <> CON_PLAYING) and (conn.idle > IDLE_NOT_PLAYING)) or (conn.idle > IDLE_PLAYING)) and ((conn.ch <> nil) and (not conn.ch.IS_IMMORT)) then begin conn.send(#13#10'You have been idle too long. Disconnecting.'#13#10); conn.thread.terminate; node := node_next; continue; end; if (conn.state=CON_PLAYING) and (not conn.ch.in_command) then GPlayer(conn.ch).emptyBuffer; if (conn.state=CON_PLAYING) and (conn.ch.wait>0) then dec(conn.ch.wait); node := node_next; end; end; procedure update_gamehour; var node, node_next : GListNode; area : GArea; ch : GCharacter; begin status := GetHeapStatus; update_affects; update_tracks; { update age of areas and reset if hit timer } node := area_list.head; while (node <> nil) do begin area := node.element; area.update; node := node.next; end; node := char_list.head; while (node <> nil) do begin ch := node.element; node_next := node.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 node := node_next; GPlayer(ch).quit; continue; end; end; node := node_next; end; end; procedure update_sec; begin calculateonline; if (boot_info.timer >= 0) then begin dec(boot_info.timer); case boot_info.timer of 60,30,10,5 : begin case boot_info.boot_type of BOOTTYPE_SHUTDOWN:begin write_log(inttostr(boot_info.timer)+' seconds till shutdown'); to_channel(nil, '$B$1 ---- Server $3shutdown$1 in $7' + inttostr(boot_info.timer) + '$1 seconds! ----',CHANNEL_ALL,AT_REPORT); end; BOOTTYPE_REBOOT:begin write_log(inttostr(boot_info.timer)+' seconds till reboot'); to_channel(nil, '$B$1 ---- Server $3reboot$1 in $7' + inttostr(boot_info.timer) + '$1 seconds! ----',CHANNEL_ALL,AT_REPORT); end; BOOTTYPE_COPYOVER:begin write_log(inttostr(boot_info.timer)+' seconds till reboot'); to_channel(nil, '$B$1 ---- Server $3copyover$1 in $7' + inttostr(boot_info.timer) + '$1 seconds! ----',CHANNEL_ALL,AT_REPORT); end; end; end; 0 : begin case boot_info.boot_type of BOOTTYPE_SHUTDOWN:begin write_log('Timer reached zero, starting shutdown now'); to_channel(nil, '$B$1 ---- Server will $3shutdown $7NOW!$1 ----',CHANNEL_ALL,AT_REPORT); end; BOOTTYPE_REBOOT:begin write_log('Timer reached zero, starting reboot now'); to_channel(nil, '$B$1 ---- Server will $3reboot $7NOW!$1 ----',CHANNEL_ALL,AT_REPORT); end; BOOTTYPE_COPYOVER:begin write_log('Timer reached zero, starting copyover now'); to_channel(nil, '$B$1 ---- Server will $3copyover $7NOW!$1 ----',CHANNEL_ALL,AT_REPORT); end; end; boot_type := boot_info.boot_type; grace_exit := true; halt; end; end; end; 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; 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.