Beispiel #1
0
bool PackedTexture::InsertImage(const Image & pImg, int & pOffsetU, int & pOffsetV, unsigned int & pTextureIndex) {
	
	// Validate image size
	if(pImg.GetWidth() > mTexSize || pImg.GetHeight() > mTexSize) {
		return false;
	}
	
	// Copy to one of the existing image
	TextureTree::Node * node = NULL;
	unsigned int nodeTree = 0;
	
	for(unsigned int i = 0; i < mTexTrees.size(); i++) {
		node = mTexTrees[i]->InsertImage( pImg );
		nodeTree = i;
	}
	
	// No space found, create a new tree
	if(!node) {
		
		mTexTrees.push_back(new TextureTree(mTexSize));
		
		Image* newPage = new Image();
		newPage->Create(mTexSize, mTexSize, mTexFormat);
		newPage->Clear();
		
		mImages.push_back(newPage);
		
		node = mTexTrees[mTexTrees.size() - 1]->InsertImage(pImg);
		nodeTree = mTexTrees.size() - 1;
	}
	
	// A node must have been found.
	arx_assert(node);
	
	// Copy texture there
	if(node) {
		
		mImages[nodeTree]->Copy( pImg, node->mRect.left, node->mRect.top );
		
		// Copy values back into info structure.
		pOffsetU = node->mRect.left;
		pOffsetV = node->mRect.top;
		pTextureIndex = nodeTree;
	}
	
	return node != NULL;
}
static SpellType getSpell(const Rune symbols[MAX_SPELL_SYMBOLS]) {
	
	const SpellDefinition * def = &definedSpells;
	
	for(size_t i = 0; i < MAX_SPELL_SYMBOLS; i++) {
		if(symbols[i] == RUNE_NONE) {
			break;
		}
		arx_assert(symbols[i] >= 0 && (size_t)symbols[i] < RUNE_COUNT);
		if(def->next[symbols[i]] == NULL) {
			return SPELL_NONE;
		}
		def = def->next[symbols[i]];
	}
	
	return def->spell;
}
void OpenGLRenderer::shutdown() {
	
	arx_assert(initialized);
	
	if(shader) {
		glDeleteObjectARB(shader);
		CHECK_GL;
	}
	
	for(size_t i = 0; i < m_TextureStages.size(); ++i) {
		delete m_TextureStages[i];
	}
	m_TextureStages.clear();
	
	maximumAnisotropy = 1.f;
	
	initialized = false;
}
void OpenGLRenderer::shutdown() {
	
	arx_assert(isInitialized());
	
	onRendererShutdown();
	
	if(shader) {
		glDeleteObjectARB(shader);
	}
	
	for(size_t i = 0; i < m_TextureStages.size(); ++i) {
		delete m_TextureStages[i];
	}
	m_TextureStages.clear();
	
	maximumAnisotropy = 1.f;
	
}
Beispiel #5
0
arx_nodiscard void * alloc_aligned(std::size_t alignment, std::size_t size) {
	
	if(alignment < GuaranteedAlignment) {
		alignment = GuaranteedAlignment;
	}
	
	unsigned char * allocation = static_cast<unsigned char *>(std::malloc(size + alignment));
	if(!allocation) {
		return NULL;
	}
	
	size_t offset = alignment - (allocation - static_cast<unsigned char *>(0)) % alignment;
	
	arx_assert(offset - 1 <= 0xff);
	allocation[offset - 1] = static_cast<unsigned char>(offset - 1);
	
	return allocation + offset;
}
Beispiel #6
0
void PrecalcDynamicLighting(const Vec3f & camPos, float camDepth) {
	
	ARX_PROFILE_FUNC();
	
	g_culledDynamicLightsCount = 0;
	
	BOOST_FOREACH(EERIE_LIGHT & light, g_dynamicLights) {
		if(light.m_exists && light.rgb != Color3f::black) {
			light.m_isVisible = closerThan(light.pos, camPos, camDepth + light.fallend);
			if(light.m_isVisible) {
				RecalcLight(&light);
				arx_assert(g_culledDynamicLightsCount < size_t(boost::size(g_culledDynamicLights)));
				g_culledDynamicLights[g_culledDynamicLightsCount++] = &light;
			}
		}
	}
	
}
void ARX_EQUIPMENT_AttachPlayerWeaponToHand() {
	arx_assert(entities.player());
	Entity * target = entities.player();
	
	for(size_t i = 0; i < MAX_EQUIPED; i++) {
		if(ValidIONum(player.equiped[i])) {
			Entity *toequip = entities[player.equiped[i]];

			if(toequip) {
				if(toequip->type_flags & (OBJECT_TYPE_DAGGER | OBJECT_TYPE_1H | OBJECT_TYPE_2H | OBJECT_TYPE_BOW)) {
					EERIE_LINKEDOBJ_UnLinkObjectFromObject(target->obj, toequip->obj);
					EERIE_LINKEDOBJ_LinkObjectToObject(target->obj, toequip->obj, "primary_attach", "primary_attach", toequip);
					return;
				}
			}
		}
	}
}
bool GLTexture2D::Create() {
	
	arx_assert(!tex, "leaking OpenGL texture");
	
	glGenTextures(1, &tex);
	
	// Set our state to the default OpenGL state
	wrapMode = TextureStage::WrapRepeat;
	mipFilter = TextureStage::FilterLinear;
	minFilter = TextureStage::FilterNearest;
	magFilter = TextureStage::FilterLinear;
	
	Vec2i nextPowerOfTwo(GetNextPowerOf2(size.x), GetNextPowerOf2(size.y));
	storedSize = renderer->hasTextureNPOT() ? size : nextPowerOfTwo;
	isNPOT = (size != nextPowerOfTwo);
	
	return (tex != GL_NONE);
}
Beispiel #9
0
void PrecastSpellsGui::update() {
	m_icons.clear();
	
	if(!isVisible())
		return;
	
	float intensity = 1.f - PULSATE * 0.5f;
	intensity = glm::clamp(intensity, 0.f, 1.f);
	
	
	for(size_t i = 0; i < Precast.size(); i++) {
		
		PRECAST_STRUCT & precastSlot = Precast[i];
		
		float val = intensity;
		
		if(precastSlot.launch_time > 0 && g_gameTime.now() >= precastSlot.launch_time) {
			float tt = (g_gameTime.now() - precastSlot.launch_time) / GameDurationMs(1000);
			
			if(tt > 1.f)
				tt = 1.f;
			
			val *= (1.f - tt);
		}
		
		Color color = Color3f(0, val * 0.5f, val).to<u8>();
		
		Rectf childRect = createChild(m_rect, Anchor_BottomLeft, m_iconSize * m_scale, Anchor_BottomLeft);
		childRect.move(i * m_iconSize.x * m_scale, 0);
		
		SpellType typ = precastSlot.typ;
		
		TextureContainer * tc = spellicons[typ].tc;
		arx_assert(tc);
		
		PrecastSpellIconSlot icon;
		icon.update(childRect, tc, color, PrecastHandle(i));
		
		if(!(player.Interface & INTER_COMBATMODE))
			icon.updateInput();
		
		m_icons.push_back(icon);
	}
}
Beispiel #10
0
void QuickSaveIconGui::draw() {
	
	if(m_remainingTime == 0) {
		return;
	}
	
	UseRenderState state(render2D().blend(BlendSrcColor, BlendOne).alphaCutout());
	
	// Flash the icon twice, starting at about 0.7 opacity
	float step = 1.f - (m_remainingTime / m_duration);
	float alpha = std::min(1.f, 0.6f * (std::sin(step * (7.f / 2.f * glm::pi<float>())) + 1.f));
	
	TextureContainer * tex = TextureContainer::LoadUI("graph/interface/icons/menu_main_save");
	arx_assert(tex);
	
	Vec2f size = Vec2f(tex->size());
	EERIEDrawBitmap(Rectf(Vec2f(0, 0), size.x, size.y), 0.f, tex, Color::gray(alpha));
	
}
void CycleTextWidget::EmptyFunction() {

	//Touche pour la selection
	if(GInput->isKeyPressedNowPressed(Keyboard::Key_LeftArrow)) {
		iPos--;

		if(iPos <= 0)
			iPos = 0;
	} else {
		if(GInput->isKeyPressedNowPressed(Keyboard::Key_RightArrow)) {
			iPos++;

			arx_assert(iPos >= 0);

			if((size_t)iPos >= vText.size() - 1)
				iPos = vText.size() - 1;
		}
	}
}
directory_iterator & directory_iterator::operator++() {
	
	directory_iterator_data * itData = (directory_iterator_data *)handle;
	arx_assert(itData->findHandle != INVALID_HANDLE_VALUE);
	
	bool cont = true;
	while(cont) {
		cont = FindNextFileW(itData->findHandle, &itData->findData) == TRUE;
		if(cont && itData->findData.cFileName[0] != L'.') {
			break;
		}
	}
	
	if(!cont) {
		FindClose(itData->findHandle);
		itData->findHandle = INVALID_HANDLE_VALUE;
	}
	
	return *this;
}
Beispiel #13
0
static void LaunchMagicMissileExplosion(const Vec3f & _ePos, bool mrCheat) {
	
	ParticleParams cp = MagicMissileExplosionParticle();
	
	if(mrCheat) {
		cp = MagicMissileExplosionMrCheatParticle();
	}
	
	ParticleSystem * pPS = new ParticleSystem();
	pPS->SetParams(cp);
	pPS->SetPos(_ePos);
	pPS->Update(0);

	LightHandle id = GetFreeDynLight();

	if(lightHandleIsValid(id)) {
		EERIE_LIGHT * light = lightHandleGet(id);
		
		light->intensity = 2.3f;
		light->fallstart = 250.f;
		light->fallend   = 420.f;

		if(mrCheat) {
			light->rgb.r = 1.f;
			light->rgb.g = 0.3f;
			light->rgb.b = .8f;
		} else {
			light->rgb.r = 0.f;
			light->rgb.g = 0.f;
			light->rgb.b = .8f;
		}

		light->pos = _ePos;
		light->duration = 1500;
	}

	arx_assert(pParticleManager);
	pParticleManager->AddSystem(pPS);

	ARX_SOUND_PlaySFX(SND_SPELL_MM_HIT, &_ePos);
}
Beispiel #14
0
bool PackedTexture::insertImage(const Image & image, unsigned int & textureIndex,
                                Vec2i & offset) {
	
	// Validate image size
	if(image.GetWidth() > textureSize || image.GetHeight() > textureSize) {
		return false;
	}
	
	// Copy to one of the existing textures
	TextureTree::Node * node = NULL;
	unsigned int nodeTree = 0;
	
	for(size_t i = 0; i < textures.size(); i++) {
		node = textures[i]->insertImage(image);
		nodeTree = i;
	}
	
	// No space found, create a new texture
	if(!node) {
		TextureTree * newTree = new TextureTree(textureSize, textureFormat);
		if(!newTree->texture) {
			delete newTree;
			return false;
		}
		textures.push_back(newTree);
		node = textures[textures.size() - 1]->insertImage(image);
		nodeTree = textures.size() - 1;
	}
	
	// A node must have been found
	arx_assert(node);
	
	// Copy texture there
	if(node) {
		// Copy values back into info structure
		offset = node->rect.topLeft();
		textureIndex = nodeTree;
	}
	
	return node != NULL;
}
Beispiel #15
0
bool TextManager::AddText(Font * font, const std::string & text,
                          const Rect & bbox, Color color,
                          PlatformDuration displayTime, PlatformDuration scrollTime,
                          float scrollSpeed, int nLineClipp) {
	
	if(text.empty()) {
		return false;
	}
	
	if(!font) {
		LogWarning << "Adding text with NULL font.";
		return false;
	}
	
	ManagedText * pArxText = new ManagedText();
	if(!pArxText) {
		return false;
	}
	
	arx_assert(!bbox.empty());
	
	pArxText->pFont = font;
	pArxText->lpszUText = text;
	pArxText->rRect = bbox;
	pArxText->lCol = color;
	pArxText->lTimeScroll = scrollTime;
	pArxText->fDeltaY = 0.f;
	pArxText->fSpeedScrollY = scrollSpeed;
	pArxText->lTimeOut = displayTime;
	pArxText->rRectClipp = pArxText->rRect;
	
	if(nLineClipp) {
		Vec2i sSize = font->getTextSize(pArxText->lpszUText);
		sSize.y *= nLineClipp;
		pArxText->rRectClipp.bottom = pArxText->rRect.top + sSize.y;
	}
	
	entries.push_back(pArxText);
	
	return true;
}
aalError DSoundSource::init(SourceId _id, DSoundSource * instance, const Channel & _channel) {
	
	arx_assert(instance->sample == sample);
	
	if(instance->stream || _channel.flags != instance->channel.flags) {
		return init(id, _channel);
	}
	
	id = _id;
	
	clean();
	
	channel = _channel;
	size = instance->size;
	
	if(backend->device->DuplicateSoundBuffer(instance->lpdsb, &lpdsb)) {
		return AAL_ERROR_SYSTEM;
	}
	
	return init();
}
Beispiel #17
0
void CurrentTorchIconGui::update() {
	
	if(!isVisible())
		return;
	
	if((player.Interface & INTER_NOTE) && TSecondaryInventory != NULL
	   && (openNote.type() == Note::BigNote || openNote.type() == Note::Book)) {
		m_isActive = false;
		return;
	}
	m_isActive = true;
	
	m_tex = player.torch->m_icon;
	arx_assert(m_tex);
	
	if(Random::getf() <= 0.2f) {
		return;
	}
	
	createFireParticle();
}
Beispiel #18
0
bool TextManager::AddText(Font* _pFont, const std::string & _lpszUText, const Rect & _rRect, Color _lCol, long _lTimeOut, long _lTimeScroll, float _fSpeedScroll, int iNbLigneClipp) {
	
	if(_lpszUText.empty()) {
		return false;
	}
	
	if(!_pFont) {
		LogWarning << "Adding text with NULL font.";
		return false;
	}
	
	ManagedText * pArxText = new ManagedText();
	if(!pArxText) {
		return false;
	}
	
	arx_assert(!_rRect.empty());
	
	pArxText->pFont = _pFont;
	pArxText->lpszUText = _lpszUText;
	pArxText->rRect = _rRect;
	pArxText->lCol = _lCol;
	pArxText->lTimeScroll = _lTimeScroll;
	pArxText->fDeltaY = 0.f;
	pArxText->fSpeedScrollY = _fSpeedScroll;
	pArxText->lTimeOut = _lTimeOut;
	pArxText->rRectClipp = pArxText->rRect;
	
	if(iNbLigneClipp) 
	{
		Vec2i sSize = _pFont->getTextSize(pArxText->lpszUText);
		sSize.y *= iNbLigneClipp;
	
		pArxText->rRectClipp.bottom = pArxText->rRect.top + sSize.y;
	}
	
	entries.push_back(pArxText);
	
	return true;
}
bool CheckboxWidget::OnMouseClick() {
	
	if(iOldState<0)
		iOldState=iState;

	iState ++;

	//NB : It seems that iState cannot be negative (used as tabular index / used as bool) but need further approval
	arx_assert(iState >= 0);

	if((size_t)iState >= 2) {
		iState = 0;
	}

	ARX_SOUND_PlayMenu(SND_MENU_CLICK);
	
	if(stateChanged) {
		stateChanged(iState);
	}
	
	return false;
}
bool CycleTextWidget::OnMouseClick() {
	
	if(!enabled) {
		return false;
	}
	
	ARX_SOUND_PlayMenu(SND_MENU_CLICK);

	if(iOldPos<0)
		iOldPos=iPos;
	
	const Vec2f cursor = Vec2f(GInput->getMousePosAbs());

	if(m_rect.contains(cursor)) {
		if(pLeftButton->m_rect.contains(cursor)) {
			iPos--;

			if(iPos < 0) {
				iPos = vText.size() - 1;
			}
		}
		
		if(pRightButton->m_rect.contains(cursor)) {
			iPos++;

			arx_assert(iPos >= 0);

			if(size_t(iPos) >= vText.size()) {
				iPos = 0;
			}
		}
	}

	if(valueChanged) {
		valueChanged(iPos, vText.at(iPos)->m_text);
	}
	
	return false;
}
Beispiel #21
0
bool GLTexture2D::Create() {
	
	arx_assert(!tex, "leaking OpenGL texture");
	
	glGenTextures(1, &tex);
	
	// Set our state to the default OpenGL state
	wrapMode = TextureStage::WrapRepeat;
	mipFilter = TextureStage::FilterLinear;
	minFilter = TextureStage::FilterNearest;
	magFilter = TextureStage::FilterLinear;

	if(GLEW_ARB_texture_non_power_of_two) {
		storedSize = size;
	} else {
		storedSize = Vec2i(GetNextPowerOf2(size.x), GetNextPowerOf2(size.y));
	}
	
	CHECK_GL;
	
	return (tex != GL_NONE);
}
bool CrashHandlerWindows::registerCrashHandlers() {
	
	arx_assert(m_pPreviousCrashHandlers == 0);
	m_pPreviousCrashHandlers = new PlatformCrashHandlers;
	
	// Unhandled exception handler.
	m_pPreviousCrashHandlers->m_SEHHandler = SetUnhandledExceptionFilter(SEHHandler);
	
	// Prevent dialog box.
	_set_error_mode(_OUT_TO_STDERR);
	
	// Catch pure virtual function calls.
	// Because there is one _purecall_handler for the whole process,
	// calling this function immediately impacts all threads. The last
	// caller on any thread sets the handler.
	// http://msdn.microsoft.com/en-us/library/t296ys27.aspx
	m_pPreviousCrashHandlers->m_pureCallHandler = _set_purecall_handler(PureCallHandler);
	
	// Catch new operator memory allocation exceptions.
	_set_new_mode(1); // Force malloc() to call new handler too
	m_pPreviousCrashHandlers->m_newHandler = _set_new_handler(NewHandler);
	
	// Catch invalid parameter exceptions.
	m_pPreviousCrashHandlers->m_invalidParameterHandler
		= _set_invalid_parameter_handler(InvalidParameterHandler);
	
	// Catch an abnormal program termination.
	_set_abort_behavior(_CALL_REPORTFAULT, _CALL_REPORTFAULT);
	m_pPreviousCrashHandlers->m_SIGABRTHandler = signal(SIGABRT, SignalHandler);
	
	// Catch illegal instruction handler.
	m_pPreviousCrashHandlers->m_SIGINTHandler = signal(SIGINT, SignalHandler);
	
	// Catch a termination request.
	m_pPreviousCrashHandlers->m_SIGTERMHandler = signal(SIGTERM, SignalHandler);
	
	// We must also register the main thread crash handlers.
	return registerThreadCrashHandlers();
}
Beispiel #23
0
static void LaunchPoisonExplosion(const Vec3f & aePos) {
	
	// système de partoches pour l'explosion
	ParticleSystem * pPS = new ParticleSystem();
	
	pPS->SetParams(g_particleParameters[ParticleParam_Poison1]);
	pPS->SetPos(aePos);
	pPS->Update(0);

	std::list<Particle *>::iterator i;

	for(i = pPS->listParticle.begin(); i != pPS->listParticle.end(); ++i) {
		Particle * pP = *i;

		if(pP->isAlive()) {
			pP->p3Velocity = glm::clamp(pP->p3Velocity, Vec3f(0, -100, 0), Vec3f(0, 100, 0));
		}
	}

	arx_assert(pParticleManager);
	pParticleManager->AddSystem(pPS);
}
//! \brief Returns the object type flag corresponding to a string
ItemType ARX_EQUIPMENT_GetObjectTypeFlag(const std::string & temp) {
	
	if(temp.empty()) {
		return 0;
	}
	
	char c = temp[0];
	
	arx_assert(std::tolower(c) == c);
	
	switch(c) {
		case 'w':
			return OBJECT_TYPE_WEAPON;
		case 'd':
			return OBJECT_TYPE_DAGGER;
		case '1':
			return OBJECT_TYPE_1H;
		case '2':
			return OBJECT_TYPE_2H;
		case 'b':
			return OBJECT_TYPE_BOW;
		case 's':
			return OBJECT_TYPE_SHIELD;
		case 'f':
			return OBJECT_TYPE_FOOD;
		case 'g':
			return OBJECT_TYPE_GOLD;
		case 'r':
			return OBJECT_TYPE_RING;
		case 'a':
			return OBJECT_TYPE_ARMOR;
		case 'h':
			return OBJECT_TYPE_HELMET;
		case 'l':
			return OBJECT_TYPE_LEGGINGS;
	}
	
	return 0;
}
	bool load() {
		
		m_data = m_save.load(m_fileName, m_size);
		if(!m_data) {
			std::cerr << m_fileName << " not found" << std::endl;
			return false;
		}
		
		size_t pos = 0;
		m_pld = reinterpret_cast<ARX_CHANGELEVEL_PLAYER_LEVEL_DATA *>(m_data + pos);
		pos += sizeof(ARX_CHANGELEVEL_PLAYER_LEVEL_DATA);
		
		if(m_pld->version != ARX_GAMESAVE_VERSION) {
			std::cout << "bad version: " << m_pld->version << std::endl;
			return false;
		}
		
		arx_assert(m_size >= pos);
		ARX_UNUSED(pos);
		
		return true;
	}
Beispiel #26
0
void Config::setActionKey(ControlAction actionId, int index, InputKeyId key) {
	
	if(actionId < 0 || (size_t)actionId >= NUM_ACTION_KEY || index > 1 || index < 0) {
		arx_assert(false);
		return;
	}
	
	ActionKey & action = actions[actionId];
	
	InputKeyId oldKey = action.key[index];
	action.key[index] = key;
	
	int otherIndex = 1 - index;
	
	if(action.key[otherIndex] == -1) {
		action.key[otherIndex] = oldKey;
		oldKey = -1;
	}
	
	if(action.key[otherIndex] == key) {
		action.key[otherIndex] = -1;
	}
	
	// remove double key assignments
	for(size_t i = 0; i < NUM_ACTION_KEY; i++) {
		
		if(i == (size_t)actionId) {
			continue;
		}
		
		for(int k = 0; i < 2; i++) {
			if(actions[i].key[k] == key) {
				actions[i].key[k] = oldKey;
				oldKey = -1;
			}
		}
		
	}
}
Beispiel #27
0
bool Input::init() {
	
	arx_assert(backend == NULL);
	
	bool autoBackend = (config.input.backend == "auto");
	
	for(int i = 0; i < 2 && !backend; i++) {
		bool first = (i == 0);
		
		bool matched = false;
		
		#ifdef ARX_HAVE_SDL
		if(!backend && first == (autoBackend || config.input.backend == "SDL")) {
			matched = true;
			backend = new SDLInputBackend;
			if(!backend->init()) {
				delete backend, backend = NULL;
			}
		}
		#endif
		
		#ifdef ARX_HAVE_DINPUT8
		if(!backend && first == (autoBackend || config.input.backend == "DirectInput8")) {
			matched = true;
			backend = new DInput8Backend;
			if(!backend->init()) {
				delete backend, backend = NULL;
			}
		}
		#endif
		
		if(first && !matched) {
			LogError << "Unknown backend: " << config.input.backend;
		}
	}
	
	return (backend != NULL);
}
Beispiel #28
0
void Win32Window::tick() {
	
	// Check if window was destroyed...
	arx_assert(m_hWnd != NULL);
	
	MSG msg;
	while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0) {
		if(msg.message == WM_QUIT) {
			DestroyWindow(m_hWnd); // Destroy window and quit
		}
		TranslateMessage(&msg);
		DispatchMessage(&msg); // Send message to the WindowProc.
	}
	
	// Check if window was destroyed...
	if(m_hWnd == NULL) {
		return;
	}
	
	if(hasFocus() && !isFullScreen()) {
		updateSize();
	}
}
WeaponType ARX_EQUIPMENT_GetPlayerWeaponType() {
	arx_assert(entities.player());
	
	if(ValidIONum(player.equiped[EQUIP_SLOT_WEAPON])) {
		Entity * toequip = entities[player.equiped[EQUIP_SLOT_WEAPON]];

		if(toequip) {
			if(toequip->type_flags & OBJECT_TYPE_DAGGER)
				return WEAPON_DAGGER;

			if(toequip->type_flags & OBJECT_TYPE_1H)
				return WEAPON_1H;

			if(toequip->type_flags & OBJECT_TYPE_2H)
				return WEAPON_2H;

			if(toequip->type_flags & OBJECT_TYPE_BOW)
				return WEAPON_BOW;
		}
	}

	return WEAPON_BARE;
}
Beispiel #30
0
void ARX_THROWN_OBJECT_Throw(EntityHandle source, const Vec3f & position, const Vec3f & vect,
							 const glm::quat & quat, float velocity, float damages, float poison) {
	
	arx_assert(arrowobj);
	
	long num = ARX_THROWN_OBJECT_GetFree();
	if(num < 0)
		return;
		
	ARX_THROWN_OBJECT *thrownObj = &Thrown[num];
	
	thrownObj->damages = damages;
	thrownObj->position = position;
	thrownObj->initial_position = position;
	thrownObj->vector = vect;
	thrownObj->quat = quat;
	thrownObj->source = source;
	thrownObj->obj = arrowobj;
	thrownObj->velocity = velocity;
	thrownObj->poisonous = poison;
	
	thrownObj->pRuban = new ArrowTrail();
	thrownObj->pRuban->SetNextPosition(thrownObj->position);
	thrownObj->pRuban->Update(framedelay);
	
	thrownObj->creation_time = (unsigned long)(arxtime);
	thrownObj->flags |= ATO_EXIST | ATO_MOVING;
	
	if(source == 0
	   && ValidIONum(player.equiped[EQUIP_SLOT_WEAPON])
	) {
		Entity * tio = entities[player.equiped[EQUIP_SLOT_WEAPON]];
		
		if(tio->ioflags & IO_FIERY)
			thrownObj->flags |= ATO_FIERY;
	}
}