Esempio n. 1
0
void VisualText::createTexture() {
	// Get the font and required metrics
	const Graphics::Font *font = StarkFontProvider->getScaledFont(_fontType, _fontCustomIndex);
	uint scaledLineHeight = StarkFontProvider->getScaledFontHeight(_fontType, _fontCustomIndex);
	uint originalLineHeight = StarkFontProvider->getOriginalFontHeight(_fontType, _fontCustomIndex);
	uint maxScaledLineWidth = StarkFontProvider->scaleWidthOriginalToCurrent(_originalRect.width());

	// Word wrap the text and compute the scaled and original resolution bounding boxes
	Common::Rect scaledRect;
	Common::Array<Common::String> lines;
	scaledRect.right = scaledRect.left + font->wordWrapText(_text, maxScaledLineWidth, lines);
	scaledRect.bottom = scaledRect.top + scaledLineHeight * lines.size();
	_originalRect.bottom = _originalRect.top + originalLineHeight * lines.size();

	// Create a surface to render to
	Graphics::Surface surface;
	surface.create(scaledRect.width(), scaledRect.height(), _gfx->getScreenFormat());
	surface.fillRect(scaledRect, _backgroundColor);

	// Render the lines to the surface
	for (uint i = 0; i < lines.size(); i++) {
		font->drawString(&surface, lines[i], 0, scaledLineHeight * i, scaledRect.width(), _color);
	}

	// Create a texture from the surface
	_texture = _gfx->createTexture(&surface);
	surface.free();
}
Esempio n. 2
0
void TestbedExitDialog::init() {
	_xOffset = 25;
	_yOffset = 0;
	Common::String text = "Thank you for using ScummVM testbed! Here are yor summarized results:";
	addText(450, 20, text, Graphics::kTextAlignCenter, _xOffset, 15);
	Common::Array<Common::String> strArray;
	GUI::ListWidget::ColorList colors;

	for (Common::Array<Testsuite *>::const_iterator i = _testsuiteList.begin(); i != _testsuiteList.end(); ++i) {
		strArray.push_back(Common::String::format("%s :", (*i)->getDescription()));
		colors.push_back(GUI::ThemeEngine::kFontColorNormal);
		if ((*i)->isEnabled()) {
			strArray.push_back(Common::String::format("Passed: %d  Failed: %d Skipped: %d", (*i)->getNumTestsPassed(), (*i)->getNumTestsFailed(), (*i)->getNumTestsSkipped()));
		} else {
			strArray.push_back("Skipped");
		}
		colors.push_back(GUI::ThemeEngine::kFontColorAlternate);
	}

	addList(0, _yOffset, 500, 200, strArray, &colors);
	text = "More Details can be viewed in the Log file : " + ConfParams.getLogFilename();
	addText(450, 20, text, Graphics::kTextAlignLeft, 0, 0);
	if (ConfParams.getLogDirectory().size()) {
		text = "Directory : " + ConfParams.getLogDirectory();
	} else {
		text = "Directory : .";
	}
	addText(500, 20, text, Graphics::kTextAlignLeft, 0, 0);
	_yOffset += 5;
	addButtonXY(_xOffset + 80, _yOffset, 120, 24, "Rerun test suite", kCmdRerunTestbed);
	addButtonXY(_xOffset + 240, _yOffset, 60, 24, "Close", GUI::kCloseCmd);
}
Esempio n. 3
0
void Graphics::loadMRG(Common::String filename, MRGFile *mrg) {
	Common::SeekableReadStream *mrgStream = _vm->data.openFile(filename);
	uint16 num_entries = mrgStream->readUint16LE();

	Common::Array<uint32> offsets;
	for (unsigned int i = 0; i < num_entries; i++) {
		offsets.push_back(mrgStream->readUint32LE());
	}

	for (unsigned int i = 0; i < num_entries; i++) {
		bool r = mrgStream->seek(offsets[i], SEEK_SET);
		assert(r);

		uint16 width = mrgStream->readUint16LE();
		uint16 height = mrgStream->readUint16LE();
		byte *pixels = new byte[width * height];
		mrgStream->read(pixels, width * height);

		mrg->heights.push_back(height);
		mrg->widths.push_back(width);
		mrg->data.push_back(pixels);
	}

	delete mrgStream;
}
Esempio n. 4
0
void Inventory::updateState() {
	Common::Array<uint16> items;
	for (ItemList::iterator it = _inventory.begin(); it != _inventory.end(); it++)
		items.push_back(it->var);

	_vm->_state->updateInventory(items);
}
Esempio n. 5
0
bool BuriedEngine::loadState(Common::SeekableReadStream *saveFile, Location &location, GlobalFlags &flags, Common::Array<int> &inventoryItems) {
    byte header[9];
    saveFile->read(header, kSavedGameHeaderSize);

    // Only compare the first 6 bytes
    // Win95 version of the game output garbage as the last two bytes
    if (saveFile->eos() || memcmp(header, s_savedGameHeader, kSavedGameHeaderSizeAlt) != 0)
        return false;

    Common::Serializer s(saveFile, 0);

    if (!syncLocation(s, location))
        return false;

    if (saveFile->eos())
        return false;

    if (!syncGlobalFlags(s, flags))
        return false;

    if (saveFile->eos())
        return false;

    uint16 itemCount = saveFile->readUint16LE();

    if (saveFile->eos())
        return false;

    inventoryItems.clear();
    for (uint16 i = 0; i < itemCount; i++)
        inventoryItems.push_back(saveFile->readUint16LE());

    return !saveFile->eos();
}
Esempio n. 6
0
void Inventory::loadFromState() {
	Common::Array<uint16> items = _vm->_state->getInventory();

	_inventory.clear();
	for (uint i = 0; i < items.size(); i++)
		addItem(items[i], true);
}
void StateProvider::writeResourceTree(Resources::Object *resource, Common::WriteStream *stream, bool current) {
	// Explicit scope to control the lifespan of the memory stream
	{
		Common::MemoryWriteStreamDynamic resourceStream(DisposeAfterUse::YES);
		ResourceSerializer serializer(nullptr, &resourceStream, kSaveVersion);

		// Serialize the resource to a memory stream
		if (current) {
			resource->saveLoadCurrent(&serializer);
		} else {
			resource->saveLoad(&serializer);
		}

		// Write the resource to the target stream
		stream->writeByte(resource->getType().get());
		stream->writeByte(resource->getSubType());
		stream->writeUint32LE(resourceStream.size());
		stream->write(resourceStream.getData(), resourceStream.size());
	}

	// Serialize the resource children
	Common::Array<Resources::Object *> children = resource->listChildren<Resources::Object>();
	for (uint i = 0; i < children.size(); i++) {
		writeResourceTree(children[i], stream, current);
	}
}
Esempio n. 8
0
Common::Array<AgeData> Database::loadAges(Common::ReadStreamEndian &s)
{
	Common::Array<AgeData> ages;

	for (uint i = 0; i < 10; i++) {
		AgeData age;

		if (_vm->getPlatform() == Common::kPlatformPS2) {
			// Really 64-bit values
			age.id = s.readUint32LE();
			s.readUint32LE();
			age.disk = s.readUint32LE();
			s.readUint32LE();
			age.roomCount = s.readUint32LE();
			s.readUint32LE();
			age.roomsOffset = s.readUint32LE() - _executableVersion->baseOffset;
			s.readUint32LE();
			age.labelId = s.readUint32LE();
			s.readUint32LE();
		} else {
			age.id = s.readUint32();
			age.disk = s.readUint32();
			age.roomCount = s.readUint32();
			age.roomsOffset = s.readUint32() - _executableVersion->baseOffset;
			age.labelId = s.readUint32();
		}

		ages.push_back(age);
	}

	return ages;
}
Esempio n. 9
0
bool Console::Cmd_DecompileScript(int argc, const char **argv) {
	if (argc >= 2) {
		uint index = atoi(argv[1]);

		Common::Array<Resources::Script *> scripts = listAllLocationScripts();
		if (index < scripts.size()) {
			Resources::Script *script = scripts[index];

			Tools::Decompiler *decompiler = new Tools::Decompiler(script);
			if (decompiler->getError() != "") {
				debugPrintf("Decompilation failure: %s\n", decompiler->getError().c_str());
			}

			debug("Script %d - %s:", index, script->getName().c_str());
			decompiler->printDecompiled();

			delete decompiler;

			return true;
		} else {
			debugPrintf("Invalid index %d, only %d indices available\n", index, scripts.size());
		}
	} else {
		debugPrintf("Too few args\n");
	}

	debugPrintf("Decompile a script. Use listScripts to get an id\n");
	debugPrintf("Usage :\n");
	debugPrintf("decompileScript [id]\n");
	return true;
}
Esempio n. 10
0
Common::Array<reg_t> DataStack::listAllOutgoingReferences(reg_t object) const {
	Common::Array<reg_t> tmp;
	for (int i = 0; i < _capacity; i++)
		tmp.push_back(_entries[i]);

	return tmp;
}
Esempio n. 11
0
bool Console::Cmd_ForceScript(int argc, const char **argv) {
	uint index = 0;

	if (argc >= 2) {
		index = atoi(argv[1]);

		Common::Array<Resources::Script *> scripts = listAllLocationScripts();
		if (index < scripts.size() ) {
			Resources::Script *script = scripts[index];
			script->enable(true);
			script->goToNextCommand(); // Skip the begin command to avoid checks
			script->execute(Resources::Script::kCallModePlayerAction);
			return true;
		} else {
			debugPrintf("Invalid index %d, only %d indices available\n", index, scripts.size());
		}
	} else {
		debugPrintf("Too few args\n");
	}

	debugPrintf("Force the execution of a script. Use listScripts to get an id\n");
	debugPrintf("Usage :\n");
	debugPrintf("forceScript [id]\n");
	return true;
}
Esempio n. 12
0
Common::Array<reg_t> LocalVariables::listAllOutgoingReferences(reg_t addr) const {
	Common::Array<reg_t> tmp;
	for (uint i = 0; i < _locals.size(); i++)
		tmp.push_back(_locals[i]);

	return tmp;
}
Esempio n. 13
0
void listSavegames(Common::Array<SavegameDesc> &saves) {
	Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();

	// Load all saves
	Common::StringList saveNames = saveFileMan->listSavefiles(((SciEngine *)g_engine)->getSavegamePattern());

	for (Common::StringList::const_iterator iter = saveNames.begin(); iter != saveNames.end(); ++iter) {
		Common::String filename = *iter;
		Common::SeekableReadStream *in;
		if ((in = saveFileMan->openForLoading(filename))) {
			SavegameMetadata meta;
			if (!get_savegame_metadata(in, &meta)) {
				// invalid
				delete in;
				continue;
			}
			delete in;

			SavegameDesc desc;
			desc.id = strtol(filename.end() - 3, NULL, 10);
			desc.date = meta.savegame_date;
			desc.time = meta.savegame_time;
			debug(3, "Savegame in file %s ok, id %d", filename.c_str(), desc.id);

			saves.push_back(desc);
		}
	}

	// Sort the list by creation date of the saves
	qsort(saves.begin(), saves.size(), sizeof(SavegameDesc), _savegame_index_struct_compare);
}
Esempio n. 14
0
void StateProvider::readResourceTree(Resources::Object *resource, Common::SeekableReadStream *stream, bool current, uint32 version) {
	// Read the resource to the source stream
	/* byte type = */ stream->readByte();
	/* byte subType = */ stream->readByte();
	uint32 size = stream->readUint32LE();

	if (size > 0) {
		Common::SeekableReadStream *resourceStream = stream->readStream(size);
		ResourceSerializer serializer(resourceStream, nullptr, version);

		// Deserialize the resource state from stream
		if (current) {
			resource->saveLoadCurrent(&serializer);
		} else {
			resource->saveLoad(&serializer);
		}

		delete resourceStream;
	}

	// Deserialize the resource children
	Common::Array<Resources::Object *> children = resource->listChildren<Resources::Object>();
	for (uint i = 0; i < children.size(); i++) {
		readResourceTree(children[i], stream, current, version);
	}
}
Esempio n. 15
0
bool SaveReader::getInfo(Common::SeekableReadStream &stream, SavePartInfo &info) {
	// Remeber the stream's starting position to seek back to
	uint32 startPos = stream.pos();

	// Get parts' basic information
	Common::Array<SaveContainer::PartInfo> *partsInfo = getPartsInfo(stream);

	// No parts => fail
	if (!partsInfo) {
		stream.seek(startPos);
		return false;
	}

	bool result = false;
	// Iterate over all parts
	for (Common::Array<SaveContainer::PartInfo>::iterator it = partsInfo->begin();
	     it != partsInfo->end(); ++it) {

		// Check for the info part
		if (it->id == SavePartInfo::kID) {
			if (!stream.seek(it->offset))
				break;

			// Read it
			result = info.read(stream);
			break;
		}
	}

	stream.seek(startPos);

	delete partsInfo;
	return result;
}
Esempio n. 16
0
void WalkRegion::computeVisibilityMatrix() {
	// Initialize visibility matrix
	_visibilityMatrix = Common::Array< Common::Array <int> >();
	for (uint idx = 0; idx < _nodes.size(); ++idx) {
		Common::Array<int> arr;
		for (uint idx2 = 0; idx2 < _nodes.size(); ++idx2)
			arr.push_back(Infinity);

		_visibilityMatrix.push_back(arr);
	}

	// Calculate visibility been vertecies
	for (uint j = 0; j < _nodes.size(); ++j) {
		for (uint i = j; i < _nodes.size(); ++i)   {
			if (isLineOfSight(_nodes[i], _nodes[j])) {
				// There is a line of sight, so save the distance between the two
				int distance = _nodes[i].distance(_nodes[j]);
				_visibilityMatrix[i][j] = distance;
				_visibilityMatrix[j][i] = distance;
			} else {
				// There is no line of sight, so save Infinity as the distance
				_visibilityMatrix[i][j] = Infinity;
				_visibilityMatrix[j][i] = Infinity;
			}
		}
	}
}
Esempio n. 17
0
Common::Array<Opcode> Database::loadOpcodes(Common::ReadStreamEndian &s) {
	Common::Array<Opcode> script;

	while (1) {
		Opcode opcode;
		uint16 code = s.readUint16();

		opcode.op = code & 0xff;
		uint8 count = code >> 8;
		if (count == 0 && opcode.op == 0)
			break;

		// The v1.0 executables use a slightly different opcode set
		// Since it's a simple conversion, we'll handle that here
		if ((_executableVersion->flags & kFlagVersion10) && opcode.op >= 122)
			opcode.op++;

		for (int i = 0; i < count; i++) {
			int16 value = s.readSint16();
			opcode.args.push_back(value);
		}

		script.push_back(opcode);
	}

	return script;
}
Esempio n. 18
0
bool Console::Cmd_EnableScript(int argc, const char **argv) {
	uint index = 0;

	if (argc >= 2) {
		index = atoi(argv[1]);

		bool value = true;
		if (argc >= 3) {
			value = atoi(argv[2]);
		}

		Common::Array<Resources::Script *> scripts = listAllLocationScripts();
		if (index < scripts.size() ) {
			Resources::Script *script = scripts[index];
			script->enable(value);
			return true;
		} else {
			debugPrintf("Invalid index %d, only %d indices available\n", index, scripts.size());
		}
	} else {
		debugPrintf("Too few args\n");
	}

	debugPrintf("Enable or disable a script. Use listScripts to get an id\n");
	debugPrintf("Usage :\n");
	debugPrintf("enableScript [id] (value)\n");
	return true;
}
Esempio n. 19
0
Common::Array<Common::String> SavesSyncRequest::getFilesToDownload() {
	Common::Array<Common::String> result;
	for (uint32 i = 0; i < _filesToDownload.size(); ++i)
		result.push_back(_filesToDownload[i].name());
	if (_currentDownloadingFile.name() != "")
		result.push_back(_currentDownloadingFile.name());
	return result;
}
Esempio n. 20
0
void FloorEdge::addNeighboursFromFace(const FloorFace *face) {
	Common::Array<FloorEdge *> faceEdges = face->getEdges();
	for (uint i = 0; i < faceEdges.size(); i++) {
		if (faceEdges[i] != this) {
			_neighbours.push_back(faceEdges[i]);
		}
	}
}
Esempio n. 21
0
Common::Array<uint32> Archive::getResourceTypeList() const {
	Common::Array<uint32> typeList;

	for (TypeMap::const_iterator it = _types.begin(); it != _types.end(); it++)
		typeList.push_back(it->_key);

	return typeList;
}
Esempio n. 22
0
MessageDialog::MessageDialog(const Common::String &message, const char *defaultButton, const char *altButton)
	: Dialog(30, 20, 260, 124) {

	const int screenW = g_system->getOverlayWidth();
	const int screenH = g_system->getOverlayHeight();

	int buttonWidth = g_gui.xmlEval()->getVar("Globals.Button.Width", 0);
	int buttonHeight = g_gui.xmlEval()->getVar("Globals.Button.Height", 0);

	// First, determine the size the dialog needs. For this we have to break
	// down the string into lines, and taking the maximum of their widths.
	// Using this, and accounting for the space the button(s) need, we can set
	// the real size of the dialog
	Common::Array<Common::String> lines;
	int lineCount, okButtonPos, cancelButtonPos;
	int maxlineWidth = g_gui.getFont().wordWrapText(message, screenW - 2 * 20, lines);

	// Calculate the desired dialog size (maxing out at 300*180 for now)
	if (altButton)
		_w = MAX(maxlineWidth, (2 * buttonWidth) + 10) + 20;
	else
		_w = MAX(maxlineWidth, buttonWidth) + 20;

	lineCount = lines.size();

	_h = 16;
	if (defaultButton || altButton)
		_h += buttonHeight + 8;

	// Limit the number of lines so that the dialog still fits on the screen.
	if (lineCount > (screenH - 20 - _h) / kLineHeight) {
		lineCount = (screenH - 20 - _h) / kLineHeight;
	}
	_h += lineCount * kLineHeight;

	// Center the dialog
	_x = (screenW - _w) / 2;
	_y = (screenH - _h) / 2;

	// Each line is represented by one static text item.
	for (int i = 0; i < lineCount; i++) {
		new StaticTextWidget(this, 10, 10 + i * kLineHeight, maxlineWidth, kLineHeight,
								lines[i], Graphics::kTextAlignCenter);
	}

	if (defaultButton && altButton) {
		okButtonPos = (_w - (buttonWidth * 2)) / 2;
		cancelButtonPos = ((_w - (buttonWidth * 2)) / 2) + buttonWidth + 10;
	} else {
		okButtonPos = cancelButtonPos = (_w - buttonWidth) / 2;
	}

	if (defaultButton)
		new ButtonWidget(this, okButtonPos, _h - buttonHeight - 8, buttonWidth, buttonHeight, defaultButton, 0, kOkCmd, Common::ASCII_RETURN);	// Confirm dialog

	if (altButton)
		new ButtonWidget(this, cancelButtonPos, _h - buttonHeight - 8, buttonWidth, buttonHeight, altButton, 0, kCancelCmd, Common::ASCII_ESCAPE);	// Cancel dialog
}
Esempio n. 23
0
// Print a list of all registered commands (and variables, if any),
// nicely word-wrapped.
bool Debugger::Cmd_Help(int argc, const char **argv) {
#ifndef USE_TEXT_CONSOLE
	const int charsPerLine = _debuggerDialog->getCharsPerLine();
#elif defined(USE_READLINE)
	int charsPerLine, rows;
	rl_get_screen_size(&rows, &charsPerLine);
#else
	// Can we do better?
	const int charsPerLine = 80;
#endif
	int width, size;
	uint i;

	DebugPrintf("Commands are:\n");

	// Obtain a list of sorted command names
	Common::Array<Common::String> cmds;
	CommandsMap::const_iterator iter, e = _cmds.end();
	for (iter = _cmds.begin(); iter != e; ++iter) {
		cmds.push_back(iter->_key);
	}
	sort(cmds.begin(), cmds.end());

	// Print them all
	width = 0;
	for (i = 0; i < cmds.size(); i++) {
		size = cmds[i].size() + 1;

		if ((width + size) >= charsPerLine) {
			DebugPrintf("\n");
			width = size;
		} else
			width += size;

		DebugPrintf("%s ", cmds[i].c_str());
	}
	DebugPrintf("\n");

	if (!_dvars.empty()) {
		DebugPrintf("\n");
		DebugPrintf("Variables are:\n");
		width = 0;
		for (i = 0; i < _dvars.size(); i++) {
			size = _dvars[i].name.size() + 1;

			if ((width + size) >= charsPerLine) {
				DebugPrintf("\n");
				width = size;
			} else
				width += size;

			DebugPrintf("%s ", _dvars[i].name.c_str());
		}
		DebugPrintf("\n");
	}

	return true;
}
Esempio n. 24
0
Common::Array<const ASTCommand *> ASTBlock::listCommands(uint16 index) const {
	Common::Array<const ASTCommand *> list;

	for (uint i = 0; i < _children.size(); i++) {
		list.push_back(_children[i]->listCommands(index));
	}

	return list;
}
Esempio n. 25
0
Common::Array<const ASTCommand *> ASTCommand::listCommands(uint16 index) const {
	Common::Array<const ASTCommand *> list;

	if (_index == index) {
		list.push_back(this);
	}

	return list;
}
Esempio n. 26
0
void TabWidget::drawWidget() {
	Common::Array<Common::String> tabs;
	for (int i = _firstVisibleTab; i < (int)_tabs.size(); ++i) {
		tabs.push_back(_tabs[i].title);
	}
	g_gui.theme()->drawDialogBackgroundClip(Common::Rect(_x + _bodyLP, _y + _bodyTP, _x+_w-_bodyRP, _y+_h-_bodyBP+_tabHeight), getBossClipRect(), _bodyBackgroundType);

	g_gui.theme()->drawTabClip(Common::Rect(_x, _y, _x+_w, _y+_h), getBossClipRect(), _tabHeight, _tabWidth, tabs, _activeTab - _firstVisibleTab, 0, _titleVPad);
}
Esempio n. 27
0
Database::Database(Myst3Engine *vm) :
		_vm(vm),
		_currentRoomID(0),
		_executableVersion(0),
		_currentRoomData(0) {

	_executableVersion = _vm->getExecutableVersion();

	if (_executableVersion != 0) {
		debug("Initializing database from %s (Platform: %s) (%s)", _executableVersion->executable, getPlatformDescription(_vm->getPlatform()), _executableVersion->description);
	} else {
		error("Could not find any executable to load");
	}

	// Load the ages and rooms description
	Common::SeekableSubReadStreamEndian *file = openDatabaseFile();
	file->seek(_executableVersion->ageTableOffset);
	_ages = loadAges(*file);

	for (uint i = 0; i < _ages.size(); i++) {
		file->seek(_ages[i].roomsOffset);

		// Read the room offset table
		Common::Array<uint32> roomsOffsets;
		for (uint j = 0; j < _ages[i].roomCount; j++) {
			uint32 offset = file->readUint32() - _executableVersion->baseOffset;
			roomsOffsets.push_back(offset);
		}

		// Load the rooms
		for (uint j = 0; j < roomsOffsets.size(); j++) {
			file->seek(roomsOffsets[j]);

			_ages[i].rooms.push_back(loadRoomDescription(*file));
		}
	}

	file->seek(_executableVersion->nodeInitScriptOffset);
	_nodeInitScript = loadOpcodes(*file);

	file->seek(_executableVersion->soundNamesOffset);
	loadSoundNames(file);

	// TODO: Remove once the offset table is complete
	if (!_executableVersion->ambientCuesOffset) {
		error("The description for this executable (%s, %s) does not contain the ambient cues offset. Please contact the ResidualVM team.",
				_executableVersion->executable, _executableVersion->description);
	}

	file->seek(_executableVersion->ambientCuesOffset);
	loadAmbientCues(file);

	preloadCommonRooms(file);
	initializeZipBitIndexTable(file);

	delete file;
}
Esempio n. 28
0
Common::Array<const ASTCommand *> ASTLoop::listCommands(uint16 index) const {
	Common::Array<const ASTCommand *> list;

	if (condition) {
		list.push_back(condition->listCommands(index));
	}
	list.push_back(loopBlock->listCommands(index));

	return list;
}
Esempio n. 29
0
Common::Array<Resources::Script *> Console::listAllLocationScripts() const {
	Common::Array<Resources::Script *> scripts;

	Resources::Level *level = StarkGlobal->getCurrent()->getLevel();
	Resources::Location *location = StarkGlobal->getCurrent()->getLocation();
	scripts.push_back(level->listChildrenRecursive<Resources::Script>());
	scripts.push_back(location->listChildrenRecursive<Resources::Script>());

	return scripts;
}
Esempio n. 30
0
void Graphics::renderPolygonEdge(Common::Array<Common::Point> &points, byte colour) {
	::Graphics::Surface *surf = _vm->_system->lockScreen();
	for (unsigned int i = 0; i < points.size(); i++) {
		if (i + 1 < points.size())
			surf->drawLine(points[i].x, points[i].y, points[i + 1].x, points[i + 1].y, colour);
		else
			surf->drawLine(points[i].x, points[i].y, points[0].x, points[0].y, colour);
	}
	_vm->_system->unlockScreen();
}