1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-09-15 06:52:34 +02:00

Merge pull request #147 from danhedron/fix/script-opcode-1

Fix opcodes 0x0213 & 0x032B
This commit is contained in:
Daniel Evans 2016-06-25 22:34:43 +01:00 committed by GitHub
commit a58486fc4f
9 changed files with 112 additions and 91 deletions

View File

@ -20,6 +20,7 @@ class GameObject;
class CharacterObject;
class InstanceObject;
class VehicleObject;
class PickupObject;
#include <render/VisualFX.hpp>
#include <data/ObjectData.hpp>
@ -104,6 +105,11 @@ public:
*/
CharacterObject* createPlayer(const glm::vec3& pos, const glm::quat& rot = glm::quat(), GameObjectID gid = 0);
/**
* Creates a pickup
*/
PickupObject* createPickup(const glm::vec3& pos, int id, int type);
/**
* Destroys an existing Object
*/

View File

@ -51,7 +51,11 @@ public:
void tick(float dt);
virtual bool onCharacterTouch(CharacterObject* character) = 0;
virtual bool onCharacterTouch(CharacterObject* character)
{
RW_UNUSED(character);
return false;
}
bool isEnabled() const { return m_enabled; }
void setEnabled(bool enabled);

View File

@ -1,6 +1,8 @@
#pragma once
#ifndef _SCRIPTTYPES_HPP_
#define _SCRIPTTYPES_HPP_
#include <rw/defines.hpp>
#include <cstdint>
#include <map>
#include <string>
@ -56,23 +58,28 @@ static SCMTypeInfoTable typeData = {
struct SCMOpcodeParameter {
SCMType type;
union {
uint32_t integer;
int32_t integer;
float real;
char string[8];
void* globalPtr;
uint32_t* globalInteger;
int32_t* globalInteger;
float* globalReal;
};
int integerValue() const
{
if ( type == TGlobal )
{
return * globalInteger;
}
else
switch (type)
{
case TGlobal:
case TLocal:
return *globalInteger;
case TInt8:
case TInt16:
case TInt32:
return integer;
default:
RW_ERROR("Unhandled type");
return 0;
}
}
};
@ -101,6 +108,8 @@ public:
return parameters->at(arg);
}
int getModel(unsigned int arg) const;
template <class T>
GameObject* getObject(unsigned int arg) const;

View File

@ -19,6 +19,7 @@
#include <objects/InstanceObject.hpp>
#include <objects/VehicleObject.hpp>
#include <objects/CutsceneObject.hpp>
#include <objects/ItemPickup.hpp>
#include <data/CutsceneData.hpp>
#include <loaders/LoaderCutsceneDAT.hpp>
@ -458,6 +459,36 @@ CharacterObject* GameWorld::createPlayer(const glm::vec3& pos, const glm::quat&
return nullptr;
}
PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type)
{
auto modelInfo = data->findObjectType<ObjectData>(id);
data->loadDFF(modelInfo->modelName + ".dff");
data->loadTXD(modelInfo->textureName + ".txd");
PickupObject* pickup = nullptr;
auto pickuptype = (PickupObject::PickupType)type;
// Attempt to find an InventoryItem associated with this model
auto it = std::find_if(
inventoryItems.begin(), inventoryItems.end(),
[=](InventoryItem* itm) { return itm->getModelID() == id; });
// If nothing, create a generic pickup instead of an item pickup
if (it != inventoryItems.end()) {
pickup = new ItemPickup(this, pos, pickuptype, *it);
}
else {
RW_UNIMPLEMENTED("Non-weapon pickups");
pickup = new PickupObject(this, pos, id, pickuptype);
}
pickupPool.insert(pickup);
allObjects.push_back(pickup);
return pickup;
}
void GameWorld::ObjectPool::insert(GameObject* object)
{
if( object->getGameObjectID() == 0 )

View File

@ -81,12 +81,12 @@ void ScriptMachine::executeThread(SCMThread &t, int msPassed)
hasExtraParameters = false;
break;
case TInt8:
parameters.back().integer = _file->read<std::uint8_t>(pc);
pc += sizeof(SCMByte);
parameters.back().integer = _file->read<std::int8_t>(pc);
pc += sizeof(SCMByte);
break;
case TInt16:
parameters.back().integer = _file->read<std::int16_t>(pc);
pc += sizeof(SCMByte) * 2;
parameters.back().integer = _file->read<std::int16_t>(pc);
pc += sizeof(SCMByte) * 2;
break;
case TGlobal: {
auto v = _file->read<std::uint16_t>(pc);
@ -95,7 +95,7 @@ void ScriptMachine::executeThread(SCMThread &t, int msPassed)
{
state->world->logger->error("SCM", "Global Out of bounds! "+ std::to_string(v) + " " + std::to_string(_file->getGlobalsSize()));
}
pc += sizeof(SCMByte) * 2;
pc += sizeof(SCMByte) * 2;
}
break;
case TLocal: {
@ -105,12 +105,12 @@ void ScriptMachine::executeThread(SCMThread &t, int msPassed)
{
state->world->logger->error("SCM", "Local Out of bounds!");
}
pc += sizeof(SCMByte) * 2;
pc += sizeof(SCMByte) * 2;
}
break;
case TInt32:
parameters.back().integer = _file->read<std::uint32_t>(pc);
pc += sizeof(SCMByte) * 4;
parameters.back().integer = _file->read<std::int32_t>(pc);
pc += sizeof(SCMByte) * 4;
break;
case TString:
std::copy(_file->data()+pc, _file->data()+pc+8,

View File

@ -4,6 +4,8 @@
#include <engine/GameWorld.hpp>
#include <objects/CharacterObject.hpp>
#include <ai/PlayerController.hpp>
#include <script/SCMFile.hpp>
#include <engine/GameData.hpp>
GameState* ScriptArguments::getState() const
{
@ -15,6 +17,25 @@ GameWorld* ScriptArguments::getWorld() const
return getVM()->getState()->world;
}
int ScriptArguments::getModel(unsigned int arg) const
{
RW_CHECK(arg < getParameters().size(), "arg out of range");
if (arg >= getParameters().size()) {
return 0;
}
int id = getParameters()[arg].integerValue();
/// @todo verify this behaviour
if (id < 0) {
id = -id;
const auto& model = getVM()->getFile()->getModels()[id];
id = getWorld()->data->findModelObject(model);
}
return id;
}
GameObject* ScriptArguments::getPlayerCharacter(unsigned int player) const
{
auto playerId = parameters->at(player).integerValue();

View File

@ -1317,8 +1317,6 @@ GameModule::GameModule()
bindFunction( 0x0329, game_has_respray_happened, 1, "Has Respray Happened" );
bindUnimplemented( 0x032B, game_create_weapon_pickup, 7, "Create Weapon Pickup" );
bindUnimplemented( 0x0335, game_free_resprays, 1, "Set Free Respray" );
bindUnimplemented( 0x0336, game_set_character_visible, 2, "Set Player Visible" );
@ -1387,7 +1385,7 @@ GameModule::GameModule()
bindUnimplemented( 0x03DA, game_set_garage_follow_player, 1, "Set Garage Camera Follows Player" );
bindFunction(0x03DC, game_add_object_blip<PickupObject>, 2, "Add blip for pickup");
bindUnimplemented(0x03DD, game_add_object_sprite_blip<PickupObject>, 3, "Add Sprite Blip for Pickup"); /// @todo crashes LUIGI4 because of missing 032B
bindFunction(0x03DD, game_add_object_sprite_blip<PickupObject>, 3, "Add Sprite Blip for Pickup");
bindUnimplemented( 0x03DE, game_set_pedestrian_density, 1, "Set Pedestrian density" );

View File

@ -915,69 +915,11 @@ void game_navigate_on_foot(const ScriptArguments& args)
void game_create_pickup(const ScriptArguments& args)
{
glm::vec3 pos (args[2].real, args[3].real, args[4].real);
int id;
int id = args.getModel(0);
int type = args[1].integer;
switch(args[0].type) {
case TInt8:
id = (std::int8_t)args[0].integer;
break;
case TInt16:
id = (std::int16_t)args[0].integer;
break;
default:
RW_ERROR("Unhandled integer type");
*args[5].globalInteger = 0;
return;
}
if ( id < 0 )
{
id = -id;
auto model = args.getVM()->getFile()->getModels()[id];
std::transform(model.begin(), model.end(), model.begin(), ::tolower);
id = args.getWorld()->data->findModelObject(model);
args.getWorld()->data->loadDFF(model+".dff");
args.getWorld()->data->loadTXD("icons.txd");
}
else
{
auto data = args.getWorld()->data->findObjectType<ObjectData>(id);
if ( ! ( id >= 170 && id <= 184 ) )
{
args.getWorld()->data->loadDFF(data->modelName+".dff");
}
args.getWorld()->data->loadTXD(data->textureName+".txd");
}
PickupObject* pickup = nullptr;
if ( id >= 170 && id <= 184 )
{
// Find the item for this model ID
auto world = args.getWorld();
InventoryItem *item = nullptr;
for (auto i = 0; i < maxInventorySlots; ++i)
{
item = world->getInventoryItem(i);
if (item->getModelID() == id) {
auto pickuptype = (PickupObject::PickupType)type;
pickup = new ItemPickup(args.getWorld(), pos, pickuptype, item);
world->pickupPool.insert( pickup );
world->allObjects.push_back(pickup);
*args[5].globalInteger = pickup->getGameObjectID();
}
}
}
else
{
RW_UNIMPLEMENTED("non-item pickups");
*args[5].globalInteger = 0;
}
PickupObject* pickup = args.getWorld()->createPickup(pos, id, type);
*args[5].globalInteger = pickup->getGameObjectID();
}
bool game_is_pickup_collected(const ScriptArguments& args)
@ -1129,6 +1071,19 @@ bool game_character_in_range(const ScriptArguments& args)
return true;
}
void game_create_weapon_pickup(const ScriptArguments& args)
{
glm::vec3 pos (args[3].real, args[4].real, args[5].real);
int id = args.getModel(0);
int type = args[1].integer;
int ammo = args[2].integer;
RW_UNUSED(ammo);
RW_UNIMPLEMENTED("game_create_weapon_pickup(): ammo count");
PickupObject* pickup = args.getWorld()->createPickup(pos, id, type);
*args[6].globalInteger = pickup->getGameObjectID();
}
void game_set_close_object_visible(const ScriptArguments& args)
{
glm::vec3 position(args[0].real, args[1].real, args[2].real);
@ -1426,7 +1381,9 @@ ObjectModule::ObjectModule()
bindFunction(0x02E3, game_get_speed, 2, "Get Vehicle Speed" );
bindFunction(0x0320, game_character_in_range, 2, "Is Character in range of character");
bindFunction(0x032B, game_create_weapon_pickup, 7, "Create Weapon Pickup" );
bindFunction(0x0339, game_objects_in_volume, 11, "Are objects in volume" );
bindFunction( 0x034D, game_rotate_object, 4, "Rotate Object" );

View File

@ -41,16 +41,11 @@ void IngameState::startTest()
getWorld()->state->playerObject = playerChar->getGameObjectID();
glm::vec3 itemspawn( 276.5f, -609.f, 36.5f);
for(int i = 1; i < maxInventorySlots; ++i) {
ItemPickup* pickup =
new ItemPickup(
getWorld(),
itemspawn,
PickupObject::OnStreet,
getWorld()->getInventoryItem(i));
getWorld()->pickupPool.insert(pickup);
getWorld()->allObjects.push_back(pickup);
glm::vec3 itemspawn(276.5f, -609.f, 36.5f);
for (int i = 1; i < maxInventorySlots; ++i) {
auto item = getWorld()->getInventoryItem(i);
getWorld()->createPickup(itemspawn, item->getModelID(),
PickupObject::OnStreet);
itemspawn.x += 2.5f;
}