Games-Axmud

 view release on metacpan or  search on metacpan

lib/Games/Axmud/Obj/Zone.pm  view on Meta::CPAN

        } elsif ($self->startCorner eq 'bottom_left') {

            # Gridblock at which the top-left corner of a window will be, when it is in the
            #   bottom-left corner of the search area
            $startX = 0;
            $startY = $self->heightBlocks - $heightBlocks;
            if ($self->orientation eq 'horizontal') {
                $step = 1;
            } else {
                $step = -1;
            }

        } elsif ($self->startCorner eq 'bottom_right') {

            # Gridblock at which the top-left corner of the first window is, when it is in the
            #   bottom-right corner of the search area
            $startX = $self->widthBlocks - $widthBlocks;
            $startY = $self->heightBlocks - $heightBlocks;
            $step = -1;
        }

        # Set more search parameters - the number of possible positions of a window, of size
        #   $widthBlocks and $heightBlocks, in this zone's internal grid
        $numX = ($self->widthBlocks - $widthBlocks + 1);
        $numY = ($self->heightBlocks - $heightBlocks + 1);

        # Conduct the search
        for (my $posX = $startX; $posX < ($startX + $numX); $posX  += $step) {

            for (my $posY = $startY; $posY < ($startY + $numY); $posY += $step) {

                # Check that every gridblock in the area starting at grid coordinates $posX/$posY
                #   region is free
                if (
                    $self->checkPosnInLayer(
                        $layer,
                        $posX,
                        $posY,
                        $widthBlocks,
                        $heightBlocks,
                        $winObj,
                    )
                ) {
                    # The entire area is free, so a window can be placed at this position, at the
                    #   specified layer, without overlapping other windows
                    return (1, $posX, $posY);
                }
            }
        }

        # There isn't space for this window anywhere in this zone at the specified layer
        return @emptyList;
    }

    sub adjustSingleWin {

        # Called by GA::Obj::Workspace->chooseWinPosn
        # If the window's proposed position on a zone's internal grid puts it rather close to the
        #   edge (or edges) of the zone, and if the gaps between the proposed window and the zone's
        #   edge(s) are unoccupied, adjust the size of the window to fill the gap (this prevents
        #   small regions of the zone from always being empty and makes the desktop look nice)
        #
        # Expected arguments
        #   $layer  - Which layer within the zone to check first (matches a number between 0 and
        #               (GA::Obj::WorkspaceGrid->maxLayers - 1) )
        #   $winXPosBlocks, $winYPosBlocks
        #           - The window's proposed x/y coordinates on the zone's internal grid (in
        #               gridblocks)
        #   $winWidthBlocks, $winHeightBlocks
        #           - The window's proposed width and height (in gridblocks)
        #
        # Return values
        #   An empty list on improper arguments
        #   Otherwise returns the list
        #       ($winXPosBlocks, $winYPosBlocks, $winWidthBlocks, $winHeightBlocks)
        #   ...some of which may have been adjusted by this function

        my (
            $self, $layer, $winXPosBlocks, $winYPosBlocks, $winWidthBlocks, $winHeightBlocks,
            $check,
        ) = @_;

        # Local variables
        my (
            $gapSize, $maxGapSize, $regionXPosBlocks, $regionYPosBlocks, $regionWidthBlocks,
            $regionHeightBlocks,
            @emptyList,
        );

        # Check for improper arguments
        if (
            ! defined $layer || ! defined $winXPosBlocks || ! defined $winYPosBlocks
            || ! defined $winWidthBlocks || ! defined $winHeightBlocks || defined $check
        ) {
            $axmud::CLIENT->writeImproper($self->_objClass . '->adjustSingleWin', @_);
            return @emptyList;
        }

        # If this zone has a maximum number of visible windows, the biggest gap this function will
        #   close is that number minus 1 (bigger gaps shouldn't occur in zones with a maximum number
        #   of visible windows)
        # Otherwise, the biggest gap is the one defined by the global variable
        if ($self->visibleAreaMax) {

            $maxGapSize = ($self->visibleAreaMax - 1);
            # If this value is 0 (because only one window is allowed), don't need to check for gaps.
            #   Return the unadjusted size of the window
            if (! $maxGapSize) {

                return (
                    $winXPosBlocks, $winYPosBlocks, $winWidthBlocks, $winHeightBlocks,
                );
            }

        } else {

            # Use the default value
            $maxGapSize = $axmud::CLIENT->gridGapMaxSize;
        }

        # Search the region to the left of the window

lib/Games/Axmud/Obj/Zone.pm  view on Meta::CPAN

        #       GA::Client->createGridWin)
        #   Otherwise returns the GA::Obj::Area object created

        my (
            $self, $layer, $xPosBlocks, $yPosBlocks, $widthBlocks, $heightBlocks, $xPosPixels,
            $yPosPixels, $widthPixels, $heightPixels, $session, $changeWinObj, $check,
        ) = @_;

        # Local variables
        my $areaObj;

        # Check for improper arguments
        if (
            ! defined $layer || ! defined $xPosBlocks  || ! defined $yPosBlocks
            || ! defined $widthBlocks || ! defined $heightBlocks || ! defined $xPosPixels
            || ! defined $yPosPixels || ! defined $widthPixels || ! defined $heightPixels
            || defined $check
        ) {
            return $axmud::CLIENT->writeImproper($self->_objClass . '->addArea', @_);
        }

        # Check that the area is unoccupied by other windows (it shouldn't be)
        if (
            ! $self->checkPosnInLayer(
                $layer,
                $xPosBlocks,
                $yPosBlocks,
                $widthBlocks,
                $heightBlocks,
                $changeWinObj,
            )
        ) {
            return $axmud::CLIENT->writeError(
                'Window cannot be placed at the specified position, because the area is already'
                . ' occupied',
                $self->_objClass . '->addArea',
            );
        }

        # Create a new area object to store details about the window's size and position
        $areaObj = Games::Axmud::Obj::Area->new($self->areaCount, $self);
        $self->ivAdd('areaHash', $areaObj->number, $areaObj);
        $self->ivIncrement('areaCount');

        # If $self->ownerString is defined, this zone is reserved for a single session. The IV's
        #   value can be any non-empty string. All zones with the same ->ownerString are reserved
        #   for a particular session
        # The first session to place one of its windows into any 'owned' zone claims all of
        #   those zones for itself. If $self->ownerString IV is 'undef', the zone is available for
        #   any session to use (subject to restriction described in the comments in $self->new)
        # ->ownerString is ignored in GA::Client->shareMainWinFlag = TRUE
        if (
            ! $axmud::CLIENT->shareMainWinFlag
            && defined $session
            && defined $self->ownerString
            && $self->ownerString ne ''
            && ! defined $self->owner
        ) {
            # Claim this zone, and all other zones (across all workspaces) with the same
            #   ->ownerString for this session
            $axmud::CLIENT->desktopObj->claimZones($session, $self->ownerString);
        }

        # Set its IVs (->set_win is called by GA::Obj::Workspace->createGridWin, once the window
        #   object has been created)
        $areaObj->set_zone($layer, $xPosBlocks, $yPosBlocks, $widthBlocks, $heightBlocks);
        $areaObj->set_posn($xPosPixels, $yPosPixels, $widthPixels, $heightPixels);

        return $areaObj;
    }

    sub removeArea {

        # Called by GA::Obj::Workspace->createGridWin, GA::Obj::WorkspaceGrid->changeWinzone and
        #   ->del_gridWin
        # Removes the GA::Obj::Area object (which is occupied by a single window) from this zone's
        #   internal grid
        # Optionally reshuffles remaining windows
        #
        # Expected arguments
        #   $areaObj        - The GA::Obj::Area which should be removed
        #
        # Optional arguments
        #   $noShuffleFlag  - Set to TRUE when called GA::Obj::WorkspaceGrid->changeWinzone, in
        #                       which case this function doesn't call $self->replaceAreaSpace to
        #                       reshuffle the positions of windows in this zone
        #
        # Return values
        #   'undef' on improper arguments, or if the area doesn't seem to exist in this zone, or
        #       if an operation to re-shuffle window positions fails
        #   1 otherwise

        my ($self, $areaObj, $noShuffleFlag, $check) = @_;

        # Check for improper arguments
        if (! defined $areaObj || defined $check) {

            return $axmud::CLIENT->writeImproper($self->_objClass . '->removeArea', @_);
        }

        # Update IVs
        $self->ivDelete('areaHash', $areaObj->number);

        # If there are no areas left in this zone, and the zone's ->owner is set, tell the
        #   GA::Obj::Desktop to check all zones across all workspaces. If the session has no windows
        #   in any of the zones it controls, free up those zones so they're available to another
        #   session
        if ($self->owner && ! $self->areaHash) {

            $axmud::CLIENT->desktopObj->relinquishZones($self->ownerString);
        }

        # If the global flag is set, reshuffle the position of all windows in this zone, removing
        #   any gaps that might have appeared in the middle of the zone, if the removed window
        #   occupied that space
        if (! $noShuffleFlag && $axmud::CLIENT->gridReshuffleFlag) {

            return $self->replaceAreaSpace($areaObj->layer);

        } else {

            return 1;
        }
    }

    sub replaceAreaSpace {

        # Called by $self->removeArea
        # After a window has been removed, it's often desirable to move all the windows in the zone
        #   (on the same layer) to fill the gap - so, instead of having a gap in the middle, we have
        #   a gap at the end (the opposite end to the starting corner).
        # This function performs that operation
        #
        # Expected arguments
        #   $layer      - Which layer to reshuffle
        #
        # Return values
        #   'undef' on improper arguments, or if (for some very unlikely reason) one of the windows
        #       won't fit in the zone
        #   1 otherwise

        my ($self, $layer, $check) = @_;

        # Local variables
        my (
            $blockSize,
            @areaList,
        );

        # Check for improper arguments
        if (! defined $layer || defined $check) {

            return $axmud::CLIENT->writeImproper($self->_objClass . '->replaceAreaSpace', @_);
        }

        # Compile a list of GA::Obj::Area objects (one area for each window), sorted in order of
        #   their proximity to the starting corner
        @areaList = $self->getSortedAreaList($layer);

        # Move the windows into position. Start with the closest windows, so that all windows are in
        #   turn moved closer to the starting corner
        $blockSize = $axmud::CLIENT->gridBlockSize;
        foreach my $areaObj (@areaList) {

            my (
                $widthBlocks, $heightBlocks, $widthPixels, $heightPixels, $xPosBlocks, $yPosBlocks,
                $xPosPixels, $yPosPixels, $successFlag,
            );

            # Get the area's size on the zone's internal grid. Remove the influence of any past



( run in 2.948 seconds using v1.01-cache-2.11-cpan-bbc515a03b3 )