quake 3 | convert quake 2 map to quake 3 | translate quake map | Search

The scaleMap function modifies a Quake 3 map file by scaling the coordinates of its brush entities and origins by a specified amount. This is likely used for resizing or adjusting the scale of map geometry.

Run example

npm run import -- "scale quake map"

scale quake map

var fs = require('fs')
var DIGITS = 100.0

function scaleMap(file, amount) {
    // get all brushes in map, leaf nodes with at least one vertex
    var brushes = importer.regexToArray(/\{[\s\S]*?\}/ig, file)
    
    // replace all brushes with scaled values
    brushes.forEach(b => {
        var newBrush = b
        newBrush = newBrush.replace(/\(((\s*[0-9\.-]+\s*)*)\)/ig, (str, $1) => {
            return '( ' + $1.trim().split(/\s+/ig)
                .map(n => Math.round((n.includes('.')
                        ? parseFloat(n.trim())
                        : parseInt(n.trim())) * amount * DIGITS) / DIGITS)
                .join(' ') + ' )'
        })
        // scale the texture on the brush
        newBrush = newBrush.replace(/\)\s+([^\)\(]*?)\s+((\s*[0-9\.-]+\s*){5,8})/ig, (str, $1, $2) => {
            return ') ' + $1 + ' ' + $2.trim().split(/\s+/ig)
                .map((n, i) => i >= 5 || i <= 2 ? n : (Math.round((n.includes('.')
                        ? parseFloat(n.trim())
                        : parseInt(n.trim())) * amount * DIGITS) / DIGITS))
                .join(' ') + '\n'
        })
        file = file.replace(b, newBrush)
    })
    
    // replace all origins with scaled
    // TODO: make this a function
    var origins = importer.regexToArray(/"origin"\s+"((\s*[0-9\.-]+\s*)*)"/ig, file, 1)
    origins.forEach($1 => {
        var newOrigin = $1.trim().split(/\s+/ig)
            .map(n => Math.round((n.includes('.')
                    ? parseFloat(n.trim())
                    : parseInt(n.trim())) * amount * DIGITS) / DIGITS)
            .join(' ')
        file = file.replace(new RegExp('"origin"\\s+"' + $1 + '"', 'ig'), '"origin" "' + newOrigin + '"')
    })
    var lips = importer.regexToArray(/"lip"\s+"((\s*[0-9\.-]+\s*)*)"/ig, file, 1)
    lips.forEach($1 => {
        var newOrigin = $1.trim().split(/\s+/ig)
            .map(n => Math.round((n.includes('.')
                    ? parseFloat(n.trim())
                    : parseInt(n.trim())) * amount * DIGITS) / DIGITS)
            .join(' ')
        file = file.replace(new RegExp('"lip"\\s+"' + $1 + '"', 'ig'), '"lip" "' + newOrigin + '"')
    })
    
    // scale models
    var models = importer.regexToArray(/\{[\s\S^\}\{]*?"classname"\s+"misc_model"[\s\S^\}\{]*?\}/ig, file)
    models.forEach(m => {
        var newModel = m
        if(m.match(/"modelscale"/i)) {
            var match = (/"modelscale"\s+"([^"]*?)"/ig).exec(m)
            var scaled = (match[1].includes('.')
                ? parseFloat(match[1])
                : parseInt(match[1])) * amount
            newModel = newModel.replace(match[0], '"modelscale" "' + scaled + '"')
        } else {
            newModel = newModel.replace(/"classname"\s+"misc_model"/ig,
                                        '"classname" "misc_model"\n "modelscale" "' + amount + '"')
        }
        file = file.replace(m, newModel)
    })
    
    return file
}

module.exports = scaleMap

What the code could have been:

const fs = require('fs');
const importer = require('./importer'); // assuming importer module is in the same directory

const DIGITS = 100.0;
const REGEX_BRUSH = /\{[\s\S]*?\}/ig;
const REGEX_ORIGIN = /"origin"\s+"((\s*[0-9\.-]+\s*)*)"/ig;
const REGEX_LIP = /"lip"\s+"((\s*[0-9\.-]+\s*)*)"/ig;
const REGEX_MODEL = /\{[\s\S^\}\{]*?"classname"\s+"misc_model"[\s\S^\}\{]*?\}/ig;

function scaleMap(file, amount) {
  // Get all brushes in map
  const brushes = importer.regexToArray(REGEX_BRUSH, file);

  // Scale brushes
  brushes.forEach((brush) => {
    const newBrush = scaleBrush(brush, amount);
    file = file.replace(brush, newBrush);
  });

  // Scale origins
  scaleOrigin(file, amount);
  scaleLip(file, amount);

  // Scale models
  const models = importer.regexToArray(REGEX_MODEL, file);
  models.forEach((model) => {
    const newModel = scaleModel(model, amount);
    file = file.replace(model, newModel);
  });

  return file;
}

function scaleBrush(brush, amount) {
  let newBrush = brush;
  newBrush = newBrush.replace(/\(((\s*[0-9\.-]+\s*)*)\)/ig, (str, $1) => {
    return '('+ $1.trim().split(/\s+/ig)
     .map((n) => Math.round((n.includes('.')? parseFloat(n.trim()) : parseInt(n.trim())) * amount * DIGITS) / DIGITS)
     .join(' ') +')';
  });

  newBrush = newBrush.replace(/\)\s+([^\)\(]*?)\s+((\s*[0-9\.-]+\s*){5,8})/ig, (str, $1, $2) => {
    return ')'+ $1 +'' + $2.trim().split(/\s+/ig)
     .map((n, i) => i >= 5 || i <= 2? n : Math.round((n.includes('.')? parseFloat(n.trim()) : parseInt(n.trim())) * amount * DIGITS) / DIGITS)
     .join(' ') + '\n';
  });

  return newBrush;
}

function scaleOrigin(file, amount) {
  const origins = importer.regexToArray(REGEX_ORIGIN, file, 1);
  origins.forEach((origin) => {
    const newOrigin = origin.trim().split(/\s+/ig)
     .map((n) => Math.round((n.includes('.')? parseFloat(n.trim()) : parseInt(n.trim())) * amount * DIGITS) / DIGITS)
     .join(' ');
    file = file.replace(new RegExp('"origin"\\s+"' + origin + '"', 'ig'), '"origin" "' + newOrigin + '"');
  });
}

function scaleLip(file, amount) {
  const lips = importer.regexToArray(REGEX_LIP, file, 1);
  lips.forEach((lip) => {
    const newOrigin = lip.trim().split(/\s+/ig)
     .map((n) => Math.round((n.includes('.')? parseFloat(n.trim()) : parseInt(n.trim())) * amount * DIGITS) / DIGITS)
     .join(' ');
    file = file.replace(new RegExp('"lip"\\s+"' + lip + '"', 'ig'), '"lip" "' + newOrigin + '"');
  });
}

function scaleModel(model, amount) {
  if (model.match(/"modelscale"/i)) {
    const match = (/"modelscale"\s+"([^"]*?)"/ig).exec(model);
    const scaled = (match[1].includes('.')? parseFloat(match[1]) : parseInt(match[1])) * amount;
    return model.replace(match[0], '"modelscale" "' + scaled + '"');
  } else {
    return model.replace(/"classname"\s+"misc_model"/ig, '"classname" "misc_model"\n "modelscale" "' + amount + '"');
  }
}

module.exports = scaleMap;

This code snippet defines a function scaleMap that modifies a Quake 3 map file by scaling its brush entities and origins.

Here's a breakdown:

  1. Initialization:

  2. scaleMap Function:

  3. Return Value:

Purpose:

This code snippet is a utility function for modifying Quake 3 map files by scaling their geometry. It's likely used in a larger project for map editing or conversion purposes.