1 /* ResidualVM - A 3D game interpreter
2 *
3 * ResidualVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the AUTHORS
5 * file distributed with this source distribution.
6 *
7 * Additional copyright for this file:
8 * Copyright (C) 1999-2000 Revolution Software Ltd.
9 * This code is based on source code created by Revolution Software,
10 * used with permission.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 *
26 */
27
28 #include "engines/icb/common/px_common.h"
29 #include "engines/icb/p4.h"
30 #include "engines/icb/p4_generic.h"
31 #include "engines/icb/debug.h"
32 #include "engines/icb/mission.h"
33 #include "engines/icb/direct_input.h"
34 #include "engines/icb/global_objects.h"
35 #include "engines/icb/global_objects_psx.h"
36 #include "engines/icb/p4.h"
37 #include "engines/icb/actor.h"
38 #include "engines/icb/actor_pc.h"
39 #include "engines/icb/drawpoly_pc.h"
40 #include "engines/icb/common/px_capri_maths.h"
41 #include "engines/icb/gfx/gfxstub.h"
42 #include "engines/icb/gfx/gfxstub_dutch.h"
43 #include "engines/icb/gfx/gfxstub_rev_dutch.h"
44 #include "engines/icb/actor_view_pc.h"
45 #include "engines/icb/res_man.h"
46
47 #include "common/keyboard.h"
48
49 namespace ICB {
50
51 // Cute little puppies
52 extern char *pRGB;
53 extern char *pZa;
54 extern int32 RGBWidth;
55 extern int32 RGBHeight;
56 extern int32 RGBPitch;
57 extern int32 RGBBytesPerPixel;
58
59 RevRenderDevice renderingDevice;
60
61 extern int32 texturesUsedThisCycle;
62
63 // This controls autoanimation (0 = None, 1 = Backward, 2 = Forward)
64 uint32 auto_anim = 2;
65
66 // Camera and animation structures
67 PXanim *pxanim;
68 SVECTOR rot; // Actor rotation
69 SVECTOR _crot; // Camera rotation
70 int32 uvframe = 0;
71
72 // Global filename stuff
73 char cluster_name[32];
74 uint32 cluster_name_hash;
75 char raj_name[128];
76 uint32 raj_name_hash;
77
78 // Pointers to useful strings for the current actor
79 char *character_name;
80 char *anim_name;
81 const char *weapon_name;
82 char *outfit_name;
83
84 int32 framenum;
85 int32 g_repeats;
86
87 // Do we allow keyboard input to affect the actor viewing
88 bool8 g_av_userControlled = FALSE8;
89
90 // Lighting structure and coordinates, colour components
91 int16 av_LightX;
92 int16 av_LightY;
93 int16 av_LightZ;
94 int32 av_LightR;
95 int32 av_LightG;
96 int32 av_LightB;
97 int32 av_LightA;
98 bool8 av_LightDir;
99 bool8 av_autoR;
100 bool8 av_autoG;
101 bool8 av_autoB;
102
103 // Render coordinates
104 int16 av_x, av_y, av_z;
105
106 // Prototypes for functions used in this module
107 TextureHandle *GetRegisteredTexture(const char *, uint32, const char *, uint32, const char *, uint32);
108 void DrawFrame(const int32 frame);
109 void MakeCameraView();
110 void ResetCamera();
111 void ResetActor();
112 void InitLight();
113 void SetLight(int32 falloff);
114 void AutoCycleLight();
115
116 #define LIGHT_DISTANCE_FROM_ACTOR 100
117 #define LIGHT_HEIGHT_LIMIT 200
118
InitActorView(const char * name,const char * outfit,const char * weapon,const char * anim,int16 ix,int16 iy,int16 iz)119 void InitActorView(const char *name, const char *outfit, const char *weapon, const char *anim, int16 ix, int16 iy, int16 iz) {
120 // Store initial offset coordinates
121 av_x = ix;
122 av_y = iy;
123 av_z = iz;
124
125 // Make hash filename of the character
126 char h_character[8];
127 HashFile(name, h_character);
128 // Make hash filename of the outfit
129 char h_outfit[8];
130 HashFile(outfit, h_outfit);
131 // Make the cluster name
132 sprintf(cluster_name, "\\C\\%s\\%s.OFT", h_character, h_outfit);
133 // Hash value for this cluster name
134 cluster_name_hash = NULL_HASH;
135
136 ResetCamera();
137 ResetActor();
138
139 raj_name_hash = NULL_HASH;
140
141 sprintf(raj_name, "%s\\%s.raj", weapon, anim);
142
143 anim_name = const_cast<char *>(anim);
144 weapon_name = const_cast<char *>(weapon);
145 outfit_name = const_cast<char *>(outfit);
146 character_name = const_cast<char *>(name);
147
148 // Animate the shape from frame to frame, looping
149 framenum = 0;
150 g_repeats = 0;
151 auto_anim = 2;
152
153 // Initialise a light to use
154 InitLight();
155
156 // Start the psx poly drawing ganky bit
157 InitDrawing();
158
159 // Load and select the appropriate texture
160 char texture_name[128];
161 uint32 texture_name_hash = NULL_HASH;
162
163 sprintf(texture_name, "material.revtex");
164
165 TextureHandle *texHan = GetRegisteredTexture(texture_name, texture_name_hash, texture_name, texture_name_hash, cluster_name, cluster_name_hash);
166
167 ChooseTexture(texHan);
168 }
169
ChangeAnimPlaying(const char * pose,const char * anim,bool8 forwards,int32 repeats,int16 ix,int16 iy,int16 iz)170 void ChangeAnimPlaying(const char *pose, const char *anim, bool8 forwards, int32 repeats, int16 ix, int16 iy, int16 iz) {
171 // Set pose
172 if (pose) {
173 // New pose
174 weapon_name = const_cast<char *>(pose);
175 } else {
176 // Default is unarmed
177 weapon_name = "unarmed";
178 }
179
180 // Require anim parameter
181 if (anim == NULL)
182 Fatal_error("ChangeAnimPlaying() cannot set active animation to NULL!");
183
184 // Remake raj filename
185 raj_name_hash = NULL_HASH;
186
187 sprintf(raj_name, "%s\\%s.raj", weapon_name, anim);
188
189 // Change animation to use
190 anim_name = const_cast<char *>(anim);
191
192 // Set direction to run the anim
193 if (forwards)
194 auto_anim = 2;
195 else
196 auto_anim = 1;
197
198 pxanim = (PXanim *)rs_anims->Res_open(raj_name, raj_name_hash, cluster_name, cluster_name_hash);
199
200 // Set to the starting frame of this anim
201 if (forwards)
202 framenum = 0;
203 else
204 framenum = pxanim->frame_qty - 2;
205
206 g_repeats = repeats;
207
208 // Store initial offset coordinates
209 av_x = ix;
210 av_y = iy;
211 av_z = iz;
212
213 ResetCamera();
214 }
215
ActorViewDraw()216 int32 ActorViewDraw() {
217 // Return value
218 int32 returnStatus = MID_ANIMATION;
219
220 // Alters the light nicely
221 AutoCycleLight();
222 // Call this each cycle to update our light
223 SetLight(500);
224
225 // This does most of the work
226 DrawFrame(framenum);
227
228 // This code acts upon user input to alter the actor's rotation and anim frame
229 // from the initialised defaults.
230 if (g_av_userControlled) {
231 // Increment in degrees
232 int32 dang = 5;
233
234 // Actor rotation
235 if (Read_DI_keys(Common::KEYCODE_LEFT)) {
236 rot.vy = (int16)(rot.vy + 4096 * dang / 360);
237 }
238 if (Read_DI_keys(Common::KEYCODE_DOWN)) {
239 rot.vy = (int16)(rot.vy - 4096 * dang / 360);
240 }
241 if (Read_DI_keys(Common::KEYCODE_UP)) {
242 rot.vx = (int16)(rot.vx + 4096 * dang / 360);
243 }
244 if (Read_DI_keys(Common::KEYCODE_DOWN)) {
245 rot.vx = (int16)(rot.vx - 4096 * dang / 360);
246 }
247 if (Read_DI_keys(Common::KEYCODE_PAGEUP)) {
248 rot.vz = (int16)(rot.vz + 4096 * dang / 360);
249 }
250 if (Read_DI_keys(Common::KEYCODE_PAGEDOWN)) {
251 rot.vz = (int16)(rot.vz - 4096 * dang / 360);
252 }
253
254 if (rot.vx > 4096)
255 rot.vx -= 4096;
256 if (rot.vy > 4096)
257 rot.vy -= 4096;
258 if (rot.vz > 4096)
259 rot.vz -= 4096;
260
261 if (rot.vx < -4096)
262 rot.vx += 4096;
263 if (rot.vy < -4096)
264 rot.vy += 4096;
265 if (rot.vz < -4096)
266 rot.vz += 4096;
267
268 // Set animation playing forwards
269 if (Read_DI_keys(Common::KEYCODE_1)) {
270 auto_anim = 2;
271 }
272 // Set animation playing backwards
273 if (Read_DI_keys(Common::KEYCODE_2)) {
274 auto_anim = 1;
275 }
276 // Previous frame
277 if (Read_DI_once_keys(Common::KEYCODE_MINUS)) {
278 auto_anim = 0;
279 framenum--;
280 }
281 // Next frame
282 if (Read_DI_once_keys(Common::KEYCODE_EQUALS)) {
283 auto_anim = 0;
284 framenum++;
285 }
286 }
287
288 // Auto animating backward
289 if (auto_anim == 1) {
290 framenum--;
291 }
292 // Auto forwards
293 else if (auto_anim) {
294 framenum++;
295 }
296
297 // Catch the loop for doing -1 in unsigned decimal
298 if (framenum > pxanim->frame_qty)
299 framenum = pxanim->frame_qty - 2;
300 if (framenum < 0) {
301 if (g_repeats > 0) {
302 g_repeats--;
303 } else {
304 if (auto_anim == 1)
305 returnStatus = ANIMATION_END;
306 }
307
308 framenum = pxanim->frame_qty - 2;
309 }
310
311 // Catch the loop for going past end of the animation
312 if (framenum > (pxanim->frame_qty - 2)) {
313 if (g_repeats > 0) {
314 g_repeats--;
315 } else {
316 if (auto_anim == 2)
317 returnStatus = ANIMATION_END;
318 }
319
320 framenum = 0;
321 }
322
323 // Catch illegal animations
324 if (framenum < 0)
325 framenum = 0;
326
327 // Draw the display list
328 drawOTList();
329
330 // Now copy the sucker to the screen
331 uint32 *address = (uint32 *)surface_manager->Lock_surface(working_buffer_id);
332 uint32 pitch = surface_manager->Get_pitch(working_buffer_id);
333 uint32 *source = (uint32 *)pRGB;
334 uint16 *zActor = (uint16 *)pZa;
335
336 uint32 *safe_ad = address;
337
338 for (int32 y = SCREEN_DEPTH; y; y--) {
339 uint32 *ad = safe_ad;
340 for (int32 x = SCREEN_WIDTH; x; x--) {
341 // If the z-map for this pixel is FFFF then this pixel doesn't contain actor
342 if (*zActor != 0xFFFF) {
343 *ad = *source;
344 *zActor = 0xFFFF;
345 }
346
347 ++zActor;
348 ++ad;
349 ++source;
350 }
351 safe_ad += pitch / 4;
352 }
353
354 // Unlock the surface
355 surface_manager->Unlock_surface(working_buffer_id);
356
357 return returnStatus;
358 }
359
DrawFrame(const int32 frame)360 void DrawFrame(const int32 frame) {
361 // These structures are needed for the drawing code to accept our light
362 PSXLampList the_lights;
363 PSXShadeList the_shades;
364 the_lights.n = 1;
365 the_lights.states[0] = 0;
366 the_lights.lamps[0] = g_av_Light;
367 the_shades.n = 0;
368
369 // Open the animation file
370 char bone_name[128];
371 char pose_name[128];
372 char mesh_name[128];
373 char smesh_name[128];
374 PSXrgb ambient;
375 ambient.r = 128;
376 ambient.g = 128;
377 ambient.b = 128;
378
379 pxanim = (PXanim *)rs_anims->Res_open(raj_name, raj_name_hash, cluster_name, cluster_name_hash);
380 PXFrameEnOfAnim(framenum, pxanim)->markers[ORG_POS];
381
382 // Make the actors orientation matrix
383 g_av_actor->rot = rot;
384 g_av_actor->rot.vy = (int16)(g_av_actor->rot.vy);
385
386 // Make the root local-world matrix
387 RotMatrix_gte(&g_av_actor->rot, &g_av_actor->lw);
388
389 // Need to use marker to get correct actor height (making crouch look correct)
390 PXframe *frm = PXFrameEnOfAnim(framenum, pxanim);
391 PXmarker &marker = frm->markers[ORG_POS];
392 float mposx, mposy, mposz;
393 marker.GetXYZ(&mposx, &mposy, &mposz);
394 int32 dy = (int32)mposy;
395
396 g_av_actor->lw.t[0] = 0;
397 g_av_actor->lw.t[1] = dy - 112;
398 g_av_actor->lw.t[2] = 0;
399
400 // Set the true rotation & position values from the ORG marker
401 g_av_actor->truePos.x = 0;
402 g_av_actor->truePos.y = dy - 112;
403 g_av_actor->truePos.z = 0;
404 g_av_actor->trueRot = g_av_actor->rot;
405
406 sprintf(pose_name, "%s\\pose.rap", weapon_name);
407 sprintf(bone_name, "%s\\%s.rab", weapon_name, anim_name);
408 sprintf(mesh_name, "mesh.rap");
409 sprintf(smesh_name, "mesh_shadow.rap");
410
411 uint32 mesh_hash = HashString(mesh_name);
412 rap_API *mesh = (rap_API *)rs_anims->Res_open(mesh_name, mesh_hash, cluster_name, cluster_name_hash);
413 uint32 smesh_hash = HashString(smesh_name);
414 rap_API *smesh = (rap_API *)rs_anims->Res_open(smesh_name, smesh_hash, cluster_name, cluster_name_hash);
415 uint32 pose_hash = HashString(pose_name);
416 rap_API *pose = (rap_API *)rs_anims->Res_open(pose_name, pose_hash, cluster_name, cluster_name_hash);
417 uint32 bone_hash = HashString(bone_name);
418 rab_API *rab = (rab_API *)rs_anims->Res_open(bone_name, bone_hash, cluster_name, cluster_name_hash);
419
420 ConvertRAP(pose);
421 ConvertRAP(smesh);
422 ConvertRAP(mesh);
423
424 // Some error checking
425 if (*(int32 *)mesh->id != *(int32 *)const_cast<char *>(RAP_API_ID)) {
426 Fatal_error("Wrong rap id value file %d api %d file:%s", mesh->id, RAP_API_ID, mesh_name);
427 }
428 if (mesh->schema != RAP_API_SCHEMA) {
429 Fatal_error("Wrong rap schema value file %d rap_api %d file:%s", mesh->schema, RAP_API_SCHEMA, mesh_name);
430 }
431 if (*(int32 *)pose->id != *(int32 *)const_cast<char *>(RAP_API_ID)) {
432 Fatal_error("Wrong rap id value file %d api %d file:%s", pose->id, RAP_API_ID, pose_name);
433 }
434 if (pose->schema != RAP_API_SCHEMA) {
435 Fatal_error("Wrong rap schema value file %d rap_api %d file:%s", pose->schema, RAP_API_SCHEMA, pose_name);
436 }
437 if (*(int32 *)rab->id != *(int32 *)const_cast<char *>(RAB_API_ID)) {
438 Fatal_error("Wrong rab id value file %d rab_api %d file:%s", rab->id, RAB_API_ID, bone_name);
439 }
440 if (rab->schema != RAB_API_SCHEMA) {
441 Fatal_error("Wrong rab schema value file %d rab_api %d file:%s", rab->schema, RAB_API_SCHEMA, bone_name);
442 }
443 if (mesh->nBones != rab->nBones) {
444 Fatal_error("mesh nBones != animation nBones %d != %d", mesh->nBones, rab->nBones);
445 }
446
447 // Pass in the linkage file and the bones file
448 Bone_Frame *bone_frame = rab->GetFrame(frame);
449 int32 brightness;
450
451 int32 debug = 1;
452
453 BoneDeformation *myBones[MAX_DEFORMABLE_BONES];
454
455 for (int32 i = 0; i < MAX_DEFORMABLE_BONES; i++) {
456 myBones[i] = NULL;
457 }
458
459 // Shadow stuff to play with
460 int32 nShadows = 0;
461 SVECTORPC p_n[3];
462 int32 p_d[3];
463
464 p_n[0].vx = 0;
465 p_n[0].vy = -1;
466 p_n[0].vz = 0;
467 p_d[0] = -118;
468
469 MATRIXPC local2screen; // not really bothered about this...
470
471 // Drawing finally
472 DrawActor4PC(g_av_actor, g_camera, bone_frame, mesh, pose, smesh, &ambient, &the_lights, &the_shades, nShadows, p_n, p_d, debug, uvframe, myBones, &brightness,
473 &local2screen);
474
475 uvframe++;
476 }
477
MakeCameraView()478 void MakeCameraView() {
479 RotMatrix_gte(&_crot, &g_camera->view);
480
481 // Include the x,y,z scalings
482 g_camera->view.m[0][0] = (int16)(g_camera->view.m[0][0] * 1);
483 g_camera->view.m[0][1] = (int16)(g_camera->view.m[0][1] * 1);
484 g_camera->view.m[0][2] = (int16)(g_camera->view.m[0][2] * 1);
485 g_camera->view.m[1][0] = (int16)(g_camera->view.m[1][0] * 1);
486 g_camera->view.m[1][1] = (int16)(g_camera->view.m[1][1] * 1);
487 g_camera->view.m[1][2] = (int16)(g_camera->view.m[1][2] * 1);
488 g_camera->view.m[2][0] = (int16)(g_camera->view.m[2][0] * 4);
489 g_camera->view.m[2][1] = (int16)(g_camera->view.m[2][1] * 4);
490 g_camera->view.m[2][2] = (int16)(g_camera->view.m[2][2] * 4);
491 }
492
ResetCamera()493 void ResetCamera() {
494 _crot.vx = (4096 * 180) / 360;
495 _crot.vy = (4096 * -30) / 360;
496 _crot.vz = 0;
497 g_camera->view.t[0] = 170 + av_x;
498 g_camera->view.t[1] = 0 + av_y;
499 g_camera->view.t[2] = 1800 + av_z;
500 g_camera->focLen = 619 * 4;
501 MakeCameraView();
502 }
503
ResetActor()504 void ResetActor() {
505 // Set up av_actor rotation
506 rot.vx = 0;
507 rot.vy = 0;
508 rot.vz = 0;
509 }
510
InitLight()511 void InitLight() {
512 g_av_Light->nStates = 1; // One state
513 g_av_Light->w = 0; // Zero width
514 g_av_Light->b = 0; // Zero bounce
515 g_av_Light->anu = 0; // Don't use it
516 g_av_Light->type = OMNI_LIGHT; // OMNI
517 g_av_Light->ba = 0; // Means nothing for an OMNI
518 g_av_Light->bs = 0; // Means nothing for an OMNI
519
520 // Don't think these things are used...
521 g_av_Light->states[0].ans2 = 0;
522 g_av_Light->states[0].ane2 = (100 * 1) * (100 * 1);
523
524 // No shade...
525 g_av_Light->states[0].m = 128;
526
527 // Direction doesn't matter; it's an OMNI light
528 g_av_Light->states[0].vx = 4096; // Ignored for an OMNI light
529 g_av_Light->states[0].vy = 0; // Ignored for an OMNI light
530 g_av_Light->states[0].vz = 0; // Ignored for an OMNI light
531
532 // Initial angle
533 av_LightA = 0;
534 av_LightDir = TRUE8;
535
536 // Initial position
537 av_LightX = 0;
538 av_LightY = 0;
539 av_LightZ = LIGHT_DISTANCE_FROM_ACTOR;
540
541 // Initial colour (RED)
542 av_LightR = 255;
543 av_LightG = 0;
544 av_LightB = 0;
545
546 // Auto flags
547 av_autoR = FALSE8;
548 av_autoG = FALSE8;
549 av_autoB = FALSE8;
550 }
551
AutoCycleLight()552 void AutoCycleLight() {
553 // Increase angle by 10 degrees
554 av_LightA += 10;
555 if (av_LightA >= 360)
556 av_LightA = 0;
557
558 // Convert to radians
559 double radians = (av_LightA * M_PI) / 180.0f;
560
561 // Now calculate z and x coordinates from this angle
562 av_LightX = (int16)(sin(radians) * LIGHT_DISTANCE_FROM_ACTOR);
563 av_LightZ = (int16)(cos(radians) * LIGHT_DISTANCE_FROM_ACTOR);
564
565 // Now bouce the light height between two fixed limits
566 if (av_LightDir) {
567 av_LightY = (int16)(av_LightY + 10);
568
569 if (av_LightY > LIGHT_HEIGHT_LIMIT) {
570 av_LightY = LIGHT_HEIGHT_LIMIT;
571 av_LightDir = FALSE8;
572 }
573 } else {
574 av_LightY = (int16)(av_LightY - 10);
575
576 if (av_LightY < -LIGHT_HEIGHT_LIMIT) {
577 av_LightY = -LIGHT_HEIGHT_LIMIT;
578 av_LightDir = TRUE8;
579 }
580 }
581
582 // Red component
583 if (av_autoR) {
584 av_LightR += 3;
585
586 if (av_LightR > 255) {
587 av_LightR = 255;
588 av_autoR = FALSE8;
589 }
590 } else {
591 av_LightR -= 2;
592
593 if (av_LightR < 0) {
594 av_LightR = 0;
595 av_autoR = TRUE8;
596 }
597 }
598
599 // Green component
600 if (av_autoG) {
601 av_LightG += 2;
602
603 if (av_LightG > 255) {
604 av_LightG = 255;
605 av_autoG = FALSE8;
606 }
607 } else {
608 av_LightG -= 3;
609
610 if (av_LightG < 0) {
611 av_LightG = 0;
612 av_autoG = TRUE8;
613 }
614 }
615
616 // Blue component
617 if (av_autoB) {
618 av_LightB += 7;
619
620 if (av_LightB > 255) {
621 av_LightB = 255;
622 av_autoB = FALSE8;
623 }
624 } else {
625 av_LightB -= 5;
626
627 if (av_LightB < 0) {
628 av_LightB = 0;
629 av_autoB = TRUE8;
630 }
631 }
632 }
633
SetLight(int32 falloff)634 void SetLight(int32 falloff) {
635 // Check colours are 0-255
636 if ((av_LightR > 255) || (av_LightR < 0) || (av_LightG > 255) || (av_LightG < 0) || (av_LightB > 255) || (av_LightB < 0))
637 Fatal_error("ActorView light rgb %d,%d,%d out of range (0-255)", av_LightR, av_LightG, av_LightB);
638
639 // Set colours (scale 0-255 to 0-4095)
640 g_av_Light->states[0].c.r = (int16)((av_LightR * 4096) / 256);
641 g_av_Light->states[0].c.g = (int16)((av_LightG * 4096) / 256);
642 g_av_Light->states[0].c.b = (int16)((av_LightB * 4096) / 256);
643
644 // Set the v field of colour to be the maximum of r,g,b
645 g_av_Light->states[0].c.v = g_av_Light->states[0].c.r; // Start at red
646 if (g_av_Light->states[0].c.g > g_av_Light->states[0].c.v) // If green bigger
647 g_av_Light->states[0].c.v = g_av_Light->states[0].c.g; // Set to green
648 if (g_av_Light->states[0].c.b > g_av_Light->states[0].c.v) // If blue bigger
649 g_av_Light->states[0].c.v = g_av_Light->states[0].c.b; // Set to blue
650
651 g_av_Light->states[0].pos.vx = (int32)av_LightX;
652 g_av_Light->states[0].pos.vy = (int32)av_LightY;
653 g_av_Light->states[0].pos.vz = (int32)av_LightZ;
654
655 // And add the players position
656 g_av_Light->states[0].pos.vx += (int32)g_av_actor->truePos.x;
657 g_av_Light->states[0].pos.vy += (int32)g_av_actor->truePos.y;
658 g_av_Light->states[0].pos.vz += (int32)g_av_actor->truePos.z;
659
660 // Falloff
661 if (falloff == 0) {
662 g_av_Light->afu = 0; // Don't use it
663 } else {
664 g_av_Light->states[0].afs2 = (falloff * falloff) / 100; // (d/10)^2 = (d*d)/100
665 g_av_Light->states[0].afe2 = falloff * falloff; // d^2 = (d*d)
666 g_av_Light->afu = 1; // Use it
667 }
668 }
669
my_sprintf(char * buf,const char * format...)670 int32 my_sprintf(char *buf, const char *format...) {
671 char lbuf[256];
672
673 // Process the variable arguments
674 va_list arglist;
675 va_start(arglist, format);
676
677 int32 slen = vsnprintf(lbuf, 256, const_cast<char *>(format), arglist);
678
679 strncpy(buf, lbuf, slen);
680 buf[slen] = '\0';
681 return slen;
682 }
683
684 } // End of namespace ICB
685