<commit_before>/*
 *  caosVM_variables.cpp
 *  openc2e
 *
 *  Created by <NAME> on Mon May 31 2004.
 *  Copyright (c) 2004 <NAME>. All rights reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 */

#include "caosVM.h"
#include "Agent.h"
#include <stdlib.h> // rand()
#include <iostream>
#include <math.h> // abs()/fabs()
#include "openc2e.h"
#include "World.h"
#include <cctype> // toupper/tolower
#include <algorithm> // transform
#include <boost/format.hpp>

#include "Vehicle.h"
#include "PointerAgent.h"
#include "Creature.h"

/**
 VAxx (variable)
 %pragma noparse
 %status maybe

 Script-local variables (exist only in the current script) with xx being from 00 to 99.  Examples: VA01, VA45. 
 */

/**
 MVxx (variable)
 %pragma noparse
 %status maybe

 Like OVxx, only for OWNR, not TARG.
 */

/**
 ADDS (command) var (variable) value (string)
 %status maybe

 Append the given string to the given variable.
*/
void caosVM::c_ADDS() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_STRING(value)
	VM_PARAM_VARIABLE(variable)

	caos_assert(variable->hasString());
	variable->setString(variable->getString() + value);
}

/**
 SETS (command) var (variable) value (string)
 %status maybe

 Sets the given variable to the given string.
*/
void caosVM::c_SETS() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_STRING(value)
	VM_PARAM_VARIABLE(var)
	var->reset();
	var->setString(value);
}

/**
 SETV (command) var (variable) value (decimal)
 %status maybe

 Sets the given variable to the given decimal value.
 */
void caosVM::c_SETV() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_DECIMAL(value)
	VM_PARAM_VARIABLE(var)
	var->reset();
	if (value.hasFloat()) {
		var->setFloat(value.getFloat());
	} else { // VM_PARAM_DECIMAL guarantees us float || int
		var->setInt(value.getInt());
	}
}

/**
 SETA (command) var (variable) value (agent)
 %status maybe

 Sets the given variable to the given agent.
*/
void caosVM::c_SETA() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_AGENT(value)
	VM_PARAM_VARIABLE(var)
	var->reset();
	var->setAgent(value);
}

/**
 OVxx (variable)
 %pragma noparse
 %status maybe

 Agent-local variables (exist only in the current agent's VM) from TARG, with xx being from 00 to 99.  Examples: OV01, OV45.
 */
// TODO: OVxx parser

/**
 TYPE (integer) value (anything)
 %status maybe

 Returns a integer value representing the type of data in 'value'.  0 is integer, 1 is float, 2 is string, 3 is agent.
*/
void caosVM::v_TYPE() {
	VM_PARAM_VALUE(value)

	caos_assert(!value.isEmpty());

	if (value.hasInt())
		result.setInt(0);
	else if (value.hasFloat())
		result.setInt(1);
	else if (value.hasString())
		result.setInt(2);
	else if (value.hasAgent()) {
		boost::shared_ptr<Agent> a = value.getAgent();
		if (a == 0)
			result.setInt(-1);
		else if (typeid(*a) == typeid(SimpleAgent))
			result.setInt(3);
		else if (typeid(*a) == typeid(PointerAgent))
			result.setInt(4);
		else if (typeid(*a) == typeid(CompoundAgent))
			result.setInt(5);
		else if (typeid(*a) == typeid(Vehicle))
			result.setInt(6);
		else {
			Creature *c = dynamic_cast<Creature *>(a.get());
			if (c)
				result.setInt(7);
			else
				result.setInt(-2); // unknown agent
		}
	} else
		throw creaturesException("caosVar confused us terribly in TYPE");
}

/**
 MODV (command) var (variable) mod (integer)
 %status maybe

 Divides the given variable by the given integer, and returns the remainder (var % mod).
*/
void caosVM::c_MODV() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_INTEGER(mod)
	VM_PARAM_VARIABLE(v) // integer
	if (!v->hasInt()) throw badParamException();
	v->setInt(v->getInt() % mod);
}

/**
 ANDV (command) var (variable) and (integer)
 %status maybe

 Returns the result of a bitwise AND comparison of the given variable and the given integer (var & and).
*/
void caosVM::c_ANDV() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_INTEGER(andv)
	VM_PARAM_VARIABLE(v)
	if (!v->hasInt()) throw badParamException();
	v->setInt(v->getInt() & andv);
}

/**
 ORRV (command) var (variable) or (integer)
 %status maybe

 Returns the result of a bitwise OR comparison of the given variable and the given integer (var | or)
*/
void caosVM::c_ORRV() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_INTEGER(orv)
	VM_PARAM_VARIABLE(v)
	if (!v->hasInt()) throw badParamException();
	v->setInt(v->getInt() | orv);
}


/**
 ADDV (command) var (variable) add (integer)
 %status maybe

 Adds the given integer to the given variable and returns the result.
*/
void caosVM::c_ADDV() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_DECIMAL(add)
	VM_PARAM_VARIABLE(v)
	if (v->hasFloat())
		v->setFloat(v->getFloat() + (add.hasFloat() ? add.getFloat() : add.getInt()));
	else if (v->hasInt())
		v->setInt((int)(v->getInt() + (add.hasFloat() ? add.getFloat() : add.getInt())));
	else
		throw badParamException();
}

/**
 SUBV (command) var (variable) sub (integer)
 %status maybe

 Subtracts the given integer from the given variable and returns the result.
*/
void caosVM::c_SUBV() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_DECIMAL(sub)
	VM_PARAM_VARIABLE(v)
	if (v->hasFloat())
		v->setFloat(v->getFloat() - (sub.hasFloat() ? sub.getFloat() : sub.getInt()));
	else if (v->hasInt())
		v->setInt((int)(v->getInt() - (sub.hasFloat() ? sub.getFloat() : sub.getInt())));
	else
		throw badParamException();
}

/**
 NEGV (command) var (variable)
 %status maybe

 Returns the inverse of (negates) the given variable.  For example, 1 to -1, or -4 to 4.
*/
void caosVM::c_NEGV() {
	VM_VERIFY_SIZE(1)
	VM_PARAM_VARIABLE(v)
	if (v->hasFloat())
		v->setFloat(-v->getFloat());
	else if (v->hasInt())
		v->setInt(-v->getInt());
	else
		throw badParamException();
}

/**
 DIVV (command) var (variable) div (decimal)
 %status maybe
 
 Divides the given variable by the given integer and returns the result.
*/
void caosVM::c_DIVV() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_DECIMAL(div)
	VM_PARAM_VARIABLE(v)

	caos_assert(div.hasDecimal());
	if (div.getFloat() == 0.0f) throw caosException("attempt to divide by zero");
	
	if (v->hasInt() && div.hasInt()) {
		// integer division
		v->setInt(v->getInt() / div.getInt());
	} else if (v->hasInt() || v->hasFloat()) {
		// floating point division
		v->setFloat((v->hasFloat() ? v->getFloat() : v->getInt()) /
					(div.hasFloat() ? div.getFloat() : div.getInt()));
	} else
		throw badParamException();
}

/**
 MULV (command) var (variable) mul (decimal)
 %status maybe

 Multiplies the given variable by the given integer and returns the result.
*/
void caosVM::c_MULV() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_DECIMAL(mul)
	VM_PARAM_VARIABLE(v)
	if (v->hasFloat())
		v->setFloat(v->getFloat() * (mul.hasFloat() ? mul.getFloat() : mul.getInt()));
	else if (v->hasInt())
		v->setInt((int)(v->getInt() * (mul.hasFloat() ? mul.getFloat() : mul.getInt())));
	else
		throw badParamException();
}

/**
 RAND (integer) value1 (integer) value2 (integer)
 %status maybe

 Returns a random integer between 'value1' and 'value2', inclusive.
 */
void caosVM::v_RAND() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_INTEGER(value2)
	VM_PARAM_INTEGER(value1)

	int diff = value2 - value1 + 1;
	double r = (rand() / (double)((unsigned int)RAND_MAX + 1));

	result.setInt((int)((r * diff) + value1));

	// TODO: we should call srand at the start of our code somewhere<commit_msg>fix RAND in a kinda messy way<commit_after>/*
 *  caosVM_variables.cpp
 *  openc2e
 *
 *  Created by <NAME> on Mon May 31 2004.
 *  Copyright (c) 2004 <NAME>. All rights reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 */

#include "caosVM.h"
#include "Agent.h"
#include <stdlib.h> // rand()
#include <iostream>
#include <math.h> // abs()/fabs()
#include "openc2e.h"
#include "World.h"
#include <cctype> // toupper/tolower
#include <algorithm> // transform
#include <boost/format.hpp>

#include "Vehicle.h"
#include "PointerAgent.h"
#include "Creature.h"

/**
 VAxx (variable)
 %pragma noparse
 %status maybe

 Script-local variables (exist only in the current script) with xx being from 00 to 99.  Examples: VA01, VA45. 
 */

/**
 MVxx (variable)
 %pragma noparse
 %status maybe

 Like OVxx, only for OWNR, not TARG.
 */

/**
 ADDS (command) var (variable) value (string)
 %status maybe

 Append the given string to the given variable.
*/
void caosVM::c_ADDS() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_STRING(value)
	VM_PARAM_VARIABLE(variable)

	caos_assert(variable->hasString());
	variable->setString(variable->getString() + value);
}

/**
 SETS (command) var (variable) value (string)
 %status maybe

 Sets the given variable to the given string.
*/
void caosVM::c_SETS() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_STRING(value)
	VM_PARAM_VARIABLE(var)
	var->reset();
	var->setString(value);
}

/**
 SETV (command) var (variable) value (decimal)
 %status maybe

 Sets the given variable to the given decimal value.
 */
void caosVM::c_SETV() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_DECIMAL(value)
	VM_PARAM_VARIABLE(var)
	var->reset();
	if (value.hasFloat()) {
		var->setFloat(value.getFloat());
	} else { // VM_PARAM_DECIMAL guarantees us float || int
		var->setInt(value.getInt());
	}
}

/**
 SETA (command) var (variable) value (agent)
 %status maybe

 Sets the given variable to the given agent.
*/
void caosVM::c_SETA() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_AGENT(value)
	VM_PARAM_VARIABLE(var)
	var->reset();
	var->setAgent(value);
}

/**
 OVxx (variable)
 %pragma noparse
 %status maybe

 Agent-local variables (exist only in the current agent's VM) from TARG, with xx being from 00 to 99.  Examples: OV01, OV45.
 */
// TODO: OVxx parser

/**
 TYPE (integer) value (anything)
 %status maybe

 Returns a integer value representing the type of data in 'value'.  0 is integer, 1 is float, 2 is string, 3 is agent.
*/
void caosVM::v_TYPE() {
	VM_PARAM_VALUE(value)

	caos_assert(!value.isEmpty());

	if (value.hasInt())
		result.setInt(0);
	else if (value.hasFloat())
		result.setInt(1);
	else if (value.hasString())
		result.setInt(2);
	else if (value.hasAgent()) {
		boost::shared_ptr<Agent> a = value.getAgent();
		if (a == 0)
			result.setInt(-1);
		else if (typeid(*a) == typeid(SimpleAgent))
			result.setInt(3);
		else if (typeid(*a) == typeid(PointerAgent))
			result.setInt(4);
		else if (typeid(*a) == typeid(CompoundAgent))
			result.setInt(5);
		else if (typeid(*a) == typeid(Vehicle))
			result.setInt(6);
		else {
			Creature *c = dynamic_cast<Creature *>(a.get());
			if (c)
				result.setInt(7);
			else
				result.setInt(-2); // unknown agent
		}
	} else
		throw creaturesException("caosVar confused us terribly in TYPE");
}

/**
 MODV (command) var (variable) mod (integer)
 %status maybe

 Divides the given variable by the given integer, and returns the remainder (var % mod).
*/
void caosVM::c_MODV() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_INTEGER(mod)
	VM_PARAM_VARIABLE(v) // integer
	if (!v->hasInt()) throw badParamException();
	v->setInt(v->getInt() % mod);
}

/**
 ANDV (command) var (variable) and (integer)
 %status maybe

 Returns the result of a bitwise AND comparison of the given variable and the given integer (var & and).
*/
void caosVM::c_ANDV() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_INTEGER(andv)
	VM_PARAM_VARIABLE(v)
	if (!v->hasInt()) throw badParamException();
	v->setInt(v->getInt() & andv);
}

/**
 ORRV (command) var (variable) or (integer)
 %status maybe

 Returns the result of a bitwise OR comparison of the given variable and the given integer (var | or)
*/
void caosVM::c_ORRV() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_INTEGER(orv)
	VM_PARAM_VARIABLE(v)
	if (!v->hasInt()) throw badParamException();
	v->setInt(v->getInt() | orv);
}


/**
 ADDV (command) var (variable) add (integer)
 %status maybe

 Adds the given integer to the given variable and returns the result.
*/
void caosVM::c_ADDV() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_DECIMAL(add)
	VM_PARAM_VARIABLE(v)
	if (v->hasFloat())
		v->setFloat(v->getFloat() + (add.hasFloat() ? add.getFloat() : add.getInt()));
	else if (v->hasInt())
		v->setInt((int)(v->getInt() + (add.hasFloat() ? add.getFloat() : add.getInt())));
	else
		throw badParamException();
}

/**
 SUBV (command) var (variable) sub (integer)
 %status maybe

 Subtracts the given integer from the given variable and returns the result.
*/
void caosVM::c_SUBV() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_DECIMAL(sub)
	VM_PARAM_VARIABLE(v)
	if (v->hasFloat())
		v->setFloat(v->getFloat() - (sub.hasFloat() ? sub.getFloat() : sub.getInt()));
	else if (v->hasInt())
		v->setInt((int)(v->getInt() - (sub.hasFloat() ? sub.getFloat() : sub.getInt())));
	else
		throw badParamException();
}

/**
 NEGV (command) var (variable)
 %status maybe

 Returns the inverse of (negates) the given variable.  For example, 1 to -1, or -4 to 4.
*/
void caosVM::c_NEGV() {
	VM_VERIFY_SIZE(1)
	VM_PARAM_VARIABLE(v)
	if (v->hasFloat())
		v->setFloat(-v->getFloat());
	else if (v->hasInt())
		v->setInt(-v->getInt());
	else
		throw badParamException();
}

/**
 DIVV (command) var (variable) div (decimal)
 %status maybe
 
 Divides the given variable by the given integer and returns the result.
*/
void caosVM::c_DIVV() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_DECIMAL(div)
	VM_PARAM_VARIABLE(v)

	caos_assert(div.hasDecimal());
	if (div.getFloat() == 0.0f) throw caosException("attempt to divide by zero");
	
	if (v->hasInt() && div.hasInt()) {
		// integer division
		v->setInt(v->getInt() / div.getInt());
	} else if (v->hasInt() || v->hasFloat()) {
		// floating point division
		v->setFloat((v->hasFloat() ? v->getFloat() : v->getInt()) /
					(div.hasFloat() ? div.getFloat() : div.getInt()));
	} else
		throw badParamException();
}

/**
 MULV (command) var (variable) mul (decimal)
 %status maybe

 Multiplies the given variable by the given integer and returns the result.
*/
void caosVM::c_MULV() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_DECIMAL(mul)
	VM_PARAM_VARIABLE(v)
	if (v->hasFloat())
		v->setFloat(v->getFloat() * (mul.hasFloat() ? mul.getFloat() : mul.getInt()));
	else if (v->hasInt())
		v->setInt((int)(v->getInt() * (mul.hasFloat() ? mul.getFloat() : mul.getInt())));
	else
		throw badParamException();
}

/**
 RAND (integer) value1 (integer) value2 (integer)
 %status maybe

 Returns a random integer between 'value1' and 'value2', inclusive.
 */
void caosVM::v_RAND() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_INTEGER(value2)
	VM_PARAM_INTEGER(value1)

	// TODO: i'm sure there's a better way to do this. tired. - fuzzie
	int diff;
	if (abs(value2) < abs(value1))
		diff = abs(value1 - value2) + 1;
	else
		diff = abs(value2 - value1) + 1;
	int val;
	if (value2 < value1)
		val = value2;
	else
		val = value1;
	double r = rand() / ((unsigned int)RAND_MAX + 1.0);

	result.setInt((int)(r * diff) + val);
{'fraction_non_alphanumeric': 0.1531848378272763, 'fraction_numerical': 0.01022534844340237, 'mean_word_length': 4.1997968167964785, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 127, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2716313', 'n_tokens_mistral': 5787, 'n_tokens_neox': 5555, 'n_words': 1558}