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:
commit
a58486fc4f
@ -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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 )
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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" );
|
||||
|
||||
|
@ -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" );
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user