示例#1
0
文件: model.c 项目: ccxvii/mio
void lerp_frame(struct pose *out, struct pose *a, struct pose *b, float t, int n)
{
	int i;
	for (i = 0; i < n; i++) {
		vec_lerp(out[i].position, a[i].position, b[i].position, t);
		quat_lerp_neighbor_normalize(out[i].rotation, a[i].rotation, b[i].rotation, t);
		vec_lerp(out[i].scale, a[i].scale, b[i].scale, t);
	}
}
示例#2
0
VECTOR* handFingerPos (ENTITY* entHand, BOOL bLeftHand, int fingerId, VECTOR* vecFingerPos, VECTOR* vecFingerDir)
{
	VECTOR vecFinger0, vecFinger1;
	
	char* j0 = _chr((g_handBoneFarNames->pstring)[fingerId]);
	char* j1 = _chr((g_handBoneNearNames->pstring)[fingerId]);		
	
	vec_for_bone(&vecFinger0, entHand, j0);
	vec_for_bone(&vecFinger1, entHand, j1);
	
	if (bLeftHand)
	{
		vec_to_ent(&vecFinger0, entHand);
		vecFinger0.x *= -1;
		vec_for_ent(&vecFinger0, entHand);	
		
		vec_to_ent(&vecFinger1, entHand);
		vecFinger1.x *= -1;
		vec_for_ent(&vecFinger1, entHand);
	}	
	
	vec_lerp(vecFingerPos, &vecFinger0, &vecFinger1, 0.5);
	vec_diff(vecFingerDir, &vecFinger1, &vecFinger0);
	
	return vecFingerPos;
}
void pAlphaFadeFlame(PARTICLE *p) {
	VECTOR vecTemp;
	vec_lerp(vecTemp, vector(128, 50, 50), vector(200, 180, 100), p.lifespan / 10);
	p.blue = vecTemp.z;
	p.green = vecTemp.y;
	p.blue = vecTemp.x;
	p.alpha = p.lifespan / 10 * 100 * 0.3;
	if (p.alpha <= 0) p.lifespan = 0;
}
示例#4
0
void creditsFog ()
{
	camera.fog_start = 128;
	camera.fog_end = 4000;
	
	fog_color = 1;
	vec_set(&d3d_fogcolor1.blue, vector(162, 174, 123));
	
	VECTOR fogColor;
	vec_set(&fogColor, vector(d3d_fogcolor1.blue, d3d_fogcolor1.green, d3d_fogcolor1.red));
	
	while (!creditsFinished)
	{
		vec_lerp(d3d_fogcolor1.blue, &fogColor, &sky_color, 0.5);
		wait(1);
	}
}
示例#5
0
void ebCreateHandJoints (ENTITY* entHand)
{
	if (entHand == NULL)
		return;
		
	BOOL* arr = NULL;
	
	if (entHand->skill20 == 1) // left
		arr = g_handChopL;
	else // right
		arr = g_handChopR;
		
	int i;
	for (i = 0; i < HAND_FINGERS; i++)
	{
		if (arr[i] == false)
		{
			char* j0 = _chr((g_handBoneFarNames->pstring)[i]);
			char* j1 = _chr((g_handBoneNearNames->pstring)[i]);
			
			VECTOR v0, v1, v;
			vec_for_bone(&v0, entHand, j0);
			vec_for_bone(&v1, entHand, j1);
			vec_lerp(&v, &v0, &v1, 0.5);
			
			if (entHand->skill20 != 0)
			{
				vec_to_ent(&v, entHand);
				v.x *= -1;
				vec_for_ent(&v, entHand);
			}
			
			ENTITY* e = ent_create("handjoint.mdl", &v, ebHandJoint);
			e->skill1 = i;
			e->skill2 = entHand;
		}
	}
}
示例#6
0
static inline Vector3 quad_interpolate(const Vector3 a, const Vector3 b, const Vector3 c, const Vector3 d, double u, double v)
{
	Vector3 ab = vec_lerp(a, b, u);
	Vector3 cd = vec_lerp(c, d, u);
	return vec_lerp(ab, cd, v);
}
/*
 * Hill-Reilly pucker-paramter based coloring
 */
void lerp_color_range(float *newcol, float val, float rmin, float rmax,
                      float *mincol, float *maxcol) {
  float range = rmax-rmin;
  float lerpval = (val - rmin) / range;
  vec_lerp(newcol, mincol, maxcol, lerpval);
}
示例#8
0
void bsp_tree_create_from_solid(struct BspTree* tree, struct Solid* solid) {
    size_t alloc_attributes_result = bsp_tree_alloc_attributes(tree, solid->attributes_size);
    log_assert( alloc_attributes_result >= solid->attributes_size );

    size_t num_polygons = solid->indices_size/3;
    size_t alloc_polygons_result = bsp_tree_alloc_polygons(tree, num_polygons);
    log_assert( alloc_polygons_result >= num_polygons );

    size_t alloc_nodes_result = bsp_tree_alloc_nodes(tree, num_polygons);
    log_assert( alloc_nodes_result >= num_polygons );

    int32_t* workset_polygons_front = malloc(alloc_polygons_result * sizeof(int32_t));
    log_assert( workset_polygons_front != NULL );
    int32_t* workset_polygons_back = malloc(alloc_polygons_result * sizeof(int32_t));
    log_assert( workset_polygons_back != NULL );

    float min_x = FLT_MAX;
    float min_y = FLT_MAX;
    float min_z = FLT_MAX;
    float max_x = -FLT_MAX;
    float max_y = -FLT_MAX;
    float max_z = -FLT_MAX;
    for( size_t indices_i = 0; indices_i < solid->indices_size+1; indices_i++ ) {
        uint32_t src_i = solid->indices[indices_i];

        if( indices_i < solid->indices_size ) {
            VecP* src = &solid->vertices[src_i*VERTEX_SIZE];
            VecP* dst = &tree->attributes.vertices[indices_i*VERTEX_SIZE];
            vec_copy3f(src, dst);
            tree->attributes.occupied += 1;

            if( src[0] < min_x ) {
                min_x = src[0];
            }
            if( src[1] < min_y ) {
                min_y = src[1];
            }
            if( src[2] < min_z ) {
                min_z = src[2];
            }

            if( src[0] > max_x ) {
                max_x = src[0];
            }
            if( src[1] > max_y ) {
                max_y = src[1];
            }
            if( src[2] > max_z ) {
                max_z = src[2];
            }
        }

        if( indices_i > 0 && indices_i % 3 == 0 ) {
            size_t poly_i = indices_i / 3 - 1;
            tree->polygons.array[poly_i].start = poly_i*3*VERTEX_SIZE;
            tree->polygons.array[poly_i].size = 3;
            polygon_normal(3, VERTEX_SIZE, &tree->attributes.vertices[poly_i*3*VERTEX_SIZE], tree->polygons.array[poly_i].normal);
            tree->polygons.occupied += 1;

            workset_polygons_front[poly_i] = poly_i;
        }

    }

    struct BspNode* root = &tree->nodes.array[0];
    bsp_node_create(root);
    tree->nodes.occupied = 1;
    root->bounds.half_width = (max_x - min_x)/2.0f;
    root->bounds.half_height = (max_y - min_y)/2.0f;
    root->bounds.half_depth = (max_z - min_z)/2.0f;
    root->bounds.center[0] = min_x + root->bounds.half_width;
    root->bounds.center[1] = min_y + root->bounds.half_height;
    root->bounds.center[2] = min_z + root->bounds.half_depth;

    root->divider = 0;    bsp_select_balanced_divider(tree, root, num_polygons, workset_polygons_front, &root->divider);

    struct BspPoly* root_divider = &tree->polygons.array[root->divider];
    const float* root_divider_polygon = &tree->attributes.vertices[root_divider->start];

    draw_polygon_wire(&global_static_canvas, 0, (Mat)IDENTITY_MAT, (Color){255, 0, 0, 255}, 0.01f, root_divider->size, root_divider_polygon, root_divider->normal);
    draw_vec(&global_static_canvas, 0, (Mat)IDENTITY_MAT, (Color){255, 0, 0, 255}, 0.01f, root_divider->normal, &root_divider_polygon[3], 1.0f, 0.1f);
    /* draw_plane(&global_static_canvas, MAX_CANVAS_LAYERS-1, (Mat)IDENTITY_MAT, (Color){120, 120, 150, 127}, root_divider->normal, &root_divider_polygon[3], 10.0f); */

    for( size_t polygon_i = 0; polygon_i < num_polygons; polygon_i++ ) {
        size_t cuts_polygon_size = 3;
        const float* cuts_polygon = &tree->attributes.vertices[polygon_i*cuts_polygon_size*VERTEX_SIZE];

        size_t result_size = cuts_polygon_size;
        struct PolygonCutPoints result_points[cuts_polygon_size];
        enum PolygonCutType result_type = polygon_cut(cuts_polygon_size, VERTEX_SIZE, cuts_polygon,
                                                      root_divider->normal, root_divider_polygon,
                                                      result_size, result_points);

        Vec3f cuts_polygon_normal = {0};
        polygon_normal(3, VERTEX_SIZE, cuts_polygon, cuts_polygon_normal);
        switch(result_type) {
            case POLYGON_COPLANNAR:
                //draw_polygon_wire(&global_static_canvas, 0, (Mat)IDENTITY_MAT, (Color){255, 255, 255, 255}, 0.01f, result_size, cuts_polygon, cuts_polygon_normal);
                break;
            case POLYGON_FRONT:
                //draw_polygon_wire(&global_static_canvas, 0, (Mat)IDENTITY_MAT, (Color){255, 0, 255, 255}, 0.01f, result_size, cuts_polygon, cuts_polygon_normal);
                break;
            case POLYGON_BACK:
                //draw_polygon_wire(&global_static_canvas, 0, (Mat)IDENTITY_MAT, (Color){0, 0, 255, 255}, 0.01f, result_size, cuts_polygon, cuts_polygon_normal);
                break;
            case POLYGON_SPANNING:
                //draw_polygon_wire(&global_static_canvas, 0, (Mat)IDENTITY_MAT, (Color){255, 255, 0, 255}, 0.01f, result_size, cuts_polygon, cuts_polygon_normal);

                if( result_points[0].num_cuts > 0 ) {
                    size_t new_poly_size = cuts_polygon_size+result_points[0].num_cuts+10;

                    size_t front_occupied = 0;
                    float front_vertices[new_poly_size*VERTEX_SIZE];

                    size_t back_occupied = 0;
                    float back_vertices[new_poly_size*VERTEX_SIZE];

                    for( size_t result_i = 0; result_i < result_size; result_i++ ) {
                        if( result_points[result_i].type == POLYGON_BACK ) {
                            vec_copy3f(&cuts_polygon[result_i*VERTEX_SIZE], &back_vertices[back_occupied*VERTEX_SIZE]);
                            back_occupied += 1;
                        } else if( result_points[result_i].type == POLYGON_FRONT ) {
                            vec_copy3f(&cuts_polygon[result_i*VERTEX_SIZE], &front_vertices[front_occupied*VERTEX_SIZE]);
                            front_occupied += 1;
                        } else if( result_points[result_i].type == POLYGON_COPLANNAR ) {
                            vec_copy3f(&cuts_polygon[result_i*VERTEX_SIZE], &back_vertices[back_occupied*VERTEX_SIZE]);
                            back_occupied += 1;
                            vec_copy3f(&cuts_polygon[result_i*VERTEX_SIZE], &front_vertices[front_occupied*VERTEX_SIZE]);
                            front_occupied += 1;
                        }

                        if( result_points[result_i].interpolation_index > -1 ) {
                            const VecP* a = &cuts_polygon[result_i*VERTEX_SIZE];
                            const VecP* b = &cuts_polygon[result_points[result_i].interpolation_index*VERTEX_SIZE];
                            Vec3f r = {0};
                            vec_lerp(b, a, result_points[result_i].interpolation_value, r);

                            vec_copy3f(r, &back_vertices[back_occupied*VERTEX_SIZE]);
                            back_occupied += 1;
                            vec_copy3f(r, &front_vertices[front_occupied*VERTEX_SIZE]);
                            front_occupied += 1;
                        }
                    }

                    //printf("front_occupied: %lu\n", front_occupied);
                    //draw_polygon_wire(&global_static_canvas, 0, (Mat)IDENTITY_MAT, red, 0.01f, front_occupied, front_vertices, cuts_polygon_normal);
                    //draw_polygon_wire(&global_static_canvas, 0, (Mat)IDENTITY_MAT, white, 0.01f, back_occupied, back_vertices, cuts_polygon_normal);
                }
                break;
        }
    }

    log_fail(__FILE__, __LINE__, "BUILT BSP TREE... OR NOT?\n");
}
示例#9
0
文件: network.c 项目: Acknex/TUST
void net_entsync(ENTITY *ent)
{
	ent.event = net_entsync_event;
	ent.emask |= ENABLE_RECEIVE;
	ent.smask = NOSEND_ALPHA | NOSEND_AMBIENT | NOSEND_ANGLES | NOSEND_ATTACH | NOSEND_COLOR | NOSEND_FLAGS | NOSEND_FRAME | NOSEND_LIGHT | NOSEND_ORIGIN | NOSEND_SCALE | NOSEND_SKIN | NOSEND_SOUND;
	// Wait for network handle
	while(ent.client_id < 0) wait(1);
	
	ent.NET_SKILL_LERPSPEED = net_ent_default_lerpspeed;
	
	proc_mode = PROC_GLOBAL | PROC_LATE;
	
	if(ent.client_id == dplay_id)
	{
		// Controller
		var update = net_ent_sendrate;
		while(handle(ent) != NULL)
		{
			// Send entity updates
			update -= time_step;
			if(update <= 0)
			{
				// Send position if distance since last update greater the minimum send distance
				if(vec_dist(ent.x, ent.NET_SKILL_POS_X) > net_ent_mindist)
				{
					vec_set(ent.NET_SKILL_POS_X, ent.x);
					if(net_ent_flags & NET_ENT_UNRELIABLE)
						send_skill(ent.NET_SKILL_POS_X, SEND_VEC | SEND_ALL | SEND_UNRELIABLE);
					else
						send_skill(ent.NET_SKILL_POS_X, SEND_VEC | SEND_ALL);
				}
				if(vec_dist(ent.pan, ent.NET_SKILL_ANG_PAN) > net_ent_mindiff)
				{
					vec_set(ent.NET_SKILL_ANG_PAN, ent.pan);
					if(net_ent_flags & NET_ENT_UNRELIABLE)
						send_skill(ent.NET_SKILL_ANG_PAN, SEND_VEC | SEND_ALL | SEND_UNRELIABLE);
					else
						send_skill(ent.NET_SKILL_ANG_PAN, SEND_VEC | SEND_ALL);
				}
				update = net_ent_sendrate;
			}
			wait(1);
		}
	}
	else
	{
		// Receiver
		while(handle(ent) != NULL)
		{
			if(net_ent_lerpfactor > 0)
			{
				// Lerping
				vec_lerp(ent.x, ent.x, ent.NET_SKILL_POS_X, net_ent_lerpfactor);
				ang_lerp(ent.pan, ent.pan, ent.NET_SKILL_ANG_PAN, net_ent_lerpfactor);
			}
			else
			{
				// Linear movement
				VECTOR dir;
				vec_diff(dir, ent.NET_SKILL_POS_X, ent.x);
				var dist = vec_length(dir);
				if(dist > 0.5 * net_ent_mindist)
				{
					vec_normalize(dir, minv(ent.NET_SKILL_LERPSPEED * time_step, dist));
					vec_add(ent.x, dir);
				}
				vec_set(ent.pan, ent.NET_SKILL_ANG_PAN);
			}
			wait(1);
		}
	}
}
示例#10
0
action ebWarghost ()
{
	g_entEbWarghost = my;
	my->material = g_mtlBossGhost;
	
	lvlLavaSuperReset ();
	
	var deadRotate = 0;
	
	var origScale = my->scale_x;
	var deadScale = origScale;
	
	BOOL isSpining = false;
	
	while (1)
	{
		// pos
		{
			VECTOR vecPos;
			vecPos.x = my->x;
			vecPos.y = 1024;
			vecPos.z = 150;
			
			if (player != NULL)
			{
				vecPos.x = player->x;
				vecPos.z = player->z;
			}
				
			vec_lerp(my->x, my->x, &vecPos, time_step * 0.025);
		}
		
		// ang
		{
			VECTOR vecLookAt, vecLook;
			vec_set(&vecLookAt, my->x);
			
			vecLookAt.y -= 1000;
			
			if (player != NULL)
			{
				vecLookAt.x = player->x;
				vecLookAt.y = player->y;
			}
			
			vec_diff(&vecLook, &vecLookAt, my->x);
			vec_to_angle(my->pan, &vecLook);
			
			if (!isEbWarghostAlive())
			{
				setPlayerControls(false);
				setPlayerPan(my);
				
				deadRotate += 10 * time_step;
				deadScale += 0.3 * time_step;
				
				g_sndEbVol = clamp(g_sndEbVol - g_sndEbVolDec * time_step, 0, 100);
				snd_tune(g_fhLvlLavastageSong, g_sndEbVol, 3, 0);
				
				if (!isSpining)
				{
					snd_play(g_sndBossSpin, 100, 0);
					snd_play(g_sndBossDeadSpeech, 100, 0);
					
					isSpining = true;
				}
			}
			
			my->pan += deadRotate;
			my->scale_x = my->scale_y = my->scale_z = deadScale;
			
			if (my->scale_x / origScale > 3)
				break;
		}
		
		if (g_ebDoHit)
			ent_animate(my, "jump", g_ebDoHitPercent, ANM_CYCLE);
		else
			ent_animate(my, "attack", total_ticks % 100, ANM_CYCLE);
			
		wait(1);
	}
	
	snd_play(g_sndBossSplatter, 100, 0);
	
	VECTOR vecPos, vecDir;
	int i, j, numVerts = ent_status(my, 0);
	
	snd_play(g_sndBossDead, 100, 0);
	
	set(my, INVISIBLE);
	
	for (i = 0; i < numVerts; i++)
	{
		vec_for_vertex(&vecPos, my, i+1);
		
		vec_diff(&vecDir, &vecPos, my->x);
		vec_normalize(&vecDir, 1);
		
		effEbBlood(&vecPos, &vecDir, 25+random(100), false, 1, 4 + random(4));
	}
	
	while (redness < 100)
	{
		redness = clamp(redness + g_rednessInc * time_step, 0, 100);
		
		g_sndEbVol = clamp(g_sndEbVol - g_sndEbVolDec * time_step, 0, 100);
		snd_tune(g_fhLvlLavastageSong, g_sndEbVol, 5, 0);		
		
		wait(1);
	}
	
	wait(-1);
	
	proc_mode = PROC_GLOBAL;
	ptr_remove(my);
	
	creditsInit();
}
示例#11
0
void ebHandWatch ()
{
	updateHandChopped(my);
	
	ebDoSparkle(my, 2000);
	snd_play(g_sndSparkle, 100, 0);
	
	set(my, PASSABLE);
	my->ambient = 75;
	
	var moveAnim = 10;
	
	var t = maxv(g_facTimeEbHandWatchMin, g_facTimeEbHandWatch * (5 + random(3))) * 16;
	
	vec_scale(my->scale_x, g_handScale);
	
	var ground, height;
	var heightSub = 32;
	
	g_ebHand = my;
	
	snd_play(g_sndHandFly, 100, 0);
	
	// move with player
	set(player, FLAG2);
	while (t > 0)
	{
		VECTOR vecBoneGround, vecTraceStart, vecTraceEnd;
		vec_for_bone(&vecBoneGround, my, "ground");
		
		vec_set(&vecTraceStart, my->x);
		vecTraceStart.y = vecBoneGround.y;
		
		vec_set(&vecTraceEnd, &vecTraceStart);
		vecTraceEnd.z -= 2000;
		
		height = player->z + 250;
		
		if (c_trace(&vecTraceStart, &vecTraceEnd, IGNORE_ME | USE_POLYGON | IGNORE_FLAG2 ) > 0)
		{
			ground = hit.z;
			height = ground + (my->z - vecBoneGround.z);
		}
		
		VECTOR v;
		vec_set(&v, player->x);
		v.z = height;
		
		vec_lerp(my->x, my->x, &v, 0.25 * time_step);
		
		ent_animate(my, "idleH", 50 + sin(total_ticks * moveAnim) * 50, ANM_CYCLE);
		
		t -= time_step;
		
		doHandChopBlood(my);
		
		wait(1);
	}
	
	g_facTimeEbHandWatch *= g_facTimeEbHandWatchDec;
	
	reset(player, FLAG2);
	
	// drop
	
	g_handDropping = true;
	
	g_ebHand->skill1 = 1; // joints = on
	g_ebHand->skill2 = 1; // joints death = on
	
	g_playerDontScanFlag2 = true;
	g_playerNoYou = true;
	
	ebCreateHandJoints(g_ebHand);
	
	set(player, ZNEAR);
	
	t = 0;
	
	BOOL bSndHandDrop = true;
	while (t < 100)
	{
		VECTOR vecBoneGround;
		vec_for_bone(&vecBoneGround, g_ebHand, "ground");
		height = ground + (g_ebHand->z - vecBoneGround.z) - heightSub;
		
		VECTOR v;
		vec_set(&v, g_ebHand->x);
		v.z = height;
		
		vec_lerp(g_ebHand->x, g_ebHand->x, &v, 0.25 * time_step);
		
		t = clamp(t + 5 * time_step, 0, 100);
		ent_animate(g_ebHand, "drop", t, 0);

		doHandChopBlood(my);
		
		if (t > 90 && bSndHandDrop)
		{
			bSndHandDrop = false;
			snd_play(g_sndHandDrop, 100, 0);
		}
		
		wait(1);
	}
	
	g_handDropping = false;
	
	g_ebHand->skill2 = 0; // joints death = off
	
	t = maxv(g_facTimeEbHandDroppedMin, g_facTimeEbHandDropped * (3+random(2)) * 16);
	
	g_fingerChopped = false;
	
	// wait	
	while (t > 0 && !g_fingerChopped)
	{
		ent_animate(g_ebHand, "down", (total_ticks * 4), ANM_CYCLE);
		t -= time_step;
		
		doHandChopBlood(my);
		
		wait(1);
	}
	
	g_facTimeEbHandDropped *= g_facTimeEbHandDroppedDec;
	
	snd_play(g_sndHandUp, 100, 0);
	
	reset(player, ZNEAR);
	
	g_ebHand->skill1 = 0;
	
	// up
	while (t < 100)
	{
		VECTOR vecBoneGround;
		vec_for_bone(&vecBoneGround, g_ebHand, "ground");
		height = ground + (g_ebHand->z - vecBoneGround.z) - heightSub;
		
		VECTOR v;
		vec_set(&v, g_ebHand->x);
		v.z = height;
		
		vec_lerp(g_ebHand->x, g_ebHand->x, &v, 0.25 * time_step);
		
		t = clamp(t + 2 * time_step, 0, 100);
		ent_animate(g_ebHand, "up", t, 0);		
		
		doHandChopBlood(my);
		
		wait(1);
	}
	
	g_playerDontScanFlag2 = false;
	g_playerNoYou = false;
	
	t = 1.5 * 16;
	
	snd_play(g_sndHandBliss, 100, 0);
	
	// go away
	while (t > 0)
	{
		t -= time_step;
		g_ebHand->z += 10 * time_step;
		g_ebHand->y -= 20 * time_step;
		g_ebHand->roll += 5 * time_step;
		
		doHandChopBlood(my);
		
		wait(1);
	}

	set(g_ebHand, INVISIBLE);
	ebDoSparkle(g_ebHand, 2000);
	snd_play(g_sndSparkle, 100, 0);

	wait(1);
	
	ent_create(NULL, nullvector, ebHandsBgFly);
	ptr_remove(g_ebHand);
}
示例#12
0
		void ebHandFly ()
		{
			updateHandChopped(my);
			
			set(my, PASSABLE);
			my->ambient = 75;
			
			VECTOR startPos, targetPos;
			vec_set(&startPos, my->x);
			
			ebDoSparkle(my, 2000);
			
			var t = 0;
			
			var distX = 500;
			
			var moveDist = 200;
			var moveTime = 0.5;
			var moveLerp = 0.2;
			var moveAnim = 2;
			
			vec_scale(my->scale_x, g_handScale);
			
			var targetRoll = -90;
			
			// Stone rain
			var randomStoneRain = 0;
			var randomStoneModel = 0;
			
			while (my->skill1 == 0)
			{
				if (t <= 0)
				{
					vec_set(&targetPos, vector(25+random(moveDist), 0, 0));
					vec_rotate(&targetPos, vector(random(360),random(360),random(360)));
					vec_add(&targetPos, &startPos);
					
					t += moveTime * 16;
				}
				else
					t -= time_step;
				
				VECTOR nuPos;
				vec_set(&nuPos, &targetPos);
				
				if (player != NULL)
					nuPos.x += player->x;
				
				vec_lerp(my->x, my->x, &nuPos, moveLerp * time_step);
					
				ent_animate(my, "idleH", (total_ticks * moveAnim) % 100, ANM_CYCLE);
				my->roll += (targetRoll - my->roll) * 0.05 * clamp(time_step, 0.001, 1);
				
				doHandChopBlood(my);
				
				if (!isEbWarghostAlive())
				{
					startPos.z -= 10 * time_step;
					targetPos.z -= 10 * time_step;
					targetRoll -= 10 * time_step;
				}
				
				// Stone rain
				
				randomStoneRain = random(1000);
				if (randomStoneRain > 950) {
					randomStoneModel = integer(random(2));
					switch(randomStoneModel) {
						case 0: ent_create("stein1.mdl", vector(player.x - 500 + random(1000), player.y, my.z + 300 + random(50)), ebHandStone); break;
						case 1: ent_create("stein2.mdl", vector(player.x - 500 + random(1000), player.y, my.z + 300 + random(50)), ebHandStone); break;
						case 2: ent_create("stein3.mdl", vector(player.x - 500 + random(1000), player.y, my.z + 300 + random(50)), ebHandStone); break;
					}
				}
				
				// -- end stone rain
				
				wait(1);
			}
			
			while (my->skill2 > 0)
			{
				my->skill2 -= time_step;
				my->z += 10 * time_step;
				my->y -= 20 * time_step;
				my->roll += 2 * time_step;
				
				doHandChopBlood(my);
				
				wait(1);
			}
			
			set(my, INVISIBLE);
			ebDoSparkle(my, 2000);
			
			wait(1);
			ptr_remove(my);
		}