void Animation::load(MSurface &backSurface, DepthSurface &depthSurface, const Common::String &resName, int flags, Common::Array<PaletteCycle> *palCycles, SceneInfo *sceneInfo) { Common::String resourceName = resName; if (!resourceName.contains(".")) resourceName += ".AA"; File f(resourceName); MadsPack madsPack(&f); Common::SeekableReadStream *stream = madsPack.getItemStream(0); _header.load(stream); delete stream; if (_header._bgType == ANIMBG_INTERFACE) flags |= PALFLAG_RESERVED; _flags = flags; if (flags & ANIMFLAG_LOAD_BACKGROUND) { loadBackground(backSurface, depthSurface, _header, flags, palCycles, sceneInfo); } if (flags & ANIMFLAG_LOAD_BACKGROUND_ONLY) { // No data _header._messagesCount = 0; _header._frameEntriesCount = 0; _header._miscEntriesCount = 0; } // Initialize the reference list _spriteListIndexes.clear(); for (int i = 0; i < _header._spriteSetsCount; ++i) _spriteListIndexes.push_back(-1); int streamIndex = 1; _messages.clear(); if (_header._messagesCount > 0) { // Chunk 2: Following is a list of any messages for the animation Common::SeekableReadStream *msgStream = madsPack.getItemStream(streamIndex++); for (int i = 0; i < _header._messagesCount; ++i) { AnimMessage rec; rec.load(msgStream); _messages.push_back(rec); } delete msgStream; } _frameEntries.clear(); if (_header._frameEntriesCount > 0) { // Chunk 3: animation frame info Common::SeekableReadStream *frameStream = madsPack.getItemStream(streamIndex++); for (int i = 0; i < _header._frameEntriesCount; i++) { AnimFrameEntry rec; rec.load(frameStream, _header._bgType == ANIMBG_INTERFACE); _frameEntries.push_back(rec); } delete frameStream; } _miscEntries.clear(); _uiEntries.clear(); if (_header._miscEntriesCount > 0) { // Chunk 4: Misc Data Common::SeekableReadStream *miscStream = madsPack.getItemStream(streamIndex++); if (_header._bgType == ANIMBG_INTERFACE) { for (int i = 0; i < _header._miscEntriesCount; ++i) { AnimUIEntry rec; rec.load(miscStream); _uiEntries.push_back(rec); } } else { for (int i = 0; i < _header._miscEntriesCount; ++i) { AnimMiscEntry rec; rec.load(miscStream); _miscEntries.push_back(rec); } } delete miscStream; } // If the animation specifies a font, then load it for access delete _font; if (_header._loadFlags & ANIMFLAG_CUSTOM_FONT) { Common::String fontName = "*" + _header._fontResource; _font = _vm->_font->getFont(fontName.c_str()); } else { _font = nullptr; } // Load all the sprite sets for the animation for (uint i = 0; i < _spriteSets.size(); ++i) delete _spriteSets[i]; _spriteSets.clear(); _spriteSets.resize(_header._spriteSetsCount); for (int i = 0; i < _header._spriteSetsCount; ++i) { if (_header._manualFlag && (i == _header._spritesIndex)) { // Skip over field, since it's manually loaded _spriteSets[i] = nullptr; } else { _spriteSets[i] = new SpriteAsset(_vm, _header._spriteSetNames[i], flags); _spriteListIndexes[i] = _vm->_game->_scene._sprites.add(_spriteSets[i]); } } if (_header._manualFlag) { Common::String assetResName = "*" + _header._spriteSetNames[_header._spritesIndex]; SpriteAsset *sprites = new SpriteAsset(_vm, assetResName, flags); _spriteSets[_header._spritesIndex] = sprites; _spriteListIndexes[_header._spritesIndex] = _scene->_sprites.add(sprites); } Common::Array<int> usageList; for (int idx = 0; idx < _header._spriteSetsCount; ++idx) usageList.push_back(_spriteSets[idx]->_usageIndex); if (usageList.size() > 0) { int spritesUsageIndex = _spriteSets[0]->_usageIndex; _vm->_palette->_paletteUsage.updateUsage(usageList, spritesUsageIndex); } // Remaps the sprite list indexes for frames to the loaded sprite list indexes for (uint i = 0; i < _frameEntries.size(); ++i) { int spriteListIndex = _frameEntries[i]._spriteSlot._spritesIndex; _frameEntries[i]._spriteSlot._spritesIndex = _spriteListIndexes[spriteListIndex]; } f.close(); }
bool WintermuteEngine::getGameInfo(const Common::FSList &fslist, Common::String &name, Common::String &caption) { bool retVal = false; caption = name = "(invalid)"; Common::SeekableReadStream *stream = nullptr; // Quick-fix, instead of possibly breaking the persistence-system, let's just roll with it BaseFileManager *fileMan = new BaseFileManager(Common::UNK_LANG, true); fileMan->registerPackages(fslist); stream = fileMan->openFile("startup.settings", false, false); // The process is as follows: Check the "GAME=" tag in startup.settings, to decide where the // game-settings are (usually "default.game"), then look into the game-settings to find // the NAME = and CAPTION = tags, to use them to generate a gameid and extras-field Common::String settingsGameFile = "default.game"; // If the stream-open failed, lets at least attempt to open the default game file afterwards // so, we don't call it a failure yet. if (stream) { while (!stream->eos() && !stream->err()) { Common::String line = stream->readLine(); line.trim(); // Get rid of indentation // Expect "SETTINGS {" or comment, or empty line if (line.size() == 0 || line[0] == ';' || (line.contains("{"))) { continue; } else { // We are looking for "GAME =" Common::StringTokenizer token(line, "="); Common::String key = token.nextToken(); Common::String value = token.nextToken(); if (value.size() == 0) { continue; } if (value[0] == '\"') { value.deleteChar(0); } else { continue; } if (value.lastChar() == '\"') { value.deleteLastChar(); } if (key == "GAME") { settingsGameFile = value; break; } } } } delete stream; stream = fileMan->openFile(settingsGameFile, false, false); if (stream) { // We do some manual parsing here, as the engine needs gfx to be initalized to do that. while (!stream->eos() && !stream->err()) { Common::String line = stream->readLine(); line.trim(); // Get rid of indentation // Expect "GAME {" or comment, or empty line if (line.size() == 0 || line[0] == ';' || (line.contains("{"))) { continue; } else { Common::StringTokenizer token(line, "="); Common::String key = token.nextToken(); Common::String value = token.nextToken(); if (value.size() == 0) { continue; } if (value[0] == '\"') { value.deleteChar(0); } else { continue; // not a string } if (value.lastChar() == '\"') { value.deleteLastChar(); } if (key == "NAME") { retVal = true; name = value; } else if (key == "CAPTION") { retVal = true; // Remove any translation tags, if they are included in the game description. // This can potentially remove parts of a string that has translation tags // and contains a "/" in its description (e.g. /tag/Name start / name end will // result in "name end"), but it's a very rare case, and this code is just used // for fallback anyway. if (value.hasPrefix("/")) { value.deleteChar(0); while (value.contains("/")) { value.deleteChar(0); } } caption = value; } } } delete stream; } delete fileMan; BaseEngine::destroy(); return retVal; }
SafeControl::SafeControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) : Control(engine, key, CONTROL_SAFE) { _statesCount = 0; _curState = 0; _animation = NULL; _innerRaduis = 0; _innerRadiusSqr = 0; _outerRadius = 0; _outerRadiusSqr = 0; _zeroPointer = 0; _startPointer = 0; _targetFrame = 0; // Loop until we find the closing brace Common::String line = stream.readLine(); _engine->getScriptManager()->trimCommentsAndWhiteSpace(&line); Common::String param; Common::String values; getParams(line, param, values); while (!stream.eos() && !line.contains('}')) { if (param.matchString("animation", true)) { _animation = _engine->loadAnimation(values); _animation->start(); } else if (param.matchString("rectangle", true)) { int x; int y; int width; int height; sscanf(values.c_str(), "%d %d %d %d", &x, &y, &width, &height); _rectangle = Common::Rect(x, y, width, height); } else if (param.matchString("num_states", true)) { _statesCount = atoi(values.c_str()); } else if (param.matchString("center", true)) { int x; int y; sscanf(values.c_str(), "%d %d", &x, &y); _center = Common::Point(x, y); } else if (param.matchString("dial_inner_radius", true)) { _innerRaduis = atoi(values.c_str()); _innerRadiusSqr = _innerRaduis * _innerRaduis; } else if (param.matchString("radius", true)) { _outerRadius = atoi(values.c_str()); _outerRadiusSqr = _outerRadius * _outerRadius; } else if (param.matchString("zero_radians_offset", true)) { _zeroPointer = atoi(values.c_str()); } else if (param.matchString("pointer_offset", true)) { _startPointer = atoi(values.c_str()); _curState = _startPointer; } else if (param.matchString("cursor", true)) { // Not used } else if (param.matchString("mirrored", true)) { // Not used } else if (param.matchString("venus_id", true)) { _venusId = atoi(values.c_str()); } line = stream.readLine(); _engine->getScriptManager()->trimCommentsAndWhiteSpace(&line); getParams(line, param, values); } if (_animation) _animation->seekToFrame(_curState); }
void TextObject::setupText() { Common::String msg = LuaBase::instance()->parseMsgText(_textID.c_str(), NULL); Common::String message; // remove spaces (NULL_TEXT) from the end of the string, // while this helps make the string unique it screws up // text justification // remove char of id 13 from the end of the string, int pos = msg.size() - 1; while (pos >= 0 && (msg[pos] == ' ' || msg[pos] == 13)) { msg.deleteLastChar(); pos = msg.size() - 1; } delete[] _lines; if (msg.size() == 0) { _lines = NULL; return; } if (g_grim->getGameType() == GType_MONKEY4) { if (_x == 0) _x = 320; if (_y == 0) _y = 240; } // format the output message to incorporate line wrapping // (if necessary) for the text object const int SCREEN_WIDTH = _width ? _width : 640; const int SCREEN_MARGIN = 75; // If the speaker is too close to the edge of the screen we have to make // some room for the subtitles. if (_isSpeech){ if (_x < SCREEN_MARGIN) { _x = SCREEN_MARGIN; } else if (SCREEN_WIDTH - _x < SCREEN_MARGIN) { _x = SCREEN_WIDTH - SCREEN_MARGIN; } } // The maximum width for any line of text is determined by the justification // mode. Note that there are no left/right margins -- this is consistent // with GrimE. int maxWidth = 0; if (_justify == CENTER) { maxWidth = 2 * MIN(_x, SCREEN_WIDTH - _x); } else if (_justify == LJUSTIFY) { maxWidth = SCREEN_WIDTH - _x; } else if (_justify == RJUSTIFY) { maxWidth = _x; } // We break the message to lines not longer than maxWidth Common::String currLine; _numberLines = 1; int lineWidth = 0; int maxLineWidth = 0; for (uint i = 0; i < msg.size(); i++) { lineWidth += MAX(_font->getCharWidth(msg[i]), _font->getCharDataWidth(msg[i])); if (lineWidth > maxWidth) { bool wordSplit = false; if (currLine.contains(' ')) { while (msg[i] != ' ' && i > 0) { lineWidth -= MAX(_font->getCharWidth(msg[i]), _font->getCharDataWidth(msg[i])); message.deleteLastChar(); --i; } } else if (msg[i] != ' ') { // if it is a unique word int dashWidth = MAX(_font->getCharWidth('-'), _font->getCharDataWidth('-')); while (lineWidth + dashWidth > maxWidth) { lineWidth -= MAX(_font->getCharWidth(msg[i]), _font->getCharDataWidth(msg[i])); message.deleteLastChar(); --i; } message += '-'; wordSplit = true; } message += '\n'; currLine.clear(); _numberLines++; if (lineWidth > maxLineWidth) { maxLineWidth = lineWidth; } lineWidth = 0; if (wordSplit) { lineWidth += MAX(_font->getCharWidth(msg[i]), _font->getCharDataWidth(msg[i])); } else { continue; // don't add the space back } } if (lineWidth > maxLineWidth) maxLineWidth = lineWidth; message += msg[i]; currLine += msg[i]; } // If the text object is a speech subtitle, the y parameter is the // coordinate of the bottom of the text block (instead of the top). It means // that every extra line pushes the previous lines up, instead of being // printed further down the screen. const int SCREEN_TOP_MARGIN = 16; if (_isSpeech) { _y -= _numberLines * _font->getHeight(); if (_y < SCREEN_TOP_MARGIN) { _y = SCREEN_TOP_MARGIN; } } _lines = new Common::String[_numberLines]; for (int j = 0; j < _numberLines; j++) { int nextLinePos, cutLen; const char *breakPos = strchr(message.c_str(), '\n'); if (breakPos) { nextLinePos = breakPos - message.c_str(); cutLen = nextLinePos + 1; } else { nextLinePos = message.size(); cutLen = nextLinePos; } Common::String currentLine(message.c_str(), message.c_str() + nextLinePos); _lines[j] = currentLine; int width = _font->getStringLength(currentLine); if (width > _maxLineWidth) _maxLineWidth = width; for (int count = 0; count < cutLen; count++) message.deleteChar(0); } _elapsedTime = 0; }
void Inter_v6::o6_playVmdOrMusic() { Common::String file = _vm->_game->_script->evalString(); VideoPlayer::Properties props; props.x = _vm->_game->_script->readValExpr(); props.y = _vm->_game->_script->readValExpr(); props.startFrame = _vm->_game->_script->readValExpr(); props.lastFrame = _vm->_game->_script->readValExpr(); props.breakKey = _vm->_game->_script->readValExpr(); props.flags = _vm->_game->_script->readValExpr(); props.palStart = _vm->_game->_script->readValExpr(); props.palEnd = _vm->_game->_script->readValExpr(); props.palCmd = 1 << (props.flags & 0x3F); props.forceSeek = true; debugC(1, kDebugVideo, "Playing video \"%s\" @ %d+%d, frames %d - %d, " "paletteCmd %d (%d - %d), flags %X", file.c_str(), props.x, props.y, props.startFrame, props.lastFrame, props.palCmd, props.palStart, props.palEnd, props.flags); // WORKAROUND: When taking the music sheet from Dr. Dramish's car, // the video that lets the sheet vanish is missing. We'll // play the one where the sheet is already gone instead. if (_vm->isCurrentTot("avt005.tot") && file.equalsIgnoreCase("MXRAMPART")) file = "PLCOFDR2"; if (file == "RIEN") { _vm->_vidPlayer->closeAll(); return; } bool close = false; if (props.lastFrame == -1) { close = true; } else if (props.lastFrame == -5) { // warning("Urban/Playtoons Stub: Stop without delay"); _vm->_sound->bgStop(); return; } else if (props.lastFrame == -6) { // warning("Urban/Playtoons Stub: Video/Music command -6 (cache video)"); return; } else if (props.lastFrame == -7) { // warning("Urban/Playtoons Stub: Video/Music command -6 (flush cache)"); return; } else if ((props.lastFrame == -8) || (props.lastFrame == -9)) { if (!file.contains('.')) file += ".WA8"; probe16bitMusic(file); if (props.lastFrame == -9) debugC(0, kDebugVideo, "Urban/Playtoons Stub: Delayed music stop?"); _vm->_sound->bgStop(); _vm->_sound->bgPlay(file.c_str(), SOUND_WAV); return; } else if (props.lastFrame <= -10) { _vm->_vidPlayer->closeVideo(); if (!(props.flags & VideoPlayer::kFlagNoVideo)) props.loop = true; } else if (props.lastFrame < 0) { warning("Urban/Playtoons Stub: Unknown Video/Music command: %d, %s", props.lastFrame, file.c_str()); return; } if (props.startFrame == -2) { props.startFrame = 0; props.lastFrame = -1; props.noBlock = true; } _vm->_vidPlayer->evaluateFlags(props); bool primary = true; if (props.noBlock && (props.flags & VideoPlayer::kFlagNoVideo)) primary = false; int slot = 0; if (!file.empty() && ((slot = _vm->_vidPlayer->openVideo(primary, file, props)) < 0)) { WRITE_VAR(11, (uint32) -1); return; } if (props.hasSound) _vm->_vidPlayer->closeLiveSound(); if (props.startFrame >= 0) _vm->_vidPlayer->play(slot, props); if (close && !props.noBlock) { if (!props.canceled) _vm->_vidPlayer->waitSoundEnd(slot); _vm->_vidPlayer->closeVideo(slot); } }
void Inter_v7::o7_playVmdOrMusic() { Common::String file = _vm->_game->_script->evalString(); VideoPlayer::Properties props; props.x = _vm->_game->_script->readValExpr(); props.y = _vm->_game->_script->readValExpr(); props.startFrame = _vm->_game->_script->readValExpr(); props.lastFrame = _vm->_game->_script->readValExpr(); props.breakKey = _vm->_game->_script->readValExpr(); props.flags = _vm->_game->_script->readValExpr(); props.palStart = _vm->_game->_script->readValExpr(); props.palEnd = _vm->_game->_script->readValExpr(); props.palCmd = 1 << (props.flags & 0x3F); props.forceSeek = true; debugC(1, kDebugVideo, "Playing video \"%s\" @ %d+%d, frames %d - %d, " "paletteCmd %d (%d - %d), flags %X", file.c_str(), props.x, props.y, props.startFrame, props.lastFrame, props.palCmd, props.palStart, props.palEnd, props.flags); if (file == "RIEN") { _vm->_vidPlayer->closeAll(); return; } bool close = false; if (props.lastFrame == -1) { close = true; } else if (props.lastFrame == -3) { if (file.empty()) { _vm->_vidPlayer->closeVideo(_vm->_mult->_objects[props.startFrame].videoSlot - 1); _vm->_mult->_objects[props.startFrame].videoSlot = 0; return; } props.flags = VideoPlayer::kFlagOtherSurface; props.sprite = -1; _vm->_mult->_objects[props.startFrame].pAnimData->animation = -props.startFrame - 1; if (_vm->_mult->_objects[props.startFrame].videoSlot > 0) _vm->_vidPlayer->closeVideo(_vm->_mult->_objects[props.startFrame].videoSlot - 1); uint32 x = props.x; uint32 y = props.y; int slot = _vm->_vidPlayer->openVideo(false, file, props); _vm->_mult->_objects[props.startFrame].videoSlot = slot + 1; if (x == 0xFFFFFFFF) { *_vm->_mult->_objects[props.startFrame].pPosX = _vm->_vidPlayer->getDefaultX(slot); *_vm->_mult->_objects[props.startFrame].pPosY = _vm->_vidPlayer->getDefaultY(slot); } else { *_vm->_mult->_objects[props.startFrame].pPosX = x; *_vm->_mult->_objects[props.startFrame].pPosY = y; } return; } else if (props.lastFrame == -4) { warning("Woodruff Stub: Video/Music command -4: Play background video %s", file.c_str()); return; } else if (props.lastFrame == -5) { // warning("Urban/Playtoons Stub: Stop without delay"); _vm->_sound->bgStop(); return; } else if (props.lastFrame == -6) { // warning("Urban/Playtoons Stub: Video/Music command -6 (cache video)"); return; } else if (props.lastFrame == -7) { // warning("Urban/Playtoons Stub: Video/Music command -6 (flush cache)"); return; } else if ((props.lastFrame == -8) || (props.lastFrame == -9)) { if (!file.contains('.')) file += ".WA8"; probe16bitMusic(file); if (props.lastFrame == -9) debugC(0, kDebugVideo, "Urban/Playtoons Stub: Delayed music stop?"); _vm->_sound->bgStop(); _vm->_sound->bgPlay(file.c_str(), SOUND_WAV); return; } else if (props.lastFrame <= -10) { _vm->_vidPlayer->closeVideo(); if (!(props.flags & VideoPlayer::kFlagNoVideo)) props.loop = true; } else if (props.lastFrame < 0) { warning("Urban/Playtoons Stub: Unknown Video/Music command: %d, %s", props.lastFrame, file.c_str()); return; } if (props.startFrame == -2) { props.startFrame = 0; props.lastFrame = -1; props.noBlock = true; } _vm->_vidPlayer->evaluateFlags(props); bool primary = true; if (props.noBlock && (props.flags & VideoPlayer::kFlagNoVideo)) primary = false; int slot = 0; if (!file.empty() && ((slot = _vm->_vidPlayer->openVideo(primary, file, props)) < 0)) { WRITE_VAR(11, (uint32) -1); return; } if (props.hasSound) _vm->_vidPlayer->closeLiveSound(); if (props.startFrame >= 0) _vm->_vidPlayer->play(slot, props); if (close && !props.noBlock) { if (!props.canceled) _vm->_vidPlayer->waitSoundEnd(slot); _vm->_vidPlayer->closeVideo(slot); } }
SlotControl::SlotControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) : Control(engine, key, CONTROL_SLOT), _cursor(CursorIndex_Active), _distanceId('0') { _renderedItem = 0; _bkg = NULL; // Loop until we find the closing brace Common::String line = stream.readLine(); _engine->getScriptManager()->trimCommentsAndWhiteSpace(&line); Common::String param; Common::String values; getParams(line, param, values); while (!stream.eos() && !line.contains('}')) { if (param.matchString("hotspot", true)) { int x; int y; int width; int height; sscanf(values.c_str(), "%d %d %d %d", &x, &y, &width, &height); _hotspot = Common::Rect(x, y, width, height); } else if (param.matchString("rectangle", true)) { int x; int y; int width; int height; sscanf(values.c_str(), "%d %d %d %d", &x, &y, &width, &height); _rectangle = Common::Rect(x, y, width, height); } else if (param.matchString("cursor", true)) { _cursor = _engine->getCursorManager()->getCursorId(values); } else if (param.matchString("distance_id", true)) { sscanf(values.c_str(), "%c", &_distanceId); } else if (param.matchString("venus_id", true)) { _venusId = atoi(values.c_str()); } else if (param.matchString("eligible_objects", true)) { char buf[256]; memset(buf, 0, 256); strncpy(buf, values.c_str(), 255); char *curpos = buf; char *strend = buf + strlen(buf); while (true) { char *st = curpos; if (st >= strend) break; while (*curpos != ' ' && curpos < strend) curpos++; *curpos = 0; curpos++; int obj = atoi(st); _eligibleObjects.push_back(obj); } } line = stream.readLine(); _engine->getScriptManager()->trimCommentsAndWhiteSpace(&line); getParams(line, param, values); } if (_hotspot.isEmpty() || _rectangle.isEmpty()) { warning("Slot %u was parsed incorrectly", key); } }
InputControl::InputControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) : Control(engine, key, CONTROL_INPUT), _background(0), _nextTabstop(0), _focused(false), _textChanged(false), _cursorOffset(0), _enterPressed(false), _readOnly(false), _txtWidth(0), _animation(NULL) { // Loop until we find the closing brace Common::String line = stream.readLine(); _engine->getScriptManager()->trimCommentsAndWhiteSpace(&line); Common::String param; Common::String values; getParams(line, param, values); while (!stream.eos() && !line.contains('}')) { if (param.matchString("rectangle", true)) { int x1; int y1; int x2; int y2; sscanf(values.c_str(), "%d %d %d %d", &x1, &y1, &x2, &y2); _textRectangle = Common::Rect(x1, y1, x2, y2); } else if (param.matchString("aux_hotspot", true)) { int x1; int y1; int x2; int y2; sscanf(values.c_str(), "%d %d %d %d", &x1, &y1, &x2, &y2); _headerRectangle = Common::Rect(x1, y1, x2, y2); } else if (param.matchString("string_init", true)) { uint fontFormatNumber; sscanf(values.c_str(), "%u", &fontFormatNumber); _stringInit.readAllStyles(_engine->getStringManager()->getTextLine(fontFormatNumber)); } else if (param.matchString("chooser_init_string", true)) { uint fontFormatNumber; sscanf(values.c_str(), "%u", &fontFormatNumber); _stringChooserInit.readAllStyles(_engine->getStringManager()->getTextLine(fontFormatNumber)); } else if (param.matchString("next_tabstop", true)) { sscanf(values.c_str(), "%u", &_nextTabstop); } else if (param.matchString("cursor_dimensions", true)) { // Ignore, use the dimensions in the animation file } else if (param.matchString("cursor_animation_frames", true)) { // Ignore, use the frame count in the animation file } else if (param.matchString("cursor_animation", true)) { char fileName[25]; sscanf(values.c_str(), "%24s %*u", fileName); _animation = _engine->loadAnimation(fileName); _animation->start(); } else if (param.matchString("focus", true)) { _focused = true; _engine->getScriptManager()->setFocusControlKey(_key); } else if (param.matchString("venus_id", true)) { _venusId = atoi(values.c_str()); } line = stream.readLine(); _engine->getScriptManager()->trimCommentsAndWhiteSpace(&line); getParams(line, param, values); } _maxTxtWidth = _textRectangle.width(); if (_animation) _maxTxtWidth -= _animation->getWidth(); }