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:
		Character update & regeneration routines
		
	## $Id: update.pas,v 1.8 2004/03/26 21:14:27 hemko Exp $
}

unit update;

interface

uses
	chars,
	dtypes,
	area,
	constants,
	util,
	timers,
	skills;


procedure regenerate_chars();

procedure update_chars();
procedure update_tracks();
procedure update_teleports();
procedure update_time();

procedure gain_condition(ch : GCharacter; iCond, value : integer);

procedure battlegroundMessage();
procedure startBattleground();
procedure update_battleground();

procedure update_objects();

implementation

uses
	SysUtils,
	mudsystem,
	commands,
	fight,
	conns,
	player,
	Channels;


// Regenerate characters
procedure regenerate_chars();
var 
	hp_gain, mv_gain, mana_gain : integer;
	ch : GCharacter;
	iterator : GIterator;
begin
  iterator := char_list.iterator();

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

    hp_gain:=0; mv_gain:=0; mana_gain:=0;

    if (not ch.IS_NPC) then
    with ch do
      begin
      case state of
            STATE_SLEEPING: begin
                            hp_gain:=9;
                            mv_gain:=7;
                            mana_gain:=3;
                            end;
             STATE_RESTING: begin
                            hp_gain:=7;
                            mv_gain:=9;
                            mana_gain:=4;
                            end;
          STATE_MEDITATING: begin
                            hp_gain:=6;
                            mv_gain:=6;
                            mana_gain:=10;
                            end;
                STATE_IDLE: begin
                            hp_gain:=2;
                            mv_gain:=2;
                            mana_gain:=1;
                            end;
        	STATE_FIGHTING: begin
                            hp_gain:=0;
                            mv_gain:=1;
                            mana_gain:=0;
                            end;
      end;

      if IS_SET(ch.aff_flags,AFF_POISON) then
        begin
        hp_gain := hp_gain div 4;
        mv_gain := mv_gain div 3;
        mana_gain := mana_gain div 2;
        end;

      if (ch.room.flags.isBitSet(ROOM_MANAROOM)) then
        mana_gain := mana_gain*2;

      hp := UMin(hp + hp_gain, max_hp);
      mv := UMin(mv + mv_gain, max_mv);
      mana := UMin(mana + mana_gain, max_mana);
      end
		else
			begin
			// update progress of running gmc scripts
		
			GNPC(ch).context.run();
			end;
    end;
		
  iterator.Free();
end;

// Update the time
procedure update_time();
var 
	buf : string;
	iterator : GIterator;
	ch : GCharacter;
begin
  inc(time_info.hour);
  buf := '';

  case time_info.hour of
    1:begin
      time_info.sunlight := SUN_DARK;
      buf := 'The moon sets.';
      end;
    5:begin
      time_info.sunlight:=SUN_DAWN;
      buf := 'The day has begun.';
      end;
    6:begin
      time_info.sunlight:=SUN_RISE;
      buf := 'The sun rises in the east.';
      end;
   12:begin
      time_info.sunlight:=SUN_LIGHT;
      buf := 'It''s noon.';
      end;
   19:begin
      time_info.sunlight:=SUN_SET;
      buf := 'The sun slowly disappears in the west.';
      end;
   20:begin
      time_info.sunlight:=SUN_MOON;
      buf := 'The night has begun, the moon slowly rises.';
      end;
   24:begin
      time_info.hour:=0;
      inc(time_info.day);
      end;
  end;

  if (time_info.day>=30) then
    begin
    time_info.day:=1;
    inc(time_info.month);
    end;

  if (time_info.month>=17) then
    begin
    time_info.month:=1;

    { it wouldn't be Grendel without this :) - Grimlord }
    to_channel(nil, 'The sky lights up with colorful flashes, created by the firework masters.'#13#10, CHANNEL_ALL, AT_GREY);

    inc(time_info.year);
    end;

  if (length(buf) > 0) then
    begin
    iterator := char_list.iterator();
    
    while (iterator.hasNext()) do
    	begin
    	ch := GCharacter(iterator.next());
    	
    	if (ch.IS_NPC) then
    		continue;
    		
    	if (ch.IS_OUTSIDE) and (ch.IS_AWAKE) then
        act(AT_REPORT,buf,false,ch,nil,nil,TO_CHAR);    		
    	end;
    
    iterator.Free();
    end;
end;

// Improve mental state
procedure better_mental_state(ch : GCharacter; modifier : integer);
var
	c : integer;
begin
  c := URANGE(0, abs(modifier), 20);
  
  if (number_percent < ch.con) then
    inc(c);
  if (ch.mental_state < 0) then
    ch.mental_state := URANGE(-MAX_COND, ch.mental_state + c, 0)
  else
  if (ch.mental_state > 0) then
    ch.mental_state := URANGE(0, ch.mental_state-c, MAX_COND);
end;

// Worsen mental state
procedure worsen_mental_state(ch : GCharacter; modifier : integer);
var
	c : integer;
begin
  c := URANGE(0, abs(modifier), 20);
  
  if (number_percent < ch.con) then
    dec(c);
  if (c<1) then exit;
  if (ch.mental_state < 0) then
    ch.mental_state := URANGE(-MAX_COND, ch.mental_state-c, MAX_COND)
  else
  if (ch.mental_state > 0) then
    ch.mental_state := URANGE(-MAX_COND, ch.mental_state+c, MAX_COND)
  else
    dec(ch.mental_state,c);
end;

procedure gain_condition(ch : GCharacter; iCond, value : integer);
var
	condition, retcode : integer;
begin
  if (value = 0) or (ch.IS_NPC) or (ch.IS_IMMORT) then
    exit;

  condition := GPlayer(ch).condition[iCond];
  GPlayer(ch).condition[iCond]:=URANGE(0, condition+value, MAX_COND);

  retcode := RESULT_NONE;

  if (GPlayer(ch).condition[iCond]=0) then
    case iCond of
       COND_FULL:begin
                 act(AT_REPORT,'You are STARVING!',false,ch,nil,nil,TO_CHAR);
                 act(AT_REPORT,'$n is starving and looks awfully weak!',false,ch,nil,nil,TO_ROOM);
                 worsen_mental_state(ch,1);

                 retcode:=damage(ch,ch,1,TYPE_SILENT);
                 end;
     COND_THIRST:begin
                 act(AT_REPORT,'You are DYING of THIRST!',false,ch,nil,nil,TO_CHAR);
                 act(AT_REPORT,'$n is dying of thirst!',false,ch,nil,nil,TO_ROOM);
                 worsen_mental_state(ch,2);
                 retcode:=damage(ch,ch,2,TYPE_SILENT);
                 end;
      COND_DRUNK:begin
                 if condition<>0 then
                   act(AT_REPORT,'You are sober again.',false,ch,nil,nil,TO_CHAR);
                 retcode:=RESULT_NONE;
                 end;
       COND_HIGH:begin
                 if condition<>0 then
                   act(AT_REPORT,'Your mind stops floating and resumes its normal course.',false,ch,nil,nil,TO_CHAR);
                 retcode:=RESULT_NONE;
                 end;
   COND_CAFFEINE:begin
                 if condition<>0 then
                   act(AT_REPORT,'Your vains are clear of caffeine... you are less tense.',false,ch,nil,nil,TO_CHAR);
                 retcode:=RESULT_NONE;
                 end;
      else begin
           bugreport('gain_condition', 'update.pas', 'invalid condition: '+inttostr(icond));
           retcode:=RESULT_NONE;
           end;
    end;

  if (retcode<>RESULT_NONE) then               { don't want to continue when ch is dead }
    exit;

  if (GPlayer(ch).condition[iCond]=3) then
    case iCond of
       COND_FULL:begin
                 act(AT_REPORT,'You are getting really hungry.',false,ch,nil,nil,TO_CHAR);
                 act(AT_REPORT,'You can hear $n''s stomach growling, $e must be hungry.',false,ch,nil,nil,TO_ROOM);
                 if random(2)=0 then
                   worsen_mental_state(ch,1);
                 end;
     COND_THIRST:begin
                 act(AT_REPORT,'You are getting really thirsty.',false,ch,nil,nil,TO_CHAR);
                 act(AT_REPORT,'$n gasps and looks thirsty.',false,ch,nil,nil,TO_ROOM);
                 worsen_mental_state(ch,1);
                 end;
      COND_DRUNK:if condition<>0 then
                   act(AT_REPORT,'The world is coming back into perspective.',false,ch,nil,nil,TO_CHAR);
       COND_HIGH:if condition<>0 then
                   act(AT_REPORT,'You are slowly returning from outer space...',false,ch,nil,nil,TO_CHAR);
    end;

  if (GPlayer(ch).condition[iCond]=8) then
    case iCond of
       COND_FULL:act(AT_REPORT,'You are hungry.',false,ch,nil,nil,TO_CHAR);
     COND_THIRST:act(AT_REPORT,'You are thirsty.',false,ch,nil,nil,TO_CHAR);
      COND_DRUNK:if condition<>0 then
                   act(AT_REPORT,'You feel a bit less light headed.',false,ch,nil,nil,TO_CHAR);
       COND_HIGH:if condition<>0 then
                   act(AT_REPORT,'Slowly but surely, your high is starting to wear off.',false,ch,nil,nil,TO_CHAR);
    end;

  if (GPlayer(ch).condition[iCond]=16) then
    case iCond of
       COND_FULL:act(AT_REPORT,'You could use a bite of something.',false,ch,nil,nil,TO_CHAR);
     COND_THIRST:act(AT_REPORT,'A drink would be nice.',false,ch,nil,nil,TO_CHAR);
      COND_DRUNK:act(AT_REPORT,'You feel as if little pixies feast inside your skull.',false,ch,nil,nil,TO_CHAR);
    end;
end;

// Update characters
procedure update_chars();
var 
	p : integer;
	ch : GCharacter;
	e : GExit;
	r : GRoom;
	iterator : GIterator;
begin
  iterator := char_list.iterator();

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

    
    if (ch.IS_NPC) then
      begin
      { switched mobs don't wander }
      if (ch.snooped_by <> nil) and (GPlayer(ch.snooped_by).switching = ch) then
      	continue;
      
      if (not IS_SET(GNPC(ch).act_flags, ACT_SENTINEL)) and (ch.state = STATE_IDLE) then
        begin
        p := random(6)+1;

        e := ch.room.findExit(p);

        if (e <> nil) then
          begin
          r := findRoom(e.vnum);

          if (r <> nil) and not (IS_SET(GNPC(ch).act_flags, ACT_STAY_AREA) and (r.area <> ch.room.area)) then
            interpret(ch, headings[p]);
          end;
        end;

      GNPC(ch).context.runSymbol('onTick', [integer(ch)]);
      end
    else
    if (not ch.IS_NPC) then
      begin
      if (GPlayer(ch).condition[COND_DRUNK] > 8) then
        worsen_mental_state(ch,GPlayer(ch).condition[COND_DRUNK] div 8);

      if (GPlayer(ch).condition[COND_FULL] > 1) then
        case ch.position of
              STATE_SLEEPING: better_mental_state(ch, 4);
               STATE_RESTING: better_mental_state(ch, 3);
                  STATE_IDLE: better_mental_state(ch, 2);
          	  STATE_FIGHTING: if (random(4) = 0) then
                                better_mental_state(ch, 1);
        end;

      if (GPlayer(ch).condition[COND_THIRST] > 1) then
        case ch.position of
              STATE_SLEEPING: better_mental_state(ch, 5);
               STATE_RESTING: better_mental_state(ch, 3);
                  STATE_IDLE: better_mental_state(ch, 2);
              STATE_FIGHTING: if (random(4) = 0) then
                                better_mental_state(ch, 1);
        end;
        
      gain_condition(ch,COND_DRUNK, -1);
      gain_condition(ch,COND_HIGH, -1);
      gain_condition(ch,COND_FULL, -1);

      case ch.room.sector of
            SECT_DESERT:gain_condition(ch,COND_THIRST,-2);
        SECT_UNDERWATER,
        SECT_OCEANFLOOR:if random(2)=0 then
                          gain_condition(ch,COND_THIRST,-1);
        else gain_condition(ch,COND_THIRST,-1);
      end;
      if (ch.mental_state>=30) then
        case (ch.mental_state+5) div 10 of
           3:begin
             act(AT_REPORT,'You feel chilly and not well.',false,ch,nil,nil,TO_CHAR);
             act(AT_REPORT,'$n doesn''t look $s normal self.',false,ch,nil,nil,TO_ROOM);
             end;
           4:begin
             act(AT_REPORT,'You don''t feel good at all.',false,ch,nil,nil,TO_CHAR);
             act(AT_REPORT,'$n doesn''t look too good.',false,ch,nil,nil,TO_ROOM);
             end;
           5:begin
             act(AT_REPORT,'You need help immediately!',false,ch,nil,nil,TO_CHAR);
             act(AT_REPORT,'$n looks like $e could use your help.',false,ch,nil,nil,TO_ROOM);
             end;
           6:begin
             act(AT_REPORT,'You are in BAD shape, get a healer!',false,ch,nil,nil,TO_CHAR);
             act(AT_REPORT,'$n looks awful and could use assistance.',false,ch,nil,nil,TO_ROOM);
             end;
           7:begin
             act(AT_REPORT,'You lose your grip on reality... what is happening?',false,ch,nil,nil,TO_CHAR);
             act(AT_REPORT,'$n seems unaware of the world and $s surroundings.',false,ch,nil,nil,TO_ROOM);
             end;
           8:begin
             act(AT_REPORT,'Understanding and knowledge flow through your mind.',false,ch,nil,nil,TO_CHAR);
             act(AT_REPORT,'$n runs about, babbling like an escaped madman!',false,ch,nil,nil,TO_ROOM);
             end;
           9:begin
             act(AT_REPORT,'You feel like... Thor.',false,ch,nil,nil,TO_CHAR);
             act(AT_REPORT,'$n stands ranting about $s immortality.',false,ch,nil,nil,TO_ROOM);
             end;
          10:begin
             act(AT_REPORT,'Your brain is a cloud of fog... you are dying.',false,ch,nil,nil,TO_CHAR);
             act(AT_REPORT,'$n kneels down, muttering and chanting in tongues...',false,ch,nil,nil,TO_ROOM);
             end;
        end;
      end;
    end; 
    
  iterator.Free();
end;

procedure teleportChar(ch : GCharacter;room:GRoom);
begin
  if (room.flags.isBitSet(ROOM_PRIVATE)) then
    exit;

  act(AT_REPORT,'$n disappears suddenly!',false,ch,nil,nil,TO_ROOM);
  act(AT_REPORT,'You feel dizzy as you are transferred to another place...',false,ch,nil,nil,TO_CHAR);

  ch.fromRoom;
  ch.toRoom(room);

  act(AT_REPORT,'$n appears in a puff of smoke.',false,ch,nil,nil,TO_ROOM);
  interpret(ch,'look _AUTO');
end;

// Update tracks
procedure update_tracks();
var
	iterator_room : GIterator;
	node_track, node_tracknext : GListNode;
	room : GRoom;
	track : GTrack;
begin
	iterator_room := room_list.iterator();
	
	while (iterator_room.hasNext()) do
		begin
		room := GRoom(iterator_room.next());
		node_track := room.tracks.head;

		while (node_track <> nil) do
			begin
			node_tracknext := node_track.next;

			track := GTrack(node_track.element);

			dec(track.life);

			if (track.life = 0) then
				begin
				room.tracks.remove(node_track);
				track.Free();
				end;

			node_track := node_tracknext;
			end;
		end;
		
	iterator_room.Free();
end;

// Update teleports
procedure update_teleports();
var 
	tele : GTeleport;
	room, dest : GRoom;
	iterator : GIterator;
begin
  iterator := teleport_list.iterator();

  while (iterator.hasNext()) do
    begin
    tele := GTeleport(iterator.next());

    dec(tele.timer);

    if (tele.timer = 0) then
      begin
      room := tele.t_room;
      dest := findRoom(room.televnum);

      while (room.chars.size() > 0) do
        teleportChar(GCharacter(room.chars.head.element), dest);

      teleport_list.remove(tele.node);
      end;
    end;
    
  iterator.Free();
end;

{ procedure update_timers;
var
   timer : GTimer;
   node, node_next : GListNode;
begin
  node := timer_list.head;
  while (node <> nil) do
    begin
    timer := node.element;
    node_next := node.next;

    dec(timer.rounds);

    if (timer.rounds = 0) then
      begin
      timers.remove(node);

      if assigned(timer.spec_func) then
        timer.spec_func(timer.ch,timer.victim,timer.sn);

      timer.Free;
      end;

    node := node_next;
    end;
end; }

procedure battlegroundMessage();
begin
  if (bg_info.prize<>nil) then
    to_channel(nil,pchar('[$B$7Battleground starting in '+inttostr(bg_info.count)+' seconds$A$7]'#13#10+
               'Allowed levels: '+inttostr(bg_info.lo_range)+
               '-'+inttostr(bg_info.hi_range)+'  Prize: '+ GObject(bg_info.prize).short),CHANNEL_ALL,AT_REPORT)
  else
    to_channel(nil,pchar('[$B$7Battleground starting in '+inttostr(bg_info.count)+' seconds$A$7]'#13#10+
               'Allowed levels: '+inttostr(bg_info.lo_range)+
               '-'+inttostr(bg_info.hi_range)),CHANNEL_ALL,AT_REPORT)
end;

procedure startBattleground();
var 
	iterator : GIterator;
	ch : GCharacter;
	s,vnum:integer;
begin
  to_channel(nil,pchar('[$B$7Battleground starting NOW!$A$7]'),CHANNEL_ALL,AT_REPORT);

	iterator := char_list.iterator();

  while (iterator.hasNext()) do
    begin
    ch := GCharacter(iterator.next());
    
    if (ch.IS_NPC) then
    	continue;

    if (GPlayer(ch).conn.isPlaying) and (GPlayer(ch).bg_status = BG_JOIN)
     and (ch.level >= bg_info.lo_range) and (ch.level <= bg_info.hi_range) then
      begin
      act(AT_REPORT,'You are transfered into the arena.',false,ch,nil,nil,TO_CHAR);
      act(AT_GREEN,'Niet mokken, lekker knokken!',false,ch,nil,nil,TO_CHAR);

      s := random(system_info.arena_end - system_info.arena_start + 1) + system_info.arena_start;
      vnum := URange(system_info.arena_start, s, system_info.arena_end);

      GPlayer(ch).bg_room := ch.room;

      ch.fromRoom();
      ch.toRoom(findRoom(vnum));

      GPlayer(ch).bg_status := BG_PARTICIPATE;
      interpret(ch,'look');
      end;
    end;
    
  iterator.Free();
end;

procedure update_battleground();
var 
	s : integer;
	ch, last : GCharacter;
	iterator : GIterator;
begin
  { battleground is running, check to see if we have a winner }
  if (bg_info.count = 0) then
    begin
    last := nil;
    s := 0;

		iterator := char_list.iterator();
		
		while (iterator.hasNext()) do
      begin
      ch := GCharacter(iterator.next());
      
      if (ch.IS_NPC) then
      	continue;

      if (GPlayer(ch).conn.isPlaying()) and (GPlayer(ch).bg_status = BG_PARTICIPATE) then
        begin
        inc(s);
        last := ch;
        end;
      end;

    if (s = 0) then
      begin
      to_channel(nil,'[$B$7Battleground stopped without a winner.$A$7]',CHANNEL_ALL,AT_REPORT);
      bg_info.count := -1;
      end
    else
    if (s = 1) then
      begin
      to_channel(nil,'[$B$3'+last.name+'$B$7 has won the battleground!$A$7]',CHANNEL_ALL,AT_REPORT);
      act(AT_REPORT,'Congratulations! You have won the battleground!',false,last,nil,nil,TO_CHAR);

      inc(GPlayer(last).bg_points,3);

      last.fromRoom();
      last.toRoom(GPlayer(last).bg_room);

      if (bg_info.prize <> nil) then
        begin
        act(AT_REPORT,'You have won $p.', false, last, bg_info.prize, nil, TO_CHAR);

        GObject(bg_info.prize).toChar(last);
        end;

      interpret(last, 'look');
      GPlayer(last).bg_status := BG_NOJOIN;
      last.hp := last.max_hp;

      bg_info.winner := last;
      bg_info.count := -1;
      bg_info.prize := nil;
      end;
    end;
end;

// Update objects
procedure update_objects();
var 
  obj : GObject;
  rch : GCharacter;
  msg : string;
  at_temp : integer;
  iterator : GIterator;
begin
  iterator := objectList.iterator();

  while (iterator.hasNext()) do
    begin
    obj := GObject(iterator.next());

    if (IS_SET(obj.flags, OBJ_NODECAY)) then
      continue;

    if (obj.timer <= 0) then
      continue;

    dec(obj.timer);
    if (obj.timer > 0) then
      continue;

    case obj.item_type of
      ITEM_CORPSE : begin
                    msg := '$p decays into dust and blows away.';
                    at_temp := AT_CORPSE;
                    end;
       ITEM_BLOOD : begin
                    msg := '$p dries up.';
                    at_temp := AT_RED;
                    end;
        ITEM_FOOD : begin
                    msg := '$p slowly rots away, leaving a foul stench.';
                    at_temp := AT_REPORT;
                    end;
      else
         begin
         msg := '$p vanishes in the wink of an eye.';
         at_temp := AT_REPORT;
         end;
    end;

    if (obj.carried_by <> nil) then
      act(at_temp, msg, false, obj.carried_by, obj, nil, TO_CHAR)
    else
    if (obj.room <> nil) then
      begin
      if (obj.room.chars.head <> nil) then
        rch := GCharacter(obj.room.chars.head.element)
      else
        rch := nil;

      if (rch <> nil) and (not IS_SET(obj.flags, OBJ_HIDDEN)) then
        begin
        act(at_temp, msg, false, rch, obj, nil, TO_ROOM);
        act(at_temp, msg, false, rch, obj, nil, TO_CHAR);
        end;
      end;

    obj.Free();
  end;
end;

end.