Initial commit
This commit is contained in:
448
engines/ultima/ultima4/views/dungeonview.cpp
Normal file
448
engines/ultima/ultima4/views/dungeonview.cpp
Normal file
@@ -0,0 +1,448 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima4/core/config.h"
|
||||
#include "ultima/ultima4/core/settings.h"
|
||||
#include "ultima/ultima4/gfx/image.h"
|
||||
#include "ultima/ultima4/gfx/imagemgr.h"
|
||||
#include "ultima/ultima4/gfx/screen.h"
|
||||
#include "ultima/ultima4/map/tileanim.h"
|
||||
#include "ultima/ultima4/map/tileset.h"
|
||||
#include "ultima/ultima4/views/dungeonview.h"
|
||||
#include "ultima/ultima4/ultima4.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
DungeonView *DungeonView::_instance = nullptr;
|
||||
|
||||
DungeonView::DungeonView(int x, int y, int columns, int rows) : TileView(x, y, rows, columns)
|
||||
, _screen3dDungeonViewEnabled(true) {
|
||||
}
|
||||
|
||||
DungeonView *DungeonView::getInstance() {
|
||||
if (!_instance) {
|
||||
_instance = new DungeonView(BORDER_WIDTH, BORDER_HEIGHT, VIEWPORT_W, VIEWPORT_H);
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
|
||||
void DungeonView::display(Context *c, TileView *view) {
|
||||
int x, y;
|
||||
|
||||
// 1st-person perspective
|
||||
if (_screen3dDungeonViewEnabled) {
|
||||
// Note: This shouldn't go above 4, unless we check opaque tiles each step of the way.
|
||||
const int farthest_non_wall_tile_visibility = 4;
|
||||
|
||||
Std::vector<MapTile> tiles;
|
||||
|
||||
g_screen->screenEraseMapArea();
|
||||
if (c->_party->getTorchDuration() > 0) {
|
||||
for (y = 3; y >= 0; y--) {
|
||||
DungeonGraphicType type;
|
||||
|
||||
// FIXME: Maybe this should be in a loop
|
||||
tiles = getTiles(y, -1);
|
||||
type = tilesToGraphic(tiles);
|
||||
drawWall(-1, y, (Direction)g_ultima->_saveGame->_orientation, type);
|
||||
|
||||
tiles = getTiles(y, 1);
|
||||
type = tilesToGraphic(tiles);
|
||||
drawWall(1, y, (Direction)g_ultima->_saveGame->_orientation, type);
|
||||
|
||||
tiles = getTiles(y, 0);
|
||||
type = tilesToGraphic(tiles);
|
||||
drawWall(0, y, (Direction)g_ultima->_saveGame->_orientation, type);
|
||||
|
||||
// This only checks that the tile at y==3 is opaque
|
||||
if (y == 3 && !tiles.front().getTileType()->isOpaque()) {
|
||||
for (int y_obj = farthest_non_wall_tile_visibility; y_obj > y; y_obj--) {
|
||||
Std::vector<MapTile> distant_tiles = getTiles(y_obj , 0);
|
||||
DungeonGraphicType distant_type = tilesToGraphic(distant_tiles);
|
||||
|
||||
if ((distant_type == DNGGRAPHIC_DNGTILE) || (distant_type == DNGGRAPHIC_BASETILE))
|
||||
drawTile(c->_location->_map->_tileSet->get(distant_tiles.front().getId()), 0, y_obj, Direction(g_ultima->_saveGame->_orientation));
|
||||
}
|
||||
}
|
||||
if ((type == DNGGRAPHIC_DNGTILE) || (type == DNGGRAPHIC_BASETILE))
|
||||
drawTile(c->_location->_map->_tileSet->get(tiles.front().getId()), 0, y, Direction(g_ultima->_saveGame->_orientation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3rd-person perspective
|
||||
else {
|
||||
Std::vector<MapTile> tiles;
|
||||
|
||||
static MapTile black = c->_location->_map->_tileSet->getByName("black")->getId();
|
||||
static MapTile avatar = c->_location->_map->_tileSet->getByName("avatar")->getId();
|
||||
|
||||
for (y = 0; y < VIEWPORT_H; y++) {
|
||||
for (x = 0; x < VIEWPORT_W; x++) {
|
||||
tiles = getTiles((VIEWPORT_H / 2) - y, x - (VIEWPORT_W / 2));
|
||||
|
||||
// Only show blackness if there is no light
|
||||
if (c->_party->getTorchDuration() <= 0)
|
||||
view->drawTile(black, false, x, y);
|
||||
else if (x == VIEWPORT_W / 2 && y == VIEWPORT_H / 2)
|
||||
view->drawTile(avatar, false, x, y);
|
||||
else
|
||||
view->drawTile(tiles, false, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DungeonView::drawInDungeon(Tile *tile, int x_offset, int distance, Direction orientation, bool tiledWall) {
|
||||
Image *scaled;
|
||||
|
||||
const static int nscale_vga[] = { 12, 8, 4, 2, 1};
|
||||
const static int nscale_ega[] = { 8, 4, 2, 1, 0};
|
||||
|
||||
const int lscale_vga[] = { 22, 18, 10, 4, 1};
|
||||
const int lscale_ega[] = { 22, 14, 6, 3, 1};
|
||||
|
||||
const int *lscale;
|
||||
const int *nscale;
|
||||
int offset_multiplier = 0;
|
||||
int offset_adj = 0;
|
||||
if (settings._videoType != "EGA") {
|
||||
lscale = & lscale_vga[0];
|
||||
nscale = & nscale_vga[0];
|
||||
offset_multiplier = 1;
|
||||
offset_adj = 2;
|
||||
} else {
|
||||
lscale = & lscale_ega[0];
|
||||
nscale = & nscale_ega[0];
|
||||
offset_adj = 1;
|
||||
offset_multiplier = 4;
|
||||
}
|
||||
|
||||
const int *dscale = tiledWall ? lscale : nscale;
|
||||
|
||||
// Clear scratchpad and set a background color
|
||||
_animated->initializeToBackgroundColor();
|
||||
// Put tile on animated scratchpad
|
||||
if (tile->getAnim()) {
|
||||
MapTile mt = tile->getId();
|
||||
tile->getAnim()->draw(_animated, tile, mt, orientation);
|
||||
} else {
|
||||
tile->getImage()->drawOn(_animated, 0, 0);
|
||||
}
|
||||
_animated->makeBackgroundColorTransparent();
|
||||
// This process involving the background color is only required for drawing in the dungeon.
|
||||
// It will not play well with semi-transparent graphics.
|
||||
|
||||
/* scale is based on distance; 1 means half size, 2 regular, 4 means scale by 2x, etc. */
|
||||
if (dscale[distance] == 0)
|
||||
return;
|
||||
else if (dscale[distance] == 1)
|
||||
scaled = g_screen->screenScaleDown(_animated, 2);
|
||||
else {
|
||||
scaled = g_screen->screenScale(_animated, dscale[distance] / 2, 1, 0);
|
||||
}
|
||||
|
||||
if (tiledWall) {
|
||||
int i_x = SCALED((VIEWPORT_W * _tileWidth / 2) + _bounds.left) - (scaled->width() / 2);
|
||||
int i_y = SCALED((VIEWPORT_H * _tileHeight / 2) + _bounds.top) - (scaled->height() / 2);
|
||||
int f_x = i_x + scaled->width();
|
||||
int f_y = i_y + scaled->height();
|
||||
int d_x = _animated->width();
|
||||
int d_y = _animated->height();
|
||||
|
||||
for (int x = i_x; x < f_x; x += d_x)
|
||||
for (int y = i_y; y < f_y; y += d_y)
|
||||
_animated->drawSubRectOn(this->_screen,
|
||||
x, y, 0, 0, f_x - x, f_y - y);
|
||||
} else {
|
||||
int y_offset = MAX(0, (dscale[distance] - offset_adj) * offset_multiplier);
|
||||
int x = SCALED((VIEWPORT_W * _tileWidth / 2) + _bounds.left) - (scaled->width() / 2);
|
||||
int y = SCALED((VIEWPORT_H * _tileHeight / 2) + _bounds.top + y_offset) - (scaled->height() / 8);
|
||||
|
||||
scaled->drawSubRectOn(this->_screen, x, y, 0, 0,
|
||||
SCALED(_tileWidth * VIEWPORT_W + _bounds.left) - x,
|
||||
SCALED(_tileHeight * VIEWPORT_H + _bounds.top) - y);
|
||||
}
|
||||
|
||||
delete scaled;
|
||||
}
|
||||
|
||||
int DungeonView::graphicIndex(int xoffset, int distance, Direction orientation, DungeonGraphicType type) {
|
||||
int index;
|
||||
|
||||
index = 0;
|
||||
|
||||
if (type == DNGGRAPHIC_LADDERUP && xoffset == 0)
|
||||
return 48 +
|
||||
(distance * 2) +
|
||||
(DIR_IN_MASK(orientation, MASK_DIR_SOUTH | MASK_DIR_NORTH) ? 1 : 0);
|
||||
|
||||
if (type == DNGGRAPHIC_LADDERDOWN && xoffset == 0)
|
||||
return 56 +
|
||||
(distance * 2) +
|
||||
(DIR_IN_MASK(orientation, MASK_DIR_SOUTH | MASK_DIR_NORTH) ? 1 : 0);
|
||||
|
||||
if (type == DNGGRAPHIC_LADDERUPDOWN && xoffset == 0)
|
||||
return 64 +
|
||||
(distance * 2) +
|
||||
(DIR_IN_MASK(orientation, MASK_DIR_SOUTH | MASK_DIR_NORTH) ? 1 : 0);
|
||||
|
||||
// FIXME
|
||||
if (type != DNGGRAPHIC_WALL && type != DNGGRAPHIC_DOOR)
|
||||
return -1;
|
||||
|
||||
if (type == DNGGRAPHIC_DOOR)
|
||||
index += 24;
|
||||
|
||||
index += (xoffset + 1) * 2;
|
||||
|
||||
index += distance * 6;
|
||||
|
||||
if (DIR_IN_MASK(orientation, MASK_DIR_SOUTH | MASK_DIR_NORTH))
|
||||
index++;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void DungeonView::drawTile(Tile *tile, int x_offset, int distance, Direction orientation) {
|
||||
// Draw the tile to the screen
|
||||
DungeonViewer.drawInDungeon(tile, x_offset, distance, orientation, tile->isTiledInDungeon());
|
||||
}
|
||||
|
||||
Std::vector<MapTile> DungeonView::getTiles(int fwd, int side) {
|
||||
MapCoords coords = g_context->_location->_coords;
|
||||
|
||||
switch (g_ultima->_saveGame->_orientation) {
|
||||
case DIR_WEST:
|
||||
coords.x -= fwd;
|
||||
coords.y -= side;
|
||||
break;
|
||||
|
||||
case DIR_NORTH:
|
||||
coords.x += side;
|
||||
coords.y -= fwd;
|
||||
break;
|
||||
|
||||
case DIR_EAST:
|
||||
coords.x += fwd;
|
||||
coords.y += side;
|
||||
break;
|
||||
|
||||
case DIR_SOUTH:
|
||||
coords.x -= side;
|
||||
coords.y += fwd;
|
||||
break;
|
||||
|
||||
case DIR_ADVANCE:
|
||||
case DIR_RETREAT:
|
||||
default:
|
||||
error("Invalid dungeon orientation");
|
||||
}
|
||||
|
||||
// Wrap the coordinates if necessary
|
||||
coords.wrap(g_context->_location->_map);
|
||||
|
||||
bool focus;
|
||||
return g_context->_location->tilesAt(coords, focus);
|
||||
}
|
||||
|
||||
DungeonGraphicType DungeonView::tilesToGraphic(const Std::vector<MapTile> &tiles) {
|
||||
MapTile tile = tiles.front();
|
||||
|
||||
if (!_tiles._loaded) {
|
||||
_tiles._corridor = g_context->_location->_map->_tileSet->getByName("brick_floor")->getId();
|
||||
_tiles._upLadder = g_context->_location->_map->_tileSet->getByName("up_ladder")->getId();
|
||||
_tiles._downLadder = g_context->_location->_map->_tileSet->getByName("down_ladder")->getId();
|
||||
_tiles._upDownLadder = g_context->_location->_map->_tileSet->getByName("up_down_ladder")->getId();
|
||||
_tiles._loaded = true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* check if the dungeon tile has an annotation or object on top
|
||||
* (always displayed as a tile, unless a ladder)
|
||||
*/
|
||||
if (tiles.size() > 1) {
|
||||
if (tile._id == _tiles._upLadder._id)
|
||||
return DNGGRAPHIC_LADDERUP;
|
||||
else if (tile._id == _tiles._downLadder._id)
|
||||
return DNGGRAPHIC_LADDERDOWN;
|
||||
else if (tile._id == _tiles._upDownLadder._id)
|
||||
return DNGGRAPHIC_LADDERUPDOWN;
|
||||
else if (tile._id == _tiles._corridor._id)
|
||||
return DNGGRAPHIC_NONE;
|
||||
else
|
||||
return DNGGRAPHIC_BASETILE;
|
||||
}
|
||||
|
||||
/*
|
||||
* if not an annotation or object, then the tile is a dungeon
|
||||
* token
|
||||
*/
|
||||
Dungeon *dungeon = dynamic_cast<Dungeon *>(g_context->_location->_map);
|
||||
assert(dungeon);
|
||||
DungeonToken token = dungeon->tokenForTile(tile);
|
||||
|
||||
switch (token) {
|
||||
case DUNGEON_TRAP:
|
||||
case DUNGEON_CORRIDOR:
|
||||
return DNGGRAPHIC_NONE;
|
||||
case DUNGEON_WALL:
|
||||
case DUNGEON_SECRET_DOOR:
|
||||
return DNGGRAPHIC_WALL;
|
||||
case DUNGEON_ROOM:
|
||||
case DUNGEON_DOOR:
|
||||
return DNGGRAPHIC_DOOR;
|
||||
case DUNGEON_LADDER_UP:
|
||||
return DNGGRAPHIC_LADDERUP;
|
||||
case DUNGEON_LADDER_DOWN:
|
||||
return DNGGRAPHIC_LADDERDOWN;
|
||||
case DUNGEON_LADDER_UPDOWN:
|
||||
return DNGGRAPHIC_LADDERUPDOWN;
|
||||
|
||||
default:
|
||||
return DNGGRAPHIC_DNGTILE;
|
||||
}
|
||||
}
|
||||
|
||||
const struct {
|
||||
const char *subimage;
|
||||
int ega_x2, ega_y2;
|
||||
int vga_x2, vga_y2;
|
||||
const char *subimage2;
|
||||
} DNG_GRAPHIC_INFO[] = {
|
||||
{ "dung0_lft_ew", -1, -1, -1, -1, nullptr },
|
||||
{ "dung0_lft_ns", -1, -1, -1, -1, nullptr },
|
||||
{ "dung0_mid_ew", -1, -1, -1, -1, nullptr },
|
||||
{ "dung0_mid_ns", -1, -1, -1, -1, nullptr },
|
||||
{ "dung0_rgt_ew", -1, -1, -1, -1, nullptr },
|
||||
{ "dung0_rgt_ns", -1, -1, -1, -1, nullptr },
|
||||
|
||||
{ "dung1_lft_ew", 0, 32, 0, 8, "dung1_xxx_ew" },
|
||||
{ "dung1_lft_ns", 0, 32, 0, 8, "dung1_xxx_ns" },
|
||||
{ "dung1_mid_ew", -1, -1, -1, -1, nullptr },
|
||||
{ "dung1_mid_ns", -1, -1, -1, -1, nullptr },
|
||||
{ "dung1_rgt_ew", 144, 32, 160, 8, "dung1_xxx_ew" },
|
||||
{ "dung1_rgt_ns", 144, 32, 160, 8, "dung1_xxx_ns" },
|
||||
|
||||
{ "dung2_lft_ew", 0, 64, 0, 48, "dung2_xxx_ew" },
|
||||
{ "dung2_lft_ns", 0, 64, 0, 48, "dung2_xxx_ns" },
|
||||
{ "dung2_mid_ew", -1, -1, -1, -1, nullptr },
|
||||
{ "dung2_mid_ns", -1, -1, -1, -1, nullptr },
|
||||
{ "dung2_rgt_ew", 112, 64, 128, 48, "dung2_xxx_ew" },
|
||||
{ "dung2_rgt_ns", 112, 64, 128, 48, "dung2_xxx_ns" },
|
||||
|
||||
{ "dung3_lft_ew", 0, 80, 48, 72, "dung3_xxx_ew" },
|
||||
{ "dung3_lft_ns", 0, 80, 48, 72, "dung3_xxx_ns" },
|
||||
{ "dung3_mid_ew", -1, -1, -1, -1, nullptr },
|
||||
{ "dung3_mid_ns", -1, -1, -1, -1, nullptr },
|
||||
{ "dung3_rgt_ew", 96, 80, 104, 72, "dung3_xxx_ew" },
|
||||
{ "dung3_rgt_ns", 96, 80, 104, 72, "dung3_xxx_ns" },
|
||||
|
||||
{ "dung0_lft_ew_door", -1, -1, -1, -1, nullptr },
|
||||
{ "dung0_lft_ns_door", -1, -1, -1, -1, nullptr },
|
||||
{ "dung0_mid_ew_door", -1, -1, -1, -1, nullptr },
|
||||
{ "dung0_mid_ns_door", -1, -1, -1, -1, nullptr },
|
||||
{ "dung0_rgt_ew_door", -1, -1, -1, -1, nullptr },
|
||||
{ "dung0_rgt_ns_door", -1, -1, -1, -1, nullptr },
|
||||
|
||||
{ "dung1_lft_ew_door", 0, 32, 0, 8, "dung1_xxx_ew" },
|
||||
{ "dung1_lft_ns_door", 0, 32, 0, 8, "dung1_xxx_ns" },
|
||||
{ "dung1_mid_ew_door", -1, -1, -1, -1, nullptr },
|
||||
{ "dung1_mid_ns_door", -1, -1, -1, -1, nullptr },
|
||||
{ "dung1_rgt_ew_door", 144, 32, 160, 8, "dung1_xxx_ew" },
|
||||
{ "dung1_rgt_ns_door", 144, 32, 160, 8, "dung1_xxx_ns" },
|
||||
|
||||
{ "dung2_lft_ew_door", 0, 64, 0, 48, "dung2_xxx_ew" },
|
||||
{ "dung2_lft_ns_door", 0, 64, 0, 48, "dung2_xxx_ns" },
|
||||
{ "dung2_mid_ew_door", -1, -1, -1, -1, nullptr },
|
||||
{ "dung2_mid_ns_door", -1, -1, -1, -1, nullptr },
|
||||
{ "dung2_rgt_ew_door", 112, 64, 128, 48, "dung2_xxx_ew" },
|
||||
{ "dung2_rgt_ns_door", 112, 64, 128, 48, "dung2_xxx_ns" },
|
||||
|
||||
{ "dung3_lft_ew_door", 0, 80, 48, 72, "dung3_xxx_ew" },
|
||||
{ "dung3_lft_ns_door", 0, 80, 48, 72, "dung3_xxx_ns" },
|
||||
{ "dung3_mid_ew_door", -1, -1, -1, -1, nullptr },
|
||||
{ "dung3_mid_ns_door", -1, -1, -1, -1, nullptr },
|
||||
{ "dung3_rgt_ew_door", 96, 80, 104, 72, "dung3_xxx_ew" },
|
||||
{ "dung3_rgt_ns_door", 96, 80, 104, 72, "dung3_xxx_ns" },
|
||||
|
||||
{ "dung0_ladderup", -1, -1, -1, -1, nullptr },
|
||||
{ "dung0_ladderup_side", -1, -1, -1, -1, nullptr },
|
||||
{ "dung1_ladderup", -1, -1, -1, -1, nullptr },
|
||||
{ "dung1_ladderup_side", -1, -1, -1, -1, nullptr },
|
||||
{ "dung2_ladderup", -1, -1, -1, -1, nullptr },
|
||||
{ "dung2_ladderup_side", -1, -1, -1, -1, nullptr },
|
||||
{ "dung3_ladderup", -1, -1, -1, -1, nullptr },
|
||||
{ "dung3_ladderup_side", -1, -1, -1, -1, nullptr },
|
||||
|
||||
{ "dung0_ladderdown", -1, -1, -1, -1, nullptr },
|
||||
{ "dung0_ladderdown_side", -1, -1, -1, -1, nullptr },
|
||||
{ "dung1_ladderdown", -1, -1, -1, -1, nullptr },
|
||||
{ "dung1_ladderdown_side", -1, -1, -1, -1, nullptr },
|
||||
{ "dung2_ladderdown", -1, -1, -1, -1, nullptr },
|
||||
{ "dung2_ladderdown_side", -1, -1, -1, -1, nullptr },
|
||||
{ "dung3_ladderdown", -1, -1, -1, -1, nullptr },
|
||||
{ "dung3_ladderdown_side", -1, -1, -1, -1, nullptr },
|
||||
|
||||
{ "dung0_ladderupdown", -1, -1, -1, -1, nullptr },
|
||||
{ "dung0_ladderupdown_side", -1, -1, -1, -1, nullptr },
|
||||
{ "dung1_ladderupdown", -1, -1, -1, -1, nullptr },
|
||||
{ "dung1_ladderupdown_side", -1, -1, -1, -1, nullptr },
|
||||
{ "dung2_ladderupdown", -1, -1, -1, -1, nullptr },
|
||||
{ "dung2_ladderupdown_side", -1, -1, -1, -1, nullptr },
|
||||
{ "dung3_ladderupdown", -1, -1, -1, -1, nullptr },
|
||||
{ "dung3_ladderupdown_side", -1, -1, -1, -1, nullptr },
|
||||
};
|
||||
|
||||
void DungeonView::drawWall(int xoffset, int distance, Direction orientation, DungeonGraphicType type) {
|
||||
int index;
|
||||
|
||||
index = graphicIndex(xoffset, distance, orientation, type);
|
||||
if (index == -1 || distance >= 4)
|
||||
return;
|
||||
|
||||
int x = 0, y = 0;
|
||||
SubImage *subimage = imageMgr->getSubImage(DNG_GRAPHIC_INFO[index].subimage);
|
||||
if (subimage) {
|
||||
x = subimage->left;
|
||||
y = subimage->top;
|
||||
}
|
||||
|
||||
g_screen->screenDrawImage(DNG_GRAPHIC_INFO[index].subimage, (BORDER_WIDTH + x) * settings._scale,
|
||||
(BORDER_HEIGHT + y) * settings._scale);
|
||||
|
||||
if (DNG_GRAPHIC_INFO[index].subimage2 != nullptr) {
|
||||
// FIXME: subimage2 is a horrible hack, needs to be cleaned up
|
||||
if (settings._videoType == "EGA")
|
||||
g_screen->screenDrawImage(DNG_GRAPHIC_INFO[index].subimage2,
|
||||
(8 + DNG_GRAPHIC_INFO[index].ega_x2) * settings._scale,
|
||||
(8 + DNG_GRAPHIC_INFO[index].ega_y2) * settings._scale);
|
||||
else
|
||||
g_screen->screenDrawImage(DNG_GRAPHIC_INFO[index].subimage2,
|
||||
(8 + DNG_GRAPHIC_INFO[index].vga_x2) * settings._scale,
|
||||
(8 + DNG_GRAPHIC_INFO[index].vga_y2) * settings._scale);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
Reference in New Issue
Block a user