mirror of
				https://github.com/pragma-/pbot.git
				synced 2025-11-04 08:37:24 +01:00 
			
		
		
		
	Plugins/Battleship: fix some bugs
This commit is contained in:
		
							parent
							
								
									e12b269fdb
								
							
						
					
					
						commit
						074ddce530
					
				@ -1,10 +1,10 @@
 | 
			
		||||
# File: Battleship.pm
 | 
			
		||||
#
 | 
			
		||||
# Purpose: Simplified version of the Battleship board game. In this variant,
 | 
			
		||||
# there is only one game grid/board and every player's ships share it.
 | 
			
		||||
# This adds an element of strategy: everybody knows where their own ships
 | 
			
		||||
# are located and they know that ships cannot overlap, ergo they know where
 | 
			
		||||
# NOT to aim. This helps to speed games up by removing some randomness.
 | 
			
		||||
# there is one game grid/board and every player's ships share it without
 | 
			
		||||
# overlapping. This adds nn element of strategy: everybody knows where their
 | 
			
		||||
# own ships are located, ergo they know where NOT to aim. This helps to speed
 | 
			
		||||
# games up by removing some randomness.
 | 
			
		||||
#
 | 
			
		||||
# Note: This code was written circa 1993 for a DikuMUD fork. It was originally
 | 
			
		||||
# written in C, as I was teaching the language to myself in my early teens. Two
 | 
			
		||||
@ -18,7 +18,8 @@
 | 
			
		||||
# players on a single board. The board grows in size for each additional player,
 | 
			
		||||
# to accomodate their ships. Whirlpools have also been added. They are initially
 | 
			
		||||
# hidden by the ocean. When shot, they reveal themselves on the map and deflect
 | 
			
		||||
# the shot to a random tile.
 | 
			
		||||
# the shot to a random tile. Much of the IOCCC silliness has been removed so that
 | 
			
		||||
# I can maintain this code without going insane.
 | 
			
		||||
 | 
			
		||||
# This Source Code Form is subject to the terms of the Mozilla Public
 | 
			
		||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
			
		||||
@ -74,10 +75,16 @@ sub initialize {
 | 
			
		||||
    # player limit per game
 | 
			
		||||
    $self->{MAX_PLAYERS} = 5;
 | 
			
		||||
 | 
			
		||||
    # types of board tiles
 | 
			
		||||
    $self->{TYPE_OCEAN}      = 0;
 | 
			
		||||
    $self->{TYPE_WHIRLPOOL}  = 1;
 | 
			
		||||
    $self->{TYPE_SHIP}       = 2;
 | 
			
		||||
 | 
			
		||||
    # battleship tile symbols
 | 
			
		||||
    $self->{TILE_HIT}   = ['1' .. $self->{MAX_PLAYERS}];
 | 
			
		||||
    $self->{TILE_OCEAN} = "$color{blue}~";
 | 
			
		||||
    $self->{TILE_MISS}  = "$color{cyan}o";
 | 
			
		||||
    $self->{TILE_HIT}        = ['1' .. $self->{MAX_PLAYERS}];
 | 
			
		||||
    $self->{TILE_OCEAN}      = "$color{blue}~";
 | 
			
		||||
    $self->{TILE_MISS}       = "$color{cyan}o";
 | 
			
		||||
    $self->{TILE_WHIRLPOOL}  = "$color{cyan}@";
 | 
			
		||||
 | 
			
		||||
    # personal ship tiles shown on player board
 | 
			
		||||
    $self->{TILE_SHIP_VERT}  = "$color{white}|";
 | 
			
		||||
@ -86,29 +93,18 @@ sub initialize {
 | 
			
		||||
    # all player ship tiles shown on final/full board
 | 
			
		||||
    $self->{TILE_SHIP}  = ['A' .. chr ord('A') + $self->{MAX_PLAYERS} - 1];
 | 
			
		||||
 | 
			
		||||
    # initially hidden by ocean, revealed when shot.
 | 
			
		||||
    # when shot, sends particle to random coordinate
 | 
			
		||||
    # and damages any ship there, including player's
 | 
			
		||||
    $self->{TILE_WHIRLPOOL} = "$color{cyan}@";
 | 
			
		||||
 | 
			
		||||
    # default board dimensions
 | 
			
		||||
    $self->{BOARD_X}         = 14;
 | 
			
		||||
    $self->{BOARD_X}         = 12;
 | 
			
		||||
    $self->{BOARD_Y}         = 8;
 | 
			
		||||
 | 
			
		||||
    # number of ships per player
 | 
			
		||||
    $self->{SHIP_COUNT}      = 8;
 | 
			
		||||
    $self->{SHIP_COUNT}      = 6;
 | 
			
		||||
 | 
			
		||||
    # modifiers for show_battlefield()
 | 
			
		||||
    $self->{BOARD_SPECTATOR} = -1;
 | 
			
		||||
    $self->{BOARD_FINAL}     = -2;
 | 
			
		||||
    $self->{BOARD_FULL}      = -3;
 | 
			
		||||
 | 
			
		||||
    # types of board tiles
 | 
			
		||||
    $self->{TYPE_OCEAN}      = 0;
 | 
			
		||||
    $self->{TYPE_SHIP}       = 1;
 | 
			
		||||
    $self->{TYPE_MISS}       = 2;
 | 
			
		||||
    $self->{TYPE_WHIRLPOOL}  = 3;
 | 
			
		||||
 | 
			
		||||
    # ship orientation
 | 
			
		||||
    $self->{ORIENT_VERT}     = 0;
 | 
			
		||||
    $self->{ORIENT_HORIZ}    = 1;
 | 
			
		||||
@ -177,7 +173,7 @@ sub cmd_battleship {
 | 
			
		||||
                return "There is already a game of Battleship underway.";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            # set game to the `accept` state to begin accepting challenges
 | 
			
		||||
            # set game to the `challenge` state to begin accepting challenge
 | 
			
		||||
            $self->set_state('challenge');
 | 
			
		||||
 | 
			
		||||
            # add player 0, the challenger, to the game
 | 
			
		||||
@ -371,13 +367,13 @@ sub cmd_battleship {
 | 
			
		||||
 | 
			
		||||
            my $msg;
 | 
			
		||||
            if (not exists $player->{location}) {
 | 
			
		||||
                $msg = "/msg $channel $nick aims at $arguments.";
 | 
			
		||||
                $msg = "/msg $channel $nick aims somewhere.";
 | 
			
		||||
            }
 | 
			
		||||
            elsif (lc $player->{location} eq lc $arguments) {
 | 
			
		||||
                return '';
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                $msg = "/msg $channel $nick aims at $arguments instead of $player->{location}.";
 | 
			
		||||
                $msg = "/msg $channel $nick aims somewhere else.";
 | 
			
		||||
            }
 | 
			
		||||
            $player->{location} = $arguments;
 | 
			
		||||
            return $msg;
 | 
			
		||||
@ -399,6 +395,10 @@ sub cmd_battleship {
 | 
			
		||||
            # show player's personal board if playing
 | 
			
		||||
            for (my $i = 0; $i < @{$self->{state_data}->{players}}; $i++) {
 | 
			
		||||
                if ($self->{state_data}->{players}->[$i]->{id} == $id) {
 | 
			
		||||
                    if ($self->{state_data}->{players}->[$i]->{removed}) {
 | 
			
		||||
                        return "$nick: You have been removed from this game. Try again next game.";
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    $self->send_message($channel, "$nick surveys the battlefield!");
 | 
			
		||||
                    $self->show_battlefield($i);
 | 
			
		||||
                    return '';
 | 
			
		||||
@ -473,13 +473,15 @@ sub new_player {
 | 
			
		||||
    return {
 | 
			
		||||
        id           => $id,
 | 
			
		||||
        name         => $nick,
 | 
			
		||||
        index        => 0,
 | 
			
		||||
        ready        => 0,
 | 
			
		||||
        health       => 0,
 | 
			
		||||
        ships        => 0,
 | 
			
		||||
        shots        => 0,
 | 
			
		||||
        hit          => 0,
 | 
			
		||||
        miss         => 0,
 | 
			
		||||
        sunk         => 0,
 | 
			
		||||
        index        => 0,
 | 
			
		||||
        lost         => 0,
 | 
			
		||||
        missedinputs => 0,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
@ -507,13 +509,12 @@ sub end_game_loop {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
    # remove `battleship loop` event
 | 
			
		||||
 | 
			
		||||
    # repeating events get re-added to queue after event completes, so we
 | 
			
		||||
    # must set repeating to 0 to ensure the event gets removed
 | 
			
		||||
    # repeating events get added back to event queue if we attempt to
 | 
			
		||||
    # dequeue_event() from within the event itself. we turn repeating
 | 
			
		||||
    # off to ensure the event gets removed when it completes.
 | 
			
		||||
    $self->{pbot}->{event_queue}->update_repeating('battleship loop', 0);
 | 
			
		||||
 | 
			
		||||
    # dequeue_event cannot remove repeating events if dequeue_event is called
 | 
			
		||||
    # from within a repeating event since the event infrastructure will just
 | 
			
		||||
    # re-add it afterwards (in other words, don't delete the above line)
 | 
			
		||||
    # dequeue event.
 | 
			
		||||
    $self->{pbot}->{event_queue}->dequeue_event('battleship loop', 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -541,6 +542,9 @@ sub init_game {
 | 
			
		||||
    # field and helps speed games up)
 | 
			
		||||
    $self->{board} = [];
 | 
			
		||||
 | 
			
		||||
    # reset winner flag
 | 
			
		||||
    $self->{got_winner} = 0;
 | 
			
		||||
 | 
			
		||||
    # place ships and ocean tiles
 | 
			
		||||
    return $self->generate_battlefield;
 | 
			
		||||
}
 | 
			
		||||
@ -578,7 +582,7 @@ sub check_ship_placement {
 | 
			
		||||
sub place_ship {
 | 
			
		||||
    my ($self, $player_id, $player_index, $ship) = @_;
 | 
			
		||||
 | 
			
		||||
    my ($x, $y, $o, $d, $i, $l);
 | 
			
		||||
    my ($x, $y, $o, $i, $l);
 | 
			
		||||
    my ($yd, $xd) = (0, 0);
 | 
			
		||||
 | 
			
		||||
    my $fail = 0;
 | 
			
		||||
@ -602,7 +606,7 @@ sub place_ship {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($self->{debug}) {
 | 
			
		||||
            $self->{pbot}->{logger}->log("attempt to place ship for player $player_index: ship $ship x,y: $x,$y  o,d: $o,$d length: $l\n");
 | 
			
		||||
            $self->{pbot}->{logger}->log("attempt to place ship for player $player_index: ship $ship x,y: $x,$y o: $o length: $l\n");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($self->check_ship_placement($x, $y, $o, $l)) {
 | 
			
		||||
@ -650,6 +654,7 @@ sub place_ship {
 | 
			
		||||
 | 
			
		||||
            $self->{ship_length}->[$ship] = $l;
 | 
			
		||||
            $self->{state_data}->{players}->[$player_index]->{health} += $l;
 | 
			
		||||
            $self->{state_data}->{players}->[$player_index]->{ships}  += 1;
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -725,13 +730,7 @@ sub check_sunk {
 | 
			
		||||
        my $top    = $y - $tile->{index};
 | 
			
		||||
        my $bottom = $y + ($tile->{length} - ($tile->{index} + 1));
 | 
			
		||||
 | 
			
		||||
        for (my $i = $y; $i >= $top; $i--) {
 | 
			
		||||
            if (not $self->{board}->[$x][$i]->{hit_by}) {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (my $i = $y + 1; $i <= $bottom; $i++) {
 | 
			
		||||
        for (my $i = $bottom; $i >= $top; $i--) {
 | 
			
		||||
            if (not $self->{board}->[$x][$i]->{hit_by}) {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
@ -742,13 +741,7 @@ sub check_sunk {
 | 
			
		||||
        my $left   = $x - $tile->{index};
 | 
			
		||||
        my $right  = $x + ($tile->{length} - ($tile->{index} + 1));
 | 
			
		||||
 | 
			
		||||
        for (my $i = $x; $i >= $left; $i--) {
 | 
			
		||||
            if (not $self->{board}->[$i][$y]->{hit_by}) {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (my $i = $x + 1; $i <= $right; $i++) {
 | 
			
		||||
        for (my $i = $right; $i >= $left; $i--) {
 | 
			
		||||
            if (not $self->{board}->[$i][$y]->{hit_by}) {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
@ -796,7 +789,7 @@ sub check_hit {
 | 
			
		||||
 | 
			
		||||
        # keep trying until we don't hit another whirlpool
 | 
			
		||||
        while (1) {
 | 
			
		||||
            $self->send_message($self->{channel}, "$player->{name} $attack $location! $color{cyan}--- SPLASH! ---$color{reset} ");
 | 
			
		||||
            $self->send_message($self->{channel}, "$player->{name} $attack $location! $color{cyan}--- SPLASH! ---$color{reset}");
 | 
			
		||||
 | 
			
		||||
            $x = $self->number(0, $self->{N_X});
 | 
			
		||||
            $y = $self->number(0, $self->{N_Y});
 | 
			
		||||
@ -821,10 +814,23 @@ sub check_hit {
 | 
			
		||||
 | 
			
		||||
    # hit a ship, damage self or enemy alike
 | 
			
		||||
    if ($self->{board}->[$x][$y]->{type} == $self->{TYPE_SHIP}) {
 | 
			
		||||
        return 1;
 | 
			
		||||
        my $player_index = $self->{board}->[$x][$y]->{player_index};
 | 
			
		||||
 | 
			
		||||
        if ($state->{players}->[$player_index]->{removed}) {
 | 
			
		||||
            # removed players no longer exist
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($self->{board}->[$x][$y]->{hit_by}) {
 | 
			
		||||
            # this piece has already been struck
 | 
			
		||||
            return 0;
 | 
			
		||||
        } else {
 | 
			
		||||
            # a hit! a very palpable hit.
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # did not hit whirlpool or ship
 | 
			
		||||
    # no hit
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -868,16 +874,17 @@ sub perform_attack {
 | 
			
		||||
        $self->{board}->[$x][$y]->{tile}   = $color{red} . $self->{TILE_HIT}->[$player->{index}];
 | 
			
		||||
        $self->{board}->[$x][$y]->{hit_by} = $player->{id};
 | 
			
		||||
 | 
			
		||||
        # deduct hit points from player
 | 
			
		||||
        $player->{health} -= 1;
 | 
			
		||||
        my $victim = $self->{state_data}->{players}->[$self->{board}->[$x][$y]->{player_index}];
 | 
			
		||||
 | 
			
		||||
        # deduct hit points from victim
 | 
			
		||||
        $victim->{health} -= 1;
 | 
			
		||||
 | 
			
		||||
        # check if ship has sunk (reveal what kind and whose ship it is)
 | 
			
		||||
        if ($self->check_sunk($x, $y)) {
 | 
			
		||||
            $player->{sunk}++;
 | 
			
		||||
            $victim->{ships}--;
 | 
			
		||||
 | 
			
		||||
            my $length    = $self->{board}->[$x][$y]->{length};
 | 
			
		||||
            my $remaining = $player->{health};
 | 
			
		||||
            my $victim    = $self->{state_data}->{players}->[$self->{board}->[$x][$y]->{player_index}]->{name};
 | 
			
		||||
 | 
			
		||||
            my %ship_names = (
 | 
			
		||||
                5 => 'battleship',
 | 
			
		||||
@ -886,11 +893,31 @@ sub perform_attack {
 | 
			
		||||
                2 => 'patrol boat',
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            $self->send_message($self->{channel}, "$color{red}$player->{name} has sunk ${victim}'s $ship_names{$length}! $victim has $remaining ship section" . ($remaining != 1 ? 's' : '') . " remaining!$color{reset}");
 | 
			
		||||
            my $ships_left    = $victim->{ships};
 | 
			
		||||
            my $sections_left = $victim->{health};
 | 
			
		||||
 | 
			
		||||
            if ($remaining == 0) {
 | 
			
		||||
                $self->send_message($self->{channel}, "$player->{name} has won the game of Battleship!");
 | 
			
		||||
                $player->{won} = 1;
 | 
			
		||||
            my $ships    = 'ship'    . ($ships_left    != 1 ? 's' : '');
 | 
			
		||||
            my $sections = 'section' . ($sections_left != 1 ? 's' : '');
 | 
			
		||||
 | 
			
		||||
            if ($sections_left > 0) {
 | 
			
		||||
                $self->send_message($self->{channel}, "$color{red}$player->{name} has sunk $victim->{name}'s $ship_names{$length}! $victim->{name} has $ships_left $ships and $sections_left $sections remaining!$color{reset}");
 | 
			
		||||
            } else {
 | 
			
		||||
                $self->send_message($self->{channel}, "$color{red}$player->{name} has sunk ${victim}->{name}'s final $ship_names{$length}! $victim->{name} is out of the game!$color{reset}");
 | 
			
		||||
                $victim->{lost} = 1;
 | 
			
		||||
 | 
			
		||||
                # check if there is only one player still standing
 | 
			
		||||
                my $still_alive = 0;
 | 
			
		||||
                my $winner;
 | 
			
		||||
                foreach my $p (@{$state->{players}}) {
 | 
			
		||||
                    next if $p->{removed} or $p->{lost};
 | 
			
		||||
                    $still_alive++;
 | 
			
		||||
                    $winner = $p;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if ($still_alive == 1) {
 | 
			
		||||
                    $self->send_message($self->{channel}, "$color{yellow}$winner->{name} has won the game of Battleship!$color{reset}");
 | 
			
		||||
                    $self->{got_winner} = 1;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
@ -930,14 +957,17 @@ sub list_players {
 | 
			
		||||
sub show_scoreboard {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
 | 
			
		||||
    foreach my $player (sort { $a->{health} <=> $b->{health} } @{$self->{state_data}->{players}}) {
 | 
			
		||||
        my $buf = sprintf("%-15s shots: %2d, hit: %2d, miss: %2d, acc: %3d%%, sunk: %2d, sections left: %2d",
 | 
			
		||||
    foreach my $player (sort { $b->{health} <=> $a->{health} } @{$self->{state_data}->{players}}) {
 | 
			
		||||
        next if $player->{removed};
 | 
			
		||||
 | 
			
		||||
        my $buf = sprintf("%-15s shots: %2d, hit: %2d, miss: %2d, acc: %3d%%, sunk: %2d, ships left: %d, sections left: %2d",
 | 
			
		||||
            "$player->{name}:",
 | 
			
		||||
            $player->{shots},
 | 
			
		||||
            $player->{hit},
 | 
			
		||||
            $player->{miss},
 | 
			
		||||
            int (($player->{hit} / ($player->{shots} ? $player->{shots} : 1)) * 100),
 | 
			
		||||
            $player->{sunk},
 | 
			
		||||
            $player->{ships},
 | 
			
		||||
            $player->{health},
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
@ -966,7 +996,7 @@ sub show_battlefield {
 | 
			
		||||
 | 
			
		||||
    # render legend
 | 
			
		||||
    if ($player) {
 | 
			
		||||
        $output .= "Legend: ships: $self->{TILE_SHIP_VERT} $self->{TILE_SHIP_HORIZ}$color{reset} ${hits}ocean: $self->{TILE_OCEAN}$color{reset} miss: $self->{TILE_MISS}$color{reset} whirlpool: $self->{TILE_WHIRLPOOL}$color{reset}\n";
 | 
			
		||||
        $output .= "Legend: Your ships: $self->{TILE_SHIP_VERT} $self->{TILE_SHIP_HORIZ}$color{reset} ${hits}ocean: $self->{TILE_OCEAN}$color{reset} miss: $self->{TILE_MISS}$color{reset} whirlpool: $self->{TILE_WHIRLPOOL}$color{reset}\n";
 | 
			
		||||
    }
 | 
			
		||||
    elsif ($player_index == $self->{BOARD_FULL} or $player_index == $self->{BOARD_FINAL}) {
 | 
			
		||||
        my $ships;
 | 
			
		||||
@ -1112,30 +1142,29 @@ sub run_one_state {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
 | 
			
		||||
    # check for naughty or missing players
 | 
			
		||||
    foreach my $player (@{$self->{state_data}->{players}}) {
 | 
			
		||||
        next if $player->{removed};
 | 
			
		||||
    my $players = 0;
 | 
			
		||||
 | 
			
		||||
    foreach my $player (@{$self->{state_data}->{players}}) {
 | 
			
		||||
        next if $player->{removed} or $player->{lost};
 | 
			
		||||
 | 
			
		||||
        # remove player if they have missed 3 inputs
 | 
			
		||||
        if ($player->{missedinputs} >= 3) {
 | 
			
		||||
            # remove player if they have missed 3 inputs
 | 
			
		||||
            $self->send_message(
 | 
			
		||||
                $self->{channel},
 | 
			
		||||
                "$color{red}$player->{name} has missed too many moves and has been ejected from the game!$color{reset}"
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            $player->{removed} = 1;
 | 
			
		||||
            next;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        # count players still in the game
 | 
			
		||||
        $players++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # ensure there's at least 2 players still playing
 | 
			
		||||
    # ensure there are at least 2 players still playing
 | 
			
		||||
    if ($self->{current_state} eq 'move' or $self->{current_state} eq 'attack') {
 | 
			
		||||
        my $players = 0;
 | 
			
		||||
 | 
			
		||||
        foreach my $player (@{$self->{state_data}->{players}}) {
 | 
			
		||||
            next if $player->{removed};
 | 
			
		||||
            ++$players;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($players < 2) {
 | 
			
		||||
        if ($players < 2 and not $self->{got_winner}) {
 | 
			
		||||
            $self->send_message($self->{channel}, "Not enough players left in the game. Aborting...");
 | 
			
		||||
            $self->set_state('gameover');
 | 
			
		||||
        }
 | 
			
		||||
@ -1429,8 +1458,8 @@ sub state_attack {
 | 
			
		||||
        # launch attack
 | 
			
		||||
        $self->perform_attack($state, $player);
 | 
			
		||||
 | 
			
		||||
        # transitiion to gameover if someone won
 | 
			
		||||
        $trans = 'gotwinner' if $player->{won};
 | 
			
		||||
        # transition to gameover if someone won
 | 
			
		||||
        $trans = 'gotwinner' if $self->{got_winner};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $state->{trans} = $trans;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user